diff --git a/Lua/addrs/M/common.lua b/Lua/addrs/M/common.lua index f6bf5f8..136a00b 100755 --- a/Lua/addrs/M/common.lua +++ b/Lua/addrs/M/common.lua @@ -109,8 +109,9 @@ return { day_night = AL(0x10, 4), time_speed = AL(0x14, 4), day = AL(0x18, 4), - day_again = AL(0x1C, 4), + days_elapsed = AL(0x1C, 4), transformation = AL(0x20, 1), + have_tatl = AL(0x22, 1), owl_save = AL(0x23, 1), -- "zeroth day" effect ZELDA3 = AL(0x24, 6), sot_count = AL(0x2A, 2), diff --git a/Lua/cheat menu.lua b/Lua/cheat menu.lua index 1779947..087983e 100755 --- a/Lua/cheat menu.lua +++ b/Lua/cheat menu.lua @@ -4,11 +4,25 @@ require "addrs.init" require "classes" require "menu classes" require "messages" +require "flag manager" local warp_menu = require "warp menu" +-- TODO: make OoT versions for most of these menus + local dummy = Callbacks() +local function Setter(t) + local cb = Callbacks() + function cb:on() + for addr, value in pairs(t) do + addr(value) + end + end + cb.hold = cb.on + return cb +end + local passives = {} Passive = Class(Callbacks) @@ -42,6 +56,13 @@ function supersonic:hold() addrs.link_actor.lin_vel(20) end +local infinite_items = Passive() +function infinite_items:tick_on() + for k, v in pairs(addrs.quantities) do + v(69) + end +end + local everything = Callbacks() function everything:on() dofile("oneshot.lua") @@ -52,11 +73,6 @@ function escape_cutscene:on() addrs.cutscene_status_2(3) end -local self_destruct = Callbacks() -function self_destruct:on() - addrs.hearts(0) -end - local playas_child = Passive() function playas_child:tick_on() addrs.age_modifier_global(1) @@ -93,15 +109,120 @@ function playas_fd:tick_on() addrs.transformation(0) end +local soft_reset = Callbacks() +function soft_reset:on() + addrs.warp_begin(0x14) + addrs.warp_destination(0x1C00) + AL(0x3F48, 2)(0xFFFA) -- doesn't quite work +end + +local pos = {} +local save_pos = Callbacks() +function save_pos:on() + local la = addrs.link_actor + 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() +end +local load_pos = Callbacks() +function load_pos:on() + local la = addrs.link_actor + 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 + +local reload_scene = Callbacks() +function reload_scene:on() + local ev = addrs.exit_value() + addrs.warp_begin(0x14) + addrs.warp_destination(ev) +end + +local saved_scene = nil +local save_scene = Callbacks() +function save_scene:on() + saved_scene = addrs.exit_value() +end +local load_scene = Callbacks() +function load_scene:on() + if saved_scene == nil then return end + addrs.warp_begin(0x14) + addrs.warp_destination(saved_scene) +end + +local first_cycle = Callbacks() +function first_cycle:on() + addrs.warp_begin(0x14) + addrs.warp_destination(0xC000) + addrs.transformation(3) -- deku + addrs.day(0) + addrs.days_elapsed(0) + addrs.time(0x3FD2) -- default time + addrs.day_night(1) + addrs.time_speed(0) + addrs.intro_completed(0) + addrs.have_tatl(1) + addrs.sot_count(0) + -- remove ocarina so time passes at first-cycle speed, among other things. + -- if really you need your ocarina, just put it on a C button beforehand. + addrs.inventory.ocarina(0xFF) + + -- happy mask salesman talking at door + scene_flag_reset(0x63, 1, 0) + -- bombers ladder balloon + scene_flag_reset(0x29, 1, 1) + -- other things to consider resetting: + -- skull kid stuff + -- deed trading quest entirely + -- bombers stuff (they don't let you do it twice) + -- ability to learn song of healing + get deku mask <-- + -- "oh no! the great fairy!" + + -- moon's tear has landed + event_flag_reset(74, 5) + event_flag_reset(74, 7) + -- moon's tear acquired + event_flag_reset(74, 6) + -- skullkid jumped off clock tower thru telescope + event_flag_reset(12, 2) + -- clock town fairy acquired + event_flag_reset(8, 7) + -- deku merchant has landed) + event_flag_reset(73, 2) + -- Talked to Town Scrub once as Deku + event_flag_reset(86, 2) + -- similar to above? + event_flag_reset(17, 5) + -- Obtained Land Title Deed + event_flag_reset(17, 7) + -- Tatl talks about clock tower entrance + event_flag_reset(79, 4) + -- Clock Tower is open? + event_flag_reset( 8, 6) + -- Tatl telling Link to hurry at Clock Tower + event_flag_reset(88, 5) +end + local playas_group = {} local playas_mm_group = {} - local playas_menu = oot and Menu{ Screen{ Text("Play as..."), Radio("Default", playas_group, dummy), Radio("Child Link", playas_group, playas_child), Radio("Adult Link", playas_group, playas_adult), + Text(""), + Oneshot("Reload Scene", reload_scene), Back(), }, } or Menu{ @@ -113,28 +234,99 @@ local playas_menu = oot and Menu{ Radio("Goron Link", playas_mm_group, playas_goron), Radio("Zora Link", playas_mm_group, playas_zora), Radio("Fierce Deity", playas_mm_group, playas_fd), + Text(""), + Oneshot("Reload Scene", reload_scene), Back(), }, } +local progress_menu = Menu{ + Screen{ + Text("Progress Menu #1/1"), + Oneshot("Setup First Cycle", first_cycle), + Text(""), + Back(), + }, +} + +local function gen_set_day(x) + local cb = Callbacks() + function cb:on() + addrs.day(x) + addrs.days_elapsed(x) + end + return cb +end + +local function gen_set_time(x) + local cb = Callbacks() + function cb:on() + addrs.time(x) + end + return cb +end + +local time_menu = Menu{ + Screen{ + Text("Day/Time Menu #1/1"), + Oneshot("Set Day to 0", Setter{[addrs.day]=0, [addrs.days_elapsed]=0}), + Oneshot("Set Day to 1", Setter{[addrs.day]=1, [addrs.days_elapsed]=1}), + Oneshot("Set Day to 2", Setter{[addrs.day]=2, [addrs.days_elapsed]=2}), + Oneshot("Set Day to 3", Setter{[addrs.day]=3, [addrs.days_elapsed]=3}), + Oneshot("Set Day to 4", Setter{[addrs.day]=4, [addrs.days_elapsed]=4}), + 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}), + -- TODO: make version-agnostic + Oneshot("Disable time flow (Scene)", Setter{[A(0x382502, 2)]=0}), + --Oneshot("Stop time glitch", stop_time), + Text(""), + Back(), + }, +} local main_menu = Menu{ + -- TODO: seperator item that's just a few underscores with half height Screen{ Text("Main Menu #1/2"), --Toggle("L to Levitate", levitate), Toggle("A to Run Fast", supersonic), Hold("Levitate", levitate), - Oneshot("100%", everything), + Toggle("Infinite Items", infinite_items), + Text(""), + Oneshot("100% Items", everything), + LinkTo("Set Progress...", progress_menu), + Text(""), Oneshot("Escape Cutscene", escape_cutscene), + Text(""), LinkTo("Play as...", playas_menu), - LinkTo("Warp to...", warp_menu), + Oneshot("Kill Link", Setter{[addrs.hearts]=0}), + Text(""), Back(), }, Screen{ Text("Main Menu #2/2"), - Oneshot("Kill Link", self_destruct), - Flags("some flags"), - Text("k"), + LinkTo("Warp to...", warp_menu), + LinkTo("Set Day/Time...", time_menu), + Text(""), + --Flags("some flags"), + 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), + -- TODO: can probably save/load position+scene using void out mechanics + Text(""), + Oneshot("Soft Reset (Warp to Title)", soft_reset), + Text(""), Back(), }, } diff --git a/Lua/flag manager.lua b/Lua/flag manager.lua new file mode 100644 index 0000000..d19a9b7 --- /dev/null +++ b/Lua/flag manager.lua @@ -0,0 +1,40 @@ +function scene_flag_get_bb(scene, word, bit_) + local byte = scene*0x14 + word*4 + math.floor(3 - bit_/8) + byte = byte + addrs.scene_flags_ingame.addr + local bitmask = bit.lshift(1, bit_ % 8) + return byte, bitmask +end + +function scene_flag_get(scene, word, bit_) + local byte, bitmask = scene_flag_get_bb(scene, word, bit_) + return bit.band(R1(byte), bitmask) ~= 0 +end +-- TODO: check if current scene is scene id +-- if it is, adjust scene_flag_current_x so it doesn't overwrite ingame flags +function scene_flag_reset(scene, word, bit_) + local byte, bitmask = scene_flag_get_bb(scene, word, bit_) + W1(byte, bit.band(R1(byte), 0xFF - bitmask)) +end +function scene_flag_set(scene, word, bit_) + local byte, bitmask = scene_flag_get_bb(scene, word, bit_) + W1(byte, bit.bor(R1(byte), bitmask)) +end + +function event_flag_get_bb(byte, bit_) + byte = byte + addrs.week_event_reg.addr + local bitmask = bit.lshift(1, bit_ % 8) + return byte, bitmask +end + +function event_flag_get(byte, bit_) + local byte, bitmask = event_flag_get_bb(byte, bit_) + return bit.band(R1(byte), bitmask) ~= 0 +end +function event_flag_reset(byte, bit_) + local byte, bitmask = event_flag_get_bb(byte, bit_) + W1(byte, bit.band(R1(byte), 0xFF - bitmask)) +end +function event_flag_set(byte, bit_) + local byte, bitmask = event_flag_get_bb(byte, bit_) + W1(byte, bit.bor(R1(byte), bitmask)) +end diff --git a/Lua/warp menu.lua b/Lua/warp menu.lua index 6b9a576..1f76d55 100644 --- a/Lua/warp menu.lua +++ b/Lua/warp menu.lua @@ -148,7 +148,9 @@ for si=0x00,0x7F do entrances = entrance_names[i] scene_name = scene_names[i] end + ins(entrance_items, Text( ("Warp to %s"):format(scene_name) )) + for j=0,32 do local ename = entrances[j] if ename == nil then @@ -158,16 +160,18 @@ for si=0x00,0x7F do local callback = Callbacks() function callback:on() addrs.warp_destination(make_exit_value(si,j,0)) - addrs.warp_begin(1) + addrs.warp_begin(0x14) end ins(entrance_items, Oneshot(ename, callback)) end + ins(entrance_items, Text("")) ins(entrance_items, Text("Cutscenes... (TODO)")) ins(entrance_items, Text("")) ins(entrance_items, Back()) local entrance_menu = Menu{Screen(entrance_items)} ins(scenes_pages[page], LinkTo(scene_name, entrance_menu)) + if si % 16 == 15 then ins(scenes_pages[page], Text("")) ins(scenes_pages[page], Back())