1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-07-03 22:44:30 +00:00

Merge branch 'main' into doc_pause_menu

This commit is contained in:
Dragorn421 2024-01-27 22:47:15 +01:00
commit 20c7fdeda6
No known key found for this signature in database
GPG key ID: 381AEBAF3D429335
81 changed files with 2616 additions and 454 deletions

3
.gitignore vendored
View file

@ -10,12 +10,14 @@ __pycache__/
CMakeLists.txt
cmake-build-debug
venv/
.venv/
# Project-specific ignores
build/
expected/
notes/
baserom/
baseroms/*/segments/
docs/doxygen/
*.elf
*.sra
@ -25,6 +27,7 @@ docs/doxygen/
*.map
*.dump
out.txt
*.ram
# Tool artifacts
tools/mipspro7.2_compiler/

4
Jenkinsfile vendored
View file

@ -6,7 +6,7 @@ pipeline {
stages {
stage('Setup') {
steps {
sh 'cp /usr/local/etc/roms/baserom_oot.z64 baserom_original.z64'
sh 'cp /usr/local/etc/roms/baserom_oot.z64 baseroms/gc-eu-mq-dbg/baserom.z64'
sh 'make -j setup'
}
}
@ -15,7 +15,7 @@ pipeline {
branch 'main'
}
steps {
sh 'ORIG_COMPILER=1 make -j'
sh 'make -j ORIG_COMPILER=1'
}
}
stage('Build') {

View file

@ -17,6 +17,8 @@ COMPILER := ido
# Target game version. Currently only the following version is supported:
# gc-eu-mq-dbg GameCube Europe/PAL Master Quest Debug (default)
VERSION := gc-eu-mq-dbg
# Number of threads to extract and compress with
N_THREADS := $(shell nproc)
CFLAGS ?=
CPPFLAGS ?=
@ -53,6 +55,7 @@ endif
PROJECT_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
BUILD_DIR := build/$(VERSION)
VENV := .venv
MAKE = make
CFLAGS += -DOOT_DEBUG
@ -72,8 +75,6 @@ else
endif
endif
N_THREADS := $(shell nproc)
#### Tools ####
ifneq ($(shell type $(MIPS_BINUTILS_PREFIX)ld >/dev/null 2>/dev/null; echo $$?), 0)
$(error Unable to find $(MIPS_BINUTILS_PREFIX)ld. Please install or build MIPS binutils, commonly mips-linux-gnu. (or set MIPS_BINUTILS_PREFIX if your MIPS binutils install uses another prefix))
@ -105,6 +106,7 @@ AS := $(MIPS_BINUTILS_PREFIX)as
LD := $(MIPS_BINUTILS_PREFIX)ld
OBJCOPY := $(MIPS_BINUTILS_PREFIX)objcopy
OBJDUMP := $(MIPS_BINUTILS_PREFIX)objdump
NM := $(MIPS_BINUTILS_PREFIX)nm
N64_EMULATOR ?=
@ -119,6 +121,7 @@ MKDMADATA := tools/mkdmadata
ELF2ROM := tools/elf2rom
ZAPD := tools/ZAPD/ZAPD.out
FADO := tools/fado/fado.elf
PYTHON ?= $(VENV)/bin/python3
# Command to replace path variables in the spec file. We can't use the C
# preprocessor for this because it won't substitute inside string literals.
@ -161,6 +164,7 @@ OBJDUMP_FLAGS := -d -r -z -Mreg-names=32
#### Files ####
# ROM image
ROMC := oot-$(VERSION)-compressed.z64
ROM := oot-$(VERSION).z64
ELF := $(ROM:.z64=.elf)
# description of ROM segments
@ -184,9 +188,10 @@ UNDECOMPILED_DATA_DIRS := $(shell find data -type d)
# source files
C_FILES := $(filter-out %.inc.c,$(foreach dir,$(SRC_DIRS) $(ASSET_BIN_DIRS),$(wildcard $(dir)/*.c)))
S_FILES := $(foreach dir,$(SRC_DIRS) $(UNDECOMPILED_DATA_DIRS),$(wildcard $(dir)/*.s))
BASEROM_BIN_FILES := $(wildcard baseroms/$(VERSION)/segments/*)
O_FILES := $(foreach f,$(S_FILES:.s=.o),$(BUILD_DIR)/$f) \
$(foreach f,$(C_FILES:.c=.o),$(BUILD_DIR)/$f) \
$(foreach f,$(wildcard baserom/*),$(BUILD_DIR)/$f.o)
$(foreach f,$(BASEROM_BIN_FILES),$(BUILD_DIR)/baserom/$(notdir $f).o)
OVL_RELOC_FILES := $(shell $(CPP) $(CPPFLAGS) $(SPEC) | $(SPEC_REPLACE_VARS) | grep -o '[^"]*_reloc.o' )
@ -246,11 +251,11 @@ $(BUILD_DIR)/src/libultra/rmon/%.o: CC := $(CC_OLD)
$(BUILD_DIR)/src/code/jpegutils.o: CC := $(CC_OLD)
$(BUILD_DIR)/src/code/jpegdecoder.o: CC := $(CC_OLD)
$(BUILD_DIR)/src/boot/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/src/code/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/src/overlays/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/src/boot/%.o: CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/src/code/%.o: CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/src/overlays/%.o: CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/assets/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
$(BUILD_DIR)/assets/%.o: CC := $(PYTHON) tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) --
else
$(BUILD_DIR)/src/libultra/libc/ll.o: OPTFLAGS := -Ofast
$(BUILD_DIR)/src/%.o: CC := $(CC) -fexec-charset=euc-jp
@ -258,14 +263,22 @@ endif
#### Main Targets ###
all: $(ROM)
ifeq ($(COMPARE),1)
all: rom compress
rom: $(ROM)
ifneq ($(COMPARE),0)
@md5sum $(ROM)
@md5sum -c checksum.md5
@md5sum -c baseroms/$(VERSION)/checksum.md5
endif
compress: $(ROMC)
ifneq ($(COMPARE),0)
@md5sum $(ROMC)
@md5sum -c baseroms/$(VERSION)/checksum-compressed.md5
endif
clean:
$(RM) -r $(ROM) $(ELF) $(BUILD_DIR)
$(RM) -r $(ROMC) $(ROM) $(ELF) $(BUILD_DIR)
assetclean:
$(RM) -r $(ASSET_BIN_DIRS)
@ -274,14 +287,19 @@ assetclean:
$(RM) -r .extracted-assets.json
distclean: clean assetclean
$(RM) -r baserom/
$(RM) -r baseroms/$(VERSION)/segments
$(MAKE) -C tools distclean
setup:
venv:
test -d $(VENV) || python3 -m venv $(VENV)
$(PYTHON) -m pip install -U pip
$(PYTHON) -m pip install -U -r requirements.txt
setup: venv
$(MAKE) -C tools
python3 fixbaserom.py
python3 extract_baserom.py
python3 extract_assets.py -j$(N_THREADS)
$(PYTHON) tools/decompress_baserom.py $(VERSION)
$(PYTHON) extract_baserom.py
$(PYTHON) extract_assets.py -j$(N_THREADS)
run: $(ROM)
ifeq ($(N64_EMULATOR),)
@ -290,13 +308,19 @@ endif
$(N64_EMULATOR) $<
.PHONY: all clean setup run distclean assetclean
.PHONY: all rom compress clean assetclean distclean venv setup run
.DEFAULT_GOAL := rom
#### Various Recipes ####
$(ROM): $(ELF)
$(ELF2ROM) -cic 6105 $< $@
$(ROMC): $(ROM) $(ELF) $(BUILD_DIR)/compress_ranges.txt
# note: $(BUILD_DIR)/compress_ranges.txt should only be used for nonmatching builds. it works by chance for matching builds too though
$(PYTHON) tools/compress.py --in $(ROM) --out $@ --dma-range `./tools/dmadata_range.sh $(NM) $(ELF)` --compress `cat $(BUILD_DIR)/compress_ranges.txt` --threads $(N_THREADS)
$(PYTHON) -m ipl3checksum sum --cic 6105 --update $@
$(ELF): $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) $(OVL_RELOC_FILES) $(BUILD_DIR)/ldscript.txt $(BUILD_DIR)/undefined_syms.txt
$(LD) -T $(BUILD_DIR)/undefined_syms.txt -T $(BUILD_DIR)/ldscript.txt --no-check-sections --accept-unknown-input-arch --emit-relocs -Map $(BUILD_DIR)/z64.map -o $@
@ -321,14 +345,14 @@ $(BUILD_DIR)/ldscript.txt: $(BUILD_DIR)/$(SPEC)
$(BUILD_DIR)/undefined_syms.txt: undefined_syms.txt
$(CPP) $(CPPFLAGS) $< > $@
$(BUILD_DIR)/baserom/%.o: baserom/%
$(BUILD_DIR)/baserom/%.o: baseroms/$(VERSION)/segments/%
$(OBJCOPY) -I binary -O elf32-big $< $@
$(BUILD_DIR)/data/%.o: data/%.s
$(AS) $(ASFLAGS) $< -o $@
$(BUILD_DIR)/assets/text/%.enc.h: assets/text/%.h assets/text/charmap.txt
python3 tools/msgenc.py assets/text/charmap.txt $< $@
$(PYTHON) tools/msgenc.py assets/text/charmap.txt $< $@
# Dependencies for files including message data headers
# TODO remove when full header dependencies are used.
@ -345,8 +369,8 @@ $(BUILD_DIR)/assets/%.o: assets/%.c
$(BUILD_DIR)/src/%.o: src/%.s
$(CPP) $(CPPFLAGS) -Iinclude $< | $(AS) $(ASFLAGS) -o $@
$(BUILD_DIR)/dmadata_table_spec.h: $(BUILD_DIR)/$(SPEC)
$(MKDMADATA) $< $@
$(BUILD_DIR)/dmadata_table_spec.h $(BUILD_DIR)/compress_ranges.txt: $(BUILD_DIR)/$(SPEC)
$(MKDMADATA) $< $(BUILD_DIR)/dmadata_table_spec.h $(BUILD_DIR)/compress_ranges.txt
# Dependencies for files that may include the dmadata header automatically generated from the spec file
$(BUILD_DIR)/src/boot/z_std_dma.o: $(BUILD_DIR)/dmadata_table_spec.h
@ -370,13 +394,13 @@ $(BUILD_DIR)/src/%.o: src/%.c
$(BUILD_DIR)/src/libultra/libc/ll.o: src/libultra/libc/ll.c
$(CC_CHECK) $<
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
python3 tools/set_o32abi_bit.py $@
$(PYTHON) tools/set_o32abi_bit.py $@
@$(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.s)
$(BUILD_DIR)/src/libultra/libc/llcvt.o: src/libultra/libc/llcvt.c
$(CC_CHECK) $<
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
python3 tools/set_o32abi_bit.py $@
$(PYTHON) tools/set_o32abi_bit.py $@
@$(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.s)
$(BUILD_DIR)/src/overlays/%_reloc.o: $(BUILD_DIR)/$(SPEC)
@ -393,3 +417,6 @@ $(BUILD_DIR)/assets/%.jpg.inc.c: assets/%.jpg
$(ZAPD) bren -eh -i $< -o $@
-include $(DEP_FILES)
# Print target for debugging
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true

View file

@ -68,13 +68,15 @@ The build process has the following package requirements:
* build-essential
* binutils-mips-linux-gnu
* python3
* python3-pip
* python3-venv
* libpng-dev
Under Debian / Ubuntu (which we recommend using), you can install them with the following commands:
```bash
sudo apt-get update
sudo apt-get install git build-essential binutils-mips-linux-gnu python3 libpng-dev
sudo apt-get install git build-essential binutils-mips-linux-gnu python3 python3-pip python3-venv libpng-dev
```
If you are using GCC as the compiler for Ocarina of Time, you will also need:
@ -100,8 +102,9 @@ cd oot
#### 3. Prepare a base ROM
Copy over your copy of the Master Quest (Debug) ROM inside the root of this new project directory.
Rename the file to "baserom_original.z64", "baserom_original.n64" or "baserom_original.v64", depending on the original extension.
Place a copy of the Master Quest (Debug) ROM inside the `baseroms/gc-eu-mq-dbg/` folder.
Rename the file to `baserom.z64`, `baserom.n64` or `baserom.v64`, depending on the original extension.
#### 4. Setup the ROM and build process
@ -111,7 +114,8 @@ Setup and extract everything from your ROM with the following command:
make setup
```
This will generate a new ROM called "baserom.z64" that will have the overdump removed and the header patched.
This downloads some dependencies (from pip), and compiles tools for the build process.
Then it generates a new ROM "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64" that will have the overdump removed and the header patched.
It will also extract the individual assets from the ROM.
#### 5. Build the ROM
@ -145,7 +149,6 @@ This means that the built ROM isn't the same as the base one, so something went
Both of these have the disadvantage that the ordering of the terminal output is scrambled, so for debugging it is best to stick to one thread (i.e. not pass `-j` or `-jN`).
## Contributing
All contributions are welcome. This is a group effort, and even small contributions can make a difference.

View file

@ -0,0 +1 @@
5831385a7f216370cdbea55616b12fed oot-gc-eu-mq-dbg-compressed.z64

View file

@ -10,13 +10,13 @@
.balign 16
glabel gSoundFontTable
.incbin "baserom.z64", 0xBCC270, 0x270
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCC270, 0x270
glabel gSequenceFontTable
.incbin "baserom.z64", 0xBCC4E0, 0x1C0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCC4E0, 0x1C0
glabel gSequenceTable
.incbin "baserom.z64", 0xBCC6A0, 0x6F0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCC6A0, 0x6F0
glabel gSampleBankTable
.incbin "baserom.z64", 0xBCCD90, 0x80
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCCD90, 0x80

View file

@ -10,21 +10,21 @@
.balign 16
glabel aspMainDataStart
.incbin "baserom.z64", 0xBCCE10, 0x2E0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCCE10, 0x2E0
glabel aspMainDataEnd
glabel gspF3DZEX2_NoN_PosLight_fifoTextStart
.incbin "baserom.z64", 0xBCD0F0, 0x1630
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCD0F0, 0x1630
glabel gspF3DZEX2_NoN_PosLight_fifoTextEnd
glabel gspF3DZEX2_NoN_PosLight_fifoDataStart
.incbin "baserom.z64", 0xBCE720, 0x420
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCE720, 0x420
glabel gspF3DZEX2_NoN_PosLight_fifoDataEnd
glabel gspS2DEX2d_fifoDataStart
.incbin "baserom.z64", 0xBCEB40, 0x390
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCEB40, 0x390
glabel gspS2DEX2d_fifoDataEnd
glabel njpgdspMainDataStart
.incbin "baserom.z64", 0xBCEED0, 0x60
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBCEED0, 0x60
glabel njpgdspMainDataEnd

View file

@ -10,13 +10,13 @@
.balign 16
glabel aspMainTextStart
.incbin "baserom.z64", 0xB89260, 0xFB0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xB89260, 0xFB0
glabel aspMainTextEnd
glabel gspS2DEX2d_fifoTextStart
.incbin "baserom.z64", 0xB8A210, 0x18C0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xB8A210, 0x18C0
glabel gspS2DEX2d_fifoTextEnd
glabel njpgdspMainTextStart
.incbin "baserom.z64", 0xB8BAD0, 0xAF0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xB8BAD0, 0xAF0
glabel njpgdspMainTextEnd

View file

@ -10,5 +10,5 @@
.balign 16
glabel rspbootTextStart
.incbin "baserom.z64", 0x9F20, 0xD0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0x9F20, 0xD0
glabel rspbootTextEnd

View file

@ -12,7 +12,7 @@
# temporary file name, rename to something more appropriate when decompiled
glabel gMojiFontTLUTs
.incbin "baserom.z64", 0xBA18E0, 0x80
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBA18E0, 0x80
glabel gMojiFontTex
.incbin "baserom.z64", 0xBA1960, 0x400
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0xBA1960, 0x400

View file

@ -1,6 +1,6 @@
def apply(config, args):
config['mapfile'] = 'build/gc-eu-mq-dbg/z64.map'
config['myimg'] = 'oot-gc-eu-mq-dbg.z64'
config['baseimg'] = 'baserom.z64'
config['baseimg'] = 'baseroms/gc-eu-mq-dbg/baserom-decompressed.z64'
config['makeflags'] = []
config['source_directories'] = ['src', 'include', 'spec']

View file

@ -229,7 +229,7 @@ which initialises common properties of actor using an InitChain, which is usuall
The InitChain script is also in the tools directory, and is called `ichaindis.py`. Simply passing it the ROM address will spit out the entire contents of the InitChain, in this case:
```
$ ./tools/ichaindis.py baserom.z64 80A88CE0
$ ./tools/ichaindis.py baseroms/gc-eu-mq-dbg/baserom-decompressed.z64 80A88CE0
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(unk_50, 87, ICHAIN_CONTINUE),
ICHAIN_F32(unk_F4, 4000, ICHAIN_CONTINUE),
@ -240,7 +240,7 @@ static InitChainEntry sInitChain[] = {
However, some of these variables have now been given names in the Actor struct. Pass it `--names` to fill these in automatically:
```
$ ./tools/ichaindis.py --names baserom.z64 80A88CE0
$ ./tools/ichaindis.py --names baseroms/gc-eu-mq-dbg/baserom-decompressed.z64 80A88CE0
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 87, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE),

View file

@ -557,7 +557,7 @@ Ignore the first line: `gDmaDataTable` is always different if the ROM is shifted
To fix this, we use a binary diff program. A suitable one is `vbindiff`: run it on the baserom and the zelda_whatever one the compiler generates:
```
vbindiff baserom.z64 oot-gc-eu-mq-dbg.z64
vbindiff baseroms/gc-eu-mq-dbg/baserom-decompressed.z64 oot-gc-eu-mq-dbg.z64
```
In this, press `g` to open up goto position, and paste in the address `0xE3ED10` from the first important line of the `first_diff` output. This gives us the following:

View file

@ -2,6 +2,27 @@
This list gives brief information on the most common usage cases. For more information, first try using `-h` or `--help` as an argument, and failing that, ask in #oot-decomp-help or #tools-other in the Discord.
Many tools require activating a Python virtual environment that contains Python
dependencies. This virtual environment is automatically installed into the
`.venv` directory by `make setup`, but you need to **activate** it in your
current terminal session in order to run Python tools. To start using the
virtual environment in your current terminal run:
```bash
source .venv/bin/activate
```
Keep in mind that for each new terminal session, you will need to activate the
Python virtual environment again. That is, run the above `source .venv/bin/activate` command.
To deactivate the virtual environment, run
```bash
deactivate
```
and your terminal session state will be restored to what it was before.
## m2ctx
This generates the context for mips2c to use to type objects in its output. It lives in the tools directory. Running

View file

@ -74,7 +74,7 @@ Add the following to (or create) the `.vscode/settings.json` file for VSCode to
"search.useIgnoreFiles": false,
"search.exclude": {
"**/.git": true,
"baserom/**": true,
"baseroms/**": true,
"build/**": true,
"expected/**": true,
},

