mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 11:40:56 +02:00
fix catch regression + add new menus
This commit is contained in:
@@ -98,6 +98,9 @@ local FirstPerson = V.require("FirstPerson")
|
||||
local FreeMove = V.require("FreeMove")
|
||||
local CamControl = V.require("CamControl")
|
||||
local VR = V.require("VR")
|
||||
-- the mod's settings menus: the categories, the screens they open, and the
|
||||
-- red ink that marks this mod's one row on the engine's OPTIONS list
|
||||
local SettingsMenu = V.require("SettingsMenu")
|
||||
-- HORDE MODE: the konami code's minigame. Horde owns the state machine and
|
||||
-- every hook; the other four are the gun, the crowd, the readout and the
|
||||
-- chip-synthesized sounds it fires. See lib/Horde.lua for the whole design.
|
||||
@@ -449,8 +452,26 @@ local function stagedBattles()
|
||||
return OverworldBattle.enabled()
|
||||
end
|
||||
|
||||
-- ------- this mod's settings, grouped the way the menus present them
|
||||
--
|
||||
-- One entry per setting: the ModSetting itself, the help text the mod
|
||||
-- manager's page carries, and the fields that decide where it is offered.
|
||||
--
|
||||
-- cat which of SettingsMenu's categories the row lives on. The table is
|
||||
-- kept in category order as well, so the mod manager's own page --
|
||||
-- which has no categories to give and lists every row flat -- at
|
||||
-- least keeps related settings next to each other.
|
||||
-- when a predicate. The row is off the menu entirely while it answers
|
||||
-- false, because a row that decides nothing reads as a broken mod.
|
||||
-- full the row SURVIVES the FULL preset. FULL owns the look, so a row
|
||||
-- goes with it by default; `full` marks the ones that were never
|
||||
-- about the look. SettingsMenu leans on this and needs no rule of
|
||||
-- its own: 3D WORLD is exactly the rows WITHOUT it, so that whole
|
||||
-- category empties out under FULL and takes itself off the menu.
|
||||
local SETTINGS = {
|
||||
{ VoxelGrid.setting, "One-pixel wireframe along every voxel edge." },
|
||||
-- ------- 3D WORLD -- the diorama's own knobs, every one of them FULL's
|
||||
{ VoxelGrid.setting, "One-pixel wireframe along every voxel edge.",
|
||||
cat = "world" },
|
||||
{ WorldCurve.setting,
|
||||
"Bend the world down over the horizon, Animal Crossing style. 1 is a "
|
||||
.. "hint of roll at the frame edges and 2 is the classic read; 3 is as "
|
||||
@@ -458,7 +479,8 @@ local SETTINGS = {
|
||||
.. "walk into. 4 and 5 are past that on purpose and they are for a "
|
||||
.. "headset's DIORAMA, where the world is a model being looked at "
|
||||
.. "rather than walked around in -- 5 curls it into a half sphere, a "
|
||||
.. "town on top of its own little planet." },
|
||||
.. "town on top of its own little planet.",
|
||||
cat = "world" },
|
||||
{ ViewBox.setting,
|
||||
"How much of the map the camera bothers to draw. FIT is exactly the "
|
||||
.. "ground on screen and no more -- the shape a tilted camera really "
|
||||
@@ -472,24 +494,23 @@ local SETTINGS = {
|
||||
.. "closest, WIDE through WIDEST push the world's edge further out, "
|
||||
.. "and OFF stops cutting entirely. Not on 1ST or 3RD -- you are "
|
||||
.. "standing in the world there -- and the box opens out and away as "
|
||||
.. "the camera dives in." },
|
||||
.. "the camera dives in.",
|
||||
cat = "world" },
|
||||
{ Water.setting,
|
||||
"Reflections on water. FULL adds screen-space reflections of the "
|
||||
.. "shoreline, the trees and the buildings behind it; SKY is the sky, "
|
||||
.. "the sun and the moon alone, which is most of the look for a "
|
||||
.. "fraction of the cost." },
|
||||
-- `full` for the AA reason: additive shafts are fill rate, and under 4X
|
||||
-- supersampling that is a question about the hardware, not the look.
|
||||
{ ForestAtmos.setting,
|
||||
"The air of the deep woods (Viridian Forest): a ground haze, and "
|
||||
.. "volumetric light let down through the unseen canopy overhead -- "
|
||||
.. "gold spears of sun by day, silver moon rays at night, pollen "
|
||||
.. "drifting through the beams and fireflies once they cool. LOW "
|
||||
.. "keeps the haze, halves the beam march and stands the particles "
|
||||
.. "down. On a phone the row offers LOW alone: the beams need a "
|
||||
.. "depth texture the pass can read back, and no mobile driver here "
|
||||
.. "grants one.",
|
||||
full = true },
|
||||
.. "fraction of the cost.",
|
||||
cat = "world" },
|
||||
{ DayNight.setting,
|
||||
"What time it is outdoors: pin the sky to DAY, NIGHT, DUSK or DAWN, "
|
||||
.. "let CYCLE run it -- ten minutes of sun, ten of moon, with the "
|
||||
.. "shadows, the sky and the light following -- or SYNC it to the "
|
||||
.. "clock on the wall, so Kanto's evening falls when yours does.",
|
||||
cat = "world" },
|
||||
|
||||
-- ------- BATTLES -- what a fight is drawn over, and how it is played
|
||||
--
|
||||
-- `full` marks a row FULL does not take away. FULL owns the diorama's own
|
||||
-- knobs; what a battle is drawn over, and how it is framed, are not that.
|
||||
-- Off the OPTIONS menu while VR is on: the headset REQUIRES staged
|
||||
@@ -509,6 +530,7 @@ local SETTINGS = {
|
||||
.. "Pokemon Stadium (US) 1.0 ROM of your own -- import it from the "
|
||||
.. "STADIUM ROM row, or drop it in the baseroms folder and restart. No "
|
||||
.. "other version works: the reader is keyed to that one cartridge.",
|
||||
cat = "battles",
|
||||
when = function() return not VR.enabled() end, full = true },
|
||||
-- Only offered while a fight can actually be staged on the map: with 3D-BTL
|
||||
-- off the engine draws the classic screen, which is this row's ON already,
|
||||
@@ -517,6 +539,7 @@ local SETTINGS = {
|
||||
"Keep your own Pokemon on the battle menu, seen from behind in its "
|
||||
.. "original slot, instead of standing it on the map facing the foe. "
|
||||
.. "The foe is still out there on its own tile.",
|
||||
cat = "battles",
|
||||
when = function() return stagedBattles() and not VR.enabled() end,
|
||||
full = true },
|
||||
-- `full` like the battle rows: this is a GAMEPLAY mode, not a knob on
|
||||
@@ -534,12 +557,26 @@ local SETTINGS = {
|
||||
.. "throws, new species and your running catch combo. Needs 3D-BTL "
|
||||
.. "on; anywhere the staged fight cannot stand, balls quietly throw "
|
||||
.. "the classic way.",
|
||||
full = true },
|
||||
{ DayNight.setting,
|
||||
"What time it is outdoors: pin the sky to DAY, NIGHT, DUSK or DAWN, "
|
||||
.. "let CYCLE run it -- ten minutes of sun, ten of moon, with the "
|
||||
.. "shadows, the sky and the light following -- or SYNC it to the "
|
||||
.. "clock on the wall, so Kanto's evening falls when yours does." },
|
||||
cat = "battles", full = true },
|
||||
|
||||
-- ------- PERFORMANCE -- what the look COSTS, which is a different question
|
||||
--
|
||||
-- All three are `full`, and all three for the same reason: FULL is a preset
|
||||
-- for the diorama, not a licence to spend whatever the machine it happens
|
||||
-- to be running on has got. The player decides what their hardware can
|
||||
-- carry, from inside FULL like anywhere else.
|
||||
-- `full` for the AA reason: additive shafts are fill rate, and under 4X
|
||||
-- supersampling that is a question about the hardware, not the look.
|
||||
{ ForestAtmos.setting,
|
||||
"The air of the deep woods (Viridian Forest): a ground haze, and "
|
||||
.. "volumetric light let down through the unseen canopy overhead -- "
|
||||
.. "gold spears of sun by day, silver moon rays at night, pollen "
|
||||
.. "drifting through the beams and fireflies once they cool. LOW "
|
||||
.. "keeps the haze, halves the beam march and stands the particles "
|
||||
.. "down. On a phone the row offers LOW alone: the beams need a "
|
||||
.. "depth texture the pass can read back, and no mobile driver here "
|
||||
.. "grants one.",
|
||||
cat = "perf", full = true },
|
||||
-- `full` on AA's reasoning below, and for the same reason: the sun's pass
|
||||
-- is the most expensive thing in the frame after the geometry, so this is
|
||||
-- a question about the machine rather than a knob on the diorama, and it
|
||||
@@ -554,13 +591,9 @@ local SETTINGS = {
|
||||
.. "phone or an old machine. OFF is no shadow at all, the flat drop "
|
||||
.. "shadows under characters included, and the forest's light shafts go "
|
||||
.. "with it: the beams are lit by the sun's own map.",
|
||||
full = true },
|
||||
cat = "perf", full = true },
|
||||
-- Marked `full` for the opposite reason the battle rows are: this is not a
|
||||
-- knob on the look at all, it is what the look COSTS. FULL is a preset for
|
||||
-- the diorama, not a licence to spend four times the fill rate on the
|
||||
-- machine it happens to be running on, so it neither sets this nor takes
|
||||
-- the row away -- the player decides what their hardware can carry, from
|
||||
-- inside FULL like anywhere else.
|
||||
-- knob on the look at all, it is what the look COSTS.
|
||||
{ AntiAlias.setting,
|
||||
"Smooth the stair-stepped edges of the 3D world -- roof ridges, ledge "
|
||||
.. "lips, a tree against the sky -- by rendering the diorama larger than "
|
||||
@@ -569,7 +602,10 @@ local SETTINGS = {
|
||||
.. "reads smoother rather than sharper. 2X costs half again as many "
|
||||
.. "pixels in each direction and 4X twice, which makes this the most "
|
||||
.. "expensive row in the mod.",
|
||||
full = true },
|
||||
cat = "perf", full = true },
|
||||
|
||||
-- ------- VR -- the headset, and the one comfort knob that is only its
|
||||
--
|
||||
-- `full` for the same reason as AA: not a knob on the look, a question
|
||||
-- about the hardware on the desk.
|
||||
{ VR.setting,
|
||||
@@ -588,6 +624,7 @@ local SETTINGS = {
|
||||
.. "Menus and dialogs float on a panel. Needs a Windows OpenXR runtime "
|
||||
.. "and the mod running from a real folder; without them the row stays "
|
||||
.. "and the game stays flat, with the reason on the console.",
|
||||
cat = "vr",
|
||||
-- on Windows the row stays even when a runtime is missing (the console
|
||||
-- says why); off Windows -- mobile above all -- there is no VR to have
|
||||
-- and the row does not exist
|
||||
@@ -601,12 +638,15 @@ local SETTINGS = {
|
||||
.. "world past a head that did not move, which is the most reliable way "
|
||||
.. "to make somebody ill in a headset. Turn it on if you have your sea "
|
||||
.. "legs and want the continuity.",
|
||||
cat = "vr",
|
||||
-- and only under STANDARD: the stick turns a HEAD, and neither diorama
|
||||
-- mode has the player standing in the world to be turned
|
||||
when = function() return VR.enabled() and not VR.dioramaMode() end,
|
||||
full = true },
|
||||
}
|
||||
|
||||
SettingsMenu.define(SETTINGS)
|
||||
|
||||
local schema = {}
|
||||
for _, entry in ipairs(SETTINGS) do
|
||||
-- the VR rows are absent from the mod manager's page too where the
|
||||
@@ -783,29 +823,31 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- ------- the mode's rows, kept together
|
||||
-- ------- the mode's rows, on menus of their own
|
||||
--
|
||||
-- The engine splices a pipeline's row in beside TILT, because a display mode
|
||||
-- belongs with the other display modes; a mod's own ui.options.rows
|
||||
-- additions land at the END of the list. That left this mod's four rows in
|
||||
-- two places with unrelated engine rows between them, which reads as two
|
||||
-- unrelated features rather than one mode with settings.
|
||||
-- This mod used to put FOURTEEN rows on the engine's OPTIONS list, in one
|
||||
-- block spliced in beside the pipeline rows. OptionRows shows four boxes at a
|
||||
-- time, so that was four screens of scrolling inside a list that already
|
||||
-- carried twenty engine rows, and finding SHADOWS meant knowing it was in
|
||||
-- there past the wireframe and the horizon bend.
|
||||
--
|
||||
-- So the plain settings are inserted directly after the last of this mod's
|
||||
-- PIPELINE rows instead of appended. Nothing else moves: the block lands
|
||||
-- where the engine already decided display modes go.
|
||||
local function insertGrouped(out, extra)
|
||||
local anchor = nil
|
||||
for i, row in ipairs(out) do
|
||||
local id = type(row) == "table" and row.id
|
||||
if id == "pipeline:voxel" or id == "pipeline:tiltshift" then anchor = i end
|
||||
-- Now there is ONE row, and it leads the list. What it opens -- the
|
||||
-- categories, the screens, and why the split falls where it does -- is
|
||||
-- lib/SettingsMenu.lua. VOXEL and T-SHIFT go with it: they are this mod's
|
||||
-- display modes, the engine only spliced them beside TILT because it had
|
||||
-- nowhere better, and TILT is not on the menu any more anyway (see below).
|
||||
--
|
||||
-- Two things it takes to move a pipeline row: the engine's descriptor is
|
||||
-- captured on the way past and handed to SettingsMenu VERBATIM -- it persists
|
||||
-- through its own step function into save.options.pipelines, and rebuilding
|
||||
-- it here would be a second implementation of something the engine already
|
||||
-- got right -- and the row is then dropped from the top-level list so it is
|
||||
-- not in two places at once.
|
||||
local function captureRow(out, id)
|
||||
for _, row in ipairs(out) do
|
||||
if type(row) == "table" and row.id == id then return row end
|
||||
end
|
||||
if not anchor then
|
||||
for _, row in ipairs(extra) do out[#out + 1] = row end
|
||||
return out
|
||||
end
|
||||
for i, row in ipairs(extra) do table.insert(out, anchor + i, row) end
|
||||
return out
|
||||
return nil
|
||||
end
|
||||
|
||||
-- FULL owns the settings that describe the LOOK, so while it is selected those
|
||||
@@ -875,6 +917,25 @@ local function pinEngineFx(game)
|
||||
if changed and game.writeOptions then pcall(game.writeOptions, game) end
|
||||
end
|
||||
|
||||
-- ------- the values that follow other values
|
||||
--
|
||||
-- Two settings hold a third in place. 3D-BTL pins BATTLE LAYOUT to OG while a
|
||||
-- fight can be staged on the map, and FULL pins DAYTIME to SYNC while it owns
|
||||
-- that row. Both pins used to be a side effect of the rows hook, which every
|
||||
-- step on the OPTIONS menu reran -- so they happened whether or not the step
|
||||
-- was the one that mattered, and nothing had to name them.
|
||||
--
|
||||
-- Now a step can happen on the mod's own menu, where no hook runs, or on the
|
||||
-- mod manager's page, where one never did. So the pinning is a function, and
|
||||
-- all three routes ask for it.
|
||||
local function pinDependents(game)
|
||||
if stagedBattles() then OverworldBattle.forceOG(game) end
|
||||
local Pipelines = require("src.render.Pipelines")
|
||||
if Voxel.isFull(Pipelines.level("voxel")) then DayNight.forceSync(game) end
|
||||
end
|
||||
|
||||
SettingsMenu.setOnChanged(pinDependents)
|
||||
|
||||
-- call next() first and decorate what comes back, so every other mod's
|
||||
-- rows survive this one
|
||||
mod.hooks:wrap("ui.options.rows", function(next, game, rows)
|
||||
@@ -901,46 +962,50 @@ mod.hooks:wrap("ui.options.rows", function(next, game, rows)
|
||||
OverworldBattle.forceOG(game)
|
||||
dropRow(out, "battleLayout")
|
||||
end
|
||||
local full = Voxel.isFull(Pipelines.level("voxel"))
|
||||
if full then
|
||||
if Voxel.isFull(Pipelines.level("voxel")) then
|
||||
-- FULL owns the rows that PARAMETERISE the diorama -- the wireframe, the
|
||||
-- horizon bend, the blur, the hour -- so those come off the menu and
|
||||
-- DAYTIME is held at SYNC while its row is unreachable.
|
||||
-- horizon bend, the blur, the hour -- so DAYTIME is held at SYNC while its
|
||||
-- row is unreachable. The rows themselves come off inside SettingsMenu,
|
||||
-- which is where they live now: T-SHIFT with the wireframe and the bend,
|
||||
-- and each of them by the same `full` rule rather than by name.
|
||||
DayNight.forceSync(game)
|
||||
dropRow(out, "pipeline:tiltshift")
|
||||
end
|
||||
local extra = {}
|
||||
for _, entry in ipairs(SETTINGS) do
|
||||
-- Two things decide whether a row is offered.
|
||||
--
|
||||
-- FULL: a preset that owns the look, so the rows that describe the look go
|
||||
-- with it. The BATTLE rows are not that -- 3D-BTL decides what a fight is
|
||||
-- drawn OVER and BACK SPRITES how it is framed, and neither is a knob on
|
||||
-- the diorama FULL is a preset for. FULL still SETS them on arrival (see
|
||||
-- applyFull); it does not hold them, so leaving them on the menu is the
|
||||
-- difference between a preset and a lock.
|
||||
--
|
||||
-- And a row whose own switch is off the table this frame (BACK SPRITES,
|
||||
-- which needs a staged fight to be about) is left off with it. The mod
|
||||
-- manager's page carries every one of them either way.
|
||||
local offered = (entry.full or not full)
|
||||
and (not entry.when or entry.when())
|
||||
if offered then extra[#extra + 1] = entry[1]:row() end
|
||||
-- The two pipeline rows move INTO the mod's own root menu: captured as the
|
||||
-- engine built them, then dropped from here so they are not in two places.
|
||||
local captured, voxelRow = {}, nil
|
||||
for _, id in ipairs({ "pipeline:voxel", "pipeline:tiltshift" }) do
|
||||
local row = captureRow(out, id)
|
||||
-- a pipeline the registry refused is simply not there, and the menu says
|
||||
-- so by not offering it rather than by offering a hole
|
||||
if row then captured[#captured + 1] = row end
|
||||
if id == "pipeline:voxel" then voxelRow = row end
|
||||
dropRow(out, id)
|
||||
end
|
||||
-- and the ROM import, which is an ACTION and not a setting: there is no
|
||||
-- rung to store, nothing for the mod manager's page to persist and nothing
|
||||
-- to restore on the next boot, so it is appended here rather than living in
|
||||
-- SETTINGS. nil on a platform with no file dialog, which takes it off the
|
||||
-- menu rather than offering a button that cannot do anything.
|
||||
-- On EVERY platform. Where there is no file dialog it says WHERE? and
|
||||
-- shows the folder to put the cartridge in, which is the one thing a
|
||||
-- player on a phone could not otherwise find out -- the row used to vanish
|
||||
-- there, which reads as the feature being missing rather than manual.
|
||||
local okPick, importRow = pcall(function()
|
||||
return V.require("StadiumRomPick").row()
|
||||
end)
|
||||
if okPick and importRow then extra[#extra + 1] = importRow end
|
||||
return insertGrouped(out, extra)
|
||||
SettingsMenu.setPipelineRows(captured)
|
||||
-- ------- one row, and it leads the list
|
||||
--
|
||||
-- At the TOP rather than spliced in beside the display modes it used to sit
|
||||
-- with. This is a mod that replaces the whole look of the game, and a player
|
||||
-- who installed it and went looking for its settings should not have to
|
||||
-- scroll to find out where they went -- least of all past the engine rows it
|
||||
-- has quietly taken away.
|
||||
--
|
||||
-- Inserted after next() has run, so it leads every OTHER mod's rows too. The
|
||||
-- second line is VOXEL's own value function, which makes the row say what
|
||||
-- the mode is currently doing without opening it -- and reuses the engine's
|
||||
-- label ladder rather than restating it.
|
||||
table.insert(out, 1, {
|
||||
id = SettingsMenu.id(SettingsMenu.ROOT),
|
||||
label = SettingsMenu.ROOT_LABEL,
|
||||
value = voxelRow and voxelRow.value or nil,
|
||||
-- `activate` and not `step`: the engine fires activate on A alone, and a
|
||||
-- row that OPENS something should not also answer Left and Right
|
||||
-- (src/ui/OptionsMenu.update).
|
||||
activate = function(g)
|
||||
g.stack:push(SettingsMenu.new(g, SettingsMenu.ROOT))
|
||||
end,
|
||||
})
|
||||
return out
|
||||
end)
|
||||
|
||||
-- The mod manager writes and persists on its own, so the only thing left
|
||||
@@ -951,14 +1016,11 @@ mod.events:on("mod.options_changed", function(payload)
|
||||
if payload.key == entry[1].key then entry[1]:sync(payload.value) end
|
||||
end
|
||||
-- 3D-BTL switched on from the manager's page pins BATTLE LAYOUT exactly as
|
||||
-- the OPTIONS row does. The manager persists its own value; this is the one
|
||||
-- that has to follow it.
|
||||
if stagedBattles() then OverworldBattle.forceOG() end
|
||||
-- and DAYTIME changed from the manager's page while FULL owns it snaps
|
||||
-- straight back to SYNC -- the OPTIONS row is hidden, but the manager's is
|
||||
-- not, and FULL's pin must hold against both
|
||||
local Pipelines = require("src.render.Pipelines")
|
||||
if Voxel.isFull(Pipelines.level("voxel")) then DayNight.forceSync() end
|
||||
-- the mod's own row does, and DAYTIME changed there while FULL owns it snaps
|
||||
-- straight back to SYNC -- that row is off the mod's menus under FULL, but
|
||||
-- the manager's page carries every setting unconditionally, and the pin has
|
||||
-- to hold against both.
|
||||
pinDependents()
|
||||
end)
|
||||
|
||||
-- ------- keeping the geometry in step with the world
|
||||
@@ -1058,30 +1120,55 @@ end)
|
||||
-- rerun every mod's ui.options.rows hook once per keypress. The cursor is
|
||||
-- clamped rather than reset, so it stays on the row it was just used on
|
||||
-- instead of jumping to the top when the list below it shortens.
|
||||
--
|
||||
-- Held on the INSTANCE rather than compared across one call of update, and
|
||||
-- that is not a tidying: those three rows live in a SUBMENU now, and the
|
||||
-- stack only ticks its top state (src/core/StateStack.update). So the step
|
||||
-- that changes them happens while this menu is suspended and a
|
||||
-- before/after pair taken around inner() would both be read after the fact
|
||||
-- and always agree. A signature that outlives the suspension does not.
|
||||
do
|
||||
local OptionsMenu = require("src.ui.OptionsMenu")
|
||||
if not OptionsMenu.dramaticShapeFullHook then
|
||||
local OptionRows = require("src.ui.OptionRows")
|
||||
local Pipelines = require("src.render.Pipelines")
|
||||
local inner = OptionsMenu.update
|
||||
local innerPalettes = OptionsMenu.sgbPalettes
|
||||
|
||||
local function idAt(menu, index)
|
||||
local row = menu.rows and menu.rows[index or 1]
|
||||
return type(row) == "table" and row.id or nil
|
||||
end
|
||||
|
||||
-- What the row LIST depends on: whether FULL is selected (it owns the
|
||||
-- rows that describe the look), and the two switches that give and take
|
||||
-- an engine row -- 3D-BTL, which owns BATTLE LAYOUT, and VR, which hides
|
||||
-- both battle rows while it is on. Only the FULL-ness of the voxel level
|
||||
-- matters, so stepping 35 to 50 is not a change.
|
||||
local function signature()
|
||||
return string.format("%s|%s|%s",
|
||||
tostring(Voxel.isFull(Pipelines.level("voxel"))),
|
||||
tostring(OverworldBattle.enabled()), tostring(VR.enabled()))
|
||||
end
|
||||
|
||||
-- Stamped where the ROWS are built, which is the thing the signature is a
|
||||
-- signature OF. Read lazily on the first update instead and a menu opened
|
||||
-- before the change and updated after it would compare the new state
|
||||
-- against itself and never rebuild.
|
||||
local innerNew = OptionsMenu.new
|
||||
function OptionsMenu.new(game, opts)
|
||||
local menu = innerNew(game, opts)
|
||||
menu.dramaticShapeSig = signature()
|
||||
return menu
|
||||
end
|
||||
|
||||
function OptionsMenu:update(dt)
|
||||
local before = Pipelines.level("voxel")
|
||||
local hadBattles = OverworldBattle.enabled()
|
||||
-- the VR row hides the two battle rows while it is on, so stepping
|
||||
-- it changes the LIST exactly the way 3D-BTL does
|
||||
local hadVR = VR.enabled()
|
||||
local wasOn = idAt(self, self.index)
|
||||
local before = self.dramaticShapeSig or signature()
|
||||
inner(self, dt)
|
||||
local after = Pipelines.level("voxel")
|
||||
local crossedFull = after ~= before
|
||||
and (Voxel.isFull(before) or Voxel.isFull(after))
|
||||
if crossedFull or OverworldBattle.enabled() ~= hadBattles
|
||||
or VR.enabled() ~= hadVR then
|
||||
local after = signature()
|
||||
self.dramaticShapeSig = after
|
||||
if before ~= after then
|
||||
local rebuilt = OptionsMenu.new(self.game)
|
||||
self.rows = rebuilt.rows
|
||||
-- Follow the row the cursor was ON rather than the slot it was in:
|
||||
@@ -1095,6 +1182,36 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- ------- and the mod's own row is red
|
||||
--
|
||||
-- Why this is a palette zone and not love.graphics.setColor -- twice over
|
||||
-- -- is written out in lib/SettingsMenu.lua, next to the code that builds
|
||||
-- the palette. The short of it: setColor picks a SHADE on this screen and
|
||||
-- the zone picks the COLOR.
|
||||
--
|
||||
-- Addressed by SLOT, because the row scrolls: it leads the list, so it is
|
||||
-- normally the top box, but a player who scrolls past it must not leave a
|
||||
-- red band behind on whatever takes its place. Searched by id rather than
|
||||
-- assumed to be row 1 for the same reason -- another mod's hook running
|
||||
-- after ours could put something above it.
|
||||
function OptionsMenu:sgbPalettes(game)
|
||||
local zones = innerPalettes and innerPalettes(self, game) or nil
|
||||
local scroll = self.scroll or 0
|
||||
for slot = 1, OptionRows.VISIBLE do
|
||||
local row = self.rows and self.rows[scroll + slot]
|
||||
if type(row) == "table"
|
||||
and row.id == SettingsMenu.id(SettingsMenu.ROOT) then
|
||||
local zone = SettingsMenu.rowZone(game and game.data, slot)
|
||||
if zone then
|
||||
zones = zones or {}
|
||||
zones[#zones + 1] = zone
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
return zones
|
||||
end
|
||||
|
||||
OptionsMenu.dramaticShapeFullHook = true
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user