From 663303793f068bb1c03dad64b994e12309f65594 Mon Sep 17 00:00:00 2001 From: Baoulettes Date: Sat, 14 May 2022 17:45:31 +0200 Subject: [PATCH] PR repo mass update, cleaning incoming --- BUILDING.md | 52 +- Dockerfile | 38 + Jenkinsfile | 172 +- OTRExporter/OTRExporter/AnimationExporter.cpp | 4 +- OTRExporter/OTRExporter/ArrayExporter.cpp | 8 +- OTRExporter/OTRExporter/CutsceneExporter.cpp | 8 +- .../OTRExporter/DisplayListExporter.cpp | 58 +- OTRExporter/OTRExporter/Main.cpp | 14 +- OTRExporter/OTRExporter/Makefile | 14 +- OTRExporter/OTRExporter/PathExporter.cpp | 4 +- OTRExporter/OTRExporter/RoomExporter.cpp | 34 +- OTRExporter/OTRExporter/TextExporter.cpp | 4 +- OTRExporter/OTRExporter/VersionInfo.cpp | 36 +- .../ship_of_harkinian/fonts/Fipps-Regular.otf | Bin 0 -> 34220 bytes .../fonts/PressStart2P-Regular.ttf | Bin 0 -> 116008 bytes OTRExporter/extract_assets.py | 135 +- OTRExporter/extract_baserom.py | 53 + OTRExporter/rom_chooser.py | 37 + OTRExporter/rom_info.py | 87 + OTRGui/src/game/game.cpp | 8 +- README.md | 80 +- ZAPDTR/ExporterTest/CollisionExporter.cpp | 2 +- ZAPDTR/ExporterTest/CollisionExporter.h | 2 +- ZAPDTR/ExporterTest/RoomExporter.cpp | 2 +- ZAPDTR/ExporterTest/RoomExporter.h | 2 +- ZAPDTR/ExporterTest/TextureExporter.cpp | 2 +- ZAPDTR/ExporterTest/TextureExporter.h | 2 +- ZAPDTR/Makefile | 7 +- ZAPDTR/ZAPD/Main.cpp | 34 +- ZAPDTR/ZAPD/OutputFormatter.cpp | 2 +- ZAPDTR/ZAPD/OutputFormatter.h | 2 +- ZAPDTR/ZAPD/ZDisplayList.cpp | 118 + ZAPDTR/ZAPD/ZDisplayList.h | 116 - ZAPDTR/ZAPD/ZLimb.h | 14 +- ZAPDTR/ZAPDUtils/Utils/BitConverter.h | 1 + ZAPDTR/ZAPDUtils/Utils/Directory.h | 2 +- ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp | 6 +- external/libGLEW.a | Bin 0 -> 837914 bytes external/libstorm.a | Bin 0 -> 838950 bytes libultraship/.gitignore | 4 +- libultraship/Makefile | 84 +- libultraship/libultraship/Animation.cpp | 2 +- libultraship/libultraship/Archive.cpp | 76 +- libultraship/libultraship/Array.cpp | 2 + libultraship/libultraship/ConfigFile.cpp | 2 +- libultraship/libultraship/ConfigFile.h | 7 +- libultraship/libultraship/Cvar.cpp | 55 +- libultraship/libultraship/Cvar.h | 16 +- .../Factories/OTRResourceLoader.cpp | 71 - libultraship/libultraship/GameOverlay.cpp | 225 ++ libultraship/libultraship/GameOverlay.h | 42 + libultraship/libultraship/GameSettings.cpp | 48 +- libultraship/libultraship/GameSettings.h | 33 +- libultraship/libultraship/GameVersions.h | 7 +- libultraship/libultraship/GlobalCtx2.cpp | 6 +- libultraship/libultraship/GlobalCtx2.h | 7 +- .../Lib/Fast3D/U64/PR/ultra64/gbi.h | 10 +- .../Lib/Fast3D/U64/PR/ultra64/mbi.h | 1 + .../Lib/Fast3D/gfx_direct3d11.cpp | 49 +- .../libultraship/Lib/Fast3D/gfx_glx.cpp | 79 +- .../libultraship/Lib/Fast3D/gfx_glx.h | 2 +- .../libultraship/Lib/Fast3D/gfx_opengl.cpp | 61 +- .../libultraship/Lib/Fast3D/gfx_pc.cpp | 104 +- libultraship/libultraship/Lib/Fast3D/gfx_pc.h | 20 +- .../Lib/Fast3D/gfx_rendering_api.h | 8 + .../libultraship/Lib/Fast3D/gfx_sdl2.cpp | 12 +- libultraship/libultraship/Lib/StrHash64.h | 12 +- .../include/spdlog/sinks/sohconsole_sink.h | 7 +- libultraship/libultraship/Model.cpp | 12 +- .../libultraship/PulseAudioPlayer.cpp | 173 ++ libultraship/libultraship/PulseAudioPlayer.h | 26 + libultraship/libultraship/Resource.cpp | 12 +- libultraship/libultraship/Resource.h | 10 +- libultraship/libultraship/ResourceMgr.cpp | 64 +- libultraship/libultraship/ResourceMgr.h | 4 +- libultraship/libultraship/SDLController.cpp | 16 +- libultraship/libultraship/SDLController.h | 9 +- libultraship/libultraship/Scene.cpp | 12 +- libultraship/libultraship/SkeletonLimb.cpp | 2 +- libultraship/libultraship/SohConsole.cpp | 18 +- libultraship/libultraship/SohConsole.h | 10 +- libultraship/libultraship/SohHooks.cpp | 2 +- libultraship/libultraship/SohHooks.h | 1 + libultraship/libultraship/SohImGuiImpl.cpp | 615 +++-- libultraship/libultraship/SohImGuiImpl.h | 8 +- libultraship/libultraship/TextureMod.cpp | 2 +- libultraship/libultraship/TextureMod.h | 9 - libultraship/libultraship/Utils.cpp | 7 +- .../libultraship/WasapiAudioPlayer.cpp | 4 +- libultraship/libultraship/WasapiAudioPlayer.h | 4 + libultraship/libultraship/Window.cpp | 25 +- libultraship/libultraship/Window.h | 2 +- libultraship/libultraship/WindowShim.cpp | 4 +- .../libultraship/libultraship.vcxproj | 2 + .../libultraship/libultraship.vcxproj.filters | 9 + libultraship/libultraship/mixer.c | 5 +- libultraship/libultraship/stox.cpp | 1 + soh/.gitignore | 11 +- soh/Makefile | 158 ++ .../GC_NMQ_D/textures/map_48x85_static.xml | 136 +- .../textures/map_48x85_static.xml | 138 +- soh/include/alloca.h | 2 +- soh/include/functions.h | 5 +- soh/include/global.h | 4 +- soh/include/libc/stddef.h | 5 + soh/include/macros.h | 18 +- soh/include/ultra64.h | 3 + soh/include/z64.h | 3 + soh/include/z64effect.h | 1 + soh/soh.vcxproj | 9 +- soh/soh.vcxproj.filters | 19 +- soh/soh/Enhancements/bootcommands.c | 4 +- soh/soh/Enhancements/debugconsole.cpp | 123 +- soh/soh/Enhancements/debugger/colViewer.cpp | 6 +- .../Enhancements/debugger/debugSaveEditor.cpp | 544 +++- soh/soh/Enhancements/gameconsole.h | 2 +- soh/soh/Enhancements/savestates.cpp | 957 +++++++ soh/soh/Enhancements/savestates.h | 62 + soh/soh/Enhancements/savestates_extern.inc | 257 ++ soh/soh/OTRAudio.h | 8 + soh/soh/OTRGlobals.cpp | 155 +- soh/soh/OTRGlobals.h | 15 +- soh/soh/frame_interpolation.cpp | 732 +++++ soh/soh/frame_interpolation.h | 61 + soh/soh/stubs.c | 6 +- soh/soh/z_play_otr.cpp | 8 +- soh/soh/z_scene_otr.cpp | 18 +- soh/src/boot/build.c | 2 +- soh/src/buffers/heaps.c | 3 - soh/src/code/audio_effects.c | 6 +- soh/src/code/audio_load.c | 20 +- soh/src/code/audio_seqplayer.c | 4 +- soh/src/code/audio_synthesis.c | 4 +- soh/src/code/graph.c | 3 + soh/src/code/padmgr.c | 2 + soh/src/code/sys_matrix.c | 22 +- soh/src/code/z_actor.c | 108 +- soh/src/code/z_bgcheck.c | 2 +- soh/src/code/z_camera.c | 19 +- soh/src/code/z_camera_data.inc | 2403 +++++++++++++++++ soh/src/code/z_demo.c | 2 +- soh/src/code/z_eff_blure.c | 4 + soh/src/code/z_eff_shield_particle.c | 4 + soh/src/code/z_eff_spark.c | 4 + soh/src/code/z_effect_soft_sprite.c | 5 + soh/src/code/z_fbdemo_circle.c | 4 +- soh/src/code/z_lifemeter.c | 226 +- soh/src/code/z_lights.c | 4 + soh/src/code/z_map_exp.c | 29 +- soh/src/code/z_map_mark.c | 2 +- soh/src/code/z_message_PAL.c | 108 +- soh/src/code/z_onepointdemo.c | 4 +- soh/src/code/z_onepointdemo_data.inc | 670 +++++ soh/src/code/z_parameter.c | 80 +- soh/src/code/z_play.c | 6 +- soh/src/code/z_player_lib.c | 9 +- soh/src/code/z_skelanime.c | 4 +- soh/src/code/z_skin_matrix.c | 3 + soh/src/code/z_view.c | 109 +- soh/src/code/z_vismono.c | 2 +- soh/src/code/z_vr_box_draw.c | 5 +- soh/src/libultra/gu/guLookAt.c | 3 +- soh/src/libultra/gu/guPerspectiveF.c | 4 +- soh/src/libultra/gu/ortho.c | 7 +- .../actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.c | 26 +- .../actors/ovl_Bg_Dodoago/z_bg_dodoago.c | 36 +- .../ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c | 10 +- .../actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c | 21 +- .../actors/ovl_Bg_Haka_Trap/z_bg_haka_trap.c | 4 +- .../ovl_Bg_Hidan_Rock/z_bg_hidan_rock.c | 6 +- .../z_bg_hidan_rsekizou.c | 3 +- .../ovl_Bg_Jya_1flift/z_bg_jya_1flift.c | 10 +- .../ovl_Bg_Jya_Bigmirror/z_bg_jya_bigmirror.c | 8 +- .../actors/ovl_Bg_Jya_Cobra/z_bg_jya_cobra.c | 6 +- .../actors/ovl_Bg_Jya_Lift/z_bg_jya_lift.c | 8 +- .../ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c | 2 +- .../ovl_Bg_Mori_Elevator/z_bg_mori_elevator.c | 10 +- .../ovl_Bg_Mori_Hineri/z_bg_mori_hineri.c | 16 +- .../ovl_Bg_Mori_Idomizu/z_bg_mori_idomizu.c | 8 +- .../z_bg_mori_kaitenkabe.c | 4 +- .../actors/ovl_Bg_Po_Event/z_bg_po_event.c | 82 +- .../ovl_Bg_Relay_Objects/z_bg_relay_objects.c | 2 +- .../ovl_Bg_Spot15_Rrbox/z_bg_spot15_rrbox.c | 4 +- .../ovl_Bg_Spot18_Basket/z_bg_spot18_basket.c | 2 +- .../overlays/actors/ovl_Boss_Fd/z_boss_fd.c | 16 + .../overlays/actors/ovl_Boss_Fd/z_boss_fd.h | 1 + .../overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c | 5 + .../actors/ovl_Boss_Ganon/z_boss_ganon.c | 332 +-- .../actors/ovl_Boss_Ganon/z_boss_ganon.h | 19 + .../actors/ovl_Boss_Ganon2/z_boss_ganon2.c | 201 +- .../actors/ovl_Boss_Ganon2/z_boss_ganon2.h | 14 + .../ovl_Boss_Ganon2/z_boss_ganon2_data.c | 41 +- .../ovl_Boss_Ganondrof/z_boss_ganondrof.c | 8 +- .../overlays/actors/ovl_Boss_Mo/z_boss_mo.c | 45 +- .../overlays/actors/ovl_Boss_Tw/z_boss_tw.c | 45 +- .../overlays/actors/ovl_Boss_Tw/z_boss_tw.h | 45 +- .../overlays/actors/ovl_Boss_Va/z_boss_va.c | 20 + .../overlays/actors/ovl_Demo_6K/z_demo_6k.c | 16 +- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 22 +- .../actors/ovl_Door_Warp1/z_door_warp1.c | 2 +- soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c | 2 +- .../actors/ovl_En_Clear_Tag/z_en_clear_tag.c | 14 +- soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c | 14 +- soh/src/overlays/actors/ovl_En_Fr/z_en_fr.h | 11 + .../overlays/actors/ovl_En_Goma/z_en_goma.c | 2 +- .../actors/ovl_En_Insect/z_en_insect.c | 6 +- .../overlays/actors/ovl_En_Ishi/z_en_ishi.c | 24 +- soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c | 6 +- .../overlays/actors/ovl_En_Ossan/z_en_ossan.c | 18 +- .../actors/ovl_En_Po_Field/z_en_po_field.c | 36 +- .../ovl_En_Takara_Man/z_en_takara_man.c | 2 +- soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c | 14 +- soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c | 4 +- soh/src/overlays/actors/ovl_En_Zl3/z_en_zl3.c | 6 +- soh/src/overlays/actors/ovl_En_Zo/z_en_zo.c | 11 + soh/src/overlays/actors/ovl_En_Zo/z_en_zo.h | 1 + .../overlays/actors/ovl_Fishing/z_fishing.c | 33 + .../actors/ovl_Obj_Oshihiki/z_obj_oshihiki.c | 4 +- .../ovl_Object_Kankyo/z_object_kankyo.c | 25 +- .../ovl_Object_Kankyo/z_object_kankyo.h | 1 + .../actors/ovl_player_actor/z_player.c | 12 +- .../ovl_file_choose/z_file_choose.c | 4 +- .../overlays/gamestates/ovl_select/z_select.c | 4 +- .../overlays/gamestates/ovl_title/z_title.c | 2 +- .../ovl_kaleido_scope/z_kaleido_collect.c | 60 +- .../ovl_kaleido_scope/z_kaleido_equipment.c | 2 +- .../ovl_kaleido_scope/z_kaleido_map_PAL.c | 10 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 92 +- .../misc/ovl_kaleido_scope/z_lmap_mark_data.c | 516 ++++ 229 files changed, 10259 insertions(+), 2423 deletions(-) create mode 100644 Dockerfile create mode 100644 OTRExporter/assets/ship_of_harkinian/fonts/Fipps-Regular.otf create mode 100644 OTRExporter/assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf create mode 100644 OTRExporter/extract_baserom.py create mode 100644 OTRExporter/rom_chooser.py create mode 100644 OTRExporter/rom_info.py create mode 100644 external/libGLEW.a create mode 100644 external/libstorm.a delete mode 100644 libultraship/libultraship/Factories/OTRResourceLoader.cpp create mode 100644 libultraship/libultraship/GameOverlay.cpp create mode 100644 libultraship/libultraship/GameOverlay.h create mode 100644 libultraship/libultraship/PulseAudioPlayer.cpp create mode 100644 libultraship/libultraship/PulseAudioPlayer.h create mode 100644 soh/Makefile create mode 100644 soh/soh/Enhancements/savestates.cpp create mode 100644 soh/soh/Enhancements/savestates.h create mode 100644 soh/soh/Enhancements/savestates_extern.inc create mode 100644 soh/soh/OTRAudio.h create mode 100644 soh/soh/frame_interpolation.cpp create mode 100644 soh/soh/frame_interpolation.h create mode 100644 soh/src/code/z_camera_data.inc create mode 100644 soh/src/code/z_onepointdemo_data.inc diff --git a/BUILDING.md b/BUILDING.md index 82c26bff4..3e4d7b21a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,13 +1,15 @@ # Building Ship of Harkinian - 1. Install [Python](https://www.python.org/ftp/python/3.10.2/python-3.10.2-amd64.exe) +## Windows + + 1. Install [Python](https://www.python.org/downloads/) >= 3.6. 2. Install [Visual Studio 2022 Community Edition](https://visualstudio.microsoft.com/vs/community/) - 2b. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`. + 3. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`. 4. Clone the Ship of Harkinian repository. 5. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice. 6. Run `OTRExporter/OTRExporter.sln`. 7. Switch the solution to `Release x64`. - 8. Build the solution. + 8. Build the solution. 9. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`. 10. Run `soh/soh.sln` 11. Switch the solution to `Release x86`. @@ -15,8 +17,50 @@ 13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`. 14. Launch `soh.exe`. -## Compatible Roms +## Linux + +```bash +# Clone the repo +git clone git@github.com:HarbourMasters/ShipWright.git +cd ShipWright +# Copy the baserom to the OTRExporter folder +cp OTRExporter +# Build the docker image +sudo docker build . -t soh +# Run the docker image with the working directory mounted to /soh +sudo docker run --rm -it -v $(pwd):/soh soh /bin/bash +``` +Inside the Docker container: +```bash +# Clone and build StormLib +git clone https://github.com/ladislav-zezula/StormLib external/StormLib +cmake -B external/StormLib/build -S external/StormLib +cmake --build external/StormLib/build +cp external/StormLib/build/libstorm.a external +cp /usr/local/lib/libGLEW.a external + +cd soh +# Extract the assets/Compile the exporter/Run the exporter +make setup -j$(nproc) OPTFLAGS=-O0 DEBUG=0 +# Compile the code +make -j $(nproc) OPTFLAGS=-O0 DEBUG=0 +``` + +# Compatible Roms ``` OOT_PAL_GC checksum 0x09465AC3 OOT_PAL_GC_DBG1 checksum 0x871E1C92 (debug non-master quest) ``` + +# OTRExporter Usage + +The OTRExporter exports an `oot.otr` archive file which Ship of Harkinian requires to play. + +Use the `extract_assets.py` script file to run the exporter using any of the following methods: + +1. Double click on the script after placing one or more roms in the directory. +2. Drag & Drop a rom onto the script. +3. In a terminal run `python3 extract_assets.py` after placing one or more roms in the directory. +4. In a terminal run `python3 extract_assets.py ` + +If the script finds multiple roms the user is prompted which to use. Selection is done using the number keys and then pressing the carriage return key. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..e981cf573 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ + + +FROM ubuntu:21.04 as build + +ENV LANG C.UTF-8 +ARG DEBIAN_FRONTEND=noninteractive + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + binutils:i386 \ + gcc-10:i386 \ + g++-10:i386 \ + python3.10 \ + python \ + make \ + cmake \ + git \ + lld \ + libsdl2-dev:i386 \ + zlib1g-dev:i386 \ + libbz2-dev:i386 \ + libpng-dev:i386 \ + libgles2-mesa-dev && \ + ln -sf /usr/bin/python3.10 /usr/bin/python3 && \ + ln -s /usr/bin/gcc-10 /usr/bin/gcc && \ + ln -s /usr/bin/gcc-10 /usr/bin/cc && \ + ln -s /usr/bin/g++-10 /usr/bin/g++ && \ + ln -s /usr/bin/g++-10 /usr/bin/c++ + +RUN git clone https://github.com/Perlmint/glew-cmake.git && \ + cmake glew-cmake && \ + make -j$(nproc) && \ + make install ARCH64=false + +RUN mkdir /soh +WORKDIR /soh diff --git a/Jenkinsfile b/Jenkinsfile index fa68703b2..7f1132bae 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,29 +1,26 @@ pipeline { - - environment { - MSBUILD='C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin\\msbuild.exe' - CONFIG='Release' - OTRPLATFORM='x64' - PLATFORM='x86' - ZIP='C:\\Program Files\\7-Zip\\7z.exe' - PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe' - TOOLSET='v142' - EMAILTO='' - } - - agent { - label 'SoH-Builders' - } - + agent none + options { timestamps() - timeout(time: 15, unit: 'MINUTES') skipDefaultCheckout(true) } - + stages { - - stage ('Checkout') { + stage ('Build Windows') { + environment { + MSBUILD='C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin\\msbuild.exe' + CONFIG='Release' + OTRPLATFORM='x64' + PLATFORM='x86' + ZIP='C:\\Program Files\\7-Zip\\7z.exe' + PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe' + CMAKE='C:\\Program Files\\CMake\\bin\\cmake.exe' + TOOLSET='v142' + } + agent { + label "SoH-Builders" + } steps { checkout([ $class: 'GitSCM', @@ -32,68 +29,89 @@ pipeline { extensions: scm.extensions, userRemoteConfigs: scm.userRemoteConfigs ]) + + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + bat """ + + "${env.MSBUILD}" ".\\OTRExporter\\OTRExporter.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.OTRPLATFORM};PlatformToolset=${env.TOOLSET};RestorePackagesConfig=true /restore /nodeReuse:false /m + + xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\" + + cd "OTRExporter" + "${env.PYTHON}" ".\\extract_assets.py" + cd "..\\" + + "${env.MSBUILD}" ".\\soh\\soh.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.PLATFORM};PlatformToolset=${env.TOOLSET} /nodeReuse:false /m + + cd OTRGui + mkdir build + cd build + + "${env.CMAKE}" .. + "${env.CMAKE}" --build . --config Release + + cd "..\\..\\" + + move "soh\\Release\\soh.exe" ".\\" + move "OTRGui\\build\\assets" ".\\" + move ".\\OTRExporter\\x64\\Release\\ZAPD.exe" ".\\assets\\extractor\\" + move ".\\OTRGui\\build\\Release\\OTRGui.exe" ".\\" + rename README.md readme.txt + + "${env.ZIP}" a soh.7z soh.exe OTRGui.exe assets readme.txt + + """ + archiveArtifacts artifacts: 'soh.7z', followSymlinks: false, onlyIfSuccessful: true + } + } + post { + always { + step([$class: 'WsCleanup']) // Clean workspace + } } } - - stage ('Build OTRExporter') { + stage ('Build Linux') { + agent { + label "SoH-Linux-Builders" + } steps { - bat """ - - "${env.MSBUILD}" ".\\OTRExporter\\OTRExporter.sln" -t:restore,build -p:Configuration=${env.CONFIG};Platform=${env.OTRPLATFORM};PlatformToolset=${env.TOOLSET};RestorePackagesConfig=true /nodeReuse:false - - """ + checkout([ + $class: 'GitSCM', + branches: scm.branches, + doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations, + extensions: scm.extensions, + userRemoteConfigs: scm.userRemoteConfigs + ]) + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + sh ''' + + cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + docker build . -t soh + docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash + cp ../../buildsoh.bash soh + docker exec sohcont soh/buildsoh.bash + + mkdir build + mv soh/soh.elf build/ + mv OTRGui/build/OTRGui build/ + mv OTRGui/build/assets build/ + mv ZAPDTR/ZAPD.out build/assets/extractor/ + mv README.md build/readme.txt + cd build + + 7z a soh-linux.7z soh.elf OTRGui assets readme.txt + mv soh-linux.7z ../ + + ''' + } + sh 'sudo docker container stop sohcont' + archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true } - } - - stage ('Extract assets') { - steps { - bat """ - - xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\" - - cd "OTRExporter" - "${env.PYTHON}" ".\\extract_assets.py" - cd "${env.WORKSPACE}" - - """ + post { + always { + step([$class: 'WsCleanup']) // Clean workspace + } } } - - stage ('Build SoH') { - steps { - bat """ - - "${env.MSBUILD}" ".\\soh\\soh.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.PLATFORM};PlatformToolset=${env.TOOLSET} /nodeReuse:false - - """ - } - } - - stage ('Archive artifacts') { - steps { - bat """ - - "${env.ZIP}" a "soh.zip" ".\\soh\\Release\\soh.exe" - - """ - - archiveArtifacts allowEmptyArchive: false, - artifacts: 'soh.zip', - caseSensitive: true, - defaultExcludes: true, - fingerprint: false, - onlyIfSuccessful: true - } - } - } - - post { - always { - step([$class: 'Mailer', - notifyEveryUnstableBuild: true, - recipients: "${env.EMAILTO}", - sendToIndividuals: false]) - step([$class: 'WsCleanup']) // Clean workspace - } } } diff --git a/OTRExporter/OTRExporter/AnimationExporter.cpp b/OTRExporter/OTRExporter/AnimationExporter.cpp index 4f031b8a8..74fa8a7e6 100644 --- a/OTRExporter/OTRExporter/AnimationExporter.cpp +++ b/OTRExporter/OTRExporter/AnimationExporter.cpp @@ -49,12 +49,12 @@ void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, Binary writer->Write((uint32_t)normalAnim->rotationValues.size()); - for (int i = 0; i < normalAnim->rotationValues.size(); i++) + for (size_t i = 0; i < normalAnim->rotationValues.size(); i++) writer->Write(normalAnim->rotationValues[i]); writer->Write((uint32_t)normalAnim->rotationIndices.size()); - for (int i = 0; i < normalAnim->rotationIndices.size(); i++) + for (size_t i = 0; i < normalAnim->rotationIndices.size(); i++) { writer->Write(normalAnim->rotationIndices[i].x); writer->Write(normalAnim->rotationIndices[i].y); diff --git a/OTRExporter/OTRExporter/ArrayExporter.cpp b/OTRExporter/OTRExporter/ArrayExporter.cpp index 2ddfd7b10..f83bfd87d 100644 --- a/OTRExporter/OTRExporter/ArrayExporter.cpp +++ b/OTRExporter/OTRExporter/ArrayExporter.cpp @@ -10,7 +10,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit writer->Write((uint32_t)arr->resList[0]->GetResourceType()); writer->Write((uint32_t)arr->arrayCnt); - for (int i = 0; i < arr->arrayCnt; i++) + for (size_t i = 0; i < arr->arrayCnt; i++) { if (arr->resList[i]->GetResourceType() == ZResourceType::Vertex) { @@ -32,7 +32,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit writer->Write((uint32_t)vec->scalarType); writer->Write((uint32_t)vec->dimensions); - for (int k = 0; k < vec->dimensions; k++) + for (size_t k = 0; k < vec->dimensions; k++) { // OTRTODO: Duplicate code here. Cleanup at a later date... switch (vec->scalarType) @@ -62,6 +62,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit writer->Write(vec->scalars[k].scalarData.u64); break; // OTRTODO: ADD OTHER TYPES + default: + break; } } } @@ -98,6 +100,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit writer->Write(scal->scalarData.u64); break; // OTRTODO: ADD OTHER TYPES + default: + break; } } } diff --git a/OTRExporter/OTRExporter/CutsceneExporter.cpp b/OTRExporter/OTRExporter/CutsceneExporter.cpp index 7cbf7f175..b52d73d8b 100644 --- a/OTRExporter/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/OTRExporter/CutsceneExporter.cpp @@ -29,7 +29,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries) { writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame)); - writer->Write(CMD_F(e->viewAngle)); + writer->Write(e->viewAngle); writer->Write(CMD_HH(e->posX, e->posY)); writer->Write(CMD_HH(e->posZ, e->unused)); } @@ -46,7 +46,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries) { writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame)); - writer->Write(CMD_F(e->viewAngle)); + writer->Write(e->viewAngle); writer->Write(CMD_HH(e->posX, e->posY)); writer->Write(CMD_HH(e->posZ, e->unused)); } @@ -105,7 +105,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries) { writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame)); - writer->Write(CMD_F(e->viewAngle)); + writer->Write(e->viewAngle); writer->Write(CMD_HH(e->posX, e->posY)); writer->Write(CMD_HH(e->posZ, e->unused)); } @@ -122,7 +122,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries) { writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame)); - writer->Write(CMD_F(e->viewAngle)); + writer->Write(e->viewAngle); writer->Write(CMD_HH(e->posX, e->posY)); writer->Write(CMD_HH(e->posZ, e->unused)); } diff --git a/OTRExporter/OTRExporter/DisplayListExporter.cpp b/OTRExporter/OTRExporter/DisplayListExporter.cpp index 1fe7cb44a..d03a06333 100644 --- a/OTRExporter/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/OTRExporter/DisplayListExporter.cpp @@ -29,20 +29,6 @@ Ab1, Ad1)) \ } -typedef int32_t Mtx_t[4][4]; - -typedef union Mtx -{ - //_Alignas(8) - Mtx_t m; - int32_t l[16]; - struct - { - int16_t i[16]; - uint16_t f[16]; - }; -} Mtx; - #define gsSPBranchLessZraw2(dl, vtx, zval) \ { _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\ (unsigned int)(zval), } @@ -71,7 +57,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina // DEBUG: Write in a marker Declaration* dbgDecl = dList->parent->GetDeclaration(dList->GetRawDataIndex()); - std::string dbgName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str()); + std::string dbgName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str()); uint64_t hash = CRC64(dbgName.c_str()); writer->Write((uint32_t)(G_MARKER << 24)); writer->Write((uint32_t)0xBEEFBEEF); @@ -81,7 +67,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina auto dlStart = std::chrono::steady_clock::now(); //for (auto data : dList->instructions) - for (int dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++) + for (size_t dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++) { auto data = dList->instructions[dataIdx]; uint32_t word0 = 0; @@ -216,7 +202,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina pp ^= G_MTX_PUSH; - mm = (mm & 0x0FFFFFFF) + 0xF0000000; + mm = (mm & 0x0FFFFFFF) + 1; Gfx value = gsSPMatrix(mm, pp); word0 = value.words.w0; @@ -243,7 +229,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (mtxDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -347,7 +333,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -370,7 +356,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina //std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str()); std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str()); - if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName)) + if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName)) { MemoryStream* dlStream = new MemoryStream(); BinaryWriter dlWriter = BinaryWriter(dlStream); @@ -383,7 +369,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina #endif if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector()); + File::WriteAllBytes("Extract/" + fName, dlStream->ToVector()); else files[fName] = dlStream->ToVector(); @@ -411,7 +397,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina Gfx value; - u32 dListVal = (data & 0x0FFFFFFF) + 0xF0000000; + u32 dListVal = (data & 0x0FFFFFFF) + 1; if (pp != 0) value = gsSPBranchList(dListVal); @@ -444,7 +430,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -467,7 +453,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina //std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str()); std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str()); - if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName)) + if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName)) { MemoryStream* dlStream = new MemoryStream(); BinaryWriter dlWriter = BinaryWriter(dlStream); @@ -475,7 +461,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina Save(dList->otherDLists[i], outPath, &dlWriter); if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector()); + File::WriteAllBytes("Extract/" + fName, dlStream->ToVector()); else files[fName] = dlStream->ToVector(); } @@ -533,7 +519,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2; int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; int32_t dd = ((data & 0x000000000000FFULL)) / 2; - + Gfx test = gsSP1Quadrangle(aa, bb, cc, dd, 0); word0 = test.words.w0; word1 = test.words.w1; @@ -689,7 +675,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t fmt = (__ & 0xE0) >> 5; uint32_t siz = (__ & 0x18) >> 3; - Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 0xF0000000); + Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 1); word0 = value.words.w0; word1 = value.words.w1; @@ -721,7 +707,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); std::string assocFileName = assocFile->GetName(); std::string fName = ""; - + if (GETSEGNUM(seg) == SEGMENT_SCENE || GETSEGNUM(seg) == SEGMENT_ROOM) fName = GetPathToRes(res, texName.c_str()); else @@ -753,7 +739,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina Gfx value = gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn)); word0 = value.words.w0; - word1 = value.words.w1 | 0xF0000000; + word1 = value.words.w1 | 1; } else { @@ -790,7 +776,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina word0 = hash >> 32; word1 = hash & 0xFFFFFFFF; - if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName)) + if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName)) { // Write vertices to file MemoryStream* vtxStream = new MemoryStream(); @@ -800,7 +786,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina auto split = StringHelper::Split(vtxDecl->text, "\n"); - for (int i = 0; i < split.size(); i++) + for (size_t i = 0; i < split.size(); i++) { std::string line = split[i]; @@ -842,7 +828,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - File::WriteAllBytes("Extract\\" + fName, vtxStream->ToVector()); + File::WriteAllBytes("Extract/" + fName, vtxStream->ToVector()); else files[fName] = vtxStream->ToVector(); @@ -858,7 +844,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } break; } - + writer->Write(word0); writer->Write(word1); } @@ -872,7 +858,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina std::string OTRExporter_DisplayList::GetPathToRes(ZResource* res, std::string varName) { std::string prefix = GetPrefix(res); - std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), varName.c_str()); + std::string fName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), varName.c_str()); return fName; } @@ -886,7 +872,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res) { auto split = StringHelper::Split(oName, "_"); oName = ""; - for (int i = 0; i < split.size() - 1; i++) + for (size_t i = 0; i < split.size() - 1; i++) oName += split[i] + "_"; oName += "scene"; @@ -897,7 +883,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res) } if (prefix != "") - oName = prefix + "\\" + oName; + oName = prefix + "/" + oName; return oName; } diff --git a/OTRExporter/OTRExporter/Main.cpp b/OTRExporter/OTRExporter/Main.cpp index a58f94ae3..2ed9cb427 100644 --- a/OTRExporter/OTRExporter/Main.cpp +++ b/OTRExporter/OTRExporter/Main.cpp @@ -52,7 +52,7 @@ static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileM for (auto item : lst) { auto fileData = File::ReadAllBytes(item); - otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size()); + otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size()); } } } @@ -76,7 +76,7 @@ static void ExporterProgramEnd() for (auto item : lst) { auto fileData = File::ReadAllBytes(item); - otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size()); + otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size()); } otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size()); @@ -117,7 +117,7 @@ static void ExporterFileBegin(ZFile* file) static void ExporterFileEnd(ZFile* file) { - int bp = 0; + // delete fileWriter; } static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) @@ -140,7 +140,7 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) { auto split = StringHelper::Split(oName, "_"); oName = ""; - for (int i = 0; i < split.size() - 1; i++) + for (size_t i = 0; i < split.size() - 1; i++) oName += split[i] + "_"; oName += "scene"; @@ -153,14 +153,14 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) std::string fName = ""; if (prefix != "") - fName = StringHelper::Sprintf("%s\\%s\\%s", prefix.c_str(), oName.c_str(), rName.c_str()); + fName = StringHelper::Sprintf("%s/%s/%s", prefix.c_str(), oName.c_str(), rName.c_str()); else - fName = StringHelper::Sprintf("%s\\%s", oName.c_str(), rName.c_str()); + fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str()); if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) files[fName] = strem->ToVector(); else - File::WriteAllBytes("Extract\\" + fName, strem->ToVector()); + File::WriteAllBytes("Extract/" + fName, strem->ToVector()); } auto end = std::chrono::steady_clock::now(); diff --git a/OTRExporter/OTRExporter/Makefile b/OTRExporter/OTRExporter/Makefile index 1c4e61bf2..954b183a3 100644 --- a/OTRExporter/OTRExporter/Makefile +++ b/OTRExporter/OTRExporter/Makefile @@ -39,13 +39,13 @@ D_FILES := $(O_FILES:%.o=%.d) LIB := OTRExporter.a INC_DIRS := $(addprefix -I, \ - ../../ZAPD/ZAPD \ - ../../ZAPD/lib/tinyxml2 \ - ../../ZAPD/lib/libgfxd \ - ../../ZAPD/ZAPDUtils \ - ../../OtrLib/otrlib \ - ../../OtrLib/otrlib/Lib/spdlog/include \ - ../../OtrLib/otrlib/Lib/Fast3D/U64 \ + ../../ZAPDTR/ZAPD \ + ../../ZAPDTR/lib/tinyxml2 \ + ../../ZAPDTR/lib/libgfxd \ + ../../ZAPDTR/ZAPDUtils \ + ../../libultraship/libultraship \ + ../../libultraship/libultraship/Lib/spdlog/include \ + ../../libultraship/libultraship/Lib/Fast3D/U64 \ ) # create build directories diff --git a/OTRExporter/OTRExporter/PathExporter.cpp b/OTRExporter/OTRExporter/PathExporter.cpp index de15789ab..75f6b723f 100644 --- a/OTRExporter/OTRExporter/PathExporter.cpp +++ b/OTRExporter/OTRExporter/PathExporter.cpp @@ -9,11 +9,11 @@ void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWrite writer->Write((uint32_t)path->pathways.size()); - for (int k = 0; k < path->pathways.size(); k++) + for (size_t k = 0; k < path->pathways.size(); k++) { writer->Write((uint32_t)path->pathways[k].points.size()); - for (int i = 0; i < path->pathways[k].points.size(); i++) + for (size_t i = 0; i < path->pathways[k].points.size(); i++) { writer->Write(path->pathways[k].points[i].scalars[0].scalarData.s16); writer->Write(path->pathways[k].points[i].scalars[1].scalarData.s16); diff --git a/OTRExporter/OTRExporter/RoomExporter.cpp b/OTRExporter/OTRExporter/RoomExporter.cpp index 5b7ce4323..9a5704bbc 100644 --- a/OTRExporter/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/OTRExporter/RoomExporter.cpp @@ -46,7 +46,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite for (size_t i = 0; i < room->commands.size(); i++) { ZRoomCommand* cmd = room->commands[i]; - + writer->Write((uint32_t)cmd->cmdID); switch (cmd->cmdID) @@ -172,7 +172,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite writer->Write((uint32_t)cmdCsCam->points.size()); - for (int i = 0; i < cmdCsCam->points.size(); i++) + for (size_t i = 0; i < cmdCsCam->points.size(); i++) { writer->Write(cmdCsCam->points[i].scalars[0].scalarData.s16); writer->Write(cmdCsCam->points[i].scalars[1].scalarData.s16); @@ -183,7 +183,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite case RoomCommand::SetMesh: { SetMesh* cmdMesh = (SetMesh*)cmd; - + writer->Write((uint8_t)cmdMesh->data); // 0x01 writer->Write(cmdMesh->meshHeaderType); @@ -207,12 +207,12 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu)); if (test->opa != 0) - writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); else writer->Write(""); - + if (test->xlu != 0) - writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str())); else writer->Write(""); @@ -228,7 +228,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->multiList[i].source)); writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->varName)); - + writer->Write(poly->multiList[i].unk_0C); writer->Write(poly->multiList[i].tlut); writer->Write(poly->multiList[i].width); @@ -338,7 +338,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++) { - //std::string roomName = StringHelper::Sprintf("%s\\%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i); + //std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i); std::string roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); writer->Write(roomName); writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart); @@ -383,7 +383,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite uint32_t baseStreamEnd = writer->GetStream().get()->GetLength(); writer->Write((uint32_t)cmdStartPos->actors.size()); // 0x01 - + for (const ActorSpawnEntry& entry : cmdStartPos->actors) { writer->Write(entry.actorNum); @@ -441,7 +441,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite case RoomCommand::SetCutscenes: { SetCutscenes* cmdSetCutscenes = (SetCutscenes*)cmd; - + std::string listName; Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID); std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); @@ -452,9 +452,9 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite BinaryWriter csWriter = BinaryWriter(csStream); OTRExporter_Cutscene cs; cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter); - + if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - File::WriteAllBytes("Extract\\" + fName, csStream->ToVector()); + File::WriteAllBytes("Extract/" + fName, csStream->ToVector()); else files[fName] = csStream->ToVector(); @@ -468,7 +468,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite writer->Write((uint32_t)cmdSetPathways->pathwayList.pathways.size()); - for (int i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++) + for (size_t i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++) { Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress)); //std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str()); @@ -481,7 +481,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter); if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - File::WriteAllBytes("Extract\\" + path, pathStream->ToVector()); + File::WriteAllBytes("Extract/" + path, pathStream->ToVector()); else files[path] = pathStream->ToVector(); @@ -514,12 +514,12 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon writer->Write(dlist->unk_06); [[fallthrough]]; default: - //writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); + //writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); if (dlist->opaDList != nullptr) { auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str())); } else writer->Write(""); @@ -527,7 +527,7 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon if (dlist->xluDList != nullptr) { auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str())); } else writer->Write(""); diff --git a/OTRExporter/OTRExporter/TextExporter.cpp b/OTRExporter/OTRExporter/TextExporter.cpp index 19bc0ced1..5819b9b33 100644 --- a/OTRExporter/OTRExporter/TextExporter.cpp +++ b/OTRExporter/OTRExporter/TextExporter.cpp @@ -8,8 +8,8 @@ void OTRExporter_Text::Save(ZResource* res, const fs::path& outPath, BinaryWrite WriteHeader(txt, outPath, writer, Ship::ResourceType::Text); writer->Write((uint32_t)txt->messages.size()); - - for (int i = 0; i < txt->messages.size(); i++) + + for (size_t i = 0; i < txt->messages.size(); i++) { writer->Write(txt->messages[i].id); writer->Write(txt->messages[i].textboxType); diff --git a/OTRExporter/OTRExporter/VersionInfo.cpp b/OTRExporter/OTRExporter/VersionInfo.cpp index 9b684d22b..0a2004673 100644 --- a/OTRExporter/OTRExporter/VersionInfo.cpp +++ b/OTRExporter/OTRExporter/VersionInfo.cpp @@ -5,21 +5,23 @@ std::map resourceVersions; void InitVersionInfo() { - resourceVersions[Ship::ResourceType::Animation] = 0; - resourceVersions[Ship::ResourceType::Model] = 0; - resourceVersions[Ship::ResourceType::Texture] = 0; - resourceVersions[Ship::ResourceType::Material] = 0; - resourceVersions[Ship::ResourceType::PlayerAnimation] = 0; - resourceVersions[Ship::ResourceType::DisplayList] = 0; - resourceVersions[Ship::ResourceType::Room] = 0; - resourceVersions[Ship::ResourceType::CollisionHeader] = 0; - resourceVersions[Ship::ResourceType::Skeleton] = 0; - resourceVersions[Ship::ResourceType::SkeletonLimb] = 0; - resourceVersions[Ship::ResourceType::Matrix] = 0; - resourceVersions[Ship::ResourceType::Path] = 0; - resourceVersions[Ship::ResourceType::Vertex] = 0; - resourceVersions[Ship::ResourceType::Cutscene] = 0; - resourceVersions[Ship::ResourceType::Array] = 0; - resourceVersions[Ship::ResourceType::Text] = 0; - resourceVersions[Ship::ResourceType::Blob] = 0; + resourceVersions = { + { Ship::ResourceType::Animation, 0 }, + { Ship::ResourceType::Model, 0 }, + { Ship::ResourceType::Texture, 0 }, + { Ship::ResourceType::Material, 0 }, + { Ship::ResourceType::PlayerAnimation, 0 }, + { Ship::ResourceType::DisplayList, 0 }, + { Ship::ResourceType::Room, 0 }, + { Ship::ResourceType::CollisionHeader, 0 }, + { Ship::ResourceType::Skeleton, 0 }, + { Ship::ResourceType::SkeletonLimb, 0 }, + { Ship::ResourceType::Matrix, 0 }, + { Ship::ResourceType::Path, 0 }, + { Ship::ResourceType::Vertex, 0 }, + { Ship::ResourceType::Cutscene, 0 }, + { Ship::ResourceType::Array, 0 }, + { Ship::ResourceType::Text, 0 }, + { Ship::ResourceType::Blob, 0 }, + }; } \ No newline at end of file diff --git a/OTRExporter/assets/ship_of_harkinian/fonts/Fipps-Regular.otf b/OTRExporter/assets/ship_of_harkinian/fonts/Fipps-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..9334dad594277ba8339786217d75260e58436dc8 GIT binary patch literal 34220 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 z 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∓eYz|5P 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 -# Invalid input results in the first rom being selected - -import json, os, signal, time, sys, shutil, glob -from multiprocessing import Pool, cpu_count, Event, Manager, ProcessError -from enum import Enum +import os, sys, shutil import shutil - -romVer = "..\\soh\\baserom_non_mq.z64" -roms = []; -checksums = ["", "", ""]; - -class Checksums(Enum): - OOT_NTSC_10 = "EC7011B7" - OOT_NTSC_11 = "D43DA81F" - OOT_NTSC_12 = "693BA2AE" - OOT_PAL_10 = "B044B569" - OOT_PAL_11 = "B2055FBD" - OOT_NTSC_JP_GC_CE = "F7F52DB8" - OOT_NTSC_JP_GC = "F611F4BA" - OOT_NTSC_US_GC = "F3DD35BA" - OOT_PAL_GC = "09465AC3" - OOT_NTSC_JP_MQ = "F43B45BA" - OOT_NTSC_US_MQ = "F034001A" - OOT_PAL_MQ = "1D4136F3" - OOT_PAL_GC_DBG1 = "871E1C92" - OOT_PAL_GC_DBG2 = "87121EFE" - OOT_PAL_GC_MQ_DBG = "917D18F6" - OOT_IQUE_TW = "3D81FB3E" - OOT_IQUE_CN = "B1E1E07B" - OOT_UNKNOWN = "FFFFFFFF" - -CompatibleChecksums = [ - Checksums.OOT_PAL_GC, - Checksums.OOT_PAL_GC_DBG1 -] +from rom_info import Z64Rom +import rom_chooser def BuildOTR(xmlPath, rom): shutil.copytree("assets", "Extract/assets") - execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out" - execStr += " ed -i %s -b %s -fl CFG\\filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom) + execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" + execStr += " ed -i %s -b %s -fl CFG/filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom) print(execStr) exitValue = os.system(execStr) @@ -55,95 +19,14 @@ def BuildOTR(xmlPath, rom): print("Aborting...", file=os.sys.stderr) print("\n") -def checkChecksum(rom): - r = open(rom, "rb") - r.seek(16) - bytes = r.read(4).hex().upper() - r.close() - - for checksum in Checksums: - if (checksum.value == bytes): - - for compat in CompatibleChecksums: - if (checksum.name == compat.name): - print("Compatible rom found!") - return checksum - print("Valid oot rom found. However, not compatible with SoH.") - print("Compatible roms:") - for compat in CompatibleChecksums: - print(compat.name+" | 0x"+compat.value) - sys.exit(1) - - print("Wrong rom! No valid checksum found") - sys.exit(1) - def main(): - - romToUse = ""; - - for file in glob.glob("*.z64"): - roms.append(file) - - if not (roms): - print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr) - sys.exit(1) - - if (len(roms) > 1): - - # If commandline args exist - if (len(sys.argv) > 1): - try: - if ((int(sys.argv[1]) - 1) < 1): - romToUse = roms[0] - - elif ((int(sys.argv[1]) - 1) > len(roms)): - romToUse = roms[len(roms) - 1] - - else: - romToUse = roms[int(sys.argv[1]) - 1] - except: - romToUse = roms[0] - - # No commandline args, select rom using user input - else: - - print(str(len(roms))+" roms found, please select one by pressing 1-"+str(len(roms))) - - count = 1 - for list in range(len(roms)): - print(str(count)+". "+roms[list]) - count += 1 - - while(1): - try: - selection = int(input()) - except: - print("Bad input. Try again with the number keys.") - continue - - if (selection < 1 or selection > len(roms)): - print("Bad input. Try again.") - continue - - else: break - - romToUse = roms[selection - 1] - - else: - romToUse = roms[0] - - match checkChecksum(romToUse): - case Checksums.OOT_PAL_GC: - xmlVer = "GC_NMQ_PAL_F" - case Checksums.OOT_PAL_GC_DBG1: - xmlVer = "GC_NMQ_D" - case _: # default case - xmlVer = "GC_MQ_D" + rom_path = rom_chooser.chooseROM() + rom = Z64Rom(rom_path) if (os.path.exists("Extract")): shutil.rmtree("Extract") - - BuildOTR("..\\soh\\assets\\xml\\" + xmlVer + "\\", romToUse) + + BuildOTR("../soh/assets/xml/" + rom.version.xml_ver + "/", rom_path) if __name__ == "__main__": main() diff --git a/OTRExporter/extract_baserom.py b/OTRExporter/extract_baserom.py new file mode 100644 index 000000000..f387df57a --- /dev/null +++ b/OTRExporter/extract_baserom.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 + +import os +import sys +import struct +from multiprocessing import Pool, cpu_count +from rom_info import Z64Rom +import rom_chooser + + +rom = None + +def initialize_worker(input_rom): + global rom + rom = input_rom + +def ExtractFunc(i): + + dma_file = rom.getDmaEntryByIndex(i) + dma_data = rom.readDmaEntry(dma_file) + + filename = '../soh/baserom/' + rom.version.file_table[i] + print('extracting ' + filename + " (0x%08X, 0x%08X)" % (dma_file.virtStart, dma_file.virtEnd)) + + try: + with open(filename, 'wb') as f: + f.write(dma_data) + except IOError: + print('failed to write file ' + filename) + + # TODO: handle this better + if dma_file.compressed: + os.system('tools/yaz0 -d ' + filename + ' ' + filename) + +##################################################################### + +def main(): + try: + os.mkdir('../soh/baserom') + except: + pass + + rom_path = rom_chooser.chooseROM() + input_rom = Z64Rom(rom_path) + + # extract files + num_cores = cpu_count() + print("Extracting baserom with " + str(num_cores) + " CPU cores.") + with Pool(num_cores, initialize_worker, (input_rom,)) as p: + p.map(ExtractFunc, range(len(input_rom.version.file_table))) + +if __name__ == "__main__": + main() diff --git a/OTRExporter/rom_chooser.py b/OTRExporter/rom_chooser.py new file mode 100644 index 000000000..5c5f875d0 --- /dev/null +++ b/OTRExporter/rom_chooser.py @@ -0,0 +1,37 @@ +import os, sys, glob + +from rom_info import Z64Rom + +def chooseROM(): + roms = [] + + for file in glob.glob("*.z64"): + if Z64Rom.isValidRom(file): + roms.append(file) + + if not (roms): + print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr) + sys.exit(1) + + if (len(roms) == 1): + return roms[0] + + print(str(len(roms))+ " roms found, please select one by pressing 1-"+str(len(roms))) + + for i in range(len(roms)): + print(str(i+1)+ ". " + roms[i]) + + while(1): + try: + selection = int(input()) + except: + print("Bad input. Try again with the number keys.") + continue + + if (selection < 1 or selection > len(roms)): + print("Bad input. Try again.") + continue + + else: break + + return roms[selection - 1] diff --git a/OTRExporter/rom_info.py b/OTRExporter/rom_info.py new file mode 100644 index 000000000..3edc8b0f9 --- /dev/null +++ b/OTRExporter/rom_info.py @@ -0,0 +1,87 @@ +from enum import Enum +from tabnanny import check +import struct + +class Checksums(Enum): + OOT_NTSC_10 = "EC7011B7" + OOT_NTSC_11 = "D43DA81F" + OOT_NTSC_12 = "693BA2AE" + OOT_PAL_10 = "B044B569" + OOT_PAL_11 = "B2055FBD" + OOT_NTSC_JP_GC_CE = "F7F52DB8" + OOT_NTSC_JP_GC = "F611F4BA" + OOT_NTSC_US_GC = "F3DD35BA" + OOT_PAL_GC = "09465AC3" + OOT_NTSC_JP_MQ = "F43B45BA" + OOT_NTSC_US_MQ = "F034001A" + OOT_PAL_MQ = "1D4136F3" + OOT_PAL_GC_DBG1 = "871E1C92" + OOT_PAL_GC_DBG2 = "87121EFE" + OOT_PAL_GC_MQ_DBG = "917D18F6" + OOT_IQUE_TW = "3D81FB3E" + OOT_IQUE_CN = "B1E1E07B" + OOT_UNKNOWN = "FFFFFFFF" + + @classmethod + def has_value(self, value): + return value in self._value2member_map_ + +class RomVersion: + def __init__(self, file_table_path, file_table_off, xml_ver): + self.file_table_off = file_table_off + self.xml_ver = xml_ver + with open(file_table_path, 'r') as f: + self.file_table = [line.strip('\n') for line in f] + +ROM_INFO_TABLE = dict() +ROM_INFO_TABLE[Checksums.OOT_PAL_GC] = RomVersion("CFG/filelists/gamecube_pal.txt", 0x7170, "GC_NMQ_PAL_F") +ROM_INFO_TABLE[Checksums.OOT_PAL_GC_DBG1] = RomVersion("CFG/filelists/dbg.txt", 0x12F70, "GC_NMQ_D") + +class RomDmaEntry: + def __init__(self, rom, i): + + off = rom.version.file_table_off + 16 * i + + (self.virtStart, \ + self.virtEnd, \ + self.physStart, \ + self.physEnd) = struct.unpack('>IIII', rom.rom_data[off:off+4*4]) + + self.compressed = self.physEnd != 0 + self.size = self.physEnd - self.physStart \ + if self.compressed \ + else self.virtEnd - self.virtStart + self.name = rom.version.file_table[i] + + +class Z64Rom: + def __init__(self, file_path): + self.file_path = file_path + with open(file_path, 'rb') as f: + self.rom_data = f.read() + + self.is_valid = len(self.rom_data) > 20 * 1024 * 1024 + + if not self.is_valid: + return + + # get checkum + checksum_str = self.rom_data[16:16+4].hex().upper() + self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.OOT_UNKNOWN + + if self.checksum == Checksums.OOT_UNKNOWN: + self.is_valid = False + return + + # get rom version + self.version = ROM_INFO_TABLE[self.checksum] + + def getDmaEntryByIndex(self, i): + return RomDmaEntry(self, i) + + def readDmaEntry(self, entry): + return self.rom_data[entry.physStart:entry.physStart + entry.size] + + @staticmethod + def isValidRom(rom_path): + return Z64Rom(rom_path).is_valid diff --git a/OTRGui/src/game/game.cpp b/OTRGui/src/game/game.cpp index 88bd7201f..022a7788e 100644 --- a/OTRGui/src/game/game.cpp +++ b/OTRGui/src/game/game.cpp @@ -67,13 +67,13 @@ void OTRGame::init(){ mat.shader = shader; } - if(fs::exists("soh.exe") && !fs::exists("oot.otr")) { + if((fs::exists("soh.exe") || fs::exists("soh.elf")) && !fs::exists("oot.otr")) { hide_second_btn = true; sohFolder = "."; } } -void ExtractRom() +void ExtractRom() { WriteResult result; @@ -188,7 +188,7 @@ void OTRGame::draw() { sohFolder = path; } - if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nMaster Quest or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) { + if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nGameCube PAL or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) { const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FILE); if (path != NULLSTR) { const std::string patched_n64 = std::string(patched_rom); @@ -220,4 +220,4 @@ void setCurrentStep(const std::string& step) { void OTRGame::exit(){ -} \ No newline at end of file +} diff --git a/README.md b/README.md index 1cbe0cd3f..8a4538e2a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The Ship does not include assets and as such requires a prior copy of the game t ## Quick Start -1) Download The Ship of Harkinian from Discord. +1) Download The Ship of Harkinian from [Discord](https://discord.com/invite/BtBmd55HVH). 2) Requires a supported copy of the game (See supported games below). 3) Use the OTRGui to generate an `oot.otr` archive file. 4) Launch `soh.exe` @@ -18,9 +18,9 @@ Build team: `zelda@srd022j` Build date: `03-02-21 00:49:18` (year-month-day) sha1: cee6bc3c2a634b41728f2af8da54d9bf8cc14099 ``` -Ocarina of Time Pal Gamecube +Ocarina of Time PAL GameCube ``` -sha1: d0c95b2cb3c6682a171db267932af7af8cf5fa82 +sha1: 0227d7c0074f2d0ac935631990da8ec5914597b4 ``` Congratulations, you are now sailing with the Ship of Harkinian! Have fun! @@ -44,7 +44,7 @@ If you still cannot get the tool to work, join our [Discord Server](https://disc ### Running The Ship of Harkinian -Launch the game. If the window immediately closes, or if there are visual artifacts, you may have selected the wrong rom in the OTRGui tool. +Launch the game. If the window immediately closes, or if there are visual artifacts, you may have selected the wrong rom in the OTRGui tool. Currently, DirectX 11 and OpenGL is supported. Change the renderer by opening the `shipofharkinian.ini` configuration file in notepad and add `sdl` to `gfx backend` for OpenGL or leave blank for DirectX. @@ -67,39 +67,45 @@ Refer to the [building instructions](BUILDING.md) to compile SoH. ## The Harbour Masters Are... - Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer - Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer - Louist103 | Developer - Save System Programmer and General Programmer - Emil | Developer - Fast3D Programmer - m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer - MelonSpeedruns | Developer - General Programmer - Rozlette | Developer - General Programmer - JoshDuMan | Developer - General Programmer - KiritoDev/Lywx | Developer - General Programmer - Theo3 | Developer - General Programmer - Random06457 | Developer - Linux Build + Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer + Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer + Louist103 | Developer - Save System Programmer and General Programmer + Emil | Developer - Fast3D Programmer + m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer + MelonSpeedruns | Developer - General Programmer + Rozlette | Developer - General Programmer + JoshDuMan | Developer - General Programmer + KiritoDev/Lywx | Developer - General Programmer + Theo3 | Developer - General Programmer + Random06457 | Developer - Linux Build ## Special Thanks - Decomp & ZAPD | Made this project even possible in the first place! - MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation. - Rrrrry123 | Speedbunner, encouragement, and community moderation - Fierce deity | Encouragement and community moderation - mzxrules | For his contributions to decomp - zel. | For his contributions to decomp - Aloxado | Developer - General Programmer - MegaMech | Developer - General Programmer - Revo | Tester - GCC support and General Testing - zfg | Tester - General Testing - Horseless Headman | Tester - General Testing - Steven Pritchett | Tester - General Testing - Trenton May | Tester - General Testing - Zeldaboy14 | Tester - General Testing, encouragement, and community moderation - Koby Howell | Tester - General Testing - Logg | Tester - General Testing - Taylor Daley | Graphic Design - Can't Sleep | Graphic Design - MicTheMicrophone | Voice actor for the King - Amphibibro | Voice actor for Link - -Lemons + Decomp & ZAPD | Made this project even possible in the first place! + MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation. + Rrrrry123 | Speedbunner, encouragement, and community moderation + Fierce deity | Encouragement and community moderation + mzxrules | For his contributions to decomp + zel. | For his contributions to decomp + Aloxado | Developer - General Programmer + MegaMech | Developer - General Programmer + Revo | Tester - GCC support and General Testing + zfg | Tester - General Testing + Horseless Headman | Tester - General Testing + Steven Pritchett | Tester - General Testing + Trenton May | Tester - General Testing + Zeldaboy14 | Tester - General Testing, encouragement, and community moderation + Koby Howell | Tester - General Testing + Logg | Tester - General Testing + Taylor Daley | Graphic Design + Can't Sleep | Graphic Design + +## Video Credits + Kenix | Producer / Writer + rainbow_fash | Executive Producer + TheLegendOfXela | Editor + MicTheMicrophone | Gwonam / The King + Amphibibro | Link + AceHeart | Zelda + +###### Lemons \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/CollisionExporter.cpp b/ZAPDTR/ExporterTest/CollisionExporter.cpp index e00f5c1b0..4ab8a62cd 100644 --- a/ZAPDTR/ExporterTest/CollisionExporter.cpp +++ b/ZAPDTR/ExporterTest/CollisionExporter.cpp @@ -1,6 +1,6 @@ #include "CollisionExporter.h" -void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] fs::path outPath, +void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath, BinaryWriter* writer) { ZCollisionHeader* col = (ZCollisionHeader*)res; diff --git a/ZAPDTR/ExporterTest/CollisionExporter.h b/ZAPDTR/ExporterTest/CollisionExporter.h index 5f48e6557..1dc50634e 100644 --- a/ZAPDTR/ExporterTest/CollisionExporter.h +++ b/ZAPDTR/ExporterTest/CollisionExporter.h @@ -6,5 +6,5 @@ class ExporterExample_Collision : public ZResourceExporter { public: - void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override; + void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; }; \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/RoomExporter.cpp b/ZAPDTR/ExporterTest/RoomExporter.cpp index 6c5552d8f..bc7ef3727 100644 --- a/ZAPDTR/ExporterTest/RoomExporter.cpp +++ b/ZAPDTR/ExporterTest/RoomExporter.cpp @@ -20,7 +20,7 @@ #include "ZRoom/Commands/SetTimeSettings.h" #include "ZRoom/Commands/SetWind.h" -void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter* writer) +void ExporterExample_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { ZRoom* room = dynamic_cast(res); diff --git a/ZAPDTR/ExporterTest/RoomExporter.h b/ZAPDTR/ExporterTest/RoomExporter.h index ee531dc87..d8f7eae01 100644 --- a/ZAPDTR/ExporterTest/RoomExporter.h +++ b/ZAPDTR/ExporterTest/RoomExporter.h @@ -6,5 +6,5 @@ class ExporterExample_Room : public ZResourceExporter { public: - void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override; + void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; }; \ No newline at end of file diff --git a/ZAPDTR/ExporterTest/TextureExporter.cpp b/ZAPDTR/ExporterTest/TextureExporter.cpp index 6488bed3a..58d0964d3 100644 --- a/ZAPDTR/ExporterTest/TextureExporter.cpp +++ b/ZAPDTR/ExporterTest/TextureExporter.cpp @@ -1,7 +1,7 @@ #include "TextureExporter.h" #include "../ZAPD/ZFile.h" -void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] fs::path outPath, +void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath, BinaryWriter* writer) { ZTexture* tex = (ZTexture*)res; diff --git a/ZAPDTR/ExporterTest/TextureExporter.h b/ZAPDTR/ExporterTest/TextureExporter.h index 41c4e79be..f3922cac1 100644 --- a/ZAPDTR/ExporterTest/TextureExporter.h +++ b/ZAPDTR/ExporterTest/TextureExporter.h @@ -7,5 +7,5 @@ class ExporterExample_Texture : public ZResourceExporter { public: - void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override; + void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; }; \ No newline at end of file diff --git a/ZAPDTR/Makefile b/ZAPDTR/Makefile index 2b47a8039..13f0dce20 100644 --- a/ZAPDTR/Makefile +++ b/ZAPDTR/Makefile @@ -44,7 +44,8 @@ ifneq ($(DEPRECATION_ON),0) endif # CXXFLAGS += -DTEXTURE_DEBUG -LDFLAGS := -lm -ldl -lpng +LDFLAGS := -lm -ldl -lpng \ + -L../external -L../libultraship -lz -lbz2 -pthread -lpulse -lultraship -lstorm -lSDL2 -lGLEW -lGL -lX11 # Use LLD if available. Set LLD=0 to not use it ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0) @@ -59,9 +60,9 @@ UNAME := $(shell uname) UNAMEM := $(shell uname -m) ifneq ($(UNAME), Darwin) LDFLAGS += -Wl,-export-dynamic -lstdc++fs - EXPORTERS := -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive + EXPORTERS := -Wl,--whole-archive ../OTRExporter/OTRExporter/OTRExporter.a -Wl,--no-whole-archive else - EXPORTERS := -Wl,-force_load ExporterTest/ExporterTest.a + EXPORTERS := -Wl,-force_load ../OTRExporter/OTRExporter/OTRExporter.a ifeq ($(UNAMEM),arm64) ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0) LDFLAGS += -L $(shell brew --prefix)/lib diff --git a/ZAPDTR/ZAPD/Main.cpp b/ZAPDTR/ZAPD/Main.cpp index dd53b9c67..65a65fea6 100644 --- a/ZAPDTR/ZAPD/Main.cpp +++ b/ZAPDTR/ZAPD/Main.cpp @@ -10,7 +10,7 @@ #include "ZFile.h" #include "ZTexture.h" -#if !defined(_MSC_VER) && !defined(__CYGWIN__) +#ifdef __linux__ #include #include #include @@ -28,6 +28,31 @@ //extern const char gBuildHash[]; const char gBuildHash[] = ""; +// LINUX_TODO: remove, those are because of soh <-> lus dependency problems +float divisor_num = 0.0f; + +extern "C" void Audio_SetGameVolume(int player_id, float volume) +{ + +} + + +extern "C" int ResourceMgr_OTRSigCheck(char* imgData) +{ + +} + +void DebugConsole_SaveCVars() +{ + +} + +void DebugConsole_LoadCVars() +{ + +} + + bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath, ZFileMode fileMode, int workerID); @@ -38,7 +63,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM volatile int numWorkersLeft = 0; -#if !defined(_MSC_VER) && !defined(__CYGWIN__) +#ifdef __linux__ #define ARRAY_COUNT(arr) (sizeof(arr) / sizeof(arr[0])) void ErrorHandler(int sig) { @@ -196,7 +221,7 @@ int main(int argc, char* argv[]) } else if (arg == "-eh") // Enable Error Handler { - #if !defined(_MSC_VER) && !defined(__CYGWIN__) +#ifdef __linux__ signal(SIGSEGV, ErrorHandler); signal(SIGABRT, ErrorHandler); #else @@ -302,7 +327,7 @@ int main(int argc, char* argv[]) ctpl::thread_pool pool(num_threads / 2); bool parseSuccessful; - + auto start = std::chrono::steady_clock::now(); int fileListSize = fileList.size(); Globals::Instance->singleThreaded = false; @@ -453,6 +478,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM numWorkersLeft--; } + return 0; } bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath, diff --git a/ZAPDTR/ZAPD/OutputFormatter.cpp b/ZAPDTR/ZAPD/OutputFormatter.cpp index 7fac434b2..362ef98fc 100644 --- a/ZAPDTR/ZAPD/OutputFormatter.cpp +++ b/ZAPDTR/ZAPD/OutputFormatter.cpp @@ -96,7 +96,7 @@ int OutputFormatter::Write(const std::string& buf) return Write(buf.data(), buf.size()); } -__declspec(thread) OutputFormatter* OutputFormatter::Instance; +thread_local OutputFormatter* OutputFormatter::Instance; int OutputFormatter::WriteStatic(const char* buf, int count) { diff --git a/ZAPDTR/ZAPD/OutputFormatter.h b/ZAPDTR/ZAPD/OutputFormatter.h index f008df2cb..03abfdb96 100644 --- a/ZAPDTR/ZAPD/OutputFormatter.h +++ b/ZAPDTR/ZAPD/OutputFormatter.h @@ -25,7 +25,7 @@ private: void Flush(); - static __declspec(thread) OutputFormatter* Instance; + static thread_local OutputFormatter* Instance; static int WriteStatic(const char* buf, int count); public: diff --git a/ZAPDTR/ZAPD/ZDisplayList.cpp b/ZAPDTR/ZAPD/ZDisplayList.cpp index 93269b65e..406245b33 100644 --- a/ZAPDTR/ZAPD/ZDisplayList.cpp +++ b/ZAPDTR/ZAPD/ZDisplayList.cpp @@ -15,6 +15,124 @@ #include "WarningHandler.h" #include "gfxd.h" + +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 + +#define G_RM_FOG_SHADE_A 0xC8000000 +#define G_RM_FOG_PRIM_A 0xC4000000 +#define G_RM_PASS 0x0C080000 +#define G_RM_AA_ZB_OPA_SURF 0x442078 +#define G_RM_AA_ZB_OPA_SURF2 0x112078 +#define G_RM_AA_ZB_XLU_SURF 0x4049D8 +#define G_RM_AA_ZB_XLU_SURF2 0x1049D8 +#define G_RM_AA_ZB_OPA_DECAL 0x442D58 +#define G_RM_AA_ZB_OPA_DECAL2 0x112D58 +#define G_RM_AA_ZB_XLU_DECAL 0x404DD8 +#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8 +#define G_RM_AA_ZB_OPA_INTER 0x442478 +#define G_RM_AA_ZB_OPA_INTER2 0x112478 +#define G_RM_AA_ZB_XLU_INTER 0x4045D8 +#define G_RM_AA_ZB_XLU_INTER2 0x1045D8 +#define G_RM_AA_ZB_XLU_LINE 0x407858 +#define G_RM_AA_ZB_XLU_LINE2 0x107858 +#define G_RM_AA_ZB_DEC_LINE 0x407F58 +#define G_RM_AA_ZB_DEC_LINE2 0x107F58 +#define G_RM_AA_ZB_TEX_EDGE 0x443078 +#define G_RM_AA_ZB_TEX_EDGE2 0x113078 +#define G_RM_AA_ZB_TEX_INTER 0x443478 +#define G_RM_AA_ZB_TEX_INTER2 0x113478 +#define G_RM_AA_ZB_SUB_SURF 0x442878 +#define G_RM_AA_ZB_SUB_SURF2 0x112278 +#define G_RM_AA_ZB_PCL_SURF 0x40007B +#define G_RM_AA_ZB_PCL_SURF2 0x10007B +#define G_RM_AA_ZB_OPA_TERR 0x402078 +#define G_RM_AA_ZB_OPA_TERR2 0x102078 +#define G_RM_AA_ZB_TEX_TERR 0x403078 +#define G_RM_AA_ZB_TEX_TERR2 0x103078 +#define G_RM_AA_ZB_SUB_TERR 0x402278 +#define G_RM_AA_ZB_SUB_TERR2 0x102278 +#define G_RM_RA_ZB_OPA_SURF 0x442038 +#define G_RM_RA_ZB_OPA_SURF2 0x112038 +#define G_RM_RA_ZB_OPA_DECAL 0x442D18 +#define G_RM_RA_ZB_OPA_DECAL2 0x112D18 +#define G_RM_RA_ZB_OPA_INTER 0x442438 +#define G_RM_RA_ZB_OPA_INTER2 0x112438 +#define G_RM_AA_OPA_SURF 0x442048 +#define G_RM_AA_OPA_SURF2 0x112048 +#define G_RM_AA_XLU_SURF 0x4041C8 +#define G_RM_AA_XLU_SURF2 0x1041C8 +#define G_RM_AA_XLU_LINE 0x407048 +#define G_RM_AA_XLU_LINE2 0x107048 +#define G_RM_AA_DEC_LINE 0x407248 +#define G_RM_AA_DEC_LINE2 0x107248 +#define G_RM_AA_TEX_EDGE 0x443048 +#define G_RM_AA_TEX_EDGE2 0x113048 +#define G_RM_AA_SUB_SURF 0x442248 +#define G_RM_AA_SUB_SURF2 0x112248 +#define G_RM_AA_PCL_SURF 0x40004B +#define G_RM_AA_PCL_SURF2 0x10004B +#define G_RM_AA_OPA_TERR 0x402048 +#define G_RM_AA_OPA_TERR2 0x102048 +#define G_RM_AA_TEX_TERR 0x403048 +#define G_RM_AA_TEX_TERR2 0x103048 +#define G_RM_AA_SUB_TERR 0x402248 +#define G_RM_AA_SUB_TERR2 0x102248 +#define G_RM_RA_OPA_SURF 0x442008 +#define G_RM_RA_OPA_SURF2 0x112008 +#define G_RM_ZB_OPA_SURF 0x442230 +#define G_RM_ZB_OPA_SURF2 0x112230 +#define G_RM_ZB_XLU_SURF 0x404A50 +#define G_RM_ZB_XLU_SURF2 0x104A50 +#define G_RM_ZB_OPA_DECAL 0x442E10 +#define G_RM_ZB_OPA_DECAL2 0x112E10 +#define G_RM_ZB_XLU_DECAL 0x404E50 +#define G_RM_ZB_XLU_DECAL2 0x104E50 +#define G_RM_ZB_CLD_SURF 0x404B50 +#define G_RM_ZB_CLD_SURF2 0x104B50 +#define G_RM_ZB_OVL_SURF 0x404F50 +#define G_RM_ZB_OVL_SURF2 0x104F50 +#define G_RM_ZB_PCL_SURF 0x0C080233 +#define G_RM_ZB_PCL_SURF2 0x03020233 +#define G_RM_OPA_SURF 0x0C084000 +#define G_RM_OPA_SURF2 0x03024000 +#define G_RM_XLU_SURF 0x00404200 +#define G_RM_XLU_SURF2 0x00104240 +#define G_RM_CLD_SURF 0x00404340 +#define G_RM_CLD_SURF2 0x00104340 +#define G_RM_TEX_EDGE 0x0C087008 +#define G_RM_TEX_EDGE2 0x03027008 +#define G_RM_PCL_SURF 0x0C084203 +#define G_RM_PCL_SURF2 0x03024203 +#define G_RM_ADD 0x04484340 +#define G_RM_ADD2 0x01124340 +#define G_RM_NOOP 0x00000000 +#define G_RM_NOOP2 0x00000000 +#define G_RM_VISCVG 0x0C844040 +#define G_RM_VISCVG2 0x03214040 +#define G_RM_OPA_CI 0x0C080000 +#define G_RM_OPA_CI2 0x03020000 + +#define AA_EN 0x8 +#define Z_CMP 0x10 +#define Z_UPD 0x20 +#define IM_RD 0x40 +#define CLR_ON_CVG 0x80 +#define CVG_DST_CLAMP 0 +#define CVG_DST_WRAP 0x100 +#define CVG_DST_FULL 0x200 +#define CVG_DST_SAVE 0x300 +#define ZMODE_OPA 0 +#define ZMODE_INTER 0x400 +#define ZMODE_XLU 0x800 +#define ZMODE_DEC 0xc00 +#define CVG_X_ALPHA 0x1000 +#define ALPHA_CVG_SEL 0x2000 +#define FORCE_BL 0x4000 +#define TEX_EDGE 0x0000 + REGISTER_ZFILENODE(DList, ZDisplayList); ZDisplayList::ZDisplayList(ZFile* nParent) : ZResource(nParent) diff --git a/ZAPDTR/ZAPD/ZDisplayList.h b/ZAPDTR/ZAPD/ZDisplayList.h index 96808315d..f3828cc79 100644 --- a/ZAPDTR/ZAPD/ZDisplayList.h +++ b/ZAPDTR/ZAPD/ZDisplayList.h @@ -166,122 +166,6 @@ enum class OoTSegments FrameBuffer = 16, }; -#define G_MDSFT_ALPHACOMPARE 0 -#define G_MDSFT_ZSRCSEL 2 -#define G_MDSFT_RENDERMODE 3 -#define G_MDSFT_BLENDER 16 - -#define G_RM_FOG_SHADE_A 0xC8000000 -#define G_RM_FOG_PRIM_A 0xC4000000 -#define G_RM_PASS 0x0C080000 -#define G_RM_AA_ZB_OPA_SURF 0x442078 -#define G_RM_AA_ZB_OPA_SURF2 0x112078 -#define G_RM_AA_ZB_XLU_SURF 0x4049D8 -#define G_RM_AA_ZB_XLU_SURF2 0x1049D8 -#define G_RM_AA_ZB_OPA_DECAL 0x442D58 -#define G_RM_AA_ZB_OPA_DECAL2 0x112D58 -#define G_RM_AA_ZB_XLU_DECAL 0x404DD8 -#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8 -#define G_RM_AA_ZB_OPA_INTER 0x442478 -#define G_RM_AA_ZB_OPA_INTER2 0x112478 -#define G_RM_AA_ZB_XLU_INTER 0x4045D8 -#define G_RM_AA_ZB_XLU_INTER2 0x1045D8 -#define G_RM_AA_ZB_XLU_LINE 0x407858 -#define G_RM_AA_ZB_XLU_LINE2 0x107858 -#define G_RM_AA_ZB_DEC_LINE 0x407F58 -#define G_RM_AA_ZB_DEC_LINE2 0x107F58 -#define G_RM_AA_ZB_TEX_EDGE 0x443078 -#define G_RM_AA_ZB_TEX_EDGE2 0x113078 -#define G_RM_AA_ZB_TEX_INTER 0x443478 -#define G_RM_AA_ZB_TEX_INTER2 0x113478 -#define G_RM_AA_ZB_SUB_SURF 0x442878 -#define G_RM_AA_ZB_SUB_SURF2 0x112278 -#define G_RM_AA_ZB_PCL_SURF 0x40007B -#define G_RM_AA_ZB_PCL_SURF2 0x10007B -#define G_RM_AA_ZB_OPA_TERR 0x402078 -#define G_RM_AA_ZB_OPA_TERR2 0x102078 -#define G_RM_AA_ZB_TEX_TERR 0x403078 -#define G_RM_AA_ZB_TEX_TERR2 0x103078 -#define G_RM_AA_ZB_SUB_TERR 0x402278 -#define G_RM_AA_ZB_SUB_TERR2 0x102278 -#define G_RM_RA_ZB_OPA_SURF 0x442038 -#define G_RM_RA_ZB_OPA_SURF2 0x112038 -#define G_RM_RA_ZB_OPA_DECAL 0x442D18 -#define G_RM_RA_ZB_OPA_DECAL2 0x112D18 -#define G_RM_RA_ZB_OPA_INTER 0x442438 -#define G_RM_RA_ZB_OPA_INTER2 0x112438 -#define G_RM_AA_OPA_SURF 0x442048 -#define G_RM_AA_OPA_SURF2 0x112048 -#define G_RM_AA_XLU_SURF 0x4041C8 -#define G_RM_AA_XLU_SURF2 0x1041C8 -#define G_RM_AA_XLU_LINE 0x407048 -#define G_RM_AA_XLU_LINE2 0x107048 -#define G_RM_AA_DEC_LINE 0x407248 -#define G_RM_AA_DEC_LINE2 0x107248 -#define G_RM_AA_TEX_EDGE 0x443048 -#define G_RM_AA_TEX_EDGE2 0x113048 -#define G_RM_AA_SUB_SURF 0x442248 -#define G_RM_AA_SUB_SURF2 0x112248 -#define G_RM_AA_PCL_SURF 0x40004B -#define G_RM_AA_PCL_SURF2 0x10004B -#define G_RM_AA_OPA_TERR 0x402048 -#define G_RM_AA_OPA_TERR2 0x102048 -#define G_RM_AA_TEX_TERR 0x403048 -#define G_RM_AA_TEX_TERR2 0x103048 -#define G_RM_AA_SUB_TERR 0x402248 -#define G_RM_AA_SUB_TERR2 0x102248 -#define G_RM_RA_OPA_SURF 0x442008 -#define G_RM_RA_OPA_SURF2 0x112008 -#define G_RM_ZB_OPA_SURF 0x442230 -#define G_RM_ZB_OPA_SURF2 0x112230 -#define G_RM_ZB_XLU_SURF 0x404A50 -#define G_RM_ZB_XLU_SURF2 0x104A50 -#define G_RM_ZB_OPA_DECAL 0x442E10 -#define G_RM_ZB_OPA_DECAL2 0x112E10 -#define G_RM_ZB_XLU_DECAL 0x404E50 -#define G_RM_ZB_XLU_DECAL2 0x104E50 -#define G_RM_ZB_CLD_SURF 0x404B50 -#define G_RM_ZB_CLD_SURF2 0x104B50 -#define G_RM_ZB_OVL_SURF 0x404F50 -#define G_RM_ZB_OVL_SURF2 0x104F50 -#define G_RM_ZB_PCL_SURF 0x0C080233 -#define G_RM_ZB_PCL_SURF2 0x03020233 -#define G_RM_OPA_SURF 0x0C084000 -#define G_RM_OPA_SURF2 0x03024000 -#define G_RM_XLU_SURF 0x00404200 -#define G_RM_XLU_SURF2 0x00104240 -#define G_RM_CLD_SURF 0x00404340 -#define G_RM_CLD_SURF2 0x00104340 -#define G_RM_TEX_EDGE 0x0C087008 -#define G_RM_TEX_EDGE2 0x03027008 -#define G_RM_PCL_SURF 0x0C084203 -#define G_RM_PCL_SURF2 0x03024203 -#define G_RM_ADD 0x04484340 -#define G_RM_ADD2 0x01124340 -#define G_RM_NOOP 0x00000000 -#define G_RM_NOOP2 0x00000000 -#define G_RM_VISCVG 0x0C844040 -#define G_RM_VISCVG2 0x03214040 -#define G_RM_OPA_CI 0x0C080000 -#define G_RM_OPA_CI2 0x03020000 - -#define AA_EN 0x8 -#define Z_CMP 0x10 -#define Z_UPD 0x20 -#define IM_RD 0x40 -#define CLR_ON_CVG 0x80 -#define CVG_DST_CLAMP 0 -#define CVG_DST_WRAP 0x100 -#define CVG_DST_FULL 0x200 -#define CVG_DST_SAVE 0x300 -#define ZMODE_OPA 0 -#define ZMODE_INTER 0x400 -#define ZMODE_XLU 0x800 -#define ZMODE_DEC 0xc00 -#define CVG_X_ALPHA 0x1000 -#define ALPHA_CVG_SEL 0x2000 -#define FORCE_BL 0x4000 -#define TEX_EDGE 0x0000 class ZDisplayList : public ZResource { diff --git a/ZAPDTR/ZAPD/ZLimb.h b/ZAPDTR/ZAPD/ZLimb.h index 53a414329..5de5276e9 100644 --- a/ZAPDTR/ZAPD/ZLimb.h +++ b/ZAPDTR/ZAPD/ZLimb.h @@ -25,19 +25,19 @@ public: ZLimbSkinType skinSegmentType = ZLimbSkinType::SkinType_0; // Skin only segptr_t skinSegment = 0; // Skin only - Struct_800A5E28 segmentStruct; // Skin only + Struct_800A5E28 segmentStruct = {0}; // Skin only // Legacy only - float legTransX, legTransY, legTransZ; // Vec3f - uint16_t rotX, rotY, rotZ; // Vec3s - segptr_t childPtr; // LegacyLimb* - segptr_t siblingPtr; // LegacyLimb* + float legTransX = 0, legTransY = 0, legTransZ = 0; // Vec3f + uint16_t rotX = 0, rotY = 0, rotZ = 0; // Vec3s + segptr_t childPtr = 0; // LegacyLimb* + segptr_t siblingPtr = 0; // LegacyLimb* segptr_t dListPtr = 0; segptr_t dList2Ptr = 0; // LOD and Curve Only - int16_t transX, transY, transZ; - uint8_t childIndex, siblingIndex; + int16_t transX = 0, transY = 0, transZ = 0; + uint8_t childIndex = 0, siblingIndex = 0; ZLimb(ZFile* nParent); diff --git a/ZAPDTR/ZAPDUtils/Utils/BitConverter.h b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h index e672b97c2..708d4b537 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BitConverter.h +++ b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h @@ -3,6 +3,7 @@ #include #include #include +#include class BitConverter { diff --git a/ZAPDTR/ZAPDUtils/Utils/Directory.h b/ZAPDTR/ZAPDUtils/Utils/Directory.h index b1ce49699..1ced139be 100644 --- a/ZAPDTR/ZAPDUtils/Utils/Directory.h +++ b/ZAPDTR/ZAPDUtils/Utils/Directory.h @@ -52,7 +52,7 @@ public: for (auto& p : fs::recursive_directory_iterator(dir)) { if (!p.is_directory()) - lst.push_back(p.path().string()); + lst.push_back(p.path().generic_string()); } } diff --git a/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp b/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp index e2b646fd9..070fffa63 100644 --- a/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp +++ b/ZAPDTR/ZAPDUtils/Utils/StringHelper.cpp @@ -3,6 +3,10 @@ #pragma optimize("2", on) #define _CRT_SECURE_NO_WARNINGS +#ifndef _MSC_VER +#define vsprintf_s vsprintf +#endif + std::vector StringHelper::Split(std::string s, const std::string& delimiter) { std::vector result; @@ -44,7 +48,7 @@ std::string StringHelper::Replace(std::string str, const std::string& from, while (start_pos != std::string::npos) { - str.replace(start_pos, from.length(), to); + str.replace(start_pos, from.length(), to); start_pos = str.find(from); } diff --git a/external/libGLEW.a b/external/libGLEW.a new file mode 100644 index 0000000000000000000000000000000000000000..b36baf085d4e043c53d113e2d767e53625353ac6 GIT binary patch literal 837914 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 E4_aU@yZ`_I literal 0 HcmV?d00001 diff --git a/external/libstorm.a b/external/libstorm.a new file mode 100644 index 0000000000000000000000000000000000000000..d652492b417d4261624d7409591e7ba438e44cc3 GIT binary patch literal 838950 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೉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 z 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 z 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 anim->rotationIndices.reserve(rotIndCnt); - for (int i = 0; i < rotIndCnt; i++) + for (size_t i = 0; i < rotIndCnt; i++) { uint16_t x = reader->ReadUInt16(); uint16_t y = reader->ReadUInt16(); diff --git a/libultraship/libultraship/Archive.cpp b/libultraship/libultraship/Archive.cpp index 41c6649f8..1e8f8d597 100644 --- a/libultraship/libultraship/Archive.cpp +++ b/libultraship/libultraship/Archive.cpp @@ -7,7 +7,7 @@ #include namespace Ship { - Archive::Archive(const std::string& MainPath, bool enableWriting) : Archive(MainPath, "", enableWriting) + Archive::Archive(const std::string& MainPath, bool enableWriting) : Archive(MainPath, "", enableWriting) { mainMPQ = nullptr; } @@ -28,7 +28,7 @@ namespace Ship { std::shared_ptr Archive::CreateArchive(const std::string& archivePath, int fileCapacity) { - Archive* archive = new Archive(archivePath, true); + auto archive = std::make_shared(archivePath, true); TCHAR* t_filename = new TCHAR[archivePath.size() + 1]; t_filename[archivePath.size()] = 0; @@ -37,10 +37,15 @@ namespace Ship { bool success = SFileCreateArchive(t_filename, MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, fileCapacity, &archive->mainMPQ); int error = GetLastError(); - if (success) { + delete[] t_filename; + + if (success) + { archive->mpqHandles[archivePath] = archive->mainMPQ; - return std::make_shared(*archive); - } else { + return archive; + } + else + { SPDLOG_ERROR("({}) We tried to create an archive, but it has fallen and cannot get up."); return nullptr; } @@ -49,11 +54,16 @@ namespace Ship { std::shared_ptr Archive::LoadFile(const std::string& filePath, bool includeParent, std::shared_ptr FileToLoad) { HANDLE fileHandle = NULL; + if (FileToLoad == nullptr) { + FileToLoad = std::make_shared(); + FileToLoad->path = filePath; + } + if (!SFileOpenFileEx(mainMPQ, filePath.c_str(), 0, &fileHandle)) { SPDLOG_ERROR("({}) Failed to open file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str()); std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->bHasLoadError = true; - return nullptr; + return FileToLoad; } DWORD dwFileSize = SFileGetFileSize(fileHandle, 0); @@ -67,18 +77,13 @@ namespace Ship { } std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->bHasLoadError = true; - return nullptr; + return FileToLoad; } if (!SFileCloseFile(fileHandle)) { SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str()); } - if (FileToLoad == nullptr) { - FileToLoad = std::make_shared(); - FileToLoad->path = filePath; - } - std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->parent = includeParent ? shared_from_this() : nullptr; FileToLoad->buffer = fileData; @@ -92,6 +97,11 @@ namespace Ship { HANDLE fileHandle = NULL; HANDLE mpqHandle = NULL; + if (FileToLoad == nullptr) { + FileToLoad = std::make_shared(); + FileToLoad->path = filePath; + } + for(auto [path, handle] : mpqHandles) { if (SFileOpenFileEx(mpqHandle, filePath.c_str(), 0, &fileHandle)) { std::unique_lock Lock(FileToLoad->FileLoadMutex); @@ -116,18 +126,13 @@ namespace Ship { } std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->bHasLoadError = true; - return nullptr; + return FileToLoad; } if (!SFileCloseFile(fileHandle)) { SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str()); } - if (FileToLoad == nullptr) { - FileToLoad = std::make_shared(); - FileToLoad->path = filePath; - } - std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->parent = includeParent ? shared_from_this() : nullptr; FileToLoad->buffer = fileData; @@ -139,13 +144,16 @@ namespace Ship { bool Archive::AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize) { HANDLE hFile; - +#ifdef _WIN32 SYSTEMTIME sysTime; GetSystemTime(&sysTime); FILETIME t; SystemTimeToFileTime(&sysTime, &t); ULONGLONG stupidHack = static_cast(t.dwHighDateTime) << (sizeof(t.dwHighDateTime) * 8) | t.dwLowDateTime; - +#else + time_t stupidHack; + time(&stupidHack); +#endif if (!SFileCreateFile(mainMPQ, path.c_str(), stupidHack, dwFileSize, 0, MPQ_FILE_COMPRESS, &hFile)) { SPDLOG_ERROR("({}) Failed to create file of {} bytes {} in archive {}", GetLastError(), dwFileSize, path.c_str(), MainPath.c_str()); return false; @@ -181,7 +189,7 @@ namespace Ship { SPDLOG_ERROR("({}) Failed to remove file {} in archive {}", GetLastError(), path.c_str(), MainPath.c_str()); return false; } - + return true; } @@ -201,7 +209,7 @@ namespace Ship { SFILE_FIND_DATA findContext; HANDLE hFind; - + hFind = SFileFindFirstFile(mainMPQ, searchMask.c_str(), &findContext, nullptr); //if (hFind && GetLastError() != ERROR_NO_MORE_FILES) { if (hFind != nullptr) { @@ -245,7 +253,7 @@ namespace Ship { auto start = std::chrono::steady_clock::now(); auto lst = ListFiles(filename); - + for (const auto& item : lst) { if (item.cFileName == filename) { result = true; @@ -267,7 +275,7 @@ namespace Ship { return LoadMainMPQ(enableWriting, genCRCMap) && LoadPatchMPQs(); } - bool Archive::Unload() + bool Archive::Unload() { bool success = true; for (const auto& mpqHandle : mpqHandles) { @@ -302,11 +310,16 @@ namespace Ship { bool Archive::LoadMainMPQ(bool enableWriting, bool genCRCMap) { HANDLE mpqHandle = NULL; +#ifdef _WIN32 + std::wstring wfullPath = std::filesystem::absolute(MainPath).wstring(); +#endif std::string fullPath = std::filesystem::absolute(MainPath).string(); - std::wstring wFileName = std::filesystem::absolute(MainPath).wstring(); - - if (!SFileOpenArchive(wFileName.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) { +#ifdef _WIN32 + if (!SFileOpenArchive(wfullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) { +#else + if (!SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) { +#endif SPDLOG_ERROR("({}) Failed to open main mpq file {}.", GetLastError(), fullPath.c_str()); return false; } @@ -340,12 +353,19 @@ namespace Ship { std::wstring wPath = std::filesystem::absolute(path).wstring(); +#ifdef _WIN32 if (!SFileOpenArchive(wPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) { +#else + if (!SFileOpenArchive(fullPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) { +#endif SPDLOG_ERROR("({}) Failed to open patch mpq file {} while applying to {}.", GetLastError(), path.c_str(), MainPath.c_str()); return false; } - +#ifdef _WIN32 if (!SFileOpenPatchArchive(mainMPQ, wPath.c_str(), "", 0)) { +#else + if (!SFileOpenPatchArchive(mainMPQ, fullPath.c_str(), "", 0)) { +#endif SPDLOG_ERROR("({}) Failed to apply patch mpq file {} to main mpq {}.", GetLastError(), path.c_str(), MainPath.c_str()); return false; } diff --git a/libultraship/libultraship/Array.cpp b/libultraship/libultraship/Array.cpp index f256903bf..fdd522c11 100644 --- a/libultraship/libultraship/Array.cpp +++ b/libultraship/libultraship/Array.cpp @@ -51,6 +51,8 @@ namespace Ship data.u16 = reader->ReadUInt16(); break; // OTRTODO: IMPLEMENT OTHER TYPES! + default: + break; } arr->scalars.push_back(data); diff --git a/libultraship/libultraship/ConfigFile.cpp b/libultraship/libultraship/ConfigFile.cpp index 2e9a8cc94..8a0794643 100644 --- a/libultraship/libultraship/ConfigFile.cpp +++ b/libultraship/libultraship/ConfigFile.cpp @@ -72,7 +72,7 @@ namespace Ship { (*this)["WINDOW"]["FULLSCREEN WIDTH"] = std::to_string(1920); (*this)["WINDOW"]["FULLSCREEN HEIGHT"] = std::to_string(1080); (*this)["WINDOW"]["FULLSCREEN"] = std::to_string(false); - (*this)["WINDOW"]["GFX BACKEND"] = "sdl"; + (*this)["WINDOW"]["GFX BACKEND"] = ""; (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CRIGHT)] = std::to_string(0x14D); (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CLEFT)] = std::to_string(0x14B); diff --git a/libultraship/libultraship/ConfigFile.h b/libultraship/libultraship/ConfigFile.h index dcf2a0e4a..b94e22f88 100644 --- a/libultraship/libultraship/ConfigFile.h +++ b/libultraship/libultraship/ConfigFile.h @@ -1,3 +1,6 @@ +#ifndef CONFIG_FILE_H +#define CONFIG_FILE_H + #pragma once #include @@ -29,9 +32,11 @@ namespace Ship { bool CreateDefaultConfig(); private: - mINI::INIFile File; mINI::INIStructure Val; std::weak_ptr Context; std::string Path; + mINI::INIFile File; }; } + +#endif diff --git a/libultraship/libultraship/Cvar.cpp b/libultraship/libultraship/Cvar.cpp index 91788fd48..891ee73af 100644 --- a/libultraship/libultraship/Cvar.cpp +++ b/libultraship/libultraship/Cvar.cpp @@ -1,23 +1,22 @@ -#include "cvar.h" +#include "Cvar.h" #include #include +#include +#include +#include #include -std::map cvars; - -CVar* CVar_GetVar(const char* name) { - std::string key(name); - return cvars.contains(key) ? cvars[key] : nullptr; -} +std::map, std::less<>> cvars; extern "C" CVar* CVar_Get(const char* name) { - return CVar_GetVar(name); + auto it = cvars.find(name); + return (it != cvars.end()) ? it->second.get() : nullptr; } extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) { CVar* cvar = CVar_Get(name); - if (cvar != nullptr) { + if (cvar) { if (cvar->type == CVAR_TYPE_S32) return cvar->value.valueS32; } @@ -28,7 +27,7 @@ extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) { extern "C" float CVar_GetFloat(const char* name, float defaultValue) { CVar* cvar = CVar_Get(name); - if (cvar != nullptr) { + if (cvar) { if (cvar->type == CVAR_TYPE_FLOAT) return cvar->value.valueFloat; } @@ -36,10 +35,10 @@ extern "C" float CVar_GetFloat(const char* name, float defaultValue) { return defaultValue; } -extern "C" char* CVar_GetString(const char* name, char* defaultValue) { +extern "C" const char* CVar_GetString(const char* name, const char* defaultValue) { CVar* cvar = CVar_Get(name); - if (cvar != nullptr) { + if (cvar) { if (cvar->type == CVAR_TYPE_STRING) return cvar->value.valueStr; } @@ -48,53 +47,43 @@ extern "C" char* CVar_GetString(const char* name, char* defaultValue) { } extern "C" void CVar_SetS32(const char* name, s32 value) { - CVar* cvar = CVar_Get(name); + auto& cvar = cvars[name]; if (!cvar) { - cvar = new CVar; - cvars[std::string(name)] = cvar; + cvar = std::make_unique(); } cvar->type = CVAR_TYPE_S32; cvar->value.valueS32 = value; } void CVar_SetFloat(const char* name, float value) { - CVar* cvar = CVar_Get(name); + auto& cvar = cvars[name]; if (!cvar) { - cvar = new CVar; - cvars[std::string(name)] = cvar; + cvar = std::make_unique(); } cvar->type = CVAR_TYPE_FLOAT; cvar->value.valueFloat = value; } -void CVar_SetString(const char* name, char* value) { - CVar* cvar = CVar_Get(name); +void CVar_SetString(const char* name, const char* value) { + auto& cvar = cvars[name]; if (!cvar) { - cvar = new CVar; - cvars[std::string(name)] = cvar; + cvar = std::make_unique(); } cvar->type = CVAR_TYPE_STRING; cvar->value.valueStr = value; } - extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) { - CVar* cvar = CVar_Get(name); - - if (cvar == nullptr) + if (!CVar_Get(name)) CVar_SetS32(name, defaultValue); } extern "C" void CVar_RegisterFloat(const char* name, float defaultValue) { - CVar* cvar = CVar_Get(name); - - if (cvar == nullptr) + if (!CVar_Get(name)) CVar_SetFloat(name, defaultValue); } -extern "C" void CVar_RegisterString(const char* name, char* defaultValue) { - CVar* cvar = CVar_Get(name); - - if (cvar == nullptr) +extern "C" void CVar_RegisterString(const char* name, const char* defaultValue) { + if (!CVar_Get(name)) CVar_SetString(name, defaultValue); } diff --git a/libultraship/libultraship/Cvar.h b/libultraship/libultraship/Cvar.h index a85bb8fd3..e16f4469f 100644 --- a/libultraship/libultraship/Cvar.h +++ b/libultraship/libultraship/Cvar.h @@ -6,13 +6,13 @@ typedef enum CVarType { CVAR_TYPE_S32, CVAR_TYPE_FLOAT, CVAR_TYPE_STRING } CVarType; typedef struct CVar { - char* name; + const char* name; CVarType type; union { s32 valueS32; float valueFloat; - char* valueStr; + const char* valueStr; } value; } CVar; @@ -22,16 +22,15 @@ extern "C" #endif //#include - CVar* CVar_Get(const char* name); s32 CVar_GetS32(const char* name, s32 defaultValue); float CVar_GetFloat(const char* name, float defaultValue); -char* CVar_GetString(const char* name, char* defaultValue); +const char* CVar_GetString(const char* name, const char* defaultValue); void CVar_SetS32(const char* name, s32 value); void CVar_RegisterS32(const char* name, s32 defaultValue); void CVar_RegisterFloat(const char* name, float defaultValue); -void CVar_RegisterString(const char* name, char* defaultValue); +void CVar_RegisterString(const char* name, const char* defaultValue); #ifdef __cplusplus }; @@ -40,10 +39,11 @@ void CVar_RegisterString(const char* name, char* defaultValue); #ifdef __cplusplus #include #include +#include +#include -extern std::map cvars; -CVar* CVar_GetVar(const char* name); +extern std::map, std::less<>> cvars; void CVar_SetFloat(const char* name, float value); -void CVar_SetString(const char* name, char* value); +void CVar_SetString(const char* name, const char* value); #endif #endif diff --git a/libultraship/libultraship/Factories/OTRResourceLoader.cpp b/libultraship/libultraship/Factories/OTRResourceLoader.cpp deleted file mode 100644 index 125e0d9ec..000000000 --- a/libultraship/libultraship/Factories/OTRResourceLoader.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "OTRResourceLoader.h" -#include "OTRMaterialFactory.h" -#include "OTRSceneFactory.h" -#include "OTRCollisionHeaderFactory.h" -#include "OTRDisplayListFactory.h" -#include "OTRPlayerAnimationFactory.h" -#include "OTRSkeletonFactory.h" -#include "OTRSkeletonLimbFactory.h" -#include "OTRAnimationFactory.h" -#include "OTRVtxFactory.h" -#include "OTRCutsceneFactory.h" -#include "OTRArrayFactory.h" -#include "OTRPathFactory.h" - -namespace OtrLib -{ - OTRResource* OTRResourceLoader::LoadResource(BinaryReader* reader) - { - Endianess endianess = (Endianess)reader->ReadByte(); - - // TODO: Setup the binaryreader to use the resource's endianess - - ResourceType resourceType = (ResourceType)reader->ReadUInt32(); - OTRResource* result = nullptr; - - switch (resourceType) - { - case ResourceType::OTRMaterial: - result = OTRMaterialFactory::ReadMaterial(reader); - break; - case ResourceType::OTRRoom: - result = OTRSceneFactory::ReadScene(reader); - break; - case ResourceType::OTRCollisionHeader: - result = OTRCollisionHeaderFactory::ReadCollisionHeader(reader); - break; - case ResourceType::OTRDisplayList: - result = OTRDisplayListFactory::ReadDisplayList(reader); - break; - case ResourceType::OTRPlayerAnimation: - result = OTRPlayerAnimationFactory::ReadPlayerAnimation(reader); - break; - case ResourceType::OTRSkeleton: - result = OTRSkeletonFactory::ReadSkeleton(reader); - break; - case ResourceType::OTRSkeletonLimb: - result = OTRSkeletonLimbFactory::ReadSkeletonLimb(reader); - break; - case ResourceType::OTRVtx: - result = OTRVtxFactory::ReadVtx(reader); - break; - case ResourceType::OTRAnimation: - result = OTRAnimationFactory::ReadAnimation(reader); - break; - case ResourceType::OTRCutscene: - result = OTRCutsceneFactory::ReadCutscene(reader); - break; - case ResourceType::OTRArray: - result = OTRArrayFactory::ReadArray(reader); - break; - case ResourceType::OTRPath: - result = OTRPathFactory::ReadPath(reader); - break; - default: - // RESOURCE TYPE NOT SUPPORTED - break; - } - - return result; - } -} \ No newline at end of file diff --git a/libultraship/libultraship/GameOverlay.cpp b/libultraship/libultraship/GameOverlay.cpp new file mode 100644 index 000000000..042ff980c --- /dev/null +++ b/libultraship/libultraship/GameOverlay.cpp @@ -0,0 +1,225 @@ +#include "GameOverlay.h" + +#include "Cvar.h" +#include "File.h" +#include "Archive.h" +#include "ResourceMgr.h" +#include "SohConsole.h" +#include "SohImGuiImpl.h" +#include "TextureMod.h" +#include "Lib/ImGui/imgui_internal.h" +#include "Utils/StringHelper.h" + +void Ship::GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) { + ImGuiIO& io = ImGui::GetIO(); + std::shared_ptr base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive(); + std::shared_ptr font = std::make_shared(); + base->LoadFile(path, false, font); + if (font->bIsLoaded) { + char* font_data = new char[font->dwBufferSize]; + memcpy(font_data, font->buffer.get(), font->dwBufferSize); + Fonts[name] = io.Fonts->AddFontFromMemoryTTF(font_data, font->dwBufferSize, fontSize); + } +} + +void Ship::GameOverlay::TextDraw(float x, float y, bool shadow, ImVec4 color, const char* fmt, ...) { + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + va_end(args); + + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::PushFont(Fonts[this->CurrentFont]); + if (shadow) { + ImGui::SetCursorPos(ImVec2(x + 1, y + 1)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.0f, .0f, .0f, color.w)); + ImGui::Text(buf, args); + } + ImGui::PopStyleColor(); + ImGui::SetCursorPos(ImVec2(x, y)); + ImGui::Text(buf, args); + ImGui::PopFont(); + ImGui::PopStyleColor(); +} + +void Ship::GameOverlay::TextDrawNotification(float duration, bool shadow, const char* fmt, ...) { + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf) - 1] = 0; + va_end(args); + this->RegisteredOverlays[StringHelper::Sprintf("NotificationID:%d%d", rand(), this->RegisteredOverlays.size())] = new Overlay({ OverlayType::NOTIFICATION, ImStrdup(buf), duration, duration }); + NeedsCleanup = true; +} + +void Ship::GameOverlay::CleanupNotifications() { + if(!NeedsCleanup) return; + for (auto it = this->RegisteredOverlays.begin(); it != this->RegisteredOverlays.end(); ) { + if (it->second->type == OverlayType::NOTIFICATION && it->second->duration <= 0.0f) { + it = this->RegisteredOverlays.erase(it); + } else { + ++it; + } + } + NeedsCleanup = false; +} + +float Ship::GameOverlay::GetScreenWidth() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + return viewport->Size.x; +} + +float Ship::GameOverlay::GetScreenHeight() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + return viewport->Size.y; +} + +float Ship::GameOverlay::GetStringWidth(const char* text) { + return CalculateTextSize(text).x; +} + +ImVec2 Ship::GameOverlay::CalculateTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) { + ImGuiContext& g = *GImGui; + + const char* text_display_end; + if (hide_text_after_double_hash) + text_display_end = ImGui::FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string + else + text_display_end = text_end; + + GameOverlay* overlay = SohImGui::overlay; + + ImFont* font = overlay->CurrentFont == "Default" ? g.Font : overlay->Fonts[overlay->CurrentFont]; + const float font_size = font->FontSize; + if (text == text_display_end) + return ImVec2(0.0f, font_size); + ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + + // Round + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); + + return text_size; +} + +void Ship::GameOverlay::Init() { + this->LoadFont("Press Start 2P", "assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf", 12.0f); + this->LoadFont("Fipps", "assets/ship_of_harkinian/fonts/Fipps-Regular.otf", 32.0f); + const std::string DefaultFont = this->Fonts.begin()->first; + if(!this->Fonts.empty()) { + const std::string font = CVar_GetString("gOverlayFont", ImStrdup(DefaultFont.c_str())); + for (auto& [name, _] : this->Fonts) { + if (font.starts_with(name)) { + this->CurrentFont = name; + break; + } + this->CurrentFont = DefaultFont; + } + } + SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" }; +} + +void Ship::GameOverlay::DrawSettings() { + ImGui::Text("Overlays Text Font"); + if (ImGui::BeginCombo("##TextFont", this->CurrentFont.c_str())) { + for (auto& [name, font] : this->Fonts) { + if (ImGui::Selectable(name.c_str(), name == this->CurrentFont)) { + this->CurrentFont = name; + CVar_SetString("gOverlayFont", ImStrdup(name.c_str())); + SohImGui::needs_save = true; + } + + } + ImGui::EndCombo(); + } +} + + +void Ship::GameOverlay::Draw() { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + + ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always); + ImGui::SetNextWindowSize(viewport->Size, ImGuiCond_Always); + ImGui::Begin("SoHOverlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); + + this->CleanupNotifications(); + + float textY = 50; + float notY = 0; + + for (auto &[key, overlay] : this->RegisteredOverlays) { + + if (overlay->type == OverlayType::TEXT) { + const char* text = ImStrdup(overlay->value); + const CVar* var = CVar_Get(text); + ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + + switch (var->type) { + case CVAR_TYPE_FLOAT: + this->TextDraw(30, textY, true, color, "%s %.2f", text, var->value.valueFloat); + break; + case CVAR_TYPE_S32: + this->TextDraw(30, textY, true, color, "%s %d", text, var->value.valueS32); + break; + case CVAR_TYPE_STRING: + this->TextDraw(30, textY, true, color, "%s %s", text, var->value.valueStr); + break; + } + + free((void*) text); + textY += 30; + } + + if (overlay->type == OverlayType::NOTIFICATION && overlay->duration > 0) { + const char* text = overlay->value; + const float duration = overlay->duration / overlay->fadeTime; + + const ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, duration); + const float textWidth = this->GetStringWidth(overlay->value); + + this->TextDraw(GetScreenWidth() - textWidth - 40, GetScreenHeight() - 40 - notY, true, color, text); + notY += 30; + overlay->duration -= .05f; + } + } + + ImGui::End(); +} + + +bool Ship::OverlayCommand(const std::vector& args) { + if (args.size() < 3) { + return CMD_FAILED; + } + + if (CVar_Get(args[2].c_str()) != nullptr) { + const char* key = args[2].c_str(); + GameOverlay* overlay = SohImGui::overlay; + if (args[1] == "add") { + if (!overlay->RegisteredOverlays.contains(key)) { + overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f }); + INFO("Added overlay: %s ", key); + } else { + ERROR("Overlay already exists: %s", key); + } + } else if (args[1] == "remove") { + if (overlay->RegisteredOverlays.contains(key)) { + overlay->RegisteredOverlays.erase(key); + INFO("Removed overlay: %s ", key); + } else { + ERROR("Overlay not found: %s ", key); + } + } + } else { + ERROR("CVar %s does not exist", args[2].c_str()); + } + + return CMD_SUCCESS; +} \ No newline at end of file diff --git a/libultraship/libultraship/GameOverlay.h b/libultraship/libultraship/GameOverlay.h new file mode 100644 index 000000000..605cd5898 --- /dev/null +++ b/libultraship/libultraship/GameOverlay.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include + +#include "Lib/ImGui/imgui.h" +#include +#include + +enum class OverlayType { + TEXT, IMAGE, NOTIFICATION +}; + +struct Overlay { + OverlayType type; + const char* value; + float fadeTime; + float duration; +}; + +namespace Ship { + class GameOverlay { + public: + std::unordered_map RegisteredOverlays; + std::unordered_map Fonts; + std::string CurrentFont = "Default"; + void Init(); + void Draw(); + void DrawSettings(); + static float GetScreenWidth(); + static float GetScreenHeight(); + static float GetStringWidth(const char* text); + static ImVec2 CalculateTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + void TextDraw(float x, float y, bool shadow, ImVec4 color, const char* text, ...); + void TextDrawNotification(float duration, bool shadow, const char* fmt, ...); + private: + bool NeedsCleanup = false; + void CleanupNotifications(); + void LoadFont(const std::string& name, const std::string& path, float fontSize); + }; + + static bool OverlayCommand(const std::vector& args); +} diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp index afae642eb..0cd9aa2f4 100644 --- a/libultraship/libultraship/GameSettings.cpp +++ b/libultraship/libultraship/GameSettings.cpp @@ -1,22 +1,22 @@ -#include "GameSettings.h" +#include "GameSettings.h" // Audio +#include +#include #include #include #include -#include #include "ConfigFile.h" #include "Cvar.h" #include "GlobalCtx2.h" #include "SohImGuiImpl.h" -#include "stox.h" #include "../../soh/include/z64audio.h" -#include #include "SohHooks.h" #include "../../soh/soh/Enhancements/debugconsole.h" #include "Window.h" +#include "Lib/Fast3D/gfx_rendering_api.h" #define ABS(var) var < 0 ? -(var) : var @@ -25,14 +25,6 @@ using namespace Ship; namespace Game { bool DeSyncAudio = false; - SoHConfigType Settings; - const std::string ConfSection = DEBUG_SECTION; - const std::string AudioSection = AUDIO_SECTION; - const std::string ControllerSection = CONTROLLER_SECTION; - const std::string EnhancementSection = ENHANCEMENTS_SECTION; - const std::string CosmeticsSection = COSMETICS_SECTION; - const std::string CheatSection = CHEATS_SECTION; - const std::string LanguagesSection = LANGUAGES_SECTION; void UpdateAudio() { Audio_SetGameVolume(SEQ_BGM_MAIN, CVar_GetFloat("gMainMusicVolume", 1)); @@ -41,18 +33,6 @@ namespace Game { Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1)); } - void LoadSettings() { - const std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); - ConfigFile& Conf = *pConf; - - // Debug - SohImGui::console->opened = stob(Conf[ConfSection]["console"]); - Settings.debug.menu_bar = stob(Conf[ConfSection]["menu_bar"]); - Settings.debug.soh = stob(Conf[ConfSection]["soh_debug"]); - - UpdateAudio(); - } - void LoadPadSettings() { const std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); ConfigFile& Conf = *pConf; @@ -65,16 +45,11 @@ namespace Game { } } + void LoadSettings() { + DebugConsole_LoadCVars(); + } + void SaveSettings() { - const std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); - ConfigFile& Conf = *pConf; - - // Debug - Conf[ConfSection]["console"] = std::to_string(SohImGui::console->opened); - Conf[ConfSection]["menu_bar"] = std::to_string(Settings.debug.menu_bar); - Conf[ConfSection]["soh_debug"] = std::to_string(Settings.debug.soh); - - Conf.Save(); DebugConsole_SaveCVars(); } @@ -82,9 +57,14 @@ namespace Game { ModInternal::registerHookListener({ AUDIO_INIT, [](HookEvent ev) { UpdateAudio(); }}); + ModInternal::registerHookListener({ GFX_INIT, [](HookEvent ev) { + gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", THREE_POINT)); + SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); + UpdateAudio(); + }}); } void SetSeqPlayerVolume(SeqPlayers playerId, float volume) { Audio_SetGameVolume(playerId, volume); } -} \ No newline at end of file +} diff --git a/libultraship/libultraship/GameSettings.h b/libultraship/libultraship/GameSettings.h index 0cfa38faa..0a9aa0ee6 100644 --- a/libultraship/libultraship/GameSettings.h +++ b/libultraship/libultraship/GameSettings.h @@ -1,24 +1,4 @@ - -#pragma once - -struct SoHConfigType { - // Debug - struct { - bool soh = false; - bool menu_bar = false; - bool soh_sink = true; - } debug; - - // Graphics - struct { - bool show = false; - } graphics; - - //Interface editor - struct { - bool uiedit = false; - } cosmetics; -}; +#pragma once enum SeqPlayers { /* 0 */ SEQ_BGM_MAIN, @@ -28,19 +8,10 @@ enum SeqPlayers { /* 4 */ SEQ_MAX }; -#define DEBUG_SECTION "DEBUG SETTINGS" -#define AUDIO_SECTION "AUDIO SETTINGS" -#define CONTROLLER_SECTION "CONTROLLER SECTION" -#define ENHANCEMENTS_SECTION "ENHANCEMENT SETTINGS" -#define COSMETICS_SECTION "COSMETIC SETTINGS" -#define CHEATS_SECTION "CHEATS SETTINGS" -#define LANGUAGES_SECTION "LANGUAGES SETTINGS" - namespace Game { - extern SoHConfigType Settings; void InitSettings(); void LoadSettings(); void LoadPadSettings(); void SaveSettings(); void SetSeqPlayerVolume(SeqPlayers playerId, float volume); -} \ No newline at end of file +} diff --git a/libultraship/libultraship/GameVersions.h b/libultraship/libultraship/GameVersions.h index a25463bf4..8d3753b21 100644 --- a/libultraship/libultraship/GameVersions.h +++ b/libultraship/libultraship/GameVersions.h @@ -1,3 +1,6 @@ +#ifndef GAME_VERSION_H +#define GAME_VERSION_H + #pragma once #define OOT_NTSC_10 0xEC7011B7 @@ -17,4 +20,6 @@ #define OOT_PAL_GC_MQ_DBG 0x917D18F6 #define OOT_IQUE_TW 0x3D81FB3E #define OOT_IQUE_CN 0xB1E1E07B -#define OOT_UNKNOWN 0xFFFFFFFF \ No newline at end of file +#define OOT_UNKNOWN 0xFFFFFFFF + +#endif diff --git a/libultraship/libultraship/GlobalCtx2.cpp b/libultraship/libultraship/GlobalCtx2.cpp index dd8125bcc..5ce59f5ab 100644 --- a/libultraship/libultraship/GlobalCtx2.cpp +++ b/libultraship/libultraship/GlobalCtx2.cpp @@ -30,7 +30,7 @@ namespace Ship { } GlobalCtx2::GlobalCtx2(const std::string& Name) : Name(Name), MainPath(""), PatchesPath("") { - + } GlobalCtx2::~GlobalCtx2() { @@ -54,7 +54,11 @@ namespace Ship { if (!ResMan->DidLoadSuccessfully()) { +#ifdef _WIN32 MessageBox(NULL, L"Main OTR file not found!", L"Uh oh", MB_OK); +#else + SPDLOG_ERROR("Main OTR file not found!"); +#endif exit(1); } INSTANCE = new ModManager(ResMan); diff --git a/libultraship/libultraship/GlobalCtx2.h b/libultraship/libultraship/GlobalCtx2.h index a10421ec0..1ed512347 100644 --- a/libultraship/libultraship/GlobalCtx2.h +++ b/libultraship/libultraship/GlobalCtx2.h @@ -1,3 +1,6 @@ +#ifndef GLOBAL_CTX_2 +#define GLOBAL_CTX_2 + #pragma once #ifdef __cplusplus @@ -38,4 +41,6 @@ namespace Ship { std::string PatchesPath; }; } -#endif \ No newline at end of file +#endif + +#endif diff --git a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h index dedc97939..a9e4f035e 100644 --- a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h +++ b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/gbi.h @@ -1004,7 +1004,7 @@ #define G_DL_PUSH 0x00 #define G_DL_NOPUSH 0x01 -#if _MSC_VER +#if defined(_MSC_VER) || defined(__GNUC__) #define _LANGUAGE_C #endif @@ -3132,7 +3132,7 @@ _DW({ \ #endif */ -#ifdef _MSC_VER +#if defined(_MSC_VER) #define CALL_2(A,B) A B #define CALL_3(A,B,C) A B C @@ -3143,12 +3143,12 @@ _DW({ \ #define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b) #endif -#if _MSC_VER +#if defined(_MSC_VER) || defined(__GNUC__) #define CALL_2(A,B) A B #define CALL_3(A,B,C) A B C -#define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b)) - //#define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0 +// #define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b)) +// #define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0 #else #define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b) #endif diff --git a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/mbi.h b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/mbi.h index fd6042ff5..988c309df 100644 --- a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/mbi.h +++ b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/mbi.h @@ -33,6 +33,7 @@ #define G_OFF (0) #include +#include "types.h" #include "gbi.h" #include "abi.h" diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp index cea82e09e..4664a0faa 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp @@ -15,11 +15,9 @@ #ifndef _LANGUAGE_C #define _LANGUAGE_C #endif -#include +#include "PR/ultra64/gbi.h" -#include "gfx_cc.h" #include "gfx_window_manager_api.h" -#include "gfx_rendering_api.h" #include "gfx_direct3d_common.h" #define DECLARE_GFX_DXGI_FUNCTIONS @@ -28,7 +26,9 @@ #include "gfx_screen_config.h" #include "../../SohImGuiImpl.h" -#define THREE_POINT_FILTERING 0 +#include "gfx_cc.h" +#include "gfx_rendering_api.h" +#include "gfx_pc.h" #define DEBUG_D3D 0 using namespace Microsoft::WRL; // For ComPtr @@ -135,6 +135,7 @@ static struct { //uint32_t current_width, current_height; uint32_t render_target_height; int current_framebuffer; + FilteringMode current_filter_mode = NONE; int8_t depth_test; int8_t depth_mask; @@ -157,7 +158,7 @@ static LARGE_INTEGER last_time, accumulated_time, frequency; int gfx_d3d11_create_framebuffer(void); -void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) { +static void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) { D3D11_TEXTURE2D_DESC texture_desc; texture_desc.Width = width; texture_desc.Height = height; @@ -397,7 +398,7 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade char buf[4096]; size_t len, num_floats; - gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, THREE_POINT_FILTERING); + gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == THREE_POINT); ComPtr vs, ps; ComPtr error_blob; @@ -564,11 +565,8 @@ static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint3 D3D11_SAMPLER_DESC sampler_desc; ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC)); -#if THREE_POINT_FILTERING - sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; -#else - sampler_desc.Filter = linear_filter ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; -#endif + sampler_desc.Filter = linear_filter && d3d.current_filter_mode == LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; + sampler_desc.AddressU = gfx_cm_to_d3d11(cms); sampler_desc.AddressV = gfx_cm_to_d3d11(cmt); sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; @@ -672,12 +670,12 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get(); d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf()); -#if THREE_POINT_FILTERING - d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width; - d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height; - d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering; - textures_changed = true; -#endif + if (d3d.current_filter_mode == THREE_POINT) { + d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width; + d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height; + d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering; + textures_changed = true; + } if (d3d.last_sampler_states[i].Get() != d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get()) { d3d.last_sampler_states[i] = d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get(); @@ -880,6 +878,15 @@ void gfx_d3d11_select_texture_fb(int fbID) { gfx_d3d11_select_texture(tile, d3d.framebuffers[fbID].texture_id); } +void gfx_d3d11_set_texture_filter(FilteringMode mode) { + d3d.current_filter_mode = mode; + gfx_texture_cache_clear(); +} + +FilteringMode gfx_d3d11_get_texture_filter(void) { + return d3d.current_filter_mode; +} + std::map, uint16_t> gfx_d3d11_get_pixel_depth(int fb_id, const std::set>& coordinates) { Framebuffer& fb = d3d.framebuffers[fb_id]; TextureData& td = d3d.textures[fb.texture_id]; @@ -985,8 +992,8 @@ std::map, uint16_t> gfx_d3d11_get_pixel_depth(int fb_id, } // namespace -ImTextureID SohImGui::GetTextureByID(int id) { - return impl.backend == Backend::DX11 ? d3d.textures[id].resource_view.Get() : reinterpret_cast(id); +ImTextureID gfx_d3d11_get_texture_by_id(int id) { + return d3d.textures[id].resource_view.Get(); } struct GfxRenderingAPI gfx_direct3d11_api = { @@ -1019,7 +1026,9 @@ struct GfxRenderingAPI gfx_direct3d11_api = { gfx_d3d11_get_pixel_depth, gfx_d3d11_get_framebuffer_texture_id, gfx_d3d11_select_texture_fb, - gfx_d3d11_delete_texture + gfx_d3d11_delete_texture, + gfx_d3d11_set_texture_filter, + gfx_d3d11_get_texture_filter }; #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp index 66bb5c182..d450558b2 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp @@ -150,29 +150,29 @@ static struct { Display *dpy; Window root; Window win; - + Atom atom_wm_state; Atom atom_wm_state_fullscreen; Atom atom_wm_delete_window; - + bool is_fullscreen; void (*on_fullscreen_changed)(bool is_now_fullscreen); - + int keymap[256]; bool (*on_key_down)(int scancode); bool (*on_key_up)(int scancode); void (*on_all_keys_up)(void); - + PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML; PFNGLXSWAPBUFFERSMSCOMLPROC glXSwapBuffersMscOML; PFNGLXWAITFORSBCOMLPROC glXWaitForSbcOML; - + PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; - + PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI; PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; - + bool has_oml_sync_control; uint64_t ust0; int64_t last_msc; @@ -181,7 +181,7 @@ static struct { uint64_t last_ust; int64_t target_msc; bool dropped_frame; - + bool has_sgi_video_sync; uint64_t last_sync_counter; int64_t this_msc; @@ -220,7 +220,7 @@ static int64_t glXGetVideoSyncSGI_wrapper(void) { static void init_keymap(void) { XkbDescPtr desc = XkbGetMap(glx.dpy, 0, XkbUseCoreKbd); XkbGetNames(glx.dpy, XkbKeyNamesMask, desc); - + for (int i = desc->min_key_code; i <= desc->max_key_code && i < 256; i++) { char name[XkbKeyNameLength + 1]; memcpy(name, desc->names->keys[i].name, XkbKeyNameLength); @@ -232,7 +232,7 @@ static void init_keymap(void) { } } } - + XkbFreeNames(desc, XkbKeyNamesMask, True); XkbFreeKeyboard(desc, 0, True); } @@ -265,7 +265,7 @@ static void gfx_glx_set_fullscreen_state(bool on, bool call_callback) { return; } glx.is_fullscreen = on; - + XEvent xev; xev.xany.type = ClientMessage; xev.xclient.message_type = glx.atom_wm_state; @@ -276,8 +276,8 @@ static void gfx_glx_set_fullscreen_state(bool on, bool call_callback) { xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; XSendEvent(glx.dpy, glx.root, 0, SubstructureNotifyMask | SubstructureRedirectMask, &xev); - gfx_glx_ShowHideMouse(on); - + gfx_glx_show_cursor(on); + if (glx.on_fullscreen_changed != NULL && call_callback) { glx.on_fullscreen_changed(on); } @@ -303,7 +303,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) { // which means that glXSwapBuffers should be non-blocking, // if we are sure to wait at least one vsync interval between calls. setenv("__GL_MaxFramesAllowed", "2", true); - + glx.dpy = XOpenDisplay(NULL); if (glx.dpy == NULL) { fprintf(stderr, "Cannot connect to X server\n"); @@ -311,7 +311,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) { } int screen = DefaultScreen(glx.dpy); glx.root = RootWindow(glx.dpy, screen); - + GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; XVisualInfo *vi = glXChooseVisual(glx.dpy, 0, att); if (vi == NULL) { @@ -323,7 +323,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) { swa.colormap = cmap; swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | FocusChangeMask; glx.win = XCreateWindow(glx.dpy, glx.root, 0, 0, DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa); - + glx.atom_wm_state = XInternAtom(glx.dpy, "_NET_WM_STATE", False); glx.atom_wm_state_fullscreen = XInternAtom(glx.dpy, "_NET_WM_STATE_FULLSCREEN", False); glx.atom_wm_delete_window = XInternAtom(glx.dpy, "WM_DELETE_WINDOW", False); @@ -340,11 +340,11 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) { XStoreName(glx.dpy, glx.win, title); GLXContext glc = glXCreateContext(glx.dpy, vi, NULL, GL_TRUE); glXMakeCurrent(glx.dpy, glx.win, glc); - + init_keymap(); - + const char *extensions = glXQueryExtensionsString(glx.dpy, screen); - + if (gfx_glx_check_extension(extensions, "GLX_OML_sync_control")) { glx.glXGetSyncValuesOML = (PFNGLXGETSYNCVALUESOMLPROC)glXGetProcAddressARB((const GLubyte *)"glXGetSyncValuesOML"); glx.glXSwapBuffersMscOML = (PFNGLXSWAPBUFFERSMSCOMLPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapBuffersMscOML"); @@ -360,7 +360,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) { glx.glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVideoSyncSGI"); glx.glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXWaitVideoSyncSGI"); } - + int64_t ust, msc, sbc; if (glx.glXGetSyncValuesOML != NULL && glx.glXGetSyncValuesOML(glx.dpy, glx.win, &ust, &msc, &sbc)) { glx.has_oml_sync_control = true; @@ -439,7 +439,7 @@ static void gfx_glx_handle_events(void) { } } } - if (xev.type == ClientMessage && xev.xclient.data.l[0] == glx.atom_wm_delete_window) { + if (xev.type == ClientMessage && (Atom)xev.xclient.data.l[0] == glx.atom_wm_delete_window) { exit(0); } } @@ -451,19 +451,19 @@ static bool gfx_glx_start_frame(void) { static void gfx_glx_swap_buffers_begin(void) { glx.wanted_ust += FRAME_INTERVAL_US_NUMERATOR; // advance 1/30 seconds on JP/US or 1/25 seconds on EU - + if (!glx.has_oml_sync_control && !glx.has_sgi_video_sync) { glFlush(); - + uint64_t target = glx.wanted_ust / FRAME_INTERVAL_US_DENOMINATOR; uint64_t now; while (target > (now = (uint64_t)get_time() - glx.ust0)) { - struct timespec ts = {(target - now) / 1000000, ((target - now) % 1000000) * 1000}; + struct timespec ts = {(time_t)((target - now) / 1000000), (time_t)(((target - now) % 1000000) * 1000)}; if (nanosleep(&ts, NULL) == 0) { break; } } - + if (target + 2 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR < now) { if (target + 32 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR >= now) { printf("Dropping frame\n"); @@ -476,10 +476,10 @@ static void gfx_glx_swap_buffers_begin(void) { } glXSwapBuffers(glx.dpy, glx.win); glx.dropped_frame = false; - + return; } - + double vsyncs_to_wait = (int64_t)(glx.wanted_ust / FRAME_INTERVAL_US_DENOMINATOR - glx.last_ust) / (double)glx.vsync_interval; if (vsyncs_to_wait <= 0) { printf("Dropping frame\n"); @@ -519,17 +519,17 @@ static void gfx_glx_swap_buffers_begin(void) { vsyncs_to_wait = 2; } glx.target_msc = glx.last_msc + vsyncs_to_wait; - + if (glx.has_oml_sync_control) { glx.glXSwapBuffersMscOML(glx.dpy, glx.win, glx.target_msc, 0, 0); } else if (glx.has_sgi_video_sync) { glFlush(); // Try to submit pending work. Don't use glFinish since that busy loops on NVIDIA proprietary driver. - + //uint64_t counter0; uint64_t counter1, counter2; - + //uint64_t before_wait = get_time(); - + counter1 = glXGetVideoSyncSGI_wrapper(); //counter0 = counter1; //int waits = 0; @@ -537,17 +537,17 @@ static void gfx_glx_swap_buffers_begin(void) { counter1 = glXWaitVideoSyncSGI_wrapper(); //++waits; } - + //uint64_t before = get_time(); glXSwapBuffers(glx.dpy, glx.win); - - + + counter2 = glXGetVideoSyncSGI_wrapper(); while (counter2 < (uint64_t)glx.target_msc) { counter2 = glXWaitVideoSyncSGI_wrapper(); } uint64_t after = get_time(); - + //printf("%.3f %.3f %.3f\t%.3f\t%u %d %.2f %u %d\n", before_wait * 0.000060, before * 0.000060, after * 0.000060, (after - before) * 0.000060, counter0, counter2 - counter0, vsyncs_to_wait, (unsigned int)glx.target_msc, waits); glx.this_msc = counter2; glx.this_ust = after; @@ -558,7 +558,7 @@ static void gfx_glx_swap_buffers_end(void) { if (glx.dropped_frame || (!glx.has_oml_sync_control && !glx.has_sgi_video_sync)) { return; } - + int64_t ust, msc, sbc; if (glx.has_oml_sync_control) { if (!glx.glXWaitForSbcOML(glx.dpy, glx.win, 0, &ust, &msc, &sbc)) { @@ -600,6 +600,10 @@ static double gfx_glx_get_time(void) { return 0.0; } +static void gfx_glx_set_frame_divisor(int divisor) { + // TODO +} + struct GfxWindowManagerAPI gfx_glx = { gfx_glx_init, gfx_glx_set_keyboard_callbacks, @@ -612,7 +616,8 @@ struct GfxWindowManagerAPI gfx_glx = { gfx_glx_start_frame, gfx_glx_swap_buffers_begin, gfx_glx_swap_buffers_end, - gfx_glx_get_time + gfx_glx_get_time, + gfx_glx_set_frame_divisor, }; #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_glx.h b/libultraship/libultraship/Lib/Fast3D/gfx_glx.h index fe78db948..1ca410901 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_glx.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_glx.h @@ -3,6 +3,6 @@ #include "gfx_window_manager_api.h" -struct GfxWindowManagerAPI gfx_glx; +extern struct GfxWindowManagerAPI gfx_glx; #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp index 6c5f47577..b2db3186a 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp @@ -29,8 +29,9 @@ #include "SDL_opengl.h" #else #include +#include #define GL_GLEXT_PROTOTYPES 1 -#include +// #include #endif #include "gfx_cc.h" @@ -73,6 +74,7 @@ static uint32_t frame_count; static vector framebuffers; static size_t current_framebuffer; static float current_noise_scale; +static FilteringMode current_filter_mode = THREE_POINT; GLuint pixel_depth_rb, pixel_depth_fb; size_t pixel_depth_rb_size; @@ -177,6 +179,7 @@ static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_ return "texel.a"; } } + return ""; } static void append_formula(char *buf, size_t *len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) { @@ -211,7 +214,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad gfx_cc_get_features(shader_id0, shader_id1, &cc_features); char vs_buf[1024]; - char fs_buf[1024]; + char fs_buf[3000]; size_t vs_len = 0; size_t fs_len = 0; size_t num_floats = 4; @@ -312,21 +315,42 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "}"); } + if (current_filter_mode == THREE_POINT) { + append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize)"); + append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));"); + append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);"); + append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(offset);"); + append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y));"); + append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)));"); + append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);"); + append_line(fs_buf, &fs_len, "}"); + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, " return filter3point(tex, uv, texSize);"); + append_line(fs_buf, &fs_len, "}"); + } else { + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, " return texture2D(tex, uv);"); + append_line(fs_buf, &fs_len, "}"); + } + append_line(fs_buf, &fs_len, "void main() {"); for (int i = 0; i < 2; i++) { if (cc_features.used_textures[i]) { bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1]; + + fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i); + if (!s && !t) { - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vTexCoord%d);\n", i, i, i); + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoord%d, texSize%d);\n", i, i, i, i); } else { - fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i); if (s && t) { - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, clamp(vTexCoord%d, 0.5 / texSize%d, vec2(vTexClampS%d, vTexClampT%d)));\n", i, i, i, i, i, i); + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, clamp(vTexCoord%d, 0.5 / texSize%d, vec2(vTexClampS%d, vTexClampT%d)), texSize%d);\n", i, i, i, i, i, i, i); } else if (s) { - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vec2(clamp(vTexCoord%d.s, 0.5 / texSize%d.s, vTexClampS%d), vTexCoord%d.t));\n", i, i, i, i, i, i); + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vec2(clamp(vTexCoord%d.s, 0.5 / texSize%d.s, vTexClampS%d), vTexCoord%d.t), texSize%d);\n", i, i, i, i, i, i, i); } else { - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, 0.5 / texSize%d.t, vTexClampT%d)));\n", i, i, i, i, i, i); + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, 0.5 / texSize%d.t, vTexClampT%d)), texSize%d);\n", i, i, i, i, i, i, i); } } } @@ -422,9 +446,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad GLint max_length = 0; glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length); char error_log[1024]; - //fprintf(stderr, "Fragment shader compilation failed\n"); + fprintf(stderr, "Fragment shader compilation failed\n"); glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]); - //fprintf(stderr, "%s\n", &error_log[0]); + fprintf(stderr, "%s\n", &error_log[0]); abort(); } @@ -549,12 +573,14 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) { case G_TX_NOMIRROR | G_TX_WRAP: return GL_REPEAT; } + return 0; } static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { + const GLint filter = linear_filter && current_filter_mode == LINEAR ? GL_LINEAR : GL_NEAREST; glActiveTexture(GL_TEXTURE0 + tile); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); } @@ -823,6 +849,15 @@ static std::map, uint16_t> gfx_opengl_get_pixel_depth(in return res; } +void gfx_opengl_set_texture_filter(FilteringMode mode) { + current_filter_mode = mode; + gfx_texture_cache_clear(); +} + +FilteringMode gfx_opengl_get_texture_filter(void) { + return current_filter_mode; +} + struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_get_clip_parameters, gfx_opengl_unload_shader, @@ -853,7 +888,9 @@ struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_get_pixel_depth, gfx_opengl_get_framebuffer_texture_id, gfx_opengl_select_texture_fb, - gfx_opengl_delete_texture + gfx_opengl_delete_texture, + gfx_opengl_set_texture_filter, + gfx_opengl_get_texture_filter }; #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp index 1d03befe6..6f7e8c271 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef _LANGUAGE_C #define _LANGUAGE_C @@ -30,6 +31,8 @@ #include "../StrHash64.h" #include "../../SohImGuiImpl.h" #include "../../Environment.h" +#include "../../GameVersions.h" +#include "../../ResourceMgr.h" // OTRTODO: fix header files for these extern "C" { @@ -45,6 +48,8 @@ extern "C" { using namespace std; +#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) + #define SUPPORT_CHECK(x) assert(x) // SCALE_M_N: upscale/downscale M-bit integer to N-bit @@ -185,8 +190,12 @@ static int game_framebuffer_msaa_resolved; uint32_t gfx_msaa_level = 1; +static bool has_drawn_imgui_menu; + static bool dropped_frame; +static const std::unordered_map *current_mtx_replacements; + static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx static size_t buf_vbo_len; static size_t buf_vbo_num_tris; @@ -209,7 +218,7 @@ static map framebuffers; static set> get_pixel_depth_pending; static map, uint16_t> get_pixel_depth_cached; -#ifdef _MSC_VER +#ifdef _WIN32 // TODO: Properly implement for MSVC static unsigned long get_time(void) { @@ -447,15 +456,15 @@ static void gfx_generate_cc(struct ColorCombiner *comb, uint64_t cc_id) { val = SHADER_COMBINED; break; } - // fallthrough for G_ACMUX_LOD_FRACTION c[i][1][j] = G_CCMUX_LOD_FRACTION; + [[fallthrough]]; // for G_ACMUX_LOD_FRACTION case G_ACMUX_1: //case G_ACMUX_PRIM_LOD_FRAC: same numerical value if (j != 2) { val = SHADER_1; break; } - // fallthrough for G_ACMUX_PRIM_LOD_FRAC + [[fallthrough]]; // for G_ACMUX_PRIM_LOD_FRAC case G_ACMUX_PRIMITIVE: case G_ACMUX_SHADE: case G_ACMUX_ENVIRONMENT: @@ -564,7 +573,7 @@ static void gfx_texture_cache_delete(const uint8_t* orig_addr) if (it->first.texture_addr == orig_addr) { gfx_texture_cache.lru.erase(*(list::iterator*)&it->second.lru_location); gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id); - gfx_texture_cache.map.erase(it); + gfx_texture_cache.map.erase(it->first); again = true; break; } @@ -911,20 +920,31 @@ static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4 static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) { float matrix[4][4]; -#ifndef GBI_FLOATS - // Original GBI where fixed point matrices are used - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j += 2) { - int32_t int_part = addr[i * 2 + j / 2]; - uint32_t frac_part = addr[8 + i * 2 + j / 2]; - matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f; - matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f; + + if (auto it = current_mtx_replacements->find((Mtx *)addr); it != current_mtx_replacements->end()) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float v = it->second.mf[i][j]; + int as_int = (int)(v * 65536.0f); + matrix[i][j] = as_int * (1.0f / 65536.0f); + } + } + } else { +#ifndef GBI_FLOATS + // Original GBI where fixed point matrices are used + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j += 2) { + int32_t int_part = addr[i * 2 + j / 2]; + uint32_t frac_part = addr[8 + i * 2 + j / 2]; + matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f; + matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f; + } } - } #else - // For a modified GBI where fixed point values are replaced with floats - memcpy(matrix, addr, sizeof(matrix)); + // For a modified GBI where fixed point values are replaced with floats + memcpy(matrix, addr, sizeof(matrix)); #endif + } if (parameters & G_MTX_PROJECTION) { if (parameters & G_MTX_LOAD) { @@ -1692,7 +1712,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t SUPPORT_CHECK(ult == 0); // The lrs field rather seems to be number of pixels to load - uint32_t word_size_shift; + uint32_t word_size_shift = 0; switch (rdp.texture_to_load.siz) { case G_IM_SIZ_4b: word_size_shift = 0; // Or -1? It's unused in SM64 anyway. @@ -1720,7 +1740,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) { SUPPORT_CHECK(tile == G_TX_LOADTILE); - uint32_t word_size_shift; + uint32_t word_size_shift = 0; switch (rdp.texture_to_load.siz) { case G_IM_SIZ_4b: word_size_shift = 0; @@ -2060,12 +2080,11 @@ static void gfx_s2dex_bg_copy(const uObjBg* bg) { static inline void* seg_addr(uintptr_t w1) { // Segmented? - if (w1 >= 0xF0000000) + if (w1 & 1) { uint32_t segNum = (w1 >> 24); - segNum -= 0xF0; - uint32_t offset = w1 & 0x00FFFFFF; + uint32_t offset = w1 & 0x00FFFFFE; //offset = 0; // Cursed Malon bug if (segmentPointers[segNum] != 0) @@ -2082,7 +2101,7 @@ static inline void* seg_addr(uintptr_t w1) #define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1)) #define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1)) -int dListBP; +unsigned int dListBP; int matrixBP; uintptr_t clearMtx; @@ -2149,8 +2168,16 @@ static void gfx_run_dl(Gfx* cmd) { uintptr_t mtxAddr = cmd->words.w1; // OTRTODO: Temp way of dealing with gMtxClear. Need something more elegant in the future... - if (mtxAddr == 0xF012DB20 || mtxAddr == 0xF012DB40) - mtxAddr = clearMtx; + uint32_t gameVersion = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->GetGameVersion(); + if (gameVersion == OOT_PAL_GC) { + if (mtxAddr == SEG_ADDR(0, 0x0FBC20)) { + mtxAddr = clearMtx; + } + } else { + if (mtxAddr == SEG_ADDR(0, 0x12DB20) || mtxAddr == SEG_ADDR(0, 0x12DB40)) { + mtxAddr = clearMtx; + } + } #ifdef F3DEX_GBI_2 gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t *) seg_addr(mtxAddr)); @@ -2250,7 +2277,7 @@ static void gfx_run_dl(Gfx* cmd) { cmd--; - if (ourHash != -1) + if (ourHash != (uint64_t)-1) ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, cmd->words.w1); cmd->words.w1 = (uintptr_t)vtx; @@ -2368,7 +2395,7 @@ static void gfx_run_dl(Gfx* cmd) { case G_QUAD: { int bp = 0; - // fallthrough + [[fallthrough]]; } #endif #if defined(F3DEX_GBI) || defined(F3DLP_GBI) @@ -2398,11 +2425,11 @@ static void gfx_run_dl(Gfx* cmd) { char* imgData = (char*)i; - if ((i & 0xF0000000) != 0xF0000000) + if ((i & 1) != 1) if (ResourceMgr_OTRSigCheck(imgData) == 1) i = (uintptr_t)ResourceMgr_LoadTexByName(imgData); - gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), (void*) i, imgData); + gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), (void*) i, imgData); break; } case G_SETTIMG_OTR: @@ -2419,7 +2446,7 @@ static void gfx_run_dl(Gfx* cmd) { char* tex = NULL; #endif - if (addr != NULL) + if (addr != 0) { tex = (char*)addr; } @@ -2433,7 +2460,7 @@ static void gfx_run_dl(Gfx* cmd) { uintptr_t oldData = cmd->words.w1; cmd->words.w1 = (uintptr_t)tex; - if (ourHash != -1) + if (ourHash != (uint64_t)-1) ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, oldData); cmd++; @@ -2648,7 +2675,7 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer(); for (int i = 0; i < 16; i++) - segmentPointers[i] = NULL; + segmentPointers[i] = 0; // Used in the 120 star TAS static uint32_t precomp_shaders[] = { @@ -2696,6 +2723,7 @@ void gfx_start_frame(void) { gfx_wapi->handle_events(); gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height); SohImGui::DrawMainMenuAndCalculateGameSize(); + has_drawn_imgui_menu = true; if (gfx_current_dimensions.height == 0) { // Avoid division by zero gfx_current_dimensions.height = 1; @@ -2734,7 +2762,7 @@ void gfx_start_frame(void) { fbActive = 0; } -void gfx_run(Gfx *commands) { +void gfx_run(Gfx *commands, const std::unordered_map& mtx_replacements) { gfx_sp_reset(); //puts("New frame"); @@ -2743,12 +2771,21 @@ void gfx_run(Gfx *commands) { if (!gfx_wapi->start_frame()) { dropped_frame = true; - SohImGui::DrawFramebufferAndGameInput(); - SohImGui::CancelFrame(); + if (has_drawn_imgui_menu) { + SohImGui::DrawFramebufferAndGameInput(); + SohImGui::CancelFrame(); + has_drawn_imgui_menu = false; + } return; } dropped_frame = false; + if (!has_drawn_imgui_menu) { + SohImGui::DrawMainMenuAndCalculateGameSize(); + } + + current_mtx_replacements = &mtx_replacements; + double t0 = gfx_wapi->get_time(); gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, 1, false, true, true, !game_renders_to_framebuffer); gfx_rapi->start_frame(); @@ -2780,6 +2817,7 @@ void gfx_run(Gfx *commands) { //printf("Process %f %f\n", t1, t1 - t0); gfx_rapi->end_frame(); gfx_wapi->swap_buffers_begin(); + has_drawn_imgui_menu = false; } void gfx_end_frame(void) { diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h index d682991d9..62f80ab3c 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h @@ -4,12 +4,16 @@ #include #include #include +#include + +#include "U64/PR/ultra64/types.h" struct GfxRenderingAPI; struct GfxWindowManagerAPI; struct XYWidthHeight { - int16_t x, y, width, height; + int16_t x, y; + uint32_t width, height; }; struct GfxDimensions { @@ -25,7 +29,7 @@ struct TextureCacheKey { uint8_t palette_index; bool operator==(const TextureCacheKey&) const noexcept = default; - + struct Hasher { size_t operator()(const TextureCacheKey& key) const noexcept { uintptr_t addr = (uintptr_t)key.texture_addr; @@ -50,26 +54,24 @@ struct TextureCacheValue { #endif }; -#ifdef __cplusplus extern "C" { -#endif + extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable) extern struct XYWidthHeight gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner extern uint32_t gfx_msaa_level; +} + void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen); struct GfxRenderingAPI* gfx_get_current_rendering_api(void); void gfx_start_frame(void); -void gfx_run(Gfx* commands); +void gfx_run(Gfx* commands, const std::unordered_map& mtx_replacements); void gfx_end_frame(void); void gfx_set_framedivisor(int); void gfx_texture_cache_clear(); -int gfx_create_framebuffer(uint32_t width, uint32_t height); +extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height); void gfx_get_pixel_depth_prepare(float x, float y); uint16_t gfx_get_pixel_depth(float x, float y); -#ifdef __cplusplus -} -#endif #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h index 84247fe60..6318be492 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h @@ -15,6 +15,12 @@ struct GfxClipParameters { bool invert_y; }; +enum FilteringMode { + THREE_POINT, + LINEAR, + NONE +}; + struct GfxRenderingAPI { struct GfxClipParameters (*get_clip_parameters)(void); void (*unload_shader)(struct ShaderProgram *old_prg); @@ -46,6 +52,8 @@ struct GfxRenderingAPI { void *(*get_framebuffer_texture_id)(int fb_id); void (*select_texture_fb)(int fb_id); void (*delete_texture)(uint32_t texID); + void (*set_texture_filter)(FilteringMode mode); + FilteringMode(*get_texture_filter)(void); }; #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index ffc46f369..e80097c81 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -1,6 +1,6 @@ #include -#if !defined(__linux__) && defined(ENABLE_OPENGL) +#if defined(ENABLE_OPENGL) #ifdef __MINGW32__ #define FOR_WINDOWS 1 @@ -23,7 +23,9 @@ #include "gfx_window_manager_api.h" #include "gfx_screen_config.h" +#ifdef _WIN32 #include +#endif #include #define GFX_API_NAME "SDL2 - OpenGL" @@ -41,7 +43,7 @@ static bool (*on_key_up_callback)(int scancode); static void (*on_all_keys_up_callback)(void); const SDL_Scancode windows_scancode_table[] = -{ +{ /* 0 1 2 3 4 5 6 7 */ /* 8 9 A B C D E F */ SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, /* 0 */ @@ -117,7 +119,9 @@ static void set_fullscreen(bool on, bool call_callback) { } static uint64_t previous_time; +#ifndef __linux__ static HANDLE timer; +#endif static int frameDivisor = 1; @@ -131,7 +135,9 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +#ifndef __linux timer = CreateWaitableTimer(nullptr, false, nullptr); +#endif //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); @@ -188,7 +194,7 @@ static void gfx_sdl_set_keyboard_callbacks(bool (*on_key_down)(int scancode), bo } static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) { - while (1) + while (1) { run_one_game_iter(); } diff --git a/libultraship/libultraship/Lib/StrHash64.h b/libultraship/libultraship/Lib/StrHash64.h index 35401bbf8..d8cc8ff62 100644 --- a/libultraship/libultraship/Lib/StrHash64.h +++ b/libultraship/libultraship/Lib/StrHash64.h @@ -86,14 +86,8 @@ #include -#define u8 uint8_t -#define u16 uint16_t -#define u32 uint32_t -#define u64 uint64_t -#define unint uint32_t - #define INITIAL_CRC64 0xffffffffffffffffULL -extern uint64_t update_crc64(const void* buf, unint len, u64 crc); -extern u64 crc64(const void* buf, unint len); -extern u64 CRC64(const char* t); \ No newline at end of file +extern uint64_t update_crc64(const void* buf, uint32_t len, uint64_t crc); +extern uint64_t crc64(const void* buf, uint32_t len); +extern uint64_t CRC64(const char* t); \ No newline at end of file diff --git a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h index 08729f4dc..4fa03b5e0 100644 --- a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h +++ b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h @@ -10,6 +10,7 @@ #include #include "SohImGuiImpl.h" #include "GameSettings.h" +#include "Cvar.h" #include #include #include @@ -45,8 +46,8 @@ protected: } formatted.push_back('\0'); const char *msg_output = formatted.data(); - if (Game::Settings.debug.soh_sink && SohImGui::console->opened) - SohImGui::console->Append("SoH Logging", priority, msg_output); + if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened) + SohImGui::console->Append("SoH Logging", priority, "%s", msg_output); } void flush_() override {} @@ -66,6 +67,8 @@ private: return Priority::ERROR_LVL; case spdlog::level::critical: return Priority::ERROR_LVL; + default: + break; } return Priority::LOG_LVL; } diff --git a/libultraship/libultraship/Model.cpp b/libultraship/libultraship/Model.cpp index 27220e3bc..9e37de177 100644 --- a/libultraship/libultraship/Model.cpp +++ b/libultraship/libultraship/Model.cpp @@ -39,7 +39,7 @@ namespace Ship Vertex* vtxData = new Vertex[numVerts]; uint32_t* indicesData = new uint32_t[numPolys]; - if (vertices != NULL) + if (vertices != 0) { reader->Seek(headerStart + vertices, SeekOffsetType::Start); @@ -47,7 +47,7 @@ namespace Ship vtxData[i].pos = reader->ReadVec3f(); } - if (normals != NULL) + if (normals != 0) { reader->Seek(headerStart + normals, SeekOffsetType::Start); @@ -55,7 +55,7 @@ namespace Ship vtxData[i].normal = reader->ReadVec3f(); } - if (vertexColors != NULL) + if (vertexColors != 0) { reader->Seek(headerStart + vertexColors, SeekOffsetType::Start); @@ -63,7 +63,7 @@ namespace Ship vtxData[i].color = reader->ReadColor3b(); } - if (uvCoords != NULL) + if (uvCoords != 0) { reader->Seek(headerStart + uvCoords, SeekOffsetType::Start); @@ -71,7 +71,7 @@ namespace Ship vtxData[i].uv = reader->ReadVec2f(); } - if (boneWeights != NULL) + if (boneWeights != 0) { reader->Seek(headerStart + boneWeights, SeekOffsetType::Start); @@ -81,7 +81,7 @@ namespace Ship mdl->boneWeights[i] = reader->ReadVec2f(); } - if (faces != NULL) + if (faces != 0) { reader->Seek(headerStart + faces, SeekOffsetType::Start); reader->Read((char*)indicesData, numPolys * sizeof(uint32_t)); diff --git a/libultraship/libultraship/PulseAudioPlayer.cpp b/libultraship/libultraship/PulseAudioPlayer.cpp new file mode 100644 index 000000000..955b225d1 --- /dev/null +++ b/libultraship/libultraship/PulseAudioPlayer.cpp @@ -0,0 +1,173 @@ +#if defined(__linux__) || defined(__BSD__) + +#include "PulseAudioPlayer.h" +#include + +namespace Ship +{ + static void pas_context_state_cb(pa_context *c, void *userdata) { + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + *(bool*)userdata = true; + break; + default: + break; + } + } + + static void pas_stream_state_cb(pa_stream *s, void *userdata) { + switch (pa_stream_get_state(s)) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + *(bool*)userdata = true; + break; + default: + break; + } + } + + static void pas_stream_write_cb(pa_stream* s, size_t length, void* userdata) { + } + + static void pas_update_complete(pa_stream* stream, int success, void* userdata) { + *(bool*)userdata = true; + } + + static void pas_write_complete(void* userdata) { + *(bool*)userdata = true; + } + + bool PulseAudioPlayer::Init() + { + bool done = false; + const pa_buffer_attr* applied_attr = nullptr; + + // Create mainloop + m_MainLoop = pa_mainloop_new(); + if (m_MainLoop == NULL) { + return false; + } + + // Create context and connect + m_Context = pa_context_new(pa_mainloop_get_api(m_MainLoop), "Ocarina of Time"); + if (m_Context == NULL) { + goto fail; + } + + pa_context_set_state_callback(m_Context, pas_context_state_cb, &done); + + if (pa_context_connect(m_Context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { + goto fail; + } + + while (!done) { + pa_mainloop_iterate(m_MainLoop, true, NULL); + } + pa_context_set_state_callback(m_Context, NULL, NULL); + if (pa_context_get_state(m_Context) != PA_CONTEXT_READY) { + goto fail; + } + + // Create stream + pa_sample_spec ss; + ss.format = PA_SAMPLE_S16LE; + ss.rate = 32000; + ss.channels = 2; + + pa_buffer_attr attr; + attr.maxlength = (1600 + 544 + 528 + 1600) * 4; + attr.tlength = (528*2 + 544) * 4; + attr.prebuf = 1500 * 4; + attr.minreq = 161 * 4; + attr.fragsize = (uint32_t)-1; + + m_Stream = pa_stream_new(m_Context, "zelda", &ss, NULL); + if (m_Stream == NULL) { + goto fail; + } + + done = false; + pa_stream_set_state_callback(m_Stream, pas_stream_state_cb, &done); + pa_stream_set_write_callback(m_Stream, pas_stream_write_cb, NULL); + if (pa_stream_connect_playback(m_Stream, NULL, &attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) { + goto fail; + } + + while (!done) { + pa_mainloop_iterate(m_MainLoop, true, NULL); + } + pa_stream_set_state_callback(m_Stream, NULL, NULL); + if (pa_stream_get_state(m_Stream) != PA_STREAM_READY) { + goto fail; + } + + applied_attr = pa_stream_get_buffer_attr(m_Stream); + SPDLOG_TRACE("maxlength: {}\ntlength: {}\nprebuf: {}\nminreq: {}\nfragsize: {}\n", + applied_attr->maxlength, applied_attr->tlength, applied_attr->prebuf, applied_attr->minreq, applied_attr->fragsize); + m_Attr = *applied_attr; + + return true; + + fail: + if (m_Stream != NULL) { + pa_stream_unref(m_Stream); + m_Stream = NULL; + } + if (m_Context != NULL) { + pa_context_disconnect(m_Context); + pa_context_unref(m_Context); + m_Context = NULL; + } + if (m_MainLoop != NULL) { + pa_mainloop_free(m_MainLoop); + m_MainLoop = NULL; + } + return false; + } + + int PulseAudioPlayer::Buffered() + { + if (m_Stream == NULL) { + return 0; + } + + bool done = false; + pa_stream_update_timing_info(m_Stream, pas_update_complete, &done); + while (!done) { + pa_mainloop_iterate(m_MainLoop, true, NULL); + } + + const pa_timing_info *info = pa_stream_get_timing_info(m_Stream); + if (info == NULL) { + SPDLOG_ERROR("pa_stream_get_timing_info failed, state is %d\n", pa_stream_get_state(m_Stream)); + } + return (info->write_index - info->read_index) / 4; + } + + int PulseAudioPlayer::GetDesiredBuffered() + { + // return 1100; + return 1680; + } + + void PulseAudioPlayer::Play(const uint8_t* buff, uint32_t len) + { + size_t ws = m_Attr.maxlength - Buffered() * 4; + if (ws < len) { + len = ws; + } + if (pa_stream_write_ext_free(m_Stream, buff, len, pas_write_complete, &m_WriteComplete, 0LL, PA_SEEK_RELATIVE) < 0) { + SPDLOG_ERROR("pa_stream_write failed"); + return; + } + while (!m_WriteComplete) { + pa_mainloop_iterate(m_MainLoop, true, NULL); + } + m_WriteComplete = false; + } +} + +#endif \ No newline at end of file diff --git a/libultraship/libultraship/PulseAudioPlayer.h b/libultraship/libultraship/PulseAudioPlayer.h new file mode 100644 index 000000000..7bc72b097 --- /dev/null +++ b/libultraship/libultraship/PulseAudioPlayer.h @@ -0,0 +1,26 @@ +#pragma once + +#if defined(__linux__) || defined(__BSD__) + +#include "AudioPlayer.h" +#include + +namespace Ship { + class PulseAudioPlayer : public AudioPlayer { + public: + PulseAudioPlayer() {} + + bool Init() override; + int Buffered() override; + int GetDesiredBuffered() override; + void Play(const uint8_t* buff, uint32_t len) override; + + private: + pa_context* m_Context = nullptr; + pa_stream* m_Stream = nullptr; + pa_mainloop* m_MainLoop = nullptr; + bool m_WriteComplete = false; + pa_buffer_attr m_Attr = {0}; + }; +} +#endif diff --git a/libultraship/libultraship/Resource.cpp b/libultraship/libultraship/Resource.cpp index 5bdfc5efd..04fc2bfbb 100644 --- a/libultraship/libultraship/Resource.cpp +++ b/libultraship/libultraship/Resource.cpp @@ -2,8 +2,8 @@ #include "DisplayList.h" #include "ResourceMgr.h" #include "Utils/BinaryReader.h" -#include "lib/tinyxml2/tinyxml2.h" -#include "lib/Fast3D/U64/PR/ultra64/gbi.h" +#include "Lib/tinyxml2/tinyxml2.h" +#include "Lib/Fast3D/U64/PR/ultra64/gbi.h" namespace Ship { @@ -25,7 +25,7 @@ namespace Ship void ResourceFile::WriteFileBinary(BinaryWriter* writer, Resource* res) { - + } void ResourceFile::WriteFileXML(tinyxml2::XMLElement* writer, Resource* res) @@ -35,17 +35,17 @@ namespace Ship Resource::~Resource() { - free(cachedGameAsset); + free(cachedGameAsset); cachedGameAsset = nullptr; - for (int i = 0; i < patches.size(); i++) + for (size_t i = 0; i < patches.size(); i++) { std::string hashStr = resMgr->HashToString(patches[i].crc); auto resShared = resMgr->GetCachedFile(hashStr); if (resShared != nullptr) { auto res = (Ship::DisplayList*)resShared.get(); - + Gfx* gfx = (Gfx*)&res->instructions[patches[i].index]; gfx->words.w1 = patches[i].origData; } diff --git a/libultraship/libultraship/Resource.h b/libultraship/libultraship/Resource.h index 1df5c5ed7..ae8dc6ce5 100644 --- a/libultraship/libultraship/Resource.h +++ b/libultraship/libultraship/Resource.h @@ -6,7 +6,7 @@ #include "GlobalCtx2.h" #include "StrHash.h" #include "File.h" -#include "lib/tinyxml2/tinyxml2.h" +#include "Lib/tinyxml2/tinyxml2.h" namespace Ship { @@ -101,10 +101,10 @@ namespace Ship class ResourcePromise { public: - std::shared_ptr Resource; - std::shared_ptr File; - std::condition_variable ResourceLoadNotifier; - std::mutex ResourceLoadMutex; + std::shared_ptr resource; + std::shared_ptr file; + std::condition_variable resourceLoadNotifier; + std::mutex resourceLoadMutex; bool bHasResourceLoaded = false; }; } \ No newline at end of file diff --git a/libultraship/libultraship/ResourceMgr.cpp b/libultraship/libultraship/ResourceMgr.cpp index b4d7b76a8..de0296d12 100644 --- a/libultraship/libultraship/ResourceMgr.cpp +++ b/libultraship/libultraship/ResourceMgr.cpp @@ -43,7 +43,7 @@ namespace Ship { const std::lock_guard ResLock(ResourceLoadMutex); bIsRunning = false; } - + FileLoadNotifier.notify_all(); ResourceLoadNotifier.notify_all(); FileLoadThread->join(); @@ -89,7 +89,7 @@ namespace Ship { OTR->LoadFile(ToLoad->path, true, ToLoad); //Lock.lock(); - + if (!ToLoad->bHasLoadError) FileCache[ToLoad->path] = ToLoad->bIsLoaded && !ToLoad->bHasLoadError ? ToLoad : nullptr; @@ -124,15 +124,15 @@ namespace Ship { // Wait for the underlying File to complete loading { - std::unique_lock FileLock(ToLoad->File->FileLoadMutex); - while (!ToLoad->File->bIsLoaded && !ToLoad->File->bHasLoadError) { - ToLoad->File->FileLoadNotifier.wait(FileLock); + std::unique_lock FileLock(ToLoad->file->FileLoadMutex); + while (!ToLoad->file->bIsLoaded && !ToLoad->file->bHasLoadError) { + ToLoad->file->FileLoadNotifier.wait(FileLock); } } - if (!ToLoad->File->bHasLoadError) + if (!ToLoad->file->bHasLoadError) { - auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->File); + auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->file); if (UnmanagedRes != nullptr) { @@ -140,13 +140,13 @@ namespace Ship { auto Res = std::shared_ptr(UnmanagedRes); if (Res != nullptr) { - std::unique_lock Lock(ToLoad->ResourceLoadMutex); + std::unique_lock Lock(ToLoad->resourceLoadMutex); ToLoad->bHasResourceLoaded = true; - ToLoad->Resource = Res; + ToLoad->resource = Res; ResourceCache[Res->file->path] = Res; - SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->File->path); + SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path); // Disabled for now because it can cause random crashes //FileCache[Res->File->path] = nullptr; @@ -155,9 +155,9 @@ namespace Ship { } else { ToLoad->bHasResourceLoaded = false; - ToLoad->Resource = nullptr; + ToLoad->resource = nullptr; - SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->File->path); + SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path); } //ResLock.lock(); @@ -167,10 +167,10 @@ namespace Ship { else { ToLoad->bHasResourceLoaded = false; - ToLoad->Resource = nullptr; + ToLoad->resource = nullptr; } - ToLoad->ResourceLoadNotifier.notify_all(); + ToLoad->resourceLoadNotifier.notify_all(); } SPDLOG_INFO("Resource Manager LoadResourceThread ended"); @@ -232,17 +232,17 @@ namespace Ship { if (!Promise->bHasResourceLoaded) { - std::unique_lock Lock(Promise->ResourceLoadMutex); + std::unique_lock Lock(Promise->resourceLoadMutex); while (!Promise->bHasResourceLoaded) { - Promise->ResourceLoadNotifier.wait(Lock); + Promise->resourceLoadNotifier.wait(Lock); } } - return Promise->Resource; + return Promise->resource; } std::shared_ptr ResourceMgr::LoadResourceAsync(std::string FilePath) { - StringHelper::ReplaceOriginal(FilePath, "/", "\\"); + StringHelper::ReplaceOriginal(FilePath, "\\", "/"); if (StringHelper::StartsWith(FilePath, "__OTR__")) FilePath = StringHelper::Split(FilePath, "__OTR__")[1]; @@ -257,9 +257,9 @@ namespace Ship { } std::shared_ptr FileData = LoadFile(FilePath); - Promise->File = FileData; + Promise->file = FileData; - if (Promise->File->bHasLoadError) + if (Promise->file->bHasLoadError) { Promise->bHasResourceLoaded = true; } @@ -271,7 +271,7 @@ namespace Ship { } } else { Promise->bHasResourceLoaded = true; - Promise->Resource = resCacheFind->second; + Promise->resource = resCacheFind->second; } return Promise; @@ -295,37 +295,37 @@ namespace Ship { auto PromiseList = CacheDirectoryAsync(SearchMask); auto LoadedList = std::make_shared>>(); - for (int32_t i = 0; i < PromiseList->size(); i++) { + for (size_t i = 0; i < PromiseList->size(); i++) { auto Promise = PromiseList->at(i); - std::unique_lock Lock(Promise->ResourceLoadMutex); + std::unique_lock Lock(Promise->resourceLoadMutex); while (!Promise->bHasResourceLoaded) { - Promise->ResourceLoadNotifier.wait(Lock); + Promise->resourceLoadNotifier.wait(Lock); } - LoadedList->push_back(Promise->Resource); + LoadedList->push_back(Promise->resource); } return LoadedList; } - std::shared_ptr>> ResourceMgr::DirtyDirectory(std::string SearchMask) + std::shared_ptr>> ResourceMgr::DirtyDirectory(std::string SearchMask) { auto PromiseList = CacheDirectoryAsync(SearchMask); auto LoadedList = std::make_shared>>(); - for (int32_t i = 0; i < PromiseList->size(); i++) { + for (size_t i = 0; i < PromiseList->size(); i++) { auto Promise = PromiseList->at(i); - std::unique_lock Lock(Promise->ResourceLoadMutex); + std::unique_lock Lock(Promise->resourceLoadMutex); while (!Promise->bHasResourceLoaded) { - Promise->ResourceLoadNotifier.wait(Lock); + Promise->resourceLoadNotifier.wait(Lock); } - if (Promise->Resource != nullptr) - Promise->Resource->isDirty = true; + if (Promise->resource != nullptr) + Promise->resource->isDirty = true; - LoadedList->push_back(Promise->Resource); + LoadedList->push_back(Promise->resource); } return LoadedList; diff --git a/libultraship/libultraship/ResourceMgr.h b/libultraship/libultraship/ResourceMgr.h index 5eae61abe..28e77e537 100644 --- a/libultraship/libultraship/ResourceMgr.h +++ b/libultraship/libultraship/ResourceMgr.h @@ -28,7 +28,7 @@ namespace Ship std::string HashToString(uint64_t Hash); void InvalidateResourceCache(); - + uint32_t GetGameVersion(); void SetGameVersion(uint32_t newGameVersion); std::shared_ptr LoadFileAsync(std::string FilePath); @@ -48,6 +48,7 @@ namespace Ship private: std::weak_ptr Context; + volatile bool bIsRunning; std::map> FileCache; std::map> ResourceCache; std::queue> FileLoadQueue; @@ -59,7 +60,6 @@ namespace Ship std::mutex ResourceLoadMutex; std::condition_variable FileLoadNotifier; std::condition_variable ResourceLoadNotifier; - volatile bool bIsRunning; uint32_t gameVersion; }; } \ No newline at end of file diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index 50bc5eabb..ab2c48b30 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -61,17 +61,17 @@ namespace Ship { if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) { auto NewCont = SDL_GameControllerOpen(i); - if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) - { - SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE); - } - // We failed to load the controller. Go to next. if (NewCont == nullptr) { SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError()); continue; } + if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) + { + SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE); + } + guid = NewGuid; Cont = NewCont; @@ -101,7 +101,7 @@ namespace Ship { } bool SDLController::Close() { - if (SDL_GameControllerHasRumble(Cont)) { + if (CanRumble()) { SDL_GameControllerRumble(Cont, 0, 0, 0); } if (Cont != nullptr) { @@ -190,7 +190,7 @@ namespace Ship { if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO)) { size_t contNumber = GetControllerNumber(); - + float gyroData[3]; SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3); @@ -347,7 +347,7 @@ namespace Ship { void SDLController::WriteToSource(ControllerCallback* controller) { - if (SDL_GameControllerHasRumble(Cont)) { + if (CanRumble()) { if (controller->rumble > 0) { float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f); SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0); diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h index 138466a89..fbffa478f 100644 --- a/libultraship/libultraship/SDLController.h +++ b/libultraship/libultraship/SDLController.h @@ -13,7 +13,12 @@ namespace Ship { void ReadFromSource(); void WriteToSource(ControllerCallback* controller); bool Connected() const { return Cont != nullptr; } - bool CanRumble() const { return SDL_GameControllerHasRumble(Cont); } + bool CanRumble() const { +#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18) + return SDL_GameControllerHasRumble(Cont); +#endif + return true; + } std::string GetGuid() { return guid; }; @@ -30,8 +35,8 @@ namespace Ship { static bool IsGuidInUse(const std::string& guid); private: - std::string guid; SDL_GameController* Cont; + std::string guid; std::map ThresholdMapping; void LoadAxisThresholds(); diff --git a/libultraship/libultraship/Scene.cpp b/libultraship/libultraship/Scene.cpp index 9468e3a59..17d2b6976 100644 --- a/libultraship/libultraship/Scene.cpp +++ b/libultraship/libultraship/Scene.cpp @@ -137,8 +137,8 @@ namespace Ship y = 0; z = 0; unk_06 = 0; - opa; - xlu; + // opa; + // xlu; } SetMesh::SetMesh(BinaryReader* reader) : SceneCommand(reader) @@ -398,18 +398,18 @@ namespace Ship LightInfo light = LightInfo(); light.type = reader->ReadUByte(); - + light.x = reader->ReadInt16(); - light.y = reader->ReadInt16(); + light.y = reader->ReadInt16(); light.z = reader->ReadInt16(); light.r = reader->ReadUByte(); light.g = reader->ReadUByte(); light.b = reader->ReadUByte(); - + light.drawGlow = reader->ReadUByte(); light.radius = reader->ReadInt16(); - + lights.push_back(light); } } diff --git a/libultraship/libultraship/SkeletonLimb.cpp b/libultraship/libultraship/SkeletonLimb.cpp index 5020fe8f5..75fd46780 100644 --- a/libultraship/libultraship/SkeletonLimb.cpp +++ b/libultraship/libultraship/SkeletonLimb.cpp @@ -15,7 +15,7 @@ namespace Ship limb->skinVtxCnt = reader->ReadUInt16(); uint32_t skinCnt = reader->ReadUInt32(); - for (int i = 0; i < skinCnt; i++) + for (size_t i = 0; i < skinCnt; i++) { Struct_800A598C struc; diff --git a/libultraship/libultraship/SohConsole.cpp b/libultraship/libultraship/SohConsole.cpp index 618cd1e1d..6f04bc917 100644 --- a/libultraship/libultraship/SohConsole.cpp +++ b/libultraship/libultraship/SohConsole.cpp @@ -16,7 +16,7 @@ std::map BindingToggle; static bool HelpCommand(const std::vector&) { INFO("SoH Commands:"); for(const auto& cmd : SohImGui::console->Commands) { - INFO((" - " + cmd.first).c_str()); + INFO("%s", (" - " + cmd.first).c_str()); } return CMD_SUCCESS; } @@ -35,7 +35,7 @@ std::string toLowerCase(std::string in) { static bool BindCommand(const std::vector& args) { if(args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; - for (int k = 0; k < std::size(io->KeysData); k++) { + for (size_t k = 0; k < std::size(io->KeysData); k++) { std::string key(ImGui::GetKeyName(k)); if(toLowerCase(args[1]) == toLowerCase(key)) { @@ -55,7 +55,7 @@ static bool BindCommand(const std::vector& args) { static bool BindToggleCommand(const std::vector& args) { if (args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; - for (int k = 0; k < std::size(io->KeysData); k++) { + for (size_t k = 0; k < std::size(io->KeysData); k++) { std::string key(ImGui::GetKeyName(k)); if (toLowerCase(args[1]) == toLowerCase(key)) { @@ -92,7 +92,7 @@ void Console::Update() { } for (auto [key, var] : BindingToggle) { if (ImGui::IsKeyPressed(key)) { - CVar* cvar = CVar_GetVar(var.c_str()); + CVar* cvar = CVar_Get(var.c_str()); Dispatch("set " + var + " " + std::to_string(cvar == nullptr ? 0 : !static_cast(cvar->value.valueS32))); } } @@ -106,7 +106,7 @@ void Console::Draw() { if (!this->opened) return; ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - ImGui::Begin("Console", &this->opened); + ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); const ImVec2 pos = ImGui::GetWindowPos(); const ImVec2 size = ImGui::GetWindowSize(); @@ -177,8 +177,10 @@ void Console::Draw() { for (const auto& filter : priority_filters) { const bool is_selected = (filter == std::string(this->level_filter)); if (ImGui::Selectable(filter.c_str(), is_selected)) + { this->level_filter = filter; if (is_selected) ImGui::SetItemDefaultFocus(); + } } ImGui::EndCombo(); } @@ -194,7 +196,7 @@ void Console::Draw() { if (ImGui::BeginTable("History", 1)) { if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow))) - if (this->selectedId < this->Log.size() - 1) ++this->selectedId; + if (this->selectedId < (int)this->Log.size() - 1) ++this->selectedId; if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) if (this->selectedId > 0) --this->selectedId; @@ -226,7 +228,7 @@ void Console::Draw() { ImGui::EndChild(); // Renders input textfield - constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | + constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; ImGui::PushItemWidth(-1); if(ImGui::InputTextWithHint("CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { @@ -317,7 +319,7 @@ int Console::CallbackStub(ImGuiInputTextCallbackData* data) { return 0; } -void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4) { +void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) { char buf[1024]; va_list args; va_start(args, fmt); diff --git a/libultraship/libultraship/SohConsole.h b/libultraship/libultraship/SohConsole.h index 57ad182f8..bfbffd0b9 100644 --- a/libultraship/libultraship/SohConsole.h +++ b/libultraship/libultraship/SohConsole.h @@ -7,10 +7,10 @@ #include "Lib/ImGui/imgui.h" -#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, __VA_ARGS__) -#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, __VA_ARGS__) -#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, __VA_ARGS__) -#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, __VA_ARGS__) +#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, ##__VA_ARGS__) +#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, ##__VA_ARGS__) +#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, ##__VA_ARGS__) +#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, ##__VA_ARGS__) #define CMD_SUCCESS true #define CMD_FAILED false #define MAX_BUFFER_SIZE 255 @@ -75,7 +75,7 @@ public: void Init(); void Update(); void Draw(); - void Append(const std::string& channel, Priority priority, const char* fmt, ...); + void Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4); void Dispatch(const std::string& line); static int CallbackStub(ImGuiInputTextCallbackData* data); }; \ No newline at end of file diff --git a/libultraship/libultraship/SohHooks.cpp b/libultraship/libultraship/SohHooks.cpp index d40ab87e2..7ede525d7 100644 --- a/libultraship/libultraship/SohHooks.cpp +++ b/libultraship/libultraship/SohHooks.cpp @@ -24,7 +24,7 @@ namespace ModInternal { bool handleHook(std::shared_ptr call) { std::string hookName = std::string(call->name); - for (int l = 0; l < listeners[hookName].size(); l++) { + for (size_t l = 0; l < listeners[hookName].size(); l++) { (listeners[hookName][l])(call); } return call->cancelled; diff --git a/libultraship/libultraship/SohHooks.h b/libultraship/libultraship/SohHooks.h index 111f789d0..9a41eeb0e 100644 --- a/libultraship/libultraship/SohHooks.h +++ b/libultraship/libultraship/SohHooks.h @@ -47,6 +47,7 @@ struct HookParameter { #include #include #include +#include struct HookCall { std::string name; diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index af9252927..95d743f1f 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -18,6 +18,7 @@ #include "TextureMod.h" #include "Window.h" #include "Cvar.h" +#include "GameOverlay.h" #include "Texture.h" #include "../Fast3D/gfx_pc.h" #include "Lib/stb/stb_image.h" @@ -43,6 +44,11 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPAR using namespace Ship; bool oldCursorState = true; +#define EXPERIMENTAL() \ + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 50, 50, 255)); \ + ImGui::Text("Experimental"); \ + ImGui::PopStyleColor(); \ + ImGui::Separator(); #define TOGGLE_BTN ImGuiKey_F1 #define HOOK(b) if(b) needs_save = true; OSContPad* pads; @@ -54,8 +60,10 @@ namespace SohImGui { WindowImpl impl; ImGuiIO* io; Console* console = new Console; + GameOverlay* overlay = new GameOverlay; bool p_open = false; bool needs_save = false; + std::vector CustomTexts; int SelectedLanguage = CVar_GetS32("gLanguages", 0); //Default Language to 0=English 1=German 2=French int SelectedHUD = CVar_GetS32("gHudColors", 1); //Default colors to Gamecube. float hearts_colors[3] = {0,0,0}; @@ -69,6 +77,7 @@ namespace SohImGui { float magic_use_colors[3] = {0,0,0}; float minimap_colors[3] = {0,0,0}; float rupee_colors[3] = {0,0,0}; + float smolekey_colors[3] = {0,0,0}; float kokiri_col[3] = { 0.118f, 0.41f, 0.106f }; float goron_col[3] = { 0.392f, 0.078f, 0.0f }; float zora_col[3] = { 0.0f, 0.235f, 0.392f }; @@ -81,6 +90,12 @@ namespace SohImGui { float navi_prop_i_col[3] = { 0.0f, 0.0f, 0.0f }; float navi_prop_o_col[3] = { 0.0f, 0.0f, 0.0f }; + const char* filters[3] = { + "Three-Point", + "Linear", + "None" + }; + std::map> windowCategories; std::map customWindows; @@ -89,11 +104,15 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplSDL2_InitForOpenGL(static_cast(impl.sdl.window), impl.sdl.context); break; +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplWin32_Init(impl.dx11.window); break; +#endif + default: + break; } - + } void ImGuiBackendInit() { @@ -101,9 +120,14 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplOpenGL3_Init("#version 120"); break; + +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplDX11_Init(static_cast(impl.dx11.device), static_cast(impl.dx11.device_context)); break; +#endif + default: + break; } } @@ -112,9 +136,13 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplSDL2_ProcessEvent(static_cast(event.sdl.event)); break; +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplWin32_WndProcHandler(static_cast(event.win32.handle), event.win32.msg, event.win32.wparam, event.win32.lparam); break; +#endif + default: + break; } } @@ -123,9 +151,13 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplSDL2_NewFrame(static_cast(impl.sdl.window)); break; +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplWin32_NewFrame(); break; +#endif + default: + break; } } @@ -134,9 +166,13 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplOpenGL3_NewFrame(); break; +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplDX11_NewFrame(); break; +#endif + default: + break; } } @@ -145,9 +181,13 @@ namespace SohImGui { case Backend::SDL: ImGui_ImplOpenGL3_RenderDrawData(data); break; +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) case Backend::DX11: ImGui_ImplDX11_RenderDrawData(data); break; +#endif + default: + break; } } @@ -155,17 +195,18 @@ namespace SohImGui { switch (impl.backend) { case Backend::DX11: return true; + default: + return false; } - return false; } - void SohImGui::ShowCursor(bool hide, Dialogues d) { + void ShowCursor(bool hide, Dialogues d) { if (d == Dialogues::dLoadSettings) { GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(hide); return; } - if (d == Dialogues::dConsole && Game::Settings.debug.menu_bar) { + if (d == Dialogues::dConsole && CVar_GetS32("gOpenMenuBar", 0)) { return; } if (!GlobalCtx2::GetInstance()->GetWindow()->IsFullscreen()) { @@ -181,7 +222,7 @@ namespace SohImGui { void LoadTexture(const std::string& name, const std::string& path) { GfxRenderingAPI* api = gfx_get_current_rendering_api(); - const auto res = GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(normalize(path)); + const auto res = GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(path); const auto asset = new GameAsset{ api->new_texture() }; uint8_t* img_data = stbi_load_from_memory(reinterpret_cast(res->buffer.get()), res->dwBufferSize, &asset->width, &asset->height, nullptr, 4); @@ -199,9 +240,88 @@ namespace SohImGui { stbi_image_free(img_data); } + void LoadInterfaceEditor(){//This function is necessary as without it IMGui wont load the updated float array. + hearts_colors[0] = (float)CVar_GetS32("gCCHeartsPrimR", 255)/255; + hearts_colors[1] = (float)CVar_GetS32("gCCHeartsPrimG", 70)/255; + hearts_colors[2] = (float)CVar_GetS32("gCCHeartsPrimB", 50)/255; + hearts_dd_colors[0] = (float)CVar_GetS32("gDDCCHeartsPrimR", 255)/255; + hearts_dd_colors[1] = (float)CVar_GetS32("gDDCCHeartsPrimG", 255)/255; + hearts_dd_colors[2] = (float)CVar_GetS32("gDDCCHeartsPrimB", 255)/255; + a_btn_colors[0] = (float)CVar_GetS32("gCCABtnPrimR", 90)/255; + a_btn_colors[1] = (float)CVar_GetS32("gCCABtnPrimG", 90)/255; + a_btn_colors[2] = (float)CVar_GetS32("gCCABtnPrimB", 255)/255; + b_btn_colors[0] = (float)CVar_GetS32("gCCBBtnPrimR", 0)/255; + b_btn_colors[1] = (float)CVar_GetS32("gCCBBtnPrimG", 150)/255; + b_btn_colors[2] = (float)CVar_GetS32("gCCBBtnPrimB", 0)/255; + c_btn_colors[0] = (float)CVar_GetS32("gCCCBtnPrimR", 255)/255; + c_btn_colors[1] = (float)CVar_GetS32("gCCCBtnPrimG", 160)/255; + c_btn_colors[2] = (float)CVar_GetS32("gCCCBtnPrimB", 0)/255; + start_btn_colors[0] = (float)CVar_GetS32("gCCStartBtnPrimR", 120)/255; + start_btn_colors[1] = (float)CVar_GetS32("gCCStartBtnPrimG", 120)/255; + start_btn_colors[2] = (float)CVar_GetS32("gCCStartBtnPrimB", 120)/255; + magic_border_colors[0] = (float)CVar_GetS32("gCCMagicBorderPrimR", 255)/255; + magic_border_colors[1] = (float)CVar_GetS32("gCCMagicBorderPrimG", 255)/255; + magic_border_colors[2] = (float)CVar_GetS32("gCCMagicBorderPrimB", 255)/255; + magic_use_colors[0] = (float)CVar_GetS32("gCCMagicPrimR", 250)/255; + magic_use_colors[1] = (float)CVar_GetS32("gCCMagicPrimG", 250)/255; + magic_use_colors[2] = (float)CVar_GetS32("gCCMagicPrimB", 0)/255; + magic_remaining_colors[0] = (float)CVar_GetS32("gCCMagicUsePrimR", 0)/255; + magic_remaining_colors[1] = (float)CVar_GetS32("gCCMagicUsePrimG", 200)/255; + magic_remaining_colors[2] = (float)CVar_GetS32("gCCMagicUsePrimB", 0)/255; + minimap_colors[0] = (float)CVar_GetS32("gCCMinimapPrimR", 0)/255; + minimap_colors[1] = (float)CVar_GetS32("gCCMinimapPrimG", 255)/255; + minimap_colors[2] = (float)CVar_GetS32("gCCMinimapPrimB", 255)/255; + rupee_colors[0] = (float)CVar_GetS32("gCCRupeePrimR", 120)/255; + rupee_colors[1] = (float)CVar_GetS32("gCCRupeePrimG", 120)/255; + rupee_colors[2] = (float)CVar_GetS32("gCCRupeePrimB", 120)/255; + smolekey_colors[0] = (float)CVar_GetS32("gCCKeysPrimR", 200)/255; + smolekey_colors[1] = (float)CVar_GetS32("gCCKeysPrimG", 230)/255; + smolekey_colors[2] = (float)CVar_GetS32("gCCKeysPrimB", 255)/255; + kokiri_col[0] = (float)CVar_GetS32("gTunic_Kokiri_R", 30)/255; + kokiri_col[1] = (float)CVar_GetS32("gTunic_Kokiri_G", 105)/255; + kokiri_col[2] = (float)CVar_GetS32("gTunic_Kokiri_B", 27)/255; + goron_col[0] = (float)CVar_GetS32("gTunic_Goron_R", 100)/255; + goron_col[1] = (float)CVar_GetS32("gTunic_Goron_G", 20)/255; + goron_col[2] = (float)CVar_GetS32("gTunic_Goron_B", 0)/255; + zora_col[0] = (float)CVar_GetS32("gTunic_Zora_R", 0)/255; + zora_col[1] = (float)CVar_GetS32("gTunic_Zora_G", 60)/255; + zora_col[2] = (float)CVar_GetS32("gTunic_Zora_B", 100)/255; + navi_idle_i_col[0] = (float)CVar_GetS32("gNavi_Idle_Inner_R", 255)/255; + navi_idle_i_col[1] = (float)CVar_GetS32("gNavi_Idle_Inner_G", 255)/255; + navi_idle_i_col[2] = (float)CVar_GetS32("gNavi_Idle_Inner_B", 255)/255; + navi_idle_o_col[0] = (float)CVar_GetS32("gNavi_Idle_Outer_R", 115)/255; + navi_idle_o_col[1] = (float)CVar_GetS32("gNavi_Idle_Outer_G", 230)/255; + navi_idle_o_col[2] = (float)CVar_GetS32("gNavi_Idle_Outer_B", 255)/255; + navi_npc_i_col[0] = (float)CVar_GetS32("gNavi_NPC_Inner_R", 100)/255; + navi_npc_i_col[1] = (float)CVar_GetS32("gNavi_NPC_Inner_G", 100)/255; + navi_npc_i_col[2] = (float)CVar_GetS32("gNavi_NPC_Inner_B", 255)/255; + navi_npc_o_col[0] = (float)CVar_GetS32("gNavi_NPC_Outer_R", 90)/255; + navi_npc_o_col[1] = (float)CVar_GetS32("gNavi_NPC_Outer_G", 90)/255; + navi_npc_o_col[2] = (float)CVar_GetS32("gNavi_NPC_Outer_B", 255)/255; + navi_enemy_i_col[0] = (float)CVar_GetS32("gNavi_Enemy_Inner_R", 255)/255; + navi_enemy_i_col[1] = (float)CVar_GetS32("gNavi_Enemy_Inner_G", 255)/255; + navi_enemy_i_col[2] = (float)CVar_GetS32("gNavi_Enemy_Inner_B", 0)/255; + navi_enemy_o_col[0] = (float)CVar_GetS32("gNavi_Enemy_Outer_R", 220)/255; + navi_enemy_o_col[1] = (float)CVar_GetS32("gNavi_Enemy_Outer_G", 220)/255; + navi_enemy_o_col[2] = (float)CVar_GetS32("gNavi_Enemy_Outer_B", 0)/255; + navi_prop_i_col[0] = (float)CVar_GetS32("gNavi_Prop_Inner_R", 0)/255; + navi_prop_i_col[1] = (float)CVar_GetS32("gNavi_Prop_Inner_G", 255)/255; + navi_prop_i_col[2] = (float)CVar_GetS32("gNavi_Prop_Inner_B", 0)/255; + navi_prop_o_col[0] = (float)CVar_GetS32("gNavi_Prop_Outer_R", 0)/255; + navi_prop_o_col[1] = (float)CVar_GetS32("gNavi_Prop_Outer_G", 220)/255; + navi_prop_o_col[2] = (float)CVar_GetS32("gNavi_Prop_Outer_B", 0)/255; + if (CVar_GetS32("gHudColors", 1) ==0) { + SelectedHUD = 0; + } else if (CVar_GetS32("gHudColors", 1) == 1) { + SelectedHUD = 1; + } else if (CVar_GetS32("gHudColors", 1) == 2) { + SelectedHUD = 2; + } + } + void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint) { GfxRenderingAPI* api = gfx_get_current_rendering_api(); - const auto res = static_cast(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(normalize(path)).get()); + const auto res = static_cast(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(path).get()); std::vector texBuffer; texBuffer.reserve(res->width * res->height * 4); @@ -243,97 +363,27 @@ namespace SohImGui { DefaultAssets[name] = asset; } - void LoadCosmeticColors(){//This function is necessary as without it IMGui wont load the updated float array. - hearts_colors[0] = (float)CVar_GetS32("gCCHeartsPrimR", 255)/255; - hearts_colors[1] = (float)CVar_GetS32("gCCHeartsPrimG", 10)/255; - hearts_colors[2] = (float)CVar_GetS32("gCCHeartsPrimB", 10)/255; - hearts_dd_colors[0] = (float)CVar_GetS32("gDDCCHeartsPrimR", 255)/255; - hearts_dd_colors[1] = (float)CVar_GetS32("gDDCCHeartsPrimG", 255)/255; - hearts_dd_colors[2] = (float)CVar_GetS32("gDDCCHeartsPrimB", 255)/255; - a_btn_colors[0] = (float)CVar_GetS32("gCCABtnPrimR", 90)/255; - a_btn_colors[1] = (float)CVar_GetS32("gCCABtnPrimG", 90)/255; - a_btn_colors[2] = (float)CVar_GetS32("gCCABtnPrimB", 255)/255; - b_btn_colors[0] = (float)CVar_GetS32("gCCBBtnPrimR", 0)/255; - b_btn_colors[1] = (float)CVar_GetS32("gCCBBtnPrimG", 150)/255; - b_btn_colors[2] = (float)CVar_GetS32("gCCBBtnPrimB", 0)/255; - c_btn_colors[0] = (float)CVar_GetS32("gCCCBtnPrimR", 255)/255; - c_btn_colors[1] = (float)CVar_GetS32("gCCCBtnPrimG", 160)/255; - c_btn_colors[2] = (float)CVar_GetS32("gCCCBtnPrimB", 0)/255; - start_btn_colors[0] = (float)CVar_GetS32("gCCStartBtnPrimR", 120)/255; - start_btn_colors[1] = (float)CVar_GetS32("gCCStartBtnPrimG", 120)/255; - start_btn_colors[2] = (float)CVar_GetS32("gCCStartBtnPrimB", 120)/255; - magic_border_colors[0] = (float)CVar_GetS32("gCCMagicBorderPrimR", 255)/255; - magic_border_colors[1] = (float)CVar_GetS32("gCCMagicBorderPrimG", 255)/255; - magic_border_colors[2] = (float)CVar_GetS32("gCCMagicBorderPrimB", 255)/255; - magic_remaining_colors[0] = (float)CVar_GetS32("gCCMagicPrimR", 250)/255; - magic_remaining_colors[1] = (float)CVar_GetS32("gCCMagicPrimG", 250)/255; - magic_remaining_colors[2] = (float)CVar_GetS32("gCCMagicPrimB", 0)/255; - magic_remaining_colors[0] = (float)CVar_GetS32("gCCMagicUsePrimR", 0)/255; - magic_remaining_colors[1] = (float)CVar_GetS32("gCCMagicUsePrimG", 200)/255; - magic_remaining_colors[2] = (float)CVar_GetS32("gCCMagicUsePrimB", 0)/255; - minimap_colors[0] = (float)CVar_GetS32("gCCMinimapPrimR", 0)/255; - minimap_colors[1] = (float)CVar_GetS32("gCCMinimapPrimG", 255)/255; - minimap_colors[2] = (float)CVar_GetS32("gCCMinimapPrimB", 255)/255; - rupee_colors[0] = (float)CVar_GetS32("gCCRupeePrimR", 120)/255; - rupee_colors[1] = (float)CVar_GetS32("gCCRupeePrimG", 120)/255; - rupee_colors[2] = (float)CVar_GetS32("gCCRupeePrimB", 120)/255; - kokiri_col[0] = (float)CVar_GetS32("gTunic_Kokiri_R", 30)/255; - kokiri_col[1] = (float)CVar_GetS32("gTunic_Kokiri_G", 105)/255; - kokiri_col[2] = (float)CVar_GetS32("gTunic_Kokiri_B", 27)/255; - goron_col[0] = (float)CVar_GetS32("gTunic_Goron_R", 100)/255; - goron_col[1] = (float)CVar_GetS32("gTunic_Goron_G", 20)/255; - goron_col[2] = (float)CVar_GetS32("gTunic_Goron_B", 0)/255; - zora_col[0] = (float)CVar_GetS32("gTunic_Zora_R", 0)/255; - zora_col[1] = (float)CVar_GetS32("gTunic_Zora_G", 60)/255; - zora_col[2] = (float)CVar_GetS32("gTunic_Zora_B", 100)/255; - navi_idle_i_col[0] = (float)CVar_GetS32("gNavi_Idle_Inner_R", 255)/255; - navi_idle_i_col[1] = (float)CVar_GetS32("gNavi_Idle_Inner_G", 255)/255; - navi_idle_i_col[2] = (float)CVar_GetS32("gNavi_Idle_Inner_B", 255)/255; - navi_idle_o_col[0] = (float)CVar_GetS32("gNavi_Idle_Outer_R", 115)/255; - navi_idle_o_col[1] = (float)CVar_GetS32("gNavi_Idle_Outer_G", 230)/255; - navi_idle_o_col[2] = (float)CVar_GetS32("gNavi_Idle_Outer_B", 255)/255; - navi_npc_i_col[0] = (float)CVar_GetS32("gNavi_NPC_Inner_R", 100)/255; - navi_npc_i_col[1] = (float)CVar_GetS32("gNavi_NPC_Inner_G", 100)/255; - navi_npc_i_col[2] = (float)CVar_GetS32("gNavi_NPC_Inner_B", 255)/255; - navi_npc_o_col[0] = (float)CVar_GetS32("gNavi_NPC_Outer_R", 90)/255; - navi_npc_o_col[1] = (float)CVar_GetS32("gNavi_NPC_Outer_G", 90)/255; - navi_npc_o_col[2] = (float)CVar_GetS32("gNavi_NPC_Outer_B", 255)/255; - navi_enemy_i_col[0] = (float)CVar_GetS32("gNavi_Enemy_Inner_R", 255)/255; - navi_enemy_i_col[1] = (float)CVar_GetS32("gNavi_Enemy_Inner_G", 255)/255; - navi_enemy_i_col[2] = (float)CVar_GetS32("gNavi_Enemy_Inner_B", 0)/255; - navi_enemy_o_col[0] = (float)CVar_GetS32("gNavi_Enemy_Outer_R", 220)/255; - navi_enemy_o_col[1] = (float)CVar_GetS32("gNavi_Enemy_Outer_G", 220)/255; - navi_enemy_o_col[2] = (float)CVar_GetS32("gNavi_Enemy_Outer_B", 0)/255; - navi_prop_i_col[0] = (float)CVar_GetS32("gNavi_Prop_Inner_R", 0)/255; - navi_prop_i_col[1] = (float)CVar_GetS32("gNavi_Prop_Inner_G", 255)/255; - navi_prop_i_col[2] = (float)CVar_GetS32("gNavi_Prop_Inner_B", 0)/255; - navi_prop_o_col[0] = (float)CVar_GetS32("gNavi_Prop_Outer_R", 0)/255; - navi_prop_o_col[1] = (float)CVar_GetS32("gNavi_Prop_Outer_G", 220)/255; - navi_prop_o_col[2] = (float)CVar_GetS32("gNavi_Prop_Outer_B", 0)/255; - } - - int ClampFloatToInt(float value, int min, int max){ - return fmin(fmax(value,min),max); - } - void Init(WindowImpl window_impl) { - impl = window_impl; Game::LoadSettings(); + impl = window_impl; ImGuiContext* ctx = ImGui::CreateContext(); ImGui::SetCurrentContext(ctx); io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; + io->Fonts->AddFontDefault(); + if (UseViewports()) { io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; } console->Init(); + overlay->Init(); ImGuiWMInit(); ImGuiBackendInit(); ModInternal::registerHookListener({ GFX_INIT, [](const HookEvent ev) { if (GlobalCtx2::GetInstance()->GetWindow()->IsFullscreen()) - ShowCursor(Game::Settings.debug.menu_bar, Dialogues::dLoadSettings); + ShowCursor(CVar_GetS32("gOpenMenuBar", 0), Dialogues::dLoadSettings); LoadTexture("Game_Icon", "assets/ship_of_harkinian/icons/gSohIcon.png"); LoadTexture("A-Btn", "assets/ship_of_harkinian/buttons/ABtn.png"); @@ -357,9 +407,8 @@ namespace SohImGui { ModInternal::registerHookListener({ CONTROLLER_READ, [](const HookEvent ev) { pads = static_cast(ev->baseArgs["cont_pad"]); - } }); + }}); Game::InitSettings(); - LoadCosmeticColors(); } void Update(EventImpl event) { @@ -372,7 +421,7 @@ namespace SohImGui { #define BindButton(btn, status) ImGui::Image(GetTextureByID(DefaultAssets[btn]->textureId), ImVec2(16.0f * scale, 16.0f * scale), ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, (status) ? 255 : 0)); - void BindAudioSlider(const char* name, const char* key, float defaultValue, SeqPlayers playerId) + void BindAudioSlider(const char* name, const char* key, float defaultValue, SeqPlayers playerId) { float value = CVar_GetFloat(key, defaultValue); @@ -412,13 +461,22 @@ namespace SohImGui { } } + void EnhancementButton(std::string text, std::string cvarName) + { + bool val = (bool)CVar_GetS32(cvarName.c_str(), 0); + if (ImGui::Button(text.c_str())) { + CVar_SetS32(cvarName.c_str(), !val); + needs_save = true; + } + } + void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format) { int val = CVar_GetS32(cvarName.c_str(), 0); ImGui::Text(text.c_str(), val); - if (ImGui::SliderInt(id.c_str(), &val, min, max, format.c_str())) + if (ImGui::SliderInt(id.c_str(), &val, min, max, format.c_str())) { CVar_SetS32(cvarName.c_str(), val); needs_save = true; @@ -469,8 +527,18 @@ namespace SohImGui { } } - void EnhancementColor3(std::string text, std::string cvarName, float ColorRGB[3]) { - if (ImGui::ColorEdit3(text.c_str(), ColorRGB)) { + int ClampFloatToInt(float value, int min, int max){ + return fmin(fmax(value,min),max); + } + + void EnhancementColor3(std::string text, std::string cvarName, float ColorRGB[3], bool TitleSameLine) { + //Simplified. + ImGuiColorEditFlags flags = ImGuiColorEditFlags_None; + if (!TitleSameLine){ + ImGui::Text("%s", text.c_str()); + flags = ImGuiColorEditFlags_NoLabel; + } + if (ImGui::ColorEdit3(text.c_str(), ColorRGB, flags)) { CVar_SetS32((cvarName+"R").c_str(), ClampFloatToInt(ColorRGB[0]*255,0,255)); CVar_SetS32((cvarName+"G").c_str(), ClampFloatToInt(ColorRGB[1]*255,0,255)); CVar_SetS32((cvarName+"B").c_str(), ClampFloatToInt(ColorRGB[2]*255,0,255)); @@ -478,6 +546,12 @@ namespace SohImGui { } } + void Tooltip(std::string text){ + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", text.c_str()); + } + } + void DrawMainMenuAndCalculateGameSize() { console->Update(); ImGuiBackendNewFrame(); @@ -488,7 +562,7 @@ namespace SohImGui { ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize; - if (Game::Settings.debug.menu_bar) window_flags |= ImGuiWindowFlags_MenuBar; + if (CVar_GetS32("gOpenMenuBar", 0)) window_flags |= ImGuiWindowFlags_MenuBar; const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->WorkPos); @@ -516,10 +590,11 @@ namespace SohImGui { ImGui::DockSpace(dockId, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None); if (ImGui::IsKeyPressed(TOGGLE_BTN)) { - Game::Settings.debug.menu_bar = !Game::Settings.debug.menu_bar; + bool menu_bar = CVar_GetS32("gOpenMenuBar", 0); + CVar_SetS32("gOpenMenuBar", !menu_bar); needs_save = true; - GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = Game::Settings.debug.menu_bar; - ShowCursor(Game::Settings.debug.menu_bar, Dialogues::dMenubar); + GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = menu_bar; + ShowCursor(menu_bar, Dialogues::dMenubar); } if (ImGui::BeginMenuBar()) { @@ -588,9 +663,42 @@ namespace SohImGui { ImGui::EndMenu(); } + if (ImGui::BeginMenu("Graphics")) + { + EnhancementSliderInt("Internal Resolution: %dx", "##IMul", "gInternalResolution", 1, 8, ""); + gfx_current_dimensions.internal_mul = CVar_GetS32("gInternalResolution", 1); + EnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, ""); + gfx_msaa_level = CVar_GetS32("gMSAAValue", 1); + + EXPERIMENTAL(); + ImGui::Text("Texture Filter (Needs reload)"); + GfxRenderingAPI* gapi = gfx_get_current_rendering_api(); + if (ImGui::BeginCombo("##filters", filters[gapi->get_texture_filter()])) { + for (int fId = 0; fId <= FilteringMode::NONE; fId++) { + if (ImGui::Selectable(filters[fId], fId == gapi->get_texture_filter())) { + INFO("New Filter: %s", filters[fId]); + gapi->set_texture_filter((FilteringMode)fId); + + CVar_SetS32("gTextureFilter", (int) fId); + needs_save = true; + } + + } + ImGui::EndCombo(); + } + overlay->DrawSettings(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Languages")) { + EnhancementRadioButton("English", "gLanguages", 0); + EnhancementRadioButton("German", "gLanguages", 1); + EnhancementRadioButton("French", "gLanguages", 2); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Enhancements")) { - ImGui::Text("Gameplay"); ImGui::Separator(); @@ -608,36 +716,39 @@ namespace SohImGui { EnhancementCheckbox("N64 Mode", "gN64Mode"); EnhancementCheckbox("Animated Link in Pause Menu", "gPauseLiveLink"); - EnhancementCheckbox("Disable LOD", "gDisableLOD"); EnhancementCheckbox("Enable 3D Dropped items", "gNewDrops"); + EnhancementCheckbox("Faster Block Push", "gFasterBlockPush"); EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon"); EnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon"); - - if (ImGui::BeginMenu("Fixes")) { - EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); - EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon"); - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Developer Tools")) - { - HOOK(ImGui::MenuItem("Stats", nullptr, &Game::Settings.debug.soh)); - HOOK(ImGui::MenuItem("Console", nullptr, &console->opened)); - - ImGui::Text("Debug"); + ImGui::Text("Fixes"); ImGui::Separator(); + EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); + EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon"); - EnhancementCheckbox("Debug Mode", "gDebugEnabled"); + EXPERIMENTAL(); + + EnhancementCheckbox("60 fps interpolation", "g60FPS"); + EnhancementCheckbox("Disable LOD", "gDisableLOD"); ImGui::EndMenu(); } - if (ImGui::BeginMenu("Graphics")) - { - HOOK(ImGui::MenuItem("Anti-aliasing", nullptr, &Game::Settings.graphics.show)); - ImGui::EndMenu(); + if (ImGui::BeginMenu("Cosmetics")) { + EnhancementCheckbox("Cosmetics editor", "gCosmticsEditor"); + Tooltip("Edit Navi and Link's Tunics color."); + EnhancementCheckbox("HUD Margins editor", "gUseMargins"); + EnhancementRadioButton("N64 interface", "gHudColors", 0); + Tooltip("Change interface color to N64 style."); + EnhancementRadioButton("Gamecube interface", "gHudColors", 1); + Tooltip("Change interface color to Gamecube style."); + EnhancementRadioButton("Custom interface", "gHudColors", 2); + Tooltip("Change interface color to your own made style."); + if (CVar_GetS32("gHudColors", 1) == 2) { + EnhancementCheckbox("Interface editor", "gColorsEditor"); + Tooltip("Edit the colors used for your own interface"); + } + ImGui::EndMenu(); } if (ImGui::BeginMenu("Cheats")) @@ -660,141 +771,153 @@ namespace SohImGui { EnhancementCheckbox("Unrestricted Items", "gNoRestrictItems"); EnhancementCheckbox("Freeze Time", "gFreezeTime"); + ImGui::EndMenu(); + } - if (ImGui::Checkbox("Climb Everything", &Game::Settings.cheats.climb_everything)) { - CVar_SetS32("gClimbEverything", Game::Settings.cheats.climb_everything); - needs_save = true; - } - - if (ImGui::Checkbox("Moon Jump on L", &Game::Settings.cheats.moon_jump_on_l)) { - CVar_SetS32("gMoonJumpOnL", Game::Settings.cheats.moon_jump_on_l); - needs_save = true; - } - - if (ImGui::Checkbox("Super Tunic", &Game::Settings.cheats.super_tunic)) { - CVar_SetS32("gSuperTunic", Game::Settings.cheats.super_tunic); - needs_save = true; - } - - if (ImGui::Checkbox("Easy ISG", &Game::Settings.cheats.ez_isg)) { - CVar_SetS32("gEzISG", Game::Settings.cheats.ez_isg); - needs_save = true; - } - - if (ImGui::Checkbox("Unrestricted Items", &Game::Settings.cheats.no_restrict_item)) { - CVar_SetS32("gNoRestrictItem", Game::Settings.cheats.no_restrict_item); - needs_save = true; - } - - if (ImGui::Checkbox("Freeze Time", &Game::Settings.cheats.freeze_time)) { - CVar_SetS32("gFreezeTime", Game::Settings.cheats.freeze_time); - needs_save = true; - } - + if (ImGui::BeginMenu("Developer Tools")) + { + EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); + ImGui::Separator(); + EnhancementCheckbox("Stats", "gStatsEnabled"); + EnhancementCheckbox("Console", "gConsoleEnabled"); + console->opened = CVar_GetS32("gConsoleEnabled", 0); ImGui::EndMenu(); - } - if (CVar_GetS32("gHudColors", 1) ==0) { - SelectedHUD = 0; - } else if (CVar_GetS32("gHudColors", 1) == 1) { - SelectedHUD = 1; - } else if (CVar_GetS32("gHudColors", 1) == 2) { - SelectedHUD = 2; - } - if (ImGui::BeginMenu("Cosmetics")) { - if (ImGui::BeginMenu("Tunics")) { - EnhancementCheckbox("Custom colors on tunics", "gUseTunicsCol"); - EnhancementColor3("Kokiri Tunic", "gTunic_Kokiri_", kokiri_col); - EnhancementColor3("Goron Tunic", "gTunic_Goron_", goron_col); - EnhancementColor3("Zora Tunic", "gTunic_Zora_", zora_col); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Navi")) { - EnhancementCheckbox("Custom colors for Navi", "gUseNaviCol"); - EnhancementColor3("Navi Idle Inner", "gNavi_Idle_Inner_", navi_idle_i_col); - EnhancementColor3("Navi Idle Outer", "gNavi_Idle_Outer_", navi_idle_o_col); - ImGui::Separator(); - EnhancementColor3("Navi NPC Inner", "gNavi_NPC_Inner_", navi_npc_i_col); - EnhancementColor3("Navi NPC Outer", "gNavi_NPC_Outer_", navi_npc_o_col); - ImGui::Separator(); - EnhancementColor3("Navi Enemy Inner", "gNavi_Enemy_Inner_", navi_enemy_i_col); - EnhancementColor3("Navi Enemy Outer", "gNavi_Enemy_Outer_", navi_enemy_o_col); - ImGui::Separator(); - EnhancementColor3("Navi Prop Inner", "gNavi_Prop_Inner_", navi_prop_i_col); - EnhancementColor3("Navi Prop Outer", "gNavi_Prop_Outer_", navi_prop_o_col); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Interface")) { - EnhancementRadioButton("N64 Colors", "gHudColors", 0); - EnhancementRadioButton("Gamecube Colors", "gHudColors", 1); - EnhancementRadioButton("Custom Colors", "gHudColors", 2); - if (ImGui::BeginMenu("Edit HUD Colors")) { - if (ImGui::BeginMenu("Hearts")) { - EnhancementColor3("Hearts normals", "gCCHeartsPrim", hearts_colors); - EnhancementColor3("Hearts double def", "gDDCCHeartsPrim", hearts_dd_colors); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Buttons")) { - EnhancementColor3("A Buttons", "gCCABtnPrim", a_btn_colors); - EnhancementColor3("B Buttons", "gCCBBtnPrim", b_btn_colors); - EnhancementColor3("C Buttons", "gCCCBtnPrim", c_btn_colors); - EnhancementColor3("Start Buttons", "gCCStartBtnPrim", start_btn_colors); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Magic Bar")) { - EnhancementColor3("Magic bar borders", "gCCMagicBorderPrim", magic_border_colors); - EnhancementColor3("Magic bar main color", "gCCMagicPrim", magic_remaining_colors); - EnhancementColor3("Magic bar being used", "gCCMagicUsePrim", magic_use_colors); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Misc")) { - EnhancementColor3("Minimap color", "gCCMinimapPrim", minimap_colors); - EnhancementColor3("Rupee icon color", "gCCRupeePrim", rupee_colors); - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } - HOOK(ImGui::MenuItem("Interface edit", nullptr, &Game::Settings.cosmetics.uiedit)); - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } + bool Margins_isOpen = CVar_GetS32("gUseMargins", 0); + bool Cosmetics_isOpen = CVar_GetS32("gCosmticsEditor", 0); + bool Interface_isOpen = CVar_GetS32("gColorsEditor", 0); - if (Game::Settings.cosmetics.uiedit) { + if (Margins_isOpen) { + if (!Margins_isOpen) { + return; + } ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); - ImGui::Begin("Interface modifier", nullptr, ImGuiWindowFlags_None); - EnhancementCheckbox("Use margins", "gHUDMargins"); - EnhancementSliderInt("Top : %dx", "##UIMARGINT", "gHUDMargin_T", -20, 20, ""); - EnhancementSliderInt("Left: %dx", "##UIMARGINL", "gHUDMargin_L", -25, 25, ""); - EnhancementSliderInt("Right: %dx", "##UIMARGINR", "gHUDMargin_R", -25, 25, ""); - EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", "gHUDMargin_B", -20, 20, ""); - ImGui::End(); + ImGui::Begin("Margins Editor", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); + if (ImGui::BeginTabBar("Margins Editor", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + if (ImGui::BeginTabItem("Interface margins")) { + EnhancementCheckbox("Use margins", "gHUDMargins"); + Tooltip("Enable/Disable custom margins. \nIf disabled you will have original margins."); + EnhancementSliderInt("Top : %dx", "##UIMARGINT", "gHUDMargin_T", -20, 20, ""); + EnhancementSliderInt("Left: %dx", "##UIMARGINL", "gHUDMargin_L", -25, 25, ""); + EnhancementSliderInt("Right: %dx", "##UIMARGINR", "gHUDMargin_R", -25, 25, ""); + EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", "gHUDMargin_B", -20, 20, ""); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } ImGui::PopStyleColor(); + ImGui::End(); } - - if (CVar_GetS32("gLanguages", 0) == 0) { - SelectedLanguage = 0; - } else if (CVar_GetS32("gLanguages", 0) == 1) { - SelectedLanguage = 1; - } else if (CVar_GetS32("gLanguages", 0) == 2) { - SelectedLanguage = 2; + if (Cosmetics_isOpen) { + if (!Cosmetics_isOpen) { + return; + } + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("Cosmetics Editor", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); + if (ImGui::BeginTabBar("Cosmetics Editor", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + if (ImGui::BeginTabItem("Navi")) { + EnhancementCheckbox("Custom colors for Navi", "gUseNaviCol"); + Tooltip("Enable/Disable custom Navi's colors. \nIf disabled you will have original colors for Navi.\nColors are refreshed when Navi goes back in your pockets."); + EnhancementColor3("Navi Idle Inner", "gNavi_Idle_Inner_", navi_idle_i_col, false); + Tooltip("Inner color for Navi (idle flying around)"); + EnhancementColor3("Navi Idle Outer", "gNavi_Idle_Outer_", navi_idle_o_col, false); + Tooltip("Outer color for Navi (idle flying around)"); + ImGui::Separator(); + EnhancementColor3("Navi NPC Inner", "gNavi_NPC_Inner_", navi_npc_i_col, false); + Tooltip("Inner color for Navi (when Navi fly around NPCs)"); + EnhancementColor3("Navi NPC Outer", "gNavi_NPC_Outer_", navi_npc_o_col, false); + Tooltip("Outer color for Navi (when Navi fly around NPCs)"); + ImGui::Separator(); + EnhancementColor3("Navi Enemy Inner", "gNavi_Enemy_Inner_", navi_enemy_i_col, false); + Tooltip("Inner color for Navi (when Navi fly around Enemies or Bosses)"); + EnhancementColor3("Navi Enemy Outer", "gNavi_Enemy_Outer_", navi_enemy_o_col, false); + Tooltip("Outer color for Navi (when Navi fly around Enemies or Bosses)"); + ImGui::Separator(); + EnhancementColor3("Navi Prop Inner", "gNavi_Prop_Inner_", navi_prop_i_col, false); + Tooltip("Inner color for Navi (when Navi fly around props (signs etc))"); + EnhancementColor3("Navi Prop Outer", "gNavi_Prop_Outer_", navi_prop_o_col, false); + Tooltip("Outer color for Navi (when Navi fly around props (signs etc))"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Tunics")) { + EnhancementCheckbox("Custom colors on tunics", "gUseTunicsCol"); + Tooltip("Enable/Disable custom Link's tunics colors. \nIf disabled you will have original colors for Link's tunics."); + EnhancementColor3("Kokiri Tunic", "gTunic_Kokiri_", kokiri_col, false); + ImGui::Separator(); + EnhancementColor3("Goron Tunic", "gTunic_Goron_", goron_col, false); + ImGui::Separator(); + EnhancementColor3("Zora Tunic", "gTunic_Zora_", zora_col, false); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::PopStyleColor(); + ImGui::End(); } - if (ImGui::BeginMenu("Languages")) { - EnhancementRadioButton("English", "gLanguages", 0); - EnhancementRadioButton("German", "gLanguages", 1); - EnhancementRadioButton("French", "gLanguages", 2); - ImGui::EndMenu(); + if (Interface_isOpen) { + if (!Interface_isOpen) { + return; + } + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("Interface Editor", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); + if (ImGui::BeginTabBar("Interface Editor", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + if (ImGui::BeginTabItem("Hearts")) { + EnhancementColor3("Hearts inner", "gCCHeartsPrim", hearts_colors, false); + Tooltip("Hearts inner color (red in original)\nAffect both Normal Hearts and the ones in Double Defense"); + EnhancementColor3("Hearts double def", "gDDCCHeartsPrim", hearts_dd_colors, false); + Tooltip("Hearts outline color (white in original)\nAffect Double Defense outline only."); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Buttons")) { + EnhancementColor3("A Buttons", "gCCABtnPrim", a_btn_colors, false); + Tooltip("A Buttons colors (Green in original Gamecube)\nAffect A buttons colors on interface, in shops, messages boxes, ocarina notes and inventory cursors."); + EnhancementColor3("B Buttons", "gCCBBtnPrim", b_btn_colors, false); + Tooltip("B Button colors (Red in original Gamecube)\nAffect B button colors on interface"); + EnhancementColor3("C Buttons", "gCCCBtnPrim", c_btn_colors, false); + Tooltip("C Buttons colors (Yellowish / Oranges in originals)\nAffect C buttons colors on interface, in inventory and ocarina notes"); + EnhancementColor3("Start Buttons", "gCCStartBtnPrim", start_btn_colors, false); + Tooltip("Start Button colors (gray in Gamecube)\nAffect Start button colors in inventory"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Magic Bar")) { + EnhancementColor3("Magic bar borders", "gCCMagicBorderPrim", magic_border_colors, false); + Tooltip("Affect the border of the magic bar when being used\nWhite flash in original game."); + EnhancementColor3("Magic bar main color", "gCCMagicPrim", magic_remaining_colors, false); + Tooltip("Affect the magic bar color\nGreen in original game."); + EnhancementColor3("Magic bar being used", "gCCMagicUsePrim", magic_use_colors, false); + Tooltip("Affect the magic bar when being used\nYellow in original game."); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Misc")) { + EnhancementColor3("Minimap color", "gCCMinimapPrim", minimap_colors, false); + Tooltip("Affect the Dungeon and Overworld minimaps."); + EnhancementColor3("Rupee icon color", "gCCRupeePrim", rupee_colors, false); + Tooltip("Affect the Rupee icon on interface\nGreen by default."); + EnhancementColor3("Small Keys icon color", "gCCKeysPrim", smolekey_colors, false); + Tooltip("Affect the Small keys icon on interface\nGray by default."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::PopStyleColor(); + ImGui::End(); } for (const auto& category : windowCategories) { if (ImGui::BeginMenu(category.first.c_str())) { for (const std::string& name : category.second) { - HOOK(ImGui::MenuItem(name.c_str(), nullptr, &customWindows[name].enabled)); + std::string varName(name); + varName.erase(std::ranges::remove_if(varName, isspace).begin(), varName.end()); + std::string toggleName = "g" + varName + "Enabled"; + + EnhancementCheckbox(name, toggleName); + customWindows[name].enabled = CVar_GetS32(toggleName.c_str(), 0); } ImGui::EndMenu(); } + } ImGui::EndMenuBar(); @@ -802,28 +925,21 @@ namespace SohImGui { ImGui::End(); - if (Game::Settings.debug.soh) { + if (CVar_GetS32("gStatsEnabled", 0)) { const float framerate = ImGui::GetIO().Framerate; ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); - ImGui::Begin("Debug Stats", nullptr, ImGuiWindowFlags_None); + ImGui::Begin("Debug Stats", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); +#ifdef _WIN32 ImGui::Text("Platform: Windows"); +#else + ImGui::Text("Platform: Linux"); +#endif ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate); ImGui::End(); ImGui::PopStyleColor(); } - if (Game::Settings.graphics.show) { - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); - ImGui::Begin("Anti-aliasing settings", nullptr, ImGuiWindowFlags_None); - ImGui::Text("Internal Resolution:"); - ImGui::SliderInt("Mul", reinterpret_cast(&gfx_current_dimensions.internal_mul), 1, 8); - ImGui::Text("MSAA:"); - ImGui::SliderInt("MSAA", reinterpret_cast(&gfx_msaa_level), 1, 8); - ImGui::End(); - ImGui::PopStyleColor(); - } - console->Draw(); for (auto& windowIter : customWindows) { @@ -864,6 +980,8 @@ namespace SohImGui { pos = ImVec2(size.x / 2 - sw / 2, 0); size = ImVec2(sw, size.y); } + + overlay->Draw(); } void DrawFramebufferAndGameInput() { @@ -973,4 +1091,15 @@ namespace SohImGui { ImTextureID GetTextureByName(const std::string& name) { return GetTextureByID(DefaultAssets[name]->textureId); } -} \ No newline at end of file + + ImTextureID GetTextureByID(int id) { +#ifdef ENABLE_DX11 + if (impl.backend == Backend::DX11) + { + ImTextureID gfx_d3d11_get_texture_by_id(int id); + return gfx_d3d11_get_texture_by_id(id); + } +#endif + return reinterpret_cast(id); + } +} diff --git a/libultraship/libultraship/SohImGuiImpl.h b/libultraship/libultraship/SohImGuiImpl.h index 64e804570..210a26db9 100644 --- a/libultraship/libultraship/SohImGuiImpl.h +++ b/libultraship/libultraship/SohImGuiImpl.h @@ -1,5 +1,6 @@ #pragma once +#include "GameOverlay.h" #include "Lib/ImGui/imgui.h" #include "SohConsole.h" @@ -58,15 +59,16 @@ namespace SohImGui { } CustomWindow; extern Console* console; + extern Ship::GameOverlay* overlay; + extern bool needs_save; void Init(WindowImpl window_impl); void Update(EventImpl event); - void EnhancementColorEdit3(std::string text, std::string cvarName, float ColorRGB[3]); - int ClampFloatToInt(float value, int min, int max); void EnhancementRadioButton(std::string text, std::string cvarName, int value); void EnhancementCheckbox(std::string text, std::string cvarName); void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format); void EnhancementSliderFloat(std::string text, std::string id, std::string cvarName, float min, float max, std::string format, float defaultValue); + void EnhancementColor3(std::string text, std::string cvarName, float ColorRGB[3], bool TitleSameLine); void DrawMainMenuAndCalculateGameSize(void); @@ -77,7 +79,7 @@ namespace SohImGui { void BindCmd(const std::string& cmd, CommandEntry entry); void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc); void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1)); + void LoadInterfaceEditor(); ImTextureID GetTextureByID(int id); ImTextureID GetTextureByName(const std::string& name); - void LoadCosmeticColors(); } diff --git a/libultraship/libultraship/TextureMod.cpp b/libultraship/libultraship/TextureMod.cpp index 2a7e39511..b44987a62 100644 --- a/libultraship/libultraship/TextureMod.cpp +++ b/libultraship/libultraship/TextureMod.cpp @@ -43,7 +43,7 @@ namespace Ship { if (raw_path == nullptr) return; const auto api = BIND_PTR("gfx_api", GfxRenderingAPI*); - const auto path = normalize(raw_path) + ".png"; + const auto path = std::string(raw_path) + ".png"; const auto node = BIND_PTR("node", TextureCacheNode**); const auto fmt = BIND_VAR("fmt", uint32_t*); const auto siz = BIND_VAR("siz", uint32_t*); diff --git a/libultraship/libultraship/TextureMod.h b/libultraship/libultraship/TextureMod.h index 987a0c6f3..8dac99387 100644 --- a/libultraship/libultraship/TextureMod.h +++ b/libultraship/libultraship/TextureMod.h @@ -36,15 +36,6 @@ namespace Ship { void Hook_InvalidateTexture(HookEvent event); }; - inline std::string normalize(std::string path) { -#ifdef _WIN32 - std::ranges::replace(path, '/', '\\'); -#else - std::replace(path.begin(), path.end(), '\\', '/'); -#endif - return path; - } - inline void GrayOutTexture(uint8_t* data, int width, int height) { for (int x = 0; x < width * height * 4; x += 4) { diff --git a/libultraship/libultraship/Utils.cpp b/libultraship/libultraship/Utils.cpp index e36ba29f5..d54952c77 100644 --- a/libultraship/libultraship/Utils.cpp +++ b/libultraship/libultraship/Utils.cpp @@ -1,9 +1,14 @@ #include "Utils.h" +#include + +#ifdef _MSC_VER +#define strdup _strdup +#endif namespace Utils { std::vector SplitText(const std::string text, char separator = ' ', bool keep_quotes = false) { std::vector args; - char* input = _strdup(text.c_str()); + char* input = strdup(text.c_str()); const size_t length = strlen(input); bool inQuotes = false; diff --git a/libultraship/libultraship/WasapiAudioPlayer.cpp b/libultraship/libultraship/WasapiAudioPlayer.cpp index 26e4504d3..30cb10905 100644 --- a/libultraship/libultraship/WasapiAudioPlayer.cpp +++ b/libultraship/libultraship/WasapiAudioPlayer.cpp @@ -1,3 +1,4 @@ +#ifdef _WIN32 #include "WasapiAudioPlayer.h" #include "spdlog/spdlog.h" @@ -169,4 +170,5 @@ namespace Ship { } return S_OK; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/libultraship/libultraship/WasapiAudioPlayer.h b/libultraship/libultraship/WasapiAudioPlayer.h index 5067d01a2..dac7dd7a7 100644 --- a/libultraship/libultraship/WasapiAudioPlayer.h +++ b/libultraship/libultraship/WasapiAudioPlayer.h @@ -1,4 +1,7 @@ #pragma once + +#ifdef _WIN32 + #include "AudioPlayer.h" #include #include @@ -39,3 +42,4 @@ namespace Ship { bool started; }; } +#endif diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 0feb7229f..588e3af50 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -12,6 +12,8 @@ #include "Matrix.h" #include "AudioPlayer.h" #include "WasapiAudioPlayer.h" +#include "PulseAudioPlayer.h" +#include "SDLAudioPlayer.h" #include "Lib/Fast3D/gfx_pc.h" #include "Lib/Fast3D/gfx_sdl.h" #include "Lib/Fast3D/gfx_opengl.h" @@ -22,6 +24,7 @@ #include #include "SohHooks.h" #include "SohConsole.h" + #include extern "C" { @@ -48,7 +51,7 @@ extern "C" { } // TODO: This for loop is debug. Burn it with fire. - for (size_t i = 0; i < SDL_NumJoysticks(); i++) { + for (int i = 0; i < SDL_NumJoysticks(); i++) { if (SDL_IsGameController(i)) { // Get the GUID from SDL char buf[33]; @@ -207,7 +210,7 @@ extern "C" { return (char*)res->imageData; } - void ResourceMgr_WriteTexS16ByName(char* texPath, int index, s16 value) { + void ResourceMgr_WriteTexS16ByName(char* texPath, size_t index, s16 value) { const auto res = static_cast(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(texPath).get()); if (res != nullptr) @@ -237,7 +240,7 @@ extern "C" { } } -extern "C" GfxWindowManagerAPI gfx_sdl; +extern GfxWindowManagerAPI gfx_sdl; void SetWindowManager(GfxWindowManagerAPI** WmApi, GfxRenderingAPI** RenderingApi, const std::string& gfx_backend); namespace Ship { @@ -279,8 +282,12 @@ namespace Ship { gfx_start_frame(); } - void Window::RunCommands(Gfx* Commands) { - gfx_run(Commands); + void Window::RunCommands(Gfx* Commands, const std::vector>& mtx_replacements) { + for (const auto& m : mtx_replacements) { + gfx_run(Commands, m); + gfx_end_frame(); + } + gfx_run(Commands, {}); gfx_end_frame(); } @@ -326,6 +333,8 @@ namespace Ship { GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen(); } + + // OTRTODO: Rig with Kirito's console? //if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) { // ToggleConsole(); @@ -397,6 +406,12 @@ namespace Ship { } void Window::SetAudioPlayer() { +#ifdef _WIN32 APlayer = std::make_shared(); +#elif defined(__linux) + APlayer = std::make_shared(); +#else + APlayer = std::make_shared(); +#endif } } diff --git a/libultraship/libultraship/Window.h b/libultraship/libultraship/Window.h index b075e496f..04886c53e 100644 --- a/libultraship/libultraship/Window.h +++ b/libultraship/libultraship/Window.h @@ -19,7 +19,7 @@ namespace Ship { void MainLoop(void (*MainFunction)(void)); void Init(); void StartFrame(); - void RunCommands(Gfx* Commands); + void RunCommands(Gfx* Commands, const std::vector>& mtx_replacements); void SetFrameDivisor(int divisor); void GetPixelDepthPrepare(float x, float y); uint16_t GetPixelDepth(float x, float y); diff --git a/libultraship/libultraship/WindowShim.cpp b/libultraship/libultraship/WindowShim.cpp index 96b636aff..4469c5c29 100644 --- a/libultraship/libultraship/WindowShim.cpp +++ b/libultraship/libultraship/WindowShim.cpp @@ -23,7 +23,9 @@ void SetWindowManager(struct GfxWindowManagerAPI** WmApi, struct GfxRenderingAPI #ifdef ENABLE_OPENGL *RenderingApi = &gfx_opengl_api; #if defined(__linux__) - *WmApi = &gfx_glx; + // LINUX_TODO: + // *WmApi = &gfx_glx; + *WmApi = &gfx_sdl; #else *WmApi = &gfx_sdl; #endif diff --git a/libultraship/libultraship/libultraship.vcxproj b/libultraship/libultraship/libultraship.vcxproj index 3bf81a67d..b3448e7b0 100644 --- a/libultraship/libultraship/libultraship.vcxproj +++ b/libultraship/libultraship/libultraship.vcxproj @@ -256,6 +256,7 @@ + @@ -343,6 +344,7 @@ + diff --git a/libultraship/libultraship/libultraship.vcxproj.filters b/libultraship/libultraship/libultraship.vcxproj.filters index 5079d826e..8ac4f0afb 100644 --- a/libultraship/libultraship/libultraship.vcxproj.filters +++ b/libultraship/libultraship/libultraship.vcxproj.filters @@ -88,6 +88,9 @@ {bd6557f1-9480-413b-b0cd-843f8efc1939} + + {3285ab8a-06d8-4dac-9af9-efb2a9723ab1} + @@ -339,6 +342,9 @@ Source Files\CustomImpl + + Source Files\CustomImpl\Overlay + @@ -629,5 +635,8 @@ Source Files\Resources + + Source Files\CustomImpl\Overlay + \ No newline at end of file diff --git a/libultraship/libultraship/mixer.c b/libultraship/libultraship/mixer.c index b81eb915a..302a54ef4 100644 --- a/libultraship/libultraship/mixer.c +++ b/libultraship/libultraship/mixer.c @@ -449,13 +449,16 @@ void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t *state_or_filter) int16_t *buf = BUF_S16(count_or_buf); if (flags == A_INIT) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmemset-elt-size" memset(tmp, 0, 8 * sizeof(int16_t)); +#pragma GCC diagnostic pop memset(tmp2, 0, 8 * sizeof(int16_t)); } else { memcpy(tmp, state_or_filter, 8 * sizeof(int16_t)); memcpy(tmp2, state_or_filter + 8, 8 * sizeof(int16_t)); } - + for (int i = 0; i < 8; i++) { rspa.filter[i] = (tmp2[i] + rspa.filter[i]) / 2; } diff --git a/libultraship/libultraship/stox.cpp b/libultraship/libultraship/stox.cpp index 75fcdfbf0..fa2dff974 100644 --- a/libultraship/libultraship/stox.cpp +++ b/libultraship/libultraship/stox.cpp @@ -1,3 +1,4 @@ +#include #include "stox.h" #include "spdlog/spdlog.h" diff --git a/soh/.gitignore b/soh/.gitignore index fafae443d..5920cfba7 100644 --- a/soh/.gitignore +++ b/soh/.gitignore @@ -25,6 +25,10 @@ docs/doxygen/ *.map *.dump out.txt +shipofharkinian.ini +imgui.ini +oot.otr +oot_save.sav # Tool artifacts tools/mipspro7.2_compiler/ @@ -279,7 +283,7 @@ ClientBin/ *.publishsettings orleans.codegen.cs -# Including strong name files can present a security risk +# Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk @@ -375,7 +379,7 @@ __pycache__/ # OpenCover UI analysis results OpenCover/ -# Azure Stream Analytics local run output +# Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log @@ -384,7 +388,7 @@ ASALocalRun/ # NVidia Nsight GPU debugger configuration file *.nvuser -# MFractors (Xamarin productivity tool) working folder +# MFractors (Xamarin productivity tool) working folder .mfractor/ *.out @@ -397,6 +401,7 @@ ZAPDUtils/ZAPDUtils.a build/ ZAPDUtils/build/ ZAPD/BuildInfo.h +cvars.cfg DebugObj/* ReleaseObj/* \ No newline at end of file diff --git a/soh/Makefile b/soh/Makefile new file mode 100644 index 000000000..be46f55e7 --- /dev/null +++ b/soh/Makefile @@ -0,0 +1,158 @@ +CXX := g++ +CC := gcc +LD := lld +AR := ar +FORMAT := clang-format-11 +ZAPD := ../ZAPDTR/ZAPD.out + +LIBULTRASHIP := ../libultraship/libultraship.a +ZAPDUTILS := ../ZAPDTR/ZAPDUtils/ZAPDUtils.a + +ASAN ?= 0 +DEBUG ?= 1 +OPTFLAGS ?= -O0 +LTO ?= 0 + +WARN := \ + -Wno-return-type \ + -funsigned-char \ + -m32 -mhard-float -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \ + +CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib -march=i386 +CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib -march=i386 +LDFLAGS := -m32 +CPPFLAGS := -MMD + +ifneq ($(DEBUG),0) + CXXFLAGS += -g + CFLAGS += -g +endif + +ifneq ($(ASAN),0) + CXXFLAGS += -fsanitize=address + LDFLAGS += -fsanitize=address +endif + +ifneq ($(LTO),0) + CXXFLAGS += -flto + LDFLAGS += -flto +endif + +TARGET := soh.elf + +INC_DIRS := $(addprefix -I, \ + . \ + assets \ + build \ + include \ + src \ + ../ZAPDTR/ZAPDUtils \ + ../libultraship/libultraship \ + ../libultraship/libultraship/Lib/spdlog/include \ + ../libultraship/libultraship/Lib/Fast3D/U64 \ + ../libultraship/libultraship/Lib/Fast3D/U64/PR \ +) + +LDDIRS := $(addprefix -L, \ + ../external \ + ../libultraship/ \ +) + +LDLIBS := \ + $(ZAPDUTILS) \ + $(addprefix -l, \ + X11 \ + dl \ + bz2 \ + z \ + pthread \ + atomic \ + SDL2 \ + GL \ + GLEW \ + storm \ + pulse\ + ultraship \ +) \ + +ASSET_BIN_DIRS := $(shell find assets/* -type d -not -path "assets/xml*") +ASSET_FILES_XML := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.xml)) +ASSET_FILES_BIN := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.bin)) +ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_XML:.xml=.c),$f) \ + $(foreach f,$(ASSET_FILES_BIN:.bin=.bin.inc.c),build/$f) + +TEXTURE_FILES_PNG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.png)) +TEXTURE_FILES_JPG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.jpg)) +TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG:.png=.inc.c),build/$f) \ + $(foreach f,$(TEXTURE_FILES_JPG:.jpg=.jpg.inc.c),build/$f) \ + +CXX_FILES := \ + $(shell find soh -type f -name *.cpp) + +C_FILES := \ + $(shell find soh -type f -name *.c) \ + $(shell find src/boot -type f -name *.c) \ + $(shell find src/buffers -type f -name *.c) \ + $(shell find src/code -type f -name *.c) \ + $(shell find src/overlays -type f -name *.c) \ + src/libultra/gu/coss.c \ + src/libultra/gu/guLookAt.c \ + src/libultra/gu/guLookAtHilite.c \ + src/libultra/gu/guPerspectiveF.c \ + src/libultra/gu/guPosition.c \ + src/libultra/gu/guS2DInitBg.c \ + src/libultra/gu/ortho.c \ + src/libultra/gu/rotate.c \ + src/libultra/gu/sins.c \ + src/libultra/gu/sintable.c \ + src/libultra/libc/sprintf.c + +O_FILES := \ + $(C_FILES:%.c=build/%.o) \ + $(CXX_FILES:%.cpp=build/%.o) +D_FILES := $(O_FILES:%.o=%.d) + +# create build directory +SRC_DIRS := $(shell find . -type d -a -not -path "*build*") +$(shell mkdir -p $(SRC_DIRS:%=build/%)) + +all: + $(MAKE) -C ../libultraship + $(MAKE) $(TARGET) + +setup: + cd ../OTRExporter && python3 extract_baserom.py + $(MAKE) mpq + +mpq: + $(MAKE) -C ../libultraship + $(MAKE) -C ../OTRExporter/OTRExporter + $(MAKE) -C ../ZAPDTR + rm -rf ../OTRExporter/oot.otr + cd ../OTRExporter && python3 extract_assets.py + cp ../OTRExporter/oot.otr . + +distclean: clean + $(RM) -r baserom/ + $(MAKE) clean -C ../libultraship + $(MAKE) clean -C ../OTRExporter/OTRExporter + $(MAKE) clean -C ../ZAPDTR + +clean: + rm -rf build $(TARGET) + +.PHONY: all clean distclean setup mpq + +build/%.o: %.cpp + $(CXX) -c $(CXXFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) $< -o $@ + +build/%.o: %.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) $< -o $@ + +# make soh depend on libultraship +$(TARGET): $(LIBULTRASHIP) + +$(TARGET): $(O_FILES) + $(CXX) $^ -o $@ $(LDFLAGS) -fuse-ld=$(LD) $(LDDIRS) $(LDLIBS) + +-include $(D_FILES) \ No newline at end of file diff --git a/soh/assets/xml/GC_NMQ_D/textures/map_48x85_static.xml b/soh/assets/xml/GC_NMQ_D/textures/map_48x85_static.xml index b5b1d1a85..2788498a8 100644 --- a/soh/assets/xml/GC_NMQ_D/textures/map_48x85_static.xml +++ b/soh/assets/xml/GC_NMQ_D/textures/map_48x85_static.xml @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/textures/map_48x85_static.xml b/soh/assets/xml/GC_NMQ_PAL_F/textures/map_48x85_static.xml index b5b1d1a85..b2ea46340 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/textures/map_48x85_static.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/textures/map_48x85_static.xml @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/soh/include/alloca.h b/soh/include/alloca.h index 9c6a0ab94..10025b7f7 100644 --- a/soh/include/alloca.h +++ b/soh/include/alloca.h @@ -1,7 +1,7 @@ #ifndef ALLOCA_H #define ALLOCA_H -void* alloca(u32); +// void* alloca(u32); //#define alloca __builtin_alloca #define alloca malloc diff --git a/soh/include/functions.h b/soh/include/functions.h index 7d368edb6..4631cdb92 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -14,7 +14,7 @@ extern "C" #if defined(INCLUDE_GAME_PRINTF) && !defined(NDEBUG) #define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__) #else -#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, __VA_ARGS__) +#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__) #endif f32 fabsf(f32 f); @@ -29,6 +29,7 @@ void gDPSetTextureImage(Gfx* pkt, u32 f, u32 s, u32 w, uintptr_t i); void gSPDisplayList(Gfx* pkt, Gfx* dl); void gSPDisplayListOffset(Gfx* pkt, Gfx* dl, int offset); void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0); +void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr); void cleararena(void); void bootproc(void); @@ -2404,7 +2405,9 @@ void Heaps_Alloc(void); void Heaps_Free(void); #ifdef __cplusplus +#undef this }; +#undef this #endif #endif diff --git a/soh/include/global.h b/soh/include/global.h index 4845728dd..2e4808fe0 100644 --- a/soh/include/global.h +++ b/soh/include/global.h @@ -4,8 +4,8 @@ #include "functions.h" #include "variables.h" #include "macros.h" -#include "soh\OTRGlobals.h" -#include "soh\Enhancements\gameconsole.h" +#include "soh/OTRGlobals.h" +#include "soh/Enhancements/gameconsole.h" #include "Cvar.h" diff --git a/soh/include/libc/stddef.h b/soh/include/libc/stddef.h index c30e392f8..e5fbe2d22 100644 --- a/soh/include/libc/stddef.h +++ b/soh/include/libc/stddef.h @@ -1,7 +1,12 @@ #ifndef STDDEF_H #define STDDEF_H +#ifndef __cplusplus #define NULL ((void*)0) +#else +#define NULL nullptr +#endif + #if 0 #define size_t unsigned long #define ssize_t long diff --git a/soh/include/macros.h b/soh/include/macros.h index c57effe02..7392274d9 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -138,6 +138,8 @@ extern GraphicsContext* __gfxCtx; #ifndef NDEBUG #define OPEN_DISPS(gfxCtx, file, line) \ { \ + void FrameInterpolation_RecordOpenChild(const void* a, int b); \ + FrameInterpolation_RecordOpenChild(file, line); \ GraphicsContext* __gfxCtx; \ Gfx* dispRefs[4]; \ __gfxCtx = gfxCtx; \ @@ -146,6 +148,8 @@ extern GraphicsContext* __gfxCtx; #else #define OPEN_DISPS(gfxCtx, file, line) \ { \ + void FrameInterpolation_RecordOpenChild(const void* a, int b); \ + FrameInterpolation_RecordOpenChild(file, line); \ GraphicsContext* __gfxCtx; \ __gfxCtx = gfxCtx; \ (void)__gfxCtx; @@ -153,11 +157,15 @@ extern GraphicsContext* __gfxCtx; #ifndef NDEBUG #define CLOSE_DISPS(gfxCtx, file, line) \ + {void FrameInterpolation_RecordCloseChild(void); \ + FrameInterpolation_RecordCloseChild();} \ Graph_CloseDisps(dispRefs, gfxCtx, file, line); \ } \ (void)0 #else #define CLOSE_DISPS(gfxCtx, file, line) \ + {void FrameInterpolation_RecordCloseChild(void); \ + FrameInterpolation_RecordCloseChild();} \ (void)0; \ } \ (void)0 @@ -205,6 +213,14 @@ extern GraphicsContext* __gfxCtx; #define ALIGNED8 #endif -#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 0xF0000000) +#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) + +#ifdef _MSC_VER +#define BOMSWAP16 _byteswap_ushort +#define BOMSWAP32 _byteswap_ulong +#else +#define BOMSWAP16 __builtin_bswap16 +#define BOMSWAP32 __builtin_bswap32 +#endif #endif diff --git a/soh/include/ultra64.h b/soh/include/ultra64.h index 65ef6d147..c2e0e9b29 100644 --- a/soh/include/ultra64.h +++ b/soh/include/ultra64.h @@ -1,6 +1,9 @@ #ifndef ULTRA64_H #define ULTRA64_H +#include +#include +#include #include "ultra64/types.h" #include "unk.h" diff --git a/soh/include/z64.h b/soh/include/z64.h index 103c8650f..7720144b4 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -30,6 +30,9 @@ #include "ichain.h" #include "regs.h" +#define AUDIO_HEAP_SIZE 0x38000 +#define SYSTEM_HEAP_SIZE (1024 * 1024 * 4) + #ifdef __cplusplus namespace Ship { diff --git a/soh/include/z64effect.h b/soh/include/z64effect.h index c85c9d617..1b35d46b6 100644 --- a/soh/include/z64effect.h +++ b/soh/include/z64effect.h @@ -225,6 +225,7 @@ typedef struct EffectSs { /* 0x5C */ s16 life; // -1 means this entry is free /* 0x5E */ u8 priority; // Lower value means higher priority /* 0x5F */ u8 type; + u32 epoch; } EffectSs; // size = 0x60 typedef struct { diff --git a/soh/soh.vcxproj b/soh/soh.vcxproj index 2bd4380b9..0a2006122 100644 --- a/soh/soh.vcxproj +++ b/soh/soh.vcxproj @@ -173,6 +173,7 @@ + @@ -180,6 +181,7 @@ + @@ -278,6 +280,7 @@ + @@ -327,7 +330,6 @@ - @@ -877,6 +879,7 @@ + @@ -925,10 +928,12 @@ + + @@ -1408,4 +1413,4 @@ - + \ No newline at end of file diff --git a/soh/soh.vcxproj.filters b/soh/soh.vcxproj.filters index a8455a4c8..04f6030a8 100644 --- a/soh/soh.vcxproj.filters +++ b/soh/soh.vcxproj.filters @@ -630,9 +630,6 @@ Source Files\src\code - - Source Files\src\code - Source Files\src\code @@ -2189,6 +2186,14 @@ Source Files\soh\Enhancements\debugger + + Source Files\soh + + + Source Files + + + Source Files\soh\Enhancements @@ -3745,6 +3750,14 @@ Header Files\soh\Enhancements\debugger + + Header Files\soh + + + Source Files\soh\Enhancements + + + Source Files\soh diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 7411c751e..2c754828f 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -29,8 +29,10 @@ void BootCommands_Init() CVar_RegisterS32("gUniformLR", 1); CVar_RegisterS32("gNewDrops", 0); CVar_RegisterS32("gVisualAgony", 0); - CVar_RegisterS32("gHudColors", 1); //0 N64 colors/1 Gamecube colors/2 Custom colors CVar_RegisterS32("gLanguages", 0); //0 = English / 1 = German / 2 = French + CVar_RegisterS32("gHudColors", 1); //0 = N64 / 1 = NGC / 2 = Custom + CVar_RegisterS32("gUseNaviCol", 0); + CVar_RegisterS32("gUseTunicsCol", 0); } //void BootCommands_ParseBootArgs(char* str) diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index ff69830e7..1b892be74 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -1,12 +1,22 @@ +#ifdef _MSC_VER +#define NOGDI +#endif + #include "debugconsole.h" #include "../libultraship/SohImGuiImpl.h" +#include "savestates.h" + #include #include +#include "soh/OTRGlobals.h" + #define Path _Path #define PATH_HACK #include #include + +#include "Lib/ImGui/imgui_internal.h" #undef PATH_HACK #undef Path @@ -18,7 +28,7 @@ extern "C" { extern GlobalContext* gGlobalCtx; } -#include "cvar.h" +#include "Cvar.h" #define CMD_REGISTER SohImGui::BindCmd @@ -122,7 +132,7 @@ static bool RuppeHandler(const std::vector& args) { try { rupeeAmount = std::stoi(args[1]); } - catch (std::invalid_argument const& ex) { + catch (std::invalid_argument const& ex) { ERROR("[SOH] Rupee count must be an integer."); return CMD_FAILED; } @@ -168,13 +178,13 @@ static bool ResetHandler(std::vector args) { ERROR("GlobalCtx == nullptr"); return CMD_FAILED; } - + SET_NEXT_GAMESTATE(&gGlobalCtx->state, TitleSetup_Init, GameState); gGlobalCtx->state.running = false; return CMD_SUCCESS; } -const static std::map ammoItems{ +const static std::map ammoItems{ { "sticks", ITEM_STICK }, { "deku_sticks", ITEM_STICK }, { "nuts", ITEM_NUT }, { "deku_nuts", ITEM_NUT }, { "bombs", ITEM_BOMB }, { "arrows", ITEM_BOW }, @@ -194,7 +204,7 @@ static bool AmmoHandler(const std::vector& args) { try { count = std::stoi(args[2]); - } catch (std::invalid_argument const& ex) { + } catch (std::invalid_argument const& ex) { ERROR("Ammo count must be an integer"); return CMD_FAILED; } @@ -203,7 +213,7 @@ static bool AmmoHandler(const std::vector& args) { ERROR("Ammo count must be positive"); return CMD_FAILED; } - + const auto& it = ammoItems.find(args[1]); if (it == ammoItems.end()) { @@ -213,7 +223,7 @@ static bool AmmoHandler(const std::vector& args) { // I dont think you can do OOB with just this AMMO(it->second) = count; - + //To use a change by uncomment this //Inventory_ChangeAmmo(it->second, count); } @@ -236,7 +246,7 @@ static bool BottleHandler(const std::vector& args) { unsigned int slot; try { slot = std::stoi(args[2]); - } catch (std::invalid_argument const& ex) { + } catch (std::invalid_argument const& ex) { ERROR("[SOH] Bottle slot must be an integer."); return CMD_FAILED; } @@ -275,7 +285,7 @@ static bool ItemHandler(const std::vector& args) { return CMD_FAILED; } - gSaveContext.inventory.items[std::stoi(args[1])] = std::stoi(args[2]); + gSaveContext.inventory.items[std::stoi(args[1])] = std::stoi(args[2]); return CMD_SUCCESS; } @@ -301,6 +311,66 @@ static bool EntranceHandler(const std::vector& args) { gSaveContext.nextTransition = 11; } +static bool SaveStateHandler(const std::vector& args) { + unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); + + switch (rtn) { + case SaveStateReturn::SUCCESS: + INFO("[SOH] Saved state to slot %u", slot); + return CMD_SUCCESS; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + ERROR("[SOH] Can not save a state outside of \"GamePlay\""); + return CMD_FAILED; + + } +} + +static bool LoadStateHandler(const std::vector& args) { + unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); + + switch (rtn) { + case SaveStateReturn::SUCCESS: + INFO("[SOH] Loaded state from slot %u", slot); + return CMD_SUCCESS; + case SaveStateReturn::FAIL_INVALID_SLOT: + ERROR("[SOH] Invalid State Slot Number (%u)", slot); + return CMD_FAILED; + case SaveStateReturn::FAIL_STATE_EMPTY: + ERROR("[SOH] State Slot (%u) is empty", slot); + return CMD_FAILED; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + ERROR("[SOH] Can not load a state outside of \"GamePlay\""); + return CMD_FAILED; + } + +} + +static bool StateSlotSelectHandler(const std::vector& args) { + if (args.size() != 2) { + ERROR("[SOH] Unexpected arguments passed"); + return CMD_FAILED; + } + int slot; + + try { + slot = std::stoi(args[1], nullptr, 10); + } catch (std::invalid_argument const& ex) { + ERROR("[SOH] SaveState slot value must be a number."); + return CMD_FAILED; + } + + if (slot < 0) { + ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2"); + return CMD_FAILED; + } + + OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot); + INFO("[SOH] Slot %u selected", OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot()); + return CMD_SUCCESS; +} + #define VARTYPE_INTEGER 0 #define VARTYPE_FLOAT 1 #define VARTYPE_STRING 2 @@ -334,7 +404,7 @@ static bool SetCVarHandler(const std::vector& args) { int vType = CheckVarType(args[2]); if (vType == VARTYPE_STRING) - CVar_SetString(args[1].c_str(), (char*)args[2].c_str()); + CVar_SetString(args[1].c_str(), args[2].c_str()); else if (vType == VARTYPE_FLOAT) CVar_SetFloat(args[1].c_str(), std::stof(args[2])); else @@ -351,7 +421,7 @@ static bool GetCVarHandler(const std::vector& args) { if (args.size() < 2) return CMD_FAILED; - CVar* cvar = CVar_GetVar(args[1].c_str()); + CVar* cvar = CVar_Get(args[1].c_str()); if (cvar != nullptr) { @@ -415,16 +485,39 @@ void DebugConsole_Init(void) { CMD_REGISTER("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", { { "entrance", ArgumentType::NUMBER } } }); + CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." }); + CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." }); + CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { + { "Slot number", ArgumentType::NUMBER, } + } }); DebugConsole_LoadCVars(); } +template bool is_number(const std::string& s) { + Numeric n; + return ((std::istringstream(s) >> n >> std::ws).eof()); +} + void DebugConsole_LoadCVars() { if (File::Exists("cvars.cfg")) { const auto lines = File::ReadAllLines("cvars.cfg"); for (const std::string& line : lines) { - SohImGui::console->Dispatch(line); + std::vector cfg = StringHelper::Split(line, " = "); + if (line.empty()) continue; + if (cfg.size() < 2) continue; + if (cfg[1].find("\"") != std::string::npos) { + std::string value(cfg[1]); + value.erase(std::ranges::remove(value, '\"').begin(), value.end()); + CVar_SetString(cfg[0].c_str(), ImStrdup(value.c_str())); + } + if (is_number(cfg[1])) { + CVar_SetFloat(cfg[0].c_str(), std::stof(cfg[1])); + } + if (is_number(cfg[1])) { + CVar_SetS32(cfg[0].c_str(), std::stoi(cfg[1])); + } } } } @@ -435,11 +528,11 @@ void DebugConsole_SaveCVars() for (const auto &cvar : cvars) { if (cvar.second->type == CVAR_TYPE_STRING) - output += StringHelper::Sprintf("set %s %s\n", cvar.first.c_str(), cvar.second->value.valueStr); + output += StringHelper::Sprintf("%s = \"%s\"\n", cvar.first.c_str(), cvar.second->value.valueStr); else if (cvar.second->type == CVAR_TYPE_S32) - output += StringHelper::Sprintf("set %s %i\n", cvar.first.c_str(), cvar.second->value.valueS32); + output += StringHelper::Sprintf("%s = %i\n", cvar.first.c_str(), cvar.second->value.valueS32); else if (cvar.second->type == CVAR_TYPE_FLOAT) - output += StringHelper::Sprintf("set %s %f\n", cvar.first.c_str(), cvar.second->value.valueFloat); + output += StringHelper::Sprintf("%s = %f\n", cvar.first.c_str(), cvar.second->value.valueFloat); } File::WriteAllText("cvars.cfg", output); diff --git a/soh/soh/Enhancements/debugger/colViewer.cpp b/soh/soh/Enhancements/debugger/colViewer.cpp index ad9d341d4..f5c283aac 100644 --- a/soh/soh/Enhancements/debugger/colViewer.cpp +++ b/soh/soh/Enhancements/debugger/colViewer.cpp @@ -1,9 +1,11 @@ #include "colViewer.h" #include "../libultraship/SohImGuiImpl.h" #include "ImGuiHelpers.h" +#include "../../frame_interpolation.h" #include #include +#include extern "C" { #include @@ -96,7 +98,7 @@ void DrawColViewerWindow(bool& open) { } ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Collision Viewer", &open)) { + if (!ImGui::Begin("Collision Viewer", &open, ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::End(); return; } @@ -322,7 +324,7 @@ void CreateSphereData() { } void InitColViewer() { - SohImGui::AddWindow("Debug", "Collision Viewer", DrawColViewerWindow); + SohImGui::AddWindow("Developer Tools", "Collision Viewer", DrawColViewerWindow); CreateCylinderData(); CreateSphereData(); diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index e2ed02705..ca1b67798 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -251,15 +251,31 @@ void DrawGroupWithBorder(T&& drawFunc) { ImGui::EndGroup(); } +char z2ASCII(int code) { + int ret; + if (code < 10) { //Digits + ret = code + 0x30; + } else if (code >= 10 && code < 36) { //Uppercase letters + ret = code + 0x37; + } else if (code >= 36 && code < 62) { //Lowercase letters + ret = code + 0x3D; + } else if (code == 62) { //Space + ret = code - 0x1E; + } else if (code == 63 || code == 64) { // _ and . + ret = code - 0x12; + } else { + ret = code; + } + return char(ret); + +} + void DrawInfoTab() { - // TODO This is the bare minimum to get the player name showing - // There will need to be more effort to get it robust and editable + // TODO Needs a better method for name changing but for now this will work. std::string name; + ImU16 one = 1; for (int i = 0; i < 8; i++) { - char letter = gSaveContext.playerName[i] + 0x3D; - if (letter == '{') { - letter = '\0'; - } + char letter = z2ASCII(gSaveContext.playerName[i]); name += letter; } name += '\0'; @@ -268,6 +284,14 @@ void DrawInfoTab() { ImGui::Text("Name: %s", name.c_str()); InsertHelpHoverText("Player Name"); + std::string nameID; + for (int i = 0; i < 8; i++) { + nameID = z2ASCII(i); + if (i % 4 != 0) { + ImGui::SameLine(); + } + ImGui::InputScalar(nameID.c_str(), ImGuiDataType_U8, &gSaveContext.playerName[i], &one, NULL); + } // Use an intermediary to keep the health from updating (and potentially killing the player) // until it is done being edited @@ -377,21 +401,101 @@ void DrawInfoTab() { ImGui::InputScalar("Bgs Day Count", ImGuiDataType_S32, &gSaveContext.bgsDayCount); InsertHelpHoverText("Total number of days elapsed since giving Biggoron the claim check"); - // TODO Changing Link's age is more involved than just setting gSaveContext.linkAge - // It might not fit here and instead should be only changable when changing scenes - /* - if (ImGui::BeginCombo("Link Age", LINK_IS_ADULT ? "Adult" : "Child")) { - if (ImGui::Selectable("Adult")) { - gSaveContext.linkAge = 0; + ImGui::InputScalar("Entrance Index", ImGuiDataType_S32, &gSaveContext.entranceIndex); + InsertHelpHoverText("From which entrance did Link arrive?"); + + ImGui::InputScalar("Cutscene Index", ImGuiDataType_S32, &gSaveContext.cutsceneIndex); + InsertHelpHoverText("Which cutscene is this?"); + + ImGui::InputScalar("Navi Timer", ImGuiDataType_U16, &gSaveContext.naviTimer); + InsertHelpHoverText("Navi wants to talk at 600 units, decides not to at 3000."); + + ImGui::InputScalar("Timer 1 State", ImGuiDataType_S16, &gSaveContext.timer1State); + InsertHelpHoverText("Heat timer, race timer, etc. Has white font"); + + ImGui::InputScalar("Timer 1 Value", ImGuiDataType_S16, &gSaveContext.timer1Value, &one, NULL); + InsertHelpHoverText("Time, in seconds"); + + ImGui::InputScalar("Timer 2 State", ImGuiDataType_S16, &gSaveContext.timer2State); + InsertHelpHoverText("Trade timer, Ganon collapse timer, etc. Has yellow font"); + + ImGui::InputScalar("Timer 2 Value", ImGuiDataType_S16, &gSaveContext.timer2Value, &one, NULL); + InsertHelpHoverText("Time, in seconds"); + + const char* audioName; + switch (gSaveContext.audioSetting) { + case 0: + audioName = "Stereo"; + break; + case 1: + audioName = "Mono"; + break; + case 2: + audioName = "Headset"; + break; + case 3: + audioName = "Surround"; + break; + default: + audioName = "?"; + } + if (ImGui::BeginCombo("Audio", audioName)) { + if (ImGui::Selectable("Stereo")) { + gSaveContext.audioSetting = 0; } - if (ImGui::Selectable("Child")) { - gSaveContext.linkAge = 1; + if (ImGui::Selectable("Mono")) { + gSaveContext.audioSetting = 1; + } + if (ImGui::Selectable("Headset")) { + gSaveContext.audioSetting = 2; + } + if (ImGui::Selectable("Surround")) { + gSaveContext.audioSetting = 3; } ImGui::EndCombo(); } - */ + InsertHelpHoverText("Sound setting"); + + bool n64DDFlag = gSaveContext.n64ddFlag != 0; + if (ImGui::Checkbox("64 DD file?", &n64DDFlag)) { + gSaveContext.n64ddFlag = n64DDFlag; + } + InsertHelpHoverText("WARNING! If you save, your file may be locked! Use caution!"); + + if (ImGui::BeginCombo("Z Target Mode", gSaveContext.zTargetSetting ? "Hold" : "Switch")) { + if (ImGui::Selectable("Switch")) { + gSaveContext.zTargetSetting = 0; + } + if (ImGui::Selectable("Hold")) { + gSaveContext.zTargetSetting = 1; + } + ImGui::EndCombo(); + } + InsertHelpHoverText("Z-Targeting behavior"); + + ImGui::PushItemWidth(ImGui::GetFontSize() * 10); + static std::array minigameHS = { "Horseback Archery", + "Big Poe Points", + "Fishing", + "Malon's Obstacle Course", + "Running Man Race", + "?", + "Dampe's Race" }; + + if (ImGui::TreeNode("Minigames")) { + for (int i = 0; i < 7; i++) { + if (i == 5) { //HS_UNK_05 is unused + continue; + } + std::string minigameLbl = minigameHS[i]; + ImGui::InputScalar(minigameLbl.c_str(), ImGuiDataType_S32, &gSaveContext.highScores[i], &one, NULL); + } + + ImGui::TreePop(); + } + ImGui::PopItemWidth(); } @@ -505,7 +609,7 @@ void DrawInventoryTab() { } // Draw a flag bitfield as an grid of checkboxes -void DrawFlagArray(const std::string& name, uint32_t& flags) { +void DrawFlagArray32(const std::string& name, uint32_t& flags) { ImGui::PushID(name.c_str()); for (int32_t flagIndex = 0; flagIndex < 32; flagIndex++) { if ((flagIndex % 8) != 0) { @@ -526,6 +630,25 @@ void DrawFlagArray(const std::string& name, uint32_t& flags) { ImGui::PopID(); } +void DrawFlagArray16(const std::string& name, uint16_t& flags) { + ImGui::PushID(name.c_str()); + for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) { + ImGui::SameLine(); + ImGui::PushID(flagIndex); + uint32_t bitMask = 1 << flagIndex; + bool flag = (flags & bitMask) != 0; + if (ImGui::Checkbox("##check", &flag)) { + if (flag) { + flags |= bitMask; + } else { + flags &= ~bitMask; + } + } + ImGui::PopID(); + } + ImGui::PopID(); +} + void DrawFlagsTab() { if (ImGui::TreeNode("Current Scene")) { if (gGlobalCtx != nullptr) { @@ -534,7 +657,7 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Switch"); InsertHelpHoverText("Permanently-saved switch flags"); - DrawFlagArray("Switch", act->flags.swch); + DrawFlagArray32("Switch", act->flags.swch); }); ImGui::SameLine(); @@ -542,13 +665,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Switch"); InsertHelpHoverText("Temporary switch flags. Unset on scene transitions"); - DrawFlagArray("Temp Switch", act->flags.tempSwch); + DrawFlagArray32("Temp Switch", act->flags.tempSwch); }); DrawGroupWithBorder([&]() { ImGui::Text("Clear"); InsertHelpHoverText("Permanently-saved room-clear flags"); - DrawFlagArray("Clear", act->flags.clear); + DrawFlagArray32("Clear", act->flags.clear); }); ImGui::SameLine(); @@ -556,13 +679,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Clear"); InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions"); - DrawFlagArray("Temp Clear", act->flags.tempClear); + DrawFlagArray32("Temp Clear", act->flags.tempClear); }); DrawGroupWithBorder([&]() { ImGui::Text("Collect"); InsertHelpHoverText("Permanently-saved collect flags"); - DrawFlagArray("Collect", act->flags.collect); + DrawFlagArray32("Collect", act->flags.collect); }); ImGui::SameLine(); @@ -570,13 +693,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Collect"); InsertHelpHoverText("Temporary collect flags. Unset on scene transitions"); - DrawFlagArray("Temp Collect", act->flags.tempCollect); + DrawFlagArray32("Temp Collect", act->flags.tempCollect); }); DrawGroupWithBorder([&]() { ImGui::Text("Chest"); InsertHelpHoverText("Permanently-saved chest flags"); - DrawFlagArray("Chest", act->flags.chest); + DrawFlagArray32("Chest", act->flags.chest); }); ImGui::SameLine(); @@ -633,7 +756,7 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Switch"); InsertHelpHoverText("Switch flags"); - DrawFlagArray("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch); + DrawFlagArray32("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch); }); ImGui::SameLine(); @@ -641,13 +764,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Clear"); InsertHelpHoverText("Room-clear flags"); - DrawFlagArray("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear); + DrawFlagArray32("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear); }); DrawGroupWithBorder([&]() { ImGui::Text("Collect"); InsertHelpHoverText("Collect flags"); - DrawFlagArray("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect); + DrawFlagArray32("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect); }); ImGui::SameLine(); @@ -655,13 +778,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Chest"); InsertHelpHoverText("Chest flags"); - DrawFlagArray("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest); + DrawFlagArray32("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest); }); DrawGroupWithBorder([&]() { ImGui::Text("Rooms"); InsertHelpHoverText("Flags for visted rooms"); - DrawFlagArray("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms); + DrawFlagArray32("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms); }); ImGui::SameLine(); @@ -669,7 +792,7 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Floors"); InsertHelpHoverText("Flags for visted floors"); - DrawFlagArray("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors); + DrawFlagArray32("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors); }); ImGui::TreePop(); @@ -730,6 +853,124 @@ void DrawFlagsTab() { gSaveContext.inventory.gsTokens = gsCount; } }); + + if (ImGui::TreeNode("Event Check Inf Flags")) { + DrawGroupWithBorder([&]() { + ImGui::Text("0"); + InsertHelpHoverText("Mostly Kokiri Forest related"); + DrawFlagArray16("eci0", gSaveContext.eventChkInf[0]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("1"); + InsertHelpHoverText("Mostly Lon Lon Ranch related"); + DrawFlagArray16("eci1", gSaveContext.eventChkInf[1]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("2"); + InsertHelpHoverText("Dodongo Related?"); + DrawFlagArray16("eci2", gSaveContext.eventChkInf[2]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("3"); + InsertHelpHoverText("Mostly Zora related"); + DrawFlagArray16("eci3", gSaveContext.eventChkInf[3]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("4"); + InsertHelpHoverText("Random"); + DrawFlagArray16("eci4", gSaveContext.eventChkInf[4]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("5"); + InsertHelpHoverText("Mostly song learning related"); + DrawFlagArray16("eci5", gSaveContext.eventChkInf[5]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("6"); + InsertHelpHoverText("Random"); + DrawFlagArray16("eci6", gSaveContext.eventChkInf[6]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("7"); + InsertHelpHoverText("Boss Battle related"); + DrawFlagArray16("eci7", gSaveContext.eventChkInf[7]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("8"); + InsertHelpHoverText("Mask related?"); + DrawFlagArray16("eci8", gSaveContext.eventChkInf[8]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("9"); + InsertHelpHoverText("Mostly carpenter related"); + DrawFlagArray16("eci9", gSaveContext.eventChkInf[9]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("A"); + InsertHelpHoverText("First-time overworld entrance cs related"); + DrawFlagArray16("eci1", gSaveContext.eventChkInf[10]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("B"); + InsertHelpHoverText("First-time dungeon entrance cs/trial cs related"); + DrawFlagArray16("eci11", gSaveContext.eventChkInf[11]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("C"); + InsertHelpHoverText("Random"); + DrawFlagArray16("eci12", gSaveContext.eventChkInf[12]); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("D"); + InsertHelpHoverText("Frog songs/GS rewards"); + DrawFlagArray16("eci13", gSaveContext.eventChkInf[13]); + }); + + ImGui::TreePop(); + } + if (ImGui::TreeNode("Inf Table Flags")) { + for (int i = 0; i < 30; i++) { + std::string it_id = "it" + std::to_string(i); + DrawGroupWithBorder([&]() { + ImGui::Text("%2d", i); + DrawFlagArray16(it_id, gSaveContext.infTable[i]); + }); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Item Get Inf Flags")) { + for (int i = 0; i < 4; i++) { + std::string igi_id = "igi" + std::to_string(i); + DrawGroupWithBorder([&]() { + ImGui::Text("%d", i); + DrawFlagArray16(igi_id, gSaveContext.itemGetInf[i]); + }); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Event Inf Flags")) { + for (int i = 0; i < 4; i++) { + std::string ei_id = "ei" + std::to_string(i); + DrawGroupWithBorder([&]() { + ImGui::Text("%d", i); + DrawFlagArray16(ei_id, gSaveContext.eventInf[i]); + }); + } + ImGui::TreePop(); + } } // Draws a combo that lets you choose and upgrade value from a drop-down of text values @@ -1057,13 +1298,249 @@ void DrawQuestStatusTab() { ImGui::PopItemWidth(); } +void DrawPlayerTab() { + if (gGlobalCtx != nullptr) { + Player* player = GET_PLAYER(gGlobalCtx); + const char* curSword; + const char* curShield; + const char* curTunic; + const char* curBoots; + + switch (player->currentSwordItem) { + case ITEM_SWORD_KOKIRI: + curSword = "Kokiri Sword"; + break; + case ITEM_SWORD_MASTER: + curSword = "Master Sword"; + break; + case ITEM_SWORD_BGS: + curSword = "Biggoron's Sword"; + break; + case ITEM_NONE: + curSword = "None"; + break; + default: + curSword = "None"; + break; + } + + switch (player->currentShield) { + case PLAYER_SHIELD_NONE: + curShield = "None"; + break; + case PLAYER_SHIELD_DEKU: + curShield = "Deku Shield"; + break; + case PLAYER_SHIELD_HYLIAN: + curShield = "Hylian Shield"; + break; + case PLAYER_SHIELD_MIRROR: + curShield = "Mirror Shield"; + break; + default: + break; + } + + switch (player->currentTunic) { + case PLAYER_TUNIC_KOKIRI: + curTunic = "Kokiri Tunic"; + break; + case PLAYER_TUNIC_GORON: + curTunic = "Goron Tunic"; + break; + case PLAYER_TUNIC_ZORA: + curTunic = "Zora Tunic"; + break; + default: + break; + } + + switch (player->currentBoots) { + case PLAYER_BOOTS_KOKIRI: + curBoots = "Kokiri Boots"; + break; + case PLAYER_BOOTS_IRON: + curBoots = "Iron Boots"; + break; + case PLAYER_BOOTS_HOVER: + curBoots = "Hover Boots"; + break; + default: + break; + } + + ImGui::PushItemWidth(ImGui::GetFontSize() * 6); + DrawGroupWithBorder([&]() { + ImGui::Text("Link's Position"); + ImGui::InputScalar("X Pos", ImGuiDataType_Float, &player->actor.world.pos.x); + ImGui::SameLine(); + ImGui::InputScalar("Y Pos", ImGuiDataType_Float, &player->actor.world.pos.y); + ImGui::SameLine(); + ImGui::InputScalar("Z Pos", ImGuiDataType_Float, &player->actor.world.pos.z); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("Link's Rotation"); + InsertHelpHoverText("For Link's rotation in relation to the world"); + ImGui::InputScalar("X Rot", ImGuiDataType_S16, &player->actor.world.rot.x); + ImGui::SameLine(); + ImGui::InputScalar("Y Rot", ImGuiDataType_S16, &player->actor.world.rot.y); + ImGui::SameLine(); + ImGui::InputScalar("Z Rot", ImGuiDataType_S16, &player->actor.world.rot.z); + }); + + DrawGroupWithBorder([&]() { + ImGui::Text("Link's Model Rotation"); + InsertHelpHoverText("For Link's actual model"); + ImGui::InputScalar("X ModRot", ImGuiDataType_S16, &player->actor.shape.rot.x); + ImGui::SameLine(); + ImGui::InputScalar("Y ModRot", ImGuiDataType_S16, &player->actor.shape.rot.y); + ImGui::SameLine(); + ImGui::InputScalar("Z ModRot", ImGuiDataType_S16, &player->actor.shape.rot.z); + }); + + ImGui::InputScalar("Linear Velocity", ImGuiDataType_Float, &player->linearVelocity); + InsertHelpHoverText("Link's speed along the XZ plane"); + + ImGui::InputScalar("Y Velocity", ImGuiDataType_Float, &player->actor.velocity.y); + InsertHelpHoverText("Link's speed along the Y plane. Caps at -20"); + + ImGui::InputScalar("Wall Height", ImGuiDataType_Float, &player->wallHeight); + InsertHelpHoverText("\"height used to determine whether link can climb or grab a ledge at the top\""); + + ImGui::InputScalar("Invincibility Timer", ImGuiDataType_S8, &player->invincibilityTimer); + InsertHelpHoverText("Can't take damage while this is nonzero"); + + ImGui::InputScalar("Gravity", ImGuiDataType_Float, &player->actor.gravity); + InsertHelpHoverText("Rate at which Link falls. Default -4.0f"); + + if (ImGui::BeginCombo("Link Age on Load", gGlobalCtx->linkAgeOnLoad == 0 ? "Adult" : "Child")) { + if (ImGui::Selectable("Adult")) { + gGlobalCtx->linkAgeOnLoad = 0; + } + if (ImGui::Selectable("Child")) { + gGlobalCtx->linkAgeOnLoad = 1; + } + ImGui::EndCombo(); + } + + InsertHelpHoverText("This will change Link's age when you load a map"); + + ImGui::Separator(); + + ImGui::Text("Link's Current Equipment"); + ImGui::PushItemWidth(ImGui::GetFontSize() * 15); + if (ImGui::BeginCombo("Sword", curSword)) { + if (ImGui::Selectable("None")) { + player->currentSwordItem = ITEM_NONE; + gSaveContext.equips.buttonItems[0] = ITEM_NONE; + Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_NONE); + } + if (ImGui::Selectable("Kokiri Sword")) { + player->currentSwordItem = ITEM_SWORD_KOKIRI; + gSaveContext.equips.buttonItems[0] = ITEM_SWORD_KOKIRI; + Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_KOKIRI); + } + if (ImGui::Selectable("Master Sword")) { + player->currentSwordItem = ITEM_SWORD_MASTER; + gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; + Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_MASTER); + } + if (ImGui::Selectable("Biggoron's Sword")) { + if (gSaveContext.bgsFlag) { + if (gSaveContext.swordHealth < 8) { + gSaveContext.swordHealth = 8; + } + player->currentSwordItem = ITEM_SWORD_BGS; + gSaveContext.equips.buttonItems[0] = ITEM_SWORD_BGS; + } else { + if (gSaveContext.swordHealth < 8) { + gSaveContext.swordHealth = 8; + } + player->currentSwordItem = ITEM_SWORD_BGS; + gSaveContext.equips.buttonItems[0] = ITEM_SWORD_KNIFE; + } + + Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_BGS); + } + ImGui::EndCombo(); + + } + if (ImGui::BeginCombo("Shield", curShield)) { + if (ImGui::Selectable("None")) { + player->currentShield = PLAYER_SHIELD_NONE; + Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_NONE); + } + if (ImGui::Selectable("Deku Shield")) { + player->currentShield = PLAYER_SHIELD_DEKU; + Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_DEKU); + } + if (ImGui::Selectable("Hylian Shield")) { + player->currentShield = PLAYER_SHIELD_HYLIAN; + Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_HYLIAN); + } + if (ImGui::Selectable("Mirror Shield")) { + player->currentShield = PLAYER_SHIELD_MIRROR; + Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_MIRROR); + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Tunic", curTunic)) { + if (ImGui::Selectable("Kokiri Tunic")) { + player->currentTunic = PLAYER_TUNIC_KOKIRI; + Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_KOKIRI + 1); + } + if (ImGui::Selectable("Goron Tunic")) { + player->currentTunic = PLAYER_TUNIC_GORON; + Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_GORON + 1); + } + if (ImGui::Selectable("Zora Tunic")) { + player->currentTunic = PLAYER_TUNIC_ZORA; + Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_ZORA + 1); + } + ImGui::EndCombo(); + } + + if (ImGui::BeginCombo("Boots", curBoots)) { + if (ImGui::Selectable("Kokiri Boots")) { + player->currentBoots = PLAYER_BOOTS_KOKIRI; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_KOKIRI + 1); + } + if (ImGui::Selectable("Iron Boots")) { + player->currentBoots = PLAYER_BOOTS_IRON; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_IRON + 1); + } + if (ImGui::Selectable("Hover Boots")) { + player->currentBoots = PLAYER_BOOTS_HOVER; + Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_HOVER + 1); + } + ImGui::EndCombo(); + } + + ImU16 one = 1; + ImGui::PushItemWidth(ImGui::GetFontSize() * 6); + DrawGroupWithBorder([&]() { + ImGui::Text("Current C Equips"); + ImGui::InputScalar("C Left", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[1], &one, NULL); + ImGui::SameLine(); + ImGui::InputScalar("C Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[2], &one, NULL); + ImGui::SameLine(); + ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL); + }); + + } else { + ImGui::Text("Global Context needed for player info!"); + } +} + void DrawSaveEditor(bool& open) { if (!open) { return; } ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Save Editor", &open)) { + if (!ImGui::Begin("Save Editor", &open, ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::End(); return; } @@ -1094,6 +1571,11 @@ void DrawSaveEditor(bool& open) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("Player")) { + DrawPlayerTab(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } @@ -1101,7 +1583,7 @@ void DrawSaveEditor(bool& open) { } void InitSaveEditor() { - SohImGui::AddWindow("Debug", "Save Editor", DrawSaveEditor); + SohImGui::AddWindow("Developer Tools", "Save Editor", DrawSaveEditor); // Load item icons into ImGui for (const auto& entry : itemMapping) { diff --git a/soh/soh/Enhancements/gameconsole.h b/soh/soh/Enhancements/gameconsole.h index d7052fce3..33301afe6 100644 --- a/soh/soh/Enhancements/gameconsole.h +++ b/soh/soh/Enhancements/gameconsole.h @@ -3,7 +3,7 @@ #include #include -#include "cvar.h" +#include "Cvar.h" #define MAX_CVARS 2048 diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp new file mode 100644 index 000000000..2b6d27189 --- /dev/null +++ b/soh/soh/Enhancements/savestates.cpp @@ -0,0 +1,957 @@ +#include "savestates.h" + +#include "GameVersions.h" + +#include // std::sprintf + +#include "spdlog/spdlog.h" + +#include +#include + +#include + +#include "z64.h" +#include "z64save.h" +#include +#include +#include "z64map_mark.h" +#include "../../src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h" +#include "../../src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h" +#include "../../src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h" +#include "../../src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h" +#include "../../src/overlays/actors/ovl_En_Fr/z_en_fr.h" + +extern "C" GlobalContext* gGlobalCtx; + +// FROM z_lights.c +// I didn't feel like moving it into a header file. +#define LIGHTS_BUFFER_SIZE 32 + +typedef struct { + /* 0x000 */ s32 numOccupied; + /* 0x004 */ s32 searchIndex; + /* 0x008 */ LightNode buf[LIGHTS_BUFFER_SIZE]; +} LightsBuffer; // size = 0x188 + +#include "savestates_extern.inc" + +typedef struct SaveStateInfo { + unsigned char sysHeapCopy[SYSTEM_HEAP_SIZE]; + unsigned char audioHeapCopy[AUDIO_HEAP_SIZE]; + + SaveContext saveContextCopy; + GameInfo gameInfoCopy; + LightsBuffer lightBufferCopy; + AudioContext audioContextCopy; + MtxF mtxStackCopy[20]; // always 20 matricies + MtxF currentMtxCopy; + uint32_t rngSeed; + int16_t blueWarpTimerCopy; /* From door_warp_1 */ + + SeqScriptState seqScriptStateCopy[4];// Unrelocated + unk_D_8016E750 unk_D_8016E750Copy[4]; + + ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK]; + uint8_t gSoundBankMutedCopy[7]; + + u8 D_801333F0_copy; + u8 gAudioSfxSwapOff_copy; + uint16_t gAudioSfxSwapSource_copy[10]; + uint16_t gAudioSfxSwapTarget_copy[10]; + uint8_t gAudioSfxSwapMode_copy[10]; + void (*D_801755D0_copy)(void); + MapMarkData** sLoadedMarkDataTableCopy; + + //Static Data + + //Camera data + int32_t sInitRegs_copy; + int32_t gDbgCamEnabled_copy; + int32_t sDbgModeIdx_copy; + int16_t sNextUID_copy; + int32_t sCameraInterfaceFlags_copy; + int32_t sCameraInterfaceAlpha_copy; + int32_t sCameraShrinkWindowVal_copy; + int32_t D_8011D3AC_copy; + int32_t sDemo5PrevAction12Frame_copy; + int32_t sDemo5PrevSfxFrame_copy; + int32_t D_8011D3F0_copy; + OnePointCsFull D_8011D6AC_copy[3]; + OnePointCsFull D_8011D724_copy[3]; + OnePointCsFull D_8011D79C_copy[3]; + OnePointCsFull D_8011D83C_copy[2]; + OnePointCsFull D_8011D88C_copy[2]; + OnePointCsFull D_8011D8DC_copy[3]; + OnePointCsFull D_8011D954_copy[4]; + OnePointCsFull D_8011D9F4_copy[3]; + int16_t D_8011DB08_copy; + int16_t D_8011DB0C_copy; + int32_t sOOBTimer_copy; + f32 D_8015CE50_copy; + f32 D_8015CE54_copy; + CamColChk D_8015CE58_copy; + + //Gameover + uint16_t gGameOverTimer_copy; + + //One point demo + uint32_t sPrevFrameCs1100_copy; + CutsceneCameraPoint D_8012013C_copy[14]; + CutsceneCameraPoint D_8012021C_copy[14]; + CutsceneCameraPoint D_801204D4_copy[14]; + CutsceneCameraPoint D_801205B4_copy[14]; + OnePointCsFull D_801208EC_copy[3]; + OnePointCsFull D_80120964_copy[2]; + OnePointCsFull D_801209B4_copy[4]; + OnePointCsFull D_80120ACC_copy[5]; + OnePointCsFull D_80120B94_copy[11]; + OnePointCsFull D_80120D4C_copy[7]; + OnePointCsFull D_80120FA4_copy[6]; + OnePointCsFull D_80121184_copy[2]; + OnePointCsFull D_801211D4_copy[2]; + OnePointCsFull D_8012133C_copy[3]; + OnePointCsFull D_801213B4_copy[5]; + OnePointCsFull D_8012151C_copy[2]; + OnePointCsFull D_8012156C_copy[2]; + OnePointCsFull D_801215BC_copy[1]; + OnePointCsFull D_80121C24_copy[7]; + OnePointCsFull D_80121D3C_copy[3]; + OnePointCsFull D_80121F1C_copy[4]; + OnePointCsFull D_80121FBC_copy[4]; + OnePointCsFull D_801220D4_copy[5]; + OnePointCsFull D_80122714_copy[4]; + OnePointCsFull D_80122CB4_copy[2]; + OnePointCsFull D_80122D04_copy[2]; + OnePointCsFull D_80122E44_copy[2][7]; + OnePointCsFull D_8012313C_copy[3]; + OnePointCsFull D_801231B4_copy[4]; + OnePointCsFull D_80123254_copy[2]; + OnePointCsFull D_801232A4_copy[1]; + OnePointCsFull D_80123894_copy[3]; + OnePointCsFull D_8012390C_copy[2]; + OnePointCsFull D_8012395C_copy[3]; + OnePointCsFull D_801239D4_copy[3]; + + uint16_t gTimeIncrement_copy; + + //Overlay static data + // z_bg_ddan_kd + Vec3f sBgDdanKdVelocity_copy; + Vec3f sBgDdanKdAccel_copy; + + // z_bg_dodoago + s16 sBgDodoagoFirstExplosiveFlag_copy; + u8 sBgDodoagoDisableBombCatcher_copy; + s32 sBgDodoagoTimer_copy; + + // z_bg_haka_trap + uint32_t D_80880F30_copy; + uint32_t D_80881014_copy; + + // z_bg_hidan_rock + float D_8088BFC0_copy; + + // z_bg_menkuri_eye + int32_t D_8089C1A0_copy; + + // z_bg_mori_hineri + int16_t sBgMoriHineriNextCamIdx_copy; + + // z_bg_po_event + uint8_t sBgPoEventBlocksAtRest_copy; + uint8_t sBgPoEventPuzzleState_copy; + float sBgPoEventblockPushDist_copy; + + // z_bg_relay_objects + uint32_t D_808A9508_copy; + + // z_bg_spot18_basket + int16_t D_808B85D0_copy; + + // z_boss_ganon + uint32_t sBossGanonSeed1_copy; + uint32_t sBossGanonSeed2_copy; + uint32_t sBossGanonSeed3_copy; + void* sBossGanonGanondorf_copy; + void* sBossGanonZelda_copy; + void* sBossGanonCape_copy; + GanondorfEffect sBossGanonEffectBuf_copy[200]; + + // z_boss_ganon + uint32_t sBossGanonSeed1; + uint32_t sBossGanonSeed2; + uint32_t sBossGanonSeed3; + void* sBossGanonGanondorf; + void* sBossGanonZelda; + void* sBossGanonCape; + GanondorfEffect sBossGanonEffectBuf[200]; + + // z_boss_ganon2 + Vec3f D_8090EB20_copy; + int8_t D_80910638_copy; + void* sBossGanon2Zelda_copy; + void* D_8090EB30_copy; + int32_t sBossGanon2Seed1_copy; + int32_t sBossGanon2Seed2_copy; + int32_t sBossGanon2Seed3_copy; + Vec3f D_809105D8_copy[4]; + Vec3f D_80910608_copy[4]; + BossGanon2Effect sBossGanon2Particles_copy[100]; + + // z_boss_tw + uint8_t sTwInitalized_copy; + BossTwEffect sTwEffects_copy[150]; + + // z_demo_6k + Vec3f sDemo6kVelocity_copy; + + // z_demo_du + int32_t D_8096CE94_copy; + + // z_demo_kekkai + Vec3f demoKekkaiVel_copy; + + // z_en_bw + int32_t sSlugGroup_copy; + + // z_en_clear_tag + uint8_t sClearTagIsEffectInitialized_copy; + EnClearTagEffect sClearTagEffects_copy[CLEAR_TAG_EFFECT_MAX_COUNT]; + + // z_en_fr + EnFrPointers sEnFrPointers_copy; + + // z_en_goma + uint8_t sSpawnNum_copy; + + // z_en_insect + float D_80A7DEB0_copy; + int16_t D_80A7DEB4_copy; + int16_t D_80A7DEB8_copy; + + // z_en_ishi + int16_t sRockRotSpeedX_copy; + int16_t sRockRotSpeedY_copy; + + // z_en_niw + int16_t D_80AB85E0_copy; + uint8_t sLowerRiverSpawned_copy; + uint8_t sUpperRiverSpawned_copy; + + // z_en_po_field + int32_t sEnPoFieldNumSpawned_copy; + Vec3s sEnPoFieldSpawnPositions_copy[10]; + u8 sEnPoFieldSpawnSwitchFlags_copy[10]; + + // z_en_takara_man + uint8_t sTakaraIsInitialized_copy; + + // z_en_xc + int32_t D_80B41D90_copy; + int32_t sEnXcFlameSpawned_copy; + int32_t D_80B41DA8_copy; + int32_t D_80B41DAC_copy; + + // z_en_zf + int16_t D_80B4A1B0_copy; + int16_t D_80B4A1B4_copy; + + int32_t D_80B5A468_copy; + int32_t D_80B5A494_copy; + int32_t D_80B5A4BC_copy; + + uint8_t sKankyoIsSpawned_copy; + int16_t sTrailingFairies_copy; + + + //Misc static data + // z_map_exp + + s16 sPlayerInitialPosX_copy; + s16 sPlayerInitialPosZ_copy; + s16 sPlayerInitialDirection_copy; + + // code_800E(something. fill me in later) + u8 sOcarinaInpEnabled_copy; + s8 D_80130F10_copy; + u8 sCurOcarinaBtnVal_copy; + u8 sPrevOcarinaNoteVal_copy; + u8 sCurOcarinaBtnIdx_copy; + u8 sLearnSongLastBtn_copy; + f32 D_80130F24_copy; + f32 D_80130F28_copy; + s8 D_80130F2C_copy; + s8 D_80130F30_copy; + s8 D_80130F34_copy; + u8 sDisplayedNoteValue_copy; + u8 sPlaybackState_copy; + u32 D_80130F3C_copy; + u32 sNotePlaybackTimer_copy; + u16 sPlaybackNotePos_copy; + u16 sStaffPlaybackPos_copy; + + u32 sCurOcarinaBtnPress_copy; + u32 D_8016BA10_copy; + u32 sPrevOcarinaBtnPress_copy; + s32 D_8016BA18_copy; + s32 D_8016BA1C_copy; + u8 sCurOcarinaSong_copy[8]; + u8 sOcarinaSongAppendPos_copy; + u8 sOcarinaHasStartedSong_copy; + u8 sOcarinaSongNoteStartIdx_copy; + u8 sOcarinaSongCnt_copy; + u16 sOcarinaAvailSongs_copy; + u8 sStaffPlayingPos_copy; + u16 sLearnSongPos_copy[0x10]; + u16 D_8016BA50_copy[0x10]; + u16 D_8016BA70_copy[0x10]; + u8 sLearnSongExpectedNote_copy[0x10]; + OcarinaNote D_8016BAA0_copy; + u8 sAudioHasMalonBgm_copy; + f32 sAudioMalonBgmDist_copy; + + // Message_PAL + s16 sOcarinaNoteBufPos_copy; + s16 sOcarinaNoteBufLen_copy; + u8 sOcarinaNoteBuf_copy[12]; + + u8 D_8014B2F4_copy; + u8 sTextboxSkipped_copy; + u16 sNextTextId_copy; + s16 sLastPlayedSong_copy; + s16 sHasSunsSong_copy; + s16 sMessageHasSetSfx_copy; + u16 sOcarinaSongBitFlags_copy; + + +} SaveStateInfo; + +class SaveState { + friend class SaveStateMgr; + + public: + SaveState(std::shared_ptr mgr, unsigned int slot); + + private: + unsigned int slot; + std::shared_ptr saveStateMgr; + std::shared_ptr info; + + void Save(void); + void Load(void); + void BackupSeqScriptState(void); + void LoadSeqScriptState(void); + void BackupCameraData(void); + void LoadCameraData(void); + void SaveOnePointDemoData(void); + void LoadOnePointDemoData(void); + void SaveOverlayStaticData(void); + void LoadOverlayStaticData(void); + + void SaveMiscCodeData(void); + void LoadMiscCodeData(void); + + SaveStateInfo* GetSaveStateInfo(void); +}; + +SaveStateMgr::SaveStateMgr() { + this->SetCurrentSlot(0); +} +SaveStateMgr::~SaveStateMgr() { + this->states.clear(); +} + +SaveState::SaveState(std::shared_ptr mgr, unsigned int slot) : saveStateMgr(mgr), slot(slot), info(nullptr) { + this->info = std::make_shared(); +} + +void SaveState::BackupSeqScriptState(void) { + for (unsigned int i = 0; i < 4; i++) { + info->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value; + + info->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0]; + info->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1]; + info->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2]; + info->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3]; + + info->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth; + + info->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap); + + info->seqScriptStateCopy[i].stack[0] = + (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap); + info->seqScriptStateCopy[i].stack[1] = + (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap); + info->seqScriptStateCopy[i].stack[2] = + (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap); + info->seqScriptStateCopy[i].stack[3] = + (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap); + } +} + +void SaveState::LoadSeqScriptState(void) { + for (unsigned int i = 0; i < 4; i++) { + gAudioContext.seqPlayers[i].scriptState.value = info->seqScriptStateCopy[i].value; + + gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = info->seqScriptStateCopy[i].remLoopIters[0]; + gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = info->seqScriptStateCopy[i].remLoopIters[1]; + gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = info->seqScriptStateCopy[i].remLoopIters[2]; + gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = info->seqScriptStateCopy[i].remLoopIters[3]; + + gAudioContext.seqPlayers[i].scriptState.depth = info->seqScriptStateCopy[i].depth; + + gAudioContext.seqPlayers[i].scriptState.pc = + (u8*)((uintptr_t)info->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap); + + gAudioContext.seqPlayers[i].scriptState.stack[0] = + (u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap); + gAudioContext.seqPlayers[i].scriptState.stack[1] = + (u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap); + gAudioContext.seqPlayers[i].scriptState.stack[2] = + (u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap); + gAudioContext.seqPlayers[i].scriptState.stack[3] = + (u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap); + } +} + +void SaveState::BackupCameraData(void) { + info->sInitRegs_copy = sInitRegs; + info->gDbgCamEnabled_copy = gDbgCamEnabled; + info->sNextUID_copy = sNextUID; + info->sCameraInterfaceFlags_copy = sCameraInterfaceFlags; + info->sCameraInterfaceAlpha_copy = sCameraInterfaceAlpha; + info->sCameraShrinkWindowVal_copy = sCameraShrinkWindowVal; + info->D_8011D3AC_copy = D_8011D3AC; + info->sDemo5PrevAction12Frame_copy = sDemo5PrevAction12Frame; + info->sDemo5PrevSfxFrame_copy = sDemo5PrevSfxFrame; + info->D_8011D3F0_copy = D_8011D3F0; + memcpy(info->D_8011D6AC_copy, D_8011D6AC, sizeof(info->D_8011D6AC_copy)); + memcpy(info->D_8011D724_copy, D_8011D724, sizeof(info->D_8011D724_copy)); + memcpy(info->D_8011D79C_copy, D_8011D79C, sizeof(info->D_8011D79C_copy)); + memcpy(info->D_8011D83C_copy, D_8011D83C, sizeof(info->D_8011D83C_copy)); + memcpy(info->D_8011D88C_copy, D_8011D88C, sizeof(info->D_8011D88C_copy)); + memcpy(info->D_8011D8DC_copy, D_8011D8DC, sizeof(info->D_8011D8DC_copy)); + memcpy(info->D_8011D954_copy, D_8011D954, sizeof(info->D_8011D954_copy)); + memcpy(info->D_8011D9F4_copy, D_8011D9F4, sizeof(info->D_8011D9F4_copy)); + info->D_8011DB08_copy = D_8011DB08; + info->D_8011DB0C_copy = D_8011DB0C; + info->sOOBTimer_copy = sOOBTimer; + info->D_8015CE50_copy = D_8015CE50; + info->D_8015CE54_copy = D_8015CE54; + memcpy(&info->D_8015CE58_copy, &D_8015CE58, sizeof(info->D_8015CE58_copy)); +} + +void SaveState::LoadCameraData(void) { + sInitRegs = info->sInitRegs_copy; + gDbgCamEnabled = info->gDbgCamEnabled_copy; + sDbgModeIdx = info->sDbgModeIdx_copy; + sNextUID = info->sNextUID_copy; + sCameraInterfaceAlpha = info->sCameraInterfaceAlpha_copy; + sCameraInterfaceFlags = info->sCameraInterfaceFlags_copy; + sCameraShrinkWindowVal = info->sCameraShrinkWindowVal_copy; + D_8011D3AC = info->D_8011D3AC_copy; + sDemo5PrevAction12Frame = info->sDemo5PrevAction12Frame_copy; + sDemo5PrevSfxFrame = info->sDemo5PrevSfxFrame_copy; + D_8011D3F0 = info->D_8011D3F0_copy; + memcpy(D_8011D6AC, info->D_8011D6AC_copy, sizeof(info->D_8011D6AC_copy)); + memcpy(D_8011D724, info->D_8011D724_copy, sizeof(info->D_8011D724_copy)); + memcpy(D_8011D79C, info->D_8011D79C_copy, sizeof(info->D_8011D79C_copy)); + memcpy(D_8011D83C, info->D_8011D83C_copy, sizeof(info->D_8011D83C_copy)); + memcpy(D_8011D88C, info->D_8011D88C_copy, sizeof(info->D_8011D88C_copy)); + memcpy(D_8011D8DC, info->D_8011D8DC_copy, sizeof(info->D_8011D8DC_copy)); + memcpy(D_8011D954, info->D_8011D954_copy, sizeof(info->D_8011D954_copy)); + memcpy(D_8011D9F4, info->D_8011D9F4_copy, sizeof(info->D_8011D9F4_copy)); + D_8011DB08 = info->D_8011DB08_copy; + D_8011DB0C = info->D_8011DB0C_copy; + sOOBTimer = info->sOOBTimer_copy; + D_8015CE50 = info->D_8015CE50_copy; + D_8015CE54 = info->D_8015CE54_copy; + memcpy(&D_8015CE58, &info->D_8015CE58_copy, sizeof(info->D_8015CE58_copy)); +} + +void SaveState::SaveOnePointDemoData(void) { + info->sPrevFrameCs1100_copy = sPrevFrameCs1100; + memcpy(info->D_8012013C_copy, D_8012013C, sizeof(info->D_8012013C_copy)); + memcpy(info->D_8012021C_copy, D_8012021C, sizeof(info->D_8012021C_copy)); + memcpy(info->D_801204D4_copy, D_801204D4, sizeof(info->D_801204D4_copy)); + memcpy(info->D_801205B4_copy, D_801205B4, sizeof(info->D_801205B4_copy)); + memcpy(info->D_801208EC_copy, D_801208EC, sizeof(info->D_801208EC_copy)); + memcpy(info->D_80120964_copy, D_80120964, sizeof(info->D_80120964_copy)); + memcpy(info->D_801209B4_copy, D_801209B4, sizeof(info->D_801209B4_copy)); + memcpy(info->D_80120ACC_copy, D_80120ACC, sizeof(info->D_80120ACC_copy)); + memcpy(info->D_80120B94_copy, D_80120B94, sizeof(info->D_80120B94_copy)); + memcpy(info->D_80120D4C_copy, D_80120D4C, sizeof(info->D_80120D4C_copy)); + memcpy(info->D_80120FA4_copy, D_80120FA4, sizeof(info->D_80120FA4_copy)); + memcpy(info->D_80121184_copy, D_80121184, sizeof(info->D_80121184_copy)); + memcpy(info->D_801211D4_copy, D_801211D4, sizeof(info->D_801211D4_copy)); + memcpy(info->D_8012133C_copy, D_8012133C, sizeof(info->D_8012133C_copy)); + memcpy(info->D_801213B4_copy, D_801213B4, sizeof(info->D_801213B4_copy)); + memcpy(info->D_8012151C_copy, D_8012151C, sizeof(info->D_8012151C_copy)); + memcpy(info->D_8012156C_copy, D_8012156C, sizeof(info->D_8012156C_copy)); + memcpy(info->D_801215BC_copy, D_801215BC, sizeof(info->D_801215BC_copy)); + memcpy(info->D_80121C24_copy, D_80121C24, sizeof(info->D_80121C24_copy)); + memcpy(info->D_80121D3C_copy, D_80121D3C, sizeof(info->D_80121D3C_copy)); + memcpy(info->D_80121F1C_copy, D_80121F1C, sizeof(info->D_80121F1C_copy)); + memcpy(info->D_80121FBC_copy, D_80121FBC, sizeof(info->D_80121FBC_copy)); + memcpy(info->D_801220D4_copy, D_801220D4, sizeof(info->D_801220D4_copy)); + memcpy(info->D_80122714_copy, D_80122714, sizeof(info->D_80122714_copy)); + memcpy(info->D_80122CB4_copy, D_80122CB4, sizeof(info->D_80122CB4_copy)); + memcpy(info->D_80122D04_copy, D_80122D04, sizeof(info->D_80122D04_copy)); + memcpy(info->D_80122E44_copy, D_80122E44, sizeof(info->D_80122E44_copy)); + memcpy(info->D_8012313C_copy, D_8012313C, sizeof(info->D_8012313C_copy)); + memcpy(info->D_801231B4_copy, D_801231B4, sizeof(info->D_801231B4_copy)); + memcpy(info->D_80123254_copy, D_80123254, sizeof(info->D_80123254_copy)); + memcpy(info->D_801232A4_copy, D_801232A4, sizeof(info->D_801232A4_copy)); + memcpy(info->D_80123894_copy, D_80123894, sizeof(info->D_80123894_copy)); + memcpy(info->D_8012390C_copy, D_8012390C, sizeof(info->D_8012390C_copy)); + memcpy(info->D_8012395C_copy, D_8012395C, sizeof(info->D_8012395C_copy)); + memcpy(info->D_801239D4_copy, D_801239D4, sizeof(info->D_801239D4_copy)); +} + +void SaveState::LoadOnePointDemoData(void) { + sPrevFrameCs1100 = info->sPrevFrameCs1100_copy; + memcpy(D_8012013C, info->D_8012013C_copy, sizeof(info->D_8012013C_copy)); + memcpy(D_8012021C, info->D_8012021C_copy, sizeof(info->D_8012021C_copy)); + memcpy(D_801204D4, info->D_801204D4_copy, sizeof(info->D_801204D4_copy)); + memcpy(D_801205B4, info->D_801205B4_copy, sizeof(info->D_801205B4_copy)); + memcpy(D_801208EC, info->D_801208EC_copy, sizeof(info->D_801208EC_copy)); + memcpy(D_80120964, info->D_80120964_copy, sizeof(info->D_80120964_copy)); + memcpy(D_801209B4, info->D_801209B4_copy, sizeof(info->D_801209B4_copy)); + memcpy(D_80120ACC, info->D_80120ACC_copy, sizeof(info->D_80120ACC_copy)); + memcpy(D_80120B94, info->D_80120B94_copy, sizeof(info->D_80120B94_copy)); + memcpy(D_80120D4C, info->D_80120D4C_copy, sizeof(info->D_80120D4C_copy)); + memcpy(D_80120FA4, info->D_80120FA4_copy, sizeof(info->D_80120FA4_copy)); + memcpy(D_80121184, info->D_80121184_copy, sizeof(info->D_80121184_copy)); + memcpy(D_801211D4, info->D_801211D4_copy, sizeof(info->D_801211D4_copy)); + memcpy(D_8012133C, info->D_8012133C_copy, sizeof(info->D_8012133C_copy)); + memcpy(D_801213B4, info->D_801213B4_copy, sizeof(info->D_801213B4_copy)); + memcpy(D_8012151C, info->D_8012151C_copy, sizeof(info->D_8012151C_copy)); + memcpy(D_8012156C, info->D_8012156C_copy, sizeof(info->D_8012156C_copy)); + memcpy(D_801215BC, info->D_801215BC_copy, sizeof(info->D_801215BC_copy)); + memcpy(D_80121C24, info->D_80121C24_copy, sizeof(info->D_80121C24_copy)); + memcpy(D_80121D3C, info->D_80121D3C_copy, sizeof(info->D_80121D3C_copy)); + memcpy(D_80121F1C, info->D_80121F1C_copy, sizeof(info->D_80121F1C_copy)); + memcpy(D_80121FBC, info->D_80121FBC_copy, sizeof(info->D_80121FBC_copy)); + memcpy(D_801220D4, info->D_801220D4_copy, sizeof(info->D_801220D4_copy)); + memcpy(D_80122714, info->D_80122714_copy, sizeof(info->D_80122714_copy)); + memcpy(D_80122CB4, info->D_80122CB4_copy, sizeof(info->D_80122CB4_copy)); + memcpy(D_80122D04, info->D_80122D04_copy, sizeof(info->D_80122D04_copy)); + memcpy(D_80122E44, info->D_80122E44_copy, sizeof(info->D_80122E44_copy)); + memcpy(D_8012313C, info->D_8012313C_copy, sizeof(info->D_8012313C_copy)); + memcpy(D_801231B4, info->D_801231B4_copy, sizeof(info->D_801231B4_copy)); + memcpy(D_80123254, info->D_80123254_copy, sizeof(info->D_80123254_copy)); + memcpy(D_801232A4, info->D_801232A4_copy, sizeof(info->D_801232A4_copy)); + memcpy(D_80123894, info->D_80123894_copy, sizeof(info->D_80123894_copy)); + memcpy(D_8012390C, info->D_8012390C_copy, sizeof(info->D_8012390C_copy)); + memcpy(D_8012395C, info->D_8012395C_copy, sizeof(info->D_8012395C_copy)); + memcpy(D_801239D4, info->D_801239D4_copy, sizeof(info->D_801239D4_copy)); +} + +void SaveState::SaveOverlayStaticData(void) { + info->sBgDdanKdVelocity_copy = sBgDdanKdVelocity; + info->sBgDdanKdAccel_copy = sBgDdanKdAccel; + info->sBgDodoagoFirstExplosiveFlag_copy = sBgDodoagoFirstExplosiveFlag; + info->sBgDodoagoDisableBombCatcher_copy = sBgDodoagoDisableBombCatcher; + info->sBgDodoagoTimer_copy = sBgDodoagoTimer; + info->D_80880F30_copy = D_80880F30; + info->D_80881014_copy = D_80881014; + info->D_8088BFC0_copy = D_8088BFC0; + info->sBgMoriHineriNextCamIdx_copy = sBgMoriHineriNextCamIdx; + info->sBgPoEventBlocksAtRest_copy = sBgPoEventBlocksAtRest; + info->sBgPoEventPuzzleState_copy = sBgPoEventPuzzleState; + info->sBgPoEventblockPushDist_copy = sBgPoEventblockPushDist; + info->D_808A9508_copy = D_808A9508; + info->D_808B85D0_copy = D_808B85D0; + info->sBossGanonSeed1_copy = sBossGanonSeed1; + info->sBossGanonSeed2_copy = sBossGanonSeed2; + info->sBossGanonSeed3_copy = sBossGanonSeed3; + info->sBossGanonGanondorf_copy = sBossGanonGanondorf; + info->sBossGanonZelda_copy = sBossGanonZelda; + info->sBossGanonCape_copy = sBossGanonCape; + memcpy(info->sBossGanonEffectBuf_copy, sBossGanonEffectBuf, sizeof(info->sBossGanonEffectBuf_copy)); + info->D_8090EB20_copy = D_8090EB20; + info->D_80910638_copy = D_80910638; + info->sBossGanon2Zelda_copy = sBossGanon2Zelda; + info->D_8090EB30_copy = D_8090EB30; + info->sBossGanon2Seed1_copy = sBossGanon2Seed1; + info->sBossGanon2Seed2_copy = sBossGanon2Seed2; + info->sBossGanon2Seed3_copy = sBossGanon2Seed3; + memcpy(info->D_809105D8_copy, D_809105D8, sizeof(D_809105D8)); + memcpy(info->D_80910608_copy, D_80910608, sizeof(D_80910608)); + memcpy(info->sBossGanon2Particles_copy, sBossGanon2Particles, sizeof(sBossGanon2Particles)); + info->sTwInitalized_copy = sTwInitalized; + memcpy(info->sTwEffects_copy, sTwEffects, sizeof(sTwEffects)); + info->sDemo6kVelocity_copy = sDemo6kVelocity; + info->D_8096CE94_copy = D_8096CE94; + info->demoKekkaiVel_copy = demoKekkaiVel; + info->sSlugGroup_copy = sSlugGroup; + info->sClearTagIsEffectInitialized_copy = sClearTagIsEffectsInitialized; + memcpy(info->sClearTagEffects_copy, sClearTagEffects, sizeof(sClearTagEffects)); + + memcpy(&info->sEnFrPointers_copy, &sEnFrPointers, sizeof(info->sEnFrPointers_copy)); + info->sSpawnNum_copy = sSpawnNum; + + info->D_80A7DEB0_copy = D_80A7DEB0; + info->D_80A7DEB4_copy = D_80A7DEB4; + info->D_80A7DEB8_copy = D_80A7DEB8; + info->sRockRotSpeedX_copy = sRockRotSpeedX; + info->sRockRotSpeedY_copy = sRockRotSpeedY; + info->D_80AB85E0_copy = D_80AB85E0; + info->sLowerRiverSpawned_copy = sLowerRiverSpawned; + info->sUpperRiverSpawned_copy = sUpperRiverSpawned; + info->sEnPoFieldNumSpawned_copy = sEnPoFieldNumSpawned; + memcpy(info->sEnPoFieldSpawnPositions_copy, sEnPoFieldSpawnPositions, sizeof(info->sEnPoFieldSpawnPositions_copy)); + memcpy(info->sEnPoFieldSpawnSwitchFlags_copy, sEnPoFieldSpawnSwitchFlags, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy)); + + info->sTakaraIsInitialized_copy = sTakaraIsInitialized; + info->D_80B41D90_copy = D_80B41D90; + info->sEnXcFlameSpawned_copy = sEnXcFlameSpawned; + info->D_80B41DA8_copy = D_80B41DA8; + info->D_80B41DAC_copy = D_80B41DAC; + info->D_80B4A1B0_copy = D_80B4A1B0; + info->D_80B4A1B4_copy = D_80B4A1B4; + info->D_80B5A468_copy = D_80B5A468; + info->D_80B5A494_copy = D_80B5A494; + info->D_80B5A4BC_copy = D_80B5A4BC; + info->sKankyoIsSpawned_copy = sKankyoIsSpawned; + info->sTrailingFairies_copy = sTrailingFairies; + +} + +void SaveState::LoadOverlayStaticData(void) { + sBgDdanKdVelocity = info->sBgDdanKdVelocity_copy; + sBgDdanKdAccel = info->sBgDdanKdAccel_copy; + sBgDodoagoFirstExplosiveFlag = info->sBgDodoagoFirstExplosiveFlag_copy; + sBgDodoagoDisableBombCatcher = info->sBgDodoagoDisableBombCatcher_copy; + sBgDodoagoTimer = info->sBgDodoagoTimer_copy; + D_80880F30 = info->D_80880F30_copy; + D_80881014 = info->D_80881014_copy; + D_8088BFC0 = info->D_8088BFC0_copy; + sBgMoriHineriNextCamIdx = info->sBgMoriHineriNextCamIdx_copy; + sBgPoEventBlocksAtRest = info->sBgPoEventBlocksAtRest_copy; + sBgPoEventPuzzleState = info->sBgPoEventPuzzleState_copy; + sBgPoEventblockPushDist = info->sBgPoEventblockPushDist_copy; + D_808A9508 = info->D_808A9508_copy; + D_808B85D0 = info->D_808B85D0_copy; + sBossGanonSeed1 = info->sBossGanonSeed1_copy; + sBossGanonSeed2 = info->sBossGanonSeed2_copy; + sBossGanonSeed3 = info->sBossGanonSeed3_copy; + sBossGanonGanondorf = info->sBossGanonGanondorf_copy; + sBossGanonZelda = info->sBossGanonZelda_copy; + sBossGanonCape = info->sBossGanonCape_copy; + memcpy(sBossGanonEffectBuf, info->sBossGanonEffectBuf_copy, sizeof(info->sBossGanonEffectBuf_copy)); + + D_8090EB20 = info->D_8090EB20_copy; + D_80910638 = info->D_80910638_copy; + sBossGanon2Zelda = info->sBossGanon2Zelda_copy; + D_8090EB30 = info->D_8090EB30_copy; + sBossGanon2Seed1 = info->sBossGanon2Seed1_copy; + sBossGanon2Seed2 = info->sBossGanon2Seed2_copy; + sBossGanon2Seed3 = info->sBossGanon2Seed3_copy; + memcpy(D_809105D8, info->D_809105D8_copy, sizeof(D_809105D8)); + memcpy(D_80910608, info->D_80910608_copy, sizeof(D_80910608)); + memcpy(sBossGanon2Particles, info->sBossGanon2Particles_copy, sizeof(sBossGanon2Particles)); + sTwInitalized = info->sTwInitalized_copy; + memcpy(sTwEffects, info->sTwEffects_copy, sizeof(sTwEffects)); + sDemo6kVelocity = info->sDemo6kVelocity_copy; + + D_8096CE94 = info->D_8096CE94_copy; + demoKekkaiVel = info->demoKekkaiVel_copy; + sSlugGroup = info->sSlugGroup_copy; + sClearTagIsEffectsInitialized = info->sClearTagIsEffectInitialized_copy; + memcpy(sClearTagEffects, info->sClearTagEffects_copy, sizeof(sClearTagEffects)); + + D_80A7DEB0 = info->D_80A7DEB0_copy; + D_80A7DEB4 = info->D_80A7DEB4_copy; + D_80A7DEB8 = info->D_80A7DEB8_copy; + sRockRotSpeedX = info->sRockRotSpeedX_copy; + sRockRotSpeedY = info->sRockRotSpeedY_copy; + D_80AB85E0 = info->D_80AB85E0_copy; + sLowerRiverSpawned = info->sLowerRiverSpawned_copy; + sUpperRiverSpawned = info->sUpperRiverSpawned_copy; + sEnPoFieldNumSpawned = info->sEnPoFieldNumSpawned_copy; + memcpy(sEnPoFieldSpawnPositions, info->sEnPoFieldSpawnPositions_copy, sizeof(info->sEnPoFieldSpawnPositions_copy)); + memcpy(sEnPoFieldSpawnSwitchFlags, info->sEnPoFieldSpawnSwitchFlags_copy, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy)); + + sTakaraIsInitialized = info->sTakaraIsInitialized_copy; + D_80B41D90 = info->D_80B41D90_copy; + sEnXcFlameSpawned = info->sEnXcFlameSpawned_copy; + D_80B41DA8 = info->D_80B41DA8_copy; + D_80B41DAC = info->D_80B41DAC_copy; + D_80B4A1B0 = info->D_80B4A1B0_copy; + D_80B4A1B4 = info->D_80B4A1B4_copy; + D_80B5A468 = info->D_80B5A468_copy; + D_80B5A494 = info->D_80B5A494_copy; + D_80B5A4BC = info->D_80B5A4BC_copy; + sKankyoIsSpawned = info->sKankyoIsSpawned_copy; + sTrailingFairies = info->sTrailingFairies_copy; +} + +void SaveState::SaveMiscCodeData(void) { + info->gGameOverTimer_copy = gGameOverTimer; + info->gTimeIncrement_copy = gTimeIncrement; + info->sLoadedMarkDataTableCopy = sLoadedMarkDataTable; + + info->sPlayerInitialPosX_copy = sPlayerInitialPosX; + info->sPlayerInitialPosZ_copy = sPlayerInitialPosZ; + info->sPlayerInitialDirection_copy = sPlayerInitialDirection; + + info->sOcarinaInpEnabled_copy = sOcarinaInpEnabled; + info->D_80130F10_copy = D_80130F10; + info->sCurOcarinaBtnVal_copy = sCurOcarinaBtnVal; + info->sPrevOcarinaNoteVal_copy = sPrevOcarinaNoteVal; + info->sCurOcarinaBtnIdx_copy = sCurOcarinaBtnIdx; + info->sLearnSongLastBtn_copy = sLearnSongLastBtn; + info->D_80130F24_copy = D_80130F24; + info->D_80130F28_copy = D_80130F28; + info->D_80130F2C_copy = D_80130F2C; + info->D_80130F30_copy = D_80130F30; + info->D_80130F34_copy = D_80130F34; + info->sPlaybackState_copy = sPlaybackState; + info->D_80130F3C_copy = D_80130F3C; + info->sNotePlaybackTimer_copy = sNotePlaybackTimer; + info->sPlaybackNotePos_copy = sPlaybackNotePos; + info->sStaffPlaybackPos_copy = sStaffPlaybackPos; + + + info->sCurOcarinaBtnPress_copy = sCurOcarinaBtnPress; + info->D_8016BA10_copy = D_8016BA10; + info->sPrevOcarinaBtnPress_copy = sPrevOcarinaBtnPress; + info->D_8016BA18_copy = D_8016BA18; + info->D_8016BA1C_copy = D_8016BA1C; + memcpy(info->sCurOcarinaSong_copy, sCurOcarinaSong, sizeof(sCurOcarinaSong)); + info->sOcarinaSongAppendPos_copy = sOcarinaSongAppendPos; + info->sOcarinaHasStartedSong_copy = sOcarinaHasStartedSong; + info->sOcarinaSongNoteStartIdx_copy = sOcarinaSongNoteStartIdx; + info->sOcarinaSongCnt_copy = sOcarinaSongCnt; + info->sOcarinaAvailSongs_copy = sOcarinaAvailSongs; + info->sStaffPlayingPos_copy = sStaffPlayingPos; + memcpy(info->sLearnSongPos_copy, sLearnSongPos, sizeof(sLearnSongPos)); + memcpy(info->D_8016BA50_copy, D_8016BA50, sizeof(D_8016BA50)); + memcpy(info->D_8016BA70_copy, D_8016BA70, sizeof(D_8016BA70)); + memcpy(info->sLearnSongExpectedNote_copy, sLearnSongExpectedNote, sizeof(sLearnSongExpectedNote)); + memcpy(&info->D_8016BAA0_copy, &D_8016BAA0, sizeof(D_8016BAA0)); + info->sAudioHasMalonBgm_copy = sAudioHasMalonBgm; + info->sAudioMalonBgmDist_copy = sAudioMalonBgmDist; + info->sDisplayedNoteValue_copy = sDisplayedNoteValue; + + + info->sOcarinaNoteBufPos_copy = sOcarinaNoteBufPos; + info->sOcarinaNoteBufLen_copy = sOcarinaNoteBufLen; + memcpy(info->sOcarinaNoteBuf_copy, sOcarinaNoteBuf, sizeof(sOcarinaNoteBuf)); + info->D_8014B2F4_copy = D_8014B2F4; + info->sTextboxSkipped_copy = sTextboxSkipped; + info->sNextTextId_copy = sNextTextId; + info->sLastPlayedSong_copy = sLastPlayedSong; + info->sHasSunsSong_copy = sHasSunsSong; + info->sMessageHasSetSfx_copy = sMessageHasSetSfx; + info->sOcarinaSongBitFlags_copy = sOcarinaSongBitFlags; +} + +void SaveState::LoadMiscCodeData(void) { + gGameOverTimer = info->gGameOverTimer_copy; + gTimeIncrement = info->gTimeIncrement_copy; + sLoadedMarkDataTable = info->sLoadedMarkDataTableCopy; + + sPlayerInitialPosX = info->sPlayerInitialPosX_copy; + sPlayerInitialPosZ = info->sPlayerInitialPosZ_copy; + sPlayerInitialDirection = info->sPlayerInitialDirection_copy; + + sOcarinaInpEnabled = info->sOcarinaInpEnabled_copy; + D_80130F10 = info->D_80130F10_copy; + sCurOcarinaBtnVal = info->sCurOcarinaBtnVal_copy; + sPrevOcarinaNoteVal = info->sPrevOcarinaNoteVal_copy; + sCurOcarinaBtnIdx = info->sCurOcarinaBtnIdx_copy; + sLearnSongLastBtn = info->sLearnSongLastBtn_copy; + D_80130F24 = info->D_80130F24_copy; + D_80130F28 = info->D_80130F28_copy; + D_80130F2C = info->D_80130F2C_copy; + D_80130F30 = info->D_80130F30_copy; + D_80130F34 = info->D_80130F34_copy; + sPlaybackState = info->sPlaybackState_copy; + D_80130F3C = info->D_80130F3C_copy; + sNotePlaybackTimer = info->sNotePlaybackTimer_copy; + sPlaybackNotePos = info->sPlaybackNotePos_copy; + sStaffPlaybackPos = info->sStaffPlaybackPos_copy; + + sCurOcarinaBtnPress = info->sCurOcarinaBtnPress_copy; + D_8016BA10 = info->D_8016BA10_copy; + sPrevOcarinaBtnPress = info->sPrevOcarinaBtnPress_copy; + D_8016BA18 = info->D_8016BA18_copy; + D_8016BA1C = info->D_8016BA1C_copy; + memcpy(sCurOcarinaSong, info->sCurOcarinaSong_copy, sizeof(sCurOcarinaSong)); + sOcarinaSongAppendPos = info->sOcarinaSongAppendPos_copy; + sOcarinaHasStartedSong = info->sOcarinaHasStartedSong_copy; + sOcarinaSongNoteStartIdx = info->sOcarinaSongNoteStartIdx_copy; + sOcarinaSongCnt = info->sOcarinaSongCnt_copy; + sOcarinaAvailSongs = info->sOcarinaAvailSongs_copy; + sStaffPlayingPos = info->sStaffPlayingPos_copy; + memcpy(info->sLearnSongPos_copy, info->sLearnSongPos_copy, sizeof(sLearnSongPos)); + memcpy(info->D_8016BA50_copy, info->D_8016BA50_copy, sizeof(D_8016BA50)); + memcpy(info->D_8016BA70_copy, info->D_8016BA70_copy, sizeof(D_8016BA70)); + memcpy(info->sLearnSongExpectedNote_copy, info->sLearnSongExpectedNote_copy, sizeof(sLearnSongExpectedNote)); + memcpy(&D_8016BAA0, &info->D_8016BAA0_copy, sizeof(D_8016BAA0)); + sAudioHasMalonBgm = info->sAudioHasMalonBgm_copy; + sAudioMalonBgmDist = info->sAudioMalonBgmDist_copy; + sDisplayedNoteValue = info->sDisplayedNoteValue_copy; + + sOcarinaNoteBufPos = info->sOcarinaNoteBufPos_copy; + sOcarinaNoteBufLen = info->sOcarinaNoteBufLen_copy; + memcpy(sOcarinaNoteBuf, info->sOcarinaNoteBuf_copy, sizeof(sOcarinaNoteBuf)); + + D_8014B2F4 = info->D_8014B2F4_copy; + sTextboxSkipped = info->sTextboxSkipped_copy; + sNextTextId = info->sNextTextId_copy; + sLastPlayedSong = info->sLastPlayedSong_copy; + sHasSunsSong = info->sHasSunsSong_copy; + sMessageHasSetSfx = info->sMessageHasSetSfx_copy; + sOcarinaSongBitFlags = info->sOcarinaSongBitFlags_copy; + + +} + +extern "C" void ProcessSaveStateRequests(void) { + OTRGlobals::Instance->gSaveStateMgr->ProcessSaveStateRequests(); +} + +void SaveStateMgr::SetCurrentSlot(unsigned int slot) { + SohImGui::overlay->TextDrawNotification(1.0f, true, "slot %u set", slot); + this->currentSlot = slot; +} + +unsigned int SaveStateMgr::GetCurrentSlot(void) { + return this->currentSlot; +} + +void SaveStateMgr::ProcessSaveStateRequests(void) { + while (!this->requests.empty()) { + const auto& request = this->requests.front(); + + switch (request.type) { + case RequestType::SAVE: + if (!this->states.contains(request.slot)) { + this->states[request.slot] = std::make_shared(OTRGlobals::Instance->gSaveStateMgr, request.slot); + } + this->states[request.slot]->Save(); + SohImGui::overlay->TextDrawNotification(1.0f, true, "saved state %u", request.slot); + break; + case RequestType::LOAD: + if (this->states.contains(request.slot)) { + this->states[request.slot]->Load(); + SohImGui::overlay->TextDrawNotification(1.0f, true, "loaded state %u", request.slot); + } else { + SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); + } + break; + [[unlikely]] default: + SPDLOG_ERROR("Invalid SaveState request type: {}", request.type); + break; + } + this->requests.pop(); + } +} + +SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) { + if (gGlobalCtx == nullptr) { + SPDLOG_ERROR("[SOH] Can not save or load a state outside of \"GamePlay\""); + SohImGui::overlay->TextDrawNotification(1.0f, true, "states not available here", request.slot); + return SaveStateReturn::FAIL_WRONG_GAMESTATE; + } + + switch (request.type) { + case RequestType::SAVE: + requests.push(request); + break; + case RequestType::LOAD: + if (states.contains(request.slot)) { + requests.push(request); + } else { + SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); + SohImGui::overlay->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot); + return SaveStateReturn::FAIL_INVALID_SLOT; + } + break; + [[unlikely]] default: + SPDLOG_ERROR("Invalid SaveState request type: {}", request.type); + return SaveStateReturn::FAIL_BAD_REQUEST; + break; + + } +} + +void SaveState::Save(void) { + std::unique_lock Lock(audio.mutex); + memcpy(&info->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */); + memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */); + + memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext)); + memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy)); + BackupSeqScriptState(); + + memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds)); + memcpy(&info->gSoundBankMutedCopy, gSoundBankMuted, sizeof(info->gSoundBankMutedCopy)); + + info->D_801333F0_copy = D_801333F0; + info->gAudioSfxSwapOff_copy = gAudioSfxSwapOff; + + memcpy(&info->gAudioSfxSwapSource_copy, gAudioSfxSwapSource, + sizeof(info->gAudioSfxSwapSource_copy)); + memcpy(&info->gAudioSfxSwapTarget_copy, gAudioSfxSwapTarget, + sizeof(info->gAudioSfxSwapTarget_copy)); + memcpy(&info->gAudioSfxSwapMode_copy, gAudioSfxSwapMode, + sizeof(info->gAudioSfxSwapMode_copy)); + + info->D_801755D0_copy = D_801755D0; + + memcpy(&info->saveContextCopy, &gSaveContext, sizeof(gSaveContext)); + memcpy(&info->gameInfoCopy, gGameInfo, sizeof(*gGameInfo)); + memcpy(&info->lightBufferCopy, &sLightsBuffer, sizeof(sLightsBuffer)); + memcpy(&info->mtxStackCopy, &sMatrixStack, sizeof(MtxF) * 20); + memcpy(&info->currentMtxCopy, &sCurrentMatrix, sizeof(MtxF)); + + //Various static data + info->blueWarpTimerCopy = sWarpTimerTarget; + BackupCameraData(); + SaveOnePointDemoData(); + SaveOverlayStaticData(); + SaveMiscCodeData(); + +} + +void SaveState::Load(void) { + std::unique_lock Lock(audio.mutex); + memcpy(gSystemHeap, &info->sysHeapCopy, SYSTEM_HEAP_SIZE); + memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE); + + memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext)); + memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy)); + LoadSeqScriptState(); + + memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext)); + memcpy(gGameInfo, &info->gameInfoCopy, sizeof(*gGameInfo)); + memcpy(&sLightsBuffer, &info->lightBufferCopy, sizeof(sLightsBuffer)); + memcpy(&sMatrixStack, &info->mtxStackCopy, sizeof(MtxF) * 20); + memcpy(&sCurrentMatrix, &info->currentMtxCopy, sizeof(MtxF)); + sWarpTimerTarget = info->blueWarpTimerCopy; + + memcpy(gActiveSounds, info->gActiveSoundsCopy, sizeof(gActiveSounds)); + memcpy(gSoundBankMuted, &info->gSoundBankMutedCopy, sizeof(info->gSoundBankMutedCopy)); + D_801333F0 = info->D_801333F0_copy; + gAudioSfxSwapOff = info->gAudioSfxSwapOff_copy; + + memcpy(gAudioSfxSwapSource, &info->gAudioSfxSwapSource_copy, + sizeof(info->gAudioSfxSwapSource_copy)); + memcpy(gAudioSfxSwapTarget, &info->gAudioSfxSwapTarget_copy, + sizeof(info->gAudioSfxSwapTarget_copy)); + memcpy(gAudioSfxSwapMode, &info->gAudioSfxSwapMode_copy, + sizeof(info->gAudioSfxSwapMode_copy)); + + //Various static data + D_801755D0 = info->D_801755D0_copy; + LoadCameraData(); + LoadOnePointDemoData(); + LoadOverlayStaticData(); + LoadMiscCodeData(); + +} diff --git a/soh/soh/Enhancements/savestates.h b/soh/soh/Enhancements/savestates.h new file mode 100644 index 000000000..4ac142172 --- /dev/null +++ b/soh/soh/Enhancements/savestates.h @@ -0,0 +1,62 @@ +#ifndef SAVE_STATES_H +#define SAVE_STATES_H + +#include +#include +#include +#include +#include + +enum class SaveStateReturn { + SUCCESS, + FAIL_INVALID_SLOT, + FAIL_NO_MEMORY, + FAIL_STATE_EMPTY, + FAIL_WRONG_GAMESTATE, + FAIL_BAD_REQUEST, +}; + +typedef struct SaveStateHeader { + uint32_t stateMagic; + uint32_t stateVersion; + //uint32_t gameVersion; +} SaveStateHeader; + +enum class RequestType { + SAVE, + LOAD, +}; + +typedef struct SaveStateRequest { + unsigned int slot; + RequestType type; +} SaveStateRequest; + +class SaveState; + +class SaveStateMgr { + friend class SaveState; + private: + unsigned int currentSlot; + std::unordered_map> states; + std::queue requests; + std::mutex mutex; + + public: + + SaveStateReturn AddRequest(const SaveStateRequest request); + SaveStateMgr(); + ~SaveStateMgr(); + + void SetCurrentSlot(unsigned int slot); + unsigned int GetCurrentSlot(void); + + SaveStateMgr& operator=(const SaveStateMgr& rhs) = delete; + SaveStateMgr(const SaveStateMgr& rhs) = delete; + + void ProcessSaveStateRequests(void); + +}; +extern std::shared_ptr gSaveStateMgr; + +#endif diff --git a/soh/soh/Enhancements/savestates_extern.inc b/soh/soh/Enhancements/savestates_extern.inc new file mode 100644 index 000000000..c3b129a32 --- /dev/null +++ b/soh/soh/Enhancements/savestates_extern.inc @@ -0,0 +1,257 @@ +extern "C" MtxF* sMatrixStack; +extern "C" MtxF* sCurrentMatrix; +extern "C" LightsBuffer sLightsBuffer; +extern "C" s16 sWarpTimerTarget; +extern "C" MapMarkData** sLoadedMarkDataTable; + +//Camera static data +extern "C" int32_t sInitRegs; +extern "C" int32_t gDbgCamEnabled; +extern "C" int32_t sDbgModeIdx; +extern "C" int16_t sNextUID; +extern "C" int32_t sCameraInterfaceFlags; +extern "C" int32_t sCameraInterfaceAlpha; +extern "C" int32_t sCameraShrinkWindowVal; +extern "C" int32_t D_8011D3AC; +extern "C" int32_t sDemo5PrevAction12Frame; +extern "C" int32_t sDemo5PrevSfxFrame; +extern "C" int32_t D_8011D3F0; +extern "C" OnePointCsFull D_8011D6AC[]; +extern "C" OnePointCsFull D_8011D724[]; +extern "C" OnePointCsFull D_8011D79C[]; +extern "C" OnePointCsFull D_8011D83C[]; +extern "C" OnePointCsFull D_8011D88C[]; +extern "C" OnePointCsFull D_8011D8DC[]; +extern "C" OnePointCsFull D_8011D954[]; +extern "C" OnePointCsFull D_8011D9F4[]; +extern "C" int16_t D_8011DB08; +extern "C" int16_t D_8011DB0C; +extern "C" int32_t sOOBTimer; +extern "C" f32 D_8015CE50; +extern "C" f32 D_8015CE54; +extern "C" CamColChk D_8015CE58; + +//Gameover +extern "C" uint16_t gGameOverTimer; + +//One Point Demo +extern "C" uint32_t sPrevFrameCs1100; +extern "C" CutsceneCameraPoint D_8012013C[14]; +extern "C" CutsceneCameraPoint D_8012021C[14]; +extern "C" CutsceneCameraPoint D_801204D4[14]; +extern "C" CutsceneCameraPoint D_801205B4[14]; +extern "C" OnePointCsFull D_801208EC[3]; +extern "C" OnePointCsFull D_80120964[2]; +extern "C" OnePointCsFull D_801209B4[4]; +extern "C" OnePointCsFull D_80120ACC[5]; +extern "C" OnePointCsFull D_80120B94[11]; +extern "C" OnePointCsFull D_80120D4C[7]; +extern "C" OnePointCsFull D_80120FA4[6]; +extern "C" OnePointCsFull D_80121184[2]; +extern "C" OnePointCsFull D_801211D4[2]; +extern "C" OnePointCsFull D_8012133C[3]; +extern "C" OnePointCsFull D_801213B4[5]; +extern "C" OnePointCsFull D_8012151C[2]; +extern "C" OnePointCsFull D_8012156C[2]; +extern "C" OnePointCsFull D_801215BC[1]; +extern "C" OnePointCsFull D_80121C24[7]; +extern "C" OnePointCsFull D_80121D3C[3]; +extern "C" OnePointCsFull D_80121F1C[4]; +extern "C" OnePointCsFull D_80121FBC[4]; +extern "C" OnePointCsFull D_801220D4[5]; +extern "C" OnePointCsFull D_80122714[4]; +extern "C" OnePointCsFull D_80122CB4[2]; +extern "C" OnePointCsFull D_80122D04[2]; +extern "C" OnePointCsFull D_80122E44[2][7]; +extern "C" OnePointCsFull D_8012313C[3]; +extern "C" OnePointCsFull D_801231B4[4]; +extern "C" OnePointCsFull D_80123254[2]; +extern "C" OnePointCsFull D_801232A4[1]; +extern "C" OnePointCsFull D_80123894[3]; +extern "C" OnePointCsFull D_8012390C[2]; +extern "C" OnePointCsFull D_8012395C[3]; +extern "C" OnePointCsFull D_801239D4[3]; + +// z_bg_ddan_kd +extern "C" Vec3f sBgDdanKdVelocity; +extern "C" Vec3f sBgDdanKdAccel; + +// z_bg_dodoago +extern "C" s16 sBgDodoagoFirstExplosiveFlag; +extern "C" u8 sBgDodoagoDisableBombCatcher; +extern "C" s32 sBgDodoagoTimer; + +// z_bg_haka_trap +extern "C" uint32_t D_80880F30; +extern "C" uint32_t D_80881014; + +// z_bg_hidan_rock +extern "C" float D_8088BFC0; + +// z_bg_menkuri_eye +extern "C" int32_t D_8089C1A0; + +// z_bg_mori_hineri +extern "C" int16_t sBgMoriHineriNextCamIdx; + +// z_bg_po_event +extern "C" uint8_t sBgPoEventBlocksAtRest; +extern "C" uint8_t sBgPoEventPuzzleState; +extern "C" float sBgPoEventblockPushDist; + +// z_bg_relay_objects +extern "C" uint32_t D_808A9508; + +// z_bg_spot18_basket +extern "C" int16_t D_808B85D0; + +// z_boss_ganon +extern "C" uint32_t sBossGanonSeed1; +extern "C" uint32_t sBossGanonSeed2; +extern "C" uint32_t sBossGanonSeed3; +extern "C" void* sBossGanonGanondorf; +extern "C" void* sBossGanonZelda; +extern "C" void* sBossGanonCape; +extern "C" GanondorfEffect sBossGanonEffectBuf[200]; + +// z_boss_ganon2 +extern "C" Vec3f D_8090EB20; +extern "C" int8_t D_80910638; +extern "C" void* sBossGanon2Zelda; +extern "C" void* D_8090EB30; +extern "C" int32_t sBossGanon2Seed1; +extern "C" int32_t sBossGanon2Seed2; +extern "C" int32_t sBossGanon2Seed3; +extern "C" Vec3f D_809105D8[4]; +extern "C" Vec3f D_80910608[4]; +extern "C" BossGanon2Effect sBossGanon2Particles[100]; + +// z_boss_tw +extern "C" uint8_t sTwInitalized; +extern "C" BossTwEffect sTwEffects[150]; + +// z_demo_6k +extern "C" Vec3f sDemo6kVelocity; + +// z_demo_du +extern "C" int32_t D_8096CE94; + +// z_demo_kekkai +extern "C" Vec3f demoKekkaiVel; + +// z_en_bw +extern "C" int32_t sSlugGroup; + +// z_en_clear_tag +extern "C" uint8_t sClearTagIsEffectsInitialized; +extern "C" EnClearTagEffect sClearTagEffects[CLEAR_TAG_EFFECT_MAX_COUNT]; + +// z_en_fr +extern "C" EnFrPointers sEnFrPointers; + +// z_en_goma +extern "C" uint8_t sSpawnNum; + +// z_en_in +extern "C" int32_t D_80A7B998; + +// z_en_insect +extern "C" float D_80A7DEB0; +extern "C" int16_t D_80A7DEB4; +extern "C" int16_t D_80A7DEB8; + +// z_en_ishi +extern "C" int16_t sRockRotSpeedX; +extern "C" int16_t sRockRotSpeedY; + +// z_en_niw +extern "C" int16_t D_80AB85E0; +extern "C" uint8_t sLowerRiverSpawned; +extern "C" uint8_t sUpperRiverSpawned; + +// z_en_po_field +extern "C" int32_t sEnPoFieldNumSpawned; +extern "C" Vec3s sEnPoFieldSpawnPositions[10]; +extern "C" u8 sEnPoFieldSpawnSwitchFlags[10]; + +// z_en_takara_man +extern "C" uint8_t sTakaraIsInitialized; + +// z_en_xc +extern "C" int32_t D_80B41D90; +extern "C" int32_t sEnXcFlameSpawned; +extern "C" int32_t D_80B41DA8; +extern "C" int32_t D_80B41DAC; + +// z_en_zf +extern "C" int16_t D_80B4A1B0; +extern "C" int16_t D_80B4A1B4; + +extern "C" int32_t D_80B5A468; +extern "C" int32_t D_80B5A494; +extern "C" int32_t D_80B5A4BC; + +extern "C" uint8_t sKankyoIsSpawned; +extern "C" int16_t sTrailingFairies; + +extern "C" uint16_t gTimeIncrement; + +extern "C" s16 sPlayerInitialPosX; +extern "C" s16 sPlayerInitialPosZ; +extern "C" s16 sPlayerInitialDirection; + +// code_800EC960 +// Related to ocarina +extern "C" u8 sOcarinaInpEnabled; +extern "C" s8 D_80130F10; +extern "C" u8 sCurOcarinaBtnVal; +extern "C" u8 sPrevOcarinaNoteVal; +extern "C" u8 sCurOcarinaBtnIdx; +extern "C" u8 sLearnSongLastBtn; +extern "C" f32 D_80130F24; +extern "C" f32 D_80130F28; +extern "C" s8 D_80130F2C; +extern "C" s8 D_80130F30; +extern "C" s8 D_80130F34; +extern "C" u8 sPlaybackState; +extern "C" u32 D_80130F3C; +extern "C" u32 sNotePlaybackTimer; +extern "C" u16 sPlaybackNotePos; +extern "C" u16 sStaffPlaybackPos; + +//IDK what this is but it looks important +extern "C" u32 sCurOcarinaBtnPress; +extern "C" u32 D_8016BA10; +extern "C" u32 sPrevOcarinaBtnPress; +extern "C" s32 D_8016BA18; +extern "C" s32 D_8016BA1C; +extern "C" u8 sCurOcarinaSong[8]; +extern "C" u8 sOcarinaSongAppendPos; +extern "C" u8 sOcarinaHasStartedSong; +extern "C" u8 sOcarinaSongNoteStartIdx; +extern "C" u8 sOcarinaSongCnt; +extern "C" u16 sOcarinaAvailSongs; +extern "C" u8 sStaffPlayingPos; +extern "C" u16 sLearnSongPos[0x10]; +extern "C" u16 D_8016BA50[0x10]; +extern "C" u16 D_8016BA70[0x10]; +extern "C" u8 sLearnSongExpectedNote[0x10]; +extern "C" OcarinaNote D_8016BAA0; +extern "C" u8 sAudioHasMalonBgm; +extern "C" f32 sAudioMalonBgmDist; +extern "C" u8 sDisplayedNoteValue; + + + +// z_message_PAL +extern "C" s16 sOcarinaNoteBufPos; +extern "C" s16 sOcarinaNoteBufLen; +extern "C" u8 sOcarinaNoteBuf[12]; + +extern "C" u8 D_8014B2F4; +extern "C" u8 sTextboxSkipped; +extern "C" u16 sNextTextId; +extern "C" s16 sLastPlayedSong; +extern "C" s16 sHasSunsSong; +extern "C" s16 sMessageHasSetSfx; +extern "C" u16 sOcarinaSongBitFlags; \ No newline at end of file diff --git a/soh/soh/OTRAudio.h b/soh/soh/OTRAudio.h new file mode 100644 index 000000000..ee0ec46a2 --- /dev/null +++ b/soh/soh/OTRAudio.h @@ -0,0 +1,8 @@ +#pragma once + +static struct { + std::condition_variable cv_to_thread, cv_from_thread; + std::mutex mutex; + bool initialized; + bool processing; +} audio; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index aad82be29..e8e1b31c1 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1,4 +1,5 @@ #include "OTRGlobals.h" +#include "OTRAudio.h" #include #include #include @@ -11,10 +12,14 @@ #include "Window.h" #include "z64animation.h" #include "z64bgcheck.h" -#include "../soh/enhancements/gameconsole.h" +#include "Enhancements/gameconsole.h" #include #include +#ifdef _WIN32 #include +#else +#include +#endif #include #include #include @@ -22,23 +27,22 @@ #include #include "Lib/stb/stb_image.h" #include "AudioPlayer.h" -#include "../soh/Enhancements/debugconsole.h" -#include "../soh/Enhancements/debugger/debugger.h" +#include "Enhancements/debugconsole.h" +#include "Enhancements/debugger/debugger.h" +#include "soh/frame_interpolation.h" #include "Utils/BitConverter.h" #include "variables.h" +#include "macros.h" #include +#include + OTRGlobals* OTRGlobals::Instance; -static struct { - std::condition_variable cv_to_thread, cv_from_thread; - std::mutex mutex; - bool initialized; - bool processing; -} audio; - OTRGlobals::OTRGlobals() { + context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian"); + gSaveStateMgr = std::make_shared(); context->GetWindow()->Init(); } @@ -59,7 +63,7 @@ extern "C" void InitOTR() { OTRGlobals::Instance = new OTRGlobals(); auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version"); - if (!t->bHasLoadError) + if (!t->bHasLoadError) { //uint32_t gameVersion = BitConverter::ToUInt32BE((uint8_t*)t->buffer.get(), 0); uint32_t gameVersion = *((uint32_t*)t->buffer.get()); @@ -72,6 +76,7 @@ extern "C" void InitOTR() { Debug_Init(); } +#ifdef _WIN32 extern "C" uint64_t GetFrequency() { LARGE_INTEGER nFreq; @@ -86,6 +91,21 @@ extern "C" uint64_t GetPerfCounter() { return ticks.QuadPart; } +#else +extern "C" uint64_t GetFrequency() { + return 1000; // sec -> ms +} + +extern "C" uint64_t GetPerfCounter() { + struct timespec monotime; + clock_gettime(CLOCK_MONOTONIC, &monotime); + + uint64_t remainingMs = (monotime.tv_nsec / 1000000); + + // in milliseconds + return monotime.tv_sec * 1000 + remainingMs; +} +#endif // C->C++ Bridge extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) { @@ -93,12 +113,69 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) { } extern "C" void Graph_StartFrame() { + // Why -1? + int32_t dwScancode = OTRGlobals::Instance->context->GetWindow()->lastScancode; + OTRGlobals::Instance->context->GetWindow()->lastScancode = -1; + + switch (dwScancode - 1) { + case SDL_SCANCODE_F5: { + const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn stateReturn = + OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); + + switch (stateReturn) { + case SaveStateReturn::SUCCESS: + SPDLOG_INFO("[SOH] Saved state to slot {}", slot); + break; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + SPDLOG_ERROR("[SOH] Can not save a state outside of \"GamePlay\""); + break; + [[unlikely]] default: + break; + } + break; + } + case SDL_SCANCODE_F6: { + unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + slot++; + if (slot > 5) { + slot = 0; + } + OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot); + SPDLOG_INFO("Set SaveState slot to {}.", slot); + break; + } + case SDL_SCANCODE_F7: { + const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn stateReturn = + OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); + + switch (stateReturn) { + case SaveStateReturn::SUCCESS: + SPDLOG_INFO("[SOH] Loaded state from slot {}", slot); + break; + case SaveStateReturn::FAIL_INVALID_SLOT: + SPDLOG_ERROR("[SOH] Invalid State Slot Number {}", slot); + break; + case SaveStateReturn::FAIL_STATE_EMPTY: + SPDLOG_ERROR("[SOH] State Slot {} is empty", slot); + break; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + SPDLOG_ERROR("[SOH] Can not load a state outside of \"GamePlay\""); + break; + [[unlikely]] default: + break; + } + + break; + } + } OTRGlobals::Instance->context->GetWindow()->StartFrame(); } // C->C++ Bridge extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { - OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(R_UPDATE_RATE); + OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(CVar_GetS32("g60FPS", 0) == 0 ? R_UPDATE_RATE : 1); if (!audio.initialized) { audio.initialized = true; @@ -110,6 +187,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { audio.cv_to_thread.wait(Lock); } } + std::unique_lock Lock(audio.mutex); //AudioMgr_ThreadEntry(&gAudioMgr); // 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333.. // in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528 @@ -135,10 +213,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { // printf("Audio samples before submitting: %d\n", audio_api->buffered()); AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); - { - std::unique_lock Lock(audio.mutex); - audio.processing = false; - } + audio.processing = false; audio.cv_from_thread.notify_one(); } }).detach(); @@ -150,7 +225,15 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { } audio.cv_to_thread.notify_one(); - OTRGlobals::Instance->context->GetWindow()->RunCommands(commands); + std::vector> mtx_replacements; + if (CVar_GetS32("g60FPS", 0) != 0) { + int to = R_UPDATE_RATE; + for (int i = 1; i < to; i++) { + mtx_replacements.push_back(FrameInterpolation_Interpolate(i / (float)to)); + } + } + + OTRGlobals::Instance->context->GetWindow()->RunCommands(commands, mtx_replacements); { std::unique_lock Lock(audio.mutex); @@ -185,7 +268,7 @@ extern "C" void OTRResetScancode() OTRGlobals::Instance->context->GetWindow()->lastScancode = -1; } -extern "C" uint32_t ResourceMgr_GetGameVersion() +extern "C" uint32_t ResourceMgr_GetGameVersion() { return OTRGlobals::Instance->context->GetResourceManager()->GetGameVersion(); } @@ -309,7 +392,7 @@ extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) { if (res->cachedGameAsset != nullptr) return (char*)res->cachedGameAsset; - else + else { Vec3s* data = (Vec3s*)malloc(sizeof(Vec3s) * res->scalars.size()); @@ -429,7 +512,7 @@ extern "C" int ResourceMgr_OTRSigCheck(char* imgData) { uintptr_t i = (uintptr_t)(imgData); - if (i == 0xD9000000 || i == 0xE7000000 || (i & 0xF0000000) == 0xF0000000) + if (i == 0xD9000000 || i == 0xE7000000 || (i & 1) == 1) return 0; if ((i & 0xFF000000) != 0xAB000000 && (i & 0xFF000000) != 0xCD000000 && i != 0) { @@ -823,24 +906,24 @@ extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) { } extern "C" void bswapSoundFontSound(SoundFontSound* swappable) { - swappable->sample = (SoundFontSample*)_byteswap_ulong((u32)swappable->sample); - swappable->tuningAsU32 = _byteswap_ulong((u32)swappable->tuningAsU32); + swappable->sample = (SoundFontSample*)BOMSWAP32((u32)swappable->sample); + swappable->tuningAsU32 = BOMSWAP32((u32)swappable->tuningAsU32); } extern "C" void bswapDrum(Drum* swappable) { bswapSoundFontSound(&swappable->sound); - swappable->envelope = (AdsrEnvelope*)_byteswap_ulong((u32)swappable->envelope); + swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope); } extern "C" void bswapInstrument(Instrument* swappable) { - swappable->envelope = (AdsrEnvelope*)_byteswap_ulong((u32)swappable->envelope); + swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope); bswapSoundFontSound(&swappable->lowNotesSound); bswapSoundFontSound(&swappable->normalNotesSound); bswapSoundFontSound(&swappable->highNotesSound); } extern "C" void bswapSoundFontSample(SoundFontSample* swappable) { - u32 origBitfield = _byteswap_ulong(swappable->asU32); + u32 origBitfield = BOMSWAP32(swappable->asU32); swappable->codec = (origBitfield >> 28) & 0x0F; swappable->medium = (origBitfield >> 24) & 0x03; @@ -848,29 +931,29 @@ extern "C" void bswapSoundFontSample(SoundFontSample* swappable) { swappable->unk_bit25 = (origBitfield >> 21) & 0x01; swappable->size = (origBitfield) & 0x00FFFFFF; - swappable->sampleAddr = (u8*)_byteswap_ulong((u32)swappable->sampleAddr); - swappable->loop = (AdpcmLoop*)_byteswap_ulong((u32)swappable->loop); - swappable->book = (AdpcmBook*)_byteswap_ulong((u32)swappable->book); + swappable->sampleAddr = (u8*)BOMSWAP32((u32)swappable->sampleAddr); + swappable->loop = (AdpcmLoop*)BOMSWAP32((u32)swappable->loop); + swappable->book = (AdpcmBook*)BOMSWAP32((u32)swappable->book); } extern "C" void bswapAdpcmLoop(AdpcmLoop* swappable) { - swappable->start = (u32)_byteswap_ulong((u32)swappable->start); - swappable->end = (u32)_byteswap_ulong((u32)swappable->end); - swappable->count = (u32)_byteswap_ulong((u32)swappable->count); + swappable->start = (u32)BOMSWAP32((u32)swappable->start); + swappable->end = (u32)BOMSWAP32((u32)swappable->end); + swappable->count = (u32)BOMSWAP32((u32)swappable->count); if (swappable->count != 0) { for (int i = 0; i < 16; i++) { - swappable->state[i] = (s16)_byteswap_ushort(swappable->state[i]); + swappable->state[i] = (s16)BOMSWAP16(swappable->state[i]); } } } extern "C" void bswapAdpcmBook(AdpcmBook* swappable) { - swappable->order = (u32)_byteswap_ulong((u32)swappable->order); - swappable->npredictors = (u32)_byteswap_ulong((u32)swappable->npredictors); + swappable->order = (u32)BOMSWAP32((u32)swappable->order); + swappable->npredictors = (u32)BOMSWAP32((u32)swappable->npredictors); for (int i = 0; i < swappable->npredictors * swappable->order * sizeof(s16) * 4; i++) - swappable->book[i] = (s16)_byteswap_ushort(swappable->book[i]); + swappable->book[i] = (s16)BOMSWAP16(swappable->book[i]); } extern "C" bool AudioPlayer_Init(void) { @@ -900,7 +983,7 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { } extern "C" int Controller_ShouldRumble(size_t i) { - for (const auto& controller : Ship::Window::Controllers.at(i)) + for (const auto& controller : Ship::Window::Controllers.at(i)) { float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", i).c_str(), 1.0f); diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 339613b25..0a318de73 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -1,17 +1,22 @@ +#ifndef OTR_GLOBALS_H +#define OTR_GLOBALS_H + #pragma once #include "GlobalCtx2.h" #ifdef __cplusplus +#include "Enhancements/savestates.h" class OTRGlobals { public: - static OTRGlobals* Instance; + static OTRGlobals* Instance; - std::shared_ptr context; + std::shared_ptr context; + std::shared_ptr gSaveStateMgr; - OTRGlobals(); - ~OTRGlobals(); + OTRGlobals(); + ~OTRGlobals(); private: @@ -68,3 +73,5 @@ void AudioPlayer_Play(const uint8_t* buf, uint32_t len); void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); int Controller_ShouldRumble(size_t i); #endif + +#endif \ No newline at end of file diff --git a/soh/soh/frame_interpolation.cpp b/soh/soh/frame_interpolation.cpp new file mode 100644 index 000000000..bd85d41ce --- /dev/null +++ b/soh/soh/frame_interpolation.cpp @@ -0,0 +1,732 @@ +#include "Cvar.h" + +#include +#include +#include +#include + +#include "frame_interpolation.h" + +/* +Frame interpolation. + +The idea of this code is to interpolate all matrices. + +The code contains two approaches. The first is to interpolate +all inputs in transformations, such as angles, scale and distances, +and then perform the same transformations with the interpolated values. +After evaluation for some reason some animations such rolling look strange. + +The second approach is to simply interpolate the final matrices. This will +more or less simply interpolate the world coordinates for movements. +This will however make rotations ~180 degrees get the "paper effect". +The mitigation is to identify this case for actors and interpolate the +matrix but in model coordinates instead, by "removing" the rotation- +translation before interpolating, create a rotation matrix with the +interpolated angle which is then applied to the matrix. + +Currently the code contains both methods but only the second one is currently +used. + +Both approaches build a tree of instructions, containing matrices +at leaves. Every node is built from OPEN_DISPS/CLOSE_DISPS and manually +inserted FrameInterpolation_OpenChild/FrameInterpolation_Close child calls. +These nodes contain information that should suffice to identify the matrix, +so we can find it in an adjacent frame. + +We can interpolate an arbitrary amount of frames between two original frames, +given a specific interpolation factor (0=old frame, 0.5=average of frames, +1.0=new frame). +*/ + +extern "C" { + +void Matrix_Init(struct GameState* gameState); +void Matrix_Push(void); +void Matrix_Pop(void); +void Matrix_Get(MtxF* dest); +void Matrix_Put(MtxF* src); +void Matrix_Mult(MtxF* mf, u8 mode); +void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode); +void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode); +void Matrix_RotateX(f32 x, u8 mode); +void Matrix_RotateY(f32 y, u8 mode); +void Matrix_RotateZ(f32 z, u8 mode); +void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode); +void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation); +void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot); +Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest); +Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line); +Mtx* Matrix_NewMtx(struct GraphicsContext* gfxCtx, char* file, s32 line); +Mtx* Matrix_MtxFToNewMtx(MtxF* src, struct GraphicsContext* gfxCtx); +void Matrix_MultVec3f(Vec3f* src, Vec3f* dest); +void Matrix_MtxFCopy(MtxF* dest, MtxF* src); +void Matrix_MtxToMtxF(Mtx* src, MtxF* dest); +void Matrix_MultVec3fExt(Vec3f* src, Vec3f* dest, MtxF* mf); +void Matrix_Transpose(MtxF* mf); +void Matrix_ReplaceRotation(MtxF* mf); +void Matrix_MtxFToYXZRotS(MtxF* mf, Vec3s* rotDest, s32 flag); +void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag); +void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode); +MtxF* Matrix_CheckFloats(MtxF* mf, char* file, s32 line); +void Matrix_SetTranslateScaleMtx2(Mtx* mtx, f32 scaleX, f32 scaleY, f32 scaleZ, f32 translateX, f32 translateY, + f32 translateZ); + +MtxF* Matrix_GetCurrent(void); + +void SkinMatrix_MtxFMtxFMult(MtxF* mfA, MtxF* mfB, MtxF* dest); + +} + +static bool invert_matrix(const float m[16], float invOut[16]); + +using namespace std; + +namespace { + + enum class Op { + OpenChild, + CloseChild, + + MatrixPush, + MatrixPop, + MatrixPut, + MatrixMult, + MatrixTranslate, + MatrixScale, + MatrixRotate1Coord, + MatrixRotateZYX, + MatrixTranslateRotateZYX, + MatrixSetTranslateRotateYXZ, + MatrixMtxFToMtx, + MatrixToMtx, + MatrixReplaceRotation, + MatrixRotateAxis, + SkinMatrixMtxFToMtx + }; + + typedef pair label; + + union Data { + Data() { + } + + struct { + MtxF src; + } matrix_put; + + struct { + MtxF mf; + u8 mode; + } matrix_mult; + + struct { + f32 x, y, z; + u8 mode; + } matrix_translate, matrix_scale; + + struct { + u32 coord; + f32 value; + u8 mode; + } matrix_rotate_1_coord; + + struct { + s16 x, y, z; + u8 mode; + } matrix_rotate_zyx; + + struct { + Vec3f translation; + Vec3s rotation; + } matrix_translate_rotate_zyx; + + struct { + f32 translateX, translateY, translateZ; + Vec3s rot; + //MtxF mtx; + bool has_mtx; + } matrix_set_translate_rotate_yxz; + + struct { + MtxF src; + Mtx* dest; + } matrix_mtxf_to_mtx; + + struct { + Mtx* dest; + MtxF src; + bool has_adjusted; + } matrix_to_mtx; + + struct { + MtxF mf; + } matrix_replace_rotation; + + struct { + f32 angle; + Vec3f axis; + u8 mode; + } matrix_rotate_axis; + + struct { + label key; + size_t idx; + } open_child; + }; + + struct Path { + map> children; + map> ops; + vector> items; + }; + + struct Recording { + Path root_path; + }; + + bool is_recording; + vector current_path; + uint32_t camera_epoch; + uint32_t previous_camera_epoch; + Recording current_recording; + Recording previous_recording; + + bool next_is_actor_pos_rot_matrix; + bool has_inv_actor_mtx; + MtxF inv_actor_mtx; + size_t inv_actor_mtx_path_index; + + Data& append(Op op) { + auto& m = current_path.back()->ops[op]; + current_path.back()->items.emplace_back(op, m.size()); + return m.emplace_back(); + } + + struct InterpolateCtx { + float step; + float w; + unordered_map mtx_replacements; + MtxF tmp_mtxf, tmp_mtxf2; + Vec3f tmp_vec3f; + Vec3s tmp_vec3s; + MtxF actor_mtx; + + MtxF* new_replacement(Mtx* addr) { + return &mtx_replacements[addr]; + } + + void interpolate_mtxf(MtxF* res, MtxF* o, MtxF* n) { + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + res->mf[i][j] = w * o->mf[i][j] + step * n->mf[i][j]; + } + } + } + + float lerp(f32 o, f32 n) { + return w * o + step * n; + } + + void lerp_vec3f(Vec3f* res, Vec3f* o, Vec3f* n) { + res->x = lerp(o->x, n->x); + res->y = lerp(o->y, n->y); + res->z = lerp(o->z, n->z); + } + + float interpolate_angle(f32 o, f32 n) { + if (o == n) + return n; + o = fmodf(o, 2 * M_PI); + if (o < 0.0f) { + o += 2 * M_PI; + } + n = fmodf(n, 2 * M_PI); + if (n < 0.0f) { + n += 2 * M_PI; + } + if (fabsf(o - n) > M_PI) { + if (o < n) { + o += 2 * M_PI; + } else { + n += 2 * M_PI; + } + } + if (fabsf(o - n) > M_PI / 2) { + //return n; + } + return lerp(o, n); + } + + s16 interpolate_angle(s16 os, s16 ns) { + if (os == ns) + return ns; + int o = (u16)os; + int n = (u16)ns; + u16 res; + int diff = o - n; + if (-0x8000 <= diff && diff <= 0x8000) { + if (diff < -0x4000 || diff > 0x4000) { + return ns; + } + res = (u16)(w * o + step * n); + } else { + if (o < n) { + o += 0x10000; + } else { + n += 0x10000; + } + diff = o - n; + if (diff < -0x4000 || diff > 0x4000) { + return ns; + } + res = (u16)(w * o + step * n); + } + if (os / 327 == ns / 327 && (s16)res / 327 != os / 327) { + int bp = 0; + } + return res; + } + + void interpolate_angles(Vec3s* res, Vec3s* o, Vec3s* n) { + res->x = interpolate_angle(o->x, n->x); + res->y = interpolate_angle(o->y, n->y); + res->z = interpolate_angle(o->z, n->z); + } + + void interpolate_branch(Path* old_path, Path *new_path) { + for (auto& item : new_path->items) { + Data& new_op = new_path->ops[item.first][item.second]; + + if (item.first == Op::OpenChild) { + if (auto it = old_path->children.find(new_op.open_child.key); + it != old_path->children.end() && new_op.open_child.idx < it->second.size()) { + interpolate_branch(&it->second[new_op.open_child.idx], + &new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]); + } else { + interpolate_branch( + &new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx], + &new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]); + } + continue; + } + + if (auto it = old_path->ops.find(item.first); it != old_path->ops.end()) { + if (item.second < it->second.size()) { + Data& old_op = it->second[item.second]; + switch (item.first) { + case Op::OpenChild: + break; + case Op::CloseChild: + break; + + case Op::MatrixPush: + Matrix_Push(); + break; + + case Op::MatrixPop: + Matrix_Pop(); + break; + + case Op::MatrixPut: + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_put.src, &new_op.matrix_put.src); + Matrix_Put(&tmp_mtxf); + break; + + case Op::MatrixMult: + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_mult.mf, &new_op.matrix_mult.mf); + Matrix_Mult(&tmp_mtxf, new_op.matrix_mult.mode); + break; + + case Op::MatrixTranslate: + Matrix_Translate(lerp(old_op.matrix_translate.x, new_op.matrix_translate.x), + lerp(old_op.matrix_translate.y, new_op.matrix_translate.y), + lerp(old_op.matrix_translate.z, new_op.matrix_translate.z), + new_op.matrix_translate.mode); + break; + + case Op::MatrixScale: + Matrix_Scale(lerp(old_op.matrix_scale.x, new_op.matrix_scale.x), + lerp(old_op.matrix_scale.y, new_op.matrix_scale.y), + lerp(old_op.matrix_scale.z, new_op.matrix_scale.z), + new_op.matrix_scale.mode); + break; + + case Op::MatrixRotate1Coord: { + float v = interpolate_angle(old_op.matrix_rotate_1_coord.value, new_op.matrix_rotate_1_coord.value); + u8 mode = new_op.matrix_rotate_1_coord.mode; + switch (new_op.matrix_rotate_1_coord.coord) { + case 0: + Matrix_RotateX(v, mode); + break; + + case 1: + Matrix_RotateY(v, mode); + break; + + case 2: + Matrix_RotateZ(v, mode); + break; + } + break; + } + + case Op::MatrixRotateZYX: + Matrix_RotateZYX(interpolate_angle(old_op.matrix_rotate_zyx.x, new_op.matrix_rotate_zyx.x), + interpolate_angle(old_op.matrix_rotate_zyx.y, new_op.matrix_rotate_zyx.y), + interpolate_angle(old_op.matrix_rotate_zyx.z, new_op.matrix_rotate_zyx.z), + new_op.matrix_rotate_zyx.mode); + break; + + case Op::MatrixTranslateRotateZYX: + lerp_vec3f(&tmp_vec3f, &old_op.matrix_translate_rotate_zyx.translation, &new_op.matrix_translate_rotate_zyx.translation); + interpolate_angles(&tmp_vec3s, &old_op.matrix_translate_rotate_zyx.rotation, &new_op.matrix_translate_rotate_zyx.rotation); + Matrix_TranslateRotateZYX(&tmp_vec3f, &tmp_vec3s); + break; + + case Op::MatrixSetTranslateRotateYXZ: + interpolate_angles(&tmp_vec3s, &old_op.matrix_set_translate_rotate_yxz.rot, + &new_op.matrix_set_translate_rotate_yxz.rot); + Matrix_SetTranslateRotateYXZ(lerp(old_op.matrix_set_translate_rotate_yxz.translateX, + new_op.matrix_set_translate_rotate_yxz.translateX), + lerp(old_op.matrix_set_translate_rotate_yxz.translateY, + new_op.matrix_set_translate_rotate_yxz.translateY), + lerp(old_op.matrix_set_translate_rotate_yxz.translateZ, + new_op.matrix_set_translate_rotate_yxz.translateZ), + &tmp_vec3s); + if (new_op.matrix_set_translate_rotate_yxz.has_mtx && old_op.matrix_set_translate_rotate_yxz.has_mtx) { + actor_mtx = *Matrix_GetCurrent(); + } + break; + + case Op::MatrixMtxFToMtx: + interpolate_mtxf(new_replacement(new_op.matrix_mtxf_to_mtx.dest), + &old_op.matrix_mtxf_to_mtx.src, &new_op.matrix_mtxf_to_mtx.src); + break; + + case Op::MatrixToMtx: { + //*new_replacement(new_op.matrix_to_mtx.dest) = *Matrix_GetCurrent(); + if (old_op.matrix_to_mtx.has_adjusted && new_op.matrix_to_mtx.has_adjusted) { + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src); + SkinMatrix_MtxFMtxFMult(&actor_mtx, &tmp_mtxf, new_replacement(new_op.matrix_to_mtx.dest)); + } else { + interpolate_mtxf(new_replacement(new_op.matrix_to_mtx.dest), + &old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src); + } + break; + } + + case Op::MatrixReplaceRotation: + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_replace_rotation.mf, &new_op.matrix_replace_rotation.mf); + Matrix_ReplaceRotation(&tmp_mtxf); + break; + + case Op::MatrixRotateAxis: + lerp_vec3f(&tmp_vec3f, &old_op.matrix_rotate_axis.axis, &new_op.matrix_rotate_axis.axis); + Matrix_RotateAxis(interpolate_angle(old_op.matrix_rotate_axis.angle, new_op.matrix_rotate_axis.angle), + &tmp_vec3f, new_op.matrix_rotate_axis.mode); + break; + + case Op::SkinMatrixMtxFToMtx: + break; + } + } + } + } + } + }; + +} // anonymous namespace + +unordered_map FrameInterpolation_Interpolate(float step) { + InterpolateCtx ctx; + ctx.step = step; + ctx.w = 1.0f - step; + ctx.interpolate_branch(&previous_recording.root_path, ¤t_recording.root_path); + return ctx.mtx_replacements; +} + +void FrameInterpolation_StartRecord(void) { + previous_recording = move(current_recording); + current_recording = {}; + current_path.clear(); + current_path.push_back(¤t_recording.root_path); + if (CVar_GetS32("g60FPS", 0) != 0) { + is_recording = true; + } +} + +void FrameInterpolation_StopRecord(void) { + previous_camera_epoch = camera_epoch; + is_recording = false; +} + +void FrameInterpolation_RecordOpenChild(const void* a, int b) { + if (!is_recording) + return; + label key = { a, b }; + auto& m = current_path.back()->children[key]; + append(Op::OpenChild).open_child = { key, m.size() }; + current_path.push_back(&m.emplace_back()); +} + +void FrameInterpolation_RecordCloseChild(void) { + if (!is_recording) + return; + //append(Op::CloseChild); + if (has_inv_actor_mtx && current_path.size() == inv_actor_mtx_path_index) { + has_inv_actor_mtx = false; + } + current_path.pop_back(); +} + +void FrameInterpolation_DontInterpolateCamera(void) { + camera_epoch = previous_camera_epoch + 1; +} + +int FrameInterpolation_GetCameraEpoch(void) { + return (int)camera_epoch; +} + +void FrameInterpolation_RecordActorPosRotMatrix(void) { + if (!is_recording) + return; + next_is_actor_pos_rot_matrix = true; +} + +void FrameInterpolation_RecordMatrixPush(void) { + if (!is_recording) + return; + append(Op::MatrixPush); +} + +void FrameInterpolation_RecordMatrixPop(void) { + if (!is_recording) + return; + append(Op::MatrixPop); +} + +void FrameInterpolation_RecordMatrixPut(MtxF* src) { + if (!is_recording) + return; + append(Op::MatrixPut).matrix_put = { *src }; +} + +void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixMult).matrix_mult = { *mf, mode }; +} + +void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixTranslate).matrix_translate = { x, y, z, mode }; +} + +void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixScale).matrix_scale = { x, y, z, mode }; +} + +void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixRotate1Coord).matrix_rotate_1_coord = { coord, value, mode }; +} + +void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixRotateZYX).matrix_rotate_zyx = { x, y, z, mode }; +} + +void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation) { + if (!is_recording) + return; + append(Op::MatrixTranslateRotateZYX).matrix_translate_rotate_zyx = { *translation, *rotation }; +} + +void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot) { + if (!is_recording) + return; + auto& d = append(Op::MatrixSetTranslateRotateYXZ).matrix_set_translate_rotate_yxz = { translateX, translateY, translateZ, + *rot }; + if (next_is_actor_pos_rot_matrix) { + d.has_mtx = true; + //d.mtx = *Matrix_GetCurrent(); + invert_matrix((const float *)Matrix_GetCurrent()->mf, (float *)inv_actor_mtx.mf); + next_is_actor_pos_rot_matrix = false; + has_inv_actor_mtx = true; + inv_actor_mtx_path_index = current_path.size(); + } +} + +void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest) { + if (!is_recording) + return; + append(Op::MatrixMtxFToMtx).matrix_mtxf_to_mtx = { *src, dest }; +} + +void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line) { + if (!is_recording) + return; + auto& d = append(Op::MatrixToMtx).matrix_to_mtx = { dest }; + if (has_inv_actor_mtx) { + d.has_adjusted = true; + SkinMatrix_MtxFMtxFMult(&inv_actor_mtx, Matrix_GetCurrent(), &d.src); + } else { + d.src = *Matrix_GetCurrent(); + } +} + +void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf) { + if (!is_recording) + return; + append(Op::MatrixReplaceRotation).matrix_replace_rotation = { *mf }; +} + +void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixRotateAxis).matrix_rotate_axis = { angle, *axis, mode }; +} + +void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest) { + if (!is_recording) + return; + FrameInterpolation_RecordMatrixMtxFToMtx(src, dest); +} + +// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix +static bool invert_matrix(const float m[16], float invOut[16]) { + float inv[16], det; + int i; + + inv[0] = m[5] * m[10] * m[15] - + m[5] * m[11] * m[14] - + m[9] * m[6] * m[15] + + m[9] * m[7] * m[14] + + m[13] * m[6] * m[11] - + m[13] * m[7] * m[10]; + + inv[4] = -m[4] * m[10] * m[15] + + m[4] * m[11] * m[14] + + m[8] * m[6] * m[15] - + m[8] * m[7] * m[14] - + m[12] * m[6] * m[11] + + m[12] * m[7] * m[10]; + + inv[8] = m[4] * m[9] * m[15] - + m[4] * m[11] * m[13] - + m[8] * m[5] * m[15] + + m[8] * m[7] * m[13] + + m[12] * m[5] * m[11] - + m[12] * m[7] * m[9]; + + inv[12] = -m[4] * m[9] * m[14] + + m[4] * m[10] * m[13] + + m[8] * m[5] * m[14] - + m[8] * m[6] * m[13] - + m[12] * m[5] * m[10] + + m[12] * m[6] * m[9]; + + inv[1] = -m[1] * m[10] * m[15] + + m[1] * m[11] * m[14] + + m[9] * m[2] * m[15] - + m[9] * m[3] * m[14] - + m[13] * m[2] * m[11] + + m[13] * m[3] * m[10]; + + inv[5] = m[0] * m[10] * m[15] - + m[0] * m[11] * m[14] - + m[8] * m[2] * m[15] + + m[8] * m[3] * m[14] + + m[12] * m[2] * m[11] - + m[12] * m[3] * m[10]; + + inv[9] = -m[0] * m[9] * m[15] + + m[0] * m[11] * m[13] + + m[8] * m[1] * m[15] - + m[8] * m[3] * m[13] - + m[12] * m[1] * m[11] + + m[12] * m[3] * m[9]; + + inv[13] = m[0] * m[9] * m[14] - + m[0] * m[10] * m[13] - + m[8] * m[1] * m[14] + + m[8] * m[2] * m[13] + + m[12] * m[1] * m[10] - + m[12] * m[2] * m[9]; + + inv[2] = m[1] * m[6] * m[15] - + m[1] * m[7] * m[14] - + m[5] * m[2] * m[15] + + m[5] * m[3] * m[14] + + m[13] * m[2] * m[7] - + m[13] * m[3] * m[6]; + + inv[6] = -m[0] * m[6] * m[15] + + m[0] * m[7] * m[14] + + m[4] * m[2] * m[15] - + m[4] * m[3] * m[14] - + m[12] * m[2] * m[7] + + m[12] * m[3] * m[6]; + + inv[10] = m[0] * m[5] * m[15] - + m[0] * m[7] * m[13] - + m[4] * m[1] * m[15] + + m[4] * m[3] * m[13] + + m[12] * m[1] * m[7] - + m[12] * m[3] * m[5]; + + inv[14] = -m[0] * m[5] * m[14] + + m[0] * m[6] * m[13] + + m[4] * m[1] * m[14] - + m[4] * m[2] * m[13] - + m[12] * m[1] * m[6] + + m[12] * m[2] * m[5]; + + inv[3] = -m[1] * m[6] * m[11] + + m[1] * m[7] * m[10] + + m[5] * m[2] * m[11] - + m[5] * m[3] * m[10] - + m[9] * m[2] * m[7] + + m[9] * m[3] * m[6]; + + inv[7] = m[0] * m[6] * m[11] - + m[0] * m[7] * m[10] - + m[4] * m[2] * m[11] + + m[4] * m[3] * m[10] + + m[8] * m[2] * m[7] - + m[8] * m[3] * m[6]; + + inv[11] = -m[0] * m[5] * m[11] + + m[0] * m[7] * m[9] + + m[4] * m[1] * m[11] - + m[4] * m[3] * m[9] - + m[8] * m[1] * m[7] + + m[8] * m[3] * m[5]; + + inv[15] = m[0] * m[5] * m[10] - + m[0] * m[6] * m[9] - + m[4] * m[1] * m[10] + + m[4] * m[2] * m[9] + + m[8] * m[1] * m[6] - + m[8] * m[2] * m[5]; + + det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + + if (det == 0) { + return false; + } + + det = 1.0 / det; + + for (i = 0; i < 16; i++) { + invOut[i] = inv[i] * det; + } + + return true; +} diff --git a/soh/soh/frame_interpolation.h b/soh/soh/frame_interpolation.h new file mode 100644 index 000000000..64c7197cd --- /dev/null +++ b/soh/soh/frame_interpolation.h @@ -0,0 +1,61 @@ +#pragma once + +#include "include/z64math.h" + +#ifdef __cplusplus + +#include + +std::unordered_map FrameInterpolation_Interpolate(float step); + +extern "C" { + +#endif + +void FrameInterpolation_StartRecord(void); + +void FrameInterpolation_StopRecord(void); + +void FrameInterpolation_RecordOpenChild(const void* a, int b); + +void FrameInterpolation_RecordCloseChild(void); + +void FrameInterpolation_DontInterpolateCamera(void); + +int FrameInterpolation_GetCameraEpoch(void); + +void FrameInterpolation_RecordActorPosRotMatrix(void); + +void FrameInterpolation_RecordMatrixPush(void); + +void FrameInterpolation_RecordMatrixPop(void); + +void FrameInterpolation_RecordMatrixPut(MtxF* src); + +void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode); + +void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode); + +void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode); + +void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode); + +void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode); + +void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation); + +void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot); + +void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest); + +void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line); + +void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf); + +void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode); + +void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest); + +#ifdef __cplusplus +} +#endif diff --git a/soh/soh/stubs.c b/soh/soh/stubs.c index c47c1fa5d..98f3b4823 100644 --- a/soh/soh/stubs.c +++ b/soh/soh/stubs.c @@ -12,12 +12,12 @@ OSViMode osViModeNtscLan1; OSViMode osViModeMpalLan1; OSViMode osViModeFpalLan1; OSViMode osViModePalLan1; -AudioContext gAudioContext; -unk_D_8016E750 D_8016E750[4]; +// AudioContext gAudioContext; +// unk_D_8016E750 D_8016E750[4]; u8 gLetterTLUT[4][32]; u8 gFontFF[999]; DmaEntry gDmaDataTable[0x60C]; -u8 D_80133418; +// u8 D_80133418; u16 gAudioSEFlagSwapSource[64]; u16 gAudioSEFlagSwapTarget[64]; u8 gAudioSEFlagSwapMode[64]; diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp index c84e37482..3e2a990d7 100644 --- a/soh/soh/z_play_otr.cpp +++ b/soh/soh/z_play_otr.cpp @@ -12,7 +12,7 @@ void OTRGameplay_InitScene(GlobalContext* globalCtx, s32 spawn); s32 OTRScene_ExecuteCommands(GlobalContext* globalCtx, Ship::Scene* sceneCmd); //Ship::OTRResource* OTRGameplay_LoadFile(GlobalContext* globalCtx, RomFile* file) { -Ship::Resource* OTRGameplay_LoadFile(GlobalContext* globalCtx, const char* fileName) +Ship::Resource* OTRGameplay_LoadFile(GlobalContext* globalCtx, const char* fileName) { auto res = OTRGlobals::Instance->context->GetResourceManager()->LoadResource(fileName); return res.get(); @@ -28,7 +28,7 @@ extern "C" void OTRGameplay_SpawnScene(GlobalContext* globalCtx, s32 sceneNum, s //osSyncPrintf("\nSCENE SIZE %fK\n", (scene->sceneFile.vromEnd - scene->sceneFile.vromStart) / 1024.0f); - std::string scenePath = StringHelper::Sprintf("scenes\\%s\\%s", scene->sceneFile.fileName, scene->sceneFile.fileName); + std::string scenePath = StringHelper::Sprintf("scenes/%s/%s", scene->sceneFile.fileName, scene->sceneFile.fileName); globalCtx->sceneSegment = (Ship::Scene*)OTRGameplay_LoadFile(globalCtx, scenePath.c_str()); @@ -47,7 +47,7 @@ extern "C" void OTRGameplay_SpawnScene(GlobalContext* globalCtx, s32 sceneNum, s //gSegments[2] = VIRTUAL_TO_PHYSICAL(globalCtx->sceneSegment); OTRGameplay_InitScene(globalCtx, spawn); - + osSyncPrintf("ROOM SIZE=%fK\n", func_80096FE8(globalCtx, &globalCtx->roomCtx) / 1024.0f); } @@ -72,7 +72,7 @@ void OTRGameplay_InitScene(GlobalContext* globalCtx, s32 spawn) { ->GetResourceManager() ->LoadResource("object_link_child\\object_link_childVtx_01FE08") .get()); - + auto data2 = ResourceMgr_LoadVtxByCRC(0x68d4ea06044e228f);*/ volatile int a = 0; diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index f63df81e4..123f9c636 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -72,7 +72,7 @@ bool func_800985DC(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { else { ActorEntry* entries = (ActorEntry*)malloc(cmdActor->entries.size() * sizeof(ActorEntry)); - + for (int i = 0; i < cmdActor->entries.size(); i++) { entries[i].id = cmdActor->entries[i].actorNum; @@ -241,7 +241,7 @@ bool func_800987F8(GlobalContext* globalCtx, Ship::SceneCommand* cmd) globalCtx->setupEntranceList[i].room = otrEntrance->entrances[i].roomToLoad; globalCtx->setupEntranceList[i].spawn = otrEntrance->entrances[i].startPositionIndex; } - + otrEntrance->cachedGameData = globalCtx->setupEntranceList; } @@ -252,11 +252,11 @@ bool func_800987F8(GlobalContext* globalCtx, Ship::SceneCommand* cmd) bool func_8009883C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { Ship::SetSpecialObjects* otrSpecial = (Ship::SetSpecialObjects*)cmd; - + if (otrSpecial->globalObject != 0) globalCtx->objectCtx.subKeepIndex = Object_Spawn(&globalCtx->objectCtx, otrSpecial->globalObject); - if (otrSpecial->elfMessage != 0) + if (otrSpecial->elfMessage != 0) { auto res = (Ship::Blob*)OTRGameplay_LoadFile(globalCtx, sNaviMsgFiles[otrSpecial->elfMessage - 1].fileName); globalCtx->cUpElfMsgs = (ElfMessage*)res->data.data(); @@ -436,7 +436,7 @@ extern "C" void* func_800982FC(ObjectContext * objectCtx, s32 bankIndex, s16 obj bool func_8009899C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { Ship::SetObjectList* cmdObj = (Ship::SetObjectList*)cmd; - + s32 i; s32 j; s32 k; @@ -743,7 +743,7 @@ bool func_8009918C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) } // Scene Command 0x18: Alternate Headers -bool func_800991A0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) +bool func_800991A0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { Ship::SetAlternateHeaders* cmdHeaders = (Ship::SetAlternateHeaders*)cmd; @@ -754,7 +754,7 @@ bool func_800991A0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) //osSyncPrintf("\n[ZU]sceneset time =[%X]", ((void)0, gSaveContext.cutsceneIndex)); //osSyncPrintf("\n[ZU]sceneset counter=[%X]", ((void)0, gSaveContext.sceneSetupIndex)); - if (gSaveContext.sceneSetupIndex != 0) + if (gSaveContext.sceneSetupIndex != 0) { std::string desiredHeader = cmdHeaders->headers[gSaveContext.sceneSetupIndex - 1]; Ship::Scene* headerData = nullptr; @@ -798,7 +798,7 @@ bool func_800991A0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) } // Scene Command 0x17: Cutscene Data -bool func_8009934C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) +bool func_8009934C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { Ship::SetCutscenes* cmdCS = (Ship::SetCutscenes*)cmd; @@ -810,7 +810,7 @@ bool func_8009934C(GlobalContext* globalCtx, Ship::SceneCommand* cmd) } // Scene Command 0x19: Misc. Settings (Camera & World Map Area) -bool func_800993C0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) +bool func_800993C0(GlobalContext* globalCtx, Ship::SceneCommand* cmd) { Ship::SetCameraSettings* cmdCam = (Ship::SetCameraSettings*)cmd; diff --git a/soh/src/boot/build.c b/soh/src/boot/build.c index f60380467..94d142020 100644 --- a/soh/src/boot/build.c +++ b/soh/src/boot/build.c @@ -1,4 +1,4 @@ -const char gBuildVersion[] = "DECKARD ALFA (1.0.0)"; +const char gBuildVersion[] = "ROY ALFA (2.0.0)"; const char gBuildTeam[] = "github.com/harbourmasters"; const char gBuildDate[] = __DATE__ " " __TIME__; const char gBuildMakeOption[] = ""; diff --git a/soh/src/buffers/heaps.c b/soh/src/buffers/heaps.c index d09f86e72..b6f16ab11 100644 --- a/soh/src/buffers/heaps.c +++ b/soh/src/buffers/heaps.c @@ -6,9 +6,6 @@ #include #endif -#define AUDIO_HEAP_SIZE 0x38000 -#define SYSTEM_HEAP_SIZE (1024 * 1024 * 128) - u8* gAudioHeap; u8* gSystemHeap; diff --git a/soh/src/code/audio_effects.c b/soh/src/code/audio_effects.c index 4813d1c63..d5aa3644f 100644 --- a/soh/src/code/audio_effects.c +++ b/soh/src/code/audio_effects.c @@ -246,7 +246,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { retry: case ADSR_STATE_LOOP: - adsr->delay = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].delay); + adsr->delay = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].delay); switch (adsr->delay) { case ADSR_DISABLE: adsr->action.s.state = ADSR_STATE_DISABLED; @@ -255,7 +255,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { adsr->action.s.state = ADSR_STATE_HANG; break; case ADSR_GOTO: - adsr->envIndex = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].arg); + adsr->envIndex = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg); goto retry; case ADSR_RESTART: adsr->action.s.state = ADSR_STATE_INITIAL; @@ -266,7 +266,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { if (adsr->delay == 0) { adsr->delay = 1; } - adsr->target = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].arg) / 32767.0f; + adsr->target = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg) / 32767.0f; adsr->target = adsr->target * adsr->target; adsr->velocity = (adsr->target - adsr->current) / adsr->delay; adsr->action.s.state = ADSR_STATE_FADE; diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index ec8b7be86..7af9037a6 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -1058,7 +1058,7 @@ void AudioLoad_InitSwapFontSampleHeaders(SoundFontSample* sample, uintptr_t romA size_t maxSoundFontSize = 0x3AA0; // soundFont 0 is the largest size at 0x3AA0 AdpcmLoop* loop; AdpcmBook* book; - + if (((uintptr_t)sample->loop > maxSoundFontSize) || ((uintptr_t)sample->book > maxSoundFontSize) ) { bswapSoundFontSample(sample); @@ -1093,7 +1093,7 @@ void AudioLoad_InitSwapFont(void) { SoundFontSound* sfxList; SoundFontSound* sfx; Instrument** instList; - Instrument* inst; + Instrument* inst; // Only up to (numFonts - 1) as final font has garbage data to prevent corruption and is never used for (fontId = 0; fontId < (numFonts - 1); fontId++) { @@ -1110,12 +1110,12 @@ void AudioLoad_InitSwapFont(void) { numInstruments = font->numInstruments; // drums - ptrs[0] = (void*)_byteswap_ulong((uintptr_t)ptrs[0]); + ptrs[0] = (void*)BOMSWAP32((uintptr_t)ptrs[0]); if ((ptrs[0] != NULL) && (numDrums != 0)) { drumList = (Drum**)BASE_ROM_OFFSET(ptrs[0]); for (i = 0; i < numDrums; i++) { - drumList[i] = (Drum*)_byteswap_ulong((uintptr_t)drumList[i]); + drumList[i] = (Drum*)BOMSWAP32((uintptr_t)drumList[i]); if (drumList[i] != NULL) { drum = (Drum*)BASE_ROM_OFFSET(drumList[i]); @@ -1128,7 +1128,7 @@ void AudioLoad_InitSwapFont(void) { } // sfxs - ptrs[1] = (void*)_byteswap_ulong((u32)ptrs[1]); + ptrs[1] = (void*)BOMSWAP32((u32)ptrs[1]); if ((ptrs[1] != NULL) && (numSfxs != 0)) { sfxList = (SoundFontSound*)BASE_ROM_OFFSET(ptrs[1]); @@ -1151,7 +1151,7 @@ void AudioLoad_InitSwapFont(void) { instList = (Instrument**)(&ptrs[2]); for (i = 0; i < numInstruments; i++) { - instList[i] = (Instrument*)_byteswap_ulong((uintptr_t)instList[i]); + instList[i] = (Instrument*)BOMSWAP32((uintptr_t)instList[i]); if (instList[i] != NULL) { inst = BASE_ROM_OFFSET(instList[i]); @@ -1159,15 +1159,15 @@ void AudioLoad_InitSwapFont(void) { if (inst->normalRangeLo != 0) { sample = (SoundFontSample*)BASE_ROM_OFFSET(inst->lowNotesSound.sample); - AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); + AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); } sample = (SoundFontSample*)BASE_ROM_OFFSET(inst->normalNotesSound.sample); - AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); - + AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); + if (inst->normalRangeHi != 0x7F) { sample = (SoundFontSample*)BASE_ROM_OFFSET(inst->highNotesSound.sample); - AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); + AudioLoad_InitSwapFontSampleHeaders(sample, romAddr); } } } diff --git a/soh/src/code/audio_seqplayer.c b/soh/src/code/audio_seqplayer.c index 03e8842e3..3dd7b811e 100644 --- a/soh/src/code/audio_seqplayer.c +++ b/soh/src/code/audio_seqplayer.c @@ -1323,14 +1323,14 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { case 0xB2: offset = (u16)parameters[0]; // OTRTODO: Byteswap added for quick audio - channel->unk_22 = _byteswap_ushort(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2))); + channel->unk_22 = BOMSWAP16(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2))); break; case 0xB4: channel->dynTable = (void*)&seqPlayer->seqData[channel->unk_22]; break; case 0xB5: // OTRTODO: Byteswap added for quick audio - channel->unk_22 = _byteswap_ushort(((u16*)(channel->dynTable))[scriptState->value]); + channel->unk_22 = BOMSWAP16(((u16*)(channel->dynTable))[scriptState->value]); break; case 0xB6: scriptState->value = (*channel->dynTable)[0][scriptState->value]; diff --git a/soh/src/code/audio_synthesis.c b/soh/src/code/audio_synthesis.c index e71c6b441..037bd2ec3 100644 --- a/soh/src/code/audio_synthesis.c +++ b/soh/src/code/audio_synthesis.c @@ -1162,7 +1162,7 @@ Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS if (temp_v0 < nSamplesToLoad) { repeats = ((nSamplesToLoad - temp_v0 + 0x3F) / 0x40); if (repeats != 0) { - aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80, 0x80); + aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80); } } synthState->samplePosInt = samplePosInt; @@ -1225,6 +1225,6 @@ Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, Not aSaveBuffer(cmd++, DMEM_NOTE_PAN_TEMP + bufLen, &synthState->synthesisBuffers->panResampleState[0x8], ALIGN16(panShift)); } - aAddMixer(cmd++, ALIGN64(bufLen), DMEM_NOTE_PAN_TEMP, dest, 0x7FFF); + aAddMixer(cmd++, ALIGN64(bufLen), DMEM_NOTE_PAN_TEMP, dest); return cmd; } diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c index 9f744ec02..4b1887c18 100644 --- a/soh/src/code/graph.c +++ b/soh/src/code/graph.c @@ -431,6 +431,8 @@ static struct RunFrameContext { extern AudioMgr gAudioMgr; +extern void ProcessSaveStateRequests(void); + static void RunFrame() { u32 size; @@ -487,6 +489,7 @@ static void RunFrame() //uint64_t diff = (ticksB - ticksA) / (freq / 1000); //printf("Frame simulated in %ims\n", diff); runFrameContext.state = 1; + ProcessSaveStateRequests(); return; nextFrame:; } diff --git a/soh/src/code/padmgr.c b/soh/src/code/padmgr.c index 08c89869f..b467f5ee6 100644 --- a/soh/src/code/padmgr.c +++ b/soh/src/code/padmgr.c @@ -3,7 +3,9 @@ //#include +#ifdef _MSC_VER extern void* __cdecl memset(_Out_writes_bytes_all_(_Size) void* _Dst, _In_ int _Val, _In_ size_t _Size); +#endif s32 D_8012D280 = 1; diff --git a/soh/src/code/sys_matrix.c b/soh/src/code/sys_matrix.c index 9d7c73967..bc90bf669 100644 --- a/soh/src/code/sys_matrix.c +++ b/soh/src/code/sys_matrix.c @@ -1,5 +1,7 @@ #include "global.h" +#include "soh/frame_interpolation.h" + // clang-format off Mtx gMtxClear = { 65536, 0, 1, 0, @@ -25,11 +27,13 @@ void Matrix_Init(GameState* gameState) { } void Matrix_Push(void) { + FrameInterpolation_RecordMatrixPush(); Matrix_MtxFCopy(sCurrentMatrix + 1, sCurrentMatrix); sCurrentMatrix++; } void Matrix_Pop(void) { + FrameInterpolation_RecordMatrixPop(); sCurrentMatrix--; ASSERT(sCurrentMatrix >= sMatrixStack, "Matrix_now >= Matrix_stack", "../sys_matrix.c", 176); } @@ -39,6 +43,7 @@ void Matrix_Get(MtxF* dest) { } void Matrix_Put(MtxF* src) { + FrameInterpolation_RecordMatrixPut(src); Matrix_MtxFCopy(sCurrentMatrix, src); } @@ -47,6 +52,7 @@ MtxF* Matrix_GetCurrent(void) { } void Matrix_Mult(MtxF* mf, u8 mode) { + FrameInterpolation_RecordMatrixMult(mf, mode); MtxF* cmf = Matrix_GetCurrent(); if (mode == MTXMODE_APPLY) { @@ -57,6 +63,7 @@ void Matrix_Mult(MtxF* mf, u8 mode) { } void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) { + FrameInterpolation_RecordMatrixTranslate(x, y, z, mode); MtxF* cmf = sCurrentMatrix; f32 tx; f32 ty; @@ -80,6 +87,7 @@ void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) { } void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) { + FrameInterpolation_RecordMatrixScale(x, y, z, mode); MtxF* cmf = sCurrentMatrix; if (mode == MTXMODE_APPLY) { @@ -101,6 +109,7 @@ void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) { } void Matrix_RotateX(f32 x, u8 mode) { + FrameInterpolation_RecordMatrixRotate1Coord(0, x, mode); MtxF* cmf; f32 sin; f32 cos; @@ -165,6 +174,7 @@ void Matrix_RotateX(f32 x, u8 mode) { } void Matrix_RotateY(f32 y, u8 mode) { + FrameInterpolation_RecordMatrixRotate1Coord(1, y, mode); MtxF* cmf; f32 sin; f32 cos; @@ -229,6 +239,7 @@ void Matrix_RotateY(f32 y, u8 mode) { } void Matrix_RotateZ(f32 z, u8 mode) { + FrameInterpolation_RecordMatrixRotate1Coord(2, z, mode); MtxF* cmf; f32 sin; f32 cos; @@ -299,6 +310,7 @@ void Matrix_RotateZ(f32 z, u8 mode) { * Original Name: Matrix_RotateXYZ, changed to reflect rotation order. */ void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) { + FrameInterpolation_RecordMatrixRotateZYX(x, y, z, mode); MtxF* cmf = sCurrentMatrix; f32 temp1; f32 temp2; @@ -389,6 +401,7 @@ void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) { * transformed according to whatever the matrix was previously. */ void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation) { + FrameInterpolation_RecordMatrixTranslateRotateZYX(translation, rotation); MtxF* cmf = sCurrentMatrix; f32 sin = Math_SinS(rotation->z); f32 cos = Math_CosS(rotation->z); @@ -530,15 +543,20 @@ void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ } else { cmf->yx = 0.0f; } + FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(translateX, translateY, translateZ, rot); } Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest) { + FrameInterpolation_RecordMatrixMtxFToMtx(src, dest); guMtxF2L(src, dest); return dest; } Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line) { - return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest); + FrameInterpolation_RecordMatrixToMtx(dest, file, line); + guMtxF2L(Matrix_CheckFloats(sCurrentMatrix, file, line), dest); + return dest; + //return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest); } Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx, char* file, s32 line) { @@ -627,6 +645,7 @@ void Matrix_Transpose(MtxF* mf) { * seen as replacing the R rotation with `mf`, hence the function name. */ void Matrix_ReplaceRotation(MtxF* mf) { + FrameInterpolation_RecordMatrixReplaceRotation(mf); MtxF* cmf = sCurrentMatrix; f32 acc; f32 temp; @@ -779,6 +798,7 @@ void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag) { * NB: `axis` is assumed to be a unit vector. */ void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode) { + FrameInterpolation_RecordMatrixRotateAxis(angle, axis, mode); MtxF* cmf; f32 sin; f32 cos; diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 052582f0f..ba5d4dcd6 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -6,14 +6,15 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h" #include "objects/object_bdoor/object_bdoor.h" +#include "soh/frame_interpolation.h" -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__GNUC__) #include #include #include #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__GNUC__) #include "textures/place_title_cards/g_pn_49.h" #include "textures/place_title_cards/g_pn_01.h" #include "textures/place_title_cards/g_pn_02.h" @@ -334,38 +335,59 @@ void func_8002BE98(TargetContext* targetCtx, s32 actorCategory, GlobalContext* g void func_8002BF60(TargetContext* targetCtx, Actor* actor, s32 actorCategory, GlobalContext* globalCtx) { NaviColor* naviColor = &sNaviColorList[actorCategory]; - if (actorCategory == ACTORCAT_PLAYER && CVar_GetS32("gUseNaviCol",0) == 1 ) { - naviColor->inner.r = CVar_GetS32("gNavi_Idle_Inner_R", naviColor->inner.r); - naviColor->inner.g = CVar_GetS32("gNavi_Idle_Inner_G", naviColor->inner.g); - naviColor->inner.b = CVar_GetS32("gNavi_Idle_Inner_B", naviColor->inner.b); - naviColor->outer.r = CVar_GetS32("gNavi_Idle_Outer_R", naviColor->outer.r); - naviColor->outer.g = CVar_GetS32("gNavi_Idle_Outer_G", naviColor->outer.g); - naviColor->outer.b = CVar_GetS32("gNavi_Idle_Outer_B", naviColor->outer.b); - } - if (actorCategory == ACTORCAT_NPC && CVar_GetS32("gUseNaviCol",0) == 1 ) { - naviColor->inner.r = CVar_GetS32("gNavi_NPC_Inner_R", naviColor->inner.r); - naviColor->inner.g = CVar_GetS32("gNavi_NPC_Inner_G", naviColor->inner.g); - naviColor->inner.b = CVar_GetS32("gNavi_NPC_Inner_B", naviColor->inner.b); - naviColor->outer.r = CVar_GetS32("gNavi_NPC_Outer_R", naviColor->outer.r); - naviColor->outer.g = CVar_GetS32("gNavi_NPC_Outer_G", naviColor->outer.g); - naviColor->outer.b = CVar_GetS32("gNavi_NPC_Outer_B", naviColor->outer.b); - } - if (actorCategory == ACTORCAT_BOSS && CVar_GetS32("gUseNaviCol",0) == 1 || actorCategory == ACTORCAT_ENEMYY && CVar_GetS32("gUseNaviCol",0) == 1 ) { - naviColor->inner.r = CVar_GetS32("gNavi_Enemy_Inner_R", naviColor->inner.r); - naviColor->inner.g = CVar_GetS32("gNavi_Enemy_Inner_G", naviColor->inner.g); - naviColor->inner.b = CVar_GetS32("gNavi_Enemy_Inner_B", naviColor->inner.b); - naviColor->outer.r = CVar_GetS32("gNavi_Enemy_Outer_R", naviColor->outer.r); - naviColor->outer.g = CVar_GetS32("gNavi_Enemy_Outer_G", naviColor->outer.g); - naviColor->outer.b = CVar_GetS32("gNavi_Enemy_Outer_B", naviColor->outer.b); - } - if (actorCategory == ACTORCAT_PROPY && CVar_GetS32("gUseNaviCol",0) == 1 ) { - naviColor->inner.r = CVar_GetS32("gNavi_Prop_Inner_R", naviColor->inner.r); - naviColor->inner.g = CVar_GetS32("gNavi_Prop_Inner_G", naviColor->inner.g); - naviColor->inner.b = CVar_GetS32("gNavi_Prop_Inner_B", naviColor->inner.b); - naviColor->outer.r = CVar_GetS32("gNavi_Prop_Outer_R", naviColor->outer.r); - naviColor->outer.g = CVar_GetS32("gNavi_Prop_Outer_G", naviColor->outer.g); - naviColor->outer.b = CVar_GetS32("gNavi_Prop_Outer_B", naviColor->outer.b); + + if (CVar_GetS32("gUseNaviCol",0) != 1 ) { + if (actorCategory == ACTORCAT_PLAYER) { + naviColor->inner.r = 255; naviColor->inner.g = 255; naviColor->inner.b = 255; + naviColor->outer.r = 115; naviColor->outer.g = 230; naviColor->outer.b = 255; + } + if (actorCategory == ACTORCAT_NPC) { + naviColor->inner.r = 100; naviColor->inner.g = 100; naviColor->inner.b = 255; + naviColor->outer.r = 90; naviColor->outer.g = 90; naviColor->outer.b = 255; + } + if (actorCategory == ACTORCAT_BOSS || actorCategory == ACTORCAT_ENEMY) { + naviColor->inner.r = 255; naviColor->inner.g = 255; naviColor->inner.b = 0; + naviColor->outer.r = 220; naviColor->outer.g = 220; naviColor->outer.b = 0; + } + if (actorCategory == ACTORCAT_PROP) { + naviColor->inner.r = 0; naviColor->inner.g = 255; naviColor->inner.b = 90; + naviColor->outer.r = 0; naviColor->outer.g = 220; naviColor->outer.b = 0; + } + } else { + if (actorCategory == ACTORCAT_PLAYER) { + naviColor->inner.r = CVar_GetS32("gNavi_Idle_Inner_R", naviColor->inner.r); + naviColor->inner.g = CVar_GetS32("gNavi_Idle_Inner_G", naviColor->inner.g); + naviColor->inner.b = CVar_GetS32("gNavi_Idle_Inner_B", naviColor->inner.b); + naviColor->outer.r = CVar_GetS32("gNavi_Idle_Outer_R", naviColor->outer.r); + naviColor->outer.g = CVar_GetS32("gNavi_Idle_Outer_G", naviColor->outer.g); + naviColor->outer.b = CVar_GetS32("gNavi_Idle_Outer_B", naviColor->outer.b); + } + if (actorCategory == ACTORCAT_NPC) { + naviColor->inner.r = CVar_GetS32("gNavi_NPC_Inner_R", naviColor->inner.r); + naviColor->inner.g = CVar_GetS32("gNavi_NPC_Inner_G", naviColor->inner.g); + naviColor->inner.b = CVar_GetS32("gNavi_NPC_Inner_B", naviColor->inner.b); + naviColor->outer.r = CVar_GetS32("gNavi_NPC_Outer_R", naviColor->outer.r); + naviColor->outer.g = CVar_GetS32("gNavi_NPC_Outer_G", naviColor->outer.g); + naviColor->outer.b = CVar_GetS32("gNavi_NPC_Outer_B", naviColor->outer.b); + } + if (actorCategory == ACTORCAT_BOSS || actorCategory == ACTORCAT_ENEMY) { + naviColor->inner.r = CVar_GetS32("gNavi_Enemy_Inner_R", naviColor->inner.r); + naviColor->inner.g = CVar_GetS32("gNavi_Enemy_Inner_G", naviColor->inner.g); + naviColor->inner.b = CVar_GetS32("gNavi_Enemy_Inner_B", naviColor->inner.b); + naviColor->outer.r = CVar_GetS32("gNavi_Enemy_Outer_R", naviColor->outer.r); + naviColor->outer.g = CVar_GetS32("gNavi_Enemy_Outer_G", naviColor->outer.g); + naviColor->outer.b = CVar_GetS32("gNavi_Enemy_Outer_B", naviColor->outer.b); + } + if (actorCategory == ACTORCAT_PROP) { + naviColor->inner.r = CVar_GetS32("gNavi_Prop_Inner_R", naviColor->inner.r); + naviColor->inner.g = CVar_GetS32("gNavi_Prop_Inner_G", naviColor->inner.g); + naviColor->inner.b = CVar_GetS32("gNavi_Prop_Inner_B", naviColor->inner.b); + naviColor->outer.r = CVar_GetS32("gNavi_Prop_Outer_R", naviColor->outer.r); + naviColor->outer.g = CVar_GetS32("gNavi_Prop_Outer_G", naviColor->outer.g); + naviColor->outer.b = CVar_GetS32("gNavi_Prop_Outer_B", naviColor->outer.b); + } } + targetCtx->naviRefPos.x = actor->focus.pos.x; targetCtx->naviRefPos.y = actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y); targetCtx->naviRefPos.z = actor->focus.pos.z; @@ -410,6 +432,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) { f32 var2; s32 i; + FrameInterpolation_RecordOpenChild(actor, 0); player = GET_PLAYER(globalCtx); spCE = 0xFF; @@ -486,10 +509,12 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) { } } } + FrameInterpolation_RecordCloseChild(); } actor = targetCtx->unk_94; if ((actor != NULL) && !(actor->flags & ACTOR_FLAG_27)) { + FrameInterpolation_RecordOpenChild(actor, 1); NaviColor* naviColor = &sNaviColorList[actor->category]; POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x7); @@ -503,6 +528,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_actor.c", 2153), G_MTX_MODELVIEW | G_MTX_LOAD); gSPDisplayList(POLY_XLU_DISP++, gZTargetArrowDL); + FrameInterpolation_RecordCloseChild(); } CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 2158); @@ -765,7 +791,7 @@ void TitleCard_InitBossName(GlobalContext* globalCtx, TitleCardContext* titleCtx titleCtx->texture = texture; titleCtx->isBossCard = true; - titleCtx->hasTranslation = hasTranslation; + titleCtx->hasTranslation = hasTranslation; titleCtx->x = x; titleCtx->y = y; titleCtx->width = width; @@ -774,7 +800,7 @@ void TitleCard_InitBossName(GlobalContext* globalCtx, TitleCardContext* titleCtx titleCtx->delayTimer = 0; } -void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCtx, char* texture, s32 x, s32 y, +void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCtx, void* texture, s32 x, s32 y, s32 width, s32 height, s32 delay) { SceneTableEntry* loadedScene = globalCtx->loadedScene; @@ -1034,13 +1060,12 @@ void TitleCard_Draw(GlobalContext* globalCtx, TitleCardContext* titleCtx) { shiftBottomY = 0x1000; //if this card is bosses cards, has translation and that is not using English language. - if (titleCtx->isBossCard == 1 && titleCtx->hasTranslation == 1 && gSaveContext.language != LANGUAGE_ENG) { + if (titleCtx->isBossCard && titleCtx->hasTranslation && gSaveContext.language != LANGUAGE_ENG) { + textureLanguageOffset = (width * height * gSaveContext.language); if (gSaveContext.language == LANGUAGE_GER) { - textureLanguageOffset = (width * height * gSaveContext.language); shiftTopY = 0x400; shiftBottomY = 0x1400; } else if (gSaveContext.language == LANGUAGE_FRA) { - textureLanguageOffset = (width * height * gSaveContext.language); shiftTopY = 0x800; shiftBottomY = 0x1800; } @@ -1052,7 +1077,7 @@ void TitleCard_Draw(GlobalContext* globalCtx, TitleCardContext* titleCtx) { gDPSetPrimColor(WORLD_OVERLAY_DISP++, 0, 0, (u8)titleCtx->intensity, (u8)titleCtx->intensity, (u8)titleCtx->intensity, (u8)titleCtx->alpha); - gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftBottomY, G_IM_FMT_IA, + gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftTopY, G_IM_FMT_IA, G_IM_SIZ_8b, width, height, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); @@ -2491,6 +2516,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) { Fault_AddClient(&faultClient, Actor_FaultPrint, actor, "Actor_draw"); + FrameInterpolation_RecordOpenChild(actor, 0); OPEN_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6035); lights = LightContext_NewLights(&globalCtx->lightCtx, globalCtx->state.gfxCtx); @@ -2498,6 +2524,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) { Lights_BindAll(lights, globalCtx->lightCtx.listHead, (actor->flags & ACTOR_FLAG_22) ? NULL : &actor->world.pos); Lights_Draw(lights, globalCtx->state.gfxCtx); + FrameInterpolation_RecordActorPosRotMatrix(); if (actor->flags & ACTOR_FLAG_12) { Matrix_SetTranslateRotateYXZ( actor->world.pos.x + globalCtx->mainCamera.skyboxOffset.x, @@ -2547,6 +2574,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) { } CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6119); + FrameInterpolation_RecordCloseChild(); Fault_RemoveClient(&faultClient); } @@ -4273,8 +4301,6 @@ s32 func_80035124(Actor* actor, GlobalContext* globalCtx) { return ret; } -#include "z_cheap_proc.c" - u8 func_800353E8(GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); diff --git a/soh/src/code/z_bgcheck.c b/soh/src/code/z_bgcheck.c index 9ce139eed..811b0bea1 100644 --- a/soh/src/code/z_bgcheck.c +++ b/soh/src/code/z_bgcheck.c @@ -4031,7 +4031,7 @@ s32 func_80041E4C(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { /** * unused */ -u32 func_80041E80(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { +s32 func_80041E80(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 26 & 0xF; } diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c index 7302f9b21..00f3f70f0 100644 --- a/soh/src/code/z_camera.c +++ b/soh/src/code/z_camera.c @@ -6,6 +6,8 @@ #include "overlays/actors/ovl_En_Horse/z_en_horse.h" +#include "soh/frame_interpolation.h" + s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags); s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags); s32 Camera_QRegInit(void); @@ -26,7 +28,7 @@ s32 Camera_CheckWater(Camera* camera); #define FLG_ADJSLOPE (1 << 0) #define FLG_OFFGROUND (1 << 7) -#include "z_camera_data.c" +#include "z_camera_data.inc" /*===============================================================*/ @@ -565,10 +567,10 @@ s16 Camera_XZAngle(Vec3f* to, Vec3f* from) { return DEGF_TO_BINANG(RADF_TO_DEGF(Math_FAtan2F(from->x - to->x, from->z - to->z))); } + f32 D_8015CE50; + f32 D_8015CE54; + CamColChk D_8015CE58; s16 func_80044ADC(Camera* camera, s16 yaw, s16 arg2) { - static f32 D_8015CE50; - static f32 D_8015CE54; - static CamColChk D_8015CE58; Vec3f playerPos; Vec3f rotatedPos; Vec3f floorNorm; @@ -6675,6 +6677,7 @@ s32 Camera_Special9(Camera* camera) { case 1: spec9->doorParams.timer1--; if (spec9->doorParams.timer1 <= 0) { + FrameInterpolation_DontInterpolateCamera(); camera->animState++; if (params->interfaceFlags & 1) { camPosData = Camera_GetCamBGData(camera); @@ -7221,9 +7224,9 @@ s32 Camera_DbgChangeMode(Camera* camera) { return true; } +s16 D_8011DB08 = 0x3F0; +s16 D_8011DB0C = 0x156; void func_80058E8C(Camera* camera) { - static s16 D_8011DB08 = 0x3F0; - static s16 D_8011DB0C = 0x156; s32 pad3; f32 sp60; s32 pad; @@ -7299,8 +7302,8 @@ void func_80058E8C(Camera* camera) { } } +s32 sOOBTimer = 0; Vec3s Camera_Update(Camera* camera) { - static s32 sOOBTimer = 0; Vec3f viewAt; Vec3f viewEye; Vec3f viewUp; @@ -7968,6 +7971,8 @@ s32 Camera_SetCSParams(Camera* camera, CutsceneCameraPoint* atPoints, CutsceneCa camera->speedRatio = 0.0f; } + FrameInterpolation_DontInterpolateCamera(); + return 1; } diff --git a/soh/src/code/z_camera_data.inc b/soh/src/code/z_camera_data.inc new file mode 100644 index 000000000..1f457888e --- /dev/null +++ b/soh/src/code/z_camera_data.inc @@ -0,0 +1,2403 @@ +#include "ultra64.h" +#include "global.h" + +typedef struct { + s16 val; + s16 dataType; +} CameraModeValue; + +typedef struct { + s16 funcIdx; + s16 valueCnt; + CameraModeValue* values; +} CameraMode; + +typedef struct { + union { + u32 unk_00; + struct { + u32 unk_bit0 : 1; + u32 unk_bit1 : 1; + u32 validModes : 30; + }; + }; + CameraMode* cameraModes; +} CameraSetting; + +/*==================================================================*/ +// Data +s16 sOREGInit[] = { + 0, 1, 5, 5, 5, 14500, 20, 16, 150, 25, 150, 6, 10, 10, 0, 0, 1, 100, + 250, 120, 80, 30, 120, 4, 1, 50, 20, 1800, 50, 50, 50, 20, 20, -10, -5460, -9100, + -6, 8, 15, 75, 60, 12, 110, 40, 50, 250, -10, 30, 30, 70, 20, 20, 20, +}; + +s16 sOREGInitCnt = 53; + +s16 sCamDataRegsInit[CAM_DATA_MAX] = { + -20, // CAM_DATA_Y_OFFSET + 200, // CAM_DATA_EYE_DIST + 300, // CAM_DATA_EYE_DIST_NEXT + 10, // CAM_DATA_PITCH_TARGET + 12, // CAM_DATA_YAW_UPDATE_RATE_TARGET + 10, // CAM_DATA_XZ_UPDATE_RATE_TARGET + 35, // CAM_DATA_MAX_YAW_UPDATE + 60, // CAM_DATA_FOV + 60, // CAM_DATA_AT_LERP_STEP_SCALE + 3, // CAM_DATA_FLAGS + 0, // CAM_DATA_YAW_TARGET + -40, // CAM_DATA_GROUND_Y_OFFSET + 20, // CAM_DATA_GROUND_AT_LERP_STEP_SCALE + 25, // CAM_DATA_SWING_YAW_INIT + 45, // CAM_DATA_SWING_YAW_FINAL + -5, // CAM_DATA_SWING_PITCH_INIT + 15, // CAM_DATA_SWING_PITCH_FINAL + 15, // CAM_DATA_SWING_PITCH_ADJ + 20, // CAM_DATA_MIN_MAX_DIST_FACTOR + 0, // CAM_DATA_AT_OFFSET_X + 0, // CAM_DATA_AT_OFFSET_Y + 0, // CAM_DATA_AT_OFFSET_Z + 6, // CAM_DATA_UNK_22 + 60, // CAM_DATA_UNK_23 + 30, // CAM_DATA_FOV_SCALE + 0, // CAM_DATA_YAW_SCALE + 5, // CAM_DATA_UNK_26 +}; + +s16 sCamDataRegsInitCount = ARRAY_COUNT(sCamDataRegsInit); + +char sCameraSettingNames[][12] = { + "NONE ", "NORMAL0 ", "NORMAL1 ", "DUNGEON0 ", "DUNGEON1 ", "NORMAL3 ", "HORSE0 ", + "BOSS_GOMA ", "BOSS_DODO ", "BOSS_BARI ", "BOSS_FGANON", "BOSS_BAL ", "BOSS_SHADES", "BOSS_MOFA ", + "BOSS_TWIN0 ", "BOSS_TWIN1 ", "BOSS_GANON1", "BOSS_GANON2", "TOWER0 ", "TOWER1 ", "FIXED0 ", + "FIXED1 ", "CIRCLE0 ", "CIRCLE2 ", "CIRCLE3 ", "PREREND0 ", "PREREND1 ", "PREREND3 ", + "DOOR0 ", "DOORC ", "RAIL3 ", "START0 ", "START1 ", "FREE0 ", "FREE2 ", + "CIRCLE4 ", "CIRCLE5 ", "DEMO0 ", "DEMO1 ", "MORI1 ", "ITEM0 ", "ITEM1 ", + "DEMO3 ", "DEMO4 ", "UFOBEAN ", "LIFTBEAN ", "SCENE0 ", "SCENE1 ", "HIDAN1 ", + "HIDAN2 ", "MORI2 ", "MORI3 ", "TAKO ", "SPOT05A ", "SPOT05B ", "HIDAN3 ", + "ITEM2 ", "CIRCLE6 ", "NORMAL2 ", "FISHING ", "DEMOC ", "UO_FIBER ", "DUNGEON2 ", + "TEPPEN ", "CIRCLE7 ", "NORMAL4 ", +}; + +char sCameraModeNames[][12] = { + "NORMAL ", "PARALLEL ", "KEEPON ", "TALK ", "BATTLE ", "CLIMB ", "SUBJECT ", + "BOWARROW ", "BOWARROWZ ", "FOOKSHOT ", "BOOMERANG ", "PACHINCO ", "CLIMBZ ", "JUMP ", + "HANG ", "HANGZ ", "FREEFALL ", "CHARGE ", "STILL ", "PUSHPULL ", "BOOKEEPON ", +}; + +/** + *===================================================================== + * General Data: NORMAL0 Setting + *===================================================================== + */ + +CameraModeValue sSetNormal0ModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 200, 300, 10, 12, 10, 35, 60, 60, 0x0003), +}; + +CameraModeValue sSetNormal0ModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 250, 0, 0, 5, 5, 45, 50, 0x200A, -40, 20), +}; + +CameraModeValue sSetNormal0ModeFollowTargetData[] = { + CAM_FUNCDATA_KEEP1(-20, 120, 140, 25, 45, -5, 15, 15, 45, 50, 0x2001, -50, 30), +}; + +CameraModeValue sSetNormal0ModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-30, 70, 200, 40, 10, 0, 5, 70, 45, 50, 10, 0x3500), +}; + +CameraModeValue sSetNormal0ModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 180, 10, 80, 0, 10, 25, 50, 80, 0x2002, -40, 25), +}; + +CameraModeValue sSetNormal0ModeClimbData[] = { + CAM_FUNCDATA_JUMP2(-20, 200, 300, 20, 5, 5, 60, 40, 0x0000), +}; + +CameraModeValue sSetNormal0ModeFirstPersonData[] = { + CAM_FUNCDATA_SUBJ3(0, 5, 50, 10, 0, 0, 0, 45, 0x0000), +}; + +CameraModeValue sSetNormal0ModeBowArrowData[] = { + CAM_FUNCDATA_SUBJ3(-7, 14, 50, 10, 0, -30, -5, 45, 0x2000), +}; + +CameraModeValue sSetNormal0ModeBowArrowZData[] = { + CAM_FUNCDATA_SUBJ3(20, 70, 70, 10, -120, 20, 0, 45, 0x2000), +}; + +CameraModeValue sSetNormal0ModeHookshotData[] = { + CAM_FUNCDATA_SPEC5_ALT(-20, 80, 250, 45, 60, 40, 6, 0x2000), +}; + +CameraModeValue sSetNormal0ModeBoomerangData[] = { + CAM_FUNCDATA_SUBJ3(5, 50, 50, 10, 0, 0, 0, 45, 0x2000), +}; + +CameraModeValue sSetNormal0ModeSlingshotData[] = { + CAM_FUNCDATA_SUBJ3(-7, 14, 50, 10, -9, -63, -30, 45, 0x2000), +}; + +CameraModeValue sSetNormal0ModeClimbZData[] = { + CAM_FUNCDATA_JUMP2(-20, 200, 300, 20, 999, 5, 60, 40, 0x2006), +}; + +CameraModeValue sSetNormal0ModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-20, 200, 300, 12, 35, 60, 40, 0x0000), +}; + +CameraModeValue sSetNormal0ModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 200, 300, 40, 60, 10, 0x0000), +}; + +CameraModeValue sSetNormal0ModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 300, 300, 70, 45, 10, 0x2000), +}; + +CameraModeValue sSetNormal0ModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(-20, 200, 300, 15, 80, 60, 20, 0x0000), +}; + +CameraModeValue sSetNormal0ModeChargeData[] = { + CAM_FUNCDATA_BATT4(-20, 300, 50, 2, 80, 20, 0xF000), +}; + +CameraModeValue sSetNormal0ModeStillData[] = { + CAM_FUNCDATA_NORM1(-20, 200, 300, 10, 100, 10, 100, 60, 5, 0xF003), +}; + +CameraModeValue sSetNormal0ModePushPullData[] = { + CAM_FUNCDATA_PARA1(0, 250, 25, 0, 5, 5, 70, 30, 0x206A, -20, 30), +}; + +CameraModeValue sSetNormal0ModeFollowBoomerangData[] = { + CAM_FUNCDATA_KEEP1(-5, 120, 140, 5, 85, 10, 5, 25, 45, 50, 0x2001, -15, 30), +}; + +/** + *===================================================================== + * Custom Data: NORMAL1 Setting + *===================================================================== + */ + +CameraModeValue sSetNormal1ModeNormalData[] = { + CAM_FUNCDATA_NORM1(0, 200, 400, 10, 12, 20, 40, 60, 60, 0x0003), +}; + +CameraModeValue sSetNormal1ModeTargetData[] = { + CAM_FUNCDATA_PARA1(0, 250, 0, 0, 5, 5, 45, 50, 0x2002, -40, 20), +}; + +CameraModeValue sSetNormal1ModeFollowTargetData[] = { + CAM_FUNCDATA_KEEP1(-20, 120, 140, 25, 45, -5, 15, 15, 45, 50, 0x2001, -50, 20), +}; + +CameraModeValue sSetNormal1ModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 250, 10, 80, 0, 10, 25, 50, 65, 0x2002, -40, 25), +}; + +CameraModeValue sSetNormal1ModeHookshotData[] = { + CAM_FUNCDATA_SPEC5(-20, 80, 250, 6, 45, 60, 40, 0x2000), +}; + +CameraModeValue sSetNormal1ModeJumpData[] = { + CAM_FUNCDATA_JUMP1(0, 250, 400, 15, 50, 60, 30, 0x0000), +}; + +CameraModeValue sSetNormal1ModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(0, 200, 400, 30, 80, 60, 20, 0x0000), +}; + +CameraModeValue sSetNormal1ModeClimbData[] = { + CAM_FUNCDATA_JUMP2(-20, 200, 400, 20, 5, 5, 60, 40, 0x0000), +}; + +CameraModeValue sSetNormal1ModeClimbZData[] = { + CAM_FUNCDATA_JUMP2(-20, 250, 400, 20, 999, 5, 60, 40, 0x2006), +}; + +CameraModeValue sSetNormal1ModeChargeData[] = { + CAM_FUNCDATA_BATT4(0, 300, 50, 2, 80, 20, 0xF000), +}; + +CameraModeValue sSetNormal1ModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 200, 400, 40, 60, 10, 0x0000), +}; + +CameraModeValue sSetNormal1ModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 400, 400, 70, 45, 10, 0x2000), +}; + +CameraModeValue sSetNormal1ModeStillData[] = { + CAM_FUNCDATA_NORM1(0, 200, 400, 10, 100, 20, 100, 60, 5, 0xF003), +}; + +/** + *===================================================================== + * Custom Data: DUNGEON0 Setting + *===================================================================== + */ + +CameraModeValue sSetDungeon0ModeNormalData[] = { + CAM_FUNCDATA_NORM1(-10, 150, 250, 5, 10, 5, 30, 60, 60, 0x0003), +}; + +CameraModeValue sSetDungeon0ModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 150, 0, 0, 5, 5, 45, 50, 0x200A, -40, 20), +}; + +CameraModeValue sSetDungeon0ModeFollowTargetData[] = { + CAM_FUNCDATA_KEEP1(-20, 120, 140, 25, 45, -5, 15, 15, 45, 50, 0x2001, -40, 20), +}; + +CameraModeValue sSetDungeon0ModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 180, 10, 80, 0, 10, 25, 45, 80, 0x2002, -40, 25), +}; + +CameraModeValue sSetDungeon0ModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-10, 150, 250, 10, 50, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon0ModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(-10, 150, 250, 10, 80, 60, 20, 0x0000), +}; + +CameraModeValue sSetDungeon0ModeClimbData[] = { + CAM_FUNCDATA_JUMP2(-40, 150, 250, 20, 5, 5, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon0ModeClimbZData[] = { + CAM_FUNCDATA_JUMP2(-40, 250, 250, 20, 999, 5, 60, 40, 0x2006), +}; + +CameraModeValue sSetDungeon0ModeChargeData[] = { + CAM_FUNCDATA_BATT4(-10, 300, 50, 2, 80, 20, 0xF000), +}; + +CameraModeValue sSetDungeon0ModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 150, 250, 40, 60, 10, 0x0000), +}; + +CameraModeValue sSetDungeon0ModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 250, 250, 70, 45, 10, 0x2000), +}; + +CameraModeValue sSetDungeon0ModeStillData[] = { + CAM_FUNCDATA_NORM1(-10, 150, 250, 5, 100, 5, 100, 60, 5, 0xF003), +}; + +/** + *===================================================================== + * Custom Data: DUNGEON1 Setting + *===================================================================== + */ + +CameraModeValue sSetDungeon1ModeNormalData[] = { + CAM_FUNCDATA_NORM1(-40, 150, 150, 0, 10, 5, 30, 60, 60, 0x0003), +}; + +CameraModeValue sSetDungeon1ModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-20, 70, 200, 40, 10, 0, 5, 70, 45, 50, 10, 0x3500), +}; + +CameraModeValue sSetDungeon1ModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-40, 150, 150, 10, 50, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon1ModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(-40, 150, 180, 12, 80, 60, 20, 0x0000), +}; + +CameraModeValue sSetDungeon1ModeClimbData[] = { + CAM_FUNCDATA_JUMP2(-40, 150, 150, 20, 5, 5, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon1ModeClimbZData[] = { + CAM_FUNCDATA_JUMP2(-40, 150, 150, 20, 999, 5, 60, 40, 0x2006), +}; + +CameraModeValue sSetDungeon1ModeChargeData[] = { + CAM_FUNCDATA_BATT4(-40, 200, 50, 2, 80, 20, 0xF000), +}; + +CameraModeValue sSetDungeon1ModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 150, 150, 40, 60, 10, 0x0000), +}; + +CameraModeValue sSetDungeon1ModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 150, 150, 70, 45, 10, 0x2000), +}; + +CameraModeValue sSetDungeon1ModeStillData[] = { + CAM_FUNCDATA_NORM1(-40, 150, 150, 0, 100, 5, 100, 60, 5, 0xF003), +}; + +CameraModeValue sSetDungeon1ModePushPullData[] = { + CAM_FUNCDATA_PARA1(-40, 180, 25, 0, 5, 5, 60, 50, 0x206A, -20, 30), +}; + +/** + *===================================================================== + * Custom Data: NORMAL3 Setting + *===================================================================== + */ + +CameraModeValue sSetNormal3ModeNormalData[] = { + CAM_FUNCDATA_JUMP3(-20, 280, 300, 20, 15, 5, 40, 60, 100, 0x0004), +}; + +CameraModeValue sSetNormal3ModeTargetData[] = { + CAM_FUNCDATA_PARA1(-50, 250, 70, 0, 15, 5, 60, 100, 0x200A, -50, 20), +}; + +CameraModeValue sSetNormal3ModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-30, 70, 200, 40, 10, 10, 20, 70, 45, 10, 10, 0x3500), +}; + +/* These values are for when the eye + * >= OREG(45) units below the surface of the water. + */ +CameraModeValue sSetNormal3ModeBoomerangData[] = { + CAM_FUNCDATA_JUMP3(-40, 150, 250, -5, 18, 5, 60, 60, 40, 0x0005), +}; + +/** + *===================================================================== + * Custom Data: HORSE Setting + *===================================================================== + */ + +CameraModeValue sSetHorseModeNormalData[] = { + CAM_FUNCDATA_NORM3(-50, 220, 250, 10, 16, 20, 60, 100, 0x0600), +}; + +CameraModeValue sSetHorseModeTargetData[] = { + CAM_FUNCDATA_NORM3(-40, 180, 220, -2, 12, 100, 45, 100, 0x2600), +}; + +CameraModeValue sSetHorseModeBowArrowData[] = { + CAM_FUNCDATA_SUBJ3(-7, 14, 100, 10, 0, -30, -5, 40, 0x2600), +}; + +CameraModeValue sSetHorseModeFollowTargetData[] = { + CAM_FUNCDATA_KEEP1(-60, 180, 220, 25, 45, -5, 15, 15, 45, 50, 0x2601, -60, 20), +}; + +CameraModeValue sSetHorseModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-60, 140, 200, 40, 10, 0, 5, 70, 45, 50, 10, 0x3500), +}; + +/** + *===================================================================== + * Custom Data: BOSS_GOHMA Setting + *===================================================================== + */ + +CameraModeValue sSetBossGohmaModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 150, 250, 0, 15, 5, 40, 60, 60, 0x0001), +}; + +CameraModeValue sSetBossGohmaModeBattleData[] = { + CAM_FUNCDATA_BATT1(-30, 150, 10, 40, -10, 0, 25, 60, 40, 0x2002, -50, 20), +}; + +/** + *===================================================================== + * Custom Data: BOSS_DODONGO Setting + *===================================================================== + */ + +CameraModeValue sSetBossDodongoModeNormalData[] = { + CAM_FUNCDATA_NORM1(0, 150, 300, 0, 12, 5, 70, 70, 40, 0x0003), +}; + +CameraModeValue sSetBossDodongoModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 160, 10, 60, -5, 0, 25, 70, 50, 0x2002, -40, 20), +}; + +/** + *===================================================================== + * Custom Data: BOSS_BARINADE Setting + *===================================================================== + */ + +CameraModeValue sSetBossBarinadeModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 150, 300, -5, 15, 5, 40, 70, 70, 0x0003), +}; + +CameraModeValue sSetBossBarinadeModeBattleData[] = { + CAM_FUNCDATA_BATT1(-30, 125, 10, 10, 0, 0, 50, 60, 50, 0x2002, -50, 20), +}; + +/** + *===================================================================== + * Custom Data: BOSS_PHANTOM_GANON Setting + *===================================================================== + */ + +CameraModeValue sSetBossPhantomGanonModeNormalData[] = { + CAM_FUNCDATA_NORM1(10, 150, 250, 0, 15, 15, 40, 60, 100, 0x0003), +}; + +CameraModeValue sSetBossPhantomGanonModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 200, 45, 40, 5, -5, 35, 60, 100, 0x2002, -40, 60), +}; + +/** + *===================================================================== + * Custom Data: BOSS_VOLVAGIA Setting + *===================================================================== + */ + +CameraModeValue sSetBossVolvagiaModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 10, 16, 10, 40, 60, 80, 0x0003), +}; + +CameraModeValue sSetBossVolvagiaModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 200, 20, 60, 0, 10, 15, 45, 50, 0x2002, -40, 20), +}; + +/** + *===================================================================== + * Custom Data: BOSS_BONGO Setting + *===================================================================== + */ + +CameraModeValue sSetBossBongoModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 10, 20, 10, 40, 60, 80, 0x0083), +}; + +CameraModeValue sSetBossBongoModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 200, 20, 60, 0, 10, 15, 45, 50, 0x2082, -40, 20), +}; + +CameraModeValue sSetBossBongoModeJumpData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 10, 20, 10, 80, 60, 80, 0x0083), +}; + +/** + *===================================================================== + * Custom Data: BOSS_MORPHA Setting + *===================================================================== + */ + +CameraModeValue sSetBossMorphaModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 100, 150, -10, 15, 10, 40, 80, 60, 0x0003), +}; + +CameraModeValue sSetBossMorphaModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 200, 10, 80, -10, 10, 25, 70, 40, 0x2002, -40, 20), +}; + +/** + *===================================================================== + * Custom Data: TWINROVA Setting + *===================================================================== + */ + +CameraModeValue sSetBossTwinrovaPlatformModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 150, 300, 0, 20, 10, 40, 60, 80, 0x0003), +}; + +CameraModeValue sSetBossTwinrovaModeBattleData[] = { + CAM_FUNCDATA_BATT1(0, 400, 0, 60, -10, 5, 25, 45, 40, 0x2002, -20, 20), +}; + +CameraModeValue sSetBossTwinrovaFloorModeNormalData[] = { + CAM_FUNCDATA_NORM1(-10, 150, 200, -10, 12, 10, 40, 60, 50, 0x0003), +}; + +/** + *===================================================================== + * Custom Data: BOSS_GANONDORF Setting + *===================================================================== + */ + +CameraModeValue sSetBossGanondorfModeNormalData[] = { + CAM_FUNCDATA_NORM1(40, 330, 330, -5, 15, 15, 40, 60, 100, 0x0000), +}; + +CameraModeValue sSetBossGanondorfModeChargeData[] = { + CAM_FUNCDATA_BATT4(-40, 250, 0, 2, 80, 20, 0xF000), +}; + +/** + *===================================================================== + * Custom Data: BOSS_GANON Setting + *===================================================================== + */ + +CameraModeValue sSetBossGanonModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 10, 20, 10, 40, 60, 80, 0x0003), +}; + +CameraModeValue sSetBossGanonModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 180, 20, 60, 0, 10, 25, 45, 50, 0x2002, -40, 20), +}; + +/** + *===================================================================== + * Custom Data: TOWER_CLIMB Setting + *===================================================================== + */ + +CameraModeValue sSetTowerClimbModeNormalData[] = { + CAM_FUNCDATA_NORM2(0, 120, 280, 60, 8, 40, 60, 50, 0x0000), +}; + +CameraModeValue sSetTowerClimbModeJumpData[] = { + CAM_FUNCDATA_NORM2(0, 120, 280, 60, 8, 40, 60, 50, 0x0080), +}; + +/** + *===================================================================== + * Custom Data: TOWER_UNUSED Setting + *===================================================================== + */ + +CameraModeValue sSetTowerUnusedModeNormalData[] = { + CAM_FUNCDATA_NORM2(0, 270, 300, 120, 8, 60, 60, 100, 0x0000), +}; + +CameraModeValue sSetTowerUnusedModeJumpData[] = { + CAM_FUNCDATA_NORM2(0, 270, 300, 120, 6, 60, 60, 100, 0x0000), +}; + +/** + *===================================================================== + * Custom Data: MARKET_BALCONY Setting + *===================================================================== + */ + +CameraModeValue sSetMarketBalconyModeNormalData[] = { + CAM_FUNCDATA_FIXD1(-40, 100, 60, 0x0000), +}; + +CameraModeValue sSetMarketBalconyModeFollowTargetData[] = { + CAM_FUNCDATA_FIXD1(-40, 100, 60, 0x2000), +}; + +CameraModeValue sSetMarketBalconyModeTalkData[] = { + CAM_FUNCDATA_FIXD1(-40, 100, 60, 0x3500), +}; + +/** + *===================================================================== + * Custom Data: CHU_BOWLING Setting + *===================================================================== + */ + +CameraModeValue sSetChuBowlingModeNormalData[] = { + CAM_FUNCDATA_FIXD1(-40, 25, 60, 0x0000), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_CRAWLSPACE Setting + *===================================================================== + */ + +CameraModeValue sSetPivotCrawlspaceModeNormalData[] = { + CAM_FUNCDATA_FIXD2(-40, 50, 80, 60, 0x0001), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_SHOP_BROWSING Setting + *===================================================================== + */ + +CameraModeValue sSetPivotShopBrowsingModeNormalData[] = { + CAM_FUNCDATA_DATA4(-40, 60, 0x3F00), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_IN_FRONT and PIVOT_FROM_SIDE + *===================================================================== + */ + +CameraModeValue sSetPivotInFrontAndFromSideModeNormalData[] = { + CAM_FUNCDATA_FIXD4(-40, 50, 80, 60, 0x0004), +}; + +/** + *===================================================================== + * Custom Data: No data, all flags off + *===================================================================== + */ + +CameraModeValue sDataOnlyNullFlags[] = { + CAM_FUNCDATA_FLAGS(0x0000), +}; + +/** + *===================================================================== + * Custom Data: PREREND_FIXED Setting + *===================================================================== + */ + +CameraModeValue sSetPrerendFixedModeFollowTargetData[] = { + CAM_FUNCDATA_FLAGS(0x2000), +}; + +/** + *===================================================================== + * Custom Data: PREREND_PIVOT Setting + *===================================================================== + */ + +CameraModeValue sSetPrerendPivotModeNormalData[] = { + CAM_FUNCDATA_UNIQ7(60, 0x0000), +}; + +CameraModeValue sSetPrerendPivotModeFollowTargetData[] = { + CAM_FUNCDATA_UNIQ7(60, 0x2000), +}; + +CameraModeValue sSetPrerendPivotModeTalkData[] = { + CAM_FUNCDATA_KEEP0(30, 0, 4, 0x3500), +}; + +/** + *===================================================================== + * Custom Data: DOOR0 Setting + *===================================================================== + */ + +CameraModeValue sSetDoor0ModeNormalData[] = { + CAM_FUNCDATA_UNIQ3(-40, 60, 0x3200), +}; + +/** + *===================================================================== + * Custom Data: DOORC Setting + *===================================================================== + */ + +CameraModeValue sSetDoorCModeNormalData[] = { + CAM_FUNCDATA_SPEC9(-5, 60, 0x3202), +}; + +CameraModeValue sSetDoorCModeTargetData[] = { + CAM_FUNCDATA_SPEC9(-5, 60, 0x320A), +}; + +/** + *===================================================================== + * Custom Data: CRAWLSPACE Setting + *===================================================================== + */ + +// Camera_Subj4 only reads one setting which is used for flags +CameraModeValue sSetCrawlspaceModeNormalData[] = { + CAM_FUNCDATA_SUBJ4(0x0000, 2, 30, 10, 45, 0x3200), +}; + +/** + *===================================================================== + * Custom Data: START1 Setting + *===================================================================== + */ + +CameraModeValue sSetStart1ModeNormalData[] = { + CAM_FUNCDATA_FLAGS(0x0001), +}; + +/** + *===================================================================== + * Custom Data: FREE0 Setting + *===================================================================== + */ + +CameraModeValue sSetFree0ModeNormalData[] = { + CAM_FUNCDATA_FLAGS(0xFF00), +}; + +/** + *===================================================================== + * Custom Data: FREE1 Setting + *===================================================================== + */ + +CameraModeValue sSetFree1ModeNormalData[] = { + CAM_FUNCDATA_FLAGS(0xFF01), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_CORNER Setting + *===================================================================== + */ + +CameraModeValue sSetPivotCornerModeNormalData[] = { + CAM_FUNCDATA_FIXD2(-40, 100, 80, 60, 0x0000), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_WATER_SURFACE Setting + *===================================================================== + */ + +CameraModeValue sSetPivotWaterSurfaceModeNormalData[] = { + CAM_FUNCDATA_UNIQ2(-40, 60, 60, 0x0002), +}; + +CameraModeValue sSetPivotWaterSurfaceModeTargetData[] = { + CAM_FUNCDATA_UNIQ2(-30, 45, 100, 0x2001), +}; + +/** + *===================================================================== + * Custom Data: Various cutscene settings + *===================================================================== + */ + +CameraModeValue sDataOnlyInterfaceFlags[] = { + CAM_FUNCDATA_FLAGS(0x3200), +}; + +/** + *===================================================================== + * Custom Data: FOREST_BIRDS_EYE Setting + *===================================================================== + */ + +CameraModeValue sSetForestBirdsEyeModeNormalData[] = { + CAM_FUNCDATA_PARA1(-50, 450, 40, 180, 5, 5, 70, 30, 0x000C, -50, 20), +}; + +CameraModeValue sSetForestBirdsEyeModeTalkData[] = { + CAM_FUNCDATA_FLAGS(0x3501), +}; + +/** + *===================================================================== + * Custom Data: SLOW_CHEST_CS Setting + *===================================================================== + */ + +// Also set to but unused by function Demo4 +CameraModeValue sSetSlowChestCsModeNormalData[] = { + CAM_FUNCDATA_DEMO3(60, 30, 0x3200), +}; + +/** + *===================================================================== + * Custom Data: CS_3 Setting + *===================================================================== + */ + +CameraModeValue sSetCs3ModeNormalData[] = { + CAM_FUNCDATA_FLAGS(0x3212), +}; + +/** + *===================================================================== + * Custom Data: BEAN_GENERIC Setting + *===================================================================== + */ + +CameraModeValue sSetBeanGenericModeNormalData[] = { + CAM_FUNCDATA_NORM1(-50, 300, 300, 50, 20, 10, 50, 70, 40, 0x0002), +}; + +CameraModeValue sSetBeanGenericModeTargetData[] = { + CAM_FUNCDATA_PARA1(-50, 300, 10, 0, 5, 5, 45, 50, 0x200A, -40, 20), +}; + +CameraModeValue sSetBeanGenericModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-50, 300, 300, 12, 35, 60, 40, 0x0000), +}; + +CameraModeValue sSetBeanGenericModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 300, 300, 60, 70, 30, 0x0000), +}; + +CameraModeValue sSetBeanGenericModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 300, 300, 70, 50, 30, 0x2000), +}; + +CameraModeValue sSetBeanGenericModeStillData[] = { + CAM_FUNCDATA_NORM1(-20, 300, 350, 50, 100, 10, 100, 70, 30, 0xF002), +}; + +/** + *===================================================================== + * Custom Data: BEAN_LOST_WOODS Setting + *===================================================================== + */ + +CameraModeValue sSetBeanLostWoodsModeNormalData[] = { + CAM_FUNCDATA_NORM1(-50, 200, 200, 20, 16, 10, 50, 60, 50, 0x0002), +}; + +CameraModeValue sSetBeanLostWoodsModeTargetData[] = { + CAM_FUNCDATA_PARA1(-50, 200, 40, 0, 5, 5, 45, 50, 0x200A, -40, 20), +}; + +CameraModeValue sSetBeanLostWoodsModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-50, 150, 250, 12, 35, 60, 40, 0x0000), +}; + +CameraModeValue sSetBeanLostWoodsModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 200, 200, 40, 60, 30, 0x0000), +}; + +CameraModeValue sSetBeanLostWoodsModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 200, 200, 60, 50, 30, 0x2000), +}; + +CameraModeValue sSetBeanLostWoodsModeStillData[] = { + CAM_FUNCDATA_NORM1(-20, 200, 250, 20, 100, 10, 100, 60, 30, 0xF002), +}; + +/** + *===================================================================== + * Custom Data: SCENE_UNUSED Setting + *===================================================================== + */ + +CameraModeValue sSetSceneUnusedModeNormalData[] = { + CAM_FUNCDATA_SPEC9(-30, 60, 0x010A), +}; + +/** + *===================================================================== + * Custom Data: SCENE_TRANSITION Setting + *===================================================================== + */ + +CameraModeValue sSetSceneTransitionModeNormalData[] = { + CAM_FUNCDATA_UNIQ2(-20, 150, 60, 0x0210), +}; + +/** + *===================================================================== + * Custom Data: BIG_OCTO Setting + *===================================================================== + */ + +CameraModeValue sSetBigOctoModeNormalData[] = { + CAM_FUNCDATA_NORM1(0, 400, 500, 35, 14, 5, 20, 60, 40, 0x0012), +}; + +CameraModeValue sSetBigOctoModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 250, 5, 10, 30, 20, 25, 45, 60, 0x2002, -40, 25), +}; + +CameraModeValue sSetBigOctoModeStillData[] = { + CAM_FUNCDATA_NORM1(0, 300, 500, 60, 8, 5, 60, 60, 30, 0x0012), +}; + +/** + *===================================================================== + * Custom Data: MEADOW_BIRDS_EYE Setting + *===================================================================== + */ + +CameraModeValue sSetMeadowBirdsEyeModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 80, 20, 10, 70, 70, 80, 0x0012), +}; + +CameraModeValue sSetMeadowBirdsEyeModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 500, 80, 0, 5, 5, 70, 80, 0x201A, -40, 40), +}; + +CameraModeValue sSetMeadowBirdsEyeModeBattleData[] = { + CAM_FUNCDATA_PARA1(-20, 500, 80, 0, 5, 5, 60, 80, 0x201A, -40, 40), +}; + +CameraModeValue sSetMeadowBirdsEyeModeClimbData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 80, 20, 10, 80, 60, 20, 0x0012), +}; + +/** + *===================================================================== + * Custom Data: MEADOW_UNUSED Setting + *===================================================================== + */ + +CameraModeValue sSetMeadowUnusedModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 750, 750, 80, 20, 10, 70, 70, 80, 0x0012), +}; + +CameraModeValue sSetMeadowUnusedModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 750, 80, 0, 5, 5, 70, 80, 0x201A, -40, 40), +}; + +CameraModeValue sSetMeadowUnusedModeBattleData[] = { + CAM_FUNCDATA_PARA1(-20, 750, 80, 0, 5, 5, 70, 80, 0x200A, -40, 40), +}; + +CameraModeValue sSetMeadowUnusedModeClimbData[] = { + CAM_FUNCDATA_NORM1(-20, 750, 750, 80, 20, 10, 80, 70, 20, 0x0012), +}; + +/** + *===================================================================== + * Custom Data: FIRE_BIRDS_EYE Setting + *===================================================================== + */ + +CameraModeValue sSetFireBirdsEyeModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 80, 20, 10, 70, 70, 80, 0x0002), +}; + +CameraModeValue sSetFireBirdsEyeModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 500, 80, 0, 5, 5, 70, 80, 0x200A, -40, 40), +}; + +CameraModeValue sSetFireBirdsEyeModeBattleData[] = { + CAM_FUNCDATA_PARA1(-20, 500, 80, 0, 5, 5, 60, 80, 0x200A, -40, 40), +}; + +CameraModeValue sSetFireBirdsEyeModeClimbData[] = { + CAM_FUNCDATA_NORM1(-20, 500, 500, 80, 20, 10, 80, 60, 20, 0x0002), +}; + +/** + *===================================================================== + * Custom Data: TURN_AROUND Setting + *===================================================================== + */ + +CameraModeValue sSetTurnAroundModeNormalData[] = { + CAM_FUNCDATA_KEEP4(-30, 120, -10, 170, 0, 60, 0x2502, 25, 6), +}; + +/** + *===================================================================== + * Custom Data: PIVOT_VERTICAL Setting + *===================================================================== + */ + +CameraModeValue sSetPivotVerticalModeNormalData[] = { + CAM_FUNCDATA_SPEC0(20, 0x3200), +}; + +/** + *===================================================================== + * Custom Data: NORMAL2/4 Setting + *===================================================================== + */ + +CameraModeValue sSetNormal2and4ModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 200, 300, 10, 12, 10, 35, 60, 60, 0x0002), +}; + +/** + *===================================================================== + * Custom Data: FISHING Setting + *===================================================================== + */ + +CameraModeValue sSetFishingModeNormalData[] = { + CAM_FUNCDATA_NORM1(0, 200, 300, 20, 12, 10, 35, 55, 60, 0x0F02), +}; + +CameraModeValue sSetFishingModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 250, 0, 0, 5, 5, 45, 50, 0x2F0A, -40, 20), +}; + +CameraModeValue sSetFishingModeFollowTargetData[] = { + CAM_FUNCDATA_BATT1(-20, 250, 0, 80, 0, 0, 25, 55, 80, 0x2F02, -40, 25), +}; + +CameraModeValue sSetFishingModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-30, 70, 200, 40, 10, 0, 5, 70, 45, 50, 10, 0x3F20), +}; + +CameraModeValue sSetFishingModeFirstPersonData[] = { + CAM_FUNCDATA_SUBJ3(0, 5, 50, 10, 0, 0, 0, 45, 0x0F00), +}; + +CameraModeValue sSetFishingModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-20, 200, 300, 12, 35, 60, 40, 0x0F00), +}; + +CameraModeValue sSetFishingModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(-20, 200, 300, 15, 80, 60, 20, 0x0F00), +}; + +CameraModeValue sSetFishingModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-80, 200, 300, 40, 60, 10, 0x0F00), +}; + +CameraModeValue sSetFishingModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-120, 300, 300, 70, 45, 10, 0x2F00), +}; + +/** + *===================================================================== + * Custom Data: CS_C Setting + *===================================================================== + */ + +CameraModeValue sSetCsCModeNormalData[] = { + CAM_FUNCDATA_FLAGS(0x3F00), +}; + +/** + *===================================================================== + * Custom Data: JABU_TENTACLE Setting + *===================================================================== + */ + +CameraModeValue sSetJabuTentacleModeNormalData[] = { + CAM_FUNCDATA_NORM1_ALT(30, 200, 300, -20, 15, 5, 50, 70, 70, 0x0003), +}; + +CameraModeValue sSetJabuTentacleModeBattleData[] = { + CAM_FUNCDATA_BATT1(-30, 160, 10, 10, 0, 0, 70, 60, 40, 0x2002, -50, 20), +}; + +/** + *===================================================================== + * Custom Data: DUNGEON2 Setting + *===================================================================== + */ + +CameraModeValue sSetDungeon2ModeNormalData[] = { + CAM_FUNCDATA_NORM1(-20, 350, 350, 20, 15, 5, 30, 60, 60, 0x0003), +}; + +CameraModeValue sSetDungeon2ModeTargetData[] = { + CAM_FUNCDATA_PARA1(-20, 200, 0, 0, 5, 5, 45, 50, 0x200A, -40, 20), +}; + +CameraModeValue sSetDungeon2ModeBattleData[] = { + CAM_FUNCDATA_BATT1(-20, 180, 10, 80, -10, 10, 25, 45, 80, 0x2002, -40, 25), +}; + +CameraModeValue sSetDungeon2ModeJumpData[] = { + CAM_FUNCDATA_JUMP1(-20, 350, 350, 10, 50, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon2ModeFreeFallData[] = { + CAM_FUNCDATA_JUMP1(-20, 350, 350, 15, 80, 60, 20, 0x0000), +}; + +CameraModeValue sSetDungeon2ModeClimbData[] = { + CAM_FUNCDATA_JUMP2(-40, 350, 350, 20, 5, 5, 60, 40, 0x0000), +}; + +CameraModeValue sSetDungeon2ModeClimbZData[] = { + CAM_FUNCDATA_JUMP2(-40, 350, 350, 20, 999, 5, 60, 40, 0x2006), +}; + +CameraModeValue sSetDungeon2ModeHangData[] = { + CAM_FUNCDATA_UNIQ1(-50, 350, 350, 40, 60, 10, 0x0000), +}; + +CameraModeValue sSetDungeon2ModeHangZData[] = { + CAM_FUNCDATA_UNIQ1(-100, 350, 350, 70, 45, 10, 0x2000), +}; + +CameraModeValue sSetDungeon2ModeStillData[] = { + CAM_FUNCDATA_NORM1(-10, 350, 350, 20, 100, 5, 100, 60, 5, 0xF003), +}; + +CameraModeValue sSetDungeon2ModePushPullData[] = { + CAM_FUNCDATA_PARA1(0, 280, 25, 0, 5, 5, 70, 30, 0x206A, -20, 30), +}; + +/** + *===================================================================== + * Custom Data: DIRECTED_YAW Setting + *===================================================================== + */ + +CameraModeValue sSetDirectedYawModeNormalData[] = { + CAM_FUNCDATA_NORM1(-10, 280, 320, -8, 20, 10, 80, 60, 80, 0x0002), +}; + +CameraModeValue sSetDirectedYawModeFollowTargetData[] = { + CAM_FUNCDATA_KEEP1(-20, 180, 200, 35, 45, 0, -5, 20, 50, 50, 0x2001, -50, 30), +}; + +CameraModeValue sSetDirectedYawModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-80, 200, 250, 30, 10, -8, -8, 30, 50, 50, 10, 0x3520), +}; + +/** + *===================================================================== + * Custom Data: NORMAL4 Setting + *===================================================================== + */ + +CameraModeValue sNormal4ModeTalkData[] = { + CAM_FUNCDATA_KEEP3(-30, 70, 200, 40, 10, 0, 5, 70, 45, 50, 10, 0x35A0), +}; + +/** + * ===================================================================== + * CAMERA SETTINGS: USAGE OF FUNCTIONS AND DATA FOR SPECIFIC MODES + * ===================================================================== + */ + +#define CAM_SETTING_MODE_ENTRY(func, data) \ + { func, ARRAY_COUNT(data), data } + +CameraMode sCamSetNormal0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetNormal1Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal1ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal1ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal1ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal1ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal1ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal1ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal1ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal1ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal1ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal1ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal1ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal1ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetDungeon0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon0ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetDungeon0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetDungeon0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal1ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon0ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetDungeon0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetDungeon1Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon1ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal1ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetDungeon1ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetDungeon0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon1ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal1ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon1ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon1ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon1ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon1ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon1ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetDungeon1ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon1ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon1ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetNormal3Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP3, sSetNormal3ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal3ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal3ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP3, sSetNormal3ModeBoomerangData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), +}; + +CameraMode sCamSetHorseModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM3, sSetHorseModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM3, sSetHorseModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetHorseModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetHorseModeTalkData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetHorseModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), +}; + +CameraMode sCamSetBossGohmaModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossGohmaModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossGohmaModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetDungeon0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossDodongoModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossDodongoModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossDodongoModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossBarinadeModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossBarinadeModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossBarinadeModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossPhantomGanonModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossPhantomGanonModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossPhantomGanonModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossVolvagiaModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossVolvagiaModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossVolvagiaModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossBongoModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossBongoModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossBongoModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossBongoModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossBongoModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossMorphaModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossMorphaModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossMorphaModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossTwinrovaPlatformModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossTwinrovaPlatformModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossTwinrovaModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossTwinrovaFloorModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossTwinrovaFloorModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossTwinrovaModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossGanondorfModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossGanondorfModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossPhantomGanonModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetBossGanondorfModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBossGanonModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBossGanonModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBossGanonModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetTowerClimbModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM2, sSetTowerClimbModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM2, sSetTowerClimbModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetTowerUnusedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM2, sSetTowerUnusedModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM2, sSetTowerUnusedModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetMarketBalconyModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD1, sSetMarketBalconyModeNormalData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD1, sSetMarketBalconyModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD1, sSetMarketBalconyModeTalkData), +}; + +CameraMode sCamSetChuBowlingModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD1, sSetChuBowlingModeNormalData), +}; + +CameraMode sCamSetPivotCrawlspaceModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD2, sSetPivotCrawlspaceModeNormalData), +}; + +CameraMode sCamSetPivotShopBrowsingModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DATA4, sSetPivotShopBrowsingModeNormalData), +}; + +CameraMode sCamSetPivotInFrontModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD4, sSetPivotInFrontAndFromSideModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetPreRendFixedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD3, sDataOnlyNullFlags), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD3, sSetPrerendFixedModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD3, sSetPrerendFixedModeFollowTargetData), +}; + +CameraMode sCamSetPreRendPivotModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ7, sSetPrerendPivotModeNormalData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ7, sSetPrerendPivotModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP0, sSetPrerendPivotModeTalkData), +}; + +CameraMode sCamSetPreRendSideScrollModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC6, sDataOnlyNullFlags), +}; + +CameraMode sCamSetDoor0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ3, sSetDoor0ModeNormalData), +}; + +CameraMode sCamSetDoorCModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC9, sSetDoorCModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC9, sSetDoorCModeTargetData), +}; + +CameraMode sCamSetCrawlspaceModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ4, sSetCrawlspaceModeNormalData), +}; + +CameraMode sCamSetStart0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ0, sDataOnlyNullFlags), +}; + +CameraMode sCamSetStart1Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ0, sSetStart1ModeNormalData), +}; + +CameraMode sCamSetFree0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ6, sSetFree0ModeNormalData), +}; + +CameraMode sCamSetFree1Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ6, sSetFree1ModeNormalData), +}; + +CameraMode sCamSetPivotCornerModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD2, sSetPivotCornerModeNormalData), +}; + +CameraMode sCamSetPivotDivingModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ2, sSetPivotWaterSurfaceModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ2, sSetPivotWaterSurfaceModeTargetData), +}; + +CameraMode sCamSetCs0Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO1, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetCsTwistedHallwayModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO2, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetForestBirdsEyeModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetForestBirdsEyeModeNormalData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA3, sSetForestBirdsEyeModeTalkData), +}; + +CameraMode sCamSetSlowChestCsModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO3, sSetSlowChestCsModeNormalData), +}; + +CameraMode sCamSetItemUnusedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO4, sSetSlowChestCsModeNormalData), +}; + +CameraMode sCamSetCs3Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO9, sSetCs3ModeNormalData), +}; + +CameraMode sCamSetCsAttentionModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO5, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetBeanGenericModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBeanGenericModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetBeanGenericModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetBeanGenericModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetBeanGenericModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetBeanGenericModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBeanGenericModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetBeanLostWoodsModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBeanLostWoodsModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetBeanLostWoodsModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetBeanLostWoodsModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetBeanLostWoodsModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetBeanLostWoodsModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBeanLostWoodsModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetSceneUnusedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC9, sSetSceneUnusedModeNormalData), +}; + +CameraMode sCamSetSceneTransitionModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ2, sSetSceneTransitionModeNormalData), +}; + +CameraMode sCamSetFirePlatformModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC7, sDataOnlyNullFlags), +}; + +CameraMode sCamSetFireStaircaseModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC4, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetForestUnusedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ5, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetForestDefeatPoeModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_DEMO6, sDataOnlyInterfaceFlags), +}; + +CameraMode sCamSetBigOctoModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBigOctoModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetDungeon0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetBigOctoModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal1ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon0ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetDungeon0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetBigOctoModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetMeadowBirdsEyeModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetMeadowBirdsEyeModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetMeadowBirdsEyeModeTargetData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetMeadowBirdsEyeModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetMeadowBirdsEyeModeClimbData), +}; + +CameraMode sCamSetMeadowUnusedModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetMeadowUnusedModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetMeadowUnusedModeTargetData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetMeadowUnusedModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetMeadowUnusedModeClimbData), +}; + +CameraMode sCamSetFireBirdsEyeModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetFireBirdsEyeModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetFireBirdsEyeModeTargetData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetFireBirdsEyeModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetFireBirdsEyeModeClimbData), +}; + +CameraMode sCamSetTurnAroundModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP4, sSetTurnAroundModeNormalData), +}; + +CameraMode sCamSetPivotVerticalModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC0, sSetPivotVerticalModeNormalData), +}; + +CameraMode sCamSetNorm2Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal2and4ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetFishingModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetFishingModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetFishingModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetFishingModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetFishingModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetFishingModeFollowTargetData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetFishingModeFirstPersonData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetFishingModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetFishingModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetFishingModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetFishingModeFreeFallData), +}; + +CameraMode sCamSetCsCModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ9, sSetCsCModeNormalData), +}; + +CameraMode sCamSetJabuTentacleModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetJabuTentacleModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetJabuTentacleModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetDungeon2Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon2ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon2ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetDungeon0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetDungeon2ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon2ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal1ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetDungeon2ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon2ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon2ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetDungeon2ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetDungeon2ModeFreeFallData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDungeon2ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetDungeon2ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetDirectedYawModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetDirectedYawModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetDirectedYawModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetDirectedYawModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal0ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraMode sCamSetPivotFromSideModes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD4, sSetPivotInFrontAndFromSideModeNormalData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_FIXD4, sSetPivotInFrontAndFromSideModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sSetNormal0ModeTalkData), + { CAM_FUNC_NONE, 0, NULL }, + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + { CAM_FUNC_NONE, 0, NULL }, + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), +}; + +CameraMode sCamSetNormal4Modes[] = { + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal2and4ModeNormalData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModeTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowTargetData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP3, sNormal4ModeTalkData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT1, sSetNormal1ModeBattleData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeFirstPersonData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBowArrowZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SPEC5, sSetNormal0ModeHookshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeBoomerangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_SUBJ3, sSetNormal0ModeSlingshotData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP2, sSetNormal0ModeClimbZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_UNIQ1, sSetNormal0ModeHangZData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_JUMP1, sSetNormal0ModeJumpData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_BATT4, sSetNormal0ModeChargeData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_NORM1, sSetNormal0ModeStillData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_PARA1, sSetNormal0ModePushPullData), + CAM_SETTING_MODE_ENTRY(CAM_FUNC_KEEP1, sSetNormal0ModeFollowBoomerangData), +}; + +CameraSetting sCameraSettings[] = { + { { 0x00000000 }, NULL }, + { { 0x051FFFFF }, sCamSetNormal0Modes }, + { { 0x051FFFFF }, sCamSetNormal1Modes }, + { { 0x051FFFFF }, sCamSetDungeon0Modes }, + { { 0x051FFFFF }, sCamSetDungeon1Modes }, + { { 0x050FF7FF }, sCamSetNormal3Modes }, + { { 0x8500018F }, sCamSetHorseModes }, + { { 0x051FFFFF }, sCamSetBossGohmaModes }, + { { 0x051FFFFF }, sCamSetBossDodongoModes }, + { { 0x051FFFFF }, sCamSetBossBarinadeModes }, + { { 0x051FFFFF }, sCamSetBossPhantomGanonModes }, + { { 0x051FFFFF }, sCamSetBossVolvagiaModes }, + { { 0x051FFFFF }, sCamSetBossBongoModes }, + { { 0x051FFFFF }, sCamSetBossMorphaModes }, + { { 0x051FFFFF }, sCamSetBossTwinrovaPlatformModes }, + { { 0x051FFFFF }, sCamSetBossTwinrovaFloorModes }, + { { 0x051FFFFF }, sCamSetBossGanondorfModes }, + { { 0x051FFFFF }, sCamSetBossGanonModes }, + { { 0x851FFFFF }, sCamSetTowerClimbModes }, + { { 0x851FFFFF }, sCamSetTowerUnusedModes }, + { { 0x8500000D }, sCamSetMarketBalconyModes }, + { { 0x85000001 }, sCamSetChuBowlingModes }, + { { 0x85000001 }, sCamSetPivotCrawlspaceModes }, + { { 0x85000001 }, sCamSetPivotShopBrowsingModes }, + { { 0x851E1FFF }, sCamSetPivotInFrontModes }, + { { 0x8C00000D }, sCamSetPreRendFixedModes }, + { { 0x8C00000D }, sCamSetPreRendPivotModes }, + { { 0x8C000001 }, sCamSetPreRendSideScrollModes }, + { { 0xC5000001 }, sCamSetDoor0Modes }, + { { 0xC5000003 }, sCamSetDoorCModes }, + { { 0xC5000001 }, sCamSetCrawlspaceModes }, + { { 0xC5000001 }, sCamSetStart0Modes }, + { { 0xC5000001 }, sCamSetStart1Modes }, + { { 0x05000001 }, sCamSetFree0Modes }, + { { 0x05000001 }, sCamSetFree1Modes }, + { { 0x85000001 }, sCamSetPivotCornerModes }, + { { 0x05000003 }, sCamSetPivotDivingModes }, + { { 0xCE000001 }, sCamSetCs0Modes }, + { { 0x4E000001 }, sCamSetCsTwistedHallwayModes }, + { { 0x05000009 }, sCamSetForestBirdsEyeModes }, + { { 0x45000001 }, sCamSetSlowChestCsModes }, + { { 0x45000001 }, sCamSetItemUnusedModes }, + { { 0x45000001 }, sCamSetCs3Modes }, + { { 0x45000001 }, sCamSetCsAttentionModes }, + { { 0x451FFFFF }, sCamSetBeanGenericModes }, + { { 0x451FFFFF }, sCamSetBeanLostWoodsModes }, + { { 0xC5000001 }, sCamSetSceneUnusedModes }, + { { 0x45000001 }, sCamSetSceneTransitionModes }, + { { 0x05000001 }, sCamSetFirePlatformModes }, + { { 0x45000001 }, sCamSetFireStaircaseModes }, + { { 0x45000001 }, sCamSetForestUnusedModes }, + { { 0x45000001 }, sCamSetForestDefeatPoeModes }, + { { 0x451FFFFF }, sCamSetBigOctoModes }, + { { 0x05000033 }, sCamSetMeadowBirdsEyeModes }, + { { 0x05000033 }, sCamSetMeadowUnusedModes }, + { { 0x05000033 }, sCamSetFireBirdsEyeModes }, + { { 0x4A000001 }, sCamSetTurnAroundModes }, + { { 0x05000001 }, sCamSetPivotVerticalModes }, + { { 0x051FFFFF }, sCamSetNorm2Modes }, + { { 0x0501E05F }, sCamSetFishingModes }, + { { 0x45000001 }, sCamSetCsCModes }, + { { 0x051FFFFF }, sCamSetJabuTentacleModes }, + { { 0x051FFFFF }, sCamSetDungeon2Modes }, + { { 0x051FFFFF }, sCamSetDirectedYawModes }, + { { 0xC5000ECD }, sCamSetPivotFromSideModes }, + { { 0x051FFFFF }, sCamSetNormal4Modes }, +}; + +s32 Camera_Normal0(Camera* camera); +s32 Camera_Normal1(Camera* camera); +s32 Camera_Normal2(Camera* camera); +s32 Camera_Normal3(Camera* camera); +s32 Camera_Normal4(Camera* camera); +s32 Camera_Parallel0(Camera* camera); +s32 Camera_Parallel1(Camera* camera); +s32 Camera_Parallel2(Camera* camera); +s32 Camera_Parallel3(Camera* camera); +s32 Camera_Parallel4(Camera* camera); +s32 Camera_KeepOn0(Camera* camera); +s32 Camera_KeepOn1(Camera* camera); +s32 Camera_KeepOn2(Camera* camera); +s32 Camera_KeepOn3(Camera* camera); +s32 Camera_KeepOn4(Camera* camera); +s32 Camera_Subj0(Camera* camera); +s32 Camera_Subj1(Camera* camera); +s32 Camera_Subj2(Camera* camera); +s32 Camera_Subj3(Camera* camera); +s32 Camera_Subj4(Camera* camera); +s32 Camera_Jump0(Camera* camera); +s32 Camera_Jump1(Camera* camera); +s32 Camera_Jump2(Camera* camera); +s32 Camera_Jump3(Camera* camera); +s32 Camera_Jump4(Camera* camera); +s32 Camera_Battle0(Camera* camera); +s32 Camera_Battle1(Camera* camera); +s32 Camera_Battle2(Camera* camera); +s32 Camera_Battle3(Camera* camera); +s32 Camera_Battle4(Camera* camera); +s32 Camera_Fixed0(Camera* camera); +s32 Camera_Fixed1(Camera* camera); +s32 Camera_Fixed2(Camera* camera); +s32 Camera_Fixed3(Camera* camera); +s32 Camera_Fixed4(Camera* camera); +s32 Camera_Data0(Camera* camera); +s32 Camera_Data1(Camera* camera); +s32 Camera_Data2(Camera* camera); +s32 Camera_Data3(Camera* camera); +s32 Camera_Data4(Camera* camera); +s32 Camera_Unique0(Camera* camera); +s32 Camera_Unique1(Camera* camera); +s32 Camera_Unique2(Camera* camera); +s32 Camera_Unique3(Camera* camera); +s32 Camera_Unique4(Camera* camera); +s32 Camera_Unique5(Camera* camera); +s32 Camera_Unique6(Camera* camera); +s32 Camera_Unique7(Camera* camera); +s32 Camera_Unique8(Camera* camera); +s32 Camera_Unique9(Camera* camera); +s32 Camera_Demo0(Camera* camera); +s32 Camera_Demo1(Camera* camera); +s32 Camera_Demo2(Camera* camera); +s32 Camera_Demo3(Camera* camera); +s32 Camera_Demo4(Camera* camera); +s32 Camera_Demo5(Camera* camera); +s32 Camera_Demo6(Camera* camera); +s32 Camera_Demo7(Camera* camera); +s32 Camera_Demo8(Camera* camera); +s32 Camera_Demo9(Camera* camera); +s32 Camera_Special0(Camera* camera); +s32 Camera_Special1(Camera* camera); +s32 Camera_Special2(Camera* camera); +s32 Camera_Special3(Camera* camera); +s32 Camera_Special4(Camera* camera); +s32 Camera_Special5(Camera* camera); +s32 Camera_Special6(Camera* camera); +s32 Camera_Special7(Camera* camera); +s32 Camera_Special8(Camera* camera); +s32 Camera_Special9(Camera* camera); + +s32 (*sCameraFunctions[])(Camera*) = { + NULL, + Camera_Normal0, + Camera_Normal1, + Camera_Normal2, + Camera_Normal3, + Camera_Normal4, + Camera_Parallel0, + Camera_Parallel1, + Camera_Parallel2, + Camera_Parallel3, + Camera_Parallel4, + Camera_KeepOn0, + Camera_KeepOn1, + Camera_KeepOn2, + Camera_KeepOn3, + Camera_KeepOn4, + Camera_Subj0, + Camera_Subj1, + Camera_Subj2, + Camera_Subj3, + Camera_Subj4, + Camera_Jump0, + Camera_Jump1, + Camera_Jump2, + Camera_Jump3, + Camera_Jump4, + Camera_Battle0, + Camera_Battle1, + Camera_Battle2, + Camera_Battle3, + Camera_Battle4, + Camera_Fixed0, + Camera_Fixed1, + Camera_Fixed2, + Camera_Fixed3, + Camera_Fixed4, + Camera_Data0, + Camera_Data1, + Camera_Data2, + Camera_Data3, + Camera_Data4, + Camera_Unique0, + Camera_Unique1, + Camera_Unique2, + Camera_Unique3, + Camera_Unique4, + Camera_Unique5, + Camera_Unique6, + Camera_Unique7, + Camera_Unique8, + Camera_Unique9, + Camera_Demo0, + Camera_Demo1, + Camera_Demo2, + Camera_Demo3, + Camera_Demo4, + Camera_Demo5, + Camera_Demo6, + Camera_Demo7, + Camera_Demo8, + Camera_Demo9, + Camera_Special0, + Camera_Special1, + Camera_Special2, + Camera_Special3, + Camera_Special4, + Camera_Special5, + Camera_Special6, + Camera_Special7, + Camera_Special8, + Camera_Special9, +}; + +s32 sInitRegs = 1; + +s32 gDbgCamEnabled = 0; +s32 sDbgModeIdx = -1; +s16 sNextUID = 0; + +s32 sCameraInterfaceFlags = 1; + +s32 sCameraInterfaceAlpha = 0x02; +s32 sCameraShrinkWindowVal = 0x20; +s32 D_8011D3AC = -1; + +s16 D_8011D3B0[] = { + 0x0AAA, 0xF556, 0x1555, 0xEAAB, 0x2AAA, 0xD556, 0x3FFF, 0xC001, 0x5555, 0xAAAB, 0x6AAA, 0x9556, 0x7FFF, 0x0000, +}; + +s16 D_8011D3CC[] = { + 0x0000, 0x02C6, 0x058C, 0x0000, 0x0000, 0xFD3A, 0x0000, 0x0852, 0x0000, 0x0000, 0x0B18, 0x02C6, 0xFA74, 0x0000, +}; + +s32 sUpdateCameraDirection = 0; +s32 D_8011D3EC = 0; +s32 D_8011D3F0 = 0; + +s32 sDemo5PrevAction12Frame = -16; + +char sCameraFunctionNames[][8] = { + "NONE ", "NORM0()", "NORM1()", "NORM2()", "NORM3()", "NORM4()", "PARA0()", "PARA1()", "PARA2()", "PARA3()", + "PARA4()", "KEEP0()", "KEEP1()", "KEEP2()", "KEEP3()", "KEEP4()", "SUBJ0()", "SUBJ1()", "SUBJ2()", "SUBJ3()", + "SUBJ4()", "JUMP0()", "JUMP1()", "JUMP2()", "JUMP3()", "JUMP4()", "BATT0()", "BATT1()", "BATT2()", "BATT3()", + "BATT4()", "FIXD0()", "FIXD1()", "FIXD2()", "FIXD3()", "FIXD4()", "DATA0()", "DATA1()", "DATA2()", "DATA3()", + "DATA4()", "UNIQ0()", "UNIQ1()", "UNIQ2()", "UNIQ3()", "UNIQ4()", "UNIQ5()", "UNIQ6()", "UNIQ7()", "UNIQ8()", + "UNIQ9()", "DEMO0()", "DEMO1()", "DEMO2()", "DEMO3()", "DEMO4()", "DEMO5()", "DEMO6()", "DEMO7()", "DEMO8()", + "DEMO9()", "SPEC0()", "SPEC1()", "SPEC2()", "SPEC3()", "SPEC4()", "SPEC5()", "SPEC6()", "SPEC7()", "SPEC8()", + "SPEC9()", "", "", "", "", "", +}; + +VecSph D_8011D658[] = { + { 50.0f, 0xEE3A, 0xD558 }, + { 75.0f, 0x0000, 0x8008 }, + { 80.0f, 0xEE3A, 0x8008 }, + { 15.0f, 0xEE3A, 0x8008 }, +}; + +Vec3f D_8011D678[] = { + { 0.0f, 40.0f, 20.0f }, + { 0.0f, 40.0f, 0.0f }, + { 0.0f, 3.0f, -3.0f }, + { 0.0f, 3.0f, -3.0 }, +}; + +/******************************************************* + * OnePoint initalization values for Demo5 + ********************************************************/ +s32 sDemo5PrevSfxFrame = -200; + +// target is player, far from eye +OnePointCsFull D_8011D6AC[] = { + { // initflags & 0x00FF (at): 2, atTarget is view lookAt + atInit + // initFlags & 0xFF00 (eye): none + // action: 15, copy at, eye, roll, fov to camera + // result: eye remains in the same locaiton, at is View's lookAt + 0x8F, + 0xFF, + 0x0002, + 0x0001, + 0x0000, + 60.0f, + 1.0f, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f } }, + { // initFlags & 0x00FF (at): 3, atTarget is camera's current at + atInit + // initFlags & 0xFF00 (eye): 3, eyeTarget is the camera's current eye + eyeInit + // action: interplate eye and at. + // result: eye and at's y interpolate to become +20 from their current location. + 0x81, + 0xFF, + 0x0303, + 0x0013, + 0x0000, + 45.0f, + 1.0f, + { 0.0f, 20.0f, 0.0f }, + { 0.0f, 20.0f, 0.0f } }, + { // initFlags & 0x00FF (at): 0 none + // initFlags & 0xFF00 (eye): 0 none + // action: 18, copy this camera to default camera. + 0x12, + 0xFF, + 0x0000, + 0x0001, + 0x0000, + 60.0f, + 1.0f, + { -1.0f, -1.0f, -1.0f }, + { -1.0f, -1.0f, -1.0f } }, +}; + +// target is player close to current eye +OnePointCsFull D_8011D724[] = { + { 0x8F, 0xFF, 0x2424, 0x0001, 0x0000, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, -20.0f } }, + { 0x81, 0xFF, 0x2121, 0x0013, 0x0000, 50.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 60.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// target is close to player +OnePointCsFull D_8011D79C[] = { + { 0xCF, 0xFF, 0x0002, 0x0001, 0x0000, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0xC1, 0xFF, 0x0303, 0x0013, 0x0000, 45.0f, 1.0f, { 0.0f, -20.0f, 0.0f }, { 0.0f, -10.0f, 5.0f } }, + { + 0xC1, + 0xFF, + 0x0303, + 0x0009, + 0x0000, + 60.0f, + 1.0f, + { 0.0f, 10.0f, 0.0f }, + { 0.0f, 10.0f, 0.0f }, + }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// target is within 300 units of eye, and player is within 30 units of eye +OnePointCsFull D_8011D83C[] = { + { 0x83, 0xFF, 0x2141, 0x0014, 0x0000, 45.0f, 0.2f, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 10.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// target is within 700 units of eye, angle between player/eye and target/eye is less than +// 76.9 degrees. The x/y coordinates of the target on screen is between (21, 41) and (300, 200), +// and the player is farther than 30 units of the eye +OnePointCsFull D_8011D88C[] = { + { 0x81, 0xFF, 0x0303, 0x0014, 0x0000, 45.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// same as above, but the target is NOT within the screen area. +OnePointCsFull D_8011D8DC[] = { + { 0x8F, 0xFF, 0x0404, 0x0014, 0x0001, 50.0f, 1.0f, { 0.0f, 5.0f, 10.0f }, { 0.0f, 10.0f, -80.0f } }, + { 0x82, 0xFF, 0x2121, 0x0005, 0x0000, 60.0f, 1.0f, { 0.0f, 5.0f, 0.0f }, { 5.0f, 5.0f, -200.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// target is a door. +OnePointCsFull D_8011D954[] = { + { 0x0F, 0xFF, 0xC1C1, 0x0014, 0x0000, 60.0f, 1.0f, { 0.0f, 0.0f, 50.0f }, { 0.0f, 0.0f, 250.0f } }, + { 0x83, 0xFF, 0x05B1, 0x0005, 0x0000, 60.0f, 0.1f, { 0.0f, 10.0f, 50.0f }, { 0.0f, 10.0f, 100.0f } }, + { 0x82, 0xFF, 0x2121, 0x0005, 0x0002, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 20.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +// otherwise +OnePointCsFull D_8011D9F4[] = { + { 0x8F, 0xFF, 0x0504, 0x0014, 0x0002, 60.0f, 1.0f, { 0.0f, 5.0f, 50.0f }, { 0.0f, 20.0f, 300.0f } }, + { 0x82, 0xFF, 0x2121, 0x0005, 0x0002, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 20.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 0x0001, 0x0000, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +Vec3f D_8011DA6C[] = { + { 3050.0f, 700.0f, 0.0f }, { 1755.0f, 3415.0f, -380.0f }, { -3120.0f, 3160.0f, 245.0f }, { 0.0f, -10.0f, 240.0f } +}; + +Vec3f D_8011DA9C[] = { + { 3160.0f, 2150.0f, 0.0f }, + { 1515.0f, 4130.0f, -835.0f }, + { -3040.0f, 4135.0f, 230.0f }, + { -50.0f, 600.0f, -75.0f }, +}; + +f32 D_8011DACC[] = { 1570.0f, 3680.0f, 3700.0f, 395.0f }; + +f32 D_8011DADC[] = { 320.0f, 320.0f, 320.0f, 0.0f }; + +s16 D_8011DAEC[] = { -2000, -1000, 0, 0, 0, 0, 0, 0 }; + +s16 D_8011DAFC[] = { + CAM_SET_NORMAL0, CAM_SET_NORMAL1, CAM_SET_NORMAL2, CAM_SET_DUNGEON0, CAM_SET_DUNGEON1, CAM_SET_DUNGEON2, +}; + +GlobalContext* D_8015BD7C; +DbCamera D_8015BD80; +CollisionPoly* playerFloorPoly; diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index d0145fb43..f6bb7d572 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -2105,7 +2105,7 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) { } void Cutscene_SetSegment(GlobalContext* globalCtx, void* segment) { - if (SEGMENT_NUMBER(segment) != 0) + if (SEGMENT_NUMBER(segment) != 0) { globalCtx->csCtx.segment = SEGMENTED_TO_VIRTUAL(segment); } else { diff --git a/soh/src/code/z_eff_blure.c b/soh/src/code/z_eff_blure.c index e08f8f337..f3a1e6122 100644 --- a/soh/src/code/z_eff_blure.c +++ b/soh/src/code/z_eff_blure.c @@ -1,6 +1,8 @@ #include "global.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + void EffectBlure_AddVertex(EffectBlure* this, Vec3f* p1, Vec3f* p2) { EffectBlureElement* elem; s32 numElements; @@ -946,6 +948,7 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) { s32 j; s32 phi_t2; + FrameInterpolation_RecordOpenChild(this, 0); OPEN_DISPS(gfxCtx, "../z_eff_blure.c", 1596); gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); @@ -1059,4 +1062,5 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) { } CLOSE_DISPS(gfxCtx, "../z_eff_blure.c", 1823); + FrameInterpolation_RecordCloseChild(); } diff --git a/soh/src/code/z_eff_shield_particle.c b/soh/src/code/z_eff_shield_particle.c index fad499286..73134a654 100644 --- a/soh/src/code/z_eff_shield_particle.c +++ b/soh/src/code/z_eff_shield_particle.c @@ -2,6 +2,8 @@ #include "vt.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + static Vtx sVertices[5] = { VTX(-32, -32, 0, 0, 1024, 0xFF, 0xFF, 0xFF, 0xFF), VTX(32, 32, 0, 1024, 0, 0xFF, 0xFF, 0xFF, 0xFF), @@ -154,6 +156,7 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) { Color_RGBA8 primColor; Color_RGBA8 envColor; + FrameInterpolation_RecordOpenChild(this, 0); OPEN_DISPS(gfxCtx, "../z_eff_shield_particle.c", 272); if (this != NULL) { @@ -213,4 +216,5 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) { } CLOSE_DISPS(gfxCtx, "../z_eff_shield_particle.c", 359); + FrameInterpolation_RecordCloseChild(); } diff --git a/soh/src/code/z_eff_spark.c b/soh/src/code/z_eff_spark.c index cfe8f628f..b76968371 100644 --- a/soh/src/code/z_eff_spark.c +++ b/soh/src/code/z_eff_spark.c @@ -1,6 +1,8 @@ #include "global.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + // original name: "spark" void EffectSpark_Init(void* thisx, void* initParamsx) { EffectSpark* this = (EffectSpark*)thisx; @@ -152,6 +154,7 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) { u8 sp1C4; f32 ratio; + FrameInterpolation_RecordOpenChild(this, 0); OPEN_DISPS(gfxCtx, "../z_eff_spark.c", 293); if (this != NULL) { @@ -274,4 +277,5 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) { end: CLOSE_DISPS(gfxCtx, "../z_eff_spark.c", 498); + FrameInterpolation_RecordCloseChild(); } diff --git a/soh/src/code/z_effect_soft_sprite.c b/soh/src/code/z_effect_soft_sprite.c index aa0b922fe..2548966cc 100644 --- a/soh/src/code/z_effect_soft_sprite.c +++ b/soh/src/code/z_effect_soft_sprite.c @@ -1,6 +1,8 @@ #include "global.h" #include "vt.h" +#include "soh/frame_interpolation.h" + EffectSsInfo sEffectSsInfo = { 0 }; // "EffectSS2Info" void EffectSs_InitInfo(GlobalContext* globalCtx, s32 tableSize) { @@ -233,6 +235,7 @@ void EffectSs_Spawn(GlobalContext* globalCtx, s32 type, s32 priority, void* init sEffectSsInfo.table[index].type = type; sEffectSsInfo.table[index].priority = priority; + sEffectSsInfo.table[index].epoch++; if (initInfo->init(globalCtx, index, &sEffectSsInfo.table[index], initParams) == 0) { osSyncPrintf(VT_FGCOL(GREEN)); @@ -284,7 +287,9 @@ void EffectSs_Draw(GlobalContext* globalCtx, s32 index) { EffectSs* effectSs = &sEffectSsInfo.table[index]; if (effectSs->draw != NULL) { + FrameInterpolation_RecordOpenChild(effectSs, effectSs->epoch); effectSs->draw(globalCtx, index, effectSs); + FrameInterpolation_RecordCloseChild(); } } diff --git a/soh/src/code/z_fbdemo_circle.c b/soh/src/code/z_fbdemo_circle.c index a6a46a0e4..5c8f688fa 100644 --- a/soh/src/code/z_fbdemo_circle.c +++ b/soh/src/code/z_fbdemo_circle.c @@ -19,9 +19,9 @@ Gfx __sCircleDList[] = { G_AC_NONE | G_ZS_PIXEL | G_RM_XLU_SURF | G_RM_XLU_SURF2), // 4 gsDPSetCombineMode(G_CC_BLENDPEDECALA, G_CC_BLENDPEDECALA), // 5 gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), // 6 - gsDPLoadTextureBlock(0xF8000000, G_IM_FMT_I, G_IM_SIZ_8b, 16, 64, 0, G_TX_NOMIRROR | G_TX_WRAP, // 7 + gsDPLoadTextureBlock(SEG_ADDR(8, 0), G_IM_FMT_I, G_IM_SIZ_8b, 16, 64, 0, G_TX_NOMIRROR | G_TX_WRAP, // 7 G_TX_NOMIRROR | G_TX_CLAMP, 4, 6, G_TX_NOLOD, G_TX_NOLOD), - gsSPDisplayList(0xF9000000), // 8 + gsSPDisplayList(SEG_ADDR(9, 0)), // 8 gsSPVertex(sCircleWipeVtx, 32, 0), // 9 gsSP2Triangles(0, 1, 2, 0, 1, 3, 4, 0), // 10 gsSP2Triangles(3, 5, 6, 0, 5, 7, 8, 0), // 11 diff --git a/soh/src/code/z_lifemeter.c b/soh/src/code/z_lifemeter.c index 7de043dc5..b89d57831 100644 --- a/soh/src/code/z_lifemeter.c +++ b/soh/src/code/z_lifemeter.c @@ -111,6 +111,9 @@ static s16 sHeartsDDEnvFactors[3][3] = { }; // Current colors for the double defense hearts +s16 HeartInner[3] = {HEARTS_PRIM_R,HEARTS_PRIM_G,HEARTS_PRIM_B}; +s16 HeartDDOutline[3] = {HEARTS_DD_PRIM_R,HEARTS_DD_PRIM_G,HEARTS_DD_PRIM_B}; +s16 HeartDDInner[3] = {HEARTS_DD_ENV_R,HEARTS_DD_ENV_G,HEARTS_DD_ENV_B}; s16 sBeatingHeartsDDPrim[3]; s16 sBeatingHeartsDDEnv[3]; s16 sHeartsDDPrim[2][3]; @@ -118,47 +121,47 @@ s16 sHeartsDDEnv[2][3]; void HealthMeter_Init(GlobalContext* globalCtx) { InterfaceContext* interfaceCtx = &globalCtx->interfaceCtx; - + if (CVar_GetS32("gHudColors", 1) == 2) { + HeartInner[0] = CVar_GetS32("gCCHeartsPrimR", 90); + HeartInner[1] = CVar_GetS32("gCCHeartsPrimG", 90); + HeartInner[2] = CVar_GetS32("gCCHeartsPrimB", 90); + HeartDDOutline[0] = CVar_GetS32("gDDCCHeartsPrimR", 90); + HeartDDOutline[1] = CVar_GetS32("gDDCCHeartsPrimG", 90); + HeartDDOutline[2] = CVar_GetS32("gDDCCHeartsPrimB", 90); + } + interfaceCtx->unk_228 = 0x140; interfaceCtx->unk_226 = gSaveContext.health; interfaceCtx->unk_22A = interfaceCtx->unk_1FE = 0; interfaceCtx->unk_22C = interfaceCtx->unk_200 = 0; - interfaceCtx->heartsPrimR[0] = HEARTS_PRIM_R; - interfaceCtx->heartsPrimG[0] = HEARTS_PRIM_G; - interfaceCtx->heartsPrimB[0] = HEARTS_PRIM_B; + interfaceCtx->heartsPrimR[0] = HeartInner[0]; + interfaceCtx->heartsPrimG[0] = HeartInner[1]; + interfaceCtx->heartsPrimB[0] = HeartInner[2]; interfaceCtx->heartsEnvR[0] = HEARTS_ENV_R; interfaceCtx->heartsEnvG[0] = HEARTS_ENV_G; interfaceCtx->heartsEnvB[0] = HEARTS_ENV_B; - interfaceCtx->heartsPrimR[1] = HEARTS_PRIM_R; - interfaceCtx->heartsPrimG[1] = HEARTS_PRIM_G; - interfaceCtx->heartsPrimB[1] = HEARTS_PRIM_B; + interfaceCtx->heartsPrimR[1] = HeartInner[0]; + interfaceCtx->heartsPrimG[1] = HeartInner[1]; + interfaceCtx->heartsPrimB[1] = HeartInner[2]; interfaceCtx->heartsEnvR[1] = HEARTS_ENV_R; interfaceCtx->heartsEnvG[1] = HEARTS_ENV_G; interfaceCtx->heartsEnvB[1] = HEARTS_ENV_B; - sHeartsDDPrim[0][0] = sHeartsDDPrim[1][0] = HEARTS_DD_PRIM_R; - sHeartsDDPrim[0][1] = sHeartsDDPrim[1][1] = HEARTS_DD_PRIM_G; - sHeartsDDPrim[0][2] = sHeartsDDPrim[1][2] = HEARTS_DD_PRIM_B; + sHeartsDDPrim[0][0] = sHeartsDDPrim[1][0] = HeartDDOutline[0]; + sHeartsDDPrim[0][1] = sHeartsDDPrim[1][1] = HeartDDOutline[1]; + sHeartsDDPrim[0][2] = sHeartsDDPrim[1][2] = HeartDDOutline[2]; - sHeartsDDEnv[0][0] = sHeartsDDEnv[1][0] = HEARTS_DD_ENV_R; - sHeartsDDEnv[0][1] = sHeartsDDEnv[1][1] = HEARTS_DD_ENV_G; - sHeartsDDEnv[0][2] = sHeartsDDEnv[1][2] = HEARTS_DD_ENV_B; + sHeartsDDPrim[2][0] = HeartInner[0]; + sHeartsDDPrim[2][1] = HeartInner[1]; + sHeartsDDPrim[2][2] = HeartInner[2]; - if (CVar_GetS32("gHudColors", 1) == 2) {//Load custom colors ! - interfaceCtx->heartsPrimR[0] = CVar_GetS32("gCCHeartsPrimR", 220); - interfaceCtx->heartsPrimG[0] = CVar_GetS32("gCCHeartsPrimG", 10); - interfaceCtx->heartsPrimB[0] = CVar_GetS32("gCCHeartsPrimB", 10); - interfaceCtx->heartsPrimR[1] = CVar_GetS32("gCCHeartsPrimR", 220); - interfaceCtx->heartsPrimG[1] = CVar_GetS32("gCCHeartsPrimG", 10); - interfaceCtx->heartsPrimB[1] = CVar_GetS32("gCCHeartsPrimB", 10); - sHeartsDDPrim[0][0] = sHeartsDDPrim[1][0] = CVar_GetS32("gDDCCHeartsPrimR", 220); - sHeartsDDPrim[0][1] = sHeartsDDPrim[1][1] = CVar_GetS32("gDDCCHeartsPrimG", 10); - sHeartsDDPrim[0][2] = sHeartsDDPrim[1][2] = CVar_GetS32("gDDCCHeartsPrimB", 10); - } + sHeartsDDEnv[0][0] = sHeartsDDEnv[1][0] = HeartDDInner[0]; + sHeartsDDEnv[0][1] = sHeartsDDEnv[1][1] = HeartDDInner[1]; + sHeartsDDEnv[0][2] = sHeartsDDEnv[1][2] = HeartDDInner[2]; } void HealthMeter_Update(GlobalContext* globalCtx) { @@ -183,7 +186,21 @@ void HealthMeter_Update(GlobalContext* globalCtx) { Bottom_LM_Margin = 0; } - if (interfaceCtx) {} + if (CVar_GetS32("gHudColors", 1) == 2) { + HeartInner[0] = CVar_GetS32("gCCHeartsPrimR", sHeartsPrimColors[0][0]); + HeartInner[1] = CVar_GetS32("gCCHeartsPrimG", sHeartsPrimColors[0][1]); + HeartInner[2] = CVar_GetS32("gCCHeartsPrimB", sHeartsPrimColors[0][2]); + HeartDDOutline[0] = CVar_GetS32("gDDCCHeartsPrimR", sHeartsDDPrim[0][0]); + HeartDDOutline[1] = CVar_GetS32("gDDCCHeartsPrimG", sHeartsDDPrim[0][1]); + HeartDDOutline[2] = CVar_GetS32("gDDCCHeartsPrimB", sHeartsDDPrim[0][2]); + } else { + HeartInner[0] = sHeartsPrimColors[0][0]; + HeartInner[1] = sHeartsPrimColors[0][1]; + HeartInner[2] = sHeartsPrimColors[0][2]; + HeartDDOutline[0] = sHeartsDDPrim[0][0]; + HeartDDOutline[1] = sHeartsDDPrim[0][1]; + HeartDDOutline[2] = sHeartsDDPrim[0][2]; + } if (interfaceCtx->unk_200 != 0) { interfaceCtx->unk_1FE--; @@ -200,96 +217,117 @@ void HealthMeter_Update(GlobalContext* globalCtx) { } ddFactor = factor; - - if (CVar_GetS32("gHudColors", 1) == 2) {//Required for runtime colors change. - interfaceCtx->heartsPrimR[0] = CVar_GetS32("gCCHeartsPrimR", 220); - interfaceCtx->heartsPrimG[0] = CVar_GetS32("gCCHeartsPrimG", 10); - interfaceCtx->heartsPrimB[0] = CVar_GetS32("gCCHeartsPrimB", 10); - } else { - interfaceCtx->heartsPrimR[0] = HEARTS_PRIM_R; - interfaceCtx->heartsPrimG[0] = HEARTS_PRIM_G; - interfaceCtx->heartsPrimB[0] = HEARTS_PRIM_B; - } - - interfaceCtx->heartsPrimR[0] = HEARTS_PRIM_R; - interfaceCtx->heartsPrimG[0] = HEARTS_PRIM_G; - interfaceCtx->heartsPrimB[0] = HEARTS_PRIM_B; + + interfaceCtx->heartsPrimR[0] = HeartInner[0]; + interfaceCtx->heartsPrimG[0] = HeartInner[1]; + interfaceCtx->heartsPrimB[0] = HeartInner[2]; interfaceCtx->heartsEnvR[0] = HEARTS_ENV_R; interfaceCtx->heartsEnvG[0] = HEARTS_ENV_G; interfaceCtx->heartsEnvB[0] = HEARTS_ENV_B; - interfaceCtx->heartsPrimR[1] = sHeartsPrimColors[type][0]; - interfaceCtx->heartsPrimG[1] = sHeartsPrimColors[type][1]; - interfaceCtx->heartsPrimB[1] = sHeartsPrimColors[type][2]; + if (CVar_GetS32("gHudColors", 1) == 2) { + interfaceCtx->heartsPrimR[1] = HeartInner[0]; + interfaceCtx->heartsPrimG[1] = HeartInner[1]; + interfaceCtx->heartsPrimB[1] = HeartInner[2]; + } else { + interfaceCtx->heartsPrimR[1] = sHeartsPrimColors[type][0]; + interfaceCtx->heartsPrimG[1] = sHeartsPrimColors[type][1]; + interfaceCtx->heartsPrimB[1] = sHeartsPrimColors[type][2]; + } interfaceCtx->heartsEnvR[1] = sHeartsEnvColors[type][0]; interfaceCtx->heartsEnvG[1] = sHeartsEnvColors[type][1]; interfaceCtx->heartsEnvB[1] = sHeartsEnvColors[type][2]; - if (CVar_GetS32("gHudColors", 1) == 2) {//Required for runtime colors change. (that when the heart grow and shrink color) - interfaceCtx->beatingHeartPrim[0] = (u8)(rFactor + CVar_GetS32("gCCHeartsPrimR", 220)) & 0xFF; - interfaceCtx->beatingHeartPrim[1] = (u8)(gFactor + CVar_GetS32("gCCHeartsPrimG", 10)) & 0xFF; - interfaceCtx->beatingHeartPrim[2] = (u8)(bFactor + CVar_GetS32("gCCHeartsPrimB", 10)) & 0xFF; - } else { - interfaceCtx->beatingHeartPrim[0] = (u8)(rFactor + HEARTS_PRIM_R) & 0xFF; - interfaceCtx->beatingHeartPrim[1] = (u8)(gFactor + HEARTS_PRIM_G) & 0xFF; - interfaceCtx->beatingHeartPrim[2] = (u8)(bFactor + HEARTS_PRIM_B) & 0xFF; - } + rFactor = sHeartsPrimFactors[0][0] * factor; + gFactor = sHeartsPrimFactors[0][1] * factor; + bFactor = sHeartsPrimFactors[0][2] * factor; + + interfaceCtx->beatingHeartPrim[0] = (u8)(rFactor + HeartInner[0]) & 0xFF; + interfaceCtx->beatingHeartPrim[1] = (u8)(gFactor + HeartInner[1]) & 0xFF; + interfaceCtx->beatingHeartPrim[2] = (u8)(bFactor + HeartInner[2]) & 0xFF; rFactor = sHeartsEnvFactors[0][0] * factor; gFactor = sHeartsEnvFactors[0][1] * factor; bFactor = sHeartsEnvFactors[0][2] * factor; - ddType = type; - interfaceCtx->beatingHeartEnv[0] = (u8)(rFactor + HEARTS_ENV_R) & 0xFF; interfaceCtx->beatingHeartEnv[1] = (u8)(gFactor + HEARTS_ENV_G) & 0xFF; interfaceCtx->beatingHeartEnv[2] = (u8)(bFactor + HEARTS_ENV_B) & 0xFF; - if (CVar_GetS32("gHudColors", 1) == 2) {//Same as abose (DD stand for Double Defense) - sHeartsDDPrim[0][0] = CVar_GetS32("gDDCCHeartsPrimR", 220); - sHeartsDDPrim[0][1] = CVar_GetS32("gDDCCHeartsPrimG", 0); - sHeartsDDPrim[0][2] = CVar_GetS32("gDDCCHeartsPrimB", 0); + ddType = type; + + sHeartsDDPrim[0][0] = HeartDDOutline[0]; + sHeartsDDPrim[0][1] = HeartDDOutline[1]; + sHeartsDDPrim[0][2] = HeartDDOutline[2]; + + sHeartsDDEnv[0][0] = HeartDDInner[0]; + sHeartsDDEnv[0][1] = HeartDDInner[1]; + sHeartsDDEnv[0][2] = HeartDDInner[2]; + + if (CVar_GetS32("gHudColors", 1) == 2) { + sHeartsDDPrim[2][0] = HeartInner[0]; + sHeartsDDPrim[2][1] = HeartInner[1]; + sHeartsDDPrim[2][2] = HeartInner[2]; + + sHeartsDDPrim[1][0] = HeartDDOutline[0]; + sHeartsDDPrim[1][1] = HeartDDOutline[1]; + sHeartsDDPrim[1][2] = HeartDDOutline[2]; + + sHeartsDDEnv[1][0] = HeartDDInner[0]; + sHeartsDDEnv[1][1] = HeartDDInner[1]; + sHeartsDDEnv[1][2] = HeartDDInner[2]; + + HeartDDInner[0] = HeartInner[0]; + HeartDDInner[1] = HeartInner[1]; + HeartDDInner[2] = HeartInner[2]; + + rFactor = sHeartsDDPrimFactors[ddType][0] * ddFactor; + gFactor = sHeartsDDPrimFactors[ddType][1] * ddFactor; + bFactor = sHeartsDDPrimFactors[ddType][2] * ddFactor; + + sBeatingHeartsDDPrim[0] = (u8)(rFactor + HeartDDOutline[0]) & 0xFF; + sBeatingHeartsDDPrim[1] = (u8)(gFactor + HeartDDOutline[1]) & 0xFF; + sBeatingHeartsDDPrim[2] = (u8)(bFactor + HeartDDOutline[2]) & 0xFF; + + rFactor = sHeartsDDEnvFactors[ddType][0] * ddFactor; + gFactor = sHeartsDDEnvFactors[ddType][1] * ddFactor; + bFactor = sHeartsDDEnvFactors[ddType][2] * ddFactor; + + sBeatingHeartsDDEnv[0] = (u8)(rFactor + HeartDDInner[0]) & 0xFF; + sBeatingHeartsDDEnv[1] = (u8)(gFactor + HeartDDInner[1]) & 0xFF; + sBeatingHeartsDDEnv[2] = (u8)(bFactor + HeartDDInner[2]) & 0xFF; } else { - sHeartsDDPrim[0][0] = HEARTS_DD_PRIM_R; - sHeartsDDPrim[0][1] = HEARTS_DD_PRIM_G; - sHeartsDDPrim[0][2] = HEARTS_DD_PRIM_B; + sHeartsDDPrim[2][0] = HeartInner[0]; + sHeartsDDPrim[2][1] = HeartInner[1]; + sHeartsDDPrim[2][2] = HeartInner[2]; + + sHeartsDDPrim[1][0] = sHeartsDDPrimColors[ddType][0]; + sHeartsDDPrim[1][1] = sHeartsDDPrimColors[ddType][1]; + sHeartsDDPrim[1][2] = sHeartsDDPrimColors[ddType][2]; + + sHeartsDDEnv[1][0] = sHeartsDDEnvColors[ddType][0]; + sHeartsDDEnv[1][1] = sHeartsDDEnvColors[ddType][1]; + sHeartsDDEnv[1][2] = sHeartsDDEnvColors[ddType][2]; + + rFactor = sHeartsDDPrimFactors[ddType][0] * ddFactor; + gFactor = sHeartsDDPrimFactors[ddType][1] * ddFactor; + bFactor = sHeartsDDPrimFactors[ddType][2] * ddFactor; + + sBeatingHeartsDDPrim[0] = (u8)(rFactor + HeartDDOutline[0]) & 0xFF; + sBeatingHeartsDDPrim[1] = (u8)(gFactor + HeartDDOutline[1]) & 0xFF; + sBeatingHeartsDDPrim[2] = (u8)(bFactor + HeartDDOutline[2]) & 0xFF; + + rFactor = sHeartsDDEnvFactors[ddType][0] * ddFactor; + gFactor = sHeartsDDEnvFactors[ddType][1] * ddFactor; + bFactor = sHeartsDDEnvFactors[ddType][2] * ddFactor; + + sBeatingHeartsDDEnv[0] = (u8)(rFactor + HeartDDInner[0]) & 0xFF; + sBeatingHeartsDDEnv[1] = (u8)(gFactor + HeartDDInner[1]) & 0xFF; + sBeatingHeartsDDEnv[2] = (u8)(bFactor + HeartDDInner[2]) & 0xFF; } - sHeartsDDEnv[0][0] = HEARTS_DD_ENV_R; - sHeartsDDEnv[0][1] = HEARTS_DD_ENV_G; - sHeartsDDEnv[0][2] = HEARTS_DD_ENV_B; - - sHeartsDDPrim[1][0] = sHeartsDDPrimColors[ddType][0]; - sHeartsDDPrim[1][1] = sHeartsDDPrimColors[ddType][1]; - sHeartsDDPrim[1][2] = sHeartsDDPrimColors[ddType][2]; - - sHeartsDDEnv[1][0] = sHeartsDDEnvColors[ddType][0]; - sHeartsDDEnv[1][1] = sHeartsDDEnvColors[ddType][1]; - sHeartsDDEnv[1][2] = sHeartsDDEnvColors[ddType][2]; - - rFactor = sHeartsDDPrimFactors[ddType][0] * ddFactor; - gFactor = sHeartsDDPrimFactors[ddType][1] * ddFactor; - bFactor = sHeartsDDPrimFactors[ddType][2] * ddFactor; - - if (CVar_GetS32("gHudColors", 1) == 2) {//Since that in Update() runtime color change will work like that :) - sBeatingHeartsDDPrim[0] = (u8)(rFactor + CVar_GetS32("gDDCCHeartsPrimR", 220)) & 0xFF; - sBeatingHeartsDDPrim[1] = (u8)(gFactor + CVar_GetS32("gDDCCHeartsPrimG", 0)) & 0xFF; - sBeatingHeartsDDPrim[2] = (u8)(bFactor + CVar_GetS32("gDDCCHeartsPrimB", 0)) & 0xFF; - } else { - sBeatingHeartsDDPrim[0] = (u8)(rFactor + HEARTS_DD_PRIM_R) & 0xFF; - sBeatingHeartsDDPrim[1] = (u8)(gFactor + HEARTS_DD_PRIM_G) & 0xFF; - sBeatingHeartsDDPrim[2] = (u8)(bFactor + HEARTS_DD_PRIM_B) & 0xFF; - } - - rFactor = sHeartsDDEnvFactors[ddType][0] * ddFactor; - gFactor = sHeartsDDEnvFactors[ddType][1] * ddFactor; - bFactor = sHeartsDDEnvFactors[ddType][2] * ddFactor; - - sBeatingHeartsDDEnv[0] = (u8)(rFactor + HEARTS_DD_ENV_R) & 0xFF; - sBeatingHeartsDDEnv[1] = (u8)(gFactor + HEARTS_DD_ENV_G) & 0xFF; - sBeatingHeartsDDEnv[2] = (u8)(bFactor + HEARTS_DD_ENV_B) & 0xFF; } s32 func_80078E18(GlobalContext* globalCtx) { @@ -582,4 +620,4 @@ u32 HealthMeter_IsCritical(void) { } else { return false; } -} +} \ No newline at end of file diff --git a/soh/src/code/z_lights.c b/soh/src/code/z_lights.c index c9b60ceca..bee677276 100644 --- a/soh/src/code/z_lights.c +++ b/soh/src/code/z_lights.c @@ -4,6 +4,8 @@ #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + #define LIGHTS_BUFFER_SIZE 32 //#define LIGHTS_BUFFER_SIZE 1024 // Kill me @@ -434,12 +436,14 @@ void Lights_DrawGlow(GlobalContext* globalCtx) { if ((info->type == LIGHT_POINT_GLOW) && (params->drawGlow)) { scale = SQ(params->radius) * 0.0000026f; + FrameInterpolation_RecordOpenChild(node, 0); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, params->color[0], params->color[1], params->color[2], 50); Matrix_Translate(params->x, params->y, params->z, MTXMODE_NEW); Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_lights.c", 918), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gGlowCircleDL); + FrameInterpolation_RecordCloseChild(); } node = node->next; diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index 87e257a39..ff6e4c9ba 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -668,12 +668,12 @@ void Minimap_Draw(GlobalContext* globalCtx) { if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) { if (CVar_GetS32("gHudColors", 1) == 2) { //Dungeon minimap - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCMinimapPrimR", 255), CVar_GetS32("gCCMinimapPrimG", 255), CVar_GetS32("gCCMinimapPrimB", 255), interfaceCtx->magicAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCMinimapPrimR", 255), CVar_GetS32("gCCMinimapPrimG", 255), CVar_GetS32("gCCMinimapPrimB", 255), interfaceCtx->minimapAlpha); } else { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 100, 255, 255, interfaceCtx->minimapAlpha); } - gSPInvalidateTexCache(OVERLAY_DISP++, interfaceCtx->mapSegment); + gSPInvalidateTexCache(OVERLAY_DISP++, interfaceCtx->mapSegment); gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegment, G_IM_FMT_I, 96, 85, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); @@ -752,18 +752,24 @@ void Minimap_Draw(GlobalContext* globalCtx) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_MINIMAP_COLOR(0), R_MINIMAP_COLOR(1), R_MINIMAP_COLOR(2), interfaceCtx->minimapAlpha); } - if (((globalCtx->sceneNum != SCENE_SPOT01) && (globalCtx->sceneNum != SCENE_SPOT04) && (globalCtx->sceneNum != SCENE_SPOT08)) || (LINK_AGE_IN_YEARS != YEARS_ADULT)) { + if (((globalCtx->sceneNum != SCENE_SPOT01) && (globalCtx->sceneNum != SCENE_SPOT04) && + (globalCtx->sceneNum != SCENE_SPOT08)) || + (LINK_AGE_IN_YEARS != YEARS_ADULT)) { s16 IconSize = 8; s16 PosX = gMapData->owEntranceIconPosX[sEntranceIconMapIndex]+Right_MM_Margin; s16 PosY = gMapData->owEntranceIconPosY[sEntranceIconMapIndex]+Bottom_MM_Margin; - if (CVar_GetS32("gFixDungeonMinimapIcon", 1) != 0){ //gFixDungeonMinimapIcon fix both Y position of visible icon and hide these non needed. - PosY = PosY+1024; //No idea why and how Original value work but this does actually fix them all. + //gFixDungeonMinimapIcon fix both Y position of visible icon and hide these non needed. + if (CVar_GetS32("gFixDungeonMinimapIcon", 1) != 0){ + //No idea why and how Original value work but this does actually fix them all. + PosY = PosY+1024; } s16 TopLeftX = OTRGetRectDimensionFromRightEdge(PosX) << 2; s16 TopLeftY = PosY << 2; s16 TopLeftW = OTRGetRectDimensionFromRightEdge(PosX + IconSize) << 2; s16 TopLeftH = (PosY + IconSize) << 2; - if ((gMapData->owEntranceFlag[sEntranceIconMapIndex] == 0xFFFF) || ((gMapData->owEntranceFlag[sEntranceIconMapIndex] != 0xFFFF) && (gSaveContext.infTable[26] & gBitFlags[gMapData->owEntranceFlag[mapIndex]]))) { + if ((gMapData->owEntranceFlag[sEntranceIconMapIndex] == 0xFFFF) || + ((gMapData->owEntranceFlag[sEntranceIconMapIndex] != 0xFFFF) && + (gSaveContext.infTable[26] & gBitFlags[gMapData->owEntranceFlag[mapIndex]]))) { if (gMapData->owEntranceIconPosY[sEntranceIconMapIndex] << 2 != 0 && CVar_GetS32("gFixDungeonMinimapIcon", 1) != 0){ gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, IconSize, IconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, @@ -777,14 +783,15 @@ void Minimap_Draw(GlobalContext* globalCtx) { gSPWideTextureRectangle(OVERLAY_DISP++, TopLeftX, TopLeftY, TopLeftW, TopLeftH, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } } - if ((globalCtx->sceneNum == SCENE_SPOT08) && (gSaveContext.infTable[26] & gBitFlags[9])) { + + if ((globalCtx->sceneNum == SCENE_SPOT08) && (gSaveContext.infTable[26] & gBitFlags[9])) { gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 8, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - const s16 entranceX = OTRGetRectDimensionFromRightEdge(270); + const s16 entranceX = OTRGetRectDimensionFromRightEdge(270); - gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, 154 << 2, (entranceX + 32) << 2, (154 + 8) << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, 154 << 2, (entranceX + 32) << 2, (154 + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -819,7 +826,7 @@ void Map_Update(GlobalContext* globalCtx) { InterfaceContext* interfaceCtx = &globalCtx->interfaceCtx; s16 floor; s16 i; - + if (CVar_GetS32("gHUDMargins", 0) != 0) { Top_MM_Margin = CVar_GetS32("gHUDMargin_T", 0); Left_MM_Margin = CVar_GetS32("gHUDMargin_L", 0); @@ -831,7 +838,7 @@ void Map_Update(GlobalContext* globalCtx) { Right_MM_Margin = 0; Bottom_MM_Margin = 0; } - + if ((globalCtx->pauseCtx.state == 0) && (globalCtx->pauseCtx.debugState == 0)) { switch (globalCtx->sceneNum) { case SCENE_YDAN: diff --git a/soh/src/code/z_map_mark.c b/soh/src/code/z_map_mark.c index e042a9a2b..894daeb2d 100644 --- a/soh/src/code/z_map_mark.c +++ b/soh/src/code/z_map_mark.c @@ -52,7 +52,7 @@ static MapMarkDataOverlay sMapMarkDataOvl = { gMapMarkDataTable, }; -static MapMarkData** sLoadedMarkDataTable; +MapMarkData** sLoadedMarkDataTable; void MapMark_Init(GlobalContext* globalCtx) { MapMarkDataOverlay* overlay = &sMapMarkDataOvl; diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index fe5a44679..fc3572b40 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -447,44 +447,44 @@ void Message_DrawTextboxIcon(GlobalContext* globalCtx, Gfx** p, s16 x, s16 y) { static s16 sIconEnvG = 0; static s16 sIconEnvB = 0; if (CVar_GetS32("gHudColors", 1) == 0) { - sIconPrimColors[0][0] = 4; - sIconPrimColors[0][1] = 84; - sIconPrimColors[0][2] = 204; - sIconPrimColors[1][0] = 45; - sIconPrimColors[1][1] = 125; - sIconPrimColors[1][2] = 255; - sIconEnvColors[0][0] = 0; - sIconEnvColors[0][1] = 0; - sIconEnvColors[0][2] = 0; - sIconEnvColors[1][0] = 0; - sIconEnvColors[1][1] = 70; - sIconEnvColors[1][2] = 255; - } else if (CVar_GetS32("gHudColors", 1) == 1) {//Probably could emptied I need some testing there, I will do it later. - sIconPrimColors[0][0] = 4; - sIconPrimColors[0][1] = 200; - sIconPrimColors[0][2] = 80; - sIconPrimColors[1][0] = 50; - sIconPrimColors[1][1] = 255; - sIconPrimColors[1][2] = 130; - sIconEnvColors[0][0] = 0; - sIconEnvColors[0][1] = 0; - sIconEnvColors[0][2] = 0; - sIconEnvColors[1][0] = 0; - sIconEnvColors[1][1] = 255; - sIconEnvColors[1][2] = 130; + sIconPrimColors[0][0] = 4; + sIconPrimColors[0][1] = 84; + sIconPrimColors[0][2] = 204; + sIconPrimColors[1][0] = 45; + sIconPrimColors[1][1] = 125; + sIconPrimColors[1][2] = 255; + sIconEnvColors[0][0] = 0; + sIconEnvColors[0][1] = 0; + sIconEnvColors[0][2] = 0; + sIconEnvColors[1][0] = 0; + sIconEnvColors[1][1] = 70; + sIconEnvColors[1][2] = 255; + } else if (CVar_GetS32("gHudColors", 1) == 1) { + sIconPrimColors[0][0] = 4; + sIconPrimColors[0][1] = 200; + sIconPrimColors[0][2] = 80; + sIconPrimColors[1][0] = 50; + sIconPrimColors[1][1] = 255; + sIconPrimColors[1][2] = 130; + sIconEnvColors[0][0] = 0; + sIconEnvColors[0][1] = 0; + sIconEnvColors[0][2] = 0; + sIconEnvColors[1][0] = 0; + sIconEnvColors[1][1] = 255; + sIconEnvColors[1][2] = 130; } else if (CVar_GetS32("gHudColors", 1) == 2) { - sIconPrimColors[0][0] = (CVar_GetS32("gCCABtnPrimR", 4)/255)*80; - sIconPrimColors[0][1] = (CVar_GetS32("gCCABtnPrimG", 200)/255)*80; - sIconPrimColors[0][2] = (CVar_GetS32("gCCABtnPrimB", 80)/255)*80; - sIconPrimColors[1][0] = CVar_GetS32("gCCABtnPrimR", 50); - sIconPrimColors[1][1] = CVar_GetS32("gCCABtnPrimG", 255); - sIconPrimColors[1][2] = CVar_GetS32("gCCABtnPrimB", 130); - sIconEnvColors[0][0] = 0; - sIconEnvColors[0][1] = 0; - sIconEnvColors[0][2] = 0; - sIconEnvColors[1][0] = 10; - sIconEnvColors[1][1] = 10; - sIconEnvColors[1][2] = 10; + sIconPrimColors[0][0] = (CVar_GetS32("gCCABtnPrimR", 4)/255)*80; + sIconPrimColors[0][1] = (CVar_GetS32("gCCABtnPrimG", 200)/255)*80; + sIconPrimColors[0][2] = (CVar_GetS32("gCCABtnPrimB", 80)/255)*80; + sIconPrimColors[1][0] = CVar_GetS32("gCCABtnPrimR", 50); + sIconPrimColors[1][1] = CVar_GetS32("gCCABtnPrimG", 255); + sIconPrimColors[1][2] = CVar_GetS32("gCCABtnPrimB", 130); + sIconEnvColors[0][0] = 0; + sIconEnvColors[0][1] = 0; + sIconEnvColors[0][2] = 0; + sIconEnvColors[1][0] = 10; + sIconEnvColors[1][1] = 10; + sIconEnvColors[1][2] = 10; } MessageContext* msgCtx = &globalCtx->msgCtx; Font* font = &msgCtx->font; @@ -563,11 +563,9 @@ void Message_DrawTextboxIcon(GlobalContext* globalCtx, Gfx** p, s16 x, s16 y) { gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - gDPSetPrimColor(gfx++, 0, 0, sIconPrimR, sIconPrimG, sIconPrimB, 255); gDPSetEnvColor(gfx++, sIconEnvR, sIconEnvG, sIconEnvB, 255); - gDPLoadTextureBlock_4b(gfx++, iconTexture, G_IM_FMT_I, FONT_CHAR_TEX_WIDTH, FONT_CHAR_TEX_HEIGHT, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); @@ -2868,23 +2866,23 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) { gDPPipeSync(gfx++); if (sOcarinaNoteBuf[i] == OCARINA_NOTE_A) { - if (CVar_GetS32("gHudColors", 1) == 0) { //A buttons :) - gDPSetPrimColor(gfx++, 0, 0, 80, 150, 255, sOcarinaNotesAlphaValues[i]); - } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteAPrimR, sOcarinaNoteAPrimG, sOcarinaNoteAPrimB, sOcarinaNotesAlphaValues[i]); - } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(gfx++, 0, 0, CVar_GetS32("gCCABtnPrimR", 0), CVar_GetS32("gCCABtnPrimG", 0), CVar_GetS32("gCCABtnPrimB", 0), sOcarinaNotesAlphaValues[i]); - } - gDPSetEnvColor(gfx++, sOcarinaNoteAEnvR, sOcarinaNoteAEnvG, sOcarinaNoteAEnvB, 0); + if (CVar_GetS32("gHudColors", 1) == 0) { //A buttons :) + gDPSetPrimColor(gfx++, 0, 0, 80, 150, 255, sOcarinaNotesAlphaValues[i]); + } else if (CVar_GetS32("gHudColors", 1) == 1) { + gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteAPrimR, sOcarinaNoteAPrimG, sOcarinaNoteAPrimB, sOcarinaNotesAlphaValues[i]); + } else if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(gfx++, 0, 0, CVar_GetS32("gCCABtnPrimR", 0), CVar_GetS32("gCCABtnPrimG", 0), CVar_GetS32("gCCABtnPrimB", 0), sOcarinaNotesAlphaValues[i]); + } + gDPSetEnvColor(gfx++, sOcarinaNoteAEnvR, sOcarinaNoteAEnvG, sOcarinaNoteAEnvB, 0); } else { - if (CVar_GetS32("gHudColors", 1) == 0) { //C buttons :) - gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteCPrimR, sOcarinaNoteCPrimG, sOcarinaNoteCPrimB, sOcarinaNotesAlphaValues[i]); - } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteCPrimR, sOcarinaNoteCPrimG, sOcarinaNoteCPrimB, sOcarinaNotesAlphaValues[i]); - } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(gfx++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 0), CVar_GetS32("gCCCBtnPrimG", 0), CVar_GetS32("gCCCBtnPrimB", 0), sOcarinaNotesAlphaValues[i]); - } - gDPSetEnvColor(gfx++, sOcarinaNoteCEnvR, sOcarinaNoteCEnvG, sOcarinaNoteCEnvB, 0); + if (CVar_GetS32("gHudColors", 1) == 0) { //C buttons :) + gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteCPrimR, sOcarinaNoteCPrimG, sOcarinaNoteCPrimB, sOcarinaNotesAlphaValues[i]); + } else if (CVar_GetS32("gHudColors", 1) == 1) { + gDPSetPrimColor(gfx++, 0, 0, sOcarinaNoteCPrimR, sOcarinaNoteCPrimG, sOcarinaNoteCPrimB, sOcarinaNotesAlphaValues[i]); + } else if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(gfx++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 0), CVar_GetS32("gCCCBtnPrimG", 0), CVar_GetS32("gCCCBtnPrimB", 0), sOcarinaNotesAlphaValues[i]); + } + gDPSetEnvColor(gfx++, sOcarinaNoteCEnvR, sOcarinaNoteCEnvG, sOcarinaNoteCEnvB, 0); } gDPLoadTextureBlock(gfx++, sOcarinaNoteTextures[sOcarinaNoteBuf[i]], G_IM_FMT_IA, G_IM_SIZ_8b, 16, diff --git a/soh/src/code/z_onepointdemo.c b/soh/src/code/z_onepointdemo.c index 96ef33c18..538859764 100644 --- a/soh/src/code/z_onepointdemo.c +++ b/soh/src/code/z_onepointdemo.c @@ -4,9 +4,9 @@ static s16 sDisableAttention = false; static s16 sUnused = -1; -static s32 sPrevFrameCs1100 = -4096; +s32 sPrevFrameCs1100 = -4096; -#include "z_onepointdemo_data.c" +#include "z_onepointdemo_data.inc" void OnePointCutscene_AddVecSphToVec3f(Vec3f* dst, Vec3f* src, VecSph* vecSph) { Vec3f out; diff --git a/soh/src/code/z_onepointdemo_data.inc b/soh/src/code/z_onepointdemo_data.inc new file mode 100644 index 000000000..2488be71b --- /dev/null +++ b/soh/src/code/z_onepointdemo_data.inc @@ -0,0 +1,670 @@ +#include "global.h" + +CutsceneCameraPoint D_8012013C[14] = { + { CS_CMD_CONTINUE, 25, 40, 70.79991f, { -1814, 533, -1297 } }, + { CS_CMD_CONTINUE, 20, 40, 70.99991f, { -1805, 434, -1293 } }, + { CS_CMD_CONTINUE, 10, 30, 60.0f, { -1794, 323, -1280 } }, + { CS_CMD_CONTINUE, 5, 25, 60.0f, { -1817, 218, -1270 } }, + { CS_CMD_CONTINUE, 3, 20, 60.0f, { -1836, 168, -1243 } }, + { CS_CMD_CONTINUE, 0, 20, 60.0f, { -1905, 115, -1193 } }, + { CS_CMD_CONTINUE, 0, 30, 55.0f, { -1969, 58, -1212 } }, + { CS_CMD_CONTINUE, 0, 30, 55.0f, { -1969, 31, -1164 } }, + { CS_CMD_CONTINUE, 0, 30, 60.0f, { -1969, 54, -1209 } }, + { CS_CMD_CONTINUE, 0, 30, 60.0f, { -1973, 35, -1206 } }, + { CS_CMD_CONTINUE, 0, 50, 60.0f, { -1974, 12, -1179 } }, + { CS_CMD_CONTINUE, 0, 50, 60.0f, { -1974, 12, -1179 } }, + { CS_CMD_STOP, 0, 50, 60.0f, { -1974, 12, -1179 } }, + { CS_CMD_STOP, 0, 30, 60.0f, { -1974, 12, -1179 } }, +}; +CutsceneCameraPoint D_8012021C[14] = { + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1751, 604, -1233 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1752, 516, -1233 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1751, 417, -1233 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1767, 306, -1219 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1776, 257, -1205 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1881, 147, -1149 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1969, 72, -1077 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1969, 7, -1048 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1969, 1, -1030 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1987, 17, -1076 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -2007, 10, -1004 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -2007, 10, -1004 } }, + { CS_CMD_STOP, 0, 0, 60.0f, { -2007, 10, -1004 } }, { CS_CMD_STOP, 0, 0, 60.0f, { -2007, 10, -1004 } }, +}; +static s16 D_801202FC = 13; +static s16 D_80120300 = 210; +static s16 D_80120304 = 0; + +static CutsceneCameraPoint D_80120308[9] = { + { CS_CMD_CONTINUE, 0, 10, 40.0f, { 0, 4, 0 } }, { CS_CMD_CONTINUE, 0, 10, 40.000004f, { 0, 4, 0 } }, + { CS_CMD_CONTINUE, 0, 10, 50.0f, { 0, 9, 0 } }, { CS_CMD_CONTINUE, 0, 12, 55.0f, { 0, 12, 0 } }, + { CS_CMD_CONTINUE, 0, 15, 61.0f, { 0, 18, 0 } }, { CS_CMD_CONTINUE, 0, 20, 65.0f, { 0, 29, 0 } }, + { CS_CMD_CONTINUE, 0, 40, 60.0f, { 0, 34, 0 } }, { CS_CMD_STOP, 0, 40, 60.0f, { 0, 34, 0 } }, + { CS_CMD_STOP, 0, 10, 60.0f, { 0, 34, 0 } }, +}; +static CutsceneCameraPoint D_80120398[9] = { + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 9, 45 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 8, 50 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 17, 58 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 21, 78 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 46, 109 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 58, 118 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 63, 119 } }, { CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, 119 } }, + { CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, 119 } }, +}; +static s16 D_80120428 = 9; +static s16 D_8012042C = 90; +static s16 D_80120430 = 1; +static CutsceneCameraPoint D_80120434[10] = { + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 9, -45 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 9, -45 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 8, -50 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 17, -58 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 21, -78 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 46, -109 } }, + { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 58, -118 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { 0, 63, -119 } }, + { CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, -119 } }, { CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, -119 } }, +}; + +CutsceneCameraPoint D_801204D4[14] = { + { CS_CMD_CONTINUE, -15, 40, 80.600006f, { -60, 332, 183 } }, + { CS_CMD_CONTINUE, -22, 30, 80.600006f, { -60, 332, 183 } }, + { CS_CMD_CONTINUE, -20, 38, 80.600006f, { -118, 344, 41 } }, + { CS_CMD_CONTINUE, -18, 32, 80.600006f, { -80, 251, -8 } }, + { CS_CMD_CONTINUE, -12, 28, 80.600006f, { -64, 259, -28 } }, + { CS_CMD_CONTINUE, -8, 22, 80.600006f, { -79, 200, -342 } }, + { CS_CMD_CONTINUE, -5, 10, 65.80005f, { -110, 140, -549 } }, + { CS_CMD_CONTINUE, -2, 8, 65.2f, { -74, 109, -507 } }, + { CS_CMD_CONTINUE, 0, 10, 65.80002f, { -32, 78, -680 } }, + { CS_CMD_CONTINUE, 0, 20, 85.199936f, { 25, 127, -950 } }, + { CS_CMD_CONTINUE, 0, 30, 85.199936f, { 25, 127, -950 } }, + { CS_CMD_CONTINUE, 0, 40, 85.199936f, { 25, 127, -950 } }, + { CS_CMD_STOP, 6, 30, 85.199936f, { 25, 127, -950 } }, + { CS_CMD_STOP, 0, 30, 85.199936f, { 25, 127, -950 } }, +}; +CutsceneCameraPoint D_801205B4[14] = { + { CS_CMD_CONTINUE, 0, 0, 60.0f, { -225, 785, -242 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -245, 784, -242 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -288, 485, -379 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -250, 244, -442 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -163, 21, -415 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -98, 86, -520 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -86, 31, -816 } }, + { CS_CMD_CONTINUE, -21, 0, 80.600006f, { -74, 18, -931 } }, + { CS_CMD_CONTINUE, 1, 0, 80.600006f, { -91, 80, -1220 } }, + { CS_CMD_CONTINUE, 0, 0, 85.199936f, { 14, 153, -1340 } }, + { CS_CMD_CONTINUE, 0, 0, 85.199936f, { 28, 125, -1340 } }, + { CS_CMD_CONTINUE, 0, 0, 85.199936f, { 48, 124, -1340 } }, + { CS_CMD_STOP, 0, 0, 85.199936f, { 48, 124, -1502 } }, + { CS_CMD_STOP, 0, 0, 85.199936f, { 48, 124, -1262 } }, +}; +static s16 D_80120694 = 14; +static s16 D_80120698 = 190; +static s16 D_8012069C = 8; + +static CutsceneCameraPoint D_801206A0[12] = { + { CS_CMD_CONTINUE, 6, 20, 80.0f, { -96, 40, 170 } }, { CS_CMD_CONTINUE, 6, 20, 80.0f, { -96, 40, 170 } }, + { CS_CMD_CONTINUE, 6, 20, 70.0f, { -70, 35, 150 } }, { CS_CMD_CONTINUE, 5, 10, 60.0f, { -57, 34, 133 } }, + { CS_CMD_CONTINUE, 4, 25, 65.0f, { -22, 32, 110 } }, { CS_CMD_CONTINUE, 3, 12, 60.0f, { -9, 33, 98 } }, + { CS_CMD_CONTINUE, 3, 5, 65.0f, { -3, 29, 87 } }, { CS_CMD_CONTINUE, 2, 10, 65.0f, { -1, 15, 84 } }, + { CS_CMD_CONTINUE, 1, 200, 65.0f, { 0, 17, 82 } }, { CS_CMD_CONTINUE, 1, 500, 65.0f, { 0, 18, 82 } }, + { CS_CMD_STOP, 8, 50, 65.0f, { 0, 18, 82 } }, { CS_CMD_STOP, 11, 60, 65.0f, { 0, 18, 82 } }, +}; +static CutsceneCameraPoint D_80120760[12] = { + { CS_CMD_CONTINUE, 6, 0, 80.0f, { -50, 10, 180 } }, { CS_CMD_CONTINUE, 6, 0, 80.0f, { -50, 20, 180 } }, + { CS_CMD_CONTINUE, 6, 0, 70.0f, { -40, 30, 177 } }, { CS_CMD_CONTINUE, 5, 0, 65.0f, { 0, 35, 172 } }, + { CS_CMD_CONTINUE, 4, 0, 65.0f, { 34, 35, 162 } }, { CS_CMD_CONTINUE, 3, 0, 65.0f, { 61, 32, 147 } }, + { CS_CMD_CONTINUE, 3, 0, 65.0f, { 72, 30, 128 } }, { CS_CMD_CONTINUE, 2, 0, 65.0f, { 74, 20, 125 } }, + { CS_CMD_CONTINUE, 1, 0, 65.0f, { 75, 18, 123 } }, { CS_CMD_CONTINUE, 1, 0, 65.0f, { 75, 10, 123 } }, + { CS_CMD_STOP, 0, 0, 65.0f, { 75, 10, 122 } }, { CS_CMD_STOP, 0, 0, 65.0f, { 75, 10, 122 } }, +}; +static CutsceneCameraPoint D_80120820[12] = { + { CS_CMD_CONTINUE, 6, 0, 80.0f, { 85, 5, 170 } }, { CS_CMD_CONTINUE, 6, 0, 80.0f, { 85, 10, 170 } }, + { CS_CMD_CONTINUE, 6, 0, 70.0f, { 80, 20, 167 } }, { CS_CMD_CONTINUE, 5, 0, 65.0f, { 74, 25, 165 } }, + { CS_CMD_CONTINUE, 4, 0, 65.0f, { 63, 30, 162 } }, { CS_CMD_CONTINUE, 3, 0, 65.0f, { 66, 34, 147 } }, + { CS_CMD_CONTINUE, 3, 0, 65.0f, { 72, 34, 128 } }, { CS_CMD_CONTINUE, 2, 0, 65.0f, { 74, 20, 125 } }, + { CS_CMD_CONTINUE, 1, 0, 65.0f, { 75, 18, 123 } }, { CS_CMD_CONTINUE, 1, 0, 65.0f, { 75, 10, 123 } }, + { CS_CMD_STOP, 0, 0, 65.0f, { 75, 10, 122 } }, { CS_CMD_STOP, 0, 0, 65.0f, { 75, 10, 122 } }, +}; +static s16 D_801208E0 = 12; +static s16 D_801208E4 = 90; +static s16 D_801208E8 = 8; + +OnePointCsFull D_801208EC[3] = { + { 0x0F, 0x08, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x81, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80120964[2] = { + { 0x8F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x81, 0xFF, 0xA121, 1, 0, 75.0f, 0.6f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, +}; + +OnePointCsFull D_801209B4[4] = { + { 0x8F, 0x08, 0x0101, 1, 0, 60.0f, 0.9f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x84, 0x01, 0x0100, 29, 0, 45.0f, 0.1f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, + { 0x83, 0xFF, 0x0000, 10, 0, 60.0f, 0.2f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80120A54[3] = { + { 0x8F, 0xFF, 0x2525, 1, 0, 75.0f, 0.1f, { 0.0f, 20.0f, -10.0f }, { 0.0f, 10.0f, -40.0f } }, + { 0x8F, 0xFF, 0x0000, 9, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x8B, 0xFF, 0x0022, 5000, 0, 75.0f, 0.005f, { 0.0f, 0.0f, -10.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80120ACC[5] = { + { 0x8F, 0xFF, 0x0442, 10, 0, 40.0f, 1.0f, { -10.0f, 45.0f, 20.0f }, { 20.0f, 30.0f, 160.0f } }, + { 0x95, 0xFF, 0x0000, 1, 0, 40.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x8F, 0x01, 0x0442, 10, 0, 40.0f, 1.0f, { -10.0f, 45.0f, 20.0f }, { 20.0f, 30.0f, 160.0f } }, + { 0x95, 0xFF, 0x0000, 1, 0, 40.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80120B94[11] = { + { 0x8F, 0x01, 0x2142, 1, 0, 40.0f, 1.0f, { 20.0f, 40.0f, 20.0f }, { -20.0f, 0.0f, -30.0f } }, + { 0x84, 0xFF, 0x0404, 19, 5, 70.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 20, 0, 60.0f, 0.01f, { 0.0f, 20.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 40, -10, 50.0f, 0.02f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x8F, 0xFF, 0x4141, 1, 0, 40.0f, 1.0f, { 0.0f, -10.0f, 20.0f }, { 0.0f, 20.0f, 50.0f } }, + { 0x84, 0xFF, 0x0404, 19, 0, 70.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 40, 10, 50.0f, 0.01f, { 0.0f, 20.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 70, 0, 60.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x8F, 0xFF, 0x4141, 1, 0, 50.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 80.0f, 20.0f, 60.0f } }, + { 0x8D, 0xFF, 0x4141, 150, 0, 50.0f, 1.0f, { 0.0f, 5.0f, 0.0f }, { 0.0f, 4.0f, 120.0f } }, + { 0x98, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80120D4C[7] = { + { 0x8F, 0x01, 0x2142, 1, 0, 40.0f, 1.0f, { 20.0f, 40.0f, 20.0f }, { -20.0f, 0.0f, -30.0f } }, + { 0x84, 0xFF, 0x0404, 19, 5, 70.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 20, 0, 60.0f, 0.01f, { 0.0f, 20.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x84, 0xFF, 0x0404, 40, -10, 50.0f, 0.02f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } }, + { 0x8F, 0xFF, 0x4141, 1, 0, 50.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 80.0f, 20.0f, 60.0f } }, + { 0x8D, 0xFF, 0x4141, 150, 0, 50.0f, 1.0f, { 0.0f, 5.0f, 0.0f }, { 0.0f, 4.0f, 120.0f } }, + { 0x98, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80120E64[8] = { + { 0x41, 0x01, 0x2142, 20, 0, 50.0f, 1.0f, { -25.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4F, 0xFF, 0x0000, 80, 0, 50.0f, 1.0f, { -25.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4B, 0xFF, 0x4242, 8, 0, 60.0f, 0.1f, { -25.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4B, 0xFF, 0x4242, 15, 4, 55.0f, 0.05f, { -50.0f, 20.0f, 20.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4B, 0xFF, 0x4242, 15, -4, 50.0f, 0.05f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4B, 0xFF, 0x4242, 15, 0, 50.0f, 0.1f, { -25.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x4F, 0xFF, 0x0000, 40, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80120FA4[6] = { + { 0x8F, 0x01, 0x2143, 30, 0, 70.0f, 0.4f, { 0.0f, 40.0f, 50.0f }, { 30.0f, 10.0f, -50.0f } }, + { 0x95, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x8F, 0xFF, 0x2222, 10, 0, 42.0f, 1.0f, { 0.0f, 40.0f, 0.0f }, { 0.0f, 85.0f, 45.0f } }, + { 0x90, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x81, 0xFF, 0x2121, 10, 0, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { 30.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121094[3] = { + { 0x0F, 0x08, 0x2101, 20, 0, 50.0f, 1.0f, { 3840.0f, 10.0f, 950.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x01, 0x01, 0x2101, 50, 0, 55.0f, 1.0f, { 4000.0f, 50.0f, 1000.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012110C[3] = { + { 0x4F, 0x05, 0x2142, 1, 0, 50.0f, 1.0f, { -25.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 5.0f } }, + { 0x41, 0xFF, 0x2121, 10, 0, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80121184[2] = { + { 0x83, 0x01, 0x0101, 40, 0, -1.0f, 0.1f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_801211D4[2] = { + { 0x8F, 0x08, 0x0101, 50, 0, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { -10.0f, 85.0f, 0.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121224[6] = { + { 0x8F, 0x01, 0x4141, 2, 0, 60.0f, 1.0f, { 0.0f, 5.0f, 10.0f }, { 0.0f, 0.0f, 45.0f } }, + { 0x81, 0xFF, 0x4141, 18, 0, 45.0f, 1.0f, { 0.0f, 5.0f, 10.0f }, { 0.0f, -10.0f, 50.0f } }, + { 0x84, 0x34, 0x4104, 80, 0, 70.0f, 0.05f, { 0.0f, 0.0f, 60.0f }, { 0.0f, 250.0f, -50.0f } }, + { 0x8F, 0x01, 0x0000, 20, 0, 70.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x8F, 0xFF, 0x0421, 60, 0, 50.0f, 1.0f, { 0.0f, -30.0f, 20.0f }, { 10.0f, 5.0f, -50.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121314[1] = { + { 0x8F, 0x08, 0x4141, 1000, 0, 75.0f, 0.6f, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 100.0f } }, +}; + +OnePointCsFull D_8012133C[3] = { + { 0x8F, 0x01, 0x0141, 40, 0, 75.0f, 1.0f, { 0.0f, 60.0f, 0.0f }, { 0.0f, 0.0f, 100.0f } }, + { 0x83, 0xFF, 0x2121, 20, 0, 60.0f, 0.2f, { 0.0f, -10.0f, -10.0f }, { 0.0f, 10.0f, -100.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_801213B4[5] = { + { 0x8F, 0x08, 0xC2C2, 40, 0, 70.0f, 1.0f, { 80.0f, 0.0f, 20.0f }, { 20.0f, 0.0f, 80.0f } }, + { 0x8B, 0x01, 0xC2C2, 120, 0, 70.0f, 0.1f, { 80.0f, 0.0f, 20.0f }, { 20.0f, 0.0f, 80.0f } }, + { 0x8F, 0x53, 0xC2C2, 30, 0, 50.0f, 1.0f, { 60.0f, 0.0f, 20.0f }, { 60.0f, 0.0f, 60.0f } }, + { 0x84, 0x45, 0x4222, 30, 0, 60.0f, 0.1f, { 0.0f, 50.0f, 0.0f }, { 5.0f, 30.0f, 220.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012147C[4] = { + { 0x8F, 0x01, 0x0101, 40, 0, 45.0f, 1.0f, { 820.0f, 1600.0f, -400.0f }, { 777.0f, 1577.0f, -577.0f } }, + { 0x8F, 0x01, 0x0142, 1, 0, 50.0f, 1.0f, { -50.0f, 80.0f, 0.0f }, { 900.0f, 1575.0f, 850.0f } }, + { 0x83, 0x08, 0x0142, 89, -4, 80.0f, 0.07f, { -50.0f, 70.0f, 0.0f }, { 975.0f, 1575.0f, 770.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_8012151C[2] = { + { 0x0F, 0x01, 0x0101, 29, 0, 60.0f, 1.0f, { -700.0f, 875.0f, -100.0f }, { -550.0f, 920.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_8012156C[2] = { + { 0x8F, 0x4D, 0x4242, 1, 0, 65.0f, 1.0f, { 60.0f, 30.0f, 0.0f }, { 50.0f, 20.0f, 150.0f } }, + { 0x81, 0xFF, 0x4242, -1, 0, 65.0f, 1.0f, { -50.0f, 60.0f, 0.0f }, { -60.0f, 40.0f, 150.0f } }, +}; + +OnePointCsFull D_801215BC[1] = { + { 0x0F, 0xFF, 0x0101, 5, 0, 65.0f, 1.0f, { -1185.0f, 655.0f, 1185.0f }, { -1255.0f, 735.0f, 1255.0f } }, +}; + +static OnePointCsFull D_801215E4[10] = { + { 0x0F, 0x08, 0x4141, 20, 0, 30.0f, 1.0f, { 0.0f, 120.0f, 0.0f }, { -10.0f, 140.0f, -90.0f } }, + { 0x0F, 0x01, 0x0101, 1, 4, 75.0f, 1.0f, { -1360.0f, -940.0f, -3343.0f }, { -1060.0f, -980.0f, -3325.0f } }, + { 0x0B, 0xFF, 0x4141, 129, 0, 75.0f, 0.5f, { 0.0f, 50.0f, 0.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x03, 0xFF, 0x0303, 30, 0, 70.0f, 0.05f, { 0.0f, 80.0f, 0.0f }, { -10.0f, 120.0f, 10.0f } }, + { 0x0F, 0x09, 0x0101, 40, -5, 70.0f, 1.0f, { -973.0f, -924.0f, -3263.0f }, { -1190.0f, -1010.0f, -3365.0f } }, + { 0x0F, 0x01, 0x0101, 1, 0, 75.0f, 1.0f, { -1355.0f, -700.0f, -3340.0f }, { -1040.0f, -940.0f, -3345.0f } }, + { 0x02, 0xFF, 0x0101, 60, 0, 45.0f, 0.8f, { -1370.0f, -875.0f, -3345.0f }, { -1230.0f, -885.0f, -3345.0f } }, + { 0x01, 0xFF, 0x0101, 10, 0, 70.0f, 1.0f, { -1370.0f, -875.0f, -3345.0f }, { -1210.0f, -900.0f, -3420.0f } }, + { 0x0F, 0xFF, 0x0000, 20, 0, 70.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121774[4] = { + { 0x0F, 0x08, 0x0101, 1, -2, 75.0f, 1.0f, { -1340.0f, -860.0f, -3345.0f }, { -1415.0f, -940.0f, -3520.0f } }, + { 0x01, 0x01, 0x0142, 39, 2, 70.0f, 1.0f, { 0.0f, -20.0f, 10.0f }, { -1140.0f, -1010.0f, -3560.0f } }, + { 0x01, 0x05, 0x0121, 20, 0, 60.0f, 1.0f, { 0.0f, -20.0f, 20.0f }, { -1220.0f, -1005.0f, -3660.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121814[4] = { + { 0x0F, 0x4C, 0x0101, 5, 0, 40.0f, 1.0f, { -1400.0f, -540.0f, -3327.0f }, { -1254.0f, -20.0f, -3357.0f } }, + { 0x01, 0xFF, 0x0101, 70, 0, 75.0f, 0.75f, { -1327.0f, 100.0f, -3342.0f }, { -1320.0f, 350.0f, -3540.0f } }, + { 0x01, 0xFF, 0x2121, 10, 0, 60.0f, 0.75f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 20.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801218B4[2] = { + { 0x0F, 0xFF, 0x0101, 60, 0, 65.0f, 1.0f, { 0.0f, 350.0f, -1520.0f }, { 0.0f, 715.0f, -885.0f } }, + { 0x03, 0xFF, 0x0101, 100, 0, 70.0f, 0.02f, { 0.0f, 75.0f, -1335.0f }, { 0.0f, 20.0f, -1190.0f } }, +}; + +static OnePointCsFull D_80121904[2] = { + { 0x0F, 0xFF, 0x0101, 50, 10, 65.0f, 1.0f, { 165.0f, 85.0f, -920.0f }, { 65.0f, -30.0f, -720.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121954[3][2] = { + { + { 0x0F, 0xFF, 0x0101, 20, 5, 60.0f, 1.0f, { -700.0f, 940.0f, 300.0f }, { -765.0f, 1000.0f, 335.0f } }, + { 0x03, 0xFF, 0x0101, 80, -10, 70.0f, 0.1f, { -540.0f, 875.0f, 245.0f }, { -585.0f, 900.0f, 335.0f } }, + }, + { + { 0x0F, 0xFF, 0x0101, 40, -30, 70.0f, 1.0f, { -80.0f, 115.0f, -180.0f }, { -5.0f, 240.0f, -190.0f } }, + { 0x0B, 0xFF, 0x0101, 60, 20, 70.0f, 0.1f, { -100.0f, 350.0f, -175.0f }, { -5.0f, 240.0f, -190.0f } }, + }, + { + { 0x03, 0xFF, 0x0101, 80, 5, 70.0f, 0.2f, { 960.0f, 900.0f, 260.0f }, { 970.0f, 950.0f, 250.0f } }, + { 0x0F, 0xFF, 0x0101, 20, 5, 70.0f, 1.0f, { 960.0f, 900.0f, 260.0f }, { 970.0f, 950.0f, 250.0f } }, + }, +}; + +static OnePointCsFull D_80121A44[12] = { + { 0x4F, 0x05, 0x2121, 10, 0, 60.0f, 1.0f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 0.0f, -80.0f } }, + { 0x42, 0x01, 0x4242, 30, 0, 50.0f, 1.0f, { 0.0f, 45.0f, 0.0f }, { 0.0f, 45.0f, 50.0f } }, + { 0x55, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x4F, 0x05, 0x2222, 40, 5, 50.0f, 1.0f, { 0.0f, 50.0f, 0.0f }, { 0.0f, 50.0f, 50.0f } }, + { 0x4F, 0x01, 0x4242, 40, 5, 60.0f, 1.0f, { 30.0f, 30.0f, 15.0f }, { 70.0f, 30.0f, -40.0f } }, + { 0x55, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x4F, 0xFF, 0x4242, 30, -5, 50.0f, 1.0f, { 20.0f, 30.0f, -5.0f }, { 0.0f, 70.0f, 70.0f } }, + { 0x50, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x4F, 0x01, 0x2242, 40, 0, 45.0f, 1.0f, { 0.0f, 30.0f, 30.0f }, { 25.0f, 60.0f, -60.0f } }, + { 0x4B, 0x01, 0x22C2, 140, 0, 60.0f, 0.04f, { 0.0f, 0.0f, 30.0f }, { 25.0f, 60.0f, -60.0f } }, + { 0x49, 0xFF, 0x2222, 20, 0, 60.0f, 0.8f, { 0.0f, 50.0f, 0.0f }, { 0.0f, 60.0f, -60.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80121C24[7] = { + { 0x0F, 0x05, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x03, 0xFF, 0x0101, 89, 0, 50.0f, 0.4f, { 125.0f, 320.0f, -1500.0f }, { 125.0f, 500.0f, -1150.0f } }, + { 0x0F, 0x08, 0x0101, 40, 4, 55.0f, 1.0f, { 0.0f, 375.0f, -1440.0f }, { 5.0f, 365.0f, -1315.0f } }, + { 0x0F, 0xFF, 0x0101, 40, -4, 55.0f, 1.0f, { 250.0f, 375.0f, -1440.0f }, { 235.0f, 365.0f, -1315.0f } }, + { 0x0F, 0xFF, 0x0101, 100, 0, 95.0f, 1.0f, { 125.0f, 345.0f, -1500.0f }, { 125.0f, 255.0f, -1350.0f } }, + { 0x02, 0xFF, 0x0101, 100, 0, 60.0f, 1.0f, { 125.0f, 325.0f, -1500.0f }, { 125.0f, 480.0f, -1000.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80121D3C[3] = { + { 0x0F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 1023.0f, 738.0f, -2628.0f }, { 993.0f, 770.0f, -2740.0f } }, + { 0x02, 0xFF, 0x0101, 4, 0, 50.0f, 1.0f, { 1255.0f, 350.0f, -1870.0f }, { 1240.0f, 575.0f, -2100.0f } }, + { 0x0F, 0xFF, 0x0000, -1, 0, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80121DB4[9] = { + { 0x0F, 0xFF, 0x0101, 40, 0, 70.0f, 1.0f, { 4290.0f, -1332.0f, -1900.0f }, { 4155.0f, -1360.0f, -1840.0f } }, + { 0x02, 0xFF, 0x0101, 60, 0, 70.0f, 1.0f, { 4215.0f, -975.0f, -2095.0f }, { 4070.0f, -1000.0f, -2025.0f } }, + { 0x0F, 0xFF, 0x0101, 5, 0, 70.0f, 1.0f, { 4215.0f, -975.0f, -2095.0f }, { 4070.0f, -1000.0f, -2025.0f } }, + { 0x0F, 0xFF, 0x0101, 80, 8, 75.0f, 1.0f, { 4010.0f, -1152.0f, -1728.0f }, { 3997.0f, -1194.0f, -1629.0f } }, + { 0x0F, 0x39, 0x2121, 1, 8, 75.0f, 1.0f, { 20.0f, 20.0f, 0.0f }, { 50.0f, 30.0f, 200.0f } }, + { 0x04, 0xFF, 0x2121, 99, 2, 70.0f, 0.02f, { -20.0f, 0.0f, 20.0f }, { 300.0f, 50.0f, -500.0f } }, + { 0x09, 0x38, 0x2121, 149, -20, 70.0f, 0.1f, { 100.0f, 50.0f, -100.0f }, { 5000.0f, 1055.0f, -2250.0f } }, + { 0x0F, 0xFF, 0x2121, 1, 0, 60.0f, 1.0f, { 0.0f, -20.0f, 0.0f }, { 0.0f, 20.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80121F1C[4] = { + { 0x0F, 0x08, 0x0101, 10, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x01, 0xFF, 0x2121, 10, 0, 50.0f, 0.5f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, + { 0x01, 0x02, 0x2121, 23, 0, 50.0f, 0.5f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80121FBC[4] = { + { 0x0F, 0xFF, 0x0101, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x01, 0xFF, 0x0101, 10, 0, 30.0f, 1.0f, { -2130.0f, 2885.0f, -1055.0f }, { -2085.0f, 2875.0f, -1145.0f } }, + { 0x0F, 0xFF, 0x0000, 30, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012205C[3] = { + { 0x0F, 0xFF, 0x42C2, 1, 0, 50.0f, 1.0f, { 0.0f, 220.0f, 0.0f }, { 0.0f, 220.0f, 240.0f } }, + { 0x0F, 0xFF, 0x0080, 29, 0, 50.0f, 1.0f, { 0.0f, 220.0f, 0.0f }, { 0.0f, 220.0f, 240.0f } }, + { 0x01, 0x01, 0x21A1, 10, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, -200.0f } }, +}; + +OnePointCsFull D_801220D4[5] = { + { 0x0F, 0x01, 0x0101, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x01, 0xFF, 0x4141, 10, 5, 55.0f, 0.75f, { 400.0f, -50.0f, 800.0f }, { 600.0f, -60.0f, 800.0f } }, + { 0x01, 0xFF, 0x4141, 15, 10, 40.0f, 0.75f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 200.0f } }, + { 0x0F, 0xFF, 0x0000, 25, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012219C[7] = { + { 0x0F, 0xFF, 0x2121, 5, 0, 60.0f, 1.0f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 0.0f, -80.0f } }, + { 0x02, 0xFF, 0x4242, 15, 0, 40.0f, 0.4f, { 0.0f, 60.0f, -20.0f }, { 0.0f, 60.0f, 100.0f } }, + { 0x0F, 0xFF, 0x0000, 20, 0, 40.0f, 1.0f, { 0.0f, 60.0f, -20.0f }, { 0.0f, 60.0f, 100.0f } }, + { 0x01, 0xFF, 0x4242, 20, 0, 60.0f, 1.0f, { 20.0f, 60.0f, 20.0f }, { 40.0f, 60.0f, -80.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0000, 90, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801222B4[5] = { + { 0x0F, 0xFF, 0x0101, 20, 10, 45.0f, 1.0f, { -1200.0f, 730.0f, -860.0f }, { -1100.0f, 500.0f, -1025.0f } }, + { 0x0B, 0xFF, 0x0101, 20, 10, 45.0f, 0.1f, { -880.0f, 480.0f, -860.0f }, { -1100.0f, 500.0f, -1025.0f } }, + { 0x0B, 0x81, 0x0101, 20, 10, 45.0f, 0.1f, { -880.0f, 500.0f, -860.0f }, { -1100.0f, 500.0f, -1025.0f } }, + { 0x0B, 0x8A, 0x0101, 5, 10, 45.0f, 0.1f, { -880.0f, 500.0f, -860.0f }, { -1100.0f, 500.0f, -1025.0f } }, + { 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012237C[2] = { + { 0x0F, 0xFF, 0x0101, 20, -2, 65.0f, 1.0f, { -625.0f, 185.0f, -685.0f }, { -692.0f, 226.0f, -515.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801223CC[6] = { + { 0x0F, 0xFF, 0x0101, 20, 0, 55.0f, 1.0f, { 60.0f, 1130.0f, -1430.0f }, { 60.0f, 1130.0f, -1190.0f } }, + { 0x0F, 0xFF, 0x0101, 18, -13, 68.0f, 1.0f, { 60.0f, 1130.0f, -1445.0f }, { 180.0f, 1170.0f, -1240.0f } }, + { 0x0F, 0xFF, 0x0101, 16, 18, 75.0f, 1.0f, { 42.0f, 1040.0f, -1400.0f }, { -20.0f, 940.0f, -1280.0f } }, + { 0x0F, 0xFF, 0x0101, 4, 0, 60.0f, 1.0f, { 60.0f, 1100.0f, -1465.0f }, { 60.0f, 1100.0f, -1180.0f } }, + { 0x02, 0xFF, 0x0101, 32, 0, 70.0f, 1.0f, { 60.0f, 1100.0f, -1030.0f }, { 60.0f, 1150.0f, -740.0f } }, + { 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801224BC[7] = { + { 0x0F, 0xFF, 0x0101, 5, 0, 70.0f, 1.0f, { 60.0f, 1800.0f, -920.0f }, { 60.0f, 1860.0f, -800.0f } }, + { 0x03, 0xFF, 0x0101, 20, 0, 70.0f, 0.1f, { 60.0f, 1720.0f, -920.0f }, { 60.0f, 1780.0f, -800.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0142, 1, 0, 75.0f, 1.0f, { 0.0f, 70.0f, 0.0f }, { 60.0f, 990.0f, -690.0f } }, + { 0x03, 0xFF, 0x0142, 119, 0, 75.0f, 0.05f, { 0.0f, 70.0f, 0.0f }, { 60.0f, 990.0f, -690.0f } }, + { 0x03, 0xFF, 0x4242, 20, 0, 60.0f, 0.1f, { 0.0f, 70.0f, 0.0f }, { 0.0f, 100.0f, 200.0f } }, + { 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801225D4[5] = { + { 0x0F, 0x08, 0x0101, 1, 0, 50.0f, 1.0f, { 4100.0f, 1200.0f, -1400.0f }, { 3900.0f, 1100.0f, -1400.0f } }, + { 0x01, 0x3B, 0x0101, 60, 4, 50.0f, 0.94f, { 4100.0f, 965.0f, -1385.0f }, { 3790.0f, 825.0f, -1325.0f } }, + { 0x03, 0xFF, 0x0101, 90, -5, 130.0f, 0.02f, { 4100.0f, 975.0f, -1375.0f }, { 3735.0f, 715.0f, -1325.0f } }, + { 0x0F, 0x08, 0x2323, 2, 0, 60.0f, 1.0f, { 0.0f, 60.0f, 0.0f }, { -10.0f, 15.0f, -200.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012269C[3] = { + { 0x0F, 0xFF, 0x0101, 20, 2, 45.0f, 1.0f, { 975.0f, 225.0f, -1195.0f }, { 918.0f, 228.0f, -1228.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80122714[4] = { + { 0x0F, 0xFF, 0x0101, 20, 0, 45.0f, 1.0f, { -915.0f, -2185.0f, 6335.0f }, { -915.0f, -2290.0f, 6165.0f } }, + { 0x02, 0xFF, 0x0101, -1, 0, 80.0f, 0.8f, { -920.0f, -2270.0f, 6140.0f }, { -920.0f, -2280.0f, 6070.0f } }, + { 0x02, 0xFF, 0x0101, 20, 0, 80.0f, 0.9f, { -920.0f, -2300.0f, 6140.0f }, { -920.0f, -2300.0f, 6070.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801227B4[6] = { + { 0x0F, 0xFF, 0x0101, 30, 0, 60.0f, 1.0f, { 1400.0f, 100.0f, -170.0f }, { 1250.0f, 100.0f, -170.0f } }, + { 0x03, 0xFF, 0x4242, 130, 0, 60.0f, 0.2f, { 0.0f, -5.0f, 0.0f }, { -150.0f, -5.0f, 0.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x02, 0xFF, 0x0303, 69, 0, 85.0f, 1.0f, { -40.0f, 0.0f, 0.0f }, { -40.0f, 0.0f, 0.0f } }, + { 0x02, 0xFF, 0x0303, 20, 0, 60.0f, 1.0f, { 10.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801228A4[5] = { + { 0x0F, 0x01, 0x0101, 20, 5, 30.0f, 1.0f, { 800.0f, -40.0f, 2170.0f }, { 512.0f, 142.0f, 2020.0f } }, + { 0x02, 0xFF, 0x0101, 20, -2, 70.0f, 0.8f, { 800.0f, -40.0f, 2170.0f }, { 512.0f, 142.0f, 2020.0f } }, + { 0x0F, 0x08, 0x0101, 90, 2, 62.0f, 1.0f, { 1140.0f, 125.0f, 1920.0f }, { 1255.0f, 150.0f, 1785.0f } }, + { 0x81, 0xFF, 0x2121, 10, 0, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { 30.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012296C[4] = { + { 0x0F, 0xFF, 0x0101, 20, -10, 70.0f, 1.0f, { -930.0f, 765.0f, -3075.0f }, { -700.0f, 700.0f, -3075.0f } }, + { 0x03, 0xFF, 0x0101, 80, -10, 70.0f, 0.05f, { -930.0f, 205.0f, -3075.0f }, { -700.0f, 140.0f, -3075.0f } }, + { 0x0F, 0xFF, 0x0000, 120, 0, 70.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80122A0C[2] = { + { 0x0F, 0xFF, 0x0101, 60, 4, 50.0f, 1.0f, { 0.0f, 400.0f, -1000.0f }, { -200.0f, 500.0f, -850.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80122A5C[8] = { + { 0x0F, 0xFF, 0x0101, 1, -15, 70.0f, 1.0f, { 230.0f, 3675.0f, -4230.0f }, { -45.0f, 3650.0f, -4415.0f } }, + { 0x15, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { -120.0f, 2187.0f, -3286.0f }, { -110.0f, 2162.0f, -3262.0f } }, + { 0x15, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0101, 55, 0, 60.0f, 1.0f, { -38.0f, 1467.0f, -1102.0f }, { 64.0f, 1423.0f, -1188.0f } }, + { 0x0F, 0xFF, 0x0101, 1, -15, 70.0f, 1.0f, { 230.0f, 3675.0f, -4230.0f }, { -20.0f, 3650.0f, -4400.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80122B9C[3] = { + { 0x0F, 0xFF, 0x0101, 60, 0, 65.0f, 1.0f, { 1095.0f, 2890.0f, -2980.0f }, { 1166.0f, 2695.0f, -2710.0f } }, + { 0x0F, 0xFF, 0x0101, 60, 15, 65.0f, 1.0f, { 566.0f, 4654.0f, -4550.0f }, { 606.0f, 5160.0f, -4740.0f } }, + { 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80122C14[1] = { + { 0x0F, 0xFF, 0x0101, 999, 0, 85.0f, 1.0f, { -15.0f, 185.0f, 160.0f }, { -15.0f, 210.0f, 250.0f } }, +}; + +static OnePointCsFull D_80122C3C[1] = { + { 0x0F, 0xFF, 0x0101, 999, -2, 70.0f, 1.0f, { -62.0f, 60.0f, -315.0f }, { -115.0f, 30.0f, -445.0f } }, +}; + +static OnePointCsFull D_80122C64[1] = { + { 0x0F, 0xFF, 0x0101, 999, 3, 70.0f, 1.0f, { -40.0f, 80.0f, 375.0f }, { -85.0f, 45.0f, 485.0f } }, +}; + +static OnePointCsFull D_80122C8C[1] = { + { 0x0F, 0xFF, 0x0101, 999, 5, 60.0f, 1.0f, { -70.0f, 140.0f, 25.0f }, { 10.0f, 180.0f, 195.0f } }, +}; + +OnePointCsFull D_80122CB4[2] = { + { 0x0F, 0xFF, 0x4242, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 1000.0f }, { 0.0f, 0.0f, 1100.0f } }, + { 0x02, 0xFF, 0x4242, -1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, -100.0f }, { 0.0f, 0.0f, 0.0f } }, +}; + +OnePointCsFull D_80122D04[2] = { + { 0x0F, 0xFF, 0x4242, 10, 0, 60.0f, 1.0f, { 0.0f, 0.0f, -100.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x02, 0xFF, 0x4242, -1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 1000.0f }, { 0.0f, 0.0f, 1100.0f } }, +}; + +static OnePointCsFull D_80122D54[3] = { + { 0x0F, 0xFF, 0x0101, 1, -4, 50.0f, 1.0f, { 230.0f, 65.0f, 300.0f }, { 50.0f, 50.0f, 225.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80122DCC[3] = { + { 0x0F, 0xFF, 0x0101, 1, 0, 50.0f, 1.0f, { 0.0f, 5.0f, -145.0f }, { 0.0f, 55.0f, 55.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80122E44[2][7] = { + { + { 0x83, 0xFF, 0x2222, 10, 5, 90.0f, 0.2f, { 50.0f, 100.0f, 140.0f }, { -30.0f, 10.0f, -20.0f } }, + { 0x8F, 0xFF, 0x0000, 20, 0, 90.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x03, 0xFF, 0x4343, 30, -5, 50.0f, 0.2f, { -10.0f, 80.0f, 10.0f }, { 20.0f, 20.0f, 120.0f } }, + { 0x10, 0xFF, 0x0000, 1, -5, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0B, 0x01, 0x4343, 160, 10, 80.0f, 0.005f, { -50.0f, 60.0f, 0.0f }, { -100.0f, 20.0f, 50.0f } }, + { 0x02, 0xFF, 0x0501, 50, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, 80.0f } }, + { 0x13, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + }, + { + { 0x83, 0xFF, 0x2222, 10, -5, 90.0f, 0.2f, { -50.0f, 100.0f, 140.0f }, { 30.0f, 10.0f, -20.0f } }, + { 0x8F, 0xFF, 0x0000, 20, 0, 90.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x03, 0xFF, 0x4343, 30, 5, 50.0f, 0.2f, { 10.0f, 80.0f, 10.0f }, { -20.0f, 20.0f, 120.0f } }, + { 0x10, 0xFF, 0x0000, 1, 5, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0B, 0x01, 0x4343, 160, -10, 80.0f, 0.005f, { 50.0f, 60.0f, 0.0f }, { 100.0f, 20.0f, 50.0f } }, + { 0x02, 0xFF, 0x0501, 50, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, 80.0f } }, + { 0x13, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + }, +}; + +static OnePointCsFull D_80123074[5] = { + { 0x8F, 0xFF, 0xA2A2, 2, 8, 70.0f, 1.0f, { -27.0f, -96.0f, 25.0f }, { 37.0f, -5.0f, 100.0f } }, + { 0x81, 0xFF, 0xA2A2, 38, 4, 60.0f, 1.0f, { 64.0f, -109.0f, 55.0f }, { 37.0f, 150.0f, 155.0f } }, + { 0x8F, 0xFF, 0xA2A2, 2, 8, 70.0f, 1.0f, { 45.0f, 123.0f, 45.0f }, { 70.0f, 5.0f, 125.0f } }, + { 0x81, 0xFF, 0xA2A2, 58, 4, 60.0f, 0.9f, { 82.0f, 95.0f, 55.0f }, { 25.0f, -175.0f, 180.0f } }, + { 0x92, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_8012313C[3] = { + { 0x8F, 0xFF, 0xA2A2, 20, 8, 70.0f, 1.0f, { 65.0f, -150.0f, 50.0f }, { 30.0f, 10.0f, 90.0f } }, + { 0x81, 0xFF, 0xA2A2, 100, 0, 60.0f, 1.0f, { 70.0f, -160.0f, 50.0f }, { 25.0f, 180.0f, 180.0f } }, + { 0x92, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_801231B4[4] = { + { 0x8F, 0xC5, 0x4343, 1, 0, 50.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 5.0f, -1.0f } }, + { 0x81, 0xC5, 0x4343, 48, 0, 50.0f, 0.75f, { 0.0f, 80.0f, 0.0f }, { 0.0f, 15.0f, -1.0f } }, + { 0x8F, 0xC5, 0x4343, 1, 5, 45.0f, 1.0f, { 0.0f, 0.0f, 30.0f }, { 30.0f, 120.0f, 60.0f } }, + { 0x81, 0xC5, 0x4343, -1, 0, -1.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80123254[2] = { + { 0x0F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x03, 0xC5, 0x0101, 49, 0, 50.0f, 0.05f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, +}; + +OnePointCsFull D_801232A4[1] = { + { 0x0F, 0x45, 0x0101, 9999, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, +}; + +static OnePointCsFull D_801232CC[5] = { + { 0x01, 0xFF, 0x0101, 45, -3, 65.0f, 1.0f, { -52.0f, 84.0f, -846.0f }, { -159.0f, 33.0f, -729.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0000, 10, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x01, 0xFF, 0x2121, 15, 0, 60.0f, 1.0f, { 10.0f, -5.0f, 0.0f }, { 0.0f, 0.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_80123394[5] = { + { 0x01, 0xFF, 0x0101, 45, 3, 65.0f, 1.0f, { -16.0f, 87.0f, -829.0f }, { 98.0f, 24.0f, -714.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0000, 10, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x01, 0xFF, 0x2121, 15, 0, 60.0f, 1.0f, { 10.0f, -5.0f, 0.0f }, { 0.0f, 0.0f, -150.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012345C[4] = { + { 0x01, 0x01, 0x4242, 40, 0, 40.0f, 1.0f, { 0.0f, 50.0f, -40.0f }, { 0.0f, 60.0f, -160.0f } }, + { 0x04, 0x4D, 0x4242, 40, 0, 60.0f, 0.3f, { 0.0f, 90.0f, -40.0f }, { 0.0f, 60.0f, -160.0f } }, + { 0x04, 0x01, 0x2121, 10, 0, 60.0f, 0.2f, { 0.0f, -10.0f, 10.0f }, { 0.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801234FC[5] = { + { 0x01, 0x05, 0x0441, 10, 0, 70.0f, 1.0f, { 0.0f, -10.0f, 20.0f }, { 0.0f, 0.0f, 120.0f } }, + { 0x03, 0xFF, 0x4141, 30, 0, 50.0f, 0.1f, { 0.0f, -10.0f, 20.0f }, { 0.0f, 10.0f, 80.0f } }, + { 0x10, 0x01, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x82, 0xFF, 0x2121, 10, 0, 60.0f, 0.9f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_801235C4[5] = { + { 0x0F, 0x01, 0x4141, 1, 0, 50.0f, 1.0f, { 0.0f, -10.0f, 20.0f }, { 0.0f, 10.0f, 60.0f } }, + { 0x83, 0xFF, 0x0441, 39, 0, 70.0f, 0.1f, { 0.0f, -10.0f, 20.0f }, { 0.0f, 0.0f, 100.0f } }, + { 0x10, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x82, 0xFF, 0x2121, 15, 0, 60.0f, 0.9f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, -80.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +static OnePointCsFull D_8012368C[4] = { + { 0x0F, 0xFF, 0x0101, 10, 0, 60.0f, 1.0f, { -1110.0f, -180.0f, -840.0f }, { -985.0f, -220.0f, -840.0f } }, + { 0x02, 0xFF, 0x0101, 70, -45, 75.0f, 1.0f, { -1060.0f, -160.0f, -840.0f }, { -1005.0f, -230.0f, -840.0f } }, + { 0x0F, 0xFF, 0x0000, 10, -45, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x0F, 0xFF, 0x0101, 180, 9, 80.0f, 1.0f, { -1205.0f, -175.0f, -840.0f }, { -1305.0f, -230.0f, -828.0f } }, +}; + +static OnePointCsFull D_8012372C[4] = { + { 0x0F, 0xFF, 0x0142, 10, 0, 70.0f, 1.0f, { 0.0f, 80.0f, 0.0f }, { -1650.0f, 200.0f, -2920.0f } }, + { 0x02, 0xFF, 0x0142, 110, -2, 50.0f, 0.5f, { 0.0f, 150.0f, 0.0f }, { -1320.0f, 170.0f, -2900.0f } }, + { 0x0B, 0xFF, 0x4242, 100, 2, 70.0f, 0.1f, { 0.0f, 150.0f, 50.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x03, 0xFF, 0x4242, 60, 2, 45.0f, 0.01f, { 0.0f, 150.0f, 50.0f }, { 0.0f, 200.0f, -80.0f } }, +}; + +static OnePointCsFull D_801237CC[5] = { + { 0x8F, 0xFF, 0x4242, 20, 0, 50.0f, 1.0f, { 0.0f, 50.0f, -10.0f }, { 0.0f, 0.0f, 100.0f } }, + { 0x0A, 0xFF, 0x0101, 80, 0, 75.0f, 1.0f, { 2900.0f, 1300.0f, 530.0f }, { 2800.0f, 1190.0f, 540.0f } }, + { 0x0F, 0xFF, 0x0000, 10, 0, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, + { 0x02, 0xFF, 0x0101, 55, 0, 75.0f, 1.0f, { 2900.0f, 1300.0f, 530.0f }, { 1500.0f, 1415.0f, 650.0f } }, + { 0x0F, 0xFF, 0x0000, 100, -45, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; + +OnePointCsFull D_80123894[3] = { + { 0x0F, 0xFF, 0x0101, 60, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x0F, 0xFF, 0x4242, 30, 0, 50.0f, 1.0f, { 0.0f, 28.0f, 0.0f }, { 0.0f, 20.0f, 40.0f } }, + { 0x0D, 0xFF, 0x0000, 120, 0, 180.0f, 0.4f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 2.0f, 40.0f } }, +}; + +OnePointCsFull D_8012390C[2] = { + { 0x0F, 0xFF, 0x0101, 30, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x0F, 0xFF, 0x4242, 180, 0, 60.0f, 1.0f, { 0.0f, 78.0f, 0.0f }, { 0.0f, 78.0f, 200.0f } }, +}; + +OnePointCsFull D_8012395C[3] = { + { 0x0F, 0xFF, 0x0101, 60, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x0F, 0xFF, 0x4242, 30, 0, 50.0f, 1.0f, { 0.0f, 28.0f, 0.0f }, { 0.0f, 20.0f, -45.0f } }, + { 0x0D, 0xFF, 0x0000, 120, 0, 180.0f, 0.4f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 2.0f, 45.0f } }, +}; + +OnePointCsFull D_801239D4[3] = { + { 0x0F, 0xFF, 0x4242, 5, 0, 60.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 40.0f, -120.0f } }, + { 0x09, 0xFF, 0x4242, 0, 0, 60.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, + { 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } }, +}; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 5c5db3c9f..3ddd59908 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2438,6 +2438,7 @@ void Interface_UpdateMagicBar(GlobalContext* globalCtx) { { 255, 255, 150 }, { 255, 255, 50 }, }; + if (CVar_GetS32("gHudColors", 1) == 2) { //This will make custom color based on users selected colors. sMagicBorderColors[0][0] = CVar_GetS32("gCCMagicBorderPrimR", 255); sMagicBorderColors[0][1] = CVar_GetS32("gCCMagicBorderPrimG", 255); @@ -2455,6 +2456,7 @@ void Interface_UpdateMagicBar(GlobalContext* globalCtx) { sMagicBorderColors[3][1] = CVar_GetS32("gCCMagicBorderPrimG", 255)/2; sMagicBorderColors[3][2] = CVar_GetS32("gCCMagicBorderPrimB", 255)/2; } + static s16 sMagicBorderIndexes[] = { 0, 1, 1, 0 }; static s16 sMagicBorderRatio = 2; static s16 sMagicBorderStep = 1; @@ -2700,7 +2702,6 @@ void Interface_DrawMagicBar(GlobalContext* globalCtx) { // Fill the rest of the bar with the normal magic color gDPPipeSync(OVERLAY_DISP++); - gDPPipeSync(OVERLAY_DISP++); if (CVar_GetS32("gHudColors", 1) == 2) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCMagicPrimR", 0), CVar_GetS32("gCCMagicPrimG", 200), CVar_GetS32("gCCMagicPrimB", 0), interfaceCtx->magicAlpha); } else { @@ -2794,7 +2795,7 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { s16 C_Right_BTN_Pos[] = { C_RIGHT_BUTTON_X+Right_HUD_Margin, C_RIGHT_BUTTON_Y+(Top_HUD_Margin*-1) }; s16 C_Up_BTN_Pos[] = { C_UP_BUTTON_X+Right_HUD_Margin, C_UP_BUTTON_Y+(Top_HUD_Margin*-1) }; s16 C_Down_BTN_Pos[] = { C_DOWN_BUTTON_X+Right_HUD_Margin, C_DOWN_BUTTON_Y+(Top_HUD_Margin*-1) }; - + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_parameter.c", 2900); // B Button Color & Texture @@ -2802,11 +2803,11 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { gDPPipeSync(OVERLAY_DISP++); gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 150, 0, interfaceCtx->bAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 150, 0, interfaceCtx->bAlpha); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_B_BTN_COLOR(0), R_B_BTN_COLOR(1), R_B_BTN_COLOR(2), interfaceCtx->bAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_B_BTN_COLOR(0), R_B_BTN_COLOR(1), R_B_BTN_COLOR(2), interfaceCtx->bAlpha); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCBBtnPrimR", 90), CVar_GetS32("gCCBBtnPrimG", 90), CVar_GetS32("gCCBBtnPrimB", 255), interfaceCtx->bAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCBBtnPrimR", 90), CVar_GetS32("gCCBBtnPrimG", 90), CVar_GetS32("gCCBBtnPrimB", 255), interfaceCtx->bAlpha); } gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255); @@ -2817,11 +2818,11 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { // C-Left Button Color & Texture gDPPipeSync(OVERLAY_DISP++); if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cLeftAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cLeftAlpha); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cLeftAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cLeftAlpha); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cLeftAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cLeftAlpha); } gSPWideTextureRectangle(OVERLAY_DISP++, OTRGetRectDimensionFromRightEdge(C_Left_BTN_Pos[0]) << 2, C_Left_BTN_Pos[1] << 2, (OTRGetRectDimensionFromRightEdge(C_Left_BTN_Pos[0]) + R_ITEM_BTN_WIDTH(1)) << 2, @@ -2830,11 +2831,11 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { // C-Down Button Color & Texture if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cDownAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cDownAlpha); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cDownAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cDownAlpha); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cDownAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cDownAlpha); } gSPWideTextureRectangle(OVERLAY_DISP++, OTRGetRectDimensionFromRightEdge(C_Down_BTN_Pos[0]) << 2, C_Down_BTN_Pos[1] << 2, (OTRGetRectDimensionFromRightEdge(C_Down_BTN_Pos[0]) + R_ITEM_BTN_WIDTH(2)) << 2, @@ -2843,13 +2844,13 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { // C-Right Button Color & Texture if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cRightAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cRightAlpha); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cRightAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cRightAlpha); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cRightAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cRightAlpha); } - SPWideTextureRectangle(OVERLAY_DISP++, OTRGetRectDimensionFromRightEdge(C_Right_BTN_Pos[0]) << 2, C_Right_BTN_Pos[1] << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, OTRGetRectDimensionFromRightEdge(C_Right_BTN_Pos[0]) << 2, C_Right_BTN_Pos[1] << 2, (OTRGetRectDimensionFromRightEdge(C_Right_BTN_Pos[0]) + R_ITEM_BTN_WIDTH(3)) << 2, (C_Right_BTN_Pos[1] + R_ITEM_BTN_WIDTH(3)) << 2, G_TX_RENDERTILE, 0, 0, R_ITEM_BTN_DD(3) << 1, R_ITEM_BTN_DD(3) << 1); @@ -2859,11 +2860,11 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { // Start Button Texture, Color & Label gDPPipeSync(OVERLAY_DISP++); if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 0, 0, interfaceCtx->startAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 0, 0, interfaceCtx->startAlpha); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 120, 120, interfaceCtx->startAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 120, 120, interfaceCtx->startAlpha); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCStartBtnPrimR", 120), CVar_GetS32("gCCStartBtnPrimG", 120), CVar_GetS32("gCCStartBtnPrimB", 120), interfaceCtx->startAlpha); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCStartBtnPrimR", 120), CVar_GetS32("gCCStartBtnPrimG", 120), CVar_GetS32("gCCStartBtnPrimB", 120), interfaceCtx->startAlpha); } gSPWideTextureRectangle(OVERLAY_DISP++, OTRGetRectDimensionFromRightEdge(startButtonLeftPos[gSaveContext.language]+Right_HUD_Margin) << 2, 68+((Top_HUD_Margin*-1)*4), (OTRGetRectDimensionFromRightEdge(startButtonLeftPos[gSaveContext.language]+Right_HUD_Margin) + 22) << 2, 156+((Top_HUD_Margin*-1)*4), @@ -2906,12 +2907,12 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { const s16 rCUpBtnX = OTRGetRectDimensionFromRightEdge(R_C_UP_BTN_X+Right_HUD_Margin); const s16 rCUPIconX = OTRGetRectDimensionFromRightEdge(R_C_UP_ICON_X+Right_HUD_Margin); - if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), temp); + if (CVar_GetS32("gHudColors", 1) == 0) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), temp); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), temp); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), temp); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), temp); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), temp); } gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); gSPWideTextureRectangle(OVERLAY_DISP++, rCUpBtnX << 2, R_C_UP_BTN_Y+(Top_HUD_Margin*-1) << 2, (rCUpBtnX + 16) << 2, @@ -2945,27 +2946,19 @@ void Interface_DrawItemButtons(GlobalContext* globalCtx) { if (temp == 1) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cLeftAlpha); - if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), - CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cLeftAlpha); - } } else if (temp == 2) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cDownAlpha); - if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), - CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cDownAlpha); - } } else { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), interfaceCtx->cRightAlpha); - if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), - CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cRightAlpha); - } } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), + CVar_GetS32("gCCCBtnPrimB", 0), interfaceCtx->cRightAlpha); + } + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, OTRGetRectDimensionFromRightEdge(R_ITEM_BTN_X(temp)+Right_HUD_Margin), R_ITEM_BTN_Y(temp)+(Top_HUD_Margin*-1), R_ITEM_BTN_WIDTH(temp), R_ITEM_BTN_WIDTH(temp), R_ITEM_BTN_DD(temp) << 1, R_ITEM_BTN_DD(temp) << 1); @@ -3050,7 +3043,7 @@ void Interface_DrawAmmoCount(GlobalContext* globalCtx, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, OTRGetRectDimensionFromRightEdge(R_ITEM_AMMO_X(button)+Right_HUD_Margin), R_ITEM_AMMO_Y(button)+(Top_HUD_Margin*-1), 8, 8, 1 << 10, 1 << 10); } @@ -3281,7 +3274,7 @@ void Interface_Draw(GlobalContext* globalCtx) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, rColor[0], rColor[1], rColor[2], interfaceCtx->magicAlpha); gDPSetEnvColor(OVERLAY_DISP++, 0, 80, 0, 255); } - + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gRupeeCounterIconTex, 16, 16, OTRGetRectDimensionFromLeftEdge(26+(Left_HUD_Margin*-1)), 206+(Bottom_HUD_Margin), 16, 16, 1 << 10, 1 << 10); @@ -3303,8 +3296,14 @@ void Interface_Draw(GlobalContext* globalCtx) { if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] >= 0) { // Small Key Icon gDPPipeSync(OVERLAY_DISP++); - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 230, 255, interfaceCtx->magicAlpha); - gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 20, 255); + + if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCKeysPrimR", 200), CVar_GetS32("gCCKeysPrimG", 230), CVar_GetS32("gCCKeysPrimB", 255), interfaceCtx->magicAlpha); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 255); //We reset this here so it match user color :) + } else { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 200, 230, 255, interfaceCtx->magicAlpha); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 20, 255); + } OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, OTRGetRectDimensionFromLeftEdge(26+(Left_HUD_Margin*-1)), 190+(Bottom_HUD_Margin), 16, 16, 1 << 10, 1 << 10); @@ -3326,7 +3325,7 @@ void Interface_Draw(GlobalContext* globalCtx) { if (interfaceCtx->counterDigits[2] != 0) { OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, ((u8*)((u8*)digitTextures[interfaceCtx->counterDigits[2]])), 8, - 16, svar3, 190, 8, 16, 1 << 10, 1 << 10); + 16, svar3, 190+(Bottom_HUD_Margin), 8, 16, 1 << 10, 1 << 10); svar3 += 8; } @@ -3497,7 +3496,6 @@ void Interface_Draw(GlobalContext* globalCtx) { } else if (CVar_GetS32("gHudColors", 1) == 2) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 90), CVar_GetS32("gCCABtnPrimG", 90), CVar_GetS32("gCCABtnPrimB", 255), interfaceCtx->aAlpha); } - if (fullUi) { Interface_DrawActionButton(globalCtx, rABtnX, R_A_BTN_Y+(Top_HUD_Margin*-1)); } diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 6218b7d76..632ed41f6 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -5,6 +5,8 @@ #include "soh/Enhancements/gameconsole.h" +#include "soh/frame_interpolation.h" + void* D_8012D1F0 = NULL; //UNK_TYPE D_8012D1F4 = 0; // unused Input* D_8012D1F8 = NULL; @@ -421,7 +423,7 @@ void Gameplay_Update(GlobalContext* globalCtx) { input = globalCtx->state.input; - if ((SREG(1) < 0) || (DREG(0) != 0)) { + if ((SREG(1) < 0) || (DREG(0) != 0)) { SREG(1) = 0; ZeldaArena_Display(); } @@ -1379,7 +1381,9 @@ void Gameplay_Main(GameState* thisx) { LOG_NUM("1", 1, "../z_play.c", 4583); } + FrameInterpolation_StartRecord(); Gameplay_Draw(globalCtx); + FrameInterpolation_StopRecord(); if (1 && HREG(63)) { LOG_NUM("1", 1, "../z_play.c", 4587); diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index a8bd93f43..cebdca3a3 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -654,7 +654,7 @@ u8 sEyeMouthIndexes[][2] = { * from adult Link's object are used here. */ -#if defined(MODDING) || (_MSC_VER) +#if defined(MODDING) || defined(_MSC_VER) || defined(__GNUC__) //TODO: Formatting void* sEyeTextures[2][8] = { { gLinkAdultEyesOpenTex, gLinkAdultEyesHalfTex, gLinkAdultEyesClosedfTex, gLinkAdultEyesRollLeftTex, @@ -670,7 +670,7 @@ void* sEyeTextures[] = { }; #endif -#if defined(modding) || defined(_MSC_VER) +#if defined(MODDING) || defined(_MSC_VER) || defined(__GNUC__) void* sMouthTextures[2][4] = { { gLinkAdultMouth1Tex, @@ -726,7 +726,7 @@ void func_8008F470(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, if (eyeIndex > 7) eyeIndex = 7; -#if defined(MODDING) || (_MSC_VER) +#if defined(MODDING) || defined(_MSC_VER) || defined(__GNUC__) gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[gSaveContext.linkAge][eyeIndex])); #else gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[eyeIndex])); @@ -738,12 +738,11 @@ void func_8008F470(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, if (mouthIndex > 3) mouthIndex = 3; -#if defined(MODDING) || (_MSC_VER) +#if defined(MODDING) || defined(_MSC_VER) || defined(__GNUC__) gSPSegment(POLY_OPA_DISP++, 0x09, SEGMENTED_TO_VIRTUAL(sMouthTextures[gSaveContext.linkAge][mouthIndex])); #else gSPSegment(POLY_OPA_DISP++, 0x09, SEGMENTED_TO_VIRTUAL(sMouthTextures[eyeIndex])); #endif - if (CVar_GetS32("gUseTunicsCol",0) != 1) { //Mod is not on bring back original colors. color = &sTunicColors[tunic]; } diff --git a/soh/src/code/z_skelanime.c b/soh/src/code/z_skelanime.c index 2c03390e9..6dbfac7ef 100644 --- a/soh/src/code/z_skelanime.c +++ b/soh/src/code/z_skelanime.c @@ -863,7 +863,7 @@ void AnimationContext_SetLoadFrame(GlobalContext* globalCtx, LinkAnimationHeader char animPath[2048]; - sprintf(animPath, "misc\\link_animetion\\gPlayerAnimData_%06X", (((uintptr_t)linkAnimHeader->segment - 0x07000000))); + sprintf(animPath, "misc/link_animetion/gPlayerAnimData_%06X", (((uintptr_t)linkAnimHeader->segment - 0x07000000))); //printf("Streaming %s, seg = %08X\n", animPath, linkAnimHeader->segment); @@ -877,7 +877,7 @@ void AnimationContext_SetLoadFrame(GlobalContext* globalCtx, LinkAnimationHeader { ramPtr[i] = i * 7; }*/ - + //DmaMgr_SendRequest2(&entry->data.load.req, ram, //LINK_ANIMATION_OFFSET(linkAnimHeader->segment, ((sizeof(Vec3s) * limbCount + 2) * frame)), diff --git a/soh/src/code/z_skin_matrix.c b/soh/src/code/z_skin_matrix.c index f7df8091f..d822d6c13 100644 --- a/soh/src/code/z_skin_matrix.c +++ b/soh/src/code/z_skin_matrix.c @@ -1,6 +1,8 @@ #include "global.h" #include "vt.h" +#include "soh/frame_interpolation.h" + // clang-format off MtxF sMtxFClear = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -523,6 +525,7 @@ void SkinMatrix_Vec3sToVec3f(Vec3s* src, Vec3f* dest) { } void SkinMatrix_MtxFToMtx(MtxF* src, Mtx* dest) { + FrameInterpolation_RecordSkinMatrixMtxFToMtx(src, dest); guMtxF2L(src, dest); } diff --git a/soh/src/code/z_view.c b/soh/src/code/z_view.c index 97f1ad26e..e03daee83 100644 --- a/soh/src/code/z_view.c +++ b/soh/src/code/z_view.c @@ -2,6 +2,9 @@ #include "vt.h" #include +#include + +#include "soh/frame_interpolation.h" vu32 D_8012ABF0 = true; @@ -277,6 +280,10 @@ void func_800AAA50(View* view, s32 arg1) { } } +static float sqr(float a) { + return a * a; +} + s32 func_800AAA9C(View* view) { f32 aspect; s32 width; @@ -307,6 +314,85 @@ s32 func_800AAA9C(View* view) { height = view->viewport.bottomY - view->viewport.topY; aspect = (f32)width / (f32)height; + viewing = Graph_Alloc(gfxCtx, sizeof(Mtx)); + LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667); + view->viewingPtr = viewing; + + if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) { + view->eye.x += 1.0f; + view->eye.y += 1.0f; + view->eye.z += 1.0f; + } + + func_800ABE74(view->eye.x, view->eye.y, view->eye.z); + MtxF viewingF; + guLookAtF(viewingF.mf, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x, + view->up.y, view->up.z); + + // Some heuristics to identify instant camera movements and skip interpolation in that case + + static View old_view; + + float dirx = view->eye.x - view->lookAt.x; + float diry = view->eye.y - view->lookAt.y; + float dirz = view->eye.z - view->lookAt.z; + float dir_dist = sqrtf(sqr(dirx) + sqr(diry) + sqr(dirz)); + dirx /= dir_dist; + diry /= dir_dist; + dirz /= dir_dist; + + float odirx = old_view.eye.x - old_view.lookAt.x; + float odiry = old_view.eye.y - old_view.lookAt.y; + float odirz = old_view.eye.z - old_view.lookAt.z; + float odir_dist = sqrtf(sqr(odirx) + sqr(odiry) + sqr(odirz)); + odirx /= odir_dist; + odiry /= odir_dist; + odirz /= odir_dist; + + float eye_dist = sqrtf(sqr(view->eye.x - old_view.eye.x) + sqr(view->eye.y - old_view.eye.y) + sqr(view->eye.z - old_view.eye.z)); + float look_dist = sqrtf(sqr(view->lookAt.x - old_view.lookAt.x) + sqr(view->lookAt.y - old_view.lookAt.y) + sqr(view->lookAt.z - old_view.lookAt.z)); + float up_dist = sqrtf(sqr(view->up.x - old_view.up.x) + sqr(view->up.y - old_view.up.y) + sqr(view->up.z - old_view.up.z)); + float d_dist = sqrtf(sqr(dirx - odirx) + sqr(diry - odiry) + sqr(dirz - odirz)); + + bool dont_interpolate = false; + + if (up_dist < 0.01 && d_dist < 0.01) { + if (eye_dist + look_dist > 300) { + dont_interpolate = true; + } + } else { + if (eye_dist >= 400) { + dont_interpolate = true; + } + if (look_dist >= 100) { + dont_interpolate = true; + } + if (up_dist >= 1.50f) { + dont_interpolate = true; + } + if (d_dist >= 1.414f && look_dist >= 15) { + dont_interpolate = true; + } + if (d_dist >= 1.414f && up_dist >= 0.31f && look_dist >= 1 && eye_dist >= 300) { + dont_interpolate = true; + } + if (d_dist >= 0.5f && up_dist >= 0.31f && look_dist >= 3 && eye_dist >= 170) { + dont_interpolate = true; + } + if (look_dist >= 52 && eye_dist >= 52) { + dont_interpolate = true; + } + if (look_dist >= 30 && eye_dist >= 90) { + dont_interpolate = true; + } + } + + if (dont_interpolate) { + FrameInterpolation_DontInterpolateCamera(); + } + + FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch()); + if (HREG(80) == 11) { if (HREG(94) != 11) { HREG(94) = 11; @@ -347,22 +433,17 @@ s32 func_800AAA9C(View* view) { gSPPerspNormalize(POLY_KAL_DISP++, view->normal); gSPMatrix(POLY_KAL_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); - viewing = Graph_Alloc(gfxCtx, sizeof(Mtx)); - LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667); - view->viewingPtr = viewing; - - if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) { - view->eye.x += 1.0f; - view->eye.y += 1.0f; - view->eye.z += 1.0f; - } - - func_800ABE74(view->eye.x, view->eye.y, view->eye.z); - guLookAt(viewing, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x, - view->up.y, view->up.z); + Matrix_MtxFToMtx(viewingF.mf, viewing); view->viewing = *viewing; + + /*if (eye_dist > 1 || look_dist > 1 || abs(up_dist) > 0.1 || abs(d_dist) > 0.1) + printf("%d %f %f %f, %f %f %f, %f %f %f, %f %f %f %f %d\n", (int)view->fovy, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, + view->up.x, view->up.y, view->up.z, eye_dist, look_dist, up_dist, d_dist, dont_interpolate);*/ + + old_view = *view; + if (QREG(88) & 2) { s32 i; MtxF mf; @@ -374,10 +455,10 @@ s32 func_800AAA9C(View* view) { } osSyncPrintf("\n"); } - gSPMatrix(POLY_OPA_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(POLY_XLU_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(POLY_KAL_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + FrameInterpolation_RecordCloseChild(); CLOSE_DISPS(gfxCtx, "../z_view.c", 711); diff --git a/soh/src/code/z_vismono.c b/soh/src/code/z_vismono.c index 82acc9a17..2af876ad6 100644 --- a/soh/src/code/z_vismono.c +++ b/soh/src/code/z_vismono.c @@ -42,7 +42,7 @@ Gfx* VisMono_DrawTexture(VisMono* this, Gfx* gfx) s32 y; s32 height = 3; //u16* tex = D_0F000000; - u16* tex = 0xFF000000; + u16* tex = SEG_ADDR(0xF, 0); gDPPipeSync(gfx++); gDPSetOtherMode(gfx++, diff --git a/soh/src/code/z_vr_box_draw.c b/soh/src/code/z_vr_box_draw.c index 292789333..13eb93bd0 100644 --- a/soh/src/code/z_vr_box_draw.c +++ b/soh/src/code/z_vr_box_draw.c @@ -1,5 +1,7 @@ #include "global.h" +#include "soh/frame_interpolation.h" + Mtx* sSkyboxDrawMatrix; Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) { @@ -13,6 +15,7 @@ Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) { void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z) { OPEN_DISPS(gfxCtx, "../z_vr_box_draw.c", 52); + FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch()); func_800945A0(gfxCtx); @@ -85,7 +88,7 @@ void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyb gDPPipeSync(POLY_OPA_DISP++); //gsSPShaderTest2(POLY_OPA_DISP++); - + FrameInterpolation_RecordCloseChild(); CLOSE_DISPS(gfxCtx, "../z_vr_box_draw.c", 125); } diff --git a/soh/src/libultra/gu/guLookAt.c b/soh/src/libultra/gu/guLookAt.c index 58946f4dc..f94204bc4 100644 --- a/soh/src/libultra/gu/guLookAt.c +++ b/soh/src/libultra/gu/guLookAt.c @@ -62,5 +62,6 @@ void guLookAt(Mtx* m, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp); - guMtxF2L((MtxF*)mf, m); + //guMtxF2L((MtxF*)mf, m); + Matrix_MtxFToMtx((MtxF*)mf, m); } diff --git a/soh/src/libultra/gu/guPerspectiveF.c b/soh/src/libultra/gu/guPerspectiveF.c index 731cec3e9..dd020f589 100644 --- a/soh/src/libultra/gu/guPerspectiveF.c +++ b/soh/src/libultra/gu/guPerspectiveF.c @@ -37,6 +37,6 @@ void guPerspective(Mtx* m, u16* perspNorm, f32 fovy, f32 aspect, f32 near, f32 f f32 mf[4][4]; guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale); - guMtxF2L((MtxF*)mf, m); - + //guMtxF2L((MtxF*)mf, m); + Matrix_MtxFToMtx((MtxF*)mf, m); } diff --git a/soh/src/libultra/gu/ortho.c b/soh/src/libultra/gu/ortho.c index 517ba1dcc..77d43ce21 100644 --- a/soh/src/libultra/gu/ortho.c +++ b/soh/src/libultra/gu/ortho.c @@ -1,5 +1,7 @@ #include "global.h" +#include "soh/frame_interpolation.h" + void guOrthoF(f32 mf[4][4], f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far, f32 scale) { s32 i, j; @@ -25,5 +27,8 @@ void guOrtho(Mtx* mtx, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 f guOrthoF(mf, left, right, bottom, top, near, far, scale); - guMtxF2L((MtxF*)mf, mtx); + //guMtxF2L((MtxF*)mf, mtx); + FrameInterpolation_RecordOpenChild("ortho", 0); + Matrix_MtxFToMtx((MtxF*)mf, mtx); + FrameInterpolation_RecordCloseChild(); } diff --git a/soh/src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.c b/soh/src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.c index 260fa21ea..9ca8599b9 100644 --- a/soh/src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.c +++ b/soh/src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.c @@ -121,8 +121,8 @@ void BgDdanKd_CheckForExplosions(BgDdanKd* this, GlobalContext* globalCtx) { } } -static Vec3f velocity = { 0.0f, 5.0f, 0.0f }; -static Vec3f accel = { 0.0f, -0.45f, 0.0f }; +Vec3f sBgDdanKdVelocity = { 0.0f, 5.0f, 0.0f }; +Vec3f sBgDdanKdAccel = { 0.0f, -0.45f, 0.0f }; void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) { Vec3f pos1; @@ -158,11 +158,11 @@ void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) { func_80033480(globalCtx, &pos1, 20.0f, 1, effectStrength * 135.0f, 60, 1); func_80033480(globalCtx, &pos2, 20.0f, 1, effectStrength * 135.0f, 60, 1); - velocity.x = Rand_CenteredFloat(3.0f); - velocity.z = Rand_CenteredFloat(3.0f); + sBgDdanKdVelocity.x = Rand_CenteredFloat(3.0f); + sBgDdanKdVelocity.z = Rand_CenteredFloat(3.0f); - func_8003555C(globalCtx, &pos1, &velocity, &accel); - func_8003555C(globalCtx, &pos2, &velocity, &accel); + func_8003555C(globalCtx, &pos1, &sBgDdanKdVelocity, &sBgDdanKdAccel); + func_8003555C(globalCtx, &pos2, &sBgDdanKdVelocity, &sBgDdanKdAccel); pos1 = this->dyna.actor.world.pos; pos1.z += 560.0f + Rand_ZeroOne() * 5.0f; @@ -170,7 +170,7 @@ void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) { pos1.y = Rand_ZeroOne() * 3.0f + (this->dyna.actor.floorHeight + 20.0f); func_80033480(globalCtx, &pos1, 20.0f, 1, effectStrength * 135.0f, 60, 1); - func_8003555C(globalCtx, &pos1, &velocity, &accel); + func_8003555C(globalCtx, &pos1, &sBgDdanKdVelocity, &sBgDdanKdAccel); } Camera_AddQuake(&globalCtx->mainCamera, 0, effectStrength * 0.6f, 3); Audio_PlaySoundGeneral(NA_SE_EV_PILLAR_SINK - SFX_FLAG, &this->dyna.actor.projectedPos, 4, &D_801333E0, @@ -192,11 +192,11 @@ void BgDdanKd_Draw(Actor* thisx, GlobalContext* globalCtx) { } void BgDdanKd_Reset(void) { - velocity.x = 0.0f; - velocity.y = 5.0f; - velocity.z = 0.0f; + sBgDdanKdVelocity.x = 0.0f; + sBgDdanKdVelocity.y = 5.0f; + sBgDdanKdVelocity.z = 0.0f; - accel.x = 0.0f; - accel.y = -0.45f; - accel.z = 0.0f; + sBgDdanKdAccel.x = 0.0f; + sBgDdanKdAccel.y = -0.45f; + sBgDdanKdAccel.z = 0.0f; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.c b/soh/src/overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.c index a089aa013..dbeb5eb7c 100644 --- a/soh/src/overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.c +++ b/soh/src/overlays/actors/ovl_Bg_Dodoago/z_bg_dodoago.c @@ -74,13 +74,13 @@ static ColliderCylinderInit sColCylinderInitLeftRight = { { 50, 60, 280, { 0, 0, 0 } }, }; -static s16 sFirstExplosiveFlag = false; +s16 sBgDodoagoFirstExplosiveFlag = false; -static u8 sDisableBombCatcher; +u8 sBgDodoagoDisableBombCatcher; -static u8 sUnused[90]; // unknown length +//static u8 sUnused[90]; // unknown length -static s32 sTimer; +s32 sBgDodoagoTimer; void BgDodoago_SetupAction(BgDodoago* this, BgDodoagoActionFunc actionFunc) { this->actionFunc = actionFunc; @@ -135,7 +135,7 @@ void BgDodoago_Init(Actor* thisx, GlobalContext* globalCtx) { Collider_SetCylinder(globalCtx, &this->colliderRight, &this->dyna.actor, &sColCylinderInitLeftRight); BgDodoago_SetupAction(this, BgDodoago_WaitExplosives); - sDisableBombCatcher = false; + sBgDodoagoDisableBombCatcher = false; } void BgDodoago_Destroy(Actor* thisx, GlobalContext* globalCtx) { @@ -170,16 +170,16 @@ void BgDodoago_WaitExplosives(BgDodoago* this, GlobalContext* globalCtx) { } else { OnePointCutscene_Init(globalCtx, 3065, 20, &this->dyna.actor, MAIN_CAM); Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - sTimer += 30; + sBgDodoagoTimer += 30; return; } // the flag is never set back to false, so this only runs once - if (!sFirstExplosiveFlag) { + if (!sBgDodoagoFirstExplosiveFlag) { // this disables the bomb catcher (see BgDodoago_Update) for a few seconds this->dyna.actor.parent = explosive; - sFirstExplosiveFlag = true; - sTimer = 50; + sBgDodoagoFirstExplosiveFlag = true; + sBgDodoagoTimer = 50; } } else if (Flags_GetEventChkInf(0xB0)) { Collider_UpdateCylinder(&this->dyna.actor, &this->colliderMain); @@ -219,11 +219,11 @@ void BgDodoago_OpenJaw(BgDodoago* this, GlobalContext* globalCtx) { } if (globalCtx->roomCtx.unk_74[BGDODOAGO_EYE_LEFT] != 255 || globalCtx->roomCtx.unk_74[BGDODOAGO_EYE_RIGHT] != 255) { - sTimer--; + sBgDodoagoTimer--; return; } - if (sTimer == 108) { + if (sBgDodoagoTimer == 108) { for (i = ARRAY_COUNT(dustOffsets) - 1; i >= 0; i--) { pos.x = dustOffsets[i].x + this->dyna.actor.world.pos.x; pos.y = dustOffsets[i].y + this->dyna.actor.world.pos.y; @@ -290,16 +290,16 @@ void BgDodoago_Update(Actor* thisx, GlobalContext* globalCtx) { this->dyna.actor.parent = &bomb->actor; bomb->timer = 50; bomb->actor.speedXZ = 0.0f; - sTimer = 0; + sBgDodoagoTimer = 0; } } } else { - sTimer++; + sBgDodoagoTimer++; Flags_GetSwitch(globalCtx, this->dyna.actor.params & 0x3F); - if (!sDisableBombCatcher && sTimer > 140) { + if (!sBgDodoagoDisableBombCatcher && sBgDodoagoTimer > 140) { if (Flags_GetSwitch(globalCtx, this->dyna.actor.params & 0x3F)) { // this prevents clearing the actor's parent pointer, effectively disabling the bomb catcher - sDisableBombCatcher++; + sBgDodoagoDisableBombCatcher++; } else { this->dyna.actor.parent = NULL; } @@ -322,7 +322,7 @@ void BgDodoago_Draw(Actor* thisx, GlobalContext* globalCtx) { } void BgDodoago_Reset(void) { - sFirstExplosiveFlag = false; - sDisableBombCatcher = 0; - sTimer = 0; + sBgDodoagoFirstExplosiveFlag = false; + sBgDodoagoDisableBombCatcher = 0; + sBgDodoagoTimer = 0; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c b/soh/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c index d1e940619..9616204cd 100644 --- a/soh/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c +++ b/soh/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c @@ -8,6 +8,8 @@ #include "overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h" #include "vt.h" +#include "soh/frame_interpolation.h" + #define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5) typedef enum { @@ -283,6 +285,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { platform = (BgGanonOtyuka*)actor; if (platform->dyna.actor.projectedPos.z > spBC) { + FrameInterpolation_RecordOpenChild(platform, 0); if (camera->eye.y > platform->dyna.actor.world.pos.y) { phi_s2 = sPlatformTopDL; } else { @@ -309,7 +312,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { } for (i = 0; i < ARRAY_COUNT(sSides); i++) { - if (platform->visibleSides & sSides[i]) { + if ((platform->visibleSides & sSides[i]) || 1) { // || 1 for frame interpolation Matrix_Push(); Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY); Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY); @@ -320,6 +323,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { Matrix_Pop(); } } + FrameInterpolation_RecordCloseChild(); } } @@ -333,6 +337,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { platform = (BgGanonOtyuka*)actor; if ((platform->dyna.actor.projectedPos.z > -30.0f) && (platform->flashState != FLASH_NONE)) { + FrameInterpolation_RecordOpenChild(platform, 0); gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, platform->flashTimer * 4, 0, 32, 64, 1, platform->flashTimer * 4, 0, 32, 64)); @@ -344,7 +349,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { Matrix_Translate(platform->dyna.actor.world.pos.x, 0.0f, platform->dyna.actor.world.pos.z, MTXMODE_NEW); for (i = 0; i < ARRAY_COUNT(sSides); i++) { - if (platform->unwalledSides & sSides[i]) { + if ((platform->unwalledSides & sSides[i]) || 1) { // || 1 for frame interpolation Matrix_Push(); Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY); Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY); @@ -356,6 +361,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) { Matrix_Pop(); } } + FrameInterpolation_RecordCloseChild(); } } diff --git a/soh/src/overlays/actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c b/soh/src/overlays/actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c index 7e3cd9155..2a4a4420f 100644 --- a/soh/src/overlays/actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c +++ b/soh/src/overlays/actors/ovl_Bg_Haka_Gate/z_bg_haka_gate.c @@ -47,7 +47,7 @@ void BgHakaGate_SkullOfTruth(BgHakaGate* this, GlobalContext* globalCtx); void BgHakaGate_FalseSkull(BgHakaGate* this, GlobalContext* globalCtx); static s16 sSkullOfTruthRotY = 0x100; -static u8 sPuzzleState = 1; +static u8 sBgPoEventPuzzleState = 1; static f32 sStatueDistToPlayer = 0; static s16 sStatueRotY; @@ -82,7 +82,7 @@ void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx) { if (sSkullOfTruthRotY != 0x100) { this->actionFunc = BgHakaGate_FalseSkull; } else if (ABS(thisx->shape.rot.y) < 0x4000) { - if ((Rand_ZeroOne() * 3.0f) < sPuzzleState) { + if ((Rand_ZeroOne() * 3.0f) < sBgPoEventPuzzleState) { this->vIsSkullOfTruth = true; sSkullOfTruthRotY = thisx->shape.rot.y + 0x8000; if (Flags_GetSwitch(globalCtx, this->switchFlag)) { @@ -91,7 +91,7 @@ void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx) { this->actionFunc = BgHakaGate_SkullOfTruth; } } else { - sPuzzleState++; + sBgPoEventPuzzleState++; this->actionFunc = BgHakaGate_FalseSkull; } } else { @@ -141,7 +141,7 @@ void BgHakaGate_Destroy(Actor* thisx, GlobalContext* globalCtx) { DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); if (this->dyna.actor.params == BGHAKAGATE_STATUE) { sSkullOfTruthRotY = 0x100; - sPuzzleState = 1; + sBgPoEventPuzzleState = 1; } } @@ -178,7 +178,7 @@ void BgHakaGate_StatueIdle(BgHakaGate* this, GlobalContext* globalCtx) { } } } else { - if (sPuzzleState == SKULL_OF_TRUTH_FOUND) { + if (sBgPoEventPuzzleState == SKULL_OF_TRUTH_FOUND) { this->actionFunc = BgHakaGate_StatueInactive; } else { this->vTimer = 0; @@ -192,7 +192,12 @@ void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx) { s16 turnAngle; this->vTurnRateDeg10++; - this->vTurnRateDeg10 = CLAMP_MAX(this->vTurnRateDeg10, 5); + if (CVar_GetS32("gFasterBlockPush", 0) != 0) { + this->vTurnRateDeg10 = 10; + CLAMP_MAX(this->vTurnRateDeg10, 5); + } else { + this->vTurnRateDeg10 = CLAMP_MAX(this->vTurnRateDeg10, 5); + } turnFinished = Math_StepToS(&this->vTurnAngleDeg10, 600, this->vTurnRateDeg10); turnAngle = this->vTurnAngleDeg10 * this->vTurnDirection; this->dyna.actor.shape.rot.y = (this->vRotYDeg10 + turnAngle) * 0.1f * (0x10000 / 360.0f); @@ -212,7 +217,7 @@ void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx) { this->vRotYDeg10 = (this->vRotYDeg10 + turnAngle) % 3600; this->vTurnRateDeg10 = 0; this->vTurnAngleDeg10 = 0; - this->vTimer = 5; + this->vTimer = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 2 : 5; this->actionFunc = BgHakaGate_StatueIdle; this->dyna.unk_150 = 0.0f; } @@ -238,7 +243,7 @@ void BgHakaGate_FloorClosed(BgHakaGate* this, GlobalContext* globalCtx) { sStatueDistToPlayer = 0.0f; if (ABS(yawDiff) < 0x80) { Flags_SetSwitch(globalCtx, this->switchFlag); - sPuzzleState = SKULL_OF_TRUTH_FOUND; + sBgPoEventPuzzleState = SKULL_OF_TRUTH_FOUND; this->actionFunc = BgHakaGate_DoNothing; } else { func_80078884(NA_SE_SY_ERROR); diff --git a/soh/src/overlays/actors/ovl_Bg_Haka_Trap/z_bg_haka_trap.c b/soh/src/overlays/actors/ovl_Bg_Haka_Trap/z_bg_haka_trap.c index 83cd8dfd6..877916b67 100644 --- a/soh/src/overlays/actors/ovl_Bg_Haka_Trap/z_bg_haka_trap.c +++ b/soh/src/overlays/actors/ovl_Bg_Haka_Trap/z_bg_haka_trap.c @@ -28,7 +28,7 @@ void func_80880AE8(BgHakaTrap* this, GlobalContext* globalCtx); void func_80880C0C(BgHakaTrap* this, GlobalContext* globalCtx); void func_80880D68(BgHakaTrap* this); -static UNK_TYPE D_80880F30 = 0; +UNK_TYPE D_80880F30 = 0; const ActorInit Bg_Haka_Trap_InitVars = { ACTOR_BG_HAKA_TRAP, @@ -107,7 +107,7 @@ static InitChainEntry sInitChain[] = { ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP), }; -static UNK_TYPE D_80881014 = 0; +UNK_TYPE D_80881014 = 0; void BgHakaTrap_Init(Actor* thisx, GlobalContext* globalCtx) { BgHakaTrap* this = (BgHakaTrap*)thisx; s32 pad; diff --git a/soh/src/overlays/actors/ovl_Bg_Hidan_Rock/z_bg_hidan_rock.c b/soh/src/overlays/actors/ovl_Bg_Hidan_Rock/z_bg_hidan_rock.c index 4522a9486..a962dbc2e 100644 --- a/soh/src/overlays/actors/ovl_Bg_Hidan_Rock/z_bg_hidan_rock.c +++ b/soh/src/overlays/actors/ovl_Bg_Hidan_Rock/z_bg_hidan_rock.c @@ -120,7 +120,7 @@ void func_8088B24C(BgHidanRock* this) { this->actionFunc = func_8088B990; } -static f32 D_8088BFC0 = 0.0f; +f32 D_8088BFC0 = 0.0f; void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) { f32 sp2C; s32 temp_v1; @@ -137,7 +137,7 @@ void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) { } } - this->dyna.actor.speedXZ += 0.05f; + this->dyna.actor.speedXZ += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.05f; this->dyna.actor.speedXZ = CLAMP_MAX(this->dyna.actor.speedXZ, 2.0f); if (D_8088BFC0 > 0.0f) { @@ -156,7 +156,7 @@ void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) { this->dyna.actor.home.pos.z = this->dyna.actor.world.pos.z; D_8088BFC0 = 0.0f; this->dyna.actor.speedXZ = 0.0f; - this->timer = 5; + this->timer = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 2 : 5; } func_8002F974(&this->dyna.actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG); diff --git a/soh/src/overlays/actors/ovl_Bg_Hidan_Rsekizou/z_bg_hidan_rsekizou.c b/soh/src/overlays/actors/ovl_Bg_Hidan_Rsekizou/z_bg_hidan_rsekizou.c index 73044e8b1..c2599e185 100644 --- a/soh/src/overlays/actors/ovl_Bg_Hidan_Rsekizou/z_bg_hidan_rsekizou.c +++ b/soh/src/overlays/actors/ovl_Bg_Hidan_Rsekizou/z_bg_hidan_rsekizou.c @@ -240,7 +240,8 @@ void BgHidanRsekizou_Draw(Actor* thisx, GlobalContext* globalCtx) { POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x14); - if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0) { + // Strange original code. Add || 1 for frame interpolation to get correct. + if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0 || 1) { for (i = 3; i >= 0; i--) { POLY_XLU_DISP = BgHidanRsekizou_DrawFireball(globalCtx, this, i, &mf, 0, POLY_XLU_DISP); } diff --git a/soh/src/overlays/actors/ovl_Bg_Jya_1flift/z_bg_jya_1flift.c b/soh/src/overlays/actors/ovl_Bg_Jya_1flift/z_bg_jya_1flift.c index 1d50e6c49..dc1a3b758 100644 --- a/soh/src/overlays/actors/ovl_Bg_Jya_1flift/z_bg_jya_1flift.c +++ b/soh/src/overlays/actors/ovl_Bg_Jya_1flift/z_bg_jya_1flift.c @@ -23,7 +23,7 @@ void BgJya1flift_SetupDoNothing(BgJya1flift* this); void BgJya1flift_ResetMoveDelay(BgJya1flift* this); void BgJya1flift_DelayMove(BgJya1flift* this, GlobalContext* globalCtx); -static u8 sIsSpawned = false; +static u8 sKankyoIsSpawned = false; const ActorInit Bg_Jya_1flift_InitVars = { ACTOR_BG_JYA_1FLIFT, @@ -94,9 +94,9 @@ void BgJya1flift_InitCollision(Actor* thisx, GlobalContext* globalCtx) { void BgJya1flift_Init(Actor* thisx, GlobalContext* globalCtx) { BgJya1flift* this = (BgJya1flift*)thisx; // "1 F lift" - osSyncPrintf("(1Fリフト)(flag %d)(room %d)\n", sIsSpawned, globalCtx->roomCtx.curRoom.num); + osSyncPrintf("(1Fリフト)(flag %d)(room %d)\n", sKankyoIsSpawned, globalCtx->roomCtx.curRoom.num); this->hasInitialized = false; - if (sIsSpawned) { + if (sKankyoIsSpawned) { Actor_Kill(thisx); return; } @@ -109,7 +109,7 @@ void BgJya1flift_Init(Actor* thisx, GlobalContext* globalCtx) { BgJya1flift_SetupWaitForSwitch(this); } thisx->room = -1; - sIsSpawned = true; + sKankyoIsSpawned = true; this->hasInitialized = true; } @@ -117,7 +117,7 @@ void BgJya1flift_Destroy(Actor* thisx, GlobalContext* globalCtx) { BgJya1flift* this = (BgJya1flift*)thisx; if (this->hasInitialized) { - sIsSpawned = false; + sKankyoIsSpawned = false; Collider_DestroyCylinder(globalCtx, &this->collider); DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); } diff --git a/soh/src/overlays/actors/ovl_Bg_Jya_Bigmirror/z_bg_jya_bigmirror.c b/soh/src/overlays/actors/ovl_Bg_Jya_Bigmirror/z_bg_jya_bigmirror.c index 934329337..e872a4cdf 100644 --- a/soh/src/overlays/actors/ovl_Bg_Jya_Bigmirror/z_bg_jya_bigmirror.c +++ b/soh/src/overlays/actors/ovl_Bg_Jya_Bigmirror/z_bg_jya_bigmirror.c @@ -14,7 +14,7 @@ void BgJyaBigmirror_Destroy(Actor* thisx, GlobalContext* globalCtx); void BgJyaBigmirror_Update(Actor* thisx, GlobalContext* globalCtx); void BgJyaBigmirror_Draw(Actor* thisx, GlobalContext* globalCtx); -static u8 sIsSpawned = false; +static u8 sKankyoIsSpawned = false; const ActorInit Bg_Jya_Bigmirror_InitVars = { ACTOR_BG_JYA_BIGMIRROR, @@ -176,7 +176,7 @@ void BgJyaBigmirror_HandleMirRay(Actor* thisx, GlobalContext* globalCtx) { void BgJyaBigmirror_Init(Actor* thisx, GlobalContext* globalCtx) { BgJyaBigmirror* this = (BgJyaBigmirror*)thisx; - if (sIsSpawned) { + if (sKankyoIsSpawned) { Actor_Kill(&this->actor); return; } @@ -185,7 +185,7 @@ void BgJyaBigmirror_Init(Actor* thisx, GlobalContext* globalCtx) { this->cobraInfo[0].rotY = sCobraSpawnData[0].initRotY; this->cobraInfo[1].rotY = sCobraSpawnData[1].initRotY; this->actor.room = -1; - sIsSpawned = true; + sKankyoIsSpawned = true; this->spawned = true; this->mirRayObjIndex = -1; @@ -197,7 +197,7 @@ void BgJyaBigmirror_Destroy(Actor* thisx, GlobalContext* globalCtx) { BgJyaBigmirror* this = (BgJyaBigmirror*)thisx; if (this->spawned) { - sIsSpawned = false; + sKankyoIsSpawned = false; } } diff --git a/soh/src/overlays/actors/ovl_Bg_Jya_Cobra/z_bg_jya_cobra.c b/soh/src/overlays/actors/ovl_Bg_Jya_Cobra/z_bg_jya_cobra.c index 3f659ad57..064537f2d 100644 --- a/soh/src/overlays/actors/ovl_Bg_Jya_Cobra/z_bg_jya_cobra.c +++ b/soh/src/overlays/actors/ovl_Bg_Jya_Cobra/z_bg_jya_cobra.c @@ -444,7 +444,7 @@ void func_80896950(BgJyaCobra* this, GlobalContext* globalCtx) { if (this->dyna.unk_150 > 0.001f) { this->unk_168++; - if (this->unk_168 >= 15) { + if (this->unk_168 >= CVar_GetS32("gFasterBlockPush", 0) != 0 ? 5 : 15) { func_808969F8(this, globalCtx); } } else { @@ -484,9 +484,11 @@ void func_808969F8(BgJyaCobra* this, GlobalContext* globalCtx) { void func_80896ABC(BgJyaCobra* this, GlobalContext* globalCtx) { s16 temp_v0; Player* player = GET_PLAYER(globalCtx); + if (CVar_GetS32("gFasterBlockPush", 0) != 0) + this->unk_16E = 150.0f; temp_v0 = (s16)((this->unk_16C * 0x2000) + this->dyna.actor.home.rot.y) - this->dyna.actor.world.rot.y; - if (ABS(temp_v0) < 7424) { + if (ABS(temp_v0) < CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3712 : 7424) { Math_StepToS(&this->unk_16E, 106, 4); } else { Math_StepToS(&this->unk_16E, 21, 10); diff --git a/soh/src/overlays/actors/ovl_Bg_Jya_Lift/z_bg_jya_lift.c b/soh/src/overlays/actors/ovl_Bg_Jya_Lift/z_bg_jya_lift.c index f57c64b84..57c7ac413 100644 --- a/soh/src/overlays/actors/ovl_Bg_Jya_Lift/z_bg_jya_lift.c +++ b/soh/src/overlays/actors/ovl_Bg_Jya_Lift/z_bg_jya_lift.c @@ -20,7 +20,7 @@ void BgJyaLift_DelayMove(BgJyaLift* this, GlobalContext* globalCtx); void BgJyaLift_SetupMove(BgJyaLift* this); void BgJyaLift_Move(BgJyaLift* this, GlobalContext* globalCtx); -static s16 sIsSpawned = false; +static s16 sKankyoIsSpawned = false; const ActorInit Bg_Jya_Lift_InitVars = { ACTOR_BG_JYA_LIFT, @@ -55,7 +55,7 @@ void BgJyaLift_Init(Actor* thisx, GlobalContext* globalCtx) { BgJyaLift* this = (BgJyaLift*)thisx; this->isSpawned = false; - if (sIsSpawned) { + if (sKankyoIsSpawned) { Actor_Kill(thisx); return; } @@ -70,7 +70,7 @@ void BgJyaLift_Init(Actor* thisx, GlobalContext* globalCtx) { BgJyaLift_SetInitPosY(this); } thisx->room = -1; - sIsSpawned = true; + sKankyoIsSpawned = true; this->isSpawned = true; } @@ -81,7 +81,7 @@ void BgJyaLift_Destroy(Actor* thisx, GlobalContext* globalCtx) { // "Goddess Lift DT" osSyncPrintf("女神リフト DT\n"); - sIsSpawned = false; + sKankyoIsSpawned = false; DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); } } diff --git a/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c b/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c index 70360c423..a8871b50c 100644 --- a/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c +++ b/soh/src/overlays/actors/ovl_Bg_Menkuri_Eye/z_bg_menkuri_eye.c @@ -28,7 +28,7 @@ const ActorInit Bg_Menkuri_Eye_InitVars = { (ActorResetFunc)BgMenkuriEye_Reset, }; -static s32 D_8089C1A0; +s32 D_8089C1A0; static ColliderJntSphElementInit sJntSphElementsInit[1] = { { diff --git a/soh/src/overlays/actors/ovl_Bg_Mori_Elevator/z_bg_mori_elevator.c b/soh/src/overlays/actors/ovl_Bg_Mori_Elevator/z_bg_mori_elevator.c index edda63bbb..269b5e411 100644 --- a/soh/src/overlays/actors/ovl_Bg_Mori_Elevator/z_bg_mori_elevator.c +++ b/soh/src/overlays/actors/ovl_Bg_Mori_Elevator/z_bg_mori_elevator.c @@ -17,7 +17,7 @@ void func_808A2008(BgMoriElevator* this, GlobalContext* globalCtx); void BgMoriElevator_MoveIntoGround(BgMoriElevator* this, GlobalContext* globalCtx); void BgMoriElevator_MoveAboveGround(BgMoriElevator* this, GlobalContext* globalCtx); -static s16 sIsSpawned = false; +static s16 sKankyoIsSpawned = false; const ActorInit Bg_Mori_Elevator_InitVars = { ACTOR_BG_MORI_ELEVATOR, @@ -87,18 +87,18 @@ void BgMoriElevator_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; CollisionHeader* colHeader = NULL; - this->unk_172 = sIsSpawned; + this->unk_172 = sKankyoIsSpawned; this->moriTexObjIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_MORI_TEX); if (this->moriTexObjIndex < 0) { Actor_Kill(thisx); // "Forest Temple obj elevator Bank Danger!" osSyncPrintf("Error : 森の神殿 obj elevator バンク危険!(%s %d)\n", "../z_bg_mori_elevator.c", 277); } else { - switch (sIsSpawned) { + switch (sKankyoIsSpawned) { case false: // "Forest Temple elevator CT" osSyncPrintf("森の神殿 elevator CT\n"); - sIsSpawned = true; + sKankyoIsSpawned = true; this->dyna.actor.room = -1; Actor_ProcessInitChain(&this->dyna.actor, sInitChain); DynaPolyActor_Init(&this->dyna, DPM_PLAYER); @@ -120,7 +120,7 @@ void BgMoriElevator_Destroy(Actor* thisx, GlobalContext* globalCtx) { // "Forest Temple elevator DT" osSyncPrintf("森の神殿 elevator DT\n"); DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); - sIsSpawned = false; + sKankyoIsSpawned = false; } } diff --git a/soh/src/overlays/actors/ovl_Bg_Mori_Hineri/z_bg_mori_hineri.c b/soh/src/overlays/actors/ovl_Bg_Mori_Hineri/z_bg_mori_hineri.c index 8dfbff765..7508b6a24 100644 --- a/soh/src/overlays/actors/ovl_Bg_Mori_Hineri/z_bg_mori_hineri.c +++ b/soh/src/overlays/actors/ovl_Bg_Mori_Hineri/z_bg_mori_hineri.c @@ -28,7 +28,7 @@ void BgMoriHineri_SpawnBossKeyChest(BgMoriHineri* this, GlobalContext* globalCtx void BgMoriHineri_DoNothing(BgMoriHineri* this, GlobalContext* globalCtx); void func_808A3D58(BgMoriHineri* this, GlobalContext* globalCtx); -static s16 sNextCamIdx = SUBCAM_NONE; +s16 sBgMoriHineriNextCamIdx = SUBCAM_NONE; const ActorInit Bg_Mori_Hineri_InitVars = { ACTOR_BG_MORI_HINERI, @@ -194,28 +194,28 @@ void func_808A3D58(BgMoriHineri* this, GlobalContext* globalCtx) { OnePointCutscene_EndCutscene(globalCtx, mainCamChildIdx); } OnePointCutscene_Init(globalCtx, 3260, 40, &this->dyna.actor, MAIN_CAM); - sNextCamIdx = OnePointCutscene_Init(globalCtx, 3261, 40, &this->dyna.actor, MAIN_CAM); + sBgMoriHineriNextCamIdx = OnePointCutscene_Init(globalCtx, 3261, 40, &this->dyna.actor, MAIN_CAM); } } void func_808A3E54(BgMoriHineri* this, GlobalContext* globalCtx) { s8 objBankIndex; - if (globalCtx->activeCamera == sNextCamIdx) { - if (sNextCamIdx != MAIN_CAM) { + if (globalCtx->activeCamera == sBgMoriHineriNextCamIdx) { + if (sBgMoriHineriNextCamIdx != MAIN_CAM) { objBankIndex = this->dyna.actor.objBankIndex; this->dyna.actor.objBankIndex = this->moriHineriObjIdx; this->moriHineriObjIdx = objBankIndex; this->dyna.actor.params ^= 1; - sNextCamIdx = MAIN_CAM; + sBgMoriHineriNextCamIdx = MAIN_CAM; func_80078884(NA_SE_SY_TRE_BOX_APPEAR); } else { this->dyna.actor.draw = NULL; this->actionFunc = func_808A3D58; - sNextCamIdx = SUBCAM_NONE; + sBgMoriHineriNextCamIdx = SUBCAM_NONE; } } - if ((sNextCamIdx >= SUBCAM_FIRST) && + if ((sBgMoriHineriNextCamIdx >= SUBCAM_FIRST) && ((GET_ACTIVE_CAM(globalCtx)->eye.z - this->dyna.actor.world.pos.z) < 1100.0f)) { func_8002F948(&this->dyna.actor, NA_SE_EV_FLOOR_ROLLING - SFX_FLAG); } @@ -283,5 +283,5 @@ void BgMoriHineri_DrawHallAndRoom(Actor* thisx, GlobalContext* globalCtx) { } void BgMoriHineri_Reset() { - sNextCamIdx = SUBCAM_NONE; + sBgMoriHineriNextCamIdx = SUBCAM_NONE; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Bg_Mori_Idomizu/z_bg_mori_idomizu.c b/soh/src/overlays/actors/ovl_Bg_Mori_Idomizu/z_bg_mori_idomizu.c index 3c605926f..962c4d1aa 100644 --- a/soh/src/overlays/actors/ovl_Bg_Mori_Idomizu/z_bg_mori_idomizu.c +++ b/soh/src/overlays/actors/ovl_Bg_Mori_Idomizu/z_bg_mori_idomizu.c @@ -19,7 +19,7 @@ void BgMoriIdomizu_WaitForMoriTex(BgMoriIdomizu* this, GlobalContext* globalCtx) void BgMoriIdomizu_SetupMain(BgMoriIdomizu* this); void BgMoriIdomizu_Main(BgMoriIdomizu* this, GlobalContext* globalCtx); -static s16 sIsSpawned = false; +static s16 sKankyoIsSpawned = false; const ActorInit Bg_Mori_Idomizu_InitVars = { ACTOR_BG_MORI_IDOMIZU, @@ -50,7 +50,7 @@ void BgMoriIdomizu_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; BgMoriIdomizu* this = (BgMoriIdomizu*)thisx; - if (sIsSpawned) { + if (sKankyoIsSpawned) { Actor_Kill(&this->actor); return; } @@ -76,7 +76,7 @@ void BgMoriIdomizu_Init(Actor* thisx, GlobalContext* globalCtx) { return; } BgMoriIdomizu_SetupWaitForMoriTex(this); - sIsSpawned = true; + sKankyoIsSpawned = true; this->isLoaded = true; this->actor.room = -1; // "Forest Temple well water" @@ -88,7 +88,7 @@ void BgMoriIdomizu_Destroy(Actor* thisx, GlobalContext* globalCtx) { BgMoriIdomizu* this = (BgMoriIdomizu*)thisx; if (this->isLoaded) { - sIsSpawned = false; + sKankyoIsSpawned = false; } } diff --git a/soh/src/overlays/actors/ovl_Bg_Mori_Kaitenkabe/z_bg_mori_kaitenkabe.c b/soh/src/overlays/actors/ovl_Bg_Mori_Kaitenkabe/z_bg_mori_kaitenkabe.c index 4ad89d7b3..68bf02fb7 100644 --- a/soh/src/overlays/actors/ovl_Bg_Mori_Kaitenkabe/z_bg_mori_kaitenkabe.c +++ b/soh/src/overlays/actors/ovl_Bg_Mori_Kaitenkabe/z_bg_mori_kaitenkabe.c @@ -94,7 +94,7 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, GlobalContext* globalCtx) { if (this->dyna.unk_150 > 0.001f) { this->timer++; - if ((this->timer > 28) && !Player_InCsMode(globalCtx)) { + if ((this->timer > CVar_GetS32("gFasterBlockPush", 0) != 0 ? 14 : 28) && !Player_InCsMode(globalCtx)) { BgMoriKaitenkabe_SetupRotate(this); func_8002DF54(globalCtx, &this->dyna.actor, 8); Math_Vec3f_Copy(&this->lockedPlayerPos, &player->actor.world.pos); @@ -118,7 +118,7 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, GlobalContext* globalCtx) { void BgMoriKaitenkabe_SetupRotate(BgMoriKaitenkabe* this) { this->actionFunc = BgMoriKaitenkabe_Rotate; - this->rotSpeed = 0.0f; + this->rotSpeed = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.0f; this->rotYdeg = 0.0f; } diff --git a/soh/src/overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.c b/soh/src/overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.c index 1a1cc6c60..c2ed8a29b 100644 --- a/soh/src/overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.c +++ b/soh/src/overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.c @@ -80,11 +80,11 @@ static ColliderTrisInit sTrisInit = { sTrisElementsInit, }; -static u8 sBlocksAtRest = 0; +u8 sBgPoEventBlocksAtRest = 0; static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; -static u8 sPuzzleState; +u8 sBgPoEventPuzzleState; void BgPoEvent_InitPaintings(BgPoEvent* this, GlobalContext* globalCtx) { static s16 paintingPosX[] = { -1302, -866, 1421, 985 }; @@ -142,10 +142,10 @@ void BgPoEvent_InitPaintings(BgPoEvent* this, GlobalContext* globalCtx) { } this->timer = 0; if (this->type == 4) { - sPuzzleState = 0; + sBgPoEventPuzzleState = 0; this->actionFunc = BgPoEvent_AmyWait; } else { - sPuzzleState = (s32)(Rand_ZeroOne() * 3.0f) % 3; + sBgPoEventPuzzleState = (s32)(Rand_ZeroOne() * 3.0f) % 3; this->actionFunc = BgPoEvent_PaintingEmpty; } } @@ -236,7 +236,7 @@ void BgPoEvent_Destroy(Actor* thisx, GlobalContext* globalCtx) { void BgPoEvent_BlockWait(BgPoEvent* this, GlobalContext* globalCtx) { this->dyna.actor.world.pos.y = 833.0f; - if (sPuzzleState == 0x3F) { + if (sBgPoEventPuzzleState == 0x3F) { if (this->type == 1) { OnePointCutscene_Init(globalCtx, 3150, 65, NULL, MAIN_CAM); } @@ -244,14 +244,14 @@ void BgPoEvent_BlockWait(BgPoEvent* this, GlobalContext* globalCtx) { this->actionFunc = BgPoEvent_BlockShake; } else if (this->dyna.actor.xzDistToPlayer > 50.0f) { if (this->type != 1) { - sPuzzleState |= (1 << this->index); + sBgPoEventPuzzleState |= (1 << this->index); } else { - sPuzzleState |= 0x10; + sBgPoEventPuzzleState |= 0x10; } } else if (this->type != 1) { - sPuzzleState &= ~(1 << this->index); + sBgPoEventPuzzleState &= ~(1 << this->index); } else { - sPuzzleState &= ~0x10; + sBgPoEventPuzzleState &= ~0x10; } } @@ -265,7 +265,7 @@ void BgPoEvent_BlockShake(BgPoEvent* this, GlobalContext* globalCtx) { } if (this->timer == 0) { this->dyna.actor.world.pos.x = this->dyna.actor.home.pos.x; - sPuzzleState = 0; + sBgPoEventPuzzleState = 0; this->timer = 60; this->actionFunc = BgPoEvent_BlockFall; } @@ -299,9 +299,9 @@ void BgPoEvent_CheckBlock(BgPoEvent* this) { } } if ((phi_v1 == phi_a1) && ((phi_t0 - phi_a3) == 60)) { - sPuzzleState |= (1 << this->index); + sBgPoEventPuzzleState |= (1 << this->index); } else { - sPuzzleState &= ~(1 << this->index); + sBgPoEventPuzzleState &= ~(1 << this->index); } } @@ -312,7 +312,7 @@ void BgPoEvent_BlockFall(BgPoEvent* this, GlobalContext* globalCtx) { if (Math_StepToF(&this->dyna.actor.world.pos.y, 433.0f, this->dyna.actor.velocity.y)) { this->dyna.actor.flags &= ~ACTOR_FLAG_5; this->dyna.actor.velocity.y = 0.0f; - sBlocksAtRest++; + sBgPoEventBlocksAtRest++; if (this->type != 1) { BgPoEvent_CheckBlock(this); } else { @@ -334,7 +334,7 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); Actor* amy; - if (sPuzzleState == 0xF) { + if (sBgPoEventPuzzleState == 0xF) { this->actionFunc = BgPoEvent_BlockSolved; if ((this->type == 0) && (this->index == 0)) { amy = @@ -348,23 +348,23 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) { gSaveContext.timer1State = 0xA; } } else { - if ((gSaveContext.timer1Value == 0) && (sBlocksAtRest == 5)) { + if ((gSaveContext.timer1Value == 0) && (sBgPoEventBlocksAtRest == 5)) { player->stateFlags2 &= ~0x10; - sPuzzleState = 0x10; - sBlocksAtRest = 0; + sBgPoEventPuzzleState = 0x10; + sBgPoEventBlocksAtRest = 0; } - if ((sPuzzleState == 0x40) || ((sPuzzleState == 0x10) && !Player_InCsMode(globalCtx))) { + if ((sBgPoEventPuzzleState == 0x40) || ((sBgPoEventPuzzleState == 0x10) && !Player_InCsMode(globalCtx))) { this->dyna.actor.world.rot.z = this->dyna.actor.shape.rot.z; this->actionFunc = BgPoEvent_BlockReset; - if (sPuzzleState == 0x10) { - sPuzzleState = 0x40; + if (sBgPoEventPuzzleState == 0x10) { + sBgPoEventPuzzleState = 0x40; Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_BLOCK_RISING); func_8002DF54(globalCtx, &player->actor, 8); } } else if (this->dyna.unk_150 != 0.0f) { if (this->direction == 0) { if (func_800435D8(globalCtx, &this->dyna, 0x1E, 0x32, -0x14) != 0) { - sBlocksAtRest--; + sBgPoEventBlocksAtRest--; this->direction = (this->dyna.unk_150 >= 0.0f) ? 1.0f : -1.0f; this->actionFunc = BgPoEvent_BlockPush; } else { @@ -382,16 +382,16 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) { } } -static f32 blockPushDist = 0.0f; +f32 sBgPoEventblockPushDist = 0.0f; void BgPoEvent_BlockPush(BgPoEvent* this, GlobalContext* globalCtx) { f32 displacement; s32 blockStop; Player* player = GET_PLAYER(globalCtx); - this->dyna.actor.speedXZ += 0.1f; + this->dyna.actor.speedXZ += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.1f; this->dyna.actor.speedXZ = CLAMP_MAX(this->dyna.actor.speedXZ, 2.0f); - blockStop = Math_StepToF(&blockPushDist, 20.0f, this->dyna.actor.speedXZ); - displacement = this->direction * blockPushDist; + blockStop = Math_StepToF(&sBgPoEventblockPushDist, 20.0f, this->dyna.actor.speedXZ); + displacement = this->direction * sBgPoEventblockPushDist; this->dyna.actor.world.pos.x = (Math_SinS(this->dyna.unk_158) * displacement) + this->dyna.actor.home.pos.x; this->dyna.actor.world.pos.z = (Math_CosS(this->dyna.unk_158) * displacement) + this->dyna.actor.home.pos.z; if (blockStop) { @@ -402,10 +402,10 @@ void BgPoEvent_BlockPush(BgPoEvent* this, GlobalContext* globalCtx) { this->dyna.unk_150 = 0.0f; this->dyna.actor.home.pos.x = this->dyna.actor.world.pos.x; this->dyna.actor.home.pos.z = this->dyna.actor.world.pos.z; - blockPushDist = 0.0f; + sBgPoEventblockPushDist = 0.0f; this->dyna.actor.speedXZ = 0.0f; - this->direction = 5; - sBlocksAtRest++; + this->direction = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3 : 5; + sBgPoEventBlocksAtRest++; this->actionFunc = BgPoEvent_BlockIdle; if (this->type == 1) { return; @@ -428,7 +428,7 @@ void BgPoEvent_BlockReset(BgPoEvent* this, GlobalContext* globalCtx) { this->index = (this->index + 1) % 4; this->actionFunc = BgPoEvent_BlockFall; - sPuzzleState = 0; + sBgPoEventPuzzleState = 0; if (this->type == 1) { this->timer += 10; this->timer = CLAMP_MAX(this->timer, 120); @@ -443,14 +443,14 @@ void BgPoEvent_BlockSolved(BgPoEvent* this, GlobalContext* globalCtx) { player->stateFlags2 &= ~0x10; } if (Math_StepToF(&this->dyna.actor.world.pos.y, 369.0f, 2.0f)) { - sPuzzleState = 0x20; + sBgPoEventPuzzleState = 0x20; Actor_Kill(&this->dyna.actor); } } void BgPoEvent_AmyWait(BgPoEvent* this, GlobalContext* globalCtx) { if (this->collider.base.acFlags & AC_HIT) { - sPuzzleState |= 0x20; + sBgPoEventPuzzleState |= 0x20; this->timer = 5; Actor_SetColorFilter(&this->dyna.actor, 0x4000, 0xFF, 0, 5); Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EN_PO_LAUGH2); @@ -461,12 +461,12 @@ void BgPoEvent_AmyWait(BgPoEvent* this, GlobalContext* globalCtx) { void BgPoEvent_AmyPuzzle(BgPoEvent* this, GlobalContext* globalCtx) { Vec3f pos; - if (sPuzzleState == 0xF) { + if (sBgPoEventPuzzleState == 0xF) { pos.x = this->dyna.actor.world.pos.x - 5.0f; pos.y = Rand_CenteredFloat(120.0f) + this->dyna.actor.world.pos.y; pos.z = Rand_CenteredFloat(120.0f) + this->dyna.actor.world.pos.z; EffectSsDeadDb_Spawn(globalCtx, &pos, &sZeroVec, &sZeroVec, 170, 0, 200, 255, 100, 170, 0, 255, 0, 1, 9, true); - } else if (sPuzzleState == 0x20) { + } else if (sBgPoEventPuzzleState == 0x20) { Actor_Kill(&this->dyna.actor); } else { DECR(this->timer); @@ -476,14 +476,14 @@ void BgPoEvent_AmyPuzzle(BgPoEvent* this, GlobalContext* globalCtx) { s32 BgPoEvent_NextPainting(BgPoEvent* this) { if ((this->dyna.actor.parent != NULL) && (this->dyna.actor.child != NULL)) { if (Rand_ZeroOne() < 0.5f) { - sPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index; + sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index; } else { - sPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index; + sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index; } } else if (this->dyna.actor.parent != NULL) { - sPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index; + sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index; } else if (this->dyna.actor.child != NULL) { - sPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index; + sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index; } else { return false; } @@ -491,7 +491,7 @@ s32 BgPoEvent_NextPainting(BgPoEvent* this) { } void BgPoEvent_PaintingEmpty(BgPoEvent* this, GlobalContext* globalCtx) { - if (sPuzzleState == this->index) { + if (sBgPoEventPuzzleState == this->index) { this->timer = 255; this->actionFunc = BgPoEvent_PaintingAppear; } @@ -636,7 +636,7 @@ void BgPoEvent_Draw(Actor* thisx, GlobalContext* globalCtx) { } void BgPoEvent_Reset(void) { - sBlocksAtRest = 0; - sPuzzleState = 0; - blockPushDist = 0.0f; + sBgPoEventBlocksAtRest = 0; + sBgPoEventPuzzleState = 0; + sBgPoEventblockPushDist = 0.0f; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c b/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c index 33e94d172..58d0f62d8 100644 --- a/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c +++ b/soh/src/overlays/actors/ovl_Bg_Relay_Objects/z_bg_relay_objects.c @@ -45,7 +45,7 @@ static InitChainEntry sInitChain[] = { ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP), }; -static u32 D_808A9508 = 0; +u32 D_808A9508 = 0; void BgRelayObjects_Init(Actor* thisx, GlobalContext* globalCtx) { BgRelayObjects* this = (BgRelayObjects*)thisx; s32 pad; diff --git a/soh/src/overlays/actors/ovl_Bg_Spot15_Rrbox/z_bg_spot15_rrbox.c b/soh/src/overlays/actors/ovl_Bg_Spot15_Rrbox/z_bg_spot15_rrbox.c index 240235917..684336e17 100644 --- a/soh/src/overlays/actors/ovl_Bg_Spot15_Rrbox/z_bg_spot15_rrbox.c +++ b/soh/src/overlays/actors/ovl_Bg_Spot15_Rrbox/z_bg_spot15_rrbox.c @@ -260,7 +260,7 @@ void func_808B4194(BgSpot15Rrbox* this, GlobalContext* globalCtx) { s32 approxFResult; Actor* actor = &this->dyna.actor; - this->unk_174 += 0.5f; + this->unk_174 += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 1.0f : 0.5f; this->unk_174 = CLAMP_MAX(this->unk_174, 2.0f); @@ -294,7 +294,7 @@ void func_808B4194(BgSpot15Rrbox* this, GlobalContext* globalCtx) { this->dyna.unk_150 = 0.0f; this->unk_178 = 0.0f; this->unk_174 = 0.0f; - this->unk_168 = 10; + this->unk_168 = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3 : 10; func_808B4084(this, globalCtx); } Audio_PlayActorSound2(actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG); diff --git a/soh/src/overlays/actors/ovl_Bg_Spot18_Basket/z_bg_spot18_basket.c b/soh/src/overlays/actors/ovl_Bg_Spot18_Basket/z_bg_spot18_basket.c index 2e9297e4c..caa727c69 100644 --- a/soh/src/overlays/actors/ovl_Bg_Spot18_Basket/z_bg_spot18_basket.c +++ b/soh/src/overlays/actors/ovl_Bg_Spot18_Basket/z_bg_spot18_basket.c @@ -84,7 +84,7 @@ void func_808B7710(Actor* thisx, GlobalContext* globalCtx) { this->dyna.actor.colChkInfo.mass = MASS_IMMOVABLE; } -static s16 D_808B85D0 = 0; +s16 D_808B85D0 = 0; void func_808B7770(BgSpot18Basket* this, GlobalContext* globalCtx, f32 arg2) { Vec3f acceleration; Vec3f velocity; diff --git a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c index 649774346..5b468c7d3 100644 --- a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c +++ b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.c @@ -12,6 +12,8 @@ #include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5) typedef enum { @@ -78,6 +80,7 @@ void BossFd_SpawnEmber(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, V effect->scale = scale / 1000.0f; effect->alpha = 255; effect->timer1 = (s16)Rand_ZeroFloat(10.0f); + effect->epoch++; break; } } @@ -95,6 +98,7 @@ void BossFd_SpawnDebris(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, effect->scale = scale / 1000.0f; effect->vFdFxRotX = Rand_ZeroFloat(100.0f); effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + effect->epoch++; break; } } @@ -111,6 +115,7 @@ void BossFd_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Ve effect->accel = *acceleration; effect->timer2 = 0; effect->scale = scale / 400.0f; + effect->epoch++; break; } } @@ -136,6 +141,7 @@ void BossFd_SpawnFireBreath(BossFdEffect* effect, Vec3f* position, Vec3f* veloci effect->timer2 = 0; effect->scale = scale / 400.0f; effect->kbAngle = kbAngle; + effect->epoch++; break; } } @@ -1522,6 +1528,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_EMBER) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberMaterialDL); @@ -1536,6 +1543,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4046), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -1543,6 +1551,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { flag = false; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_DEBRIS) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D18(globalCtx->state.gfxCtx); gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisMaterialDL); @@ -1557,6 +1566,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4068), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -1564,6 +1574,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { flag = false; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_DUST) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL); @@ -1580,6 +1591,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2])); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -1587,6 +1599,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { flag = false; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_FIRE_BREATH) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL); @@ -1603,6 +1616,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2])); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -1610,6 +1624,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { flag = false; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_SKULL_PIECE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceMaterialDL); @@ -1624,6 +1639,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4192), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceModelDL); + FrameInterpolation_RecordCloseChild(); } } diff --git a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h index ea24fd346..d9580fc28 100644 --- a/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h +++ b/soh/src/overlays/actors/ovl_Boss_Fd/z_boss_fd.h @@ -49,6 +49,7 @@ typedef struct { /* 0x30 */ f32 scale; /* 0x34 */ f32 bFdFxFloat1; /* 0x38 */ f32 bFdFxFloat2; + u32 epoch; } BossFdEffect; // size = 0x3C #define BOSSFD_EFFECT_COUNT 180 diff --git a/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c b/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c index 20db1fb55..779584e32 100644 --- a/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c +++ b/soh/src/overlays/actors/ovl_Boss_Fd2/z_boss_fd2.c @@ -87,6 +87,7 @@ void BossFd2_SpawnDebris(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* effect->scale = scale / 1000.0f; effect->vFdFxRotX = Rand_ZeroFloat(100.0f); effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + effect->epoch++; break; } } @@ -112,6 +113,7 @@ void BossFd2_SpawnFireBreath(GlobalContext* globalCtx, BossFdEffect* effect, Vec effect->timer2 = 0; effect->scale = scale / 400.0f; effect->kbAngle = kbAngle; + effect->epoch++; break; } } @@ -130,6 +132,7 @@ void BossFd2_SpawnEmber(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* p effect->scale = scale / 1000.0f; effect->alpha = 255; effect->timer1 = (s16)Rand_ZeroFloat(10.0f); + effect->epoch++; break; } } @@ -148,6 +151,7 @@ void BossFd2_SpawnSkullPiece(GlobalContext* globalCtx, BossFdEffect* effect, Vec effect->scale = scale / 1000.0f; effect->vFdFxRotX = Rand_ZeroFloat(100.0f); effect->vFdFxRotY = Rand_ZeroFloat(100.0f); + effect->epoch++; break; } } @@ -164,6 +168,7 @@ void BossFd2_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, V effect->accel = *acceleration; effect->timer2 = 0; effect->scale = scale / 400.0f; + effect->epoch++; break; } } diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c index e4a5afc65..21199d420 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c @@ -9,6 +9,8 @@ #include "assets/objects/object_ganon_anime2/object_ganon_anime2.h" #include "assets/scenes/dungeons/ganon_boss/ganon_boss_scene.h" +#include "soh/frame_interpolation.h" + #include #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5) @@ -105,35 +107,17 @@ static ColliderCylinderInit sLightBallCylinderInit = { static u8 D_808E4C58[] = { 0, 12, 10, 12, 14, 16, 12, 14, 16, 12, 14, 16, 12, 14, 16, 10, 16, 14 }; static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; -static EnGanonMant* sCape; +EnGanonMant* sBossGanonCape; -static s32 sSeed1; -static s32 sSeed2; -static s32 sSeed3; +s32 sBossGanonSeed1; +s32 sBossGanonSeed3; +s32 sBossGanonSeed2; -static BossGanon* sGanondorf; +BossGanon* sBossGanonGanondorf; -static EnZl3* sZelda; +EnZl3* sBossGanonZelda; -typedef struct { - /* 0x00 */ u8 type; - /* 0x01 */ u8 timer; - /* 0x04 */ Vec3f pos; - /* 0x10 */ Vec3f velocity; - /* 0x1C */ Vec3f accel; - /* 0x28 */ Color_RGB8 color; - /* 0x2C */ s16 alpha; - /* 0x2E */ s16 unk_2E; - /* 0x30 */ s16 unk_30; - /* 0x34 */ f32 scale; - /* 0x38 */ f32 unk_38; // scale target mostly, but used for other things - /* 0x3C */ f32 unk_3C; // mostly z rot - /* 0x40 */ f32 unk_40; - /* 0x44 */ f32 unk_44; // mostly x rot - /* 0x48 */ f32 unk_48; // mostly y rot -} GanondorfEffect; // size = 0x4C - -GanondorfEffect sEffectBuf[200]; +GanondorfEffect sBossGanonEffectBuf[200]; void BossGanonEff_SpawnWindowShard(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, f32 scale) { static Color_RGB8 shardColors[] = { { 255, 175, 85 }, { 155, 205, 155 }, { 155, 125, 55 } }; @@ -156,6 +140,7 @@ void BossGanonEff_SpawnWindowShard(GlobalContext* globalCtx, Vec3f* pos, Vec3f* eff->color.g = color->g; eff->color.b = color->b; eff->timer = (s16)Rand_ZeroFloat(20.0f); + eff->epoch++; break; } } @@ -176,6 +161,7 @@ void BossGanonEff_SpawnSparkle(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velo eff->unk_2E = (s16)Rand_ZeroFloat(100.0f) + 0xC8; eff->unk_30 = arg6; eff->timer = (s16)Rand_ZeroFloat(10.0f); + eff->epoch++; break; } } @@ -200,6 +186,7 @@ void BossGanonEff_SpawnLightRay(GlobalContext* globalCtx, Vec3f* pos, Vec3f* vel eff->timer = (s16)Rand_ZeroFloat(10.0f); eff->unk_48 = Math_Atan2F(eff->velocity.z, eff->velocity.x); eff->unk_44 = -Math_Atan2F(sqrtf(SQXZ(eff->velocity)), eff->velocity.y); + eff->epoch++; break; } } @@ -219,6 +206,7 @@ void BossGanonEff_SpawnShock(GlobalContext* globalCtx, f32 scale, s16 shockType) eff->scale = scale / 1000.0f; eff->unk_2E = shockType; eff->timer = 0; + eff->epoch++; break; } } @@ -238,6 +226,7 @@ void BossGanonEff_SpawnLightning(GlobalContext* globalCtx, f32 scale, f32 arg2, eff->unk_48 = arg2; eff->unk_3C = arg3; eff->timer = 0; + eff->epoch++; break; } } @@ -258,6 +247,7 @@ void BossGanonEff_SpawnDustDark(GlobalContext* globalCtx, Vec3f* pos, f32 scale, eff->unk_38 = arg3; eff->unk_30 = (s16)Rand_ZeroFloat(100.0f); eff->unk_2E = eff->timer = eff->alpha = 0; + eff->epoch++; break; } } @@ -275,6 +265,7 @@ void BossGanonEff_SpawnDustLight(GlobalContext* globalCtx, Vec3f* pos, f32 scale effArr[bufIndex].unk_38 = arg3; effArr[bufIndex].unk_30 = Rand_ZeroFloat(100.0f); effArr[bufIndex].unk_2E = effArr[bufIndex].timer = effArr[bufIndex].alpha = 0; + effArr[bufIndex].epoch++; } void BossGanonEff_SpawnShockwave(GlobalContext* globalCtx, Vec3f* pos, f32 scale, f32 arg3) { @@ -293,6 +284,7 @@ void BossGanonEff_SpawnShockwave(GlobalContext* globalCtx, Vec3f* pos, f32 scale eff->unk_38 = arg3; eff->unk_30 = (s16)Rand_ZeroFloat(100.0f); eff->unk_2E = eff->timer = 0; + eff->epoch++; break; } } @@ -313,6 +305,7 @@ void BossGanonEff_SpawnBlackDot(GlobalContext* globalCtx, Vec3f* pos, f32 scale) eff->timer = 0; eff->alpha = 0; eff->unk_2E = 0; + eff->epoch++; break; } } @@ -348,13 +341,13 @@ void BossGanon_Init(Actor* thisx, GlobalContext* globalCtx2) { if (thisx->params < 0x64) { Flags_SetSwitch(globalCtx, 0x14); - globalCtx->specialEffects = sEffectBuf; + globalCtx->specialEffects = sBossGanonEffectBuf; - for (i = 0; i < ARRAY_COUNT(sEffectBuf); i++) { - sEffectBuf[i].type = GDF_EFF_NONE; + for (i = 0; i < ARRAY_COUNT(sBossGanonEffectBuf); i++) { + sBossGanonEffectBuf[i].type = GDF_EFF_NONE; } - sGanondorf = this; + sBossGanonGanondorf = this; thisx->colChkInfo.health = 40; Actor_ProcessInitChain(thisx, sInitChain); ActorShape_Init(&thisx->shape, 0, NULL, 0); @@ -381,7 +374,7 @@ void BossGanon_Init(Actor* thisx, GlobalContext* globalCtx2) { BossGanon_SetupTowerCutscene(this, globalCtx); } - sCape = (EnGanonMant*)Actor_SpawnAsChild(&globalCtx->actorCtx, thisx, globalCtx, ACTOR_EN_GANON_MANT, 0.0f, + sBossGanonCape = (EnGanonMant*)Actor_SpawnAsChild(&globalCtx->actorCtx, thisx, globalCtx, ACTOR_EN_GANON_MANT, 0.0f, 0.0f, 0.0f, 0, 0, 0, 1); Actor_ChangeCategory(globalCtx, &globalCtx->actorCtx, thisx, ACTORCAT_BOSS); } else { @@ -538,10 +531,10 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->animBankIndex].segment); - sCape->backPush = -2.0f; - sCape->backSwayMagnitude = 0.25f; - sCape->sideSwayMagnitude = -1.0f; - sCape->minDist = 0.0f; + sBossGanonCape->backPush = -2.0f; + sBossGanonCape->backSwayMagnitude = 0.25f; + sBossGanonCape->sideSwayMagnitude = -1.0f; + sBossGanonCape->minDist = 0.0f; this->csTimer++; @@ -584,13 +577,13 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { this->useOpenHand = true; BossGanon_SetIntroCsCamera(this, 0); this->csState = 1; - sZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f, + sBossGanonZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f, 220.0f, -150.0f, 0, 0, 0, 0x2000); } Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_GANON_ORGAN, 0.0f, 0.0f, 0.0f, 0, 0, 0, 1); - sCape->minY = 57.0f; + sBossGanonCape->minY = 57.0f; // fallthrough case 1: this->envLightMode = 3; @@ -736,7 +729,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { this->csState = 9; this->csTimer = 0; func_8002DF54(globalCtx, &this->actor, 8); - sZelda->unk_3C8 = 0; + sBossGanonZelda->unk_3C8 = 0; this->triforceType = GDF_TRIFORCE_ZELDA; this->fwork[GDF_TRIFORCE_SCALE] = 10.0f; this->fwork[GDF_TRIFORCE_PRIM_A] = 0.0f; @@ -755,7 +748,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { Math_ApproachF(&this->fwork[GDF_TRIFORCE_ENV_G], 200.0f, 1.0f, 3.0f); if (this->csTimer == 30) { - sZelda->unk_3C8 = 1; + sBossGanonZelda->unk_3C8 = 1; } if (this->csTimer >= 32) { @@ -847,7 +840,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { this->csTimer = 0; BossGanon_SetIntroCsCamera(this, 11); this->unk_198 = 2; - sZelda->unk_3C8 = 2; + sBossGanonZelda->unk_3C8 = 2; this->timers[2] = 110; this->envLightMode = 3; } @@ -883,7 +876,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { if (this->csTimer > 10) { if (this->csTimer == 62) { - sCape->attachRightArmTimer = 20.0f; + sBossGanonCape->attachRightArmTimer = 20.0f; } if (this->csTimer == 57) { @@ -1076,7 +1069,7 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f); SkelAnime_Update(&this->skelAnime); this->actor.shape.yOffset = 0.0f; - sCape->attachShouldersTimer = 18.0f; + sBossGanonCape->attachShouldersTimer = 18.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); this->unk_198 = 0; Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_GANONDORF_BOSS); @@ -1101,9 +1094,9 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { Math_ApproachF(&this->actor.world.pos.y, 228.0f, 0.05f, 2.0f); Math_ApproachF(&this->actor.world.pos.z, -230.0f, 0.05f, 4.0f); - sCape->backPush = -3.0f; - sCape->backSwayMagnitude = 0.25f; - sCape->sideSwayMagnitude = -3.0f; + sBossGanonCape->backPush = -3.0f; + sBossGanonCape->backSwayMagnitude = 0.25f; + sBossGanonCape->sideSwayMagnitude = -3.0f; sin = Math_SinS(this->csTimer * 1500); this->actor.velocity.y = this->fwork[GDF_FWORK_0] * sin * 0.04f; @@ -1136,10 +1129,10 @@ void BossGanon_IntroCutscene(BossGanon* this, GlobalContext* globalCtx) { BossGanon_SetupWait(this, globalCtx); } - if (sZelda != NULL) { - sZelda->actor.world.pos.x = 0.0f; - sZelda->actor.world.pos.y = 350.0f; - sZelda->actor.world.pos.z = 0.0f; + if (sBossGanonZelda != NULL) { + sBossGanonZelda->actor.world.pos.x = 0.0f; + sBossGanonZelda->actor.world.pos.y = 350.0f; + sBossGanonZelda->actor.world.pos.z = 0.0f; } } @@ -1529,7 +1522,7 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->fwork[1] = Animation_GetLastFrame(&object_ganon_anime2_Anim_00EA00); this->csState = 101; this->skelAnime.playSpeed = 0.0f; - sZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f, + sBossGanonZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 0.0f, 6000.0f, 0.0f, 0, 0, 0, 0x2000); player->actor.world.pos.x = -472.0f; @@ -1551,12 +1544,12 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->csCamAt.z = -100.0f; - sCape->backPush = -2.0f; - sCape->backSwayMagnitude = 0.25f; - sCape->sideSwayMagnitude = -1.0f; - sCape->minDist = 0.0f; - sCape->minY = 4104.0f; - sCape->tearTimer = 20; + sBossGanonCape->backPush = -2.0f; + sBossGanonCape->backSwayMagnitude = 0.25f; + sBossGanonCape->sideSwayMagnitude = -1.0f; + sBossGanonCape->minDist = 0.0f; + sBossGanonCape->minY = 4104.0f; + sBossGanonCape->tearTimer = 20; this->whiteFillAlpha = 255.0f; globalCtx->envCtx.unk_D8 = 1.0f; @@ -1620,27 +1613,27 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) if (this->csTimer == 90) { this->csState = 103; this->csTimer = 0; - sZelda->actor.world.pos.x = -472.0f; - sZelda->actor.world.pos.y = 4352.0f; - sZelda->actor.world.pos.z = -200.0f; - sZelda->unk_3C8 = 3; + sBossGanonZelda->actor.world.pos.x = -472.0f; + sBossGanonZelda->actor.world.pos.y = 4352.0f; + sBossGanonZelda->actor.world.pos.z = -200.0f; + sBossGanonZelda->unk_3C8 = 3; } break; case 103: - Audio_PlayActorSound2(&sZelda->actor, NA_SE_EV_DOWN_TO_GROUND - SFX_FLAG); - Math_ApproachF(&sZelda->actor.world.pos.y, 4102.0f, 0.05f, 1.5f); + Audio_PlayActorSound2(&sBossGanonZelda->actor, NA_SE_EV_DOWN_TO_GROUND - SFX_FLAG); + Math_ApproachF(&sBossGanonZelda->actor.world.pos.y, 4102.0f, 0.05f, 1.5f); this->csCamEye.x = -242.0f; this->csCamEye.y = 4122.0f; this->csCamEye.z = -190.0f; - this->csCamAt.x = sZelda->actor.world.pos.x; - this->csCamAt.y = sZelda->actor.world.pos.y + 40.0f + 5.0f; - this->csCamAt.z = sZelda->actor.world.pos.z; + this->csCamAt.x = sBossGanonZelda->actor.world.pos.x; + this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f; + this->csCamAt.z = sBossGanonZelda->actor.world.pos.z; if (this->csTimer == 200) { - sZelda->actor.world.pos.y = 4102.0f; + sBossGanonZelda->actor.world.pos.y = 4102.0f; this->csState = 104; this->csTimer = 0; } else { @@ -1652,20 +1645,20 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->csCamEye.y = 4147.0f; this->csCamEye.z = -200.0f; - this->csCamAt.x = sZelda->actor.world.pos.x; - this->csCamAt.y = sZelda->actor.world.pos.y + 40.0f + 5.0f; - this->csCamAt.z = sZelda->actor.world.pos.z; + this->csCamAt.x = sBossGanonZelda->actor.world.pos.x; + this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f; + this->csCamAt.z = sBossGanonZelda->actor.world.pos.z; if (this->csTimer >= 10) { Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f); } if (this->csTimer == 10) { - sZelda->unk_3C8 = 8; + sBossGanonZelda->unk_3C8 = 8; } if (this->csTimer == 50) { - sZelda->unk_3C8 = 4; + sBossGanonZelda->unk_3C8 = 4; } if (this->csTimer == 100) { @@ -1679,9 +1672,9 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->csCamEye.y = 4154.0f; this->csCamEye.z = -182.0f; - this->csCamAt.x = sZelda->actor.world.pos.x - 5.0f; - this->csCamAt.y = sZelda->actor.world.pos.y + 40.0f + 5.0f; - this->csCamAt.z = sZelda->actor.world.pos.z - 25.0f; + this->csCamAt.x = sBossGanonZelda->actor.world.pos.x - 5.0f; + this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f; + this->csCamAt.z = sBossGanonZelda->actor.world.pos.z - 25.0f; if (this->csTimer == 10) { Message_StartTextbox(globalCtx, 0x70D0, NULL); @@ -1698,7 +1691,7 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG); if (this->csTimer == 20) { - sZelda->unk_3C8 = 5; + sBossGanonZelda->unk_3C8 = 5; func_8002DF54(globalCtx, &this->actor, 0x39); } @@ -1747,15 +1740,15 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->csCamEye.y = 4154.0f; this->csCamEye.z = -182.0f; - this->csCamAt.x = sZelda->actor.world.pos.x - 5.0f; - this->csCamAt.y = sZelda->actor.world.pos.y + 40.0f + 5.0f; - this->csCamAt.z = sZelda->actor.world.pos.z - 25.0f; + this->csCamAt.x = sBossGanonZelda->actor.world.pos.x - 5.0f; + this->csCamAt.y = sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f; + this->csCamAt.z = sBossGanonZelda->actor.world.pos.z - 25.0f; this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.3f; func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG); if (this->csTimer == 70) { - sZelda->unk_3C8 = 6; + sBossGanonZelda->unk_3C8 = 6; } if (this->csTimer == 90) { @@ -1778,12 +1771,12 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->csCamEye.y = 4154.0f; this->csCamEye.z = -242.0f; - this->csCamAt.x = (sZelda->actor.world.pos.x - 5.0f) - 30.0f; - this->csCamAt.y = (sZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f; - this->csCamAt.z = (sZelda->actor.world.pos.z - 25.0f) + 80.0f; + this->csCamAt.x = (sBossGanonZelda->actor.world.pos.x - 5.0f) - 30.0f; + this->csCamAt.y = (sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f; + this->csCamAt.z = (sBossGanonZelda->actor.world.pos.z - 25.0f) + 80.0f; if ((this->csTimer > 50) && (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_NONE)) { - sZelda->unk_3C8 = 7; + sBossGanonZelda->unk_3C8 = 7; this->csState = 108; this->csTimer = 0; } @@ -1793,9 +1786,9 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx) this->unk_70C = Math_SinS(this->csTimer * 0x6300) * 0.8f; func_80078884(NA_SE_EV_EARTHQUAKE - SFX_FLAG); - this->csCamAt.x = (sZelda->actor.world.pos.x - 5.0f) - 30.0f; - this->csCamAt.y = (sZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f; - this->csCamAt.z = (sZelda->actor.world.pos.z - 25.0f) + 80.0f; + this->csCamAt.x = (sBossGanonZelda->actor.world.pos.x - 5.0f) - 30.0f; + this->csCamAt.y = (sBossGanonZelda->actor.world.pos.y + 40.0f + 5.0f) - 20.0f; + this->csCamAt.z = (sBossGanonZelda->actor.world.pos.z - 25.0f) + 80.0f; if (this->csTimer > 50) { mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM); @@ -1905,7 +1898,7 @@ void BossGanon_PoundFloor(BossGanon* this, GlobalContext* globalCtx) { break; case 1: - sCape->gravity = -1.0f; + sBossGanonCape->gravity = -1.0f; this->envLightMode = 1; Math_ApproachF(&this->actor.velocity.y, -50.0f, 1.0f, 10.0f); this->actor.world.pos.y += this->actor.velocity.y; @@ -1952,7 +1945,7 @@ void BossGanon_PoundFloor(BossGanon* this, GlobalContext* globalCtx) { this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp3Anim); Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f); SkelAnime_Update(&this->skelAnime); - sCape->attachShouldersTimer = 18.0f; + sBossGanonCape->attachShouldersTimer = 18.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); this->unk_1C2 = 4; } @@ -2136,7 +2129,7 @@ void BossGanon_ChargeBigMagic(BossGanon* this, GlobalContext* globalCtx) { } if (this->timers[0] == 1) { - sCape->attachLeftArmTimer = 15.0f; + sBossGanonCape->attachLeftArmTimer = 15.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); } @@ -2174,7 +2167,7 @@ void BossGanon_ChargeBigMagic(BossGanon* this, GlobalContext* globalCtx) { } if (Animation_OnFrame(&this->skelAnime, 3.0f)) { - sCape->attachShouldersTimer = 26.0f; + sBossGanonCape->attachShouldersTimer = 26.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); } @@ -2202,7 +2195,7 @@ void BossGanon_SetupWait(BossGanon* this, GlobalContext* globalCtx) { this->fwork[GDF_FWORK_0] = 0.0f; this->timers[0] = (s16)Rand_ZeroFloat(64.0f) + 30; this->unk_1C2 = 0; - sCape->minY = 2.0f; + sBossGanonCape->minY = 2.0f; } void BossGanon_Wait(BossGanon* this, GlobalContext* globalCtx) { @@ -2213,10 +2206,10 @@ void BossGanon_Wait(BossGanon* this, GlobalContext* globalCtx) { this->legSwayEnabled = true; - sCape->backPush = -3.0f; - sCape->backSwayMagnitude = 0.25f; - sCape->sideSwayMagnitude = -3.0f; - sCape->minDist = 20.0f; + sBossGanonCape->backPush = -3.0f; + sBossGanonCape->backSwayMagnitude = 0.25f; + sBossGanonCape->sideSwayMagnitude = -3.0f; + sBossGanonCape->minDist = 20.0f; SkelAnime_Update(&this->skelAnime); @@ -2271,10 +2264,10 @@ void BossGanon_SetupChargeLightBall(BossGanon* this, GlobalContext* globalCtx) { void BossGanon_ChargeLightBall(BossGanon* this, GlobalContext* globalCtx) { SkelAnime_Update(&this->skelAnime); - sCape->backPush = -3.0f; - sCape->backSwayMagnitude = 1.25f; - sCape->sideSwayMagnitude = -2.0f; - sCape->minDist = 10.0f; + sBossGanonCape->backPush = -3.0f; + sBossGanonCape->backSwayMagnitude = 1.25f; + sBossGanonCape->sideSwayMagnitude = -2.0f; + sBossGanonCape->minDist = 10.0f; if (this->timers[0] < 17) { this->envLightMode = 1; @@ -2355,7 +2348,7 @@ void BossGanon_PlayTennis(BossGanon* this, GlobalContext* globalCtx) { rand = Rand_ZeroOne() * 1.99f; this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(volleyAnims[rand]); Animation_MorphToPlayOnce(&this->skelAnime, volleyAnims[rand], 0.0f); - sCape->attachRightArmTimer = capeRightArmDurations[rand]; + sBossGanonCape->attachRightArmTimer = capeRightArmDurations[rand]; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); this->startVolley = false; } @@ -2383,7 +2376,7 @@ void BossGanon_SetupBlock(BossGanon* this, GlobalContext* globalCtx) { } this->unk_1C2 = 0; - sCape->attachLeftArmTimer = this->timers[0] = 10; + sBossGanonCape->attachLeftArmTimer = this->timers[0] = 10; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); this->handLightBallScale = 0.0f; } @@ -2391,10 +2384,10 @@ void BossGanon_SetupBlock(BossGanon* this, GlobalContext* globalCtx) { void BossGanon_Block(BossGanon* this, GlobalContext* globalCtx) { this->collider.base.colType = 9; SkelAnime_Update(&this->skelAnime); - sCape->backPush = -9.0f; - sCape->backSwayMagnitude = 0.25f; - sCape->sideSwayMagnitude = -2.0f; - sCape->minDist = 13.0f; + sBossGanonCape->backPush = -9.0f; + sBossGanonCape->backSwayMagnitude = 0.25f; + sBossGanonCape->sideSwayMagnitude = -2.0f; + sBossGanonCape->minDist = 13.0f; if (this->unk_1C2 == 0) { if (this->timers[0] == 0) { @@ -2402,11 +2395,11 @@ void BossGanon_Block(BossGanon* this, GlobalContext* globalCtx) { Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBlockReleaseAnim, 0.0f); this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBlockReleaseAnim); SkelAnime_Update(&this->skelAnime); - sCape->attachShouldersTimer = 15.0f; + sBossGanonCape->attachShouldersTimer = 15.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); } } else { - sCape->sideSwayMagnitude = -13.0f; + sBossGanonCape->sideSwayMagnitude = -13.0f; if (Animation_OnFrame(&this->skelAnime, this->fwork[GDF_FWORK_1])) { BossGanon_SetupWait(this, globalCtx); @@ -2429,7 +2422,7 @@ void BossGanon_SetupHitByLightBall(BossGanon* this, GlobalContext* globalCtx) { this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfBigMagicHitAnim); Animation_MorphToPlayOnce(&this->skelAnime, &gDorfBigMagicHitAnim, 0); this->timers[0] = 70; - sCape->attachRightArmTimer = sCape->attachLeftArmTimer = 0; + sBossGanonCape->attachRightArmTimer = sBossGanonCape->attachLeftArmTimer = 0; for (i = 1; i < 15; i++) { this->unk_4E4[i] = D_808E4C58[i]; @@ -2466,7 +2459,7 @@ void BossGanon_HitByLightBall(BossGanon* this, GlobalContext* globalCtx) { Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f); this->unk_1C2 = 2; SkelAnime_Update(&this->skelAnime); - sCape->attachShouldersTimer = 18.0f; + sBossGanonCape->attachShouldersTimer = 18.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_RESTORE); this->timers[2] = 130; @@ -2500,7 +2493,7 @@ void BossGanon_SetupVulnerable(BossGanon* this, GlobalContext* globalCtx) { BossGanon_SetAnimationObject(this, globalCtx, OBJECT_GANON_ANIME1); this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfLightArrowHitAnim); Animation_MorphToPlayOnce(&this->skelAnime, &gDorfLightArrowHitAnim, 0.0f); - sCape->attachRightArmTimer = sCape->attachLeftArmTimer = 0; + sBossGanonCape->attachRightArmTimer = sBossGanonCape->attachLeftArmTimer = 0; this->actionFunc = BossGanon_Vulnerable; this->actor.velocity.x = 0.0f; @@ -2508,10 +2501,10 @@ void BossGanon_SetupVulnerable(BossGanon* this, GlobalContext* globalCtx) { this->actor.velocity.z = 0.0f; this->unk_1C2 = 0; - sCape->backPush = -4.0f; - sCape->backSwayMagnitude = 0.75f; - sCape->sideSwayMagnitude = -3.0f; - sCape->minDist = 20.0f; + sBossGanonCape->backPush = -4.0f; + sBossGanonCape->backSwayMagnitude = 0.75f; + sBossGanonCape->sideSwayMagnitude = -3.0f; + sBossGanonCape->minDist = 20.0f; for (i = 0; i < 10; i++) { Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_GANON, this->unk_1FC.x, @@ -2571,7 +2564,7 @@ void BossGanon_Vulnerable(BossGanon* this, GlobalContext* globalCtx) { break; case 2: - sCape->minDist = 0.0f; + sBossGanonCape->minDist = 0.0f; this->actor.velocity.y = this->actor.velocity.y - 0.5f; if (this->actor.world.pos.y < 40.0f) { @@ -2625,7 +2618,7 @@ void BossGanon_Vulnerable(BossGanon* this, GlobalContext* globalCtx) { this->unk_1C2 = 6; this->fwork[GDF_FWORK_1] = Animation_GetLastFrame(&gDorfGetUp2Anim); Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp2Anim, 0.0f); - sCape->minDist = 20.0f; + sBossGanonCape->minDist = 20.0f; this->unk_19F = 1; } break; @@ -2646,7 +2639,7 @@ void BossGanon_Vulnerable(BossGanon* this, GlobalContext* globalCtx) { Animation_MorphToPlayOnce(&this->skelAnime, &gDorfGetUp3Anim, 0.0f); this->unk_1C2 = 8; SkelAnime_Update(&this->skelAnime); - sCape->attachShouldersTimer = 18.0f; + sBossGanonCape->attachShouldersTimer = 18.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EV_GANON_MANTLE); Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_RESTORE); break; @@ -2743,10 +2736,10 @@ void BossGanon_UpdateDamage(BossGanon* this, GlobalContext* globalCtx) { this->actor.colChkInfo.health -= damage; } - for (i = 0; i < ARRAY_COUNT(sCape->strands); i++) { + for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) { for (j = 1; j < 12; j++) { - sCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f); - sCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f); + sBossGanonCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f); + sBossGanonCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f); } } @@ -2762,16 +2755,16 @@ void BossGanon_UpdateDamage(BossGanon* this, GlobalContext* globalCtx) { Audio_PlayActorSound2(&this->actor, NA_SE_EN_GANON_CUTBODY); BossGanon_SetupDamaged(this, globalCtx); this->unk_1A6 = 15; - sCape->tearTimer = 1; + sBossGanonCape->tearTimer = 1; } } } else if (acHitInfo->toucher.dmgFlags & 0x1F8A4) { Audio_PlayActorSound2(&this->actor, 0); - for (i = 0; i < ARRAY_COUNT(sCape->strands); i++) { + for (i = 0; i < ARRAY_COUNT(sBossGanonCape->strands); i++) { for (j = 1; j < 12; j++) { - sCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f); - sCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f); + sBossGanonCape->strands[i].velocities[j].x = Rand_CenteredFloat(15.0f); + sBossGanonCape->strands[i].velocities[j].z = Rand_CenteredFloat(15.0f); } } } @@ -2841,7 +2834,7 @@ void BossGanon_Update(Actor* thisx, GlobalContext* globalCtx2) { } this->collider.base.colType = 3; - sCape->gravity = -3.0f; + sBossGanonCape->gravity = -3.0f; this->shockGlow = false; this->actor.flags &= ~ACTOR_FLAG_0; this->unk_1A2++; @@ -3334,20 +3327,20 @@ void BossGanon_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList } void BossGanon_InitRand(s32 seedInit0, s32 seedInit1, s32 seedInit2) { - sSeed1 = seedInit0; - sSeed2 = seedInit1; - sSeed3 = seedInit2; + sBossGanonSeed1 = seedInit0; + sBossGanonSeed2 = seedInit1; + sBossGanonSeed3 = seedInit2; } f32 BossGanon_RandZeroOne(void) { // Wichmann-Hill algorithm f32 randFloat; - sSeed1 = (sSeed1 * 171) % 30269; - sSeed2 = (sSeed2 * 172) % 30307; - sSeed3 = (sSeed3 * 170) % 30323; + sBossGanonSeed1 = (sBossGanonSeed1 * 171) % 30269; + sBossGanonSeed2 = (sBossGanonSeed2 * 172) % 30307; + sBossGanonSeed3 = (sBossGanonSeed3 * 170) % 30323; - randFloat = (sSeed1 / 30269.0f) + (sSeed2 / 30307.0f) + (sSeed3 / 30323.0f); + randFloat = (sBossGanonSeed1 / 30269.0f) + (sBossGanonSeed2 / 30307.0f) + (sBossGanonSeed3 / 30323.0f); while (randFloat >= 1.0f) { randFloat -= 1.0f; @@ -3559,7 +3552,7 @@ void BossGanon_DrawTriforce(BossGanon* this, GlobalContext* globalCtx) { this->triforcePos.y += 3.0f; this->triforcePos.z += -2.0f; } else if (this->triforceType == GDF_TRIFORCE_ZELDA) { - this->triforcePos = sZelda->unk_31C; + this->triforcePos = sBossGanonZelda->unk_31C; this->triforcePos.y += 1.8f; this->triforcePos.z += 4.0f; @@ -3734,9 +3727,9 @@ void BossGanon_GenShadowTexture(u8* tex, BossGanon* this, GlobalContext* globalC for (i = 0; i < 12; i++) { for (j = 0; j < 12; j++) { - sp7C.x = sCape->strands[i].joints[j].x - this->actor.world.pos.x; - sp7C.y = sCape->strands[i].joints[j].y - this->actor.world.pos.y + 76.0f + 100.0f + 30.0f; - sp7C.z = sCape->strands[i].joints[j].z - this->actor.world.pos.z; + sp7C.x = sBossGanonCape->strands[i].joints[j].x - this->actor.world.pos.x; + sp7C.y = sBossGanonCape->strands[i].joints[j].y - this->actor.world.pos.y + 76.0f + 100.0f + 30.0f; + sp7C.z = sBossGanonCape->strands[i].joints[j].z - this->actor.world.pos.z; Matrix_MultVec3f(&sp7C, &sp70); @@ -3746,7 +3739,7 @@ void BossGanon_GenShadowTexture(u8* tex, BossGanon* this, GlobalContext* globalC baseX = (s32)(sp70.x + 32.0f); baseY = (s16)sp70.y * 0x40; - if (!sCape->strands[i].torn[j]) { + if (!sBossGanonCape->strands[i].torn[j]) { for (y = -1, addY = -0x40; y <= 1; y++, addY += 0x40) { for (x = -3; x <= 3; x++) { index = baseX + x + baseY + addY; @@ -3827,13 +3820,13 @@ void BossGanon_Draw(Actor* thisx, GlobalContext* globalCtx) { BossGanon_DrawEffects(globalCtx); - sCape->actor.world.pos = this->actor.world.pos; + sBossGanonCape->actor.world.pos = this->actor.world.pos; - sCape->rightForearmPos = this->unk_214; - sCape->leftForearmPos = this->unk_220; + sBossGanonCape->rightForearmPos = this->unk_214; + sBossGanonCape->leftForearmPos = this->unk_220; - sCape->rightShoulderPos = this->unk_22C; - sCape->leftShoulderPos = this->unk_238; + sBossGanonCape->rightShoulderPos = this->unk_22C; + sBossGanonCape->leftShoulderPos = this->unk_238; BossGanon_DrawShock(this, globalCtx); BossGanon_DrawHandLightBall(this, globalCtx); @@ -4628,7 +4621,7 @@ void BossGanon_UpdateEffects(GlobalContext* globalCtx) { spA0.x = 0.0f; spA0.y = 0.0f; - for (i = 0; i < ARRAY_COUNT(sEffectBuf); i++, eff++) { + for (i = 0; i < ARRAY_COUNT(sBossGanonEffectBuf); i++, eff++) { if (eff->type != GDF_EFF_NONE) { eff->pos.x += eff->velocity.x; eff->pos.y += eff->velocity.y; @@ -4662,9 +4655,9 @@ void BossGanon_UpdateEffects(GlobalContext* globalCtx) { eff->alpha = 255; } } else if (eff->type == GDF_EFF_BLACK_DOT) { - xDiff = sGanondorf->unk_278.x - eff->pos.x; - yDiff = sGanondorf->unk_278.y - eff->pos.y; - zDiff = sGanondorf->unk_278.z - eff->pos.z; + xDiff = sBossGanonGanondorf->unk_278.x - eff->pos.x; + yDiff = sBossGanonGanondorf->unk_278.y - eff->pos.y; + zDiff = sBossGanonGanondorf->unk_278.z - eff->pos.z; yRot = Math_FAtan2F(xDiff, zDiff); @@ -4704,9 +4697,9 @@ void BossGanon_UpdateEffects(GlobalContext* globalCtx) { if (eff->unk_2E == GDF_SHOCK_DORF_YELLOW) { bodyPart = (s16)Rand_ZeroFloat(13.9f) + 1; - eff->pos.x = sGanondorf->unk_2EC[bodyPart].x + Rand_CenteredFloat(20.0f); - eff->pos.y = sGanondorf->unk_2EC[bodyPart].y + Rand_CenteredFloat(20.0f); - eff->pos.z = sGanondorf->unk_2EC[bodyPart].z + Rand_CenteredFloat(20.0f); + eff->pos.x = sBossGanonGanondorf->unk_2EC[bodyPart].x + Rand_CenteredFloat(20.0f); + eff->pos.y = sBossGanonGanondorf->unk_2EC[bodyPart].y + Rand_CenteredFloat(20.0f); + eff->pos.z = sBossGanonGanondorf->unk_2EC[bodyPart].z + Rand_CenteredFloat(20.0f); } else { bodyPart = (s16)Rand_ZeroFloat(17.9f); @@ -4799,7 +4792,7 @@ void BossGanon_UpdateEffects(GlobalContext* globalCtx) { if (((eff->scale * 150.0f) < distToPlayer) && (distToPlayer < (eff->scale * 300.0f))) { eff->timer = 150; - func_8002F6D4(globalCtx, &sGanondorf->actor, 7.0f, sGanondorf->actor.yawTowardsPlayer, 0.0f, + func_8002F6D4(globalCtx, &sBossGanonGanondorf->actor, 7.0f, sBossGanonGanondorf->actor.yawTowardsPlayer, 0.0f, 0x20); } } @@ -4838,6 +4831,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 200; i++, eff++) { if (eff->type == GDF_EFF_WINDOW_SHARD) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_OPA_DISP++); if (flag == 0) { gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardMaterialDL); @@ -4855,6 +4849,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10898), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4863,6 +4858,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_SPARKLE) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); if (flag == 0) { gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0); @@ -4877,6 +4873,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10932), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4885,6 +4882,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_LIGHT_RAY) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); if (flag == 0) { gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0); @@ -4901,6 +4899,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10971), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4909,6 +4908,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_SHOCK) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); if (flag == 0) { gDPPipeSync(POLY_XLU_DISP++); if (eff->unk_2E == GDF_SHOCK_PLAYER_PURPLE) { @@ -4927,6 +4927,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11023), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfShockDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4934,13 +4935,14 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_LIGHTNING) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, sLightningPrimColors[(eff->timer * 3) + 0], sLightningPrimColors[(eff->timer * 3) + 1], sLightningPrimColors[(eff->timer * 3) + 2], 255); gDPSetEnvColor(POLY_XLU_DISP++, sLightningEnvColors[(eff->timer * 3) + 0], sLightningEnvColors[(eff->timer * 3) + 1], sLightningEnvColors[(eff->timer * 3) + 2], 0); - Matrix_Translate(sGanondorf->unk_260.x, sGanondorf->unk_260.y, sGanondorf->unk_260.z, MTXMODE_NEW); + Matrix_Translate(sBossGanonGanondorf->unk_260.x, sBossGanonGanondorf->unk_260.y, sBossGanonGanondorf->unk_260.z, MTXMODE_NEW); Matrix_RotateY(eff->unk_48, MTXMODE_APPLY); Matrix_RotateZ(eff->unk_3C, MTXMODE_APPLY); Matrix_Scale(eff->scale, eff->scale, eff->scale, MTXMODE_APPLY); @@ -4949,6 +4951,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sLightningTextures[eff->timer])); gSPDisplayList(POLY_XLU_DISP++, gDorfLightningDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4956,6 +4959,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_IMPACT_DUST_DARK) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, eff->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 100, 70, 0, 128); @@ -4967,6 +4971,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11121), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfImpactDarkDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4974,6 +4979,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_IMPACT_DUST_LIGHT) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, eff->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 200, 100, 0, 128); @@ -4985,6 +4991,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11165), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfImpactLightDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4992,6 +4999,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_SHOCKWAVE) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 170, eff->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 150, 255, 0, 128); @@ -5004,6 +5012,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11209), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfShockwaveDL); + FrameInterpolation_RecordCloseChild(); } } @@ -5011,6 +5020,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { for (i = 0; i < 150; i++, eff++) { if (eff->type == GDF_EFF_BLACK_DOT) { + FrameInterpolation_RecordOpenChild(eff, eff->epoch); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 150, 170, 0, eff->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128); @@ -5023,6 +5033,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11250), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gDorfDotDL); + FrameInterpolation_RecordCloseChild(); } } @@ -5032,16 +5043,11 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) { #include "overlays/ovl_Boss_Ganon/ovl_Boss_Ganon.h" void BossGanon_Reset(void) { - -static EnGanonMant* sCape; - - sSeed1 = 0; - sSeed2 = 0; - sSeed3 = 0; - sGanondorf = NULL; - sZelda = NULL; - sCape = NULL; - - - memset(sEffectBuf, 0, sizeof(sEffectBuf)); -} + sBossGanonSeed1 = 0; + sBossGanonSeed2 = 0; + sBossGanonSeed3 = 0; + sBossGanonGanondorf = NULL; + sBossGanonZelda = NULL; + sBossGanonCape = NULL; + memset(sBossGanonEffectBuf, 0, sizeof(sBossGanonEffectBuf)); +} \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h index a3e3e503e..7a797ad74 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h +++ b/soh/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h @@ -53,6 +53,25 @@ typedef enum { /* 2 */ GDF_TRIFORCE_DORF } GanondorfTriforceType; +typedef struct { + /* 0x00 */ u8 type; + /* 0x01 */ u8 timer; + /* 0x04 */ Vec3f pos; + /* 0x10 */ Vec3f velocity; + /* 0x1C */ Vec3f accel; + /* 0x28 */ Color_RGB8 color; + /* 0x2C */ s16 alpha; + /* 0x2E */ s16 unk_2E; + /* 0x30 */ s16 unk_30; + /* 0x34 */ f32 scale; + /* 0x38 */ f32 unk_38; // scale target mostly, but used for other things + /* 0x3C */ f32 unk_3C; // mostly z rot + /* 0x40 */ f32 unk_40; + /* 0x44 */ f32 unk_44; // mostly x rot + /* 0x48 */ f32 unk_48; // mostly y rot + u32 epoch; +} GanondorfEffect; // size = 0x4C + typedef struct BossGanon { /* 0x0000 */ Actor actor; /* 0x014C */ s32 animBankIndex; diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c index 21fd1a149..b946054b8 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c @@ -49,21 +49,40 @@ const ActorInit Boss_Ganon2_InitVars = { #include "z_boss_ganon2_data.c" +Vec3f D_8090EB20; + +EnZl3* sBossGanon2Zelda; + +Actor* D_8090EB30; + +BossGanon2Effect sBossGanon2Particles[100]; + +s32 sBossGanon2Seed1; +s32 sBossGanon2Seed2; +s32 sBossGanon2Seed3; + +Vec3f D_809105D8[4]; + +Vec3f D_80910608[4]; + +s8 D_80910638; + + void BossGanon2_InitRand(s32 seedInit0, s32 seedInit1, s32 seedInit2) { - sSeed1 = seedInit0; - sSeed2 = seedInit1; - sSeed3 = seedInit2; + sBossGanon2Seed1 = seedInit0; + sBossGanon2Seed2 = seedInit1; + sBossGanon2Seed3 = seedInit2; } f32 BossGanon2_RandZeroOne(void) { // Wichmann-Hill algorithm f32 randFloat; - sSeed1 = (sSeed1 * 171) % 30269; - sSeed2 = (sSeed2 * 172) % 30307; - sSeed3 = (sSeed3 * 170) % 30323; + sBossGanon2Seed1 = (sBossGanon2Seed1 * 171) % 30269; + sBossGanon2Seed2 = (sBossGanon2Seed2 * 172) % 30307; + sBossGanon2Seed3 = (sBossGanon2Seed3 * 170) % 30323; - randFloat = (sSeed1 / 30269.0f) + (sSeed2 / 30307.0f) + (sSeed3 / 30323.0f); + randFloat = (sBossGanon2Seed1 / 30269.0f) + (sBossGanon2Seed2 / 30307.0f) + (sBossGanon2Seed3 / 30323.0f); while (randFloat >= 1.0f) { randFloat -= 1.0f; } @@ -114,7 +133,7 @@ void func_808FD27C(GlobalContext* globalCtx, Vec3f* position, Vec3f* velocity, f BossGanon2Effect* effect = globalCtx->specialEffects; s16 i; - for (i = 0; i < ARRAY_COUNT(sParticles); i++, effect++) { + for (i = 0; i < ARRAY_COUNT(sBossGanon2Particles); i++, effect++) { if (effect->type == 0) { effect->type = 2; effect->position = *position; @@ -136,10 +155,10 @@ void BossGanon2_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; s16 i; - globalCtx->specialEffects = sParticles; + globalCtx->specialEffects = sBossGanon2Particles; - for (i = 0; i < ARRAY_COUNT(sParticles); i++) { - sParticles[i].type = 0; + for (i = 0; i < ARRAY_COUNT(sBossGanon2Particles); i++) { + sBossGanon2Particles[i].type = 0; } this->actor.colChkInfo.mass = MASS_IMMOVABLE; @@ -204,13 +223,13 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { Gameplay_ChangeCameraStatus(globalCtx, MAIN_CAM, CAM_STAT_WAIT); Gameplay_ChangeCameraStatus(globalCtx, this->unk_39E, CAM_STAT_ACTIVE); this->unk_39C = 1; - sZelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 970.0f, + sBossGanon2Zelda = (EnZl3*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_ZL3, 970.0f, 1086.0f, -200.0f, 0, 0, 0, 1); - sZelda->unk_3C8 = 0; - sZelda->actor.world.pos.x = 970.0f; - sZelda->actor.world.pos.y = 1086.0f; - sZelda->actor.world.pos.z = -214.0f; - sZelda->actor.shape.rot.y = -0x7000; + sBossGanon2Zelda->unk_3C8 = 0; + sBossGanon2Zelda->actor.world.pos.x = 970.0f; + sBossGanon2Zelda->actor.world.pos.y = 1086.0f; + sBossGanon2Zelda->actor.world.pos.z = -214.0f; + sBossGanon2Zelda->actor.shape.rot.y = -0x7000; this->unk_3BC.x = 0.0f; this->unk_3BC.y = 1.0f; this->unk_3BC.z = 0.0f; @@ -258,20 +277,20 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { player->actor.world.pos.x = 970.0f; player->actor.world.pos.y = 1086.0f; player->actor.world.pos.z = -166.0f; - sZelda->actor.world.pos.x = 974.0f; - sZelda->actor.world.pos.y = 1086.0f; - sZelda->actor.world.pos.z = -186.0f; + sBossGanon2Zelda->actor.world.pos.x = 974.0f; + sBossGanon2Zelda->actor.world.pos.y = 1086.0f; + sBossGanon2Zelda->actor.world.pos.z = -186.0f; player->actor.shape.rot.y = -0x5000; - sZelda->actor.shape.rot.y = -0x5000; + sBossGanon2Zelda->actor.shape.rot.y = -0x5000; if (this->unk_398 == 60) { Message_StartTextbox(globalCtx, 0x70D4, NULL); } if (this->unk_398 == 40) { - sZelda->unk_3C8 = 1; + sBossGanon2Zelda->unk_3C8 = 1; func_8002DF54(globalCtx, &this->actor, 0x4E); } if (this->unk_398 == 85) { - sZelda->unk_3C8 = 2; + sBossGanon2Zelda->unk_3C8 = 2; func_8002DF54(globalCtx, &this->actor, 0x4F); } this->unk_3A4.x = 930.0f; @@ -300,14 +319,14 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_STOP); } if (this->unk_398 == 20) { - sZelda->unk_3C8 = 3; + sBossGanon2Zelda->unk_3C8 = 3; func_8002DF54(globalCtx, &this->actor, 0x50); } if (this->unk_398 == 55) { this->unk_39C = 4; this->unk_398 = 0; this->unk_410.x = 0.0f; - sZelda->unk_3C8 = 4; + sBossGanon2Zelda->unk_3C8 = 4; func_8002DF54(globalCtx, &this->actor, 0x50); } break; @@ -347,11 +366,11 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { player->actor.world.pos.x = 490.0f; player->actor.world.pos.y = 1086.0f; player->actor.world.pos.z = -166.0f; - sZelda->actor.world.pos.x = 724.0f; - sZelda->actor.world.pos.y = 1086.0f; - sZelda->actor.world.pos.z = -186.0f; + sBossGanon2Zelda->actor.world.pos.x = 724.0f; + sBossGanon2Zelda->actor.world.pos.y = 1086.0f; + sBossGanon2Zelda->actor.world.pos.z = -186.0f; player->actor.shape.rot.y = -0x4000; - sZelda->actor.shape.rot.y = -0x5000; + sBossGanon2Zelda->actor.shape.rot.y = -0x5000; this->unk_3A4.x = 410.0f; this->unk_3A4.y = 1096.0f; this->unk_3A4.z = -110.0f; @@ -370,7 +389,7 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { this->unk_339 = 4; } if (this->unk_398 == 30) { - sZelda->unk_3C8 = 5; + sBossGanon2Zelda->unk_3C8 = 5; func_8002DF54(globalCtx, &this->actor, 0x51); } if (this->unk_398 == 50) { @@ -384,11 +403,11 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { player->actor.world.pos.x = 490.0f; player->actor.world.pos.y = 1086.0f; player->actor.world.pos.z = -166.0f; - sZelda->actor.world.pos.x = 724.0f; - sZelda->actor.world.pos.y = 1086.0f; - sZelda->actor.world.pos.z = -186.0f; + sBossGanon2Zelda->actor.world.pos.x = 724.0f; + sBossGanon2Zelda->actor.world.pos.y = 1086.0f; + sBossGanon2Zelda->actor.world.pos.z = -186.0f; player->actor.shape.rot.y = -0x4000; - sZelda->actor.shape.rot.y = -0x5000; + sBossGanon2Zelda->actor.shape.rot.y = -0x5000; this->unk_3A4.x = 450.0f; this->unk_3A4.y = 1121.0f; this->unk_3A4.z = -158.0f; @@ -457,9 +476,9 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { player->actor.world.pos.y = 1086.0f; player->actor.world.pos.z = -266.0f; player->actor.shape.rot.y = -0x4000; - sZelda->actor.world.pos.x = 724.0f; - sZelda->actor.world.pos.y = 1086.0f; - sZelda->actor.world.pos.z = -186.0f; + sBossGanon2Zelda->actor.world.pos.x = 724.0f; + sBossGanon2Zelda->actor.world.pos.y = 1086.0f; + sBossGanon2Zelda->actor.world.pos.z = -186.0f; this->unk_3A4.x = this->actor.world.pos.x + -10.0f; this->unk_3A4.y = this->actor.world.pos.y + 80.0f; this->unk_3A4.z = this->actor.world.pos.z + 50.0f; @@ -770,9 +789,9 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { BossGanon2Effect* effect = globalCtx->specialEffects; effect->unk_2E = 1; - effect->position.x = sZelda->actor.world.pos.x + 50.0f + 10.0f; - effect->position.y = sZelda->actor.world.pos.y + 350.0f; - effect->position.z = sZelda->actor.world.pos.z - 25.0f; + effect->position.x = sBossGanon2Zelda->actor.world.pos.x + 50.0f + 10.0f; + effect->position.y = sBossGanon2Zelda->actor.world.pos.y + 350.0f; + effect->position.z = sBossGanon2Zelda->actor.world.pos.z - 25.0f; effect->velocity.x = 0.0f; effect->velocity.z = 0.0f; effect->velocity.y = -30.0f; @@ -782,15 +801,15 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { break; } case 26: - this->unk_3A4.x = sZelda->actor.world.pos.x + 100.0f + 30.0f; - this->unk_3A4.y = sZelda->actor.world.pos.y + 10.0f; - this->unk_3A4.z = sZelda->actor.world.pos.z + 5.0f; - this->unk_3B0.x = sZelda->actor.world.pos.x; - this->unk_3B0.y = sZelda->actor.world.pos.y + 30.0f; - this->unk_3B0.z = sZelda->actor.world.pos.z - 20.0f; + this->unk_3A4.x = sBossGanon2Zelda->actor.world.pos.x + 100.0f + 30.0f; + this->unk_3A4.y = sBossGanon2Zelda->actor.world.pos.y + 10.0f; + this->unk_3A4.z = sBossGanon2Zelda->actor.world.pos.z + 5.0f; + this->unk_3B0.x = sBossGanon2Zelda->actor.world.pos.x; + this->unk_3B0.y = sBossGanon2Zelda->actor.world.pos.y + 30.0f; + this->unk_3B0.z = sBossGanon2Zelda->actor.world.pos.z - 20.0f; this->unk_3BC.z = -0.5f; if (this->unk_398 == 13) { - sZelda->unk_3C8 = 6; + sBossGanon2Zelda->unk_3C8 = 6; } if (this->unk_398 == 50) { this->unk_39C = 27; @@ -879,7 +898,7 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) { func_808FFDB0(this, globalCtx); this->unk_1A2[1] = 50; this->actor.flags |= ACTOR_FLAG_0; - sZelda->unk_3C8 = 7; + sBossGanon2Zelda->unk_3C8 = 7; } break; } @@ -1323,12 +1342,12 @@ void func_80900890(BossGanon2* this, GlobalContext* globalCtx) { break; case 2: this->unk_1A2[0] = 300; - this->unk_3A4.x = sZelda->actor.world.pos.x - 100.0f; - this->unk_3A4.y = sZelda->actor.world.pos.y + 30.0f; - this->unk_3A4.z = (sZelda->actor.world.pos.z + 30.0f) - 60.0f; - this->unk_3B0.x = sZelda->actor.world.pos.x; - this->unk_3B0.y = sZelda->actor.world.pos.y + 30.0f; - this->unk_3B0.z = sZelda->actor.world.pos.z - 10.0f; + this->unk_3A4.x = sBossGanon2Zelda->actor.world.pos.x - 100.0f; + this->unk_3A4.y = sBossGanon2Zelda->actor.world.pos.y + 30.0f; + this->unk_3A4.z = (sBossGanon2Zelda->actor.world.pos.z + 30.0f) - 60.0f; + this->unk_3B0.x = sBossGanon2Zelda->actor.world.pos.x; + this->unk_3B0.y = sBossGanon2Zelda->actor.world.pos.y + 30.0f; + this->unk_3B0.z = sBossGanon2Zelda->actor.world.pos.z - 10.0f; Math_ApproachZeroF(&this->unk_324, 1.0f, 5.0f); Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 1.0f / 51); if (this->unk_1A2[1] == 80) { @@ -1356,8 +1375,8 @@ void func_80900890(BossGanon2* this, GlobalContext* globalCtx) { func_8002DF54(globalCtx, &this->actor, 0x60); this->unk_398 = 0; case 11: - player->actor.world.pos.x = sZelda->actor.world.pos.x + 50.0f + 10.0f; - player->actor.world.pos.z = sZelda->actor.world.pos.z - 25.0f; + player->actor.world.pos.x = sBossGanon2Zelda->actor.world.pos.x + 50.0f + 10.0f; + player->actor.world.pos.z = sBossGanon2Zelda->actor.world.pos.z - 25.0f; player->actor.shape.rot.y = -0x8000; this->unk_3A4.x = (player->actor.world.pos.x + 100.0f) - 80.0f; this->unk_3A4.y = (player->actor.world.pos.y + 60.0f) - 40.0f; @@ -1482,7 +1501,7 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { func_8002DF54(globalCtx, &this->actor, 8); this->unk_39C = 1; this->unk_398 = 0; - sZelda->unk_3C8 = 9; + sBossGanon2Zelda->unk_3C8 = 9; this->unk_31C = 0; this->unk_1A2[2] = 0; this->unk_336 = 0; @@ -1522,9 +1541,9 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { player->actor.shape.rot.y = -0x4000; player->actor.world.pos.x = 200.0f; player->actor.world.pos.z = 30.0f; - sZelda->actor.world.pos.x = 340.0f; - sZelda->actor.world.pos.z = -250.0f; - sZelda->actor.world.rot.y = sZelda->actor.shape.rot.y = -0x2000; + sBossGanon2Zelda->actor.world.pos.x = 340.0f; + sBossGanon2Zelda->actor.world.pos.z = -250.0f; + sBossGanon2Zelda->actor.world.rot.y = sBossGanon2Zelda->actor.shape.rot.y = -0x2000; this->unk_3A4.x = 250; this->unk_3A4.y = 1150.0f; this->unk_3A4.z = 0.0f; @@ -1543,9 +1562,9 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { this->unk_3A4.x = 250; this->unk_3A4.y = 1150.0f; this->unk_3A4.z = 0.0f; - Math_ApproachF(&this->unk_3B0.x, sZelda->actor.world.pos.x, 0.2f, 20.0f); - Math_ApproachF(&this->unk_3B0.y, sZelda->actor.world.pos.y + 50.0f, 0.2f, 10.0f); - Math_ApproachF(&this->unk_3B0.z, sZelda->actor.world.pos.z, 0.2f, 20.0f); + Math_ApproachF(&this->unk_3B0.x, sBossGanon2Zelda->actor.world.pos.x, 0.2f, 20.0f); + Math_ApproachF(&this->unk_3B0.y, sBossGanon2Zelda->actor.world.pos.y + 50.0f, 0.2f, 10.0f); + Math_ApproachF(&this->unk_3B0.z, sBossGanon2Zelda->actor.world.pos.z, 0.2f, 20.0f); if (this->unk_398 == 50) { this->unk_39C = 3; this->unk_398 = 0; @@ -1557,9 +1576,9 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { this->unk_3A4.x = 330.0f; this->unk_3A4.y = 1120.0f; this->unk_3A4.z = -150.0f; - this->unk_3B0.x = sZelda->actor.world.pos.x; - this->unk_3B0.y = sZelda->actor.world.pos.y + 40.0f; - this->unk_3B0.z = sZelda->actor.world.pos.z; + this->unk_3B0.x = sBossGanon2Zelda->actor.world.pos.x; + this->unk_3B0.y = sBossGanon2Zelda->actor.world.pos.y + 40.0f; + this->unk_3B0.z = sBossGanon2Zelda->actor.world.pos.z; if (this->unk_398 == 10) { Message_StartTextbox(globalCtx, 0x70D8, NULL); } @@ -1572,7 +1591,7 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { if (this->unk_398 > 10) { Math_ApproachZeroF(&this->unk_37C, 1.0f, 10.0f); if (this->unk_398 == 30) { - sZelda->unk_3C8 = 10; + sBossGanon2Zelda->unk_3C8 = 10; } this->unk_339 = 23; Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.05f); @@ -1743,7 +1762,7 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { if (this->unk_398 == 40) { this->unk_39C = 9; this->unk_398 = 0; - sZelda->unk_3C8 = 11; + sBossGanon2Zelda->unk_3C8 = 11; Message_StartTextbox(globalCtx, 0x70D9, NULL); this->unk_336 = 0; globalCtx->envCtx.unk_D8 = 0.0f; @@ -1754,9 +1773,9 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { this->unk_3A4.x = 330.0f; this->unk_3A4.y = 1120.0f; this->unk_3A4.z = -150.0f; - this->unk_3B0.x = sZelda->actor.world.pos.x; - this->unk_3B0.y = sZelda->actor.world.pos.y + 40.0f; - this->unk_3B0.z = sZelda->actor.world.pos.z; + this->unk_3B0.x = sBossGanon2Zelda->actor.world.pos.x; + this->unk_3B0.y = sBossGanon2Zelda->actor.world.pos.y + 40.0f; + this->unk_3B0.z = sBossGanon2Zelda->actor.world.pos.z; if (this->unk_398 > 60) { this->unk_39C = 10; this->unk_398 = 0; @@ -1771,26 +1790,26 @@ void func_8090120C(BossGanon2* this, GlobalContext* globalCtx) { if ((this->unk_398 >= 40) && (this->unk_398 <= 110)) { Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.02f); Math_ApproachF(&this->unk_384, 10.0f, 0.1f, 0.2f); - Audio_PlayActorSound2(&sZelda->actor, NA_SE_EV_GOD_LIGHTBALL_2 - SFX_FLAG); + Audio_PlayActorSound2(&sBossGanon2Zelda->actor, NA_SE_EV_GOD_LIGHTBALL_2 - SFX_FLAG); } else { Math_ApproachZeroF(&this->unk_384, 1.0f, 0.2f); } if (this->unk_398 > 130) { - Math_ApproachF(&this->unk_3B0.y, (sZelda->actor.world.pos.y + 40.0f + 10.0f) - 20.0f, 0.1f, + Math_ApproachF(&this->unk_3B0.y, (sBossGanon2Zelda->actor.world.pos.y + 40.0f + 10.0f) - 20.0f, 0.1f, this->unk_410.x); } else { - Math_ApproachF(&this->unk_3B0.y, sZelda->actor.world.pos.y + 40.0f + 10.0f, 0.05f, + Math_ApproachF(&this->unk_3B0.y, sBossGanon2Zelda->actor.world.pos.y + 40.0f + 10.0f, 0.05f, this->unk_410.x * 0.25f); } Math_ApproachF(&this->unk_410.x, 1.0f, 1.0f, 0.01f); if (this->unk_398 == 10) { - sZelda->unk_3C8 = 12; + sBossGanon2Zelda->unk_3C8 = 12; } if (this->unk_398 == 110) { - sZelda->unk_3C8 = 13; + sBossGanon2Zelda->unk_3C8 = 13; } if (this->unk_398 == 140) { - Audio_PlayActorSound2(&sZelda->actor, NA_SE_EV_HUMAN_BOUND); + Audio_PlayActorSound2(&sBossGanon2Zelda->actor, NA_SE_EV_HUMAN_BOUND); } if (this->unk_398 < 160) { break; @@ -1845,7 +1864,7 @@ void func_80902348(BossGanon2* this, GlobalContext* globalCtx) { } func_8002F6D4(globalCtx, &this->actor, 15.0f, this->actor.yawTowardsPlayer + phi_v0_2, 2.0f, 0); - sZelda->unk_3C8 = 8; + sBossGanon2Zelda->unk_3C8 = 8; this->unk_316 = 10; break; } @@ -1864,7 +1883,7 @@ void func_80902348(BossGanon2* this, GlobalContext* globalCtx) { player->isBurning = true; func_8002F6D4(globalCtx, &this->actor, 10.0f, Math_Atan2S(temp_f12, temp_f2), 0.0f, 0x10); - sZelda->unk_3C8 = 8; + sBossGanon2Zelda->unk_3C8 = 8; } } } @@ -2168,7 +2187,7 @@ void BossGanon2_Update(Actor* thisx, GlobalContext* globalCtx) { if (D_80906D78 != 0) { D_80906D78 = 0; - for (i2 = 0; i2 < ARRAY_COUNT(sParticles); i2++) { + for (i2 = 0; i2 < ARRAY_COUNT(sBossGanon2Particles); i2++) { angle = Rand_ZeroFloat(2 * M_PI); sp44 = Rand_ZeroFloat(40.0f) + 10.0f; sp58 = this->actor.world.pos; @@ -2641,7 +2660,7 @@ void func_80904FC8(BossGanon2* this, GlobalContext* globalCtx) { gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 200); gDPSetEnvColor(POLY_XLU_DISP++, 255, 200, 0, 0); gSPDisplayList(POLY_XLU_DISP++, ovl_Boss_Ganon2_DL_00B308); - Matrix_Translate(sZelda->actor.world.pos.x, sZelda->actor.world.pos.y + 80.0f, sZelda->actor.world.pos.z, + Matrix_Translate(sBossGanon2Zelda->actor.world.pos.x, sBossGanon2Zelda->actor.world.pos.y + 80.0f, sBossGanon2Zelda->actor.world.pos.z, MTXMODE_NEW); Matrix_ReplaceRotation(&globalCtx->billboardMtxF); Matrix_Scale(this->unk_384, this->unk_384, this->unk_384, MTXMODE_APPLY); @@ -2728,8 +2747,8 @@ void func_80905674(BossGanon2* this, GlobalContext* globalCtx) { this->unk_19C * -8, 32, 32)); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 170, (s16)this->unk_37C); gDPSetEnvColor(POLY_XLU_DISP++, 255, 200, 0, 128); - Matrix_Translate(sZelda->actor.world.pos.x + 100.0f, sZelda->actor.world.pos.y + 35.0f + 7.0f, - sZelda->actor.world.pos.z - 100.0f, MTXMODE_NEW); + Matrix_Translate(sBossGanon2Zelda->actor.world.pos.x + 100.0f, sBossGanon2Zelda->actor.world.pos.y + 35.0f + 7.0f, + sBossGanon2Zelda->actor.world.pos.z - 100.0f, MTXMODE_NEW); Matrix_RotateY(-M_PI / 4.0f, MTXMODE_APPLY); Matrix_Scale(0.040000003f, 0.040000003f, this->unk_380, MTXMODE_APPLY); Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY); @@ -2826,7 +2845,7 @@ void func_80905DA8(BossGanon2* this, GlobalContext* globalCtx) { Vec3f sp78; s16 i; - for (i = 0; i < ARRAY_COUNT(sParticles); i++, effect++) { + for (i = 0; i < ARRAY_COUNT(sBossGanon2Particles); i++, effect++) { if (effect->type != 0) { effect->position.x += effect->velocity.x; effect->position.y += effect->velocity.y; @@ -2934,7 +2953,7 @@ void func_809060E8(GlobalContext* globalCtx) { effect = effects; - for (i = 0; i < ARRAY_COUNT(sParticles); i++, effect++) { + for (i = 0; i < ARRAY_COUNT(sBossGanon2Particles); i++, effect++) { if (effect->type == 2) { if (!usingObjectGEff) { BossGanon2_SetObjectSegment(NULL, globalCtx, OBJECT_GEFF, true); @@ -3080,12 +3099,12 @@ void BossGanon2_Reset(void) { D_8090EB20.y = 0; D_8090EB20.z = 0; D_80910638 = 0; - sZelda = NULL; + sBossGanon2Zelda = NULL; D_8090EB30 = NULL; - sSeed1 = 0; - sSeed2 = 0; - sSeed3 = 0; + sBossGanon2Seed1 = 0; + sBossGanon2Seed2 = 0; + sBossGanon2Seed3 = 0; memset(D_809105D8, 0, sizeof(D_809105D8)); memset(D_80910608, 0, sizeof(D_80910608)); - memset(sParticles, 0, sizeof(sParticles)); -} + memset(sBossGanon2Particles, 0, sizeof(sBossGanon2Particles)); +} \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h index 3d2625231..6271f5c14 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h +++ b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h @@ -4,6 +4,20 @@ #include "ultra64.h" #include "global.h" + +typedef struct { + /* 0x00 */ u8 type; + /* 0x01 */ u8 unk_01; + /* 0x04 */ Vec3f position; + /* 0x10 */ Vec3f velocity; + /* 0x1C */ Vec3f accel; + /* 0x28 */ char unk_28[0x6]; + /* 0x2E */ s16 unk_2E; + /* 0x30 */ char unk_30[0x4]; + /* 0x34 */ f32 scale; + /* 0x38 */ Vec3f unk_38; +} BossGanon2Effect; // size = 0x44 + struct BossGanon2; typedef void (*BossGanon2ActionFunc)(struct BossGanon2*, GlobalContext*); diff --git a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2_data.c b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2_data.c index 47201ed0d..e19b36bd6 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2_data.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2_data.c @@ -2,19 +2,6 @@ #include "overlays/actors/ovl_En_Zl3/z_en_zl3.h" #include "objects/object_ganon2/object_ganon2.h" -typedef struct { - /* 0x00 */ u8 type; - /* 0x01 */ u8 unk_01; - /* 0x04 */ Vec3f position; - /* 0x10 */ Vec3f velocity; - /* 0x1C */ Vec3f accel; - /* 0x28 */ char unk_28[0x6]; - /* 0x2E */ s16 unk_2E; - /* 0x30 */ char unk_30[0x4]; - /* 0x34 */ f32 scale; - /* 0x38 */ Vec3f unk_38; -} BossGanon2Effect; // size = 0x44 - static Vec3f D_80906D60 = { 0.0f, 0.0f, 0.0f }; static Vec3f D_80906D6C = { 0.0f, 0.0f, 500.0f }; @@ -326,31 +313,7 @@ static s16 D_809071CC[] = { 1, -1, 1, 1, 3, 4, 1, 6, 7, 2, 9, 10, 2, 12, 13 }; static u8 D_809071EC[] = { 3, 2, 2, 1, 3, 3, 1, 3, 3, 1, 0, 3, 1, 0, 3 }; -// padding -static u32 D_809071FC[2] = { 0 }; - #include "overlays/ovl_Boss_Ganon2/ovl_Boss_Ganon2.h" -static Vec3f D_8090EB20; - -static EnZl3* sZelda; - -static Actor* D_8090EB30; - -// unused -static UNK_TYPE D_8090EB34; - -static BossGanon2Effect sParticles[100]; - -static s32 sSeed1; -static s32 sSeed2; -static s32 sSeed3; - -// unused -static UNK_TYPE D_809105DC; - -static Vec3f D_809105D8[4]; - -static Vec3f D_80910608[4]; - -static s8 D_80910638; +// padding +//static u32 D_809071FC[2] = { 0 }; diff --git a/soh/src/overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.c b/soh/src/overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.c index 94ea16422..227e0d6f0 100644 --- a/soh/src/overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.c +++ b/soh/src/overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.c @@ -210,7 +210,7 @@ static Vec3f sAudioVec = { 0.0f, 0.0f, 50.0f }; // OTRTODO: This code appears to cause the game to gradually crash... // Might be an OoB write. For now it's disabled. -void BossGanondrof_ClearPixels8x8(s16* texture, u8* mask, s16 index) +void BossGanondrof_ClearPixels8x8(s16* texture, u8* mask, s16 index) { //texture = ResourceMgr_LoadTexByName(texture); if (mask[index]) { @@ -248,18 +248,18 @@ void BossGanondrof_ClearPixels32x16(s16* texture, u8* mask, s16 index) { } } -void BossGanondrof_ClearPixels16x32(s16* texture, u8* mask, s16 index) { +void BossGanondrof_ClearPixels16x32(s16* texture, u8* mask, s16 index) { //texture = ResourceMgr_LoadTexByName(texture); if (mask[index]) { s16 i = ((index & 0xF) * 2) + ((index & 0xF0) * 2); - + ResourceMgr_WriteTexS16ByName(texture, i + 1, 0); ResourceMgr_WriteTexS16ByName(texture, i, 0); //texture[i + 1] = 0; //texture[i] = 0; } - + } void BossGanondrof_ClearPixels(u8* mask, s16 index) { diff --git a/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c b/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c index c6d8a8032..ae436ca2d 100644 --- a/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c +++ b/soh/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c @@ -10,6 +10,8 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "vt.h" +#include "soh/frame_interpolation.h" + #include #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5) @@ -34,6 +36,7 @@ typedef struct { /* 0x30 */ f32 scale; /* 0x30 */ f32 fwork[2]; /* 0x3C */ Vec3f* targetPos; + u32 epoch; } BossMoEffect; // size = 0x40 #define MO_FX_MAX_SIZE 0 @@ -144,25 +147,25 @@ static f32 sFlatWidth[41] = { #include "z_boss_mo_colchk.c" static BossMoEffect sEffects[300]; -static s32 sSeed1; -static s32 sSeed2; -static s32 sSeed3; +static s32 sBossGanonSeed1; +static s32 sBossGanonSeed2; +static s32 sBossGanonSeed3; void BossMo_InitRand(s32 seedInit0, s32 seedInit1, s32 seedInit2) { - sSeed1 = seedInit0; - sSeed2 = seedInit1; - sSeed3 = seedInit2; + sBossGanonSeed1 = seedInit0; + sBossGanonSeed2 = seedInit1; + sBossGanonSeed3 = seedInit2; } f32 BossMo_RandZeroOne(void) { // Wichmann-Hill algorithm f32 randFloat; - sSeed1 = (sSeed1 * 171) % 30269; - sSeed2 = (sSeed2 * 172) % 30307; - sSeed3 = (sSeed3 * 170) % 30323; + sBossGanonSeed1 = (sBossGanonSeed1 * 171) % 30269; + sBossGanonSeed2 = (sBossGanonSeed2 * 172) % 30307; + sBossGanonSeed3 = (sBossGanonSeed3 * 170) % 30323; - randFloat = (sSeed1 / 30269.0f) + (sSeed2 / 30307.0f) + (sSeed3 / 30323.0f); + randFloat = (sBossGanonSeed1 / 30269.0f) + (sBossGanonSeed2 / 30307.0f) + (sBossGanonSeed3 / 30323.0f); while (randFloat >= 1.0f) { randFloat -= 1.0f; } @@ -211,6 +214,7 @@ void BossMo_SpawnRipple(BossMoEffect* effect, Vec3f* pos, f32 scale, f32 maxScal effect->rippleMode = 1; effect->fwork[MO_FX_SPREAD_RATE] = (effect->fwork[MO_FX_MAX_SIZE] - effect->scale) * 0.1f; } + effect->epoch++; break; } } @@ -232,6 +236,7 @@ void BossMo_SpawnDroplet(s16 type, BossMoEffect* effect, Vec3f* pos, Vec3f* vel, effect->scale = scale; effect->fwork[MO_FX_SPREAD_RATE] = 1.0f; effect->stopTimer = 0; + effect->epoch++; break; } } @@ -250,6 +255,7 @@ void BossMo_SpawnStillDroplet(BossMoEffect* effect, Vec3f* pos, f32 scale) { effect->accel = zeroVec; effect->scale = scale; effect->fwork[MO_FX_SPREAD_RATE] = 1.0f; + effect->epoch++; break; } } @@ -274,6 +280,7 @@ void BossMo_SpawnBubble(BossMoEffect* effect, Vec3f* pos, Vec3f* vel, Vec3f* acc effect->alpha = 0; } effect->timer = 0; + effect->epoch++; break; } } @@ -2909,6 +2916,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) { if (effect->type == MO_FX_BIG_RIPPLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { func_80094BC4(gfxCtx); @@ -2925,6 +2933,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gEffWaterRippleDL); + FrameInterpolation_RecordCloseChild(); } } @@ -2932,6 +2941,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) { if (effect->type == MO_FX_SMALL_RIPPLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { func_80093D84(globalCtx->state.gfxCtx); @@ -2948,6 +2958,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gEffShockwaveDL); + FrameInterpolation_RecordCloseChild(); } } @@ -2956,6 +2967,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) { if (((effect->type == MO_FX_DROPLET) || (effect->type == MO_FX_SPLASH)) || (effect->type == MO_FX_SPLASH_TRAIL)) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0); @@ -2977,6 +2989,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gMorphaDropletModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -2984,6 +2997,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) { if (effect->type == MO_FX_WET_SPOT) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { func_80094044(gfxCtx); @@ -3003,6 +3017,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gMorphaWetSpotModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -3010,6 +3025,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) { if (effect->type == MO_FX_BUBBLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { func_80093D18(globalCtx->state.gfxCtx); @@ -3027,6 +3043,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gMorphaBubbleDL); + FrameInterpolation_RecordCloseChild(); } } @@ -3588,7 +3605,7 @@ void BossMo_Reset(void) { sMorphaTent1 = NULL; sMorphaTent2 = NULL; memset(sEffects, 0, sizeof(sEffects)); - sSeed1 = 0; - sSeed2 = 0; - sSeed3 = 0; -} + sBossGanonSeed1 = 0; + sBossGanonSeed2 = 0; + sBossGanonSeed3 = 0; +} \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c index 6b31635b9..3c8fa9d91 100644 --- a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c +++ b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.c @@ -7,34 +7,6 @@ #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5) -typedef enum { - /* 0 */ TWEFF_NONE, - /* 1 */ TWEFF_DOT, - /* 2 */ TWEFF_2, - /* 3 */ TWEFF_3, - /* 4 */ TWEFF_RING, - /* 5 */ TWEFF_PLYR_FRZ, - /* 6 */ TWEFF_FLAME, - /* 7 */ TWEFF_MERGEFLAME, - /* 8 */ TWEFF_SHLD_BLST, - /* 9 */ TWEFF_SHLD_DEFL, - /* 10 */ TWEFF_SHLD_HIT -} TwEffType; - -typedef enum { - /* 0 */ EFF_ARGS, - /* 1 */ EFF_UNKS1, - /* 2 */ EFF_WORK_MAX -} EffectWork; - -typedef enum { - /* 0 */ EFF_SCALE, - /* 1 */ EFF_DIST, - /* 2 */ EFF_ROLL, - /* 3 */ EFF_YAW, - /* 4 */ EFF_FWORK_MAX -} EffectFWork; - typedef enum { /* 0x00 */ TW_KOTAKE, /* 0x01 */ TW_KOUME, @@ -47,19 +19,6 @@ typedef enum { /* 0x69 */ TW_DEATHBALL_KOUME } TwinrovaType; -typedef struct { - /* 0x0000 */ u8 type; - /* 0x0001 */ u8 frame; - /* 0x0004 */ Vec3f pos; - /* 0x0010 */ Vec3f curSpeed; - /* 0x001C */ Vec3f accel; - /* 0x0028 */ Color_RGB8 color; - /* 0x002C */ s16 alpha; - /* 0x002E */ s16 work[EFF_WORK_MAX]; - /* 0x0034 */ f32 workf[EFF_FWORK_MAX]; - /* 0x0044 */ Actor* target; -} BossTwEffect; - void BossTw_Init(Actor* thisx, GlobalContext* globalCtx); void BossTw_Destroy(Actor* thisx, GlobalContext* globalCtx); void BossTw_Update(Actor* thisx, GlobalContext* globalCtx); @@ -200,7 +159,7 @@ static Vec3f sTwinrovaPillarPos[] = { { 0.0f, 380.0f, -580.0f }, }; -static u8 sTwInitalized = false; +u8 sTwInitalized = false; static InitChainEntry sInitChain[] = { ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), @@ -233,7 +192,7 @@ static u8 D_8094C878; static s16 D_8094C87A; static s16 D_8094C87C; static u8 D_8094C87E; -static BossTwEffect sTwEffects[150]; +BossTwEffect sTwEffects[150]; void BossTw_AddDotEffect(GlobalContext* globalCtx, Vec3f* initalPos, Vec3f* initalSpeed, Vec3f* accel, f32 scale, s16 args, s16 countLimit) { diff --git a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h index 575997c26..51b664726 100644 --- a/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h +++ b/soh/src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h @@ -4,9 +4,46 @@ #include "ultra64.h" #include "global.h" -struct BossTw; +typedef enum { + /* 0 */ TWEFF_NONE, + /* 1 */ TWEFF_DOT, + /* 2 */ TWEFF_2, + /* 3 */ TWEFF_3, + /* 4 */ TWEFF_RING, + /* 5 */ TWEFF_PLYR_FRZ, + /* 6 */ TWEFF_FLAME, + /* 7 */ TWEFF_MERGEFLAME, + /* 8 */ TWEFF_SHLD_BLST, + /* 9 */ TWEFF_SHLD_DEFL, + /* 10 */ TWEFF_SHLD_HIT +} TwEffType; -typedef void (*BossTwActionFunc)(struct BossTw* this, GlobalContext* globalCtx); +typedef enum { + /* 0 */ EFF_ARGS, + /* 1 */ EFF_UNKS1, + /* 2 */ EFF_WORK_MAX +} EffectWork; + +typedef enum { + /* 0 */ EFF_SCALE, + /* 1 */ EFF_DIST, + /* 2 */ EFF_ROLL, + /* 3 */ EFF_YAW, + /* 4 */ EFF_FWORK_MAX +} EffectFWork; + +typedef struct { + /* 0x0000 */ u8 type; + /* 0x0001 */ u8 frame; + /* 0x0004 */ Vec3f pos; + /* 0x0010 */ Vec3f curSpeed; + /* 0x001C */ Vec3f accel; + /* 0x0028 */ Color_RGB8 color; + /* 0x002C */ s16 alpha; + /* 0x002E */ s16 work[EFF_WORK_MAX]; + /* 0x0034 */ f32 workf[EFF_FWORK_MAX]; + /* 0x0044 */ Actor* target; +} BossTwEffect; typedef enum { /* 0 */ CS_TIMER_1, @@ -55,6 +92,10 @@ typedef enum { /* 26 */ FWORK_MAX } TwFwork; +struct BossTw; + +typedef void (*BossTwActionFunc)(struct BossTw*, GlobalContext* globalCtx); + typedef struct BossTw { /* 0x0000 */ Actor actor; /* 0x014C */ BossTwActionFunc actionFunc; diff --git a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c index c5b60a327..3d6865e24 100644 --- a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c +++ b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c @@ -12,6 +12,8 @@ #include "overlays/actors/ovl_En_Boom/z_en_boom.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "soh/frame_interpolation.h" + #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5) #define GET_BODY(this) ((BossVa*)(this)->actor.parent) @@ -40,6 +42,7 @@ typedef struct BossVaEffect { /* 0x44 */ f32 scaleMod; /* 0x48 */ Vec3f offset; /* 0x54 */ struct BossVa* parent; + u32 epoch; } BossVaEffect; // size = 0x58 typedef enum { @@ -3519,6 +3522,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_LARGE_SPARK) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0); @@ -3534,12 +3538,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 4976), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710); + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_SPARK_BALL) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011738); @@ -3560,12 +3566,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gDPSetEnvColor(POLY_XLU_DISP++, effect->envColor[0], effect->envColor[1], effect->envColor[2], effect->envColor[3]); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011768); + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_BLOOD) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009430); @@ -3590,6 +3598,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5052), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009468); + FrameInterpolation_RecordCloseChild(); } } @@ -3598,6 +3607,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { if (effect->type == VA_TUMOR) { BossVa* parent = effect->parent; + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D18(globalCtx->state.gfxCtx); gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, effect->envColor[3]); @@ -3614,12 +3624,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012948); } + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_GORE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D18(globalCtx->state.gfxCtx); gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012BA0); @@ -3645,12 +3657,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5124), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012C50); + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_ZAP_CHARGE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_0135B0); @@ -3668,12 +3682,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5152), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_013638); + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_BLAST_SPARK) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093C14(globalCtx->state.gfxCtx); gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0); @@ -3690,12 +3706,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5180), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710); + FrameInterpolation_RecordCloseChild(); } } effect = effectHead; for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) { if (effect->type == VA_SMALL_SPARK) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!flag) { func_80093D84(globalCtx->state.gfxCtx); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 100, 0); @@ -3712,6 +3730,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5208), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008F70); + FrameInterpolation_RecordCloseChild(); } } @@ -3734,6 +3753,7 @@ void BossVa_SpawnSpark(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* t effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 111; effect->velocity = effect->accel = sZeroVec; effect->mode = mode; + effect->epoch++; switch (mode) { case SPARK_UNUSED: diff --git a/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c b/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c index 4f75a03cd..acff25c75 100644 --- a/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c +++ b/soh/src/overlays/actors/ovl_Demo_6K/z_demo_6k.c @@ -307,7 +307,7 @@ void func_8096712C(Demo6K* this, GlobalContext* globalCtx) { } } -static Vec3f velocity = { 0.0f, 0.0f, 0.0f }; +Vec3f sDemo6kVelocity = { 0.0f, 0.0f, 0.0f }; void func_80967244(Demo6K* this, GlobalContext* globalCtx) { static Vec3f accel = { 0.0f, 0.0f, 0.0f }; static Color_RGBA8 primColor = { 255, 255, 255, 0 }; @@ -324,9 +324,9 @@ void func_80967244(Demo6K* this, GlobalContext* globalCtx) { rand1 = Rand_ZeroFloat(0xFFFF); rand2 = Rand_ZeroFloat(0xFFFF); - velocity.x = Math_SinS(rand2) * Math_CosS(rand1) * 20.0f; - velocity.z = Math_CosS(rand2) * Math_CosS(rand1) * 20.0f; - velocity.y = Math_SinS(rand1) * 20.0f; + sDemo6kVelocity.x = Math_SinS(rand2) * Math_CosS(rand1) * 20.0f; + sDemo6kVelocity.z = Math_CosS(rand2) * Math_CosS(rand1) * 20.0f; + sDemo6kVelocity.y = Math_SinS(rand1) * 20.0f; accel.y = 0.0f; @@ -342,7 +342,7 @@ void func_80967244(Demo6K* this, GlobalContext* globalCtx) { scale = 18000; } - EffectSsKiraKira_SpawnFocused(globalCtx, &pos, &velocity, &accel, &primColor, &envColor, scale, 20); + EffectSsKiraKira_SpawnFocused(globalCtx, &pos, &sDemo6kVelocity, &accel, &primColor, &envColor, scale, 20); } void func_80967410(Demo6K* this, GlobalContext* globalCtx) { @@ -820,7 +820,7 @@ void func_809691BC(Demo6K* this, GlobalContext* globalCtx, s32 params) { } void Demo6K_Reset(void) { - velocity.x = 0.0f; - velocity.y = 0.0f; - velocity.z = 0.0f; + sDemo6kVelocity.x = 0.0f; + sDemo6kVelocity.y = 0.0f; + sDemo6kVelocity.z = 0.0f; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index a94fa36af..53044464c 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -132,7 +132,7 @@ void DemoKekkai_Destroy(Actor* thisx, GlobalContext* globalCtx) { Collider_DestroyCylinder(globalCtx, &this->collider2); } -static Vec3f vel = { 0.0f, 0.0f, 0.0f }; +Vec3f demoKekkaiVel = { 0.0f, 0.0f, 0.0f }; void DemoKekkai_SpawnParticles(DemoKekkai* this, GlobalContext* globalCtx) { static Vec3f accel = { 0.0f, 0.0f, 0.0f }; static Color_RGBA8 lightYellow = { 255, 255, 170, 0 }; @@ -144,15 +144,15 @@ void DemoKekkai_SpawnParticles(DemoKekkai* this, GlobalContext* globalCtx) { s16 roll = Rand_ZeroFloat(65535.0f); s16 yaw = Rand_ZeroFloat(65535.0f); - vel.x = Math_SinS(yaw) * Math_CosS(roll) * Rand_ZeroFloat(8.0f); - vel.z = Math_CosS(yaw) * Math_CosS(roll) * Rand_ZeroFloat(8.0f); - vel.y = Math_SinS(roll) * Rand_ZeroFloat(3.0f); + demoKekkaiVel.x = Math_SinS(yaw) * Math_CosS(roll) * Rand_ZeroFloat(8.0f); + demoKekkaiVel.z = Math_CosS(yaw) * Math_CosS(roll) * Rand_ZeroFloat(8.0f); + demoKekkaiVel.y = Math_SinS(roll) * Rand_ZeroFloat(3.0f); - pos.x = (vel.x * 7.0f) + this->actor.world.pos.x; - pos.y = (vel.y * 20.0f) + this->actor.world.pos.y + 120.0f; - pos.z = (vel.z * 7.0f) + this->actor.world.pos.z; + pos.x = (demoKekkaiVel.x * 7.0f) + this->actor.world.pos.x; + pos.y = (demoKekkaiVel.y * 20.0f) + this->actor.world.pos.y + 120.0f; + pos.z = (demoKekkaiVel.z * 7.0f) + this->actor.world.pos.z; - EffectSsKiraKira_SpawnFocused(globalCtx, &pos, &vel, &accel, &lightYellow, &darkRed, 3000, + EffectSsKiraKira_SpawnFocused(globalCtx, &pos, &demoKekkaiVel, &accel, &lightYellow, &darkRed, 3000, (s32)Rand_ZeroFloat(40.0f) + 45); } } @@ -338,7 +338,7 @@ void DemoKekkai_DrawTowerBarrier(Actor* thisx, GlobalContext* globalCtx) { } void DemoKekkai_Reset(void) { - vel.x = 0.0f; - vel.y = 0.0f; - vel.z = 0.0f; + demoKekkaiVel.x = 0.0f; + demoKekkaiVel.y = 0.0f; + demoKekkaiVel.z = 0.0f; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c index 46f3d1857..ee503dd43 100644 --- a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c +++ b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c @@ -53,7 +53,7 @@ static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneDownward, 4000, ICHAIN_STOP), }; -static s16 sWarpTimerTarget; +s16 sWarpTimerTarget; void DoorWarp1_SetupAction(DoorWarp1* this, DoorWarp1ActionFunc actionFunc) { this->actionFunc = actionFunc; diff --git a/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c b/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c index 14e9ff15c..6eaa2f777 100644 --- a/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c +++ b/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c @@ -122,7 +122,7 @@ static DamageTable sDamageTable = { /* Unknown 2 */ DMG_ENTRY(0, 0x0), }; -static s32 sSlugGroup = 0; +s32 sSlugGroup = 0; void EnBw_SetupAction(EnBw* this, EnBwActionFunc actionFunc) { this->actionFunc = actionFunc; diff --git a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c index e68eaabb1..274505978 100644 --- a/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c +++ b/soh/src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.c @@ -35,7 +35,7 @@ const ActorInit En_Clear_Tag_InitVars = { (ActorResetFunc)EnClearTag_Reset, }; -static u8 sIsEffectsInitialized = false; +u8 sClearTagIsEffectsInitialized = false; static Vec3f sZeroVector = { 0.0f, 0.0f, 0.0f }; @@ -79,10 +79,10 @@ static ColliderCylinderInit sLaserCylinderInit = { { 15, 30, 10, { 0, 0, 0 } }, }; -static UNK_TYPE4 D_809D5C98 = 0; // unused -static UNK_TYPE4 D_809D5C9C = 0; // unused +//static UNK_TYPE4 D_809D5C98 = 0; // unused +//static UNK_TYPE4 D_809D5C9C = 0; // unused -static EnClearTagEffect sClearTagEffects[CLEAR_TAG_EFFECT_MAX_COUNT]; +EnClearTagEffect sClearTagEffects[CLEAR_TAG_EFFECT_MAX_COUNT]; #include "overlays/ovl_En_Clear_Tag/ovl_En_Clear_Tag.h" @@ -273,8 +273,8 @@ void EnClearTag_Init(Actor* thisx, GlobalContext* globalCtx) { } // Initialize all effects to available if effects have not been initialized. - if (!sIsEffectsInitialized) { - sIsEffectsInitialized = true; + if (!sClearTagIsEffectsInitialized) { + sClearTagIsEffectsInitialized = true; globalCtx->specialEffects = &sClearTagEffects[0]; for (i = 0; i < CLEAR_TAG_EFFECT_MAX_COUNT; i++) { sClearTagEffects[i].type = CLEAR_TAG_EFFECT_AVAILABLE; @@ -1027,5 +1027,5 @@ void EnClearTag_DrawEffects(GlobalContext* globalCtx) { void EnClearTag_Reset(void) { memset(sClearTagEffects, 0, sizeof(sClearTagEffects)); - sIsEffectsInitialized = false; + sClearTagIsEffectsInitialized = false; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c b/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c index 38c86eda3..c84a22fb8 100644 --- a/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c +++ b/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c @@ -84,18 +84,7 @@ sEnFrPointers.flags = 12 - Deactivate frogs, frogs will jump back into the water */ -typedef struct { - u8 flags; - EnFr* frogs[5]; -} EnFrPointers; - -typedef struct { - f32 xzDist; - f32 yaw; - f32 yDist; -} LogSpotToFromWater; - -static EnFrPointers sEnFrPointers = { +EnFrPointers sEnFrPointers = { 0x00, { NULL, @@ -106,6 +95,7 @@ static EnFrPointers sEnFrPointers = { }, }; + // Flags for gSaveContext.eventChkInf[13] static u16 sSongIndex[] = { 0x0002, 0x0004, 0x0010, 0x0008, 0x0020, 0x0040, 0x0001, 0x0000, diff --git a/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.h b/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.h index ba2ef5014..154aefc17 100644 --- a/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.h +++ b/soh/src/overlays/actors/ovl_En_Fr/z_en_fr.h @@ -28,6 +28,12 @@ typedef enum { /* 07 */ FROG_NO_SONG } FrogSongType; +typedef struct { + f32 xzDist; + f32 yaw; + f32 yDist; +} LogSpotToFromWater; + typedef struct EnFr { /* 0x0000 */ Actor actor; /* 0x014C */ SkelAnime skelAnime; // Frog Skeleton @@ -69,4 +75,9 @@ typedef struct EnFr { /* 0x03B8 */ Vec3f posButterflyLight; // Used in Lights_PointNoGlowSetInfo() } EnFr; // size = 0x03C4 +typedef struct { + u8 flags; + EnFr* frogs[5]; +} EnFrPointers; + #endif diff --git a/soh/src/overlays/actors/ovl_En_Goma/z_en_goma.c b/soh/src/overlays/actors/ovl_En_Goma/z_en_goma.c index 85049b7f1..a9997c383 100644 --- a/soh/src/overlays/actors/ovl_En_Goma/z_en_goma.c +++ b/soh/src/overlays/actors/ovl_En_Goma/z_en_goma.c @@ -96,7 +96,7 @@ static ColliderCylinderInit D_80A4B7CC = { { 15, 30, 10, { 0, 0, 0 } }, }; -static u8 sSpawnNum = 0; +u8 sSpawnNum = 0; static Vec3f sDeadEffectVel = { 0.0f, 0.0f, 0.0f }; static InitChainEntry sInitChain[] = { diff --git a/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c b/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c index 649c1b747..bd529ea55 100644 --- a/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c +++ b/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c @@ -32,9 +32,9 @@ void func_80A7D26C(EnInsect* this, GlobalContext* globalCtx); void func_80A7D39C(EnInsect* this); void func_80A7D460(EnInsect* this, GlobalContext* globalCtx); -static f32 D_80A7DEB0 = 0.0f; -static s16 D_80A7DEB4 = 0; -static s16 D_80A7DEB8 = 0; +f32 D_80A7DEB0 = 0.0f; +s16 D_80A7DEB4 = 0; +s16 D_80A7DEB8 = 0; const ActorInit En_Insect_InitVars = { ACTOR_EN_INSECT, diff --git a/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c b/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c index 4ce8fae20..11573dba0 100644 --- a/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c +++ b/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c @@ -29,8 +29,8 @@ void EnIshi_SpawnFragmentsLarge(EnIshi* this, GlobalContext* globalCtx); void EnIshi_SpawnDustSmall(EnIshi* this, GlobalContext* globalCtx); void EnIshi_SpawnDustLarge(EnIshi* this, GlobalContext* globalCtx); -static s16 sRotSpeedX = 0; -static s16 sRotSpeedY = 0; +s16 sRockRotSpeedX = 0; +s16 sRockRotSpeedY = 0; const ActorInit En_Ishi_InitVars = { ACTOR_EN_ISHI, @@ -405,11 +405,11 @@ void EnIshi_SetupFly(EnIshi* this) { this->actor.velocity.x = Math_SinS(this->actor.world.rot.y) * this->actor.speedXZ; this->actor.velocity.z = Math_CosS(this->actor.world.rot.y) * this->actor.speedXZ; if ((this->actor.params & 1) == ROCK_SMALL) { - sRotSpeedX = (Rand_ZeroOne() - 0.5f) * 16000.0f; - sRotSpeedY = (Rand_ZeroOne() - 0.5f) * 2400.0f; + sRockRotSpeedX = (Rand_ZeroOne() - 0.5f) * 16000.0f; + sRockRotSpeedY = (Rand_ZeroOne() - 0.5f) * 2400.0f; } else { - sRotSpeedX = (Rand_ZeroOne() - 0.5f) * 8000.0f; - sRotSpeedY = (Rand_ZeroOne() - 0.5f) * 1600.0f; + sRockRotSpeedX = (Rand_ZeroOne() - 0.5f) * 8000.0f; + sRockRotSpeedY = (Rand_ZeroOne() - 0.5f) * 1600.0f; } this->actor.colChkInfo.mass = 240; this->actionFunc = EnIshi_Fly; @@ -455,8 +455,8 @@ void EnIshi_Fly(EnIshi* this, GlobalContext* globalCtx) { EffectSsGRipple_Spawn(globalCtx, &contactPos, 500, 1300, 8); } this->actor.minVelocityY = -6.0f; - sRotSpeedX >>= 2; - sRotSpeedY >>= 2; + sRockRotSpeedX >>= 2; + sRockRotSpeedY >>= 2; SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 40, NA_SE_EV_DIVE_INTO_WATER_L); this->actor.bgCheckFlags &= ~0x40; } @@ -464,8 +464,8 @@ void EnIshi_Fly(EnIshi* this, GlobalContext* globalCtx) { EnIshi_Fall(this); func_80A7ED94(&this->actor.velocity, D_80A7FA28[type]); func_8002D7EC(&this->actor); - this->actor.shape.rot.x += sRotSpeedX; - this->actor.shape.rot.y += sRotSpeedY; + this->actor.shape.rot.x += sRockRotSpeedX; + this->actor.shape.rot.y += sRockRotSpeedY; Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 7.5f, 35.0f, 0.0f, 0xC5); Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); @@ -502,6 +502,6 @@ void EnIshi_Draw(Actor* thisx, GlobalContext* globalCtx) { } void EnIshi_Reset(void) { - sRotSpeedX = 0; - sRotSpeedY = 0; + sRockRotSpeedX = 0; + sRockRotSpeedY = 0; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c index c6e23b8b9..5cf7abc25 100644 --- a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c +++ b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c @@ -35,7 +35,7 @@ void EnNiw_FeatherSpawn(EnNiw* this, Vec3f* pos, Vec3f* vel, Vec3f* accel, f32 s void EnNiw_FeatherUpdate(EnNiw* this, GlobalContext* globalCtx); void EnNiw_FeatherDraw(EnNiw* this, GlobalContext* globalCtx); -static s16 D_80AB85E0 = 0; +s16 D_80AB85E0 = 0; const ActorInit En_Niw_InitVars = { ACTOR_EN_NIW, @@ -70,9 +70,9 @@ static s16 sKakarikoFlagList[] = { 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, }; -static u8 sLowerRiverSpawned = false; +u8 sLowerRiverSpawned = false; -static u8 sUpperRiverSpawned = false; +u8 sUpperRiverSpawned = false; static ColliderCylinderInit sCylinderInit1 = { { diff --git a/soh/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c b/soh/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c index bd85ded7a..62704b516 100644 --- a/soh/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c +++ b/soh/src/overlays/actors/ovl_En_Ossan/z_en_ossan.c @@ -1888,17 +1888,17 @@ void EnOssan_UpdateCursorAnim(EnOssan* this) { } } if (CVar_GetS32("gHudColors", 1) == 0) { - this->cursorColorR = ColChanMix(0, 0.0f, t); - this->cursorColorG = ColChanMix(80, 80.0f, t); - this->cursorColorB = ColChanMix(255, 0.0f, t); + this->cursorColorR = ColChanMix(0, 0.0f, t); + this->cursorColorG = ColChanMix(80, 80.0f, t); + this->cursorColorB = ColChanMix(255, 0.0f, t); } else if (CVar_GetS32("gHudColors", 1) == 1) { - this->cursorColorR = ColChanMix(0, 0.0f, t); - this->cursorColorG = ColChanMix(255, 80.0f, t); - this->cursorColorB = ColChanMix(80, 0.0f, t); + this->cursorColorR = ColChanMix(0, 0.0f, t); + this->cursorColorG = ColChanMix(255, 80.0f, t); + this->cursorColorB = ColChanMix(80, 0.0f, t); } else if (CVar_GetS32("gHudColors", 1) == 2) { - this->cursorColorR = ColChanMix(CVar_GetS32("gCCABtnPrimR", 90), ((CVar_GetS32("gCCABtnPrimR", 90)/255)*100), t); - this->cursorColorG = ColChanMix(CVar_GetS32("gCCABtnPrimG", 90), ((CVar_GetS32("gCCABtnPrimG", 90)/255)*100), t); - this->cursorColorB = ColChanMix(CVar_GetS32("gCCABtnPrimB", 90), ((CVar_GetS32("gCCABtnPrimB", 90)/255)*100), t); + this->cursorColorR = ColChanMix(CVar_GetS32("gCCABtnPrimR", 90), ((CVar_GetS32("gCCABtnPrimR", 90)/255)*100), t); + this->cursorColorG = ColChanMix(CVar_GetS32("gCCABtnPrimG", 90), ((CVar_GetS32("gCCABtnPrimG", 90)/255)*100), t); + this->cursorColorB = ColChanMix(CVar_GetS32("gCCABtnPrimB", 90), ((CVar_GetS32("gCCABtnPrimB", 90)/255)*100), t); } this->cursorColorA = ColChanMix(255, 0.0f, t); this->cursorAnimTween = t; diff --git a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c index 93f48417e..63b386238 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c +++ b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c @@ -126,7 +126,7 @@ static DamageTable sDamageTable = { /* Unknown 2 */ DMG_ENTRY(0, 0x0), }; -static s32 sNumSpawned = 0; +s32 sEnPoFieldNumSpawned = 0; static Vec3f sFieldMiddle = { -1000.0f, 0.0f, 6500.0f }; @@ -145,22 +145,22 @@ static EnPoFieldInfo sPoFieldInfo[2] = { static Vec3f D_80AD714C = { 0.0f, 1400.0f, 0.0f }; -static Vec3s sSpawnPositions[10]; -static u8 sSpawnSwitchFlags[10]; +Vec3s sEnPoFieldSpawnPositions[10]; +u8 sEnPoFieldSpawnSwitchFlags[10]; static MtxF sLimb7Mtx; void EnPoField_Init(Actor* thisx, GlobalContext* globalCtx) { EnPoField* this = (EnPoField*)thisx; s32 pad; - if (sNumSpawned != 10) { - sSpawnPositions[sNumSpawned].x = this->actor.world.pos.x; - sSpawnPositions[sNumSpawned].y = this->actor.world.pos.y; - sSpawnPositions[sNumSpawned].z = this->actor.world.pos.z; - sSpawnSwitchFlags[sNumSpawned] = this->actor.params & 0xFF; - sNumSpawned++; + if (sEnPoFieldNumSpawned != 10) { + sEnPoFieldSpawnPositions[sEnPoFieldNumSpawned].x = this->actor.world.pos.x; + sEnPoFieldSpawnPositions[sEnPoFieldNumSpawned].y = this->actor.world.pos.y; + sEnPoFieldSpawnPositions[sEnPoFieldNumSpawned].z = this->actor.world.pos.z; + sEnPoFieldSpawnSwitchFlags[sEnPoFieldNumSpawned] = this->actor.params & 0xFF; + sEnPoFieldNumSpawned++; } - if (sNumSpawned >= 2) { + if (sEnPoFieldNumSpawned >= 2) { this->actor.params = 0xFF; Actor_Kill(&this->actor); return; @@ -407,10 +407,10 @@ void EnPoField_WaitForSpawn(EnPoField* this, GlobalContext* globalCtx) { this->actionTimer--; } if (this->actionTimer == 0) { - for (i = 0; i < sNumSpawned; i++) { - if (fabsf(sSpawnPositions[i].x - player->actor.world.pos.x) < 150.0f && - fabsf(sSpawnPositions[i].z - player->actor.world.pos.z) < 150.0f) { - if (Flags_GetSwitch(globalCtx, sSpawnSwitchFlags[i])) { + for (i = 0; i < sEnPoFieldNumSpawned; i++) { + if (fabsf(sEnPoFieldSpawnPositions[i].x - player->actor.world.pos.x) < 150.0f && + fabsf(sEnPoFieldSpawnPositions[i].z - player->actor.world.pos.z) < 150.0f) { + if (Flags_GetSwitch(globalCtx, sEnPoFieldSpawnSwitchFlags[i])) { if (player->stateFlags1 & 0x800000) { // Player riding Epona return; } else { @@ -711,7 +711,7 @@ void EnPoField_SoulInteract(EnPoField* this, GlobalContext* globalCtx) { } else { this->actor.textId = 0x508F; Item_Give(globalCtx, ITEM_BIG_POE); - Flags_SetSwitch(globalCtx, sSpawnSwitchFlags[this->spawnFlagIndex]); + Flags_SetSwitch(globalCtx, sEnPoFieldSpawnSwitchFlags[this->spawnFlagIndex]); } } else { Audio_PlayActorSound2(&this->actor, NA_SE_EN_PO_LAUGH); @@ -1009,8 +1009,8 @@ void EnPoField_DrawSoul(Actor* thisx, GlobalContext* globalCtx) { } void EnPoField_Reset(void) { - sNumSpawned = 0; + sEnPoFieldNumSpawned = 0; - memset(sSpawnPositions, 0, sizeof(sSpawnPositions)); - memset(sSpawnSwitchFlags, 0, sizeof(sSpawnSwitchFlags)); + memset(sEnPoFieldSpawnPositions, 0, sizeof(sEnPoFieldSpawnPositions)); + memset(sEnPoFieldSpawnSwitchFlags, 0, sizeof(sEnPoFieldSpawnSwitchFlags)); } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_En_Takara_Man/z_en_takara_man.c b/soh/src/overlays/actors/ovl_En_Takara_Man/z_en_takara_man.c index 71cd47144..c1d169dfe 100644 --- a/soh/src/overlays/actors/ovl_En_Takara_Man/z_en_takara_man.c +++ b/soh/src/overlays/actors/ovl_En_Takara_Man/z_en_takara_man.c @@ -35,7 +35,7 @@ const ActorInit En_Takara_Man_InitVars = { (ActorResetFunc)EnTakaraMan_Reset, }; -static u8 sTakaraIsInitialized = false; +u8 sTakaraIsInitialized = false; void EnTakaraMan_Reset(Actor* thisx, GlobalContext* globalCtx) { sTakaraIsInitialized = false; diff --git a/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c b/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c index c64f9acb7..92497bf3e 100644 --- a/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c +++ b/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c @@ -447,7 +447,7 @@ void func_80B3D118(GlobalContext* globalCtx) { static Vec3f D_80B42DA0; -static s32 D_80B41D90 = 0; +s32 D_80B41D90 = 0; void EnXc_SetColossusWindSFX(GlobalContext* globalCtx) { if (gSaveContext.sceneSetupIndex == 4) { static Vec3f sPos = { 0.0f, 0.0f, 0.0f }; @@ -484,17 +484,17 @@ void EnXc_SetColossusWindSFX(GlobalContext* globalCtx) { } } -static s32 sFlameSpawned = false; +s32 sEnXcFlameSpawned = false; void EnXc_SpawnFlame(EnXc* this, GlobalContext* globalCtx) { - if (!sFlameSpawned) { + if (!sEnXcFlameSpawned) { CsCmdActorAction* npcAction = EnXc_GetCsCmd(globalCtx, 0); f32 xPos = npcAction->startPos.x; f32 yPos = npcAction->startPos.y; f32 zPos = npcAction->startPos.z; this->flameActor = Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_LIGHT, xPos, yPos, zPos, 0, 0, 0, 5); - sFlameSpawned = true; + sEnXcFlameSpawned = true; } } @@ -519,7 +519,7 @@ void EnXc_DestroyFlame(EnXc* this) { Actor_Kill(&this->actor); } -static s32 D_80B41DA8 = 1; +s32 D_80B41DA8 = 1; void EnXc_InitFlame(EnXc* this, GlobalContext* globalCtx) { s32 pad; s16 sceneNum = globalCtx->sceneNum; @@ -1402,7 +1402,7 @@ void func_80B3F534(GlobalContext* globalCtx) { } } -static s32 D_80B41DAC = 1; +s32 D_80B41DAC = 1; void func_80B3F59C(EnXc* this, GlobalContext* globalCtx) { CsCmdActorAction* npcAction = EnXc_GetCsCmd(globalCtx, 0); @@ -2430,7 +2430,7 @@ const ActorInit En_Xc_InitVars = { void EnXc_Reset(void) { D_80B41D90 = 0; - sFlameSpawned = false; + sEnXcFlameSpawned = false; D_80B41DA8 = 1; D_80B41DAC = 1; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c b/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c index c5ed809db..a6b0f5809 100644 --- a/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c +++ b/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c @@ -97,8 +97,8 @@ static Vec3f sPlatformPositions[] = { }; // These seem to relate to the tagging in/out the minibosses do -static s16 D_80B4A1B0 = 0; -static s16 D_80B4A1B4 = 1; +s16 D_80B4A1B0 = 0; +s16 D_80B4A1B4 = 1; const ActorInit En_Zf_InitVars = { ACTOR_EN_ZF, diff --git a/soh/src/overlays/actors/ovl_En_Zl3/z_en_zl3.c b/soh/src/overlays/actors/ovl_En_Zl3/z_en_zl3.c index 8ad3a2cef..6ea271bf4 100644 --- a/soh/src/overlays/actors/ovl_En_Zl3/z_en_zl3.c +++ b/soh/src/overlays/actors/ovl_En_Zl3/z_en_zl3.c @@ -45,7 +45,7 @@ static void* sEyeTextures[] = { gZelda2EyeOpenTex, gZelda2EyeHalfTex, gZelda2Eye static void* sMouthTextures[] = { gZelda2MouthSeriousTex, gZelda2MouthHappyTex, gZelda2MouthOpenTex }; -static s32 D_80B5A468 = 0; +s32 D_80B5A468 = 0; static Vec3f D_80B5A46C = { 0.0f, 0.0f, 0.0f }; @@ -55,7 +55,7 @@ static f32 D_80B5A484 = 0.0f; static Vec3f D_80B5A488 = { 0.0f, 0.0f, 0.0f }; -static s32 D_80B5A494 = -1; +s32 D_80B5A494 = -1; static Vec3f D_80B5A498 = { 148.0f, 260.0f, -87.0f }; @@ -63,7 +63,7 @@ static Vec3f D_80B5A4A4 = { -12.0f, 260.0f, -147.0f }; static Vec3f D_80B5A4B0 = { 42.0f, 260.0f, 13.0f }; -static u32 D_80B5A4BC = 0; +u32 D_80B5A4BC = 0; void func_80B533B0(Actor* thisx, GlobalContext* globalCtx) { EnZl3* this = (EnZl3*)thisx; diff --git a/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.c b/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.c index b55777484..ac50f226a 100644 --- a/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.c +++ b/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.c @@ -7,6 +7,8 @@ #include "z_en_zo.h" #include "objects/object_zo/object_zo.h" +#include "soh/frame_interpolation.h" + #define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3) typedef enum { @@ -41,6 +43,7 @@ void EnZo_Ripple(EnZo* this, Vec3f* pos, f32 scale, f32 targetScale, u8 alpha) { effect->scale = scale; effect->targetScale = targetScale; effect->color.a = alpha; + effect->epoch++; break; } effect++; @@ -65,6 +68,7 @@ void EnZo_Bubble(EnZo* this, Vec3f* pos) { effect->vec = *pos; effect->vel = vel; effect->scale = ((Rand_ZeroOne() - 0.5f) * 0.02f) + 0.12f; + effect->epoch++; break; } } @@ -87,6 +91,7 @@ void EnZo_Splash(EnZo* this, Vec3f* pos, Vec3f* vel, f32 scale) { effect->vel = *vel; effect->color.a = (Rand_ZeroOne() * 100.0f) + 100.0f; effect->scale = scale; + effect->epoch++; break; } effect++; @@ -180,6 +185,7 @@ void EnZo_DrawRipples(EnZo* this, GlobalContext* globalCtx) { func_80093D84(globalCtx->state.gfxCtx); for (i = 0; i < ARRAY_COUNT(this->effects); i++) { if (effect->type == ENZO_EFFECT_RIPPLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!setup) { if (1) {} gDPPipeSync(POLY_XLU_DISP++); @@ -194,6 +200,7 @@ void EnZo_DrawRipples(EnZo* this, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_zo_eff.c", 242), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gZoraRipplesModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -210,6 +217,7 @@ void EnZo_DrawBubbles(EnZo* this, GlobalContext* globalCtx) { func_80093D84(globalCtx->state.gfxCtx); for (i = 0; i < ARRAY_COUNT(this->effects); i++) { if (effect->type == ENZO_EFFECT_BUBBLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!setup) { if (1) {} gSPDisplayList(POLY_XLU_DISP++, gZoraBubblesMaterialDL); @@ -227,6 +235,7 @@ void EnZo_DrawBubbles(EnZo* this, GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_zo_eff.c", 281), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gZoraBubblesModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -244,6 +253,7 @@ void EnZo_DrawSplashes(EnZo* this, GlobalContext* globalCtx) { func_80093D84(globalCtx->state.gfxCtx); for (i = 0; i < ARRAY_COUNT(this->effects); i++) { if (effect->type == ENZO_EFFECT_SPLASH) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (!setup) { if (1) {} gSPDisplayList(POLY_XLU_DISP++, gZoraSplashesMaterialDL); @@ -260,6 +270,7 @@ void EnZo_DrawSplashes(EnZo* this, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gZoraSplashesModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } diff --git a/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.h b/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.h index ba6eebb30..8911ce399 100644 --- a/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.h +++ b/soh/src/overlays/actors/ovl_En_Zo/z_en_zo.h @@ -15,6 +15,7 @@ typedef struct { /* 0x14 */ Vec3f pos; /* 0x20 */ Vec3f vel; /* 0x2C */ Vec3f vec; // Usage specific + u32 epoch; } EnZoEffect; // size = 0x38 typedef void (*EnZoActionFunc)(struct EnZo*, GlobalContext*); diff --git a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c index a103c4826..0798145db 100644 --- a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c +++ b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c @@ -10,6 +10,8 @@ #include "objects/object_fish/object_fish.h" #include "vt.h" +#include "soh/frame_interpolation.h" + #define FLAGS ACTOR_FLAG_4 #define WATER_SURFACE_Y(globalCtx) globalCtx->colCtx.colHeader->waterBoxes->ySurface @@ -56,6 +58,7 @@ typedef struct { /* 0x34 */ f32 unk_34; /* 0x38 */ f32 unk_38; /* 0x3C */ f32 unk_3C; + u32 epoch; } FishingEffect; // size = 0x40 #define POND_PROP_COUNT 140 @@ -490,6 +493,8 @@ void Fishing_SpawnRipple(Vec3f* projectedPos, FishingEffect* effect, Vec3f* pos, effect->unk_2C = 1; effect->unk_38 = (effect->unk_34 - effect->unk_30) * 0.1f; } + + effect->epoch++; break; } @@ -514,6 +519,7 @@ void Fishing_SpawnDustSplash(Vec3f* projectedPos, FishingEffect* effect, Vec3f* effect->accel = accel; effect->alpha = 100 + (s16)Rand_ZeroFloat(100.0f); effect->unk_30 = scale; + effect->epoch++; break; } @@ -539,6 +545,7 @@ void Fishing_SpawnWaterDust(Vec3f* projectedPos, FishingEffect* effect, Vec3f* p effect->timer = (s16)Rand_ZeroFloat(100.0f); effect->unk_30 = scale; effect->unk_34 = 2.0f * scale; + effect->epoch++; break; } @@ -563,6 +570,7 @@ void Fishing_SpawnBubble(Vec3f* projectedPos, FishingEffect* effect, Vec3f* pos, effect->timer = (s16)Rand_ZeroFloat(100.0f); effect->unk_30 = scale; effect->unk_2C = arg4; + effect->epoch++; break; } @@ -591,6 +599,7 @@ void Fishing_SpawnRainDrop(FishingEffect* effect, Vec3f* pos, Vec3f* rot) { Matrix_RotateY(rot->y, MTXMODE_NEW); Matrix_RotateX(rot->x, MTXMODE_APPLY); Matrix_MultVec3f(&velSrc, &effect->vel); + effect->epoch++; break; } @@ -1182,6 +1191,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { for (i = 0; i < 100; i++) { if (effect->type == FS_EFF_RIPPLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_XLU_DISP++, gFishingRippleMaterialDL); gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 155, 0); @@ -1197,6 +1207,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingRippleModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1205,6 +1216,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < 100; i++) { if (effect->type == FS_EFF_DUST_SPLASH) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_XLU_DISP++, gFishingDustSplashMaterialDL); gDPSetEnvColor(POLY_XLU_DISP++, 200, 200, 200, 0); @@ -1221,6 +1233,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingDustSplashModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1229,6 +1242,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < 100; i++) { if (effect->type == FS_EFF_WATER_DUST) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_OPA_DISP++, gFishingWaterDustMaterialDL); gDPSetEnvColor(POLY_OPA_DISP++, 40, 90, 80, 128); @@ -1249,6 +1263,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gFishingWaterDustModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1257,6 +1272,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 0; i < 100; i++) { if (effect->type == FS_EFF_BUBBLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_XLU_DISP++, gFishingBubbleMaterialDL); gDPSetEnvColor(POLY_XLU_DISP++, 150, 150, 150, 0); @@ -1272,6 +1288,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingBubbleModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1280,6 +1297,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 30; i < EFFECT_COUNT; i++) { if (effect->type == FS_EFF_RAIN_DROP) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x14); gDPSetCombineMode(POLY_XLU_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); @@ -1297,6 +1315,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingRainDropModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1307,6 +1326,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 30; i < EFFECT_COUNT; i++) { if (effect->type == FS_EFF_RAIN_RIPPLE) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_XLU_DISP++, gFishingRippleMaterialDL); gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 155, 0); @@ -1321,6 +1341,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingRippleModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } @@ -1329,6 +1350,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { flag = 0; for (i = 30; i < EFFECT_COUNT; i++) { if (effect->type == FS_EFF_RAIN_SPLASH) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); if (flag == 0) { gSPDisplayList(POLY_XLU_DISP++, gFishingRainSplashMaterialDL); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, KREG(19) + 80); @@ -1350,12 +1372,14 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingRainSplashModelDL); + FrameInterpolation_RecordCloseChild(); } effect++; } effect = firstEffect; if (effect->type == FS_EFF_OWNER_HAT) { + FrameInterpolation_RecordOpenChild(effect, effect->epoch); Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); Matrix_RotateY((sEffOwnerHatRot.y * M_PI) / 32768, MTXMODE_APPLY); Matrix_RotateX((sEffOwnerHatRot.x * M_PI) / 32768, MTXMODE_APPLY); @@ -1367,6 +1391,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gFishingOwnerHatDL); + FrameInterpolation_RecordCloseChild(); } Matrix_Pop(); @@ -4398,6 +4423,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { } if (prop->shouldDraw) { + FrameInterpolation_RecordOpenChild(prop, 0); Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW); Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY); Matrix_RotateY(prop->rotY, MTXMODE_APPLY); @@ -4407,6 +4433,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7726), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingReedModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4423,12 +4450,14 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { } if (prop->shouldDraw) { + FrameInterpolation_RecordOpenChild(prop, 0); Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW); Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY); gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7748), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gFishingWoodPostModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4445,6 +4474,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { } if (prop->shouldDraw) { + FrameInterpolation_RecordOpenChild(prop, 0); Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW); Matrix_Scale(prop->scale, 1.0f, prop->scale, MTXMODE_APPLY); Matrix_RotateY(prop->lilyPadAngle * (M_PI / 32768), MTXMODE_APPLY); @@ -4454,6 +4484,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7774), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gFishingLilyPadModelDL); + FrameInterpolation_RecordCloseChild(); } } @@ -4470,6 +4501,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { } if (prop->shouldDraw) { + FrameInterpolation_RecordOpenChild(prop, 0); Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW); Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY); Matrix_RotateY(prop->rotY, MTXMODE_APPLY); @@ -4477,6 +4509,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) { gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7798), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, gFishingRockModelDL); + FrameInterpolation_RecordCloseChild(); } } diff --git a/soh/src/overlays/actors/ovl_Obj_Oshihiki/z_obj_oshihiki.c b/soh/src/overlays/actors/ovl_Obj_Oshihiki/z_obj_oshihiki.c index 76e285881..70e4f4d7f 100644 --- a/soh/src/overlays/actors/ovl_Obj_Oshihiki/z_obj_oshihiki.c +++ b/soh/src/overlays/actors/ovl_Obj_Oshihiki/z_obj_oshihiki.c @@ -558,7 +558,7 @@ void ObjOshihiki_Push(ObjOshihiki* this, GlobalContext* globalCtx) { f32 pushDistSigned; s32 stopFlag; - this->pushSpeed += 0.5f; + this->pushSpeed += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 1.0f : 0.5f; this->stateFlags |= PUSHBLOCK_PUSH; this->pushSpeed = CLAMP_MAX(this->pushSpeed, 2.0f); stopFlag = Math_StepToF(&this->pushDist, 20.0f, this->pushSpeed); @@ -586,7 +586,7 @@ void ObjOshihiki_Push(ObjOshihiki* this, GlobalContext* globalCtx) { this->dyna.unk_150 = 0.0f; this->pushDist = 0.0f; this->pushSpeed = 0.0f; - this->timer = 10; + this->timer = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3 : 10; if (this->floorBgIds[this->highestFloor] == BGCHECK_SCENE) { ObjOshihiki_SetupOnScene(this, globalCtx); } else { diff --git a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c index 237f1e926..d4282b91b 100644 --- a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c +++ b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c @@ -9,6 +9,8 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/object_spot02_objects/object_spot02_objects.h" +#include "soh/frame_interpolation.h" + #define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5 | ACTOR_FLAG_25) void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx); @@ -57,8 +59,8 @@ const ActorInit Object_Kankyo_InitVars = { (ActorResetFunc)ObjectKankyo_Reset, }; -static u8 sIsSpawned = false; -static s16 sTrailingFairies = 0; +u8 sKankyoIsSpawned = false; +s16 sTrailingFairies = 0; void ObjectKankyo_SetupAction(ObjectKankyo* this, ObjectKankyoActionFunc action) { this->actionFunc = action; @@ -76,18 +78,18 @@ void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.room = -1; switch (this->actor.params) { case 0: - if (!sIsSpawned) { + if (!sKankyoIsSpawned) { ObjectKankyo_SetupAction(this, ObjectKankyo_Fairies); - sIsSpawned = true; + sKankyoIsSpawned = true; } else { Actor_Kill(&this->actor); } break; case 3: - if (!sIsSpawned) { + if (!sKankyoIsSpawned) { ObjectKankyo_SetupAction(this, ObjectKankyo_Snow); - sIsSpawned = true; + sKankyoIsSpawned = true; } else { Actor_Kill(&this->actor); } @@ -260,6 +262,7 @@ void ObjectKankyo_Fairies(ObjectKankyo* this, GlobalContext* globalCtx) { this->effects[i].dirPhase.z = Rand_ZeroOne() * 360.0f; this->effects[i].state++; this->effects[i].timer = 0; + this->effects[i].epoch++; break; case 1: // blinking fairies / inactive fairy trails @@ -417,26 +420,32 @@ void ObjectKankyo_Fairies(ObjectKankyo* this, GlobalContext* globalCtx) { if (this->effects[i].base.x + this->effects[i].pos.x - baseX > maxDist) { this->effects[i].base.x = baseX - maxDist; this->effects[i].pos.x = 0.0f; + this->effects[i].epoch++; } if (this->effects[i].base.x + this->effects[i].pos.x - baseX < -maxDist) { this->effects[i].base.x = baseX + maxDist; this->effects[i].pos.x = 0.0f; + this->effects[i].epoch++; } if (this->effects[i].base.y + this->effects[i].pos.y - baseY > 50.0f) { this->effects[i].base.y = baseY - 50.0f; this->effects[i].pos.y = 0.0f; + this->effects[i].epoch++; } if (this->effects[i].base.y + this->effects[i].pos.y - baseY < -50.0f) { this->effects[i].base.y = baseY + 50.0f; this->effects[i].pos.y = 0.0f; + this->effects[i].epoch++; } if (this->effects[i].base.z + this->effects[i].pos.z - baseZ > maxDist) { this->effects[i].base.z = baseZ - maxDist; this->effects[i].pos.z = 0.0f; + this->effects[i].epoch++; } if (this->effects[i].base.z + this->effects[i].pos.z - baseZ < -maxDist) { this->effects[i].base.z = baseZ + maxDist; this->effects[i].pos.z = 0.0f; + this->effects[i].epoch++; } } } @@ -496,6 +505,7 @@ void ObjectKankyo_DrawFairies(ObjectKankyo* this2, GlobalContext* globalCtx2) { gSPDisplayList(POLY_XLU_DISP++, gKokiriDustMoteTextureLoadDL); for (i = 0; i < globalCtx->envCtx.unk_EE[3]; i++) { + FrameInterpolation_RecordOpenChild(&this->effects[i], this->effects[i].epoch); Matrix_Translate(this->effects[i].base.x + this->effects[i].pos.x, this->effects[i].base.y + this->effects[i].pos.y, this->effects[i].base.z + this->effects[i].pos.z, MTXMODE_NEW); @@ -561,6 +571,7 @@ void ObjectKankyo_DrawFairies(ObjectKankyo* this2, GlobalContext* globalCtx2) { Matrix_RotateZ(DEG_TO_RAD(globalCtx->state.frames * 20.0f), MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_object_kankyo.c", 913), G_MTX_LOAD); gSPDisplayList(POLY_XLU_DISP++, gKokiriDustMoteDL); + FrameInterpolation_RecordCloseChild(); } CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_object_kankyo.c", 922); } @@ -939,6 +950,6 @@ void ObjectKankyo_DrawBeams(ObjectKankyo* this2, GlobalContext* globalCtx2) { } void ObjectKankyo_Reset(void) { - sIsSpawned = false; + sKankyoIsSpawned = false; sTrailingFairies = 0; } \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h index 9b9a69975..fc45e156e 100644 --- a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h +++ b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h @@ -24,6 +24,7 @@ typedef struct ObjectKankyoEffect { /* 0x4A */ u16 flightRadius; /* 0x4C */ f32 amplitude; /* 0x50 */ u16 timer; + u32 epoch; } ObjectKankyoEffect; // size = 0x54 typedef struct ObjectKankyo { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 1197febd6..e849a1b69 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -4804,7 +4804,7 @@ s32 func_8083ADD4(GlobalContext* globalCtx, Player* this) { void func_8083AE40(Player* this, s16 objectId) { s32 pad; - u32 size; + size_t size; if (objectId != OBJECT_INVALID) { this->giObjectLoading = true; @@ -4815,7 +4815,7 @@ void func_8083AE40(Player* this, s16 objectId) { LOG_HEX("size", size, "../z_player.c", 9090); ASSERT(size <= 1024 * 8, "size <= 1024 * 8", "../z_player.c", 9091); - DmaMgr_SendRequest2(&this->giObjectDmaRequest, (u32)this->giObjectSegment, gObjectTable[objectId].vromStart, + DmaMgr_SendRequest2(&this->giObjectDmaRequest, (uintptr_t)this->giObjectSegment, gObjectTable[objectId].vromStart, size, 0, &this->giObjectLoadQueue, NULL, "../z_player.c", 9099); } } @@ -10283,8 +10283,8 @@ void func_80848EF8(Player* this, GlobalContext* globalCtx) { int rectTop = 60; //Top Y Pos int rectWidth = 24; //Texture Width int rectHeight = 24; //Texture Heigh - int DefaultIconA= 50; //Default icon alpha (55 on 255) - + int DefaultIconA= 50; //Default icon alphe (55 on 255) + if (CVar_GetS32("gHUDMargins", 0) != 0) { rectLeft = OTRGetRectDimensionFromLeftEdge(26+(CVar_GetS32("gHUDMargin_L", 0)*-1)); rectTop = 60+(CVar_GetS32("gHUDMargin_T", 0)*-1); @@ -10292,7 +10292,7 @@ void func_80848EF8(Player* this, GlobalContext* globalCtx) { rectTop = 60; rectLeft = OTRGetRectDimensionFromLeftEdge(26); } - + OPEN_DISPS(globalCtx->state.gfxCtx, "../z_player.c", 2824); gDPPipeSync(OVERLAY_DISP++); gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, DefaultIconA); @@ -10759,7 +10759,7 @@ void Player_UpdateCommon(Player* this, GlobalContext* globalCtx, Input* input) { static Vec3f D_80854838 = { 0.0f, 0.0f, -30.0f }; void Player_Update(Actor* thisx, GlobalContext* globalCtx) { - static Vec3f sDogSpawnPos; + static Vec3f sDogSpawnPos; Player* this = (Player*)thisx; s32 dogParams; s32 pad; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index dc48b277d..570eedd1f 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -1505,9 +1505,9 @@ void FileChoose_LoadGame(GameState* thisx) { (gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KNIFE)) { gSaveContext.equips.buttonItems[0] = ITEM_NONE; - swordEquipMask = _byteswap_ushort(gEquipMasks[EQUIP_SWORD]) & gSaveContext.equips.equipment; + swordEquipMask = BOMSWAP16(gEquipMasks[EQUIP_SWORD]) & gSaveContext.equips.equipment; gSaveContext.equips.equipment &= gEquipNegMasks[EQUIP_SWORD]; - gSaveContext.inventory.equipment ^= (gBitFlags[swordEquipMask - 1] << _byteswap_ushort(gEquipShifts[EQUIP_SWORD])); + gSaveContext.inventory.equipment ^= (gBitFlags[swordEquipMask - 1] << BOMSWAP16(gEquipShifts[EQUIP_SWORD])); } } } diff --git a/soh/src/overlays/gamestates/ovl_select/z_select.c b/soh/src/overlays/gamestates/ovl_select/z_select.c index 98aaa4a63..c4a467d63 100644 --- a/soh/src/overlays/gamestates/ovl_select/z_select.c +++ b/soh/src/overlays/gamestates/ovl_select/z_select.c @@ -624,10 +624,10 @@ void Select_Init(GameState* thisx) { this->pageDownIndex = dREG(82); } R_UPDATE_RATE = 1; - #ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__GNUC__) this->staticSegment = GameState_Alloc(&this->state, size, "../z_select.c", 1114); DmaMgr_SendRequest1(this->staticSegment, _z_select_staticSegmentRomStart, size, "../z_select.c", 1115); - #endif +#endif gSaveContext.cutsceneIndex = 0x8000; gSaveContext.linkAge = 1; } diff --git a/soh/src/overlays/gamestates/ovl_title/z_title.c b/soh/src/overlays/gamestates/ovl_title/z_title.c index 380720dd1..18996f15e 100644 --- a/soh/src/overlays/gamestates/ovl_title/z_title.c +++ b/soh/src/overlays/gamestates/ovl_title/z_title.c @@ -34,7 +34,7 @@ void Title_PrintBuildInfo(Gfx** gfxp) { #ifdef _MSC_VER GfxPrint_Printf(&printer, "MSVC SHIP"); #else - GfxPrint_Printf(printer, "GCC SHIP"); + GfxPrint_Printf(&printer, "GCC SHIP"); #endif GfxPrint_SetPos(&printer, 5, 4); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_collect.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_collect.c index 36f2fc6b6..7790cd518 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_collect.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_collect.c @@ -495,20 +495,20 @@ void KaleidoScope_DrawQuestStatus(GlobalContext* globalCtx, GraphicsContext* gfx if (D_8082A124[sp218] == 0) { if (CVar_GetS32("gHudColors", 1) == 0) { // A Button notes - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, D_8082A150[sp218]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, D_8082A150[sp218]); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, D_8082A150[sp218]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, D_8082A150[sp218]); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), D_8082A150[sp218]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), D_8082A150[sp218]); } } else { - if (CVar_GetS32("gHudColors", 1) == 0) { // C Buttons notes - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[sp218]); - } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[sp218]); - } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), D_8082A150[sp218]); - } + if (CVar_GetS32("gHudColors", 1) == 0) { // C Buttons notes + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[sp218]); + } else if (CVar_GetS32("gHudColors", 1) == 1) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[sp218]); + } else if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), D_8082A150[sp218]); + } } gDPSetEnvColor(POLY_KAL_DISP++, 10, 10, 10, 0); @@ -537,20 +537,20 @@ void KaleidoScope_DrawQuestStatus(GlobalContext* globalCtx, GraphicsContext* gfx if (pauseCtx->unk_1E4 == 8) { if (gOcarinaSongNotes[sp224].notesIdx[phi_s3] == 0) { if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, 200); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, 200); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, 200); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, 200); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), 200); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), 200); } } else { - if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, 200); - } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, 200); - } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), 200); - } + if (CVar_GetS32("gHudColors", 1) == 0) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, 200); + } else if (CVar_GetS32("gHudColors", 1) == 1) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, 200); + } else if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), 200); + } } } else { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 150, 150, 150, 150); @@ -604,20 +604,20 @@ void KaleidoScope_DrawQuestStatus(GlobalContext* globalCtx, GraphicsContext* gfx if (D_8082A124[phi_s3] == 0) { if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, D_8082A150[phi_s3]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 150, 255, D_8082A150[phi_s3]); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, D_8082A150[phi_s3]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 80, 255, 150, D_8082A150[phi_s3]); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), D_8082A150[phi_s3]); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 80), CVar_GetS32("gCCABtnPrimG", 255), CVar_GetS32("gCCABtnPrimB", 150), D_8082A150[phi_s3]); } } else { - if (CVar_GetS32("gHudColors", 1) == 0) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[phi_s3]); - } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[phi_s3]); - } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), D_8082A150[phi_s3]); - } + if (CVar_GetS32("gHudColors", 1) == 0) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[phi_s3]); + } else if (CVar_GetS32("gHudColors", 1) == 1) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 50, D_8082A150[phi_s3]); + } else if (CVar_GetS32("gHudColors", 1) == 2) { + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 255), CVar_GetS32("gCCCBtnPrimG", 160), CVar_GetS32("gCCCBtnPrimB", 0), D_8082A150[phi_s3]); + } } gDPSetEnvColor(POLY_KAL_DISP++, 10, 10, 10, 0); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index 5b90725e1..27575c3b6 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -119,7 +119,7 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) { func_8009214C(globalCtx, pauseCtx->playerSegment, &pauseCtx->playerSkelAnime, &pos, &rot, scale, CUR_EQUIP_VALUE(EQUIP_SWORD), CUR_EQUIP_VALUE(EQUIP_TUNIC) - 1, CUR_EQUIP_VALUE(EQUIP_SHIELD), CUR_EQUIP_VALUE(EQUIP_BOOTS) - 1); - gsSPResetFB(globalCtx->state.gfxCtx->polyOpa.p++, fbTest); + gsSPResetFB(globalCtx->state.gfxCtx->polyOpa.p++); } void KaleidoScope_DrawEquipment(GlobalContext* globalCtx) { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c index bd5277286..f0b59fa4b 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c @@ -17,6 +17,14 @@ void KaleidoScope_DrawDungeonMap(GlobalContext* globalCtx, GraphicsContext* gfxC gPauseDekuTitleENGTex, gPauseDodongoTitleENGTex, gPauseJabuTitleENGTex, gPauseForestTitleENGTex, gPauseFireTitleENGTex, gPauseWaterTitleENGTex, gPauseSpiritTitleENGTex, gPauseShadowTitleENGTex, gPauseBotWTitleENGTex, gPauseIceCavernTitleENGTex, + + gPauseDekuTitleGERTex, gPauseDodongoTitleGERTex, gPauseJabuTitleGERTex, gPauseForestTitleGERTex, + gPauseFireTitleGERTex, gPauseWaterTitleGERTex, gPauseSpiritTitleGERTex, gPauseShadowTitleGERTex, + gPauseBotWTitleGERTex, gPauseIceCavernTitleGERTex, + + gPauseDekuTitleFRATex, gPauseDodongoTitleFRATex, gPauseJabuTitleFRATex, gPauseForestTitleFRATex, + gPauseFireTitleFRATex, gPauseWaterTitleFRATex, gPauseSpiritTitleFRATex, gPauseShadowTitleFRATex, + gPauseBotWTitleFRATex, gPauseIceCavernTitleFRATex, }; static void* floorIconTexs[] = { gDungeonMapBlankFloorButtonTex, gDungeonMap8FButtonTex, gDungeonMap7FButtonTex, gDungeonMap6FButtonTex, @@ -216,7 +224,7 @@ void KaleidoScope_DrawDungeonMap(GlobalContext* globalCtx, GraphicsContext* gfxC gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[68], 16, 0); - gDPLoadTextureBlock(POLY_KAL_DISP++, dungeonTitleTexs[gSaveContext.mapIndex], G_IM_FMT_IA, G_IM_SIZ_8b, 96, 16, 0, + gDPLoadTextureBlock(POLY_KAL_DISP++, dungeonTitleTexs[gSaveContext.mapIndex+(10*gSaveContext.language)], G_IM_FMT_IA, G_IM_SIZ_8b, 96, 16, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 75a8efa54..3d0bcade0 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -14,6 +14,8 @@ #include "vt.h" #include "SohHooks.h" +#include "soh/frame_interpolation.h" + static void* sEquipmentFRATexs[] = { gPauseEquipment00FRATex, gPauseEquipment01Tex, gPauseEquipment02Tex, gPauseEquipment03Tex, gPauseEquipment04Tex, gPauseEquipment10FRATex, gPauseEquipment11Tex, gPauseEquipment12Tex, gPauseEquipment13Tex, gPauseEquipment14Tex, @@ -967,17 +969,17 @@ void KaleidoScope_DrawCursor(GlobalContext* globalCtx, u16 pageIndex) { temp = pauseCtx->unk_1E4; if (CVar_GetS32("gHudColors", 1) == 0) { - sCursorColors[2][0] = 0; - sCursorColors[2][1] = 50; - sCursorColors[2][2] = 255; + sCursorColors[2][0] = 0; + sCursorColors[2][1] = 50; + sCursorColors[2][2] = 255; } else if (CVar_GetS32("gHudColors", 1) == 1) { - sCursorColors[2][0] = 0; - sCursorColors[2][1] = 255; - sCursorColors[2][2] = 50; + sCursorColors[2][0] = 0; + sCursorColors[2][1] = 255; + sCursorColors[2][2] = 50; } else if (CVar_GetS32("gHudColors", 1) == 2) { - sCursorColors[2][0] = CVar_GetS32("gCCABtnPrimR", 0); - sCursorColors[2][1] = CVar_GetS32("gCCABtnPrimG", 50); - sCursorColors[2][2] = CVar_GetS32("gCCABtnPrimB", 255); + sCursorColors[2][0] = CVar_GetS32("gCCABtnPrimR", 0); + sCursorColors[2][1] = CVar_GetS32("gCCABtnPrimG", 50); + sCursorColors[2][2] = CVar_GetS32("gCCABtnPrimB", 255); } if ((((pauseCtx->unk_1E4 == 0) || (temp == 8)) && (pauseCtx->state == 6)) || @@ -1050,30 +1052,28 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 255, 50 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 255, 50 }, }; - if (CVar_GetS32("gHudColors", 1) == 0) { - D_8082ACF4[8][0] = 0; - D_8082ACF4[8][1] = 50; - D_8082ACF4[8][2] = 255; - D_8082ACF4[11][0] = 0; - D_8082ACF4[11][1] = 50; - D_8082ACF4[11][2] = 255; + D_8082ACF4[8][0] = 0; + D_8082ACF4[8][1] = 50; + D_8082ACF4[8][2] = 255; + D_8082ACF4[11][0] = 0; + D_8082ACF4[11][1] = 50; + D_8082ACF4[11][2] = 255; } else if (CVar_GetS32("gHudColors", 1) == 1) { - D_8082ACF4[8][0] = 0; - D_8082ACF4[8][1] = 255; - D_8082ACF4[8][2] = 50; - D_8082ACF4[11][0] = 0; - D_8082ACF4[11][1] = 255; - D_8082ACF4[11][2] = 50; + D_8082ACF4[8][0] = 0; + D_8082ACF4[8][1] = 255; + D_8082ACF4[8][2] = 50; + D_8082ACF4[11][0] = 0; + D_8082ACF4[11][1] = 255; + D_8082ACF4[11][2] = 50; } else if (CVar_GetS32("gHudColors", 1) == 2) { - D_8082ACF4[8][0] = CVar_GetS32("gCCABtnPrimR", 0); - D_8082ACF4[8][1] = CVar_GetS32("gCCABtnPrimG", 50); - D_8082ACF4[8][2] = CVar_GetS32("gCCABtnPrimB", 255); - D_8082ACF4[11][0] = CVar_GetS32("gCCABtnPrimR", 0); - D_8082ACF4[11][1] = CVar_GetS32("gCCABtnPrimG", 50); - D_8082ACF4[11][2] = CVar_GetS32("gCCABtnPrimB", 255); + D_8082ACF4[8][0] = CVar_GetS32("gCCABtnPrimR", 0); + D_8082ACF4[8][1] = CVar_GetS32("gCCABtnPrimG", 50); + D_8082ACF4[8][2] = CVar_GetS32("gCCABtnPrimB", 255); + D_8082ACF4[11][0] = CVar_GetS32("gCCABtnPrimR", 0); + D_8082ACF4[11][1] = CVar_GetS32("gCCABtnPrimG", 50); + D_8082ACF4[11][2] = CVar_GetS32("gCCABtnPrimB", 255); } - static s16 D_8082AD3C = 20; static s16 D_8082AD40 = 0; static s16 D_8082AD44 = 0; @@ -1085,6 +1085,7 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) { s16 stepG; s16 stepB; + FrameInterpolation_RecordOpenChild(NULL, pauseCtx->state + pauseCtx->pageIndex * 100); OPEN_DISPS(gfxCtx, "../z_kaleido_scope_PAL.c", 1100); if ((pauseCtx->state < 8) || (pauseCtx->state > 0x11)) { @@ -1401,13 +1402,12 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) { gDPSetCombineLERP(POLY_KAL_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0); - if (CVar_GetS32("gHudColors", 1) == 0) {//Save prompt cursor colour - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 100, 100, 255, VREG(61)); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 100, 100, 255, VREG(61)); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 100, 255, 100, VREG(61)); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 100, 255, 100, VREG(61)); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 0), CVar_GetS32("gCCABtnPrimG", 50), CVar_GetS32("gCCABtnPrimB", 255), VREG(61)); //Save prompt cursor colour + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCABtnPrimR", 0), CVar_GetS32("gCCABtnPrimG", 50), CVar_GetS32("gCCABtnPrimB", 255), VREG(61)); //Save prompt cursor colour } if (pauseCtx->promptChoice == 0) { @@ -1463,6 +1463,7 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) { } CLOSE_DISPS(gfxCtx, "../z_kaleido_scope_PAL.c", 1577); + FrameInterpolation_RecordCloseChild(); } void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { @@ -1805,8 +1806,8 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { //gSPDisplayList(POLY_KAL_DISP++, gAButtonIconDL);//This is changed to load the texture only so we can prim color it. gDPLoadTextureBlock(POLY_KAL_DISP++, gABtnSymbolTex, G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); - - //gDPPipeSync(POLY_KAL_DISP++); + + gDPPipeSync(POLY_KAL_DISP++); gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, D_8082AD60[gSaveContext.language], @@ -1849,18 +1850,18 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = D_8082ADD8[gSaveContext.language] << 5; - + if (CVar_GetS32("gHudColors", 1) == 0) {//To equip text C button icon - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), 255); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), 255); } else if (CVar_GetS32("gHudColors", 1) == 1) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), 255); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, R_C_BTN_COLOR(0), R_C_BTN_COLOR(1), R_C_BTN_COLOR(2), 255); } else if (CVar_GetS32("gHudColors", 1) == 2) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 0), CVar_GetS32("gCCCBtnPrimG", 50), CVar_GetS32("gCCCBtnPrimB", 255), 255); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, CVar_GetS32("gCCCBtnPrimR", 0), CVar_GetS32("gCCCBtnPrimG", 50), CVar_GetS32("gCCCBtnPrimB", 255), 255); } //gSPDisplayList(POLY_KAL_DISP++, gCButtonIconsDL); //Same reason for every A button, to be able to recolor them. gDPLoadTextureBlock(POLY_KAL_DISP++, gCBtnSymbolsTex, G_IM_FMT_IA, G_IM_SIZ_8b, 48, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); - + gDPPipeSync(POLY_KAL_DISP++); gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); @@ -1892,6 +1893,7 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = D_8082ADE8[gSaveContext.language] << 5; + if (CVar_GetS32("gHudColors", 1) == 0) {//To play melody A button gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, gABtnTexColour[1][0], gABtnTexColour[1][1], gABtnTexColour[1][2], gABtnTexColour[1][3]); } else if (CVar_GetS32("gHudColors", 1) == 1) { @@ -1902,6 +1904,7 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { //gSPDisplayList(POLY_KAL_DISP++, gAButtonIconDL); gDPLoadTextureBlock(POLY_KAL_DISP++, gABtnSymbolTex, G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); + gDPPipeSync(POLY_KAL_DISP++); gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); @@ -1925,6 +1928,8 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { pauseCtx->infoPanelVtx[21].v.tc[0] = pauseCtx->infoPanelVtx[23].v.tc[0] = D_8082ADD8[gSaveContext.language] << 5; + + //gSPDisplayList(POLY_KAL_DISP++, gAButtonIconDL); if (CVar_GetS32("gHudColors", 1) == 0) {//To equip A button gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, gABtnTexColour[1][0], gABtnTexColour[1][1], gABtnTexColour[1][2], gABtnTexColour[1][3]); } else if (CVar_GetS32("gHudColors", 1) == 1) { @@ -1934,8 +1939,7 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { } gDPLoadTextureBlock(POLY_KAL_DISP++, gABtnSymbolTex, G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); - //gSPDisplayList(POLY_KAL_DISP++, gAButtonIconDL); - + gDPPipeSync(POLY_KAL_DISP++); gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); @@ -3260,9 +3264,9 @@ void KaleidoScope_Update(GlobalContext* globalCtx) if (gSaveContext.language == LANGUAGE_ENG) { memcpy(pauseCtx->nameSegment + 0x400, ResourceMgr_LoadTexByName(mapNameTextures[36 + gSaveContext.worldMapArea]), 0xA00); } else if (gSaveContext.language == LANGUAGE_GER) { - memcpy(pauseCtx->nameSegment + 0x400, ResourceMgr_LoadTexByName(mapNameTextures[59 + gSaveContext.worldMapArea]), 0xA00); + memcpy(pauseCtx->nameSegment + 0x400, ResourceMgr_LoadTexByName(mapNameTextures[58 + gSaveContext.worldMapArea]), 0xA00); } else { - memcpy(pauseCtx->nameSegment + 0x400, ResourceMgr_LoadTexByName(mapNameTextures[81 + gSaveContext.worldMapArea]), 0xA00); + memcpy(pauseCtx->nameSegment + 0x400, ResourceMgr_LoadTexByName(mapNameTextures[80 + gSaveContext.worldMapArea]), 0xA00); } } // OTRTODO - player on pause diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark_data.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark_data.c index df96fc876..64275108b 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark_data.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark_data.c @@ -15,6 +15,522 @@ static const Vtx sMarkChestVtx[] = { }; PauseMapMarksData gPauseMapMarkDataTable[] = { + // Deku Tree map 3F + { + { PAUSE_MAP_MARK_CHEST, + 23, //unk + sMarkChestVtx, + 4, //unk + 2, //Number of icons to show. + { //ID, X, Y + { 2, 40.0f, -33.0f }, + { 6, 49.0f, -42.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Deku Tree map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 1, 48.0f, -63.0f }, + { 5, 52.0f, -68.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Deku Tree map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 3, 84.0f, -39.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Deku Tree map B1 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 4, 77.0f, -26.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Deku Tree map B2 + { + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 55.0f, 0.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Dodongo's Cavern map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 10, 25.0f, -41.0f }, + { 4, 53.0f, -47.0f }, + { 6, 58.0f, -59.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Dodongo's Cavern map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 5, 13.0f, -60.0f }, + { 8, 20.0f, -49.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 23.0f, -25.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Jabu-Jabu's Belly map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 1, 67.0f, -13.0f }, + { 2, 28.0f, -13.0f }, + { 4, 38.0f, 0.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 65.0f, -37.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Jabu-Jabu's Belly map B1 + { + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Forest Temple map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 4, + { + { 0, 49.0f, -3.0f }, + { 2, 12.0f, -26.0f }, + { 5, 74.0f, -13.0f }, + { 7, 82.0f, -22.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Forest Temple map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 4, + { + { 0, 49.0f, -3.0f }, + { 2, 12.0f, -26.0f }, + { 5, 74.0f, -13.0f }, + { 7, 82.0f, -22.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Forest Temple map B1 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 9, 31.0f, -29.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Forest Temple map B2 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 11, 40.0f, -41.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 50.0f, -11.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Fire Temple map 5F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 5, 22.0f, -41.0f }, + { 13, 74.0f, -29.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Fire Temple map 4F + { + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Fire Temple map 3F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 3, 76.0f, -48.0f }, + { 6, 72.0f, -50.0f }, + { 7, 44.0f, -17.0f }, + { 8, 63.0f, -12.0f }, + { 9, 30.0f, -34.0f }, + { 10, 61.0f, -31.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Fire Temple map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 11, 78.0f, -34.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Fire Temple map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 5, + { + { 0, 48.0f, -17.0f }, + { 1, 35.0f, -45.0f }, + { 2, 67.0f, -58.0f }, + { 4, 74.0f, -15.0f }, + { 12, 47.0f, -27.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 26.0f, -34.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Water Temple map 3F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 2, 88.0f, -60.0f }, + { 7, 23.0f, -2.0f }, + { 9, 84.0f, -45.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 62.0f, -23.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Water Temple map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 0, 86.0f, -60.0f }, + { 8, 76.0f, -72.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Water Temple map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 4, + { + { 1, 88.0f, -60.0f }, + { 3, 42.0f, -21.0f }, + { 5, 47.0f, -15.0f }, + { 10, 33.0f, -31.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Water Temple map B1 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 6, 77.0f, -66.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Spirit Temple map 4F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 10, 59.0f, -9.0f }, + { 18, 32.0f, -20.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Spirit Temple map 3F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 5, + { + { 1, 20.0f, -43.0f }, + { 5, 83.0f, -26.0f }, + { 15, 57.0f, -14.0f }, + { 20, 81.0f, -55.0f }, + { 21, 87.0f, -55.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 47.0f, 0.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Spirit Temple map 2F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 6, + { + { 2, 41.0f, -16.0f }, + { 3, 47.0f, -17.0f }, + { 6, 27.0f, -16.0f }, + { 12, 29.0f, -20.0f }, + { 13, 70.0f, -22.0f }, + { 14, 70.0f, -25.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Spirit Temple map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 4, + { + { 0, 38.0f, -17.0f }, + { 4, 55.0f, -14.0f }, + { 8, 15.0f, -14.0f }, + { 7, 78.0f, -3.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Shadow Temple map B1 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 1, 41.0f, -17.0f }, + { 7, 27.0f, -24.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Shadow Temple map B2 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 2, 81.0f, -20.0f }, + { 3, 74.0f, -37.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Shadow Temple map B3 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 2, + { + { 12, 96.0f, -51.0f }, + { 22, 96.0f, -55.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Shadow Temple map B4 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 10, + { + { 4, 43.0f, -66.0f }, + { 5, 37.0f, -66.0f }, + { 6, 33.0f, -72.0f }, + { 8, 85.0f, -18.0f }, + { 9, 61.0f, -42.0f }, + { 10, 15.0f, -4.0f }, + { 11, 25.0f, -4.0f }, + { 13, 19.0f, -29.0f }, + { 21, 92.0f, -29.0f }, + { 20, 87.0f, -20.0f }, + } }, + { PAUSE_MAP_MARK_BOSS, + 23, + sMarkBossVtx, + 4, + 1, + { + { -1, 31.0f, -45.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Bottom of the Well map B1 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 9, + { + { 1, 51.0f, -24.0f }, + { 3, 84.0f, -38.0f }, + { 4, 31.0f, -2.0f }, + { 5, 67.0f, -27.0f }, + { 8, 46.0f, -27.0f }, + { 10, 82.0f, -12.0f }, + { 12, 80.0f, -16.0f }, + { 14, 62.0f, -24.0f }, + { 20, 89.0f, -38.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Bottom of the Well map B2 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 2, 54.0f, -27.0f }, + { 9, 28.0f, -17.0f }, + { 16, 56.0f, -38.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Bottom of the Well map B3 + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 1, + { + { 7, 71.0f, -33.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, + // Ice Cavern map 1F + { + { PAUSE_MAP_MARK_CHEST, + 23, + sMarkChestVtx, + 4, + 3, + { + { 0, 66.0f, -2.0f }, + { 1, 77.0f, -46.0f }, + { 2, 27.0f, -45.0f }, + } }, + { PAUSE_MAP_MARK_NONE, 0, NULL, 0, 0, { 0 } }, + }, +}; +PauseMapMarksData gPauseMapMarkDataTableMasterQuest[] = { // Deku Tree map 0 { { PAUSE_MAP_MARK_CHEST,