2015-05-26 06:40:47 -07:00
|
|
|
require = require "depend"
|
2015-03-04 21:38:30 -08:00
|
|
|
require "boilerplate"
|
2015-05-03 16:46:09 -07:00
|
|
|
require "addrs.init"
|
|
|
|
require "classes"
|
|
|
|
require "menu classes"
|
2015-11-14 16:30:04 -08:00
|
|
|
require "menu input handlers"
|
2015-05-07 15:27:26 -07:00
|
|
|
require "messages"
|
2015-11-12 09:09:14 -08:00
|
|
|
require "flag manager"
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-11-12 09:09:14 -08:00
|
|
|
-- TODO: make OoT versions for most of these menus
|
|
|
|
|
2015-11-14 14:59:37 -08:00
|
|
|
--[[ control schemes:
|
|
|
|
normal: (alt_input = false; eat_input = false)
|
|
|
|
L opens the menu
|
|
|
|
L selects menu items
|
|
|
|
D-Pad navigates up/down items and left/right through pages
|
2015-11-14 16:30:04 -08:00
|
|
|
alternate: (alt_input = true; eat_input = false)
|
2015-11-14 14:59:37 -08:00
|
|
|
L+R opens/closes the menu
|
|
|
|
L goes back a menu (or closes)
|
|
|
|
R selects menu items
|
2015-11-14 16:30:04 -08:00
|
|
|
L+Z hides the menu without closing (FIXME: interferes with back button)
|
2015-11-14 14:59:37 -08:00
|
|
|
D-Pad navigates
|
|
|
|
greedy: (alt_input = false; eat_input = true)
|
2015-11-14 16:42:50 -08:00
|
|
|
L opens/closes the menu
|
2015-11-14 16:30:04 -08:00
|
|
|
while the menu is open, the game receives no inputs
|
|
|
|
D-Pad/Joystick/C-Buttons navigate through items and pages
|
2015-11-14 16:42:50 -08:00
|
|
|
A select menu items
|
2015-11-14 16:30:04 -08:00
|
|
|
B/R go back a menu (or closes)
|
|
|
|
Z hides the menu without closing
|
2015-11-14 14:59:37 -08:00
|
|
|
TODO: joystick, a/b button etc
|
2015-11-14 16:30:04 -08:00
|
|
|
greedy alt: (alt_input = true; eat_input = true)
|
|
|
|
same as greedy but pauses the game while in menu
|
|
|
|
(enables run_while_paused)
|
2015-11-14 14:59:37 -08:00
|
|
|
--]]
|
|
|
|
|
2015-11-14 13:46:04 -08:00
|
|
|
local run_while_paused = true
|
2015-11-14 14:59:37 -08:00
|
|
|
local alt_input = true
|
2015-11-14 16:30:04 -08:00
|
|
|
local eat_input = true
|
2015-11-14 14:59:37 -08:00
|
|
|
|
2015-11-14 08:57:37 -08:00
|
|
|
local fn = 'cheat menu.save.lua'
|
|
|
|
local saved = deserialize('cheat menu.save.lua') or {}
|
|
|
|
local function save()
|
|
|
|
serialize(fn, saved)
|
|
|
|
end
|
|
|
|
|
2015-11-14 10:31:10 -08:00
|
|
|
dummy = Callbacks()
|
|
|
|
|
2015-11-12 09:23:46 -08:00
|
|
|
function Setter(t)
|
2015-11-12 09:09:14 -08:00
|
|
|
local cb = Callbacks()
|
|
|
|
function cb:on()
|
|
|
|
for addr, value in pairs(t) do
|
|
|
|
addr(value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
cb.hold = cb.on
|
|
|
|
return cb
|
|
|
|
end
|
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
local passives = {}
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
Passive = Class(Callbacks)
|
|
|
|
function Passive:init(...)
|
|
|
|
Callbacks.init(self, ...)
|
|
|
|
table.insert(passives, self)
|
2015-03-04 21:38:30 -08:00
|
|
|
end
|
2015-05-03 16:46:09 -07:00
|
|
|
function Passive:tick()
|
2015-05-26 10:44:34 -07:00
|
|
|
if self.state then self:tick_on() end
|
|
|
|
end
|
|
|
|
function Passive:tick_on()
|
2015-03-04 21:38:30 -08:00
|
|
|
end
|
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
local levitate = Passive()
|
2015-05-26 10:44:34 -07:00
|
|
|
function levitate:tick_on()
|
2015-11-14 17:07:53 -08:00
|
|
|
if bit.band(addrs.buttons(), 0x800) > 0 then
|
2015-05-26 10:44:34 -07:00
|
|
|
self:hold()
|
2015-03-04 21:38:30 -08:00
|
|
|
end
|
|
|
|
end
|
2015-05-03 16:46:09 -07:00
|
|
|
function levitate:hold()
|
|
|
|
addrs.link_actor.y_vel(10)
|
|
|
|
end
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-05-13 11:16:02 -07:00
|
|
|
local supersonic = Passive()
|
2015-05-26 10:44:34 -07:00
|
|
|
function supersonic:tick_on()
|
|
|
|
if bit.band(addrs.buttons(), 0x8000) > 0 then
|
|
|
|
self:hold()
|
2015-05-13 11:16:02 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
function supersonic:hold()
|
|
|
|
addrs.link_actor.lin_vel(20)
|
|
|
|
end
|
|
|
|
|
2015-11-12 09:09:14 -08:00
|
|
|
local infinite_items = Passive()
|
|
|
|
function infinite_items:tick_on()
|
|
|
|
for k, v in pairs(addrs.quantities) do
|
|
|
|
v(69)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-11-14 16:45:36 -08:00
|
|
|
local any_item = Passive()
|
|
|
|
function any_item:tick_on()
|
|
|
|
addrs.buttons_enabled(0)
|
|
|
|
end
|
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
local everything = Callbacks()
|
|
|
|
function everything:on()
|
|
|
|
dofile("oneshot.lua")
|
|
|
|
end
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-11-10 05:59:03 -08:00
|
|
|
local escape_cutscene = Callbacks()
|
|
|
|
function escape_cutscene:on()
|
|
|
|
addrs.cutscene_status_2(3)
|
|
|
|
end
|
|
|
|
|
2015-11-12 09:09:14 -08:00
|
|
|
local soft_reset = Callbacks()
|
|
|
|
function soft_reset:on()
|
|
|
|
addrs.warp_begin(0x14)
|
|
|
|
addrs.warp_destination(0x1C00)
|
2015-11-14 11:22:41 -08:00
|
|
|
addrs.fade_type(0x0B)
|
|
|
|
addrs.entrance_mod_setter(0xFFFA)
|
2015-11-12 09:09:14 -08:00
|
|
|
end
|
|
|
|
|
|
|
|
local save_pos = Callbacks()
|
|
|
|
function save_pos:on()
|
|
|
|
local la = addrs.link_actor
|
2015-11-14 08:57:37 -08:00
|
|
|
saved.pos = {}
|
|
|
|
local pos = saved.pos
|
2015-11-12 09:09:14 -08:00
|
|
|
pos.x = la.x()
|
|
|
|
pos.y = la.y()
|
|
|
|
pos.z = la.z()
|
|
|
|
pos.a = la.angle()
|
|
|
|
-- also save ISG for glitch testers ;)
|
|
|
|
pos.isg = la.sword_active()
|
2015-11-14 08:57:37 -08:00
|
|
|
save()
|
2015-11-12 09:09:14 -08:00
|
|
|
end
|
|
|
|
local load_pos = Callbacks()
|
|
|
|
function load_pos:on()
|
|
|
|
local la = addrs.link_actor
|
2015-11-14 08:57:37 -08:00
|
|
|
local pos = saved.pos
|
|
|
|
if pos == nil then return end
|
2015-11-12 09:09:14 -08:00
|
|
|
la.x(pos.x)
|
|
|
|
la.y(pos.y)
|
|
|
|
la.z(pos.z)
|
|
|
|
-- also set xyz copies so collision detection doesn't interfere
|
|
|
|
la.x_copy(pos.x)
|
|
|
|
la.y_copy(pos.y)
|
|
|
|
la.z_copy(pos.z)
|
|
|
|
la.angle(pos.a)
|
|
|
|
la.sword_active(pos.isg)
|
|
|
|
end
|
|
|
|
|
2015-11-12 09:23:46 -08:00
|
|
|
reload_scene = Callbacks()
|
2015-11-12 09:09:14 -08:00
|
|
|
function reload_scene:on()
|
|
|
|
local ev = addrs.exit_value()
|
|
|
|
addrs.warp_begin(0x14)
|
|
|
|
addrs.warp_destination(ev)
|
|
|
|
end
|
|
|
|
|
|
|
|
local save_scene = Callbacks()
|
|
|
|
function save_scene:on()
|
2015-11-14 08:57:37 -08:00
|
|
|
saved.scene = addrs.exit_value()
|
|
|
|
save()
|
2015-11-12 09:09:14 -08:00
|
|
|
end
|
|
|
|
local load_scene = Callbacks()
|
|
|
|
function load_scene:on()
|
2015-11-14 08:57:37 -08:00
|
|
|
if saved.scene == nil then return end
|
|
|
|
addrs.warp_begin(0x14)
|
|
|
|
addrs.warp_destination(saved.scene)
|
|
|
|
end
|
|
|
|
|
|
|
|
local save_scene_pos = Callbacks()
|
|
|
|
function save_scene_pos:on()
|
|
|
|
saved.scenepos = {}
|
|
|
|
local sp = saved.scenepos
|
|
|
|
sp.scene = addrs.exit_value()
|
|
|
|
local la = addrs.link_actor
|
|
|
|
sp.x = la.x()
|
|
|
|
sp.y = la.y()
|
|
|
|
sp.z = la.z()
|
|
|
|
sp.a = la.angle()
|
|
|
|
--sp.room = la.room_number()
|
|
|
|
save()
|
|
|
|
end
|
|
|
|
local load_scene_pos = Callbacks()
|
|
|
|
function load_scene_pos:on()
|
|
|
|
local sp = saved.scenepos
|
|
|
|
if sp == nil then return end
|
2015-11-12 09:09:14 -08:00
|
|
|
addrs.warp_begin(0x14)
|
2015-11-14 08:57:37 -08:00
|
|
|
addrs.warp_destination(sp.scene)
|
2015-11-14 10:13:54 -08:00
|
|
|
local fade = fades_killed and 0x0B or 0x01
|
|
|
|
addrs.fade_type(fade)
|
2015-11-14 08:57:37 -08:00
|
|
|
-- TODO: add these to address list
|
|
|
|
-- probably the same struct for both MM and OoT
|
|
|
|
AL(0x3CB0, 4)(-4) -- void out type: reload area
|
|
|
|
AL(0x3CB4, 'f')(sp.x)
|
|
|
|
AL(0x3CB8, 'f')(sp.y)
|
|
|
|
AL(0x3CBC, 'f')(sp.z)
|
|
|
|
AL(0x3CC0, 2)(sp.a)
|
|
|
|
AL(0x3CC2, 2)(0x0BFF) -- puts camera behind link instead of at entrance
|
|
|
|
--AL(0x3CC6, 2)(sp.room)
|
2015-11-12 09:09:14 -08:00
|
|
|
end
|
|
|
|
|
2015-11-14 09:20:36 -08:00
|
|
|
local kill_fades = Callbacks()
|
|
|
|
function kill_fades:on()
|
|
|
|
local et = addrs.entrance_table
|
|
|
|
if et == nil then return end
|
|
|
|
local et_size = 1244
|
|
|
|
|
|
|
|
local new_fade = 0x0B -- instant
|
|
|
|
local fades = new_fade*0x80 + new_fade
|
|
|
|
|
|
|
|
for i=0, et_size*4 - 1, 4 do
|
|
|
|
local a = et.addr + i
|
|
|
|
if R1(a) ~= 0x80 then -- don't mess up the pointers
|
|
|
|
-- the lower word works like this:
|
|
|
|
-- mmIIIIIIIOOOOOOO
|
|
|
|
-- m = mode; I = fade in; O = fade out (probably).
|
|
|
|
local mode = bit.band(R2(a+2), 0xC000)
|
|
|
|
W2(a+2, mode + fades)
|
|
|
|
end
|
|
|
|
end
|
2015-11-14 10:13:54 -08:00
|
|
|
|
|
|
|
fades_killed = true
|
2015-11-14 09:20:36 -08:00
|
|
|
end
|
|
|
|
|
2015-11-12 09:09:14 -08:00
|
|
|
local time_menu = Menu{
|
|
|
|
Screen{
|
|
|
|
Text("Day/Time Menu #1/1"),
|
2015-11-14 08:59:30 -08:00
|
|
|
Oneshot("Set Day to Zeroth", Setter{[addrs.day]=0, [addrs.days_elapsed]=0}),
|
|
|
|
Oneshot("Set Day to First", Setter{[addrs.day]=1, [addrs.days_elapsed]=1}),
|
|
|
|
Oneshot("Set Day to Second", Setter{[addrs.day]=2, [addrs.days_elapsed]=2}),
|
|
|
|
Oneshot("Set Day to Final", Setter{[addrs.day]=3, [addrs.days_elapsed]=3}),
|
|
|
|
Oneshot("Set Day to New", Setter{[addrs.day]=4, [addrs.days_elapsed]=4}),
|
2015-11-12 09:09:14 -08:00
|
|
|
Oneshot("Set Time to 06:00", Setter{[addrs.time]=0x4000}),
|
|
|
|
Oneshot("Set Time to 12:00", Setter{[addrs.time]=0x8000}),
|
|
|
|
Oneshot("Set Time to 18:00", Setter{[addrs.time]=0xC000}),
|
|
|
|
Oneshot("Set Time to 00:00", Setter{[addrs.time]=0x0000}),
|
|
|
|
Text(""),
|
|
|
|
Oneshot("Time flow: Fast", Setter{[addrs.time_speed]=2}),
|
|
|
|
Oneshot("Time flow: Normal", Setter{[addrs.time_speed]=0}),
|
|
|
|
Oneshot("Time flow: Slow (iSoT)", Setter{[addrs.time_speed]=-2}),
|
|
|
|
Oneshot("Time flow: Stopped", Setter{[addrs.time_speed]=-3}),
|
|
|
|
Oneshot("Time flow: Backwards", Setter{[addrs.time_speed]=-5}),
|
2015-11-14 19:16:13 -08:00
|
|
|
Oneshot("Disable time flow (Scene)", Setter{[addrs.scene_time_speed]=0}),
|
2015-11-12 09:09:14 -08:00
|
|
|
--Oneshot("Stop time glitch", stop_time),
|
|
|
|
Text(""),
|
|
|
|
Back(),
|
|
|
|
},
|
|
|
|
}
|
2015-11-10 05:59:03 -08:00
|
|
|
|
2015-11-12 09:23:46 -08:00
|
|
|
local warp_menu = require "menus.warp"
|
|
|
|
local progress_menu = require "menus.progress"
|
|
|
|
local playas_menu = require "menus.playas"
|
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
local main_menu = Menu{
|
|
|
|
Screen{
|
2015-05-26 08:43:23 -07:00
|
|
|
Text("Main Menu #1/2"),
|
2015-11-14 17:07:53 -08:00
|
|
|
Toggle("D-Up to Levitate", levitate),
|
2015-05-13 11:16:02 -07:00
|
|
|
Toggle("A to Run Fast", supersonic),
|
2015-11-12 09:09:14 -08:00
|
|
|
Toggle("Infinite Items", infinite_items),
|
2015-11-14 16:45:36 -08:00
|
|
|
Toggle("Use Any Item", any_item),
|
2015-11-12 09:09:14 -08:00
|
|
|
Text(""),
|
|
|
|
Oneshot("100% Items", everything),
|
|
|
|
LinkTo("Set Progress...", progress_menu),
|
|
|
|
Text(""),
|
2015-11-10 05:59:03 -08:00
|
|
|
Oneshot("Escape Cutscene", escape_cutscene),
|
2015-11-12 09:09:14 -08:00
|
|
|
Text(""),
|
2015-11-10 05:59:03 -08:00
|
|
|
LinkTo("Play as...", playas_menu),
|
2015-11-12 09:09:14 -08:00
|
|
|
Oneshot("Kill Link", Setter{[addrs.hearts]=0}),
|
|
|
|
Text(""),
|
2015-05-03 16:46:09 -07:00
|
|
|
Back(),
|
|
|
|
},
|
|
|
|
Screen{
|
2015-05-26 08:43:23 -07:00
|
|
|
Text("Main Menu #2/2"),
|
2015-11-12 09:09:14 -08:00
|
|
|
LinkTo("Warp to...", warp_menu),
|
|
|
|
LinkTo("Set Day/Time...", time_menu),
|
|
|
|
Text(""),
|
|
|
|
Oneshot("Store Position", save_pos),
|
|
|
|
Oneshot("Restore Position", load_pos),
|
|
|
|
Text(""),
|
|
|
|
Oneshot("Reload Scene", reload_scene),
|
|
|
|
Oneshot("Store Scene", save_scene),
|
|
|
|
Oneshot("Restore Scene", load_scene),
|
2015-11-14 08:57:37 -08:00
|
|
|
Text(""),
|
|
|
|
Oneshot("Store Scene & Position", save_scene_pos),
|
|
|
|
Oneshot("Restore Scene & Position", load_scene_pos),
|
2015-11-12 09:09:14 -08:00
|
|
|
Text(""),
|
2015-11-14 09:20:36 -08:00
|
|
|
Oneshot("Kill Transitions", kill_fades),
|
2015-11-12 09:09:14 -08:00
|
|
|
Text(""),
|
2015-11-14 11:22:41 -08:00
|
|
|
Oneshot("Soft Reset (Warp to Title)", soft_reset),
|
|
|
|
Text(""),
|
2015-05-03 16:46:09 -07:00
|
|
|
Back(),
|
|
|
|
},
|
|
|
|
}
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-11-14 16:30:04 -08:00
|
|
|
local input = InputHandler()
|
|
|
|
input = JoyWrapper(input)
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-05-26 08:43:23 -07:00
|
|
|
local handle = MenuHandler(main_menu, T_TL)
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
while mm or oot do
|
|
|
|
local ctrl, pressed = input:update()
|
2015-11-14 16:30:04 -08:00
|
|
|
|
|
|
|
if eat_input then
|
|
|
|
local old_menu = handle.menu
|
|
|
|
handle_eat_input(handle, ctrl, pressed)
|
|
|
|
if alt_input and handle.menu ~= old_menu then
|
|
|
|
run_while_paused = true
|
|
|
|
if handle.menu then client.pause() else client.unpause() end
|
|
|
|
end
|
|
|
|
elseif alt_input then
|
2015-11-14 14:59:37 -08:00
|
|
|
handle_alt_input(handle, ctrl, pressed)
|
|
|
|
else
|
2015-11-14 16:30:04 -08:00
|
|
|
for _, v in ipairs{'left', 'right', 'up', 'down'} do
|
|
|
|
ctrl[v] = ctrl['d_'..v]
|
|
|
|
pressed[v] = pressed['d_'..v]
|
|
|
|
end
|
2015-11-14 14:59:37 -08:00
|
|
|
ctrl.enter = ctrl.L
|
|
|
|
pressed.enter = pressed.L
|
2015-11-14 16:30:04 -08:00
|
|
|
handle:update(ctrl, pressed)
|
2015-11-14 14:59:37 -08:00
|
|
|
end
|
2015-03-04 21:38:30 -08:00
|
|
|
|
2015-05-03 16:46:09 -07:00
|
|
|
for i, passive in ipairs(passives) do
|
|
|
|
passive:tick()
|
2015-03-04 21:38:30 -08:00
|
|
|
end
|
|
|
|
|
2015-11-14 13:46:04 -08:00
|
|
|
if run_while_paused then
|
|
|
|
emu.yield()
|
|
|
|
gui.cleartext()
|
|
|
|
else
|
|
|
|
emu.frameadvance()
|
|
|
|
end
|
2015-03-04 21:38:30 -08:00
|
|
|
end
|