mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-18 19:54:21 +02:00
CLOSES #1181, CLOSES #1212, CLOSES #1214, CLOSES #1224, CLOSES #1230, CLOSES #1249, CLOSES #1271, CLOSES #1272, CLOSES #1273, CLOSES #1298, CLOSES #1305, CLOSES #1307, CLOSES #1318, CLOSES #1328, CLOSES #1330, CLOSES #1331, CLOSES #1333, CLOSES #1334, CLOSES #1335, CLOSES #1340, CLOSES #1345, CLOSES #1346, CLOSES #1360, CLOSES #1362
This commit is contained in:
@@ -134,13 +134,15 @@ function SummaryMenu:draw()
|
||||
Font.draw(("%03d"):format(def.dex or 0), 24, 56)
|
||||
|
||||
if self.page == 1 then
|
||||
-- HP bar (11,3) + numbers row 4, STATUS/ (9,6), the DrawLineBox
|
||||
-- bracket around the name/HP block, and PrintLevel at (14,2). The
|
||||
-- level belongs to page 1 ONLY: StatusScreen2 opens with ClearScreenArea
|
||||
-- over (9,2) 5x10 (status_screen.asm:303-305), which wipes it. #280
|
||||
-- level is page 1 only: StatusScreen2 opens with ClearScreenArea over
|
||||
-- (9,2) 5x10 (status_screen.asm:303-305). #280
|
||||
printLevel(14, 2, mon.level)
|
||||
drawLineBox(19, 1, 6, 10)
|
||||
HudTiles.drawHPBar(data, 11, 3, mon, 1) -- wHPBarType 1
|
||||
-- engine/pokemon/status_screen.asm:120-125
|
||||
local PaletteFX = require("src.render.PaletteFX")
|
||||
local barZoned = PaletteFX.shader() ~= nil
|
||||
and PaletteFX.pal(data, "GREENBAR") ~= nil
|
||||
HudTiles.drawHPBar(data, 11, 3, mon, 1, barZoned) -- wHPBarType 1
|
||||
Font.draw(("%3d/%3d"):format(mon.hp, mon.stats.hp), 96, 32)
|
||||
Font.draw(Strings("STATUS/"), 72, 48)
|
||||
Font.draw(mon.status or "OK", 128, 48)
|
||||
|
||||
+27
-4
@@ -171,6 +171,27 @@ local function markVisibleTrueColor(x, y, w, h, cover)
|
||||
if ix2 < right then P.markTrueColor(ix2, iy1, right - ix2, iy2 - iy1) end
|
||||
end
|
||||
|
||||
-- ..(engine/movie/title.asm ln 321)
|
||||
local function replayObjSprite(game, image, quad, x, y)
|
||||
local P = require("src.render.PaletteFX")
|
||||
if not P.usesSpriteObp() then return end
|
||||
local top = game.stack and game.stack:top()
|
||||
local box = top and top.titleUiBox
|
||||
if box then
|
||||
local w, h
|
||||
if quad then
|
||||
w, h = select(3, quad:getViewport())
|
||||
else
|
||||
w, h = image:getDimensions()
|
||||
end
|
||||
if x < (box[3] + 1) * 8 and x + w > box[1] * 8
|
||||
and y < (box[4] + 1) * 8 and y + h > box[2] * 8 then
|
||||
return
|
||||
end
|
||||
end
|
||||
P.markUiSpriteRedraw(image, quad, x, y)
|
||||
end
|
||||
|
||||
function TitleState.new(game, opts)
|
||||
opts = opts or {}
|
||||
local self = setmetatable({}, TitleState)
|
||||
@@ -662,12 +683,11 @@ function TitleState:draw()
|
||||
local x = 40 + math.floor((56 - w) / 2) + self.monOffset
|
||||
local y = 136 - h
|
||||
love.graphics.draw(sprite, x, y)
|
||||
-- a full-color mon keeps its own palette through the SGB pass, minus
|
||||
-- the strip Red's OAM covers (#350). Yellow never reaches here: its
|
||||
-- layout has no cycling mon and no Red art (title_yellow.asm).
|
||||
-- SGB: the mon keeps its palette minus the strip Red's OAM covers
|
||||
-- (#350); Yellow never reaches here (title_yellow.asm)
|
||||
if spriteTrueColor then
|
||||
local cover
|
||||
if playerImage then
|
||||
if playerImage and not require("src.render.PaletteFX").usesSpriteObp() then
|
||||
local pw, ph = playerImage:getDimensions()
|
||||
cover = { 82, 80, pw, ph }
|
||||
end
|
||||
@@ -678,10 +698,13 @@ function TitleState:draw()
|
||||
if self.playerQuads then
|
||||
for _, part in ipairs(self.playerQuads) do
|
||||
love.graphics.draw(playerImage, part[1], 82 + part[2], 80 + part[3])
|
||||
replayObjSprite(self.game, playerImage, part[1], 82 + part[2], 80 + part[3])
|
||||
end
|
||||
love.graphics.draw(playerImage, self.ballQuad, 82, self.ballY)
|
||||
replayObjSprite(self.game, playerImage, self.ballQuad, 82, self.ballY)
|
||||
elseif playerImage then
|
||||
love.graphics.draw(playerImage, 82, 80)
|
||||
replayObjSprite(self.game, playerImage, nil, 82, 80)
|
||||
end
|
||||
end
|
||||
self:drawCopyright(136 + (preRibbon and 0 or scrollY))
|
||||
|
||||
+63
-25
@@ -31,6 +31,7 @@ local ItemEffects = require("src.core.gen2.ItemEffects")
|
||||
local Mon = require("src.battle.gen2.Mon")
|
||||
local Palettes = require("src.world.gen2.Palettes")
|
||||
local Pokerus = require("src.core.gen2.Pokerus")
|
||||
local Prize = require("src.battle.gen2.Prize")
|
||||
local Runtime = require("src.mods.Runtime")
|
||||
local Screens = require("src.ui.Screens")
|
||||
local Sound = require("src.core.Sound")
|
||||
@@ -621,6 +622,19 @@ function BattleState:drawPic(mon, back)
|
||||
and not (self.vanishAnim and self.vanishAnim == self.anim) then
|
||||
return
|
||||
end
|
||||
-- GetSubstitutePic (engine/battle_anims/anim_commands.asm:905-960): the
|
||||
-- doll sits in the mon's own pic box and takes its palette.
|
||||
local doll, dollQuad
|
||||
if not (trainerBack or enemyTrainer) then
|
||||
local over = anim and anim.pic
|
||||
local up
|
||||
if over ~= nil then
|
||||
up = over == "substitute"
|
||||
else
|
||||
up = mon and mon.volatile and (mon.volatile.substitute or 0) > 0
|
||||
end
|
||||
if up then doll, dollQuad = self:substituteDoll(back) end
|
||||
end
|
||||
local G = love.graphics
|
||||
local w, h = image:getDimensions()
|
||||
local px, py
|
||||
@@ -660,6 +674,10 @@ function BattleState:drawPic(mon, back)
|
||||
px = px + math.floor(w * (1 - scale) / 2)
|
||||
py = py + math.floor(h * (1 - scale))
|
||||
end
|
||||
if doll then
|
||||
px = (back and 32 or 112) + ((anim and anim.slide) or 0)
|
||||
py = back and 80 or 40
|
||||
end
|
||||
G.setColor(1, 1, 1, 1)
|
||||
-- No mon on this side at all in the catching tutorial, where the box holds
|
||||
-- the DUDE's back-pic and nothing else for the whole battle.
|
||||
@@ -682,6 +700,10 @@ function BattleState:drawPic(mon, back)
|
||||
-- what is still inside the box rather than drawn over the HUD below it.
|
||||
local sunk = self:faintSink(side)
|
||||
local function body()
|
||||
if doll then
|
||||
G.draw(doll, dollQuad, px, py)
|
||||
return
|
||||
end
|
||||
if sunk > 0 then
|
||||
local visible = h - math.floor(sunk / scale)
|
||||
if visible <= 0 then return end
|
||||
@@ -701,6 +723,24 @@ function BattleState:drawPic(mon, back)
|
||||
end
|
||||
end
|
||||
|
||||
-- MonsterSpriteGFX (gfx/sprites.asm:82): the facing-DOWN 16x16 frame for the
|
||||
-- enemy's frontpic, facing-UP for the player's backpic.
|
||||
function BattleState:substituteDoll(back)
|
||||
if self.subDoll == nil then
|
||||
local ok, image = pcall(Assets.image, "assets/generated/sprites/monster.png")
|
||||
if ok and image then
|
||||
local w, h = image:getDimensions()
|
||||
self.subDoll = { image = image,
|
||||
down = love.graphics.newQuad(0, 0, 16, 16, w, h),
|
||||
up = love.graphics.newQuad(0, 16, 16, 16, w, h) }
|
||||
else
|
||||
self.subDoll = false
|
||||
end
|
||||
end
|
||||
if not self.subDoll then return nil end
|
||||
return self.subDoll.image, back and self.subDoll.up or self.subDoll.down
|
||||
end
|
||||
|
||||
-- The top `visible` rows of a pic, for the faint slide. One quad, re-aimed,
|
||||
-- the way BattleAnimView keeps one blit quad rather than a new one per frame.
|
||||
function BattleState:cropQuad(image, visible)
|
||||
@@ -1072,16 +1112,8 @@ function BattleState:stepAnim(input)
|
||||
end
|
||||
end
|
||||
|
||||
-- NOTE on picHidden and the animation runtime. An animation that ENDS with a
|
||||
-- pic box cleared could latch it here, and the tilemap argument says it should:
|
||||
-- BattleAnimRestoreHuds redraws the two HUDs and nothing else. It deliberately
|
||||
-- does not, because BATTLE_BG_EFFECT_REMOVE_MON and _RETURN_MON are also used
|
||||
-- by moves whose user is still standing there afterwards -- SUBSTITUTE (the
|
||||
-- doll takes the box over, and nothing in this port draws one yet), SKY_ATTACK,
|
||||
-- BEAT_UP, BATON_PASS -- and a blanket latch would make those mons invisible
|
||||
-- for the rest of the fight. The two moments the cart really does leave the
|
||||
-- box empty for good are latched explicitly instead: a catch (pushCaught) and
|
||||
-- a faint (MonFaintedAnimation, in update).
|
||||
-- REMOVE_MON / RETURN_MON also serve SUBSTITUTE, SKY_ATTACK, BEAT_UP and
|
||||
-- BATON_PASS, so picHidden is only latched by a catch and a faint.
|
||||
|
||||
-- Whatever Call_PlayBattleAnim was standing in front of: a send-out's cry and
|
||||
-- HUD update run the moment its animation is done, cut short or not.
|
||||
@@ -1101,6 +1133,7 @@ function BattleState:animPicState(side)
|
||||
size = bg.picSize[side],
|
||||
slide = bg.slide[side] or 0,
|
||||
shade = bg.monShade[side],
|
||||
pic = self.anim.picOverride[side],
|
||||
}
|
||||
end
|
||||
|
||||
@@ -1190,22 +1223,14 @@ function BattleState:advanceQueue()
|
||||
if event.kind == "level" and event.index then
|
||||
self.evolvable[event.index] = true
|
||||
-- GiveExperiencePoints' `.skip_active_mon_update` guard
|
||||
-- (engine/battle/core.asm:6999-7003): only the mon that is OUT copies its
|
||||
-- recalculated HP, max HP and level into the battle struct, and only then
|
||||
-- does `callfar UpdatePlayerHUD` (:7034) redraw the bar. That is a
|
||||
-- REDRAW, not AnimateHPBar, so the shown HP snaps instead of chasing --
|
||||
-- without it the bar kept the pre-level-up HP against the new maximum
|
||||
-- until the next damage or heal event moved it.
|
||||
-- (engine/battle/core.asm:6999-7003): the OUT mon's shown HP snaps.
|
||||
local battle = self.battle
|
||||
local mon = battle and battle.party and battle.party[event.index]
|
||||
-- pokegold engine/battle/core.asm:7057-7069: every mon that leveled
|
||||
-- gets the stats box, not just the mon currently on the field.
|
||||
self.pendingStatsMon = mon
|
||||
-- engine/battle/core.asm:7044
|
||||
-- engine/battle/core.asm:7284
|
||||
if mon and mon == battle.player then
|
||||
event.text = nil
|
||||
event.sfx = nil
|
||||
event.waitSfx = nil
|
||||
if self.shownHp then
|
||||
self.shownHp.player = mon.hp or 0
|
||||
if self.hpAnim and self.hpAnim.side == "player" then
|
||||
@@ -1213,9 +1238,6 @@ function BattleState:advanceQueue()
|
||||
end
|
||||
end
|
||||
-- `ld [wBattleMonLevel], a` in the same guarded block (:7018-7020).
|
||||
-- AnimateExpBar has already walked the number up one level at a time by
|
||||
-- the time this runs, so this only catches a level gained with no exp
|
||||
-- crawl behind it.
|
||||
self.shownLevel = mon.level or self.shownLevel
|
||||
end
|
||||
end
|
||||
@@ -2464,7 +2486,10 @@ function BattleState:pushCaught(enemy, itemId)
|
||||
self:push({ kind = "dex-entry", species = enemy.species })
|
||||
end
|
||||
if self.contest then
|
||||
return self:contestCatch(enemy)
|
||||
-- A contest catch still exits through the `.run` arm with result WIN
|
||||
-- (engine/battle/core.asm:4780-4783), so CheckPayDay runs for it too.
|
||||
self:contestCatch(enemy)
|
||||
return self:pushPayDay()
|
||||
end
|
||||
save.party = save.party or {}
|
||||
local toPc = #save.party >= Boxes.PARTY_SIZE
|
||||
@@ -2520,6 +2545,19 @@ function BattleState:pushCaught(enemy, itemId)
|
||||
self:push({ kind = "message",
|
||||
text = self:name(enemy) .. " was sent to BILL's PC." })
|
||||
end
|
||||
self:pushPayDay()
|
||||
end
|
||||
|
||||
-- CheckPayDay runs on a capture too: `and $f` keeps the win arm
|
||||
-- (engine/battle/core.asm:7971-7976, :8014-8042).
|
||||
function BattleState:pushPayDay()
|
||||
local save = self.save
|
||||
local coins = Prize.payDay(save, self.battle.payDay, self.battle.amuletCoin)
|
||||
self.battle.payDay = nil
|
||||
if coins then
|
||||
self:push({ kind = "message",
|
||||
text = Prize.payDayMessage(coins, save.player and save.player.name) })
|
||||
end
|
||||
end
|
||||
|
||||
-- CheckWhetherToAskSwitch: a started battle, more than one mon, no link, the
|
||||
@@ -3029,7 +3067,7 @@ function BattleState:applyPartyItem(itemId, action, mon, slot)
|
||||
local before = (mon and mon.hp) or 0
|
||||
local result
|
||||
if action == "pp" then
|
||||
result = ItemEffects.usePpItem(itemId, mon, slot)
|
||||
result = ItemEffects.usePpItem(itemId, mon, slot, data)
|
||||
else
|
||||
result = ItemEffects.useOnMon(itemId, mon, data)
|
||||
end
|
||||
|
||||
@@ -172,6 +172,17 @@ local ROWS = {
|
||||
text = function(options)
|
||||
return require("src.render.GBCFX").levelLabel(options.gbcfx or 0)
|
||||
end },
|
||||
{ label = "VIDEO MODE", key = "videoMode", port = true,
|
||||
cycle = function(options, delta)
|
||||
local VideoMode = require("src.core.VideoMode")
|
||||
options.videoMode = VideoMode.cycle(options.videoMode, delta)
|
||||
VideoMode.apply(options.videoMode)
|
||||
end,
|
||||
text = function(options)
|
||||
local VideoMode = require("src.core.VideoMode")
|
||||
return VideoMode.normalize(options.videoMode) == "borderless"
|
||||
and "FULL" or "WINDOWED"
|
||||
end },
|
||||
{ id = "touchControls", label = "TOUCH PAD", port = true,
|
||||
text = function(options)
|
||||
local tc = options.touchControls
|
||||
|
||||
@@ -283,6 +283,14 @@ function PartyMenu:finishSwitch()
|
||||
if self.save and self.save.party == party then
|
||||
Mail.swapSlots(self.save, from, to)
|
||||
end
|
||||
-- engine/pokemon/switchpartymons.asm:38
|
||||
local data = self.game and self.game.data
|
||||
local ok, Sound = pcall(require, "src.core.Sound")
|
||||
if not (ok and data and Sound and Sound.play) then return end
|
||||
local sfx = data.audio and data.audio.sfx
|
||||
if sfx and sfx[Sound.resolve(data, "Sfx_SwitchPokemon")] then
|
||||
pcall(Sound.play, data, "Sfx_SwitchPokemon")
|
||||
end
|
||||
end
|
||||
|
||||
-- The reopened list: InitPartyMenuNoCancel caps the cursor at the last mon,
|
||||
|
||||
Reference in New Issue
Block a user