mirror of
https://github.com/notwa/mm
synced 2025-02-05 13:23:23 -08:00
complete rewrite of cheat menu
This commit is contained in:
parent
4c363dae6f
commit
9dabf504d4
5 changed files with 308 additions and 162 deletions
|
@ -1,5 +1,6 @@
|
||||||
require "boilerplate"
|
require "boilerplate"
|
||||||
require "addrs.init"
|
require "addrs.init"
|
||||||
|
require "classes"
|
||||||
|
|
||||||
-- check for errors in the actor linked lists
|
-- check for errors in the actor linked lists
|
||||||
local validate = false
|
local validate = false
|
||||||
|
@ -177,26 +178,6 @@ function collect_actors()
|
||||||
return any > 0, actors_by_type, new_counts
|
return any > 0, actors_by_type, new_counts
|
||||||
end
|
end
|
||||||
|
|
||||||
InputHandler = Class()
|
|
||||||
function InputHandler:init(binds)
|
|
||||||
self.binds = binds
|
|
||||||
self.old_ctrl = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
function InputHandler:update()
|
|
||||||
local ctrl = {}
|
|
||||||
local pressed = {}
|
|
||||||
local j = joypad.getimmediate()
|
|
||||||
for k, v in pairs(self.binds) do
|
|
||||||
ctrl[k] = j[v]
|
|
||||||
end
|
|
||||||
for k, v in pairs(ctrl) do
|
|
||||||
pressed[k] = ctrl[k] and not self.old_ctrl[k]
|
|
||||||
end
|
|
||||||
self.old_ctrl = ctrl
|
|
||||||
return ctrl, pressed
|
|
||||||
end
|
|
||||||
|
|
||||||
ActorLister = Class()
|
ActorLister = Class()
|
||||||
function ActorLister:init()
|
function ActorLister:init()
|
||||||
self.before = 0
|
self.before = 0
|
||||||
|
|
|
@ -235,8 +235,7 @@ return {
|
||||||
kegs = AL(0xAC, 1),
|
kegs = AL(0xAC, 1),
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons_1 = AG(0x1A, 1),
|
buttons = AG(0x1A, 2),
|
||||||
buttons_2 = AG(0x1B, 1),
|
|
||||||
framerate_limiter = AG(0xA2, 1),
|
framerate_limiter = AG(0xA2, 1),
|
||||||
scene_number = AG(0xA4, 2),
|
scene_number = AG(0xA4, 2),
|
||||||
screen_T = AG(0xC0, 4),
|
screen_T = AG(0xC0, 4),
|
||||||
|
|
|
@ -1,158 +1,101 @@
|
||||||
require "boilerplate"
|
require "boilerplate"
|
||||||
local addrs = require "addrs.init"
|
require "addrs.init"
|
||||||
|
require "classes"
|
||||||
|
require "menu classes"
|
||||||
|
|
||||||
local close = {text="close", type="close"}
|
function T(x, y, color, pos, s, ...)
|
||||||
|
if #{...} > 0 then
|
||||||
|
s = s:format(...)
|
||||||
|
end
|
||||||
|
gui.text(10*x + 2, 16*y + 4, s, nil, color or "white", pos or "bottomright")
|
||||||
|
end
|
||||||
|
|
||||||
local menu = {
|
function T_BR(x, y, color, ...) T(x, y, color, "bottomright", ...) end
|
||||||
{
|
function T_BL(x, y, color, ...) T(x, y, color, "bottomleft", ...) end
|
||||||
close,
|
function T_TL(x, y, color, ...) T(x, y, color, "topleft", ...) end
|
||||||
{text="hey"},
|
function T_TR(x, y, color, ...) T(x, y, color, "topright", ...) end
|
||||||
{text="L to levitate", type="toggle", id="levitate"},
|
|
||||||
{text="levitate", type="hold", call_id="levitate"},
|
local passives = {}
|
||||||
{text="everything", type="oneshot", call_id="everything"},
|
|
||||||
active = 1,
|
Passive = Class(Callbacks)
|
||||||
|
function Passive:init(...)
|
||||||
|
Callbacks.init(self, ...)
|
||||||
|
table.insert(passives, self)
|
||||||
|
end
|
||||||
|
function Passive:tick()
|
||||||
|
end
|
||||||
|
|
||||||
|
local levitate = Passive()
|
||||||
|
function levitate:tick()
|
||||||
|
if self.state then
|
||||||
|
if bit.band(addrs.buttons(), 0x20) > 0 then
|
||||||
|
self:hold()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function levitate:hold()
|
||||||
|
addrs.link_actor.y_vel(10)
|
||||||
|
end
|
||||||
|
|
||||||
|
local everything = Callbacks()
|
||||||
|
function everything:on()
|
||||||
|
dofile("oneshot.lua")
|
||||||
|
end
|
||||||
|
|
||||||
|
local self_destruct = Callbacks()
|
||||||
|
function self_destruct:on()
|
||||||
|
addrs.hearts(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local main_menu = Menu{
|
||||||
|
Screen{
|
||||||
|
Text("hey"),
|
||||||
|
Toggle("L to Levitate", levitate),
|
||||||
|
Hold("Levitate", levitate),
|
||||||
|
Oneshot("100%", everything),
|
||||||
|
Back(),
|
||||||
},
|
},
|
||||||
{
|
Screen{
|
||||||
close,
|
Oneshot("Kill Link", self_destruct),
|
||||||
{text="kill link", type="oneshot", call_id="kill"},
|
Flags("some flags"),
|
||||||
{text="some flags", type="control"}, -- how to handle this?
|
Text("k"),
|
||||||
-- i guess with a function like update_text
|
Back(),
|
||||||
-- and self_render and handle_input basically
|
|
||||||
-- or call_id="submenu" options={yada yada}
|
|
||||||
{text="k"},
|
|
||||||
active = 1,
|
|
||||||
},
|
},
|
||||||
active = 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local active_menu = nil
|
local input = InputHandler{
|
||||||
|
enter = "P1 L",
|
||||||
local menu_state = {
|
up = "P1 DPad U",
|
||||||
levitate = false,
|
down = "P1 DPad D",
|
||||||
|
left = "P1 DPad L",
|
||||||
|
right = "P1 DPad R",
|
||||||
}
|
}
|
||||||
|
|
||||||
local menu_calls = {
|
local menu = nil
|
||||||
levitate = function(item, state)
|
|
||||||
addrs.z_vel(16)
|
|
||||||
end,
|
|
||||||
kill = function(item, state)
|
|
||||||
addrs.hearts(0)
|
|
||||||
end,
|
|
||||||
set = function(item, state)
|
|
||||||
A(item.addr, item.type)(item.value)
|
|
||||||
end,
|
|
||||||
everything = function(item, state)
|
|
||||||
dofile("oneshot.lua")
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
function T(x, y, s, color)
|
while mm or oot do
|
||||||
color = color or "white"
|
local ctrl, pressed = input:update()
|
||||||
gui.text(10*x + 2, 16*y + 4, s, nil, color, "bottomright")
|
|
||||||
end
|
|
||||||
|
|
||||||
function draw_row(row, row_number, is_active)
|
local delay = false
|
||||||
local color = is_active and "cyan" or "white"
|
if not menu and pressed.enter then
|
||||||
if row.type == "toggle" then
|
delay = true
|
||||||
T(4, row_number, row.text, color)
|
menu = main_menu
|
||||||
T(0, row_number, "[ ]", "yellow")
|
menu:focus()
|
||||||
if menu_state[row.id] then
|
|
||||||
T(1, row_number, "x", "cyan")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
T(0, row_number, row.text, color)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function run_row(row, hold)
|
if menu and not delay then
|
||||||
local rt = row.type
|
local old = menu
|
||||||
if rt == "hold" then
|
menu = menu:navigate(ctrl, pressed)
|
||||||
if row.call_id then
|
if menu ~= old then
|
||||||
menu_calls[row.call_id](row, menu_state)
|
old:unfocus()
|
||||||
end
|
if menu then menu:focus() end
|
||||||
if row.id then
|
|
||||||
menu_state[row.id] = true -- TODO: set to false later
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if menu then menu:draw(T_TL, 0) end
|
||||||
|
|
||||||
if hold then return end
|
for i, passive in ipairs(passives) do
|
||||||
|
passive:tick()
|
||||||
if rt == "toggle" then
|
|
||||||
menu_state[row.id] = not menu_state[row.id]
|
|
||||||
if row.call_id then
|
|
||||||
menu_calls[row.call_id](row, menu_state)
|
|
||||||
end
|
|
||||||
elseif rt == "close" then
|
|
||||||
active_menu = nil
|
|
||||||
elseif rt == "oneshot" then
|
|
||||||
menu_calls[row.call_id](row, menu_state)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
emu.frameadvance()
|
||||||
function run_mainmenu(ctrl, pressed)
|
|
||||||
local active_submenu = menu.active
|
|
||||||
if pressed.left then
|
|
||||||
active_submenu = active_submenu - 1
|
|
||||||
end
|
|
||||||
if pressed.right then
|
|
||||||
active_submenu = active_submenu + 1
|
|
||||||
end
|
|
||||||
active_submenu = (active_submenu - 1) % #menu + 1
|
|
||||||
menu.active = active_submenu
|
|
||||||
|
|
||||||
local submenu = menu[active_submenu]
|
|
||||||
|
|
||||||
local active_row = submenu.active
|
|
||||||
if pressed.down then
|
|
||||||
active_row = active_row - 1
|
|
||||||
end
|
|
||||||
if pressed.up then
|
|
||||||
active_row = active_row + 1
|
|
||||||
end
|
|
||||||
active_row = (active_row - 1) % #submenu + 1
|
|
||||||
submenu.active = active_row
|
|
||||||
|
|
||||||
local row = submenu[active_row]
|
|
||||||
|
|
||||||
if pressed.enter then
|
|
||||||
run_row(row)
|
|
||||||
elseif ctrl.enter then
|
|
||||||
run_row(row, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
T(0, 0, ("menu %02i/%02i"):format(active_submenu, #menu), "yellow")
|
|
||||||
for i, row in ipairs(submenu) do
|
|
||||||
draw_row(row, i, i == active_row)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local pressed = {}
|
|
||||||
local old_ctrl = {}
|
|
||||||
while true do
|
|
||||||
local j = joypad.getimmediate()
|
|
||||||
local ctrl = {
|
|
||||||
enter = j["P1 L"],
|
|
||||||
up = j["P1 DPad U"],
|
|
||||||
down = j["P1 DPad D"],
|
|
||||||
left = j["P1 DPad L"],
|
|
||||||
right = j["P1 DPad R"],
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v in pairs(ctrl) do
|
|
||||||
pressed[k] = ctrl[k] and not old_ctrl[k]
|
|
||||||
end
|
|
||||||
|
|
||||||
gui.clearGraphics()
|
|
||||||
|
|
||||||
if pressed.enter and not active_menu then
|
|
||||||
active_menu = menu
|
|
||||||
pressed.enter = false
|
|
||||||
end
|
|
||||||
|
|
||||||
if active_menu == menu then
|
|
||||||
run_mainmenu(ctrl, pressed)
|
|
||||||
end
|
|
||||||
|
|
||||||
old_ctrl = ctrl
|
|
||||||
emu.yield()
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,3 +41,23 @@ function Monitor:save(fn)
|
||||||
self.dirty = false
|
self.dirty = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
InputHandler = Class()
|
||||||
|
function InputHandler:init(binds)
|
||||||
|
self.binds = binds
|
||||||
|
self.old_ctrl = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function InputHandler:update()
|
||||||
|
local ctrl = {}
|
||||||
|
local pressed = {}
|
||||||
|
local j = joypad.getimmediate()
|
||||||
|
for k, v in pairs(self.binds) do
|
||||||
|
ctrl[k] = j[v]
|
||||||
|
end
|
||||||
|
for k, v in pairs(ctrl) do
|
||||||
|
pressed[k] = ctrl[k] and not self.old_ctrl[k]
|
||||||
|
end
|
||||||
|
self.old_ctrl = ctrl
|
||||||
|
return ctrl, pressed
|
||||||
|
end
|
||||||
|
|
203
Lua/menu classes.lua
Normal file
203
Lua/menu classes.lua
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
function wrap(x, around)
|
||||||
|
return (x - 1) % around + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
MenuItem = Class()
|
||||||
|
Text = Class(MenuItem)
|
||||||
|
Back = Class(Text)
|
||||||
|
Close = Back -- FIXME
|
||||||
|
|
||||||
|
Active = Class(Text)
|
||||||
|
Toggle = Class(Active)
|
||||||
|
Hold = Class(Active)
|
||||||
|
Oneshot = Class(Active)
|
||||||
|
Flags = Class(Active)
|
||||||
|
|
||||||
|
Screen = Class()
|
||||||
|
Menu = Class()
|
||||||
|
|
||||||
|
Callbacks = Class()
|
||||||
|
|
||||||
|
function Callbacks:init()
|
||||||
|
self.state = false
|
||||||
|
end
|
||||||
|
function Callbacks:on()
|
||||||
|
self.state = true
|
||||||
|
end
|
||||||
|
function Callbacks:off()
|
||||||
|
self.state = false
|
||||||
|
end
|
||||||
|
function Callbacks:hold()
|
||||||
|
end
|
||||||
|
function Callbacks:release()
|
||||||
|
end
|
||||||
|
|
||||||
|
function MenuItem:init()
|
||||||
|
self.focused = false
|
||||||
|
end
|
||||||
|
function MenuItem:run()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
function MenuItem:hold()
|
||||||
|
self:release()
|
||||||
|
end
|
||||||
|
function MenuItem:focus()
|
||||||
|
self.focused = true
|
||||||
|
end
|
||||||
|
function MenuItem:unfocus()
|
||||||
|
self.focused = false
|
||||||
|
end
|
||||||
|
function MenuItem:release()
|
||||||
|
end
|
||||||
|
function MenuItem:draw(brush, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Text:init(text)
|
||||||
|
MenuItem.init(self)
|
||||||
|
self.text = text
|
||||||
|
end
|
||||||
|
function Text:draw(brush, y)
|
||||||
|
local color = self.focused and 'yellow' or 'white'
|
||||||
|
brush(0, y, color, self.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Back:init()
|
||||||
|
Text.init(self, 'back')
|
||||||
|
end
|
||||||
|
function Back:run()
|
||||||
|
return nil -- FIXME
|
||||||
|
end
|
||||||
|
|
||||||
|
function Active:init(text, callbacks)
|
||||||
|
self.text = text
|
||||||
|
self.callbacks = callbacks or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Toggle:init(text, callbacks)
|
||||||
|
Active.init(self, text, callbacks)
|
||||||
|
self.state = false
|
||||||
|
end
|
||||||
|
function Toggle:run()
|
||||||
|
self.state = not self.state
|
||||||
|
if self.state then
|
||||||
|
self.callbacks:on(true)
|
||||||
|
else
|
||||||
|
self.callbacks:off(false)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
function Toggle:draw(brush, y)
|
||||||
|
local color = self.focused and 'yellow' or 'white'
|
||||||
|
brush(0, y, 'cyan', '[ ]')
|
||||||
|
if self.state then
|
||||||
|
brush(1, y, color, 'x')
|
||||||
|
end
|
||||||
|
brush(4, y, color, self.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Oneshot:run()
|
||||||
|
self.callbacks:on()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Hold:run()
|
||||||
|
self:hold()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
function Hold:hold()
|
||||||
|
self.callbacks:hold()
|
||||||
|
end
|
||||||
|
function Hold:release()
|
||||||
|
self.callbacks:release()
|
||||||
|
end
|
||||||
|
|
||||||
|
--function Flags:init
|
||||||
|
|
||||||
|
function Screen:init(items)
|
||||||
|
self.items = items
|
||||||
|
self.item_sel = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Screen:focus()
|
||||||
|
self.items[self.item_sel]:focus()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Screen:unfocus()
|
||||||
|
self.items[self.item_sel]:unfocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Screen:navigate(ctrl, pressed)
|
||||||
|
local i = self.item_sel
|
||||||
|
local old = self.items[i]
|
||||||
|
|
||||||
|
if pressed.down then i = i + 1 end
|
||||||
|
if pressed.up then i = i - 1 end
|
||||||
|
i = wrap(i, #self.items)
|
||||||
|
self.item_sel = i
|
||||||
|
|
||||||
|
local item = self.items[i]
|
||||||
|
|
||||||
|
if item ~= old then
|
||||||
|
old:unfocus()
|
||||||
|
old:release()
|
||||||
|
item:focus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local focus = self
|
||||||
|
if pressed.enter then
|
||||||
|
focus = item:run()
|
||||||
|
elseif ctrl.enter then
|
||||||
|
item:hold()
|
||||||
|
else
|
||||||
|
item:release()
|
||||||
|
end
|
||||||
|
|
||||||
|
if focus == item then
|
||||||
|
focus = self
|
||||||
|
end
|
||||||
|
|
||||||
|
return focus
|
||||||
|
end
|
||||||
|
|
||||||
|
function Screen:draw(brush, y)
|
||||||
|
for i, item in ipairs(self.items) do
|
||||||
|
item:draw(brush, y + i - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu:init(screens)
|
||||||
|
self.screens = screens
|
||||||
|
self.screen_sel = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu:focus()
|
||||||
|
self.screens[self.screen_sel]:focus()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu:unfocus()
|
||||||
|
self.screens[self.screen_sel]:unfocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu:navigate(ctrl, pressed)
|
||||||
|
local s = self.screen_sel
|
||||||
|
local old = self.screens[s]
|
||||||
|
if pressed.left then s = s - 1 end
|
||||||
|
if pressed.right then s = s + 1 end
|
||||||
|
s = wrap(s, #self.screens)
|
||||||
|
self.screen_sel = s
|
||||||
|
|
||||||
|
local screen = self.screens[s]
|
||||||
|
if screen ~= old then
|
||||||
|
old:unfocus()
|
||||||
|
screen:focus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local focus = screen:navigate(ctrl, pressed)
|
||||||
|
if focus == screen then focus = self end
|
||||||
|
|
||||||
|
return focus
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu:draw(brush, y)
|
||||||
|
self.screens[self.screen_sel]:draw(brush, y)
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue