mirror of
https://github.com/HackerN64/HackerOoT.git
synced 2026-01-21 10:37:37 -08:00
fix issues
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,6 +28,7 @@ docs/doxygen/
|
||||
*.dump
|
||||
out.txt
|
||||
*.ram
|
||||
common-key.bin
|
||||
|
||||
# Tool artifacts
|
||||
tools/mipspro7.2_compiler/
|
||||
|
||||
0
baseroms/gc-eu-mq-dbg/.gitkeep
Normal file
0
baseroms/gc-eu-mq-dbg/.gitkeep
Normal file
@@ -1 +0,0 @@
|
||||
5831385a7f216370cdbea55616b12fed oot-gc-eu-mq-dbg-compressed.z64
|
||||
@@ -1 +0,0 @@
|
||||
f0b7f35375f9cc8ca1b2d59d78e35405 oot-gc-eu-mq-dbg.z64
|
||||
0
baseroms/gc-eu-mq/.gitkeep
Normal file
0
baseroms/gc-eu-mq/.gitkeep
Normal file
@@ -1 +0,0 @@
|
||||
1618403427e4344a57833043db5ce3c3 oot-gc-eu-mq-compressed.z64
|
||||
@@ -1 +0,0 @@
|
||||
1a438f4235f8038856971c14a798122a oot-gc-eu-mq.z64
|
||||
0
baseroms/hacker-mq/.gitkeep
Normal file
0
baseroms/hacker-mq/.gitkeep
Normal file
@@ -10,6 +10,7 @@ from pathlib import Path
|
||||
|
||||
|
||||
EXTRACTED_ASSETS_NAMEFILE = ".extracted-assets.json"
|
||||
VERSION = ""
|
||||
|
||||
|
||||
def SignalHandler(sig, frame):
|
||||
@@ -28,7 +29,7 @@ def ExtractFile(xmlPath, outputPath, outputSourcePath):
|
||||
Path(outputPath).mkdir(parents=True, exist_ok=True)
|
||||
Path(outputSourcePath).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
execStr = f"{zapdPath} e -eh -i {xmlPath} -b baseroms/gc-eu-mq-dbg/segments -o {outputPath} -osf {outputSourcePath} -gsf 1 -rconf {configPath} {ZAPDArgs}"
|
||||
execStr = f"{zapdPath} e -eh -i {xmlPath} -b baseroms/{VERSION}/segments -o {outputPath} -osf {outputSourcePath} -gsf 1 -rconf {configPath} {ZAPDArgs}"
|
||||
|
||||
if "overlays" in xmlPath:
|
||||
execStr += " --static"
|
||||
@@ -100,8 +101,12 @@ def main():
|
||||
parser.add_argument("-j", "--jobs", help="Number of cpu cores to extract with.")
|
||||
parser.add_argument("-u", "--unaccounted", help="Enables ZAPD unaccounted detector warning system.", action="store_true")
|
||||
parser.add_argument("-Z", help="Pass the argument on to ZAPD, e.g. `-ZWunaccounted` to warn about unaccounted blocks in XMLs. Each argument should be passed separately, *without* the leading dash.", metavar="ZAPD_ARG", action="append")
|
||||
parser.add_argument("-v", "--version", help="OoT Version", choices=["gc-eu-mq-dbg", "hacker-mq"])
|
||||
args = parser.parse_args()
|
||||
|
||||
global VERSION
|
||||
VERSION = args.version
|
||||
|
||||
global ZAPDArgs
|
||||
ZAPDArgs = processZAPDArgs(args.Z) if args.Z else ""
|
||||
|
||||
@@ -141,7 +146,7 @@ def main():
|
||||
if extract_text_path is not None or extract_staff_text_path is not None:
|
||||
print("Extracting text")
|
||||
from tools import msgdis
|
||||
msgdis.extract_all_text(extract_text_path, extract_staff_text_path)
|
||||
msgdis.extract_all_text(extract_text_path, extract_staff_text_path, VERSION)
|
||||
|
||||
xmlFiles = []
|
||||
for currentPath, _, files in os.walk(os.path.join("assets", "xml")):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import struct
|
||||
import argparse
|
||||
from multiprocessing import Pool, cpu_count
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1581,6 +1582,20 @@ def ExtractFunc(i):
|
||||
#####################################################################
|
||||
|
||||
def main():
|
||||
description = "Extract data from baserom."
|
||||
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument("version", help="Version of the game to extract.", choices=["gc-eu-mq-dbg", "hacker-mq"])
|
||||
|
||||
args = parser.parse_args()
|
||||
version = args.version
|
||||
|
||||
global ROM_FILE_PATH
|
||||
global SEGMENTS_PATH
|
||||
if version == "hacker-mq":
|
||||
ROM_FILE_PATH = Path(f'baseroms/{version}/baserom-decompressed.z64')
|
||||
SEGMENTS_PATH = Path(f'baseroms/{version}/segments/')
|
||||
|
||||
SEGMENTS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# read baserom data
|
||||
|
||||
@@ -30,7 +30,7 @@ APPLY_OPTS = "--format --style=file"
|
||||
|
||||
# Compiler options used with Clang-Tidy
|
||||
# Normal warnings are disabled with -Wno-everything to focus only on tidying
|
||||
INCLUDES = "-Iinclude -Isrc -Ibuild/gc-eu-mq-dbg -I."
|
||||
INCLUDES = "-Iinclude -Isrc -Ibuild/gc-eu-mq-dbg -Ibuild/hacker-mq -I."
|
||||
DEFINES = "-D_LANGUAGE_C -DNON_MATCHING"
|
||||
COMPILER_OPTS = f"-fno-builtin -std=gnu90 -m32 -Wno-everything {INCLUDES} {DEFINES}"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import mapfile_parser
|
||||
def symInfoMain():
|
||||
parser = argparse.ArgumentParser(description="Display various information about a symbol or address.")
|
||||
parser.add_argument("symname", help="symbol name or VROM/VRAM address to lookup")
|
||||
parser.add_argument("-v", "--oot-version", help="Which version should be processed", default="gc-eu-mq-dbg")
|
||||
parser.add_argument("-v", "--oot-version", help="Which version should be processed", default="hacker-mq")
|
||||
parser.add_argument("-e", "--expected", dest="use_expected", action="store_true", help="use the map file in expected/build/ instead of build/")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CFLAGS := -Wall -Wextra -pedantic -std=c99 -g -O2
|
||||
PROGRAMS := elf2rom makeromfs mkdmadata mkldscript reloc_prereq vtxdis yaz0
|
||||
PROGRAMS := elf2rom makeromfs mkdmadata mkldscript reloc_prereq
|
||||
|
||||
ifeq ($(shell command -v clang >/dev/null 2>&1; echo $$?),0)
|
||||
CC := clang
|
||||
@@ -20,11 +20,20 @@ endif
|
||||
all: $(PROGRAMS)
|
||||
$(MAKE) -C ZAPD
|
||||
$(MAKE) -C fado
|
||||
ifeq ($(wildcard ./gzinject/Makefile),)
|
||||
cd ./gzinject && ./configure
|
||||
endif
|
||||
$(MAKE) -C gzinject
|
||||
$(MAKE) -C z64compress
|
||||
|
||||
clean:
|
||||
$(RM) $(PROGRAMS) $(addsuffix .exe,$(PROGRAMS))
|
||||
$(MAKE) -C ZAPD clean
|
||||
$(MAKE) -C fado clean
|
||||
ifneq ($(wildcard ./gzinject/Makefile),)
|
||||
$(MAKE) -C gzinject clean
|
||||
endif
|
||||
$(MAKE) -C z64compress clean
|
||||
|
||||
distclean: clean
|
||||
|
||||
@@ -35,8 +44,6 @@ makeromfs_SOURCES := makeromfs.c n64chksum.c util.c
|
||||
mkdmadata_SOURCES := mkdmadata.c spec.c util.c
|
||||
mkldscript_SOURCES := mkldscript.c spec.c util.c
|
||||
reloc_prereq_SOURCES := reloc_prereq.c spec.c util.c
|
||||
vtxdis_SOURCES := vtxdis.c
|
||||
yaz0_SOURCES := yaz0tool.c yaz0.c util.c
|
||||
|
||||
|
||||
define COMPILE =
|
||||
|
||||
177
tools/assist.py
177
tools/assist.py
@@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
|
||||
gAddressWidth = 18 # if your ld >= 2.40 change this to 10
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = script_dir + "/../"
|
||||
asm_dir = root_dir + "asm/non_matchings/overlays/actors"
|
||||
build_dir = root_dir + "build/gc-eu-mq-dbg/"
|
||||
|
||||
def read_rom():
|
||||
with open("baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", "rb") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def find_dir(query):
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for d in dirs:
|
||||
if d == query:
|
||||
return os.path.join(root, d)
|
||||
return None
|
||||
|
||||
|
||||
def get_all_s_files():
|
||||
ret = set()
|
||||
for root, dirs, files in os.walk(asm_dir):
|
||||
for f in files:
|
||||
if f.endswith(".s"):
|
||||
ret.add(f[:-2])
|
||||
return ret
|
||||
|
||||
|
||||
def get_symbol_bytes(offsets, func):
|
||||
if func not in offsets or "start" not in offsets[func] or "end" not in offsets[func]:
|
||||
return None
|
||||
start = offsets[func]["start"]
|
||||
end = offsets[func]["end"]
|
||||
return list(rom_bytes[start:end])
|
||||
|
||||
|
||||
def parse_map(fname):
|
||||
ram_offset = None
|
||||
cur_file = "<no file>"
|
||||
syms = {}
|
||||
prev_sym = None
|
||||
prev_line = ""
|
||||
with open(fname) as f:
|
||||
for line in f:
|
||||
if "load address" in line:
|
||||
if "noload" in line or "noload" in prev_line:
|
||||
ram_offset = None
|
||||
continue
|
||||
ram = int(line[16 : 16 + gAddressWidth], 0)
|
||||
rom = int(line[16 + gAddressWidth + 25 : 16 + gAddressWidth + 25 + gAddressWidth], 0)
|
||||
ram_offset = ram - rom
|
||||
continue
|
||||
prev_line = line
|
||||
|
||||
if (
|
||||
ram_offset is None
|
||||
or "=" in line
|
||||
or "*fill*" in line
|
||||
or " 0x" not in line
|
||||
):
|
||||
continue
|
||||
ram = int(line[16 : 16 + gAddressWidth], 0)
|
||||
rom = ram - ram_offset
|
||||
fn = line.split()[-1]
|
||||
if "0x" in fn:
|
||||
ram_offset = None
|
||||
elif "/" in fn:
|
||||
cur_file = fn
|
||||
else:
|
||||
syms[fn] = (rom, cur_file, prev_sym, ram)
|
||||
prev_sym = fn
|
||||
return syms
|
||||
|
||||
|
||||
def get_map_offsets(syms):
|
||||
offsets = {}
|
||||
for sym in syms:
|
||||
prev_sym = syms[sym][2]
|
||||
if sym not in offsets:
|
||||
offsets[sym] = {}
|
||||
if prev_sym not in offsets:
|
||||
offsets[prev_sym] = {}
|
||||
offsets[sym]["start"] = syms[sym][0]
|
||||
offsets[prev_sym]["end"] = syms[sym][0]
|
||||
return offsets
|
||||
|
||||
|
||||
def diff_syms(qb, tb):
|
||||
if len(tb) < 8:
|
||||
return 0
|
||||
|
||||
if len(qb) > len(tb):
|
||||
larger = qb
|
||||
smaller = tb
|
||||
else:
|
||||
larger = tb
|
||||
smaller = qb
|
||||
|
||||
len_ratio = len(smaller) / len(larger)
|
||||
|
||||
n_bytes = len(smaller)
|
||||
matches = 0
|
||||
for i in range(0, n_bytes, 4):
|
||||
if smaller[i] == larger[i]:
|
||||
matches += 4
|
||||
return (matches / n_bytes) * len_ratio
|
||||
|
||||
|
||||
def get_matches(query):
|
||||
query_bytes = get_symbol_bytes(map_offsets, query)
|
||||
if query_bytes is None:
|
||||
sys.exit("Symbol '" + query + "' not found")
|
||||
|
||||
ret = {}
|
||||
for symbol in map_offsets:
|
||||
if symbol is not None and query != symbol:
|
||||
target_bytes = get_symbol_bytes(map_offsets, symbol)
|
||||
if target_bytes is not None:
|
||||
score = diff_syms(query_bytes, target_bytes)
|
||||
if score >= args.threshold:
|
||||
ret[symbol] = score
|
||||
return OrderedDict(sorted(ret.items(), key=lambda kv: kv[1], reverse=True))
|
||||
|
||||
|
||||
def do_query(query):
|
||||
matches = get_matches(query)
|
||||
num_matches = len(matches)
|
||||
|
||||
if num_matches == 0:
|
||||
print(query + " - found no matches")
|
||||
return
|
||||
|
||||
i = 0
|
||||
more_str = ":"
|
||||
if args.num_out < num_matches:
|
||||
more_str = " (showing only " + str(args.num_out) + "):"
|
||||
|
||||
print(query + " - found " + str(num_matches) + " matches total" + more_str)
|
||||
for match in matches:
|
||||
if i == args.num_out:
|
||||
break
|
||||
match_str = "{:.2f} - {}".format(matches[match], match)
|
||||
if match not in s_files:
|
||||
match_str += " (decompiled)"
|
||||
print(match_str)
|
||||
i += 1
|
||||
print()
|
||||
|
||||
parser = argparse.ArgumentParser(description="Tools to assist with decomp")
|
||||
parser.add_argument("query", help="function or file")
|
||||
parser.add_argument("--threshold", help="score threshold between 0 and 1 (higher is more restrictive)", type=float, default=0.95, required=False)
|
||||
parser.add_argument("--num-out", help="number of functions to display", type=int, default=10, required=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
rom_bytes = read_rom()
|
||||
map_syms = parse_map(build_dir + "z64.map")
|
||||
map_offsets = get_map_offsets(map_syms)
|
||||
|
||||
s_files = get_all_s_files()
|
||||
|
||||
query_dir = find_dir(args.query)
|
||||
|
||||
if query_dir is not None:
|
||||
files = os.listdir(query_dir)
|
||||
for f_name in files:
|
||||
do_query(f_name[:-2])
|
||||
else:
|
||||
do_query(args.query)
|
||||
@@ -35,11 +35,13 @@ def decompress(data: bytes, is_zlib_compressed: bool) -> bytes:
|
||||
FILE_TABLE_OFFSET = {
|
||||
"gc-eu-mq": 0x07170,
|
||||
"gc-eu-mq-dbg": 0x12F70,
|
||||
"hacker-mq": 0x12F70,
|
||||
}
|
||||
|
||||
VERSIONS_MD5S = {
|
||||
"gc-eu-mq": "1a438f4235f8038856971c14a798122a",
|
||||
"gc-eu-mq-dbg": "f0b7f35375f9cc8ca1b2d59d78e35405",
|
||||
"hacker-mq": "f0b7f35375f9cc8ca1b2d59d78e35405",
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +155,7 @@ def byte_swap(file_content: bytearray) -> bytearray:
|
||||
|
||||
|
||||
def per_version_fixes(file_content: bytearray, version: str) -> bytearray:
|
||||
if version == "gc-eu-mq-dbg":
|
||||
if version in {"gc-eu-mq-dbg", "hacker-mq"}:
|
||||
# Strip the overdump
|
||||
print("Stripping overdump...")
|
||||
file_content = file_content[0:0x3600000]
|
||||
@@ -256,7 +258,7 @@ def main():
|
||||
f"Error: Expected a hash of {correct_str_hash} but got {str_hash}. The baserom has probably been tampered, find a new one"
|
||||
)
|
||||
|
||||
if version == "gc-eu-mq-dbg":
|
||||
if version in {"gc-eu-mq-dbg", "hacker-mq"}:
|
||||
if str_hash == "32fe2770c0f9b1a9cd2a4d449348c1cb":
|
||||
print(
|
||||
"The provided baserom is a rom which has been edited with ZeldaEdit and is not suitable for use with decomp. Find a new one."
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import struct, sys
|
||||
|
||||
item_ids = {
|
||||
0x00 : "ITEM_DEKU_STICK",
|
||||
0x01 : "ITEM_DEKU_NUT",
|
||||
0x02 : "ITEM_BOMB",
|
||||
0x03 : "ITEM_BOW",
|
||||
0x04 : "ITEM_ARROW_FIRE",
|
||||
0x05 : "ITEM_DINS_FIRE",
|
||||
0x06 : "ITEM_SLINGSHOT",
|
||||
0x07 : "ITEM_OCARINA_FAIRY",
|
||||
0x08 : "ITEM_OCARINA_OF_TIME",
|
||||
0x09 : "ITEM_BOMBCHU",
|
||||
0x0A : "ITEM_HOOKSHOT",
|
||||
0x0B : "ITEM_LONGSHOT",
|
||||
0x0C : "ITEM_ARROW_ICE",
|
||||
0x0D : "ITEM_FARORES_WIND",
|
||||
0x0E : "ITEM_BOOMERANG",
|
||||
0x0F : "ITEM_LENS_OF_TRUTH",
|
||||
0x10 : "ITEM_MAGIC_BEAN",
|
||||
0x11 : "ITEM_HAMMER",
|
||||
0x12 : "ITEM_ARROW_LIGHT",
|
||||
0x13 : "ITEM_NAYRUS_LOVE",
|
||||
0x14 : "ITEM_BOTTLE_EMPTY",
|
||||
0x15 : "ITEM_BOTTLE_POTION_RED",
|
||||
0x16 : "ITEM_BOTTLE_POTION_GREEN",
|
||||
0x17 : "ITEM_BOTTLE_POTION_BLUE",
|
||||
0x18 : "ITEM_BOTTLE_FAIRY",
|
||||
0x19 : "ITEM_BOTTLE_FISH",
|
||||
0x1A : "ITEM_BOTTLE_MILK_FULL",
|
||||
0x1B : "ITEM_BOTTLE_RUTOS_LETTER",
|
||||
0x1C : "ITEM_BOTTLE_BLUE_FIRE",
|
||||
0x1D : "ITEM_BOTTLE_BUG",
|
||||
0x1E : "ITEM_BOTTLE_BIG_POE",
|
||||
0x1F : "ITEM_BOTTLE_MILK_HALF",
|
||||
0x20 : "ITEM_BOTTLE_POE",
|
||||
0x21 : "ITEM_WEIRD_EGG",
|
||||
0x22 : "ITEM_CHICKEN",
|
||||
0x23 : "ITEM_ZELDAS_LETTER",
|
||||
0x24 : "ITEM_MASK_KEATON",
|
||||
0x25 : "ITEM_MASK_SKULL",
|
||||
0x26 : "ITEM_MASK_SPOOKY",
|
||||
0x27 : "ITEM_MASK_BUNNY_HOOD",
|
||||
0x28 : "ITEM_MASK_GORON",
|
||||
0x29 : "ITEM_MASK_ZORA",
|
||||
0x2A : "ITEM_MASK_GERUDO",
|
||||
0x2B : "ITEM_MASK_TRUTH",
|
||||
0x2C : "ITEM_SOLD_OUT",
|
||||
0x2D : "ITEM_POCKET_EGG",
|
||||
0x2E : "ITEM_POCKET_CUCCO",
|
||||
0x2F : "ITEM_COJIRO",
|
||||
0x30 : "ITEM_ODD_MUSHROOM",
|
||||
0x31 : "ITEM_ODD_POTION",
|
||||
0x32 : "ITEM_POACHERS_SAW",
|
||||
0x33 : "ITEM_BROKEN_GORONS_SWORD",
|
||||
0x34 : "ITEM_PRESCRIPTION",
|
||||
0x35 : "ITEM_EYEBALL_FROG",
|
||||
0x36 : "ITEM_EYE_DROPS",
|
||||
0x37 : "ITEM_CLAIM_CHECK",
|
||||
0x38 : "ITEM_BOW_FIRE",
|
||||
0x39 : "ITEM_BOW_ICE",
|
||||
0x3A : "ITEM_BOW_LIGHT",
|
||||
0x3B : "ITEM_SWORD_KOKIRI",
|
||||
0x3C : "ITEM_SWORD_MASTER",
|
||||
0x3D : "ITEM_SWORD_BIGGORON",
|
||||
0x3E : "ITEM_SHIELD_DEKU",
|
||||
0x3F : "ITEM_SHIELD_HYLIAN",
|
||||
0x40 : "ITEM_SHIELD_MIRROR",
|
||||
0x41 : "ITEM_TUNIC_KOKIRI",
|
||||
0x42 : "ITEM_TUNIC_GORON",
|
||||
0x43 : "ITEM_TUNIC_ZORA",
|
||||
0x44 : "ITEM_BOOTS_KOKIRI",
|
||||
0x45 : "ITEM_BOOTS_IRON",
|
||||
0x46 : "ITEM_BOOTS_HOVER",
|
||||
0x47 : "ITEM_BULLET_BAG_30",
|
||||
0x48 : "ITEM_BULLET_BAG_40",
|
||||
0x49 : "ITEM_BULLET_BAG_50",
|
||||
0x4A : "ITEM_QUIVER_30",
|
||||
0x4B : "ITEM_QUIVER_40",
|
||||
0x4C : "ITEM_QUIVER_50",
|
||||
0x4D : "ITEM_BOMB_BAG_20",
|
||||
0x4E : "ITEM_BOMB_BAG_30",
|
||||
0x4F : "ITEM_BOMB_BAG_40",
|
||||
0x50 : "ITEM_STRENGTH_GORONS_BRACELET",
|
||||
0x51 : "ITEM_STRENGTH_SILVER_GAUNTLETS",
|
||||
0x52 : "ITEM_STRENGTH_GOLD_GAUNTLETS",
|
||||
0x53 : "ITEM_SCALE_SILVER",
|
||||
0x54 : "ITEM_SCALE_GOLDEN",
|
||||
0x55 : "ITEM_GIANTS_KNIFE",
|
||||
0x56 : "ITEM_ADULTS_WALLET",
|
||||
0x57 : "ITEM_GIANTS_WALLET",
|
||||
0x58 : "ITEM_DEKU_SEEDS",
|
||||
0x59 : "ITEM_FISHING_POLE",
|
||||
0x5A : "ITEM_SONG_MINUET",
|
||||
0x5B : "ITEM_SONG_BOLERO",
|
||||
0x5C : "ITEM_SONG_SERENADE",
|
||||
0x5D : "ITEM_SONG_REQUIEM",
|
||||
0x5E : "ITEM_SONG_NOCTURNE",
|
||||
0x5F : "ITEM_SONG_PRELUDE",
|
||||
0x60 : "ITEM_SONG_LULLABY",
|
||||
0x61 : "ITEM_SONG_EPONA",
|
||||
0x62 : "ITEM_SONG_SARIA",
|
||||
0x63 : "ITEM_SONG_SUN",
|
||||
0x64 : "ITEM_SONG_TIME",
|
||||
0x65 : "ITEM_SONG_STORMS",
|
||||
0x66 : "ITEM_MEDALLION_FOREST",
|
||||
0x67 : "ITEM_MEDALLION_FIRE",
|
||||
0x68 : "ITEM_MEDALLION_WATER",
|
||||
0x69 : "ITEM_MEDALLION_SPIRIT",
|
||||
0x6A : "ITEM_MEDALLION_SHADOW",
|
||||
0x6B : "ITEM_MEDALLION_LIGHT",
|
||||
0x6C : "ITEM_KOKIRI_EMERALD",
|
||||
0x6D : "ITEM_GORON_RUBY",
|
||||
0x6E : "ITEM_ZORA_SAPPHIRE",
|
||||
0x6F : "ITEM_STONE_OF_AGONY",
|
||||
0x70 : "ITEM_GERUDOS_CARD",
|
||||
0x71 : "ITEM_SKULL_TOKEN",
|
||||
0x72 : "ITEM_HEART_CONTAINER",
|
||||
0x73 : "ITEM_HEART_PIECE",
|
||||
0x74 : "ITEM_DUNGEON_BOSS_KEY",
|
||||
0x75 : "ITEM_DUNGEON_COMPASS",
|
||||
0x76 : "ITEM_DUNGEON_MAP",
|
||||
0x77 : "ITEM_SMALL_KEY",
|
||||
0x78 : "ITEM_MAGIC_JAR_SMALL",
|
||||
0x79 : "ITEM_MAGIC_JAR_BIG",
|
||||
0x7A : "ITEM_HEART_PIECE_2",
|
||||
0x7B : "ITEM_INVALID_1",
|
||||
0x7C : "ITEM_INVALID_2",
|
||||
0x7D : "ITEM_INVALID_3",
|
||||
0x7E : "ITEM_INVALID_4",
|
||||
0x7F : "ITEM_INVALID_5",
|
||||
0x80 : "ITEM_INVALID_6",
|
||||
0x81 : "ITEM_INVALID_7",
|
||||
0x82 : "ITEM_MILK",
|
||||
0x83 : "ITEM_RECOVERY_HEART",
|
||||
0x84 : "ITEM_RUPEE_GREEN",
|
||||
0x85 : "ITEM_RUPEE_BLUE",
|
||||
0x86 : "ITEM_RUPEE_RED",
|
||||
0x87 : "ITEM_RUPEE_PURPLE",
|
||||
0x88 : "ITEM_RUPEE_GOLD",
|
||||
0x89 : "ITEM_INVALID_8",
|
||||
0x8A : "ITEM_DEKU_STICKS_5",
|
||||
0x8B : "ITEM_DEKU_STICKS_10",
|
||||
0x8C : "ITEM_DEKU_NUTS_5",
|
||||
0x8D : "ITEM_DEKU_NUTS_10",
|
||||
0x8E : "ITEM_BOMBS_5",
|
||||
0x8F : "ITEM_BOMBS_10",
|
||||
0x90 : "ITEM_BOMBS_20",
|
||||
0x91 : "ITEM_BOMBS_30",
|
||||
0x92 : "ITEM_ARROWS_5",
|
||||
0x93 : "ITEM_ARROWS_10",
|
||||
0x94 : "ITEM_ARROWS_30",
|
||||
0x95 : "ITEM_DEKU_SEEDS_30",
|
||||
0x96 : "ITEM_BOMBCHUS_5",
|
||||
0x97 : "ITEM_BOMBCHUS_20",
|
||||
0x98 : "ITEM_DEKU_STICK_UPGRADE_20",
|
||||
0x99 : "ITEM_DEKU_STICK_UPGRADE_30",
|
||||
0x9A : "ITEM_DEKU_NUT_UPGRADE_30",
|
||||
0x9B : "ITEM_DEKU_NUT_UPGRADE_40",
|
||||
0xFC : "ITEM_SWORD_CS",
|
||||
0xFE : "ITEM_NONE_FE",
|
||||
0xFF : "ITEM_NONE",
|
||||
}
|
||||
|
||||
def disas_elfmsgs(start):
|
||||
baserom = None
|
||||
with open("baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", "rb") as infile:
|
||||
baserom = bytearray(infile.read())
|
||||
|
||||
branches = []
|
||||
pos = start
|
||||
|
||||
while (True):
|
||||
print(f"/* {pos - start:04X} {((pos - start) // 4):3} */ ", end="")
|
||||
|
||||
b0, b1, b2, b3 = struct.unpack(">BBBB", baserom[pos:pos+4])
|
||||
|
||||
elf_message_types = {
|
||||
0x00: "CHECK",
|
||||
0x20: "UNK_1",
|
||||
0x40: "UNK_2",
|
||||
0x60: "SKIP",
|
||||
0xE0: "END",
|
||||
}
|
||||
|
||||
cont = True
|
||||
branch_to = None
|
||||
|
||||
# Get Type
|
||||
|
||||
elf_message_type = b0 & 0xE0
|
||||
ARG_0 = elf_message_types[elf_message_type]
|
||||
|
||||
if elf_message_type in [0, 0x20, 0x40, 0xE0]:
|
||||
if elf_message_type == 0xE0:
|
||||
cont = False
|
||||
ARG_1 = f"0x{(b2 & 0xFF):04X}"
|
||||
elif elf_message_type == 0x60:
|
||||
branch_to = 4 * (b2 & 0xFF)
|
||||
ARG_1 = (b2 & 0xFF)
|
||||
else:
|
||||
assert False , "Encountered unknown type"
|
||||
|
||||
ARG_2 = f"{bool(b0 & 1)}".lower()
|
||||
|
||||
# Get condition
|
||||
condition_type = b0 & 0x1E
|
||||
|
||||
if condition_type == 0:
|
||||
if elf_message_type == 0xE0 and b1 == 0 and not (b0 & 1):
|
||||
print(f"QUEST_HINT_END({ARG_1}),")
|
||||
else:
|
||||
print(f"QUEST_HINT_FLAG({ARG_0}, {ARG_1}, {ARG_2}, 0x{b1:02X}), /* eventChkInf[{(b1 >> 4) & 0xF}] & 0x{1 << (b1 & 0xF):X} */")
|
||||
assert b3 == 0
|
||||
elif condition_type == 2:
|
||||
print(f"QUEST_HINT_DUNGEON_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}),")
|
||||
assert b3 == 0
|
||||
elif condition_type == 4:
|
||||
print(f"QUEST_HINT_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}, {item_ids[b3]}),")
|
||||
elif condition_type == 6:
|
||||
condition_other_type = b1 & 0xF0
|
||||
|
||||
if condition_other_type == 0:
|
||||
print(f"QUEST_HINT_STRENGTH_UPG({ARG_0}, {ARG_1}, {ARG_2}, {b1 & 0xF}),")
|
||||
assert b3 == 0
|
||||
elif condition_other_type == 0x10:
|
||||
print(f"QUEST_HINT_BOOTS({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
|
||||
assert (b1 & 0xF) == 0
|
||||
elif condition_other_type == 0x20:
|
||||
print(f"QUEST_HINT_SONG({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
|
||||
assert (b1 & 0xF) == 0
|
||||
elif condition_other_type == 0x30:
|
||||
print(f"QUEST_HINT_MEDALLION({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
|
||||
assert (b1 & 0xF) == 0
|
||||
elif condition_other_type == 0x40:
|
||||
print(f"QUEST_HINT_MAGIC({ARG_0}, {ARG_1}, {ARG_2}),")
|
||||
assert (b1 & 0xF) == 0
|
||||
assert b3 == 0
|
||||
else:
|
||||
assert False , "Encountered unknown condition (other) type"
|
||||
else:
|
||||
assert False , "Encountered unknown condition type"
|
||||
|
||||
# Control flow
|
||||
|
||||
if branch_to is not None:
|
||||
branches.append(branch_to)
|
||||
pos += 4
|
||||
if not cont:
|
||||
print("")
|
||||
if not cont and all([dst < pos - start for dst in branches]):
|
||||
break
|
||||
|
||||
disas_elfmsgs(int(sys.argv[1],16))
|
||||
@@ -1,12 +0,0 @@
|
||||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/krimtonz/gzinject.git
|
||||
branch = master
|
||||
commit = ee44efce5d842e5d4488ee47c16da8b673da5086
|
||||
parent = 53941daac4bb1482a9125f3595642df1bafb5f6d
|
||||
method = merge
|
||||
cmdver = 0.4.5
|
||||
0
tools/gzinject/configure
vendored
Normal file → Executable file
0
tools/gzinject/configure
vendored
Normal file → Executable file
0
tools/gzinject/install-sh
Normal file → Executable file
0
tools/gzinject/install-sh
Normal file → Executable file
@@ -6,6 +6,8 @@
|
||||
import re, struct
|
||||
from os import path
|
||||
|
||||
VERSION = ""
|
||||
|
||||
# ===================================================
|
||||
# Util
|
||||
# ===================================================
|
||||
@@ -280,9 +282,10 @@ def read_tables():
|
||||
|
||||
global combined_message_entry_table
|
||||
global staff_message_entry_table
|
||||
global VERSION
|
||||
|
||||
baserom = None
|
||||
with open("baseroms/gc-eu-mq-dbg/baserom-decompressed.z64","rb") as infile:
|
||||
with open(f"baseroms/{VERSION}/baserom-decompressed.z64","rb") as infile:
|
||||
baserom = infile.read()
|
||||
|
||||
nes_message_entry_table = as_message_table_entry(baserom[nes_message_entry_table_addr:ger_message_entry_table_addr])
|
||||
@@ -313,6 +316,7 @@ def fixup_message(message):
|
||||
###
|
||||
|
||||
def dump_all_text():
|
||||
global VERSION
|
||||
# text id, ypos, type, nes, ger, fra
|
||||
messages = []
|
||||
for i,entry in enumerate(combined_message_entry_table,0):
|
||||
@@ -326,7 +330,7 @@ def dump_all_text():
|
||||
nes_offset = segmented_to_physical(entry[3])
|
||||
nes_length = next_entry[3] - entry[3]
|
||||
nes_text = ""
|
||||
with open("baseroms/gc-eu-mq-dbg/segments/nes_message_data_static","rb") as infile:
|
||||
with open(f"baseroms/{VERSION}/segments/nes_message_data_static","rb") as infile:
|
||||
infile.seek(nes_offset)
|
||||
nes_text = fixup_message(decode(infile.read(nes_length), entry[1]).replace("\x00","",-1))
|
||||
|
||||
@@ -337,13 +341,13 @@ def dump_all_text():
|
||||
next_entry = combined_message_entry_table[i+2]
|
||||
ger_offset = segmented_to_physical(entry[4])
|
||||
ger_length = next_entry[4] - entry[4]
|
||||
with open("baseroms/gc-eu-mq-dbg/segments/ger_message_data_static","rb") as infile:
|
||||
with open(f"baseroms/{VERSION}/segments/ger_message_data_static","rb") as infile:
|
||||
infile.seek(ger_offset)
|
||||
ger_text = fixup_message(decode(infile.read(ger_length), entry[1]).replace("\x00","",-1))
|
||||
|
||||
fra_offset = segmented_to_physical(entry[5])
|
||||
fra_length = next_entry[5] - entry[5]
|
||||
with open("baseroms/gc-eu-mq-dbg/segments/fra_message_data_static","rb") as infile:
|
||||
with open(f"baseroms/{VERSION}/segments/fra_message_data_static","rb") as infile:
|
||||
infile.seek(fra_offset)
|
||||
fra_text = fixup_message(decode(infile.read(fra_length), entry[1]).replace("\x00","",-1))
|
||||
|
||||
@@ -352,7 +356,8 @@ def dump_all_text():
|
||||
return messages
|
||||
|
||||
def dump_staff_text():
|
||||
staff_message_data_static_size = path.getsize("baseroms/gc-eu-mq-dbg/segments/staff_message_data_static")
|
||||
global VERSION
|
||||
staff_message_data_static_size = path.getsize(f"baseroms/{VERSION}/segments/staff_message_data_static")
|
||||
# text id, ypos, type, staff
|
||||
messages = []
|
||||
for i,entry in enumerate(staff_message_entry_table,0):
|
||||
@@ -361,14 +366,18 @@ def dump_staff_text():
|
||||
staff_offset = segmented_to_physical(entry[3])
|
||||
# hacky way to ensure the staff message entry table is read all the way to the end
|
||||
staff_length = (staff_message_data_static_size if entry[0] == 0x052F else segmented_to_physical(next_entry[3])) - segmented_to_physical(entry[3])
|
||||
with open("baseroms/gc-eu-mq-dbg/segments/staff_message_data_static","rb") as infile:
|
||||
with open(f"baseroms/{VERSION}/segments/staff_message_data_static","rb") as infile:
|
||||
infile.seek(staff_offset)
|
||||
messages.append((entry[0], entry[1], entry[2], fixup_message(decode(infile.read(staff_length), entry[1]).replace("\x00","",-1))))
|
||||
else:
|
||||
messages.append((entry[0], entry[1], entry[2], "///END///"))
|
||||
return messages
|
||||
|
||||
def extract_all_text(text_out, staff_text_out):
|
||||
def extract_all_text(text_out, staff_text_out, version: str):
|
||||
global VERSION
|
||||
if len(VERSION) == 0:
|
||||
VERSION = version
|
||||
|
||||
if text_out is not None or staff_text_out is not None:
|
||||
read_tables()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user