diff --git a/MM addrs.lua b/MM addrs.lua deleted file mode 100755 index 0d8fb43..0000000 --- a/MM addrs.lua +++ /dev/null @@ -1,196 +0,0 @@ -local A = require "boilerplate" - -local link = 0x1EF670 -- "ZELDA3" - 0x24 -local function AL(a, s) return A(link+a, s) end -local US_10 = { - link = A(link, 0x4000), -- what gets copied to save files (mostly) - area_mod = AL(0x02, 2), - cutscene_status = AL(0x0A, 2), -- TODO: RE - time = AL(0x0C, 2), - time_speed = AL(0x16, 2), - day = AL(0x1B, 1), - transformation = AL(0x20, 1), -- fierce deity, goron, zora, deku, normal - zeroth_day = AL(0x23, 1), -- mayor's warp effect - sot_count = AL(0x2A, 2), - name = AL(0x2C, 8), - max_hearts = AL(0x34, 2), - hearts = AL(0x36, 2), - magic_1 = AL(0x39, 1), -- set to 0x60? - rupees = AL(0x3A, 2), - magic_2 = AL(0x40, 2), -- set to 0x101? - owls_hit = AL(0x46, 2), -- bitfield - sword_shield = AL(0x6D, 1), -- mixed - inventory_items = AL(0x70, 24), - inventory_masks = AL(0x88, 24), - inventory_counts = AL(0xA0, 24), -- number of arrows, bombs, etc. - wallet_flags = AL(0xBA, 1), -- needs testing, 0xEF = max? - quiver_bag = AL(0xBB, 1), -- mixed - status_items = AL(0xBD, 3), -- bitfield - scene_flags_save = AL(0x470, 0x960), - area_map = AL(0xEB2, 1), -- bitfield 0x80 - banked_rupees = AL(0xEDE, 2), -- max 9999 before messed up text - archery = AL(0xF00, 1), -- bitfield 0x01 - chateau_romani = AL(0xF06, 1), -- bitfield 0x08 - disable_c_buttons = AL(0xF4A, 1), -- bitfield 0x08 - sword_disable_c = AL(0xF52, 1), -- bitfield 0x20, TODO: RE - map_visited = AL(0xF5E, 2), -- bitfield, for pause menu map - map_visible = AL(0xF62, 2), -- bitfield, for pause menu map - checksum = AL(0x100A, 2), -- only relevant for save files - disable_pause = AL(0x100D, 1), -- bitfield 0x80 - hookshot_ba = AL(0x100E, 1), -- set to 0x80 for endless day - disable_c_buttons_2 = AL(0x100F, 1), -- bitfield 0x10, also hides hearts/magic - disable_items = AL(0x1010, 1), -- bitfield 0x02, dims B/C buttons - rock_sirloin = AL(0x1014, 1), -- maybe other flags? TODO: RE - sword_disabler = AL(0x1015, 1), -- TODO: RE - 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), - -- first non-pictograph byte: 0x1F3310 (link+0x3CA0) - title_screen_mod = AL(0x3CA8, 4), --[[ - nonzero: the HUD is hidden and you can't pause. - 1: no other effects occur. this is used for the title screen. - 2: it takes you to the file select menu. - 3: certain areas load a different scene setup. - 4: it loads the title screen from the start. - 4+: same effect as three? - --]] - entrance_mod = AL(0x3CAC, 4), -- gets added to area mod, can play cutscenes - timer_crap = AL(0x3DD0, 4), -- TODO: RE - timer_x = AL(0x3EFA, 2), - timer_y = AL(0x3F08, 2), - buttons_enabled = AL(0x3F18, 4), -- C and A button booleans - magic_modifier = AL(0x3F28, 4), -- TODO: RE - magic_max = AL(0x3F2E, 2), - weird_a_graphic = AL(0x3F42, 1), - target_style = AL(0x3F45, 1), -- 0 for switch, 1 for hold - music_mod = AL(0x3F46, 2), - entrance_mod_setter = AL(0x3F4A, 2), -- sets entrance mod. -10 = 0 - insta_crash = AL(0x3F4C, 1), -- TODO: RE - transition_mod = AL(0x3F55, 2), -- does it even work? - suns_song_effect = AL(0x3F58, 2), - health_mod = AL(0x3F5A, 2), -- heals you - screen_scale_enable = AL(0x3F60, 1), - screen_scale = AL(0x3F64, 'f'), - scene_flags_ingame = AL(0x3F68, 0x960), - -- last link byte (probably): 0x1F3670 - - 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), - }, - - random = A(0x097530, 4), - visibility = A(0x166118, 2), -- wtf does this even do? - bomb_counter = A(0x1AF10E, 1), -- used for limiting number of bombs active - stored_epona = A(0x1BDA9F, 1), -- takes effect on load (REQUIRES EPONA'S SONG) - stored_song = A(0x1C6A7D, 1), - buttons_3 = A(0x1FB870, 2), -- used for turbo cheat - buttons_4 = A(0x1FB876, 2), -- used for turbo cheat - buttons_1 = A(0x3E6B3A, 1), -- some buttons - buttons_2 = A(0x3E6B3B, 1), -- some more buttons - framerate_limiter = A(0x3E6BC2, 1), -- 1 = 60fps, 2 = 30fps, 3 = 20fps, etc. - bomb_counter_2 = A(0x3E87F7, 1), -- or maybe this, can't remember - 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), -- set to -10 and load - warp_begin = A(0x3FF395, 1), -- set to nonzero to begin warping - screen_dim = A(0x3FF397, 1), -- B) - warp_destination = A(0x3FF39A, 2), - link_scale_x = A(0x3FFE08, 2), - link_scale_y = A(0x3FFE0C, 2), - link_scale_z = A(0x3FFE10, 2), - z_vel = A(0x3FFE18, 'f'), - quick_draw = A(0x3FFEF8, 1), -- item in link's hand - animation_id = A(0x3FFFFA, 2), - linear_vel = A(0x400880, 'f'), - infinite_sword = A(0x40088B, 1), -} - -local EU_DBG = { - room_ptr = A(0x460DEC, 4), - animation_id = A(0x461C1A, 2), -} - -local JP_10 = { - room_ptr = A(0x3FF3BC, 4), - animation_id = A(0x4001EA, 2), -} - -local versions = { - ['D6133ACE5AFAA0882CF214CF88DABA39E266C078'] = US_10, - ['B38B71D2961DFFB523020A67F4807A4B704E347A'] = EU_DBG, - ['5FB2301AACBF85278AF30DCA3E4194AD48599E36'] = JP_10, -} - -local hash = gameinfo.getromhash() -local addrs = versions[hash] - -return addrs diff --git a/MM movement tests.lua b/MM movement tests.lua deleted file mode 100755 index 23e5c36..0000000 --- a/MM movement tests.lua +++ /dev/null @@ -1,195 +0,0 @@ --- 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/MM test chests.lua b/MM test chests.lua deleted file mode 100755 index f7367ac..0000000 --- a/MM test chests.lua +++ /dev/null @@ -1,100 +0,0 @@ --- 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/MM watch animations.lua b/MM watch animations.lua deleted file mode 100755 index fbae171..0000000 --- a/MM watch animations.lua +++ /dev/null @@ -1,27 +0,0 @@ -local US_10 = 0x3FFD40 -local EU_DBG = 0x461C1A - -local versions = { - ['D6133ACE5AFAA0882CF214CF88DABA39E266C078'] = US_10, - ['B38B71D2961DFFB523020A67F4807A4B704E347A'] = EU_DBG, -} - -local hash = gameinfo.getromhash() -local anim_addr = versions[hash] - -local anims_seen = {} - -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 diff --git a/boilerplate.lua b/boilerplate.lua deleted file mode 100755 index a0b7562..0000000 --- a/boilerplate.lua +++ /dev/null @@ -1,65 +0,0 @@ --- 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) 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