View file

@ -28,7 +28,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 baserom -o {outputPath} -osf {outputSourcePath} -gsf 1 -rconf {configPath} {ZAPDArgs}"
execStr = f"{zapdPath} e -eh -i {xmlPath} -b baseroms/gc-eu-mq-dbg/segments -o {outputPath} -osf {outputSourcePath} -gsf 1 -rconf {configPath} {ZAPDArgs}"
if "overlays" in xmlPath:
execStr += " --static"

View file

@ -1,12 +1,12 @@
#!/usr/bin/python3
import os
import sys
import struct
from multiprocessing import Pool, cpu_count
from pathlib import Path
ROM_FILE_NAME = 'baserom.z64'
ROM_FILE_PATH = Path('baseroms/gc-eu-mq-dbg/baserom-decompressed.z64')
SEGMENTS_PATH = Path('baseroms/gc-eu-mq-dbg/segments/')
FILE_TABLE_OFFSET = 0x12F70
FILE_NAMES = [
@ -1562,7 +1562,7 @@ def write_output_file(name, offset, size):
print('failed to write file ' + name)
def ExtractFunc(i):
filename = 'baserom/' + FILE_NAMES[i]
filename = SEGMENTS_PATH / FILE_NAMES[i]
entryOffset = FILE_TABLE_OFFSET + 16 * i
virtStart = read_uint32_be(entryOffset + 0)
@ -1571,32 +1571,24 @@ def ExtractFunc(i):
physEnd = read_uint32_be(entryOffset + 12)
if physEnd == 0: # uncompressed
compressed = False
size = virtEnd - virtStart
else: # compressed
compressed = True
size = physEnd - physStart
print('extracting ' + filename + " (0x%08X, 0x%08X)" % (virtStart, virtEnd))
print(f'extracting {filename} (0x{virtStart:08X}, 0x{virtEnd:08X})')
write_output_file(filename, physStart, size)
if compressed:
os.system('tools/yaz0 -d ' + filename + ' ' + filename)
#####################################################################
def main():
try:
os.mkdir('baserom')
except:
pass
SEGMENTS_PATH.mkdir(parents=True, exist_ok=True)
# read baserom data
try:
with open(ROM_FILE_NAME, 'rb') as f:
rom_data = f.read()
rom_data = ROM_FILE_PATH.read_bytes()
except IOError:
print('failed to read file' + ROM_FILE_NAME)
sys.exit(1)
print(f'failed to read file {ROM_FILE_PATH}')
exit(1)
# extract files
num_cores = cpu_count()

View file

@ -3,17 +3,8 @@
import argparse
from pathlib import Path
try:
import rabbitizer
except ImportError:
print("Missing dependency rabbitizer, install it with `python3 -m pip install 'rabbitizer>=1.0.0,<2.0.0'`")
exit(1)
try:
import mapfile_parser
except ImportError:
print("Missing dependency mapfile_parser, install it with `python3 -m pip install 'mapfile-parser>=1.2.1,<2.0.0'`")
exit(1)
import rabbitizer
import mapfile_parser
def decodeInstruction(bytesDiff: bytes, mapFile: mapfile_parser.MapFile) -> str:
@ -49,7 +40,7 @@ def firstDiffMain():
BUILTROM = Path(f"oot-{args.version}.z64")
BUILTMAP = buildFolder / "z64.map"
EXPECTEDROM = Path("baserom.z64")
EXPECTEDROM = Path(f"baseroms/{args.version}/baserom-decompressed.z64")
EXPECTEDMAP = "expected" / BUILTMAP
mapfile_parser.frontends.first_diff.doFirstDiff(BUILTMAP, EXPECTEDMAP, BUILTROM, EXPECTEDROM, args.count, mismatchSize=True, addColons=args.add_colons, bytesConverterCallback=decodeInstruction)

View file

@ -1,96 +0,0 @@
from os import path
import sys
import struct
import hashlib
def get_str_hash(byte_array):
return str(hashlib.md5(byte_array).hexdigest())
# If the baserom exists and is correct, we don't need to change anything
if path.exists("baserom.z64"):
with open("baserom.z64", mode="rb") as file:
fileContent = bytearray(file.read())
if get_str_hash(fileContent) == "f0b7f35375f9cc8ca1b2d59d78e35405":
print("Found valid baserom - exiting early")
sys.exit(0)
# Determine if we have a ROM file
romFileExtensions = ["z64", "n64", "v64"]
def find_baserom_original():
for romFileExtLower in romFileExtensions:
for romFileExt in (romFileExtLower, romFileExtLower.upper()):
romFileNameCandidate = "baserom_original." + romFileExt
if path.exists(romFileNameCandidate):
return romFileNameCandidate
return None
romFileName = find_baserom_original()
if romFileName is None:
print("Error: Could not find baserom_original.z64/baserom_original.n64/baserom_original.v64.")
sys.exit(1)
# Read in the original ROM
print("File '" + romFileName + "' found.")
with open(romFileName, mode="rb") as file:
fileContent = bytearray(file.read())
# Strip the overdump
print("Stripping overdump...")
fileContent = fileContent[0:0x3600000]
fileContentLen = len(fileContent)
# Check if ROM needs to be byte/word swapped
# Little-endian
if fileContent[0] == 0x40:
# Word Swap ROM
print("ROM needs to be word swapped...")
words = str(int(fileContentLen/4))
little_byte_format = "<" + words + "I"
big_byte_format = ">" + words + "I"
tmp = struct.unpack_from(little_byte_format, fileContent, 0)
struct.pack_into(big_byte_format, fileContent, 0, *tmp)
print("Word swapping done.")
# Byte-swapped
elif fileContent[0] == 0x37:
# Byte Swap ROM
print("ROM needs to be byte swapped...")
halfwords = str(int(fileContentLen/2))
little_byte_format = "<" + halfwords + "H"
big_byte_format = ">" + halfwords + "H"
tmp = struct.unpack_from(little_byte_format, fileContent, 0)
struct.pack_into(big_byte_format, fileContent, 0, *tmp)
print("Byte swapping done.")
# Patch the header
print("Patching header...")
fileContent[0x3E] = 0x50
for i in range(0x35CF000, len(fileContent)):
fileContent[i] = 0xFF
# Check to see if the ROM is a "vanilla" Debug ROM
str_hash = get_str_hash(bytearray(fileContent))
if str_hash != "f0b7f35375f9cc8ca1b2d59d78e35405":
print("Error: Expected a hash of f0b7f35375f9cc8ca1b2d59d78e35405 but got " + str_hash + ". " +
"The baserom has probably been tampered, find a new one")
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.")
sys.exit(1)
# Write out our new ROM
print("Writing new ROM 'baserom.z64'.")
with open("baserom.z64", mode="wb") as file:
file.write(bytes(fileContent))
print("Done!")

View file

@ -354,8 +354,9 @@ void Actor_MoveXZGravity(Actor* actor);
void Actor_UpdateVelocityXYZ(Actor* actor);
void Actor_MoveXYZ(Actor* actor);
void Actor_SetProjectileSpeed(Actor* actor, f32 speedXYZ);
s16 Actor_WorldYawTowardActor(Actor* actorA, Actor* actorB);
s16 Actor_WorldYawTowardPoint(Actor* actor, Vec3f* refPoint);
s16 Actor_WorldYawTowardActor(Actor* origin, Actor* target);
s16 Actor_FocusYawTowardActor(Actor* origin, Actor* target);
s16 Actor_WorldYawTowardPoint(Actor* origin, Vec3f* point);
f32 Actor_WorldDistXYZToActor(Actor* actorA, Actor* actorB);
f32 Actor_WorldDistXYZToPoint(Actor* actor, Vec3f* refPoint);
s16 Actor_WorldPitchTowardActor(Actor* actorA, Actor* actorB);
@ -856,7 +857,7 @@ void Math_Vec3f_Scale(Vec3f* vec, f32 scaleF);
f32 Math_Vec3f_DistXYZ(Vec3f* a, Vec3f* b);
f32 Math_Vec3f_DistXYZAndStoreDiff(Vec3f* a, Vec3f* b, Vec3f* dest);
f32 Math_Vec3f_DistXZ(Vec3f* a, Vec3f* b);
s16 Math_Vec3f_Yaw(Vec3f* a, Vec3f* b);
s16 Math_Vec3f_Yaw(Vec3f* origin, Vec3f* point);
s16 Math_Vec3f_Pitch(Vec3f* a, Vec3f* b);
void Actor_ProcessInitChain(Actor* actor, InitChainEntry* ichain);
f32 Math_SmoothStepToF(f32* pValue, f32 target, f32 fraction, f32 step, f32 minStep);

View file

@ -103,14 +103,14 @@
#ifdef OOT_DEBUG
#define PRINTF osSyncPrintf
#else
#ifdef __GNUC__
#define PRINTF(format, ...) (void)0
#else
#ifdef __sgi /* IDO compiler */
// IDO doesn't support variadic macros, but it merely throws a warning for the
// number of arguments not matching the definition (warning 609) instead of
// throwing an error. We suppress this warning and rely on GCC to catch macro
// argument errors instead.
#define PRINTF(args) (void)0
#else
#define PRINTF(format, ...) (void)0
#endif
#endif
@ -189,6 +189,8 @@ extern struct GraphicsContext* __gfxCtx;
#define ZELDA_ARENA_MALLOC(size, file, line) ZeldaArena_MallocDebug(size, file, line)
#define ZELDA_ARENA_MALLOC_R(size, file, line) ZeldaArena_MallocRDebug(size, file, line)
#define ZELDA_ARENA_FREE(size, file, line) ZeldaArena_FreeDebug(size, file, line)
#define LOG_UTILS_CHECK_NULL_POINTER(exp, ptr, file, line) LogUtils_CheckNullPointer(exp, ptr, file, line)
#define LOG_UTILS_CHECK_VALID_POINTER(exp, ptr, file, line) LogUtils_CheckValidPointer(exp, ptr, file, line)
#else
@ -215,6 +217,8 @@ extern struct GraphicsContext* __gfxCtx;
#define ZELDA_ARENA_MALLOC(size, file, line) ZeldaArena_Malloc(size)
#define ZELDA_ARENA_MALLOC_R(size, file, line) ZeldaArena_MallocR(size)
#define ZELDA_ARENA_FREE(size, file, line) ZeldaArena_Free(size)
#define LOG_UTILS_CHECK_NULL_POINTER(exp, ptr, file, line) (void)0
#define LOG_UTILS_CHECK_VALID_POINTER(exp, ptr, file, line) (void)0
#endif /* OOT_DEBUG */

View file

@ -140,36 +140,90 @@ typedef struct {
/* 0x18 */ Vec3f feetPos[2]; // Update by using `Actor_SetFeetPos` in PostLimbDraw
} ActorShape; // size = 0x30
//
#define ACTOR_FLAG_0 (1 << 0)
//
#define ACTOR_FLAG_2 (1 << 2)
//
#define ACTOR_FLAG_3 (1 << 3)
//
#define ACTOR_FLAG_4 (1 << 4)
//
#define ACTOR_FLAG_5 (1 << 5)
//
#define ACTOR_FLAG_6 (1 << 6)
#define ACTOR_FLAG_7 (1 << 7)
// hidden or revealed by Lens of Truth (depending on room lensMode)
#define ACTOR_FLAG_REACT_TO_LENS (1 << 7)
// Signals that player has accepted an offer to talk to an actor
// Player will retain this flag until the player is finished talking
// Actor will retain this flag until `Actor_TalkOfferAccepted` is called or manually turned off by the actor
#define ACTOR_FLAG_TALK (1 << 8)
//
#define ACTOR_FLAG_9 (1 << 9)
//
#define ACTOR_FLAG_10 (1 << 10)
//
#define ACTOR_FLAG_ENKUSA_CUT (1 << 11)
#define ACTOR_FLAG_IGNORE_QUAKE (1 << 12) // actor will not shake when a quake occurs
// Actor will not shake when a quake occurs
#define ACTOR_FLAG_IGNORE_QUAKE (1 << 12)
//
#define ACTOR_FLAG_13 (1 << 13)
//
#define ACTOR_FLAG_14 (1 << 14)
//
#define ACTOR_FLAG_15 (1 << 15)
//
#define ACTOR_FLAG_16 (1 << 16)
//
#define ACTOR_FLAG_17 (1 << 17)
//
#define ACTOR_FLAG_18 (1 << 18)
//
#define ACTOR_FLAG_19 (1 << 19)
//
#define ACTOR_FLAG_20 (1 << 20)
//
#define ACTOR_FLAG_21 (1 << 21)
#define ACTOR_FLAG_22 (1 << 22)
// ignores point lights but not directional lights (such as environment lights)
#define ACTOR_FLAG_IGNORE_POINT_LIGHTS (1 << 22)
//
#define ACTOR_FLAG_23 (1 << 23)
//
#define ACTOR_FLAG_24 (1 << 24)
//
#define ACTOR_FLAG_25 (1 << 25)
//
#define ACTOR_FLAG_26 (1 << 26)
//
#define ACTOR_FLAG_27 (1 << 27)
//
#define ACTOR_FLAG_28 (1 << 28)
#define COLORFILTER_GET_COLORINTENSITY(colorFilterParams) (((colorFilterParams) & 0x1F00) >> 5)
@ -251,7 +305,9 @@ typedef struct Actor {
/* 0x130 */ ActorFunc update; // Update Routine. Called by `Actor_UpdateAll`
/* 0x134 */ ActorFunc draw; // Draw Routine. Called by `Actor_Draw`
/* 0x138 */ ActorOverlay* overlayEntry; // Pointer to the overlay table entry for this actor
/* 0x13C */ char dbgPad[0x10]; // Padding that only exists in the debug rom
#ifdef OOT_DEBUG
/* 0x13C */ char dbgPad[0x10];
#endif
} Actor; // size = 0x14C
typedef enum {

18
requirements.txt Normal file
View file

@ -0,0 +1,18 @@
# Setup and compression
crunch64>=0.3.1,<1.0.0
ipl3checksum>=1.2.0,<2.0.0
# asm-differ
argcomplete
colorama
cxxfilt
python-Levenshtein
watchdog
# decomp-permuter
pycparser
toml
# tools
mapfile-parser>=1.2.1,<2.0.0
rabbitizer>=1.0.0,<2.0.0

1456
spec

File diff suppressed because it is too large Load diff

View file

@ -53,10 +53,10 @@ void PreRender_CopyImage(PreRender* this, Gfx** gfxP, void* img, void* imgDst) {
s32 curRow;
s32 nRows;
LogUtils_CheckNullPointer("this", this, "../PreRender.c", 215);
LogUtils_CheckNullPointer("glistpp", gfxP, "../PreRender.c", 216);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../PreRender.c", 215);
LOG_UTILS_CHECK_NULL_POINTER("glistpp", gfxP, "../PreRender.c", 216);
gfx = *gfxP;
LogUtils_CheckNullPointer("glistp", gfx, "../PreRender.c", 218);
LOG_UTILS_CHECK_NULL_POINTER("glistp", gfx, "../PreRender.c", 218);
gDPPipeSync(gfx++);
// Configure the cycle type to COPY mode, disable blending
@ -114,10 +114,10 @@ void PreRender_CopyImageRegionImpl(PreRender* this, Gfx** gfxP) {
s32 curRow;
s32 nRows;
LogUtils_CheckNullPointer("this", this, "../PreRender.c", 278);
LogUtils_CheckNullPointer("glistpp", gfxP, "../PreRender.c", 279);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../PreRender.c", 278);
LOG_UTILS_CHECK_NULL_POINTER("glistpp", gfxP, "../PreRender.c", 279);
gfx = *gfxP;
LogUtils_CheckNullPointer("glistp", gfx, "../PreRender.c", 281);
LOG_UTILS_CHECK_NULL_POINTER("glistp", gfx, "../PreRender.c", 281);
gDPPipeSync(gfx++);
// Configure the cycle type to COPY mode, disable blending
@ -177,10 +177,10 @@ void func_800C170C(PreRender* this, Gfx** gfxP, void* buf, void* bufSave, u32 r,
s32 curRow;
s32 nRows;
LogUtils_CheckNullPointer("this", this, "../PreRender.c", 343);
LogUtils_CheckNullPointer("glistpp", gfxP, "../PreRender.c", 344);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../PreRender.c", 343);
LOG_UTILS_CHECK_NULL_POINTER("glistpp", gfxP, "../PreRender.c", 344);
gfx = *gfxP;
LogUtils_CheckNullPointer("glistp", gfx, "../PreRender.c", 346);
LOG_UTILS_CHECK_NULL_POINTER("glistp", gfx, "../PreRender.c", 346);
gDPPipeSync(gfx++);
// Set the cycle type to 1-cycle mode to use the color combiner
@ -256,10 +256,10 @@ void PreRender_CoverageRgba16ToI8(PreRender* this, Gfx** gfxP, void* img, void*
s32 curRow;
s32 nRows;
LogUtils_CheckNullPointer("this", this, "../PreRender.c", 422);
LogUtils_CheckNullPointer("glistpp", gfxP, "../PreRender.c", 423);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../PreRender.c", 422);
LOG_UTILS_CHECK_NULL_POINTER("glistpp", gfxP, "../PreRender.c", 423);
gfx = *gfxP;
LogUtils_CheckNullPointer("glistp", gfx, "../PreRender.c", 425);
LOG_UTILS_CHECK_NULL_POINTER("glistp", gfx, "../PreRender.c", 425);
gDPPipeSync(gfx++);
gDPSetOtherMode(gfx++,
@ -333,8 +333,8 @@ void PreRender_CoverageRgba16ToI8(PreRender* this, Gfx** gfxP, void* img, void*
* Saves zbuf to zbufSave
*/
void PreRender_SaveZBuffer(PreRender* this, Gfx** gfxP) {
LogUtils_CheckNullPointer("this->zbuf_save", this->zbufSave, "../PreRender.c", 481);
LogUtils_CheckNullPointer("this->zbuf", this->zbuf, "../PreRender.c", 482);
LOG_UTILS_CHECK_NULL_POINTER("this->zbuf_save", this->zbufSave, "../PreRender.c", 481);
LOG_UTILS_CHECK_NULL_POINTER("this->zbuf", this->zbuf, "../PreRender.c", 482);
if ((this->zbufSave != NULL) && (this->zbuf != NULL)) {
PreRender_CopyImage(this, gfxP, this->zbuf, this->zbufSave);
@ -345,8 +345,8 @@ void PreRender_SaveZBuffer(PreRender* this, Gfx** gfxP) {
* Saves fbuf to fbufSave
*/
void PreRender_SaveFramebuffer(PreRender* this, Gfx** gfxP) {
LogUtils_CheckNullPointer("this->fbuf_save", this->fbufSave, "../PreRender.c", 495);
LogUtils_CheckNullPointer("this->fbuf", this->fbuf, "../PreRender.c", 496);
LOG_UTILS_CHECK_NULL_POINTER("this->fbuf_save", this->fbufSave, "../PreRender.c", 495);
LOG_UTILS_CHECK_NULL_POINTER("this->fbuf", this->fbuf, "../PreRender.c", 496);
if ((this->fbufSave != NULL) && (this->fbuf != NULL)) {
func_800C1AE8(this, gfxP, this->fbuf, this->fbufSave);
@ -401,7 +401,7 @@ void PreRender_FetchFbufCoverage(PreRender* this, Gfx** gfxP) {
*/
void PreRender_DrawCoverage(PreRender* this, Gfx** gfxP) {
PreRender_FetchFbufCoverage(this, gfxP);
LogUtils_CheckNullPointer("this->cvg_save", this->cvgSave, "../PreRender.c", 532);
LOG_UTILS_CHECK_NULL_POINTER("this->cvg_save", this->cvgSave, "../PreRender.c", 532);
if (this->cvgSave != NULL) {
PreRender_CoverageRgba16ToI8(this, gfxP, this->fbuf, this->cvgSave);
}
@ -426,10 +426,10 @@ void func_800C213C(PreRender* this, Gfx** gfxP) {
s32 rtile = 1;
if (this->cvgSave != NULL) {
LogUtils_CheckNullPointer("this", this, "../PreRender.c", 563);
LogUtils_CheckNullPointer("glistpp", gfxP, "../PreRender.c", 564);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../PreRender.c", 563);
LOG_UTILS_CHECK_NULL_POINTER("glistpp", gfxP, "../PreRender.c", 564);
gfx = *gfxP;
LogUtils_CheckNullPointer("glistp", gfx, "../PreRender.c", 566);
LOG_UTILS_CHECK_NULL_POINTER("glistp", gfx, "../PreRender.c", 566);
gDPPipeSync(gfx++);
gDPSetEnvColor(gfx++, 255, 255, 255, 32);

View file

@ -415,7 +415,7 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g
PRINTF("init 処理時間 %d us\n", OS_CYCLES_TO_USEC(endTime - startTime));
startTime = endTime;
LogUtils_CheckNullPointer("this->cleanup", gameState->destroy, "../game.c", 1088);
LOG_UTILS_CHECK_NULL_POINTER("this->cleanup", gameState->destroy, "../game.c", 1088);
VisCvg_Init(&sVisCvg);
VisZBuf_Init(&sVisZBuf);
VisMono_Init(&sVisMono);
@ -440,7 +440,7 @@ void GameState_Destroy(GameState* gameState) {
AudioMgr_StopAllSfx();
func_800F3054();
osRecvMesg(&gameState->gfxCtx->queue, NULL, OS_MESG_BLOCK);
LogUtils_CheckNullPointer("this->cleanup", gameState->destroy, "../game.c", 1139);
LOG_UTILS_CHECK_NULL_POINTER("this->cleanup", gameState->destroy, "../game.c", 1139);
if (gameState->destroy != NULL) {
gameState->destroy(gameState);
}

View file

@ -49,8 +49,8 @@ void GameAlloc_Free(GameAlloc* this, void* data) {
if (data != NULL) {
ptr = &((GameAllocEntry*)data)[-1];
LogUtils_CheckNullPointer("ptr->prev", ptr->prev, "../gamealloc.c", 120);
LogUtils_CheckNullPointer("ptr->next", ptr->next, "../gamealloc.c", 121);
LOG_UTILS_CHECK_NULL_POINTER("ptr->prev", ptr->prev, "../gamealloc.c", 120);
LOG_UTILS_CHECK_NULL_POINTER("ptr->next", ptr->next, "../gamealloc.c", 121);
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
this->head = this->base.prev;

View file

@ -59,9 +59,9 @@ u32 sIrqMgrRetraceCount = 0;
void IrqMgr_AddClient(IrqMgr* irqMgr, IrqMgrClient* client, OSMesgQueue* msgQueue) {
OSIntMask prevInt;
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 96);
LogUtils_CheckNullPointer("c", client, "../irqmgr.c", 97);
LogUtils_CheckNullPointer("msgQ", msgQueue, "../irqmgr.c", 98);
LOG_UTILS_CHECK_NULL_POINTER("this", irqMgr, "../irqmgr.c", 96);
LOG_UTILS_CHECK_NULL_POINTER("c", client, "../irqmgr.c", 97);
LOG_UTILS_CHECK_NULL_POINTER("msgQ", msgQueue, "../irqmgr.c", 98);
prevInt = osSetIntMask(OS_IM_NONE);
@ -85,8 +85,8 @@ void IrqMgr_RemoveClient(IrqMgr* irqMgr, IrqMgrClient* client) {
IrqMgrClient* lastClient = NULL;
OSIntMask prevInt;
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 129);
LogUtils_CheckNullPointer("c", client, "../irqmgr.c", 130);
LOG_UTILS_CHECK_NULL_POINTER("this", irqMgr, "../irqmgr.c", 129);
LOG_UTILS_CHECK_NULL_POINTER("c", client, "../irqmgr.c", 130);
// Disable interrupts to prevent a thread context switch while the linked list is modified
prevInt = osSetIntMask(OS_IM_NONE);
@ -290,8 +290,8 @@ void IrqMgr_ThreadEntry(void* arg) {
}
void IrqMgr_Init(IrqMgr* irqMgr, void* stack, OSPri pri, u8 retraceCount) {
LogUtils_CheckNullPointer("this", irqMgr, "../irqmgr.c", 346);
LogUtils_CheckNullPointer("stack", stack, "../irqmgr.c", 347);
LOG_UTILS_CHECK_NULL_POINTER("this", irqMgr, "../irqmgr.c", 346);
LOG_UTILS_CHECK_NULL_POINTER("stack", stack, "../irqmgr.c", 347);
irqMgr->clients = NULL;
// Messages to send to each client message queue on each interrupt event

View file

@ -4,8 +4,8 @@ void MtxConv_F2L(Mtx* m1, MtxF* m2) {
s32 i;
s32 j;
LogUtils_CheckNullPointer("m1", m1, "../mtxuty-cvt.c", 31);
LogUtils_CheckNullPointer("m2", m2, "../mtxuty-cvt.c", 32);
LOG_UTILS_CHECK_NULL_POINTER("m1", m1, "../mtxuty-cvt.c", 31);
LOG_UTILS_CHECK_NULL_POINTER("m2", m2, "../mtxuty-cvt.c", 32);
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
@ -18,7 +18,7 @@ void MtxConv_F2L(Mtx* m1, MtxF* m2) {
}
void MtxConv_L2F(MtxF* m1, Mtx* m2) {
LogUtils_CheckNullPointer("m1", m1, "../mtxuty-cvt.c", 55);
LogUtils_CheckNullPointer("m2", m2, "../mtxuty-cvt.c", 56);
LOG_UTILS_CHECK_NULL_POINTER("m1", m1, "../mtxuty-cvt.c", 55);
LOG_UTILS_CHECK_NULL_POINTER("m2", m2, "../mtxuty-cvt.c", 56);
guMtxL2F(m1, m2);
}

View file

@ -477,7 +477,7 @@ void PadMgr_ThreadEntry(PadMgr* padMgr) {
}
osRecvMesg(&padMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
LogUtils_CheckNullPointer("msg", msg, "../padmgr.c", 563);
LOG_UTILS_CHECK_NULL_POINTER("msg", msg, "../padmgr.c", 563);
switch (*msg) {
case OS_SC_RETRACE_MSG:

View file

@ -58,7 +58,7 @@ OSTime sRDPTimeStart;
void Sched_SwapFrameBufferImpl(CfbInfo* cfbInfo) {
u16 width;
LogUtils_CheckValidPointer("cfbinfo->swapbuffer", cfbInfo->swapBuffer, "../sched.c", 340);
LOG_UTILS_CHECK_VALID_POINTER("cfbinfo->swapbuffer", cfbInfo->swapBuffer, "../sched.c", 340);
if (cfbInfo->swapBuffer != NULL) {
// Register the swapbuffer to display on next VI
@ -330,7 +330,7 @@ void Sched_SetNextFramebufferFromTask(Scheduler* sc, OSScTask* task) {
if (sc->pendingSwapBuf1 == NULL) {
sc->pendingSwapBuf1 = task->framebuffer;
LogUtils_CheckValidPointer("sc->pending_swapbuffer1", sc->pendingSwapBuf1, "../sched.c", 618);
LOG_UTILS_CHECK_VALID_POINTER("sc->pending_swapbuffer1", sc->pendingSwapBuf1, "../sched.c", 618);
if (sc->curBuf == NULL || sc->curBuf->updateTimer <= 0) {
Sched_SwapFrameBuffer(sc, task->framebuffer);

View file

@ -92,7 +92,7 @@ typedef struct {
gDPPipeSync(gfx)
void SpeedMeter_InitImpl(SpeedMeter* this, u32 x, u32 y) {
LogUtils_CheckNullPointer("this", this, "../speed_meter.c", 181);
LOG_UTILS_CHECK_NULL_POINTER("this", this, "../speed_meter.c", 181);
this->x = x;
this->y = y;
}

View file

@ -915,16 +915,25 @@ void Actor_UpdatePosByAnimation(Actor* actor, SkelAnime* skelAnime) {
actor->world.pos.z += posDiff.z * actor->scale.z;
}
s16 Actor_WorldYawTowardActor(Actor* actorA, Actor* actorB) {
return Math_Vec3f_Yaw(&actorA->world.pos, &actorB->world.pos);
/**
* @return Yaw towards `target` for `origin`, using world positions.
*/
s16 Actor_WorldYawTowardActor(Actor* origin, Actor* target) {
return Math_Vec3f_Yaw(&origin->world.pos, &target->world.pos);
}
s16 Actor_FocusYawTowardActor(Actor* actorA, Actor* actorB) {
return Math_Vec3f_Yaw(&actorA->focus.pos, &actorB->focus.pos);
/**
* @return Yaw towards `target` for `origin`, using focus positions.
*/
s16 Actor_FocusYawTowardActor(Actor* origin, Actor* target) {
return Math_Vec3f_Yaw(&origin->focus.pos, &target->focus.pos);
}
s16 Actor_WorldYawTowardPoint(Actor* actor, Vec3f* refPoint) {
return Math_Vec3f_Yaw(&actor->world.pos, refPoint);
/**
* @return Yaw towards `point` for `origin`.
*/
s16 Actor_WorldYawTowardPoint(Actor* origin, Vec3f* point) {
return Math_Vec3f_Yaw(&origin->world.pos, point);
}
s16 Actor_WorldPitchTowardActor(Actor* actorA, Actor* actorB) {
@ -2302,7 +2311,8 @@ void Actor_Draw(PlayState* play, Actor* actor) {
lights = LightContext_NewLights(&play->lightCtx, play->state.gfxCtx);
Lights_BindAll(lights, play->lightCtx.listHead, (actor->flags & ACTOR_FLAG_22) ? NULL : &actor->world.pos);
Lights_BindAll(lights, play->lightCtx.listHead,
(actor->flags & ACTOR_FLAG_IGNORE_POINT_LIGHTS) ? NULL : &actor->world.pos);
Lights_Draw(lights, play->state.gfxCtx);
if (actor->flags & ACTOR_FLAG_IGNORE_QUAKE) {
@ -2552,7 +2562,7 @@ void func_800315AC(PlayState* play, ActorContext* actorCtx) {
if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(71) == 0)) {
if ((actor->init == NULL) && (actor->draw != NULL) && (actor->flags & (ACTOR_FLAG_5 | ACTOR_FLAG_6))) {
if ((actor->flags & ACTOR_FLAG_7) &&
if ((actor->flags & ACTOR_FLAG_REACT_TO_LENS) &&
((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) || play->actorCtx.lensActive ||
(actor->room != play->roomCtx.curRoom.num))) {
ASSERT(invisibleActorCounter < INVISIBLE_ACTOR_MAX,

View file

@ -17,7 +17,7 @@ KaleidoMgrOverlay* gKaleidoMgrCurOvl = NULL;
u8 gBossMarkState = 0;
void KaleidoManager_LoadOvl(KaleidoMgrOverlay* ovl) {
LogUtils_CheckNullPointer("KaleidoArea_allocp", sKaleidoAreaPtr, "../z_kaleido_manager.c", 99);
LOG_UTILS_CHECK_NULL_POINTER("KaleidoArea_allocp", sKaleidoAreaPtr, "../z_kaleido_manager.c", 99);
ovl->loadedRamAddr = sKaleidoAreaPtr;
Overlay_Load(ovl->vromStart, ovl->vromEnd, ovl->vramStart, ovl->vramEnd, ovl->loadedRamAddr);
@ -58,7 +58,7 @@ void KaleidoManager_Init(PlayState* play) {
PRINTF(VT_RST);
sKaleidoAreaPtr = GAME_STATE_ALLOC(&play->state, largestSize, "../z_kaleido_manager.c", 150);
LogUtils_CheckNullPointer("KaleidoArea_allocp", sKaleidoAreaPtr, "../z_kaleido_manager.c", 151);
LOG_UTILS_CHECK_NULL_POINTER("KaleidoArea_allocp", sKaleidoAreaPtr, "../z_kaleido_manager.c", 151);
PRINTF(VT_FGCOL(GREEN));
PRINTF("KaleidoArea %08x - %08x\n", sKaleidoAreaPtr, (uintptr_t)sKaleidoAreaPtr + largestSize);

View file

@ -300,9 +300,14 @@ f32 Math_Vec3f_DiffY(Vec3f* a, Vec3f* b) {
return b->y - a->y;
}
s16 Math_Vec3f_Yaw(Vec3f* a, Vec3f* b) {
f32 dx = b->x - a->x;
f32 dz = b->z - a->z;
/**
* @param origin Position of the origin, the location from which to look at the target `point`
* @param point Position of the target point, in the same space as `origin`
* @return The yaw towards `point` when at `origin`, assuming +z is forwards.
*/
s16 Math_Vec3f_Yaw(Vec3f* origin, Vec3f* point) {
f32 dx = point->x - origin->x;
f32 dz = point->z - origin->z;
return Math_Atan2S(dz, dx);
}

View file

@ -58,7 +58,7 @@ void MapMark_Init(PlayState* play) {
u32 overlaySize = (uintptr_t)overlay->vramEnd - (uintptr_t)overlay->vramStart;
overlay->loadedRamAddr = GAME_STATE_ALLOC(&play->state, overlaySize, "../z_map_mark.c", 235);
LogUtils_CheckNullPointer("dlftbl->allocp", overlay->loadedRamAddr, "../z_map_mark.c", 236);
LOG_UTILS_CHECK_NULL_POINTER("dlftbl->allocp", overlay->loadedRamAddr, "../z_map_mark.c", 236);
Overlay_Load(overlay->vromStart, overlay->vromEnd, overlay->vramStart, overlay->vramEnd, overlay->loadedRamAddr);

View file

@ -20,8 +20,11 @@ Vec3f OnePointCutscene_AddVecGeoToVec3f(Vec3f* a, VecGeo* geo) {
return sum;
}
s16 OnePointCutscene_Vec3fYaw(Vec3f* vec1, Vec3f* vec2) {
return CAM_DEG_TO_BINANG(RAD_TO_DEG(Math_FAtan2F(vec2->x - vec1->x, vec2->z - vec1->z)));
/**
* @see Math_Vec3f_Yaw
*/
s16 OnePointCutscene_Vec3fYaw(Vec3f* origin, Vec3f* point) {
return CAM_DEG_TO_BINANG(RAD_TO_DEG(Math_FAtan2F(point->x - origin->x, point->z - origin->z)));
}
void OnePointCutscene_Vec3sToVec3f(Vec3f* src, Vec3s* dst) {

View file

@ -483,6 +483,26 @@ void Scene_CommandMiscSettings(PlayState* play, SceneCmd* cmd) {
}
}
void Scene_SetTransitionForNextEntrance(PlayState* play) {
s16 entranceIndex;
if (!IS_DAY) {
if (!LINK_IS_ADULT) {
entranceIndex = play->nextEntranceIndex + 1;
} else {
entranceIndex = play->nextEntranceIndex + 3;
}
} else {
if (!LINK_IS_ADULT) {
entranceIndex = play->nextEntranceIndex;
} else {
entranceIndex = play->nextEntranceIndex + 2;
}
}
play->transitionType = ENTRANCE_INFO_START_TRANS_TYPE(gEntranceTable[entranceIndex].field);
}
void (*gSceneCmdHandlers[SCENE_CMD_ID_MAX])(PlayState*, SceneCmd*) = {
Scene_CommandPlayerEntryList, // SCENE_CMD_ID_SPAWN_LIST
Scene_CommandActorEntryList, // SCENE_CMD_ID_ACTOR_LIST

View file

@ -77,26 +77,6 @@ Gfx sDefaultDisplayList[] = {
gsSPEndDisplayList(),
};
void Scene_SetTransitionForNextEntrance(PlayState* play) {
s16 entranceIndex;
if (!IS_DAY) {
if (!LINK_IS_ADULT) {
entranceIndex = play->nextEntranceIndex + 1;
} else {
entranceIndex = play->nextEntranceIndex + 3;
}
} else {
if (!LINK_IS_ADULT) {
entranceIndex = play->nextEntranceIndex;
} else {
entranceIndex = play->nextEntranceIndex + 2;
}
}
play->transitionType = ENTRANCE_INFO_START_TRANS_TYPE(gEntranceTable[entranceIndex].field);
}
void Scene_DrawConfigDefault(PlayState* play) {
OPEN_DISPS(play->state.gfxCtx, "../z_scene_table.c", 4725);

View file

@ -292,7 +292,7 @@ s32 View_ApplyPerspective(View* view) {
// Viewport
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
LogUtils_CheckNullPointer("vp", vp, "../z_view.c", 601);
LOG_UTILS_CHECK_NULL_POINTER("vp", vp, "../z_view.c", 601);
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
@ -303,7 +303,7 @@ s32 View_ApplyPerspective(View* view) {
// Perspective projection
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 616);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 616);
view->projectionPtr = projection;
width = view->viewport.rightX - view->viewport.leftX;
@ -351,7 +351,7 @@ s32 View_ApplyPerspective(View* view) {
// View matrix (look-at)
viewing = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667);
LOG_UTILS_CHECK_NULL_POINTER("viewing", viewing, "../z_view.c", 667);
view->viewingPtr = viewing;
if (view->eye.x == view->at.x && view->eye.y == view->at.y && view->eye.z == view->at.z) {
@ -395,7 +395,7 @@ s32 View_ApplyOrtho(View* view) {
OPEN_DISPS(gfxCtx, "../z_view.c", 726);
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
LogUtils_CheckNullPointer("vp", vp, "../z_view.c", 730);
LOG_UTILS_CHECK_NULL_POINTER("vp", vp, "../z_view.c", 730);
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
@ -406,7 +406,7 @@ s32 View_ApplyOrtho(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 744);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 744);
view->projectionPtr = projection;
guOrtho(projection, -(f32)gScreenWidth * 0.5f, (f32)gScreenWidth * 0.5f, -(f32)gScreenHeight * 0.5f,
@ -435,7 +435,7 @@ s32 View_ApplyOrthoToOverlay(View* view) {
OPEN_DISPS(gfxCtx, "../z_view.c", 777);
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
LogUtils_CheckNullPointer("vp", vp, "../z_view.c", 781);
LOG_UTILS_CHECK_NULL_POINTER("vp", vp, "../z_view.c", 781);
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
@ -445,7 +445,7 @@ s32 View_ApplyOrthoToOverlay(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 791);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 791);
view->projectionPtr = projection;
guOrtho(projection, -(f32)gScreenWidth * 0.5f, (f32)gScreenWidth * 0.5f, -(f32)gScreenHeight * 0.5f,
@ -476,7 +476,7 @@ s32 View_ApplyPerspectiveToOverlay(View* view) {
OPEN_DISPS(gfxCtx, "../z_view.c", 816);
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
LogUtils_CheckNullPointer("vp", vp, "../z_view.c", 821);
LOG_UTILS_CHECK_NULL_POINTER("vp", vp, "../z_view.c", 821);
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
@ -486,7 +486,7 @@ s32 View_ApplyPerspectiveToOverlay(View* view) {
gSPViewport(OVERLAY_DISP++, vp);
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 833);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 833);
view->projectionPtr = projection;
width = view->viewport.rightX - view->viewport.leftX;
@ -501,7 +501,7 @@ s32 View_ApplyPerspectiveToOverlay(View* view) {
gSPMatrix(OVERLAY_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
viewing = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 848);
LOG_UTILS_CHECK_NULL_POINTER("viewing", viewing, "../z_view.c", 848);
view->viewingPtr = viewing;
// This check avoids a divide-by-zero in guLookAt if eye == at
@ -552,7 +552,7 @@ s32 View_ApplyTo(View* view, s32 mask, Gfx** gfxP) {
if (mask & VIEW_VIEWPORT) {
vp = GRAPH_ALLOC(gfxCtx, sizeof(Vp));
LogUtils_CheckNullPointer("vp", vp, "../z_view.c", 910);
LOG_UTILS_CHECK_NULL_POINTER("vp", vp, "../z_view.c", 910);
View_ViewportToVp(vp, &view->viewport);
view->vp = *vp;
@ -565,7 +565,7 @@ s32 View_ApplyTo(View* view, s32 mask, Gfx** gfxP) {
if (mask & VIEW_PROJECTION_ORTHO) {
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 921);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 921);
view->projectionPtr = projection;
guOrtho(projection, -(f32)gScreenWidth * 0.5f, (f32)gScreenWidth * 0.5f, -(f32)gScreenHeight * 0.5f,
@ -576,7 +576,7 @@ s32 View_ApplyTo(View* view, s32 mask, Gfx** gfxP) {
gSPMatrix(gfx++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
} else if (mask & (VIEW_PROJECTION_PERSPECTIVE | VIEW_VIEWPORT)) {
projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("projection", projection, "../z_view.c", 932);
LOG_UTILS_CHECK_NULL_POINTER("projection", projection, "../z_view.c", 932);
view->projectionPtr = projection;
width = view->viewport.rightX - view->viewport.leftX;
@ -593,7 +593,7 @@ s32 View_ApplyTo(View* view, s32 mask, Gfx** gfxP) {
if (mask & VIEW_VIEWING) {
viewing = GRAPH_ALLOC(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 948);
LOG_UTILS_CHECK_NULL_POINTER("viewing", viewing, "../z_view.c", 948);
view->viewingPtr = viewing;
View_ErrorCheckEyePosition(view->eye.x, view->eye.y, view->eye.z);

View file

@ -1,4 +1,4 @@
.section .text
.incbin "baserom.z64", 0x40, 0xFC0
.incbin "baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", 0x40, 0xFC0

View file

@ -7,7 +7,7 @@
#include "z_bg_bombwall.h"
#include "assets/objects/gameplay_field_keep/gameplay_field_keep.h"
#define FLAGS ACTOR_FLAG_22
#define FLAGS ACTOR_FLAG_IGNORE_POINT_LIGHTS
void BgBombwall_Init(Actor* thisx, PlayState* play);
void BgBombwall_Destroy(Actor* thisx, PlayState* play);

View file

@ -55,7 +55,7 @@ void BgGndDarkmeiro_Init(Actor* thisx, PlayState* play2) {
switch (this->dyna.actor.params & 0xFF) {
case DARKMEIRO_INVISIBLE_PATH:
this->dyna.actor.draw = BgGndDarkmeiro_DrawInvisiblePath;
this->dyna.actor.flags |= ACTOR_FLAG_7;
this->dyna.actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
break;
case DARKMEIRO_CLEAR_BLOCK:
CollisionHeader_GetVirtual(&gClearBlockCol, &colHeader);

View file

@ -40,9 +40,9 @@ void BgGndNisekabe_Update(Actor* thisx, PlayState* play) {
BgGndNisekabe* this = (BgGndNisekabe*)thisx;
if (play->actorCtx.lensActive) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
} else {
this->actor.flags &= ~ACTOR_FLAG_7;
this->actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
}
}
@ -55,7 +55,7 @@ void BgGndNisekabe_Draw(Actor* thisx, PlayState* play) {
BgGndNisekabe* this = (BgGndNisekabe*)thisx;
u32 index = this->actor.params & 0xFF;
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
Gfx_DrawDListXlu(play, dLists[index]);
} else {
Gfx_DrawDListOpa(play, dLists[index]);

View file

@ -292,9 +292,9 @@ void BgHakaGate_FalseSkull(BgHakaGate* this, PlayState* play) {
Math_StepToS(&this->vFlameScale, 350, 20);
}
if (play->actorCtx.lensActive) {
this->dyna.actor.flags |= ACTOR_FLAG_7;
this->dyna.actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
} else {
this->dyna.actor.flags &= ~ACTOR_FLAG_7;
this->dyna.actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
}
}
@ -345,7 +345,7 @@ void BgHakaGate_Draw(Actor* thisx, PlayState* play) {
BgHakaGate* this = (BgHakaGate*)thisx;
MtxF currentMtxF;
if (CHECK_FLAG_ALL(thisx->flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(thisx->flags, ACTOR_FLAG_REACT_TO_LENS)) {
Gfx_DrawDListXlu(play, object_haka_objects_DL_00F1B0);
} else {
Gfx_SetupDL_25Opa(play->state.gfxCtx);

View file

@ -8,7 +8,7 @@
#include "assets/objects/object_hakach_objects/object_hakach_objects.h"
#include "assets/objects/object_haka_objects/object_haka_objects.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5 | ACTOR_FLAG_7)
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5 | ACTOR_FLAG_REACT_TO_LENS)
void BgHakaMegane_Init(Actor* thisx, PlayState* play);
void BgHakaMegane_Destroy(Actor* thisx, PlayState* play);
@ -109,10 +109,10 @@ void func_8087DBF0(BgHakaMegane* this, PlayState* play) {
Actor* thisx = &this->dyna.actor;
if (play->actorCtx.lensActive) {
thisx->flags |= ACTOR_FLAG_7;
thisx->flags |= ACTOR_FLAG_REACT_TO_LENS;
DynaPoly_DisableCollision(play, &play->colCtx.dyna, this->dyna.bgId);
} else {
thisx->flags &= ~ACTOR_FLAG_7;
thisx->flags &= ~ACTOR_FLAG_REACT_TO_LENS;
DynaPoly_EnableCollision(play, &play->colCtx.dyna, this->dyna.bgId);
}
}
@ -129,7 +129,7 @@ void BgHakaMegane_Update(Actor* thisx, PlayState* play) {
void BgHakaMegane_Draw(Actor* thisx, PlayState* play) {
BgHakaMegane* this = (BgHakaMegane*)thisx;
if (CHECK_FLAG_ALL(thisx->flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(thisx->flags, ACTOR_FLAG_REACT_TO_LENS)) {
Gfx_DrawDListXlu(play, sDLists[thisx->params]);
} else {
Gfx_DrawDListOpa(play, sDLists[thisx->params]);

View file

@ -72,7 +72,7 @@ void BgHakaMeganeBG_Init(Actor* thisx, PlayState* play) {
if (thisx->params == 0) {
CollisionHeader_GetVirtual(&object_haka_objects_Col_009168, &colHeader);
thisx->flags |= ACTOR_FLAG_7;
thisx->flags |= ACTOR_FLAG_REACT_TO_LENS;
this->unk_16A = 20;
this->actionFunc = func_8087DFF8;
} else if (thisx->params == 3) {

View file

@ -142,7 +142,7 @@ void BgHakaSgami_Init(Actor* thisx, PlayState* play) {
thisx->params = (thisx->params >> 8) & 0xFF;
if (this->unk_151 != 0) {
thisx->flags |= ACTOR_FLAG_7;
thisx->flags |= ACTOR_FLAG_REACT_TO_LENS;
}
Collider_InitTris(play, colliderScythe);

View file

@ -41,9 +41,9 @@ void BgMenkuriNisekabe_Update(Actor* thisx, PlayState* play) {
BgMenkuriNisekabe* this = (BgMenkuriNisekabe*)thisx;
if (play->actorCtx.lensActive) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
} else {
this->actor.flags &= ~ACTOR_FLAG_7;
this->actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
}
}
@ -51,7 +51,7 @@ void BgMenkuriNisekabe_Draw(Actor* thisx, PlayState* play) {
BgMenkuriNisekabe* this = (BgMenkuriNisekabe*)thisx;
u32 index = this->actor.params & 0xFF;
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
Gfx_DrawDListXlu(play, sDLists[index]);
} else {
Gfx_DrawDListOpa(play, sDLists[index]);

View file

@ -74,7 +74,7 @@ void BgSpot02Objects_Init(Actor* thisx, PlayState* play) {
} else if (thisx->params == 1) {
this->actionFunc = func_808AC8FC;
CollisionHeader_GetVirtual(&object_spot02_objects_Col_0128D8, &colHeader);
thisx->flags |= ACTOR_FLAG_22;
thisx->flags |= ACTOR_FLAG_IGNORE_POINT_LIGHTS;
} else {
if (play->sceneId == SCENE_GRAVEYARD) {
this->actionFunc = func_808AC908;

View file

@ -9,7 +9,7 @@
#include "overlays/effects/ovl_Effect_Ss_Kakera/z_eff_ss_kakera.h"
#include "assets/objects/gameplay_field_keep/gameplay_field_keep.h"
#define FLAGS ACTOR_FLAG_22
#define FLAGS ACTOR_FLAG_IGNORE_POINT_LIGHTS
void BgSpot08Bakudankabe_Init(Actor* thisx, PlayState* play);
void BgSpot08Bakudankabe_Destroy(Actor* thisx, PlayState* play);

View file

@ -1878,8 +1878,8 @@ void func_80902348(BossGanon2* this, PlayState* play) {
}
}
void func_80902524(BossGanon2* this, PlayState* play) {
s8 temp_v0_4;
void BossGanon2_CollisionCheck(BossGanon2* this, PlayState* play) {
s8 health;
ColliderElement* acHitElem;
s16 i;
u8 phi_v1_2;
@ -1909,11 +1909,11 @@ void func_80902524(BossGanon2* this, PlayState* play) {
Actor_PlaySfx(&this->actor, NA_SE_EN_MGANON_DAMAGE);
Audio_StopSfxById(NA_SE_EN_MGANON_UNARI);
this->actor.colChkInfo.health -= 2;
temp_v0_4 = this->actor.colChkInfo.health;
if (temp_v0_4 < 0x15 && this->unk_334 == 0) {
health = this->actor.colChkInfo.health;
if (health <= 20 && this->unk_334 == 0) {
func_80900818(this, play);
} else {
if (temp_v0_4 <= 0) {
if (health <= 0) {
func_80901020(this, play);
} else {
func_80900210(this, play);
@ -1943,13 +1943,13 @@ void func_80902524(BossGanon2* this, PlayState* play) {
}
}
this->actor.colChkInfo.health -= phi_v1_2;
temp_v0_4 = this->actor.colChkInfo.health;
if ((temp_v0_4 < 0x15) && (this->unk_334 == 0)) {
health = this->actor.colChkInfo.health;
if ((health <= 20) && (this->unk_334 == 0)) {
func_80900818(this, play);
} else if ((temp_v0_4 <= 0) && (phi_v1_2 >= 2)) {
} else if ((health <= 0) && (phi_v1_2 >= 2)) {
func_80901020(this, play);
} else {
if (temp_v0_4 <= 0) {
if (health <= 0) {
this->actor.colChkInfo.health = 1;
}
func_80900210(this, play);
@ -2067,7 +2067,7 @@ void BossGanon2_Update(Actor* thisx, PlayState* play) {
func_80902348(this, play);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->unk_424.base);
if (this->actionFunc != func_8090120C) {
func_80902524(this, play);
BossGanon2_CollisionCheck(this, play);
CollisionCheck_SetAC(play, &play->colChkCtx, &this->unk_424.base);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->unk_444.base);
CollisionCheck_SetAC(play, &play->colChkCtx, &this->unk_444.base);

View file

@ -581,7 +581,7 @@ void BossSst_HeadIntro(BossSst* this, PlayState* play) {
sSubCamEye.y += 400.0f * 0.01f;
sSubCamEye.z += 1550.0f * 0.01f;
this->vVanish = true;
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
} else if (revealStateTimer < 40) {
sSubCamAt.x += 125.0f * 0.01f;
sSubCamAt.y += 350.0f * 0.01f;
@ -819,7 +819,7 @@ void BossSst_HeadSetupStunned(BossSst* this) {
this->colliderJntSph.base.atFlags &= ~(AT_ON | AT_HIT);
this->colliderCyl.base.acFlags &= ~AC_ON;
this->vVanish = false;
this->actor.flags &= ~ACTOR_FLAG_7;
this->actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
BossSst_HeadSfx(this, NA_SE_EN_SHADEST_FREEZE);
this->actionFunc = BossSst_HeadStunned;
}
@ -2646,9 +2646,9 @@ void BossSst_UpdateHead(Actor* thisx, PlayState* play) {
this->actionFunc(this, play);
if (this->vVanish) {
if (!play->actorCtx.lensActive || (thisx->colorFilterTimer != 0)) {
this->actor.flags &= ~ACTOR_FLAG_7;
this->actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
} else {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
}
}
@ -2668,7 +2668,7 @@ void BossSst_UpdateHead(Actor* thisx, PlayState* play) {
}
BossSst_MoveAround(this);
if ((!this->vVanish || CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) &&
if ((!this->vVanish || CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) &&
((this->actionFunc == BossSst_HeadReadyCharge) || (this->actionFunc == BossSst_HeadCharge) ||
(this->actionFunc == BossSst_HeadFrozenHand) || (this->actionFunc == BossSst_HeadStunned) ||
(this->actionFunc == BossSst_HeadVulnerable) || (this->actionFunc == BossSst_HeadDamage))) {
@ -2777,7 +2777,7 @@ s32 BossSst_OverrideHeadDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f*
s32 timer12;
f32 shakeMod;
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7) && this->vVanish) {
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS) && this->vVanish) {
*dList = NULL;
} else if (this->actionFunc == BossSst_HeadThrash) { // Animation modifications for death cutscene
shakeAmp = (this->timer / 10) + 1;
@ -2868,7 +2868,7 @@ void BossSst_DrawHead(Actor* thisx, PlayState* play) {
OPEN_DISPS(play->state.gfxCtx, "../z_boss_sst.c", 6810);
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gDPSetPrimColor(POLY_OPA_DISP++, 0x00, 0x80, sBodyColor.r, sBodyColor.g, sBodyColor.b, 255);
if (!sBodyStatic) {
@ -2895,7 +2895,7 @@ void BossSst_DrawHead(Actor* thisx, PlayState* play) {
Matrix_RotateY(-randYaw, MTXMODE_APPLY);
}
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
POLY_OPA_DISP =
SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
BossSst_OverrideHeadDraw, BossSst_PostHeadDraw, this, POLY_OPA_DISP);

View file

@ -160,7 +160,7 @@ void EnBox_Init(Actor* thisx, PlayState* play2) {
this->dyna.actor.flags |= ACTOR_FLAG_4;
} else {
if (this->type == ENBOX_TYPE_4 || this->type == ENBOX_TYPE_6) {
this->dyna.actor.flags |= ACTOR_FLAG_7;
this->dyna.actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
}
EnBox_SetupAction(this, EnBox_WaitOpen);
this->movementFlags |= ENBOX_MOVE_IMMOBILE;
@ -438,7 +438,7 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) {
void EnBox_Open(EnBox* this, PlayState* play) {
u16 sfxId;
this->dyna.actor.flags &= ~ACTOR_FLAG_7;
this->dyna.actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
if (SkelAnime_Update(&this->skelanime)) {
if (this->unk_1F4 > 0) {
@ -621,11 +621,11 @@ void EnBox_Draw(Actor* thisx, PlayState* play) {
OPEN_DISPS(play->state.gfxCtx, "../z_en_box.c", 1581);
/*
this->dyna.actor.flags & ACTOR_FLAG_7 is set by Init (if type is 4 or 6)
this->dyna.actor.flags & ACTOR_FLAG_REACT_TO_LENS is set by Init (if type is 4 or 6)
and cleared by Open
*/
if ((this->alpha == 255 && !(this->type == ENBOX_TYPE_4 || this->type == ENBOX_TYPE_6)) ||
(!CHECK_FLAG_ALL(this->dyna.actor.flags, ACTOR_FLAG_7) &&
(!CHECK_FLAG_ALL(this->dyna.actor.flags, ACTOR_FLAG_REACT_TO_LENS) &&
(this->type == ENBOX_TYPE_4 || this->type == ENBOX_TYPE_6))) {
gDPPipeSync(POLY_OPA_DISP++);
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);

View file

@ -191,7 +191,7 @@ void EnDh_SetupWait(EnDh* this) {
this->actor.shape.yOffset = -15000.0f;
this->dirtWaveSpread = this->actor.speed = 0.0f;
this->actor.world.rot.y = this->actor.shape.rot.y;
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
this->dirtWavePhase = this->actionState = this->actor.params = ENDH_WAIT_UNDERGROUND;
EnDh_SetupAction(this, EnDh_Wait);
}
@ -208,7 +208,7 @@ void EnDh_Wait(EnDh* this, PlayState* play) {
case 0:
this->actor.flags |= ACTOR_FLAG_0;
this->actor.shape.rot.y = this->actor.yawTowardsPlayer;
this->actor.flags &= ~ACTOR_FLAG_7;
this->actor.flags &= ~ACTOR_FLAG_REACT_TO_LENS;
this->actionState++;
this->drawDirtWave++;
Actor_PlaySfx(&this->actor, NA_SE_EN_DEADHAND_HIDE);

View file

@ -147,7 +147,7 @@ void EnFirefly_Init(Actor* thisx, PlayState* play) {
CollisionCheck_SetInfo(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit);
if ((this->actor.params & 0x8000) != 0) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
if (1) {}
this->actor.draw = EnFirefly_DrawInvisible;
this->actor.params &= 0x7FFF;

View file

@ -138,7 +138,7 @@ void EnFloormas_Init(Actor* thisx, PlayState* play2) {
// s16 cast needed
this->actor.params &= (s16) ~(SPAWN_INVISIBLE);
if (invisble) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
this->actor.draw = EnFloormas_DrawHighlighted;
}
@ -280,7 +280,7 @@ void EnFloormas_SetupLand(EnFloormas* this) {
void EnFloormas_SetupSplit(EnFloormas* this) {
Actor_SetScale(&this->actor, 0.004f);
this->actor.flags |= ACTOR_FLAG_4;
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
this->actor.draw = EnFloormas_DrawHighlighted;
} else {
this->actor.draw = EnFloormas_Draw;

View file

@ -18,7 +18,8 @@ typedef enum {
/* 0 */ HONOTRAP_EYE_OPEN,
/* 1 */ HONOTRAP_EYE_HALF,
/* 2 */ HONOTRAP_EYE_CLOSE,
/* 3 */ HONOTRAP_EYE_SHUT
/* 3 */ HONOTRAP_EYE_SHUT,
/* 4 */ HONOTRAP_EYE_MAX
} EnHonotrapEyeState;
void EnHonotrap_Init(Actor* thisx, PlayState* play);
@ -35,8 +36,8 @@ void EnHonotrap_EyeAttack(EnHonotrap* this, PlayState* play);
void EnHonotrap_SetupEyeClose(EnHonotrap* this);
void EnHonotrap_EyeClose(EnHonotrap* this, PlayState* play);
void EnHonotrap_SetupFlame(EnHonotrap* this);
void EnHonotrap_Flame(EnHonotrap* this, PlayState* play);
void EnHonotrap_SetupFlameGrow(EnHonotrap* this);
void EnHonotrap_FlameGrow(EnHonotrap* this, PlayState* play);
void EnHonotrap_SetupFlameDrop(EnHonotrap* this);
void EnHonotrap_FlameDrop(EnHonotrap* this, PlayState* play);
@ -138,17 +139,17 @@ void EnHonotrap_FlameCollisionCheck(EnHonotrap* this, PlayState* play) {
}
void EnHonotrap_GetNormal(Vec3f* normal, Vec3f* vec) {
f32 mag = Math3D_Vec3fMagnitude(vec);
f32 magnitude = Math3D_Vec3fMagnitude(vec);
if (mag < 0.001f) {
if (magnitude < 0.001f) {
PRINTF("Warning : vector size zero (%s %d)\n", "../z_en_honotrap.c", 328, normal);
normal->x = normal->y = 0.0f;
normal->z = 1.0f;
} else {
normal->x = vec->x * (1.0f / mag);
normal->y = vec->y * (1.0f / mag);
normal->z = vec->z * (1.0f / mag);
normal->x = vec->x * (1.0f / magnitude);
normal->y = vec->y * (1.0f / magnitude);
normal->z = vec->z * (1.0f / magnitude);
}
}
@ -198,9 +199,9 @@ void EnHonotrap_InitFlame(Actor* thisx, PlayState* play) {
this->targetPos = GET_PLAYER(play)->actor.world.pos;
this->targetPos.y += 10.0f;
this->flameScroll = Rand_ZeroOne() * 511.0f;
EnHonotrap_SetupFlame(this);
EnHonotrap_SetupFlameGrow(this);
Actor_PlaySfx(&this->actor, NA_SE_EV_FLAME_IGNITION);
if (this->actor.params == HONOTRAP_FLAME_DROP) {
if (this->actor.params == HONOTRAP_TYPE_FLAME_DROP) {
this->actor.room = -1;
this->collider.cyl.dim.radius = 12;
this->collider.cyl.dim.height = 30;
@ -210,7 +211,7 @@ void EnHonotrap_InitFlame(Actor* thisx, PlayState* play) {
void EnHonotrap_Init(Actor* thisx, PlayState* play) {
Actor_ProcessInitChain(thisx, sInitChain);
if (thisx->params == HONOTRAP_EYE) {
if (thisx->params == HONOTRAP_TYPE_EYE) {
EnHonotrap_InitEye(thisx, play);
} else {
EnHonotrap_InitFlame(thisx, play);
@ -221,7 +222,7 @@ void EnHonotrap_Destroy(Actor* thisx, PlayState* play) {
s32 pad;
EnHonotrap* this = (EnHonotrap*)thisx;
if (this->actor.params == HONOTRAP_EYE) {
if (this->actor.params == HONOTRAP_TYPE_EYE) {
Collider_DestroyTris(play, &this->collider.tris);
} else {
Collider_DestroyCylinder(play, &this->collider.cyl);
@ -236,11 +237,14 @@ void EnHonotrap_SetupEyeIdle(EnHonotrap* this) {
void EnHonotrap_EyeIdle(EnHonotrap* this, PlayState* play) {
if (this->actor.child != NULL) {
this->timer = 200;
} else if ((this->timer <= 0) && (this->actor.xzDistToPlayer < 750.0f) && (0.0f > this->actor.yDistToPlayer) &&
(this->actor.yDistToPlayer > -700.0f) &&
(-0x4000 < (this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) &&
((this->actor.yawTowardsPlayer - this->actor.shape.rot.y) < 0x4000)) {
EnHonotrap_SetupEyeOpen(this);
} else if ((this->timer <= 0) && (this->actor.xzDistToPlayer < 750.0f)) {
if ((this->actor.yDistToPlayer < 0.0f) && (this->actor.yDistToPlayer > -700.0f)) {
s32 angle = this->actor.yawTowardsPlayer - this->actor.shape.rot.y;
if ((angle > -0x4000) && (angle < 0x4000)) {
EnHonotrap_SetupEyeOpen(this);
}
}
}
}
@ -252,18 +256,14 @@ void EnHonotrap_SetupEyeOpen(EnHonotrap* this) {
}
void EnHonotrap_EyeOpen(EnHonotrap* this, PlayState* play) {
f32 cos;
f32 sin;
this->eyeState--;
if (this->eyeState <= HONOTRAP_EYE_OPEN) {
EnHonotrap_SetupEyeAttack(this);
sin = Math_SinS(this->actor.shape.rot.y);
cos = Math_CosS(this->actor.shape.rot.y);
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_HONOTRAP,
(sin * 12.0f) + this->actor.home.pos.x, this->actor.home.pos.y - 10.0f,
(cos * 12.0f) + this->actor.home.pos.z, this->actor.home.rot.x, this->actor.home.rot.y,
this->actor.home.rot.z, HONOTRAP_FLAME_MOVE);
Actor_SpawnAsChild(
&play->actorCtx, &this->actor, play, ACTOR_EN_HONOTRAP,
(Math_SinS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.x, this->actor.home.pos.y - 10.0f,
(Math_CosS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.z, this->actor.home.rot.x,
this->actor.home.rot.y, this->actor.home.rot.z, HONOTRAP_TYPE_FLAME_MOVE);
}
}
@ -290,20 +290,19 @@ void EnHonotrap_EyeClose(EnHonotrap* this, PlayState* play) {
}
}
void EnHonotrap_SetupFlame(EnHonotrap* this) {
this->actionFunc = EnHonotrap_Flame;
void EnHonotrap_SetupFlameGrow(EnHonotrap* this) {
this->actionFunc = EnHonotrap_FlameGrow;
}
void EnHonotrap_Flame(EnHonotrap* this, PlayState* play) {
s32 pad;
s32 ready =
Math_StepToF(&this->actor.scale.x, (this->actor.params == HONOTRAP_FLAME_MOVE) ? 0.004f : 0.0048f, 0.0006f);
void EnHonotrap_FlameGrow(EnHonotrap* this, PlayState* play) {
f32 targetScale = (this->actor.params == HONOTRAP_TYPE_FLAME_MOVE) ? 0.004f : 0.0048f;
s32 targetReached = Math_StepToF(&this->actor.scale.x, targetScale, 0.0006f);
this->actor.scale.z = this->actor.scale.y = this->actor.scale.x;
if (ready) {
if (this->actor.params == HONOTRAP_FLAME_MOVE) {
if (targetReached) {
if (this->actor.params == HONOTRAP_TYPE_FLAME_MOVE) {
EnHonotrap_SetupFlameMove(this);
} else {
} else { // HONOTRAP_TYPE_FLAME_DROP
EnHonotrap_SetupFlameDrop(this);
}
}
@ -324,49 +323,46 @@ void EnHonotrap_FlameDrop(EnHonotrap* this, PlayState* play) {
}
this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = 0.0f;
EnHonotrap_SetupFlameVanish(this);
} else {
if (this->actor.velocity.y > 0.0f) {
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Actor_UpdateBgCheckInfo(play, &this->actor, 7.0f, 12.0f, 0.0f,
UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2);
}
if (!Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 1.0f, this->actor.velocity.y)) {
this->actor.velocity.y += 1.0f;
} else {
this->actor.velocity.y = 0.0f;
}
EnHonotrap_FlameCollisionCheck(this, play);
return;
}
if (this->actor.velocity.y > 0.0f) {
this->actor.world.pos.x += this->actor.velocity.x;
this->actor.world.pos.z += this->actor.velocity.z;
Actor_UpdateBgCheckInfo(play, &this->actor, 7.0f, 12.0f, 0.0f, UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2);
}
if (!Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 1.0f, this->actor.velocity.y)) {
this->actor.velocity.y += 1.0f;
} else {
this->actor.velocity.y = 0.0f;
}
EnHonotrap_FlameCollisionCheck(this, play);
}
void EnHonotrap_SetupFlameMove(EnHonotrap* this) {
f32 distFrac;
f32 distInverse;
this->actionFunc = EnHonotrap_FlameMove;
distFrac = 1.0f / (Actor_WorldDistXYZToPoint(&this->actor, &this->targetPos) + 1.0f);
this->actor.velocity.x = (this->targetPos.x - this->actor.world.pos.x) * distFrac;
this->actor.velocity.y = (this->targetPos.y - this->actor.world.pos.y) * distFrac;
this->actor.velocity.z = (this->targetPos.z - this->actor.world.pos.z) * distFrac;
distInverse = 1.0f / (Actor_WorldDistXYZToPoint(&this->actor, &this->targetPos) + 1.0f);
this->actor.velocity.x = (this->targetPos.x - this->actor.world.pos.x) * distInverse;
this->actor.velocity.y = (this->targetPos.y - this->actor.world.pos.y) * distInverse;
this->actor.velocity.z = (this->targetPos.z - this->actor.world.pos.z) * distInverse;
this->speedMod = 0.0f;
this->timer = 160;
}
void EnHonotrap_FlameMove(EnHonotrap* this, PlayState* play) {
s32 pad;
Actor* thisx = &this->actor;
Vec3f speed;
s32 ready;
s32 targetReached;
Math_StepToF(&this->speedMod, 13.0f, 0.5f);
speed.x = fabsf(this->speedMod * this->actor.velocity.x);
speed.y = fabsf(this->speedMod * this->actor.velocity.y);
speed.z = fabsf(this->speedMod * this->actor.velocity.z);
ready = true;
ready &= Math_StepToF(&this->actor.world.pos.x, this->targetPos.x, speed.x);
ready &= Math_StepToF(&this->actor.world.pos.y, this->targetPos.y, speed.y);
ready &= Math_StepToF(&this->actor.world.pos.z, this->targetPos.z, speed.z);
speed.x = fabsf(this->speedMod * thisx->velocity.x);
speed.y = fabsf(this->speedMod * thisx->velocity.y);
speed.z = fabsf(this->speedMod * thisx->velocity.z);
targetReached = true;
targetReached &= Math_StepToF(&thisx->world.pos.x, this->targetPos.x, speed.x);
targetReached &= Math_StepToF(&thisx->world.pos.y, this->targetPos.y, speed.y);
targetReached &= Math_StepToF(&thisx->world.pos.z, this->targetPos.z, speed.z);
Actor_UpdateBgCheckInfo(play, &this->actor, 7.0f, 10.0f, 0.0f,
UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_3 |
UPDBGCHECKINFO_FLAG_4);
@ -382,19 +378,20 @@ void EnHonotrap_FlameMove(EnHonotrap* this, PlayState* play) {
shieldVec.z = -player->shieldMf.zz;
EnHonotrap_GetNormal(&shieldNorm, &shieldVec);
tempVel = this->actor.velocity;
Math3D_Vec3fReflect(&tempVel, &shieldNorm, &this->actor.velocity);
this->actor.speed = this->speedMod * 0.5f;
this->actor.world.rot.y = Math_Atan2S(this->actor.velocity.z, this->actor.velocity.x);
tempVel = thisx->velocity;
Math3D_Vec3fReflect(&tempVel, &shieldNorm, &thisx->velocity);
thisx->speed = this->speedMod * 0.5f;
thisx->world.rot.y = Math_Atan2S(thisx->velocity.z, thisx->velocity.x);
EnHonotrap_SetupFlameVanish(this);
} else if (this->collider.tris.base.atFlags & AT_HIT) {
this->actor.velocity.y = this->actor.speed = 0.0f;
thisx->speed = 0.0f;
thisx->velocity.y = 0.0f;
EnHonotrap_SetupFlameVanish(this);
} else if (this->timer <= 0) {
EnHonotrap_SetupFlameVanish(this);
} else {
EnHonotrap_FlameCollisionCheck(this, play);
if (ready) {
if (targetReached) {
EnHonotrap_SetupFlameChase(this);
}
}
@ -402,10 +399,9 @@ void EnHonotrap_FlameMove(EnHonotrap* this, PlayState* play) {
void EnHonotrap_SetupFlameChase(EnHonotrap* this) {
this->actionFunc = EnHonotrap_FlameChase;
this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = this->actor.speed = 0.0f;
this->actor.speed = 0.0f;
this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = 0.0f;
this->actor.world.rot.x = this->actor.world.rot.y = this->actor.world.rot.z = 0;
this->timer = 100;
}
@ -448,28 +444,27 @@ void EnHonotrap_SetupFlameVanish(EnHonotrap* this) {
void EnHonotrap_FlameVanish(EnHonotrap* this, PlayState* play) {
s32 pad;
s32 ready = Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f);
s32 targetReached = Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f);
this->actor.scale.z = this->actor.scale.y = this->actor.scale.x;
Actor_MoveXZGravity(&this->actor);
Actor_UpdateBgCheckInfo(play, &this->actor, 7.0f, 10.0f, 0.0f,
UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_3 |
UPDBGCHECKINFO_FLAG_4);
if (ready) {
if (targetReached) {
Actor_Kill(&this->actor);
}
}
void EnHonotrap_Update(Actor* thisx, PlayState* play) {
static Vec3f velocity = { 0.0f, 0.0f, 0.0f };
static Vec3f accel = { 0.0f, 0.1f, 0.0f };
s32 pad;
static Vec3f sVelocity = { 0.0f, 0.0f, 0.0f };
static Vec3f sAccel = { 0.0f, 0.1f, 0.0f };
EnHonotrap* this = (EnHonotrap*)thisx;
if (this->timer > 0) {
this->timer--;
}
if (this->actor.params == HONOTRAP_EYE) {
if (this->actor.params == HONOTRAP_TYPE_EYE) {
if ((this->actor.child != NULL) && (this->actor.child->update == NULL)) {
this->actor.child = NULL;
}
@ -481,9 +476,9 @@ void EnHonotrap_Update(Actor* thisx, PlayState* play) {
Actor_PlaySfx(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG);
}
this->actionFunc(this, play);
if (this->actor.params == HONOTRAP_EYE) {
if (this->actor.params == HONOTRAP_TYPE_EYE) {
if (this->collider.tris.base.acFlags & AC_HIT) {
EffectSsBomb2_SpawnLayered(play, &this->actor.world.pos, &velocity, &accel, 15, 8);
EffectSsBomb2_SpawnLayered(play, &this->actor.world.pos, &sVelocity, &sAccel, 15, 8);
Actor_Kill(&this->actor);
} else if (this->eyeState < HONOTRAP_EYE_SHUT) {
this->collider.tris.base.acFlags &= ~AC_HIT;
@ -493,7 +488,7 @@ void EnHonotrap_Update(Actor* thisx, PlayState* play) {
}
void EnHonotrap_DrawEye(Actor* thisx, PlayState* play) {
static void* eyeTextures[] = {
static void* sSilverEyeTextures[HONOTRAP_EYE_MAX] = {
gEyeSwitchSilverOpenTex,
gEyeSwitchSilverHalfTex,
gEyeSwitchSilverClosedTex,
@ -504,7 +499,7 @@ void EnHonotrap_DrawEye(Actor* thisx, PlayState* play) {
OPEN_DISPS(play->state.gfxCtx, "../z_en_honotrap.c", 982);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(eyeTextures[this->eyeState]));
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sSilverEyeTextures[this->eyeState]));
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEW(play->state.gfxCtx, "../z_en_honotrap.c", 987),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gEyeSwitch2DL);
@ -520,10 +515,9 @@ void EnHonotrap_DrawFlame(Actor* thisx, PlayState* play) {
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
this->flameScroll -= 20;
this->flameScroll &= 0x1FF;
gSPSegment(
POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(play->state.gfxCtx, G_TX_RENDERTILE, 0, 0, 0x20, 0x40, 1, 0, this->flameScroll, 0x20, 0x80));
this->flameScroll %= (128U << 2);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(play->state.gfxCtx, G_TX_RENDERTILE, 0, 0, 32, 64, 1, 0, this->flameScroll, 32, 128));
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 200, 0, 255);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0);
Matrix_RotateY(BINANG_TO_RAD((s16)(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play)) - this->actor.shape.rot.y + 0x8000)),
@ -537,11 +531,12 @@ void EnHonotrap_DrawFlame(Actor* thisx, PlayState* play) {
void EnHonotrap_Draw(Actor* thisx, PlayState* play) {
switch (thisx->params) {
case HONOTRAP_EYE:
case HONOTRAP_TYPE_EYE:
EnHonotrap_DrawEye(thisx, play);
break;
case HONOTRAP_FLAME_MOVE:
case HONOTRAP_FLAME_DROP:
case HONOTRAP_TYPE_FLAME_MOVE:
case HONOTRAP_TYPE_FLAME_DROP:
EnHonotrap_DrawFlame(thisx, play);
break;
}

View file

@ -10,10 +10,10 @@ typedef void (*EnHonotrapActionFunc)(struct EnHonotrap*, PlayState*);
typedef union {
struct {
ColliderTris tris;
ColliderTrisElement elements[2];
/* 0x00 */ ColliderTris tris;
/* 0x20 */ ColliderTrisElement elements[2];
};
ColliderCylinder cyl;
/* 0x00 */ ColliderCylinder cyl;
} EnHonotrapCollider; // size = 0xD8
typedef struct EnHonotrap {
@ -30,9 +30,9 @@ typedef struct EnHonotrap {
} EnHonotrap; // size = 0x0244
typedef enum {
HONOTRAP_EYE,
HONOTRAP_FLAME_MOVE,
HONOTRAP_FLAME_DROP
HONOTRAP_TYPE_EYE,
HONOTRAP_TYPE_FLAME_MOVE,
HONOTRAP_TYPE_FLAME_DROP
} EnHonotrapType;
#endif

View file

@ -7,7 +7,7 @@
#include "z_en_po_desert.h"
#include "assets/objects/object_po_field/object_po_field.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_7 | ACTOR_FLAG_IGNORE_QUAKE)
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_REACT_TO_LENS | ACTOR_FLAG_IGNORE_QUAKE)
void EnPoDesert_Init(Actor* thisx, PlayState* play);
void EnPoDesert_Destroy(Actor* thisx, PlayState* play);
@ -197,11 +197,11 @@ void EnPoDesert_Update(Actor* thisx, PlayState* play) {
Collider_UpdateCylinder(&this->actor, &this->collider);
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
if (play->actorCtx.lensActive) {
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_REACT_TO_LENS;
this->actor.shape.shadowDraw = ActorShadow_DrawCircle;
} else {
this->actor.shape.shadowDraw = NULL;
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_7);
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_REACT_TO_LENS);
}
}
@ -214,7 +214,7 @@ s32 EnPoDesert_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec
mtxScale = this->actionTimer / 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
}
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
*dList = NULL;
}
return false;
@ -234,7 +234,7 @@ void EnPoDesert_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s*
color.r = (s16)(rand * 30.0f) + 225;
color.g = (s16)(rand * 100.0f) + 155;
color.b = (s16)(rand * 160.0f) + 95;
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
gDPPipeSync((*gfxP)++);
gDPSetEnvColor((*gfxP)++, color.r, color.g, color.b, 255);
gSPMatrix((*gfxP)++, MATRIX_NEW(play->state.gfxCtx, "../z_en_po_desert.c", 523),

View file

@ -204,7 +204,7 @@ void EnPoRelay_Race(EnPoRelay* this, PlayState* play) {
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HONOTRAP,
Math_CosS(this->unk_19A) * speedXZ + this->actor.world.pos.x, this->actor.world.pos.y,
Math_SinS(this->unk_19A) * speedXZ + this->actor.world.pos.z, 0,
(this->unk_19A + 0x8000) - (0x2000 * multiplier), 0, HONOTRAP_FLAME_DROP);
(this->unk_19A + 0x8000) - (0x2000 * multiplier), 0, HONOTRAP_TYPE_FLAME_DROP);
}
}
Math_SmoothStepToS(&this->actor.world.rot.y, this->unk_19A, 2, 0x1000, 0x100);

View file

@ -181,7 +181,7 @@ void EnRd_Init(Actor* thisx, PlayState* play) {
SkelAnime_Update(&this->skelAnime);
if (this->actor.params == REDEAD_TYPE_INVISIBLE) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
}
}

View file

@ -790,7 +790,7 @@ void EnSt_Init(Actor* thisx, PlayState* play) {
this->blureIdx = EnSt_CreateBlureEffect(play);
EnSt_InitColliders(this, play);
if (thisx->params == 2) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
}
if (this->actor.params == 1) {
this->actor.naviEnemyId = NAVI_ENEMY_BIG_SKULLTULA;

View file

@ -306,7 +306,7 @@ void EnTest_Init(Actor* thisx, PlayState* play) {
}
if (this->actor.params == STALFOS_TYPE_INVISIBLE) {
this->actor.flags |= ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_REACT_TO_LENS;
}
}
@ -1810,10 +1810,10 @@ void EnTest_Update(Actor* thisx, PlayState* play) {
if (this->actor.params == STALFOS_TYPE_INVISIBLE) {
if (play->actorCtx.lensActive) {
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_7;
this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_REACT_TO_LENS;
this->actor.shape.shadowDraw = ActorShadow_DrawFeet;
} else {
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_7);
this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_REACT_TO_LENS);
this->actor.shape.shadowDraw = NULL;
}
}
@ -1836,7 +1836,8 @@ s32 EnTest_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f*
CLOSE_DISPS(play->state.gfxCtx, "../z_en_test.c", 3587);
}
if ((this->actor.params == STALFOS_TYPE_INVISIBLE) && !CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) {
if ((this->actor.params == STALFOS_TYPE_INVISIBLE) &&
!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_REACT_TO_LENS)) {
*dList = NULL;
}

View file

@ -9,7 +9,7 @@
#include "assets/objects/gameplay_keep/gameplay_keep.h"
#include "terminal.h"
#define FLAGS ACTOR_FLAG_22
#define FLAGS ACTOR_FLAG_IGNORE_POINT_LIGHTS
void ObjBean_Init(Actor* thisx, PlayState* play);
void ObjBean_Destroy(Actor* thisx, PlayState* play);

View file

@ -3,11 +3,7 @@
import argparse
from pathlib import Path
try:
import mapfile_parser
except ImportError:
print("Missing dependency mapfile_parser, install it with `python3 -m pip install 'mapfile-parser>=1.2.1,<2.0.0'`")
exit(1)
import mapfile_parser
def symInfoMain():

View file

@ -13,7 +13,7 @@ asm_dir = root_dir + "asm/non_matchings/overlays/actors"
build_dir = root_dir + "build/gc-eu-mq-dbg/"
def read_rom():
with open("baserom.z64", "rb") as f:
with open("baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", "rb") as f:
return f.read()

342
tools/compress.py Normal file
View file

@ -0,0 +1,342 @@
# SPDX-FileCopyrightText: 2024 zeldaret
# SPDX-License-Identifier: CC0-1.0
from __future__ import annotations
import argparse
from pathlib import Path
import dataclasses
import struct
import time
import multiprocessing
import multiprocessing.pool
import crunch64
STRUCT_IIII = struct.Struct(">IIII")
@dataclasses.dataclass
class DmaEntry:
"""
A Python counterpart to the dmadata entry struct:
```c
typedef struct {
/* 0x00 */ uintptr_t vromStart;
/* 0x04 */ uintptr_t vromEnd;
/* 0x08 */ uintptr_t romStart;
/* 0x0C */ uintptr_t romEnd;
} DmaEntry;
```
"""
vromStart: int
vromEnd: int
romStart: int
romEnd: int
def __repr__(self):
return (
"DmaEntry("
f"vromStart=0x{self.vromStart:08X}, "
f"vromEnd=0x{self.vromEnd:08X}, "
f"romStart=0x{self.romStart:08X}, "
f"romEnd=0x{self.romEnd:08X}"
")"
)
SIZE_BYTES = STRUCT_IIII.size
def to_bin(self, data: memoryview):
STRUCT_IIII.pack_into(
data,
0,
self.vromStart,
self.vromEnd,
self.romStart,
self.romEnd,
)
@staticmethod
def from_bin(data: memoryview):
return DmaEntry(*STRUCT_IIII.unpack_from(data))
DMA_ENTRY_ZERO = DmaEntry(0, 0, 0, 0)
def align(v: int):
v += 0xF
return v // 0x10 * 0x10
@dataclasses.dataclass
class RomSegment:
vromStart: int
vromEnd: int
is_compressed: bool
data: memoryview | None
data_async: multiprocessing.pool.AsyncResult | None
@property
def uncompressed_size(self):
return self.vromEnd - self.vromStart
# Make interrupting the compression with ^C less jank
# https://stackoverflow.com/questions/72967793/keyboardinterrupt-with-python-multiprocessing-pool
def set_sigint_ignored():
import signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
def compress_rom(
rom_data: memoryview,
dmadata_offset_start: int,
dmadata_offset_end: int,
compress_entries_indices: set[int],
n_threads: int = None,
):
"""
rom_data: the uncompressed rom data
dmadata_offset_start: the offset in the rom where the dmadata starts (inclusive)
dmadata_offset_end: the offset in the rom where the dmadata ends (exclusive)
compress_entries_indices: the indices in the dmadata of the segments that should be compressed
n_threads: how many cores to use for compression
"""
# Segments of the compressed rom (not all are compressed)
compressed_rom_segments: list[RomSegment] = []
with multiprocessing.Pool(n_threads, initializer=set_sigint_ignored) as p:
# Extract each segment from the input rom
for entry_index, dmadata_offset in enumerate(
range(dmadata_offset_start, dmadata_offset_end, DmaEntry.SIZE_BYTES)
):
dma_entry = DmaEntry.from_bin(rom_data[dmadata_offset:])
if dma_entry == DMA_ENTRY_ZERO:
continue
segment_rom_start = dma_entry.romStart
segment_rom_end = dma_entry.romStart + (
dma_entry.vromEnd - dma_entry.vromStart
)
segment_data_uncompressed = rom_data[segment_rom_start:segment_rom_end]
is_compressed = entry_index in compress_entries_indices
if is_compressed:
segment_data = None
segment_data_async = p.apply_async(
crunch64.yaz0.compress,
(bytes(segment_data_uncompressed),),
)
else:
segment_data = segment_data_uncompressed
segment_data_async = None
compressed_rom_segments.append(
RomSegment(
dma_entry.vromStart,
dma_entry.vromEnd,
is_compressed,
segment_data,
segment_data_async,
)
)
# Technically optional but required for matching.
compressed_rom_segments.sort(key=lambda segment: segment.vromStart)
# Wait on compression of all compressed segments
waiting_on_segments = [
segment for segment in compressed_rom_segments if segment.is_compressed
]
total_uncompressed_size_of_data_to_compress = sum(
segment.uncompressed_size for segment in waiting_on_segments
)
uncompressed_size_of_data_compressed_so_far = 0
while waiting_on_segments:
# Show progress
progress = (
uncompressed_size_of_data_compressed_so_far
/ total_uncompressed_size_of_data_to_compress
)
print(f"Compressing... {progress * 100:.1f}%", end="\r")
# The segments for which the compression is not finished yet are
# added to this list
still_waiting_on_segments = []
got_some_results = False
for segment in waiting_on_segments:
assert segment.data is None
assert segment.data_async is not None
try:
compressed_data = segment.data_async.get(0)
except multiprocessing.TimeoutError:
# Compression not finished yet
still_waiting_on_segments.append(segment)
else:
# Compression finished!
assert isinstance(compressed_data, bytes)
segment.data = memoryview(compressed_data)
uncompressed_size_of_data_compressed_so_far += (
segment.uncompressed_size
)
got_some_results = True
segment.data_async = None
if not got_some_results and still_waiting_on_segments:
# Nothing happened this wait iteration, idle a bit
time.sleep(0.010)
waiting_on_segments = still_waiting_on_segments
print("Putting together the compressed rom...")
# Put together the compressed rom
compressed_rom_size = sum(
align(len(segment.data)) for segment in compressed_rom_segments
)
pad_to_multiple_of = 8 * 2**20 # 8 MiB
compressed_rom_size_padded = (
(compressed_rom_size + pad_to_multiple_of - 1)
// pad_to_multiple_of
* pad_to_multiple_of
)
compressed_rom_data = memoryview(bytearray(compressed_rom_size_padded))
compressed_rom_dma_entries: list[DmaEntry] = []
rom_offset = 0
for segment in compressed_rom_segments:
assert segment.data is not None
segment_rom_start = rom_offset
segment_rom_end = align(segment_rom_start + len(segment.data))
i = segment_rom_start + len(segment.data)
assert i <= len(compressed_rom_data)
compressed_rom_data[segment_rom_start:i] = segment.data
compressed_rom_dma_entries.append(
DmaEntry(
segment.vromStart,
segment.vromEnd,
segment_rom_start,
segment_rom_end if segment.is_compressed else 0,
)
)
rom_offset = segment_rom_end
assert rom_offset == compressed_rom_size
# Pad the compressed rom with the pattern matching the baseroms
for i in range(compressed_rom_size, compressed_rom_size_padded):
compressed_rom_data[i] = i % 256
# Write the new dmadata
dmadata_offset = dmadata_offset_start
for dma_entry in compressed_rom_dma_entries:
assert dmadata_offset + DmaEntry.SIZE_BYTES <= dmadata_offset_end
dma_entry.to_bin(compressed_rom_data[dmadata_offset:])
dmadata_offset += DmaEntry.SIZE_BYTES
return compressed_rom_data
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--in",
dest="in_rom",
required=True,
help="path to an uncompressed rom to be compressed",
)
parser.add_argument(
"--out",
dest="out_rom",
required=True,
help="path of the compressed rom to write out",
)
parser.add_argument(
"--dma-range",
dest="dma_range",
required=True,
help=(
"The dmadata location in the rom, in format"
" 'start_inclusive-end_exclusive' and using hexadecimal offsets"
" (e.g. '0x12f70-0x19030')."
),
)
parser.add_argument(
"--compress",
dest="compress_ranges",
required=True,
help=(
"The indices in the dmadata of the entries to be compressed,"
" where 0 is the first entry."
" It is a comma-separated list of individual indices and inclusive ranges."
" e.g. '0-1,3,5,6-9' is all indices from 0 to 9 (included) except 2 and 4."
),
)
parser.add_argument(
"--threads",
dest="n_threads",
type=int,
default=1,
help="how many cores to use for parallel compression",
)
args = parser.parse_args()
in_rom_p = Path(args.in_rom)
if not in_rom_p.exists():
parser.error(f"Input rom file {in_rom_p} doesn't exist.")
out_rom_p = Path(args.out_rom)
dma_range_str: str = args.dma_range
dma_range_ends_str = dma_range_str.split("-")
assert len(dma_range_ends_str) == 2, dma_range_str
dmadata_offset_start, dmadata_offset_end = (
int(v_str, 16) for v_str in dma_range_ends_str
)
assert dmadata_offset_start < dmadata_offset_end, dma_range_str
compress_ranges_str: str = args.compress_ranges
compress_entries_indices = set()
for compress_range_str in compress_ranges_str.split(","):
compress_range_ends_str = compress_range_str.split("-")
assert len(compress_range_ends_str) <= 2, (
compress_range_ends_str,
compress_range_str,
compress_ranges_str,
)
compress_range_ends = [int(v_str) for v_str in compress_range_ends_str]
if len(compress_range_ends) == 1:
compress_entries_indices.add(compress_range_ends[0])
else:
assert len(compress_range_ends) == 2
compress_range_first, compress_range_last = compress_range_ends
compress_entries_indices.update(
range(compress_range_first, compress_range_last + 1)
)
n_threads = args.n_threads
in_rom_data = in_rom_p.read_bytes()
out_rom_data = compress_rom(
memoryview(in_rom_data),
dmadata_offset_start,
dmadata_offset_end,
compress_entries_indices,
n_threads,
)
out_rom_p.write_bytes(out_rom_data)
if __name__ == "__main__":
main()

View file

@ -496,7 +496,7 @@ def main():
script_dir = os.path.dirname(os.path.realpath(__file__))
cs_data = None
with open(script_dir + "/../baserom/" + file_result.name, "rb") as ovl_file:
with open(script_dir + "/../baseroms/gc-eu-mq-dbg/segments/" + file_result.name, "rb") as ovl_file:
ovl_file.seek(file_result.offset)
cs_data = [i[0] for i in struct.iter_unpack(">I", bytearray(ovl_file.read()))]
if cs_data is not None:

273
tools/decompress_baserom.py Executable file
View file

@ -0,0 +1,273 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: © 2024 ZeldaRET
# SPDX-License-Identifier: CC0-1.0
from __future__ import annotations
import hashlib
import io
import struct
from pathlib import Path
import argparse
import crunch64
import ipl3checksum
import zlib
def decompress_zlib(data: bytes) -> bytes:
decomp = zlib.decompressobj(-zlib.MAX_WBITS)
output = bytearray()
output.extend(decomp.decompress(data))
while decomp.unconsumed_tail:
output.extend(decomp.decompress(decomp.unconsumed_tail))
output.extend(decomp.flush())
return bytes(output)
def decompress(data: bytes, is_zlib_compressed: bool) -> bytes:
if is_zlib_compressed:
return decompress_zlib(data)
return crunch64.yaz0.decompress(data)
FILE_TABLE_OFFSET = {
"gc-eu-mq-dbg": 0x12F70,
}
VERSIONS_MD5S = {
"gc-eu-mq-dbg": "f0b7f35375f9cc8ca1b2d59d78e35405",
}
def round_up(n, shift):
mod = 1 << shift
return (n + mod - 1) >> shift << shift
def as_word_list(b) -> list[int]:
return [i[0] for i in struct.iter_unpack(">I", b)]
def read_dmadata_entry(file_content: bytearray, addr: int) -> list[int]:
return as_word_list(file_content[addr : addr + 0x10])
def read_dmadata(file_content: bytearray, start) -> list[list[int]]:
dmadata = []
addr = start
entry = read_dmadata_entry(file_content, addr)
i = 0
while any([e != 0 for e in entry]):
dmadata.append(entry)
addr += 0x10
i += 1
entry = read_dmadata_entry(file_content, addr)
return dmadata
def update_crc(decompressed: io.BytesIO) -> io.BytesIO:
print("Recalculating crc...")
calculated_checksum = ipl3checksum.CICKind.CIC_X105.calculateChecksum(
bytes(decompressed.getbuffer())
)
new_crc = struct.pack(f">II", calculated_checksum[0], calculated_checksum[1])
decompressed.seek(0x10)
decompressed.write(new_crc)
return decompressed
def decompress_rom(
file_content: bytearray, dmadata_addr: int, dmadata: list[list[int]], version: str
) -> bytearray:
rom_segments = {} # vrom start : data s.t. len(data) == vrom_end - vrom_start
new_dmadata = bytearray() # new dmadata: {vrom start , vrom end , vrom start , 0}
decompressed = io.BytesIO(b"")
for v_start, v_end, p_start, p_end in dmadata:
if p_start == 0xFFFFFFFF and p_end == 0xFFFFFFFF:
new_dmadata.extend(struct.pack(">IIII", v_start, v_end, p_start, p_end))
continue
if p_end == 0: # uncompressed
rom_segments.update(
{v_start: file_content[p_start : p_start + v_end - v_start]}
)
else: # compressed
rom_segments.update(
{
v_start: decompress(
file_content[p_start:p_end], version in {"ique-cn", "ique-zh"}
)
}
)
new_dmadata.extend(struct.pack(">IIII", v_start, v_end, v_start, 0))
# write rom segments to vaddrs
for vrom_st, data in rom_segments.items():
decompressed.seek(vrom_st)
decompressed.write(data)
# write new dmadata
decompressed.seek(dmadata_addr)
decompressed.write(new_dmadata)
# pad to size
padding_end = round_up(dmadata[-1][1], 14)
decompressed.seek(padding_end - 1)
decompressed.write(bytearray([0]))
# re-calculate crc
return bytearray(update_crc(decompressed).getbuffer())
def get_str_hash(byte_array):
return str(hashlib.md5(byte_array).hexdigest())
def check_existing_rom(rom_path: Path, correct_str_hash: str):
# If the baserom exists and is correct, we don't need to change anything
if rom_path.exists():
if get_str_hash(rom_path.read_bytes()) == correct_str_hash:
return True
return False
def word_swap(file_content: bytearray) -> bytearray:
words = str(int(len(file_content) / 4))
little_byte_format = "<" + words + "I"
big_byte_format = ">" + words + "I"
tmp = struct.unpack_from(little_byte_format, file_content, 0)
struct.pack_into(big_byte_format, file_content, 0, *tmp)
return file_content
def byte_swap(file_content: bytearray) -> bytearray:
halfwords = str(int(len(file_content) / 2))
little_byte_format = "<" + halfwords + "H"
big_byte_format = ">" + halfwords + "H"
tmp = struct.unpack_from(little_byte_format, file_content, 0)
struct.pack_into(big_byte_format, file_content, 0, *tmp)
return file_content
def per_version_fixes(file_content: bytearray, version: str) -> bytearray:
if version == "gc-eu-mq-dbg":
# Strip the overdump
print("Stripping overdump...")
file_content = file_content[0:0x3600000]
# Patch the header
print("Patching header...")
file_content[0x3E] = 0x50
return file_content
def pad_rom(file_content: bytearray, dmadata: list[list[int]]) -> bytearray:
padding_start = round_up(dmadata[-1][1], 12)
padding_end = round_up(dmadata[-1][1], 14)
print(f"Padding from {padding_start:X} to {padding_end:X}...")
for i in range(padding_start, padding_end):
file_content[i] = 0xFF
return file_content
# Determine if we have a ROM file
ROM_FILE_EXTENSIONS = ["z64", "n64", "v64"]
def find_baserom(version: str) -> Path | None:
for rom_file_ext_lower in ROM_FILE_EXTENSIONS:
for rom_file_ext in (rom_file_ext_lower, rom_file_ext_lower.upper()):
rom_file_name_candidate = Path(f"baseroms/{version}/baserom.{rom_file_ext}")
if rom_file_name_candidate.exists():
return rom_file_name_candidate
return None
def main():
description = "Convert a rom that uses dmadata to an uncompressed one."
parser = argparse.ArgumentParser(description=description)
parser.add_argument("version", help="Version of the game to decompress.", choices=list(VERSIONS_MD5S.keys()))
args = parser.parse_args()
version = args.version
uncompressed_path = Path(f"baseroms/{version}/baserom-decompressed.z64")
file_table_offset = FILE_TABLE_OFFSET[version]
correct_str_hash = VERSIONS_MD5S[version]
if check_existing_rom(uncompressed_path, correct_str_hash):
print("Found valid baserom - exiting early")
return
rom_file_name = find_baserom(version)
if rom_file_name is None:
path_list = [
f"baseroms/{version}/baserom.{rom_file_ext}" for rom_file_ext in ROM_FILE_EXTENSIONS
]
print(f"Error: Could not find {','.join(path_list)}.")
exit(1)
# Read in the original ROM
print(f"File '{rom_file_name}' found.")
file_content = bytearray(rom_file_name.read_bytes())
# Check if ROM needs to be byte/word swapped
# Little-endian
if file_content[0] == 0x40:
# Word Swap ROM
print("ROM needs to be word swapped...")
file_content = word_swap(file_content)
print("Word swapping done.")
# Byte-swapped
elif file_content[0] == 0x37:
# Byte Swap ROM
print("ROM needs to be byte swapped...")
file_content = byte_swap(file_content)
print("Byte swapping done.")
file_content = per_version_fixes(file_content, version)
dmadata = read_dmadata(file_content, file_table_offset)
# Decompress
if any(
[
b != 0
for b in file_content[
file_table_offset + 0xAC : file_table_offset + 0xAC + 0x4
]
]
):
print("Decompressing rom...")
file_content = decompress_rom(file_content, file_table_offset, dmadata, version)
file_content = pad_rom(file_content, dmadata)
# Check to see if the ROM is a "vanilla" ROM
str_hash = get_str_hash(file_content)
if str_hash != correct_str_hash:
print(
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 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."
)
exit(1)
# Write out our new ROM
print(f"Writing new ROM {uncompressed_path}.")
uncompressed_path.write_bytes(file_content)
print("Done!")
if __name__ == "__main__":
main()

View file

@ -166,7 +166,7 @@ item_ids = {
def disas_elfmsgs(start):
baserom = None
with open("baserom.z64", "rb") as infile:
with open("baseroms/gc-eu-mq-dbg/baserom-decompressed.z64", "rb") as infile:
baserom = bytearray(infile.read())
branches = []

16
tools/dmadata_range.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/sh
NM=$1
ELF=$2
# dmadata_syms contents look like:
# ffffffff80015850 T _dmadataSegmentTextStart
# 00000000 A _dmadataSegmentTextSize
# 00011a40 A _dmadataSegmentRomStart
# ffffffff8001b920 T _dmadataSegmentRoDataEnd
dmadata_syms=`$NM $ELF --no-sort --radix=x --format=bsd | grep dmadata`
_dmadataSegmentRomStart=`echo "$dmadata_syms" | grep '\b_dmadataSegmentRomStart\b' | cut -d' ' -f1`
_dmadataSegmentRomEnd=` echo "$dmadata_syms" | grep '\b_dmadataSegmentRomEnd\b' | cut -d' ' -f1`
echo 0x"$_dmadataSegmentRomStart"-0x"$_dmadataSegmentRomEnd"

View file

@ -20,22 +20,53 @@ static void write_dmadata_table(FILE *fout)
fprintf(fout, "DEFINE_DMA_ENTRY(%s, \"%s\")\n", g_segments[i].name, g_segments[i].name);
}
static void write_compress_ranges(FILE *fout)
{
int i;
bool continue_list = false;
int stride_first = -1;
for (i = 0; i < g_segmentsCount; i++) {
if (g_segments[i].compress) {
if (stride_first == -1)
stride_first = i;
}
if (!g_segments[i].compress || i == g_segmentsCount - 1) {
if (stride_first != -1) {
int stride_last = i - 1;
if (continue_list) {
fprintf(fout, ",");
}
if (stride_first == stride_last) {
fprintf(fout, "%d", stride_first);
} else {
fprintf(fout, "%d-%d", stride_first, stride_last);
}
continue_list = true;
stride_first = -1;
}
}
}
}
static void usage(const char *execname)
{
fprintf(stderr, "zelda64 dmadata generation tool v0.01\n"
"usage: %s SPEC_FILE DMADATA_TABLE\n"
"usage: %s SPEC_FILE DMADATA_TABLE COMPRESS_RANGES\n"
"SPEC_FILE file describing the organization of object files into segments\n"
"DMADATA_TABLE filename of output dmadata table header\n",
"DMADATA_TABLE filename of output dmadata table header\n"
"COMPRESS_RANGES filename to write which files are compressed (e.g. 0-5,7,10-20)\n",
execname);
}
int main(int argc, char **argv)
{
FILE *dmaout;
FILE *compress_ranges_out;
void *spec;
size_t size;
if (argc != 3)
if (argc != 4)
{
usage(argv[0]);
return 1;
@ -49,6 +80,13 @@ int main(int argc, char **argv)
util_fatal_error("failed to open file '%s' for writing", argv[2]);
write_dmadata_table(dmaout);
fclose(dmaout);
compress_ranges_out = fopen(argv[3], "w");
if (compress_ranges_out == NULL)
util_fatal_error("failed to open file '%s' for writing", argv[3]);
write_compress_ranges(compress_ranges_out);
fclose(compress_ranges_out);
free_rom_spec(g_segments, g_segmentsCount);
free(spec);

View file

@ -282,7 +282,7 @@ def read_tables():
global staff_message_entry_table
baserom = None
with open("baserom.z64","rb") as infile:
with open("baseroms/gc-eu-mq-dbg/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])
@ -326,7 +326,7 @@ def dump_all_text():
nes_offset = segmented_to_physical(entry[3])
nes_length = next_entry[3] - entry[3]
nes_text = ""
with open("baserom/nes_message_data_static","rb") as infile:
with open("baseroms/gc-eu-mq-dbg/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 +337,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("baserom/ger_message_data_static","rb") as infile:
with open("baseroms/gc-eu-mq-dbg/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("baserom/fra_message_data_static","rb") as infile:
with open("baseroms/gc-eu-mq-dbg/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 +352,7 @@ def dump_all_text():
return messages
def dump_staff_text():
staff_message_data_static_size = path.getsize("baserom/staff_message_data_static")
staff_message_data_static_size = path.getsize("baseroms/gc-eu-mq-dbg/segments/staff_message_data_static")
# text id, ypos, type, staff
messages = []
for i,entry in enumerate(staff_message_entry_table,0):
@ -361,7 +361,7 @@ 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("baserom/staff_message_data_static","rb") as infile:
with open("baseroms/gc-eu-mq-dbg/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:

View file

@ -387,7 +387,7 @@ def GetColliderInit(address, type, num, path):
else:
return("ItemInit type must specify number of elements")
ovlFile = open(path + "/baserom/" + fileResult.name, "rb")
ovlFile = open(path + "/baseroms/gc-eu-mq-dbg/segments/" + fileResult.name, "rb")
ovlData = bytearray(ovlFile.read())
ovlFile.close()
@ -470,7 +470,7 @@ print(GetColliderInitFull(args.address, args.type, args.num, repo))
# script_dir = os.path.dirname(os.path.realpath(__file__))
# ovlFile = open(script_dir + "/../../baserom/" + fileResult.name, "rb")
# ovlFile = open(script_dir + "/../../baseroms/" + fileResult.name, "rb")
# ovlData = bytearray(ovlFile.read())
# ovlFile.close()

View file

@ -132,7 +132,7 @@ def get_damage_bytes(address, repo):
print(file_result)
with open(repo + os.sep + "baserom" + os.sep + file_result.name, "rb") as ovl_file:
with open(repo + os.sep + "baseroms/gc-eu-mq-dbg/segments" + os.sep + file_result.name, "rb") as ovl_file:
ovl_data = bytearray(ovl_file.read())
damage_data = ovl_data[file_result.offset:file_result.offset+0x20]

View file

@ -72,7 +72,7 @@ repo = scriptDir + os.sep + ".." + os.sep + ".."
kaleido_scope_data = []
with open(repo + "/baserom/ovl_kaleido_scope", "rb") as file:
with open(repo + "/baseroms/gc-eu-mq-dbg/segments/ovl_kaleido_scope", "rb") as file:
kaleido_scope_data = bytearray(file.read())
scenemaps = []

View file

@ -97,7 +97,7 @@ repo = scriptDir + os.sep + ".." + os.sep + ".."
map_mark_data = []
with open(repo + "/baserom/ovl_map_mark_data", "rb") as file:
with open(repo + "/baseroms/gc-eu-mq-dbg/segments/ovl_map_mark_data", "rb") as file:
map_mark_data = bytearray(file.read())
scenemaps = []

View file

@ -127,6 +127,7 @@ static const char *const stmtNames[] =
[STMT_after] = "after",
[STMT_align] = "align",
[STMT_beginseg] = "beginseg",
[STMT_compress] = "compress",
[STMT_endseg] = "endseg",
[STMT_entry] = "entry",
[STMT_flags] = "flags",
@ -216,10 +217,13 @@ bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, i
currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0;
currSeg->includes[currSeg->includesCount - 1].dataWithRodata = (stmt == STMT_include_data_with_rodata);
break;
case STMT_increment:
case STMT_increment:
if (!parse_number(args, &currSeg->increment))
util_fatal_error("line %i: expected number after 'increment'", lineNum);
break;
case STMT_compress:
currSeg->compress = true;
break;
case STMT_pad_text:
currSeg->includes[currSeg->includesCount - 1].linkerPadding += 0x10;
break;

View file

@ -9,6 +9,7 @@ typedef enum {
STMT_after,
STMT_align,
STMT_beginseg,
STMT_compress,
STMT_endseg,
STMT_entry,
STMT_flags,
@ -48,6 +49,7 @@ typedef struct Segment {
uint32_t number;
struct Include* includes;
int includesCount;
bool compress;
} Segment;
void parse_rom_spec(char* spec, struct Segment** segments, int* segment_count);