1
0
Fork 0
mirror of https://github.com/notwa/mm synced 2024-11-04 20:09:03 -08:00

complete rewrite of cheat menu

This commit is contained in:
Connor Olding 2015-05-03 16:46:09 -07:00
parent 4c363dae6f
commit 9dabf504d4
5 changed files with 308 additions and 162 deletions

View file

@ -1,5 +1,6 @@
require "boilerplate"
require "addrs.init"
require "classes"
-- check for errors in the actor linked lists
local validate = false
@ -177,26 +178,6 @@ function collect_actors()
return any > 0, actors_by_type, new_counts
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()
function ActorLister:init()
self.before = 0

View file

@ -235,8 +235,7 @@ return {
kegs = AL(0xAC, 1),
},
buttons_1 = AG(0x1A, 1),
buttons_2 = AG(0x1B, 1),
buttons = AG(0x1A, 2),
framerate_limiter = AG(0xA2, 1),
scene_number = AG(0xA4, 2),
screen_T = AG(0xC0, 4),

View file

@ -1,158 +1,101 @@
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 = {
{
close,
{text="hey"},
{text="L to levitate", type="toggle", id="levitate"},
{text="levitate", type="hold", call_id="levitate"},
{text="everything", type="oneshot", call_id="everything"},
active = 1,
function T_BR(x, y, color, ...) T(x, y, color, "bottomright", ...) end
function T_BL(x, y, color, ...) T(x, y, color, "bottomleft", ...) end
function T_TL(x, y, color, ...) T(x, y, color, "topleft", ...) end
function T_TR(x, y, color, ...) T(x, y, color, "topright", ...) end
local passives = {}
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(),
},
{
close,
{text="kill link", type="oneshot", call_id="kill"},
{text="some flags", type="control"}, -- how to handle this?
-- i guess with a function like update_text
-- and self_render and handle_input basically
-- or call_id="submenu" options={yada yada}
{text="k"},
active = 1,
Screen{
Oneshot("Kill Link", self_destruct),
Flags("some flags"),
Text("k"),
Back(),
},
active = 1,
}
local active_menu = nil
local menu_state = {
levitate = false,
local input = InputHandler{
enter = "P1 L",
up = "P1 DPad U",
down = "P1 DPad D",
left = "P1 DPad L",
right = "P1 DPad R",
}
local menu_calls = {
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,
}
local menu = nil
function T(x, y, s, color)
color = color or "white"
gui.text(10*x + 2, 16*y + 4, s, nil, color, "bottomright")
end
while mm or oot do
local ctrl, pressed = input:update()
function draw_row(row, row_number, is_active)
local color = is_active and "cyan" or "white"
if row.type == "toggle" then
T(4, row_number, row.text, color)
T(0, row_number, "[ ]", "yellow")
if menu_state[row.id] then
T(1, row_number, "x", "cyan")
end
else
T(0, row_number, row.text, color)
local delay = false
if not menu and pressed.enter then
delay = true
menu = main_menu
menu:focus()
end
end
function run_row(row, hold)
local rt = row.type
if rt == "hold" then
if row.call_id then
menu_calls[row.call_id](row, menu_state)
end
if row.id then
menu_state[row.id] = true -- TODO: set to false later
if menu and not delay then
local old = menu
menu = menu:navigate(ctrl, pressed)
if menu ~= old then
old:unfocus()
if menu then menu:focus() end
end
end
if menu then menu:draw(T_TL, 0) end
if hold then return end
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)
for i, passive in ipairs(passives) do
passive:tick()
end
end
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()
emu.frameadvance()
end

View file

@ -41,3 +41,23 @@ function Monitor:save(fn)
self.dirty = false
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
View 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