├── .gitattributes ├── .gitignore ├── Lua ├── .gitignore ├── README.md ├── RNG index.lua ├── cheat menu.lua ├── count flags.lua ├── data │ ├── _anims_seen.lua │ ├── _anims_seen_oot.lua │ ├── _eci.lua │ ├── _ei.lua │ ├── _exits_seen.lua │ ├── _igi.lua │ ├── _inf.lua │ ├── _it.lua │ ├── _ootmemod.lua │ ├── _unk.lua │ ├── _weg.lua │ ├── actor names oot.lua │ ├── actor names.lua │ ├── damage names oot.lua │ ├── damage names.lua │ ├── entrance names oot.lua │ ├── entrance names.lua │ ├── item values early.lua │ ├── item values oot.lua │ ├── item values.lua │ ├── object names oot.lua │ ├── object names.lua │ └── scene to entrance.lua ├── inject.lua ├── lib │ ├── README.md │ ├── actors.lua │ ├── addrs │ │ ├── M │ │ │ ├── BB.lua │ │ │ ├── EU10.lua │ │ │ ├── EU11.lua │ │ │ ├── EUDB.lua │ │ │ ├── EUGC.lua │ │ │ ├── JP10.lua │ │ │ ├── JP11.lua │ │ │ ├── JPGC.lua │ │ │ ├── US10.lua │ │ │ ├── USDE.lua │ │ │ ├── USGC.lua │ │ │ ├── USGC64.lua │ │ │ └── common.lua │ │ ├── O │ │ │ ├── BB.lua │ │ │ ├── BB2.lua │ │ │ ├── BQ11.lua │ │ │ ├── CNIQ BB.lua │ │ │ ├── CNIQ.lua │ │ │ ├── ENIQ BB.lua │ │ │ ├── EU10.lua │ │ │ ├── EU11.lua │ │ │ ├── EUDB MQ.lua │ │ │ ├── EUDB.lua │ │ │ ├── EUGC MQ.lua │ │ │ ├── EUGC.lua │ │ │ ├── JP09.lua │ │ │ ├── JP10.lua │ │ │ ├── JP11.lua │ │ │ ├── JP12.lua │ │ │ ├── JPGC MQ.lua │ │ │ ├── JPGC.lua │ │ │ ├── JPZC.lua │ │ │ ├── TWIQ.lua │ │ │ ├── US09.lua │ │ │ ├── US10.lua │ │ │ ├── US11.lua │ │ │ ├── US12.lua │ │ │ ├── USGC MQ.lua │ │ │ ├── USGC.lua │ │ │ └── common.lua │ │ ├── addrs.lua │ │ ├── basics.lua │ │ ├── init.lua │ │ └── versions.lua │ ├── boilerplate.lua │ ├── classes.lua │ ├── classes │ │ ├── ActorLister.lua │ │ ├── ByteMonitor.lua │ │ ├── FlagMonitor.lua │ │ ├── InputHandler.lua │ │ ├── JoyWrapper.lua │ │ ├── Monitor.lua │ │ └── SceneFlagMonitor.lua │ ├── extra.lua │ ├── flag manager.lua │ ├── lips │ │ ├── Base.lua │ │ ├── Collector.lua │ │ ├── Dumper.lua │ │ ├── Expander.lua │ │ ├── Expression.lua │ │ ├── LICENSE │ │ ├── Lexer.lua │ │ ├── Parser.lua │ │ ├── Preproc.lua │ │ ├── Reader.lua │ │ ├── Statement.lua │ │ ├── Token.lua │ │ ├── TokenIter.lua │ │ ├── data.lua │ │ ├── init.lua │ │ ├── overrides.lua │ │ ├── util.lua │ │ └── writers.lua │ ├── menu classes.lua │ ├── menu input handlers.lua │ ├── messages.lua │ ├── pt.lua │ ├── serialize.lua │ ├── setup.lua │ └── strict.lua ├── menus │ ├── playas.lua │ ├── progress.lua │ ├── warp oot.lua │ └── warp.lua ├── monitor actors.lua ├── monitor animations.lua ├── monitor debug memory editor.lua ├── monitor debug text.lua ├── monitor epona.lua ├── monitor event flags.lua ├── monitor exits used.lua ├── monitor exits.lua ├── monitor misc.lua ├── monitor rooms.lua ├── monitor scene flags.lua ├── setup hundred.lua ├── setup race file.lua ├── test chests.lua └── test movement.lua ├── README.md ├── Yaz0.py ├── Yaz0_fast.pyx ├── asm ├── .gitignore ├── argparse.lua ├── beta.asm ├── bombtornado.asm ├── code.asm ├── common.asm ├── common.sh ├── crc32.asm ├── dma O EUDB MQ.asm ├── dpad control.asm ├── entrances.asm ├── extra.asm ├── extra.lua ├── mm-bq ├── oot-dbg-comp ├── oot-spawner ├── oot-widescreen ├── patch.lua ├── print.asm ├── serialize.lua ├── simple spawn.asm ├── simple text.asm ├── spawn O EUDB MQ.asm ├── spawn mm early.asm ├── spawn mm.asm ├── spawn oot.asm ├── spawn.asm ├── widescreen-either.asm ├── widescreen-inline-rom.asm └── widescreen-inline.asm ├── chksum.py ├── dump └── .gitignore ├── dumptext.py ├── dumptext2.py ├── fn M US10.txt ├── fn O US10.txt ├── fn O US12.txt ├── heuristics.py ├── img └── M_US10.2016-10-02 19.02.17.png ├── mm-bitflags.txt ├── n64.py ├── n64_fast.pyx ├── notes.md ├── util.py ├── z64crc.c ├── z64dump.py ├── z64yaz0.c └── z64yaz0.new.c /.gitattributes: -------------------------------------------------------------------------------- 1 | *.lua text eol=lf 2 | *.py text eol=lf 3 | *.pyx text eol=lf 4 | *.pyxbld text eol=lf 5 | *.txt text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * - Copy* 2 | *.7z 3 | *.State 4 | *.bin 5 | *.exe 6 | *.z64 7 | __pycache__/* 8 | cm mm save.lua 9 | cm oot save.lua 10 | z64crc 11 | z64yaz0 12 | -------------------------------------------------------------------------------- /Lua/.gitignore: -------------------------------------------------------------------------------- 1 | *.State 2 | oot debug.txt 3 | -------------------------------------------------------------------------------- /Lua/README.md: -------------------------------------------------------------------------------- 1 | # Zelda 64 Lua Scripts 2 | 3 | These are written for 4 | [the latest revision of Bizhawk.][biz] 5 | 6 | [biz]: //github.com/TASVideos/bizhawk/ 7 | 8 | Note that some scripts lack full support for Ocarina of Time. 9 | 10 | ## Scripts 11 | 12 | #### cheat menu.lua 13 | Provides an onscreen UI for many features. 14 | Has four different input methods; 15 | refer to the comment near the start of the script. 16 | Generally, it's opened with L and navigated with the D-Pad. 17 | 18 | #### count flags.lua 19 | Simply counts the number of scene flags globally set. 20 | 21 | #### inject.lua 22 | Assembles and injects code into the game. 23 | 24 | #### m64p entry.lua 25 | Ignore this for now. 26 | This is a rough interfacing script for passing to mupen64plus, 27 | and serves no purpose on Bizhawk. 28 | 29 | #### setup hundred.lua 30 | Instantly gives you all the items in the game, etc. 31 | 32 | Does not set scene/event flags, 33 | except the one required for the Great Spin Attack. 34 | 35 | #### setup race file.lua 36 | Sets up a race file. 37 | 38 | A race file is a save in which the first cycle has been completed, 39 | the Deku Mask has been acquired, 40 | and some other details. 41 | 42 | #### test chests.lua 43 | TODO 44 | 45 | #### test movement.lua 46 | Tests the fastest form of basic movement in Majora's Mask. 47 | Run it in the Clock Town Great Fairy's Fountain. 48 | 49 | ### Monitors 50 | 51 | #### monitor actors.lua 52 | Lists actor data onscreen, 53 | and focuses the camera on them. 54 | Actors may be selected using the D-Pad. 55 | 56 | #### monitor debug memory editor.lua 57 | (Ocarina of Time) Used for determining which values 58 | listed by the in-game debug memory editor are constant. 59 | 60 | #### monitor debug text.lua 61 | TODO 62 | 63 | #### monitor epona.lua 64 | used to investigate [this glitch with unloading Epona.][eponaglitch] 65 | 66 | [eponaglitch]: //www.youtube.com/watch?v=kX0ZcIS8P84 67 | 68 | #### monitor event flags.lua 69 | Monitors event flags, 70 | and announces which bits are being changed, 71 | and if they have ever been seen changing before. 72 | 73 | #### monitor exits.lua 74 | Dumps information on the current exit value; 75 | scene name, entrance, entrance with unused offset; 76 | using human-readable English names. 77 | 78 | Provides the function `dump_all_exits(fn)` 79 | which produces [a large csv file.][csv] 80 | 81 | [csv]: //eaguru.guru/t/_exits.csv 82 | 83 | #### monitor misc.lua 84 | Monitors unknown regions of memory. 85 | Currently, this region is a chunk of save data, ignoring known addresses. 86 | 87 | #### monitor rooms.lua 88 | Parses and dumps the currently loaded room headers. 89 | 90 | #### monitor scene flags.lua 91 | Monitors the current scene's flags, 92 | and announces which bits are being changed, 93 | and if they have ever been seen changing before. 94 | 95 | #### watch animations.lua 96 | Monitors Link's used animations. 97 | 98 | ## Libraries 99 | 100 | See [the README in the lib directory][libs] for information. 101 | 102 | [libs]: /Lua/lib/README.md 103 | 104 | ## Data 105 | 106 | Any data (that isn't provided by the games themselves) 107 | is located in the data directory. 108 | 109 | Much of this should be self-explanitory. However, 110 | files beginning with an underscore contain serialized tables 111 | (generally from monitor scripts) 112 | and usually won't make sense out of context. 113 | -------------------------------------------------------------------------------- /Lua/count flags.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | 5 | -- precalculate hamming weights of bytes 6 | local hamming_weight = {} 7 | for i = 0, 255 do 8 | local w = 0 9 | for b = 0, 7 do 10 | w = w + bit.band(bit.rshift(i, b), 1) 11 | end 12 | hamming_weight[i] = w 13 | end 14 | 15 | local function hamming_of(addr, size) 16 | local weight = 0 17 | local bytes = mainmemory.readbyterange(addr, size) 18 | for k,v in pairs(bytes) do 19 | if v ~= 0 then 20 | weight = weight + hamming_weight[tonumber(v, 16)] 21 | end 22 | end 23 | return weight 24 | end 25 | 26 | local function hamming_of_A(a) 27 | return hamming_of(a.addr, a.type) 28 | end 29 | 30 | print("###") 31 | local current = 0 32 | for i = 1, 5 do 33 | local addr = addrs['current_scene_flags_'..tostring(i)].addr 34 | current = current + hamming_of(addr, 4) 35 | end 36 | local ingame = hamming_of_A(addrs.scene_flags_ingame) 37 | local save = hamming_of_A(addrs.scene_flags_save) 38 | print("current", current) 39 | print("ingame ", ingame) 40 | print("save ", save) 41 | -------------------------------------------------------------------------------- /Lua/data/_anims_seen.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [53096] = true, 3 | [53104] = true, 4 | [53216] = true, 5 | [53224] = true, 6 | [53352] = true, 7 | [53384] = true, 8 | [53392] = true, 9 | [53400] = true, 10 | [53416] = true, 11 | [53448] = true, 12 | [53456] = true, 13 | [53464] = true, 14 | [53480] = true, 15 | [53488] = true, 16 | [53568] = true, 17 | [53576] = true, 18 | [54024] = true, 19 | [54208] = true, 20 | [54224] = true, 21 | [54344] = true, 22 | [54352] = true, 23 | [54424] = true, 24 | [54432] = true, 25 | [54488] = true, 26 | [54688] = true, 27 | [54696] = true, 28 | [54704] = true, 29 | [54936] = true, 30 | [54944] = true, 31 | [54952] = true, 32 | [55072] = true, 33 | [55080] = true, 34 | [55088] = true, 35 | [55152] = true, 36 | [55168] = true, 37 | [55176] = true, 38 | [55184] = true, 39 | [55208] = true, 40 | [55224] = true, 41 | [55232] = true, 42 | [55240] = true, 43 | [55280] = true, 44 | [55296] = true, 45 | [55384] = true, 46 | [55400] = true, 47 | [55416] = true, 48 | [55440] = true, 49 | [55448] = true, 50 | [55472] = true, 51 | [55496] = true, 52 | [55512] = true, 53 | [55576] = true, 54 | [55584] = true, 55 | [55592] = true, 56 | [55600] = true, 57 | [55608] = true, 58 | [55648] = true, 59 | [55688] = true, 60 | [55696] = true, 61 | [55704] = true, 62 | [55712] = true, 63 | [55904] = true, 64 | [55912] = true, 65 | [55920] = true, 66 | [55928] = true, 67 | [55936] = true, 68 | [56000] = true, 69 | [56016] = true, 70 | [56024] = true, 71 | [56032] = true, 72 | [56040] = true, 73 | [56080] = true, 74 | [56088] = true, 75 | [56104] = true, 76 | [56256] = true, 77 | [56264] = true, 78 | [56304] = true, 79 | [56320] = true, 80 | [56328] = true, 81 | [56368] = true, 82 | [56384] = true, 83 | [56440] = true, 84 | [56448] = true, 85 | [56456] = true, 86 | [56464] = true, 87 | [56512] = true, 88 | [56536] = true, 89 | [56544] = true, 90 | [56552] = true, 91 | [56560] = true, 92 | [56568] = true, 93 | [56592] = true, 94 | [56600] = true, 95 | [56608] = true, 96 | [56616] = true, 97 | [56624] = true, 98 | [56752] = true, 99 | [56760] = true, 100 | [56864] = true, 101 | [56896] = true, 102 | [56904] = true, 103 | [56912] = true, 104 | [56936] = true, 105 | [56944] = true, 106 | [56952] = true, 107 | [56960] = true, 108 | [56968] = true, 109 | [56976] = true, 110 | [56992] = true, 111 | [57000] = true, 112 | [57016] = true, 113 | [57032] = true, 114 | [57040] = true, 115 | [57056] = true, 116 | [57064] = true, 117 | [57096] = true, 118 | [57104] = true, 119 | [57112] = true, 120 | [57120] = true, 121 | [57128] = true, 122 | [57136] = true, 123 | [57160] = true, 124 | [57168] = true, 125 | [57176] = true, 126 | [57184] = true, 127 | [57192] = true, 128 | [57200] = true, 129 | [57288] = true, 130 | [57296] = true, 131 | [57304] = true, 132 | [57312] = true, 133 | [57320] = true, 134 | [57344] = true, 135 | [57360] = true, 136 | [57384] = true, 137 | [57392] = true, 138 | [57408] = true, 139 | [57416] = true, 140 | [57424] = true, 141 | [57456] = true, 142 | [57480] = true, 143 | [57488] = true, 144 | [57496] = true, 145 | [57520] = true, 146 | [57528] = true, 147 | [57560] = true, 148 | [57568] = true, 149 | [57576] = true, 150 | [57584] = true, 151 | [57848] = true, 152 | [57856] = true, 153 | [57864] = true, 154 | [57872] = true, 155 | [57880] = true, 156 | [57896] = true, 157 | [57904] = true, 158 | [57920] = true, 159 | [57928] = true, 160 | [57944] = true, 161 | [57952] = true, 162 | [57968] = true, 163 | [58024] = true, 164 | [58032] = true, 165 | [58080] = true, 166 | [58120] = true, 167 | [58136] = true, 168 | [58144] = true, 169 | [58152] = true, 170 | [58168] = true, 171 | [58184] = true, 172 | [58280] = true, 173 | [58336] = true, 174 | [58344] = true, 175 | [58352] = true, 176 | [58360] = true, 177 | [58368] = true, 178 | [58384] = true, 179 | [58448] = true, 180 | } 181 | -------------------------------------------------------------------------------- /Lua/data/_anims_seen_oot.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [9016] = true, 3 | [9216] = true, 4 | [9424] = true, 5 | [9576] = true, 6 | [9584] = true, 7 | [9616] = true, 8 | [9680] = true, 9 | [9800] = true, 10 | [9824] = true, 11 | [9832] = true, 12 | [9840] = true, 13 | [9960] = true, 14 | [9984] = true, 15 | [9992] = true, 16 | [10120] = true, 17 | [10496] = true, 18 | [10512] = true, 19 | [10576] = true, 20 | [10592] = true, 21 | [10600] = true, 22 | [10608] = true, 23 | [10632] = true, 24 | [10648] = true, 25 | [10656] = true, 26 | [10664] = true, 27 | [10688] = true, 28 | [10696] = true, 29 | [10704] = true, 30 | [10712] = true, 31 | [10720] = true, 32 | [10880] = true, 33 | [10888] = true, 34 | [10896] = true, 35 | [10904] = true, 36 | [10912] = true, 37 | [10952] = true, 38 | [10976] = true, 39 | [10984] = true, 40 | [10992] = true, 41 | [11000] = true, 42 | [11048] = true, 43 | [11056] = true, 44 | [11064] = true, 45 | [11184] = true, 46 | [11208] = true, 47 | [11576] = true, 48 | [11584] = true, 49 | [11592] = true, 50 | [11608] = true, 51 | [11616] = true, 52 | [11648] = true, 53 | [11664] = true, 54 | [11672] = true, 55 | [11680] = true, 56 | [11688] = true, 57 | [11720] = true, 58 | [11744] = true, 59 | [11760] = true, 60 | [11784] = true, 61 | [11936] = true, 62 | [11944] = true, 63 | [11976] = true, 64 | [11984] = true, 65 | [12048] = true, 66 | [12064] = true, 67 | [12144] = true, 68 | [12160] = true, 69 | [12216] = true, 70 | [12224] = true, 71 | [12256] = true, 72 | [12264] = true, 73 | [12272] = true, 74 | [12280] = true, 75 | [12288] = true, 76 | [12296] = true, 77 | [12304] = true, 78 | [12320] = true, 79 | [12328] = true, 80 | [12336] = true, 81 | [12344] = true, 82 | [12352] = true, 83 | [12440] = true, 84 | [12448] = true, 85 | [12456] = true, 86 | [12472] = true, 87 | [12488] = true, 88 | [12504] = true, 89 | [12536] = true, 90 | [12544] = true, 91 | [12568] = true, 92 | [12576] = true, 93 | [12584] = true, 94 | [12600] = true, 95 | [12608] = true, 96 | [12616] = true, 97 | [12624] = true, 98 | [12648] = true, 99 | [12656] = true, 100 | [12664] = true, 101 | [12672] = true, 102 | [12680] = true, 103 | [12688] = true, 104 | [12696] = true, 105 | [12704] = true, 106 | [12712] = true, 107 | [12744] = true, 108 | [12792] = true, 109 | [12800] = true, 110 | [12840] = true, 111 | [12848] = true, 112 | [12856] = true, 113 | [12864] = true, 114 | [12904] = true, 115 | [12912] = true, 116 | [12920] = true, 117 | [12928] = true, 118 | [12936] = true, 119 | [12944] = true, 120 | [13000] = true, 121 | [13008] = true, 122 | [13016] = true, 123 | [13032] = true, 124 | [13040] = true, 125 | [13056] = true, 126 | [13064] = true, 127 | [13096] = true, 128 | [13416] = true, 129 | } 130 | -------------------------------------------------------------------------------- /Lua/data/_eci.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [1] = true, 3 | [2] = true, 4 | [4] = true, 5 | [8] = true, 6 | [9] = true, 7 | [10] = true, 8 | [11] = true, 9 | [12] = true, 10 | [13] = true, 11 | [15] = true, 12 | [16] = true, 13 | [19] = true, 14 | [20] = true, 15 | [21] = true, 16 | [24] = true, 17 | [25] = true, 18 | [26] = true, 19 | [27] = true, 20 | [28] = true, 21 | [29] = true, 22 | [30] = true, 23 | [39] = true, 24 | [43] = true, 25 | [45] = true, 26 | [48] = true, 27 | [49] = true, 28 | [50] = true, 29 | [51] = true, 30 | [52] = true, 31 | [56] = true, 32 | [57] = true, 33 | [59] = true, 34 | [63] = true, 35 | [64] = true, 36 | [65] = true, 37 | [66] = true, 38 | [67] = true, 39 | [69] = true, 40 | [70] = true, 41 | [71] = true, 42 | [72] = true, 43 | [75] = true, 44 | [77] = true, 45 | [81] = true, 46 | [82] = true, 47 | [83] = true, 48 | [88] = true, 49 | [89] = true, 50 | [90] = true, 51 | [92] = true, 52 | [93] = true, 53 | [96] = true, 54 | [97] = true, 55 | [98] = true, 56 | [99] = true, 57 | [103] = true, 58 | [109] = true, 59 | [111] = true, 60 | [112] = true, 61 | [120] = true, 62 | [121] = true, 63 | [122] = true, 64 | [123] = true, 65 | [124] = true, 66 | [125] = true, 67 | [126] = true, 68 | [127] = true, 69 | [132] = true, 70 | [133] = true, 71 | [134] = true, 72 | [135] = true, 73 | [136] = true, 74 | [138] = true, 75 | [148] = true, 76 | [152] = true, 77 | [153] = true, 78 | [154] = true, 79 | [155] = true, 80 | [156] = true, 81 | [157] = true, 82 | [158] = true, 83 | [160] = true, 84 | [161] = true, 85 | [162] = true, 86 | [164] = true, 87 | [165] = true, 88 | [168] = true, 89 | [169] = true, 90 | [171] = true, 91 | [172] = true, 92 | [173] = true, 93 | [174] = true, 94 | [175] = true, 95 | [176] = true, 96 | [177] = true, 97 | [178] = true, 98 | [179] = true, 99 | [180] = true, 100 | [181] = true, 101 | [182] = true, 102 | [183] = true, 103 | [184] = true, 104 | [185] = true, 105 | [186] = true, 106 | [187] = true, 107 | [188] = true, 108 | [189] = true, 109 | [190] = true, 110 | [191] = true, 111 | [192] = true, 112 | [193] = true, 113 | [200] = true, 114 | [201] = true, 115 | [203] = true, 116 | [204] = true, 117 | [205] = true, 118 | [206] = true, 119 | [207] = true, 120 | [210] = true, 121 | [211] = true, 122 | [212] = true, 123 | [213] = true, 124 | } 125 | -------------------------------------------------------------------------------- /Lua/data/_ei.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [0] = true, 3 | [2] = true, 4 | [7] = true, 5 | [8] = true, 6 | [9] = true, 7 | [10] = true, 8 | [13] = true, 9 | [14] = true, 10 | [24] = true, 11 | [40] = true, 12 | [41] = true, 13 | [42] = true, 14 | [43] = true, 15 | [44] = true, 16 | [56] = true, 17 | } 18 | -------------------------------------------------------------------------------- /Lua/data/_exits_seen.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ["0000"] = true, 3 | ["0400"] = true, 4 | ["0600"] = true, 5 | ["0610"] = true, 6 | ["0800"] = true, 7 | ["0E00"] = true, 8 | ["0E10"] = true, 9 | ["1500"] = true, 10 | ["1C00"] = true, 11 | ["2000"] = true, 12 | ["2010"] = true, 13 | ["2020"] = true, 14 | ["2030"] = true, 15 | ["2040"] = true, 16 | ["2050"] = true, 17 | ["2060"] = true, 18 | ["20B0"] = true, 19 | ["20C0"] = true, 20 | ["20D0"] = true, 21 | ["20E0"] = true, 22 | ["2200"] = true, 23 | ["2210"] = true, 24 | ["2220"] = true, 25 | ["2230"] = true, 26 | ["2240"] = true, 27 | ["2260"] = true, 28 | ["2270"] = true, 29 | ["22A0"] = true, 30 | ["22C0"] = true, 31 | ["2400"] = true, 32 | ["2600"] = true, 33 | ["2800"] = true, 34 | ["2A00"] = true, 35 | ["2C00"] = true, 36 | ["2E10"] = true, 37 | ["3200"] = true, 38 | ["3210"] = true, 39 | ["3400"] = true, 40 | ["3410"] = true, 41 | ["3420"] = true, 42 | ["3430"] = true, 43 | ["3440"] = true, 44 | ["3450"] = true, 45 | ["3460"] = true, 46 | ["3600"] = true, 47 | ["3A00"] = true, 48 | ["3C00"] = true, 49 | ["3E00"] = true, 50 | ["3E10"] = true, 51 | ["3E20"] = true, 52 | ["3E30"] = true, 53 | ["3E40"] = true, 54 | ["4000"] = true, 55 | ["4010"] = true, 56 | ["4020"] = true, 57 | ["4030"] = true, 58 | ["4050"] = true, 59 | ["4060"] = true, 60 | ["4080"] = true, 61 | ["4090"] = true, 62 | ["40A0"] = true, 63 | ["4200"] = true, 64 | ["4400"] = true, 65 | ["4410"] = true, 66 | ["4600"] = true, 67 | ["4610"] = true, 68 | ["4620"] = true, 69 | ["4630"] = true, 70 | ["4640"] = true, 71 | ["4800"] = true, 72 | ["4A00"] = true, 73 | ["4C00"] = true, 74 | ["4C10"] = true, 75 | ["4C20"] = true, 76 | ["5000"] = true, 77 | ["5010"] = true, 78 | ["5020"] = true, 79 | ["5030"] = true, 80 | ["5040"] = true, 81 | ["5050"] = true, 82 | ["5200"] = true, 83 | ["5400"] = true, 84 | ["5410"] = true, 85 | ["5420"] = true, 86 | ["5430"] = true, 87 | ["5440"] = true, 88 | ["5450"] = true, 89 | ["5460"] = true, 90 | ["5470"] = true, 91 | ["5480"] = true, 92 | ["5490"] = true, 93 | ["54A0"] = true, 94 | ["5600"] = true, 95 | ["5800"] = true, 96 | ["5E00"] = true, 97 | ["5E10"] = true, 98 | ["6000"] = true, 99 | ["6010"] = true, 100 | ["6020"] = true, 101 | ["6030"] = true, 102 | ["6040"] = true, 103 | ["6050"] = true, 104 | ["6060"] = true, 105 | ["6200"] = true, 106 | ["6400"] = true, 107 | ["6420"] = true, 108 | ["6430"] = true, 109 | ["6440"] = true, 110 | ["6450"] = true, 111 | ["6600"] = true, 112 | ["6800"] = true, 113 | ["6810"] = true, 114 | ["6820"] = true, 115 | ["6830"] = true, 116 | ["6840"] = true, 117 | ["6850"] = true, 118 | ["6860"] = true, 119 | ["6870"] = true, 120 | ["6880"] = true, 121 | ["68B0"] = true, 122 | ["68C0"] = true, 123 | ["6A00"] = true, 124 | ["6A10"] = true, 125 | ["6A20"] = true, 126 | ["6A30"] = true, 127 | ["6A40"] = true, 128 | ["6A50"] = true, 129 | ["6A60"] = true, 130 | ["6C00"] = true, 131 | ["7000"] = true, 132 | ["7010"] = true, 133 | ["7020"] = true, 134 | ["7030"] = true, 135 | ["7040"] = true, 136 | ["7050"] = true, 137 | ["7060"] = true, 138 | ["7200"] = true, 139 | ["7400"] = true, 140 | ["7600"] = true, 141 | ["7610"] = true, 142 | ["7A00"] = true, 143 | ["7A10"] = true, 144 | ["7A20"] = true, 145 | ["7C00"] = true, 146 | ["7E00"] = true, 147 | ["8000"] = true, 148 | ["8400"] = true, 149 | ["8410"] = true, 150 | ["8420"] = true, 151 | ["8430"] = true, 152 | ["8440"] = true, 153 | ["8450"] = true, 154 | ["8460"] = true, 155 | ["8470"] = true, 156 | ["8480"] = true, 157 | ["8490"] = true, 158 | ["84A0"] = true, 159 | ["8600"] = true, 160 | ["8620"] = true, 161 | ["8640"] = true, 162 | ["8E00"] = true, 163 | ["9000"] = true, 164 | ["9010"] = true, 165 | ["9200"] = true, 166 | ["9210"] = true, 167 | ["9220"] = true, 168 | ["9230"] = true, 169 | ["9250"] = true, 170 | ["9400"] = true, 171 | ["9420"] = true, 172 | ["9430"] = true, 173 | ["9600"] = true, 174 | ["9800"] = true, 175 | ["9A10"] = true, 176 | ["9A20"] = true, 177 | ["9A30"] = true, 178 | ["9A40"] = true, 179 | ["9A60"] = true, 180 | ["9A80"] = true, 181 | ["9C00"] = true, 182 | ["9E00"] = true, 183 | A000 = true, 184 | A010 = true, 185 | A020 = true, 186 | A200 = true, 187 | A400 = true, 188 | A600 = true, 189 | A800 = true, 190 | A810 = true, 191 | AA00 = true, 192 | AA10 = true, 193 | AA20 = true, 194 | AA30 = true, 195 | AC00 = true, 196 | AC10 = true, 197 | B000 = true, 198 | B010 = true, 199 | B200 = true, 200 | B210 = true, 201 | B220 = true, 202 | B230 = true, 203 | B400 = true, 204 | B410 = true, 205 | B420 = true, 206 | BA00 = true, 207 | BC00 = true, 208 | BC10 = true, 209 | C000 = true, 210 | C010 = true, 211 | C200 = true, 212 | CA00 = true, 213 | CE00 = true, 214 | CE30 = true, 215 | D000 = true, 216 | D200 = true, 217 | D210 = true, 218 | D220 = true, 219 | D230 = true, 220 | D240 = true, 221 | D250 = true, 222 | D260 = true, 223 | D270 = true, 224 | D280 = true, 225 | D290 = true, 226 | D2A0 = true, 227 | D2B0 = true, 228 | D400 = true, 229 | D410 = true, 230 | D420 = true, 231 | D430 = true, 232 | D440 = true, 233 | D450 = true, 234 | D460 = true, 235 | D470 = true, 236 | D480 = true, 237 | D600 = true, 238 | D610 = true, 239 | D620 = true, 240 | D630 = true, 241 | D640 = true, 242 | D800 = true, 243 | D810 = true, 244 | D820 = true, 245 | D830 = true, 246 | D840 = true, 247 | D850 = true, 248 | D860 = true, 249 | D870 = true, 250 | D890 = true, 251 | DA00 = true, 252 | DA10 = true, 253 | } 254 | -------------------------------------------------------------------------------- /Lua/data/_igi.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [0] = true, 3 | [1] = true, 4 | [2] = true, 5 | [4] = true, 6 | [6] = true, 7 | [7] = true, 8 | [10] = true, 9 | [11] = true, 10 | [12] = true, 11 | [13] = true, 12 | [14] = true, 13 | [15] = true, 14 | [16] = true, 15 | [17] = true, 16 | [18] = true, 17 | [21] = true, 18 | [23] = true, 19 | [24] = true, 20 | [27] = true, 21 | [29] = true, 22 | [30] = true, 23 | [34] = true, 24 | [36] = true, 25 | [38] = true, 26 | [43] = true, 27 | [44] = true, 28 | [45] = true, 29 | [46] = true, 30 | [48] = true, 31 | [49] = true, 32 | [50] = true, 33 | [51] = true, 34 | [55] = true, 35 | [56] = true, 36 | [57] = true, 37 | } 38 | -------------------------------------------------------------------------------- /Lua/data/_inf.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [3] = true, 3 | [13] = true, 4 | [14] = true, 5 | [15] = true, 6 | [20] = true, 7 | [23] = true, 8 | [25] = true, 9 | [28] = "curious", 10 | [29] = true, 11 | [31] = true, 12 | [32] = true, 13 | [33] = true, 14 | [38] = true, 15 | [42] = true, 16 | [44] = true, 17 | [47] = true, 18 | [49] = true, 19 | [56] = true, 20 | [57] = true, 21 | [58] = true, 22 | [59] = true, 23 | [60] = true, 24 | [61] = true, 25 | [62] = true, 26 | } 27 | -------------------------------------------------------------------------------- /Lua/data/_it.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [4] = true, 3 | [6] = true, 4 | [8] = true, 5 | [9] = true, 6 | [11] = true, 7 | [22] = true, 8 | [29] = true, 9 | [32] = true, 10 | [42] = true, 11 | [44] = true, 12 | [46] = true, 13 | [100] = true, 14 | [110] = true, 15 | [118] = true, 16 | [126] = true, 17 | [127] = true, 18 | [131] = true, 19 | [140] = true, 20 | [141] = true, 21 | [146] = true, 22 | [156] = true, 23 | [159] = true, 24 | [163] = true, 25 | [184] = true, 26 | [185] = true, 27 | [190] = true, 28 | [191] = true, 29 | [192] = true, 30 | [193] = true, 31 | [194] = true, 32 | [195] = true, 33 | [196] = true, 34 | [197] = true, 35 | [200] = true, 36 | [201] = true, 37 | [202] = true, 38 | [205] = true, 39 | [206] = true, 40 | [207] = true, 41 | [227] = true, 42 | [232] = true, 43 | [238] = true, 44 | [248] = true, 45 | [252] = true, 46 | [257] = true, 47 | [259] = true, 48 | [260] = true, 49 | [262] = true, 50 | [274] = true, 51 | [283] = true, 52 | [289] = true, 53 | [300] = true, 54 | [304] = true, 55 | [305] = true, 56 | [328] = true, 57 | [329] = true, 58 | [330] = true, 59 | [331] = true, 60 | [332] = true, 61 | [333] = true, 62 | [334] = true, 63 | [335] = true, 64 | [356] = true, 65 | [362] = true, 66 | [363] = true, 67 | [364] = true, 68 | [368] = true, 69 | [375] = true, 70 | [376] = true, 71 | [378] = true, 72 | [382] = true, 73 | [400] = true, 74 | [401] = true, 75 | [402] = true, 76 | [403] = true, 77 | [404] = true, 78 | [405] = true, 79 | [406] = true, 80 | [407] = true, 81 | [408] = true, 82 | [409] = true, 83 | [410] = true, 84 | [414] = true, 85 | [415] = true, 86 | [416] = true, 87 | [417] = true, 88 | [418] = true, 89 | [419] = true, 90 | [420] = true, 91 | [421] = true, 92 | [422] = true, 93 | [423] = true, 94 | [424] = true, 95 | [425] = true, 96 | [426] = true, 97 | [427] = true, 98 | [428] = true, 99 | [429] = true, 100 | [430] = true, 101 | [431] = true, 102 | [472] = true, 103 | } 104 | -------------------------------------------------------------------------------- /Lua/data/_ootmemod.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [0] = true, 3 | [1] = true, 4 | [2] = true, 5 | [3] = true, 6 | [4] = true, 7 | [5] = true, 8 | [6] = true, 9 | [7] = true, 10 | [8] = true, 11 | [10] = true, 12 | [11] = true, 13 | [12] = true, 14 | [13] = true, 15 | [14] = true, 16 | [34] = true, 17 | [35] = true, 18 | [36] = true, 19 | [37] = true, 20 | [38] = true, 21 | [45] = true, 22 | [126] = true, 23 | [129] = true, 24 | [187] = true, 25 | [190] = true, 26 | [288] = true, 27 | [289] = true, 28 | [290] = true, 29 | [291] = true, 30 | [292] = true, 31 | [293] = true, 32 | [294] = true, 33 | [295] = true, 34 | [296] = true, 35 | [297] = true, 36 | [298] = true, 37 | [299] = true, 38 | [300] = true, 39 | [301] = true, 40 | [302] = true, 41 | [303] = true, 42 | [304] = true, 43 | [305] = true, 44 | [307] = true, 45 | [308] = true, 46 | [309] = true, 47 | [532] = true, 48 | [533] = true, 49 | [534] = true, 50 | [535] = true, 51 | [575] = true, 52 | [576] = true, 53 | [578] = true, 54 | [583] = true, 55 | [584] = true, 56 | [591] = true, 57 | [592] = true, 58 | [593] = true, 59 | [598] = true, 60 | [599] = true, 61 | [607] = true, 62 | [647] = true, 63 | [648] = true, 64 | [651] = true, 65 | [930] = true, 66 | [933] = true, 67 | [967] = true, 68 | [968] = true, 69 | [1075] = true, 70 | [1349] = true, 71 | [1399] = true, 72 | [1400] = true, 73 | [1401] = true, 74 | [1409] = true, 75 | [1411] = true, 76 | [1412] = true, 77 | [1413] = true, 78 | [1416] = true, 79 | [1417] = true, 80 | [1443] = true, 81 | [1444] = true, 82 | [1445] = true, 83 | [1446] = true, 84 | [1447] = true, 85 | [1448] = true, 86 | [1719] = true, 87 | [1720] = true, 88 | [1728] = true, 89 | [1730] = true, 90 | [1735] = true, 91 | [1744] = true, 92 | [1745] = true, 93 | [1757] = true, 94 | [1758] = true, 95 | [1815] = true, 96 | [1818] = true, 97 | [1920] = true, 98 | [1921] = true, 99 | [1922] = true, 100 | [1923] = true, 101 | [1924] = true, 102 | [1925] = true, 103 | [1926] = true, 104 | [1927] = true, 105 | [1928] = true, 106 | [1929] = true, 107 | [1930] = true, 108 | [1931] = true, 109 | [1932] = true, 110 | [1933] = true, 111 | [1934] = true, 112 | [1935] = true, 113 | [1936] = true, 114 | [1937] = true, 115 | [1939] = true, 116 | [1940] = true, 117 | [1941] = true, 118 | [1942] = true, 119 | [1943] = true, 120 | [1944] = true, 121 | [1945] = true, 122 | [1965] = true, 123 | [1967] = true, 124 | [1968] = true, 125 | [1969] = true, 126 | [1981] = true, 127 | [1982] = true, 128 | [1983] = true, 129 | [2082] = true, 130 | [2096] = true, 131 | [2098] = true, 132 | } 133 | -------------------------------------------------------------------------------- /Lua/data/_unk.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [216] = { 3 | [0] = true, 4 | [12] = true, 5 | }, 6 | [217] = { 7 | [0] = true, 8 | [4] = true, 9 | }, 10 | [354] = { 11 | [0] = true, 12 | [128] = true, 13 | }, 14 | [550] = { 15 | [0] = true, 16 | [64] = true, 17 | }, 18 | [653] = { 19 | [0] = true, 20 | [2] = true, 21 | }, 22 | [737] = { 23 | [0] = true, 24 | [5] = true, 25 | [7] = true, 26 | }, 27 | [763] = { 28 | [0] = true, 29 | [112] = true, 30 | }, 31 | [764] = { 32 | [0] = true, 33 | [176] = true, 34 | }, 35 | [781] = { 36 | [0] = true, 37 | [16] = true, 38 | [24] = true, 39 | }, 40 | [784] = { 41 | [0] = true, 42 | [8] = true, 43 | }, 44 | [785] = { 45 | [0] = true, 46 | [4] = true, 47 | }, 48 | [822] = { 49 | [0] = true, 50 | [128] = true, 51 | }, 52 | [886] = { 53 | [0] = true, 54 | [128] = true, 55 | }, 56 | } 57 | -------------------------------------------------------------------------------- /Lua/data/damage names oot.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [0]="Nut", 3 | "Stick/Pot", 4 | "Slingshot", 5 | "Explosion", 6 | "Boomerang", 7 | "Arrow", 8 | "Hammer", 9 | "Hookshot", 10 | "(K)Slash", 11 | "(K)Jump/(M)Slash", -- Spin/Jump 12 | "(B)Slash", 13 | "(A)Fire", 14 | "(A)Ice", 15 | "(A)Light", 16 | "(A)4", 17 | "(A)5", 18 | "(A)6", 19 | "Din's Fire", 20 | "Ice Magic", 21 | "Light Magic", 22 | "?", 23 | "?", 24 | "(K)Spin", -- Blue Spin 25 | "(G)Spin", 26 | "(M)Spin", 27 | "(BG)Jump", -- Spin/Jump? 28 | "(G)Jump", -- Spin/Jump 29 | "(M)Jump", 30 | "?", 31 | "?", 32 | "(H)Jump", 33 | "?", 34 | } 35 | -------------------------------------------------------------------------------- /Lua/data/damage names.lua: -------------------------------------------------------------------------------- 1 | return { 2 | [0]="Nut", 3 | "Stick", 4 | "Epona", 5 | "Bomb", 6 | "(Z)Fins", 7 | "Bow", 8 | "Mirror?", 9 | "Hook", 10 | "(G)Punch", 11 | "Sword", 12 | "(G)Pound", 13 | "Fire", 14 | "Ice", 15 | "Light", 16 | "(G)Spikes", 17 | "(D)Spin", 18 | "(D)Shoot", 19 | "(D)Dive", 20 | "(D)Bomb", 21 | "(Z)Barrier", 22 | "?", 23 | "?", 24 | "Bush", 25 | "(Z)Karate", 26 | "M. Spin", -- ??? 27 | "(F)Beam", 28 | "Roll", 29 | "?", 30 | "?", 31 | "?", 32 | "?", 33 | "Keg", 34 | } 35 | -------------------------------------------------------------------------------- /Lua/data/item values early.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ocarina = 0x00, 3 | bow = 0x01, 4 | fire_arrows = 0x02, 5 | ice_arrows = 0x03, 6 | light_arrows = 0x04, 7 | bombs = 0x06, 8 | bombchu = 0x07, 9 | deku_stick = 0x08, 10 | deku_nut = 0x09, 11 | magic_beans = 0x0A, 12 | powder_keg = 0x0C, 13 | pictograph = 0x0D, 14 | lens_of_truth = 0x0E, 15 | hookshot = 0x0F, 16 | fairy_sword = 0x10, 17 | 18 | bottle = 0x12, 19 | fairy = 0x16, 20 | milk = 0x18, 21 | fish = 0x1A, 22 | bugs = 0x1B, 23 | chateau_romani = 0x25, 24 | 25 | postman = 0x5A, 26 | all_night = 0x55, 27 | blast = 0x63, 28 | stone = 0x61, 29 | great_fairy = 0x5C, 30 | deku = 0x4E, 31 | keaton = 0x56, 32 | bremen = 0x62, 33 | bunny = 0x54, 34 | don_gero = 0x5E, 35 | scents = 0x64, 36 | goron = 0x4F, 37 | romani = 0x58, 38 | troupe_leader = 0x59, 39 | kafei = 0x53, 40 | couples = 0x5B, 41 | truth = 0x52, 42 | zora = 0x50, 43 | kamaro = 0x5F, 44 | gibdo = 0x5D, 45 | garos = 0x57, 46 | captains = 0x60, 47 | giants = 0x65, 48 | fierce_deity = 0x51, 49 | 50 | kokiri_sword = 0x6C, 51 | razor_sword = 0x6D, 52 | gilded_sword = 0x6E, 53 | } 54 | -------------------------------------------------------------------------------- /Lua/data/item values oot.lua: -------------------------------------------------------------------------------- 1 | return { 2 | deku_stick = 0x00, 3 | deku_nut = 0x01, 4 | bombs = 0x02, 5 | bow = 0x03, 6 | fire_arrows = 0x04, 7 | dins_fire = 0x05, 8 | slingshot = 0x06, 9 | fairy_ocarina = 0x07, 10 | ocarina = 0x08, 11 | bombchu = 0x09, 12 | hookshot = 0x0A, 13 | longshot = 0x0B, 14 | ice_arrows = 0x0C, 15 | farores_wind = 0x0D, 16 | boomerang = 0x0E, 17 | lens_of_truth = 0x0F, 18 | magic_beans = 0x10, 19 | hammer = 0x11, 20 | light_arrows = 0x12, 21 | nayrus_love = 0x13, 22 | 23 | bottle = 0x14, 24 | fairy = 0x18, 25 | fish = 0x19, 26 | blue_fire = 0x1C, 27 | bugs = 0x1D, 28 | } 29 | -------------------------------------------------------------------------------- /Lua/data/item values.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ocarina = 0x00, 3 | bow = 0x01, 4 | fire_arrows = 0x02, 5 | ice_arrows = 0x03, 6 | light_arrows = 0x04, 7 | bombs = 0x06, 8 | bombchu = 0x07, 9 | deku_stick = 0x08, 10 | deku_nut = 0x09, 11 | magic_beans = 0x0A, 12 | powder_keg = 0x0C, 13 | pictograph = 0x0D, 14 | lens_of_truth = 0x0E, 15 | hookshot = 0x0F, 16 | fairy_sword = 0x10, 17 | 18 | bottle = 0x12, 19 | fairy = 0x16, 20 | milk = 0x18, 21 | fish = 0x1A, 22 | bugs = 0x1B, 23 | chateau_romani = 0x25, 24 | 25 | postman = 0x3E, 26 | all_night = 0x38, 27 | blast = 0x47, 28 | stone = 0x45, 29 | great_fairy = 0x40, 30 | deku = 0x32, 31 | keaton = 0x3A, 32 | bremen = 0x46, 33 | bunny = 0x39, 34 | don_gero = 0x42, 35 | scents = 0x48, 36 | goron = 0x33, 37 | romani = 0x3C, 38 | troupe_leader = 0x3D, 39 | kafei = 0x37, 40 | couples = 0x3F, 41 | truth = 0x36, 42 | zora = 0x34, 43 | kamaro = 0x43, 44 | gibdo = 0x41, 45 | garos = 0x3B, 46 | captains = 0x44, 47 | giants = 0x49, 48 | fierce_deity = 0x35, 49 | 50 | kokiri_sword = 0x4D, 51 | razor_sword = 0x4E, 52 | gilded_sword = 0x4F, 53 | } 54 | -------------------------------------------------------------------------------- /Lua/data/object names oot.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/data/scene to entrance.lua: -------------------------------------------------------------------------------- 1 | -- maybe we could figure this out in code, but hardcoding will do for now. 2 | return { 3 | [0]=0x12, 4 | 0x0B, 5 | 0x0A, 6 | 0x10, 7 | 0x11, 8 | 0x0C, 9 | 0x00, 10 | 0x0D, 11 | nil, 12 | nil, 13 | 0x07, 14 | nil, 15 | nil, 16 | nil, 17 | 0x08, 18 | nil, 19 | 0x13, 20 | 0x14, 21 | 0x15, 22 | 0x16, 23 | 0x17, 24 | 0x18, 25 | 0x19, 26 | 0x1A, 27 | 0x1B, 28 | 0x1C, 29 | 0x1D, 30 | 0x1E, 31 | 0x1F, 32 | 0x20, 33 | 0x21, 34 | 0x22, 35 | 0x23, 36 | 0x24, 37 | 0x25, 38 | 0x26, 39 | 0x27, 40 | 0x28, 41 | 0x29, 42 | 0x2A, 43 | 0x2B, 44 | 0x2C, 45 | 0x2D, 46 | 0x2E, 47 | 0x2F, 48 | 0x30, 49 | nil, 50 | 0x32, 51 | 0x33, 52 | 0x34, 53 | 0x35, 54 | 0x36, 55 | 0x37, 56 | 0x38, 57 | 0x39, 58 | nil, 59 | 0x3B, 60 | 0x3C, 61 | 0x3D, 62 | 0x3E, 63 | 0x3F, 64 | 0x40, 65 | 0x41, 66 | 0x42, 67 | 0x43, 68 | 0x44, 69 | 0x45, 70 | 0x46, 71 | 0x47, 72 | 0x48, 73 | 0x49, 74 | 0x4A, 75 | 0x4B, 76 | 0x4C, 77 | 0x4D, 78 | 0x4E, 79 | 0x4F, 80 | 0x50, 81 | 0x51, 82 | 0x52, 83 | 0x53, 84 | 0x54, 85 | 0x55, 86 | 0x56, 87 | 0x57, 88 | 0x58, 89 | 0x59, 90 | 0x5A, 91 | 0x5B, 92 | 0x5C, 93 | 0x5D, 94 | 0x5E, 95 | 0x5F, 96 | 0x60, 97 | 0x61, 98 | 0x62, 99 | 0x63, 100 | 0x64, 101 | 0x65, 102 | 0x66, 103 | 0x67, 104 | 0x68, 105 | 0x69, 106 | 0x6A, 107 | 0x6B, 108 | 0x6C, 109 | 0x6D, 110 | 0x6E, 111 | 0x6F, 112 | 0x70, 113 | } 114 | -------------------------------------------------------------------------------- /Lua/lib/README.md: -------------------------------------------------------------------------------- 1 | ## Libraries 2 | 3 | #### actors.lua 4 | TODO 5 | 6 | #### classes.lua 7 | For lazy people. 8 | Populate the global namespace with all available classes, 9 | excluding menu/interface classes. 10 | 11 | #### extra.lua 12 | Implements the `opairs` iterator function 13 | and its helper functions, 14 | providing iteration by sorted keys in alphabetical order. 15 | 16 | #### flag manager.lua 17 | Provides basic functions for poking at event flags and scene flags. 18 | 19 | #### boilerplate.lua 20 | Provides common functions used in the majority of scripts. 21 | This should generally be imported before any other scripts, besides depend.lua. 22 | 23 | #### lips.lua 24 | TODO 25 | 26 | #### menu classes.lua 27 | Provides various classes for implementing onscreen menus. 28 | 29 | #### menu input handlers.lua 30 | Provides classes for interfacing user inputs with menus. 31 | 32 | #### messages.lua 33 | Provides functions for printing onscreen, 34 | such as printing for a given number of game frames. 35 | 36 | #### pt.lua 37 | Dumps Lua tables as pseudo-yaml, 38 | complete with references to prevent recursion. 39 | Invaluable for debugging. 40 | [Its repository is on gist][pt] — look there for basic usage. 41 | 42 | #### serialize.lua 43 | Serializes (saves, dumps) Lua tables for later deserialization (loading). 44 | 45 | unlike `pt`, this dumps as Lua and cannot handle complicated (recursive) tables. 46 | 47 | Also provides deferred printing, 48 | to print to console all at once at the end of a frame, 49 | which works around printing being otherwise slow on Bizhawk. 50 | 51 | [pt]: https://gist.github.com/notwa/13fbddf05f654ba48321 52 | 53 | #### setup.lua 54 | TODO 55 | 56 | ### addrs 57 | 58 | #### addrs/init.lua 59 | Using boilerplate.lua's functions, 60 | this provides the bulk of the interface to the games. 61 | 62 | Note that this particular initialization script populates the global namespace 63 | with `version`, `oot`, `mm`, and most importantly `addrs`. 64 | 65 | #### addrs/basics.lua 66 | Returns a table of tables of offsetable common addresses 67 | between every known version of OoT and MM. 68 | 69 | **table keys:** 70 | 71 | * **link:** the bulk of the player's state in the game; 72 | not to be confused with Link's actor. 73 | most of this is saved to SRAM. 74 | 75 | * **global:** global context. 76 | this is passed as an argument to many functions in the game's code 77 | and contains a wealth of miscellaneous game state information. 78 | this is actually allocated on heap, but its address never changes 79 | — except on the file select screen? 80 | 81 | * **actor:** Link's actor. 82 | this includes position, rotation, animation status, etc. 83 | Link's actor is the only actor that 84 | has the same address consistently, 85 | as it's always the first one loaded. 86 | 87 | #### addrs/versions.lua 88 | Returns a dictionary of md5 and sha1 hashes 89 | of every known version of OoT and MM. 90 | 91 | The format of version strings is 92 | `(O|M) (US|JP|EU)(1[0-9]|GC|DE|DB)( MQ)?`, 93 | where: 94 | * O: Ocarina of Time 95 | * M: Majora's Mask 96 | * US: American NTSC (United States) 97 | * JP: Japanese NTSC 98 | * EU: European PAL 99 | * [two digits]: version number of a release build for the N64 100 | * GC: Gamecube 101 | * DE: Demo (includes Debug features) 102 | * DB: Debug 103 | * MQ: Master Quest 104 | 105 | ### menus/\* 106 | Contains various submenus for `cheat menu.lua`. 107 | 108 | ### classes/\* 109 | Contains various classes. 110 | Note that the base `Class` function is defined in `boilerplate.lua`. 111 | 112 | -------------------------------------------------------------------------------- /Lua/lib/actors.lua: -------------------------------------------------------------------------------- 1 | -- check for errors in the actor linked lists 2 | local validate = false 3 | 4 | -- creating an object every time is a bit slow, so 5 | -- using a template to offset from will do for now. 6 | local actor_t = Actor(0) 7 | 8 | local function sort_by_key(t) 9 | local sorted = {} 10 | local i = 1 11 | for k, v in pairs(t) do 12 | sorted[i] = {k=k, v=v} 13 | i = i + 1 14 | end 15 | table.sort(sorted, function(a, b) return a.k < b.k end) 16 | return sorted 17 | end 18 | 19 | local function get_actor_count(i) 20 | return R4(addrs.actor_counts[i].addr) 21 | end 22 | 23 | local function get_first_actor(i) 24 | return deref(R4(addrs.actor_firsts[i].addr)) 25 | end 26 | 27 | local function get_next_actor(addr) 28 | return deref(R4(addr + actor_t.next.addr)) 29 | end 30 | 31 | local function get_prev_actor(addr) 32 | return deref(R4(addr + actor_t.prev.addr)) 33 | end 34 | 35 | local function count_actors() 36 | local counts = {} 37 | for i = 0, 11 do 38 | counts[i] = get_actor_count(i) 39 | end 40 | return counts 41 | end 42 | 43 | local function iter_actors(counts) 44 | local at, ai = 0, 0 45 | local addr 46 | 47 | local y = 1 48 | local complain = function(s) 49 | s = s..(" (%2i:%3i)"):format(at, ai) 50 | T_TR(0, y, "yellow", s) 51 | y = y + 1 52 | end 53 | 54 | local iterate 55 | iterate = function() 56 | if ai == 0 then 57 | addr = get_first_actor(at) 58 | if validate and addr and get_prev_actor(addr) then 59 | complain("item before first") 60 | end 61 | else 62 | local prev = addr 63 | addr = get_next_actor(addr) 64 | if validate then 65 | if addr and prev ~= get_prev_actor(addr) then 66 | complain("previous mismatch") 67 | end 68 | end 69 | end 70 | 71 | if not addr then 72 | if validate then 73 | if ai < counts[at] then 74 | -- known case: romani ranch on first/third night 75 | complain("list ended early") 76 | elseif ai > counts[at] then 77 | complain("list ended late") 78 | end 79 | end 80 | 81 | ai = 0 82 | at = at + 1 83 | if at == 12 then return nil end 84 | return iterate() 85 | else 86 | local temp = ai 87 | ai = ai + 1 88 | return at, temp, addr 89 | end 90 | end 91 | 92 | return iterate 93 | end 94 | 95 | local function collect_actors() 96 | local game_counts = count_actors() 97 | local any = 0 98 | for i = 0, 11 do 99 | any = any + game_counts[i] 100 | --FIXME: T_BR(0, 13 - i, nil, "#%2i: %2i", i, game_counts[i]) 101 | end 102 | --FIXME: T_BR(0, 1, nil, "sum:%3i", any) 103 | 104 | local actors_by_type = {[0]={},{},{},{},{},{},{},{},{},{},{},{}} -- 12 105 | local new_counts = {[0]=0,0,0,0,0,0,0,0,0,0,0,0} -- 12 106 | if any > 0 then 107 | any = 0 108 | for at, ai, addr in iter_actors(game_counts) do 109 | actors_by_type[at][ai] = addr 110 | new_counts[at] = new_counts[at] + 1 111 | any = any + 1 112 | end 113 | end 114 | return any > 0, actors_by_type, new_counts 115 | end 116 | 117 | return globalize{ 118 | sort_by_key = sort_by_key, 119 | get_actor_count = get_actor_count, 120 | get_first_actor = get_first_actor, 121 | get_next_actor = get_next_actor, 122 | get_prev_actor = get_prev_actor, 123 | count_actors = count_actors, 124 | iter_actors = iter_actors, 125 | collect_actors = collect_actors, 126 | } 127 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/BB.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/EU10.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/EU11.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/EUDB.lua: -------------------------------------------------------------------------------- 1 | return { 2 | entrance_table = A(0x20D480, 0), 3 | owl_table = A(0x2107A8, 0), 4 | stored_song = A(0x2107CD, 0), 5 | mask_mask_bit = A(0x24405A, 3), 6 | scene_time_speed = A(0x3E4082, 2), 7 | } 8 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/EUGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/JP10.lua: -------------------------------------------------------------------------------- 1 | return { 2 | lottery_numbers = { 3 | { 4 | AL(0x1370, 1), 5 | AL(0x1371, 1), 6 | AL(0x1372, 1), 7 | }, { 8 | AL(0x1373, 1), 9 | AL(0x1374, 1), 10 | AL(0x1375, 1), 11 | }, { 12 | AL(0x1376, 1), 13 | AL(0x1377, 1), 14 | AL(0x1378, 1), 15 | }, 16 | }, 17 | spider_mask_order = { 18 | AL(0x1379, 1), 19 | AL(0x137A, 1), 20 | AL(0x137B, 1), 21 | AL(0x137C, 1), 22 | AL(0x137D, 1), 23 | AL(0x137E, 1), 24 | }, 25 | bombers_code = { 26 | AL(0x137F, 1), 27 | AL(0x1380, 1), 28 | AL(0x1381, 1), 29 | AL(0x1382, 1), 30 | AL(0x1383, 1), 31 | }, 32 | 33 | epona_scene = AL(0x1384, 2), -- this is where you left epona 34 | epona_x = AL(0x1386, 2), -- NOT where she currently is 35 | epona_y = AL(0x1388, 2), 36 | epona_z = AL(0x138A, 2), 37 | epona_angle = AL(0x138C, 2), 38 | checksum = AL(0x138E, 2), 39 | disable_pause = nil, 40 | hookshot_ba = nil, 41 | disable_c_buttons_2 = nil, 42 | disable_items = nil, 43 | rock_sirloin = AL(0x3F55, 1), 44 | sword_disabler = nil, 45 | bubble_timer = AL(0x3F58, 2), 46 | rupee_accumulator = AL(0x4078, 2), 47 | spring_water_timers = AL(0x41D8, 0xC0), 48 | pictograph_picture = AL(0x1390, 0x2BC0), 49 | current_save = AL(0x3F50, 4), 50 | title_screen_mod = AL(0x3F5C, 4), 51 | entrance_mod = AL(0x3F60, 4), 52 | voidout_type = AL(0x3F64, 4), 53 | voidout_x = AL(0x3F68, 'f'), 54 | voidout_y = AL(0x3F6C, 'f'), 55 | voidout_z = AL(0x3F70, 'f'), 56 | voidout_angle = AL(0x3F74, 2), 57 | voidout_var = AL(0x3F76, 2), 58 | voidout_entrance = AL(0x3F78, 2), 59 | voidout_room_number = AL(0x3F7A, 2), 60 | timer_crap = AL(0x408C, 4), 61 | timer_x = AL(0x41B8, 2), 62 | timer_y = AL(0x41C6, 2), 63 | buttons_enabled = AL(0x429C, 4), 64 | magic_modifier = AL(0x42AC, 4), 65 | magic_max = AL(0x42B2, 2), 66 | weird_a_graphic = AL(0x42CE, 1), 67 | target_style = AL(0x42D1, 1), 68 | music_mod = nil, 69 | entrance_mod_setter = AL(0x42D6, 2), 70 | title_screen_thing = AL(0x42D8, 1), 71 | transition_mod = nil, 72 | suns_song_effect = AL(0x42E4, 2), 73 | health_mod = AL(0x42E6, 2), 74 | screen_scale_enable = AL(0x42EC, 1), 75 | screen_scale = AL(0x42F0, 'f'), 76 | scene_flags_ingame = AL(0x42F4, 0x960), 77 | 78 | stored_epona = A(0x1B892F, 1), 79 | stored_song = A(0x1C18ED, 1), 80 | scene_time_speed = A(0x382672, 2), 81 | } 82 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/JP11.lua: -------------------------------------------------------------------------------- 1 | return { 2 | lottery_numbers = { 3 | { 4 | AL(0x1370, 1), 5 | AL(0x1371, 1), 6 | AL(0x1372, 1), 7 | }, { 8 | AL(0x1373, 1), 9 | AL(0x1374, 1), 10 | AL(0x1375, 1), 11 | }, { 12 | AL(0x1376, 1), 13 | AL(0x1377, 1), 14 | AL(0x1378, 1), 15 | }, 16 | }, 17 | spider_mask_order = { 18 | AL(0x1379, 1), 19 | AL(0x137A, 1), 20 | AL(0x137B, 1), 21 | AL(0x137C, 1), 22 | AL(0x137D, 1), 23 | AL(0x137E, 1), 24 | }, 25 | bombers_code = { 26 | AL(0x137F, 1), 27 | AL(0x1380, 1), 28 | AL(0x1381, 1), 29 | AL(0x1382, 1), 30 | AL(0x1383, 1), 31 | }, 32 | 33 | checksum = AL(0x138E, 2), 34 | disable_pause = nil, 35 | hookshot_ba = nil, 36 | disable_c_buttons_2 = nil, 37 | disable_items = nil, 38 | rock_sirloin = AL(0x3F55, 1), 39 | sword_disabler = nil, 40 | bubble_timer = AL(0x3F58, 2), 41 | rupee_accumulator = AL(0x4078, 2), 42 | spring_water_timers = AL(0x41D8, 0xC0), 43 | pictograph_picture = AL(0x1390, 0x2BC0), 44 | title_screen_mod = AL(0x3F5C, 4), 45 | entrance_mod = AL(0x3F60, 4), 46 | voidout_type = AL(0x3F64, 4), 47 | voidout_x = AL(0x3F68, 'f'), 48 | voidout_y = AL(0x3F6C, 'f'), 49 | voidout_z = AL(0x3F70, 'f'), 50 | voidout_angle = AL(0x3F74, 2), 51 | voidout_var = AL(0x3F76, 2), 52 | voidout_entrance = AL(0x3F78, 2), 53 | voidout_room_number = AL(0x3F7A, 2), 54 | timer_crap = AL(0x408C, 4), 55 | timer_x = AL(0x41B8, 2), 56 | timer_y = AL(0x41C6, 2), 57 | buttons_enabled = AL(0x429C, 4), 58 | magic_modifier = AL(0x42AC, 4), 59 | magic_max = AL(0x42B2, 2), 60 | weird_a_graphic = AL(0x42CE, 1), 61 | target_style = AL(0x42D1, 1), 62 | music_mod = nil, 63 | entrance_mod_setter = AL(0x42D6, 2), 64 | title_screen_thing = AL(0x42D8, 1), 65 | transition_mod = nil, 66 | suns_song_effect = AL(0x42E4, 2), 67 | health_mod = AL(0x42E6, 2), 68 | screen_scale_enable = AL(0x42EC, 1), 69 | screen_scale = AL(0x42F0, 'f'), 70 | scene_flags_ingame = AL(0x42F4, 0x960), 71 | } 72 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/JPGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/US10.lua: -------------------------------------------------------------------------------- 1 | return { 2 | random = A(0x097530, 4), 3 | massive_counter = A(0x09E5B0, 4), 4 | visibility = A(0x166118, 2), 5 | timestop = A(0x1BD8B0, 2), 6 | stored_epona = A(0x1BDA9F, 1), 7 | entrance_table = A(0x1C43B0, 0), 8 | scene_table = A(0x1C5720, 0), 9 | owl_table = A(0x1C6A58, 0), 10 | stored_song = A(0x1C6A7D, 1), 11 | mask_mask_bit = A(0x1F3F3A, 3), 12 | visual_frame = A(0x1F9F80, 4), 13 | buttons_3 = A(0x1FB870, 2), 14 | buttons_4 = A(0x1FB876, 2), 15 | music_speed = A(0x2050D8, 1), 16 | scene_time_speed = A(0x382502, 2), 17 | } 18 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/USDE.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/USGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/M/USGC64.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/BB.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/BB2.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/BQ11.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/CNIQ BB.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/CNIQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/ENIQ BB.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EU10.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EU11.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EUDB MQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EUDB.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EUGC MQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/EUGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JP09.lua: -------------------------------------------------------------------------------- 1 | -- dummy file; please edit O/US09.lua instead 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JP10.lua: -------------------------------------------------------------------------------- 1 | -- dummy file; please edit O/US10.lua instead 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JP11.lua: -------------------------------------------------------------------------------- 1 | -- dummy file; please edit O/US11.lua instead 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JP12.lua: -------------------------------------------------------------------------------- 1 | -- dummy file; please edit O/US12.lua instead 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JPGC MQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JPGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/JPZC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/TWIQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/US09.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/US10.lua: -------------------------------------------------------------------------------- 1 | return { 2 | target_style = AL(0x140C, 1), 3 | } 4 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/US11.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/US12.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/USGC MQ.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/O/USGC.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /Lua/lib/addrs/addrs.lua: -------------------------------------------------------------------------------- 1 | local basics = require "addrs.basics" 2 | local versions = require "addrs.versions" 3 | 4 | local same = { 5 | ["O JP09"] = "O US09", 6 | ["O JP10"] = "O US10", 7 | ["O JP11"] = "O US11", 8 | ["O JP12"] = "O US12", 9 | } 10 | 11 | rawset(_G, 'Actor', function() end) 12 | 13 | return function(hash) 14 | local version = versions[hash] or rawget(_G, 'VERSION_OVERRIDE') 15 | if version == nil then 16 | error('unknown ROM; try setting VERSION_OVERRIDE') 17 | return 18 | end 19 | local v = version:sub(1, 2) 20 | local rv = same[version] or version 21 | 22 | local b = basics[rv] 23 | local function AL(a, s) return A(b.save + a, s) end 24 | local function AG(a, s) 25 | if rv == 'M JP10' or rv == 'M JP11' then 26 | if a >= 0x17000 then -- approximate 27 | a = a - 0x20 28 | end 29 | end 30 | return A(b.global + a, s) 31 | end 32 | local function AA(a, s) 33 | if rv == 'O EUDB MQ' then 34 | if a >= 0x130 then -- approximate 35 | a = a + 0x10 36 | end 37 | end 38 | return A(b.actor + a, s) 39 | end 40 | 41 | local subdir = version:sub(1, 1) 42 | local rvs = rv:sub(3) 43 | 44 | rawset(_G, 'AL', AL) 45 | rawset(_G, 'AG', AG) 46 | rawset(_G, 'AA', AA) 47 | 48 | local addrs = require("addrs."..subdir.."."..rvs) 49 | addrs.version = version 50 | addrs.oot = v == "O " 51 | addrs.mm = v == "M " 52 | local common = require("addrs."..subdir..".common") 53 | return setmetatable(addrs, {__index=common}) 54 | end 55 | -------------------------------------------------------------------------------- /Lua/lib/addrs/basics.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ["M US10"] = { 3 | save = 0x1EF670, 4 | global = 0x3E6B20, 5 | actor = 0x3FFDB0, 6 | LLsize = 0x10, 7 | }, 8 | ["M USDE"] = { 9 | save = 0x1EEE80, 10 | global = 0x3E63B0, 11 | actor = 0x3FF680, 12 | LLsize = 0x30, 13 | }, 14 | ["M USGC"] = { 15 | save = 0x1ED830, 16 | global = 0x381260, 17 | actor = 0x39A4F0, 18 | LLsize = 0x10, 19 | }, 20 | ["M USGC64"] = { 21 | save = 0x1ED830, 22 | global = 0x381260, 23 | actor = 0x39A4F0, 24 | LLsize = 0x10, 25 | }, 26 | ["M EU10"] = { 27 | save = 0x1E6B50, 28 | global = 0x3DDFC0, 29 | actor = 0x3F7250, 30 | LLsize = 0x10, 31 | }, 32 | ["M EU11"] = { 33 | save = 0x1E6EF0, 34 | global = 0x3DE360, 35 | actor = 0x3F75F0, 36 | LLsize = 0x10, 37 | }, 38 | ["M EUDB"] = { 39 | save = 0x23F790, 40 | global = 0x448700, 41 | actor = 0x4619D0, 42 | LLsize = 0x30, 43 | }, 44 | ["M EUGC"] = { 45 | save = 0x1E5480, 46 | global = 0x378EB0, 47 | actor = 0x392140, 48 | LLsize = 0x10, 49 | }, 50 | ["M JP10"] = { 51 | save = 0x1EF460, 52 | global = 0x3E6CF0, 53 | actor = 0x3FFFA0, 54 | LLsize = 0x30, 55 | }, 56 | ["M JP11"] = { 57 | save = 0x1EF710, 58 | global = 0x3E6FB0, 59 | actor = 0x400260, 60 | LLsize = 0x30, 61 | }, 62 | ["M JPGC"] = { 63 | save = 0x1ED820, 64 | global = 0x381250, 65 | actor = 0x39A4E0, 66 | LLsize = 0x10, 67 | }, 68 | 69 | ["O US10"] = { 70 | save = 0x11A5D0, 71 | global = 0x1C84A0, 72 | actor = 0x1DAA30, 73 | LLsize = 0x30, 74 | }, 75 | ["O US11"] = { 76 | save = 0x11A7B0, 77 | global = 0x1C8660, 78 | actor = 0x1DABF0, 79 | LLsize = 0x30, 80 | }, 81 | ["O US12"] = { 82 | save = 0x11AC80, 83 | global = 0x1C8D60, 84 | actor = 0x1DB2F0, 85 | LLsize = 0x30, 86 | }, 87 | ["O USGC"] = { 88 | save = 0x11B148, 89 | global = 0x1C9660, 90 | actor = 0x1DBBB0, 91 | LLsize = 0x10, 92 | }, 93 | ["O EU10"] = { 94 | save = 0x1183D0, 95 | global = 0x1C64E0, 96 | actor = 0x1D8A70, 97 | LLsize = 0x30, 98 | }, 99 | ["O EU11"] = { 100 | save = 0x118410, 101 | global = 0x1C6520, 102 | actor = 0x1D8AB0, 103 | LLsize = 0x30, 104 | }, 105 | ["O EUGC"] = { 106 | save = 0x118958, 107 | global = 0x1C6E60, 108 | actor = 0x1D93B0, 109 | LLsize = 0x10, 110 | }, 111 | ["O EUDB"] = { 112 | save = 0x15E680, 113 | global = 0x212060, 114 | actor = 0x2245F0, 115 | LLsize = 0x30, 116 | }, 117 | ["O JPGC"] = { 118 | save = 0x11B168, 119 | global = 0x1C9660, 120 | actor = 0x1DBBB0, 121 | LLsize = 0x10, 122 | }, 123 | ["O JPZC"] = { 124 | save = 0x11B148, 125 | global = 0x1C9660, 126 | actor = 0x1DBBB0, 127 | LLsize = 0x10, 128 | }, 129 | ["O CNIQ"] = { 130 | save = 0x137F40, 131 | global = 0x1D5A20, 132 | actor = 0x1E7F70, 133 | LLsize = 0x10, 134 | }, 135 | ["O TWIQ"] = { 136 | save = 0x137300, 137 | global = 0x1D4DE0, 138 | actor = 0x1E7330, 139 | LLsize = 0x10, 140 | }, 141 | ["O USGC MQ"] = { 142 | save = 0x11B128, 143 | global = 0x1C9620, 144 | actor = 0x1DBB70, 145 | LLsize = 0x10, 146 | }, 147 | ["O EUGC MQ"] = { 148 | save = 0x118938, 149 | global = 0x1C6E20, 150 | actor = 0x1D9370, 151 | LLsize = 0x10, 152 | }, 153 | ["O EUDB MQ"] = { 154 | save = 0x15E660, 155 | global = 0x212020, 156 | actor = 0x2245B0, 157 | LLsize = 0x30, 158 | }, 159 | ["O JPGC MQ"] = { 160 | save = 0x11B148, 161 | global = 0x1C9660, 162 | actor = 0x1DBBB0, 163 | LLsize = 0x10, 164 | }, 165 | 166 | ["O BQ11"] = { 167 | save = 0x11A5D0, 168 | global = 0x1C8A10, 169 | actor = 0x1DAFD0, 170 | LLsize = 0x30, 171 | }, 172 | 173 | ["O BB"] = { 174 | save = 0x11B228, 175 | global = 0x1C9720, 176 | actor = 0x1DBC70, 177 | LLsize = 0x10, 178 | }, 179 | 180 | ["O BB2"] = { 181 | save = 0x11B188, 182 | global = 0x1C96A0, 183 | actor = 0x1DBBF0, 184 | LLsize = 0x10, 185 | }, 186 | 187 | ["M BB"] = { 188 | save = 0x1EFA70, 189 | global = 0x3E6EE0, 190 | actor = 0x400170, 191 | LLsize = 0x10, 192 | }, 193 | 194 | ["O CNIQ BB"] = { 195 | save = 0x137F40, 196 | global = 0x1D5A20, 197 | actor = 0x1E7F70, 198 | LLsize = 0x10, 199 | }, 200 | 201 | ["O ENIQ BB"] = { 202 | save = 0x137E00, 203 | global = 0x1D58E0, 204 | actor = 0x1E7E30, 205 | LLsize = 0x10, 206 | }, 207 | 208 | ["O US09"] = { 209 | save = 0x11A3C0, 210 | global = 0x1C82A0, 211 | actor = 0x1DA830, 212 | LLsize = 0x30, 213 | }, 214 | } 215 | -------------------------------------------------------------------------------- /Lua/lib/addrs/init.lua: -------------------------------------------------------------------------------- 1 | local hash 2 | if bizstring then 3 | hash = gameinfo.getromhash() 4 | else 5 | hash = m64p.rom.settings.MD5 6 | end 7 | local Game = require "addrs.addrs" 8 | local game = Game(hash) 9 | 10 | -- TODO: return globalize instead 11 | globalize{ 12 | version = game.version, 13 | oot = game.oot, 14 | mm = game.mm, 15 | addrs = game, 16 | } 17 | return game 18 | -------------------------------------------------------------------------------- /Lua/lib/addrs/versions.lua: -------------------------------------------------------------------------------- 1 | return { -- md5 and sha1 hashes of .z64s 2 | -- NOTE: OoT debug ROMs have two entries; one for the original NZLP 3 | -- in the ROM header, and one for the more commonly hacked NZLE. 4 | 5 | -- Majora's Mask 6 | ["2A0A8ACB61538235BC1094D297FB6556"] = "M US10", 7 | ["8F281800FBA5DDCB1D2B377731FC0215"] = "M USDE", 8 | ["AC0751DBC23AB2EC0C3144203ACA0003"] = "M USGC", 9 | ["13FAB67E603B002CEAF0EEA84130E973"] = "M EU10", 10 | ["BECCFDED43A2F159D03555027462A950"] = "M EU11", 11 | ["71FBAE5D2B27926EA54E92CE2FC91622"] = "M EUDB", 12 | ["DBE9AF0DB46256E42B5C67902B696549"] = "M EUGC", 13 | ["15D1A2217CAD61C39CFECBFFA0703E25"] = "M JP10", 14 | ["C38A7F6F6B61862EA383A75CDF888279"] = "M JP11", 15 | ["D3929AADF7640F8C5B4CE8321AD4393A"] = "M JPGC", 16 | ["D6133ACE5AFAA0882CF214CF88DABA39E266C078"] = "M US10", 17 | ["2F0744F2422B0421697A74B305CB1EF27041AB11"] = "M USDE", 18 | ["9743AA026E9269B339EB0E3044CD5830A440C1FD"] = "M USGC", 19 | ["C04599CDAFEE1C84A7AF9A71DF68F139179ADA84"] = "M EU10", 20 | ["BB4E4757D10727C7584C59C1F2E5F44196E9C293"] = "M EU11", 21 | ["B38B71D2961DFFB523020A67F4807A4B704E347A"] = "M EUDB", 22 | ["A849A65E56D57D4DD98B550524150F898DF90A9F"] = "M EUGC", 23 | ["5FB2301AACBF85278AF30DCA3E4194AD48599E36"] = "M JP10", 24 | ["41FDB879AB422EC158B4EAFEA69087F255EA8589"] = "M JP11", 25 | ["1438FD501E3E5B25461770AF88C02AB1E41D3A7E"] = "M JPGC", 26 | 27 | -- iQue 28 | ["0AB48B2D44A74B3BB2D384F6170C2742"] = "O CNIQ", 29 | ["A475E9F8615513666A265C464708AE8F"] = "O TWIQ", 30 | ["1015D0F3AF34B89149BFD773580BBC66466AF54E"] = "O CNIQ", 31 | ["8668469647423735CC05F55A479C9D3135FBF838"] = "O TWIQ", 32 | 33 | -- Ocarina of Time 34 | ["5BD1FE107BF8106B2AB6650ABECD54D6"] = "O US10", 35 | ["721FDCC6F5F34BE55C43A807F2A16AF4"] = "O US11", 36 | ["57A9719AD547C516342E1A15D5C28C3D"] = "O US12", 37 | ["CD09029EDCFB7C097AC01986A0F83D3F"] = "O USGC", 38 | ["E040DE91A74B61E3201DB0E2323F768A"] = "O EU10", 39 | ["D714580DD74C2C033F5E1B6DC0AEAC77"] = "O EU11", 40 | ["2C27B4E000E85FD78DBCA551F1B1C965"] = "O EUGC", 41 | ["3C10B67A76616AE2C162DEF7528724CF"] = "O EUDB", -- NZLP 42 | ["EFB755B4A9B33FF85E857CFA599D520D"] = "O EUDB", -- NZLE 43 | ["9F04C8E68534B870F707C247FA4B50FC"] = "O JP10", 44 | ["1BF5F42B98C3E97948F01155F12E2D88"] = "O JP11", 45 | ["2258052847BDD056C8406A9EF6427F13"] = "O JP12", 46 | ["33FB7852C180B18EA0B9620B630F413F"] = "O JPGC", 47 | ["0C13E0449A28EA5B925CDB8AF8D29768"] = "O JPZC", 48 | ["AD69C91157F6705E8AB06C79FE08AAD47BB57BA7"] = "O US10", 49 | ["D3ECB253776CD847A5AA63D859D8C89A2F37B364"] = "O US11", 50 | ["41B3BDC48D98C48529219919015A1AF22F5057C2"] = "O US12", 51 | ["B82710BA2BD3B4C6EE8AA1A7E9ACF787DFC72E9B"] = "O USGC", 52 | ["328A1F1BEBA30CE5E178F031662019EB32C5F3B5"] = "O EU10", 53 | ["CFBB98D392E4A9D39DA8285D10CBEF3974C2F012"] = "O EU11", 54 | ["0227D7C0074F2D0AC935631990DA8EC5914597B4"] = "O EUGC", 55 | ["CEE6BC3C2A634B41728F2AF8DA54D9BF8CC14099"] = "O EUDB", -- NZLP 56 | ["F5FBCEBF1E00397EFFB83163FC97E463A815CCE9"] = "O EUDB", -- NZLE 57 | ["C892BBDA3993E66BD0D56A10ECD30B1EE612210F"] = "O JP10", 58 | ["DBFC81F655187DC6FEFD93FA6798FACE770D579D"] = "O JP11", 59 | ["FA5F5942B27480D60243C2D52C0E93E26B9E6B86"] = "O JP12", 60 | ["0769C84615422D60F16925CD859593CDFA597F84"] = "O JPGC", 61 | ["2CE2D1A9F0534C9CD9FA04EA5317B80DA21E5E73"] = "O JPZC", 62 | 63 | -- Ocarina of Time: Master Quest 64 | ["DA35577FE54579F6A266931CC75F512D"] = "O USGC MQ", 65 | ["1618403427E4344A57833043DB5CE3C3"] = "O EUGC MQ", 66 | ["09AE099051BDF6377D482D1944171DFC"] = "O EUDB MQ", -- NZLP 67 | ["8CA71E87DE4CE5E9F6EC916202A623E9"] = "O EUDB MQ", -- NZLE 68 | ["69895C5C78442260F6EAFB2506DC482A"] = "O JPGC MQ", 69 | ["8B5D13AAC69BFBF989861CFDC50B1D840945FC1D"] = "O USGC MQ", 70 | ["F46239439F59A2A594EF83CF68EF65043B1BFFE2"] = "O EUGC MQ", 71 | ["CFECFDC58D650E71A200C81F033DE4E6D617A9F6"] = "O EUDB MQ", -- NZLP 72 | ["50BEBEDAD9E0F10746A52B07239E47FA6C284D03"] = "O EUDB MQ", -- NZLE 73 | ["DD14E143C4275861FE93EA79D0C02E36AE8C6C2F"] = "O JPGC MQ", 74 | 75 | -- hacks 76 | ["8B88986EC8A637ED8C2FC5BF956FA949479B3430"] = "O BQ11", -- beta quest "V1" (no fix) 77 | ["FE2453E7BA38454F9C8BF219B0B89AE614CD08E9"] = "M USGC64", 78 | 79 | -- leaked pre-release builds 80 | ["21F7B4A4FF463464BFC23498C1AB9DA1"] = "O US09", 81 | ["C92D3DB57CA14B7BB9CC9FB507BE6EA1"] = "O JP09", 82 | ["70537A3144C8813B115252C40065C117CB139DCD"] = "O US09", 83 | ["9B21840DE7D01B6A1546B310812B1EA7359AA3EB"] = "O JP09", 84 | 85 | -- leaked builds 86 | ["D0C048E282D8760F2806E7912AFF35AF"] = "O BB", 87 | ["6C2747FF2A0D4FE923E200E04D819708"] = "O BB2", 88 | ["7FFC69CBB2704B27C68B73063925BDB0"] = "M BB", 89 | ["4CDB19D8C05327C9494A1FE8F836BFC3DC0B386E"] = "O BB", 90 | ["699F3F0F18D56BFA2830B2E582B6FC9570EDD108"] = "O BB2", 91 | ["30E35977B09FCBD881BE78A6AEAC0B0418B36372"] = "M BB", 92 | 93 | -- leaked iQue builds 94 | ["058BD5D3A6ED7F10EED123ABBFEE8348"] = "O CNIQ BB", 95 | ["656207C4A7D131E7AB2D0C52A6166E1C"] = "O ENIQ BB", 96 | ["7371679F6BD8F5275D559F20D895724CAD115B91"] = "O CNIQ BB", 97 | ["9F9214AA614C56D5BE93ADFFE104D58CE391FAD5"] = "O ENIQ BB", 98 | } 99 | -------------------------------------------------------------------------------- /Lua/lib/boilerplate.lua: -------------------------------------------------------------------------------- 1 | -- boilerplate convenience functions 2 | 3 | require "extra" 4 | 5 | local R1, R2, R4, RF, W1, W2, W4, WF, X1, X2, X4, XF 6 | 7 | if bizstring then 8 | local mm = mainmemory 9 | local m = memory 10 | m.usememorydomain("ROM") 11 | 12 | R1 = mm.readbyte 13 | R2 = mm.read_u16_be 14 | R4 = mm.read_u32_be 15 | RF = function(addr) return mm.readfloat(addr, true) end 16 | 17 | W1 = mm.writebyte 18 | W2 = mm.write_u16_be 19 | W4 = mm.write_u32_be 20 | WF = function(addr, value) mm.writefloat(addr, value, true) end 21 | 22 | X1 = m.readbyte 23 | X2 = m.read_u16_be 24 | X4 = m.read_u32_be 25 | XF = function(addr) return m.readfloat(addr, true) end 26 | else 27 | local unimplemented = function() error('unimplemented', 2) end 28 | local ram = 0x80000000 29 | local rom = 0x90000000 -- might be wrong for upper 32MB of 64MB roms? 30 | R1 = function(addr) return m64p.memory:read(addr+ram, 'u8') end 31 | R2 = function(addr) return m64p.memory:read(addr+ram, 'u16') end 32 | R4 = function(addr) return m64p.memory:read(addr+ram, 'u32') end 33 | RF = function(addr) return m64p.memory:read(addr+ram, 'float') end 34 | 35 | W1 = function(addr, value) m64p.memory:write(addr+ram, 'u8', value) end 36 | W2 = function(addr, value) m64p.memory:write(addr+ram, 'u16', value) end 37 | W4 = function(addr, value) m64p.memory:write(addr+ram, 'u32', value) end 38 | WF = function(addr, value) m64p.memory:write(addr+ram, 'float', value) end 39 | 40 | X1 = function(addr) return m64p.memory:read(addr+rom, 'u8') end 41 | X2 = function(addr) return m64p.memory:read(addr+rom, 'u16') end 42 | X4 = function(addr) return m64p.memory:read(addr+rom, 'u32') end 43 | XF = function(addr) return m64p.memory:read(addr+rom, 'float') end 44 | end 45 | 46 | local H1 = function(self, value) 47 | return value and W1(self.addr, value) or R1(self.addr) 48 | end 49 | local H2 = function(self, value) 50 | return value and W2(self.addr, value) or R2(self.addr) 51 | end 52 | local H4 = function(self, value) 53 | return value and W4(self.addr, value) or R4(self.addr) 54 | end 55 | local HF = function(self, value) 56 | return value and WF(self.addr, value) or RF(self.addr) 57 | end 58 | 59 | local mts = { 60 | [1] = {__call = H1}, 61 | [2] = {__call = H2}, 62 | [4] = {__call = H4}, 63 | ['f'] = {__call = HF}, 64 | } 65 | 66 | local function A(addr, atype) 67 | local mt = mts[atype] 68 | return setmetatable({ 69 | addr=addr, 70 | type=atype, 71 | }, mt) 72 | end 73 | 74 | local function Class(inherit) 75 | local class = {} 76 | local mt_obj = {__index = class} 77 | local mt_class = { 78 | __call = function(self, ...) 79 | local obj = setmetatable({}, mt_obj) 80 | obj:init(...) 81 | return obj 82 | end, 83 | __index = inherit, 84 | } 85 | 86 | return setmetatable(class, mt_class) 87 | end 88 | 89 | local function getindex(obj) 90 | local gm = getmetatable(obj) 91 | if not gm then return end 92 | return gm.__index 93 | end 94 | 95 | local function printf(fmt, ...) 96 | print(fmt:format(...)) 97 | end 98 | 99 | local function is_ptr(ptr) 100 | return bit.band(0xFF800000, ptr) == 0x80000000 101 | end 102 | 103 | local function deref(ptr) 104 | return is_ptr(ptr) and ptr - 0x80000000 105 | end 106 | 107 | local function asciize(bytes) 108 | local str = "" 109 | local seq = false 110 | for i, v in ipairs(bytes) do 111 | local c = type(v) == 'number' and v or tonumber(v, 16) 112 | if c == 9 or c == 10 or c == 13 or (c >= 32 and c < 127) then 113 | str = str..string.char(c) 114 | seq = false 115 | elseif seq == false then 116 | str = str..' ' 117 | seq = true 118 | end 119 | end 120 | return str 121 | end 122 | 123 | local function hex(i) 124 | -- convenience function for use in console 125 | if i == nil then 126 | print('nil') 127 | return 128 | end 129 | if i > 0xFFFFFFFF then 130 | print('warning: truncated') 131 | end 132 | printf("%08X", i) 133 | end 134 | 135 | --[[ 136 | -- now we can just write: 137 | handle = A(0x123456, 1) 138 | print(handle()) -- get 1 byte at address 139 | handle(0xFF) -- set 1 byte at address 140 | 141 | -- or just: 142 | A(0x123456, 1)(0xFF) -- set address value 143 | 144 | -- and taking advantage of A returning a table and not just a function: 145 | A(handle.addr + 1, handle.type)(0x00) -- set the byte after our address 146 | 147 | -- this doesn't limit us to just the type we initially specified. eg: 148 | A(handle.addr, 2)(0x1234) -- set 2 bytes as opposed to our original 1 149 | --]] 150 | 151 | -- TODO: return globalize instead 152 | globalize{ 153 | Class = Class, 154 | 155 | R1 = R1, R2 = R2, R4 = R4, 156 | W1 = W1, W2 = W2, W4 = W4, 157 | X1 = X1, X2 = X2, X4 = X4, 158 | A = A, 159 | 160 | printf = printf, 161 | hex = hex, 162 | 163 | is_ptr = is_ptr, 164 | deref = deref, 165 | asciize = asciize, 166 | 167 | getindex = getindex, 168 | } 169 | return A 170 | -------------------------------------------------------------------------------- /Lua/lib/classes.lua: -------------------------------------------------------------------------------- 1 | -- for lazy people. 2 | -- populate the global namespace with all available classes, 3 | -- excluding menu/interface classes. 4 | 5 | require "boilerplate" 6 | 7 | local classes = { 8 | "Monitor", 9 | "ByteMonitor", 10 | "FlagMonitor", 11 | "SceneFlagMonitor", 12 | "ActorLister", 13 | "InputHandler", 14 | "JoyWrapper", 15 | } 16 | 17 | for _, class in ipairs(classes) do 18 | rawset(_G, class, require("classes."..class)) 19 | end 20 | -------------------------------------------------------------------------------- /Lua/lib/classes/ByteMonitor.lua: -------------------------------------------------------------------------------- 1 | local Monitor = require "classes.Monitor" 2 | local ByteMonitor = Class(Monitor) 3 | 4 | local printf = rawget(_G, 'dprintf') or printf 5 | 6 | function ByteMonitor:mark(i, x, x1) 7 | if self.ignore and self:ignore(i) then return end 8 | local now = emu.framecount() 9 | local str = ('%04X=%02X (%s)'):format(i, x, self.name) 10 | if self.byvalue then 11 | if not self.modified[i] then 12 | self.modified[i] = {} 13 | end 14 | if not self.modified[i][x] then 15 | self.modified[i][x] = true 16 | self.dirty = true 17 | str = str..' (NEW!)' 18 | end 19 | else 20 | if not self.modified[i] then 21 | self.modified[i] = true 22 | self.dirty = true 23 | str = str..' (NEW!)' 24 | end 25 | end 26 | printf('%s @%i', str, now) 27 | message(str, 180) 28 | end 29 | 30 | return ByteMonitor 31 | -------------------------------------------------------------------------------- /Lua/lib/classes/FlagMonitor.lua: -------------------------------------------------------------------------------- 1 | local printf = rawget(_G, 'dprintf') or printf 2 | 3 | local Monitor = require "classes.Monitor" 4 | local FlagMonitor = Class(Monitor) 5 | 6 | function FlagMonitor:init(name, a, ignore) 7 | Monitor.init(self, name, a) 8 | self.ignore = ignore or {} 9 | end 10 | 11 | function FlagMonitor:mark(i, x, x1) 12 | local now = emu.framecount() 13 | local diff = bit.bxor(x, x1) 14 | for which = 0, 7 do 15 | if bit.band(diff, 2^which) ~= 0 then 16 | local state = bit.band(x, 2^which) ~= 0 and 1 or 0 17 | local str 18 | if self.oot then 19 | local row = math.floor(i/2) 20 | local col = which + (1 - (i % 2))*8 21 | str = ('%02i,%X=%i (%s)'):format(row, col, state, self.name) 22 | else 23 | str = ('%02i,%i=%i (%s)'):format(i, which, state, self.name) 24 | end 25 | local ib = i*8 + which 26 | local curious = self.modified[ib] == "curious" 27 | if not self.modified[ib] or curious then 28 | self.modified[ib] = true 29 | self.dirty = true 30 | if not curious then 31 | str = str..' (NEW!)' 32 | else 33 | str = str..' (!!!)' 34 | end 35 | end 36 | if not self.ignore[str] then 37 | printf('%s @%i', str, now) 38 | message(str, 180) 39 | end 40 | end 41 | end 42 | end 43 | 44 | function FlagMonitor:dump(current) 45 | local t = current and self:read() or self.modified 46 | 47 | local size = self.oot and 16 or 8 48 | local rows = math.floor(self.len/size*8) 49 | 50 | local buff = self.name..'\n' 51 | 52 | buff = buff..' \t' 53 | for col = size-1, 0, -1 do 54 | buff = buff..('%X'):format(col) 55 | if col % 4 == 0 then buff = buff..' ' end 56 | end 57 | 58 | for row = 0, rows-1 do 59 | s = ('%02i\t'):format(row) 60 | for col = size-1, 0, -1 do 61 | local B, b = row, col 62 | if size == 16 then 63 | B = row*2 + (col < 8 and 1 or 0) 64 | b = col % 8 65 | end 66 | local ib = B*8 + b 67 | local v 68 | if current then v = bit.band(t[B], 2^b) > 0 else v = t[ib] end 69 | s = s..(v and '1' or '0') 70 | if col % 4 == 0 then s = s..' ' end 71 | end 72 | buff = buff..'\n'..s 73 | end 74 | 75 | return buff 76 | end 77 | 78 | function FlagMonitor:wipe() 79 | for i = self.begin, self.begin+self.len-1 do 80 | W1(i, 0) 81 | end 82 | end 83 | 84 | function FlagMonitor:set_unknowns() 85 | self.save = function() end -- no clutter 86 | local mod = self.modified_backup 87 | if not mod then 88 | mod = {} 89 | for i, v in pairs(self.modified) do 90 | mod[i] = v 91 | end 92 | self.modified_backup = mod 93 | end 94 | for i = 0, self.len-1 do 95 | local v = R1(self.begin + i) 96 | for which = 0, 7 do 97 | local ib = i*8 + which 98 | if not mod[ib] and bit.band(v, 2^which) == 0 then 99 | v = v + 2^which 100 | end 101 | end 102 | --printf("%04X = %02X", self.begin + i, sum) 103 | W1(self.begin + i, v) 104 | end 105 | end 106 | 107 | return FlagMonitor 108 | -------------------------------------------------------------------------------- /Lua/lib/classes/InputHandler.lua: -------------------------------------------------------------------------------- 1 | local InputHandler = Class() 2 | function InputHandler:init(binds) 3 | self.binds = binds or { 4 | A = "P1 A", 5 | B = "P1 B", 6 | L = "P1 L", 7 | R = "P1 R", 8 | Z = "P1 Z", 9 | d_up = "P1 DPad U", 10 | d_down = "P1 DPad D", 11 | d_left = "P1 DPad L", 12 | d_right = "P1 DPad R", 13 | j_up = "P1 Joy U", 14 | j_down = "P1 Joy D", 15 | j_left = "P1 Joy L", 16 | j_right = "P1 Joy R", 17 | c_up = "P1 C Up", 18 | c_down = "P1 C Down", 19 | c_left = "P1 C Left", 20 | c_right = "P1 C Right", 21 | start = "P1 Start", 22 | } 23 | self.old_ctrl = {} 24 | end 25 | 26 | function InputHandler:update(inputs) 27 | local ctrl = {} 28 | local pressed = {} 29 | local j = inputs or joypad.getimmediate() 30 | for k, v in pairs(self.binds) do 31 | ctrl[k] = j[v] 32 | end 33 | for k, v in pairs(ctrl) do 34 | pressed[k] = ctrl[k] and not self.old_ctrl[k] 35 | end 36 | self.old_ctrl = ctrl 37 | return ctrl, pressed 38 | end 39 | 40 | return InputHandler 41 | -------------------------------------------------------------------------------- /Lua/lib/classes/JoyWrapper.lua: -------------------------------------------------------------------------------- 1 | local JoyWrapper = Class() 2 | function JoyWrapper:init(handler, threshold) 3 | self.handler = handler 4 | self.old_ctrl = {} 5 | self.threshold = threshold or 80 6 | end 7 | 8 | function JoyWrapper:update(inputs) 9 | local j = inputs or joypad.getimmediate() 10 | local jj = joypad.get() 11 | local jx = jj['P1 X Axis'] 12 | local jy = jj['P1 Y Axis'] 13 | j["P1 Joy R"] = jx >= self.threshold or jj['P1 A Right'] 14 | j["P1 Joy L"] = jx <= -self.threshold or jj['P1 A Left'] 15 | j["P1 Joy U"] = jy >= self.threshold or jj['P1 A Up'] 16 | j["P1 Joy D"] = jy <= -self.threshold or jj['P1 A Down'] 17 | return self.handler:update(j) 18 | end 19 | 20 | return JoyWrapper 21 | -------------------------------------------------------------------------------- /Lua/lib/classes/Monitor.lua: -------------------------------------------------------------------------------- 1 | require "serialize" 2 | 3 | local Monitor = Class() 4 | function Monitor:init(name, a) 5 | self.name = name 6 | self.begin = a.addr 7 | self.len = a.type 8 | self.once = false 9 | self.old_bytes = {} 10 | self.modified = {} 11 | self.dirty = false 12 | end 13 | 14 | function Monitor:read() 15 | local raw = mainmemory.readbyterange(self.begin, self.len) 16 | local bytes = {} 17 | for k, v in pairs(raw) do 18 | bytes[k] = v 19 | end 20 | return bytes 21 | end 22 | 23 | function Monitor:diff() 24 | local bytes = self:read() 25 | local old_bytes = self.old_bytes 26 | if self.once then 27 | for i, v in pairs(bytes) do 28 | local x = v 29 | local x1 = old_bytes[i] 30 | if x ~= x1 then 31 | self:mark(i, x, x1) 32 | end 33 | end 34 | end 35 | self.old_bytes = bytes 36 | self.once = true 37 | end 38 | 39 | function Monitor:load(fn) 40 | self.modified = deserialize(fn) or {} 41 | self.dirty = false 42 | self.fn = fn 43 | end 44 | 45 | function Monitor:save(fn) 46 | if self.dirty then 47 | serialize(fn or self.fn, self.modified) 48 | self.dirty = false 49 | end 50 | end 51 | 52 | return Monitor 53 | -------------------------------------------------------------------------------- /Lua/lib/classes/SceneFlagMonitor.lua: -------------------------------------------------------------------------------- 1 | local Monitor = require "classes.Monitor" 2 | local SceneFlagMonitor = Class(Monitor) 3 | 4 | function SceneFlagMonitor:mark(i, x, x1) 5 | if not x1 then return end 6 | local now = emu.framecount() 7 | local diff = bit.bxor(x, x1) 8 | for which = 0, 7 do 9 | if bit.band(diff, 2^which) ~= 0 then 10 | local state = bit.band(x, 2^which) ~= 0 and 1 or 0 11 | local col = (3 - i)*8 + which 12 | local str = ('%s: %02i=%i'):format(self.name, col, state) 13 | printf('%s @%i', str, now) 14 | message(str, 180) 15 | end 16 | end 17 | end 18 | 19 | return SceneFlagMonitor 20 | -------------------------------------------------------------------------------- /Lua/lib/extra.lua: -------------------------------------------------------------------------------- 1 | local function strpad(num, count, pad) 2 | num = tostring(num) 3 | return (pad:rep(count)..num):sub(#num) 4 | end 5 | 6 | local function add_zeros(num, count) 7 | return strpad(num, count - 1, '0') 8 | end 9 | 10 | local function mixed_sorter(a, b) 11 | a = type(a) == 'number' and add_zeros(a, 16) or tostring(a) 12 | b = type(b) == 'number' and add_zeros(b, 16) or tostring(b) 13 | return a < b 14 | end 15 | 16 | -- loosely based on http://lua-users.org/wiki/SortedIteration 17 | -- the original didn't make use of closures for who knows why 18 | local function order_keys(t) 19 | local oi = {} 20 | for key in pairs(t) do 21 | table.insert(oi, key) 22 | end 23 | table.sort(oi, mixed_sorter) 24 | return oi 25 | end 26 | 27 | local function opairs(t, cache) 28 | local oi = cache and cache[t] or order_keys(t) 29 | if cache then 30 | cache[t] = oi 31 | end 32 | local i = 0 33 | return function() 34 | i = i + 1 35 | local key = oi[i] 36 | if key then return key, t[key] end 37 | end 38 | end 39 | 40 | return { 41 | strpad = strpad, 42 | add_zeros = add_zeros, 43 | mixed_sorter = mixed_sorter, 44 | order_keys = order_keys, 45 | opairs = opairs, 46 | } 47 | -------------------------------------------------------------------------------- /Lua/lib/flag manager.lua: -------------------------------------------------------------------------------- 1 | local function scene_flag_get_bb(scene, word, bit_) 2 | local byte = scene*0x14 + word*4 + 3 - math.floor(bit_/8) 3 | byte = byte + addrs.scene_flags_ingame.addr 4 | local bitmask = bit.lshift(1, bit_ % 8) 5 | return byte, bitmask 6 | end 7 | 8 | local function scene_flag_get(scene, word, bit_) 9 | local byte, bitmask = scene_flag_get_bb(scene, word, bit_) 10 | return bit.band(R1(byte), bitmask) ~= 0 11 | end 12 | -- TODO: check if current scene is scene id 13 | -- if it is, adjust scene_flag_current_x so it doesn't overwrite ingame flags 14 | local function scene_flag_reset(scene, word, bit_) 15 | local byte, bitmask = scene_flag_get_bb(scene, word, bit_) 16 | W1(byte, bit.band(R1(byte), 0xFF - bitmask)) 17 | end 18 | local function scene_flag_set(scene, word, bit_) 19 | local byte, bitmask = scene_flag_get_bb(scene, word, bit_) 20 | W1(byte, bit.bor(R1(byte), bitmask)) 21 | end 22 | 23 | local function event_flag_get_bb(byte, bit_) 24 | byte = byte + addrs.week_event_reg.addr 25 | local bitmask = bit.lshift(1, bit_ % 8) 26 | return byte, bitmask 27 | end 28 | 29 | local function event_flag_get(byte, bit_) 30 | local byte, bitmask = event_flag_get_bb(byte, bit_) 31 | return bit.band(R1(byte), bitmask) ~= 0 32 | end 33 | local function event_flag_reset(byte, bit_) 34 | local byte, bitmask = event_flag_get_bb(byte, bit_) 35 | W1(byte, bit.band(R1(byte), 0xFF - bitmask)) 36 | end 37 | local function event_flag_set(byte, bit_) 38 | local byte, bitmask = event_flag_get_bb(byte, bit_) 39 | W1(byte, bit.bor(R1(byte), bitmask)) 40 | end 41 | 42 | return globalize{ 43 | scene_flag_get_bb = scene_flag_get_bb, 44 | scene_flag_get = scene_flag_get, 45 | scene_flag_reset = scene_flag_reset, 46 | scene_flag_set = scene_flag_set, 47 | event_flag_get_bb = event_flag_get_bb, 48 | event_flag_get = event_flag_get, 49 | event_flag_reset = event_flag_reset, 50 | event_flag_set = event_flag_set, 51 | } 52 | -------------------------------------------------------------------------------- /Lua/lib/lips/Base.lua: -------------------------------------------------------------------------------- 1 | -- mostly just semantics over knife.base 2 | -- https://github.com/airstruck/knife/blob/master/knife/base.lua 3 | return { 4 | extend = function(self, subtype) 5 | subtype = subtype or {} 6 | local meta = { __index = subtype } 7 | return setmetatable(subtype, { 8 | __index = self, 9 | __call = function(self, ...) 10 | local obj = setmetatable({}, meta) 11 | return obj, obj:init(...) 12 | end 13 | }) 14 | end, 15 | 16 | init = function() end, 17 | } 18 | -------------------------------------------------------------------------------- /Lua/lib/lips/Expander.lua: -------------------------------------------------------------------------------- 1 | local insert = table.insert 2 | 3 | local path = string.gsub(..., "[^.]+$", "") 4 | local data = require(path.."data") 5 | local overrides = require(path.."overrides") 6 | local Statement = require(path.."Statement") 7 | local Reader = require(path.."Reader") 8 | 9 | local Expander = Reader:extend() 10 | function Expander:init(options) 11 | self.options = options or {} 12 | end 13 | 14 | function Expander:statement(...) 15 | local s = Statement(self.fn, self.line, ...) 16 | return s 17 | end 18 | 19 | function Expander:push(s) 20 | s:validate() 21 | insert(self.statements, s) 22 | end 23 | 24 | function Expander:push_new(...) 25 | self:push(self:statement(...)) 26 | end 27 | 28 | function Expander:pop(kind) 29 | local ret 30 | if kind == nil then 31 | ret = self.s[self.i] 32 | elseif kind == 'CPU' then 33 | ret = self:register(data.registers) 34 | elseif kind == 'FPU' then 35 | ret = self:register(data.fpu_registers) 36 | elseif kind == 'DEREF' then 37 | ret = self:deref() 38 | elseif kind == 'CONST' then 39 | ret = self:const() 40 | elseif kind == 'END' then 41 | if self.s[self.i] ~= nil then 42 | self:error('expected EOL; too many arguments') 43 | end 44 | return -- don't increment self.i past end of arguments 45 | else 46 | error('Internal Error: unknown kind, got '..tostring(kind)) 47 | end 48 | self.i = self.i + 1 49 | return ret 50 | end 51 | 52 | function Expander:expand(statements) 53 | -- third pass: expand pseudo-instructions and register arguments 54 | self.statements = {} 55 | for i, s in ipairs(statements) do 56 | self.s = s 57 | self.fn = s.fn 58 | self.line = s.line 59 | if s.type:sub(1, 1) == '!' then 60 | self:push(s) 61 | else 62 | local name = s.type 63 | local h = data.instructions[name] 64 | if h == nil then 65 | error('Internal Error: unknown instruction') 66 | end 67 | 68 | if data.one_register_variants[name] then 69 | self.i = 1 70 | local a = self:register(data.all_registers) 71 | local b = s[2] 72 | if b == nil or b.tt ~= 'REG' then 73 | insert(s, 2, self:token(a)) 74 | end 75 | elseif data.two_register_variants[name] then 76 | self.i = 1 77 | local a = self:register(data.all_registers) 78 | local b = self:register(data.all_registers) 79 | local c = s[3] 80 | if c == nil or c.tt ~= 'REG' then 81 | insert(s, 2, self:token(a)) 82 | end 83 | end 84 | 85 | if overrides[name] then 86 | self.i = 1 87 | overrides[name](self, name) 88 | self:pop('END') 89 | else 90 | self:push(s) 91 | end 92 | end 93 | end 94 | 95 | return self.statements 96 | end 97 | 98 | return Expander 99 | -------------------------------------------------------------------------------- /Lua/lib/lips/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015,2016 Connor Olding 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Lua/lib/lips/Parser.lua: -------------------------------------------------------------------------------- 1 | local insert = table.insert 2 | 3 | local path = string.gsub(..., "[^.]+$", "") 4 | local Base = require(path.."Base") 5 | local Token = require(path.."Token") 6 | local Lexer = require(path.."Lexer") 7 | local Collector = require(path.."Collector") 8 | local Preproc = require(path.."Preproc") 9 | local Expander = require(path.."Expander") 10 | local Dumper = require(path.."Dumper") 11 | 12 | local Parser = Base:extend() 13 | function Parser:init(writer, fn, options) 14 | self.writer = writer 15 | self.fn = fn or '(string)' 16 | self.main_fn = self.fn 17 | self.options = options or {} 18 | end 19 | 20 | function Parser:tokenize(asm) 21 | local lexer = Lexer(asm, self.main_fn, self.options) 22 | local tokens = {} 23 | 24 | local loop = true 25 | while loop do 26 | lexer:lex(function(tt, tok, fn, line) 27 | assert(tt, 'Internal Error: missing token') 28 | local t = Token(fn, line, tt, tok) 29 | insert(tokens, t) 30 | -- don't break if this is an included file's EOF 31 | if tt == 'EOF' and fn == self.main_fn then 32 | loop = false 33 | end 34 | end) 35 | end 36 | 37 | -- the lexer guarantees an EOL and EOF for a blank file 38 | assert(#tokens > 0, 'Internal Error: no tokens after preprocessing') 39 | 40 | local collector = Collector(self.options) 41 | return collector:collect(tokens, self.main_fn) 42 | end 43 | 44 | function Parser:dump() 45 | for i, s in ipairs(self.statements) do 46 | print(s.line, s.type, s:dump()) 47 | end 48 | end 49 | 50 | function Parser:parse(asm) 51 | self.statements = self:tokenize(asm) 52 | if self.options.debug_token then self:dump() end 53 | 54 | self.statements = Preproc(self.options):process(self.statements) 55 | if self.options.debug_pre then self:dump() end 56 | 57 | self.statements = Expander(self.options):expand(self.statements) 58 | if self.options.debug_post then self:dump() end 59 | 60 | local dumper = Dumper(self.writer, self.options) 61 | self.statements = dumper:load(self.statements) 62 | if self.options.debug_asm then self:dump() end 63 | 64 | if self.options.labels then 65 | dumper:export_labels(self.options.labels) 66 | end 67 | return dumper:dump() 68 | end 69 | 70 | return Parser 71 | -------------------------------------------------------------------------------- /Lua/lib/lips/Reader.lua: -------------------------------------------------------------------------------- 1 | local path = string.gsub(..., "[^.]+$", "") 2 | local Base = require(path.."Base") 3 | local Token = require(path.."Token") 4 | 5 | local Reader = Base:extend() 6 | -- no base init method 7 | 8 | -- Reader expects self.s to be set to a statement, and self.i to a token index 9 | 10 | function Reader:error(msg, got) 11 | if got ~= nil then 12 | msg = msg..', got '..tostring(got) 13 | end 14 | error(('%s:%d: Error: %s'):format(self.fn, self.line, msg), 2) 15 | end 16 | 17 | function Reader:token(t, ...) 18 | local new 19 | if type(t) == 'table' then 20 | new = Token(t, ...) 21 | else 22 | new = Token(self.fn, self.line, t, ...) 23 | end 24 | return new 25 | end 26 | 27 | function Reader:expect(tts) 28 | local t = self.s[self.i] 29 | if t == nil then 30 | local err = ("expected another argument for %s at position %i"):format(self.s.type, self.i) 31 | self:error(err) 32 | end 33 | 34 | self.fn = t.fn 35 | self.line = t.line 36 | 37 | for _, tt in pairs(tts) do 38 | if t.tt == tt then 39 | return t.ok 40 | end 41 | end 42 | 43 | local err 44 | if #tts == 1 then 45 | err = ("argument %i of %s expected type %s"):format(self.i, self.s.type, tts[1]) 46 | else 47 | err = ("unexpected type for argument %i of %s"):format(self.i, self.s.type) 48 | end 49 | self:error(err, t.tt) 50 | end 51 | 52 | function Reader:register(registers) 53 | self:expect{'REG'} 54 | local t = self.s[self.i] 55 | local numeric = registers[t.tok] 56 | if not numeric then 57 | self:error('wrong type of register', t.tok) 58 | end 59 | local new = Token(t) 60 | return new 61 | end 62 | 63 | function Reader:const(relative, no_label) 64 | self:expect{'NUM', 'LABELSYM', 'LABELREL'} 65 | local t = self.s[self.i] 66 | -- overrides will want to LUI a label; let portioned labels pass 67 | if no_label and not t.portion then 68 | self:expect{'NUM', 'LABELREL'} 69 | end 70 | local new = Token(t) 71 | if relative then -- you probably shouldn't use this in Preproc 72 | if t.tt == 'LABELSYM' then 73 | new.tt = 'LABELREL' 74 | elseif t.tt == 'NUM' then 75 | new.tt = 'REL' 76 | end 77 | end 78 | return new 79 | end 80 | 81 | function Reader:deref() 82 | self:expect{'DEREF'} 83 | local t = self.s[self.i] 84 | local new = Token(t) 85 | --new.tt = 'REG' 86 | return new 87 | end 88 | 89 | function Reader:peek(tt) 90 | local t = self.s[self.i] 91 | local seen = t and t.tt or nil 92 | if tt ~= nil then 93 | return seen == tt 94 | end 95 | return t 96 | end 97 | 98 | return Reader 99 | -------------------------------------------------------------------------------- /Lua/lib/lips/Statement.lua: -------------------------------------------------------------------------------- 1 | local path = string.gsub(..., "[^.]+$", "") 2 | local util = require(path.."util") 3 | local Base = require(path.."Base") 4 | local Token = require(path.."Token") 5 | 6 | local Statement = Base:extend() 7 | function Statement:init(...) 8 | local args = {...} 9 | if #args == 1 then 10 | local t = args[1] 11 | if util.parent(t) ~= Statement then 12 | error('Internal Error: 1-arg Statement:init expected a Statement', 3) 13 | end 14 | if type(t) == 'table' then 15 | for k, v in pairs(t) do 16 | self[k] = v 17 | end 18 | end 19 | elseif #args >= 3 then 20 | self.fn = args[1] 21 | self.line = args[2] 22 | self.type = args[3] 23 | for i, v in ipairs(args) do 24 | if i > 3 then 25 | self[i - 3] = v 26 | end 27 | end 28 | else 29 | error('Internal Error: Statement:init takes 1 or 3+ arguments', 3) 30 | end 31 | self:validate(1) 32 | return self 33 | end 34 | 35 | function Statement:validate(n) 36 | n = (n or 0) + 3 -- depth for error message 37 | if not self.fn then 38 | error('Internal Error: statements require a filename', n) 39 | end 40 | if not self.line then 41 | error('Internal Error: statements require a line number', n) 42 | end 43 | if not self.type then 44 | error('Internal Error: statement is missing a type', n) 45 | end 46 | for i, v in ipairs(self) do 47 | if util.parent(v) ~= Token then 48 | self[i] = Token(self.fn, self.line, v) 49 | end 50 | end 51 | end 52 | 53 | local boring = { 54 | tt = true, 55 | tok = true, 56 | fn = true, 57 | line = true, 58 | } 59 | 60 | function Statement:dump() 61 | local values = '' 62 | for j, t in ipairs(self) do 63 | local tok = t.tok 64 | if type(tok) == 'number' then 65 | tok = ("$%X"):format(tok) 66 | end 67 | values = values..'\t'..t.tt..'('..tostring(tok)..')' 68 | for k, v in pairs(t) do 69 | if not boring[k] then 70 | values = values..'['..k..'='..tostring(v)..']' 71 | end 72 | end 73 | end 74 | return values:sub(2) 75 | end 76 | 77 | return Statement 78 | -------------------------------------------------------------------------------- /Lua/lib/lips/Token.lua: -------------------------------------------------------------------------------- 1 | local floor = math.floor 2 | 3 | local path = string.gsub(..., "[^.]+$", "") 4 | local Base = require(path.."Base") 5 | local util = require(path.."util") 6 | 7 | local bitrange = util.bitrange 8 | 9 | local Token = Base:extend() 10 | function Token:init(...) 11 | local args = {...} 12 | if #args == 1 then 13 | local t = args[1] 14 | if type(t) == 'table' then 15 | for k, v in pairs(t) do 16 | self[k] = v 17 | end 18 | end 19 | elseif #args == 3 then 20 | self.fn = args[1] 21 | self.line = args[2] 22 | local t = args[3] 23 | if type(t) == 'table' then 24 | self.tt = t[1] 25 | self.tok = t[2] 26 | elseif type(t) == 'string' then 27 | self.tt = 'REG' 28 | self.tok = t 29 | elseif type(t) == 'number' then 30 | self.tt = 'NUM' 31 | self.tok = t 32 | else 33 | error('Internal Error: unknown type to construct', 3) 34 | end 35 | elseif #args == 4 then 36 | self.fn = args[1] 37 | self.line = args[2] 38 | self.tt = args[3] 39 | self.tok = args[4] 40 | else 41 | error('Internal Error: init takes 1, 3 or 4 arguments', 3) 42 | end 43 | self:validate(1) 44 | return self 45 | end 46 | 47 | function Token:validate(n) 48 | n = (n or 0) + 3 -- depth for error message 49 | if not self.fn then 50 | error('Internal Error: tokens require a filename', n) 51 | end 52 | if not self.line then 53 | error('Internal Error: tokens require a line number', n) 54 | end 55 | if not self.tt then 56 | error('Internal Error: token is missing a type', n) 57 | end 58 | if not self.tok then 59 | error('Internal Error: token is missing a value', n) 60 | end 61 | end 62 | 63 | function Token:set(key, value) 64 | if value == nil then 65 | value = true 66 | end 67 | self[key] = value 68 | return self 69 | end 70 | 71 | function Token:compute(n) 72 | local n = n or self.tok 73 | assert(n or self.tt == 'NUM', 'Internal Error: cannot compute a non-number token') 74 | 75 | if self.offset then 76 | n = n + self.offset 77 | end 78 | 79 | if self.index then 80 | n = n % 0x80000000 81 | n = floor(n/4) 82 | end 83 | if self.negate then 84 | n = -n 85 | end 86 | 87 | if self.portion == 'upper' then 88 | n = bitrange(n, 16, 31) 89 | elseif self.portion == 'lower' then 90 | n = bitrange(n, 0, 15) 91 | elseif self.portion == 'upperoff' then 92 | local upper = bitrange(n, 16, 31) 93 | local lower = bitrange(n, 0, 15) 94 | if lower >= 0x8000 then 95 | -- accommodate for offsets being signed 96 | upper = (upper + 1) % 0x10000 97 | end 98 | n = upper 99 | end 100 | 101 | if self.signed then 102 | if n >= 0x10000 or n < -0x8000 then 103 | return n, 'value out of range' 104 | end 105 | n = n % 0x10000 106 | end 107 | 108 | return n 109 | end 110 | 111 | return Token 112 | -------------------------------------------------------------------------------- /Lua/lib/lips/init.lua: -------------------------------------------------------------------------------- 1 | local lips = { 2 | _DESCRIPTION = 'Assembles MIPS assembly files for the R4300i CPU.', 3 | _URL = 'https://github.com/notwa/lips/', 4 | _LICENSE = [[ 5 | Copyright (C) 2015,2016 Connor Olding 6 | 7 | This program is licensed under the terms of the MIT License, and 8 | is distributed without any warranty. You should have received a 9 | copy of the license along with this program; see the file LICENSE. 10 | ]], 11 | } 12 | 13 | local path = string.gsub(..., "%.init$", "").."." 14 | local util = require(path.."util") 15 | local Parser = require(path.."Parser") 16 | 17 | lips.writers = require(path.."writers") 18 | 19 | function lips.assemble(fn_or_asm, writer, options) 20 | -- assemble MIPS R4300i assembly code. 21 | -- if fn_or_asm contains a newline; treat as assembly, otherwise load file. 22 | -- returns error message on error, or nil on success. 23 | fn_or_asm = tostring(fn_or_asm) 24 | local default_writer = not writer 25 | writer = writer or lips.writers.make_word() 26 | options = options or {} 27 | 28 | local function main() 29 | if options.offset then 30 | if options.origin or options.base then 31 | error('offset and origin/base options are mutually exclusive') 32 | end 33 | io.stderr:write('Warning: options.offset is deprecated.\n') 34 | options.origin = options.offset 35 | options.base = 0 36 | else 37 | options.origin = options.origin or 0 38 | options.base = options.base or 0x80000000 39 | end 40 | 41 | local fn = nil 42 | local asm 43 | if fn_or_asm:find('[\r\n]') then 44 | asm = fn_or_asm 45 | else 46 | fn = fn_or_asm 47 | asm = util.readfile(fn) 48 | options.path = fn:match(".*/") 49 | end 50 | 51 | local parser = Parser(writer, fn, options) 52 | parser:parse(asm) 53 | 54 | if default_writer then 55 | writer() 56 | end 57 | end 58 | 59 | if options.unsafe then 60 | return main() 61 | else 62 | local ok, err = pcall(main) 63 | return err 64 | end 65 | end 66 | 67 | return setmetatable(lips, { 68 | __call = function(self, ...) 69 | return self.assemble(...) 70 | end, 71 | }) 72 | -------------------------------------------------------------------------------- /Lua/lib/lips/util.lua: -------------------------------------------------------------------------------- 1 | local floor = math.floor 2 | local open = io.open 3 | 4 | local function readfile(fn, binary) 5 | local mode = binary and 'rb' or 'r' 6 | local f = open(fn, mode) 7 | if not f then 8 | local kind = binary and 'binary' or 'assembly' 9 | error('could not open '..kind..' file for reading: '..tostring(fn), 2) 10 | end 11 | local data = f:read('*a') 12 | f:close() 13 | return data 14 | end 15 | 16 | local function bitrange(x, lower, upper) 17 | return floor(x / 2^lower) % 2^(upper - lower + 1) 18 | end 19 | 20 | local function parent(t) 21 | local mt = getmetatable(t) 22 | if mt == nil then 23 | return nil 24 | end 25 | return mt.__index 26 | end 27 | 28 | local function signs(s) 29 | local start, end_ = s:find('[+-]+') 30 | if start ~= 1 then 31 | return 0 32 | end 33 | if s:sub(1, 1) == '+' then 34 | return end_ 35 | elseif s:sub(1, 1) == '-' then 36 | return -end_ 37 | end 38 | end 39 | 40 | -- http://stackoverflow.com/a/9279009 41 | local loadcode 42 | if setfenv and loadstring then -- 5.1, JIT 43 | loadcode = function(code, environment) 44 | local f = assert(loadstring(code)) 45 | setfenv(f, environment) 46 | return f 47 | end 48 | else -- 5.2, 5.3 49 | loadcode = function(code, environment) 50 | return assert(load(code, nil, 't', environment)) 51 | end 52 | end 53 | 54 | local data_sizes = { 55 | BYTE = 1, 56 | HALFWORD = 2, 57 | WORD = 4, 58 | } 59 | 60 | local function measure_data(s) 61 | assert(s and s.type == '!DATA', 'Internal Error: expected !DATA statement') 62 | local n = 0 63 | for i, t in ipairs(s) do 64 | if t.tt == 'LABELSYM' then 65 | n = n + 4 66 | elseif t.tt == 'NUM' then 67 | if t.size == nil then 68 | error('Internal Error: unspecified data size in NUM') 69 | end 70 | local size = data_sizes[t.size] 71 | if size == nil then 72 | error('Internal Error: unknown data size in NUM, got '..tostring(t.size)) 73 | end 74 | n = n + size 75 | elseif t.tt == 'WORDS' then 76 | n = n + #t.tok * 4 77 | elseif t.tt == 'HALFWORDS' then 78 | n = n + #t.tok * 2 79 | elseif t.tt == 'BYTES' then 80 | n = n + #t.tok * 1 81 | else 82 | error('Internal Error: unknown data type in !DATA, got '..tostring(t.tt)) 83 | end 84 | end 85 | return n 86 | end 87 | 88 | return { 89 | readfile = readfile, 90 | bitrange = bitrange, 91 | parent = parent, 92 | signs = signs, 93 | loadcode = loadcode, 94 | measure_data = measure_data, 95 | } 96 | -------------------------------------------------------------------------------- /Lua/lib/lips/writers.lua: -------------------------------------------------------------------------------- 1 | local writers = {} 2 | 3 | function writers.make_word() 4 | local buff = {} 5 | local max = -1 6 | return function(pos, b) 7 | if pos then 8 | buff[pos] = ("%02X"):format(b) 9 | if pos > max then 10 | max = pos 11 | end 12 | elseif max >= 0 then 13 | for i=0, max, 4 do 14 | local a = buff[i+0] or '00' 15 | local b = buff[i+1] or '00' 16 | local c = buff[i+2] or '00' 17 | local d = buff[i+3] or '00' 18 | print(a..b..c..d) 19 | end 20 | end 21 | end 22 | end 23 | 24 | function writers.make_verbose() 25 | local buff = {} 26 | local max = -1 27 | return function(pos, b) 28 | if pos then 29 | buff[pos] = b 30 | if pos > max then 31 | max = pos 32 | end 33 | elseif max >= 0 then 34 | for i=0, max, 4 do 35 | local a = buff[i+0] or nil 36 | local b = buff[i+1] or nil 37 | local c = buff[i+2] or nil 38 | local d = buff[i+3] or nil 39 | if a or b or c or d then 40 | a = a and ("%02X"):format(a) or '--' 41 | b = b and ("%02X"):format(b) or '--' 42 | c = c and ("%02X"):format(c) or '--' 43 | d = d and ("%02X"):format(d) or '--' 44 | print(('%08X %s'):format(i, a..b..c..d)) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | 51 | function writers.make_tester() 52 | local buff = {} 53 | local max = -1 54 | return function(pos, b) 55 | if pos then 56 | buff[pos] = b 57 | if pos > max then 58 | max = pos 59 | end 60 | elseif max >= 0 then 61 | local s = '' 62 | local last_i = 0 63 | for i=0, max, 4 do 64 | local a = buff[i+0] or nil 65 | local b = buff[i+1] or nil 66 | local c = buff[i+2] or nil 67 | local d = buff[i+3] or nil 68 | if a or b or c or d then 69 | a = a and ("%02X"):format(a) or '--' 70 | b = b and ("%02X"):format(b) or '--' 71 | c = c and ("%02X"):format(c) or '--' 72 | d = d and ("%02X"):format(d) or '--' 73 | if last_i ~= i - 4 then 74 | s = s..('@%08X\n'):format(i) 75 | end 76 | s = s..a..b..c..d.."\n" 77 | last_i = i 78 | end 79 | end 80 | return s 81 | end 82 | end 83 | end 84 | 85 | function writers.make_gameshark() 86 | local buff = {} 87 | local max = -1 88 | return function(pos, b) 89 | if pos then 90 | pos = pos % 0x80000000 91 | buff[pos] = b 92 | if pos > max then 93 | max = pos 94 | end 95 | elseif max >= 0 then 96 | for i=0, max, 2 do 97 | local a = buff[i+0] 98 | local b = buff[i+1] 99 | a = a and ("%02X"):format(a) 100 | b = b and ("%02X"):format(b) 101 | if a and b then 102 | print(('81%06X %s'):format(i, a..b)) 103 | elseif a then 104 | print(('80%06X 00%s'):format(i, a)) 105 | elseif b then 106 | print(('80%06X 00%s'):format(i + 1, b)) 107 | end 108 | end 109 | end 110 | end 111 | end 112 | 113 | return writers 114 | -------------------------------------------------------------------------------- /Lua/lib/menu input handlers.lua: -------------------------------------------------------------------------------- 1 | local function handle_alt_input(handle, ctrl, pressed) 2 | for _, v in ipairs{'left', 'right', 'up', 'down'} do 3 | ctrl[v] = ctrl['d_'..v] 4 | pressed[v] = pressed['d_'..v] 5 | end 6 | pressed.enter = false 7 | ctrl.enter = false 8 | local open_close = ctrl.L and ctrl.R and (pressed.L or pressed.R) 9 | local hide = ctrl.L and ctrl.Z and (pressed.L or pressed.Z) 10 | if open_close then 11 | if handle.menu then -- if menu is open 12 | handle:navigate('close') 13 | else 14 | pressed.enter = true 15 | ctrl.enter = true 16 | end 17 | else 18 | if hide then 19 | handle:navigate('hide') 20 | elseif pressed.L then 21 | handle:navigate('back') 22 | elseif handle.menu then 23 | pressed.enter = pressed.R 24 | ctrl.enter = ctrl.R 25 | end 26 | end 27 | handle:update(ctrl, pressed) 28 | end 29 | 30 | local function handle_eat_input(handle, ctrl, pressed) 31 | for _, v in ipairs{'left', 'right', 'up', 'down'} do 32 | ctrl[v] = ctrl['d_'..v] or ctrl['j_'..v] or ctrl['c_'..v] 33 | pressed[v] = pressed['d_'..v] or pressed['j_'..v] or pressed['c_'..v] 34 | end 35 | if not handle.menu then 36 | pressed.enter = pressed.L 37 | else 38 | if pressed.L then 39 | handle:navigate('close') 40 | elseif pressed.Z then 41 | handle:navigate('hide') 42 | elseif pressed.R or pressed.B then 43 | handle:navigate('back') 44 | else 45 | pressed.enter = pressed.A or pressed.L 46 | ctrl.enter = ctrl.A 47 | end 48 | 49 | --joypad.set({}, 1) 50 | --joypad.setanalog({["X Axis"]=false, ["Y Axis"]=false}, 1) 51 | end 52 | handle:update(ctrl, pressed) 53 | end 54 | 55 | return globalize{ 56 | handle_eat_input = handle_eat_input, 57 | handle_alt_input = handle_alt_input, 58 | } 59 | -------------------------------------------------------------------------------- /Lua/lib/messages.lua: -------------------------------------------------------------------------------- 1 | -- gui.addmessage sucks so we're doing this our way 2 | 3 | local function T(x, y, color, pos, s, ...) 4 | if #{...} > 0 then 5 | s = s:format(...) 6 | end 7 | gui.text(10*x + 2, 16*y + 4, s, color or "white", pos or "bottomright") 8 | end 9 | 10 | local function T_BR(x, y, color, ...) T(x, y, color, "bottomright", ...) end 11 | local function T_BL(x, y, color, ...) T(x, y, color, "bottomleft", ...) end 12 | local function T_TL(x, y, color, ...) T(x, y, color, "topleft", ...) end 13 | local function T_TR(x, y, color, ...) T(x, y, color, "topright", ...) end 14 | 15 | local messages = {} 16 | local __messages_then = 0 17 | 18 | local function message(text, frames) 19 | local now = emu.framecount() 20 | frames = frames or 60 21 | local when = now + frames 22 | table.insert(messages, {text=text, when=when}) 23 | end 24 | 25 | local function draw_messages() 26 | local now = emu.framecount() 27 | if now == __messages_then then 28 | -- already drawn this frame 29 | return 30 | end 31 | if now ~= __messages_then + 1 then 32 | -- nonlinearity in time, probably a savestate 33 | messages = {} 34 | end 35 | 36 | local okay = {} 37 | for i, t in ipairs(messages) do 38 | if now < t.when then 39 | table.insert(okay, t) 40 | end 41 | end 42 | for i, t in ipairs(okay) do 43 | T_BL(0, #okay - i, nil, t.text) 44 | end 45 | 46 | messages = okay 47 | __messages_then = now 48 | end 49 | 50 | local __dprinted = {} 51 | 52 | local function dprint(...) -- defer print 53 | -- helps with lag from printing directly to Bizhawk's console 54 | table.insert(__dprinted, {...}) 55 | end 56 | 57 | local function dprintf(fmt, ...) 58 | table.insert(__dprinted, fmt:format(...)) 59 | end 60 | 61 | local function print_deferred() 62 | local buff = '' 63 | for i, t in ipairs(__dprinted) do 64 | if type(t) == 'string' then 65 | buff = buff..t..'\n' 66 | elseif type(t) == 'table' then 67 | local s = '' 68 | for j, v in ipairs(t) do 69 | s = s..tostring(v) 70 | if j ~= #t then s = s..'\t' end 71 | end 72 | buff = buff..s..'\n' 73 | end 74 | end 75 | if #buff > 0 then 76 | print(buff:sub(1, #buff - 1)) 77 | end 78 | __dprinted = {} 79 | end 80 | 81 | return globalize{ 82 | T = T, 83 | T_BR = T_BR, 84 | T_BL = T_BL, 85 | T_TL = T_TL, 86 | T_TR = T_TR, 87 | dprint = dprint, 88 | dprintf = dprintf, 89 | print_deferred = print_deferred, 90 | message = message, 91 | draw_messages = draw_messages, 92 | } 93 | -------------------------------------------------------------------------------- /Lua/lib/serialize.lua: -------------------------------------------------------------------------------- 1 | -- it's simple, dumb, unsafe, incomplete, and it gets the damn job done 2 | 3 | local type = type 4 | local extra = require "extra" 5 | local opairs = extra.opairs 6 | local tostring = tostring 7 | local open = io.open 8 | local strfmt = string.format 9 | local strrep = string.rep 10 | 11 | local function kill_bom(s) 12 | if #s >= 3 and s:byte(1)==0xEF and s:byte(2)==0xBB and s:byte(3)==0xBF then 13 | return s:sub(4) 14 | end 15 | return s 16 | end 17 | 18 | local function sanitize(v) 19 | local force = type(v) == 'string' and v:sub(1, 1):match('%d') 20 | force = force and true or false 21 | return type(v) == 'string' and strfmt('%q', v) or tostring(v), force 22 | end 23 | 24 | local function _serialize(value, writer, level) 25 | level = level or 1 26 | if type(value) == 'table' then 27 | local indent = strrep('\t', level) 28 | writer('{\n') 29 | for key,value in opairs(value) do 30 | local sane, force = sanitize(key) 31 | local keyval = (sane == '"'..key..'"' and not force) and key or '['..sane..']' 32 | writer(indent..keyval..' = ') 33 | _serialize(value, writer, level + 1) 34 | writer(',\n') 35 | end 36 | writer(strrep('\t', level - 1)..'}') 37 | else 38 | local sane, force = sanitize(value) 39 | writer(sane) 40 | end 41 | end 42 | 43 | local function _deserialize(script) 44 | local f = loadstring(kill_bom(script)) 45 | if f ~= nil then 46 | return f() 47 | else 48 | print('WARNING: no function to deserialize with') 49 | return nil 50 | end 51 | end 52 | 53 | local function serialize(path, value) 54 | local file = open(path, 'w') 55 | if not file then return end 56 | file:write("return ") 57 | _serialize(value, function(...) 58 | file:write(...) 59 | end) 60 | file:write("\n") 61 | file:close() 62 | end 63 | 64 | local function deserialize(path) 65 | local file = open(path, 'r') 66 | if not file then return end 67 | local script = file:read('*a') 68 | local value = _deserialize(script) 69 | file:close() 70 | return value 71 | end 72 | 73 | return globalize{ 74 | serialize = serialize, 75 | deserialize = deserialize, 76 | } 77 | -------------------------------------------------------------------------------- /Lua/lib/setup.lua: -------------------------------------------------------------------------------- 1 | if _require then return end 2 | _require = require 3 | 4 | package.path = package.path..';./lib/?.lua' 5 | package.path = package.path..';./lib/?/init.lua' 6 | 7 | require "strict" 8 | 9 | local function depend(path) 10 | if package and package.loaded and package.loaded[path] then 11 | package.loaded[path] = nil 12 | end 13 | return _require(path) 14 | end 15 | 16 | local function globalize(t) 17 | for k, v in pairs(t) do 18 | rawset(_G, k, v) 19 | end 20 | end 21 | 22 | return globalize{ 23 | depend = depend, 24 | globalize = globalize, 25 | } 26 | -------------------------------------------------------------------------------- /Lua/lib/strict.lua: -------------------------------------------------------------------------------- 1 | local mt = getmetatable(_G) 2 | if mt == nil then 3 | mt = {} 4 | setmetatable(_G, mt) 5 | end 6 | 7 | function mt.__newindex(t, n, v) 8 | if n == '_TEMP_BIZHAWK_RULES_' or n == 'VERSION_OVERRIDE' then 9 | rawset(t, n, v) 10 | return 11 | end 12 | error("cannot assign undeclared global '" .. tostring(n) .. "'", 2) 13 | end 14 | 15 | function mt.__index(t, n) 16 | if n == '_TEMP_BIZHAWK_RULES_' then 17 | return 18 | end 19 | error("cannot use undeclared global '" .. tostring(n) .. "'", 2) 20 | end 21 | -------------------------------------------------------------------------------- /Lua/menus/playas.lua: -------------------------------------------------------------------------------- 1 | local playas_child = Passive() 2 | function playas_child:tick_on() 3 | addrs.age_modifier_global(1) 4 | end 5 | local playas_adult = Passive() 6 | function playas_adult:tick_on() 7 | addrs.age_modifier_global(0) 8 | end 9 | 10 | local PassiveResetMask = Class(Passive) 11 | function PassiveResetMask:on() 12 | Passive.on(self) 13 | addrs.mask_worn(0) 14 | end 15 | 16 | local playas_human = PassiveResetMask() 17 | function playas_human:tick_on() 18 | addrs.transformation(4) 19 | end 20 | local playas_deku = PassiveResetMask() 21 | function playas_deku:tick_on() 22 | addrs.transformation(3) 23 | end 24 | local playas_goron = PassiveResetMask() 25 | function playas_goron:tick_on() 26 | addrs.transformation(1) 27 | end 28 | local playas_zora = PassiveResetMask() 29 | function playas_zora:tick_on() 30 | addrs.transformation(2) 31 | end 32 | local playas_fd = PassiveResetMask() 33 | function playas_fd:tick_on() 34 | addrs.transformation(0) 35 | end 36 | 37 | local playas_group = {} 38 | local playas_mm_group = {} 39 | return oot and Menu{ 40 | Screen{ 41 | Text("Play as..."), 42 | Radio("Default", playas_group, dummy), 43 | Radio("Child Link", playas_group, playas_child), 44 | Radio("Adult Link", playas_group, playas_adult), 45 | Text(""), 46 | Oneshot("Reload Scene", reload_scene), 47 | Back(), 48 | }, 49 | } or Menu{ 50 | Screen{ 51 | Text("Play as..."), 52 | Radio("Default", playas_mm_group, dummy), 53 | Radio("Human Link", playas_mm_group, playas_human), 54 | Radio("Deku Link", playas_mm_group, playas_deku), 55 | Radio("Goron Link", playas_mm_group, playas_goron), 56 | Radio("Zora Link", playas_mm_group, playas_zora), 57 | Radio("Fierce Deity", playas_mm_group, playas_fd), 58 | Text(""), 59 | Oneshot("Reload Scene", reload_scene), 60 | Back(), 61 | }, 62 | } 63 | -------------------------------------------------------------------------------- /Lua/menus/warp oot.lua: -------------------------------------------------------------------------------- 1 | local ins = table.insert 2 | local entrance_names = require "data.entrance names oot" 3 | local maxscene = #entrance_names 4 | 5 | local per_page = 16 6 | local pagecount = math.ceil((maxscene + 1)/per_page) 7 | 8 | local scenes_pages = {} 9 | for si=0, maxscene do 10 | local i = si 11 | local page = math.floor(si/per_page) + 1 12 | 13 | if si % per_page == 0 then 14 | scenes_pages[page] = {} 15 | local s = ("Warp to Scene #%i/%i"):format(page, pagecount) 16 | ins(scenes_pages[page], Text(s)) 17 | end 18 | 19 | local entrance_items = {} 20 | local entrances = entrance_names[i] 21 | local scene_name = entrances.name 22 | 23 | ins(entrance_items, Text( ("Warp to %s"):format(scene_name) )) 24 | 25 | for j=0,24 do 26 | local e = entrances[j] 27 | local ename = "n/a" 28 | local edest = 0 29 | if e == nil then 30 | if j ~= 0 then break end 31 | ename = "n/a" 32 | edest = 0 33 | else 34 | ename = e[1] 35 | edest = e[2] 36 | if ename == nil then 37 | if j ~= 0 then break end 38 | ename = "n/a" 39 | edest = 0 40 | end 41 | end 42 | local callback = function() 43 | addrs.warp_destination(edest) 44 | addrs.warp_begin(0x14) 45 | end 46 | ins(entrance_items, Oneshot(ename, callback)) 47 | end 48 | 49 | ins(entrance_items, Text("")) 50 | ins(entrance_items, Text("Cutscenes... (TODO)")) 51 | ins(entrance_items, Text("")) 52 | ins(entrance_items, Back()) 53 | local entrance_menu = Menu{Screen(entrance_items)} 54 | ins(scenes_pages[page], LinkTo(scene_name, entrance_menu)) 55 | end 56 | 57 | local menu = Menu{} 58 | for i, v in ipairs(scenes_pages) do 59 | ins(v, Text("")) 60 | ins(v, Back()) 61 | ins(menu.screens, Screen(v)) 62 | end 63 | 64 | return menu 65 | -------------------------------------------------------------------------------- /Lua/menus/warp.lua: -------------------------------------------------------------------------------- 1 | local ins = table.insert 2 | local entrance_names = require "data.entrance names" 3 | local scene_id_to_entrance_id = require "data.scene to entrance" 4 | 5 | local function make_exit_value(s, e, c) 6 | return bit.lshift(s, 9) + bit.lshift(e, 4) + c 7 | end 8 | 9 | local per_page = 16 10 | 11 | local function fill_entrances(entrance_items, entrances, si) 12 | for j=0,32 do 13 | local ename = entrances[j] 14 | if ename == nil then 15 | if j ~= 0 then break end 16 | ename = "[crash?]" 17 | end 18 | local callback = function() 19 | addrs.warp_destination(make_exit_value(si,j,0)) 20 | addrs.warp_begin(0x14) 21 | end 22 | ins(entrance_items, Oneshot(ename, callback)) 23 | end 24 | 25 | ins(entrance_items, Text("")) 26 | ins(entrance_items, Text("Cutscenes... (TODO)")) 27 | ins(entrance_items, Text("")) 28 | ins(entrance_items, Back()) 29 | end 30 | 31 | local scenes_pages = {} 32 | if entrance_names.custom_order then 33 | local lut = {} 34 | for si=0x00,0x7F do 35 | local i = scene_id_to_entrance_id[si] 36 | if i ~= nil then 37 | local e = entrance_names[i] 38 | if e.name ~= nil then 39 | --print(e.name, ("%04X"):format(si * 0x200)) 40 | lut[e.name] = {si=si, i=i} 41 | end 42 | end 43 | end 44 | 45 | local page = 1 46 | scenes_pages[page] = {} 47 | for i, v in ipairs(entrance_names.custom_order) do 48 | if v == "\n" then 49 | page = page + 1 50 | scenes_pages[page] = {} 51 | elseif lut[v] ~= nil then 52 | local entrance_items = {} 53 | local entrances = entrance_names[lut[v].i] 54 | local scene_name = entrances.name 55 | 56 | ins(entrance_items, Text( ("Warp to %s"):format(scene_name) )) 57 | fill_entrances(entrance_items, entrances, lut[v].si) 58 | local entrance_menu = Menu{Screen(entrance_items)} 59 | ins(scenes_pages[page], LinkTo(scene_name, entrance_menu)) 60 | else 61 | ins(scenes_pages[page], Text(v)) 62 | end 63 | end 64 | 65 | for i=1,page do 66 | local s = ("Warp to Scene #%i/%i"):format(i, page) 67 | ins(scenes_pages[i], 1, Text(s)) 68 | ins(scenes_pages[i], Text("")) 69 | ins(scenes_pages[i], Back()) 70 | end 71 | 72 | else 73 | for si=0x00,0x7F do 74 | local i = scene_id_to_entrance_id[si] 75 | local page = math.floor(si/per_page) + 1 76 | 77 | if si % per_page == 0 then 78 | scenes_pages[page] = {} 79 | local s = ("Warp to Scene #%i/8"):format(page) 80 | ins(scenes_pages[page], Text(s)) 81 | end 82 | 83 | local entrance_items = {} 84 | local entrances = {} 85 | local scene_name = '[crash]' 86 | if i ~= nil then 87 | entrances = entrance_names[i] 88 | scene_name = entrances.name 89 | end 90 | 91 | ins(entrance_items, Text( ("Warp to %s"):format(scene_name) )) 92 | fill_entrances(entrance_items, entrances, si) 93 | local entrance_menu = Menu{Screen(entrance_items)} 94 | ins(scenes_pages[page], LinkTo(scene_name, entrance_menu)) 95 | 96 | if si % per_page == per_page - 1 then 97 | ins(scenes_pages[page], Text("")) 98 | ins(scenes_pages[page], Back()) 99 | end 100 | end 101 | end 102 | 103 | local screens = {} 104 | for i, v in ipairs(scenes_pages) do 105 | ins(screens, Screen(v)) 106 | end 107 | 108 | return Menu(screens) 109 | -------------------------------------------------------------------------------- /Lua/monitor actors.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "messages" 5 | require "classes" 6 | require "actors" 7 | 8 | local suffix = oot and " oot" or "" 9 | local damage_names = require("data.damage names"..suffix) 10 | 11 | -- creating an object every time is a bit slow, so 12 | -- using a template to offset from will do for now. 13 | local actor_t = Actor(0) 14 | 15 | -- for figuring out actor variables 16 | local debug_mode = false 17 | 18 | local debug_watch = mm and { 19 | {'room_number', '%02X'}, 20 | --{'x_rot_init', '%04X'}, 21 | --{'y_rot_init', '%04X'}, 22 | --{'z_rot_init', '%04X'}, 23 | --{'unk_1A', '%02X'}, 24 | {'unk_1E', '%02X'}, 25 | {'unk_20', '%08X'}, 26 | {'unk_22', '%04X'}, 27 | --{'unnamed_x_rot', '%04X'}, 28 | --{'unnamed_y_rot', '%04X'}, 29 | --{'unnamed_z_rot', '%04X'}, 30 | {'unk_36', '%04X'}, 31 | {'unk_38', '%02X'}, 32 | {'x', '%9.3f'}, 33 | {'y', '%9.3f'}, 34 | {'z', '%9.3f'}, 35 | {'lin_vel_old', '%9.3f'}, 36 | {'unk_54', '%9.3f'}, 37 | {'unk_74', '%9.3f'}, 38 | {'unk_78', '%9.3f'}, 39 | } or {} 40 | 41 | local function longbinary(x) 42 | return ('%032s'):format(bizstring.binary(x)) 43 | end 44 | 45 | local function focus(actor, dump) 46 | local color = actor.name:sub(1,1) == "?" and "red" or "orange" 47 | local flags = longbinary(actor.flags) 48 | local y = debug_mode and #debug_watch + 9 or 9 49 | local write = function(color, fmt, ...) 50 | T_BL(0, y, color, fmt, ...) 51 | y = y - 1 52 | return y + 1 53 | end 54 | 55 | write(nil, 'Hi: %s', flags:sub(1,16)) 56 | write(nil, 'Lo: %s', flags:sub(17,32)) 57 | write(color, actor.name) 58 | write(nil, 'HP: %02X', actor.hp) 59 | write('cyan', 'No.: %03X', actor.num) 60 | write(nil, 'Var: %04X', actor.var) 61 | write(nil, '80%06X', actor.addr) 62 | write(nil, 'type: %3i', actor.at) 63 | write(nil, 'index: %3i', actor.ai) 64 | write(nil, 'count: %3i', actor.type_count) 65 | 66 | if debug_mode then 67 | local a = Actor(actor.addr) 68 | 69 | for i, t in ipairs(debug_watch) do 70 | write(nil, '%12s: '..t[2], t[1], a[t[1]]()) 71 | end 72 | 73 | if dump then 74 | a.unk_38(math.random(0, 0xFF)) 75 | --print(R1(actor.addr + 0x1E)) 76 | --W1(actor.addr + actor_t.unk_1E.addr, 0xFF) 77 | end 78 | --a.x_old(a.x()) 79 | --a.y_old(a.y()) 80 | --a.z_old(a.z()) 81 | 82 | return -- skip damage table crap 83 | end 84 | 85 | local dmg = deref(R4(actor.addr + actor_t.damage_table.addr)) 86 | if dmg then 87 | for i = 0, 31 do 88 | local name = damage_names[i] 89 | local str = ('%9s: %02X'):format(name, R1(dmg + i)) 90 | 91 | if i >= 16 then 92 | T_TR(0, i - 16, nil, str) 93 | else 94 | T_TL(0, i, nil, str) 95 | end 96 | end 97 | end 98 | 99 | if dump then 100 | console.clear() 101 | local s = ("%04X\t%02X\t%02X"):format(actor.num, actor.at, actor.hp) 102 | if dmg then 103 | for i = 0, 31 do 104 | s = s..("\t%02X"):format(R1(dmg + i)) 105 | end 106 | end 107 | print(s) 108 | end 109 | end 110 | 111 | local input_handler = InputHandler{ 112 | enter = "P1 L", 113 | up = "P1 DPad U", 114 | down = "P1 DPad D", 115 | left = "P1 DPad L", 116 | right = "P1 DPad R", 117 | } 118 | 119 | globalize{ 120 | focus = focus, 121 | } 122 | 123 | local al = ActorLister(input_handler, debug_mode) 124 | event.onexit(function() al = nil end, 'actor cleanup') 125 | event.onloadstate(function() if al then al:wipe() end end, 'actor wipe') 126 | while oot or mm do 127 | local now = emu.framecount() 128 | al:runwrap(now) 129 | print_deferred() 130 | emu.frameadvance() 131 | end 132 | -------------------------------------------------------------------------------- /Lua/monitor animations.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "serialize" 5 | 6 | local anim_addr = addrs.link_actor.animation_id.addr 7 | local fn = mm and 'data/_anims_seen.lua' or 'data/_anims_seen_oot.lua' 8 | local anims_seen = deserialize(fn) or {} 9 | 10 | while mm or oot do 11 | local anim_id = mainmemory.read_u16_be(anim_addr) 12 | local actor_loaded = mainmemory.read_u8(anim_addr - 2) == 4 13 | local hexid = ('%04X'):format(anim_id) 14 | local frame = emu.framecount() 15 | if actor_loaded then 16 | gui.text(2, 4, hexid, nil, 'white', "bottomleft") 17 | if not anims_seen[anim_id] then 18 | anims_seen[anim_id] = true 19 | print(frame, hexid) 20 | serialize(fn, anims_seen) 21 | end 22 | end 23 | emu.frameadvance() 24 | end 25 | -------------------------------------------------------------------------------- /Lua/monitor debug memory editor.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "classes" 5 | 6 | local blocknames = { 7 | 'R ', 'RS', 'RO', 'RP', 8 | 'RQ', 'RM', 'RY', 'RD', 9 | 'RU', 'RI', 'RZ', 'RC', 10 | 'RN', 'RK', 'RX', 'Rc', 11 | 'Rs', 'Ri', 'RW', 'RA', 12 | 'RV', 'RH', 'RG', 'Rm', 13 | 'Rn', 'RB', 'Rd', 'Rk', 14 | 'Rb', 15 | } 16 | 17 | local function distribute_index(ih) 18 | local block = math.floor(ih/16/6) 19 | local ir = ih - block*16*6 20 | local page = math.floor(ir/16) 21 | local row = ir - page*16 22 | return block, page, row 23 | end 24 | 25 | local ShortMonitor = Class(Monitor) 26 | 27 | function ShortMonitor:mark(i, x, x1) 28 | local ih = math.floor(i/2) 29 | if not self.modified[ih] then 30 | self.modified[ih] = true 31 | self.dirty = true 32 | local block, page, row = distribute_index(ih) 33 | printf('%2s Page %1i Row %3i', blocknames[block+1], page+1, row+1) 34 | end 35 | end 36 | 37 | function ShortMonitor:dump() 38 | local buff = '' 39 | for i=0, self.len/2 - 1 do 40 | local ih = i 41 | local block, page, row = distribute_index(ih) 42 | local mod = self.modified[ih] 43 | local value = R2(self.begin + ih*2) 44 | local vs = mod and 'n/a' or ('%04X'):format(value) 45 | local name = ('%s%02i'):format(blocknames[block+1], page*16 + row) 46 | local s = ('%s\t%i\t%i\t%s\n'):format(name, page+1, row+1, vs) 47 | buff = buff..s 48 | end 49 | print(buff) 50 | end 51 | 52 | -- 2 bytes each, 16 values per page, 6 pages per block, 29 blocks 53 | -- = 5568 bytes (0x15C0) 54 | local me = ShortMonitor('me', A(0x210A24, 0x15C0)) 55 | me:load('data/_ootmemod.lua') 56 | while version == "O EUDB MQ" do 57 | me:diff() 58 | me:save() 59 | emu.frameadvance() 60 | end 61 | -------------------------------------------------------------------------------- /Lua/monitor debug text.lua: -------------------------------------------------------------------------------- 1 | -- use with inject.lua on O EUDB MQ 2 | require "lib.setup" 3 | require "boilerplate" 4 | require "addrs.init" 5 | 6 | local buffer = 0x700700 7 | 8 | local vfc = A(0x168960, 4) 9 | 10 | -- $ tail -f oot\ debug.txt | iconv -f euc-jp 11 | local f = io.open('oot debug.txt', 'w+b') 12 | 13 | local ignore_vframes = true 14 | 15 | while version == "O EUDB MQ" do 16 | local pos = buffer 17 | local str = '' 18 | local fmt = '%c' 19 | while true do 20 | local b = R1(pos) 21 | pos = pos + 1 22 | if b == 0 then 23 | break 24 | end 25 | str = str..string.char(b) 26 | end 27 | f:write(str) 28 | f:flush() 29 | if ignore_vframes then 30 | if R4(0x7006FC) == 0 then 31 | W4(0x7006F8, 0x80700700) 32 | W1(0x700700, 0) 33 | else 34 | print('buffer in use') 35 | end 36 | emu.frameadvance() 37 | else 38 | local old = vfc() 39 | for i=1,30 do 40 | emu.frameadvance() 41 | local new = vfc() 42 | if new ~= old then break end 43 | end 44 | end 45 | end 46 | 47 | f:close() 48 | -------------------------------------------------------------------------------- /Lua/monitor epona.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "messages" 5 | require "actors" 6 | 7 | local actor_names = require "data.actor names" 8 | 9 | local epona_addr = 0 10 | while true do 11 | local nearest = {} 12 | local offset = 0x800000 13 | 14 | for at, ai, addr in iter_actors() do 15 | local actor_number = R2(addr) 16 | local name = actor_names[actor_number] or "[error]" 17 | local size = R4(addr - 0xC) -- read linked list data above the actor 18 | if actor_number == 0x00D then 19 | epona_addr = addr 20 | end 21 | 22 | if epona_addr then 23 | local diff = addr - epona_addr 24 | if diff >= 0 and diff < offset then 25 | offset = diff 26 | nearest.name = name 27 | nearest.addr = addr 28 | nearest.at = at 29 | nearest.ai = ai 30 | nearest.size = size 31 | end 32 | end 33 | end 34 | 35 | if nearest.addr then 36 | local color = offset <= nearest.size and 'white' or 'yellow' 37 | T_BR(0, 4, 'white', 'Epona: %06X', epona_addr) 38 | T_BR(0, 3, 'white', '%s: %06X', nearest.name, nearest.addr) 39 | T_BR(0, 2, color, 'Offset: %06X', offset) 40 | T_BR(0, 1, color, 'Size: %06X', nearest.size) 41 | T_BR(0, 0, 'white', 'Type, Index: %2i, %2i', nearest.at, nearest.ai) 42 | else 43 | T_BR(0, 0, 'yellow', 'Epona not found') 44 | epona_addr = nil 45 | end 46 | 47 | emu.frameadvance() 48 | end 49 | -------------------------------------------------------------------------------- /Lua/monitor event flags.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "messages" 5 | require "classes" 6 | 7 | local mm_ignore = { 8 | -- TODO: use list of bytes/bits rather than full strings 9 | -- every time a scene (un)loads 10 | ['92,7=0 (weg)'] = true, 11 | ['92,7=1 (weg)'] = true, 12 | -- night transition available 13 | ['05,2=0 (inf)'] = true, 14 | ['05,2=1 (inf)'] = true, 15 | -- daily postman crap 16 | ['27,6=0 (weg)'] = true, 17 | ['27,7=0 (weg)'] = true, 18 | ['28,0=0 (weg)'] = true, 19 | ['28,1=0 (weg)'] = true, 20 | ['28,2=0 (weg)'] = true, 21 | ['27,6=1 (weg)'] = true, 22 | ['27,7=1 (weg)'] = true, 23 | ['28,0=1 (weg)'] = true, 24 | ['28,1=1 (weg)'] = true, 25 | ['28,2=1 (weg)'] = true, 26 | } 27 | 28 | local weg,inf,eci,igi,it_,ei_ 29 | local fms 30 | if mm then 31 | weg = FlagMonitor('weg', addrs.week_event_reg, mm_ignore) 32 | inf = FlagMonitor('inf', addrs.event_inf, mm_ignore) 33 | --mmb = FlagMonitor('mmb', addrs.mask_mask_bit) -- 100% known, no point 34 | weg:load('data/_weg.lua') 35 | inf:load('data/_inf.lua') 36 | fms = {weg, inf} 37 | elseif oot then 38 | eci = FlagMonitor('eci', addrs.event_chk_inf) 39 | igi = FlagMonitor('igi', addrs.item_get_inf) 40 | it_ = FlagMonitor('it ', addrs.inf_table) 41 | ei_ = FlagMonitor('ei ', addrs.event_inf) 42 | eci:load('data/_eci.lua') 43 | igi:load('data/_igi.lua') 44 | it_:load('data/_it.lua') 45 | ei_:load('data/_ei.lua') 46 | fms = {eci, igi, it_, ei_} 47 | for i, fm in ipairs(fms) do fm.oot = true end 48 | end 49 | 50 | local function ef_wipe() 51 | for _, fm in ipairs(fms) do fm:wipe() end 52 | end 53 | 54 | local function ef_unk() 55 | for _, fm in ipairs(fms) do fm:set_unknowns() end 56 | end 57 | 58 | while mm or oot do 59 | for i, fm in ipairs(fms) do 60 | fm:diff() 61 | fm:save() 62 | end 63 | print_deferred() 64 | draw_messages() 65 | emu.frameadvance() 66 | end 67 | -------------------------------------------------------------------------------- /Lua/monitor exits used.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "serialize" 5 | 6 | local entrance_names = require "data.entrance names" 7 | 8 | local fn = mm and 'data/_exits_seen.lua' or 'data/_exits_seen_oot.lua' 9 | local exits_seen = deserialize(fn) or {} 10 | 11 | -- one-way entrances 12 | -- 2C00 going to top of clock tower (usually) 13 | 14 | -- one-way exits 15 | -- 5010 thrown out of deku palace 16 | -- 8490 down ikana waterfall 17 | -- 3440 into castle from above 18 | -- 3450 into trap fall from above castle blah 19 | 20 | -- TODO: get peeking into/out of shop 21 | -- TODO: get blue warp in deku race 22 | -- TODO: is getting thrown out after sonata different? 23 | -- TODO: get graveyard stuff 24 | 25 | -- TODO: mark more one-way stuff (remember: it's anything that isn't paired!) 26 | 27 | while true do 28 | local exit_id = addrs.warp_destination() 29 | local exit_hex = ('%04X'):format(exit_id) 30 | local frame = emu.framecount() 31 | if not exits_seen[exit_hex] then 32 | exits_seen[exit_hex] = true 33 | print(frame, exit_hex) 34 | serialize(fn, exits_seen) 35 | end 36 | emu.frameadvance() 37 | end 38 | -------------------------------------------------------------------------------- /Lua/monitor exits.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | 5 | local entrance_names = require "data.entrance names" 6 | 7 | local open = io.open 8 | 9 | local function sdata(i) 10 | local a = addrs.scene_table.addr + i*4*3 11 | -- entrance count, entrance table (ptr), name (ptr) 12 | return {R4(a), R4(a + 4), R4(a + 8)} 13 | end 14 | 15 | local function mirror(scene_id) 16 | if scene_id > 0x80 then 17 | return 0x100 - scene_id 18 | end 19 | return scene_id 20 | end 21 | 22 | local function calc_dump(a, writer) 23 | if type(a) ~= "number" then 24 | writer('[crash]') 25 | return 26 | end 27 | a = deref(R4(a)) or a 28 | local scene_id = mirror(R1(a)) 29 | local entrance = R1(a + 1) 30 | local t = entrance_names[scene_id] 31 | if t == nil then 32 | writer("err") 33 | return 34 | end 35 | writer(t.name) 36 | if t[entrance] then 37 | writer(t[entrance]) 38 | else 39 | writer("[unknown entrance]") 40 | end 41 | end 42 | 43 | local function split_exit(exit) 44 | return bit.rshift(exit, 9), bit.band(bit.rshift(exit, 4), 0x1F), bit.band(exit, 0xF) 45 | end 46 | 47 | local function calc(exit) 48 | console.clear() 49 | local scene, entrance, offset = split_exit(exit) 50 | printf("%i, %i, %i", scene, entrance, offset) 51 | 52 | local sd = sdata(scene) 53 | local first_entrance = deref(sd[2]) 54 | print("# Scene:") 55 | calc_dump(first_entrance, print) 56 | 57 | if not first_entrance then return end 58 | 59 | local orig_entrance = first_entrance + entrance*4 60 | local entr_before_offset = deref(R4(orig_entrance)) 61 | print("# Scene + Entrance:") 62 | calc_dump(entr_before_offset, print) 63 | 64 | if not entr_before_offset then return end 65 | 66 | local final_entrance = entr_before_offset + offset*4 67 | print("# Scene + Entrance + Offset:") 68 | calc_dump(final_entrance, print) 69 | 70 | -- TODO: read until \x00 71 | --print('internal name:') 72 | --print(asciize(mainmemory.readbyterange(deref(sd[3]), 8))) 73 | end 74 | 75 | local function dump_all_exits(fn) 76 | local f = open(fn or 'data/_exits.csv', 'w') 77 | if f == nil then 78 | print("couldn't open file for writing") 79 | return 80 | end 81 | f:write('ID,Scene,Entrance,Offset,Scene + Entrance + Offset,(entrance),Scene + Entrance,(entrance),Original Scene,(entrance)\n') 82 | for i = 0, 0xFFFF do 83 | local scene, entrance, offset = split_exit(i) 84 | f:write(('0x%04X,%i,%i,%i'):format(i, scene, entrance, offset)) 85 | local fail = function() 86 | f:write(',,,,,,\n') 87 | end 88 | for _ = 1, 1 do -- "continue" hack 89 | local sd = sdata(scene) 90 | local first_entrance = deref(sd[2]) 91 | if not first_entrance then fail(); break end 92 | local orig_entrance = first_entrance + entrance*4 93 | local entr_before_offset = deref(R4(orig_entrance)) 94 | if not entr_before_offset then fail(); break end 95 | local final_entrance = entr_before_offset + offset*4 96 | 97 | local writer = function(...) 98 | return f:write(',"') and f:write(...) and f:write('"') 99 | end 100 | calc_dump(final_entrance, writer) 101 | calc_dump(entr_before_offset, writer) 102 | calc_dump(first_entrance, writer) 103 | f:write("\n") 104 | end 105 | end 106 | f:close() 107 | end 108 | 109 | globalize{dump_all_exits=dump_all_exits} 110 | 111 | local old_value = -1 112 | while true do 113 | local exit_value = addrs.exit_value() 114 | if exit_value and exit_value ~= old_value then 115 | console.clear() 116 | calc(exit_value) 117 | end 118 | old_value = exit_value 119 | emu.frameadvance() 120 | end 121 | -------------------------------------------------------------------------------- /Lua/monitor misc.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "messages" 5 | require "classes" 6 | 7 | -- no effect on OoT 8 | local unk_only = false 9 | 10 | local unk = ByteMonitor('unk', AL(0xF6, 0x37A)) 11 | unk.byvalue = true 12 | unk:load('data/_unk.lua') 13 | 14 | local size = addrs.checksum.addr - addrs.exit_value.addr + 4 15 | local link = ByteMonitor('link', AL(0, size)) 16 | local ignore_fields = mm and { 17 | addrs.exit_value, 18 | addrs.mask_worn, 19 | addrs.intro_completed, 20 | addrs.anti_mash_timer, 21 | addrs.cutscene_status, 22 | addrs.time, 23 | addrs.owl_id, 24 | addrs.day_night, 25 | addrs.time_speed, 26 | addrs.day, 27 | addrs.days_elapsed, 28 | addrs.transformation, 29 | addrs.have_tatl, 30 | addrs.owl_save, 31 | addrs.ZELDA3, 32 | addrs.sot_count, 33 | addrs.name, 34 | addrs.max_hearts, 35 | addrs.hearts, 36 | addrs.magic_level, 37 | addrs.magic, 38 | addrs.rupees, 39 | addrs.navi_timer, 40 | addrs.has_normal_magic, 41 | addrs.has_double_magic, 42 | addrs.owls_hit, 43 | -- addrs.tunic_boots, 44 | addrs.sword_shield, 45 | addrs.inventory_items, 46 | addrs.inventory_masks, 47 | addrs.inventory_quantities, 48 | addrs.upgrades, 49 | addrs.quest_items, 50 | addrs.items_wft, 51 | addrs.items_sht, 52 | addrs.items_gbt, 53 | addrs.items_stt, 54 | addrs.keys_wft, 55 | addrs.keys_sht, 56 | addrs.keys_gbt, 57 | addrs.keys_stt, 58 | addrs.doubled_hearts, 59 | addrs.fairies_wft, 60 | addrs.fairies_sht, 61 | addrs.fairies_gbt, 62 | addrs.fairies_stt, 63 | -- addrs.strange_string, 64 | 65 | addrs.inventory.b_button_item, 66 | addrs.inventory.c_left_item, 67 | addrs.inventory.c_down_item, 68 | addrs.inventory.c_right_item, 69 | addrs.inventory.c_left_slot, 70 | addrs.inventory.c_down_slot, 71 | addrs.inventory.c_right_slot, 72 | addrs.scene_flags_save, 73 | addrs.scene_flags_ingame, 74 | addrs.week_event_reg, 75 | addrs.event_inf, 76 | } or { 77 | addrs.exit_value, 78 | addrs.cutscene_status, 79 | addrs.time, 80 | addrs.hearts, 81 | addrs.magic, 82 | addrs.rupees, 83 | addrs.navi_timer, 84 | addrs.scene_flags_save, 85 | addrs.inventory_items, 86 | addrs.inventory_quantities, 87 | addrs.event_chk_inf, 88 | addrs.item_get_inf, 89 | addrs.inf_table, 90 | addrs.event_inf, 91 | } 92 | 93 | function link:ignore(i) 94 | for _, v in pairs(ignore_fields) do 95 | local size = v.type 96 | if size == 'f' then size = 4 end 97 | local a = v.addr - self.begin 98 | if i >= a and i < a + size then return true end 99 | end 100 | end 101 | 102 | while mm or oot do 103 | if mm and unk_only then 104 | unk:diff() 105 | unk:save() 106 | else 107 | link:diff() 108 | end 109 | draw_messages() 110 | print_deferred() 111 | emu.frameadvance() 112 | end 113 | -------------------------------------------------------------------------------- /Lua/monitor scene flags.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | require "addrs" 4 | require "classes" 5 | require "messages" 6 | 7 | local x1 = SceneFlagMonitor('x1', addrs.current_scene_flags_1) 8 | local x2 = SceneFlagMonitor('x2', addrs.current_scene_flags_2) 9 | local x3 = SceneFlagMonitor('x3', addrs.current_scene_flags_3) 10 | local x4 = SceneFlagMonitor('x4', addrs.current_scene_flags_4) 11 | local x5 = SceneFlagMonitor('x5', addrs.current_scene_flags_5) 12 | local scenes = {} 13 | local n1 = -1 14 | while mm or oot do 15 | local n = addrs.scene_number() 16 | if n ~= n1 then 17 | if not scenes[n] then 18 | scenes[n] = {} 19 | printf('new scene %04X',n)--already has {TODO} flags', n) 20 | end 21 | if not scenes[n1] then 22 | scenes[n1] = {} 23 | end 24 | 25 | scenes[n1][1] = x1.old_bytes 26 | scenes[n1][2] = x2.old_bytes 27 | scenes[n1][3] = x3.old_bytes 28 | scenes[n1][4] = x4.old_bytes 29 | scenes[n1][5] = x5.old_bytes 30 | x1.old_bytes = scenes[n][1] or {} 31 | x2.old_bytes = scenes[n][2] or {} 32 | x3.old_bytes = scenes[n][3] or {} 33 | x4.old_bytes = scenes[n][4] or {} 34 | x5.old_bytes = scenes[n][5] or {} 35 | end 36 | n1 = n 37 | 38 | x1:diff() 39 | x2:diff() 40 | x3:diff() 41 | x4:diff() 42 | x5:diff() 43 | draw_messages() 44 | emu.frameadvance() 45 | end 46 | -------------------------------------------------------------------------------- /Lua/setup hundred.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | local a = require "addrs" 4 | 5 | -- gimme gimme gimme 6 | 7 | local iv 8 | if version == "M JP10" or version == "M JP11" then 9 | iv = require "data.item values early" 10 | elseif oot then 11 | iv = require "data.item values oot" 12 | else 13 | iv = require "data.item values" 14 | end 15 | 16 | local inv = a.inventory 17 | local masks = a.masks 18 | local quantities = a.quantities 19 | 20 | local function set(f, v) 21 | -- wrapper for addresses that *might* be undefined 22 | if f then f(v) end 23 | end 24 | 25 | set(a.target_style, 1) 26 | 27 | --set(buttons_enabled, 0) 28 | --set(sword_active, 1) 29 | set(a.owl_save, 0) 30 | set(a.sot_count, 0) 31 | 32 | set(a.target_style, 1) 33 | set(a.bubble_timer, 0) 34 | set(a.chateau_romani, 8) 35 | 36 | a.hearts (16*20) 37 | a.max_hearts (16*20) 38 | a.doubled_hearts(20) 39 | a.magic (0x60) 40 | set(a.magic_max, 0x60) 41 | a.rupees (500) 42 | 43 | -- nuts, sticks, bombs, wallet, Scale, gauntlets, Bullets, quiver 44 | -- ?????????nnnsssbbbwwSSSgggBBBqqq 45 | a.upgrades(tonumber('00000000010101101110010011011011', 2)) 46 | 47 | if oot then 48 | a.tunic_boots (0xFF) -- normally 0x77 49 | a.sword_shield (0xF7) -- normally 0x77? 50 | 51 | -- get epona 52 | local addr = a.event_chk_inf.addr + 2 53 | if bit then 54 | W2(addr, bit.bor(R2(addr), 0x0100)) 55 | else 56 | --FIXME 57 | end 58 | else 59 | a.sword_shield (0x23) 60 | a.owls_hit (0xFFFF) 61 | a.map_visible (0xFFFF) 62 | a.map_visited (0xFFFF) 63 | a.banked_rupees (5000) 64 | 65 | a.lottery_numbers[1][1](1) 66 | a.lottery_numbers[1][2](2) 67 | a.lottery_numbers[1][3](3) 68 | a.lottery_numbers[2][1](4) 69 | a.lottery_numbers[2][2](5) 70 | a.lottery_numbers[2][3](6) 71 | a.lottery_numbers[3][1](7) 72 | a.lottery_numbers[3][2](8) 73 | a.lottery_numbers[3][3](9) 74 | a.spider_mask_order[1](0) 75 | a.spider_mask_order[2](0) 76 | a.spider_mask_order[3](0) 77 | a.spider_mask_order[4](0) 78 | a.spider_mask_order[5](0) 79 | a.spider_mask_order[6](0) 80 | a.bombers_code[1](1) 81 | a.bombers_code[2](2) 82 | a.bombers_code[3](3) 83 | a.bombers_code[4](4) 84 | a.bombers_code[5](5) 85 | 86 | a.items_wft(7) 87 | a.items_sht(7) 88 | a.items_gbt(7) 89 | a.items_stt(7) 90 | a.keys_wft(69) 91 | a.keys_sht(69) 92 | a.keys_gbt(69) 93 | a.keys_stt(69) 94 | a.fairies_wft(69) 95 | a.fairies_sht(69) 96 | a.fairies_gbt(69) 97 | a.fairies_stt(69) 98 | 99 | -- great spin attack 100 | -- this one's a bit odd; it goes off an event flag 101 | local addr = a.week_event_reg.addr + 23 102 | if bit then 103 | W1(addr, bit.bor(R1(addr), 0x02)) 104 | else 105 | --W1(addr, R1(addr) | 0x02) -- FIXME 106 | end 107 | end 108 | 109 | set(a.magic_level, 2) 110 | set(a.has_normal_magic, 1) 111 | set(a.has_double_magic, 1) 112 | a.quest_items (0x00FFFFFF) 113 | 114 | --a.slulltula_count_wf(69) 115 | --a.slulltula_count_gb(69) 116 | 117 | --inv.b_button (0x4F) -- don't really need this 118 | 119 | for k, f in pairs(inv) do 120 | if iv[k] then f(iv[k]) end 121 | end 122 | 123 | if iv.longshot then 124 | inv.hookshot(iv.longshot) 125 | end 126 | 127 | inv.bottle_1 (iv.bottle ) 128 | inv.bottle_2 (iv.fairy ) 129 | inv.bottle_3 (iv.bugs ) 130 | inv.bottle_4 (iv.fish ) 131 | set(inv.bottle_5, iv.milk ) 132 | set(inv.bottle_6, iv.chateau_romani) 133 | 134 | --set(a.event_1, 0x05) 135 | --set(a.event_2, 0x0B) 136 | --set(a.event_3, 0x11) 137 | 138 | if masks then 139 | for k, f in pairs(masks) do 140 | f(iv[k]) 141 | end 142 | end 143 | 144 | for k, f in pairs(quantities) do 145 | f(69) 146 | end 147 | -------------------------------------------------------------------------------- /Lua/setup race file.lua: -------------------------------------------------------------------------------- 1 | require "lib.setup" 2 | require "boilerplate" 3 | local a = require "addrs" 4 | local inv = a.inventory 5 | local masks = a.masks 6 | local quantities = a.quantities 7 | 8 | if not mm then return end 9 | local early = version == "M JP10" or version == "M JP11" 10 | 11 | local zelda3 = "ZELDA3" 12 | -- TODO: support (E) text format too 13 | local link_str = {0x15, 0x12, 0x17, 0x14, 0x3E, 0x3E, 0x3E, 0x3E} 14 | local lastsaveslot = 1 15 | local iv 16 | if early then 17 | link_str = {0xB6, 0xB3, 0xB8, 0xB5, 0xDF, 0xDF, 0xDF, 0xDF} 18 | lastsaveslot = 2 19 | iv = require "data.item values early" 20 | else 21 | iv = require "data.item values" 22 | end 23 | 24 | require "flag manager" 25 | 26 | for i = a.link.addr, a.link.addr + a.link.type - 1, 4 do W4(i, 0) end 27 | 28 | if a.current_save() == 0xFF then a.current_save(lastsaveslot) end 29 | 30 | for i = 1, 6 do W1(a.ZELDA3.addr + i - 1, zelda3:sub(i, i):byte()) end 31 | AL(0x50, 4)(0x6CFFFFFF) -- goron C/B buttons 32 | AL(0x54, 4)(0x6CFFFFFF) -- zora C/B buttons 33 | AL(0x58, 4)(0x09FFFFFF) -- deku C/B buttons 34 | AL(0x60, 4)(0xFFFFFFFF) -- unknown 35 | AL(0x64, 4)(0xFFFFFFFF) -- unknown 36 | AL(0x68, 4)(0xFFFFFFFF) -- unknown 37 | 38 | -- TODO: support (E) text format too 39 | if early then 40 | for i = 0, 7 do W1(a.name.addr + i, 0xDF) end 41 | W1(a.name.addr, 0) 42 | else 43 | for i = 0, 7 do W1(a.name.addr + i, 0x3E) end 44 | W1(a.name.addr, 0) 45 | end 46 | 47 | a.warp_begin(1) 48 | a.warp_destination(0xD800) 49 | a.cutscene_status_2(3) 50 | a.target_style(1) 51 | --a.fade_timer(0x3C) -- doesn't help... 52 | -- TODO: force dialog after scene is loaded with SoT stored? could be nice 53 | 54 | for i = 1, 8 do W1(a.link.addr + 0xDE + i - 1, link_str[i]) end 55 | for i = 1, 8 do W1(a.link.addr + 0xE6 + i - 1, link_str[i]) end 56 | for i = 1, 8 do W1(a.link.addr + 0xEE + i - 1, link_str[i]) end 57 | 58 | AL(0xD2, 1)(0xFF) -- unused key counter 59 | 60 | a.exit_value(0xD800) 61 | --a.mask_worn(0) 62 | a.intro_completed(1) 63 | a.time(0x3FFF) 64 | --a.owl_id(0) 65 | --a.day_night(0) 66 | --a.time_speed(0) 67 | --a.day(0) 68 | --a.days_elapsed(0) 69 | a.transformation(4) 70 | a.have_tatl(1) 71 | --a.owl_save(0) 72 | a.sot_count(1) 73 | a.max_hearts(0x30) 74 | a.hearts(0x30) 75 | a.magic_level(1) 76 | a.magic(0x30) 77 | a.magic_max(0x30) 78 | --a.rupees(0) 79 | a.has_normal_magic(1) 80 | --a.has_double_magic(0) 81 | AL(0x44, 2)(0xFF00) -- unknown 82 | --a.owls_hit(0) 83 | AL(0x48, 2)(0xFF00) -- unknown 84 | AL(0x4A, 2)(0x0008) -- unknown 85 | for k, f in pairs(inv) do f(-1) end 86 | for k, f in pairs(masks) do f(-1) end 87 | inv.b_button_item(iv.kokiri_sword) 88 | inv.b_button_goron(iv.kokiri_sword) 89 | inv.b_button_zora(iv.kokiri_sword) 90 | inv.b_button_deku(iv.deku_nut) 91 | inv.c_left_item(iv.ocarina) 92 | inv.c_down_item(-1) 93 | inv.c_right_item(-1) 94 | inv.c_left_slot(iv.ocarina) 95 | inv.c_down_slot(-1) 96 | inv.c_right_slot(-1) 97 | --a.tunic_boots(0) 98 | a.sword_shield(0x11) 99 | inv.ocarina(iv.ocarina) 100 | masks.deku(iv.deku) 101 | --for k, f in pairs(quantities) do f(0) end 102 | a.upgrades(0x00120000) -- deku nut 20 and deku stick 10 103 | a.quest_items(0x10003000) 104 | a.banked_rupees(101) 105 | AL(0xE6C, 4)(0x1D4C) -- unknown 106 | AL(0xE70, 4)(0x1D4C) -- unknown 107 | AL(0xE74, 4)(0x1DB0) -- unknown 108 | AL(0xEE8, 4)(0x0013000A) -- unknown 109 | AL(0xEEC, 4)(0x1770) -- unknown 110 | AL(0xEF4, 4)(0x000A0027) -- unknown 111 | event_flag_set(2, 5) 112 | event_flag_set(2, 4) 113 | event_flag_set(2, 3) 114 | event_flag_set(31, 2) 115 | event_flag_set(59, 2) 116 | event_flag_set(92, 7) 117 | a.map_visited(0x20) 118 | a.map_visible(0x00) 119 | a.bombers_code[1](1) 120 | a.bombers_code[2](2) 121 | a.bombers_code[3](3) 122 | a.bombers_code[4](4) 123 | a.bombers_code[5](5) 124 | a.spider_mask_order[1](0) -- red 125 | a.spider_mask_order[2](1) -- blue 126 | a.spider_mask_order[3](0) -- red 127 | a.spider_mask_order[4](1) -- blue 128 | a.spider_mask_order[5](0) -- red 129 | a.spider_mask_order[6](1) -- blue 130 | a.lottery_numbers[1][1](1) 131 | a.lottery_numbers[1][2](2) 132 | a.lottery_numbers[1][3](3) 133 | a.lottery_numbers[2][1](4) 134 | a.lottery_numbers[2][2](5) 135 | a.lottery_numbers[2][3](6) 136 | a.lottery_numbers[3][1](7) 137 | a.lottery_numbers[3][2](8) 138 | a.lottery_numbers[3][3](9) 139 | a.epona_scene(53) 140 | a.epona_x(-1420) 141 | a.epona_y(257) 142 | a.epona_z(-1285) 143 | a.epona_angle(10922) -- 35500 before playing Song of Time once. weird. 144 | 145 | local scene_count = 0x78 146 | 147 | -- wipe all scene flags. 148 | for scene_id = 0, scene_count - 1 do 149 | local temp = a.scene_flags_ingame.addr + 0x14 * scene_id 150 | W4(temp + 0, 0) 151 | W4(temp + 1, 0) 152 | W4(temp + 2, 0) 153 | W4(temp + 3, 0) 154 | W4(temp + 4, 0) 155 | end 156 | 157 | -- 0x1EFA44 should be 0x00000005 158 | scene_flag_set(26, 1, 0) 159 | scene_flag_set(26, 1, 2) 160 | -- 0x1EFB94 should be 0x00000400 161 | scene_flag_set(38, 1, 10) 162 | -- 0x1F0240 should be 0x00000001 163 | scene_flag_set(99, 1, 0) 164 | -- 0x1F039C should be 0x00000400 165 | scene_flag_set(111, 4, 10) 166 | 167 | local src = a.scene_flags_ingame.addr 168 | local dst = a.scene_flags_save.addr 169 | for scene_id = 0, scene_count - 1 do 170 | local src_temp = src + scene_id * 0x14 171 | local dst_temp = dst + scene_id * 0x1C 172 | W4(dst_temp + 0, R4(src_temp + 0)) 173 | W4(dst_temp + 4, R4(src_temp + 4)) 174 | W4(dst_temp + 8, R4(src_temp + 8)) 175 | W4(dst_temp + 12, R4(src_temp + 12)) 176 | W4(dst_temp + 16, R4(src_temp + 16)) 177 | W4(dst_temp + 20, 0) 178 | W4(dst_temp + 24, 0) 179 | end 180 | -------------------------------------------------------------------------------- /Lua/test chests.lua: -------------------------------------------------------------------------------- 1 | -- go to a grotto with a red rupee chest, stand in front of it and run this script 2 | 3 | local hash = gameinfo.getromhash() 4 | local versions = { 5 | ['D6133ACE5AFAA0882CF214CF88DABA39E266C078'] = "US10", 6 | ['5FB2301AACBF85278AF30DCA3E4194AD48599E36'] = "JP10", 7 | } 8 | local version = versions[hash] 9 | 10 | local index = 0 11 | local fn = 'data/lua chest test.State' 12 | 13 | local start, ours, text 14 | if version == 'US10' then 15 | start = 0x779884 -- the get item table 16 | ours = 0x779896 -- the chest we're standing in front of 17 | text = 0x3FCE10 -- ascii text buffer 18 | elseif version == 'JP10' then 19 | start = 0x7797E4 -- the get item table 20 | ours = 0x7797F6 -- the chest we're standing in front of 21 | text = 0x3FD660 -- no such thing in JP but we need something 22 | end 23 | 24 | function draw_index() 25 | gui.text(304, 8, ("%03i"):format(index), nil, nil, 'bottomleft') 26 | end 27 | 28 | function advance() 29 | draw_index() 30 | emu.frameadvance() 31 | draw_index() 32 | emu.frameadvance() 33 | draw_index() 34 | emu.frameadvance() 35 | end 36 | 37 | function read_ascii(addr, len) 38 | local begin = addr 39 | local bytes = mainmemory.readbyterange(begin, len) 40 | local str = "" 41 | 42 | -- pairs() won't give us the bytes in order 43 | -- so we'll set up a table we can use ipairs() on 44 | local ordered_bytes = {} 45 | for a, v in pairs(bytes) do 46 | ordered_bytes[tonumber(a, 16) + 1] = v 47 | end 48 | 49 | local seq = false 50 | for i, v in ipairs(ordered_bytes) do 51 | local c = tonumber(v, 16) 52 | if c == 9 or c == 10 or c == 13 or (c >= 32 and c < 127) then 53 | str = str..string.char(c) 54 | seq = false 55 | elseif seq == false then 56 | str = str..' ' 57 | seq = true 58 | end 59 | end 60 | return str 61 | end 62 | 63 | client.unpause() 64 | savestate.save(fn) 65 | for off=index*6, 185*6, 6 do 66 | index = index + 1 67 | for i=0, 5 do 68 | local byte = mainmemory.readbyte(start + off + i) 69 | mainmemory.writebyte(ours + i, byte) 70 | end 71 | joypad.set({A=true}, 1) 72 | advance() 73 | joypad.set({A=false}, 1) 74 | 75 | local good = false 76 | for i=1, 9*20 do 77 | if version == 'JP10' and (index >= 85 and index <= 88) then 78 | break -- crashes 79 | end 80 | advance() 81 | if mainmemory.readbyte(text + 0xA) == 0xFF then 82 | if version == 'US10' then 83 | local begin = text + 0xC 84 | print(off/6 + 1, read_ascii(begin, 0x100)) 85 | good = true 86 | else 87 | for _=1, 40 do 88 | advance() 89 | end 90 | end 91 | break 92 | end 93 | end 94 | if not good then 95 | print(off/6 + 1, '[error]') 96 | end 97 | savestate.load(fn) 98 | end 99 | client.pause() 100 | -------------------------------------------------------------------------------- /Yaz0.py: -------------------------------------------------------------------------------- 1 | # decoder ripped from: http://www.amnoid.de/gc/yaz0.txt 2 | 3 | def decode(comp): 4 | src = 16 # skip header 5 | dst = 0 6 | valid = 0 # bit count 7 | curr = 0 # code byte 8 | 9 | assert(comp[:4] == b'Yaz0') 10 | assert(comp[8:12] == b'\x00\x00\x00\x00') 11 | assert(comp[12:16] == b'\x00\x00\x00\x00') 12 | 13 | # we could use struct but eh we only need it once 14 | size = comp[4]*0x1000000 + comp[5]*0x10000 + comp[6]*0x100 + comp[7] 15 | uncomp = bytearray(size) 16 | 17 | while dst < size: 18 | if not valid: 19 | curr = comp[src] 20 | src += 1 21 | valid = 8 22 | 23 | if curr & 0x80: 24 | uncomp[dst] = comp[src] 25 | dst += 1 26 | src += 1 27 | else: 28 | byte1 = comp[src] 29 | byte2 = comp[src + 1] 30 | src += 2 31 | 32 | dist = ((byte1 & 0xF) << 8) | byte2 33 | copy = dst - (dist + 1) 34 | assert(copy >= 0) 35 | 36 | n = byte1 >> 4 37 | if n: 38 | n += 2 39 | else: 40 | n = comp[src] + 0x12 41 | src += 1 42 | 43 | for i in range(n): 44 | uncomp[dst] = uncomp[copy] 45 | copy += 1 46 | dst += 1 47 | 48 | curr <<= 1 49 | valid -= 1 50 | 51 | return uncomp 52 | -------------------------------------------------------------------------------- /Yaz0_fast.pyx: -------------------------------------------------------------------------------- 1 | # decoder ripped from: http://www.amnoid.de/gc/yaz0.txt 2 | 3 | from libc.stdint cimport uint32_t, uint8_t 4 | ctypedef uint32_t ulong 5 | ctypedef uint8_t uchar 6 | 7 | cdef ulong get_size(uchar *comp): 8 | return comp[4]*0x1000000 + comp[5]*0x10000 + comp[6]*0x100 + comp[7] 9 | 10 | cdef void _decode(uchar *comp, uchar *uncomp): 11 | cdef: 12 | ulong src = 16 # skip header 13 | ulong dst = 0 14 | uchar valid = 0 # bit count 15 | uchar curr = 0 # code byte 16 | 17 | ulong size = get_size(comp) 18 | 19 | uchar byte1, byte2 20 | ulong dist, copy, i, n 21 | 22 | while dst < size: 23 | if not valid: 24 | curr = comp[src] 25 | src += 1 26 | valid = 8 27 | 28 | if curr & 0x80: 29 | uncomp[dst] = comp[src] 30 | dst += 1 31 | src += 1 32 | else: 33 | byte1 = comp[src] 34 | byte2 = comp[src + 1] 35 | src += 2 36 | 37 | dist = ((byte1 & 0xF) << 8) | byte2 38 | copy = dst - (dist + 1) 39 | 40 | n = byte1 >> 4 41 | if n: 42 | n += 2 43 | else: 44 | n = comp[src] + 0x12 45 | src += 1 46 | 47 | for i in range(n): 48 | uncomp[dst] = uncomp[copy] 49 | copy += 1 50 | dst += 1 51 | 52 | curr <<= 1 53 | valid -= 1 54 | 55 | def decode(comp): 56 | size = get_size(comp) 57 | uncomp = bytearray(size) 58 | _decode(comp, uncomp) 59 | return uncomp 60 | -------------------------------------------------------------------------------- /asm/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | lips 3 | -------------------------------------------------------------------------------- /asm/bombtornado.asm: -------------------------------------------------------------------------------- 1 | // bomb tornado 2 | // originally written by RainingChain in Lua 3 | // rewritten in assembly by notwa 4 | 5 | [global_context]: 0x803E6B20 6 | [link_actor]: 0x803FFDB0 7 | 8 | [actorlist_offset]: 0x1CB0 9 | [actorlist_dead_space]: 0x4 10 | 11 | [actor_x]: 0x24 12 | [actor_y]: 0x28 13 | [actor_z]: 0x2C 14 | [actor_prev]: 0x128 15 | [actor_next]: 0x12C 16 | [actor_bomb_timer]: 0x1F1 17 | 18 | [at_bomb]: 0x0009 19 | 20 | [rotate_amount]: 0x3E567750 ; pi/15 21 | 22 | // F12 = input (single), F0 = output (single), F4 = output (double) 23 | [sinf]: 0x80088350 24 | [cosf]: 0x80091F40 25 | 26 | main: 27 | push 4, s1, s3, s4, ra 28 | // s1: current actor ptr 29 | // s3: current actor type ptr 30 | // s4: current actor type index 31 | li t0, @global_context 32 | addi s3, t0, @actorlist_offset 33 | li s4, 0 34 | 35 | // update rotations 36 | la t0, rotations 37 | li t2, @rotate_amount 38 | li t9, 0 39 | -: 40 | lw t1, 0(t0) 41 | mtc1 t1, F0 42 | mtc1 t2, F1 43 | add.s F0, F0, F1 44 | mfc1 t1, F0 45 | sw t1, 0(t0) 46 | addi t0, t0, 4 47 | addi t9, t9, 1 48 | li at, 6 49 | bne t9, at, - 50 | nop 51 | la t0, rotations 52 | sw t0, current_rotation 53 | 54 | typeloop: 55 | addi s3, s3, 4 // skip over count 56 | lw s1, 0(s3) 57 | 58 | beq s1, r0, continue 59 | listloop: 60 | mov a0, s1 61 | bal process_actor 62 | lw s1, @actor_next(s1) 63 | bne s1, r0, listloop 64 | nop 65 | 66 | continue: 67 | addi s3, s3, 4 68 | addi s4, s4, 1 69 | li t0, 12 70 | bne s4, t0, typeloop 71 | addi s3, s3, @actorlist_dead_space 72 | 73 | ret 4, s1, s3, s4, ra 74 | 75 | process_actor: // args: a0. returns nothing. 76 | // TODO: ignore bomb explosions, they share the same type 77 | push 4, s0, s1, ra 78 | // s0: result of sin 79 | // s1: result of cos 80 | lh t0, 0(a0) 81 | subiu t0, t0, @at_bomb 82 | bne t0, r0, + 83 | nop 84 | li t0, 0x45 85 | sb t0, @actor_bomb_timer(a0) 86 | 87 | lw t5, current_rotation 88 | lw t5, 0(t5) 89 | jal @sinf 90 | mtc1 t5, F12 91 | mfc1 s0, F0 92 | 93 | lw t5, current_rotation 94 | lw t5, 0(t5) 95 | jal @cosf 96 | mtc1 t5, F12 97 | mfc1 s1, F0 98 | 99 | li t1, @link_actor 100 | lw t2, @actor_x(t1) 101 | lw t3, @actor_y(t1) 102 | lw t4, @actor_z(t1) 103 | 104 | li t0, 0x42960000 // 75 105 | mtc1 t0, F2 106 | 107 | // process X 108 | mtc1 s0, F0 109 | mtc1 t2, F1 110 | mul.s F0, F0, F2 111 | add.s F0, F0, F1 112 | mfc1 t2, F0 113 | 114 | // process Z 115 | mtc1 s1, F0 116 | mtc1 t4, F1 117 | mul.s F0, F0, F2 118 | add.s F0, F0, F1 119 | mfc1 t4, F0 120 | 121 | sw t2, @actor_x(a0) 122 | sw t3, @actor_y(a0) 123 | sw t4, @actor_z(a0) 124 | 125 | lw t5, current_rotation 126 | addi t5, t5, 4 127 | sw t5, current_rotation 128 | 129 | +: 130 | ret 4, s0, s1, ra 131 | 132 | rotations: 133 | .word 0x00000000 // pi*0/6 134 | .word 0x40060a92 // pi*4/6 135 | .word 0x40860a92 // pi*8/6 136 | .word 0x40c90fdb // pi*12/6 137 | .word 0x41060a92 // pi*16/6 138 | .word 0x41278d36 // pi*20/6 139 | 140 | current_rotation: 141 | .word 0 142 | -------------------------------------------------------------------------------- /asm/code.asm: -------------------------------------------------------------------------------- 1 | .include "common.asm" 2 | 3 | [game_main]: 0xCEDE0 ; 0x801748A0 4 | [dma_overwrite]: 0xC4808 ; 0x8016A2C8 5 | [tunic_color_overwrite]: 0x80710 6 | [starting_exit_func]: 0x9F87C 7 | [starting_exit_jr]: 0x9F9A4 8 | [default_save]: 0x120DD8 9 | 10 | ; 0x8016A2C8 -> 0xC4808 11 | ; 0x8016A2C8 - 0xC4808 = 0x800A5AC0 12 | ; 0x8016AC0C - 0x8016A2C8 = 0x944 13 | 14 | .org @game_main 15 | ; this appears to be the main game loop function 16 | ; we can "make room" for some injected code 17 | ; by taking advantage of it never returning under normal circumstances. 18 | ; we'll cut out pushing RA, S1-S8 stuff on stack. 19 | ; props to CloudMax for doing this in OoT first. 20 | addiu sp, sp, 0xFCC0 ; original code 21 | ; push removed here 22 | li s0, 0x801BD910 ; original code 23 | ; pushes removed here 24 | ; 6 instructions to work with 25 | call @DMARomToRam, @start, @vstart, @size 26 | 27 | .org @dma_overwrite 28 | j dma_hook ; 1 29 | nop ; 1 30 | 31 | .org @tunic_color_overwrite 32 | j tunic_color_hook 33 | lhu t1, 0x1DB0(t1); original code 34 | 35 | .org @starting_exit_func 36 | li t8, @starting_exit ; modified code 37 | li t4, @starting_exit ; modified code 38 | 39 | .org @starting_exit_jr 40 | j load_hook ; tail call 41 | 42 | .org @default_save 43 | .ascii "\0\0\0\0\0\0" ; ZELDA3 44 | .half 1 ; SoT count 45 | .ascii ">>>>>>>>" ; player name 46 | .half 0x30 ; hearts 47 | .half 0x30 ; max hearts 48 | .byte 1 ; magic level 49 | .byte 0x30 ; magic amount 50 | .half 0 ; rupees 51 | .word 0 ; navi timer 52 | .byte 1 ; has normal magic 53 | .byte 0 ; has double magic 54 | .half 0 ; double defense 55 | .half 0xFF00 ; unknown 56 | .half 0x0000 ; owls hit 57 | .word 0xFF000008 ; unknown 58 | .word 0x4DFFFFFF ; human buttons 59 | .word 0x4DFFFFFF ; goron buttons 60 | .word 0x4DFFFFFF ; zora buttons 61 | .word 0xFDFFFFFF ; deku buttons 62 | .word 0x00FFFFFF ; equipped slots 63 | .word 0xFFFFFFFF ; unknown 64 | .word 0xFFFFFFFF ; unknown 65 | .word 0xFFFFFFFF ; unknown 66 | .half 0x0011 ; tunic & boots 67 | .half 0 ; unknown 68 | ; inventory items 69 | .byte 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ; ocarina, nothing else 70 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 71 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 72 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 73 | ; mask items 74 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x32 ; deku mask, nothing else 75 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 76 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 77 | .byte 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 78 | ; item quantities 79 | .byte 0, 0, 0, 0, 0, 0 80 | .byte 0, 0, 0, 0, 0, 0 81 | .byte 0, 0, 0, 0, 0, 0 82 | .byte 0, 0, 0, 0, 0, 0 83 | ; 84 | .word 0 ; upgrades 85 | .word 0x00003000 ; quest status (set song of time and song of healing) 86 | -------------------------------------------------------------------------------- /asm/common.asm: -------------------------------------------------------------------------------- 1 | [vstart]: 0x02EE7040 ; VROM address of our "extra" file 2 | [start]: 0x80780000 ; RAM address of the "extra" file after DMA hook 3 | [size]: 0x5A800 ; this is the most we can store in this region of RAM 4 | 5 | [DMARomToRam]: 0x80080C90 6 | 7 | [link_save]: 0x801EF670 8 | [has_completed_intro]: 0x5 9 | [have_tatl]: 0x22 10 | [player_name]: 0x2C 11 | [scene_flags]: 0x470 12 | [week_event_reg]: 0xEF8 13 | [voidout_type]: 0x3CB0 14 | [voidout_exit]: 0x3CC4 15 | [exit_mod_setter]: 0x3F4A 16 | [scene_flags_ingame]: 0x3F68 17 | 18 | [global_context]: 0x803E6B20 ; FIXME: don't hardcode 19 | 20 | [link_actor]: 0x803FFDB0 ; FIXME: don't hardcode 21 | [link_object_ptr]: 0x803FFFF4 ; actually just an offset of link_actor? 22 | ;[link_object_ptr]: 0x244 23 | 24 | [scene_record_size]: 0x14 25 | 26 | [starting_exit]: 0xD800 27 | -------------------------------------------------------------------------------- /asm/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | fast=0 3 | [[ "$1" == "fast" ]] && fast=1 && shift || [[ "$1" == "test" ]] && fast=2 && shift 4 | args="$@" 5 | 6 | lips="$(readlink -f ../Lua/lib/lips)" 7 | YAZ0="$(readlink -f ../z64yaz0)" 8 | DUMP="$(readlink -f ../z64dump.py)" 9 | 10 | #extracted="$(readlink -f "$extracted")" 11 | rom="$(readlink -f "$rom")" 12 | 13 | mkdir -p build 14 | quiet=0 15 | 16 | patchme="build/patchme" 17 | 18 | #[ ! -s "$YAZ0" ] && cc -O3 "${YAZ0}.c" -o "$YAZ0" 19 | 20 | dump() { 21 | #(cd "$(dirname "$DUMP")"; ./z64dump.py "$@") 22 | "$DUMP" "$@" 23 | } 24 | 25 | if [ $fast -eq 0 ] || [ ! -d "$patchme" ]; then 26 | if [ -n "$sha1" ]; then 27 | [ -d "$patchme" ] && rm -r "$patchme" 28 | dump -c "$rom" 29 | mv "$sha1" "$patchme" 30 | else 31 | cp "$rom" "build/$out" 32 | fi 33 | fi 34 | 35 | ratio() { 36 | local len1="$(wc -c < "$1")" 37 | local len2="$(wc -c < "$2")" 38 | 39 | if [ $len1 -eq 0 ]; then 40 | [ $quiet -le 0 ] && echo empty 41 | else 42 | let percent=(len2*100)/len1 43 | [ $quiet -le 0 ] && echo "ratio: $percent%" 44 | return "$((percent < 100))" 45 | fi 46 | } 47 | 48 | unc() { 49 | local in="$patchme"/"$1".Yaz0 50 | local out="$patchme"/"$1" 51 | 52 | [ -e "$in" ] || return 0 53 | "$YAZ0" "$in" > "$out" 54 | [ $quiet -le 0 ] && echo "uncompressed $1" 55 | ratio "$out" "$in" || true 56 | rm "$patchme"/"$1".Yaz0 57 | } 58 | 59 | comp() { 60 | local in="$patchme"/"$1" 61 | local out="$patchme"/"$1".Yaz0 62 | 63 | [ -e "$in" ] || return 0 64 | "$YAZ0" "$in" > "$out" 65 | [ $quiet -le 0 ] && echo "compressed $1" 66 | ratio "$in" "$out" && { 67 | [ $quiet -le 1 ] && echo "leaving uncompressed $1" 68 | rm "$out" 69 | } || { 70 | rm "$in" 71 | } 72 | } 73 | 74 | copy_rom() { 75 | dd if="$patchme".z64 of="$1" bs=$((1024*1024)) count="${2:-32}" status=none 76 | } 77 | 78 | # don't copy entire dir; avoid copying dotfiles (.git) 79 | mkdir -p lips 80 | cp "$lips"/* lips 81 | -------------------------------------------------------------------------------- /asm/crc32.asm: -------------------------------------------------------------------------------- 1 | crc32: 2 | // this is a re-implementation of the C code 3 | // available at https://gist.github.com/notwa/5689243 4 | // a0: pointer to input data 5 | // a1: input data length 6 | // a2: existing crc value (use 0xFFFFFFFF for initialization) 7 | // v0: new crc value (bitwise NOT it when you're finished cycling) 8 | mov v0, a2 9 | la t9, crc32_constants 10 | -: 11 | lbu t0, (a0) // *ptr 12 | // first nybble 13 | //crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*ptr & 0xf)]; 14 | andi t2, v0, 0xF 15 | andi t3, t0, 0xF 16 | srl t1, v0, 4 17 | xor t4, t2, t3 18 | sll t5, t4, 2 // offset = index*sizeof(word) 19 | addu t6, t5, t9 20 | lw t7, (t6) 21 | xor v0, t1, t7 22 | // second nybble 23 | //crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*(ptr++) >> 4)]; 24 | andi t2, v0, 0xF 25 | srl t3, t0, 4 26 | srl t1, v0, 4 27 | xor t4, t2, t3 28 | sll t5, t4, 2 // offset = index*sizeof(word) 29 | addu t6, t5, t9 30 | lw t7, (t6) 31 | xor v0, t1, t7 32 | // iterate or return 33 | subi a1, 1 // cnt-- 34 | bnez a1, - 35 | addi a0, 1 // ptr++ 36 | jr 37 | nop 38 | 39 | crc32_constants: // ethernet standard (0x04C11DB7 as the crc divisor) 40 | .word 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC 41 | .word 0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C 42 | .word 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C 43 | .word 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C 44 | -------------------------------------------------------------------------------- /asm/dma O EUDB MQ.asm: -------------------------------------------------------------------------------- 1 | .push pc 2 | 3 | [DMARomToRam]: 0x80000BFC 4 | 5 | [vstart]: 0x035D0000 6 | [start]: 0x80700000 7 | [size]: 0x10000 8 | 9 | /* 10 | .org 0x18F30 11 | ; add an entry to the end of dmatable to hold our extra code 12 | ; this actually just crashes the game so don't bother 13 | ; (no debug filename associated with it = bad pointer dereference? maybe?) 14 | .word @vstart ; virtual start 15 | .word 0x035E0000 ; virtual end (@vstart + @size) 16 | .word @vstart ; physical start (should be same as virtual start) 17 | .word 0 ; physical end (should be 0 for uncompressed) 18 | */ 19 | 20 | .base 0x7F588E60 ; code file in memory 21 | 22 | .org 0xB3D9E4 ; 0x800C6844 23 | ; this appears to be the main game loop function 24 | ; we can "make room" for some injected code 25 | ; by taking advantage of it never returning under normal circumstances. 26 | ; we'll cut out pushing RA, S1-S8 stuff on stack. 27 | ; props to CloudMax for coming up with this. 28 | addiu sp, sp, 0xFC60 ; original code 29 | ; push removed here 30 | li s0, 0x8011F830 ; original code 31 | ; pushes removed here 32 | ; 9 instructions to work with? 33 | ; a0 and a1 are backwards compared to MM? 34 | call @DMARomToRam, @vstart, @start, @size 35 | lui a0 0x8014 ; original code 36 | cl a1 37 | cl a2 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | 44 | .pop pc 45 | -------------------------------------------------------------------------------- /asm/dpad control.asm: -------------------------------------------------------------------------------- 1 | dpad_control: 2 | // a0: number you want to control 3 | // a1: button state 4 | // v0: number after modifications 5 | la t1, dpad_values 6 | srl t0, a1, 8 7 | andi t0, 0xF 8 | add t0, t1 9 | lb t0, 0(t0) 10 | jr 11 | add v0, a0, t0 12 | 13 | dpad_values: 14 | // use table of values for branchless operation 15 | .byte 0, 1, -1, 0 16 | .byte -16, -4, -64, -16 17 | .byte +16, +64, +4, +16 18 | .byte 0, 1, -1, 0 19 | .align 20 | -------------------------------------------------------------------------------- /asm/extra.lua: -------------------------------------------------------------------------------- 1 | local function strpad(num, count, pad) 2 | num = tostring(num) 3 | return (pad:rep(count)..num):sub(#num) 4 | end 5 | 6 | local function add_zeros(num, count) 7 | return strpad(num, count - 1, '0') 8 | end 9 | 10 | local function mixed_sorter(a, b) 11 | a = type(a) == 'number' and add_zeros(a, 16) or tostring(a) 12 | b = type(b) == 'number' and add_zeros(b, 16) or tostring(b) 13 | return a < b 14 | end 15 | 16 | -- loosely based on http://lua-users.org/wiki/SortedIteration 17 | -- the original didn't make use of closures for who knows why 18 | local function order_keys(t) 19 | local oi = {} 20 | for key in pairs(t) do 21 | table.insert(oi, key) 22 | end 23 | table.sort(oi, mixed_sorter) 24 | return oi 25 | end 26 | 27 | local function opairs(t, cache) 28 | local oi = cache and cache[t] or order_keys(t) 29 | if cache then 30 | cache[t] = oi 31 | end 32 | local i = 0 33 | return function() 34 | i = i + 1 35 | local key = oi[i] 36 | if key then return key, t[key] end 37 | end 38 | end 39 | 40 | local function traverse(path) 41 | if not path then return end 42 | local parent = _G 43 | local key 44 | for w in path:gfind("[%w_]+") do 45 | if key then 46 | parent = rawget(parent, key) 47 | if type(parent) ~= 'table' then return end 48 | end 49 | key = w 50 | end 51 | if not key then return end 52 | return {parent=parent, key=key} 53 | end 54 | 55 | return { 56 | strpad = strpad, 57 | add_zeros = add_zeros, 58 | mixed_sorter = mixed_sorter, 59 | order_keys = order_keys, 60 | opairs = opairs, 61 | traverse = traverse, 62 | } 63 | -------------------------------------------------------------------------------- /asm/mm-bq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | sha1=d6133ace5afaa0882cf214cf88daba39e266c078 5 | rom=../../roms/everything/"Legend of Zelda, The - Majora's Mask (U) [!].z64" 6 | out=mm-bq.z64 7 | 8 | . common.sh 9 | 10 | code="0031 V00B3C000" 11 | extra="1552 V02EE7040" 12 | 13 | unc "$code" 14 | 15 | dd if=/dev/zero of=extra bs=370688 count=1 2>/dev/null 16 | 17 | luajit patch.lua -e build/labels.lua -b 0x80780000 "$@" extra.asm extra 18 | luajit patch.lua -i build/labels.lua "$@" code.asm build/patchme/"$code" 19 | 20 | # ensure the file is the proper size (Lua seems to expand it?) 21 | dd if=extra of=build/patchme/"$extra" bs=370688 count=1 2>/dev/null 22 | rm extra 23 | 24 | if [ $fast -ne 2 ]; then 25 | comp "$code" 26 | comp "$extra" 27 | dump "$patchme" 28 | copy_rom "build/$out" 32 29 | fi 30 | -------------------------------------------------------------------------------- /asm/oot-spawner: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | rom=../../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" 5 | lips=../Lua/lib/lips 6 | out=oot-spawner.z64 7 | 8 | . common.sh 9 | 10 | luajit patch.lua \ 11 | -O 0x035D0000 -b $((0x80700000 - 0x035D0000)) \ 12 | 'spawn O EUDB MQ.asm' "build/$out" 13 | 14 | dump -f "build/$out" 15 | -------------------------------------------------------------------------------- /asm/oot-widescreen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | rom=../../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" 5 | lips=../Lua/lib/lips 6 | out=oot-widescreen.z64 7 | 8 | . common.sh 9 | 10 | luajit patch.lua \ 11 | -O 0x035D0000 -b $((0x80700000 - 0x035D0000)) \ 12 | widescreen-inline-rom.asm "build/$out" 13 | 14 | dump -f "build/$out" 15 | -------------------------------------------------------------------------------- /asm/patch.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | --require "test.strict" 3 | local assemble = require "lips.init" 4 | local cereal = require "serialize" 5 | local argparse = require "argparse" 6 | 7 | local function lament(...) 8 | io.stdout:write(...) 9 | io.stdout:write('\n') 10 | end 11 | 12 | local function parsenum(s) 13 | if type(s) == 'number' then 14 | return s 15 | end 16 | if s:sub(1, 2) == '0x' or s:sub(1, 1) == '$' then 17 | return tonumber(s, 16) 18 | elseif s:sub(1, 2) == '0o' or s:sub(1, 1) == '0' then 19 | return tonumber(s, 8) 20 | elseif s:sub(1, 2) == '0b' or s:sub(1, 1) == '%' then 21 | return tonumber(s, 2) 22 | else 23 | return tonumber(s) 24 | end 25 | end 26 | 27 | local function make_verbose_writer() 28 | -- TODO: further optimize 29 | local buff = {} 30 | local function write(i) 31 | local a = buff[i+0] or nil 32 | local b = buff[i+1] or nil 33 | local c = buff[i+2] or nil 34 | local d = buff[i+3] or nil 35 | if a or b or c or d then 36 | a = a and ("%02X"):format(a) or '--' 37 | b = b and ("%02X"):format(b) or '--' 38 | c = c and ("%02X"):format(c) or '--' 39 | d = d and ("%02X"):format(d) or '--' 40 | print(('%08X %s'):format(i, a..b..c..d)) 41 | end 42 | end 43 | 44 | local max = -1 45 | local maxp = -1 46 | return function(pos, b) 47 | if pos then 48 | buff[pos] = b 49 | if pos > max then 50 | max = pos 51 | end 52 | if pos < 0x80000000 and pos > maxp then 53 | maxp = pos 54 | end 55 | elseif max >= 0 then 56 | for i=0, maxp, 4 do 57 | write(i) 58 | end 59 | for i=0x80000000, max, 4 do 60 | write(i) 61 | end 62 | end 63 | end 64 | end 65 | 66 | local function inject(args) 67 | local offset = args.offset and parsenum(args.offset) or 0 68 | local origin = args.origin and parsenum(args.origin) or 0 69 | local base = args.base and parsenum(args.base) or 0x80000000 70 | 71 | local f 72 | if args.output then 73 | f = io.open(args.output, 'r+b') 74 | if not f then 75 | lament("file not found: ", args.output) 76 | return 77 | end 78 | end 79 | 80 | local state = {} 81 | for _, import in ipairs(args.import) do 82 | local new_state = cereal.deserialize(import) 83 | for k, v in pairs(new_state) do 84 | state[k] = v 85 | end 86 | end 87 | 88 | local function write(pos, b) 89 | if pos >= offset then 90 | pos = pos - offset 91 | end 92 | if pos >= 1024*1024*1024 then 93 | lament(("oops: %08X %02X"):format(pos, b)) 94 | return 95 | end 96 | 97 | if f then 98 | f:seek('set', pos) 99 | f:write(string.char(b)) 100 | else 101 | print(("%08X %02X"):format(pos, b)) 102 | end 103 | end 104 | 105 | local options = { 106 | unsafe = true, 107 | labels = state, 108 | debug_token = args.dump_token, 109 | debug_pre = args.dump_pre, 110 | debug_post = args.dump_post, 111 | debug_asm = args.dump_asm, 112 | } 113 | if args.offset then 114 | if args.origin or args.base then 115 | error('--offset is mutually exclusive from --origin, --base') 116 | end 117 | options.offset = offset 118 | else 119 | options.origin = origin 120 | options.base = base 121 | end 122 | 123 | if f then 124 | assemble(args.input, write, options) 125 | else 126 | local vb = make_verbose_writer() 127 | assemble(args.input, vb, options) 128 | vb() 129 | end 130 | 131 | if args.export then 132 | cereal.serialize(args.export, state) 133 | end 134 | 135 | if f then 136 | f:close() 137 | end 138 | end 139 | 140 | local ap = argparse("patch", "patch a binary file with assembly") 141 | 142 | -- TODO: option to dump hex or gs codes when no output is given 143 | ap:argument("input", "input assembly file") 144 | ap:argument("output", "output binary file"):args('?') 145 | ap:option("-o --offset", "(deprecated) offset to pass to lips", nil) 146 | ap:option("-O --origin", "origin to pass to lips", nil) 147 | ap:option("-b --base", "base to pass to lips", nil) 148 | ap:option("-i --import", "import state file(s) containing labels"):count("*") 149 | ap:option("-e --export", "export state file containing labels") 150 | ap:flag("--dump-token", "(debug) dump statements to stdout after lexing") 151 | ap:flag("--dump-pre", "(debug) dump statements to stdout after preprocessing") 152 | ap:flag("--dump-post", "(debug) dump statements to stdout after expanding") 153 | ap:flag("--dump-asm", "(debug) dump statements to stdout after assembling") 154 | --ap:option("-s --state", "--import and --export to this file") 155 | -- TODO: use -D defines instead 156 | 157 | local inject_args = ap:parse() 158 | 159 | inject(inject_args) 160 | -------------------------------------------------------------------------------- /asm/print.asm: -------------------------------------------------------------------------------- 1 | // translates calls to 800021F8 2 | // to copy strings to memory instead 3 | // for Lua to later pick up on 4 | 5 | jr 6 | nop 7 | /* 8 | [global_context]: 0x80212020 9 | 10 | // offset from first pointer in global context 11 | [dlist_offset]: 0x2B0 12 | 13 | [SetTextRGBA]: 0x800FB3AC 14 | [SetTextXY]: 0x800FB41C 15 | [SetTextString]: 0x800FBCB4 16 | [TxtPrinter]: 0x800FBB60 17 | [InitTxtStruct]: 0x800FBB8C ; unused here; we set it up inline 18 | [DoTxtStruct]: 0x800FBC1C 19 | [UpdateTxtStruct]: 0x800FBC64 20 | push 4, 1, ra 21 | // draw the debug text 22 | li a0, 0x00010001 // xy 23 | li a1, 0x88CCFFFF // rgba 24 | la a2, fmt 25 | la a3, buffer 26 | jal simple_text 27 | nop 28 | // reset buffer position 29 | la t0, buffer 30 | sw t0, buffer_pos 31 | // and set the string to null 32 | sb r0, 0(t0) 33 | ret 4, 1, ra 34 | 35 | fmt: 36 | .asciiz "%s" 37 | .align 38 | 39 | .include "simple text.asm" 40 | */ 41 | 42 | // keep track of where we are in the buffer 43 | .org 0x807006F8 44 | buffer_pos: 45 | .word buffer 46 | 47 | buffer_lock: 48 | .word 0 49 | 50 | //.align 4 51 | buffer: 52 | .skip 0x3000 53 | 54 | // force a crash-like thing that dumps a ton of (RDP?) info: 55 | //.org 0x800C5E78 56 | // li t8, 0x29a 57 | 58 | // overwrite (not hook) the debug printing function 59 | .org 0x800021B0 60 | // a0: unknown 61 | // a1: char *msg 62 | // a2: size_t len 63 | li t0, 1 64 | sw t0, buffer_lock 65 | lw t0, buffer_pos 66 | copy_loop: 67 | lb t1, 0(a1) 68 | sb t1, 0(t0) 69 | addi t0, t0, 1 70 | addi a1, a1, 1 71 | subi a2, a2, 1 72 | bne a2, r0, copy_loop 73 | sb r0, 0(t0) // null terminate 74 | sw t0, buffer_pos 75 | sw r0, buffer_lock 76 | jr 77 | nop 78 | -------------------------------------------------------------------------------- /asm/serialize.lua: -------------------------------------------------------------------------------- 1 | -- it's simple, dumb, unsafe, incomplete, and it gets the damn job done 2 | 3 | local type = type 4 | local extra = require "extra" 5 | local opairs = extra.opairs 6 | local tostring = tostring 7 | local open = io.open 8 | local strfmt = string.format 9 | local strrep = string.rep 10 | 11 | local function kill_bom(s) 12 | if #s >= 3 and s:byte(1)==0xEF and s:byte(2)==0xBB and s:byte(3)==0xBF then 13 | return s:sub(4) 14 | end 15 | return s 16 | end 17 | 18 | local function sanitize(v) 19 | local force = type(v) == 'string' and v:sub(1, 1):match('%d') 20 | force = force and true or false 21 | return type(v) == 'string' and strfmt('%q', v) or tostring(v), force 22 | end 23 | 24 | local function _serialize(value, writer, level) 25 | level = level or 1 26 | if type(value) == 'table' then 27 | local indent = strrep('\t', level) 28 | writer('{\n') 29 | for key,value in opairs(value) do 30 | local sane, force = sanitize(key) 31 | local keyval = (sane == '"'..key..'"' and not force) and key or '['..sane..']' 32 | writer(indent..keyval..' = ') 33 | _serialize(value, writer, level + 1) 34 | writer(',\n') 35 | end 36 | writer(strrep('\t', level - 1)..'}') 37 | else 38 | local sane, force = sanitize(value) 39 | writer(sane) 40 | end 41 | end 42 | 43 | local function _deserialize(script) 44 | local f = loadstring(kill_bom(script)) 45 | if f ~= nil then 46 | return f() 47 | else 48 | print('WARNING: no function to deserialize with') 49 | return nil 50 | end 51 | end 52 | 53 | local function serialize(path, value) 54 | local file = open(path, 'w') 55 | if not file then return end 56 | file:write("return ") 57 | _serialize(value, function(...) 58 | file:write(...) 59 | end) 60 | file:write("\n") 61 | file:close() 62 | end 63 | 64 | local function deserialize(path) 65 | local file = open(path, 'r') 66 | if not file then return end 67 | local script = file:read('*a') 68 | local value = _deserialize(script) 69 | file:close() 70 | return value 71 | end 72 | 73 | return { 74 | serialize = serialize, 75 | deserialize = deserialize, 76 | } 77 | -------------------------------------------------------------------------------- /asm/simple spawn.asm: -------------------------------------------------------------------------------- 1 | simple_spawn: 2 | // a0: actor number 3 | // a1: actor variable 4 | push 4, 9, ra 5 | mov a2, a0 6 | mov t4, a1 7 | li a1, @global_context 8 | addi a0, a1, @actor_spawn_offset 9 | li t0, @link_actor 10 | lw t1, @actor_x(t0) 11 | lw t2, @actor_y(t0) 12 | lw t3, @actor_z(t0) 13 | lhu t7, @actor_horiz_angle(t0) 14 | call @actor_spawn a0, a1, a2, t1, t2, t3, 0, t7, 0, t4, 0x7F, 0x3FF, 0 15 | ret 4, 9, ra 16 | 17 | /* old version (before call pseudo-instruction existed) with comments 18 | simple_spawn: 19 | // a0: actor number 20 | // a1: actor variable 21 | push 4, 9, ra 22 | mov a2, a0 23 | mov t4, a1 24 | li a1, @global_context 25 | addi a0, a1, @actor_spawn_offset 26 | li t0, @link_actor 27 | lw t1, @actor_x(t0) 28 | lw t2, @actor_y(t0) 29 | lw t3, @actor_z(t0) 30 | mov a3, t1 // X position 31 | sw t2, 0x10(sp) // Y position 32 | sw t3, 0x14(sp) // Z position 33 | 34 | li t9, 0x0 35 | sw t9, 0x18(sp) // rotation? 36 | lhu t7, @actor_horiz_angle(t0) 37 | sw t7, 0x1C(sp) // horizontal rotation 38 | li t9, 0x0 39 | sw t9, 0x20(sp) // rotation? 40 | 41 | sw t4, 0x24(sp) // actor variable 42 | 43 | li t9, 0x0000007F 44 | sw t9, 0x28(sp) // unknown 45 | li t9, 0x000003FF 46 | sw t9, 0x2C(sp) // spawn time? (probably MM only) 47 | li t9, 0x00000000 48 | sw t9, 0x30(sp) // unknown 49 | jal @actor_spawn 50 | nop 51 | ret 4, 9, ra 52 | */ 53 | -------------------------------------------------------------------------------- /asm/simple text.asm: -------------------------------------------------------------------------------- 1 | textdata: 2 | .word 0, 0, 0, 0, 0 3 | simple_text: 4 | // a0: xxxxyyyy 5 | // a1: rrggbbaa 6 | // a2: printf formatting string 7 | // a3: first argument for format string (optional) 8 | // TODO: support more than 4 args 9 | push 4, 1, s0, s1, ra 10 | 11 | la s0, textdata 12 | 13 | sw a0, 32(sp) 14 | sw a1, 36(sp) 15 | sw a2, 40(sp) 16 | sw a3, 44(sp) 17 | 18 | li t0, @TxtPrinter 19 | sw t0, 0(s0) // printer 20 | sw r0, 4(s0) // dlist end 21 | sh r0, 8(s0) // x 22 | sh r0, 10(s0) // y 23 | li t0, 0xC 24 | sw t0, 12(s0) // unknown 25 | sw r0, 16(s0) // color 26 | 27 | li t0, @global_context 28 | lw s1, 0(t0) 29 | lw t2, @dlist_offset(s1) 30 | 31 | call @DoTxtStruct, s0, t2 32 | 33 | lbu a1, 36(sp) 34 | lbu a2, 37(sp) 35 | lbu a3, 38(sp) 36 | lbu t1, 39(sp) 37 | call @SetTextRGBA, s0, a1, a2, a3, t1 38 | 39 | lh a1, 32(sp) 40 | lh a2, 34(sp) 41 | call @SetTextXY, s0, a1, a2 42 | 43 | lw a1, 40(sp) 44 | lw a2, 44(sp) 45 | call @SetTextString, s0, a1, a2 46 | 47 | call @UpdateTxtStruct, s0 48 | 49 | sw v0, @dlist_offset(s1) 50 | 51 | ret 4, 1, s0, s1, ra 52 | -------------------------------------------------------------------------------- /asm/spawn O EUDB MQ.asm: -------------------------------------------------------------------------------- 1 | .include "dma O EUDB MQ.asm" 2 | 3 | [original]: 0x800C6AC4 4 | [inject_from]: 0xB3D458 ; 0x800C62B8 5 | [inject_to]: 0x80700000 6 | 7 | .push pc 8 | .base 0x7F588E60 ; code file in memory 9 | 10 | .org @inject_from 11 | jal @inject_to 12 | 13 | .pop pc 14 | 15 | sw ra, -4(sp) 16 | sw a0, 0(sp) 17 | sw a1, 4(sp) 18 | sw a2, 8(sp) 19 | sw a3, 12(sp) 20 | bal spawn 21 | subi sp, sp, 24 22 | lw ra, 20(sp) 23 | lw a0, 24(sp) 24 | lw a1, 28(sp) 25 | lw a2, 32(sp) 26 | lw a3, 36(sp) 27 | j @original 28 | addi sp, sp, 24 29 | 30 | [actor_spawn]: 0x80031F50 31 | [object_spawn]: 0x80097C00 32 | [object_index]: 0xB0F2CC ; 0x8009812C 33 | 34 | [max_actor_no]: 0x1D6 35 | 36 | [global_context]: 0x80212020 37 | [buttons_offset]: 0x14 38 | [actor_spawn_offset]: 0x1C24 39 | [object_spawn_offset]: 0x117A4 40 | 41 | [link_actor]: 0x802245B0 42 | [actor_x]: 0x24 43 | [actor_y]: 0x28 44 | [actor_z]: 0x2C 45 | [actor_horiz_angle]: 0x46 46 | 47 | // offset from first pointer in global context 48 | [dlist_offset]: 0x2B0 49 | 50 | [SetTextRGBA]: 0x800FB3AC 51 | [SetTextXY]: 0x800FB41C 52 | [SetTextString]: 0x800FBCB4 53 | [TxtPrinter]: 0x800FBB60 54 | [InitTxtStruct]: 0x800FBB8C ; unused here; we set it up inline 55 | [DoTxtStruct]: 0x800FBC1C 56 | [UpdateTxtStruct]: 0x800FBC64 57 | 58 | .include "spawn.asm" 59 | -------------------------------------------------------------------------------- /asm/spawn mm early.asm: -------------------------------------------------------------------------------- 1 | [actor_spawn]: 0x800BC98C 2 | [object_spawn]: 0x80130D50 3 | [object_index]: 0x80131078 4 | [max_actor_no]: 0x2B1 5 | 6 | [global_context]: 0x803E6CF0 7 | [buttons_offset]: 0x14 8 | [actor_spawn_offset]: 0x1CA0 9 | [object_spawn_offset]: 0x17D68 10 | 11 | [link_actor]: 0x803FFFA0 12 | [actor_x]: 0x24 13 | [actor_y]: 0x28 14 | [actor_z]: 0x2C 15 | [actor_horiz_angle]: 0x32 16 | 17 | [link_save]: 0x801EF460 18 | [rupees_offset]: 0x3A 19 | [upgrades_offset]: 0xB8 20 | [upgrades_2_offset]: 0xBA 21 | 22 | .include "spawn.asm" 23 | -------------------------------------------------------------------------------- /asm/spawn mm.asm: -------------------------------------------------------------------------------- 1 | [actor_spawn]: 0x800BAE14 2 | [object_spawn]: 0x8012F2E0 3 | [object_index]: 0x8012F608 4 | [max_actor_no]: 0x2B1 5 | 6 | [global_context]: 0x803E6B20 7 | [buttons_offset]: 0x14 8 | [actor_spawn_offset]: 0x1CA0 9 | [object_spawn_offset]: 0x17D88 10 | 11 | [link_actor]: 0x803FFDB0 12 | [actor_x]: 0x24 13 | [actor_y]: 0x28 14 | [actor_z]: 0x2C 15 | [actor_horiz_angle]: 0x32 16 | 17 | [link_save]: 0x801EF670 18 | [rupees_offset]: 0x3A 19 | [upgrades_offset]: 0xB8 20 | [upgrades_2_offset]: 0xBA 21 | 22 | [dlist_offset]: 0x2B0 23 | 24 | [SetTextRGBA]: 0x800859BC 25 | [SetTextXY]: 0x80085A2C 26 | [SetTextString]: 0x800860D8 27 | [TxtPrinter]: 0x80085FE4 28 | [InitTxtStruct]: 0x80086010 ; unused here; we set it up inline 29 | [DoTxtStruct]: 0x8008606C 30 | [UpdateTxtStruct]: 0x800860A0 31 | 32 | .include "spawn.asm" 33 | 34 | [whatever]: 0x807D0000 ; stupid hack since i can't store/restore PC (not yet!) 35 | .org @whatever 36 | push 5, ra 37 | lhu t0, 0(a1) 38 | andi t0, t0, 0x07FF 39 | bnei t0, 0x0C5, + // skip if not title screen actor 40 | nop 41 | jal 0x800BB2D0 // original code 42 | nop 43 | +: 44 | ret 5, ra 45 | 46 | .org 0x800B9430 // part of scene actor loading routine 47 | jal @whatever 48 | 49 | .org 0x8012FC18 // scene command 0x0B (objects) 50 | // don't load any objects manually, 51 | // since spawn.asm handles that automatically 52 | jr 53 | nop 54 | -------------------------------------------------------------------------------- /asm/spawn oot.asm: -------------------------------------------------------------------------------- 1 | [actor_spawn]: 0x80025110 2 | [object_spawn]: 0x800812F0 3 | [object_index]: 0x80081628 4 | [max_actor_no]: 0x1D6 5 | 6 | [global_context]: 0x801C84A0 7 | [buttons_offset]: 0x14 8 | [actor_spawn_offset]: 0x1C24 9 | [object_spawn_offset]: 0x117A4 10 | 11 | [link_actor]: 0x801DAA30 12 | [actor_x]: 0x24 13 | [actor_y]: 0x28 14 | [actor_z]: 0x2C 15 | [actor_horiz_angle]: 0x46 16 | 17 | [link_save]: 0x8011A5D0 18 | [rupees_offset]: 0x34 19 | [upgrades_offset]: 0xA0 20 | [upgrades_2_offset]: 0xA2 21 | 22 | [dlist_offset]: 0x2B0 23 | 24 | [SetTextRGBA]: 0x800CBE58 25 | [SetTextXY]: 0x800CBEC8 26 | [SetTextString]: 0x800CC588 27 | [TxtPrinter]: 0x800CC480 28 | [InitTxtStruct]: 0x800CC4AC ; unused here; we set it up inline 29 | [DoTxtStruct]: 0x800CC508 30 | [UpdateTxtStruct]: 0x800CC550 31 | 32 | .include "spawn.asm" 33 | -------------------------------------------------------------------------------- /asm/spawn.asm: -------------------------------------------------------------------------------- 1 | [button_L]: 0x0020 2 | [button_R]: 0x0010 3 | [button_any]: 0x0F20 4 | 5 | [min_actor_no]: 0 6 | 7 | [hold_delay_amount]: 3 8 | 9 | spawn: 10 | push 4, s0, s1, s2, s3, s4, ra, 11 | li t1, @global_context 12 | lhu s0, anum 13 | lw s1, hold_delay 14 | lhu s2, @buttons_offset(t1) 15 | lhu s3, avar 16 | lw s4, selected 17 | // set selected 18 | // andi t2, s2, @button_R 19 | srl s4, s2, 4 20 | andi s4, 1 21 | // handle hold delay 22 | andi t4, s2, @button_any 23 | bnez t4, + 24 | addi s1, s1, 1 25 | li s1, 0 26 | +: 27 | beqi s1, 1, + 28 | nop 29 | subi t4, s1, @hold_delay_amount 30 | bltz t4, return 31 | nop 32 | +: // handle dpad 33 | bnez s4, + 34 | mov a1, s2 35 | call dpad_control, s0, a1 36 | mov s0, v0 37 | b ++ 38 | nop 39 | +: 40 | call dpad_control, s3, a1 41 | andi s3, v0, 0xFFFF 42 | +: // set min/max on actor number 43 | subi t4, s0, @min_actor_no 44 | bgez t4, + 45 | nop 46 | li s0, @max_actor_no 47 | +: 48 | subi t4, s0, @max_actor_no 49 | blez t4, + 50 | nop 51 | li s0, @min_actor_no 52 | +: // spawn 53 | andi t3, s2, @button_L 54 | beqz t3, return 55 | nop 56 | mov a0, s0 57 | mov a1, s3 58 | bal simple_spawn 59 | nop 60 | return: 61 | // render actor number 62 | call simple_text, 0x000F001B, 0x88CCFFFF, fmt, s0 63 | // render actor variable 64 | call simple_text, 0x0014001B, 0xFFCC88FF, fmt, s3 65 | // done 66 | sh s0, anum 67 | sw s1, hold_delay 68 | sh s3, avar 69 | sw s4, selected 70 | ret 4, s0, s1, s2, s3, s4, ra, 71 | 72 | .word 0xDEADBEEF 73 | .word textdata 74 | 75 | anum: 76 | .word 0 77 | avar: 78 | .word 0 79 | selected: 80 | .word 0 81 | 82 | fmt: 83 | .asciiz "%04X" 84 | .align 85 | 86 | /* old version that didn't account for negative arguments 87 | object_index_hook: 88 | push 4, 1, ra 89 | mov t0, a0 90 | lbu t1, 8(a0) // remaining items 91 | cl v0 92 | sll a1, 0x10 93 | sra a1, 0x10 94 | abs a1 95 | -: 96 | lhu t2, 12(t0) // item's object number 97 | abs t2 98 | beq a1, t2, + 99 | subi t1, 1 100 | addiu v0, 1 101 | bnez t1, - 102 | addi t0, 68 103 | call @object_spawn, a0, a1 104 | ; subiu v0, r0, -1 // original code 105 | +: 106 | ret 4, 1, ra 107 | */ 108 | 109 | ; based on game code 110 | object_index_hook: 111 | // a0: object table 112 | // a1: object number 113 | sll t1, a1, 0x10 114 | sra t1, 0x10 115 | lbu t3, 8(a0) 116 | cl v0 117 | mov t2, a0 118 | blez t3, +give_up ; interesting: give up if object number read is <= 0 119 | -: 120 | lh t0, 12(t2) 121 | abs t0 122 | bne t0, t1, + 123 | nop 124 | jr ra 125 | nop 126 | +: 127 | addiu v0, 1 128 | blt v0, t3, - ; if we still have some left... v0 is number of objects 129 | addiu t2, 68 130 | +give_up: 131 | ; ; dump failed object number to ram 132 | ; la t0, DEBUG 133 | ; lw t2, (t0) 134 | ; addiu t2, 1 135 | ; sw t2, (t0) 136 | ; sll t1, t2, 2 137 | ; addu t1, t0 138 | ; sw a1, (t1) 139 | ; beqi t2, 2, + 140 | push 4, s0, s1, 1, ra 141 | mov s1, a0 142 | lbu s0, 9(s1) 143 | call @object_spawn, a0, a1 144 | sb s0, 9(s1) 145 | ret 4, s0, s1, 1, ra 146 | +: 147 | jr 148 | li v0, -1 149 | 150 | /* 151 | .word 0xDEADBEEF 152 | DEBUG: 153 | .skip 0x100 0 154 | */ 155 | 156 | .include "dpad control.asm" 157 | .include "simple spawn.asm" 158 | .include "simple text.asm" 159 | 160 | hold_delay: 161 | .word 0 162 | 163 | .org @object_index 164 | // a0: object table 165 | // a1: object number 166 | // we have space for 22 instructions (on debug, 23 on 1.0?) 167 | j object_index_hook 168 | nop 169 | -------------------------------------------------------------------------------- /asm/widescreen-inline-rom.asm: -------------------------------------------------------------------------------- 1 | ; oot debug rom 2 | ; mess with display lists 3 | ; game note: #2 jumps to #3 which jumps to #1 which calls pieces of #2 4 | ; what a mess 5 | 6 | [ctxt]: 0x80212020 7 | [dlists]: 0x80168930 8 | 9 | [original]: 0x800C6AC4 10 | [inject_from]: 0xB3D458 ; 0x800C62B8 11 | [inject_to]: 0x80700000 12 | 13 | ; set up screen dimensions to render widescreen. 14 | [res2_L]: 0 15 | [res2_T]: 30 16 | [res2_R]: 320 17 | [res2_B]: 210 18 | 19 | .include "dma O EUDB MQ.asm" 20 | 21 | .push pc 22 | .base 0x7F588E60 ; code file in memory 23 | 24 | .org @inject_from 25 | jal @inject_to 26 | 27 | .org 0xB21D30 ; 0x800AAB90 28 | li t3, @res2_B ; 240B00D2 29 | li t4, @res2_T ; 240C001E 30 | .org 0xB21D48 ; 0x800AABA8 31 | li t1, @res2_R ; 24090140 32 | li t2, @res2_L ; 240A0000 33 | 34 | .pop pc 35 | sw ra, -4(sp) 36 | sw a0, 0(sp) 37 | sw a1, 4(sp) 38 | sw a2, 8(sp) 39 | sw a3, 12(sp) 40 | bal start 41 | subi sp, sp, 24 42 | lw ra, 20(sp) 43 | lw a0, 24(sp) 44 | lw a1, 28(sp) 45 | lw a2, 32(sp) 46 | lw a3, 36(sp) 47 | j @original 48 | addi sp, sp, 24 49 | 50 | .include "widescreen-either.asm" 51 | -------------------------------------------------------------------------------- /asm/widescreen-inline.asm: -------------------------------------------------------------------------------- 1 | ; oot debug rom 2 | ; mess with display lists 3 | ; game note: #2 jumps to #3 which jumps to #1 which calls pieces of #2 4 | ; what a mess 5 | 6 | [ctxt]: 0x80212020 7 | [dlists]: 0x80168930 8 | 9 | [original]: 0x800C6AC4 10 | [inject_from]: 0x800C62B8 11 | [inject_to]: 0x80700000 12 | 13 | .org @inject_from 14 | jal @inject_to 15 | 16 | .org @inject_to 17 | sw ra, -4(sp) 18 | sw a0, 0(sp) 19 | sw a1, 4(sp) 20 | sw a2, 8(sp) 21 | sw a3, 12(sp) 22 | bal start 23 | subi sp, sp, 24 24 | lw ra, 20(sp) 25 | lw a0, 24(sp) 26 | lw a1, 28(sp) 27 | lw a2, 32(sp) 28 | lw a3, 36(sp) 29 | j @original 30 | addi sp, sp, 24 31 | 32 | .include "widescreen-either.asm" 33 | 34 | ; set up screen dimensions to render widescreen. 35 | [res2_L]: 0 36 | [res2_T]: 30 37 | [res2_R]: 320 38 | [res2_B]: 210 39 | .org 0x800AAB90 40 | li t3, @res2_B ; 240B00D2 41 | li t4, @res2_T ; 240C001E 42 | .org 0x800AABA8 43 | li t1, @res2_R ; 24090140 44 | li t2, @res2_L ; 240A0000 45 | -------------------------------------------------------------------------------- /chksum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # fixes the checksums in a Majora's Mask savefile for Bizhawk 3 | # note: copies are ignored and overwritten, so don't bother editing them. 4 | 5 | import sys 6 | from util import R2, W2, swap_order 7 | 8 | lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs) 9 | 10 | MAX16 = 0xFFFF 11 | 12 | chksum_offset = 0x100A 13 | save_size = 0x2000 14 | owl_size = 0x4000 15 | 16 | save_1 = (0x20800, save_size) 17 | save_2 = (0x24800, save_size) 18 | owl_1 = (0x28800, owl_size) 19 | owl_2 = (0x30800, owl_size) 20 | save_1_copy = (0x22800, save_size) 21 | save_2_copy = (0x26800, save_size) 22 | owl_1_copy = (0x2C800, owl_size) 23 | owl_2_copy = (0x34800, owl_size) 24 | 25 | def calc_sum(data): 26 | chksum = 0 27 | for b in data: 28 | chksum += b 29 | chksum &= MAX16 30 | return chksum 31 | 32 | def fix_sum(f, save, owl=False): 33 | f.seek(save[0]) 34 | data = f.read(save[1]) 35 | chksum = calc_sum(data[:chksum_offset]) 36 | 37 | if owl and data != b'\x00'*len(data): 38 | chksum += 0x24 # don't know why 39 | chksum &= MAX16 40 | 41 | f.seek(save[0] + chksum_offset) 42 | old_chksum = R2(f.read(2)) 43 | f.seek(save[0] + chksum_offset) 44 | f.write(W2(chksum)) 45 | lament('{:04X} -> {:04X}'.format(old_chksum, chksum)) 46 | 47 | def copy_save(f, save_from, save_to): 48 | f.seek(save_from[0]) 49 | data = f.read(save_from[1]) 50 | f.seek(save_to[0]) 51 | f.write(data[:save_to[1]]) 52 | 53 | def delete_save(f, save): 54 | f.seek(save[0]) 55 | f.write(b'\x00'*save[1]) 56 | 57 | def run(args): 58 | for fn in args: 59 | with open(fn, 'r+b') as f: 60 | # dumb way to determine byte order 61 | endian = 'big' 62 | f.seek(0x10000) 63 | if f.read(4) != b'\x03\x00\x03\x00': 64 | endian = 'little' 65 | 66 | if endian == 'little': 67 | swap_order(f, 'L') 68 | 69 | fix_sum(f, save_1) 70 | fix_sum(f, save_2) 71 | fix_sum(f, owl_1, owl=True) 72 | fix_sum(f, owl_2, owl=True) 73 | copy_save(f, save_1, save_1_copy) 74 | copy_save(f, save_2, save_2_copy) 75 | copy_save(f, owl_1, owl_1_copy) 76 | copy_save(f, owl_2, owl_2_copy) 77 | 78 | if endian == 'little': 79 | swap_order(f, 'L') 80 | return 0 81 | 82 | if __name__ == '__main__': 83 | try: 84 | ret = run(sys.argv[1:]) 85 | sys.exit(ret) 86 | except KeyboardInterrupt: 87 | sys.exit(1) 88 | -------------------------------------------------------------------------------- /dump/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /heuristics.py: -------------------------------------------------------------------------------- 1 | from util import * 2 | 3 | def try_makerom(f): 4 | f.seek(0) 5 | if f.read(12) == b'\x80\x37\x12\x40\x00\x00\x00\x0f\x80\x00\x04\x00': 6 | return True 7 | return False 8 | 9 | def try_dmadata(f): 10 | f.seek(0) 11 | if f.read(20) == b"\x00\x00\x00\x00\x00\x00\x10\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x60": 12 | return True 13 | return False 14 | 15 | def try_actor(f): 16 | f.seek(-4, 2) 17 | section_size = R4(f.read(4)) 18 | file_size = f.tell() 19 | if section_size > 0x4000 or section_size == 0: 20 | # assume this section isn't larger than 16KiB 21 | # (that's 4 times larger than the largest one in OoT) 22 | return False 23 | f.seek(-section_size, 2) 24 | section_start = f.tell() 25 | if section_start + 12 >= file_size: 26 | return False 27 | data_offset = R4(f.read(4)) 28 | data_size = R4(f.read(4)) 29 | misc_size = R4(f.read(4)) 30 | if section_start == data_offset + data_size + misc_size: 31 | return True 32 | return False 33 | 34 | def try_scene_or_room(f, bank=2): 35 | # note: doesn't detect syotes_room_0 because it's missing a header 36 | f.seek(0) 37 | while True: 38 | command = f.read(8) 39 | if len(command) == 0: 40 | return False 41 | if command[2:4] != b'\x00\x00': 42 | return False 43 | if command[0] > 0x1e: 44 | return False 45 | if command[4] != bank and command[4] != 0x00: 46 | if command[0] not in (0x05, 0x10, 0x11, 0x12): 47 | return False 48 | if command == b'\x14\x00\x00\x00\x00\x00\x00\x00': 49 | return True 50 | 51 | def detect_format(f, fn=None): 52 | if try_makerom(f): 53 | return None 54 | if try_dmadata(f): 55 | return None 56 | if try_actor(f): 57 | return 'actor' 58 | if try_scene_or_room(f, 2): 59 | return 'scene' 60 | if try_scene_or_room(f, 3): 61 | return 'room' 62 | 63 | return None 64 | -------------------------------------------------------------------------------- /img/M_US10.2016-10-02 19.02.17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notwa/mm/649325acc7912fadb11e5bae2b7a4e006b10bd8b/img/M_US10.2016-10-02 19.02.17.png -------------------------------------------------------------------------------- /mm-bitflags.txt: -------------------------------------------------------------------------------- 1 | address: 80400A0C JP 1.0 (note: bytes here in backwards order?) 2 | 00000001 - can't control link, time stops 3 | 00000002 - frozen world (time still passes, sword works, don't try jumping) 4 | 00000004 - camera pans above link, can't c-up, walk through actors, getting hurt causes you to get thrown 5 | 00000008 - ??? pulling out bombs resets it 6 | 00000010 - using zora magic 7 | 00000020 - take away control, hud goes into cutscene mode 8 | 00000040 - bombs stick in air? 9 | 00000080 - link is dead (can only walk, walk through actors, time stops) 10 | 11 | 00000100 - putting mask on effect appears sometimes 12 | 00000200 - freeze everything (tatl still flies around, camera pans) 13 | 00000400 - tatl flies to where the camera is 14 | 00000800 - holding something (ground jump if nothing) 15 | 00001000 - can't untarget 16 | 00002000 - same as 00000004 17 | 00004000 - similar to above 18 | 00008000 - am z-targeting (again) 19 | 20 | 00010000 - am z-targeting? (locked on?) 21 | 00020000 - am z-targeting (persists angle) 22 | 00040000 - am in air/jumping 23 | 00080000 - janky camera (z-targeting?) 24 | 00100000 - am c-uping? (stops camera from changing when talking) 25 | 00200000 - spinny camera 26 | 00400000 - shield enemy attacks 27 | 00800000 - crash 28 | 29 | 01000000 - ??? 30 | 02000000 - z-targeting (locked camera) 31 | 04000000 - can't take damage (mostly) 32 | 08000000 - strange immobile/sliding state (c-up related?) 33 | 10000000 - freeze actors 34 | 20000000 - freeze link 35 | 40000000 - disable z targetting? 36 | 80000000 - falling into grotto (loads mayor's) 37 | 38 | combinations: 39 | 00000003 - set when using ocarina 40 | A0000000 - fall into floor (grotto + frozen link = doesn't load mayor's) 41 | 00018000 - set when z-targetting with target 42 | 00028000 - set when z-targetting 43 | 7F000000 - can't do anything 44 | 5F000000 - slidey link, locked camera 45 | 20010040 - talking state 46 | FF7FFFFF - the most you can have on without crashing 47 | 01000008 - all unknown flags at once 48 | 49 | address: 80400A10 JP 1.0 (note: bytes here in backwards order?) 50 | 00000001 - ??? 51 | 00000002 - set when a target is available 52 | 00000004 - ??? 53 | 00000008 - sometimes set when you're walking 54 | 00000010 - link won't get pushed back by explosions 55 | 00000020 - set when you're walking 56 | 00000040 - set when deku spinning 57 | 00000080 - ??? 58 | 59 | 00000100 - ??? sometimes causes a z target 60 | 00000200 - ??? 61 | 00000400 - play surfacing water animation 62 | 00000800 - displays dive timer on A button 63 | 00001000 - ??? 64 | 00002000 - can't un-Z-target? 65 | 00004000 - ??? 66 | 00008000 - freeze link in place (can still pause) 67 | 68 | 00010000 - ??? 69 | 00020000 - screen pulsating? 70 | 00040000 - ??? doesn't reset 71 | 00080000 - ??? 72 | 00100000 - whether tatl is flying around link 73 | 00200000 - tatl has something to say 74 | 00400000 - ??? 75 | 00800000 - semi-fixed camera (can still rotate) 76 | 77 | 01000000 - graphical error? 78 | 02000000 - disables items, sword 79 | 04000000 - causes weird model flipping on z axis? 80 | 08000000 - disables actors and some loading (set when link is using ocarina) 81 | 10000000 - link is doing an idle animation 82 | 20000000 - link goes invisible and leaves his body (seriously this is silly) 83 | 40000000 - ??? set when attacking sometimes 84 | 80000000 - instant void out (crushed?) 85 | 86 | combinations: 87 | 404D52C5 - all unknown flags at once 88 | (one of those causes an ice effect to appear at link's feet) 89 | 90 | address: 80400A14 JP 1.0 (note: bytes here in backwards order?) 91 | 00000001 - fall through floor 92 | 00000002 - ??? 93 | 00000004 - freeze link in place 94 | 00000008 - camera doesn't rotate (and lags behind a little?) 95 | 00000010 - ??? 96 | 00000020 - ??? 97 | 00000040 - set when charging up a shot (arrows, bubbles, etc) 98 | 00000080 - link pull out an item. forever. 99 | 100 | 00000100 - deku inside flower 101 | 00000200 - deku firing out of flower (reduces descent, gravity?) 102 | 00000400 - ??? 103 | 00000800 - ??? 104 | 00001000 - goron roll state 105 | 00002000 - deku flying camera/angle 106 | 00004000 - ??? 107 | 00008000 - distant camera (used for what?) 108 | 109 | 00010000 - ??? 110 | 00020000 - set when changing masks 111 | 00040000 - major graphical errors? 112 | 00080000 - goron magic roll state (camera zooms out) 113 | 00100000 - set when deku spinning (again) (gives the damage effect?) 114 | 00200000 - puts a 6 on the A button? 115 | 00400000 - ??? 116 | 00800000 - usually set after using boomerangs? 117 | 118 | 01000000 - deku nuts on B (deku flying state) 119 | 02000000 - set when link uses sword 120 | 04000000 - ??? 121 | 08000000 - set when rolling (does not give invulnerability) 122 | 10000000 - ??? 123 | 20000000 - disables items, sword (again) 124 | 40000000 - link won't stop attacking (fierce deity related?) 125 | 80000000 - allows third-person aiming items (arrows, bubbles, etc) 126 | 127 | combinations: 128 | 01002200 - firing from deku flower state (rocket deku farts) 129 | 14410C32 - all unknown flags at once 130 | -------------------------------------------------------------------------------- /n64.py: -------------------------------------------------------------------------------- 1 | # Based on uCON64's N64 checksum algorithm by Andreas Sterbenz 2 | 3 | from zlib import crc32 4 | 5 | MAX32 = 0xFFFFFFFF 6 | 7 | crc_seeds = { 8 | 6101: 0xF8CA4DDC, 9 | 6102: 0xF8CA4DDC, 10 | 6103: 0xA3886759, 11 | 6105: 0xDF26F436, 12 | 6106: 0x1FEA617A, 13 | } 14 | 15 | bootcode_crcs = { 16 | 0x6170A4A1: 6101, 17 | 0x90BB6CB5: 6102, 18 | 0x0B050EE0: 6103, 19 | 0x98BC2C86: 6105, 20 | 0xACC8580A: 6106, 21 | } 22 | 23 | def ROL(i, b): 24 | return ((i << b) | (i >> (32 - b))) & MAX32 25 | 26 | def R4(b): 27 | return b[0]*0x1000000 + b[1]*0x10000 + b[2]*0x100 + b[3] 28 | 29 | def crc(f, bootcode=6105): 30 | seed = crc_seeds[bootcode] 31 | t1 = t2 = t3 = t4 = t5 = t6 = seed 32 | 33 | if bootcode == 6105: 34 | f.seek(0x0710 + 0x40) 35 | lookup = f.read(0x100) 36 | 37 | f.seek(0x1000) 38 | for i in range(0x1000, 0x101000, 4): 39 | d = R4(f.read(4)) 40 | 41 | if ((t6 + d) & MAX32) < t6: 42 | t4 += 1 43 | t4 &= MAX32 44 | 45 | t6 += d 46 | t6 &= MAX32 47 | 48 | t3 ^= d 49 | 50 | r = ROL(d, d & 0x1F) 51 | 52 | t5 += r 53 | t5 &= MAX32 54 | 55 | if t2 > d: 56 | t2 ^= r 57 | else: 58 | t2 ^= t6 ^ d 59 | 60 | if bootcode == 6105: 61 | o = i & 0xFF 62 | temp = R4(lookup[o:o + 4]) 63 | else: 64 | temp = t5 65 | t1 += temp ^ d 66 | t1 &= MAX32 67 | 68 | if bootcode == 6103: 69 | crc1 = (t6 ^ t4) + t3 70 | crc2 = (t5 ^ t2) + t1 71 | elif bootcode == 6106: 72 | crc1 = t6*t4 + t3 73 | crc2 = t5*t2 + t1 74 | else: 75 | crc1 = t6 ^ t4 ^ t3 76 | crc2 = t5 ^ t2 ^ t1 77 | return crc1 & MAX32, crc2 & MAX32 78 | 79 | def bootcode_version(f): 80 | f.seek(0x40) 81 | return bootcode_crcs[crc32(f.read(0x1000 - 0x40)) & MAX32] 82 | -------------------------------------------------------------------------------- /n64_fast.pyx: -------------------------------------------------------------------------------- 1 | # Based on uCON64's N64 checksum algorithm by Andreas Sterbenz 2 | 3 | from libc.stdint cimport uint32_t, uint8_t 4 | # ulong must be 32 bits since we expect them to overflow as such 5 | ctypedef uint32_t ulong 6 | ctypedef uint8_t uchar 7 | 8 | from zlib import crc32 9 | 10 | crc_seeds = { 11 | 6101: 0xF8CA4DDC, 12 | 6102: 0xF8CA4DDC, 13 | 6103: 0xA3886759, 14 | 6105: 0xDF26F436, 15 | 6106: 0x1FEA617A, 16 | } 17 | 18 | bootcode_crcs = { 19 | 0x6170A4A1: 6101, 20 | 0x90BB6CB5: 6102, 21 | 0x0B050EE0: 6103, 22 | 0x98BC2C86: 6105, 23 | 0xACC8580A: 6106, 24 | } 25 | 26 | cdef ulong ROL(ulong i, ulong b): 27 | return (i << b) | (i >> (32 - b)) 28 | 29 | cdef ulong R4(uchar *b): 30 | return b[0]*0x1000000 + b[1]*0x10000 + b[2]*0x100 + b[3] 31 | 32 | cdef object _crc(uchar *data, ulong bootcode, uchar *lookup): 33 | cdef: 34 | ulong seed = crc_seeds[bootcode] 35 | ulong t1, t2, t3, t4, t5, t6 36 | ulong i, d, b, r, o 37 | ulong crc1, crc2 38 | 39 | t1 = t2 = t3 = t4 = t5 = t6 = seed 40 | 41 | for i in range(0x1000, 0x101000, 4): 42 | d = R4(data + i) 43 | 44 | if t6 + d < t6: 45 | t4 += 1 46 | 47 | t6 += d 48 | 49 | t3 ^= d 50 | 51 | r = ROL(d, d & 0x1F) 52 | 53 | t5 += r 54 | 55 | if t2 > d: 56 | t2 ^= r 57 | else: 58 | t2 ^= t6 ^ d 59 | 60 | if bootcode == 6105: 61 | o = i & 0xFF 62 | t1 += R4(lookup + o)^ d 63 | else: 64 | t1 += t5 65 | 66 | if bootcode == 6103: 67 | crc1 = (t6 ^ t4) + t3 68 | crc2 = (t5 ^ t2) + t1 69 | elif bootcode == 6106: 70 | crc1 = t6*t4 + t3 71 | crc2 = t5*t2 + t1 72 | else: 73 | crc1 = t6 ^ t4 ^ t3 74 | crc2 = t5 ^ t2 ^ t1 75 | return crc1, crc2 76 | 77 | def crc(f, bootcode=6105): 78 | f.seek(0) 79 | data = f.read() 80 | lookup = data[0x750:0x850] 81 | return _crc(data, bootcode, lookup) 82 | 83 | def bootcode_version(f): 84 | f.seek(0x40) 85 | return bootcode_crcs[crc32(f.read(0x1000 - 0x40)) & 0xFFFFFFFF] 86 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | # Miscellaneous notes on Majora's Mask 2 | 3 | for brevity, all addresses written here are given for the original US version. 4 | refer to the spreadsheets or Lua tables for their equivalent in other versions. 5 | 6 | ## save files 7 | 8 | save contents are mostly documented by [the save file binary templates.][savebt] 9 | 10 | [savebt]: //github.com/EntranceJew/zelda-binary-templates/tree/master/filetypes/Save 11 | 12 | *note: the following text is specific to MM; OoT is slightly different.* 13 | 14 | in the versions of the game with owl saves, 15 | regular saves are 0x100C in size, and owl saves are 0x3CA0. 16 | owls use the extra space primarily to store the pictograph picture. 17 | 18 | the game checks a checksum, and for the text "ZELDA3". 19 | each slot has one backup copy of itself, though they don't seem to be used? 20 | if a slot is corrupted, it will show up as empty in the menu. 21 | 22 | the checksum is a 16-bit sum of all bytes up to that point, allowing overflows. 23 | i've written [a checksum-fixing program][chksum] in Python for Bizhawk savefiles. 24 | i've also written an [010][010] Editor [script][chksum2] 25 | and its [OoT variant][chksumOoT] 26 | for properly formed save files, such as those made by nemu64. 27 | 28 | owl saves always have 0x24 added to their checksum for some reason. 29 | 30 | [chksum]: /chksum.py 31 | [chksum2]: //github.com/EntranceJew/zelda-binary-templates/blob/master/scripts/FixSaveMM.1sc 32 | [chksumOoT]: //github.com/EntranceJew/zelda-binary-templates/blob/master/scripts/FixSaveOoT.1sc 33 | [010]: http://www.sweetscape.com/010editor/ 34 | 35 | bizhawk save files, at the time of writing, have the first file offset to 0x20800. 36 | also, their byte order is wrong. 37 | 38 | here's my usual process (in bash) for hacking on save files: 39 | ``` 40 | alias revend='objcopy -I binary -O binary --reverse-bytes=4' 41 | s="Legend of Zelda, The - Majora's Mask (USA).SaveRAM" 42 | x=mm-save.xxd 43 | revend "$s" 44 | xxd "$s" > $x 45 | $EDITOR $x 46 | xxd -r $x > "$s" 47 | ./chksum.py $s 48 | revend "$s" 49 | ``` 50 | 51 | ## MM Save Files 52 | 53 | because no one likes first cycle. 54 | 55 | sometime i'll bother checking what the bombers/lottery codes are for these. 56 | 57 | * [Bizhawk US 1.0 race file](//eaguru.guru/t/MM%20US%20Race%20File%20for%20Bizhawk.zip ) 58 | * [mupen64plus US 1.0 race file](//eaguru.guru/t/Legend%20of%20Zelda%2C%20The%20-%20Majora%27s%20Mask%20%28U%29%20%5B%21%5D.zip) 59 | 60 | you can make your own by using [the provided setup race file script.][racelua] 61 | simply run the script and play Song of Time after South Clock Town has loaded. 62 | 63 | using this script will also set the bombers code to 12345, 64 | set the daily lottery numbers to 123, 456, 789, 65 | and set the Oceanside Spider House puzzle solution to 66 | Red, Blue, Red, Blue, Red, Blue. 67 | 68 | [racelua]: /Lua/setup%20race%20file.lua 69 | 70 | ## bitfields 71 | 72 | ### scene flags 73 | 74 | two regions of 0x960 bytes are allocated for all the scene flags in the game. 75 | the first at `801EFAE0` is loaded from save files, 76 | the second at `801F35D8` is used for in-game changes. 77 | basically, edit the first for save hacking, and the second for in-game hacking. 78 | 79 | each scene in the game uses 0x14 bytes of scene flags. 80 | this implies there's 0x78 possible scenes: 0x78\*0x14 = 0x960. 81 | 82 | the current scene's flags are always copied into the same place in memory. 83 | they appear in a different order than in save files, however. 84 | 85 | (four bytes each) 86 | `803E8978` corresponds to offset 0x04 in the save file. 87 | `803E897C` corresponds to offset 0x08. 88 | `803E8988` corresponds to offset 0x00. 89 | `803E898C` corresponds to offset 0x0C. 90 | `803E8994` corresponds to offset 0x10. 91 | 92 | ### Link's status 93 | 94 | here's [an incomplete document on some of Link's bitfields][linkfields] for JP 1.0. 95 | 96 | [linkfields]: /mm-bitflags.txt 97 | -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import struct, array 3 | 4 | R1 = lambda data: struct.unpack('>B', data)[0] 5 | R2 = lambda data: struct.unpack('>H', data)[0] 6 | R4 = lambda data: struct.unpack('>I', data)[0] 7 | W1 = lambda data: struct.pack('>B', data) 8 | W2 = lambda data: struct.pack('>H', data) 9 | W4 = lambda data: struct.pack('>I', data) 10 | 11 | def dump_as(b, fn, size=None): 12 | with open(fn, 'w+b') as f: 13 | if size: 14 | f.write(bytearray(size)) 15 | f.seek(0) 16 | f.write(b) 17 | 18 | def swap_order(f, size='H'): 19 | f.seek(0) 20 | a = array.array(size, f.read()) 21 | a.byteswap() 22 | f.seek(0) 23 | f.write(a.tobytes()) 24 | 25 | class SubDir: 26 | def __init__(self, d): 27 | self.d = d 28 | def __enter__(self): 29 | self.cwd = os.getcwd() 30 | try: 31 | os.mkdir(self.d) 32 | except FileExistsError: 33 | pass 34 | os.chdir(self.d) 35 | def __exit__(self, type_, value, traceback): 36 | os.chdir(self.cwd) 37 | --------------------------------------------------------------------------------