diff --git a/.gitignore b/.gitignore index a6d3f3b8f..aa4a3a5c4 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ tools/ido_recomp/* binary ctx.c graphs/ *.c.m2c +tools/**/*dSYM/ tools/decomp-permuter/ tools/mips_to_c/ diff --git a/Makefile b/Makefile index 082203bae..5c4cdd549 100644 --- a/Makefile +++ b/Makefile @@ -36,12 +36,7 @@ else endif endif -# Threads to compress and extract assets with, TODO improve later -ifeq ($(DETECTED_OS),linux) - N_THREADS ?= $(shell nproc) -else - N_THREADS ?= 1 -endif +N_THREADS ?= $(shell nproc) #### Tools #### ifeq ($(shell type mips-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0) @@ -246,7 +241,7 @@ setup: $(MAKE) -C tools python3 tools/fixbaserom.py python3 tools/extract_baserom.py - python3 extract_assets.py -t $(N_THREADS) + python3 extract_assets.py -j $(N_THREADS) ## Assembly generation disasm: diff --git a/README.md b/README.md index 80d1e5d54..845a10cc6 100644 --- a/README.md +++ b/README.md @@ -23,26 +23,35 @@ in an experimental and research phase and cannot currently be used traditionally source code base for general changes. ``` -**This repo does not include any assets or code necessary for compiling the ROM. A prior copy of the game is required to extract the required assets.** +This is a WIP **decompilation** of ***The Legend of Zelda: Majora's Mask***. The purpose of the project is to recreate a source code base for the game from scratch, using information found inside the game along with static and/or dynamic analysis. **It is not producing a PC port.** For more information you can get in touch with the team on our [Discord server](https://discord.zelda64.dev). -This is a decompilation of Legend of Zelda: Majora's Mask (US) 1.0 +The only build currently supported is N64 US, but other versions are planned to be supported. -It builds the following ROM: +It currently builds the following ROM: * mm.us.rev1.rom.z64 `md5: 2a0a8acb61538235bc1094d297fb6556` +**This repo does not include any assets or assembly code necessary for compiling the ROM. A prior copy of the game is required to extract the required assets.** + Please refer to the following for more information: - [Website](https://zelda64.dev/) - [Discord](https://discord.zelda64.dev/) - [How to Contribute](CONTRIBUTING.md) + ## Installation ### Windows For Windows 10, install WSL and a distribution by following this [Windows Subsystem for Linux Installation Guide](https://docs.microsoft.com/en-us/windows/wsl/install-win10). -We recommend using Debian or Ubuntu 18.04 Linux distributions. +We recommend using Debian or Ubuntu 20.04 Linux distributions. + + +### MacOS + +Preparation is covered in a [separate document](docsBUILDING_MACOS.md). + ### Linux (Native or under WSL / VM) @@ -110,30 +119,23 @@ This means that something is wrong with the ROM's contents. Either the baserom f Running `make init` will also make the `./expected` directory and copy all of the files there, which will be useful when running the diff script. The diff script is useful in decompiling functions and can be ran with this command: `./tools/asm-differ/diff.py -wmo3 ` -**Note**: to speed up the build, you can either: -* Pass `-jN` to `make setup` and `make`, where N is the number of threads to use in the build, e.g. `make -j4`. The generally-accepted wisdom is to use the number of virtual cores your computer has. -* Pass `-j` to `make setup` and `make`, to use as many threads as possible, but beware that this can use too much memory on lower-end systems. -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`). +**Note**: to speed up the build, you can pass `-jN` to `make setup` and `make`, where N is the number of threads to use in the build, e.g. `make -j4`. The generally-accepted wisdom is to use the number of virtual cores your computer has, which is the output of `nproc` (which should be installed as part of `coreutils`). +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 `-jN`). +(`-j` also exists, which uses unlimited jobs, but is generally slower.) -**Note**: if you rename symbols, it is recommended that you use the `tools/rename_sym.sh` to ensure that you cover all instances, including the tables which are used to generate the `asm/` directory. - -Usage: `tools/rename_sym.sh old_name new_name`. Example: - -```bash -tools/rename_sym.sh func_808A3428 EnTorch2_UpdateIdle -``` ## Contributing All contributions are welcome. This is a group effort, and even small contributions can make a difference. Some tasks also don't require much knowledge to get started. -Anyone who wishes to contribute to the OOT or MM projects **must not have accessed leaked source code at any point in time** for Nintendo 64 SDK, iQue player SDK, libultra, Ocarina of Time, Majora's Mask, Animal Crossing/Animal Forest, or any other game that shares the same game engine or significant portions of code to a Zelda 64 game or any other console similar to the Nintendo 64. +Please note that is is our strict policy that *Anyone who wishes to contribute to the OOT or MM projects **must not have accessed leaked source code at any point in time** for Nintendo 64 SDK, iQue player SDK, libultra, Ocarina of Time, Majora's Mask, Animal Crossing/Animal Forest, or any other game that shares the same game engine or significant portions of code to a Zelda 64 game or any other console similar to the Nintendo 64.* Most discussions happen on our [Discord Server](https://discord.zelda64.dev), where you are welcome to ask if you need help getting started, or if you have any questions regarding this project and other decompilation projects. For more information on getting started, see our [Contributing Guide](CONTRIBUTING.md) and our [Code Review Guidelines](REVIEWING.md) to see what code quality guidelines we follow. + ## FAQ ### Q: Why does MM use transient assembly? diff --git a/assets/xml/objects/object_fall.xml b/assets/xml/objects/object_fall.xml index f84ecffc5..5a90c5a24 100644 --- a/assets/xml/objects/object_fall.xml +++ b/assets/xml/objects/object_fall.xml @@ -8,6 +8,9 @@ + + + diff --git a/assets/xml/objects/object_oF1d_map.xml b/assets/xml/objects/object_oF1d_map.xml index 9eac29aaa..78d5fbc9c 100644 --- a/assets/xml/objects/object_oF1d_map.xml +++ b/assets/xml/objects/object_oF1d_map.xml @@ -71,7 +71,10 @@ - + + + + @@ -98,7 +101,7 @@ - + diff --git a/docs/BUILDING_MACOS.md b/docs/BUILDING_MACOS.md new file mode 100644 index 000000000..17b683442 --- /dev/null +++ b/docs/BUILDING_MACOS.md @@ -0,0 +1,83 @@ +# Building on macOS + +**N.B. C++17 is required to build the asset processing program that we use (ZAPD), so check your OS version can support this before proceeding** + + +## Dependencies + +For macOS, use Homebrew to install the following dependencies: + +* coreutils +* make +* python3 +* libpng +* bash +* clang-format 11 + +You can install them with the following commands: + +```bash +brew update +brew install coreutils make python3 libpng bash clang-format@11 +``` + +(The repository expects Homebrew-installed programs to be either linked correctly in `$PATH` etc. or in their default locations.) + + +## Building mips-linux-binutils + +The following instructions are written for MacOS users but should apply to any Unix-like system, with maybe some modifications at the end regarding the bash_profile. + +Create destination dir for binutils +```bash +sudo mkdir -p /opt/cross +``` + +Create and enter local working dir +```bash +mkdir ~/binutils-tmp +cd ~/binutils-tmp +``` + +Get and extract binutils source +```bash +wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.bz2 +tar xjf binutils-2.35.tar.bz2 +``` +(You may find this command does not work: if so, just access the URL in a browser and save it to `~/binutils-tmp`.) + +Create and enter a build directory +```bash +mkdir build-binutils +cd build-binutils +``` + +Configure the build +```bash +../binutils-2.35/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-gprof --disable-gdb --disable-werror +``` + +Make and install binutils +```bash +make -j +sudo make install +``` + +Edit your `~/.bash_profile`/`~/.zsh_profile` (or whichever shell you use) to add the new binutils binaries to the system PATH +```bash +echo "export PATH=$PATH:/opt/cross/bin" >> ~/.bash_profile +``` + +Reload ~/.bash_profile (or just launch a new terminal tab) +```bash +source ~/.bash_profile +``` + +If this worked, you can now delete the temporary directory `~/binutils-tmp`. + + +## Final note + +Apple's version of `make` is very out-of-date, so you should use the brew-installed `gmake` in place of `make` in this repo from now on. + +You should now be able to continue from [step 2](README.md#2-clone-the-repository) of the Linux instructions. diff --git a/extract_assets.py b/extract_assets.py index a7825af1f..dda5efaec 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -import argparse, json, os, signal, time, colorama -from multiprocessing import Pool, Event, Manager +import argparse, json, os, signal, time, colorama, multiprocessing -colorama.init(); +colorama.init() EXTRACTED_ASSETS_NAMEFILE = ".extracted-assets.json" @@ -71,33 +70,33 @@ def initializeWorker(abort, unaccounted: bool, extractedAssetsTracker: dict, man def main(): parser = argparse.ArgumentParser(description="baserom asset extractor") parser.add_argument("-s", "--single", help="asset path relative to assets/, e.g. objects/gameplay_keep") - parser.add_argument("-t", "--threads", help="Number of cpu cores to extract with.") parser.add_argument("-f", "--force", help="Force the extraction of every xml instead of checking the touched ones.", action="store_true") + parser.add_argument("-j", "--jobs", help="Number of cpu cores to extract with.") parser.add_argument("-u", "--unaccounted", help="Enables ZAPD unaccounted detector warning system.", action="store_true") parser.add_argument("-Z", help="Pass the argument on to ZAPD, e.g. `-ZWunaccounted` to warn about unaccounted blocks in XMLs. Each argument should be passed separately, *without* the leading dash.", metavar="ZAPD_ARG", action="append") args = parser.parse_args() - global ZAPDArgs; - ZAPDArgs = ""; + global ZAPDArgs + ZAPDArgs = "" if args.Z is not None: - badZAPDArg = False; + badZAPDArg = False for i in range(len(args.Z)): z = args.Z[i] if z[0] == '-': - print(f"{colorama.Fore.LIGHTRED_EX}error{colorama.Fore.RESET}: argument \"{z}\" starts with \"-\", which is not supported.", file=os.sys.stderr); - badZAPDArg = True; + print(f"{colorama.Fore.LIGHTRED_EX}error{colorama.Fore.RESET}: argument \"{z}\" starts with \"-\", which is not supported.", file=os.sys.stderr) + badZAPDArg = True else: - args.Z[i] = "-" + z; + args.Z[i] = "-" + z if badZAPDArg: - exit(1); + exit(1) - ZAPDArgs = " ".join(args.Z); - print("Using extra ZAPD arguments: " + ZAPDArgs); + ZAPDArgs = " ".join(args.Z) + print("Using extra ZAPD arguments: " + ZAPDArgs) global mainAbort - mainAbort = Event() - manager = Manager() + mainAbort = multiprocessing.Event() + manager = multiprocessing.Manager() signal.signal(signal.SIGINT, SignalHandler) extractedAssetsTracker = manager.dict() @@ -125,12 +124,20 @@ def main(): if file.endswith(".xml"): xmlFiles.append(fullPath) - numCores = int(args.threads or 0) - if numCores <= 0: - numCores = 1 - print("Extracting assets with " + str(numCores) + " CPU core" + ("s" if numCores > 1 else "") + ".") - with Pool(numCores, initializer=initializeWorker, initargs=(mainAbort, args.unaccounted, extractedAssetsTracker, manager)) as p: - p.map(ExtractFunc, xmlFiles) + try: + numCores = int(args.jobs or 0) + if numCores <= 0: + numCores = 1 + print("Extracting assets with " + str(numCores) + " CPU core" + ("s" if numCores > 1 else "") + ".") + with multiprocessing.get_context("fork").Pool(numCores, initializer=initializeWorker, initargs=(mainAbort, args.unaccounted, extractedAssetsTracker, manager)) as p: + p.map(ExtractFunc, xmlFiles) + except (multiprocessing.ProcessError, TypeError): + print("Warning: Multiprocessing exception ocurred.", file=os.sys.stderr) + print("Disabling mutliprocessing.", file=os.sys.stderr) + + initializeWorker(mainAbort, args.unaccounted, extractedAssetsTracker, manager) + for singlePath in xmlFiles: + ExtractFunc(singlePath) with open(EXTRACTED_ASSETS_NAMEFILE, 'w', encoding='utf-8') as f: serializableDict = dict() diff --git a/format.sh b/format.sh index 89a0906ad..1c9389a9a 100755 --- a/format.sh +++ b/format.sh @@ -5,6 +5,16 @@ FORMAT_OPTS="-i -style=file" TIDY_OPTS="-p . --fix --fix-errors" COMPILER_OPTS="-fno-builtin -std=gnu90 -Iinclude -Isrc -D_LANGUAGE_C -DNON_MATCHING" +# https://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/index.html +# "gets the last character of the file pipes it into read, which will exit with a nonzero exit code if it encounters EOF before newline (so, if the last character of the file isn't a newline). If read exits nonzero, then append a newline onto the file using echo (if read exits 0, that satisfies the ||, so the echo command isn't run)." (https://stackoverflow.com/a/34865616) +function add_final_newline () { + for file in "$@" + do + tail -c1 $file | read -r _ || echo >> $file + done +} +export -f add_final_newline + shopt -s globstar if [ -z `command -v clang-format-${FORMAT_VER}` ] @@ -20,7 +30,7 @@ if (( $# > 0 )); then echo "Running clang-tidy..." clang-tidy ${TIDY_OPTS} "$@" -- ${COMPILER_OPTS} &> /dev/null echo "Adding missing final new lines..." - sed -i -e '$a\' "$@" + add_final_newline "$@" echo "Done formatting file(s) $*" exit fi @@ -31,6 +41,6 @@ clang-format-${FORMAT_VER} ${FORMAT_OPTS} src/**/*.c echo "Running clang-tidy..." clang-tidy ${TIDY_OPTS} src/**/*.c -- ${COMPILER_OPTS} &> /dev/null echo "Adding missing final new lines..." -find src/ -type f -name "*.c" -exec sed -i -e '$a\' {} \; -find assets/xml/ -type f -name "*.xml" -exec sed -i -e '$a\' {} \; +find src/ -type f -name "*.c" -exec bash -c 'add_final_newline "$@"' bash {} + +find assets/xml/ -type f -name "*.xml" -exec bash -c 'add_final_newline "$@"' bash {} + echo "Done formatting all files." diff --git a/include/functions.h b/include/functions.h index ad92fbeca..8fd2e769f 100644 --- a/include/functions.h +++ b/include/functions.h @@ -97,7 +97,7 @@ void FaultDrawer_SetCharPad(s8 padW, s8 padH); void FaultDrawer_SetCursor(s32 x, s32 y); void FaultDrawer_FillScreen(void); void* FaultDrawer_FormatStringFunc(void* arg, const char* str, size_t count); -void FaultDrawer_VPrintf(const char* str, char* args); +void FaultDrawer_VPrintf(const char* fmt, va_list ap); void FaultDrawer_Printf(const char* fmt, ...); void FaultDrawer_DrawText(s32 x, s32 y, const char* fmt, ...); void FaultDrawer_SetDrawerFB(void* fb, u16 w, u16 h); @@ -3791,9 +3791,9 @@ void func_8019F230(void); // cancel // void func_8019F258(void); // void func_8019F300(void); void func_8019F420(Vec3f* pos, u16 sfxId); -// void func_8019F4AC(void); +void func_8019F4AC(Vec3f* pos, u16 sfxId); void func_8019F540(u8 arg0); -// void func_8019F570(void); +void func_8019F570(Vec3f* pos, s8 arg1); // void func_8019F5AC(void); // void func_8019F638(void); // void func_8019F780(void); @@ -3884,7 +3884,7 @@ void func_801A3CD8(s8 param_1); // void func_801A3D98(void); // void func_801A3E38(void); // void func_801A3EC0(void); -// void func_801A3F54(void); +void func_801A3F54(s32 arg0); // void func_801A3F6C(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6); // void func_801A3FB4(void); // void func_801A3FFC(UNK_TYPE1 param_1); diff --git a/include/variables.h b/include/variables.h index e41db0546..8b9999058 100644 --- a/include/variables.h +++ b/include/variables.h @@ -1260,7 +1260,7 @@ extern UNK_PTR D_801C02F8; // extern UNK_TYPE1 D_801C07F0; // extern UNK_TYPE1 D_801C0820; // extern UNK_TYPE1 D_801C0838; -// extern UNK_TYPE1 D_801C0850; +extern Gfx D_801C0850[]; // extern UNK_TYPE1 D_801C0860; extern UNK_PTR D_801C0870; // extern UNK_TYPE1 D_801C0890; @@ -3773,7 +3773,7 @@ extern u16 gFramebuffer0[SCREEN_HEIGHT][SCREEN_WIDTH]; // keep objects extern Gfx D_040008D0[]; -extern UNK_TYPE D_040032B0; +extern Gfx D_040032B0[]; extern UNK_TYPE D_0400CF58; extern UNK_TYPE D_0400CF88; extern UNK_TYPE D_0400CF98; @@ -3976,7 +3976,7 @@ extern UNK_TYPE D_04062020; extern UNK_TYPE D_04062040; extern UNK_TYPE D_04062060; extern Gfx D_040622C0[]; -extern UNK_TYPE D_0406AB30; +extern Gfx D_0406AB30[]; extern UNK_TYPE D_0406B730; extern UNK_TYPE D_0406BB0C; extern UNK_TYPE D_0406F380; diff --git a/spec b/spec index 75e8c7d28..69a6097c9 100644 --- a/spec +++ b/spec @@ -1946,8 +1946,7 @@ beginseg name "ovl_Effect_Ss_Stick" compress include "build/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.o" - include "build/data/ovl_Effect_Ss_Stick/ovl_Effect_Ss_Stick.data.o" - include "build/data/ovl_Effect_Ss_Stick/ovl_Effect_Ss_Stick.reloc.o" + include "build/src/overlays/effects/ovl_Effect_Ss_Stick/ovl_Effect_Ss_Stick_reloc.o" endseg beginseg @@ -3120,9 +3119,7 @@ beginseg name "ovl_En_Fall" compress include "build/src/overlays/actors/ovl_En_Fall/z_en_fall.o" - include "build/data/ovl_En_Fall/ovl_En_Fall.data.o" - include "build/data/ovl_En_Fall/ovl_En_Fall.bss.o" - include "build/data/ovl_En_Fall/ovl_En_Fall.reloc.o" + include "build/src/overlays/actors/ovl_En_Fall/ovl_En_Fall_reloc.o" endseg beginseg @@ -3362,8 +3359,7 @@ beginseg name "ovl_Obj_Tokeidai" compress include "build/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.o" - include "build/data/ovl_Obj_Tokeidai/ovl_Obj_Tokeidai.data.o" - include "build/data/ovl_Obj_Tokeidai/ovl_Obj_Tokeidai.reloc.o" + include "build/src/overlays/actors/ovl_Obj_Tokeidai/ovl_Obj_Tokeidai_reloc.o" endseg beginseg @@ -3854,8 +3850,7 @@ beginseg name "ovl_En_Talk_Gibud" compress include "build/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.o" - include "build/data/ovl_En_Talk_Gibud/ovl_En_Talk_Gibud.data.o" - include "build/data/ovl_En_Talk_Gibud/ovl_En_Talk_Gibud.reloc.o" + include "build/src/overlays/actors/ovl_En_Talk_Gibud/ovl_En_Talk_Gibud_reloc.o" endseg beginseg @@ -4579,8 +4574,7 @@ beginseg name "ovl_En_Geg" compress include "build/src/overlays/actors/ovl_En_Geg/z_en_geg.o" - include "build/data/ovl_En_Geg/ovl_En_Geg.data.o" - include "build/data/ovl_En_Geg/ovl_En_Geg.reloc.o" + include "build/src/overlays/actors/ovl_En_Geg/ovl_En_Geg_reloc.o" endseg beginseg diff --git a/src/boot_O2/boot_80086760.c b/src/boot_O2/boot_80086760.c index 1a9b37453..3c75bcd3f 100644 --- a/src/boot_O2/boot_80086760.c +++ b/src/boot_O2/boot_80086760.c @@ -24,30 +24,30 @@ f32 func_80086760(f32 x) { // Unused // Math_FFloorF f32 func_80086794(f32 x) { - func_80086C70(x); + return func_80086C70(x); } // Unused // Math_FCeilF f32 func_800867B4(f32 x) { - func_80086CA8(x); + return func_80086CA8(x); } // Unused // Math_FRoundF f32 func_800867D4(f32 x) { - func_80086D50(x); + return func_80086D50(x); } // Unused // Math_FTruncF f32 func_800867F4(f32 x) { - func_80086CE0(x); + return func_80086CE0(x); } // Math_FNearbyIntF f32 func_80086814(f32 x) { - func_80086D18(x); + return func_80086D18(x); } /** diff --git a/src/overlays/actors/ovl_En_Fall/z_en_fall.c b/src/overlays/actors/ovl_En_Fall/z_en_fall.c index 43582bf26..11a98fabc 100644 --- a/src/overlays/actors/ovl_En_Fall/z_en_fall.c +++ b/src/overlays/actors/ovl_En_Fall/z_en_fall.c @@ -1,10 +1,24 @@ /* * File: z_en_fall.c * Overlay: ovl_En_Fall - * Description: The Moon and related effects + * Description: The moon and related effects, along with the Moon's Tear that falls from its eye. + * + * This actor handles mutliple types of moon as well as a variety of effects. Specifically, it handles: + * - A high-detail moon, used in Termina Field, the Clock Tower, and a few cutscenes + * - A high-detail open-mouthed moon, used in the cutscene prior to warping to the moon's interior. + * - An enlarged high-detail moon, used for when the moon is crashing. + * - A low-detail moon, used everywhere else. Its object file is named "Lodmoon". + * - The Moon's Tear that can be seen falling from the telescope, along with its associated fire trail. + * - The ball of fire that surrounds the moon when it is crashing. + * - The debris that rises from the ground as the moon is crashing. + * - The ring of fire that expands outward when the moon is almost done crashing. */ #include "z_en_fall.h" +#include "objects/object_fall/object_fall.h" +#include "objects/object_fall2/object_fall2.h" +#include "objects/object_lodmoon/object_lodmoon.h" +#include "objects/object_moonston/object_moonston.h" #define FLAGS 0x00000030 @@ -14,16 +28,34 @@ void EnFall_Init(Actor* thisx, GlobalContext* globalCtx); void EnFall_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnFall_Update(Actor* thisx, GlobalContext* globalCtx); -void func_80A6C3FC(EnFall* this, GlobalContext* globalCtx); -void func_80A6C9A8(EnFall* this, GlobalContext* globalCtx); -void func_80A6CA9C(EnFall* this, GlobalContext* globalCtx); -void func_80A6CB74(EnFall* this, GlobalContext* globalCtx); -void func_80A6CD38(EnFall* this, GlobalContext* globalCtx); -void func_80A6CD74(EnFall* this, GlobalContext* globalCtx); -void func_80A6CF60(EnFall* this, GlobalContext* globalCtx); -void func_80A6CF70(EnFall* this, GlobalContext* globalCtx); +void EnFall_Setup(EnFall* this, GlobalContext* globalCtx); +void EnFall_CrashingMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx); +void EnFall_StoppedOpenMouthMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx); +void EnFall_StoppedClosedMouthMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx); +void EnFall_ClockTowerOrTitleScreenMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx); +void EnFall_Moon_PerformDefaultActions(EnFall* this, GlobalContext* globalCtx); +void EnFall_MoonsTear_Fall(EnFall* this, GlobalContext* globalCtx); +void EnFall_FireBall_Update(Actor* thisx, GlobalContext* globalCtx); +void EnFall_RisingDebris_Update(Actor* thisx, GlobalContext* globalCtx); +void EnFall_FireRing_Update(Actor* thisx, GlobalContext* globalCtx); +void EnFall_Moon_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnFall_OpenMouthMoon_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnFall_LodMoon_DrawWithoutLerp(Actor* thisx, GlobalContext* globalCtx); +void EnFall_LodMoon_DrawWithLerp(Actor* thisx, GlobalContext* globalCtx); +void EnFall_FireBall_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnFall_RisingDebris_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnFall_FireRing_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnFall_MoonsTear_Draw(Actor* thisx, GlobalContext* globalCtx); + +typedef struct { + u8 dListIndex; + Vec3f pos; + Vec3f velocity; + Vec3s rot; +} EnFallDebrisParticle; + +EnFallDebrisParticle debrisParticles[50]; -#if 0 const ActorInit En_Fall_InitVars = { ACTOR_EN_FALL, ACTORCAT_ITEMACTION, @@ -36,75 +68,792 @@ const ActorInit En_Fall_InitVars = { (ActorFunc)NULL, }; -#endif +/** + * Sets the scale of the moon depending on the current day. On the Final Day, + * it also moves the moon closer to the ground depending on the current time. + */ +void EnFall_Moon_AdjustScaleAndPosition(EnFall* this, GlobalContext* globalCtx) { + u16 currentTime = gSaveContext.save.time; + u16 dayStartTime = this->dayStartTime; + f32 finalDayRelativeHeight; -extern UNK_TYPE D_06000198; -extern UNK_TYPE D_060004C0; -extern UNK_TYPE D_060010E0; -extern UNK_TYPE D_060011D0; -extern UNK_TYPE D_06001220; -extern UNK_TYPE D_06002970; -extern UNK_TYPE D_06004E38; -extern UNK_TYPE D_060077F0; + if (currentTime < dayStartTime) { + finalDayRelativeHeight = 1.0f - (((f32)dayStartTime - (f32)currentTime) * (1.0f / 0x10000)); + } else { + finalDayRelativeHeight = ((f32)currentTime - (f32)dayStartTime) * (1.0f / 0x10000); + } + switch (CURRENT_DAY) { + case 0: + Actor_SetScale(&this->actor, this->scale * 1.2f); + this->actor.world.pos.y = this->actor.home.pos.y; + break; + case 1: + Actor_SetScale(&this->actor, this->scale * 2.4f); + this->actor.world.pos.y = this->actor.home.pos.y; + break; + case 2: + Actor_SetScale(&this->actor, this->scale * 3.6f); + this->actor.world.pos.y = this->actor.home.pos.y; + break; + case 3: + Actor_SetScale(&this->actor, this->scale * 3.6f); + if (EN_FALL_TYPE(&this->actor) == EN_FALL_TYPE_LODMOON_INVERTED_STONE_TOWER) { + this->actor.world.pos.y = + this->actor.home.pos.y + (finalDayRelativeHeight * 6700.0f * (this->scale * 6.25f)); + } else { + this->actor.world.pos.y = + this->actor.home.pos.y - (finalDayRelativeHeight * 6700.0f * (this->scale * 6.25f)); + } + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6BF90.s") +void EnFall_RisingDebris_ResetParticles(EnFall* this) { + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6C1DC.s") + for (i = 0; i < ARRAY_COUNT(debrisParticles); i++) { + debrisParticles[i].dListIndex = 3; + } + this->activeDebrisParticleCount = 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/EnFall_Init.s") +void EnFall_Init(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + s32 objectIndex; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/EnFall_Destroy.s") + this->eyeGlowIntensity = 0.0f; + this->flags = 0; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6C3AC.s") + // This system is basically never used in the final game; all instances + // of EnFall will use the default case. + switch (EN_FALL_SCALE(&this->actor)) { + case 1: + this->scale = 0.08f; + break; + case 2: + this->scale = 0.04f; + break; + case 3: + this->scale = 0.02f; + break; + case 4: + this->scale = 0.01f; + break; + default: + this->scale = 0.16f; + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6C3FC.s") + switch (EN_FALL_TYPE(&this->actor)) { + case EN_FALL_TYPE_LODMOON_NO_LERP: + case EN_FALL_TYPE_LODMOON: + case EN_FALL_TYPE_LODMOON_INVERTED_STONE_TOWER: + objectIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_LODMOON); + break; + case EN_FALL_TYPE_MOONS_TEAR: + objectIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_MOONSTON); + break; + case EN_FALL_TYPE_STOPPED_MOON_OPEN_MOUTH: + objectIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_FALL2); + break; + default: + objectIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_FALL); + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6C7C0.s") + if (objectIndex < 0) { + Actor_MarkForDeath(&this->actor); + return; + } + this->objIndex = objectIndex; + this->actionFunc = EnFall_Setup; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6C9A8.s") +void EnFall_Destroy(Actor* thisx, GlobalContext* globalCtx) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CA9C.s") +/** + * Finds the Termina Field moon so the Moon's Tear can spawn in the correct place. + */ +Actor* EnFall_MoonsTear_GetTerminaFieldMoon(GlobalContext* globalCtx) { + Actor* itemAction = globalCtx->actorCtx.actorList[ACTORCAT_ITEMACTION].first; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CB74.s") + while (itemAction != NULL) { + if (itemAction->id == ACTOR_EN_FALL && EN_FALL_TYPE(itemAction) == EN_FALL_TYPE_TERMINA_FIELD_MOON) { + return itemAction; + } + itemAction = itemAction->next; + } + return NULL; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CD38.s") +void EnFall_Setup(EnFall* this, GlobalContext* globalCtx) { + Actor* moon; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CD74.s") + if (Object_IsLoaded(&globalCtx->objectCtx, this->objIndex)) { + this->actor.objBankIndex = this->objIndex; + this->actionFunc = EnFall_Moon_PerformDefaultActions; + switch (EN_FALL_TYPE(&this->actor)) { + case EN_FALL_TYPE_TITLE_SCREEN_MOON: + this->actor.draw = EnFall_Moon_Draw; + this->actionFunc = EnFall_ClockTowerOrTitleScreenMoon_PerformCutsceneActions; + Actor_SetScale(&this->actor, this->scale); + break; + case EN_FALL_TYPE_STOPPED_MOON_CLOSED_MOUTH: + this->actor.draw = EnFall_Moon_Draw; + this->actionFunc = EnFall_StoppedClosedMouthMoon_PerformCutsceneActions; + Actor_SetScale(&this->actor, this->scale * 3.0f); + if (!(gSaveContext.save.weekEventReg[0x19] & 2)) { + Actor_MarkForDeath(&this->actor); + } + break; + case EN_FALL_TYPE_CLOCK_TOWER_MOON: + this->actionFunc = EnFall_ClockTowerOrTitleScreenMoon_PerformCutsceneActions; + Actor_SetScale(&this->actor, this->scale * 3.0f); + this->actor.draw = EnFall_Moon_Draw; + if (gSaveContext.save.weekEventReg[0x19] & 2) { + Actor_MarkForDeath(&this->actor); + } + break; + case EN_FALL_TYPE_CRASHING_MOON: + this->actor.draw = EnFall_Moon_Draw; + Actor_SetScale(&this->actor, this->scale * 5.3999996f); + this->actionFunc = EnFall_CrashingMoon_PerformCutsceneActions; + break; + case EN_FALL_TYPE_CRASH_FIRE_BALL: + this->actor.update = EnFall_FireBall_Update; + this->actor.draw = EnFall_FireBall_Draw; + this->scale = 1.0f; + this->actor.shape.rot.z = 0; + this->fireBallIntensity = 0.0f; + this->fireBallAlpha = 100; + this->actor.shape.rot.x = this->actor.shape.rot.z; + break; + case EN_FALL_TYPE_CRASH_RISING_DEBRIS: + this->actor.update = EnFall_RisingDebris_Update; + this->actor.draw = EnFall_RisingDebris_Draw; + this->scale = 1.0f; + EnFall_RisingDebris_ResetParticles(this); + Actor_SetScale(&this->actor, 1.0f); + this->actor.shape.rot.x = 0; + break; + case EN_FALL_TYPE_LODMOON_NO_LERP: + this->actor.draw = EnFall_LodMoon_DrawWithoutLerp; + this->dayStartTime = CLOCK_TIME(6, 0); + this->currentDay = CURRENT_DAY; + EnFall_Moon_AdjustScaleAndPosition(this, globalCtx); + break; + case EN_FALL_TYPE_LODMOON: + case EN_FALL_TYPE_LODMOON_INVERTED_STONE_TOWER: + this->actor.draw = EnFall_LodMoon_DrawWithLerp; + this->dayStartTime = CLOCK_TIME(6, 0); + this->currentDay = CURRENT_DAY; + EnFall_Moon_AdjustScaleAndPosition(this, globalCtx); + break; + case EN_FALL_TYPE_MOONS_TEAR: + this->actor.update = EnFall_Update; + this->actor.draw = NULL; + this->actionFunc = EnFall_MoonsTear_Fall; + Actor_SetScale(&this->actor, 0.02f); + if (!(globalCtx->actorCtx.unk5 & 2)) { + Actor_MarkForDeath(&this->actor); + } + moon = EnFall_MoonsTear_GetTerminaFieldMoon(globalCtx); + this->actor.child = moon; + if (moon == NULL) { + Actor_MarkForDeath(&this->actor); + } + break; + case EN_FALL_TYPE_STOPPED_MOON_OPEN_MOUTH: + this->actor.draw = NULL; + this->actionFunc = EnFall_StoppedOpenMouthMoon_PerformCutsceneActions; + Actor_SetScale(&this->actor, this->scale * 3.0f); + break; + case EN_FALL_TYPE_CRASH_FIRE_RING: + this->actor.update = EnFall_FireRing_Update; + this->actor.draw = EnFall_FireRing_Draw; + Actor_SetScale(&this->actor, 0.2f); + break; + default: + this->actor.draw = EnFall_Moon_Draw; + this->dayStartTime = CLOCK_TIME(6, 0); + this->currentDay = CURRENT_DAY; + EnFall_Moon_AdjustScaleAndPosition(this, globalCtx); + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CECC.s") +void EnFall_CrashingMoon_HandleGiantsCutscene(EnFall* this, GlobalContext* globalCtx) { + static s32 sGiantsCutsceneState = 0; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CF60.s") + if (globalCtx->sceneNum == SCENE_00KEIKOKU && gSaveContext.sceneSetupIndex == 1 && globalCtx->csCtx.unk_12 == 0) { + switch (sGiantsCutsceneState) { + case 0: + if (globalCtx->csCtx.state != 0) { + sGiantsCutsceneState += 2; + } + break; + case 2: + if (CHECK_QUEST_ITEM(QUEST_REMAINS_ODOWLA) && CHECK_QUEST_ITEM(QUEST_REMAINS_GOHT) && + CHECK_QUEST_ITEM(QUEST_REMAINS_GYORG) && CHECK_QUEST_ITEM(QUEST_REMAINS_TWINMOLD)) { + if (gSaveContext.save.weekEventReg[0x5D] & 4) { + if (ActorCutscene_GetCanPlayNext(0xC)) { + ActorCutscene_Start(0xC, &this->actor); + sGiantsCutsceneState++; + } else { + ActorCutscene_SetIntentToPlay(0xC); + } + } else if (ActorCutscene_GetCanPlayNext(0xB)) { + ActorCutscene_Start(0xB, &this->actor); + gSaveContext.save.weekEventReg[0x5D] |= 4; + sGiantsCutsceneState++; + } else { + ActorCutscene_SetIntentToPlay(0xB); + } + } else if (globalCtx->csCtx.frames > 1600) { + globalCtx->nextEntranceIndex = 0x2C00; + gSaveContext.nextCutsceneIndex = 0xFFF2; + globalCtx->sceneLoadFlag = 0x14; + globalCtx->unk_1887F = 2; + gSaveContext.nextTransition = 2; + sGiantsCutsceneState = 9; + } + break; + case 9: + globalCtx->csCtx.frames--; + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6CF70.s") +void EnFall_CrashingMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx) { + EnFall_CrashingMoon_HandleGiantsCutscene(this, globalCtx); + if (func_800EE29C(globalCtx, 0x85)) { + if (func_800EE29C(globalCtx, 0x85) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0 == 1) { + this->actor.draw = NULL; + } else { + this->actor.draw = EnFall_Moon_Draw; + if (func_800EE29C(globalCtx, 0x85) && + globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0 == 2) { + func_800EDF24(&this->actor, globalCtx, func_800EE200(globalCtx, 0x85)); + } + } + } else { + this->actor.draw = NULL; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/EnFall_Update.s") +void EnFall_StoppedOpenMouthMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x85)) { + switch (globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0) { + case 3: + if (this->eyeGlowIntensity == 0.0f) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_MOON_EYE_FLASH); + } + this->eyeGlowIntensity += 0.033333335f; + if (this->eyeGlowIntensity > 1.0f) { + this->eyeGlowIntensity = 1.0f; + } + break; + case 4: + this->actor.draw = EnFall_OpenMouthMoon_Draw; + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D100.s") +void EnFall_StoppedClosedMouthMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x85)) { + switch (globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0) { + case 2: + func_800EDF24(&this->actor, globalCtx, func_800EE200(globalCtx, 0x85)); + break; + case 4: + this->actor.draw = NULL; + break; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D220.s") + if (globalCtx->sceneNum == SCENE_OKUJOU && gSaveContext.sceneSetupIndex == 2) { + switch (globalCtx->csCtx.unk_12) { + case 0: + switch (globalCtx->csCtx.frames) { + case 1060: + Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOON_SCREAM1); + break; + case 1089: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_MOON_CRY); + break; + case 1303: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_SLIP_MOON); + break; + } + if (globalCtx->csCtx.frames >= 1145) { + func_800B9010(&this->actor, NA_SE_EV_FALL_POWER - SFX_FLAG); + } + break; + case 1: + switch (globalCtx->csCtx.frames) { + case 561: + Audio_PlayActorSound2(&this->actor, NA_SE_EN_MOON_SCREAM1); + break; + case 590: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_MOON_CRY); + break; + case 737: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_SLIP_MOON); + break; + } + if (globalCtx->csCtx.frames >= 650) { + func_800B9010(&this->actor, NA_SE_EV_FALL_POWER - SFX_FLAG); + } + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D444.s") +void EnFall_ClockTowerOrTitleScreenMoon_PerformCutsceneActions(EnFall* this, GlobalContext* globalCtx) { + if (globalCtx->csCtx.state != 0 && globalCtx->sceneNum == SCENE_OKUJOU) { + func_800B9010(&this->actor, NA_SE_EV_MOON_FALL - SFX_FLAG); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D504.s") +/** + * This is rarely used in the final game. One example of where it *is* used + * is when the moon is crashing; there is a second, smaller moon hidden within + * the larger moon that uses this action function. + */ +void EnFall_Moon_PerformDefaultActions(EnFall* this, GlobalContext* globalCtx) { + u16 currentDay; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D698.s") + if (func_800EE29C(globalCtx, 0x85)) { + if (func_800EE29C(globalCtx, 0x85) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0 == 1) { + this->actor.draw = NULL; + } else { + Actor_SetScale(&this->actor, this->scale * 3.6f); + this->actor.draw = EnFall_Moon_Draw; + if (func_800EE29C(globalCtx, 0x85) && + globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x85)]->unk0 == 2) { + func_800EDF24(&this->actor, globalCtx, func_800EE200(globalCtx, 0x85)); + } + } + } else { + if (this->actor.draw == NULL) { + this->actor.draw = EnFall_Moon_Draw; + } + currentDay = CURRENT_DAY; + if ((u16)this->currentDay != (u32)currentDay) { + this->currentDay = currentDay; + this->dayStartTime = gSaveContext.save.time; + } + EnFall_Moon_AdjustScaleAndPosition(this, globalCtx); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D75C.s") +void EnFall_MoonsTear_Initialize(EnFall* this) { + s32 pad[2]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D88C.s") + this->actor.draw = EnFall_MoonsTear_Draw; + if (this->actor.child != NULL) { + // The focus of the child needs to be shifted in EnFall_Moon_Draw first, + // otherwise the tear will spawn in the wrong place. + Math_Vec3f_Copy(&this->actor.world.pos, &this->actor.child->focus.pos); + } + this->actor.world.rot.y = Math_Vec3f_Yaw(&this->actor.world.pos, &this->actor.home.pos); + this->actor.world.rot.x = Math_Vec3f_Pitch(&this->actor.world.pos, &this->actor.home.pos); + this->actor.speedXZ = Math_Vec3f_DistXYZ(&this->actor.world.pos, &this->actor.home.pos) / 82.0f; + this->actor.shape.rot.x = this->actor.world.rot.x; + this->actor.shape.rot.y = this->actor.world.rot.y; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6D98C.s") +void EnFall_DoNothing(EnFall* this, GlobalContext* globalCtx) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6DA7C.s") +void EnFall_MoonsTear_Fall(EnFall* this, GlobalContext* globalCtx) { + s32 pad; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6DC20.s") + if (func_800EE29C(globalCtx, 0x205) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x205)]->unk0 == 2 && + this->actor.draw == NULL) { + EnFall_MoonsTear_Initialize(this); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6DC40.s") + if (this->actor.draw != NULL) { + if (Math_Vec3f_StepTo(&this->actor.world.pos, &this->actor.home.pos, this->actor.speedXZ) <= 0.0f) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_GORON_BOUND_1); + gSaveContext.save.weekEventReg[0x4A] |= 0x80; + gSaveContext.save.weekEventReg[0x4A] |= 0x20; + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_TEST, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, -2); + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_CLEAR_TAG, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, CLEAR_TAG_LARGE_EXPLOSION); + this->actor.draw = NULL; + this->actionFunc = EnFall_DoNothing; + } else { + func_800B9010(&this->actor, NA_SE_EV_MOONSTONE_FALL - SFX_FLAG); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6DD3C.s") +void EnFall_Update(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + this->actionFunc(this, globalCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6E07C.s") +/** + * Updates the alpha for every vertex in the fire ball so that some parts of + * the sphere are more transparent or opaque than others. + */ +void EnFall_FireBall_SetPerVertexAlpha(f32 fireBallAlpha) { + static u8 sAlphaTableIndex[] = { + 4, 4, 0, 1, 1, 1, 1, 1, 1, 3, 3, 0, 0, 3, 0, 1, 1, 1, 4, 0, 4, 0, 1, 1, 1, 3, 0, 3, 0, 1, 1, 1, 4, 4, 1, + 1, 0, 4, 4, 0, 1, 1, 1, 1, 1, 1, 3, 3, 0, 0, 3, 3, 0, 0, 1, 1, 1, 1, 1, 4, 0, 4, 4, 0, 4, 4, 1, 1, 1, 1, + 1, 1, 3, 3, 0, 0, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 4, 4, 0, 4, 0, 1, 1, 1, 3, 0, 3, 3, 0, 0, 1, 1, 1, 1, 1, + 1, 4, 4, 0, 4, 4, 0, 1, 1, 1, 1, 1, 1, 3, 3, 0, 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 0, 1, 1, 0, 0, 1, 0, + 2, 0, 0, 1, 0, 2, 0, 0, 2, 1, 2, 0, 1, 0, 1, 0, 0, 1, 2, 2, 0, 0, 2, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, + 0, 0, 2, 0, 2, 2, 0, 1, 1, 0, 0, 1, 0, 0, 1, 2, 2, 0, 0, 0, 2, 2, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, + }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6E214.s") + s32 pad; + u8 perVertexAlphaTable[5]; + Vtx* vertices = Lib_SegmentedToVirtual(&object_fall_Vtx_0004C0); + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Fall/func_80A6E37C.s") + if (fireBallAlpha > 1.0f) { + fireBallAlpha = 1.0f; + } + perVertexAlphaTable[0] = 0; + perVertexAlphaTable[1] = (s8)(255.0f * fireBallAlpha); + perVertexAlphaTable[2] = (s8)(155.0f * fireBallAlpha); + perVertexAlphaTable[3] = (s8)(104.0f * fireBallAlpha); + perVertexAlphaTable[4] = (s8)(54.0f * fireBallAlpha); + + for (i = 0; i < ARRAY_COUNT(sAlphaTableIndex); i++, vertices++) { + vertices->v.cn[3] = perVertexAlphaTable[sAlphaTableIndex[i]]; + } +} + +void EnFall_FireBall_Update(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + + if (globalCtx->sceneNum == SCENE_00KEIKOKU && gSaveContext.sceneSetupIndex == 0 && globalCtx->csCtx.unk_12 == 2) { + globalCtx->skyboxCtx.rotY -= 0.05f; + } + + if (func_800EE29C(globalCtx, 0x1C2)) { + this->actor.draw = EnFall_FireBall_Draw; + if (this->flags & EN_FALL_FLAG_FIRE_BALL_INTENSIFIES) { + this->fireBallIntensity += 0.01f; + if (this->fireBallIntensity > 1.0f) { + this->fireBallIntensity = 1.0f; + } + } + func_800EDF24(&this->actor, globalCtx, func_800EE200(globalCtx, 0x1C2)); + + switch (globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x1C2)]->unk0) { + default: + this->actor.draw = NULL; + this->fireBallAlpha = 0; + break; + case 2: + if (this->fireBallAlpha < 100) { + this->fireBallAlpha += 4; + } + if (this->fireBallAlpha > 100) { + this->fireBallAlpha = 100; + } + EnFall_FireBall_SetPerVertexAlpha(this->fireBallAlpha * 0.01f); + break; + case 3: + if (this->fireBallAlpha > 0) { + this->fireBallAlpha -= 2; + } + if (this->fireBallAlpha < 0) { + this->fireBallAlpha = 0; + } + EnFall_FireBall_SetPerVertexAlpha(this->fireBallAlpha * 0.01f); + break; + case 4: + this->flags |= EN_FALL_FLAG_FIRE_BALL_INTENSIFIES; + break; + case 5: + break; + } + } else { + this->actor.draw = NULL; + } + + if (func_800EE29C(globalCtx, 0x1C2) && this->fireBallAlpha > 0) { + func_8019F128(NA_SE_EV_MOON_FALL_LAST - SFX_FLAG); + } + Actor_SetScale(&this->actor, this->scale * 1.74f); +} + +void EnFall_RisingDebris_UpdateParticles(EnFall* this) { + s32 i; + + for (i = 0; i < ARRAY_COUNT(debrisParticles); i++) { + if (debrisParticles[i].dListIndex < 3) { + debrisParticles[i].pos.x += debrisParticles[i].velocity.x; + debrisParticles[i].pos.y += debrisParticles[i].velocity.y; + debrisParticles[i].pos.z += debrisParticles[i].velocity.z; + debrisParticles[i].rot.x += 0x64; + debrisParticles[i].rot.y += 0xC8; + debrisParticles[i].rot.z += 0x12C; + if ((this->actor.world.pos.y + 3000.0f) < debrisParticles[i].pos.y) { + debrisParticles[i].dListIndex = 3; + this->activeDebrisParticleCount--; + } + } + } +} + +s32 EnFall_RisingDebris_InitializeParticles(EnFall* this) { + s16 angle; + s32 i; + f32 scale; + + for (i = 0; i < ARRAY_COUNT(debrisParticles); i++) { + if (debrisParticles[i].dListIndex >= 3) { + debrisParticles[i].dListIndex = (s32)Rand_ZeroFloat(3.0f); + debrisParticles[i].pos.x = this->actor.world.pos.x; + debrisParticles[i].pos.y = this->actor.world.pos.y; + debrisParticles[i].pos.z = this->actor.world.pos.z; + angle = randPlusMinusPoint5Scaled(0x10000); + scale = (1.0f - (Rand_ZeroFloat(1.0f) * Rand_ZeroFloat(1.0f))) * 3000.0f; + debrisParticles[i].pos.x += Math_SinS(angle) * scale; + debrisParticles[i].pos.z += Math_CosS(angle) * scale; + debrisParticles[i].velocity.x = 0.0f; + debrisParticles[i].velocity.z = 0.0f; + debrisParticles[i].velocity.y = 80.0f; + debrisParticles[i].rot.x = randPlusMinusPoint5Scaled(0x10000); + debrisParticles[i].rot.y = randPlusMinusPoint5Scaled(0x10000); + debrisParticles[i].rot.z = randPlusMinusPoint5Scaled(0x10000); + this->activeDebrisParticleCount++; + return true; + } + } + + return false; +} + +void EnFall_RisingDebris_Update(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + + if (func_800EE29C(globalCtx, 0x1C3)) { + if (func_800EE29C(globalCtx, 0x1C3) && + globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x1C3)]->unk0 == 2) { + EnFall_RisingDebris_UpdateParticles(this); + EnFall_RisingDebris_InitializeParticles(this); + } else if (this->activeDebrisParticleCount != 0) { + EnFall_RisingDebris_ResetParticles(this); + } + } else if (thisx->home.rot.x != 0) { + EnFall_RisingDebris_UpdateParticles(this); + EnFall_RisingDebris_InitializeParticles(this); + } +} + +void EnFall_FireRing_Update(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + + if (func_800EE29C(globalCtx, 0x1C2) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x1C2)]->unk0 == 5) { + if (!(this->flags & EN_FALL_FLAG_FIRE_RING_APPEARS)) { + Audio_PlayActorSound2(&this->actor, NA_SE_IT_DM_RING_EXPLOSION); + } + this->flags |= EN_FALL_FLAG_FIRE_RING_APPEARS; + } + if (this->flags & EN_FALL_FLAG_FIRE_RING_APPEARS) { + this->fireRingAlpha += 0.033333335f; + if (this->fireRingAlpha > 1.0f) { + this->fireRingAlpha = 1.0f; + } + if (this->actor.scale.x < 18.0f) { + this->actor.scale.x += 0.2f; + } + this->actor.scale.z = this->actor.scale.x; + this->actor.scale.y = Math_SinS(this->fireWallYScale) * 5.0f; + if (this->fireWallYScale < 0x4000) { + this->fireWallYScale += 0x147; + } + } +} + +void EnFall_Moon_Draw(Actor* thisx, GlobalContext* globalCtx) { + // This offsets the moon's focus so that the Moon's Tear actually falls + // out of its eye when looking at it through the telescope. + static Vec3f sFocusOffset[] = { 1800.0f, 1000.0f, 4250.0f }; + EnFall* this = THIS; + s32 primColor; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + Matrix_MultiplyVector3fByState(sFocusOffset, &this->actor.focus.pos); + primColor = (this->eyeGlowIntensity * 200.0f) + 40.0f; + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0x80, primColor, primColor, primColor, 255); + gSPDisplayList(POLY_OPA_DISP++, object_fall_DL_0077F0); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnFall_OpenMouthMoon_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnFall* this = THIS; + s32 primColor; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + primColor = (this->eyeGlowIntensity * 200.0f) + 40.0f; + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0x80, primColor, primColor, primColor, 255); + gSPDisplayList(POLY_OPA_DISP++, object_fall2_DL_002970); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnFall_LodMoon_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnFall* this = THIS; + s32 primColor; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 20, 25, 30, 0, 0x3E7, 0x3200); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2); + gSPLoadGeometryMode(POLY_OPA_DISP++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_SHADING_SMOOTH); + primColor = (this->eyeGlowIntensity * 200.0f) + 40.0f; + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0x80, primColor, primColor, primColor, 255); + gSPDisplayList(POLY_OPA_DISP++, object_lodmoon_DL_0010E0); + gSPLoadGeometryMode(POLY_OPA_DISP++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH); + gSPDisplayList(POLY_OPA_DISP++, object_lodmoon_DL_001158); + POLY_OPA_DISP = func_801660B8(globalCtx, POLY_OPA_DISP); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnFall_LodMoon_DrawWithoutLerp(Actor* thisx, GlobalContext* globalCtx) { + EnFall_LodMoon_Draw(thisx, globalCtx); +} + +/** + * If the moon is more than 9000 units away from the eye, this will lerp it + * to be 9000 units away before drawing it. + */ +void EnFall_LodMoon_DrawWithLerp(Actor* thisx, GlobalContext* globalCtx) { + f32 distanceToEye = Actor_DistanceToPoint(thisx, &globalCtx->view.eye); + f32 scale; + Vec3f translation; + + if (distanceToEye > 9000.0f) { + scale = 9000.0f / distanceToEye; + translation.x = (-(globalCtx->view.eye.x - thisx->world.pos.x) * scale) + globalCtx->view.eye.x; + translation.y = (-(globalCtx->view.eye.y - thisx->world.pos.y) * scale) + globalCtx->view.eye.y; + translation.z = (-(globalCtx->view.eye.z - thisx->world.pos.z) * scale) + globalCtx->view.eye.z; + Matrix_InsertTranslation(translation.x, translation.y, translation.z, MTXMODE_NEW); + Matrix_Scale(thisx->scale.x, thisx->scale.y, thisx->scale.z, MTXMODE_APPLY); + Matrix_RotateY(thisx->shape.rot.y, MTXMODE_APPLY); + Matrix_InsertXRotation_s(thisx->shape.rot.x, MTXMODE_APPLY); + Matrix_InsertZRotation_s(thisx->shape.rot.z, MTXMODE_APPLY); + } + EnFall_LodMoon_Draw(thisx, globalCtx); +} + +void EnFall_FireBall_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnFall* this = THIS; + u32 gameplayFrames = globalCtx->gameplayFrames; + + OPEN_DISPS(globalCtx->state.gfxCtx); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C2DC(globalCtx->state.gfxCtx); + this->fireBallYTexScroll1 += (s32)(4.0f + (this->fireBallIntensity * 12.0f)); + this->fireBallYTexScroll2 += (s32)(2.0f + (this->fireBallIntensity * 6.0f)); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, + (s32)(((1.0f - this->fireBallIntensity) * 160.0f) + (255.0f * this->fireBallIntensity)), + (s32)((70.0f * (1.0f - this->fireBallIntensity)) + (255.0f * this->fireBallIntensity)), + (s32)(70.0f * (1.0f - this->fireBallIntensity)), 255); + gDPSetEnvColor( + POLY_XLU_DISP++, (s32)(((1.0f - this->fireBallIntensity) * 50.0f) + (200.0f * this->fireBallIntensity)), + (s32)(20.0f * (1.0f - this->fireBallIntensity)), (s32)(20.0f * (1.0f - this->fireBallIntensity)), 255); + + // Glowing sphere of fire + gSPSegment(POLY_XLU_DISP++, 0x09, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, gameplayFrames, -this->fireBallYTexScroll2, 64, 64, 1, + -gameplayFrames, -this->fireBallYTexScroll1, 64, 64)); + + // "Flecks" of fire + gSPSegment(POLY_XLU_DISP++, 0x0A, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, gameplayFrames * 2, -this->fireBallYTexScroll1, 64, 64, 1, + -gameplayFrames * 2, -this->fireBallYTexScroll1, 64, 64)); + + gDPSetColorDither(POLY_XLU_DISP++, G_CD_NOISE); + gDPSetAlphaDither(POLY_XLU_DISP++, G_AD_NOISE); + gSPDisplayList(POLY_XLU_DISP++, object_fall_DL_0011D0); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnFall_RisingDebris_Draw(Actor* thisx, GlobalContext* globalCtx) { + static Gfx* sDebrisDLists[] = { object_fall_DL_000220, object_fall_DL_000428, object_fall_DL_000498 }; + EnFall* this = THIS; + f32 scale = this->scale * 0.06f; + s32 i; + + OPEN_DISPS(globalCtx->state.gfxCtx); + func_8012C28C(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, object_fall_DL_000198); + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + for (i = 0; i < ARRAY_COUNT(debrisParticles); i++) { + if (debrisParticles[i].dListIndex < 3) { + Matrix_InsertTranslation(debrisParticles[i].pos.x, debrisParticles[i].pos.y, debrisParticles[i].pos.z, + MTXMODE_NEW); + Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); + Matrix_InsertRotation(debrisParticles[i].rot.x, debrisParticles[i].rot.y, debrisParticles[i].rot.z, + MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, sDebrisDLists[debrisParticles[i].dListIndex]); + } + } + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnFall_FireRing_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnFall* this = THIS; + + if (!(this->fireRingAlpha <= 0.0f)) { + if (this->fireRingAlpha > 1.0f) { + this->fireRingAlpha = 1.0f; + } + OPEN_DISPS(globalCtx->state.gfxCtx); + AnimatedMat_DrawXlu(globalCtx, Lib_SegmentedToVirtual(&object_fall_Matanimheader_004E38)); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C2DC(globalCtx->state.gfxCtx); + gDPSetColorDither(POLY_XLU_DISP++, G_CD_NOISE); + gDPSetAlphaDither(POLY_XLU_DISP++, G_AD_NOISE); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 255, (s32)(this->fireRingAlpha * 255.0f)); + gSPDisplayList(POLY_XLU_DISP++, object_fall_DL_003C30); + CLOSE_DISPS(globalCtx->state.gfxCtx); + } +} + +void EnFall_MoonsTear_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + + OPEN_DISPS(globalCtx->state.gfxCtx); + AnimatedMat_Draw(globalCtx, Lib_SegmentedToVirtual(&object_moonston_Matanimheader_001220)); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C28C(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, object_moonston_DL_000400); + Matrix_Scale(3.0f, 3.0f, 6.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C2DC(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_XLU_DISP++, object_moonston_DL_0004C8); + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Fall/z_en_fall.h b/src/overlays/actors/ovl_En_Fall/z_en_fall.h index fb149f7e5..0124087d9 100644 --- a/src/overlays/actors/ovl_En_Fall/z_en_fall.h +++ b/src/overlays/actors/ovl_En_Fall/z_en_fall.h @@ -3,14 +3,54 @@ #include "global.h" +#define EN_FALL_SCALE(thisx) ((thisx)->params & 0x7F) +#define EN_FALL_TYPE(thisx) (((thisx)->params & 0xF80) >> 7) + +#define EN_FALL_FLAG_FIRE_BALL_INTENSIFIES (1 << 0) +#define EN_FALL_FLAG_FIRE_RING_APPEARS (1 << 1) + +typedef enum { + /* 0 */ EN_FALL_TYPE_TERMINA_FIELD_MOON, + /* 1 */ EN_FALL_TYPE_TITLE_SCREEN_MOON, + /* 2 */ EN_FALL_TYPE_CRASHING_MOON, + /* 3 */ EN_FALL_TYPE_CRASH_FIRE_BALL, + /* 4 */ EN_FALL_TYPE_CRASH_RISING_DEBRIS, + /* 5 */ EN_FALL_TYPE_LODMOON_NO_LERP, // unused in final game + /* 6 */ EN_FALL_TYPE_LODMOON, + /* 7 */ EN_FALL_TYPE_STOPPED_MOON_CLOSED_MOUTH, + /* 8 */ EN_FALL_TYPE_MOONS_TEAR, + /* 9 */ EN_FALL_TYPE_CLOCK_TOWER_MOON, + /* 10 */ EN_FALL_TYPE_STOPPED_MOON_OPEN_MOUTH, + /* 11 */ EN_FALL_TYPE_CRASH_FIRE_RING, + /* 12 */ EN_FALL_TYPE_LODMOON_INVERTED_STONE_TOWER, +} EnFallType; + struct EnFall; typedef void (*EnFallActionFunc)(struct EnFall*, GlobalContext*); typedef struct EnFall { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x1C]; - /* 0x0160 */ EnFallActionFunc actionFunc; + /* 0x000 */ Actor actor; + /* 0x144 */ s16 dayStartTime; + /* 0x146 */ s16 currentDay; + /* 0x148 */ u8 objIndex; + /* 0x14C */ f32 scale; + /* 0x150 */ union { + f32 eyeGlowIntensity; + f32 fireBallIntensity; + f32 fireRingAlpha; + }; + /* 0x154 */ u16 flags; + /* 0x158 */ union { + s32 fireBallAlpha; + s32 activeDebrisParticleCount; + }; + /* 0x15C */ union { + s16 fireBallYTexScroll1; + s16 fireWallYScale; + }; + /* 0x15E */ s16 fireBallYTexScroll2; + /* 0x160 */ EnFallActionFunc actionFunc; } EnFall; // size = 0x164 extern const ActorInit En_Fall_InitVars; diff --git a/src/overlays/actors/ovl_En_Geg/z_en_geg.c b/src/overlays/actors/ovl_En_Geg/z_en_geg.c index 260f3d74e..ab8af7dcb 100644 --- a/src/overlays/actors/ovl_En_Geg/z_en_geg.c +++ b/src/overlays/actors/ovl_En_Geg/z_en_geg.c @@ -5,6 +5,11 @@ */ #include "z_en_geg.h" +#include "overlays/actors/ovl_En_Bom/z_en_bom.h" +#include "objects/object_oF1d_map/object_oF1d_map.h" +#include "objects/object_taisou/object_taisou.h" +#include "objects/object_hakugin_demo/object_hakugin_demo.h" +#include "objects/gameplay_keep/gameplay_keep.h" #define FLAGS 0x00000019 @@ -31,7 +36,6 @@ void func_80BB32AC(EnGeg* this, GlobalContext* globalCtx); void func_80BB3318(EnGeg* this, GlobalContext* globalCtx); void func_80BB347C(EnGeg* this, GlobalContext* globalCtx); -#if 0 const ActorInit En_Geg_InitVars = { ACTOR_EN_GEG, ACTORCAT_NPC, @@ -44,25 +48,49 @@ const ActorInit En_Geg_InitVars = { (ActorFunc)EnGeg_Draw, }; -// static ColliderSphereInit sSphereInit = { -static ColliderSphereInit D_80BB3E70 = { - { COLTYPE_NONE, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_SPHERE, }, - { ELEMTYPE_UNK0, { 0x20000000, 0x00, 0x04 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderSphereInit sSphereInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_SPHERE, + }, + { + ELEMTYPE_UNK0, + { 0x20000000, 0x00, 0x04 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 0, { { 0, 0, 0 }, 0 }, 100 }, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80BB3E9C = { - { COLTYPE_HIT1, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_HIT1, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 0, 0, 0, { 0, 0, 0 } }, }; -// sColChkInfoInit -static CollisionCheckInfoInit2 D_80BB3EC8 = { 0, 0, 0, 0, MASS_IMMOVABLE }; +static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE }; -// static DamageTable sDamageTable = { -static DamageTable D_80BB3ED4 = { +static DamageTable sDamageTable = { /* Deku Nut */ DMG_ENTRY(1, 0x0), /* Deku Stick */ DMG_ENTRY(1, 0x0), /* Horse trample */ DMG_ENTRY(1, 0x0), @@ -97,87 +125,953 @@ static DamageTable D_80BB3ED4 = { /* Powder Keg */ DMG_ENTRY(1, 0x0), }; -#endif +static ActorAnimationEntryS sAnimations[] = { + { &object_oF1d_map_Anim_011D98, 1.0f, 0, -1, 0, 0 }, { &object_oF1d_map_Anim_011D98, 1.0f, 0, -1, 0, -4 }, + { &object_oF1d_map_Anim_012DE0, 2.0f, 0, -1, 2, 0 }, { &object_oF1d_map_Anim_012DE0, 2.0f, 0, -1, 2, -4 }, + { &object_oF1d_map_Anim_012DE0, -2.0f, 0, -1, 2, -4 }, { &object_oF1d_map_Anim_003E28, 1.0f, 0, -1, 0, 0 }, + { &object_oF1d_map_Anim_003E28, 1.0f, 0, -1, 0, -4 }, { &object_oF1d_map_Anim_0039D8, 1.0f, 0, -1, 2, -4 }, + { &object_taisou_Anim_0016C8, 1.0f, 0, -1, 0, 0 }, { &object_taisou_Anim_004DD4, 1.0f, 0, -1, 0, 0 }, + { &object_taisou_Anim_00283C, 1.0f, 0, -1, 0, 0 }, { &object_taisou_Anim_007764, 1.0f, 0, -1, 0, 0 }, + { &object_taisou_Anim_005EE0, 1.0f, 0, -1, 0, 0 }, { &object_taisou_Anim_002C48, 1.0f, 0, -1, 0, 0 }, + { &object_taisou_Anim_0031D8, 1.0f, 0, -1, 0, 0 }, { &object_taisou_Anim_005790, 1.0f, 0, -1, 0, 0 }, + { &object_oF1d_map_Anim_003650, 1.0f, 0, -1, 0, 0 }, { &object_hakugin_demo_Anim_002704, 1.0f, 0, -1, 2, 0 }, + { &object_hakugin_demo_Anim_003378, 1.0f, 0, -1, 0, -4 }, { &object_oF1d_map_Anim_0135E8, 1.0f, 0, -1, 2, 0 }, + { &object_oF1d_map_Anim_014CE0, 1.0f, 0, -1, 0, 0 }, +}; -extern ColliderSphereInit D_80BB3E70; -extern ColliderCylinderInit D_80BB3E9C; -extern CollisionCheckInfoInit2 D_80BB3EC8; -extern DamageTable D_80BB3ED4; +u16 func_80BB16D0(EnGeg* this) { + switch (this->unk_496) { + case 0xD5E: + return 0xD5F; + case 0xD5F: + return 0xD60; + case 0xD60: + return 0xD61; + case 0xD62: + return 0xD63; + case 0xD64: + return 0xD65; + case 0xD66: + return 0xD67; + case 0xD67: + return 0xD68; + case 0xD68: + return 0xD69; + case 0xD6A: + return 0xD6B; + case 0xD6B: + return 0xD6C; + case 0xD6C: + return 0xD6D; + case 0xD6E: + return 0xD6F; + case 0xD70: + return 0xD71; + case 0xD71: + return 0xD72; + case 0xD73: + return 0xD74; + case 0xD74: + return 0xD75; + case 0xD89: + return 0xD8A; + } + return 0; +} -extern UNK_TYPE D_06004DB0; -extern UNK_TYPE D_060091A8; -extern UNK_TYPE D_06012DE0; +void func_80BB178C(EnGeg* this, GlobalContext* globalCtx) { + Vec3f sp34 = this->actor.world.pos; + Collider* collider; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB16D0.s") + if (this->unk_230 & 1) { + this->colliderSphere.dim.worldSphere.center.x = sp34.x; + this->colliderSphere.dim.worldSphere.center.y = sp34.y; + this->colliderSphere.dim.worldSphere.center.y += (s16)this->actor.shape.yOffset; + this->colliderSphere.dim.worldSphere.center.z = sp34.z; + this->colliderSphere.dim.modelSphere.radius = 20; + this->colliderSphere.dim.worldSphere.radius = + this->colliderSphere.dim.modelSphere.radius * this->colliderSphere.dim.scale; + collider = &this->colliderSphere.base; + } else { + f32 radius = 24.0f; + f32 height = 62.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB178C.s") + this->colliderCylinder.dim.pos.x = sp34.x; + this->colliderCylinder.dim.pos.y = sp34.y; + this->colliderCylinder.dim.pos.z = sp34.z; + this->colliderCylinder.dim.radius = radius; + this->colliderCylinder.dim.height = height; + collider = &this->colliderCylinder.base; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB18FC.s") + if (collider != NULL) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, collider); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 30.0f, 12.0f, 0.0f, 5); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB19C0.s") +s32 func_80BB18FC(EnGeg* this, Actor* actor) { + if (actor->bgCheckFlags & 1) { + f32 sp24 = Math_Vec3f_DistXZ(&this->actor.world.pos, &actor->world.pos); + f32 sp20 = Math_Vec3f_DiffY(&this->actor.world.pos, &actor->world.pos); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1B14.s") + if ((sp24 < 150.0f) && (fabsf(sp20) < 5.0f)) { + this->unk_230 |= 0x20; + actor->speedXZ = 0.0f; + actor->velocity.y = 0.0f; + this->actor.child = actor; + actor->parent = &this->actor; + return true; + } + } + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1C1C.s") +Vec3f* func_80BB19C0(Vec3f* arg0, EnGeg* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f sp40; + Vec3f sp34; + s16 sp32 = player->actor.world.rot.y + 0x4000; + s16 sp30; + f32 sp2C; + f32 sp28; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1C8C.s") + sp40.x = (Math_SinS(sp32) * 50.0f) + player->actor.world.pos.x; + sp40.y = player->actor.world.pos.y; + sp40.z = (Math_CosS(sp32) * 50.0f) + player->actor.world.pos.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1D04.s") + sp2C = Math_Vec3f_DistXZ(&this->actor.world.pos, &sp40); + sp30 = player->actor.world.rot.y - 0x4000; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1D64.s") + sp34.x = (Math_SinS(sp30) * 50.0f) + player->actor.world.pos.x; + sp34.y = player->actor.world.pos.y; + sp34.z = (Math_CosS(sp30) * 50.0f) + player->actor.world.pos.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB1FCC.s") + if (Math_Vec3f_DistXZ(&this->actor.world.pos, &sp34) < sp2C) { + // clang-format off + *arg0 = sp40; return arg0; + // clang-format on + } else { + *arg0 = sp34; + } + return arg0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2020.s") +u8 func_80BB1B14(EnGeg* this, GlobalContext* globalCtx) { + Actor* explosive; + Actor* mm = func_ActorCategoryIterateById(globalCtx, NULL, ACTORCAT_ITEMACTION, ACTOR_EN_MM); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2088.s") + if (mm != NULL) { + this->unk_4B0 = Math_Vec3f_Yaw(&this->actor.world.pos, &mm->world.pos); + if (func_80BB18FC(this, mm)) { + return 1; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB217C.s") + explosive = globalCtx->actorCtx.actorList[ACTORCAT_EXPLOSIVES].first; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB221C.s") + while (explosive != NULL) { + if ((explosive->id == ACTOR_EN_BOM) && func_80BB18FC(this, explosive)) { + this->unk_4B0 = Math_Vec3f_Yaw(&this->actor.world.pos, &explosive->world.pos); + if (this->unk_230 & 0x200) { + return 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2520.s") + if (((EnBom*)explosive)->unk_1F9 == 0) { + return 2; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB26EC.s") + return 3; + } + explosive = explosive->next; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB27D4.s") + this->unk_230 &= ~0x200; + return 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2944.s") +void func_80BB1C1C(EnGeg* this) { + u16 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2A54.s") + this->unk_49C[0] = this->actor.cutscene; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2B1C.s") + for (i = 1; i < ARRAY_COUNT(this->unk_49C); i++) { + this->unk_49C[i] = ActorCutscene_GetAdditionalCutscene(this->unk_49C[i - 1]); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2E00.s") +void func_80BB1C8C(EnGeg* this) { + if (DECR(this->unk_240) == 0) { + this->unk_23E++; + if (this->unk_23E >= 3) { + this->unk_240 = Rand_S16Offset(30, 30); + this->unk_23E = 0; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB2F7C.s") +void func_80BB1D04(EnGeg* this) { + f32 temp; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB30B4.s") + if (this->unk_230 & 1) { + temp = this->actor.shape.yOffset; + } else { + temp = 58.0f; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB31B8.s") + this->actor.focus.pos.x = this->actor.world.pos.x; + this->actor.focus.pos.y = temp + this->actor.world.pos.y; + this->actor.focus.pos.z = this->actor.world.pos.z; + this->actor.focus.rot.x = this->actor.world.rot.x; + this->actor.focus.rot.y = this->actor.world.rot.y; + this->actor.focus.rot.z = this->actor.world.rot.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB32AC.s") +s32 func_80BB1D64(EnGeg* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f sp40; + Vec3f sp34; + s16 yaw = (this->actor.yawTowardsPlayer - this->unk_46E) - this->actor.shape.rot.y; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB3318.s") + Math_SmoothStepToS(&this->unk_46A, yaw, 4, 0x2AA8, 1); + this->unk_46A = CLAMP(this->unk_46A, -0x1FFE, 0x1FFE); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB347C.s") + yaw = (this->actor.yawTowardsPlayer - this->unk_46A) - this->actor.shape.rot.y; + Math_SmoothStepToS(&this->unk_46E, yaw, 4, 0x2AA8, 1); + this->unk_46E = CLAMP(this->unk_46E, -0x1C70, 0x1C70); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/EnGeg_Init.s") + if (this->unk_230 & 0x20) { + sp40 = player->actor.world.pos; + } else { + sp40 = player->actor.world.pos; + sp40.y = player->bodyPartsPos[7].y + 3.0f; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/EnGeg_Destroy.s") + sp34 = this->actor.world.pos; + sp34.y += 70.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/EnGeg_Update.s") + yaw = Math_Vec3f_Pitch(&sp34, &sp40); + Math_SmoothStepToS(&this->unk_468, yaw - this->unk_46C, 4, 0x2AA8, 1); + this->unk_468 = CLAMP(this->unk_468, -0x1C70, 0x1C70); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB3728.s") + yaw = Math_Vec3f_Pitch(&sp34, &sp40); + Math_SmoothStepToS(&this->unk_46C, yaw - this->unk_468, 4, 0x2AA8, 1); + this->unk_46C = CLAMP(this->unk_46C, -0x1C70, 0x1C70); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB3860.s") + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB387C.s") +void func_80BB1FCC(EnGeg* this, GlobalContext* globalCtx) { + gSegments[6] = PHYSICAL_TO_VIRTUAL2(globalCtx->objectCtx.status[this->unk_248].segment); + SkelAnime_Update(&this->skelAnime); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB39F8.s") +void func_80BB2020(EnGeg* this, GlobalContext* globalCtx) { + gSegments[6] = PHYSICAL_TO_VIRTUAL2(globalCtx->objectCtx.status[this->unk_248].segment); + func_8013BC6C(&this->skelAnime, sAnimations, this->unk_4AC); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB3BE0.s") +s32 func_80BB2088(EnGeg* this, GlobalContext* globalCtx) { + if (DECR(this->unk_242) != 0) { + this->unk_468 = 0; + this->unk_46A = 0; + this->unk_230 &= ~2; + this->unk_46C = 0; + this->unk_46E = 0; + return true; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/func_80BB3CB4.s") + if (Actor_IsActorFacingLinkAndWithinRange(&this->actor, 300.0f, 0x7FF8) && + ((this->unk_4AC == 5) || ((this->unk_4AC == 13) && (this->unk_496 == 0xD69)))) { + this->unk_230 |= 2; + func_80BB1D64(this, globalCtx); + } else { + if (this->unk_230 & 2) { + this->unk_242 = 20; + } + this->unk_230 &= ~2; + this->unk_468 = 0; + this->unk_46A = 0; + this->unk_46C = 0; + this->unk_46E = 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Geg/EnGeg_Draw.s") + return true; +} + +void func_80BB217C(EnGeg* this, GlobalContext* globalCtx) { + if (Object_IsLoaded(&globalCtx->objectCtx, this->unk_248)) { + this->unk_4AC = 5; + func_80BB2020(this, globalCtx); + Actor_SetScale(&this->actor, 0.01f); + this->unk_230 = 0; + this->actor.shape.shadowScale = 20.0f; + this->actor.gravity = -1.0f; + func_80BB1C1C(this); + this->actionFunc = func_80BB221C; + this->actor.targetMode = 3; + } +} + +void func_80BB221C(EnGeg* this, GlobalContext* globalCtx) { + u8 sp27 = func_80BB1B14(this, globalCtx); + + if (sp27 != 0) { + this->unk_230 &= ~8; + if (func_800B84D0(&this->actor, globalCtx) && (this->unk_230 & 4)) { + if (sp27 == 1) { + this->unk_496 = 0xD66; + this->unk_49A = this->unk_49C[3]; + } else if (sp27 == 2) { + this->unk_496 = 0xD64; + this->unk_49A = this->unk_49C[2]; + this->unk_230 &= ~4; + } else if (sp27 == 3) { + this->unk_230 |= 0x200; + this->unk_496 = 0xD64; + this->unk_49A = this->unk_49C[2]; + this->unk_230 &= ~4; + } + func_801518B0(globalCtx, this->unk_496, &this->actor); + this->actionFunc = func_80BB2520; + this->actor.flags &= ~0x10000; + } else if (this->actor.xzDistToPlayer < 300.0f) { + this->unk_230 |= 4; + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 300.0f); + } + } else { + this->unk_230 &= ~4; + if (gSaveContext.save.weekEventReg[35] & 0x40) { + if (func_800B84D0(&this->actor, globalCtx) && (this->unk_230 & 8)) { + this->unk_496 = 0xD62; + func_801518B0(globalCtx, this->unk_496, &this->actor); + this->unk_230 &= ~8; + this->actionFunc = func_80BB27D4; + } else if ((this->actor.xzDistToPlayer < 300.0f) && this->actor.isTargeted) { + func_800B8614(&this->actor, globalCtx, 300.0f); + this->unk_230 |= 8; + } + } else if (func_800B84D0(&this->actor, globalCtx) && (this->unk_230 & 8)) { + gSaveContext.save.weekEventReg[35] |= 0x40; + this->unk_496 = 0xD5E; + this->unk_49A = this->unk_49C[0]; + func_801518B0(globalCtx, this->unk_496, &this->actor); + this->actionFunc = func_80BB2520; + this->unk_230 &= ~8; + this->actor.flags &= ~0x10000; + } else if (this->actor.xzDistToPlayer < 300.0f) { + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 300.0f); + this->unk_230 |= 8; + } + } +} + +void func_80BB2520(EnGeg* this, GlobalContext* globalCtx) { + if (this->unk_230 & 0x10) { + ActorCutscene_Stop(this->unk_498); + this->unk_230 &= ~0x10; + if (ActorCutscene_GetCurrentIndex() == 0x7C) { + ActorCutscene_Stop(0x7C); + } + this->unk_498 = this->unk_49A; + ActorCutscene_SetIntentToPlay(this->unk_498); + return; + } + + if (ActorCutscene_GetCanPlayNext(this->unk_498)) { + ActorCutscene_StartAndSetFlag(this->unk_498, &this->actor); + this->unk_230 |= 0x10; + + switch (this->unk_496) { + case 0xD5E: + case 0xD5F: + this->actionFunc = func_80BB26EC; + break; + + case 0xD64: + this->unk_230 &= ~0x20; + this->actionFunc = func_80BB2A54; + break; + + case 0xD66: + this->unk_248 = Object_GetIndex(&globalCtx->objectCtx, OBJECT_OF1D_MAP); + if (this->unk_248 >= 0) { + this->unk_4AC = 19; + func_80BB2020(this, globalCtx); + } + this->unk_230 |= 0x20; + this->actionFunc = func_80BB2944; + break; + + case 0xD67: + this->unk_498 = this->unk_49C[5]; + this->actionFunc = func_80BB2B1C; + break; + + case 0xD69: + case 0xD72: + case 0xD75: + case 0xD8B: + this->unk_248 = Object_GetIndex(&globalCtx->objectCtx, OBJECT_OF1D_MAP); + if (this->unk_248 >= 0) { + this->unk_4AC = 4; + func_80BB2020(this, globalCtx); + } + this->actionFunc = func_80BB2E00; + break; + } + } else { + if (ActorCutscene_GetCurrentIndex() == 0x7C) { + ActorCutscene_Stop(0x7C); + } + this->unk_498 = this->unk_49A; + ActorCutscene_SetIntentToPlay(this->unk_498); + } +} + +void func_80BB26EC(EnGeg* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + switch (this->unk_496) { + case 0xD5E: + this->unk_49A = this->unk_49C[1]; + this->actionFunc = func_80BB2520; + break; + + case 0xD61: + ActorCutscene_Stop(this->unk_498); + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->unk_230 &= ~0x10; + this->actionFunc = func_80BB221C; + return; + } + + this->unk_496 = func_80BB16D0(this); + func_801518B0(globalCtx, this->unk_496, &this->actor); + } +} + +void func_80BB27D4(EnGeg* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + switch (this->unk_496) { + case 0xD63: + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->actionFunc = func_80BB221C; + break; + + case 0xD69: + this->unk_49A = this->unk_49C[6]; + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->actionFunc = func_80BB2520; + break; + + case 0xD6D: + case 0xD6F: + case 0xD8A: + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->actionFunc = func_80BB31B8; + break; + + case 0xD72: + case 0xD75: + case 0xD8B: + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->unk_230 &= ~0x10; + this->unk_49A = this->unk_49C[7]; + this->actionFunc = func_80BB2520; + break; + + default: + this->unk_496 = func_80BB16D0(this); + func_801518B0(globalCtx, this->unk_496, &this->actor); + break; + } + } +} + +void func_80BB2944(EnGeg* this, GlobalContext* globalCtx) { + u8 sp27 = func_80152498(&globalCtx->msgCtx); + s16 curFrame = this->skelAnime.curFrame; + s16 lastFrame = Animation_GetLastFrame(sAnimations[this->unk_4AC].animationSeg); + + if (this->unk_4AC == 19) { + if (curFrame == lastFrame) { + this->unk_4AC = 6; + func_80BB2020(this, globalCtx); + } + } else if ((sp27 == 5) && func_80147624(globalCtx)) { + if (this->unk_496 == 0xD67) { + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->unk_49A = this->unk_49C[4]; + this->actionFunc = func_80BB2520; + } else { + this->unk_496 = func_80BB16D0(this); + func_80151938(globalCtx, this->unk_496); + } + } +} + +void func_80BB2A54(EnGeg* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + if (this->unk_496 == 0xD65) { + ActorCutscene_Stop(this->unk_498); + this->unk_230 &= ~0x10; + this->unk_244 = 65; + globalCtx->msgCtx.unk11F22 = 0x43; + globalCtx->msgCtx.unk12023 = 4; + this->actionFunc = func_80BB347C; + } else { + this->unk_496 = func_80BB16D0(this); + func_801518B0(globalCtx, this->unk_496, &this->actor); + } + } +} + +void func_80BB2B1C(EnGeg* this, GlobalContext* globalCtx) { + Vec3f sp74; + f32 temp_f20; + s16 i; + f32 sp68; + + this->actor.child->world.pos = this->unk_4B4; + this->actor.child->shape.rot = this->actor.shape.rot; + + if (ActorCutscene_GetCurrentIndex() != this->unk_49C[4]) { + if (ActorCutscene_GetCanPlayNext(this->unk_498)) { + gSaveContext.save.weekEventReg[37] |= 8; + if (this->actor.child != NULL) { + Actor_MarkForDeath(this->actor.child); + } + this->unk_230 |= 0x10; + ActorCutscene_StartAndSetFlag(this->unk_498, &this->actor); + this->unk_496 = 0xD68; + func_80151938(globalCtx, this->unk_496); + this->unk_248 = Object_GetIndex(&globalCtx->objectCtx, OBJECT_TAISOU); + if (this->unk_248 >= 0) { + this->unk_4AC = 13; + func_80BB2020(this, globalCtx); + } + this->actionFunc = func_80BB27D4; + } else { + if (ActorCutscene_GetCurrentIndex() == 0x7C) { + ActorCutscene_Stop(0x7C); + } + ActorCutscene_SetIntentToPlay(this->unk_498); + } + } else { + temp_f20 = this->unk_4E0 * 0.005f; + sp68 = this->unk_4E0 * 0.07f; + + sp74.x = Rand_Centered() * temp_f20; + sp74.y = Rand_Centered() * temp_f20; + sp74.z = Rand_Centered() * temp_f20; + + this->actor.child->scale.x *= 0.98f; + this->actor.child->scale.y *= 0.98f; + this->actor.child->scale.z *= 0.98f; + + if (this->unk_4E0 > 70) { + for (i = 0; i < ARRAY_COUNT(this->unk_4C0); i++) { + this->unk_4C0[i].x *= temp_f20; + this->unk_4C0[i].y *= temp_f20; + this->unk_4C0[i].z *= temp_f20; + EffectSsHahen_Spawn(globalCtx, &this->unk_4B4, &this->unk_4C0[i], &sp74, 1, sp68, 1, 15, + gameplay_keep_DL_06AB30); + } + } + this->unk_4E0--; + } + func_8019F570(&this->actor.projectedPos, 1); + func_8019F4AC(&this->actor.projectedPos, NA_SE_EN_GOLON_SIRLOIN_EAT - SFX_FLAG); +} + +void func_80BB2E00(EnGeg* this, GlobalContext* globalCtx) { + s16 sp2E = this->skelAnime.curFrame; + s16 sp2C = Animation_GetLastFrame(sAnimations[this->unk_4AC].animationSeg); + + if (this->unk_4AC == 2) { + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; + if (sp2E == sp2C) { + ActorCutscene_Stop(this->unk_498); + this->unk_4AC = 20; + func_80BB2020(this, globalCtx); + this->actionFunc = func_80BB30B4; + } else if (Animation_OnFrame(&this->skelAnime, 24.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_GOLON_STAND_IMT); + } + } else if (this->unk_4AC == 4) { + if (Animation_OnFrame(&this->skelAnime, 0.0f)) { + this->unk_230 |= 1; + this->actor.shape.yOffset = 14.0f; + if (this->unk_496 == 0xD69) { + func_80BB19C0(&this->unk_4E4, this, globalCtx); + this->actionFunc = func_80BB2F7C; + } else { + this->actionFunc = func_80BB3318; + } + } else if (Animation_OnFrame(&this->skelAnime, 24.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_GOLON_SIT_IMT); + } + } +} + +void func_80BB2F7C(EnGeg* this, GlobalContext* globalCtx) { + Math_SmoothStepToS(&this->actor.world.rot.y, Math_Vec3f_Yaw(&this->actor.world.pos, &this->unk_4E4), 4, 1000, 1); + this->actor.shape.rot.y = this->actor.world.rot.y; + + if ((this->actor.xzDistToPlayer < 150.0f) && (fabsf(this->actor.playerHeightRel) < 10.0f) && + (this->actor.bgCheckFlags & 1)) { + this->unk_4AC = 2; + this->actor.speedXZ = 0.0f; + this->unk_230 &= ~1; + this->actor.shape.yOffset = 0.0f; + func_80BB2020(this, globalCtx); + this->actionFunc = func_80BB2E00; + } else { + this->actor.speedXZ = 5.0f; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } + + if (this->actor.bgCheckFlags & 1) { + if (this->unk_230 & 0x80) { + func_800B9010(&this->actor, NA_SE_EN_GOLON_SIRLOIN_ROLL - SFX_FLAG); + } else { + this->unk_230 |= 0x80; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_EYEGOLE_ATTACK); + } + } +} + +void func_80BB30B4(EnGeg* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (func_800B84D0(&this->actor, globalCtx)) { + if (player->transformation == PLAYER_FORM_GORON) { + this->unk_496 = 0xD6A; + } else if (Player_GetMask(globalCtx) == PLAYER_MASK_DON_GERO) { + this->unk_496 = 0xD89; + } else { + this->unk_496 = 0xD6E; + } + func_801518B0(globalCtx, this->unk_496, &this->actor); + this->actionFunc = func_80BB27D4; + this->actor.flags &= ~0x10000; + } else if (this->actor.xzDistToPlayer < 150.0f) { + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 150.0f); + } +} + +void func_80BB31B8(EnGeg* this, GlobalContext* globalCtx) { + s32 getItemId = GI_MASK_DON_GERO; + + if (INV_CONTENT(ITEM_MASK_DON_GERO) == ITEM_MASK_DON_GERO) { + if (Player_GetMask(globalCtx) == PLAYER_MASK_DON_GERO) { + this->unk_496 = 0xD8B; + getItemId = GI_RUPEE_PURPLE; + } else { + this->unk_496 = 0xD73; + getItemId = GI_RUPEE_PURPLE; + } + } else { + this->unk_496 = 0xD70; + } + + if (Actor_HasParent(&this->actor, globalCtx)) { + this->actor.parent = NULL; + gSaveContext.save.weekEventReg[61] |= 1; + if (getItemId == GI_MASK_DON_GERO) { + this->unk_230 |= 0x40; + } + this->actionFunc = func_80BB32AC; + } else { + func_800B8A1C(&this->actor, globalCtx, getItemId, 300.0f, 300.0f); + } +} + +void func_80BB32AC(EnGeg* this, GlobalContext* globalCtx) { + if (func_800B84D0(&this->actor, globalCtx)) { + func_801518B0(globalCtx, this->unk_496, &this->actor); + this->actionFunc = func_80BB27D4; + } else { + func_800B85E0(&this->actor, globalCtx, 400.0f, -1); + } +} + +void func_80BB3318(EnGeg* this, GlobalContext* globalCtx) { + static Vec3f D_80BB4044[] = { + { -550.0f, 8.0f, 550.0f }, + { 220.0f, 43.0f, 525.0f }, + }; + s16 sp46; + f32 sp40; + + if (this->unk_4D8 < 2) { + sp46 = Math_Vec3f_Yaw(&this->actor.world.pos, &D_80BB4044[this->unk_4D8]); + sp40 = Math_Vec3f_DistXZ(&this->actor.world.pos, &D_80BB4044[this->unk_4D8]); + Math_SmoothStepToS(&this->actor.world.rot.y, sp46, 4, 1000, 1); + if (sp40 < 20.0f) { + this->unk_4D8++; + } + this->actor.shape.rot.y = this->actor.world.rot.y; + func_800AE930(&globalCtx->colCtx, Effect_GetByIndex(this->unk_4DC), &this->actor.world.pos, 18.0f, + this->actor.shape.rot.y, this->actor.floorPoly, this->actor.floorBgId); + } + + if (ActorCutscene_GetCurrentIndex() != this->unk_49C[7]) { + func_800AEF44(Effect_GetByIndex(this->unk_4DC)); + Actor_MarkForDeath(&this->actor); + } else { + Math_ApproachF(&this->actor.speedXZ, 10.0f, 0.2f, 1.0f); + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } + + func_800B9010(&this->actor, NA_SE_EN_GOLON_SIRLOIN_ROLL - SFX_FLAG); +} + +void func_80BB347C(EnGeg* this, GlobalContext* globalCtx) { + if (DECR(this->unk_244) == 0) { + this->unk_244 = 65; + this->actionFunc = func_80BB221C; + } +} + +void EnGeg_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnGeg* this = THIS; + s32 pad2; + s32 sp34[] = { 0x3E, 0xF64 }; + + if (gSaveContext.save.weekEventReg[61] & 1) { + Actor_MarkForDeath(&this->actor); + return; + } + + ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 0.0f); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_oF1d_map_Skel_011AC8, &object_oF1d_map_Anim_012DE0, + this->jointTable, this->morphTable, 18); + + Collider_InitCylinder(globalCtx, &this->colliderCylinder); + Collider_SetCylinder(globalCtx, &this->colliderCylinder, &this->actor, &sCylinderInit); + Collider_InitSphere(globalCtx, &this->colliderSphere); + Collider_SetSphere(globalCtx, &this->colliderSphere, &this->actor, &sSphereInit); + CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + + if (this->actor.update != NULL) { + this->unk_248 = Object_GetIndex(&globalCtx->objectCtx, OBJECT_OF1D_MAP); + if (this->unk_248 < 0) { + Actor_MarkForDeath(&this->actor); + } + } + + Effect_Add(globalCtx, &this->unk_4DC, 4, 0, 0, &sp34); + thisx->draw = NULL; + this->unk_4E0 = 100; + this->actor.draw = EnGeg_Draw; + this->actionFunc = func_80BB217C; +} + +void EnGeg_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnGeg* this = THIS; + + Collider_DestroyCylinder(globalCtx, &this->colliderCylinder); + Collider_DestroySphere(globalCtx, &this->colliderSphere); + Effect_Destroy(globalCtx, this->unk_4DC); +} + +void EnGeg_Update(Actor* thisx, GlobalContext* globalCtx) { + EnGeg* this = THIS; + + this->actionFunc(this, globalCtx); + func_80BB1FCC(this, globalCtx); + func_80BB2088(this, globalCtx); + func_80BB1C8C(this); + func_8013D9C8(globalCtx, &this->unk_238, &this->unk_232, 3); + func_80BB1D04(this); + func_80BB178C(this, globalCtx); +} + +s32 func_80BB3728(s16 arg0, s16 arg1, Vec3f* arg2, Vec3s* arg3, s32 arg4, s32 arg5) { + Vec3f sp7C; + Vec3f sp70 = gZeroVec3f; + Vec3s sp68; + MtxF sp28; + + Matrix_MultiplyVector3fByState(&sp70, &sp7C); + Matrix_CopyCurrentState(&sp28); + func_8018219C(&sp28, &sp68, 0); + *arg2 = sp7C; + + if (!arg4 && !arg5) { + arg3->x = sp68.x; + arg3->y = sp68.y; + arg3->z = sp68.z; + return true; + } + + if (arg5) { + sp68.z = arg0; + sp68.y = arg1; + } + Math_SmoothStepToS(&arg3->x, sp68.x, 3, 0x2AA8, 0xB6); + Math_SmoothStepToS(&arg3->y, sp68.y, 3, 0x2AA8, 0xB6); + Math_SmoothStepToS(&arg3->z, sp68.z, 3, 0x2AA8, 0xB6); + + return true; +} + +s32 EnGeg_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + return false; +} + +void EnGeg_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + static Vec3f D_80BB407C = { -1500.0f, 1500.0f, 0.0f }; + EnGeg* this = THIS; + Vec3f sp38 = { 1.0f, 5.0f, -0.5f }; + Vec3f sp2C = { -1.0f, 5.0f, -0.5f }; + + if (limbIndex == 17) { + if (!(this->unk_230 & 0x40)) { + func_8012C28C(globalCtx->state.gfxCtx); + + OPEN_DISPS(globalCtx->state.gfxCtx); + + gSPDisplayList(POLY_OPA_DISP++, object_oF1d_map_DL_004DB0); + + CLOSE_DISPS(globalCtx->state.gfxCtx); + } + + sp38.x += Rand_Centered(); + sp38.y += 2.0f * Rand_Centered(); + sp38.z += Rand_Centered(); + + sp2C.x += Rand_Centered(); + sp2C.y += 2.0f * Rand_Centered(); + sp2C.z += Rand_Centered(); + + Matrix_MultiplyVector3fByState(&D_80BB407C, &this->unk_4B4); + Matrix_StatePush(); + Matrix_RotateY(this->actor.shape.rot.y, MTXMODE_NEW); + Matrix_MultiplyVector3fByState(&sp38, &this->unk_4C0[0]); + Matrix_MultiplyVector3fByState(&sp2C, &this->unk_4C0[1]); + Matrix_StatePop(); + } +} + +void EnGeg_UnkDraw(GlobalContext* globalCtx, s32 limbIndex, Actor* thisx) { + EnGeg* this = THIS; + s32 phi_v0; + s32 phi_v1; + + switch (limbIndex) { + case 17: + if (this->unk_230 & 2) { + phi_v1 = true; + } else { + phi_v1 = false; + } + + if (this->unk_242 != 0) { + phi_v0 = true; + } else { + phi_v0 = false; + } + + func_80BB3728(this->unk_468 + this->unk_46C + 0x4000, + this->unk_46A + this->unk_46E + this->actor.shape.rot.y + 0x4000, &this->unk_470, + &this->unk_47C, phi_v0, phi_v1); + Matrix_StatePop(); + Matrix_InsertTranslation(this->unk_470.x, this->unk_470.y, this->unk_470.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Matrix_RotateY(this->unk_47C.y, MTXMODE_APPLY); + Matrix_InsertXRotation_s(this->unk_47C.x, MTXMODE_APPLY); + Matrix_InsertZRotation_s(this->unk_47C.z, MTXMODE_APPLY); + Matrix_StatePush(); + break; + + case 10: + if (this->unk_230 & 2) { + phi_v1 = true; + } else { + phi_v1 = false; + } + + if (this->unk_242 != 0) { + phi_v0 = true; + } else { + phi_v0 = false; + } + + func_80BB3728(this->unk_46C + 0x4000, this->unk_46E + this->actor.shape.rot.y + 0x4000, &this->unk_484, + &this->unk_490, phi_v0, phi_v1); + Matrix_StatePop(); + Matrix_InsertTranslation(this->unk_484.x, this->unk_484.y, this->unk_484.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Matrix_RotateY(this->unk_490.y, MTXMODE_APPLY); + Matrix_InsertXRotation_s(this->unk_490.x, MTXMODE_APPLY); + Matrix_InsertZRotation_s(this->unk_490.z, MTXMODE_APPLY); + Matrix_StatePush(); + break; + } +} + +void func_80BB3BE0(EnGeg* this, GlobalContext* globalCtx) { + static TexturePtr D_80BB4088[] = { + &object_oF1d_map_Tex_010438, + &object_oF1d_map_Tex_010C38, + &object_oF1d_map_Tex_011038, + &object_oF1d_map_Tex_010838, + }; + s32 pad; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(D_80BB4088[this->unk_23E])); + gDPPipeSync(POLY_OPA_DISP++); + + func_801343C0(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnGeg_OverrideLimbDraw, EnGeg_PostLimbDraw, EnGeg_UnkDraw, &this->actor); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void func_80BB3CB4(EnGeg* this, GlobalContext* globalCtx) { + f32 sp24 = globalCtx->state.frames * this->actor.speedXZ * 1400.0f; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + Matrix_InsertTranslation(this->actor.world.pos.x, this->actor.world.pos.y + this->actor.shape.yOffset, + this->actor.world.pos.z, MTXMODE_NEW); + Matrix_RotateY(this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, -this->actor.shape.yOffset, 0.0f, MTXMODE_APPLY); + Matrix_InsertZRotation_s(this->actor.shape.rot.z, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, this->actor.shape.yOffset, 0.0f, MTXMODE_APPLY); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Matrix_InsertXRotation_s(sp24, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, object_oF1d_map_DL_0091A8); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void EnGeg_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnGeg* this = THIS; + + if (this->unk_230 & 1) { + func_80BB3CB4(this, globalCtx); + } else { + func_80BB3BE0(this, globalCtx); + } +} diff --git a/src/overlays/actors/ovl_En_Geg/z_en_geg.h b/src/overlays/actors/ovl_En_Geg/z_en_geg.h index 1bd18cc05..c846f447b 100644 --- a/src/overlays/actors/ovl_En_Geg/z_en_geg.h +++ b/src/overlays/actors/ovl_En_Geg/z_en_geg.h @@ -8,10 +8,44 @@ struct EnGeg; typedef void (*EnGegActionFunc)(struct EnGeg*, GlobalContext*); typedef struct EnGeg { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x44]; - /* 0x0188 */ EnGegActionFunc actionFunc; - /* 0x018C */ char unk_18C[0x364]; + /* 0x000 */ Actor actor; + /* 0x144 */ SkelAnime skelAnime; + /* 0x188 */ EnGegActionFunc actionFunc; + /* 0x18C */ ColliderCylinder colliderCylinder; + /* 0x1D8 */ ColliderSphere colliderSphere; + /* 0x230 */ u16 unk_230; + /* 0x232 */ s16 unk_232; + /* 0x234 */ UNK_TYPE1 unk234[4]; + /* 0x238 */ s16 unk_238; + /* 0x23A */ UNK_TYPE1 unk23A[0x4]; + /* 0x23E */ s16 unk_23E; + /* 0x240 */ s16 unk_240; + /* 0x242 */ s16 unk_242; + /* 0x244 */ s16 unk_244; + /* 0x248 */ s32 unk_248; + /* 0x24C */ Vec3s jointTable[18]; + /* 0x2B8 */ Vec3s morphTable[18]; + /* 0x324 */ UNK_TYPE1 unk324[0x144]; + /* 0x468 */ s16 unk_468; + /* 0x46A */ s16 unk_46A; + /* 0x46C */ s16 unk_46C; + /* 0x46E */ s16 unk_46E; + /* 0x470 */ Vec3f unk_470; + /* 0x47C */ Vec3s unk_47C; + /* 0x484 */ Vec3f unk_484; + /* 0x490 */ Vec3s unk_490; + /* 0x496 */ u16 unk_496; + /* 0x498 */ s16 unk_498; + /* 0x49A */ s16 unk_49A; + /* 0x49C */ s16 unk_49C[8]; + /* 0x4AC */ s32 unk_4AC; + /* 0x4B0 */ s16 unk_4B0; + /* 0x4B4 */ Vec3f unk_4B4; + /* 0x4C0 */ Vec3f unk_4C0[2]; + /* 0x4D8 */ s16 unk_4D8; + /* 0x4DC */ s32 unk_4DC; + /* 0x4E0 */ s16 unk_4E0; + /* 0x4E4 */ Vec3f unk_4E4; } EnGeg; // size = 0x4F0 extern const ActorInit En_Geg_InitVars; diff --git a/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c b/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c index 0c5dbfa71..379ac2f45 100644 --- a/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c +++ b/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c @@ -5,6 +5,7 @@ */ #include "z_en_talk_gibud.h" +#include "objects/object_rd/object_rd.h" #define FLAGS 0x00000415 @@ -15,7 +16,81 @@ void EnTalkGibud_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnTalkGibud_Update(Actor* thisx, GlobalContext* globalCtx); void EnTalkGibud_Draw(Actor* thisx, GlobalContext* globalCtx); -#if 0 +void EnTalkGibud_SetupIdle(EnTalkGibud* this); +void EnTalkGibud_Idle(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupAttemptPlayerStun(EnTalkGibud* this); +void EnTalkGibud_AttemptPlayerStun(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupWalkToPlayer(EnTalkGibud* this); +void EnTalkGibud_WalkToPlayer(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupGrab(EnTalkGibud* this); +void EnTalkGibud_Grab(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupGrabFail(EnTalkGibud* this); +void EnTalkGibud_GrabFail(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupTurnAwayAndShakeHead(EnTalkGibud* this); +void EnTalkGibud_TurnAwayAndShakeHead(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupWalkToHome(EnTalkGibud* this); +void EnTalkGibud_WalkToHome(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_Stunned(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupDamage(EnTalkGibud* this); +void EnTalkGibud_Damage(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupDead(EnTalkGibud* this); +void EnTalkGibud_Dead(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupRevive(EnTalkGibud* this); +void EnTalkGibud_Revive(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_PassiveIdle(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupTalk(EnTalkGibud* this); +void EnTalkGibud_Talk(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_SetupDisappear(EnTalkGibud* this); +void EnTalkGibud_Disappear(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_FacePlayerWhenTalking(EnTalkGibud* this, GlobalContext* globalCtx); +s32 EnTalkGibud_PlayerInRangeWithCorrectState(EnTalkGibud* this, GlobalContext* globalCtx); +s32 EnTalkGibud_PlayerOutOfRange(EnTalkGibud* this, GlobalContext* globalCtx); +void EnTalkGibud_TurnTowardsPlayer(EnTalkGibud* this, GlobalContext* globalCtx); +s32 EnTalkGibud_MoveToIdealGrabPositionAndRotation(EnTalkGibud* this, GlobalContext* globalCtx); + +typedef struct { + /* 0x0 */ s32 itemActionParam; + /* 0x4 */ s32 item; + /* 0x8 */ s32 amount; + /* 0xC */ s16 isBottledItem; +} EnTalkGibudRequestedItem; + +typedef enum { + /* 0 */ EN_TALK_GIBUD_ANIMATION_GRAB_ATTACK, + /* 1 */ EN_TALK_GIBUD_ANIMATION_GRAB_END, + /* 2 */ EN_TALK_GIBUD_ANIMATION_GRAB_START, + /* 3 */ EN_TALK_GIBUD_ANIMATION_LOOK_AWAY, + /* 4 */ EN_TALK_GIBUD_ANIMATION_CROUCH_WIPING_TEARS, + /* 5 */ EN_TALK_GIBUD_ANIMATION_CROUCH_CRYING, + /* 6 */ EN_TALK_GIBUD_ANIMATION_DEATH, + /* 7 */ EN_TALK_GIBUD_ANIMATION_DAMAGE, + /* 8 */ EN_TALK_GIBUD_ANIMATION_CROUCH_END, + /* 9 */ EN_TALK_GIBUD_ANIMATION_IDLE, + /* 10 */ EN_TALK_GIBUD_ANIMATION_WALK, + /* 11 */ EN_TALK_GIBUD_ANIMATION_DANCE_SQUAT, + /* 12 */ EN_TALK_GIBUD_ANIMATION_DANCE_PIROUETTE, + /* 13 */ EN_TALK_GIBUD_ANIMATION_DANCE_CLAP, +} EnTalkGibudAnimations; + +typedef enum { + /* 0 */ EN_TALK_GIBUD_REQUESTED_ITEM_MET, + /* 1 */ EN_TALK_GIBUD_REQUESTED_ITEM_NOT_ENOUGH_AMMO, + /* 2 */ EN_TALK_GIBUD_REQUESTED_ITEM_NOT_MET, +} EnTalkGibudRequestedItemState; + +typedef enum { + /* 0 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BLUE_POTION, + /* 1 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BEANS, + /* 2 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_SPRING_WATER, + /* 3 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_FISH, + /* 4 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BUGS, + /* 5 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_DEKU_NUTS, + /* 6 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BOMBS, + /* 7 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_HOT_SPRING_WATER, + /* 8 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BIG_POE, + /* 9 */ EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_MILK, +} EnTalkGibudRequestedItemIndex; + const ActorInit En_Talk_Gibud_InitVars = { ACTOR_EN_TALK_GIBUD, ACTORCAT_ENEMY, @@ -28,166 +103,1056 @@ const ActorInit En_Talk_Gibud_InitVars = { (ActorFunc)EnTalkGibud_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80B01350 = { - { COLTYPE_HIT0, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0xF7EFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON | BUMP_HOOKABLE, OCELEM_ON, }, +static ActorAnimationEntry sAnimations[] = { + { &object_rd_Anim_006678, 1.0f, 0.0f, 0.0f, 0, -8.0f }, { &object_rd_Anim_006B08, 0.5f, 0.0f, 0.0f, 3, 0.0f }, + { &object_rd_Anim_006EEC, 1.0f, 0.0f, 0.0f, 2, -8.0f }, { &object_rd_Anim_0073A4, 0.0f, 0.0f, 0.0f, 2, -8.0f }, + { &object_rd_Anim_007BBC, 1.0f, 0.0f, 0.0f, 2, -8.0f }, { &object_rd_Anim_0081A8, 1.0f, 0.0f, 0.0f, 0, -8.0f }, + { &object_rd_Anim_009298, 1.0f, 0.0f, 0.0f, 2, -8.0f }, { &object_rd_Anim_009900, 1.0f, 0.0f, 0.0f, 2, -8.0f }, + { &object_rd_Anim_00A450, 1.0f, 0.0f, 0.0f, 2, -8.0f }, { &object_rd_Anim_00ABE0, 1.0f, 0.0f, 0.0f, 0, -8.0f }, + { &object_rd_Anim_0113EC, 0.4f, 0.0f, 0.0f, 1, -8.0f }, { &object_rd_Anim_01216C, 1.0f, 0.0f, 0.0f, 0, -8.0f }, + { &object_rd_Anim_0118D8, 1.0f, 0.0f, 0.0f, 0, -8.0f }, { &object_rd_Anim_011DB8, 1.0f, 0.0f, 0.0f, 0, -8.0f }, +}; + +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_HIT0, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0x00000000, 0x00, 0x00 }, + { 0xF7EFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON | BUMP_HOOKABLE, + OCELEM_ON, + }, { 20, 70, 0, { 0, 0, 0 } }, }; -// static DamageTable sDamageTable = { -static DamageTable D_80B0137C = { - /* Deku Nut */ DMG_ENTRY(0, 0x0), - /* Deku Stick */ DMG_ENTRY(2, 0xF), - /* Horse trample */ DMG_ENTRY(0, 0x0), - /* Explosives */ DMG_ENTRY(1, 0xF), - /* Zora boomerang */ DMG_ENTRY(0, 0xD), - /* Normal arrow */ DMG_ENTRY(0, 0xD), - /* UNK_DMG_0x06 */ DMG_ENTRY(2, 0xF), - /* Hookshot */ DMG_ENTRY(0, 0xD), - /* Goron punch */ DMG_ENTRY(1, 0xF), - /* Sword */ DMG_ENTRY(1, 0xF), - /* Goron pound */ DMG_ENTRY(1, 0xF), - /* Fire arrow */ DMG_ENTRY(1, 0x2), - /* Ice arrow */ DMG_ENTRY(0, 0xD), - /* Light arrow */ DMG_ENTRY(2, 0x4), - /* Goron spikes */ DMG_ENTRY(1, 0xF), - /* Deku spin */ DMG_ENTRY(0, 0x1), - /* Deku bubble */ DMG_ENTRY(0, 0xD), - /* Deku launch */ DMG_ENTRY(2, 0xF), - /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0), - /* Zora barrier */ DMG_ENTRY(0, 0xC), - /* Normal shield */ DMG_ENTRY(0, 0x0), - /* Light ray */ DMG_ENTRY(0, 0xE), - /* Thrown object */ DMG_ENTRY(1, 0xF), - /* Zora punch */ DMG_ENTRY(1, 0xF), - /* Spin attack */ DMG_ENTRY(1, 0xF), - /* Sword beam */ DMG_ENTRY(0, 0x0), - /* Normal Roll */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0), - /* Unblockable */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0), - /* Powder Keg */ DMG_ENTRY(1, 0xF), +typedef enum { + /* 0x0 */ EN_TALK_GIBUD_DMGEFF_NONE, // Does not interact with the Gibdo/Redead at all + /* 0x1 */ EN_TALK_GIBUD_DMGEFF_STUN, // Stuns without applying any effect + /* 0x2 */ EN_TALK_GIBUD_DMGEFF_FIRE_ARROW, // Damages and changes a Gibdo into a Redead + /* 0x4 */ EN_TALK_GIBUD_DMGEFF_LIGHT_ARROW = 0x4, // Damages and applies a light effect + /* 0xC */ EN_TALK_GIBUD_DMGEFF_ZORA_MAGIC = 0xC, // Stuns and applies an electric effect + /* 0xD */ EN_TALK_GIBUD_DMGEFF_RECOIL, // Deals no damage, but displays hit mark and recoil animation + /* 0xE */ EN_TALK_GIBUD_DMGEFF_LIGHT_RAY, // Instantly kills a Redead on contact + /* 0xF */ EN_TALK_GIBUD_DMGEFF_DAMAGE, // Deals damage and plays the damage animation +} EnTalkGibudDamageEffect; + +static DamageTable sDamageTable = { + /* Deku Nut */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Deku Stick */ DMG_ENTRY(2, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Horse trample */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Explosives */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Zora boomerang */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_RECOIL), + /* Normal arrow */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_RECOIL), + /* UNK_DMG_0x06 */ DMG_ENTRY(2, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Hookshot */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_RECOIL), + /* Goron punch */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Sword */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Goron pound */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Fire arrow */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_FIRE_ARROW), + /* Ice arrow */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_RECOIL), + /* Light arrow */ DMG_ENTRY(2, EN_TALK_GIBUD_DMGEFF_LIGHT_ARROW), + /* Goron spikes */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Deku spin */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_STUN), + /* Deku bubble */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_RECOIL), + /* Deku launch */ DMG_ENTRY(2, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* UNK_DMG_0x12 */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Zora barrier */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_ZORA_MAGIC), + /* Normal shield */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Light ray */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_LIGHT_RAY), + /* Thrown object */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Zora punch */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Spin attack */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), + /* Sword beam */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Normal Roll */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* UNK_DMG_0x1B */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* UNK_DMG_0x1C */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Unblockable */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* UNK_DMG_0x1E */ DMG_ENTRY(0, EN_TALK_GIBUD_DMGEFF_NONE), + /* Powder Keg */ DMG_ENTRY(1, EN_TALK_GIBUD_DMGEFF_DAMAGE), }; -// sColChkInfoInit -static CollisionCheckInfoInit2 D_80B0139C = { 8, 0, 0, 0, MASS_HEAVY }; +static CollisionCheckInfoInit2 sColChkInfoInit = { 8, 0, 0, 0, MASS_HEAVY }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80B01448[] = { +static EnTalkGibudRequestedItem sRequestedItemTable[] = { + { PLAYER_AP_BOTTLE_POTION_BLUE, ITEM_POTION_BLUE, 1, true }, + { PLAYER_AP_MAGIC_BEANS, ITEM_BEAN, 5, false }, + { PLAYER_AP_BOTTLE_SPRING_WATER, ITEM_SPRING_WATER, 1, true }, + { PLAYER_AP_BOTTLE_FISH, ITEM_FISH, 1, true }, + { PLAYER_AP_BOTTLE_BUG, ITEM_BUG, 1, true }, + { PLAYER_AP_NUT, ITEM_NUT, 10, false }, + { PLAYER_AP_BOMB, ITEM_BOMB, 10, false }, + { PLAYER_AP_BOTTLE_HOT_SPRING_WATER, ITEM_HOT_SPRING_WATER, 1, true }, + { PLAYER_AP_BOTTLE_BIG_POE, ITEM_BIG_POE, 1, true }, + { PLAYER_AP_BOTTLE_MILK, ITEM_MILK_BOTTLE, 1, true }, +}; + +static InitChainEntry sInitChain[] = { ICHAIN_F32(targetArrowOffset, 2000, ICHAIN_CONTINUE), ICHAIN_VEC3F_DIV1000(scale, 10, ICHAIN_CONTINUE), ICHAIN_F32_DIV1000(gravity, -3500, ICHAIN_STOP), }; -#endif +static Vec3f sVelocity = { 0.0f, 0.0f, 0.0f }; -extern ColliderCylinderInit D_80B01350; -extern DamageTable D_80B0137C; -extern CollisionCheckInfoInit2 D_80B0139C; -extern InitChainEntry D_80B01448[]; +static Vec3f sAccel = { 0.0f, 0.600000023842f, 0.0f }; -extern UNK_TYPE D_06009298; -extern UNK_TYPE D_0600ABE0; -extern UNK_TYPE D_06010B88; +void EnTalkGibud_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnTalkGibud* this = THIS; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/EnTalkGibud_Init.s") + Actor_ProcessInitChain(&this->actor, sInitChain); + this->actor.targetMode = 0; + this->actor.hintId = 0x2D; + this->actor.textId = 0; + ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 28.0f); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_rd_Skel_0053E8, &object_rd_Anim_00ABE0, this->jointTable, + this->morphTable, EN_TALK_GIBUD_LIMB_MAX); + Collider_InitCylinder(globalCtx, &this->collider); + Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); + CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + this->playerStunWaitTimer = 0; + this->grabState = EN_TALK_GIBUD_GRAB_START; + this->grabWaitTimer = 0; + this->itemActionParam = PLAYER_AP_NONE; + this->effectTimer = 0; + this->effectType = 0; + this->isTalking = false; + this->type = EN_TALK_GIBUD_TYPE_GIBDO; + this->requestedItemIndex = EN_TALK_GIBUD_REQUESTED_ITEM_INDEX(thisx); + this->switchFlag = EN_TALK_GIBUD_SWITCH_FLAG(thisx); + this->effectAlpha = 0.0f; + this->effectScale = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/EnTalkGibud_Destroy.s") + for (i = 0; i < ARRAY_COUNT(this->limbPos); i++) { + this->limbPos[i] = gZeroVec3f; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFEB38.s") + if (this->requestedItemIndex < EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BLUE_POTION) { + this->requestedItemIndex = EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BLUE_POTION; + } + if (this->requestedItemIndex > EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_MILK) { + this->requestedItemIndex = EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_MILK; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFEB7C.s") + if (this->switchFlag == 0xFF) { + this->switchFlag = -1; + } + if (this->switchFlag != -1 && Flags_GetSwitch(globalCtx, this->switchFlag)) { + Actor_MarkForDeath(&this->actor); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFEC08.s") + EnTalkGibud_SetupIdle(this); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFEC4C.s") +void EnTalkGibud_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnTalkGibud* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFED08.s") + Collider_DestroyCylinder(globalCtx, &this->collider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFED7C.s") +void EnTalkGibud_SetupIdle(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_IDLE); + this->actionFunc = EnTalkGibud_Idle; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFEFD4.s") +/** + * This is the idle for when the player is not wearing the Gibdo Mask. The + * Gibdo will attack the player if they get too close. + */ +void EnTalkGibud_Idle(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actor.xzDistToPlayer <= 150.0f && func_800B715C(globalCtx)) { + EnTalkGibud_SetupAttemptPlayerStun(this); + } + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 0x64, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 0x64, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF030.s") +void EnTalkGibud_SetupAttemptPlayerStun(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_IDLE); + this->actionFunc = EnTalkGibud_AttemptPlayerStun; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF22C.s") +void EnTalkGibud_AttemptPlayerStun(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + s16 rot = this->actor.shape.rot.y + this->headRotation.y + this->upperBodyRotation.y; + s16 yaw = BINANG_SUB(this->actor.yawTowardsPlayer, rot); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF288.s") + if (ABS_ALT(yaw) < 0x2008) { + player->actor.freezeTimer = 60; + func_8013ECE0(this->actor.xzDistToPlayer, 255, 20, 150); + func_80123E90(globalCtx, &this->actor); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_AIM); + EnTalkGibud_SetupWalkToPlayer(this); + } + EnTalkGibud_TurnTowardsPlayer(this, globalCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF330.s") +void EnTalkGibud_SetupWalkToPlayer(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_WALK); + this->actor.speedXZ = 0.4f; + if (this->actionFunc == EnTalkGibud_AttemptPlayerStun) { + this->playerStunWaitTimer = 80; + } else { + this->playerStunWaitTimer = 20; + } + this->actionFunc = EnTalkGibud_WalkToPlayer; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF378.s") +void EnTalkGibud_WalkToPlayer(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + s32 pad; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF45C.s") + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0xFA); + this->actor.world.rot = this->actor.shape.rot; + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 100, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 100, 0); + if (EnTalkGibud_PlayerInRangeWithCorrectState(this, globalCtx) && Actor_IsActorFacingLink(&this->actor, 0x38E3)) { + if (this->grabWaitTimer == 0 && this->actor.xzDistToPlayer <= 45.0f) { + player->actor.freezeTimer = 0; + if (gSaveContext.save.playerForm == PLAYER_FORM_GORON || gSaveContext.save.playerForm == PLAYER_FORM_DEKU) { + // If the Gibdo/Redead tries to grab Goron or Deku Link, it will fail to + // do so. It will appear to take damage and shake its head side-to-side. + EnTalkGibud_SetupGrabFail(this); + } else if (globalCtx->grabPlayer(globalCtx, player)) { + EnTalkGibud_SetupGrab(this); + } + } else { + if (this->playerStunWaitTimer == 0) { + player->actor.freezeTimer = 40; + this->playerStunWaitTimer = 60; + func_8013ECE0(this->actor.xzDistToPlayer, 255, 20, 150); + func_80123E90(globalCtx, &this->actor); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_AIM); + } else { + this->playerStunWaitTimer--; + } + } + } else if (this->grabWaitTimer == 0 && this->actor.xzDistToPlayer <= 45.0f) { + EnTalkGibud_SetupWalkToHome(this); + } else if (EnTalkGibud_PlayerOutOfRange(this, globalCtx)) { + EnTalkGibud_SetupWalkToHome(this); + } + if (this->grabWaitTimer > 0) { + this->grabWaitTimer--; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF4AC.s") + if (Animation_OnFrame(&this->skelAnime, 10.0f) || Animation_OnFrame(&this->skelAnime, 22.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_RIZA_WALK); + } else if (!(globalCtx->gameplayFrames & 0x5F)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_CRY); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF618.s") +void EnTalkGibud_SetupGrab(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_GRAB_START); + this->grabDamageTimer = 0; + this->actor.flags &= ~1; + this->grabState = EN_TALK_GIBUD_GRAB_START; + this->actionFunc = EnTalkGibud_Grab; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF6A0.s") +void EnTalkGibud_Grab(EnTalkGibud* this, GlobalContext* globalCtx) { + // This function needs to have two different temps for Player to match, + // but you don't have to necessarily use them both. This is just the most + // likely scenario; they got an Actor* pointer in the first temp, then + // casted it to Player* in the second temp. + Actor* playerActor = &GET_PLAYER(globalCtx)->actor; + Player* player = (Player*)playerActor; + s32 inPositionToAttack; + u16 damageSfxId; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF700.s") + switch (this->grabState) { + case EN_TALK_GIBUD_GRAB_START: + inPositionToAttack = EnTalkGibud_MoveToIdealGrabPositionAndRotation(this, globalCtx); + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && inPositionToAttack == true) { + this->grabState = EN_TALK_GIBUD_GRAB_ATTACK; + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_GRAB_ATTACK); + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF76C.s") + case EN_TALK_GIBUD_GRAB_ATTACK: + if (this->grabDamageTimer == 20) { + s16 requiredScopeTemp; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF880.s") + damageSfxId = player->ageProperties->unk_92 + NA_SE_VO_LI_DAMAGE_S; + globalCtx->damagePlayer(globalCtx, -8); + func_800B8E58(playerActor, damageSfxId); + func_8013ECE0(this->actor.xzDistToPlayer, 240, 1, 12); + this->grabDamageTimer = 0; + } else { + this->grabDamageTimer++; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF8E4.s") + if (Animation_OnFrame(&this->skelAnime, 0.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_ATTACK); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFF9CC.s") + if (!(player->stateFlags2 & 0x80) || player->unk_B62 != 0) { + if (player->unk_B62 != 0 && (player->stateFlags2 & 0x80)) { + player->stateFlags2 &= ~0x80; + player->unk_AE8 = 100; + } + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_GRAB_END); + this->actor.flags |= 1; + this->grabState = EN_TALK_GIBUD_GRAB_RELEASE; + this->grabDamageTimer = 0; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFA68.s") + case EN_TALK_GIBUD_GRAB_RELEASE: + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->grabWaitTimer = 20; + this->actor.shape.yOffset = 0.0f; + EnTalkGibud_SetupWalkToPlayer(this); + } else { + Math_SmoothStepToF(&this->actor.shape.yOffset, 0.0f, 1.0f, 400.0f, 0.0f); + } + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFAB0.s") +void EnTalkGibud_SetupGrabFail(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_DAMAGE); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_DAMAGE); + this->actionFunc = EnTalkGibud_GrabFail; + this->actor.speedXZ = -2.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFC10.s") +void EnTalkGibud_GrabFail(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actor.speedXZ < 0.0f) { + this->actor.speedXZ += 0.15f; + } + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 0x12C, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 0x12C, 0); + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->actor.world.rot.y = this->actor.shape.rot.y; + EnTalkGibud_SetupTurnAwayAndShakeHead(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFC9C.s") +void EnTalkGibud_SetupTurnAwayAndShakeHead(EnTalkGibud* this) { + this->headShakeTimer = 0; + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_WALK); + this->actionFunc = EnTalkGibud_TurnAwayAndShakeHead; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFD3C.s") +void EnTalkGibud_TurnAwayAndShakeHead(EnTalkGibud* this, GlobalContext* globalCtx) { + Math_SmoothStepToS(&this->actor.world.rot.y, BINANG_ROT180(this->actor.yawTowardsPlayer), 5, 3500, 200); + this->actor.shape.rot.y = this->actor.world.rot.y; + if (this->headShakeTimer > 60) { + EnTalkGibud_SetupWalkToHome(this); + this->playerStunWaitTimer = 0; + } else { + this->headRotation.y = + Math_SinS(this->headShakeTimer * 4000) * (0x256F * ((60 - this->headShakeTimer) / 60.0f)); + this->headShakeTimer++; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFE3C.s") +void EnTalkGibud_SetupWalkToHome(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_WALK); + this->actor.speedXZ = 0.4f; + this->actionFunc = EnTalkGibud_WalkToHome; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFE94.s") +void EnTalkGibud_WalkToHome(EnTalkGibud* this, GlobalContext* globalCtx) { + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 100, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 100, 0); + if (Actor_XZDistanceToPoint(&this->actor, &this->actor.home.pos) < 5.0f) { + if (this->actor.speedXZ > 0.2f) { + this->actor.speedXZ -= 0.2f; + } else { + this->actor.speedXZ = 0.0f; + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 1, 200, 10); + this->actor.world.rot.y = this->actor.shape.rot.y; + if (this->actor.world.rot.y == this->actor.home.rot.y) { + EnTalkGibud_SetupIdle(this); + } + } else { + Math_ScaledStepToS(&this->actor.shape.rot.y, Actor_YawToPoint(&this->actor, &this->actor.home.pos), 450); + this->actor.world.rot = this->actor.shape.rot; + } + if (EnTalkGibud_PlayerInRangeWithCorrectState(this, globalCtx)) { + if (gSaveContext.save.playerForm != PLAYER_FORM_GORON && gSaveContext.save.playerForm != PLAYER_FORM_DEKU && + Actor_IsActorFacingLink(&this->actor, 0x38E3)) { + EnTalkGibud_SetupWalkToPlayer(this); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFFA4.s") +void EnTalkGibud_SetupStunned(EnTalkGibud* this) { + this->stunTimer = 10; + this->actor.speedXZ = 0.0f; + this->actor.world.rot.y = this->actor.shape.rot.y; + if (this->effectTimer != 0) { + func_800BCB70(&this->actor, 0, 0xC8, 0, 0x28); + } else { + func_800BCB70(&this->actor, 0, 0xC8, 0, 0x28); + } + this->actionFunc = EnTalkGibud_Stunned; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80AFFFBC.s") +void EnTalkGibud_Stunned(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actor.colorFilterTimer == 0) { + if (this->actor.colChkInfo.health == 0) { + EnTalkGibud_SetupDead(this); + } else { + EnTalkGibud_SetupDamage(this); + } + } + if (this->stunTimer != 0) { + this->stunTimer--; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B000FC.s") +void EnTalkGibud_SetupDamage(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_DAMAGE); + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_DAMAGE); + this->stunTimer = 0; + this->grabWaitTimer = 0; + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + this->actionFunc = EnTalkGibud_Damage; + this->actor.speedXZ = -2.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00158.s") +void EnTalkGibud_Damage(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actor.speedXZ < 0.0f) { + this->actor.speedXZ += 0.15f; + } + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->unk_3F7 = -1; + this->actor.world.rot.y = this->actor.shape.rot.y; + if (this->effectTimer > 0 && this->effectType == 0 && this->type == EN_TALK_GIBUD_TYPE_GIBDO) { + this->actor.hintId = 0x2A; + this->actor.flags &= ~(0x8 | 0x1); + this->actor.flags |= (0x4 | 0x1); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_rd_Skel_010B88, NULL, this->jointTable, + this->morphTable, EN_TALK_GIBUD_LIMB_MAX); + this->type = EN_TALK_GIBUD_TYPE_REDEAD; + } + if (EnTalkGibud_PlayerOutOfRange(this, globalCtx)) { + EnTalkGibud_SetupWalkToHome(this); + } else { + EnTalkGibud_SetupWalkToPlayer(this); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00384.s") +void EnTalkGibud_SetupDead(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_DEATH); + this->actor.flags &= ~1; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_DEAD); + this->deathTimer = 0; + this->actionFunc = EnTalkGibud_Dead; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B0040C.s") +void EnTalkGibud_Dead(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->deathTimer > 300) { + EnTalkGibud_SetupRevive(this); + } else { + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 250, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 250, 0); + this->deathTimer++; + } + if (this->deathTimer == 20 && this->effectTimer > 0 && this->effectType == 0 && + this->type == EN_TALK_GIBUD_TYPE_GIBDO) { + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_rd_Skel_010B88, NULL, this->jointTable, + this->morphTable, EN_TALK_GIBUD_LIMB_MAX); + this->type = EN_TALK_GIBUD_TYPE_REDEAD; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00484.s") +void EnTalkGibud_SetupRevive(EnTalkGibud* this) { + Animation_Change(&this->skelAnime, &object_rd_Anim_009298, -1.0f, Animation_GetLastFrame(&object_rd_Anim_009298), + 0.0f, 2, -8.0f); + this->actor.flags |= 1; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_REVERSE); + this->deathTimer = 0; + this->actor.world.rot.y = this->actor.shape.rot.y; + this->actionFunc = EnTalkGibud_Revive; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B004D0.s") +void EnTalkGibud_Revive(EnTalkGibud* this, GlobalContext* globalCtx) { + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->actor.colChkInfo.health = 8; + EnTalkGibud_SetupIdle(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B005EC.s") +void EnTalkGibud_GetTextIdForRequestedItem(EnTalkGibud* this, GlobalContext* globalCtx) { + switch (this->requestedItemIndex) { + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BLUE_POTION: + func_801518B0(globalCtx, 0x138C, &this->actor); + this->textId = 0x138C; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BEANS: + func_801518B0(globalCtx, 0x138D, &this->actor); + this->textId = 0x138D; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_SPRING_WATER: + func_801518B0(globalCtx, 0x138E, &this->actor); + this->textId = 0x138E; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_FISH: + func_801518B0(globalCtx, 0x138F, &this->actor); + this->textId = 0x138F; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BUGS: + func_801518B0(globalCtx, 0x1390, &this->actor); + this->textId = 0x1390; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_DEKU_NUTS: + func_801518B0(globalCtx, 0x1391, &this->actor); + this->textId = 0x1391; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BOMBS: + func_801518B0(globalCtx, 0x1392, &this->actor); + this->textId = 0x1392; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_HOT_SPRING_WATER: + func_801518B0(globalCtx, 0x1393, &this->actor); + this->textId = 0x1393; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_BIG_POE: + func_801518B0(globalCtx, 0x1394, &this->actor); + this->textId = 0x1394; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_INDEX_MILK: + func_801518B0(globalCtx, 0x1395, &this->actor); + this->textId = 0x1395; + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00760.s") +void EnTalkGibud_GetNextTextBoxId(EnTalkGibud* this, GlobalContext* globalCtx) { + if (func_80147624(globalCtx)) { + switch (this->textId) { + case 0x1388: + EnTalkGibud_GetTextIdForRequestedItem(this, globalCtx); + break; + case 0x138C: + case 0x138D: + case 0x138E: + case 0x138F: + case 0x1390: + case 0x1391: + case 0x1392: + case 0x1393: + case 0x1394: + case 0x1395: + // Prompts the player to choose an item + func_801518B0(globalCtx, 0xFF, &this->actor); + this->textId = 0xFF; + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B008BC.s") +s32 EnTalkGibud_PresentedItemMatchesRequest(EnTalkGibud* this, GlobalContext* globalCtx, s32 presentedItemActionParam) { + EnTalkGibudRequestedItem* requestedItem = &sRequestedItemTable[this->requestedItemIndex]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B008FC.s") + if (requestedItem->itemActionParam == presentedItemActionParam) { + if (!requestedItem->isBottledItem) { + if (AMMO(requestedItem->item) >= requestedItem->amount) { + return EN_TALK_GIBUD_REQUESTED_ITEM_MET; + } else { + return EN_TALK_GIBUD_REQUESTED_ITEM_NOT_ENOUGH_AMMO; + } + } + if (Interface_HasItemInBottle(requestedItem->item)) { + return EN_TALK_GIBUD_REQUESTED_ITEM_MET; + } + } + return EN_TALK_GIBUD_REQUESTED_ITEM_NOT_MET; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B0094C.s") +void EnTalkGibud_CheckPresentedItem(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + s32 itemActionParam; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00B8C.s") + if (this->itemActionParam == PLAYER_AP_NONE) { + itemActionParam = func_80123810(globalCtx); + if (itemActionParam != PLAYER_AP_NONE) { + this->itemActionParam = itemActionParam; + } + if (this->itemActionParam > PLAYER_AP_NONE) { + switch (EnTalkGibud_PresentedItemMatchesRequest(this, globalCtx, this->itemActionParam)) { + case EN_TALK_GIBUD_REQUESTED_ITEM_MET: + player->actor.textId = 0x138A; + this->textId = 0x138A; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_NOT_ENOUGH_AMMO: + player->actor.textId = 0x138B; + this->textId = 0x138B; + break; + case EN_TALK_GIBUD_REQUESTED_ITEM_NOT_MET: + player->actor.textId = 0x1389; + this->textId = 0x1389; + break; + default: + break; + } + func_801477B4(globalCtx); + } else if (this->itemActionParam < PLAYER_AP_NONE) { + func_801518B0(globalCtx, 0x1389, &this->actor); + this->textId = 0x1389; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00C94.s") +void EnTalkGibud_SetupPassiveIdle(EnTalkGibud* this) { + this->isTalking = false; + if (this->actionFunc != EnTalkGibud_Talk) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_IDLE); + } + this->actionFunc = EnTalkGibud_PassiveIdle; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00D9C.s") +/** + * This is the idle for when the player is wearing the Gibdo Mask. The + * Gibdo will not attempt to attack the player and can be spoken to. + */ +void EnTalkGibud_PassiveIdle(EnTalkGibud* this, GlobalContext* globalCtx) { + if (func_800B84D0(&this->actor, globalCtx)) { + this->isTalking = true; + func_801518B0(globalCtx, 0x1388, &this->actor); + this->textId = 0x1388; + Audio_PlayActorSound2(&this->actor, NA_SE_EN_REDEAD_AIM); + EnTalkGibud_SetupTalk(this); + } else if (this->actor.xzDistToPlayer < 100.0f && !(this->collider.base.acFlags & AC_HIT)) { + func_800E9250(globalCtx, &this->actor, &this->headRotation, &this->upperBodyRotation, this->actor.focus.pos); + func_800B8614(&this->actor, globalCtx, 100.0f); + } else { + Math_SmoothStepToS(&this->headRotation.y, 0, 1, 100, 0); + Math_SmoothStepToS(&this->upperBodyRotation.y, 0, 1, 100, 0); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/EnTalkGibud_Update.s") +void EnTalkGibud_SetupTalk(EnTalkGibud* this) { + this->itemActionParam = PLAYER_AP_NONE; + this->actionFunc = EnTalkGibud_Talk; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00F08.s") +void EnTalkGibud_Talk(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + EnTalkGibudRequestedItem* requestedItem; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/func_80B00F64.s") + switch (func_80152498(&globalCtx->msgCtx)) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + break; + case 5: + EnTalkGibud_GetNextTextBoxId(this, globalCtx); + break; + case 6: + if (func_80147624(globalCtx)) { + if (this->textId == 0x138A) { + // Remove the requested item/amount from the player's inventory + requestedItem = &sRequestedItemTable[this->requestedItemIndex]; + if (!requestedItem->isBottledItem) { + Inventory_ChangeAmmo(requestedItem->item, -requestedItem->amount); + } else { + func_80123D50(globalCtx, player, ITEM_BOTTLE, PLAYER_AP_BOTTLE); + } + player->stateFlags1 |= 0x20; + player->stateFlags1 |= 0x20000000; + this->actor.flags |= 0x100000; + EnTalkGibud_SetupDisappear(this); + } else { + EnTalkGibud_SetupPassiveIdle(this); + } + } + break; + case 16: + EnTalkGibud_CheckPresentedItem(this, globalCtx); + break; + } + EnTalkGibud_FacePlayerWhenTalking(this, globalCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Talk_Gibud/EnTalkGibud_Draw.s") +void EnTalkGibud_SetupDisappear(EnTalkGibud* this) { + func_800BDC5C(&this->skelAnime, sAnimations, EN_TALK_GIBUD_ANIMATION_IDLE); + this->actor.flags &= ~1; + this->disappearanceTimer = 40; + this->actionFunc = EnTalkGibud_Disappear; +} + +void EnTalkGibud_Disappear(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f velocity = sVelocity; + Vec3f accel = sAccel; + Vec3f pos; + s32 numFlamesToSpawn; + s32 i; + + if (this->disappearanceTimer > 0) { + numFlamesToSpawn = CLAMP_MAX(this->disappearanceTimer, 3); + for (i = 0; i < numFlamesToSpawn; i++) { + pos = this->actor.world.pos; + pos.x += Rand_Centered() * 20.0f; + pos.y += 50.0f + (Rand_Centered() * 50.0f); + pos.z += Rand_Centered() * 20.0f; + velocity.x += Rand_Centered() * 1.5f; + velocity.z += Rand_Centered() * 1.5f; + func_800B3030(globalCtx, &pos, &velocity, &accel, 100, 0, 1); + } + func_800B9010(&this->actor, NA_SE_EN_COMMON_EXTINCT_LEV - SFX_FLAG); + player->stateFlags1 |= 0x20000000; + this->disappearanceTimer--; + } else { + if (this->switchFlag != -1) { + Actor_SetSwitchFlag(globalCtx, this->switchFlag); + } + player->stateFlags1 &= ~0x20; + player->stateFlags1 &= ~0x20000000; + Actor_MarkForDeath(&this->actor); + } +} + +void EnTalkGibud_FacePlayerWhenTalking(EnTalkGibud* this, GlobalContext* globalCtx) { + s16 target = this->actor.yawTowardsPlayer; + + Math_ScaledStepToS(&this->actor.shape.rot.y, target, 0x320); + target -= this->actor.shape.rot.y; + this->actor.world.rot.y = this->actor.shape.rot.y; + Math_ScaledStepToS(&this->upperBodyRotation.y, target, 0x258); + target -= this->upperBodyRotation.y; + Math_ScaledStepToS(&this->headRotation.y, target, 0x190); +} + +s32 EnTalkGibud_PlayerInRangeWithCorrectState(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if ((Actor_DistanceToPoint(&player->actor, &this->actor.home.pos) < 150.0f) && !(player->stateFlags1 & 0x2C6080) && + !(player->stateFlags2 & 0x4080)) { + return true; + } + + return false; +} + +/** + * Gibdos/Redeads have a very short range around their home where they will + * engage with the player. If the player is out of this range, they will simply + * walk back to their home. + */ +s32 EnTalkGibud_PlayerOutOfRange(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (Actor_DistanceToPoint(&player->actor, &this->actor.home.pos) >= 150.0f) { + return true; + } + + return false; +} + +void EnTalkGibud_CheckForGibdoMask(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actionFunc != EnTalkGibud_Grab && this->actionFunc != EnTalkGibud_Dead && + this->actionFunc != EnTalkGibud_Disappear && this->actionFunc != EnTalkGibud_Revive && + this->actionFunc != EnTalkGibud_Damage && this->actionFunc != EnTalkGibud_Talk) { + if (this->actionFunc != EnTalkGibud_PassiveIdle) { + if (Player_GetMask(globalCtx) == PLAYER_MASK_GIBDO) { + this->actor.flags &= ~(0x4 | 0x1); + this->actor.flags |= (0x8 | 0x1); + this->actor.hintId = 0xFF; + this->actor.textId = 0; + EnTalkGibud_SetupPassiveIdle(this); + } + } else if (Player_GetMask(globalCtx) != PLAYER_MASK_GIBDO) { + this->actor.flags &= ~(0x8 | 0x1); + this->actor.flags |= (0x4 | 0x1); + if (this->type == EN_TALK_GIBUD_TYPE_REDEAD) { + this->actor.hintId = 0x2A; + } else { + this->actor.hintId = 0x2D; + } + this->actor.textId = 0; + EnTalkGibud_SetupWalkToHome(this); + } + } +} + +void EnTalkGibud_TurnTowardsPlayer(EnTalkGibud* this, GlobalContext* globalCtx) { + s16 headAngle = (this->actor.yawTowardsPlayer - this->actor.shape.rot.y) - this->upperBodyRotation.y; + s16 upperBodyAngle = CLAMP(headAngle, -500, 500); + + headAngle -= this->headRotation.y; + headAngle = CLAMP(headAngle, -500, 500); + + if (BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y) >= 0) { + this->upperBodyRotation.y += ABS_ALT(upperBodyAngle); + this->headRotation.y += ABS_ALT(headAngle); + } else { + this->upperBodyRotation.y -= ABS_ALT(upperBodyAngle); + this->headRotation.y -= ABS_ALT(headAngle); + } + + this->upperBodyRotation.y = CLAMP(this->upperBodyRotation.y, -0x495F, 0x495F); + this->headRotation.y = CLAMP(this->headRotation.y, -0x256F, 0x256F); +} + +/** + * Returns true if the Gibdo is in the correct position and rotation to start + * performing its grab attack. Regardless of what this returns, the Gibdo is + * moved closer to this ideal position and rotation. + */ +s32 EnTalkGibud_MoveToIdealGrabPositionAndRotation(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f targetPos; + f32 distanceFromTargetPos; + f32 distanceFromTargetYOffset = 0.0f; + s16 distanceFromTargetAngle; + + targetPos = player->actor.world.pos; + targetPos.x -= 25.0f * Math_SinS(player->actor.shape.rot.y); + targetPos.z -= 25.0f * Math_CosS(player->actor.shape.rot.y); + distanceFromTargetPos = Math_Vec3f_StepTo(&this->actor.world.pos, &targetPos, 10.0f); + distanceFromTargetAngle = Math_SmoothStepToS(&this->actor.shape.rot.y, player->actor.shape.rot.y, 1, 0x1770, 0x64); + this->actor.world.rot.y = this->actor.shape.rot.y; + if (gSaveContext.save.playerForm == PLAYER_FORM_HUMAN) { + distanceFromTargetYOffset = Math_SmoothStepToF(&this->actor.shape.yOffset, -1500.0f, 1.0f, 150.0f, 0.0f); + } + + if (distanceFromTargetPos == 0.0f && ABS_ALT(distanceFromTargetAngle) < 100 && distanceFromTargetYOffset == 0.0f) { + return true; + } + + return false; +} + +void EnTalkGibud_PlayAnimation(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actionFunc != EnTalkGibud_Stunned) { + SkelAnime_Update(&this->skelAnime); + } +} + +void EnTalkGibud_MoveWithGravity(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->actionFunc == EnTalkGibud_WalkToPlayer || this->actionFunc == EnTalkGibud_WalkToHome || + this->actionFunc == EnTalkGibud_Damage) { + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } +} + +void EnTalkGibud_CheckDamageEffect(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (this->collider.base.acFlags & AC_HIT) { + this->collider.base.acFlags &= ~AC_HIT; + Actor_ApplyDamage(&this->actor); + + switch (this->actor.colChkInfo.damageEffect) { + case EN_TALK_GIBUD_DMGEFF_DAMAGE: + func_800BCB70(&this->actor, 0x4000, 255, 0, 8); + if (player->unk_ADC != 0) { + this->unk_3F7 = player->unk_ADD; + } + this->actor.shape.yOffset = 0.0f; + if (this->actor.colChkInfo.health == 0) { + EnTalkGibud_SetupDead(this); + } else { + EnTalkGibud_SetupDamage(this); + } + break; + + case EN_TALK_GIBUD_DMGEFF_LIGHT_RAY: + if (this->type == EN_TALK_GIBUD_TYPE_REDEAD) { + this->actor.colChkInfo.health = 0; + this->actor.shape.yOffset = 0.0f; + EnTalkGibud_SetupDead(this); + } + break; + + case EN_TALK_GIBUD_DMGEFF_FIRE_ARROW: + func_800BCB70(&this->actor, 0x4000, 255, 0, 8); + if (this->actor.colChkInfo.health == 0) { + EnTalkGibud_SetupDead(this); + } else { + EnTalkGibud_SetupDamage(this); + } + this->effectTimer = 180; + this->effectType = 0; + this->effectAlpha = 1.0f; + break; + + case EN_TALK_GIBUD_DMGEFF_LIGHT_ARROW: + func_800BCB70(&this->actor, 0x4000, 255, 0, 8); + if (this->actor.colChkInfo.health == 0) { + EnTalkGibud_SetupDead(this); + } else { + EnTalkGibud_SetupDamage(this); + } + this->effectTimer = 60; + this->effectType = 20; + this->effectAlpha = 1.0f; + break; + + case EN_TALK_GIBUD_DMGEFF_ZORA_MAGIC: + if (this->actionFunc != EnTalkGibud_Grab && + (this->actionFunc != EnTalkGibud_Stunned || this->stunTimer == 0)) { + this->effectAlpha = 1.0f; + this->effectTimer = 40; + this->effectType = 30; + EnTalkGibud_SetupStunned(this); + } + break; + + case EN_TALK_GIBUD_DMGEFF_STUN: + if ((this->actionFunc != EnTalkGibud_Stunned) || this->stunTimer == 0) { + EnTalkGibud_SetupStunned(this); + } + break; + } + } +} + +void EnTalkGibud_CheckCollision(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (this->actionFunc != EnTalkGibud_Dead && this->actionFunc != EnTalkGibud_Disappear && + this->actionFunc != EnTalkGibud_Revive && + (this->actionFunc != EnTalkGibud_Grab || this->grabState == EN_TALK_GIBUD_GRAB_RELEASE)) { + if (this->isTalking != true) { + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + if ((this->actionFunc != EnTalkGibud_Damage || + (player->unk_ADC != 0 && player->unk_ADD != this->unk_3F7)) && + (this->actionFunc != EnTalkGibud_Stunned || this->stunTimer == 0)) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + } + } + } +} + +/** + * If the Gibdo is starting a grab and is touching a wall, the player is moved + * away from that wall with this function. This can happen when the player's + * back is close to a wall before being grabbed. The Gibdo changes its own + * position to match the player's position at the start of a grab, so moving + * the player like this will help prevent the Gibdo from looking like it's + * clipping into the wall as it grabs onto the player. + */ +void EnTalkGibud_MoveGrabbedPlayerAwayFromWall(EnTalkGibud* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f targetPos; + + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 30.0f, 20.0f, 35.0f, 29); + if (this->actionFunc == EnTalkGibud_Grab && this->grabState == EN_TALK_GIBUD_GRAB_START && + (this->actor.bgCheckFlags & 8)) { + targetPos = player->actor.world.pos; + targetPos.x += 10.0f * Math_SinS(this->actor.wallYaw); + targetPos.z += 10.0f * Math_CosS(this->actor.wallYaw); + Math_Vec3f_StepTo(&player->actor.world.pos, &targetPos, 5.0f); + } +} + +void EnTalkGibud_UpdateEffect(EnTalkGibud* this, GlobalContext* globalCtx) { + if (this->effectTimer > 0) { + this->effectTimer--; + } + if (this->effectTimer < 20) { + Math_SmoothStepToF(&this->effectScale, 0.0f, 0.5f, 0.03f, 0.0f); + this->effectAlpha = this->effectTimer * 0.05f; + } else { + Math_SmoothStepToF(&this->effectScale, 0.5f, 0.1f, 0.02f, 0.0f); + } +} + +void EnTalkGibud_Update(Actor* thisx, GlobalContext* globalCtx) { + EnTalkGibud* this = THIS; + + EnTalkGibud_CheckForGibdoMask(this, globalCtx); + EnTalkGibud_CheckDamageEffect(this, globalCtx); + this->actionFunc(this, globalCtx); + EnTalkGibud_PlayAnimation(this, globalCtx); + EnTalkGibud_MoveWithGravity(this, globalCtx); + EnTalkGibud_CheckCollision(this, globalCtx); + EnTalkGibud_MoveGrabbedPlayerAwayFromWall(this, globalCtx); + EnTalkGibud_UpdateEffect(this, globalCtx); + this->actor.focus.pos = this->actor.world.pos; + this->actor.focus.pos.y += 50.0f; +} + +s32 EnTalkGibud_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + Actor* thisx, Gfx** gfx) { + EnTalkGibud* this = THIS; + + if (limbIndex == EN_TALK_GIBUD_LIMB_UPPER_BODY_ROOT) { + rot->y += this->upperBodyRotation.y; + } else if (limbIndex == EN_TALK_GIBUD_LIMB_HEAD_ROOT) { + rot->y += this->headRotation.y; + } + + return false; +} + +void EnTalkGibud_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, + Gfx** gfx) { + EnTalkGibud* this = THIS; + + if ((this->effectTimer != 0) && + ((limbIndex == EN_TALK_GIBUD_LIMB_LEFT_THIGH) || (limbIndex == EN_TALK_GIBUD_LIMB_LEFT_LOWER_LEG) || + (limbIndex == EN_TALK_GIBUD_LIMB_LEFT_FOOT) || (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_THIGH) || + (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_LOWER_LEG) || (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_FOOT) || + (limbIndex == EN_TALK_GIBUD_LIMB_TORSO) || (limbIndex == EN_TALK_GIBUD_LIMB_LEFT_SHOULDER_AND_UPPER_ARM) || + (limbIndex == EN_TALK_GIBUD_LIMB_LEFT_FOREARM) || (limbIndex == EN_TALK_GIBUD_LIMB_LEFT_HAND) || + (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_SHOULDER_AND_UPPER_ARM) || + (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_FOREARM) || (limbIndex == EN_TALK_GIBUD_LIMB_RIGHT_HAND) || + (limbIndex == EN_TALK_GIBUD_LIMB_HEAD) || (limbIndex == EN_TALK_GIBUD_LIMB_PELVIS))) { + Matrix_GetStateTranslation(&this->limbPos[this->limbIndex]); + this->limbIndex++; + } +} + +void EnTalkGibud_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnTalkGibud* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + this->limbIndex = 0; + if (this->actor.shape.shadowAlpha == 255) { + func_8012C28C(globalCtx->state.gfxCtx); + + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->actor.shape.shadowAlpha); + gSPSegment(POLY_OPA_DISP++, 0x08, D_801AEFA0); + + POLY_OPA_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, EnTalkGibud_OverrideLimbDraw, + EnTalkGibud_PostLimbDraw, &this->actor, POLY_OPA_DISP); + } else { + func_8012C2DC(globalCtx->state.gfxCtx); + + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->actor.shape.shadowAlpha); + gSPSegment(POLY_XLU_DISP++, 0x08, D_801AEF88); + + POLY_XLU_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, EnTalkGibud_OverrideLimbDraw, + EnTalkGibud_PostLimbDraw, &this->actor, POLY_XLU_DISP); + } + if (this->effectTimer > 0) { + func_800BE680(globalCtx, &this->actor, this->limbPos, ARRAY_COUNT(this->limbPos), this->effectScale, 0.5f, + this->effectAlpha, this->effectType); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.h b/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.h index 57c0d2ae9..2c154ea89 100644 --- a/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.h +++ b/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.h @@ -3,15 +3,86 @@ #include "global.h" +#define EN_TALK_GIBUD_REQUESTED_ITEM_INDEX(thisx) ((thisx)->params & 0xF) +#define EN_TALK_GIBUD_SWITCH_FLAG(thisx) (((thisx)->params & 0xFF0) >> 4) + +typedef enum { + /* 0 */ EN_TALK_GIBUD_TYPE_GIBDO, + /* 1 */ EN_TALK_GIBUD_TYPE_REDEAD, +} EnTalkGibudType; + +typedef enum { + /* 0 */ EN_TALK_GIBUD_GRAB_START, + /* 1 */ EN_TALK_GIBUD_GRAB_ATTACK, + /* 2 */ EN_TALK_GIBUD_GRAB_RELEASE, +} EnTalkGibudGrabState; + +typedef enum { + /* 0 */ EN_TALK_GIBUD_LIMB_NONE, + /* 1 */ EN_TALK_GIBUD_LIMB_ROOT, // Root of Left Leg Root, Right Leg Root, Upper Body Root, and Pelvis + /* 2 */ EN_TALK_GIBUD_LIMB_LEFT_LEG_ROOT, + /* 3 */ EN_TALK_GIBUD_LIMB_LEFT_THIGH, + /* 4 */ EN_TALK_GIBUD_LIMB_LEFT_LOWER_LEG, + /* 5 */ EN_TALK_GIBUD_LIMB_LEFT_FOOT_ROOT, + /* 6 */ EN_TALK_GIBUD_LIMB_LEFT_FOOT, + /* 7 */ EN_TALK_GIBUD_LIMB_RIGHT_LEG_ROOT, + /* 8 */ EN_TALK_GIBUD_LIMB_RIGHT_THIGH, + /* 9 */ EN_TALK_GIBUD_LIMB_RIGHT_LOWER_LEG, + /* 10 */ EN_TALK_GIBUD_LIMB_RIGHT_FOOT_ROOT, + /* 11 */ EN_TALK_GIBUD_LIMB_RIGHT_FOOT, + /* 12 */ EN_TALK_GIBUD_LIMB_UPPER_BODY_ROOT, + /* 13 */ EN_TALK_GIBUD_LIMB_UPPER_BODY, // Root of Torso + /* 14 */ EN_TALK_GIBUD_LIMB_TORSO, // Root of Left Arm Root, Right Arm Root, and Head Root + /* 15 */ EN_TALK_GIBUD_LIMB_LEFT_ARM_ROOT, + /* 16 */ EN_TALK_GIBUD_LIMB_LEFT_SHOULDER_AND_UPPER_ARM, + /* 17 */ EN_TALK_GIBUD_LIMB_LEFT_FOREARM, + /* 18 */ EN_TALK_GIBUD_LIMB_LEFT_HAND, + /* 19 */ EN_TALK_GIBUD_LIMB_RIGHT_ARM_ROOT, + /* 20 */ EN_TALK_GIBUD_LIMB_RIGHT_SHOULDER_AND_UPPER_ARM, + /* 21 */ EN_TALK_GIBUD_LIMB_RIGHT_FOREARM, + /* 22 */ EN_TALK_GIBUD_LIMB_RIGHT_HAND, + /* 23 */ EN_TALK_GIBUD_LIMB_HEAD_ROOT, + /* 24 */ EN_TALK_GIBUD_LIMB_HEAD, + /* 25 */ EN_TALK_GIBUD_LIMB_PELVIS, + /* 26 */ EN_TALK_GIBUD_LIMB_MAX, +} EnTalkGibudLimbs; + struct EnTalkGibud; typedef void (*EnTalkGibudActionFunc)(struct EnTalkGibud*, GlobalContext*); typedef struct EnTalkGibud { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x90]; - /* 0x01D4 */ EnTalkGibudActionFunc actionFunc; - /* 0x01D8 */ char unk_1D8[0x220]; + /* 0x000 */ Actor actor; + /* 0x144 */ ColliderCylinder collider; + /* 0x190 */ SkelAnime skelAnime; + /* 0x1D4 */ EnTalkGibudActionFunc actionFunc; + /* 0x1D8 */ Vec3f limbPos[15]; + /* 0x28C */ s32 limbIndex; + /* 0x290 */ s32 requestedItemIndex; + /* 0x294 */ s32 itemActionParam; + /* 0x298 */ s32 switchFlag; + /* 0x29C */ f32 effectAlpha; + /* 0x2A0 */ f32 effectScale; + /* 0x2A4 */ Vec3s jointTable[EN_TALK_GIBUD_LIMB_MAX]; + /* 0x340 */ Vec3s morphTable[EN_TALK_GIBUD_LIMB_MAX]; + /* 0x3DC */ s16 textId; + /* 0x3DE */ Vec3s headRotation; + /* 0x3E4 */ Vec3s upperBodyRotation; + /* 0x3EA */ union { + s16 playerStunWaitTimer; // Cannot stun the player if this is non-zero + s16 grabDamageTimer; + s16 headShakeTimer; + s16 stunTimer; + s16 deathTimer; + s16 disappearanceTimer; + }; + /* 0x3EC */ s16 grabState; + /* 0x3EE */ s16 grabWaitTimer; // Cannot grab the player if this is non-zero + /* 0x3F0 */ s16 effectTimer; + /* 0x3F2 */ s16 type; + /* 0x3F4 */ s16 isTalking; + /* 0x3F6 */ u8 effectType; + /* 0x3F7 */ s8 unk_3F7; // related to player->unk_ADD } EnTalkGibud; // size = 0x3F8 extern const ActorInit En_Talk_Gibud_InitVars; diff --git a/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.c b/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.c index 13fbb074b..f3d120dfe 100644 --- a/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.c +++ b/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.c @@ -1,43 +1,51 @@ /* * File: z_obj_tokeidai.c * Overlay: ovl_Obj_Tokeidai - * Description: Components of the Clock Tower (gears, clock face, counterweight, etc). + * Description: Components of the Clock Tower (gears, clock face, counterweight, etc). Also used for wall clocks. + * + * This actor handles most of the functionality related to the Clock Tower and the various + * wall clocks around Clock Town. Among its responsibilities are making the clocks correctly + * tell the time by spinning the various pieces and gears and controlling the spotlight that + * is emitted from the Clock Tower at night. + * + * On the midnight of the Final Day, the Clock Tower opens up, and the various pieces of it + * are moved around. This actor is responsible for managing all of this movement. Additionally, + * if the moon crashes into Termina, this actor is responsible for making the pieces of the + * Clock Tower collapse. */ #include "z_obj_tokeidai.h" +#include "objects/object_obj_tokeidai/object_obj_tokeidai.h" #define FLAGS 0x00000030 #define THIS ((ObjTokeidai*)thisx) +#define GET_CURRENT_HOUR(this) ((s32)((this)->currentTime * (24.0f / 0x10000))) +#define GET_CURRENT_MINUTE(this) ((s32)((this)->currentTime * (360 * 2.0f / 0x10000)) % 30) +#define GET_CLOCK_FACE_ROTATION(currentHour) ((s16)(currentHour * (0x10000 / 24.0f))) +#define GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute) ((s16)(currentMinute * (0x10000 * 12.0f / 360))) + void ObjTokeidai_Init(Actor* thisx, GlobalContext* globalCtx); void ObjTokeidai_Destroy(Actor* thisx, GlobalContext* globalCtx); void ObjTokeidai_Update(Actor* thisx, GlobalContext* globalCtx); void ObjTokeidai_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_80AB319C(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3240(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB32F0(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3370(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB34CC(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3544(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3598(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB363C(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB365C(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3808(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3880(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB38B0(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB39BC(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3A7C(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3B34(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3BD8(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3BE8(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB3ED0(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB4040(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB4080(ObjTokeidai* this, GlobalContext* globalCtx); -void func_80AB4160(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_DoNothing(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_TowerClock_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_TowerGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_Counterweight_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_WallClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_TowerGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_Counterweight_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_Walls_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_StaircaseIntoTower_Idle(ObjTokeidai* this, GlobalContext* globalCtx); +void ObjTokeidai_SetupTowerOpening(ObjTokeidai* this); +void ObjTokeidai_Clock_Draw(Actor* thisx, GlobalContext* globalCtx); +void ObjTokeidai_Counterweight_Draw(Actor* thisx, GlobalContext* globalCtx); +void ObjTokeidai_TowerGear_Draw(Actor* thisx, GlobalContext* globalCtx); -#if 0 const ActorInit Obj_Tokeidai_InitVars = { ACTOR_OBJ_TOKEIDAI, ACTORCAT_PROP, @@ -50,87 +58,794 @@ const ActorInit Obj_Tokeidai_InitVars = { (ActorFunc)ObjTokeidai_Draw, }; -#endif +static InitChainEntry sInitChain[] = { + ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_CONTINUE), + ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE), + ICHAIN_F32(uncullZoneScale, 3300, ICHAIN_CONTINUE), + ICHAIN_F32(uncullZoneForward, 1100, ICHAIN_STOP), +}; -extern UNK_TYPE D_0600B208; -extern UNK_TYPE D_0600BA78; -extern UNK_TYPE D_0600CF28; -extern UNK_TYPE D_0600D388; +/** + * Returns the angle necessary to show the correct side of + * the sun and moon disk based on the time of day. The actual + * angle can differ from the target angle if the disk is in + * the middle of rotating. + */ +s32 ObjTokeidai_GetTargetSunMoonDiskRotation() { + if (gSaveContext.save.isNight) { + return 0x8000; + } + return 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB2790.s") +void ObjTokeidai_SetupClockOrGear(ObjTokeidai* this) { + s32 currentMinute = GET_CURRENT_MINUTE(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB27B4.s") + this->clockMinute = currentMinute; + this->outerRingOrGearRotation = GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute); + this->outerRingOrGearRotationalVelocity = 0x3C; + this->outerRingOrGearRotationTimer = 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB2834.s") +void ObjTokeidai_Clock_Init(ObjTokeidai* this) { + s32 currentHour; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB28C8.s") + ObjTokeidai_SetupClockOrGear(this); + currentHour = GET_CURRENT_HOUR(this); + this->clockHour = currentHour; + this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentHour); + this->clockFaceRotationalVelocity = 0; + this->clockFaceRotationTimer = 0; + this->sunMoonDiskRotationalVelocity = 0; + this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation(); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB29F8.s") +void ObjTokeidai_TowerGear_Init(ObjTokeidai* this, GlobalContext* globalCtx) { + this->actor.draw = ObjTokeidai_TowerGear_Draw; + this->opaDList = object_obj_tokeidai_DL_00BA78; + ObjTokeidai_SetupClockOrGear(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB2BBC.s") + if (((globalCtx->sceneNum == SCENE_CLOCKTOWER) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0)) || + ((globalCtx->sceneNum == SCENE_00KEIKOKU) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0))) { + ObjTokeidai_SetupTowerOpening(this); + } else if ((CURRENT_DAY == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) { + this->actionFunc = ObjTokeidai_TowerGear_OpenedIdle; + this->actor.world.pos.y += this->actor.scale.y * 1900.0f; + this->actor.shape.yOffset = 1500.0f; + gSaveContext.save.weekEventReg[8] |= 0x40; + } else { + this->actionFunc = ObjTokeidai_TowerGear_Idle; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/ObjTokeidai_Init.s") +void ObjTokeidai_TowerClock_Init(ObjTokeidai* this, GlobalContext* globalCtx) { + this->actor.draw = ObjTokeidai_Clock_Draw; + ObjTokeidai_Clock_Init(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/ObjTokeidai_Destroy.s") + if (((globalCtx->sceneNum == SCENE_CLOCKTOWER) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0)) || + ((globalCtx->sceneNum == SCENE_00KEIKOKU) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0))) { + ObjTokeidai_SetupTowerOpening(this); + } else if ((CURRENT_DAY == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) { + this->actor.world.pos.y += (this->actor.scale.y * 5191.0f) - 50.0f; + this->actor.world.pos.x += Math_SinS(this->actor.world.rot.y) * this->actor.scale.z * 1791.0f; + this->actor.world.pos.z += -Math_CosS(this->actor.world.rot.y) * this->actor.scale.z * 1791.0f; + this->clockFaceZTranslation = -0x140; + this->actor.shape.rot.x = -0x4000; + this->actor.home.pos = this->actor.world.pos; + this->actor.home.pos.y -= 1178.0f; + this->actor.home.pos.z += 13.0f; + this->actionFunc = ObjTokeidai_TowerClock_OpenedIdle; + } else { + this->actionFunc = ObjTokeidai_TowerClock_Idle; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3010.s") +void ObjTokeidai_Counterweight_Init(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 type; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB319C.s") + this->actor.draw = ObjTokeidai_Counterweight_Draw; + this->opaDList = object_obj_tokeidai_DL_00B208; + this->xluDList = object_obj_tokeidai_DL_00B0C0; + if (gSaveContext.save.isNight) { + this->spotlightIntensity = 100; + } else { + this->spotlightIntensity = 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3240.s") + if (((globalCtx->sceneNum == SCENE_CLOCKTOWER) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0)) || + ((globalCtx->sceneNum == SCENE_00KEIKOKU) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0))) { + this->spotlightIntensity = 0; + ObjTokeidai_SetupTowerOpening(this); + if (this->actor.child == NULL) { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + if (type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN || + type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) { + this->actor.child = + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_HANABI, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0); + } + } + if (this->actor.child != NULL) { + if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) { + this->actor.child->home.rot.x = 0x384; + } else { + this->actor.child->home.rot.x = 0x12C; + } + } + } else if ((CURRENT_DAY == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) { + this->spotlightIntensity = 0; + this->actor.world.pos.y += this->actor.scale.y * -2160.0f; + this->actor.world.pos.x += Math_SinS(this->actor.world.rot.y) * this->actor.scale.z * 5400.0f; + this->actor.world.pos.z += -Math_CosS(this->actor.world.rot.y) * this->actor.scale.z * 5400.0f; + this->actor.shape.rot.x = -0x4000; + this->actionFunc = ObjTokeidai_Counterweight_OpenedIdle; + } else { + this->actionFunc = ObjTokeidai_Counterweight_Idle; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB32F0.s") +void ObjTokeidai_Init(Actor* thisx, GlobalContext* globalCtx) { + ObjTokeidai* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3370.s") + Actor_ProcessInitChain(&this->actor, sInitChain); + this->actionFunc = ObjTokeidai_DoNothing; + this->opaDList = NULL; + this->xluDList = NULL; + this->xRotation = 0; + this->yTranslation = 0; + this->clockFaceZTranslation = 0; + this->currentTime = gSaveContext.save.time; + this->actor.home.rot.x = 0; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB34CC.s") + switch (OBJ_TOKEIDAI_TYPE(&this->actor)) { + case OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD: + Actor_SetScale(&this->actor, 0.15f); + ObjTokeidai_TowerGear_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_TOWER_GEAR_CLOCK_TOWN: + ObjTokeidai_TowerGear_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_UNUSED_WALL: + this->opaDList = object_obj_tokeidai_DL_00D388; + break; + case OBJ_TOKEIDAI_TYPE_TOWER_WALLS_TERMINA_FIELD: + Actor_SetScale(&this->actor, 1.0f); + this->opaDList = object_obj_tokeidai_DL_009A08; + this->actionFunc = ObjTokeidai_Walls_Idle; + break; + case OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD: + Actor_SetScale(&this->actor, 0.15f); + ObjTokeidai_TowerClock_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN: + ObjTokeidai_TowerClock_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_WALL_CLOCK: + Actor_SetScale(&this->actor, 0.02f); + this->actor.draw = ObjTokeidai_Clock_Draw; + ObjTokeidai_Clock_Init(this); + this->actionFunc = ObjTokeidai_WallClock_Idle; + break; + case OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK: + Actor_SetScale(&this->actor, 0.01f); + this->actor.draw = ObjTokeidai_Clock_Draw; + ObjTokeidai_Clock_Init(this); + this->actionFunc = ObjTokeidai_WallClock_Idle; + break; + case OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD: + Actor_SetScale(&this->actor, 0.15f); + ObjTokeidai_Counterweight_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN: + ObjTokeidai_Counterweight_Init(this, globalCtx); + break; + case OBJ_TOKEIDAI_TYPE_STAIRCASE_INTO_TOWER: + this->opaDList = object_obj_tokeidai_DL_00D8E8; + this->xluDList = object_obj_tokeidai_DL_00D8E0; + this->actionFunc = ObjTokeidai_StaircaseIntoTower_Idle; + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3544.s") +void ObjTokeidai_Destroy(Actor* thisx, GlobalContext* globalCtx) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3598.s") +void ObjTokeidai_RotateOnMinuteChange(ObjTokeidai* this, s32 playSfx) { + s32 currentMinute = GET_CURRENT_MINUTE(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB363C.s") + if (currentMinute != this->clockMinute) { + if (this->outerRingOrGearRotationTimer == 8 && playSfx) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_SECOND_HAND); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB365C.s") + if (this->outerRingOrGearRotationTimer > 8) { + // This actually performs the rotation to the next minute + // for the outer ring or gear. + this->outerRingOrGearRotationalVelocity += 0x3C; + this->outerRingOrGearRotation += this->outerRingOrGearRotationalVelocity; + } else { + // This makes the outer ring or gear wiggle in place for a bit + // before rotating to the next position. + if ((this->outerRingOrGearRotationTimer & 3) == 0) { + this->outerRingOrGearRotation += 0x5A; + } + if ((this->outerRingOrGearRotationTimer & 3) == 1) { + this->outerRingOrGearRotation -= 0x5A; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB36C4.s") + this->outerRingOrGearRotationTimer++; + if ((currentMinute == 15 && this->outerRingOrGearRotation < 0) || + (currentMinute != 15 && this->outerRingOrGearRotation > GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute))) { + this->outerRingOrGearRotation = GET_OUTER_RING_OR_GEAR_ROTATION(currentMinute); + this->clockMinute = currentMinute; + this->outerRingOrGearRotationalVelocity = 0x5A; + this->outerRingOrGearRotationTimer = 0; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3808.s") +void ObjTokeidai_TowerGear_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) { + if ((this->actor.bgCheckFlags & 1) || this->actor.world.pos.y < 0.0f) { + this->actionFunc = ObjTokeidai_DoNothing; + } else { + this->actor.shape.rot.x += 0x50; + this->actor.shape.rot.z += 0x50; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 0.0f, 0.0f, 0.0f, 4); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3880.s") +void ObjTokeidai_TowerGear_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x84) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 2) { + this->actionFunc = ObjTokeidai_TowerGear_Collapse; + this->actor.speedXZ = this->actor.scale.y * 5.0f; + this->actor.velocity.y = 0.0f; + this->actor.minVelocityY = this->actor.scale.y * -50.0f; + this->actor.gravity = this->actor.scale.y * -5.0f; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB38B0.s") +/** + * This is hard to see in the final game. This, used in conjunction + * with the following function, makes the tower's clock slide off the + * tower and spin through the air when the moon crashes. + */ +void ObjTokeidai_TowerClock_Fall(ObjTokeidai* this, GlobalContext* globalCtx) { + this->actor.shape.rot.x += this->fallingClockFaceRotationalVelocity; + if (this->fallingClockFaceRotationalVelocity > 0xA0) { + this->fallingClockFaceRotationalVelocity -= 5; + } + this->actor.world.pos.z += 4.0f; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + if (this->actor.world.pos.y < 0.0f) { + this->actionFunc = ObjTokeidai_DoNothing; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB39BC.s") +/** + * This is hard to see in the final game. This makes the + * tower's clock slide off as the moon crashes into it. + */ +void ObjTokeidai_TowerClock_SlideOff(ObjTokeidai* this, GlobalContext* globalCtx) { + f32 cos; + f32 sin; + Actor* thisx = &this->actor; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3A7C.s") + if (this->slidingClockFaceAngle < 0x4000) { + this->slidingClockFaceAngle += 0x28; + } + if (this->slidingClockFaceAngle > 0x800) { + this->aerialClockFaceSpeed += 4; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3B34.s") + if (this->aerialClockFaceSpeed < 0x80) { + thisx->shape.rot.x = this->slidingClockFaceAngle - 0x4000; + this->fallingClockFaceRotationalVelocity = 0x28; + } else { + if (thisx->shape.rot.x < -0x1000) { + thisx->shape.rot.x += this->fallingClockFaceRotationalVelocity; + if (this->fallingClockFaceRotationalVelocity < 0x1E0) { + this->fallingClockFaceRotationalVelocity += 0xA; + } + } else { + thisx->shape.rot.x += this->fallingClockFaceRotationalVelocity; + this->actionFunc = ObjTokeidai_TowerClock_Fall; + thisx->minVelocityY = -7.5f; + thisx->gravity = -0.75f; + thisx->velocity.y = -2.0f; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3BB0.s") + sin = Math_SinS(this->slidingClockFaceAngle); + cos = Math_CosS(this->slidingClockFaceAngle); + thisx->world.pos.y = (1178.0f * cos) - (this->aerialClockFaceSpeed * sin) + thisx->home.pos.y; + thisx->world.pos.z = (1178.0f * sin) + (this->aerialClockFaceSpeed * cos) + thisx->home.pos.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3BD8.s") +void ObjTokeidai_TowerClock_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x84) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 1) { + this->actionFunc = ObjTokeidai_TowerClock_SlideOff; + this->slidingClockFaceAngle = 0; + this->aerialClockFaceSpeed = -0xD; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3BE8.s") +void ObjTokeidai_Counterweight_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) { + if (this->actor.world.pos.y < 0.0f) { + this->actionFunc = ObjTokeidai_DoNothing; + } else { + this->xRotation += 0x64; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3C50.s") +void ObjTokeidai_Counterweight_OpenedIdle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x84) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 3) { + this->actionFunc = ObjTokeidai_Counterweight_Collapse; + this->xRotation = 0; + this->actor.velocity.y = 0.0f; + this->actor.minVelocityY = this->actor.scale.y * -50.0f; + this->actor.gravity = this->actor.scale.y * -5.0f; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3CCC.s") +/** + * This is hard to see in the final game. It makes the walls of + * the clock tower tip over as the moon crashes into it, but the + * giant moon mostly obscures it. + */ +void ObjTokeidai_Walls_Collapse(ObjTokeidai* this, GlobalContext* globalCtx) { + if (this->actor.shape.rot.x < 0x4000) { + this->actor.shape.rot.x += 0x28; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB3ED0.s") +void ObjTokeidai_Walls_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x84) != 0 && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 1) { + this->actionFunc = ObjTokeidai_Walls_Collapse; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4040.s") +void ObjTokeidai_TowerOpening_EndCutscene(ObjTokeidai* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, 0x84) != 0 && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 5) { + gSaveContext.save.weekEventReg[8] |= 0x40; + if (((globalCtx->sceneNum == SCENE_CLOCKTOWER) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0)) || + ((globalCtx->sceneNum == SCENE_00KEIKOKU) && (gSaveContext.sceneSetupIndex == 2) && + (globalCtx->csCtx.unk_12 == 0))) { + func_801A3F54(false); + gSaveContext.save.cutscene = 0; + gSaveContext.nextCutsceneIndex = 0; + gSaveContext.respawnFlag = 2; + globalCtx->sceneLoadFlag = 0x14; + globalCtx->nextEntranceIndex = gSaveContext.respawn[1].entranceIndex; + globalCtx->unk_1887F = 2; + if (gSaveContext.respawn[1].playerParams == 0xCFF) { + gSaveContext.nextTransition = 0x15; + } else { + gSaveContext.nextTransition = 2; + } + } + this->actionFunc = ObjTokeidai_DoNothing; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4080.s") +void ObjTokeidai_TowerOpening_FinishOpening(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 type; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4160.s") + if (this->clockFaceZTranslation > -320) { + // Recess the clock face before ending the cutscene, since the Termina + // Field version of the cutscene looks right at it. + this->clockFaceZTranslation -= 10; + } else { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + if ((type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN) || + (type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD)) { + ObjTokeidai_TowerOpening_EndCutscene(this, globalCtx); + } else { + this->actionFunc = ObjTokeidai_DoNothing; + if (this->actor.child != NULL) { + this->actor.child->home.rot.x = 0; + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/ObjTokeidai_Update.s") +void ObjTokeidai_TowerOpening_Wait(ObjTokeidai* this, GlobalContext* globalCtx) { + if (this->openingWaitTimer > 0) { + this->openingWaitTimer--; + } else { + this->actionFunc = ObjTokeidai_TowerOpening_FinishOpening; + this->openingWaitTimer = 0; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/ObjTokeidai_Draw.s") +void ObjTokeidai_TowerOpening_DropCounterweight(ObjTokeidai* this, GlobalContext* globalCtx) { + this->xRotation += this->counterweightRotationalVelocity; + if (this->xRotation < 0x4000) { + this->counterweightRotationalVelocity += this->counterweightRotationalAcceleration; + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4394.s") + this->counterweightRotationalAcceleration = 0x14; + this->xRotation = 0x4000; + switch (this->boundCount) { + case 0: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_0); + break; + case 1: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_1); + break; + case 2: + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_BOUND_2); + break; + } + this->boundCount++; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4664.s") + if (this->counterweightRotationalVelocity > 0x190) { + // This condition is met for the first bound, causing the counterweight + // to rebound upwards quickly. + this->counterweightRotationalVelocity = -0xC8; + } else if (this->counterweightRotationalVelocity > 0x32) { + // This condition is met for the second bound, causing the counterweight + // to rebound upwards slowly. + this->counterweightRotationalVelocity = -(this->counterweightRotationalVelocity >> 1); + } else { + // This condition is met for the third bound, causing the counterweight + // to stop moving. + this->actionFunc = ObjTokeidai_TowerOpening_Wait; + this->openingWaitTimer = 10; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Tokeidai/func_80AB4894.s") +void ObjTokeidai_TowerOpening_FinishRaise(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 type; + + if (this->settleTimer > 0) { + // Jiggle the parts of the tower up and down to give it the appearance + // of "settling" into place. + if (this->settleTimer & 1) { + this->yTranslation = this->settleAmount + 3400; + } else { + this->yTranslation = 3400 - this->settleAmount; + if (this->settleAmount > 0) { + this->settleAmount -= 4; + } + } + this->settleTimer--; + } else { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + if ((type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN) || + (type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_FALL); + } + this->yTranslation = 3400; + this->actionFunc = ObjTokeidai_TowerOpening_DropCounterweight; + this->counterweightRotationalVelocity = 0; + this->counterweightRotationalAcceleration = 0xA; + this->boundCount = 0; + } +} + +void ObjTokeidai_TowerOpening_RaiseTower(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 type; + + if (this->yTranslation < 3400) { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + this->yTranslation += 25; + if ((type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN) || + (type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD)) { + func_800B9010(&this->actor, NA_SE_EV_CLOCK_TOWER_UP - SFX_FLAG); + } + } else { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + if ((type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN) || + (type == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_CLOCK_TOWER_STOP); + } + this->yTranslation = 3400; + this->actionFunc = ObjTokeidai_TowerOpening_FinishRaise; + this->settleTimer = 10; + this->settleAmount = 20; + } +} + +void ObjTokeidai_TowerOpening_Start(ObjTokeidai* this, GlobalContext* globalCtx) { + if ((func_800EE29C(globalCtx, 0x84) && globalCtx->csCtx.npcActions[func_800EE200(globalCtx, 0x84)]->unk0 == 4) || + (gSaveContext.save.weekEventReg[8] & 0x40)) { + this->actionFunc = ObjTokeidai_TowerOpening_RaiseTower; + } +} + +/** + * Sets up the sequence where the Clock Tower "transforms" and opens up + * on the midnight of the Final Day. + */ +void ObjTokeidai_SetupTowerOpening(ObjTokeidai* this) { + this->actionFunc = ObjTokeidai_TowerOpening_Start; + this->clockFaceRotationalVelocity = 0; + this->clockFaceRotationTimer = 0; + this->yTranslation = 0; + this->xRotation = 0; + this->clockFaceZTranslation = 0; +} + +void ObjTokeidai_DoNothing(ObjTokeidai* this, GlobalContext* globalCtx) { +} + +void ObjTokeidai_StaircaseIntoTower_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (((CURRENT_DAY == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) || CURRENT_DAY >= 4) || + (gSaveContext.save.weekEventReg[8] & 0x40)) { + this->actor.draw = ObjTokeidai_Draw; + } else { + this->actor.draw = NULL; + } +} + +s32 ObjTokeidai_IsPostFirstCycleFinalHours(ObjTokeidai* this, GlobalContext* globalCtx) { + if (gSaveContext.save.inventory.items[SLOT_OCARINA] == ITEM_NONE) { + return false; + } + if (CURRENT_DAY == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) { + ObjTokeidai_SetupTowerOpening(this); + return true; + } + return false; +} + +void ObjTokeidai_RotateOnHourChange(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 currentHour = GET_CURRENT_HOUR(this); + + if (currentHour != this->clockHour) { + if (this->clockFaceRotationTimer > 12) { + // This actually performs the rotation to the next hour + // for the clock face. + this->clockFaceRotationalVelocity += 0xA; + this->clockFaceRotation += this->clockFaceRotationalVelocity; + } else { + // This makes the clock face wiggle in place for a bit + // before rotating to the next position. + if ((this->clockFaceRotationTimer & 3) == 0) { + this->clockFaceRotation += 0x3C; + } + if ((this->clockFaceRotationTimer & 3) == 1) { + this->clockFaceRotation -= 0x3C; + } + } + + this->clockFaceRotationTimer++; + if ((currentHour == 12 && this->clockFaceRotation < 0) || + (currentHour != 12 && this->clockFaceRotation > GET_CLOCK_FACE_ROTATION(currentHour))) { + this->clockFaceRotation = GET_CLOCK_FACE_ROTATION(currentHour); + this->clockHour = currentHour; + this->clockFaceRotationalVelocity = 0; + this->clockFaceRotationTimer = 0; + } + } + + // If the sun and moon disk doesn't have the target rotation (e.g., the time of day + // just changed), rotate it until it matches the target. + if (this->sunMoonDiskRotation != ObjTokeidai_GetTargetSunMoonDiskRotation()) { + if (this->clockHour == 6) { + this->sunMoonDiskRotationalVelocity += 0x222; + this->sunMoonDiskRotation += this->sunMoonDiskRotationalVelocity; + if (this->sunMoonDiskRotation > 0x10000) { + this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation(); + this->sunMoonDiskRotationalVelocity = 0; + } + } + if (this->clockHour == 18) { + this->sunMoonDiskRotationalVelocity += 0x222; + this->sunMoonDiskRotation += this->sunMoonDiskRotationalVelocity; + if (this->sunMoonDiskRotation > 0x8000) { + this->sunMoonDiskRotation = ObjTokeidai_GetTargetSunMoonDiskRotation(); + this->sunMoonDiskRotationalVelocity = 0; + } + } + } +} + +void ObjTokeidai_TowerClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (CURRENT_DAY == 3 && this->clockHour < 6 && gSaveContext.save.time < CLOCK_TIME(6, 0)) { + this->actor.draw = ObjTokeidai_Clock_Draw; + ObjTokeidai_SetupTowerOpening(this); + gSaveContext.save.weekEventReg[8] |= 0x40; + return; + } + + if (globalCtx->csCtx.state != 0) { + this->actor.home.rot.x = 1; + this->currentTime += 3; + this->actor.draw = ObjTokeidai_Clock_Draw; + } else { + if (!(globalCtx->actorCtx.unk5 & 2) && + OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD && + ActorCutscene_GetCurrentIndex() == -1) { + this->actor.draw = NULL; + } + this->currentTime = gSaveContext.save.time; + if (this->actor.home.rot.x != 0) { + ObjTokeidai_Clock_Init(this); + this->actor.home.rot.x = 0; + } + } + + if (CURRENT_DAY != 3 || gSaveContext.save.time >= CLOCK_TIME(6, 0)) { + ObjTokeidai_RotateOnMinuteChange(this, true); + } + ObjTokeidai_RotateOnHourChange(this, globalCtx); +} + +void ObjTokeidai_WallClock_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + this->currentTime = gSaveContext.save.time; + ObjTokeidai_RotateOnMinuteChange(this, true); + ObjTokeidai_RotateOnHourChange(this, globalCtx); +} + +void ObjTokeidai_TowerGear_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + if (ObjTokeidai_IsPostFirstCycleFinalHours(this, globalCtx)) { + this->actor.draw = ObjTokeidai_TowerGear_Draw; + } else { + if (globalCtx->csCtx.state != 0) { + this->actor.home.rot.x = 1; + this->currentTime += 3; + this->actor.draw = ObjTokeidai_TowerGear_Draw; + } else { + if ((globalCtx->actorCtx.unk5 & 2) == 0 && + OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD && + ActorCutscene_GetCurrentIndex() == -1) { + this->actor.draw = NULL; + } + this->currentTime = gSaveContext.save.time; + if (this->actor.home.rot.x != 0) { + ObjTokeidai_SetupClockOrGear(this); + this->actor.home.rot.x = 0; + } + } + ObjTokeidai_RotateOnMinuteChange(this, false); + } +} + +void ObjTokeidai_Counterweight_Idle(ObjTokeidai* this, GlobalContext* globalCtx) { + s32 type; + + if (ObjTokeidai_IsPostFirstCycleFinalHours(this, globalCtx)) { + this->spotlightIntensity = 0; + if (this->actor.child == NULL) { + type = OBJ_TOKEIDAI_TYPE(&this->actor); + if (type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN || + type == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) { + this->actor.child = + Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_HANABI, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 0); + } + } + if (this->actor.child != NULL) { + if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD) { + this->actor.child->home.rot.x = 0x384; + } else { + this->actor.child->home.rot.x = 0x12C; + } + } + } else { + this->actor.shape.rot.y -= 0x40; + if (gSaveContext.save.isNight) { + if (this->spotlightIntensity < 100) { + this->spotlightIntensity += 4; + } + } else if (this->spotlightIntensity > 0) { + this->spotlightIntensity -= 4; + } + } +} + +void ObjTokeidai_Update(Actor* thisx, GlobalContext* globalCtx) { + ObjTokeidai* this = THIS; + this->actionFunc(this, globalCtx); +} + +void ObjTokeidai_Draw(Actor* thisx, GlobalContext* globalCtx) { + ObjTokeidai* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + if (this->opaDList != NULL) { + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C28C(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, this->opaDList); + } + if (this->xluDList != NULL) { + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C2DC(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_XLU_DISP++, this->xluDList); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void ObjTokeidai_Clock_Draw(Actor* thisx, GlobalContext* globalCtx) { + ObjTokeidai* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_8012C28C(globalCtx->state.gfxCtx); + Matrix_InsertTranslation(0.0f, this->yTranslation, 0.0f, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, 0.0f, -1791.0f, MTXMODE_APPLY); + Matrix_InsertXRotation_s(-this->xRotation, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, 0.0f, 1791.0f, MTXMODE_APPLY); + Matrix_StatePush(); + Matrix_InsertZRotation_s(-this->outerRingOrGearRotation, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00CF28); + Matrix_StatePop(); + Matrix_InsertTranslation(0.0f, 0.0f, this->clockFaceZTranslation, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00BEE8); + Matrix_InsertZRotation_s(-this->clockFaceRotation * 2, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + if (OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_WALL_CLOCK || + OBJ_TOKEIDAI_TYPE(&this->actor) == OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK) { + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00F518); + } else { + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00E818); + } + Matrix_InsertTranslation(0.0f, -1112.0f, -19.6f, MTXMODE_APPLY); + Matrix_RotateY((s16)this->sunMoonDiskRotation, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00C368); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void ObjTokeidai_Counterweight_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + u32 gameplayFrames = globalCtx->gameplayFrames; + ObjTokeidai* this = THIS; + + Matrix_RotateY(-this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, this->yTranslation, 0.0f, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, -5480.0f, 80.0f, MTXMODE_APPLY); + Matrix_InsertXRotation_s(-this->xRotation, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, 5480.0f, -80.0f, MTXMODE_APPLY); + Matrix_RotateY(this->actor.shape.rot.y, MTXMODE_APPLY); + + OPEN_DISPS(globalCtx->state.gfxCtx); + + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, -gameplayFrames, 0, 0x20, 0x20)); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C28C(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, this->opaDList); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C2DC(globalCtx->state.gfxCtx); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 255, 255, 235, 180, (s32)(this->spotlightIntensity * 2.55f)); + gSPDisplayList(POLY_XLU_DISP++, this->xluDList); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void ObjTokeidai_TowerGear_Draw(Actor* thisx, GlobalContext* globalCtx) { + ObjTokeidai* this = THIS; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + Matrix_InsertTranslation(0.0f, this->yTranslation, 0.0f, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, 0.0f, -1791.0f, MTXMODE_APPLY); + Matrix_RotateY(-this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_InsertXRotation_s(-this->xRotation, MTXMODE_APPLY); + Matrix_RotateY(thisx->shape.rot.y, MTXMODE_APPLY); + Matrix_InsertTranslation(0.0f, 0.0f, 1791.0f, MTXMODE_APPLY); + Matrix_InsertZRotation_s(this->outerRingOrGearRotation, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C28C(globalCtx->state.gfxCtx); + gSPDisplayList(POLY_OPA_DISP++, object_obj_tokeidai_DL_00BA78); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.h b/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.h index f550606f0..c5cf8d70c 100644 --- a/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.h +++ b/src/overlays/actors/ovl_Obj_Tokeidai/z_obj_tokeidai.h @@ -3,14 +3,63 @@ #include "global.h" +#define OBJ_TOKEIDAI_TYPE(thisx) (((thisx)->params & 0xF000) >> 12) + +typedef enum { + /* 0 */ OBJ_TOKEIDAI_TYPE_TOWER_GEAR_CLOCK_TOWN, + /* 1 */ OBJ_TOKEIDAI_TYPE_UNUSED_WALL, + /* 2 */ OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_CLOCK_TOWN, + /* 3 */ OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_CLOCK_TOWN, + /* 4 */ OBJ_TOKEIDAI_TYPE_TOWER_GEAR_TERMINA_FIELD, + /* 5 */ OBJ_TOKEIDAI_TYPE_TOWER_CLOCK_TERMINA_FIELD, + /* 6 */ OBJ_TOKEIDAI_TYPE_COUNTERWEIGHT_TERMINA_FIELD, + /* 8 */ OBJ_TOKEIDAI_TYPE_TOWER_WALLS_TERMINA_FIELD = 8, + /* 9 */ OBJ_TOKEIDAI_TYPE_WALL_CLOCK, + /* 10 */ OBJ_TOKEIDAI_TYPE_SMALL_WALL_CLOCK, + /* 11 */ OBJ_TOKEIDAI_TYPE_STAIRCASE_INTO_TOWER, +} ObjTokeidaiType; + struct ObjTokeidai; typedef void (*ObjTokeidaiActionFunc)(struct ObjTokeidai*, GlobalContext*); typedef struct ObjTokeidai { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x30]; - /* 0x0174 */ ObjTokeidaiActionFunc actionFunc; + /* 0x000 */ Actor actor; + /* 0x144 */ Gfx* opaDList; + /* 0x148 */ Gfx* xluDList; + /* 0x14C */ s16 outerRingOrGearRotation; + /* 0x14E */ s16 outerRingOrGearRotationalVelocity; + /* 0x150 */ s16 outerRingOrGearRotationTimer; + /* 0x152 */ s16 clockFaceRotation; + /* 0x154 */ union { + s16 clockFaceRotationalVelocity; + s16 settleTimer; + s16 counterweightRotationalVelocity; + s16 openingWaitTimer; + s16 slidingClockFaceAngle; + }; + /* 0x156 */ union { + s16 clockFaceRotationTimer; + s16 settleAmount; + s16 counterweightRotationalAcceleration; + s16 aerialClockFaceSpeed; + }; + /* 0x158 */ s32 sunMoonDiskRotation; + /* 0x15C */ union { + s16 sunMoonDiskRotationalVelocity; + s16 fallingClockFaceRotationalVelocity; + }; + /* 0x15E */ s16 yTranslation; + /* 0x160 */ s16 xRotation; + /* 0x162 */ s16 clockFaceZTranslation; // amount the clock face recesses inwards once it transforms + /* 0x164 */ s16 boundCount; + /* 0x168 */ s32 clockMinute; // only 30 minutes in an hour + /* 0x16C */ union { + s32 clockHour; + s32 spotlightIntensity; + }; + /* 0x170 */ u16 currentTime; + /* 0x174 */ ObjTokeidaiActionFunc actionFunc; } ObjTokeidai; // size = 0x178 extern const ActorInit Obj_Tokeidai_InitVars; diff --git a/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.c b/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.c index 2b4feda09..c49059262 100644 --- a/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.c +++ b/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.c @@ -1,27 +1,57 @@ /* * File: z_eff_ss_stick.c * Overlay: ovl_Effect_Ss_Stick - * Description: + * Description: Breaking Deku Stick Fragment */ #include "z_eff_ss_stick.h" +#include "objects/gameplay_keep/gameplay_keep.h" #define PARAMS ((EffectSsStickInitParams*)initParamsx) -s32 EffectSsStick_Init(GlobalContext* globalCtx, u32 index, EffectSs* this, void* initParamsx); +u32 EffectSsStick_Init(GlobalContext* globalCtx, u32 index, EffectSs* this, void* initParamsx); void EffectSsStick_Update(GlobalContext* globalCtx, u32 index, EffectSs* this); void EffectSsStick_Draw(GlobalContext* globalCtx, u32 index, EffectSs* this); -#if 0 const EffectSsInit Effect_Ss_Stick_InitVars = { EFFECT_SS_STICK, EffectSsStick_Init, }; -#endif +u32 EffectSsStick_Init(GlobalContext* globalCtx, u32 index, EffectSs* this, void* initParamsx) { + EffectSsStickInitParams* params = PARAMS; + Vec3f pos; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Effect_Ss_Stick/EffectSsStick_Init.s") + this->regs[0] = Object_GetIndex(&globalCtx->objectCtx, GAMEPLAY_KEEP); + pos = params->pos; + this->pos = pos; + this->vec = pos; + this->regs[1] = params->yaw; + this->velocity.x = Math_SinS(params->yaw) * 6.0f; + this->velocity.z = Math_CosS(params->yaw) * 6.0f; + this->life = 20; + this->draw = EffectSsStick_Draw; + this->update = EffectSsStick_Update; + this->velocity.y = 26.0f; + this->accel.y = -4.0f; + return 1; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Effect_Ss_Stick/EffectSsStick_Draw.s") +void EffectSsStick_Draw(GlobalContext* globalCtx, u32 index, EffectSs* this) { + s32 pad; + GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Effect_Ss_Stick/EffectSsStick_Update.s") + OPEN_DISPS(gfxCtx); + Matrix_InsertTranslation(this->pos.x, this->pos.y, this->pos.z, MTXMODE_NEW); + Matrix_Scale(0.01f, 0.0025f, 0.01f, MTXMODE_APPLY); + Matrix_InsertRotation(0, this->regs[1], 0, MTXMODE_APPLY); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + func_8012C28C(gfxCtx); + gSPSegment(POLY_OPA_DISP++, 0x06, globalCtx->objectCtx.status[this->regs[0]].segment); + gSPSegment(POLY_OPA_DISP++, 0x0C, D_801C0850); + gSPDisplayList(POLY_OPA_DISP++, gameplay_keep_DL_0032B0); + CLOSE_DISPS(gfxCtx); +} + +void EffectSsStick_Update(GlobalContext* globalCtx, u32 index, EffectSs* this) { +} diff --git a/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.h b/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.h index ec43b41bf..d44a6a468 100644 --- a/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.h +++ b/src/overlays/effects/ovl_Effect_Ss_Stick/z_eff_ss_stick.h @@ -8,6 +8,4 @@ typedef struct { /* 0x0C */ s16 yaw; } EffectSsStickInitParams; // size = 0x10 -extern const EffectSsInit Effect_Ss_Stick_InitVars; - #endif diff --git a/tools/ZAPD/.gitrepo b/tools/ZAPD/.gitrepo index a942638a2..ccd6c7d64 100644 --- a/tools/ZAPD/.gitrepo +++ b/tools/ZAPD/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/zeldaret/ZAPD.git branch = master - commit = 50242eca96a9c36fd84f438bab24548e73b42303 - parent = 744955732b1fc9e8a835c62440aa97799cfe8940 + commit = fd5a7f434171a33b1b3eb2a3e112fdcee6d9262d + parent = 844c24e39c96b7a3f3a40035058bda6c91ed4bbf method = merge cmdver = 0.4.3 diff --git a/tools/ZAPD/Jenkinsfile b/tools/ZAPD/Jenkinsfile index 8db69a1e3..ec9b56ac5 100644 --- a/tools/ZAPD/Jenkinsfile +++ b/tools/ZAPD/Jenkinsfile @@ -22,13 +22,13 @@ pipeline { } } - // stage('Checkout mm') { - // steps{ - // dir('mm') { - // git url: 'https://github.com/zeldaret/mm.git' - // } - // } - // } + stage('Checkout mm') { + steps{ + dir('mm') { + git url: 'https://github.com/zeldaret/mm.git' + } + } + } } } @@ -51,20 +51,20 @@ pipeline { } } - // stage('Setup MM') { - // steps { - // dir('mm') { - // sh 'cp /usr/local/etc/roms/mm.us.rev1.z64 baserom.mm.us.rev1.z64' + stage('Setup MM') { + steps { + dir('mm') { + sh 'cp /usr/local/etc/roms/mm.us.rev1.z64 baserom.mm.us.rev1.z64' - // // Identical to `make setup` except for copying our newer ZAPD.out into mm - // sh 'make -C tools' - // sh 'cp ../ZAPD.out tools/ZAPD/' - // sh 'python3 tools/fixbaserom.py' - // sh 'python3 tools/extract_baserom.py' - // sh 'python3 extract_assets.py -t 4' - // } - // } - // } + // Identical to `make setup` except for copying our newer ZAPD.out into mm + sh 'make -C tools' + sh 'cp ../ZAPD.out tools/ZAPD/' + sh 'python3 tools/fixbaserom.py' + sh 'python3 tools/extract_baserom.py' + sh 'python3 extract_assets.py -t$(nproc)' + } + } + } } } @@ -78,14 +78,14 @@ pipeline { } } } - // stage('Build mm') { - // steps { - // dir('mm') { - // sh 'make -j disasm' - // sh 'make -j all' - // } - // } - // } + stage('Build mm') { + steps { + dir('mm') { + sh 'make -j disasm' + sh 'make -j all' + } + } + } } } } diff --git a/tools/ZAPD/README.md b/tools/ZAPD/README.md index 44d26b8b3..448aea033 100644 --- a/tools/ZAPD/README.md +++ b/tools/ZAPD/README.md @@ -119,6 +119,7 @@ ZAPD also accepts the following list of extra parameters: - `-tm MODE`: Test Mode (enables certain experimental features). To enable it, set `MODE` to `1`. - `-se` / `--set-exporter` : Sets which exporter to use. - `--gcc-compat` : Enables GCC compatibly mode. Slower. +- `-us` / `--unaccounted-static` : Mark unaccounted data as `static` - `-s` / `--static` : Mark every asset as `static`. - This behaviour can be overridden per asset using `Static=` in the respective XML node. - `-W...`: warning flags, see below diff --git a/tools/ZAPD/ZAPD/Declaration.h b/tools/ZAPD/ZAPD/Declaration.h index b7bb0d30d..4a743b50f 100644 --- a/tools/ZAPD/ZAPD/Declaration.h +++ b/tools/ZAPD/ZAPD/Declaration.h @@ -12,8 +12,7 @@ typedef uint32_t offset_t; enum class DeclarationAlignment { Align4, - Align8, - Align16 + Align8 }; enum class StaticConfig diff --git a/tools/ZAPD/ZAPD/Globals.cpp b/tools/ZAPD/ZAPD/Globals.cpp index 528a09d25..a10705e9a 100644 --- a/tools/ZAPD/ZAPD/Globals.cpp +++ b/tools/ZAPD/ZAPD/Globals.cpp @@ -152,8 +152,8 @@ bool Globals::GetSegmentedPtrName(segptr_t segAddress, ZFile* currentFile, } } - const auto& symbolFromMap = Globals::Instance->symbolMap.find(segAddress); - if (symbolFromMap != Globals::Instance->symbolMap.end()) + const auto& symbolFromMap = Globals::Instance->cfg.symbolMap.find(segAddress); + if (symbolFromMap != Globals::Instance->cfg.symbolMap.end()) { declName = "&" + symbolFromMap->second; return true; diff --git a/tools/ZAPD/ZAPD/Globals.h b/tools/ZAPD/ZAPD/Globals.h index 19e193f12..1ae753e20 100644 --- a/tools/ZAPD/ZAPD/Globals.h +++ b/tools/ZAPD/ZAPD/Globals.h @@ -58,11 +58,11 @@ public: bool verboseUnaccounted = false; bool gccCompat = false; bool forceStatic = false; + bool forceUnaccountedStatic = false; std::vector files; std::vector externalFiles; std::vector segments; - std::map symbolMap; std::string currentExporter; static std::map& GetExporterMap(); diff --git a/tools/ZAPD/ZAPD/Main.cpp b/tools/ZAPD/ZAPD/Main.cpp index fd2ed06dc..048338fb7 100644 --- a/tools/ZAPD/ZAPD/Main.cpp +++ b/tools/ZAPD/ZAPD/Main.cpp @@ -48,7 +48,7 @@ void ErrorHandler(int sig) const char* crashEasterEgg[] = { "\tYou've met with a terrible fate, haven't you?", "\tSEA BEARS FOAM. SLEEP BEARS DREAMS. \n\tBOTH END IN THE SAME WAY: CRASSSH!", - "ZAPD has fallen and cannot get up." + "\tZAPD has fallen and cannot get up.", }; srand(time(nullptr)); @@ -216,6 +216,10 @@ int main(int argc, char* argv[]) { Globals::Instance->forceStatic = true; } + else if (arg == "-us" || arg == "--unaccounted-static") + { + Globals::Instance->forceUnaccountedStatic = true; + } } // Parse File Mode diff --git a/tools/ZAPD/ZAPD/OtherStructs/SkinLimbStructs.cpp b/tools/ZAPD/ZAPD/OtherStructs/SkinLimbStructs.cpp index 9d16de438..087986199 100644 --- a/tools/ZAPD/ZAPD/OtherStructs/SkinLimbStructs.cpp +++ b/tools/ZAPD/ZAPD/OtherStructs/SkinLimbStructs.cpp @@ -263,7 +263,7 @@ void Struct_800A5E28::DeclareReferences(const std::string& prefix) ZResource::DeclareReferences(varPrefix); - if (unk_4 != 0 && GETSEGNUM(unk_4) == parent->segment) + if (unk_4 != SEGMENTED_NULL && GETSEGNUM(unk_4) == parent->segment) { const auto& res = unk_4_arr.at(0); std::string unk_4_Str = res.GetDefaultName(varPrefix); @@ -293,7 +293,7 @@ void Struct_800A5E28::DeclareReferences(const std::string& prefix) decl->text = entryStr; } - if (unk_8 != 0 && GETSEGNUM(unk_8) == parent->segment) + if (unk_8 != SEGMENTED_NULL && GETSEGNUM(unk_8) == parent->segment) { uint32_t unk_8_Offset = Seg2Filespace(unk_8, parent->baseAddress); @@ -306,6 +306,8 @@ void Struct_800A5E28::DeclareReferences(const std::string& prefix) std::string dListStr = StringHelper::Sprintf("%sSkinLimbDL_%06X", varPrefix.c_str(), unk_8_Offset); unk_8_dlist->SetName(dListStr); + unk_8_dlist->DeclareVar(varPrefix, ""); + unk_8_dlist->DeclareReferences(varPrefix); parent->AddResource(unk_8_dlist); } } diff --git a/tools/ZAPD/ZAPD/Overlays/ZOverlay.cpp b/tools/ZAPD/ZAPD/Overlays/ZOverlay.cpp index 510de19ab..113c4ef33 100644 --- a/tools/ZAPD/ZAPD/Overlays/ZOverlay.cpp +++ b/tools/ZAPD/ZAPD/Overlays/ZOverlay.cpp @@ -90,7 +90,8 @@ ZOverlay* ZOverlay::FromBuild(fs::path buildPath, fs::path cfgFolderPath) std::vector readers; for (size_t i = 1; i < cfgLines.size(); i++) { - std::string elfPath = (buildPath / (cfgLines[i].substr(0, cfgLines[i].size() - 2) + ".o")).string(); + std::string elfPath = + (buildPath / (cfgLines[i].substr(0, cfgLines[i].size() - 2) + ".o")).string(); elfio* reader = new elfio(); if (!reader->load(elfPath)) diff --git a/tools/ZAPD/ZAPD/ZAnimation.cpp b/tools/ZAPD/ZAPD/ZAnimation.cpp index adb0ae7c9..4d9266b09 100644 --- a/tools/ZAPD/ZAPD/ZAnimation.cpp +++ b/tools/ZAPD/ZAPD/ZAnimation.cpp @@ -104,7 +104,7 @@ void ZNormalAnimation::DeclareReferences(const std::string& prefix) valuesStr += "\n "; } - parent->AddDeclarationArray(rotationValuesOffset, DeclarationAlignment::Align16, + parent->AddDeclarationArray(rotationValuesOffset, DeclarationAlignment::Align4, rotationValues.size() * 2, "s16", StringHelper::Sprintf("%sFrameData", defaultPrefix.c_str()), rotationValues.size(), valuesStr); @@ -118,7 +118,7 @@ void ZNormalAnimation::DeclareReferences(const std::string& prefix) indicesStr += "\n"; } - parent->AddDeclarationArray(rotationIndicesOffset, DeclarationAlignment::Align16, + parent->AddDeclarationArray(rotationIndicesOffset, DeclarationAlignment::Align4, rotationIndices.size() * 6, "JointIndex", StringHelper::Sprintf("%sJointIndices", defaultPrefix.c_str()), rotationIndices.size(), indicesStr); @@ -385,7 +385,7 @@ size_t ZCurveAnimation::GetRawDataSize() const DeclarationAlignment ZCurveAnimation::GetDeclarationAlignment() const { - return DeclarationAlignment::Align16; + return DeclarationAlignment::Align4; } std::string ZCurveAnimation::GetSourceTypeName() const diff --git a/tools/ZAPD/ZAPD/ZDisplayList.cpp b/tools/ZAPD/ZAPD/ZDisplayList.cpp index bdb7374fe..5e9b1b205 100644 --- a/tools/ZAPD/ZAPD/ZDisplayList.cpp +++ b/tools/ZAPD/ZAPD/ZDisplayList.cpp @@ -27,8 +27,8 @@ ZDisplayList::ZDisplayList(ZFile* nParent) : ZResource(nParent) lastTexSizTest = F3DZEXTexSizes::G_IM_SIZ_16b; lastTexLoaded = false; lastTexIsPalette = false; - name = ""; dListType = Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX; + RegisterOptionalAttribute("Ucode"); } ZDisplayList::~ZDisplayList() @@ -44,13 +44,29 @@ void ZDisplayList::ExtractFromXML(tinyxml2::XMLElement* reader, uint32_t nRawDat { rawDataIndex = nRawDataIndex; ParseXML(reader); + // TODO add error handling here + bool ucodeSet = registeredAttributes.at("Ucode").wasSet; + std::string ucodeValue = registeredAttributes.at("Ucode").value; + if ((Globals::Instance->game == ZGame::OOT_SW97) || (ucodeValue == "f3dex")) + { + dListType = DListType::F3DEX; + } + else if (!ucodeSet || ucodeValue == "f3dex2") + { + dListType = DListType::F3DZEX; + } + else + { + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("Invalid ucode type in node: %s\n", reader->Name()), ""); + } // Don't parse raw data of external files if (parent->GetMode() != ZFileMode::ExternalFile) { - int32_t rawDataSize = ZDisplayList::GetDListLength( - parent->GetRawData(), rawDataIndex, - Globals::Instance->game == ZGame::OOT_SW97 ? DListType::F3DEX : DListType::F3DZEX); + int32_t rawDataSize = + ZDisplayList::GetDListLength(parent->GetRawData(), rawDataIndex, dListType); numInstructions = rawDataSize / 8; ParseRawData(); } @@ -693,7 +709,8 @@ void ZDisplayList::Opcode_G_DL(uint64_t data, const std::string& prefix, char* l else if (dListDecl != nullptr) sprintf(line, "gsSPBranchList(%s),", dListDecl->varName.c_str()); else - sprintf(line, "gsSPBranchList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), GETSEGOFFSET(data)); + sprintf(line, "gsSPBranchList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), + GETSEGOFFSET(data)); } else { @@ -702,7 +719,8 @@ void ZDisplayList::Opcode_G_DL(uint64_t data, const std::string& prefix, char* l else if (dListDecl != nullptr) sprintf(line, "gsSPDisplayList(%s),", dListDecl->varName.c_str()); else - sprintf(line, "gsSPDisplayList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), GETSEGOFFSET(data)); + sprintf(line, "gsSPDisplayList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), + GETSEGOFFSET(data)); } // if (segNum == 8 || segNum == 9 || segNum == 10 || segNum == 11 || segNum == 12 || segNum == @@ -832,7 +850,7 @@ void ZDisplayList::Opcode_G_VTX(uint64_t data, char* line) { segptr_t segmented = data & 0xFFFFFFFF; references.push_back(segmented); - parent->AddDeclaration(segmented, DeclarationAlignment::Align16, 16, "Vtx", + parent->AddDeclaration(segmented, DeclarationAlignment::Align8, 16, "Vtx", StringHelper::Sprintf("0x%08X", segmented), ""); return; } @@ -1748,7 +1766,7 @@ void ZDisplayList::DeclareReferences(const std::string& prefix) if (vertices.size() > 0) { std::vector>> verticesSorted(vertices.begin(), - vertices.end()); + vertices.end()); for (size_t i = 0; i < verticesSorted.size() - 1; i++) { @@ -1796,7 +1814,7 @@ void ZDisplayList::DeclareReferences(const std::string& prefix) if (vertices.size() > 0) { std::vector>> verticesSorted(vertices.begin(), - vertices.end()); + vertices.end()); for (size_t i = 0; i < verticesSorted.size() - 1; i++) { diff --git a/tools/ZAPD/ZAPD/ZFile.cpp b/tools/ZAPD/ZAPD/ZFile.cpp index 77387fc72..22a6a4505 100644 --- a/tools/ZAPD/ZAPD/ZFile.cpp +++ b/tools/ZAPD/ZAPD/ZFile.cpp @@ -8,6 +8,7 @@ #include "Globals.h" #include "OutputFormatter.h" #include "Utils/BinaryWriter.h" +#include "Utils/BitConverter.h" #include "Utils/Directory.h" #include "Utils/File.h" #include "Utils/MemoryStream.h" @@ -192,7 +193,7 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) rawData = File::ReadAllBytes((basePath / name).string()); if (reader->Attribute("RangeEnd") == nullptr) - rangeEnd = rawData.size(); + rangeEnd = rawData.size(); } std::unordered_set nameSet; @@ -378,7 +379,7 @@ void ZFile::ExtractResources() ZResourceExporter* exporter = Globals::Instance->GetExporter(res->GetResourceType()); if (exporter != nullptr) { - //exporter->Save(res, Globals::Instance->outputPath.string(), &writerFile); + // exporter->Save(res, Globals::Instance->outputPath.string(), &writerFile); exporter->Save(res, Globals::Instance->outputPath.string(), &writerRes); } @@ -391,7 +392,7 @@ void ZFile::ExtractResources() File::WriteAllBytes(StringHelper::Sprintf("%s%s.bin", Globals::Instance->outputPath.string().c_str(), GetName().c_str()), - memStreamFile->ToVector()); + memStreamFile->ToVector()); } writerFile.Close(); @@ -949,9 +950,6 @@ std::string ZFile::ProcessDeclarations() defines += ProcessTextureIntersections(name); - // Account for padding/alignment - uint32_t lastAddr = 0; - // printf("RANGE START: 0x%06X - RANGE END: 0x%06X\n", rangeStart, rangeEnd); // Optimization: See if there are any arrays side by side that can be merged... @@ -1002,43 +1000,6 @@ std::string ZFile::ProcessDeclarations() { while (item.second->size % 4 != 0) item.second->size++; - - if (lastAddr != 0) - { - if (item.second->alignment == DeclarationAlignment::Align16) - { - int32_t curPtr = lastAddr + declarations[lastAddr]->size; - - while (curPtr % 4 != 0) - { - declarations[lastAddr]->size++; - curPtr++; - } - } - else if (item.second->alignment == DeclarationAlignment::Align8) - { - size_t curPtr = lastAddr + declarations[lastAddr]->size; - - while (curPtr % 4 != 0) - { - declarations[lastAddr]->size++; - curPtr++; - } - - while (curPtr % 8 != 0) - { - char buffer[2048]; - - sprintf(buffer, "u32 %s_align%02zX = 0;\n", name.c_str(), curPtr); - item.second->preText = buffer + item.second->preText; - - declarations[lastAddr]->size += 4; - curPtr += 4; - } - } - } - - lastAddr = item.first; } HandleUnaccountedData(); @@ -1199,14 +1160,15 @@ void ZFile::HandleUnaccountedData() { uint32_t lastAddr = 0; uint32_t lastSize = 0; - std::vector declsAddresses; + std::vector declsAddresses; + for (const auto& item : declarations) { declsAddresses.push_back(item.first); } bool breakLoop = false; - for (uint32_t currentAddress : declsAddresses) + for (offset_t currentAddress : declsAddresses) { if (currentAddress >= rangeEnd) { @@ -1235,7 +1197,7 @@ void ZFile::HandleUnaccountedData() } } -bool ZFile::HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, uint32_t& lastSize) +bool ZFile::HandleUnaccountedAddress(offset_t currentAddress, offset_t lastAddr, uint32_t& lastSize) { if (currentAddress != lastAddr && declarations.find(lastAddr) != declarations.end()) { @@ -1275,6 +1237,29 @@ bool ZFile::HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, xmlFilePath.c_str(), currentAddress, name.c_str(), rawData.size())); } + // Handle Align8 + if (currentAddress % 8 == 0 && diff % 8 != 0) + { + Declaration* currentDecl = GetDeclaration(currentAddress); + + if (currentDecl != nullptr) + { + if (currentDecl->alignment == DeclarationAlignment::Align8) + { + // Check removed bytes are zeroes + if (BitConverter::ToUInt32BE(rawData, unaccountedAddress + diff - 4) == 0) + { + diff -= 4; + } + } + + if (diff == 0) + { + return false; + } + } + } + for (int i = 0; i < diff; i++) { uint8_t val = rawData.at(unaccountedAddress + i); @@ -1320,7 +1305,10 @@ bool ZFile::HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, StringHelper::Sprintf("%s_%s_%06X", name.c_str(), unaccountedPrefix.c_str(), unaccountedAddress), diff, src); + decl->isUnaccounted = true; + if (Globals::Instance->forceUnaccountedStatic) + decl->staticConf = StaticConfig::On; if (nonZeroUnaccounted) { diff --git a/tools/ZAPD/ZAPD/ZFile.h b/tools/ZAPD/ZAPD/ZFile.h index 7918d5f59..ac4062d5b 100644 --- a/tools/ZAPD/ZAPD/ZFile.h +++ b/tools/ZAPD/ZAPD/ZFile.h @@ -133,5 +133,5 @@ protected: std::string ProcessTextureIntersections(const std::string& prefix); void HandleUnaccountedData(); - bool HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, uint32_t& lastSize); + bool HandleUnaccountedAddress(offset_t currentAddress, offset_t lastAddr, uint32_t& lastSize); }; diff --git a/tools/ZAPD/ZAPD/ZLimb.cpp b/tools/ZAPD/ZAPD/ZLimb.cpp index a47615d6c..330fbaf7c 100644 --- a/tools/ZAPD/ZAPD/ZLimb.cpp +++ b/tools/ZAPD/ZAPD/ZLimb.cpp @@ -228,8 +228,8 @@ std::string ZLimb::GetBodySourceCode() const { std::string childName; std::string siblingName; - Globals::Instance->GetSegmentedPtrName(childPtr, parent, "Gfx", childName); - Globals::Instance->GetSegmentedPtrName(siblingPtr, parent, "Gfx", siblingName); + Globals::Instance->GetSegmentedPtrName(childPtr, parent, "LegacyLimb", childName); + Globals::Instance->GetSegmentedPtrName(siblingPtr, parent, "LegacyLimb", siblingName); entryStr += StringHelper::Sprintf("%s,\n", dListStr.c_str()); entryStr += diff --git a/tools/ZAPD/ZAPD/ZRoom/Commands/SetMesh.cpp b/tools/ZAPD/ZAPD/ZRoom/Commands/SetMesh.cpp index 69668c49c..ba0bbe2c2 100644 --- a/tools/ZAPD/ZAPD/ZRoom/Commands/SetMesh.cpp +++ b/tools/ZAPD/ZAPD/ZRoom/Commands/SetMesh.cpp @@ -152,7 +152,6 @@ void PolygonDlist::GetSourceOutputCode(const std::string& prefix) DeclareVar(prefix, bodyStr); else decl->text = bodyStr; - } std::string PolygonDlist::GetSourceTypeName() const diff --git a/tools/ZAPD/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp b/tools/ZAPD/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp index 0c24a2f32..696a3de01 100644 --- a/tools/ZAPD/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp +++ b/tools/ZAPD/ZAPD/ZRoom/Commands/SetSpecialObjects.cpp @@ -1,6 +1,8 @@ #include "SetSpecialObjects.h" + #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "ZRoom/ZNames.h" SetSpecialObjects::SetSpecialObjects(ZFile* nParent) : ZRoomCommand(nParent) { @@ -15,8 +17,10 @@ void SetSpecialObjects::ParseRawData() std::string SetSpecialObjects::GetBodySourceCode() const { - return StringHelper::Sprintf("SCENE_CMD_SPECIAL_FILES(0x%02X, 0x%04X)", elfMessage, - globalObject); + std::string objectName = ZNames::GetObjectName(globalObject); + + return StringHelper::Sprintf("SCENE_CMD_SPECIAL_FILES(0x%02X, %s)", elfMessage, + objectName.c_str()); } std::string SetSpecialObjects::GetCommandCName() const diff --git a/tools/ZAPD/ZAPD/ZRoom/ZRoom.cpp b/tools/ZAPD/ZAPD/ZRoom/ZRoom.cpp index d47a2e75c..5831eaa56 100644 --- a/tools/ZAPD/ZAPD/ZRoom/ZRoom.cpp +++ b/tools/ZAPD/ZAPD/ZRoom/ZRoom.cpp @@ -261,7 +261,8 @@ void ZRoom::ParseRawData() if (Globals::Instance->profile) { auto end = std::chrono::steady_clock::now(); - int64_t diff = std::chrono::duration_cast(end - start).count(); + int64_t diff = + std::chrono::duration_cast(end - start).count(); if (diff > 50) printf("OP: %s, TIME: %" PRIi64 "ms\n", cmd->GetCommandCName().c_str(), diff); } diff --git a/tools/ZAPD/ZAPD/ZSkeleton.cpp b/tools/ZAPD/ZAPD/ZSkeleton.cpp index 1a2f93ff7..4467c9632 100644 --- a/tools/ZAPD/ZAPD/ZSkeleton.cpp +++ b/tools/ZAPD/ZAPD/ZSkeleton.cpp @@ -139,7 +139,7 @@ ZResourceType ZSkeleton::GetResourceType() const DeclarationAlignment ZSkeleton::GetDeclarationAlignment() const { - return DeclarationAlignment::Align16; + return DeclarationAlignment::Align4; } uint8_t ZSkeleton::GetLimbCount() diff --git a/tools/ZAPD/ZAPD/ZVtx.cpp b/tools/ZAPD/ZAPD/ZVtx.cpp index d5214e840..e4b3d9796 100644 --- a/tools/ZAPD/ZAPD/ZVtx.cpp +++ b/tools/ZAPD/ZAPD/ZVtx.cpp @@ -82,5 +82,5 @@ std::string ZVtx::GetExternalExtension() const DeclarationAlignment ZVtx::GetDeclarationAlignment() const { - return DeclarationAlignment::Align16; + return DeclarationAlignment::Align8; } diff --git a/tools/ZAPD/ZAPDUtils/Utils/StringHelper.h b/tools/ZAPD/ZAPDUtils/Utils/StringHelper.h index 0b0d67642..6c9e54119 100644 --- a/tools/ZAPD/ZAPDUtils/Utils/StringHelper.h +++ b/tools/ZAPD/ZAPDUtils/Utils/StringHelper.h @@ -109,6 +109,6 @@ public: static bool IEquals(const std::string& a, const std::string& b) { return std::equal(a.begin(), a.end(), b.begin(), b.end(), - [](char a, char b) { return tolower(a) == tolower(b); }); + [](char a, char b) { return tolower(a) == tolower(b); }); } }; diff --git a/tools/actorfixer.py b/tools/actorfixer.py index 89d7364ea..77fe5d38a 100755 --- a/tools/actorfixer.py +++ b/tools/actorfixer.py @@ -304,7 +304,7 @@ animdict = { "func_800A81F0": "EffectBlure_AddVertex", "func_800A8514": "EffectBlure_AddSpace", "Effect_GetParams": "Effect_GetByIndex", - "D_0407D590": "gGameplayKeepDrawFlameDL" + "D_0407D590": "gGameplayKeepDrawFlameDL", "skelanime.unk03": "skelanime.taper", diff --git a/tools/disasm/disasm.py b/tools/disasm/disasm.py index 5f8aae37d..42473379e 100755 --- a/tools/disasm/disasm.py +++ b/tools/disasm/disasm.py @@ -3,7 +3,7 @@ import argparse, ast, math, os, re, struct import bisect from mips_isa import * -from multiprocessing import Pool +from multiprocessing import * parser = argparse.ArgumentParser() parser.add_argument('-j', dest='jobs', type=int, default=1, help='number of processes to run at once') @@ -1170,7 +1170,7 @@ for segment in files_spec: # Construct variable_addrs, now that variable_addrs is fully constructed variable_addrs = sorted(variables_ast.keys()) -pool = Pool(jobs) +pool = get_context("fork").Pool(jobs) # Find symbols for each segment for segment in files_spec: if segment[2] == 'makerom': @@ -1385,7 +1385,7 @@ print("Disassembling Segments") disassemble_makerom(next(segment for segment in files_spec if segment[2] == 'makerom')) # Textual disassembly for each segment -with Pool(jobs) as p: +with get_context("fork").Pool(jobs) as p: p.map(disassemble_segment, (segment for segment in files_spec if segment[2] != 'makerom')) print("Splitting text and migrating rodata") diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 084fb5842..d35cda7e7 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -10907,37 +10907,37 @@ 0x80A6B0D8:("func_80A6B0D8",), 0x80A6B3F8:("EnMushi2_Update",), 0x80A6B8D0:("EnMushi2_Draw",), - 0x80A6BF90:("func_80A6BF90",), - 0x80A6C1DC:("func_80A6C1DC",), + 0x80A6BF90:("EnFall_Moon_AdjustScaleAndPosition",), + 0x80A6C1DC:("EnFall_RisingDebris_ResetParticles",), 0x80A6C22C:("EnFall_Init",), 0x80A6C39C:("EnFall_Destroy",), - 0x80A6C3AC:("func_80A6C3AC",), - 0x80A6C3FC:("func_80A6C3FC",), - 0x80A6C7C0:("func_80A6C7C0",), - 0x80A6C9A8:("func_80A6C9A8",), - 0x80A6CA9C:("func_80A6CA9C",), - 0x80A6CB74:("func_80A6CB74",), - 0x80A6CD38:("func_80A6CD38",), - 0x80A6CD74:("func_80A6CD74",), - 0x80A6CECC:("func_80A6CECC",), - 0x80A6CF60:("func_80A6CF60",), - 0x80A6CF70:("func_80A6CF70",), + 0x80A6C3AC:("EnFall_MoonsTear_GetTerminaFieldMoon",), + 0x80A6C3FC:("EnFall_Setup",), + 0x80A6C7C0:("EnFall_CrashingMoon_HandleGiantsCutscene",), + 0x80A6C9A8:("EnFall_CrashingMoon_PerformCutsceneActions",), + 0x80A6CA9C:("EnFall_StoppedOpenMouthMoon_PerformCutsceneActions",), + 0x80A6CB74:("EnFall_StoppedClosedMouthMoon_PerformCutsceneActions",), + 0x80A6CD38:("EnFall_ClockTowerOrTitleScreenMoon_PerformCutsceneActions",), + 0x80A6CD74:("EnFall_Moon_PerformDefaultActions",), + 0x80A6CECC:("EnFall_MoonsTear_Initialize",), + 0x80A6CF60:("EnFall_DoNothing",), + 0x80A6CF70:("EnFall_MoonsTear_Fall",), 0x80A6D0DC:("EnFall_Update",), - 0x80A6D100:("func_80A6D100",), - 0x80A6D220:("func_80A6D220",), - 0x80A6D444:("func_80A6D444",), - 0x80A6D504:("func_80A6D504",), - 0x80A6D698:("func_80A6D698",), - 0x80A6D75C:("func_80A6D75C",), - 0x80A6D88C:("func_80A6D88C",), - 0x80A6D98C:("func_80A6D98C",), - 0x80A6DA7C:("func_80A6DA7C",), - 0x80A6DC20:("func_80A6DC20",), - 0x80A6DC40:("func_80A6DC40",), - 0x80A6DD3C:("func_80A6DD3C",), - 0x80A6E07C:("func_80A6E07C",), - 0x80A6E214:("func_80A6E214",), - 0x80A6E37C:("func_80A6E37C",), + 0x80A6D100:("EnFall_FireBall_SetPerVertexAlpha",), + 0x80A6D220:("EnFall_FireBall_Update",), + 0x80A6D444:("EnFall_RisingDebris_UpdateParticles",), + 0x80A6D504:("EnFall_RisingDebris_InitializeParticles",), + 0x80A6D698:("EnFall_RisingDebris_Update",), + 0x80A6D75C:("EnFall_FireRing_Update",), + 0x80A6D88C:("EnFall_Moon_Draw",), + 0x80A6D98C:("EnFall_OpenMouthMoon_Draw",), + 0x80A6DA7C:("EnFall_LodMoon_Draw",), + 0x80A6DC20:("EnFall_LodMoon_DrawWithoutLerp",), + 0x80A6DC40:("EnFall_LodMoon_DrawWithLerp",), + 0x80A6DD3C:("EnFall_FireBall_Draw",), + 0x80A6E07C:("EnFall_RisingDebris_Draw",), + 0x80A6E214:("EnFall_FireRing_Draw",), + 0x80A6E37C:("EnFall_MoonsTear_Draw",), 0x80A6F0A0:("EnMm3_Init",), 0x80A6F1EC:("EnMm3_Destroy",), 0x80A6F22C:("func_80A6F22C",), @@ -11667,45 +11667,45 @@ 0x80AB2544:("DmChar09_Update",), 0x80AB25D8:("func_80AB25D8",), 0x80AB261C:("DmChar09_Draw",), - 0x80AB2790:("func_80AB2790",), - 0x80AB27B4:("func_80AB27B4",), - 0x80AB2834:("func_80AB2834",), - 0x80AB28C8:("func_80AB28C8",), - 0x80AB29F8:("func_80AB29F8",), - 0x80AB2BBC:("func_80AB2BBC",), + 0x80AB2790:("ObjTokeidai_GetTargetSunMoonDiskRotation",), + 0x80AB27B4:("ObjTokeidai_SetupClockOrGear",), + 0x80AB2834:("ObjTokeidai_Clock_Init",), + 0x80AB28C8:("ObjTokeidai_TowerGear_Init",), + 0x80AB29F8:("ObjTokeidai_TowerClock_Init",), + 0x80AB2BBC:("ObjTokeidai_Counterweight_Init",), 0x80AB2DEC:("ObjTokeidai_Init",), 0x80AB3000:("ObjTokeidai_Destroy",), - 0x80AB3010:("func_80AB3010",), - 0x80AB319C:("func_80AB319C",), - 0x80AB3240:("func_80AB3240",), - 0x80AB32F0:("func_80AB32F0",), - 0x80AB3370:("func_80AB3370",), - 0x80AB34CC:("func_80AB34CC",), - 0x80AB3544:("func_80AB3544",), - 0x80AB3598:("func_80AB3598",), - 0x80AB363C:("func_80AB363C",), - 0x80AB365C:("func_80AB365C",), - 0x80AB36C4:("func_80AB36C4",), - 0x80AB3808:("func_80AB3808",), - 0x80AB3880:("func_80AB3880",), - 0x80AB38B0:("func_80AB38B0",), - 0x80AB39BC:("func_80AB39BC",), - 0x80AB3A7C:("func_80AB3A7C",), - 0x80AB3B34:("func_80AB3B34",), - 0x80AB3BB0:("func_80AB3BB0",), - 0x80AB3BD8:("func_80AB3BD8",), - 0x80AB3BE8:("func_80AB3BE8",), - 0x80AB3C50:("func_80AB3C50",), - 0x80AB3CCC:("func_80AB3CCC",), - 0x80AB3ED0:("func_80AB3ED0",), - 0x80AB4040:("func_80AB4040",), - 0x80AB4080:("func_80AB4080",), - 0x80AB4160:("func_80AB4160",), + 0x80AB3010:("ObjTokeidai_RotateOnMinuteChange",), + 0x80AB319C:("ObjTokeidai_TowerGear_Collapse",), + 0x80AB3240:("ObjTokeidai_TowerGear_OpenedIdle",), + 0x80AB32F0:("ObjTokeidai_TowerClock_Fall",), + 0x80AB3370:("ObjTokeidai_TowerClock_SlideOff",), + 0x80AB34CC:("ObjTokeidai_TowerClock_OpenedIdle",), + 0x80AB3544:("ObjTokeidai_Counterweight_Collapse",), + 0x80AB3598:("ObjTokeidai_Counterweight_OpenedIdle",), + 0x80AB363C:("ObjTokeidai_Walls_Collapse",), + 0x80AB365C:("ObjTokeidai_Walls_Idle",), + 0x80AB36C4:("ObjTokeidai_TowerTransformation_EndCutscene",), + 0x80AB3808:("ObjTokeidai_TowerOpening_FinishOpening",), + 0x80AB3880:("ObjTokeidai_TowerOpening_Wait",), + 0x80AB38B0:("ObjTokeidai_TowerOpening_DropCounterweight",), + 0x80AB39BC:("ObjTokeidai_TowerOpening_FinishRaise",), + 0x80AB3A7C:("ObjTokeidai_TowerOpening_RaiseTower",), + 0x80AB3B34:("ObjTokeidai_TowerOpening_Start",), + 0x80AB3BB0:("ObjTokeidai_SetupTowerOpening",), + 0x80AB3BD8:("ObjTokeidai_DoNothing",), + 0x80AB3BE8:("ObjTokeidai_StaircaseIntoTower_Idle",), + 0x80AB3C50:("ObjTokeidai_IsPostFirstCycleFinalHours",), + 0x80AB3CCC:("ObjTokeidai_RotateOnHourChange",), + 0x80AB3ED0:("ObjTokeidai_TowerClock_Idle",), + 0x80AB4040:("ObjTokeidai_WallClock_Idle",), + 0x80AB4080:("ObjTokeidai_TowerGear_Idle",), + 0x80AB4160:("ObjTokeidai_Counterweight_Idle",), 0x80AB4278:("ObjTokeidai_Update",), 0x80AB429C:("ObjTokeidai_Draw",), - 0x80AB4394:("func_80AB4394",), - 0x80AB4664:("func_80AB4664",), - 0x80AB4894:("func_80AB4894",), + 0x80AB4394:("ObjTokeidai_Clock_Draw",), + 0x80AB4664:("ObjTokeidai_Counterweight_Draw",), + 0x80AB4894:("ObjTokeidai_TowerGear_Draw",), 0x80AB4D10:("func_80AB4D10",), 0x80AB4E34:("func_80AB4E34",), 0x80AB4E58:("func_80AB4E58",), @@ -12817,53 +12817,53 @@ 0x80AFE650:("func_80AFE650",), 0x80AFE8A0:("EnTalkGibud_Init",), 0x80AFEB0C:("EnTalkGibud_Destroy",), - 0x80AFEB38:("func_80AFEB38",), - 0x80AFEB7C:("func_80AFEB7C",), - 0x80AFEC08:("func_80AFEC08",), - 0x80AFEC4C:("func_80AFEC4C",), - 0x80AFED08:("func_80AFED08",), - 0x80AFED7C:("func_80AFED7C",), - 0x80AFEFD4:("func_80AFEFD4",), - 0x80AFF030:("func_80AFF030",), - 0x80AFF22C:("func_80AFF22C",), - 0x80AFF288:("func_80AFF288",), - 0x80AFF330:("func_80AFF330",), - 0x80AFF378:("func_80AFF378",), - 0x80AFF45C:("func_80AFF45C",), - 0x80AFF4AC:("func_80AFF4AC",), - 0x80AFF618:("func_80AFF618",), - 0x80AFF6A0:("func_80AFF6A0",), - 0x80AFF700:("func_80AFF700",), - 0x80AFF76C:("func_80AFF76C",), - 0x80AFF880:("func_80AFF880",), - 0x80AFF8E4:("func_80AFF8E4",), - 0x80AFF9CC:("func_80AFF9CC",), - 0x80AFFA68:("func_80AFFA68",), - 0x80AFFAB0:("func_80AFFAB0",), - 0x80AFFC10:("func_80AFFC10",), - 0x80AFFC9C:("func_80AFFC9C",), - 0x80AFFD3C:("func_80AFFD3C",), - 0x80AFFE3C:("func_80AFFE3C",), - 0x80AFFE94:("func_80AFFE94",), - 0x80AFFFA4:("func_80AFFFA4",), - 0x80AFFFBC:("func_80AFFFBC",), - 0x80B000FC:("func_80B000FC",), - 0x80B00158:("func_80B00158",), - 0x80B00384:("func_80B00384",), - 0x80B0040C:("func_80B0040C",), - 0x80B00484:("func_80B00484",), - 0x80B004D0:("func_80B004D0",), - 0x80B005EC:("func_80B005EC",), - 0x80B00760:("func_80B00760",), - 0x80B008BC:("func_80B008BC",), - 0x80B008FC:("func_80B008FC",), - 0x80B0094C:("func_80B0094C",), - 0x80B00B8C:("func_80B00B8C",), - 0x80B00C94:("func_80B00C94",), - 0x80B00D9C:("func_80B00D9C",), + 0x80AFEB38:("EnTalkGibud_SetupIdle",), + 0x80AFEB7C:("EnTalkGibud_Idle",), + 0x80AFEC08:("EnTalkGibud_SetupAttemptPlayerStun",), + 0x80AFEC4C:("EnTalkGibud_AttemptStun",), + 0x80AFED08:("EnTalkGibud_SetupWalkToPlayer",), + 0x80AFED7C:("EnTalkGibud_WalkToPlayer",), + 0x80AFEFD4:("EnTalkGibud_SetupGrab",), + 0x80AFF030:("EnTalkGibud_Grab",), + 0x80AFF22C:("EnTalkGibud_SetupGrabFail",), + 0x80AFF288:("EnTalkGibud_GrabFail",), + 0x80AFF330:("EnTalkGibud_SetupTurnAwayAndShakeHead",), + 0x80AFF378:("EnTalkGibud_TurnAwayAndShakeHead",), + 0x80AFF45C:("EnTalkGibud_SetupWalkToHome",), + 0x80AFF4AC:("EnTalkGibud_WalkToHome",), + 0x80AFF618:("EnTalkGibud_SetupStunned",), + 0x80AFF6A0:("EnTalkGibud_Stunned",), + 0x80AFF700:("EnTalkGibud_SetupDamage",), + 0x80AFF76C:("EnTalkGibud_Damage",), + 0x80AFF880:("EnTalkGibud_SetupDead",), + 0x80AFF8E4:("EnTalkGibud_Dead",), + 0x80AFF9CC:("EnTalkGibud_SetupRevive",), + 0x80AFFA68:("EnTalkGibud_Revive",), + 0x80AFFAB0:("EnTalkGibud_GetTextIdForRequestedItem",), + 0x80AFFC10:("EnTalkGibud_GetNextTextBoxId",), + 0x80AFFC9C:("EnTalkGibud_PresentedItemMatchesRequest",), + 0x80AFFD3C:("EnTalkGibud_CheckPresentedItem",), + 0x80AFFE3C:("EnTalkGibud_SetupPassiveIdle",), + 0x80AFFE94:("EnTalkGibud_PassiveIdle",), + 0x80AFFFA4:("EnTalkGibud_SetupTalk",), + 0x80AFFFBC:("EnTalkGibud_Talk",), + 0x80B000FC:("EnTalkGibud_SetupDisappear",), + 0x80B00158:("EnTalkGibud_Disappear",), + 0x80B00384:("EnTalkGibud_FacePlayerWhenTalking",), + 0x80B0040C:("EnTalkGibud_PlayerInRangeWithCorrectState",), + 0x80B00484:("EnTalkGibud_PlayerOutOfRange",), + 0x80B004D0:("EnTalkGibud_CheckForGibdoMask",), + 0x80B005EC:("EnTalkGibud_TurnTowardsPlayer",), + 0x80B00760:("EnTalkGibud_MoveToIdealGrabPositionAndRotation",), + 0x80B008BC:("EnTalkGibud_PlayAnimation",), + 0x80B008FC:("EnTalkGibud_MoveWithGravity",), + 0x80B0094C:("EnTalkGibud_CheckDamageEffect",), + 0x80B00B8C:("EnTalkGibud_CheckCollision",), + 0x80B00C94:("EnTalkGibud_MoveGrabbedPlayerAwayFromWall",), + 0x80B00D9C:("EnTalkGibud_UpdateEffect",), 0x80B00E48:("EnTalkGibud_Update",), - 0x80B00F08:("func_80B00F08",), - 0x80B00F64:("func_80B00F64",), + 0x80B00F08:("EnTalkGibud_OverrideLimbDraw",), + 0x80B00F64:("EnTalkGibud_PostLimbDraw",), 0x80B01040:("EnTalkGibud_Draw",), 0x80B01990:("EnGiant_ChangeAnimation",), 0x80B01A74:("EnGiant_IsImprisoned",), @@ -15324,9 +15324,9 @@ 0x80BB3650:("EnGeg_Destroy",), 0x80BB36A0:("EnGeg_Update",), 0x80BB3728:("func_80BB3728",), - 0x80BB3860:("func_80BB3860",), - 0x80BB387C:("func_80BB387C",), - 0x80BB39F8:("func_80BB39F8",), + 0x80BB3860:("EnGeg_OverrideLimbDraw",), + 0x80BB387C:("EnGeg_PostLimbDraw",), + 0x80BB39F8:("EnGeg_UnkDraw",), 0x80BB3BE0:("func_80BB3BE0",), 0x80BB3CB4:("func_80BB3CB4",), 0x80BB3E0C:("EnGeg_Draw",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index f74a26f36..0f0ab7531 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -12283,10 +12283,7 @@ 0x80A6BB00:("D_80A6BB00","f32","",0x4), 0x80A6E490:("En_Fall_InitVars","UNK_TYPE1","",0x1), 0x80A6E4B0:("D_80A6E4B0","UNK_TYPE4","",0x4), - 0x80A6E4B4:("D_80A6E4B4","UNK_TYPE1","",0x1), - 0x80A6E4B5:("D_80A6E4B5","UNK_TYPE1","",0x1), - 0x80A6E584:("D_80A6E584","UNK_TYPE1","",0x1), - 0x80A6E585:("D_80A6E585","UNK_TYPE1","",0x1), + 0x80A6E4B4:("D_80A6E4B4","s8","[0xD1]",0xD0), 0x80A6E588:("D_80A6E588","UNK_TYPE1","",0x1), 0x80A6E594:("D_80A6E594","UNK_TYPE1","",0x1), 0x80A6E5A0:("D_80A6E5A0","f32","",0x4), @@ -12318,8 +12315,6 @@ 0x80A6E650:("D_80A6E650","f32","",0x4), 0x80A6E654:("D_80A6E654","f32","",0x4), 0x80A6E990:("D_80A6E990","UNK_TYPE1","",0x1), - 0x80A6E9B4:("D_80A6E9B4","UNK_TYPE1","",0x1), - 0x80A6E9D8:("D_80A6E9D8","UNK_TYPE1","",0x1), 0x80A6F098:("D_80A6F098","UNK_TYPE1","",0x1), 0x80A703D0:("En_Mm3_InitVars","UNK_TYPE1","",0x1), 0x80A703F0:("D_80A703F0","UNK_TYPE1","",0x1), diff --git a/tools/vtxdis.c b/tools/vtxdis.c index 1ba696963..8debd89e0 100644 --- a/tools/vtxdis.c +++ b/tools/vtxdis.c @@ -254,4 +254,4 @@ int main(int argc, char **argv) } return 0; -} \ No newline at end of file +} diff --git a/undefined_syms.txt b/undefined_syms.txt index cb1d8903a..b20f97bd7 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -2171,21 +2171,6 @@ D_0600A490 = 0x0600A490; D_06010240 = 0x06010240; -// ovl_En_Fall - -D_06000198 = 0x06000198; -D_06000400 = 0x06000400; -D_060004C0 = 0x060004C0; -D_060004C8 = 0x060004C8; -D_060010E0 = 0x060010E0; -D_06001158 = 0x06001158; -D_060011D0 = 0x060011D0; -D_06001220 = 0x06001220; -D_06002970 = 0x06002970; -D_06003C30 = 0x06003C30; -D_06004E38 = 0x06004E38; -D_060077F0 = 0x060077F0; - // ovl_En_Fall2 D_06005EF4 = 0x06005EF4; @@ -2357,13 +2342,6 @@ D_0600A344 = 0x0600A344; D_06001EFC = 0x06001EFC; D_0600A808 = 0x0600A808; -// ovl_En_Geg - -D_06004DB0 = 0x06004DB0; -D_060091A8 = 0x060091A8; -D_06011AC8 = 0x06011AC8; -D_06012DE0 = 0x06012DE0; - // ovl_En_Gg D_0600F578 = 0x0600F578; @@ -3639,13 +3617,6 @@ D_06009890 = 0x06009890; D_0600A280 = 0x0600A280; D_0600AD98 = 0x0600AD98; -// ovl_En_Talk_Gibud - -D_060053E8 = 0x060053E8; -D_06009298 = 0x06009298; -D_0600ABE0 = 0x0600ABE0; -D_06010B88 = 0x06010B88; - // ovl_En_Tanron2 D_06003450 = 0x06003450; @@ -4295,21 +4266,6 @@ D_06001CB0 = 0x06001CB0; D_06001400 = 0x06001400; -// ovl_Obj_Tokeidai - -D_06009A08 = 0x06009A08; -D_0600B0C0 = 0x0600B0C0; -D_0600B208 = 0x0600B208; -D_0600BA78 = 0x0600BA78; -D_0600BEE8 = 0x0600BEE8; -D_0600C368 = 0x0600C368; -D_0600CF28 = 0x0600CF28; -D_0600D388 = 0x0600D388; -D_0600D8E0 = 0x0600D8E0; -D_0600D8E8 = 0x0600D8E8; -D_0600E818 = 0x0600E818; -D_0600F518 = 0x0600F518; - // ovl_Obj_Tokei_Turret D_06002508 = 0x06002508;