diff --git a/Lua/A EU10.lua b/Lua/A EU10.lua new file mode 100755 index 0000000..85c303c --- /dev/null +++ b/Lua/A EU10.lua @@ -0,0 +1,12 @@ +local link = 0x1E6B50 +local global = 0x3DDFC0 +local actor = 0x3F7250 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A EU11.lua b/Lua/A EU11.lua new file mode 100755 index 0000000..2cc4b43 --- /dev/null +++ b/Lua/A EU11.lua @@ -0,0 +1,12 @@ +local link = 0x1E6EF0 +local global = 0x3DE360 +local actor = 0x3F75F0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A EUDB.lua b/Lua/A EUDB.lua new file mode 100755 index 0000000..d9fa2ab --- /dev/null +++ b/Lua/A EUDB.lua @@ -0,0 +1,48 @@ +local link = 0x23F790 +local global = 0x448700 +local actor = 0x4619D0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { + checksum = AL(0x100A, 2), + disable_pause = AL(0x100D, 1), + hookshot_ba = AL(0x100E, 1), + disable_c_buttons_2 = AL(0x100F, 1), + disable_items = AL(0x1010, 1), + rock_sirloin = AL(0x1014, 1), + sword_disabler = AL(0x1015, 1), + bubble_timer = AL(0x1016, 2), + rupee_accumulator = AL(0x1018, 2), + spring_water_timers = AL(0x1020, 0xC0), + spring_water_time_1 = AL(0x1020, 0x20), + spring_water_time_2 = AL(0x1040, 0x20), + spring_water_time_3 = AL(0x1060, 0x20), + spring_water_time_4 = AL(0x1080, 0x20), + spring_water_time_5 = AL(0x10A0, 0x20), + spring_water_time_6 = AL(0x10C0, 0x20), + pictograph_picture = AL(0x10E0, 0x2BC0), + title_screen_mod = AL(0x3CA8, 4), + entrance_mod = AL(0x3CAC, 4), + timer_crap = AL(0x3DD0, 4), + timer_x = AL(0x3EFA, 2), + timer_y = AL(0x3F08, 2), + buttons_enabled = AL(0x3F18, 4), + magic_modifier = AL(0x3F28, 4), + magic_max = AL(0x3F2E, 2), + weird_a_graphic = AL(0x3F42, 1), + target_style = AL(0x3F45, 1), + music_mod = AL(0x3F46, 2), + entrance_mod_setter = AL(0x3F4A, 2), + title_screen_thing = AL(0x3F4C, 1), + transition_mod = AL(0x3F55, 2), + suns_song_effect = AL(0x3F58, 2), + health_mod = AL(0x3F5A, 2), + screen_scale_enable = AL(0x3F60, 1), + screen_scale = AL(0x3F64, 'f'), + scene_flags_ingame = AL(0x3F68, 0x960), +}) diff --git a/Lua/A EUGC.lua b/Lua/A EUGC.lua new file mode 100755 index 0000000..c246348 --- /dev/null +++ b/Lua/A EUGC.lua @@ -0,0 +1,12 @@ +local link = 0x1E5480 +local global = 0x378EB0 +local actor = 0x392140 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A JP10.lua b/Lua/A JP10.lua new file mode 100755 index 0000000..b63828d --- /dev/null +++ b/Lua/A JP10.lua @@ -0,0 +1,64 @@ +local link = 0x1EF460 +local global = 0x3E6CF0 +local actor = 0x3FFFA0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { + checksum = AL(0x138E, 2), + --disable_pause = AL(, 1), + --hookshot_ba = AL(, 1), + --disable_c_buttons_2 = AL(, 1), + --disable_items = AL(, 1), + --rock_sirloin = AL(, 1), + --sword_disabler = AL(, 1), + --bubble_timer = AL(, 2), + rupee_accumulator = AL(0x4078, 2), + spring_water_timers = AL(0x41D8, 0xC0), + spring_water_time_1 = AL(0x41F8, 0x20), + spring_water_time_2 = AL(0x4218, 0x20), + spring_water_time_3 = AL(0x4238, 0x20), + spring_water_time_4 = AL(0x4258, 0x20), + spring_water_time_5 = AL(0x4278, 0x20), + spring_water_time_6 = AL(0x4298, 0x20), + pictograph_picture = AL(0x1390, 0x2BC0), + title_screen_mod = AL(0x3F5C, 4), + --entrance_mod = AL(, 4), + timer_crap = AL(0x408C, 4), + timer_x = AL(0x41B8, 2), + timer_y = AL(0x41C6, 2), + buttons_enabled = AL(0x429C, 4), + magic_modifier = AL(0x42AC, 4), + magic_max = AL(0x42B2, 2), + weird_a_graphic = AL(0x42CE, 1), + --target_style = AL(, 1), + --music_mod = AL(, 2), + --entrance_mod_setter = AL(, 2), + title_screen_thing = AL(0x42D8, 1), + --transition_mod = AL(, 2), + suns_song_effect = AL(0x42E4, 2), + health_mod = AL(0x42E6, 2), + screen_scale_enable = AL(0x42EC, 1), + screen_scale = AL(0x42F0, 'f'), + --scene_flags_ingame = AL(, 0x960), + + --random = A(, 4), + --visibility = A(, 2), + stored_epona = A(0x1B892F, 1), + stored_song = A(0x1C18ED, 1), + --buttons_3 = A(, 2), + --buttons_4 = A(, 2), + + --text_open = A(, 1), + --text_status = A(, 1), + room_number = A(0x3FF3B0, 1), + room_ptr = A(0x3FF3BC, 4), + --actor_disable = A(, 2), + --warp_begin = A(, 1), + --screen_dim = A(, 1), + --warp_destination = A(, 2), +}) diff --git a/Lua/A JP11.lua b/Lua/A JP11.lua new file mode 100755 index 0000000..b1b68f4 --- /dev/null +++ b/Lua/A JP11.lua @@ -0,0 +1,12 @@ +local link = 0x1EF710 +local global = 0x3E6FB0 +local actor = 0x400260 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A JPGC.lua b/Lua/A JPGC.lua new file mode 100755 index 0000000..2a5e69c --- /dev/null +++ b/Lua/A JPGC.lua @@ -0,0 +1,12 @@ +local link = 0x1ED820 +local global = 0x381250 +local actor = 0x39A4E0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A US10.lua b/Lua/A US10.lua new file mode 100755 index 0000000..34f9573 --- /dev/null +++ b/Lua/A US10.lua @@ -0,0 +1,64 @@ +local link = 0x1EF670 +local global = 0x3E6B20 +local actor = 0x3FFDB0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { + checksum = AL(0x100A, 2), + disable_pause = AL(0x100D, 1), + hookshot_ba = AL(0x100E, 1), + disable_c_buttons_2 = AL(0x100F, 1), + disable_items = AL(0x1010, 1), + rock_sirloin = AL(0x1014, 1), + sword_disabler = AL(0x1015, 1), + bubble_timer = AL(0x1016, 2), + rupee_accumulator = AL(0x1018, 2), + spring_water_timers = AL(0x1020, 0xC0), + spring_water_time_1 = AL(0x1020, 0x20), + spring_water_time_2 = AL(0x1040, 0x20), + spring_water_time_3 = AL(0x1060, 0x20), + spring_water_time_4 = AL(0x1080, 0x20), + spring_water_time_5 = AL(0x10A0, 0x20), + spring_water_time_6 = AL(0x10C0, 0x20), + pictograph_picture = AL(0x10E0, 0x2BC0), + title_screen_mod = AL(0x3CA8, 4), + entrance_mod = AL(0x3CAC, 4), + timer_crap = AL(0x3DD0, 4), + timer_x = AL(0x3EFA, 2), + timer_y = AL(0x3F08, 2), + buttons_enabled = AL(0x3F18, 4), + magic_modifier = AL(0x3F28, 4), + magic_max = AL(0x3F2E, 2), + weird_a_graphic = AL(0x3F42, 1), + target_style = AL(0x3F45, 1), + music_mod = AL(0x3F46, 2), + entrance_mod_setter = AL(0x3F4A, 2), + title_screen_thing = AL(0x3F4C, 1), + transition_mod = AL(0x3F55, 2), + suns_song_effect = AL(0x3F58, 2), + health_mod = AL(0x3F5A, 2), + screen_scale_enable = AL(0x3F60, 1), + screen_scale = AL(0x3F64, 'f'), + scene_flags_ingame = AL(0x3F68, 0x960), + + random = A(0x097530, 4), + visibility = A(0x166118, 2), + stored_epona = A(0x1BDA9F, 1), + stored_song = A(0x1C6A7D, 1), + buttons_3 = A(0x1FB870, 2), + buttons_4 = A(0x1FB876, 2), + + text_open = A(0x3FD33B, 1), + text_status = A(0x3FD34A, 1), + room_number = A(0x3FF200, 1), + room_ptr = A(0x3FF20C, 4), + actor_disable = A(0x3FF366, 2), + warp_begin = A(0x3FF395, 1), + screen_dim = A(0x3FF397, 1), + warp_destination = A(0x3FF39A, 2), +}) diff --git a/Lua/A USDE.lua b/Lua/A USDE.lua new file mode 100755 index 0000000..b5764be --- /dev/null +++ b/Lua/A USDE.lua @@ -0,0 +1,12 @@ +local link = 0x1EEE80 +local global = 0x3E63B0 +local actor = 0x3FF680 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A USGC.lua b/Lua/A USGC.lua new file mode 100755 index 0000000..165333f --- /dev/null +++ b/Lua/A USGC.lua @@ -0,0 +1,12 @@ +local link = 0x1ED830 +local global = 0x381260 +local actor = 0x39A4F0 + +function AL(a, s) return A(link+a, s) end +function AG(a, s) return A(global+a, s) end +function AA(a, s) return A(actor+a, s) end + +local common = dofile("A common.lua") + +return merge(common, { +}) diff --git a/Lua/A common.lua b/Lua/A common.lua new file mode 100755 index 0000000..8ca9274 --- /dev/null +++ b/Lua/A common.lua @@ -0,0 +1,187 @@ +-- version-agnostic addresses +function merge(t1, t2) + for k, v in pairs(t1) do + t2[k] = v + end + return t2 +end + +function Actor(addr) + local function AA(a, s) return A(addr+a, s) end + return { + number = AA(0x0, 2), + type = AA(0x2, 1), + flags = AA(0x4, 4), + x_copy = AA(0x8, 'f'), + y_copy = AA(0xC, 'f'), + z_copy = AA(0x10, 'f'), + x = AA(0x24, 'f'), + y = AA(0x28, 'f'), + z = AA(0x2C, 'f'), + angle_old = AA(0x4A, 2), + x_scale = AA(0x58, 'f'), + y_scale = AA(0x5C, 'f'), + z_scale = AA(0x60, 'f'), + x_vel = AA(0x64, 'f'), + y_vel = AA(0x68, 'f'), + z_vel = AA(0x6C, 'f'), + lin_vel_old = AA(0x70, 'f'), + ground_y = AA(0x88, 'f'), + angle = AA(0xBA, 2), + foot_left_x = AA(0xD4, 'f'), + foot_left_y = AA(0xD8, 'f'), + foot_left_z = AA(0xDC, 'f'), + foot_right_x = AA(0xE0, 'f'), + foot_right_y = AA(0xE4, 'f'), + foot_right_z = AA(0xE8, 'f'), + camera_rel_x = AA(0xEC, 'f'), + camera_rel_y = AA(0xF0, 'f'), + camera_rel_z = AA(0xF4, 'f'), + unknown_z = AA(0xF8, 'f'), + x_old = AA(0x108, 'f'), + y_old = AA(0x10C, 'f'), + z_old = AA(0x108, 'f'), + prev = AA(0x128, 4), + next = AA(0x12C, 4), + } +end + +return { + link = A(link, 0x4000), + area_mod = AL(0x02, 2), + cutscene_status = AL(0x0A, 2), + time = AL(0x0C, 2), + time_speed = AL(0x16, 2), + day = AL(0x1B, 1), + transformation = AL(0x20, 1), + zeroth_day = AL(0x23, 1), + sot_count = AL(0x2A, 2), + name = AL(0x2C, 8), + max_hearts = AL(0x34, 2), + hearts = AL(0x36, 2), + magic_1 = AL(0x39, 1), + rupees = AL(0x3A, 2), + magic_2 = AL(0x40, 2), + owls_hit = AL(0x46, 2), + sword_shield = AL(0x6D, 1), + inventory_items = AL(0x70, 24), + inventory_masks = AL(0x88, 24), + inventory_counts = AL(0xA0, 24), + wallet_flags = AL(0xBA, 1), + quiver_bag = AL(0xBB, 1), + status_items = AL(0xBD, 3), + scene_flags_save = AL(0x470, 0x960), + area_map = AL(0xEB2, 1), + banked_rupees = AL(0xEDE, 2), + archery = AL(0xF00, 1), + chateau_romani = AL(0xF06, 1), + disable_c_buttons = AL(0xF4A, 1), + sword_disable_c = AL(0xF52, 1), + map_visited = AL(0xF5E, 2), + map_visible = AL(0xF62, 2), + + inventory = { + b_button = AL(0x4C, 1), + + ocarina = AL(0x70, 1), + bow = AL(0x71, 1), + fire_arrows = AL(0x72, 1), + ice_arrows = AL(0x73, 1), + light_arrows = AL(0x74, 1), + event_1 = AL(0x75, 1), + bombs = AL(0x76, 1), + bombchu = AL(0x77, 1), + deku_stick = AL(0x78, 1), + deku_nut = AL(0x79, 1), + magic_beans = AL(0x7A, 1), + event_2 = AL(0x7B, 1), + powder_keg = AL(0x7C, 1), + pictograph = AL(0x7D, 1), + lens_of_truth = AL(0x7E, 1), + hookshot = AL(0x7F, 1), + fairy_sword = AL(0x80, 1), + event_3 = AL(0x81, 1), + bottle_1 = AL(0x82, 1), + bottle_2 = AL(0x83, 1), + bottle_3 = AL(0x84, 1), + bottle_4 = AL(0x85, 1), + bottle_5 = AL(0x86, 1), + bottle_6 = AL(0x87, 1), + }, + masks = { + postman = AL(0x88, 1), + all_night = AL(0x89, 1), + blast = AL(0x8A, 1), + stone = AL(0x8B, 1), + great_fairy = AL(0x8C, 1), + deku = AL(0x8D, 1), + keaton = AL(0x8E, 1), + bremen = AL(0x8F, 1), + bunny = AL(0x90, 1), + don_gero = AL(0x91, 1), + scents = AL(0x92, 1), + goron = AL(0x93, 1), + romani = AL(0x94, 1), + troupe_leader = AL(0x95, 1), + kafei = AL(0x96, 1), + couples = AL(0x97, 1), + truth = AL(0x98, 1), + zora = AL(0x99, 1), + kamaro = AL(0x9A, 1), + gibdo = AL(0x9B, 1), + garos = AL(0x9C, 1), + captains = AL(0x9D, 1), + giants = AL(0x9E, 1), + fierce_deity = AL(0x9F, 1), + }, + counts = { + arrows = AL(0xA1, 1), + bombs = AL(0xA6, 1), + bombchu = AL(0xA7, 1), + sticks = AL(0xA8, 1), + nuts = AL(0xA9, 1), + beans = AL(0xAA, 1), + kegs = AL(0xAC, 1), + }, + + buttons_1 = AG(0x1A, 1), + buttons_2 = AG(0x1B, 1), + framerate_limiter = AG(0xA2, 1), + camera_target = AG(0x2B0, 4), + actor_count_0 = AG(0x1CB0, 4), + actor_first_0 = AG(0x1CB4, 4), + actor_count_1 = AG(0x1CBC, 4), + actor_first_1 = AG(0x1CC0, 4), + actor_count_2 = AG(0x1CC8, 4), + actor_first_2 = AG(0x1CCC, 4), + actor_count_3 = AG(0x1CD4, 4), + actor_first_3 = AG(0x1CD8, 4), + actor_count_4 = AG(0x1CE0, 4), + actor_first_4 = AG(0x1CE4, 4), + actor_count_5 = AG(0x1CEC, 4), + actor_first_5 = AG(0x1CF0, 4), + actor_count_6 = AG(0x1CF8, 4), + actor_first_6 = AG(0x1CFC, 4), + actor_count_7 = AG(0x1D04, 4), + actor_first_7 = AG(0x1D08, 4), + actor_count_8 = AG(0x1D10, 4), + actor_first_8 = AG(0x1D14, 4), + actor_count_9 = AG(0x1D1C, 4), + actor_first_9 = AG(0x1D20, 4), + actor_count_10 = AG(0x1D28, 4), + actor_first_10 = AG(0x1D2C, 4), + actor_count_11 = AG(0x1D34, 4), + actor_first_11 = AG(0x1D38, 4), + bomb_counter = AG(0x1CD4, 1), + z_cursor_actor = AG(0x1DF8, 4), + z_target_actor = AG(0x1DFC, 4), + + link_actor = merge(Actor(AA(0,0).addr), { + item_in_hand = AA(0x148, 1), + animation_id = AA(0x24A, 2), + link_flags = AA(0xA6C, 0xC), + lin_vel = AA(0xAD0, 'f'), + movement_angle = AA(0xAD4, 2), + active_sword = AA(0xADB, 1), + }), +} diff --git a/Lua/actor change.lua b/Lua/actor change.lua new file mode 100755 index 0000000..1481bae --- /dev/null +++ b/Lua/actor change.lua @@ -0,0 +1,95 @@ +require "boilerplate" +local addrs = require "addrs" + +local actor_type = 2 +local actor_index = 0 + +local pressed = {} +local old_ctrl = {} + +function get_actor_count(i) + return R4(addrs.actor_count_0.addr + i*0xC) +end + +function get_first_actor(i) + return bit.band(R4(addrs.actor_first_0.addr + i*0xC), 0x7FFFFFFF) +end + +function get_next_actor(a) + return bit.band(R4(a + 0x12C), 0x7FFFFFFF) +end + +function T(x, y, s, color, pos) + color = color or "white" + pos = pos or "bottomright" + gui.text(10*x + 2, 16*y + 4, s, nil, color, pos) +end + +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 + + if pressed.left then + actor_index = actor_index - 1 + end + if pressed.right then + actor_index = actor_index + 1 + end + if pressed.down then + -- follow Link again + actor_type = 2 + actor_index = 0 + end + + local any = 0 + for i = 0, 11 do + local count = get_actor_count(i) + T(0, 11 - i, ("#%2i: %2i"):format(i, count), "white", "bottomleft") + any = any + count + end + + local actor_count = get_actor_count(actor_type) + if any > 0 then + while actor_index < 0 do + actor_type = (actor_type - 1) % 12 + actor_count = get_actor_count(actor_type) + actor_index = actor_count - 1 + end + while actor_index >= actor_count do + actor_type = (actor_type + 1) % 12 + actor_count = get_actor_count(actor_type) + actor_index = 0 + end + + local actor = get_first_actor(actor_type) + T(0, 2, ('type: %02X'):format(actor_type)) + T(0, 1, ('index: %02X'):format(actor_index)) + T(0, 0, ('count: %02X'):format(actor_count)) + if actor_index > 0 then + for i = 0, actor_index do + actor = get_next_actor(actor) + if actor == 0 then + T(0, 3, "no actor found", "yellow") + break + end + end + end + if actor ~= 0 then + addrs.camera_target(0x80000000 + actor) + end + end + + old_ctrl = ctrl + emu.yield() +end diff --git a/Lua/addrs.lua b/Lua/addrs.lua new file mode 100755 index 0000000..e057327 --- /dev/null +++ b/Lua/addrs.lua @@ -0,0 +1,19 @@ +require "boilerplate" + +local versions = { + ['D6133ACE5AFAA0882CF214CF88DABA39E266C078'] = require "A US10", + ['2F0744F2422B0421697A74B305CB1EF27041AB11'] = require "A USDE", + ['9743AA026E9269B339EB0E3044CD5830A440C1FD'] = require "A USGC", + ['C04599CDAFEE1C84A7AF9A71DF68F139179ADA84'] = require "A EU10", + ['BB4E4757D10727C7584C59C1F2E5F44196E9C293'] = require "A EU11", + ['B38B71D2961DFFB523020A67F4807A4B704E347A'] = require "A EUDB", + ['A849A65E56D57D4DD98B550524150F898DF90A9F'] = require "A EUGC", + ['5FB2301AACBF85278AF30DCA3E4194AD48599E36'] = require "A JP10", + ['41FDB879AB422EC158B4EAFEA69087F255EA8589'] = require "A JP11", + ['1438FD501E3E5B25461770AF88C02AB1E41D3A7E'] = require "A JPGC", +} + +local hash = gameinfo.getromhash() +local addrs = versions[hash] + +return addrs diff --git a/Lua/boilerplate.lua b/Lua/boilerplate.lua new file mode 100755 index 0000000..fb1bf02 --- /dev/null +++ b/Lua/boilerplate.lua @@ -0,0 +1,65 @@ +-- boilerplate convenience functions +-- TODO: respect little endian consoles too + +local mm = mainmemory + +R1 = mm.readbyte +R2 = mm.read_u16_be +R3 = mm.read_u24_be +R4 = mm.read_u32_be +RF = function(addr) return mm.readfloat(addr, true) end + +W1 = mm.writebyte +W2 = mm.write_u16_be +W3 = mm.write_u24_be +W4 = mm.write_u32_be +WF = function(addr, value) mm.writefloat(addr, value, true) end + +local readers = { + [1] = R1, + [2] = R2, + [3] = R3, + [4] = R4, + ['f'] = RF, +} + +local writers = { + [1] = W1, + [2] = W2, + [3] = W3, + [4] = W4, + ['f'] = WF, +} + +local mt = { + __call = function(self, value) + return value and self.write(self.addr, value) or self.read(self.addr) + end +} + +function A(addr, atype) + return setmetatable({ + addr=addr, + type=atype, + read=readers[atype], + write=writers[atype] + }, mt) +end + +--[[ +-- now we can just write: +handle = A(0x123456, 1) +print(handle()) -- get 1 byte at address +handle(0xFF) -- set 1 byte at address + +-- or just: +A(0x123456, 1)(0xFF) -- set address value + +-- and taking advantage of A returning a table and not just a function: +A(handle.addr + 1, handle.type)(0x00) -- set the byte after our address + +-- this doesn't limit us to just the type we initially specified. eg: +A(handle.addr, 2)(0x1234) -- set 2 bytes as opposed to our original 1 +--]] + +return A diff --git a/Lua/cheat menu.lua b/Lua/cheat menu.lua new file mode 100755 index 0000000..77f7abf --- /dev/null +++ b/Lua/cheat menu.lua @@ -0,0 +1,234 @@ +require "boilerplate" +local addrs = require "addrs" + +local close = {text="close", type="close"} + +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, + }, + { + 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, + }, + active = 1, +} + +local active_menu = nil + +local menu_state = { + levitate = false, +} + +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) + local inv = addrs.inventory + local masks = addrs.masks + local counts = addrs.counts + --addrs.target_style (1) + --addrs.buttons_enabled (0) + --addrs.infinite_sword(1) + addrs.zeroth_day (1) + addrs.sot_count (0) + addrs.bubble_timer (0) + -- + addrs.sword_shield (0x23) + addrs.quiver_bag (0x1B) + addrs.hearts (16*20) + addrs.max_hearts (16*20) + addrs.owls_hit (0xFFFF) + addrs.map_visible (0xFFFF) + addrs.map_visited (0xFFFF) + addrs.rupees (0xFFFF) + addrs.magic_1 (0x60) -- fixme + addrs.magic_2 (0x101) -- fixme + addrs.status_items (0xFFFFFF) + inv.b_button (0x4F) + inv.ocarina (0x00) + inv.bow (0x01) + inv.fire_arrows (0x02) + inv.ice_arrows (0x03) + inv.light_arrows (0x04) + inv.bombs (0x06) + inv.bombchu (0x07) + inv.deku_stick (0x08) + inv.deku_nut (0x09) + inv.magic_beans (0x0A) + inv.powder_keg (0x0C) + inv.pictograph (0x0D) + inv.lens_of_truth (0x0E) + inv.hookshot (0x0F) + inv.fairy_sword (0x10) + inv.bottle_1 (0x12) + inv.bottle_2 (0x1B) + inv.bottle_3 (0x1A) + inv.bottle_4 (0x18) + inv.bottle_5 (0x16) + inv.bottle_6 (0x25) + --addrs.event_1 (0x05) + --addrs.event_2 (0x0B) + --addrs.event_3 (0x11) + masks.postman (0x3E) + masks.all_night (0x38) + masks.blast (0x47) + masks.stone (0x45) + masks.great_fairy (0x40) + masks.deku (0x32) + masks.keaton (0x3A) + masks.bremen (0x46) + masks.bunny (0x39) + masks.don_gero (0x42) + masks.scents (0x48) + masks.goron (0x33) + masks.romani (0x3C) + masks.troupe_leader (0x3D) + masks.kafei (0x37) + masks.couples (0x3F) + masks.truth (0x36) + masks.zora (0x34) + masks.kamaro (0x43) + masks.gibdo (0x41) + masks.garos (0x3B) + masks.captains (0x44) + masks.giants (0x49) + masks.fierce_deity (0x35) + counts.arrows (69) + counts.bombs (69) + counts.bombchu (69) + counts.sticks (69) + counts.nuts (69) + counts.beans (69) + counts.kegs (69) + end, +} + +function T(x, y, s, color) + color = color or "white" + gui.text(10*x + 2, 16*y + 4, s, nil, color, "bottomright") +end + +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) + 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 + end + 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) + 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() +end diff --git a/Lua/movement tests.lua b/Lua/movement tests.lua new file mode 100755 index 0000000..23e5c36 --- /dev/null +++ b/Lua/movement tests.lua @@ -0,0 +1,195 @@ +-- movement speed testing in Majora's Mask +-- by notwa, for Bizhawk 1.9.1, ROM version US 1.0 +-- +-- go to the fairy's fountain in clock town as human link and run this script. + +local length = 70 -- in frames +local print_each = true + +local tests = { + optimal_roll = { + [ 1]={ Y=127}, + [ 2]={Z=true, Y=127, A=true}, + [17]={Z=true, Y=127}, + [18]={Z=true, Y=127, A=true}, + [33]={goto=17}, + }, + + mash_roll = { + [ 1]={ Y=127}, + [ 2]={Z=true, Y=127, A=true}, + [13]={Z=true, Y=127}, + [14]={Z=true, Y=127, A=true}, + [25]={goto=13}, + }, + + sidehop = { + [ 1]={ X=127}, + [ 2]={Z=true}, + [ 8]={Z=true, X=-127, A=true}, + [ 9]={Z=true, X=-127}, + [15]={goto=8}, + }, + + quick_turnaround = { + [1]={Z=true}, + [2]={}, + [5]={ Y=-127}, + [6]={Z=true, Y=-127}, + }, + + backwalk = { + [1]={ Y=-127}, + [2]={Z=true}, + [8]={Z=true, Y=-127}, + }, + + walk = { + [1]={Y=127}, + }, + + inverse_backwalk = { + [1]={Z=true, Y=127}, + [4]={}, + [7]={ Y=-127}, + [8]={Z=true, Y=127}, + }, +} + +local x_ptr = 0x3FFDD4 -- my x and y pointers +local y_ptr = 0x3FFDDC -- might be backwards +local z_ptr = 0x3FFDD8 +local a_ptr = 0x3FFE6E + +local pos = {2400, 375, 20} +local angle = 180/360*65536 + +local fn = 'lua movement test' + +function pythag(x, y) + return math.sqrt(x*x + y*y) +end + +function reset_stick() + joypad.setanalog({["X Axis"]=false, ["Y Axis"]=false}, 1) +end + +function find_displacement() + local x = mainmemory.readfloat(x_ptr, true) + local y = mainmemory.readfloat(y_ptr, true) + return pythag(pos[1] - x, pos[2] - y) +end + +function setup() + client.unpause() + for _=1, 2 do + reset_stick() + mainmemory.write_s16_be(a_ptr, angle) + mainmemory.writefloat(x_ptr, pos[1], true) + mainmemory.writefloat(y_ptr, pos[2], true) + mainmemory.writefloat(z_ptr, pos[3], true) + for i=1, 3*21 do + emu.frameadvance() + joypad.set({A=i % 4 > 0, Z=i > 9 and i <= 12}, 1) + end + end + savestate.save(fn) +end + +function reload() + savestate.load(fn) +end + +function finish() + reset_stick() + client.pause() +end + +function preprocess(inputs) + for f, j in pairs(inputs) do + if type(f) == 'number' then + j['Start'] = j['S'] + j['C Down'] = j['CD'] + j['C Left'] = j['CL'] + j['C Right'] = j['CR'] + j['C Up'] = j['CU'] + j['X Axis'] = j['X'] + j['Y Axis'] = j['Y'] + end + end +end + +function test_inputs(name, inputs, length) + preprocess(inputs) + reload() + local to = length or inputs.length + local frame = 0 + local latest, action + for _=1, to do + frame = frame + 1 + for _=1, 10 do -- limit number of goto's to follow + latest = 0 + action = nil + for f, j in pairs(inputs) do + if type(f) == 'number' and frame >= f and f > latest then + latest = f + action = j + end + end + if action == nil or type(action.goto) ~= 'number' then + break + else + frame = action.goto + end + end + if action ~= nil then + for _=1, 3 do + joypad.setanalog(action, 1) + joypad.set(action, 1) + emu.frameadvance() + end + end + reset_stick() + end + return x +end + +function run_tests(length) + setup() + + local fmt = '%20s: %10.5f' + local spd_fmt = '%20.5f units/frame' + print('# testing') + + if tests['testme'] ~= nil then + local key = 'testme' + local x = test_inputs(key, tests[key], length) + local distance = find_displacement() + print(fmt:format(key, distance)) + print(spd_fmt:format(distance/length)) + else + local furthest = nil + local distance = 0 + for k, v in pairs(tests) do + local x = test_inputs(k, v, length) + local new_distance = find_displacement() + if print_each then + print(fmt:format(k, new_distance)) + end + if new_distance > distance then + furthest = k + distance = new_distance + end + end + if furthest ~= nil then + print() + print(('## and the winner for %i frames is...'):format(length)) + print(fmt:format(furthest, distance)) + print(spd_fmt:format(distance/length)) + end + end + print() + finish() +end + +run_tests(length) diff --git a/Lua/room debug.lua b/Lua/room debug.lua new file mode 100755 index 0000000..0bf8deb --- /dev/null +++ b/Lua/room debug.lua @@ -0,0 +1,139 @@ +local A = require "boilerplate" +local addrs = require "addrs" + +function printf(fmt, ...) + print(fmt:format(...)) +end + +function gs2(addr, value) + printf("81%06X %04X", addr, value) + W2(addr, value) +end + +function is_ptr(ptr) + local head = bit.band(0xFF000000, ptr) + return head == 0x80000000 +end + +function deref(ptr) + return is_ptr(ptr) and ptr - 0x80000000 +end + +function dump_half_row(addr) + printf("%04X %04X %04X %04X", R2(addr), R2(addr+2), R2(addr+4), R2(addr+6)) +end + +function dump_room(start) + local addr = start + printf("start: %08X", start) + + local object_n, objects + local actor_n, actors + + for _ = 1,128 do -- give up after a while + local cmd = R1(addr) + if cmd == 0x14 then break end + + local dumpy = function() + local bank = R1(addr+4) + local offset = R3(addr+5) + if bank ~= 3 then + printf(" in bank %i at %06X", bank, offset) + return + else + local new_addr = start + offset + printf(" at %08X (+%06X)", new_addr, offset) + return new_addr + end + end + + if cmd == 0x18 then + printf("alt:") + dumpy() + elseif cmd == 0x01 then + actor_n = R1(addr+1) + printf("actors: %2i", actor_n) + actors = dumpy() + elseif cmd == 0x02 then + printf("cameras: %2i", R1(addr+1)) + dumpy() + elseif cmd == 0x03 then + printf("collisions:") + dumpy() + elseif cmd == 0x04 then + printf("maps: %2i", R1(addr+1)) + dumpy() + elseif cmd == 0x06 then + printf("entrances:") + dumpy() + elseif cmd == 0x08 then + print("[room behaviour]") + dump_half_row(addr) + elseif cmd == 0x0A then + printf("mesh:") + dumpy() + elseif cmd == 0x0B then + object_n = R1(addr+1) + printf("objects: %2i", object_n) + objects = dumpy() + elseif cmd == 0x0D then + printf("pathways: %2i", R1(addr+1)) + dumpy() + elseif cmd == 0x10 then + print("[time]") + elseif cmd == 0x12 then + print("[skybox]") + elseif cmd == 0x13 then + printf("exits:") + dumpy() + elseif cmd == 0x16 then + printf("echo: %2i", R1(addr+7)) + elseif cmd == 0x17 then + printf("cutscenes: %2i", R1(addr+1)) + dumpy() + else + dump_half_row(addr) + end + + addr = addr + 8 + end + + --[[ + local obj_i = 0 + local act_i = 1 + if objects and object_n > obj_i and actors and actor_n > act_i then + gs2(objects + 2*obj_i, 0x00FC) + gs2(actors + 16*act_i+0x0, 0x00A8) + gs2(actors + 16*act_i+0xE, 0x0010) + end + --]] + if objects and actors then + for i = 0, object_n - 1 do + --printf('O: %04X', R2(objects + 2*i)) + --gs2(objects+2*i, 0x00FC) + + end + for i = 0, actor_n - 1 do + --print('A:') + --dump_half_row(actors+16*i+0) + --dump_half_row(actors+16*i+8) + --gs2(actors+16*i+0x0, 0x00A8) + --gs2(actors+16*i+0xE, 0x0010) + end + end +end + +local last_addr +while true do + local addr = deref(addrs.room_ptr()) + if addr and addr ~= last_addr then + print('# new room loaded #') + dump_room(addr) + print('') + end + last_addr = addr + + gui.clearGraphics() + + emu.yield() +end diff --git a/Lua/test chests.lua b/Lua/test chests.lua new file mode 100755 index 0000000..f7367ac --- /dev/null +++ b/Lua/test chests.lua @@ -0,0 +1,100 @@ +-- go to a grotto with a red rupee chest, stand in front of it and run this script + +local hash = gameinfo.getromhash() +local versions = { + ['D6133ACE5AFAA0882CF214CF88DABA39E266C078'] = 'US10', +} +local version = versions[hash] + +local JP = version ~= 'US10' + +local index = 84 + +local start, ours, text +if not JP then + -- US 1.0 + start = 0x779884 -- the get item table + ours = 0x779896 -- the chest we're standing in front of + text = 0x3FCE10 -- ascii text buffer +else + start = 0x7797E4 -- the get item table + ours = 0x7797F6 -- the chest we're standing in front of + text = 0x3FD660 -- ascii text buffer (not quite but close enough) +end + +function draw_index() + gui.text(304, 8, ("%03i"):format(index), nil, nil, 'bottomleft') +end + +function advance() + draw_index() + emu.frameadvance() + draw_index() + emu.frameadvance() + draw_index() + emu.frameadvance() +end + +function read_ascii(addr, len) + local begin = addr + local bytes = mainmemory.readbyterange(begin, 0x100) + local str = "" + + -- pairs() won't give us the bytes in order + -- so we'll set up a table we can use ipairs() on + local ordered_bytes = {} + for a, v in pairs(bytes) do + ordered_bytes[tonumber(a, 16) - begin + 1] = v + end + + local seq = false + for i, v in ipairs(ordered_bytes) do + local c = tonumber(v, 16) + if c == 9 or c == 10 or c == 13 or (c >= 32 and c < 127) then + str = str..string.char(c) + seq = false + elseif seq == false then + str = str..' ' + seq = true + end + end + return str +end + +local fn = 'lua chest test' +client.unpause() +savestate.save(fn) +for off=index*6, 185*6, 6 do + index = index + 1 + for i=0, 5 do + local byte = mainmemory.readbyte(start + off + i) + mainmemory.writebyte(ours + i, byte) + end + joypad.set({A=true}, 1) + advance() + joypad.set({A=false}, 1) + local good = false + for i=1, 9*20 do + if JP and ( + (index >= 85 and index <= 88) + ) then break end -- crashes + advance() + if mainmemory.readbyte(text + 0xA) == 0xFF then + if not JP then + local begin = text + 0xC + print(off/6 + 1, read_ascii(begin)) + good = true + else + for _=1, 40 do + advance() + end + end + break + end + end + if not good then + print(off/6 + 1, '[error]') + end + savestate.load(fn) +end +client.pause() diff --git a/Lua/watch animations.lua b/Lua/watch animations.lua new file mode 100755 index 0000000..25d0832 --- /dev/null +++ b/Lua/watch animations.lua @@ -0,0 +1,154 @@ +local addrs = require "addrs" +local anim_addr = addrs.link_actor.animation_id.addr + +local anims_seen = { + [0xCF68] = true, + [0xCF70] = true, + [0xCFE0] = true, + [0xCFE8] = true, + [0xD068] = true, + [0xD088] = true, + [0xD090] = true, + [0xD098] = true, + [0xD0A8] = true, + [0xD0C8] = true, + [0xD0D0] = true, + [0xD0D8] = true, + [0xD140] = true, + [0xD148] = true, + [0xD308] = true, + [0xD448] = true, + [0xD450] = true, + [0xD5A0] = true, + [0xD5A8] = true, + [0xD5B0] = true, + [0xD698] = true, + [0xD6A0] = true, + [0xD6A8] = true, + [0xD720] = true, + [0xD728] = true, + [0xD730] = true, + [0xD770] = true, + [0xD780] = true, + [0xD788] = true, + [0xD790] = true, + [0xD7A8] = true, + [0xD7B8] = true, + [0xD7F0] = true, + [0xD800] = true, + [0xD858] = true, + [0xD868] = true, + [0xD878] = true, + [0xD890] = true, + [0xD898] = true, + [0xD8B0] = true, + [0xD8C8] = true, + [0xD8D8] = true, + [0xD918] = true, + [0xD920] = true, + [0xD928] = true, + [0xD930] = true, + [0xD938] = true, + [0xD988] = true, + [0xD990] = true, + [0xD998] = true, + [0xD9A0] = true, + [0xDA60] = true, + [0xDA68] = true, + [0xDA70] = true, + [0xDA78] = true, + [0xDA80] = true, + [0xDAC0] = true, + [0xDB10] = true, + [0xDB18] = true, + [0xDB28] = true, + [0xDC00] = true, + [0xDC08] = true, + [0xDC30] = true, + [0xDC40] = true, + [0xDCD8] = true, + [0xDCE0] = true, + [0xDCE8] = true, + [0xDCF0] = true, + [0xDCF8] = true, + [0xDD10] = true, + [0xDD18] = true, + [0xDD20] = true, + [0xDD28] = true, + [0xDD30] = true, + [0xDDB0] = true, + [0xDDB8] = true, + [0xDE40] = true, + [0xDE48] = true, + [0xDE50] = true, + [0xDE68] = true, + [0xDE70] = true, + [0xDE78] = true, + [0xDE80] = true, + [0xDE88] = true, + [0xDE90] = true, + [0xDEA0] = true, + [0xDEA8] = true, + [0xDEB8] = true, + [0xDEC8] = true, + [0xDED0] = true, + [0xDEE0] = true, + [0xDEE8] = true, + [0xDF20] = true, + [0xDF28] = true, + [0xDF30] = true, + [0xDF48] = true, + [0xDF50] = true, + [0xDF58] = true, + [0xDF60] = true, + [0xDF68] = true, + [0xDF70] = true, + [0xDFC8] = true, + [0xDFD0] = true, + [0xDFD8] = true, + [0xDFE0] = true, + [0xDFE8] = true, + [0xE000] = true, + [0xE0B0] = true, + [0xE0B8] = true, + [0xE0D8] = true, + [0xE0E0] = true, + [0xE0E8] = true, + [0xE0F0] = true, + [0xE208] = true, + [0xE210] = true, + [0xE218] = true, + [0xE228] = true, + [0xE230] = true, + [0xE240] = true, + [0xE248] = true, + [0xE258] = true, + [0xE260] = true, + [0xE270] = true, + [0xE2E0] = true, + [0xE308] = true, + [0xE320] = true, + [0xE338] = true, + [0xE348] = true, + [0xE3A8] = true, + [0xE3F0] = true, + [0xE3F8] = true, + [0xE400] = true, + [0xE410] = true, + [0xE450] = true, +} + +while true do + local anim_id = mainmemory.read_u16_be(anim_addr) + local actor_loaded = mainmemory.read_u8(anim_addr - 2) == 4 + local hexid = ('%04X'):format(anim_id) + local frame = emu.framecount() + if actor_loaded then + gui.text(2, 4, hexid, nil, 'white', "bottomleft") + if not anims_seen[anim_id] then + anims_seen[anim_id] = true + print(frame, hexid) + end + end + emu.yield() +end