Merge remote-tracking branch 'upstream/master' into interaction-stuff

This commit is contained in:
Catobat 2023-05-06 12:32:38 +02:00
commit a2785bc0fa
18 changed files with 566 additions and 799 deletions

163
GBA.mk Normal file
View File

@ -0,0 +1,163 @@
.PHONY: default
default:
@echo do not use this directly
include Toolchain.mk
GAME_VERSION ?= USA
BUILD_DIR = build/$(GAME_VERSION)
TITLE := GBAZELDA MC
MAKER_CODE := 01
REVISION := 0
ifeq ($(GAME_VERSION), EU)
GAME_CODE := BZMP
BUILD_NAME := tmc_eu
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/English.bin translations/French.bin translations/German.bin translations/Spanish.bin translations/Italian.bin
else ifeq ($(GAME_VERSION), JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_jp
GAME_LANGUAGE := JAPANESE
TRANSLATIONS :=
else ifeq ($(GAME_VERSION), USA)
GAME_CODE := BZME
BUILD_NAME := tmc
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/USA.bin
else ifeq ($(GAME_VERSION), DEMO_USA)
GAME_CODE := BZHE
BUILD_NAME := tmc_demo_usa
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/USA.bin
else ifeq ($(GAME_VERSION), DEMO_JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_demo_jp
GAME_LANGUAGE := JAPANESE
TRANSLATIONS :=
else
$(error unknown version $(GAME_VERSION))
endif
ROM = $(BUILD_NAME).gba
ELF = $(BUILD_NAME).elf
# Clear the default suffixes
.SUFFIXES:
# Don't delete intermediate files
.SECONDARY:
# Delete files that weren't built properly
.DELETE_ON_ERROR:
# Secondary expansion is required for dependency variables in object rules.
.SECONDEXPANSION:
# ==================
# entrypoint targets
# ==================
CUSTOM ?=
COMPARE ?= $(if $(CUSTOM),0,1)
.PHONY: build extract_assets build_assets
build: $(if $(CUSTOM), build_assets, $(BUILD_DIR)/extracted_assets_$(GAME_VERSION))
@$(MAKE) -f GBA.mk $(ROM)
ifeq ($(COMPARE), 1)
@$(SHA1) $(BUILD_NAME).sha1
endif
extract_assets: $(BUILD_DIR)/converted_assets_$(GAME_VERSION)
# TODO this is slow, especially on builds with minor/no changes
build_assets: $(BUILD_DIR)/converted_assets_$(GAME_VERSION)
$(ASSET_PROCESSOR) build $(GAME_VERSION) $(BUILD_DIR)/assets
.PHONY: clean
clean:
rm -rf build
rm -f t*.gba
rm -f t*.elf
# ===============
# build ASM files
# ===============
ASINCLUDE := -I $(BUILD_DIR)/assets -I $(BUILD_DIR)/enum_include
ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 $(ASINCLUDE)
# TODO try solve this without the glob
ENUM_ASM_SRCS := $(wildcard include/*.h)
ENUM_ASM_HEADERS := $(patsubst include/%.h,$(BUILD_DIR)/enum_include/%.inc,$(ENUM_ASM_SRCS))
# if this is too broad dependency scanning will clash with C file
$(BUILD_DIR)/asm/%.o: deps = $(shell $(SCANINC) -I . $(ASINCLUDE) $*.s)
$(BUILD_DIR)/data/%.o: deps = $(shell $(SCANINC) -I . $(ASINCLUDE) $*.s)
$(BUILD_DIR)/%.o: %.s $$(deps) $(ENUM_ASM_HEADERS)
@mkdir -p $(dir $@)
$(PREPROC) $(BUILD_NAME) $< -- $(ASINCLUDE) | $(AS) $(ASFLAGS) -o $@
$(BUILD_DIR)/enum_include/%.inc: include/%.h
@mkdir -p $(dir $@)
$(ENUM_PROCESSOR) $< $(CC) "-D__attribute__(x)=" "-D$(GAME_VERSION)" "-E" "-nostdinc" "-Itools/agbcc" "-Itools/agbcc/include" "-iquote include" > $@
# =============
# build C files
# =============
# agbcc includes are separate because we don't want dependency scanning on them
CINCLUDE := -I include -I $(BUILD_DIR)
CPPFLAGS := -I tools/agbcc -I tools/agbcc/include $(CINCLUDE) -nostdinc -undef -D$(GAME_VERSION) -DREVISION=$(REVISION) -D$(GAME_LANGUAGE)
CFLAGS := -O2 -Wimplicit -Wparentheses -Werror -Wno-multichar -g3
interwork := $(BUILD_DIR)/src/interrupts.o \
$(BUILD_DIR)/src/collision.o \
$(BUILD_DIR)/src/playerItem.o \
$(BUILD_DIR)/src/object.o \
$(BUILD_DIR)/src/manager.o \
$(BUILD_DIR)/src/npc.o \
$(BUILD_DIR)/src/gba/m4a.o
$(interwork): CFLAGS += -mthumb-interwork
$(BUILD_DIR)/src/eeprom.o: CFLAGS += -O1 -mthumb-interwork
# if this is too broad dependency scanning will clash with ASM file
$(BUILD_DIR)/src/%.o: deps = $(shell $(SCANINC) $(CINCLUDE) $*.c)
$(BUILD_DIR)/%.o : %.c $$(deps)
@mkdir -p $(dir $@)
$(CPP) $(CPPFLAGS) $< -o $(BUILD_DIR)/$*.i
$(CC1) $(CFLAGS) -o $(BUILD_DIR)/$*.s $(BUILD_DIR)/$*.i
@echo "\t.text\n\t.align\t2, 0 @ Don't pad with nop\n" >> $(BUILD_DIR)/$*.s
$(AS) $(ASFLAGS) -o $@ $(BUILD_DIR)/$*.s
# ==============
# build binaries
# ==============
LDFLAGS = -Map ../../$(BUILD_DIR)/$(BUILD_NAME).map
LIB := -L ../../tools/agbcc/lib -lc
$(ROM): $(ELF)
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
$(ELF): objs = $(shell grep -o -E "(\w|/)+\.o" linker.ld)
$(ELF): $(BUILD_DIR)/linker.ld $$(addprefix $(BUILD_DIR)/, $$(objs))
cd $(BUILD_DIR) && $(LD) $(LDFLAGS) -n -T linker.ld -o ../../$@ $(LIB)
$(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
$(BUILD_DIR)/linker.ld: linker.ld
@mkdir -p $(BUILD_DIR)
$(CPP) $(CPPFLAGS) -x c linker.ld | grep -v '^#' >$(BUILD_DIR)/linker.ld
# ======
# assets
# ======
$(BUILD_DIR)/extracted_assets_%: assets/assets.json assets/gfx.json assets/map.json assets/samples.json assets/sounds.json $(TRANSLATIONS)
@mkdir -p $(dir $@)
$(ASSET_PROCESSOR) extract $(GAME_VERSION) $(BUILD_DIR)/assets
touch $@
$(BUILD_DIR)/converted_assets_%: $(BUILD_DIR)/extracted_assets_%
@mkdir -p $(dir $@)
$(ASSET_PROCESSOR) convert $(GAME_VERSION) $(BUILD_DIR)/assets
touch $@
translations/%.bin: translations/%.json
tools/bin/tmc_strings -p --source $< --dest $@

View File

@ -1,14 +1,22 @@
# Install
First, you must put a The Legend of Zelda: The Minish Cap (U) ROM (with SHA1: `b4bd50e4131b027c334547b4524e2dbbd4227130`) in the root directory of the repository and name it `baserom.gba`.
This repository does not include any of the games assets.
To build the game using the decomp you need an original baserom for each version you want to build.
Put them with the appropriate filename into the repository root directory.
The supported versions are:
## Building other variants
To build other variants, you need to place the corresponding baserom before building, e.g. `baserom_jp.gba` for JP.
| Version | Filename | SHA1 |
|-----------------------|------------------------|--------------------------------------------|
| USA (project default) | `baserom.gba` | `b4bd50e4131b027c334547b4524e2dbbd4227130` |
| EU | `baserom_eu.gba` | `cff199b36ff173fb6faf152653d1bccf87c26fb7` |
| JP | `baserom_jp.gba` | `6c5404a1effb17f481f352181d0f1c61a2765c5d` |
| USA (Demo) | `baserom_demo_usa.gba` | `63fcad218f9047b6a9edbb68c98bd0dec322d7a1` |
| JP (Demo) | `baserom_demo_jp.gba` | `9cdb56fa79bba13158b81925c1f3641251326412` |
## Prerequisites
| Linux | macOS | Windows 10 (build 18917+) | Windows 10 (1709+) | Windows 8, 8.1, and 10 (1507, 1511, 1607, 1703)
| ----- | ----- | ------------------------- | ------------------ | ---------------------------------------------------------
| none | [Xcode Command Line Tools package][xcode] | [Windows Subsystem for Linux 2][wsl2] | [Windows Subsystem for Linux][wsl] | [Cygwin][cygwin]
| Linux | macOS | Windows 10 (build 18917+) | Windows 10 (1709+) | Windows 8, 8.1, and 10 (1507, 1511, 1607, 1703) |
|-------|-------------------------------------------|---------------------------------------|------------------------------------|-------------------------------------------------|
| none | [Xcode Command Line Tools package][xcode] | [Windows Subsystem for Linux 2][wsl2] | [Windows Subsystem for Linux][wsl] | [Cygwin][cygwin] |
[xcode]: https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-DOWNLOADING_COMMAND_LINE_TOOLS_IS_NOT_AVAILABLE_IN_XCODE_FOR_MACOS_10_9__HOW_CAN_I_INSTALL_THEM_ON_MY_MACHINE_
[wsl2]: https://docs.microsoft.com/windows/wsl/wsl2-install
@ -17,53 +25,59 @@ To build other variants, you need to place the corresponding baserom before buil
The [prerelease version of the Linux subsystem](https://docs.microsoft.com/windows/wsl/install-legacy) available in the 1607 and 1703 releases of Windows 10 is obsolete so consider uninstalling it.
Make sure that the `build-essential`, `git`, `python3`, `python3-pip`, `cmake` and `libpng-dev` packages are installed. The `build-essential` package includes the `make`, `gcc-core`, and `g++` packages so they do not have to be obtained separately.
Make sure that the `build-essential`, `git`, `python3`, `python3-pip`, `cmake` and `libpng-dev` packages are installed. The `build-essential` package includes the `make`, `gcc-core`, and `g++` packages, so they do not have to be obtained separately.
In the case of Cygwin, [include](https://cygwin.com/cygwin-ug-net/setup-net.html#setup-packages) the `make`, `git`, `gcc-core`, `gcc-g++`, and `libpng-devel` packages.
Install the **devkitARM** toolchain of [devkitPro](https://devkitpro.org/wiki/Getting_Started) and add its environment variables. For Windows versions without the Linux subsystem, the devkitPro [graphical installer](https://github.com/devkitPro/installer/releases) includes a preconfigured MSYS2 environment, thus the steps below are not required.
To build the games code, the `arm-none-eabi-gcc` compiler is required.
Both a standalone installation and [devkitPro](https://devkitpro.org/wiki/Getting_Started) are supported.
For devkitPro, install the `gba-dev` package.
sudo (dkp-)pacman -S gba-dev
export DEVKITPRO=/opt/devkitpro
echo "export DEVKITPRO=$DEVKITPRO" >> ~/.bashrc
export DEVKITARM=$DEVKITPRO/devkitARM
echo "export DEVKITARM=$DEVKITARM" >> ~/.bashrc
If `arm-none-eabi-gcc` is not available through `PATH` use `TOOLCHAIN_PATH=<path>` to indicate its location.
This is not required for devkitPro, the `DEVKITARM` environment variable is used for auto-detection.
Install the pycparser python package:
pip3 install pycparser
Install `python3` and the `pycparser` python package:
`pip3 install pycparser`
## Installation
To set up the repository:
```shell
git clone https://github.com/zeldaret/tmc
git clone https://github.com/pret/agbcc
git clone https://github.com/zeldaret/tmc
git clone https://github.com/pret/agbcc
cd ./agbcc
sh build.sh
sh install.sh ../tmc
cd ./agbcc
sh build.sh
sh install.sh ../tmc
cd ../tmc
make tools
```
To build `tmc.gba`:
```shell
make -j$(nproc)
```
>**Note:** If the build command is not recognized on Linux, including the Linux environment used within Windows, run `nproc` and replace `$(nproc)` with the returned value (e.g.: `make -j4`). Because `nproc` is not available on macOS, the alternative is `sysctl -n hw.ncpu`.
cd ../tmc
make setup
You can configure the game version built by using the `GAME_VERSION` variable (ie. `make GAME_VERSION=EU`).
Convenience targets for all 5 versions exist (`make usa eu jp demo_usa demo_jp`).
`make all` builds all 5 versions.
To build **tmc.gba**:
If you modify the game you need to do a custom build.
Use `CUSTOM=1` for that (any nonempty value will enable it, so `CUSTOM=0` will NOT disable it).
There is a convenience target `make custom` that does a custom USA build.
make -j$(nproc)
If only `.c` or `.s` files were changed, turn off the dependency scanning temporarily. Changes to any other files will be ignored and the build will either fail or not reflect those changes.
make -j$(nproc) NODEP=1
**Note:** If the build command is not recognized on Linux, including the Linux environment used within Windows, run `nproc` and replace `$(nproc)` with the returned value (e.g.: `make -j4`). Because `nproc` is not available on macOS, the alternative is `sysctl -n hw.ncpu`.
The `COMPARE` variable controls the SHA1 verification check.
It is enabled (`1`) for normal builds and disabled (`0`) for custom builds by default.
### Note for Mac users
The BSD make that comes with Mac XCode can be buggy, so obtain GNU make and sed using [Homebrew](https://brew.sh):
brew install make gnu-sed
```shell
brew install make gnu-sed
```
When compiling agbcc, substitute the `build.sh` line for
gsed 's/^make/gmake/g' build.sh | sh
```shell
gsed 's/^make/gmake/g' build.sh | sh
```
Finally, use `gmake` instead of `make` to compile the ROM(s).

4
Jenkinsfile vendored
View File

@ -12,12 +12,12 @@ pipeline {
sh 'cp /usr/local/etc/roms/tmc.demo.jp.gba baserom_demo_jp.gba'
sh 'cp /usr/local/etc/roms/tmc.jp.gba baserom_jp.gba'
sh 'cp /usr/local/etc/roms/tmc.eu.gba baserom_eu.gba'
sh 'make -j setup'
sh 'make tools'
}
}
stage('Build') {
steps {
sh 'make usa demo_usa jp demo_jp eu -j'
sh 'make all -j'
}
}
stage('Report Progress') {

305
Makefile
View File

@ -1,294 +1,41 @@
include $(DEVKITARM)/base_tools
COMPARE ?= 0
CPP := $(CC) -E
LD := $(DEVKITARM)/bin/arm-none-eabi-ld
GAME_VERSION ?= USA
REVISION := 0
GAME_LANGUAGE := ENGLISH
TITLE := GBAZELDA MC
MAKER_CODE := 01
ifeq ($(GAME_VERSION), USA)
GAME_CODE := BZME
BUILD_NAME := tmc
else
ifeq ($(GAME_VERSION), DEMO_USA)
GAME_CODE := BZHE
BUILD_NAME := tmc_demo_usa
else
ifeq ($(GAME_VERSION), JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_jp
GAME_LANGUAGE := JAPANESE
else
ifeq ($(GAME_VERSION), DEMO_JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_demo_jp
GAME_LANGUAGE := JAPANESE
else
ifeq ($(GAME_VERSION), EU)
GAME_CODE := BZMP
BUILD_NAME := tmc_eu
else
$(error unknown version $(GAME_VERSION))
endif
endif
endif
endif
endif
SHELL := /bin/bash -o pipefail
ROM := $(BUILD_NAME).gba
OBJ_DIR := build/$(BUILD_NAME)
ELF = $(ROM:.gba=.elf)
MAP = $(ROM:.gba=.map)
C_SUBDIR = src
DATA_C_SUBDIR = src/data
ASM_SUBDIR = asm
DATA_ASM_SUBDIR = data
SONG_SUBDIR = sound/songs
MID_SUBDIR = sound/songs/midi
ASSET_SUBDIR = assets
ENUM_INCLUDE_SUBDIR = enum_include
C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR)
ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR)
ASM_ENUM_INCLUDE_DIR = $(ASM_BUILDDIR)/$(ENUM_INCLUDE_SUBDIR)
DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR)
SONG_BUILDDIR = $(OBJ_DIR)/$(SONG_SUBDIR)
MID_BUILDDIR = $(OBJ_DIR)/$(MID_SUBDIR)
ASSET_BUILDDIR = $(OBJ_DIR)/$(ASSET_SUBDIR)
PREPROC_INC_PATHS = $(ASSET_BUILDDIR) $(ASM_ENUM_INCLUDE_DIR)
ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR)
CC1 := tools/agbcc/bin/agbcc
override CFLAGS += -O2 -Wimplicit -Wparentheses -Werror -Wno-multichar -g3
# -fhex-asm
# ifeq ($(DINFO),1)
# override CFLAGS += -g
# endif
CPPFLAGS := -I tools/agbcc -I tools/agbcc/include -iquote include -nostdinc -undef -D$(GAME_VERSION) -DREVISION=$(REVISION) -D$(GAME_LANGUAGE) -I $(OBJ_DIR)
LDFLAGS = -Map ../../$(MAP)
LIB := -L ../../tools/agbcc/lib -lc
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
GFX := tools/bin/gbagfx
AIF := tools/bin/aif2pcm
MID := tools/bin/mid2agb
SCANINC := tools/bin/scaninc
# TODO: use charmap?
PREPROC := tools/bin/preproc
FIX := tools/bin/gbafix
ASSET_PROCESSOR := tools/bin/asset_processor
ENUM_PROCESSOR := tools/extract_include_enum.py
ASSET_CONFIGS = assets/assets.json assets/gfx.json assets/map.json assets/samples.json assets/sounds.json
TRANSLATIONS = translations/USA.bin translations/English.bin translations/French.bin translations/German.bin translations/Spanish.bin translations/Italian.bin
# Clear the default suffixes
.SUFFIXES:
# Don't delete intermediate files
.SECONDARY:
# Delete files that weren't built properly
.DELETE_ON_ERROR:
# Secondary expansion is required for dependency variables in object rules.
.SECONDEXPANSION:
$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR))
infoshell = $(foreach line, $(shell $1 | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line))))
# Build tools when building the rom
# Disable dependency scanning for clean/tidy/tools
ifeq (,$(filter-out all compare target,$(MAKECMDGOALS)))
$(call infoshell, $(MAKE) tools)
else
NODEP := 1
endif
interwork := $(C_BUILDDIR)/interrupts.o \
$(C_BUILDDIR)/collision.o \
$(C_BUILDDIR)/playerItem.o \
$(C_BUILDDIR)/object.o \
$(C_BUILDDIR)/manager.o \
$(C_BUILDDIR)/npc.o
$(interwork): CFLAGS += -mthumb-interwork
$(C_BUILDDIR)/gba/m4a.o: CFLAGS = -O2 -mthumb-interwork -Wimplicit -Wparentheses -Werror -Wno-multichar
$(C_BUILDDIR)/eeprom.o: CFLAGS = -O1 -mthumb-interwork -Wimplicit -Wparentheses -Werror -Wno-multichar
C_SRCS := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c)
C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
ASM_SRCS := $(wildcard $(ASM_SUBDIR)/*.s $(ASM_SUBDIR)/*/*.s)
ASM_OBJS := $(patsubst $(ASM_SUBDIR)/%.s,$(ASM_BUILDDIR)/%.o,$(ASM_SRCS)) $(patsubst $(ASM_SUBDIR)/*/%.s,$(ASM_BUILDDIR)/**/%.o,$(ASM_SRCS))
DATA_ASM_SRCS := $(wildcard $(DATA_ASM_SUBDIR)/*.s $(DATA_ASM_SUBDIR)/**/*.s $(DATA_ASM_SUBDIR)/**/**/*.s)
DATA_ASM_OBJS := $(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o,$(DATA_ASM_SRCS))
SONG_SRCS := $(wildcard $(SONG_SUBDIR)/*.s)
SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS))
MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid)
MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
ENUM_ASM_SRCS := $(wildcard include/*.h)
ENUM_ASM_HEADERS := $(patsubst include/%.h,$(ASM_ENUM_INCLUDE_DIR)/%.inc,$(ENUM_ASM_SRCS))
OBJS := $(C_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
SUBDIRS := $(sort $(dir $(OBJS) $(ENUM_ASM_HEADERS)))
$(shell mkdir -p $(SUBDIRS))
.PHONY: all setup clean-tools mostlyclean clean tidy tools extractassets buildassets custom
.PHONY: default all
default: build
all: eu jp usa demo_jp demo_usa
MAKEFLAGS += --no-print-directory
AUTO_GEN_TARGETS :=
.PHONY: build eu jp usa demo_jp demo_usa custom
build: GAME_VERSION ?=USA
build: tools
@$(MAKE) -f GBA.mk build GAME_VERSION=$(GAME_VERSION)
# TODO do we really need this extra step just so that the assets are always extracted at first?
all: build/extracted_assets_$(GAME_VERSION)
@$(MAKE) target GAME_VERSION=$(GAME_VERSION)
eu: GAME_VERSION=EU
jp: GAME_VERSION=JP
usa: GAME_VERSION=USA
demo_jp: GAME_VERSION=DEMO_JP
demo_usa: GAME_VERSION=DEMO_USA
eu jp usa demo_jp demo_usa: tools
@$(MAKE) GAME_VERSION=$(GAME_VERSION)
target: $(ROM)
@$(SHA1) $(BUILD_NAME).sha1
custom: tools
@$(MAKE) GAME_VERSION=USA CUSTOM=1
custom: buildassets
@$(MAKE) target GAME_VERSION=$(GAME_VERSION)
.PHONY: extract_assets
extract_assets: tools
@$(MAKE) -f GBA.mk extract_assets
# kept for backwards compat
compare: $(ROM)
@$(SHA1) $(BUILD_NAME).sha1
.PHONY: tools
tools: tools/bin
setup: tools
# all tools are build at once
# FIXME figure out why make builds multiple times when specifying all tools here
tools: $(GFX)
$(GFX) $(AIF) $(MID) $(SCANINC) $(PREPROC) $(FIX) $(ASSET_PROCESSOR) tools/bin/agb2mid tools/bin/tmc_strings tools/bin/bin2c &:
tools/bin:
mkdir -p tools/cmake-build
unset CC CXX AS LD LDFLAGS && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=tools -S tools -B tools/cmake-build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=tools -S tools -B tools/cmake-build
cmake --build tools/cmake-build -j --target install
# Automatically extract binary data
build/extracted_assets_%: $(ASSET_CONFIGS) $(TRANSLATIONS)
$(ASSET_PROCESSOR) extract $(GAME_VERSION) $(ASSET_BUILDDIR)
touch $@
# Extract assets to human readable form
extractassets:
$(ASSET_PROCESSOR) convert $(GAME_VERSION) $(ASSET_BUILDDIR)
# Build the assets from the human readable form
buildassets:
$(ASSET_PROCESSOR) build $(GAME_VERSION) $(ASSET_BUILDDIR)
mostlyclean: tidy
rm -f sound/direct_sound_samples/*.bin
rm -f $(SONG_OBJS) $(MID_SUBDIR)/*.s
find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} +
rm -f $(AUTO_GEN_TARGETS)
.PHONY: clean clean-tools
clean:
@$(MAKE) -f GBA.mk clean
clean-tools:
rm -rf tools/bin
rm -rf tools/cmake-build
clean: mostlyclean clean-tools
tidy:
rm -f tmc.gba tmc.elf tmc.map
rm -f tmc_demo_usa.gba tmc_demo_usa.elf tmc_demo_usa.map
rm -f tmc_jp.gba tmc_jp.elf tmc_jp.map
rm -f tmc_demo_jp.gba tmc_demo_jp.elf tmc_demo_jp.map
rm -f tmc_eu.gba tmc_eu.elf tmc_eu.map
rm -r build/*
%.s: ;
%.png: ;
%.pal: ;
%.aif: ;
%.1bpp: %.png ; $(GFX) $< $@
%.4bpp: %.png ; $(GFX) $< $@
%.8bpp: %.png ; $(GFX) $< $@
%.gbapal: %.pal ; $(GFX) $< $@
%.gbapal: %.png ; $(GFX) $< $@
%.lz: % ; $(GFX) $< $@
%.rl: % ; $(GFX) $< $@
cd $(@D) && ../../$(MID) $(<F)
translations/USA.bin: translations/USA.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x499E0
translations/English.bin: translations/English.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x488C0
translations/French.bin: translations/French.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x47A90
translations/German.bin: translations/German.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x42FC0
translations/Spanish.bin: translations/Spanish.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x41930
translations/Italian.bin: translations/Italian.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x438E0
ifeq ($(NODEP),1)
$(C_BUILDDIR)/%.o: c_dep :=
else
$(C_BUILDDIR)/%.o: c_dep = $(shell $(SCANINC) -I include $(C_SUBDIR)/$*.c)
endif
$(C_BUILDDIR)/%.o : $(C_SUBDIR)/%.c $$(c_dep)
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
$(PREPROC) $(BUILD_NAME) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
@echo -e "\t.text\n\t.align\t2, 0 @ Don't pad with nop\n" >> $(C_BUILDDIR)/$*.s
$(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
ifeq ($(NODEP),1)
$(ASM_BUILDDIR)/%.o: asm_dep :=
else
$(ASM_BUILDDIR)/%.o: asm_dep = $(shell $(SCANINC) -I . $(ASM_SUBDIR)/$*.s)
endif
$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep)
$(PREPROC) $(BUILD_NAME) $< -- $(PREPROC_INC_PATHS) | $(AS) $(ASFLAGS) -o $@
$(ASM_ENUM_INCLUDE_DIR)/%.inc: include/%.h
$(ENUM_PROCESSOR) $< $(CC) "-D__attribute__(x)=" "-D$(GAME_VERSION)" "-E" "-nostdinc" "-Itools/agbcc" "-Itools/agbcc/include" "-iquote include" > $@
ifeq ($(NODEP),1)
$(DATA_ASM_BUILDDIR)/%.o: data_dep :=
else
$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) -I . -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR) $(DATA_ASM_SUBDIR)/$*.s)
endif
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep) $(ENUM_ASM_HEADERS)
$(PREPROC) $(BUILD_NAME) $< charmap.txt -- $(PREPROC_INC_PATHS) | $(CPP) -I include -nostdinc -undef -Wno-unicode - | $(AS) $(ASFLAGS) -o $@
$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s
$(AS) $(ASFLAGS) -I sound -o $@ $<
$(OBJ_DIR)/linker.ld: linker.ld
$(CPP) $(CPPFLAGS) -x c linker.ld | grep -v '^#' >$(OBJ_DIR)/linker.ld
$(ELF): $(OBJS) $(OBJ_DIR)/linker.ld
cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -n -T linker.ld -o ../../$@ $(LIB)
$(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
$(ROM): $(ELF)
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
usa: ; @$(MAKE) GAME_VERSION=USA
demo_usa: ; @$(MAKE) GAME_VERSION=DEMO_USA
jp: ; @$(MAKE) GAME_VERSION=JP
demo_jp: ; @$(MAKE) GAME_VERSION=DEMO_JP
eu: ; @$(MAKE) GAME_VERSION=EU

38
Toolchain.mk Normal file
View File

@ -0,0 +1,38 @@
# ========
# compiler
# ========
ifndef TOOLCHAIN_PATH
ifneq (,$(shell which arm-none-eabi-gcc))
TOOLCHAIN_PATH :=
else ifdef DEVKITARM
TOOLCHAIN_PATH := $(DEVKITARM)/bin/
else
$(error arm-none-eabi-gcc not found, please install (devkitPro supported))
endif
endif
# ensure trailing slash
ifneq ($(TOOLCHAIN_PATH),)
override TOOLCHAIN_PATH:=$(TOOLCHAIN_PATH)/
endif
CC := $(TOOLCHAIN_PATH)arm-none-eabi-gcc
CPP := $(CC) -E
CXX := $(TOOLCHAIN_PATH)arm-none-eabi-g++
AS := $(TOOLCHAIN_PATH)arm-none-eabi-as
LD := $(TOOLCHAIN_PATH)arm-none-eabi-ld
OBJCOPY := $(TOOLCHAIN_PATH)arm-none-eabi-objcopy
# ============
# custom tools
# ============
CC1 := tools/agbcc/bin/agbcc
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
SCANINC := tools/bin/scaninc
PREPROC := tools/bin/preproc
ASSET_PROCESSOR := tools/bin/asset_processor
ENUM_PROCESSOR := tools/extract_include_enum.py
FIX := tools/bin/gbafix

View File

@ -1,134 +0,0 @@
.syntax unified
push {r4, r5, r6, r7, lr}
mov r7, sb
mov r6, r8
push {r6, r7}
adds r5, r0, #0
ldrb r4, [r5, #0xa]
cmp r4, #0
bne _080AC668
ldr r0, _080AC664 @ =gEntCount
ldrb r0, [r0]
cmp r0, #0x43
bhi _080AC670
adds r1, r5, #0
adds r1, #0x79
movs r0, #0x11
strb r0, [r1]
movs r0, #0x22
bl CreateProjectile
adds r6, r0, #0
ldrb r0, [r5, #0xa]
strb r0, [r6, #0xa]
movs r0, #1
strb r0, [r6, #0xb]
ldr r0, [r5, #0x50]
str r0, [r6, #0x50]
adds r1, r6, #0
adds r1, #0x79
movs r0, #0x12
strb r0, [r1]
str r6, [r5, #0x54]
movs r0, #0x22
bl CreateProjectile
adds r7, r0, #0
ldrb r0, [r5, #0xa]
strb r0, [r7, #0xa]
movs r0, #2
strb r0, [r7, #0xb]
ldr r0, [r5, #0x50]
str r0, [r7, #0x50]
adds r0, r7, #0
adds r0, #0x79
movs r1, #0x14
mov r8, r1
mov r1, r8
strb r1, [r0]
str r7, [r6, #0x54]
movs r0, #0x22
bl CreateProjectile
ldrb r1, [r5, #0xa]
strb r1, [r0, #0xa]
movs r1, #3
strb r1, [r0, #0xb]
ldr r1, [r5, #0x50]
str r1, [r0, #0x50]
str r4, [r0, #0x54]
adds r1, r0, #0
adds r1, #0x79
strb r4, [r1]
str r0, [r7, #0x54]
b _080AC6C8
.align 2, 0
_080AC664: .4byte gEntCount
_080AC668:
ldr r0, _080AC674 @ =gEntCount
ldrb r0, [r0]
cmp r0, #0x44
bls _080AC678
_080AC670:
movs r0, #0
b _080AC6E8
.align 2, 0
_080AC674: .4byte gEntCount
_080AC678:
adds r1, r5, #0
adds r1, #0x79
movs r0, #0
mov sb, r0
movs r0, #0xf
strb r0, [r1]
movs r0, #0x22
bl CreateProjectile
adds r6, r0, #0
ldrb r0, [r5, #0xa]
strb r0, [r6, #0xa]
movs r0, #1
strb r0, [r6, #0xb]
ldr r0, [r5, #0x50]
str r0, [r6, #0x50]
adds r0, r6, #0
adds r0, #0x79
movs r1, #0x10
mov r8, r1
mov r1, r8
strb r1, [r0]
str r6, [r5, #0x54]
movs r0, #0x22
bl CreateProjectile
adds r7, r0, #0
ldrb r0, [r5, #0xa]
strb r0, [r7, #0xa]
movs r0, #2
strb r0, [r7, #0xb]
ldr r0, [r5, #0x50]
str r0, [r7, #0x50]
mov r0, sb
str r0, [r7, #0x54]
adds r1, r7, #0
adds r1, #0x79
movs r0, #0x20
strb r0, [r1]
str r7, [r6, #0x54]
_080AC6C8:
movs r0, #0x22
bl CreateProjectile
adds r6, r0, #0
ldrb r0, [r5, #0xa]
strb r0, [r6, #0xa]
movs r0, #4
strb r0, [r6, #0xb]
ldr r0, [r5, #0x50]
str r0, [r6, #0x50]
str r5, [r6, #0x54]
adds r0, r6, #0
adds r0, #0x79
mov r1, r8
strb r1, [r0]
movs r0, #1
_080AC6E8:
pop {r3, r4}
mov r8, r3
mov sb, r4
pop {r4, r5, r6, r7, pc}
.syntax divided

View File

@ -1,287 +0,0 @@
.syntax unified
push {r4, r5, r6, r7, lr}
mov r7, sb
mov r6, r8
push {r6, r7}
mov r8, r0
ldr r4, _08068414 @ =gPlayerEntity
ldrh r1, [r4, #0x2e]
ldr r3, _08068418 @ =0xFFFF0000
adds r0, r3, #0
ands r0, r6
orrs r0, r1
ldrh r1, [r4, #0x32]
lsls r1, r1, #0x10
ldr r2, _0806841C @ =0x0000FFFF
ands r0, r2
adds r6, r0, #0
orrs r6, r1
ldrh r0, [r4, #0x36]
ands r3, r7
orrs r3, r0
adds r7, r3, #0
ldr r0, _08068420 @ =gPlayerState
adds r0, #0xa8
ldrb r0, [r0]
lsls r0, r0, #0x10
ldr r2, _08068424 @ =0xFF00FFFF
ands r2, r3
orrs r2, r0
adds r7, r2, #0
ldrb r1, [r4, #0x14]
movs r0, #0x3f
ands r1, r0
lsls r1, r1, #0x18
ldr r0, _08068428 @ =0xC0FFFFFF
ands r0, r2
orrs r0, r1
adds r7, r0, #0
adds r1, r4, #0
adds r1, #0x38
ldrb r1, [r1]
lsls r1, r1, #0x1e
ldr r2, _0806842C @ =0x3FFFFFFF
ands r0, r2
adds r7, r0, #0
orrs r7, r1
mov r0, r8
ldr r5, [r0, #0x64]
ldrb r1, [r5, #6]
cmp r1, #0xa
bne _08068386
lsrs r0, r7, #0x10
lsls r0, r0, #0x18
lsrs r0, r0, #0x18
cmp r0, #0xa
bne _08068394
_08068386:
cmp r1, #0x16
bne _080683B4
lsrs r0, r7, #0x10
lsls r0, r0, #0x18
lsrs r0, r0, #0x18
cmp r0, #0x16
beq _080683B4
_08068394:
ldrh r0, [r4, #0x2e]
mov r1, r8
strh r0, [r1, #0x2e]
ldrh r0, [r4, #0x32]
strh r0, [r1, #0x32]
ldrb r1, [r1, #0x18]
movs r0, #4
rsbs r0, r0, #0
ands r0, r1
movs r1, #1
orrs r0, r1
mov r2, r8
strb r0, [r2, #0x18]
mov r0, r8
bl sub_08068578
_080683B4:
movs r3, #0
mov sb, r3
ldr r0, [r5]
cmp r6, r0
bne _080683D0
ldr r0, [r5, #4]
cmp r7, r0
bne _080683D0
lsls r1, r7, #8
lsrs r0, r1, #0x18
cmp r0, #0x16
beq _080683D0
cmp r0, #0xa
bne _08068430
_080683D0:
mov r0, r8
ldr r5, [r0, #0x64]
adds r5, #0x90
mov r4, r8
adds r4, #0x69
mov r3, r8
adds r3, #0x38
movs r1, #0x58
add r1, r8
mov ip, r1
movs r2, #0x12
_080683E6:
ldr r0, [r5]
ldr r1, [r5, #4]
str r0, [r5, #8]
str r1, [r5, #0xc]
subs r5, #8
subs r2, #1
cmp r2, #0
bge _080683E6
mov r2, r8
ldr r5, [r2, #0x64]
str r6, [r5]
str r7, [r5, #4]
movs r0, #4
mov sb, r0
ldrb r1, [r4]
movs r0, #0
ldrsb r0, [r4, r0]
cmp r0, #0
ble _080684A8
subs r0, r1, #1
strb r0, [r4]
b _080684A8
.align 2, 0
_08068414: .4byte gPlayerEntity
_08068418: .4byte 0xFFFF0000
_0806841C: .4byte 0x0000FFFF
_08068420: .4byte gPlayerState
_08068424: .4byte 0xFF00FFFF
_08068428: .4byte 0xC0FFFFFF
_0806842C: .4byte 0x3FFFFFFF
_08068430:
adds r5, #0x98
movs r1, #4
ldrsh r0, [r5, r1]
cmp r0, #0
bge _08068466
mov r2, r8
ldr r5, [r2, #0x64]
adds r5, #0x90
mov r4, r8
adds r4, #0x69
mov r3, r8
adds r3, #0x38
movs r0, #0x58
add r0, r8
mov ip, r0
movs r2, #0x12
_08068450:
ldr r0, [r5]
ldr r1, [r5, #4]
str r0, [r5, #8]
str r1, [r5, #0xc]
subs r5, #8
subs r2, #1
cmp r2, #0
bge _08068450
movs r1, #4
mov sb, r1
b _080684A8
_08068466:
ldr r1, _0806851C @ =gPlayerEntity
movs r2, #0x2e
ldrsh r0, [r1, r2]
movs r3, #0x32
ldrsh r1, [r1, r3]
ldrh r2, [r5]
ldrh r3, [r5, #2]
bl sub_080041E8
lsrs r0, r0, #4
mov r4, r8
adds r4, #0x69
mov r3, r8
adds r3, #0x38
movs r1, #0x58
add r1, r8
mov ip, r1
cmp r0, #0x18
ble _080684A8
mov r2, r8
ldr r5, [r2, #0x64]
adds r5, #0x90
movs r2, #0x12
_08068494:
ldr r0, [r5]
ldr r1, [r5, #4]
str r0, [r5, #8]
str r1, [r5, #0xc]
subs r5, #8
subs r2, #1
cmp r2, #0
bge _08068494
movs r0, #4
mov sb, r0
_080684A8:
mov r1, r8
ldr r5, [r1, #0x64]
adds r5, #0x98
ldrh r0, [r5]
strh r0, [r1, #0x2e]
ldrh r0, [r5, #2]
strh r0, [r1, #0x32]
ldrh r0, [r5, #4]
strh r0, [r1, #0x36]
ldrb r0, [r5, #7]
lsls r0, r0, #0x1a
lsrs r0, r0, #0x1a
strb r0, [r1, #0x14]
ldrb r0, [r5, #7]
lsrs r0, r0, #6
strb r0, [r3]
ldrb r0, [r5, #6]
cmp r0, #0x16
beq _080684D2
cmp r0, #0xa
bne _080684DE
_080684D2:
mov r2, r8
ldrb r1, [r2, #0x18]
movs r0, #4
rsbs r0, r0, #0
ands r0, r1
strb r0, [r2, #0x18]
_080684DE:
adds r1, r4, #0
ldrb r2, [r1]
movs r0, #0
ldrsb r0, [r1, r0]
cmp r0, #0
ble _080684EE
subs r0, r2, #1
strb r0, [r1]
_080684EE:
mov r2, sb
mov r3, r8
ldrb r0, [r3, #0x14]
lsrs r0, r0, #1
add sb, r0
mov r0, ip
ldrb r0, [r0]
cmp sb, r0
beq _08068520
cmp r2, #0
bne _0806850C
movs r0, #0
ldrsb r0, [r1, r0]
cmp r0, #0
bgt _08068520
_0806850C:
mov r0, r8
mov r1, sb
bl InitAnimationForceUpdate
movs r0, #0x1e
strb r0, [r4]
b _08068526
.align 2, 0
_0806851C: .4byte gPlayerEntity
_08068520:
mov r0, r8
bl UpdateAnimationSingleFrame
_08068526:
mov r0, r8
bl sub_0800451C
mov r1, r8
movs r2, #0x36
ldrsh r0, [r1, r2]
cmp r0, #0
bge _08068542
movs r2, #0xc
rsbs r2, r2, #0
mov r0, r8
movs r1, #0
bl sub_0806F854
_08068542:
pop {r3, r4}
mov r8, r3
mov sb, r4
pop {r4, r5, r6, r7, pc}
.align 2, 0
.syntax divided

View File

@ -45,4 +45,4 @@ gSpriteAnimations_Sturgeon:: @ 0810FBD0
.4byte gSpriteAnimations_Sturgeon_7
.4byte gSpriteAnimations_Sturgeon_8
.4byte gSpriteAnimations_Sturgeon_9
.4byte 00000000
.4byte 00000000

View File

@ -3,6 +3,8 @@
#include "global.h"
// clang-format off
bool32 CheckFlags(u32);
bool32 CheckGlobalFlag(u32);
bool32 CheckGlobalFlags(u32, u32);
@ -1762,4 +1764,6 @@ typedef enum {
END_12,
} LocalFlags12;
// clang-format on
#endif // FLAGS_H

View File

@ -867,7 +867,7 @@ SECTIONS {
src/gba/m4a.o(.text);
asm/lib/libagbsyscall.o(.text);
src/eeprom.o(.text);
*libc.a:memcpy.o(.text);
libc.a(.text);
/* handwritten assembly in arm mode */
asm/src/intr.o(.text);

View File

@ -2,7 +2,6 @@
import argparse
import json
import git
import os
import re
@ -26,7 +25,7 @@ def parse_map(non_matching_funcs):
data = 0
non_matching = 0
with open('tmc.map', 'r') as map:
with open('build/USA/tmc.map', 'r') as map:
# Skip to the linker script section
line = map.readline()
while not line.startswith('Linker script and memory map'):
@ -119,6 +118,7 @@ def main():
if args.format == 'csv':
import git
version = 2
git_object = git.Repo().head.object
timestamp = str(git_object.committed_date)

View File

@ -76,6 +76,7 @@ void sub_080620F4(Entity*);
void sub_08062130(Entity*);
void sub_08062194(Entity*);
void (*const gUnk_0810BE0C[])(Entity*) = { sub_080620F4, sub_08062130, sub_08062194 };
extern s32 sub_080041E8(s32 x1, s32 y1, s32 x2, s32 y2);
void sub_08062194(Entity*);
const Dialog gUnk_0810BE10[] = {
@ -182,17 +183,21 @@ void sub_080622F4(Entity*);
void sub_0806265C(Entity*, ScriptExecutionContext*);
void sub_0806252C(Entity*);
typedef struct {
u16 x;
u16 y;
u16 z;
u8 framestate;
u8 animationState : 6;
u8 collisionLayer : 2;
typedef union {
struct {
s16 x;
s16 y;
s16 z;
u8 framestate;
u8 animationState : 6;
u8 collisionLayer : 2;
} FIELDS;
u64 DWORD;
} KidHeapItem;
#define KID_HEAP_COUNT 0x14
typedef KidHeapItem KidHeap[KID_HEAP_COUNT];
#define KID_HEAP ((KidHeapItem*)this->myHeap)
void Kid(Entity* this) {
if ((this->flags & ENT_SCRIPTED) != 0) {
@ -307,7 +312,107 @@ void sub_080621AC(Entity* this) {
}
}
ASM_FUNC("asm/non_matching/kid/sub_080622F4.inc", void sub_080622F4(Entity* this))
#define KID_HEAP_SHIFT_RIGHT \
heapPtr = KID_HEAP; \
heapPtr += (KID_HEAP_COUNT - 2); \
for (i = 0; i < (KID_HEAP_COUNT - 1); i++) { \
heapPtr[1] = heapPtr[0]; \
heapPtr--; \
}
void sub_080622F4(Entity* this) {
s32 dx;
s32 dy;
s32 dist;
s32 i;
u32 animIndex; // used as 2nd param of InitAnimationForceUpdate
u32 animIndexTmp;
KidHeapItem* heapPtr;
KidHeapItem item;
// Prepended heap item is initialized from player's current state.
item.FIELDS.x = gPlayerEntity.x.HALF_U.HI;
item.FIELDS.y = gPlayerEntity.y.HALF_U.HI;
item.FIELDS.z = gPlayerEntity.z.HALF_U.HI;
item.FIELDS.framestate = gPlayerState.framestate;
item.FIELDS.animationState = gPlayerEntity.animationState;
item.FIELDS.collisionLayer = gPlayerEntity.collisionLayer;
heapPtr = this->myHeap;
if (heapPtr->FIELDS.framestate == 0x16 && item.FIELDS.framestate != 0x16) {
dx = this->x.HALF.HI - gPlayerEntity.x.HALF.HI;
dy = this->y.HALF.HI - gPlayerEntity.y.HALF.HI;
if (dx < 0)
dx = -dx;
if (dy < 0)
dy = -dy;
if (dx > 120 || dy > 80) {
this->field_0x68.HALF.LO = 0;
return;
}
sub_0806252C(this);
}
animIndex = 0;
if (item.DWORD != heapPtr->DWORD) {
KID_HEAP_SHIFT_RIGHT;
heapPtr = KID_HEAP;
heapPtr[0] = item;
animIndex = 0x4;
if ((s8)this->field_0x68.HALF.HI > 0) {
this->field_0x68.HALF.HI = this->field_0x68.HALF.HI - 1;
}
} else {
heapPtr += KID_HEAP_COUNT - 1;
if (heapPtr->FIELDS.z < 0) {
KID_HEAP_SHIFT_RIGHT;
animIndex = 0x4;
} else {
dist = sub_080041E8(gPlayerEntity.x.HALF.HI, gPlayerEntity.y.HALF.HI, (u16)heapPtr->FIELDS.x,
(u16)heapPtr->FIELDS.y);
dist = ((u32)dist) >> 0x4;
if (dist > 0x18) {
KID_HEAP_SHIFT_RIGHT;
animIndex = 0x4;
}
}
}
heapPtr = KID_HEAP;
heapPtr += +KID_HEAP_COUNT - 1;
this->x.HALF.HI = heapPtr->FIELDS.x;
this->y.HALF.HI = heapPtr->FIELDS.y;
this->z.HALF.HI = heapPtr->FIELDS.z;
this->animationState = heapPtr->FIELDS.animationState;
this->collisionLayer = heapPtr->FIELDS.collisionLayer;
if (((s8)this->field_0x68.HALF.HI) > 0) {
this->field_0x68.HALF.HI = this->field_0x68.HALF.HI - 1;
}
animIndexTmp = animIndex;
animIndex += this->animationState >> 1;
if (this->type == OBJECT) {
animIndex += 0x10;
}
if (!(animIndex == this->animIndex || (animIndexTmp == 0 && ((s8)this->field_0x68.HALF.HI) > 0))) {
InitAnimationForceUpdate(this, animIndex);
this->field_0x68.HALF.HI = 0x1e;
} else {
UpdateAnimationSingleFrame(this);
}
sub_0800451C(this);
return;
}
void sub_08062500(Entity* this) {
this->myHeap = zMalloc(sizeof(KidHeap));
@ -388,12 +493,12 @@ void sub_0806252C(Entity* this) {
x = 0;
for (loopVar = KID_HEAP_COUNT - 1; loopVar >= 0; loopVar--) {
item->x = r5 - (x >> 8);
item->y = (r5 >> 0x10) - (y >> 8);
item->z = r6;
item->framestate = r6 >> 0x10;
item->animationState = this->animationState & 0x3f;
item->collisionLayer = this->collisionLayer;
item->FIELDS.x = r5 - (x >> 8);
item->FIELDS.y = (r5 >> 0x10) - (y >> 8);
item->FIELDS.z = r6;
item->FIELDS.framestate = r6 >> 0x10;
item->FIELDS.animationState = this->animationState & 0x3f;
item->FIELDS.collisionLayer = this->collisionLayer;
item++;
y = y + r8;
x = x + r10;

View File

@ -2,16 +2,36 @@
#include "entity.h"
#include "functions.h"
typedef struct {
u16 x;
u16 y;
u16 z;
u8 framestate;
u8 animationState : 6;
u8 collisionLayer : 2;
extern s32 sub_080041E8(s32 x1, s32 y1, s32 x2, s32 y2);
typedef union {
struct {
u16 x;
u16 y;
u16 z;
u8 framestate;
u8 animationState : 6;
u8 collisionLayer : 2;
} FIELDS;
u64 DWORD;
} ZeldaFollowerItem;
typedef ZeldaFollowerItem ZeldaFollowerHeap[20];
#define ZELDA_FOLLOWER_HEAP_LEN 20
#define ZELDA_FOLLOWER_HEAP ((ZeldaFollowerItem *)this->myHeap)
#define ZELDA_FOLLOWER_HEAP_END ((ZeldaFollowerItem *)this->myHeap + (ZELDA_FOLLOWER_HEAP_LEN - 1))
#define ZELDA_FOLLOWER_HEAP_SHIFT_RIGHT(this, heapPtr) \
do { \
int i; \
heapPtr = ((ZeldaFollowerItem*)this->myHeap); \
heapPtr += (ZELDA_FOLLOWER_HEAP_LEN - 2); \
for ( i = 0; i < (ZELDA_FOLLOWER_HEAP_LEN - 1); i++) { \
heapPtr[1] = heapPtr[0]; \
heapPtr--; \
} \
} while (0)
void sub_08068318(Entity*);
void sub_0806854C(Entity*, u32*);
@ -35,10 +55,99 @@ void ZeldaFollower(Entity* this) {
}
}
ASM_FUNC("asm/non_matching/zeldaFollower/sub_08068318.inc", void sub_08068318(Entity* this))
void sub_08068318(Entity* this) {
s32 dist;
s16 z;
u32 animIndex;
u32 animIndexTmp;
ZeldaFollowerItem* heapPtr;
ZeldaFollowerItem item;
item.FIELDS.x = gPlayerEntity.x.HALF_U.HI;
item.FIELDS.y = gPlayerEntity.y.HALF_U.HI;
item.FIELDS.z = gPlayerEntity.z.HALF_U.HI;
item.FIELDS.framestate = gPlayerState.framestate;
item.FIELDS.animationState = gPlayerEntity.animationState;
item.FIELDS.collisionLayer = gPlayerEntity.collisionLayer;
heapPtr = this->myHeap;
if ( (heapPtr->FIELDS.framestate == 0xa && item.FIELDS.framestate != 0xa) ||
(heapPtr->FIELDS.framestate == 0x16 && item.FIELDS.framestate != 0x16)) {
this->x.HALF.HI = gPlayerEntity.x.HALF.HI;
this->y.HALF.HI = gPlayerEntity.y.HALF.HI;
this->spriteSettings.draw = 1;
sub_08068578(this);
}
animIndex = 0;
if (item.DWORD != heapPtr->DWORD || item.FIELDS.framestate == 0x16 || item.FIELDS.framestate == 0xa ) {
ZELDA_FOLLOWER_HEAP_SHIFT_RIGHT(this, heapPtr);
heapPtr = ZELDA_FOLLOWER_HEAP;
heapPtr[0] = item;
animIndex = 0x4;
if ((s8)this->field_0x68.HALF.HI > 0) {
this->field_0x68.HALF.HI = this->field_0x68.HALF.HI - 1;
}
} else {
heapPtr += ZELDA_FOLLOWER_HEAP_LEN - 1;
z = heapPtr->FIELDS.z;
if (z < 0) {
ZELDA_FOLLOWER_HEAP_SHIFT_RIGHT(this, heapPtr);
animIndex = 0x4;
} else {
dist = sub_080041E8(
gPlayerEntity.x.HALF.HI,
gPlayerEntity.y.HALF.HI,
(u16) heapPtr->FIELDS.x,
(u16) heapPtr->FIELDS.y
);
dist = ((u32)dist) >> 0x4;
if (dist > 0x18) {
ZELDA_FOLLOWER_HEAP_SHIFT_RIGHT(this, heapPtr);
animIndex = 0x4;
}
}
}
heapPtr = ZELDA_FOLLOWER_HEAP;
heapPtr += ZELDA_FOLLOWER_HEAP_LEN - 1;
this->x.HALF.HI = heapPtr->FIELDS.x;
this->y.HALF.HI = heapPtr->FIELDS.y;
this->z.HALF.HI = heapPtr->FIELDS.z;
this->animationState = heapPtr->FIELDS.animationState;
this->collisionLayer = heapPtr->FIELDS.collisionLayer;
if (heapPtr->FIELDS.framestate == 0x16 || heapPtr->FIELDS.framestate == 0xa) {
this->spriteSettings.draw = 0;
}
if (((s8)this->field_0x68.HALF.HI) > 0) {
this->field_0x68.HALF.HI = this->field_0x68.HALF.HI - 1;
}
animIndexTmp = animIndex;
animIndex += this->animationState >> 1;
if (!(animIndex == this->animIndex || (animIndexTmp == 0 && ((s8)this->field_0x68.HALF.HI) > 0))) {
InitAnimationForceUpdate(this, animIndex);
this->field_0x68.HALF.HI = 0x1e;
} else {
UpdateAnimationSingleFrame(this);
}
sub_0800451C(this);
if (this->z.HALF.HI < 0) {
sub_0806F854(this, 0x0, -0xc);
}
}
void sub_0806854C(Entity* this, u32* none) {
this->myHeap = zMalloc(sizeof(ZeldaFollowerHeap));
this->myHeap = zMalloc(sizeof(ZeldaFollowerItem[ZELDA_FOLLOWER_HEAP_LEN]));
if (this->myHeap != NULL) {
this->field_0x68.HALF.LO = 1;
RemoveInteractableObject(this);
@ -156,12 +265,12 @@ void sub_08068578(Entity* this) {
// Down here the u32 are suddendly accessed correctly as u16 and bitfields?
// How are the results of above u32 calculations used?
for (index = 0x13; index >= 0; index--) {
item->x = r5 - (x >> 8);
item->y = (r5 >> 0x10) - (y >> 8);
item->z = r6;
item->framestate = r6 >> 0x10;
item->animationState = this->animationState & 0x3f;
item->collisionLayer = this->collisionLayer;
item->FIELDS.x = r5 - (x >> 8);
item->FIELDS.y = (r5 >> 0x10) - (y >> 8);
item->FIELDS.z = r6;
item->FIELDS.framestate = r6 >> 0x10;
item->FIELDS.animationState = this->animationState & 0x3f;
item->FIELDS.collisionLayer = this->collisionLayer;
item++;
y = y + r8;
x = x + r10;

View File

@ -169,70 +169,76 @@ void sub_080AC560(Entity* this) {
this->y.WORD = entity->y.WORD - gSineTable[entity->direction + 0x40] * factor;
}
NONMATCH("asm/non_matching/gyorgTail/sub_080AC5E4.inc", bool32 sub_080AC5E4(Entity* this)) {
bool32 sub_080AC5E4(Entity* this) {
// TODO regalloc
Entity* entity;
Entity* new_var2;
Entity* entity2;
Entity* entity3;
Entity* entity4;
u8 uVar3;
if (this->type == 0) {
if (0x43 < gEntCount) {
if (gEntCount > 0x43) {
return FALSE;
}
this->field_0x78.HALF.HI = 0x11;
entity = CreateProjectile(0x22);
entity = CreateProjectile(GYORG_TAIL);
entity->type = this->type;
entity->type2 = 1;
entity->parent = this->parent;
entity->field_0x78.HALF.HI = 0x12;
this->child = entity;
entity2 = CreateProjectile(0x22);
entity2 = CreateProjectile(GYORG_TAIL);
entity2->type = this->type;
entity2->type2 = 2;
entity2->parent = this->parent;
entity2->field_0x78.HALF.HI = 0x14;
uVar3 = entity2->field_0x78.HALF.HI;
entity2->field_0x78.HALF.HI = uVar3;
entity->child = entity2;
entity3 = CreateProjectile(0x22);
entity3 = CreateProjectile(GYORG_TAIL);
entity3->type = this->type;
entity3->type2 = 3;
entity3->parent = this->parent;
entity3->child = NULL;
entity3->field_0x78.HALF.HI = 0;
entity2->child = entity3;
entity = CreateProjectile(GYORG_TAIL);
entity->type = this->type;
entity->type2 = 4;
entity->parent = this->parent;
entity->child = this;
entity->field_0x78.HALF.HI = 0x14;
} else {
if (0x44 < gEntCount) {
if (gEntCount > 0x44) {
return FALSE;
}
this->field_0x78.HALF.HI = 0xf;
entity = CreateProjectile(0x22);
entity = CreateProjectile(GYORG_TAIL);
entity->type = this->type;
entity->type2 = 1;
entity->parent = this->parent;
entity->field_0x78.HALF.HI = 0x10;
uVar3 = entity->field_0x78.HALF.HI;
entity->field_0x78.HALF.HI = uVar3;
this->child = entity;
entity2 = CreateProjectile(0x22);
entity2 = CreateProjectile(GYORG_TAIL);
entity2->type = this->type;
entity2->type2 = 2;
entity2->parent = this->parent;
entity2->child = NULL;
entity2->field_0x78.HALF.HI = 0x20;
entity->child = entity2;
entity = CreateProjectile(GYORG_TAIL);
entity->type = this->type;
entity->type2 = 4;
entity->parent = this->parent;
entity->child = this;
entity->field_0x78.HALF.HI = 0x10;
}
entity = CreateProjectile(0x22);
entity->type = this->type;
entity->type2 = 4;
entity->parent = this->parent;
entity->child = this;
entity->field_0x78.HALF.HI = uVar3;
return TRUE;
}
END_NONMATCH
void sub_080AC6F0(Entity* this) {
static const u8 gUnk_0812A9C0[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,

2
tools/.gitignore vendored
View File

@ -1,2 +1,4 @@
bin
cmake-build*
*.cmake
json*.hpp

View File

@ -29,7 +29,7 @@ AsmFile::AsmFile(std::string path) {
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL)
fatal_error("Failed to open \"%s\" for reading.\n", path.c_str());
fatal_error("Failed to open \"{}\" for reading.\n", path.c_str());
std::fseek(fp, 0, SEEK_END);
@ -40,7 +40,7 @@ AsmFile::AsmFile(std::string path) {
std::rewind(fp);
if (std::fread(m_buffer, m_size, 1, fp) != 1)
fatal_error("Failed to read \"%s\".\n", path.c_str());
fatal_error("Failed to read \"{}\".\n", path.c_str());
std::fclose(fp);
@ -159,7 +159,7 @@ void AsmFile::SkipString() {
fatal_error(INPUT_ERROR_MESSAGE("unexpected EOF in string\n"));
if (c == '\\') {
c = GetChar();
c = GetChar();
}
}
}

View File

@ -26,7 +26,7 @@ CFile::CFile(std::string path) {
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL)
fatal_error("Failed to open \"%s\" for reading.\n", path.c_str());
fatal_error("Failed to open \"{}\" for reading.\n", path.c_str());
std::fseek(fp, 0, SEEK_END);
@ -38,7 +38,7 @@ CFile::CFile(std::string path) {
std::rewind(fp);
if (std::fread(m_buffer, m_size, 1, fp) != 1)
fatal_error("Failed to read \"%s\".\n", path.c_str());
fatal_error("Failed to read \"{}\".\n", path.c_str());
std::fclose(fp);

View File

@ -25,7 +25,7 @@ SourceFileType GetFileType(std::string& path) {
std::size_t pos = path.find_last_of('.');
if (pos == std::string::npos)
fatal_error("no file extension in path \"%s\"\n", path.c_str());
fatal_error("no file extension in path \"{}\"\n", path.c_str());
std::string extension = path.substr(pos + 1);
@ -38,7 +38,7 @@ SourceFileType GetFileType(std::string& path) {
else if (extension == "inc")
return SourceFileType::Inc;
else
fatal_error("Unrecognized extension \"%s\"\n", extension.c_str());
fatal_error("Unrecognized extension \"{}\"\n", extension.c_str());
// Unreachable
return SourceFileType::Cpp;