diff --git a/src/assets.lua b/src/assets.lua index 71f0ddb..d4438c3 100644 --- a/src/assets.lua +++ b/src/assets.lua @@ -3,7 +3,13 @@ -- luacheck: ignore ---@type pd_image -DarkPlayerBack = playdate.graphics.image.new("images/game/DarkPlayerBack.png") +DarkPlayerFrown = playdate.graphics.image.new("images/game/DarkPlayerFrown.png") +-- luacheck: ignore +---@type pd_image +LightPlayerAwayBase = playdate.graphics.image.new("images/game/LightPlayerAwayBase.png") +-- luacheck: ignore +---@type pd_image +LightPlayerSmile = playdate.graphics.image.new("images/game/LightPlayerSmile.png") -- luacheck: ignore ---@type pd_image Glove = playdate.graphics.image.new("images/game/Glove.png") @@ -15,37 +21,52 @@ PerfectPowerFlickerRight = playdate.graphics.image.new("images/game/PerfectPower DarkSkinFan = playdate.graphics.image.new("images/game/DarkSkinFan.png") -- luacheck: ignore ---@type pd_image -PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png") +DarkPlayerAwayBase = playdate.graphics.image.new("images/game/DarkPlayerAwayBase.png") -- luacheck: ignore ---@type pd_image PerfectPowerFlickerLeft = playdate.graphics.image.new("images/game/PerfectPowerFlickerLeft.png") -- luacheck: ignore ---@type pd_image +LightPlayerFrown = playdate.graphics.image.new("images/game/LightPlayerFrown.png") +-- luacheck: ignore +---@type pd_image +LightPlayerAwayBack = playdate.graphics.image.new("images/game/LightPlayerAwayBack.png") +-- luacheck: ignore +---@type pd_image +DarkPlayerAwayBack = playdate.graphics.image.new("images/game/DarkPlayerAwayBack.png") +-- luacheck: ignore +---@type pd_image +LightPlayerHomeBack = playdate.graphics.image.new("images/game/LightPlayerHomeBack.png") +-- luacheck: ignore +---@type pd_image BigBat = playdate.graphics.image.new("images/game/BigBat.png") -- luacheck: ignore ---@type pd_image LightSkinFan = playdate.graphics.image.new("images/game/LightSkinFan.png") -- luacheck: ignore ---@type pd_image +DarkPlayerHomeBack = playdate.graphics.image.new("images/game/DarkPlayerHomeBack.png") +-- luacheck: ignore +---@type pd_image GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png") -- luacheck: ignore ---@type pd_image GameLogo = playdate.graphics.image.new("images/game/GameLogo.png") -- luacheck: ignore ---@type pd_image -Hat = playdate.graphics.image.new("images/game/Hat.png") +LightPlayerHomeBase = playdate.graphics.image.new("images/game/LightPlayerHomeBase.png") -- luacheck: ignore ---@type pd_image -DarkPlayerBase = playdate.graphics.image.new("images/game/DarkPlayerBase.png") +Hat = playdate.graphics.image.new("images/game/Hat.png") -- luacheck: ignore ---@type pd_image MenuImage = playdate.graphics.image.new("images/game/MenuImage.png") -- luacheck: ignore ---@type pd_image -PlayerSmile = playdate.graphics.image.new("images/game/PlayerSmile.png") +Minimap = playdate.graphics.image.new("images/game/Minimap.png") -- luacheck: ignore ---@type pd_image -Minimap = playdate.graphics.image.new("images/game/Minimap.png") +DarkPlayerHomeBase = playdate.graphics.image.new("images/game/DarkPlayerHomeBase.png") -- luacheck: ignore ---@type pd_image GrassBackground = playdate.graphics.image.new("images/game/GrassBackground.png") @@ -54,13 +75,10 @@ GrassBackground = playdate.graphics.image.new("images/game/GrassBackground.png") GrassBackgroundSmall = playdate.graphics.image.new("images/game/GrassBackgroundSmall.png") -- luacheck: ignore ---@type pd_image -LightPlayerBase = playdate.graphics.image.new("images/game/LightPlayerBase.png") +DarkPlayerSmile = playdate.graphics.image.new("images/game/DarkPlayerSmile.png") -- luacheck: ignore ---@type pd_image PerfectPowerBg = playdate.graphics.image.new("images/game/PerfectPowerBg.png") --- luacheck: ignore ----@type pd_image -LightPlayerBack = playdate.graphics.image.new("images/game/LightPlayerBack.png") -- luacheck: ignore ---@type pd_sampleplayer diff --git a/src/baserunning.lua b/src/baserunning.lua index ebb9168..7a91df5 100644 --- a/src/baserunning.lua +++ b/src/baserunning.lua @@ -1,10 +1,10 @@ ---- @alias Runner { ---- x: number, ---- y: number, ---- nextBase: Base, ---- prevBase: Base | nil, ---- forcedTo: Base | nil, ---- } +--- @class Runner +--- @field x number +--- @field y number +--- @field nextBase Base +--- @field prevBase Base | nil +--- @field forcedTo Base | nil +--- @field spriteIndex number ---@class Baserunning ---@field runners Runner[] @@ -158,6 +158,7 @@ function Baserunning:pushNewBatter() nextBase = C.RightHandedBattersBox, prevBase = nil, forcedTo = C.Bases[C.First], + spriteIndex = math.random(#HomeTeamSpriteGroup), } self.runners[#self.runners + 1] = new self.batter = new diff --git a/src/draw/fielder.lua b/src/draw/fielder.lua index b9949ec..0c60fca 100644 --- a/src/draw/fielder.lua +++ b/src/draw/fielder.lua @@ -17,7 +17,7 @@ local function drawFielderGlove(ball, fielderX, fielderY, flip) end end ----@param playerSprites SpriteCollection +---@param playerSprites PlayerImageBundle ---@param ball Point3d ---@param x number ---@param y number diff --git a/src/draw/player.lua b/src/draw/player.lua index 6426081..393d219 100644 --- a/src/draw/player.lua +++ b/src/draw/player.lua @@ -1,7 +1,9 @@ -- selene: allow(shadowing) local gfx = playdate.graphics ----@alias SpriteCollection { smiling: pd_image, lowHat: pd_image, frowning: pd_image, back: pd_image } +---@alias PlayerImageBundle { smiling: pd_image, lowHat: pd_image, frowning: pd_image, back: pd_image } + +---@alias SpriteCollection PlayerImageBundle[] ---@param image pd_image ---@param drawInverted boolean @@ -16,31 +18,31 @@ function maybeDrawInverted(image, x, y, drawInverted) end --- TODO: Custom names on jerseys? ----@return SpriteCollection +---@return PlayerImageBundle ---@param base pd_image ----@param isDark boolean -function buildCollection(base, back, logo, isDark) +---@param isInverted boolean +function buildPlayerBundle(base, back, smile, frown, logo, isInverted) local smiling = gfx.image.new(base:getSize()) gfx.lockFocus(smiling) base:draw(0, 0) Hat:draw(6, 0) - PlayerSmile:draw(5, 9) - maybeDrawInverted(logo, 3, 25, isDark) + smile:draw(5, 9) + maybeDrawInverted(logo, 3, 25, isInverted) local lowHat = gfx.image.new(base:getSize()) gfx.lockFocus(lowHat) base:draw(0, 0) Hat:draw(6, 2) - PlayerSmile:draw(5, 9) - maybeDrawInverted(logo, 3, 25, isDark) + smile:draw(5, 9) + maybeDrawInverted(logo, 3, 25, isInverted) local frowning = gfx.image.new(base:getSize()) gfx.lockFocus(frowning) base:draw(0, 0) - maybeDrawInverted(logo, 3, 25, isDark) + maybeDrawInverted(logo, 3, 25, isInverted) Hat:draw(6, 0) - PlayerFrown:draw(5, 9) + frown:draw(5, 9) gfx.unlockFocus() @@ -52,20 +54,24 @@ function buildCollection(base, back, logo, isDark) } end ---selene: allow(unscoped_variables) ---@type SpriteCollection -AwayTeamSprites = nil +AwayTeamSpriteGroup = nil ---selene: allow(unscoped_variables) ---@type SpriteCollection -HomeTeamSprites = nil +HomeTeamSpriteGroup = nil function replaceAwayLogo(logo) - AwayTeamSprites = buildCollection(DarkPlayerBase, DarkPlayerBack, logo, true) + AwayTeamSpriteGroup = { + buildPlayerBundle(DarkPlayerAwayBase, DarkPlayerAwayBack, DarkPlayerSmile, DarkPlayerFrown, logo, true), + buildPlayerBundle(LightPlayerAwayBase, LightPlayerAwayBack, LightPlayerSmile, LightPlayerFrown, logo, true), + } end function replaceHomeLogo(logo) - HomeTeamSprites = buildCollection(LightPlayerBase, LightPlayerBack, logo, false) + HomeTeamSpriteGroup = { + buildPlayerBundle(DarkPlayerHomeBase, DarkPlayerHomeBack, DarkPlayerSmile, DarkPlayerFrown, logo, true), + buildPlayerBundle(LightPlayerHomeBase, LightPlayerHomeBack, LightPlayerSmile, LightPlayerFrown, logo, true), + } end replaceAwayLogo(Logos[1].image) diff --git a/src/fielding.lua b/src/fielding.lua index f3d1d1d..a99a67f 100644 --- a/src/fielding.lua +++ b/src/fielding.lua @@ -3,6 +3,7 @@ --- @field y number --- @field target XyPair | nil --- @field speed number +--- @field spriteIndex number ---@class Fielders ---@field first Fielder @@ -30,6 +31,7 @@ local function newFielder(name, speed) return { name = name, speed = speed * C.FielderRunMult, + spriteIndex = math.random(#HomeTeamSpriteGroup) } end diff --git a/src/fonts/Nano Sans-table-6-10.png b/src/fonts/Nano Sans-table-6-10.png new file mode 100644 index 0000000..399c9dd Binary files /dev/null and b/src/fonts/Nano Sans-table-6-10.png differ diff --git a/src/fonts/Nano Sans.fnt b/src/fonts/Nano Sans.fnt new file mode 100644 index 0000000..a849656 --- /dev/null +++ b/src/fonts/Nano Sans.fnt @@ -0,0 +1,104 @@ +tracking=1 + +space 2 +A 3 +B 3 +T 3 +a 3 +b 3 +c 3 +d 3 +e 3 +f 3 +g 3 +h 3 +i 1 +l 2 +q 3 +r 3 +s 3 +w 5 +z 3 +j 1 +n 3 +o 3 +p 3 +m 5 +k 3 +t 3 +u 3 +v 3 +y 3 +x 3 +. 1 +C 3 +D 3 +E 3 +F 3 +G 3 +H 3 +I 3 +0 3 +1 3 +8 3 +9 3 +7 3 +6 3 +5 3 +4 3 +3 3 +2 3 +: 1 +; 1 +! 1 +" 3 +{ 3 +} 3 +| 1 +J 3 +K 3 +L 3 +M 5 +N 4 +O 3 +W 5 +U 3 +V 3 +X 3 +Y 3 +Z 3 +Q 3 +S 3 +R 3 +P 3 +[ 2 +] 2 +^ 3 +< 3 += 3 +> 3 +? 3 +@ 4 +\ 3 +_ 3 +` 2 +~ 5 +¥ 3 +… 5 +™ 5 +‼ 3 +© 5 +® 5 +� 5 +# 5 +/ 3 +- 3 ++ 3 +, 1 +* 3 +) 2 +( 2 +' 1 +$ 3 +% 3 +& 4 \ No newline at end of file diff --git a/src/graphics.lua b/src/graphics.lua index 7bd8479..7c82300 100644 --- a/src/graphics.lua +++ b/src/graphics.lua @@ -27,15 +27,16 @@ blipper = {} --- Build an object that simply "blips" between the given images at the given interval. --- Expects `playdate.graphics.animation.blinker.updateAll()` to be called on every update. -function blipper.new(msInterval, smiling, lowHat) +function blipper.new(msInterval, spriteCollection) local blinker = playdate.graphics.animation.blinker.new(msInterval, msInterval, true) blinker:start() return { blinker = blinker, smiling = smiling, lowHat = lowHat, - draw = function(self, disableBlipping, x, y) - local currentImage = (disableBlipping or self.blinker.on) and self.lowHat or self.smiling + draw = function(self, disableBlipping, x, y, hasSpriteIndex) + local spriteBundle = spriteCollection[hasSpriteIndex.spriteIndex] + local currentImage = (disableBlipping or self.blinker.on) and spriteBundle.lowHat or spriteBundle.smiling local offsetY = currentImage == lowHat and -1 or 0 currentImage:draw(x, y + offsetY) end, diff --git a/src/images/game/DarkPlayerAwayBack.png b/src/images/game/DarkPlayerAwayBack.png new file mode 100644 index 0000000..cdf509c Binary files /dev/null and b/src/images/game/DarkPlayerAwayBack.png differ diff --git a/src/images/game/DarkPlayerAwayBase.png b/src/images/game/DarkPlayerAwayBase.png new file mode 100644 index 0000000..aaaa91c Binary files /dev/null and b/src/images/game/DarkPlayerAwayBase.png differ diff --git a/src/images/game/DarkPlayerFrown.png b/src/images/game/DarkPlayerFrown.png new file mode 100644 index 0000000..aa7e677 Binary files /dev/null and b/src/images/game/DarkPlayerFrown.png differ diff --git a/src/images/game/DarkPlayerHomeBack.png b/src/images/game/DarkPlayerHomeBack.png new file mode 100644 index 0000000..8cddfe3 Binary files /dev/null and b/src/images/game/DarkPlayerHomeBack.png differ diff --git a/src/images/game/DarkPlayerHomeBase.png b/src/images/game/DarkPlayerHomeBase.png new file mode 100644 index 0000000..7aca994 Binary files /dev/null and b/src/images/game/DarkPlayerHomeBase.png differ diff --git a/src/images/game/DarkPlayerSmile.png b/src/images/game/DarkPlayerSmile.png new file mode 100644 index 0000000..2e4872c Binary files /dev/null and b/src/images/game/DarkPlayerSmile.png differ diff --git a/src/images/game/DarkSkinFan.png b/src/images/game/DarkSkinFan.png index 220155a..44ff214 100644 Binary files a/src/images/game/DarkSkinFan.png and b/src/images/game/DarkSkinFan.png differ diff --git a/src/images/game/DarkPlayerBack.png b/src/images/game/LightPlayerAwayBack.png similarity index 100% rename from src/images/game/DarkPlayerBack.png rename to src/images/game/LightPlayerAwayBack.png diff --git a/src/images/game/DarkPlayerBase.png b/src/images/game/LightPlayerAwayBase.png similarity index 100% rename from src/images/game/DarkPlayerBase.png rename to src/images/game/LightPlayerAwayBase.png diff --git a/src/images/game/PlayerFrown.png b/src/images/game/LightPlayerFrown.png similarity index 100% rename from src/images/game/PlayerFrown.png rename to src/images/game/LightPlayerFrown.png diff --git a/src/images/game/LightPlayerBack.png b/src/images/game/LightPlayerHomeBack.png similarity index 100% rename from src/images/game/LightPlayerBack.png rename to src/images/game/LightPlayerHomeBack.png diff --git a/src/images/game/LightPlayerBase.png b/src/images/game/LightPlayerHomeBase.png similarity index 73% rename from src/images/game/LightPlayerBase.png rename to src/images/game/LightPlayerHomeBase.png index a36931f..42ee6b0 100644 Binary files a/src/images/game/LightPlayerBase.png and b/src/images/game/LightPlayerHomeBase.png differ diff --git a/src/images/game/LightPlayerSmile.png b/src/images/game/LightPlayerSmile.png new file mode 100644 index 0000000..746b75e Binary files /dev/null and b/src/images/game/LightPlayerSmile.png differ diff --git a/src/images/game/LightSkinFan.png b/src/images/game/LightSkinFan.png index 21484ba..4996dd5 100644 Binary files a/src/images/game/LightSkinFan.png and b/src/images/game/LightSkinFan.png differ diff --git a/src/images/game/PlayerSmile.png b/src/images/game/PlayerSmile.png deleted file mode 100644 index b6e9f82..0000000 Binary files a/src/images/game/PlayerSmile.png and /dev/null differ diff --git a/src/main-menu.lua b/src/main-menu.lua index 4f244c4..ef07832 100644 --- a/src/main-menu.lua +++ b/src/main-menu.lua @@ -5,7 +5,8 @@ MainMenu = { } local gfx = playdate.graphics -local StartFont = gfx.font.new("fonts/Roobert-20-Medium.pft") +local StartFont = gfx.font.new("fonts/Roobert-11-Medium.pft") +local TinyFont = gfx.font.new("fonts/Nano Sans.pft") --- Take control of playdate.update --- Will replace playdate.update when the menu is done. @@ -21,8 +22,8 @@ local inningCountSelection = 3 local function startGame() local next = MainMenu.next.new({ finalInning = inningCountSelection, - homeTeamSprites = HomeTeamSprites, - awayTeamSprites = AwayTeamSprites, + homeTeamSpriteGroup = HomeTeamSpriteGroup, + awayTeamSpriteGroup = AwayTeamSpriteGroup, }) playdate.resetElapsedTime() transitionBetween(MainMenu, next) @@ -87,16 +88,18 @@ function MainMenu:update() startGame() end if playdate.buttonJustPressed(playdate.kButtonUp) then - inningCountSelection = inningCountSelection + 1 + inningCountSelection = math.min(99, inningCountSelection + 1) end if playdate.buttonJustPressed(playdate.kButtonDown) then - inningCountSelection = inningCountSelection - 1 + inningCountSelection = math.max(1, inningCountSelection - 1) end - GameLogo:drawCentered(C.Center.x, 50) + local logoCenter = 90 + GameLogo:drawCentered(C.Center.x, logoCenter) + TinyFont:drawTextAligned("a game by Sage", C.Center.x, logoCenter + 35, kTextAlignment.center) - StartFont:drawTextAligned("Press A to start!", C.Center.x, 140, kTextAlignment.center) - gfx.drawTextAligned("with " .. inningCountSelection .. " innings", C.Center.x, 190, kTextAlignment.center) + StartFont:drawTextAligned("Press A to start!", C.Center.x, 180, kTextAlignment.center) + gfx.drawTextAligned("with " .. inningCountSelection .. " innings", C.Center.x, 210, kTextAlignment.center) local ball = { x = animatorX:currentValue(), @@ -105,10 +108,9 @@ function MainMenu:update() size = 6, } - local ballIsHeld = drawFielder(AwayTeamSprites, ball, 30, 200) - ballIsHeld = drawFielder(HomeTeamSprites, ball, 350, 200, playdate.graphics.kImageFlippedX) or ballIsHeld + local ballIsHeld = drawFielder(AwayTeamSpriteGroup[1], ball, 30, 200) + ballIsHeld = drawFielder(HomeTeamSpriteGroup[2], ball, 350, 200, playdate.graphics.kImageFlippedX) or ballIsHeld - -- drawFielder(AwayTeamSprites, { x = 0, y = 0, z = 0 }, ball.x, ball.y) if not ballIsHeld then gfx.setLineWidth(2) diff --git a/src/main.lua b/src/main.lua index d81675a..687e074 100644 --- a/src/main.lua +++ b/src/main.lua @@ -69,8 +69,8 @@ local teams = { ---@class Settings ---@field finalInning number ---@field userTeam TeamId | nil ----@field awayTeamSprites SpriteCollection ----@field homeTeamSprites SpriteCollection +---@field awayTeamSpriteGroup SpriteCollection +---@field homeTeamSpriteGroup SpriteCollection ---@class MutableState ---@field deltaSeconds number @@ -114,8 +114,8 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state) fielding = fielding or Fielding.new() settings.userTeam = "away" - local homeTeamBlipper = blipper.new(100, settings.homeTeamSprites.smiling, settings.homeTeamSprites.lowHat) - local awayTeamBlipper = blipper.new(100, settings.awayTeamSprites.smiling, settings.awayTeamSprites.lowHat) + local homeTeamBlipper = blipper.new(100, settings.homeTeamSpriteGroup) + local awayTeamBlipper = blipper.new(100, settings.awayTeamSpriteGroup) local battingTeam = "away" local runnerBlipper = battingTeam == "away" and awayTeamBlipper or homeTeamBlipper local ball = Ball.new(gfx.animator) @@ -138,8 +138,8 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state) inning = 1, pitchIsOver = true, didSwing = false, - battingTeamSprites = settings.awayTeamSprites, - fieldingTeamSprites = settings.homeTeamSprites, + battingTeamSprites = settings.awayTeamSpriteGroup, + fieldingTeamSprites = settings.homeTeamSpriteGroup, runnerBlipper = runnerBlipper, stats = Statistics.new(), }, @@ -266,12 +266,12 @@ function Game:nextHalfInning() self.state.battingTeam = getOppositeTeamId(self.state.battingTeam) playdate.timer.new(2000, function() if self.state.battingTeam == "home" then - self.state.battingTeamSprites = self.settings.homeTeamSprites + self.state.battingTeamSprites = self.settings.homeTeamSpriteGroup self.state.runnerBlipper = self.homeTeamBlipper - self.state.fieldingTeamSprites = self.settings.awayTeamSprites + self.state.fieldingTeamSprites = self.settings.awayTeamSpriteGroup else - self.state.battingTeamSprites = self.settings.awayTeamSprites - self.state.fieldingTeamSprites = self.settings.homeTeamSprites + self.state.battingTeamSprites = self.settings.awayTeamSpriteGroup + self.state.fieldingTeamSprites = self.settings.homeTeamSpriteGroup self.state.runnerBlipper = self.awayTeamBlipper end end) @@ -608,7 +608,7 @@ function Game:update() for _, fielder in pairs(self.fielding.fielders) do addDraw(fielder.y + danceOffset, function() local ballHeldByThisFielder = - drawFielder(self.state.fieldingTeamSprites, self.state.ball, fielder.x, fielder.y + danceOffset) + drawFielder(self.state.fieldingTeamSprites[fielder.spriteIndex], self.state.ball, fielder.x, fielder.y + danceOffset) if ballHeldByThisFielder then ballHeldBy = fielder end @@ -620,13 +620,13 @@ function Game:update() addDraw(runner.y, function() if runner == self.baserunning.batter then if self.state.batAngleDeg > 50 and self.state.batAngleDeg < 200 then - self.state.battingTeamSprites.back:draw(runner.x, runner.y - playerHeightOffset) + self.state.battingTeamSprites[runner.spriteIndex].back:draw(runner.x, runner.y - playerHeightOffset) else - self.state.battingTeamSprites.smiling:draw(runner.x, runner.y - playerHeightOffset) + self.state.battingTeamSprites[runner.spriteIndex].smiling:draw(runner.x, runner.y - playerHeightOffset) end else -- TODO? Change blip speed depending on runner speed? - self.state.runnerBlipper:draw(false, runner.x, runner.y - playerHeightOffset) + self.state.runnerBlipper:draw(false, runner.x, runner.y - playerHeightOffset, runner) end end) end @@ -644,13 +644,15 @@ function Game:update() end for _, runner in pairs(self.baserunning.outRunners) do - self.state.battingTeamSprites.frowning:draw(runner.x, runner.y - playerHeightOffset) + self.state.battingTeamSprites[runner.spriteIndex].frowning:draw(runner.x, runner.y - playerHeightOffset) end for _, runner in pairs(self.baserunning.scoredRunners) do - self.state.battingTeamSprites.smiling:draw(runner.x, runner.y - playerHeightOffset) + self.state.battingTeamSprites[runner.spriteIndex].smiling:draw(runner.x, runner.y - playerHeightOffset) end - throwMeter:drawNearFielder(ballHeldBy) + if self:userIsOn('defense') then + throwMeter:drawNearFielder(ballHeldBy) + end if not ballHeldBy then gfx.setLineWidth(2)