mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-08 01:34:06 -04:00
battle speed
This commit is contained in:
+5
-5
@@ -1251,13 +1251,13 @@ level is part of a row label rather than a drawn field. Both are noted in
|
||||
RFC 0019 as follow-ups.
|
||||
|
||||
`core.logic_speed` receives `(next, game)` once per `Game:logicSpeed()` call
|
||||
(once per frame), but only on frames where the speed is not locked. Every
|
||||
battle (wild, trainer, link, online, tournament, spectate), link play and a
|
||||
(once per frame), but only on frames where the speed is not locked. Link
|
||||
play (link, online, tournament and spectate battles included) and a
|
||||
fixed-speed minigame lock the logic clock to 1X, and `Game:speedLocked()`
|
||||
is checked before anything else: the hook is never called on those frames,
|
||||
so it cannot fast-forward a battle. On every other frame vanilla behavior
|
||||
resolves the per-category GAME SPEED option (`speedOverworld` or
|
||||
`speedMenu`) for whichever category `Game.speedCategoryInStack` says is
|
||||
so it cannot fast-forward a link battle. On every other frame vanilla
|
||||
behavior resolves the per-category GAME SPEED option (`speedOverworld`,
|
||||
`speedBattle` or `speedMenu`) for whichever category `Game.speedCategoryInStack` says is
|
||||
active. A mod may call `next(game)` and return its result to pass that
|
||||
resolution through, or return a different number outright to override it
|
||||
for that frame (a bot mod forcing 1X for one route segment, say). The
|
||||
|
||||
@@ -27,7 +27,7 @@ Features intentionally added beyond the original Pokémon Red, Blue, and Yellow
|
||||
* **Filter Find mods by game**, a generation or single-game filter of its own, with every listing showing the games and tags it declares
|
||||
* **Update all** in one press from the MODS tab, installing every outdated mod and every installed cart the index lists ahead of it, with a summary of what failed
|
||||
* **Rebindable GAME SPEED shortcuts**, SPEED - / SPEED + rows in CONTROLS that move the shoulder hotkeys to any pad button or switch them off
|
||||
* **Fast-forward locks to 1X in battles and link rooms**, every battle, link session and the FireRed/LeafGreen Union Room on every game
|
||||
* **Fast-forward locks to 1X in link play**, every link or online battle, link session and the FireRed/LeafGreen Union Room on every game
|
||||
* **40-player Union Room** on FireRed and LeafGreen online, a larger square room where every trainer keeps a fixed spot and anyone can be talked to
|
||||
* **Key bar on the touch pad**, a corner toggle that slides out SAVE, LOAD, SPEED, COLOR, TILT and ZOOM for phones with no keyboard
|
||||
* **Save editor item verbs**, sorting the bag and PC by item number or name, filling one stack or every stack to x99, and a coin editor on every game
|
||||
|
||||
@@ -387,9 +387,6 @@ function Game:speedLocked()
|
||||
if Game.isFixedSpeedInStack and Game.isFixedSpeedInStack(self.stack) then
|
||||
return true, "minigame"
|
||||
end
|
||||
if Game.speedCategoryInStack(self.stack) == "battle" then
|
||||
return true, "battle"
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@@ -1291,7 +1291,6 @@ function Game2:speedLocked()
|
||||
local states = self.stack and self.stack.states
|
||||
for i = #(states or {}), 1, -1 do
|
||||
local state = states[i]
|
||||
if state and state.isBattle then return true, "battle" end
|
||||
if state and (state.isFixedSpeed or state.isMinigame) then
|
||||
return true, "minigame"
|
||||
end
|
||||
|
||||
+2
-5
@@ -595,11 +595,8 @@ function Game3:speedLocked()
|
||||
if self:isFixedSpeed() then return true, "link" end
|
||||
local Battle = package.loaded["src.core.game3.battle"]
|
||||
if type(Battle) == "table" and Battle.isActive and Battle.isActive() then
|
||||
return true, "battle"
|
||||
end
|
||||
local Transition = package.loaded["src.core.game3.battle_transition"]
|
||||
if type(Transition) == "table" and Transition.isActive and Transition.isActive() then
|
||||
return true, "battle"
|
||||
local st = Battle.getState and Battle.getState()
|
||||
if type(st) == "table" and st.link then return true, "link" end
|
||||
end
|
||||
local Union = package.loaded["src.core.game3.link.union_room"]
|
||||
if type(Union) == "table" and Union.isActive and Union.isActive() then
|
||||
|
||||
@@ -350,6 +350,12 @@ local function coreRows(opts, hooks)
|
||||
opts.speedOverworld = GameSpeed.cycle(opts.speedOverworld, dir)
|
||||
return true
|
||||
end)
|
||||
add(Strings("BATTLE SPEED"),
|
||||
function() return GameSpeed.levelLabel(opts.speedBattle) end,
|
||||
function(dir)
|
||||
opts.speedBattle = GameSpeed.cycle(opts.speedBattle, dir)
|
||||
return true
|
||||
end)
|
||||
add(Strings("MENU SPEED"),
|
||||
function() return GameSpeed.levelLabel(opts.speedMenu) end,
|
||||
function(dir)
|
||||
|
||||
@@ -14,7 +14,6 @@ local Runtime = require("src.mods.Runtime")
|
||||
local BattleTransition = {}
|
||||
BattleTransition.__index = BattleTransition
|
||||
BattleTransition.isOpaque = false -- draws over the frozen overworld
|
||||
BattleTransition.isFixedSpeed = true
|
||||
|
||||
-- BattleTransition_FlashScreenPalettes: fade to black and back, then to
|
||||
-- white and back; each palette held 2 frames, whole sequence played 3
|
||||
|
||||
+10
-1
@@ -539,6 +539,15 @@ local function buildRows(game)
|
||||
o.speedOverworld = GameSpeed.cycle(o.speedOverworld, dir)
|
||||
return true
|
||||
end },
|
||||
{ id = "speedBattle", label = Strings("BATTLE SPEED"),
|
||||
value = function(g)
|
||||
return gameSpeedLabel(g.save.options.speedBattle)
|
||||
end,
|
||||
step = function(g, dir)
|
||||
local o = g.save.options
|
||||
o.speedBattle = GameSpeed.cycle(o.speedBattle, dir)
|
||||
return true
|
||||
end },
|
||||
{ id = "speedMenu", label = Strings("MENU SPEED"),
|
||||
value = function(g)
|
||||
return gameSpeedLabel(g.save.options.speedMenu)
|
||||
@@ -714,7 +723,7 @@ local GROUPS = {
|
||||
members = { "uiLayout", "videoMode", "orientation", "faithfulRes",
|
||||
"screenPos", "fpsCap", "vsync", "logicClock" } },
|
||||
{ id = "group.speed", label = "SPEED",
|
||||
members = { "textSpeed", "speedOverworld", "speedMenu" } },
|
||||
members = { "textSpeed", "speedOverworld", "speedBattle", "speedMenu" } },
|
||||
{ id = "group.graphics", label = "GRAPHICS",
|
||||
members = { "colors", "uiLetterbox", "shaderfx", "shaderfx2" } },
|
||||
-- A mod's Pipelines row splices in after TILT and is in no group, so it
|
||||
|
||||
@@ -70,6 +70,7 @@ function Rows.build(ctx)
|
||||
step = function(c, dir) return cartCycle(c, "textSpeed", 3, dir) end,
|
||||
})
|
||||
add(speedRow("speedOverworld", "OVERWORLD SPEED", "speedOverworld"))
|
||||
add(speedRow("speedBattle", "BATTLE SPEED", "speedBattle"))
|
||||
add(speedRow("speedMenu", "MENU SPEED", "speedMenu"))
|
||||
|
||||
add({
|
||||
@@ -396,7 +397,7 @@ end
|
||||
|
||||
Rows.GROUPS = {
|
||||
{ id = "group.speed", label = "SPEED",
|
||||
members = { "textSpeed", "speedOverworld", "speedMenu" } },
|
||||
members = { "textSpeed", "speedOverworld", "speedBattle", "speedMenu" } },
|
||||
{ id = "group.video", label = "VIDEO",
|
||||
members = { "uiLayout", "videoMode", "orientation", "faithfulRes",
|
||||
"screenPos", "fpsCap", "vsync", "logicClock" } },
|
||||
|
||||
@@ -35,7 +35,6 @@ local Tilt = require("src.render.Tilt")
|
||||
local BattleTransition = {}
|
||||
BattleTransition.__index = BattleTransition
|
||||
BattleTransition.isOpaque = false
|
||||
BattleTransition.isFixedSpeed = true
|
||||
|
||||
local COLS, ROWS = 20, 18 -- SCREEN_WIDTH x SCREEN_HEIGHT, in tiles
|
||||
|
||||
|
||||
@@ -25,19 +25,6 @@ return function(game)
|
||||
ow:pushBattle(battle)
|
||||
|
||||
U.log("logic speed", game:logicSpeed(), "sfx rate", Sound.rate())
|
||||
local function inBattle()
|
||||
for _, st in ipairs(game.stack.states) do
|
||||
if st == battle then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function assertLocked(where)
|
||||
if inBattle() and game:logicSpeed() ~= 1 then
|
||||
error(("speed lock: %s ran at %sX with speedOverride 4")
|
||||
:format(where, tostring(game:logicSpeed())))
|
||||
end
|
||||
end
|
||||
assertLocked("battle start")
|
||||
if Sound.rate() ~= 1 then
|
||||
error(("bug2087: Game:update pitched SFX off battle speed (rate %s at 4X)")
|
||||
:format(tostring(Sound.rate())))
|
||||
@@ -71,11 +58,8 @@ return function(game)
|
||||
end
|
||||
end
|
||||
|
||||
local lockedFrames = 0
|
||||
local shot = false
|
||||
for _ = 1, 2400 do
|
||||
assertLocked("entrance")
|
||||
if inBattle() then lockedFrames = lockedFrames + 1 end
|
||||
poll("entrance cry")
|
||||
if battle.phase == "menu" then break end
|
||||
if battle.waitingSound and not shot then
|
||||
@@ -103,7 +87,6 @@ return function(game)
|
||||
for _ = 1, 2400 do
|
||||
poll("post-move sfx")
|
||||
if game.stack:top() ~= battle then break end
|
||||
assertLocked("post-move")
|
||||
if #gates > before and cur and not shotLevel then
|
||||
shotLevel = U.shot(game, DIR .. "/bug2087_levelup.png")
|
||||
end
|
||||
@@ -122,12 +105,11 @@ return function(game)
|
||||
fail = ("bug2087: %s was pitched with battle speed (%s)"):format(
|
||||
g.label, tostring(g.pitch))
|
||||
elseif g.dur and g.held < g.dur * 0.9 then
|
||||
fail = ("bug2087: %s cut short (%.3fs of %.3fs)"):format(
|
||||
fail = ("bug2087: %s cut short at 4X (%.3fs of %.3fs)"):format(
|
||||
g.label, g.held, g.dur)
|
||||
end
|
||||
end
|
||||
if fail then error(fail) end
|
||||
if lockedFrames == 0 then error("speed lock: the battle never reached the stack") end
|
||||
U.log("PASS every battle sfx gate held for its real length, battle locked to 1X under a 4X override")
|
||||
U.log("PASS every battle sfx gate held for its real length at 4X")
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
@@ -25,26 +25,12 @@ return function(game)
|
||||
ow:pushBattle(battle)
|
||||
|
||||
U.log("logic speed", game:logicSpeed(), "sfx rate", Sound.rate())
|
||||
local function inBattle()
|
||||
for _, st in ipairs(game.stack.states) do
|
||||
if st == battle then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function assertLocked(where)
|
||||
if inBattle() and game:logicSpeed() ~= 1 then
|
||||
error(("speed lock: %s ran at %sX with speedOverride 4")
|
||||
:format(where, tostring(game:logicSpeed())))
|
||||
end
|
||||
end
|
||||
assertLocked("battle start")
|
||||
if Sound.rate() ~= 1 then
|
||||
error(("bug1952: Game:update pitched SFX off GAME SPEED (rate %s at 4X)")
|
||||
:format(tostring(Sound.rate())))
|
||||
end
|
||||
|
||||
for _ = 1, 240 do
|
||||
assertLocked("battle intro")
|
||||
if battle.phase == "menu" then break end
|
||||
U.tap(game, "a")
|
||||
U.wait(3)
|
||||
@@ -63,7 +49,6 @@ return function(game)
|
||||
local shot = false
|
||||
for _ = 1, 1200 do
|
||||
U.wait(1)
|
||||
assertLocked("level-up")
|
||||
if battle.waitingSound and not t0 then
|
||||
local src = battle.waitingSound
|
||||
t0 = love.timer.getTime()
|
||||
@@ -94,25 +79,13 @@ return function(game)
|
||||
|
||||
if not dur then error("bug1952: no duration for the level-up fanfare") end
|
||||
if held < dur * 0.9 then
|
||||
error(("bug2087: the battle cut the fanfare short (%.3fs of %.3fs)")
|
||||
error(("bug2087: the 4X battle cut the fanfare short (%.3fs of %.3fs)")
|
||||
:format(held, dur))
|
||||
end
|
||||
if held > dur + 1 then
|
||||
error(("bug1952: the fanfare dragged past its length (%.3fs of %.3fs)")
|
||||
:format(held, dur))
|
||||
end
|
||||
for _ = 1, 2400 do
|
||||
if not inBattle() then break end
|
||||
assertLocked("battle end")
|
||||
U.tap(game, "a")
|
||||
U.wait(1)
|
||||
end
|
||||
if inBattle() then error("speed lock: the battle never ended") end
|
||||
U.wait(2)
|
||||
if game:logicSpeed() ~= 4 then
|
||||
error(("speed lock: after the battle logic speed is %s, want 4")
|
||||
:format(tostring(game:logicSpeed())))
|
||||
end
|
||||
U.log("PASS the fanfare kept natural pitch at 1X in a 4X-override battle, 4X back after")
|
||||
U.log("PASS the fanfare kept natural pitch and played to completion at 4X")
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ return function(game)
|
||||
local o = game.options
|
||||
|
||||
game.speedOverride = nil
|
||||
o.speedOverworld, o.speedBattle, o.speedMenu = 10, 200, 1
|
||||
o.speedOverworld, o.speedBattle, o.speedMenu = 10, 4, 1
|
||||
U.wait(2)
|
||||
if game:logicSpeed() ~= 10 then
|
||||
fail(("field at OVERWORLD SPEED 10 reads %s"):format(tostring(game:logicSpeed())))
|
||||
@@ -55,27 +55,27 @@ return function(game)
|
||||
local Ui = require("src.core.game3.battle.ui")
|
||||
for f = 1, 20000 do
|
||||
if not Battle.isActive() then break end
|
||||
if game:logicSpeed() ~= 1 then
|
||||
fail(("battle ran at %sX with speedBattle 200"):format(tostring(game:logicSpeed())))
|
||||
if game:logicSpeed() ~= 4 then
|
||||
fail(("local battle ran at %sX with speedBattle 4"):format(tostring(game:logicSpeed())))
|
||||
end
|
||||
checked = checked + 1
|
||||
if checked == 30 then
|
||||
local st = Battle.getState()
|
||||
st.link = true
|
||||
key("1")
|
||||
game:gamepadaxis(nil, "triggerright", 1)
|
||||
game:gamepadaxis(nil, "triggerright", 0)
|
||||
if o.speedOverworld ~= 10 or o.speedBattle ~= 200 or o.speedMenu ~= 1 then
|
||||
fail(("speed presses in battle changed options (%s/%s/%s)"):format(
|
||||
if o.speedOverworld ~= 10 or o.speedBattle ~= 4 or o.speedMenu ~= 1 then
|
||||
fail(("speed presses in a link battle changed options (%s/%s/%s)"):format(
|
||||
tostring(o.speedOverworld), tostring(o.speedBattle), tostring(o.speedMenu)))
|
||||
end
|
||||
game.speedOverride = 200
|
||||
if game:logicSpeed() ~= 1 then fail("speedOverride 200 defeated the battle lock") end
|
||||
if game:logicSpeed() ~= 1 then fail("a link battle was not locked to 1X") end
|
||||
game.speedOverride = nil
|
||||
if game.touchSkinHotkey then game:touchSkinHotkey("fast_forward_hold", true) end
|
||||
if game:logicSpeed() ~= 1 then fail("skin FF hold defeated the battle lock") end
|
||||
if game.touchSkinHotkey then game:touchSkinHotkey("fast_forward_hold", false) end
|
||||
st.link = false
|
||||
end
|
||||
if checked == 200 and not shot then
|
||||
shot = U.shot(game, DIR .. "/firered_battle_locked.png")
|
||||
shot = U.shot(game, DIR .. "/firered_battle_speed.png")
|
||||
end
|
||||
local st = Battle.getState and Battle.getState()
|
||||
if st and Battle._phase == "command" and Ui._mode == "menu" and not Ui._pendingCommand then
|
||||
@@ -96,7 +96,7 @@ return function(game)
|
||||
if Battle.isActive() then
|
||||
fail(("battle never ended (phase %s, ui %s)"):format(tostring(Battle._phase), tostring(Ui._mode)))
|
||||
end
|
||||
U.log("battle frames checked at 1X", checked)
|
||||
U.log("battle frames checked at 4X", checked)
|
||||
U.wait(120)
|
||||
if game:logicSpeed() ~= 10 then
|
||||
fail(("after the battle logic speed is %s, want 10"):format(tostring(game:logicSpeed())))
|
||||
@@ -144,6 +144,6 @@ return function(game)
|
||||
end
|
||||
U.shot(game, DIR .. "/firered_union_locked.png")
|
||||
U.log("union room frames checked at 1X", seen, "union state", tostring(Union.state))
|
||||
U.log("PASS firered battle and Union Room locked to 1X, OVERWORLD SPEED 10 back after the battle")
|
||||
U.log("PASS firered local battle at BATTLE SPEED 4, link battle and Union Room locked to 1X")
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
@@ -50,25 +50,25 @@ return function(game)
|
||||
local checked, shot = 0, false
|
||||
for _ = 1, 2000 do
|
||||
if not inBattle() then break end
|
||||
if game:logicSpeed() ~= 1 then
|
||||
return fail(("battle ran at %sX with GAME SPEED 10"):format(tostring(game:logicSpeed())))
|
||||
if game:logicSpeed() ~= 10 then
|
||||
return fail(("local battle ran at %sX with GAME SPEED 10"):format(tostring(game:logicSpeed())))
|
||||
end
|
||||
checked = checked + 1
|
||||
if checked == 30 then
|
||||
game:hotkey("1")
|
||||
game:_cycleSpeed(1)
|
||||
game:_cycleSpeed(-1)
|
||||
if game.options.speed ~= 10 then
|
||||
return fail(("speed presses in battle moved GAME SPEED to %s"):format(tostring(game.options.speed)))
|
||||
end
|
||||
game.linkNet = { closed = false }
|
||||
game.speedOverride = 200
|
||||
if game:logicSpeed() ~= 1 then
|
||||
return fail("speedOverride 200 defeated the battle lock")
|
||||
return fail("a link battle was not locked to 1X")
|
||||
end
|
||||
game:_cycleSpeed(1)
|
||||
if game.options.speed ~= 10 then
|
||||
return fail(("speed press in a link battle moved GAME SPEED to %s"):format(tostring(game.options.speed)))
|
||||
end
|
||||
game.speedOverride = nil
|
||||
game.linkNet = nil
|
||||
end
|
||||
if battle.phase == "menu" and not shot then
|
||||
shot = U.shot(game, DIR .. "/gold_battle_locked.png")
|
||||
shot = U.shot(game, DIR .. "/gold_battle_speed.png")
|
||||
end
|
||||
if battle.battle and battle.battle.over then
|
||||
tap("a", 3)
|
||||
@@ -85,7 +85,7 @@ return function(game)
|
||||
tostring(battle.phase), tostring(battle.battle and battle.battle.over),
|
||||
tostring(top and (top.screenId or top.name) or top)))
|
||||
end
|
||||
U.log("battle frames checked at 1X", checked)
|
||||
U.log("battle frames checked at 10X", checked)
|
||||
U.wait(30)
|
||||
if game:logicSpeed() ~= 10 then
|
||||
return fail(("after the battle logic speed is %s, want 10"):format(tostring(game:logicSpeed())))
|
||||
@@ -97,6 +97,6 @@ return function(game)
|
||||
if game:logicSpeed() ~= 1 then return fail("a linkSession did not lock 1X") end
|
||||
game.linkSession = nil
|
||||
U.shot(game, DIR .. "/gold_after_battle.png")
|
||||
U.log("PASS gold battle and link locked to 1X, GAME SPEED 10 back after")
|
||||
U.log("PASS gold local battle at GAME SPEED 10, link locked to 1X")
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
@@ -18,7 +18,7 @@ return function(game)
|
||||
|
||||
local o = game.save.options
|
||||
game.speedOverride = nil
|
||||
o.speedOverworld, o.speedBattle, o.speedMenu = 10, 200, 1
|
||||
o.speedOverworld, o.speedBattle, o.speedMenu = 10, 4, 1
|
||||
U.wait(2)
|
||||
if game:logicSpeed() ~= 10 then
|
||||
fail(("overworld at OVERWORLD SPEED 10 reads %s"):format(tostring(game:logicSpeed())))
|
||||
@@ -46,34 +46,32 @@ return function(game)
|
||||
local checked, shot = 0, false
|
||||
for _ = 1, 2400 do
|
||||
if not inBattle() then break end
|
||||
if game:logicSpeed() ~= 1 then
|
||||
fail(("battle ran at %sX with speedBattle 200"):format(tostring(game:logicSpeed())))
|
||||
if game:logicSpeed() ~= 4 then
|
||||
fail(("local battle ran at %sX with speedBattle 4"):format(tostring(game:logicSpeed())))
|
||||
end
|
||||
checked = checked + 1
|
||||
if checked == 20 then
|
||||
game.linkSession = true
|
||||
key("1")
|
||||
game:gamepadaxis(nil, "triggerright", 1)
|
||||
game:gamepadaxis(nil, "triggerright", 0)
|
||||
game:touchSkinHotkey("fast_forward_toggle", true)
|
||||
if o.speedOverworld ~= 10 or o.speedBattle ~= 200 or o.speedMenu ~= 1 then
|
||||
fail(("speed presses in battle changed options (%s/%s/%s)"):format(
|
||||
if o.speedOverworld ~= 10 or o.speedBattle ~= 4 or o.speedMenu ~= 1 then
|
||||
fail(("speed presses in a link battle changed options (%s/%s/%s)"):format(
|
||||
tostring(o.speedOverworld), tostring(o.speedBattle), tostring(o.speedMenu)))
|
||||
end
|
||||
game:touchSkinHotkey("fast_forward_hold", true)
|
||||
if game:logicSpeed() ~= 1 then fail("skin FF hold defeated the battle lock") end
|
||||
game:touchSkinHotkey("fast_forward_hold", false)
|
||||
game.speedOverride = 200
|
||||
if game:logicSpeed() ~= 1 then fail("speedOverride 200 defeated the battle lock") end
|
||||
if game:logicSpeed() ~= 1 then fail("a link battle was not locked to 1X") end
|
||||
game.speedOverride = nil
|
||||
game.linkSession = nil
|
||||
end
|
||||
if battle.phase == "menu" and not shot then
|
||||
shot = U.shot(game, DIR .. "/red_battle_locked.png")
|
||||
shot = U.shot(game, DIR .. "/red_battle_speed.png")
|
||||
end
|
||||
U.tap(game, "a")
|
||||
U.wait(2)
|
||||
end
|
||||
if inBattle() then fail("battle never ended") end
|
||||
U.log("battle frames checked at 1X", checked)
|
||||
U.log("battle frames checked at 4X", checked)
|
||||
U.wait(10)
|
||||
if game:logicSpeed() ~= 10 then
|
||||
fail(("after the battle logic speed is %s, want 10"):format(tostring(game:logicSpeed())))
|
||||
@@ -82,6 +80,6 @@ return function(game)
|
||||
if game:logicSpeed() ~= 1 then fail("a link session did not lock 1X") end
|
||||
game.linkSession = nil
|
||||
U.shot(game, DIR .. "/red_after_battle.png")
|
||||
U.log("PASS red battle and link locked to 1X, OVERWORLD SPEED 10 back after")
|
||||
U.log("PASS red local battle at BATTLE SPEED 4, link locked to 1X")
|
||||
love.event.quit(0)
|
||||
end
|
||||
|
||||
@@ -39,12 +39,9 @@ do
|
||||
battleActive = true
|
||||
eq(g:speedCategory(), "battle", "battle stays battle")
|
||||
g.options.speedBattle = 10
|
||||
eq(g:logicSpeed(), 1, "a gen3 battle runs 1X whatever BATTLE SPEED says")
|
||||
g.speedOverride = 20
|
||||
eq(g:logicSpeed(), 1, "and whatever speedOverride says")
|
||||
g.speedOverride = nil
|
||||
eq(g:logicSpeed(), 10, "a local gen3 battle runs at BATTLE SPEED")
|
||||
g:keypressed("1")
|
||||
eq(g.options.speedBattle, 10, "1 in battle is ignored")
|
||||
check(g.options.speedBattle ~= 10, "1 in battle cycles BATTLE SPEED")
|
||||
eq(g.options.speedOverworld, 2, "and leaves OVERWORLD SPEED alone")
|
||||
battleActive = false
|
||||
eq(newGame3("boot"):speedCategory(), "menu", "boot phase stays menu")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-- Per-category GAME SPEED (RFC 0007): Game.speedCategoryInStack's stack
|
||||
-- walk, Game:logicSpeed()'s precedence (battle/link lock / run-argument override /
|
||||
-- walk, Game:logicSpeed()'s precedence (link lock / run-argument override /
|
||||
-- the core.logic_speed hook), Game:_cycleSpeed's per-category cycling, and
|
||||
-- the core.logic_speed hook itself exercised through the public mod API
|
||||
-- (Hooks.new() + bus:wrap, the same idiom other hooks' tests use -- not a
|
||||
@@ -66,7 +66,7 @@ do
|
||||
local g = gameWith({ battle },
|
||||
{ speedOverworld = 4, speedBattle = 10, speedMenu = 2 })
|
||||
eq(g:_resolveLogicSpeed(), 10, "battle reads speedBattle")
|
||||
eq(g:logicSpeed(), 1, "but a battle always runs 1X whatever speedBattle says")
|
||||
eq(g:logicSpeed(), 10, "and a local battle runs at BATTLE SPEED")
|
||||
end
|
||||
do
|
||||
local g = gameWith({ overlay },
|
||||
@@ -105,9 +105,8 @@ end
|
||||
do
|
||||
local g = gameWith({ overworld, battle }, { speedOverworld = 50, speedBattle = 50 })
|
||||
g.speedOverride = 20
|
||||
eq(g:logicSpeed(), 1, "a battle forces 1X over speedOverride too")
|
||||
local locked, why = g:speedLocked()
|
||||
check(locked and why == "battle", "speedLocked reports the battle")
|
||||
eq(g:logicSpeed(), 20, "speedOverride wins in a local battle")
|
||||
check(not g:speedLocked(), "a local battle is not speed locked")
|
||||
end
|
||||
do
|
||||
local g = gameWith({ overworld }, { speedOverworld = 4 })
|
||||
@@ -180,10 +179,10 @@ do
|
||||
{ speedOverworld = 1, speedBattle = 1, speedMenu = 1 })
|
||||
function g:writeOptions() writeOptions.calls = writeOptions.calls + 1 end
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.save.options.speedBattle, 1, "cycling during battle is ignored")
|
||||
eq(g.save.options.speedBattle, 2, "cycling during battle bumps speedBattle")
|
||||
eq(g.save.options.speedOverworld, 1, "...and leaves speedOverworld alone")
|
||||
eq(g.save.options.speedMenu, 1, "...and leaves speedMenu alone")
|
||||
eq(writeOptions.calls, 0, "and persists nothing")
|
||||
eq(writeOptions.calls, 1, "a successful cycle persists the option")
|
||||
end
|
||||
do
|
||||
local calls = 0
|
||||
|
||||
@@ -31,11 +31,11 @@ local world = {}
|
||||
|
||||
eq(game({ options = { speed = 10 }, stack = stack(world) }):logicSpeed(), 10,
|
||||
"the overworld under a plain stack honors GAME SPEED")
|
||||
eq(game({ options = { speed = 10 }, stack = stack(world, battle) }):logicSpeed(), 1,
|
||||
"a battle on the stack is locked to 1X")
|
||||
eq(game({ options = { speed = 10 }, speedOverride = 20,
|
||||
stack = stack(world, battle, {}) }):logicSpeed(), 1,
|
||||
"even with speedOverride and a menu over the battle")
|
||||
eq(game({ options = { speed = 10 }, stack = stack(world, battle) }):logicSpeed(), 10,
|
||||
"a local battle honors GAME SPEED")
|
||||
eq(game({ options = { speed = 10 }, linkNet = { closed = false },
|
||||
stack = stack(world, battle) }):logicSpeed(), 1,
|
||||
"a link battle is locked to 1X")
|
||||
eq(game({ options = { speed = 10 }, linkNet = { closed = false } }):logicSpeed(), 1,
|
||||
"an open linkNet (online arena, LinkBattle2) is locked to 1X")
|
||||
eq(game({ options = { speed = 10 }, linkNet = { closed = true } }):logicSpeed(), 10,
|
||||
@@ -48,10 +48,12 @@ eq(require("src.ui.gen2.BattleState").isBattle, true,
|
||||
do
|
||||
local persisted = 0
|
||||
local g = game({ options = { speed = 1 }, stack = stack(world, battle),
|
||||
linkNet = { closed = false },
|
||||
persistOptions = function() persisted = persisted + 1 end })
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.options.speed, 1, "SPEED + in battle is ignored")
|
||||
eq(g.options.speed, 1, "SPEED + in a link battle is ignored")
|
||||
eq(persisted, 0, "and persists nothing")
|
||||
g.linkNet = nil
|
||||
g.stack = stack(world)
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.options.speed, 2, "SPEED + on the overworld still cycles")
|
||||
|
||||
@@ -53,7 +53,7 @@ end
|
||||
|
||||
for _, spec in ipairs({
|
||||
{ "group.battle", 6 }, { "group.audio", 3 }, { "group.video", 5 },
|
||||
{ "group.speed", 3 }, { "group.graphics", 4 }, { "group.extras", 3 },
|
||||
{ "group.speed", 4 }, { "group.graphics", 4 }, { "group.extras", 3 },
|
||||
}) do
|
||||
local row = find(menu.view, spec[1])
|
||||
T.check(row, spec[1] .. " has an opener row")
|
||||
@@ -100,7 +100,7 @@ game.stack:pop()
|
||||
local speed = find(menu.view, "group.speed")
|
||||
speed.activate(game)
|
||||
T.eq(ids(game.stack:top().view),
|
||||
"textSpeed,speedOverworld,speedMenu",
|
||||
"textSpeed,speedOverworld,speedBattle,speedMenu",
|
||||
"TEXT SPEED heads the SPEED page")
|
||||
game.stack:pop()
|
||||
|
||||
|
||||
@@ -31,16 +31,18 @@ do
|
||||
eq(g:logicSpeed(), 200, "gen1 overworld runs the saved 200X")
|
||||
check(not g:speedLocked(), "gen1 overworld is not locked")
|
||||
g = gen1({ overworld, battle })
|
||||
eq(g:logicSpeed(), 1, "gen1 battle is 1X at speedBattle 200")
|
||||
eq(g:logicSpeed(), 200, "gen1 local battle runs BATTLE SPEED")
|
||||
g.linkSession = true
|
||||
eq(g:logicSpeed(), 1, "gen1 link battle is 1X at speedBattle 200")
|
||||
g.speedOverride = 200
|
||||
eq(g:logicSpeed(), 1, "gen1 battle ignores speedOverride (--speed, skin FF hold)")
|
||||
eq(g:logicSpeed(), 1, "gen1 link battle ignores speedOverride (--speed, skin FF hold)")
|
||||
local bus = Hooks.new()
|
||||
local saved = Runtime.hooks
|
||||
Runtime.hooks = bus
|
||||
local ran = false
|
||||
local unsub = bus:wrap("core.logic_speed", function() ran = true; return 200 end)
|
||||
g.speedOverride = nil
|
||||
eq(g:logicSpeed(), 1, "gen1 battle ignores a core.logic_speed hook returning 200")
|
||||
eq(g:logicSpeed(), 1, "gen1 link battle ignores a core.logic_speed hook returning 200")
|
||||
check(not ran, "the hook is never called while locked")
|
||||
local ow = gen1({ overworld })
|
||||
eq(ow:logicSpeed(), 200, "outside battle the hook still runs")
|
||||
@@ -52,6 +54,7 @@ end
|
||||
do
|
||||
GameSpeed.setAllowed({ 2, 4 })
|
||||
local g = gen1({ overworld, battle })
|
||||
g.linkSession = true
|
||||
eq(g:logicSpeed(), 1, "a cart ladder without 1 still locks to a literal 1")
|
||||
eq(gen1({ overworld }, { speedOverworld = 4 }):logicSpeed(), 4,
|
||||
"and outside battle the ladder applies")
|
||||
@@ -61,17 +64,21 @@ end
|
||||
do
|
||||
local g = gen1({ overworld, battle },
|
||||
{ speedOverworld = 1, speedBattle = 1, speedMenu = 1 })
|
||||
g.linkSession = true
|
||||
g:_cycleSpeed(1)
|
||||
g:_cycleSpeed(-1)
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.save.options.speedBattle, 1, "gen1 speed presses in battle leave speedBattle")
|
||||
eq(g.save.options.speedBattle, 1, "gen1 speed presses in a link battle leave speedBattle")
|
||||
eq(g.save.options.speedOverworld, 1, "and speedOverworld")
|
||||
g:touchSkinHotkey("fast_forward_toggle", true)
|
||||
eq(g.save.options.speedBattle, 1, "gen1 skin FF toggle in battle is ignored")
|
||||
eq(g.save.options.speedBattle, 1, "gen1 skin FF toggle in a link battle is ignored")
|
||||
g:touchSkinHotkey("fast_forward_hold", true)
|
||||
eq(g:logicSpeed(), 1, "gen1 skin FF hold in battle stays 1X")
|
||||
eq(g:logicSpeed(), 1, "gen1 skin FF hold in a link battle stays 1X")
|
||||
g:touchSkinHotkey("fast_forward_hold", false)
|
||||
eq(g.speedOverride, nil, "and releasing restores the pre-hold override")
|
||||
g.linkSession = nil
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.save.options.speedBattle, 2, "gen1 speed press in a local battle cycles speedBattle")
|
||||
end
|
||||
|
||||
do
|
||||
@@ -91,27 +98,28 @@ end
|
||||
do
|
||||
eq(gen2({ options = { speed = 200 }, stack = stack({}) }):logicSpeed(), 200,
|
||||
"gen2 overworld runs GAME SPEED")
|
||||
eq(gen2({ options = { speed = 200 }, stack = stack({}, battle) }):logicSpeed(), 1,
|
||||
"gen2 battle is 1X")
|
||||
eq(gen2({ options = { speed = 200 }, speedOverride = 200,
|
||||
eq(gen2({ options = { speed = 200 }, stack = stack({}, battle) }):logicSpeed(), 200,
|
||||
"gen2 local battle runs GAME SPEED")
|
||||
eq(gen2({ options = { speed = 200 }, speedOverride = 200, linkNet = { closed = false },
|
||||
stack = stack({}, battle) }):logicSpeed(), 1,
|
||||
"gen2 battle ignores speedOverride")
|
||||
"gen2 link battle ignores speedOverride")
|
||||
eq(gen2({ options = { speed = 200 }, linkNet = { closed = false } }):logicSpeed(), 1,
|
||||
"gen2 online arena / LinkBattle2 linkNet is 1X")
|
||||
eq(gen2({ options = { speed = 200 }, linkSession = true }):logicSpeed(), 1,
|
||||
"gen2 tournament / spectate linkSession is 1X")
|
||||
local g = gen2({ options = { speed = 1 }, stack = stack({}, battle) })
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.options.speed, 1, "gen2 pad speed press in battle is ignored")
|
||||
eq(g.options.speed, 2, "gen2 pad speed press in a local battle cycles")
|
||||
g.stack = stack({})
|
||||
g.linkNet = { closed = false }
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.options.speed, 1, "gen2 pad speed press over a link is ignored")
|
||||
eq(g.options.speed, 2, "gen2 pad speed press over a link is ignored")
|
||||
end
|
||||
|
||||
local battleActive = false
|
||||
local battleActive, battleLink = false, false
|
||||
package.loaded["src.core.game3.battle"] = {
|
||||
isActive = function() return battleActive end,
|
||||
getState = function() return { link = battleLink } end,
|
||||
}
|
||||
|
||||
local function gen3()
|
||||
@@ -126,13 +134,15 @@ do
|
||||
local g = gen3()
|
||||
eq(g:logicSpeed(), 200, "gen3 field runs OVERWORLD SPEED")
|
||||
battleActive = true
|
||||
eq(g:logicSpeed(), 1, "gen3 battle is 1X")
|
||||
eq(g:logicSpeed(), 200, "gen3 local battle runs BATTLE SPEED")
|
||||
battleLink = true
|
||||
eq(g:logicSpeed(), 1, "gen3 link battle is 1X")
|
||||
g.speedOverride = 200
|
||||
eq(g:logicSpeed(), 1, "gen3 battle ignores speedOverride")
|
||||
eq(g:logicSpeed(), 1, "gen3 link battle ignores speedOverride")
|
||||
g.speedOverride = nil
|
||||
g:_cycleSpeed(1)
|
||||
eq(g.options.speedBattle, 200, "gen3 speed press in battle is ignored")
|
||||
battleActive = false
|
||||
eq(g.options.speedBattle, 200, "gen3 speed press in a link battle is ignored")
|
||||
battleActive, battleLink = false, false
|
||||
package.loaded["src.core.game3.link.union_room"] = { isActive = function() return true end }
|
||||
eq(g:logicSpeed(), 1, "gen3 Union Room is 1X")
|
||||
package.loaded["src.core.game3.link.union_room"] = nil
|
||||
@@ -148,7 +158,11 @@ local function runFrame(g, lockAt)
|
||||
FixedStep.clock = function() return 0 end
|
||||
FixedStep:init(function()
|
||||
steps = steps + 1
|
||||
if steps == lockAt then battleActive = true; g.stack = stack(overworld, battle) end
|
||||
if steps == lockAt then
|
||||
battleActive, battleLink = true, true
|
||||
g.linkSession = true
|
||||
g.stack = stack(overworld, battle)
|
||||
end
|
||||
g:_speedLockEdge()
|
||||
end)
|
||||
local speed = g:logicSpeed()
|
||||
@@ -165,18 +179,18 @@ do
|
||||
local g = gen3()
|
||||
local steps, speed = runFrame(g, 3)
|
||||
eq(speed, 200, "the frame started unlocked at 200X")
|
||||
eq(steps, 3, "gen3: a battle starting mid-frame ends the frame on that step")
|
||||
battleActive = false
|
||||
eq(steps, 3, "gen3: a link battle starting mid-frame ends the frame on that step")
|
||||
battleActive, battleLink = false, false
|
||||
|
||||
local g1 = gen1({ overworld })
|
||||
steps = runFrame(g1, 5)
|
||||
eq(steps, 5, "gen1: a battle push mid-frame ends the frame on that step")
|
||||
eq(steps, 5, "gen1: a link battle push mid-frame ends the frame on that step")
|
||||
eq(g1:logicSpeed(), 1, "and the next frame samples 1X")
|
||||
|
||||
local g2 = gen2({ options = { speed = 200 }, stack = stack({}) })
|
||||
steps = runFrame(g2, 2)
|
||||
eq(steps, 2, "gen2: a battle push mid-frame ends the frame on that step")
|
||||
battleActive = false
|
||||
eq(steps, 2, "gen2: a link battle push mid-frame ends the frame on that step")
|
||||
battleActive, battleLink = false, false
|
||||
|
||||
local plain = gen1({ overworld })
|
||||
steps = runFrame(plain, -1)
|
||||
|
||||
@@ -288,7 +288,7 @@ local WANT_IDS = { "textSpeed", "animations", "battleStyle", "battleLayout",
|
||||
"performance", "colors",
|
||||
"tilt", "uiLetterbox", "shaderfx", "shaderfx2", "zoom", "voidFill",
|
||||
"videoMode", "faithfulRes", "screenPos", "fpsCap", "vsync", "logicClock",
|
||||
"speedOverworld", "speedMenu",
|
||||
"speedOverworld", "speedBattle", "speedMenu",
|
||||
"mods", "controls", "dateFormat", "timeFormat" }
|
||||
local function orow(menu, id)
|
||||
for _, row in ipairs(menu.rows) do
|
||||
|
||||
+5
-1
@@ -2980,7 +2980,11 @@ do
|
||||
-- bug when the cycling is fine and the row is simply one longer.
|
||||
for _ = 1, #GameSpeed.LEVELS - 1 do press("a") end
|
||||
eq(og.save.options.speedOverworld, 1, "OVERWORLD SPEED wraps back to NORMAL")
|
||||
check(not seek("speedBattle"), "no BATTLE SPEED row: battles always run 1X")
|
||||
check(seek("speedBattle"), "cursor reaches BATTLE SPEED")
|
||||
press("a")
|
||||
eq(og.save.options.speedBattle, 2, "A cycles BATTLE SPEED to 2X")
|
||||
for _ = 1, #GameSpeed.LEVELS - 1 do press("a") end
|
||||
eq(og.save.options.speedBattle, 1, "BATTLE SPEED wraps back to NORMAL")
|
||||
check(seek("speedMenu"), "cursor reaches MENU SPEED")
|
||||
press("a")
|
||||
eq(og.save.options.speedMenu, 2, "A cycles MENU SPEED to 2X")
|
||||
|
||||
Reference in New Issue
Block a user