diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml index daa99f19f..5e124da35 100644 --- a/.github/workflows/generate-builds.yml +++ b/.github/workflows/generate-builds.yml @@ -229,48 +229,48 @@ jobs: soh.nro soh.otr readme.txt - build-wiiu: - needs: generate-soh-otr - runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }} - container: - image: devkitpro/devkitppc:latest - steps: - - name: Install dependencies - if: ${{ !vars.LINUX_RUNNER }} - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - uses: actions/checkout@v3 - with: - submodules: true - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ runner.os }}-wiiu-ccache - - name: Build SoH - run: | - cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache - cmake --build build-wiiu --target soh_wuhb --config Release -j3 + # build-wiiu: + # needs: generate-soh-otr + # runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }} + # container: + # image: devkitpro/devkitppc:latest + # steps: + # - name: Install dependencies + # if: ${{ !vars.LINUX_RUNNER }} + # run: | + # sudo apt-get update + # sudo apt-get install -y ninja-build + # - uses: actions/checkout@v3 + # with: + # submodules: true + # - name: ccache + # uses: hendrikmuhs/ccache-action@v1.2 + # with: + # key: ${{ runner.os }}-wiiu-ccache + # - name: Build SoH + # run: | + # cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache + # cmake --build build-wiiu --target soh_wuhb --config Release -j3 - mv build-wiiu/soh/*.rpx soh.rpx - mv build-wiiu/soh/*.wuhb soh.wuhb - mv README.md readme.txt - env: - DEVKITPRO: /opt/devkitpro - DEVKITPPC: /opt/devkitpro/devkitPPC - - name: Download soh.otr - uses: actions/download-artifact@v3 - with: - name: soh.otr - - name: Upload build - uses: actions/upload-artifact@v3 - with: - name: soh-wiiu - path: | - soh.rpx - soh.wuhb - soh.otr - readme.txt + # mv build-wiiu/soh/*.rpx soh.rpx + # mv build-wiiu/soh/*.wuhb soh.wuhb + # mv README.md readme.txt + # env: + # DEVKITPRO: /opt/devkitpro + # DEVKITPPC: /opt/devkitpro/devkitPPC + # - name: Download soh.otr + # uses: actions/download-artifact@v3 + # with: + # name: soh.otr + # - name: Upload build + # uses: actions/upload-artifact@v3 + # with: + # name: soh-wiiu + # path: | + # soh.rpx + # soh.wuhb + # soh.otr + # readme.txt build-windows: needs: generate-soh-otr runs-on: ${{ (vars.WINDOWS_RUNNER && fromJSON(vars.WINDOWS_RUNNER)) || 'windows-latest' }} diff --git a/OTRExporter/OTRExporter/DisplayListExporter.cpp b/OTRExporter/OTRExporter/DisplayListExporter.cpp index 4ac8586df..3a77cba8f 100644 --- a/OTRExporter/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/OTRExporter/DisplayListExporter.cpp @@ -15,7 +15,7 @@ #define GFX_SIZE 8 -#define gsDPSetCombineLERP2(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ +#define gsDPSetCombineLERP_NoMacros(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ { \ _SHIFTL(G_SETCOMBINE, 24, 8) | \ @@ -607,7 +607,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t ab1 = (data & 0b00000000000000000000000000000000000000000000000000000000111000) >> 3; int32_t ad1 = (data & 0b00000000000000000000000000000000000000000000000000000000000111) >> 0; - Gfx value = {gsDPSetCombineLERP2(a0, b0, c0, d0, aa0, ab0, ac0, ad0, a1, b1, c1, d1, aa1, ab1, ac1, ad1)}; + Gfx value = { gsDPSetCombineLERP_NoMacros(a0, b0, c0, d0, aa0, ab0, ac0, ad0, a1, b1, c1, d1, aa1, ab1, ac1, ad1)}; word0 = value.words.w0; word1 = value.words.w1; } diff --git a/OTRExporter/OTRExporter/Main.cpp b/OTRExporter/OTRExporter/Main.cpp index 85300e6f8..7895fe759 100644 --- a/OTRExporter/OTRExporter/Main.cpp +++ b/OTRExporter/OTRExporter/Main.cpp @@ -259,6 +259,11 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) //printf("Exported Resource End %s in %zums\n", res->GetName().c_str(), diff); } +static void ExporterProcessCompilable(tinyxml2::XMLElement* reader) +{ + std::string nodeName = reader->Name(); +} + static void ExporterXMLBegin() { } @@ -285,6 +290,7 @@ void ImportExporters() ExporterSet* exporterSet = new ExporterSet(); exporterSet->processFileModeFunc = ExporterProcessFileMode; exporterSet->parseFileModeFunc = ExporterParseFileMode; + exporterSet->processCompilableFunc = ExporterProcessCompilable; exporterSet->parseArgsFunc = ExporterParseArgs; exporterSet->beginFileFunc = ExporterFileBegin; exporterSet->endFileFunc = ExporterFileEnd; diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/SoHShiny b/OTRExporter/assets/textures/nintendo_rogo_static/SoHShiny new file mode 100644 index 000000000..5e5c7b52b Binary files /dev/null and b/OTRExporter/assets/textures/nintendo_rogo_static/SoHShiny differ diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL new file mode 100644 index 000000000..5e5435d84 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 new file mode 100644 index 000000000..2986de72b --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 new file mode 100644 index 000000000..2aa9bea6d --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 new file mode 100644 index 000000000..2b8fe0d11 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 new file mode 100644 index 000000000..53edaf74f --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 new file mode 100644 index 000000000..2c2ee793b --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 new file mode 100644 index 000000000..ec462b114 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 new file mode 100644 index 000000000..cc906e23e --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 new file mode 100644 index 000000000..68e4babcf --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material new file mode 100644 index 000000000..e48b335c0 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 new file mode 100644 index 000000000..e98640319 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 new file mode 100644 index 000000000..b2db72d79 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 new file mode 100644 index 000000000..be60fd46b --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material new file mode 100644 index 000000000..3cda02a88 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 new file mode 100644 index 000000000..3cda02a88 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 new file mode 100644 index 000000000..3cda02a88 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 new file mode 100644 index 000000000..3cda02a88 --- /dev/null +++ b/OTRExporter/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/OTRExporter/assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 b/OTRExporter/assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 new file mode 100644 index 000000000..2edcaacb3 Binary files /dev/null and b/OTRExporter/assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 differ diff --git a/OTRExporter/assets/textures/virtual/gEmptyTexture.rgba32.png b/OTRExporter/assets/textures/virtual/gEmptyTexture.rgba32.png new file mode 100644 index 000000000..eaf806b71 Binary files /dev/null and b/OTRExporter/assets/textures/virtual/gEmptyTexture.rgba32.png differ diff --git a/README.md b/README.md index 4fe9dafec..318ff7fa5 100644 --- a/README.md +++ b/README.md @@ -1,105 +1,72 @@ -# Welcome to the Ship of Harkinian! +![Ship of Harkinian](docs/shiptitle.darkmode.png#gh-dark-mode-only) +![Ship of Harkinian](docs/shiptitle.lightmode.png#gh-light-mode-only) -A PC port of OoT allowing you to enjoy the game with modern controls, widescreen, high-resolution, gyroscopy and other great features! Setup is simple, let's get started! +## Website -The Ship does not include any copyrighted assets. You are required to provide a supported copy of the game. +Official Website: https://www.shipofharkinian.com/ ## Discord -Official Discord: https://discord.com/invite/BtBmd55HVH +Official Discord: https://discord.com/invite/shipofharkinian -## Quick Start (Windows) +If you're having any trouble after reading through this `README`, feel free ask for help in the Support text channels. Please keep in mind that we do not condone piracy. -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 `OTRGui.exe` to generate an `oot.otr` archive file. -4) Launch `soh.exe` +# Quick Start -### Supported Games -#### Ocarina of Time Debug PAL GC (not Master Quest) +The Ship does not include any copyrighted assets. You are required to provide a supported copy of the game. + +### 1. Check your `sha1` +You can verify you have a supported copy of the game by checking the `sha1` hash. There are many ways to do this, one of the simplest is using the [`hasher-js`](https://github.com/snarfblam/hasher-js) webapp hosted at https://www.romhacking.net/hash/. + +| Supported Version | `sha1` | +| - | - | +| PAL GC | `0227d7c0074f2d0ac935631990da8ec5914597b4` | +| PAL GC (Debug) | `cee6bc3c2a634b41728f2af8da54d9bf8cc14099` | +| PAL MQ | `079b855b943d6ad8bd1eb026c0ed169ecbdac7da` | +| PAL MQ | `50bebedad9e0f10746a52b07239e47fa6c284d03` | + +### 2. Download The Ship of Harkinian from [Discord](https://discord.com/invite/shipofharkinian) +The latest release is available in the most recent post in the `#downloads` channel. + +### 3. Launch the Game! +#### Windows +* Extract the zip +* Launch `soh.exe` + +#### Linux +* Place your supported copy of the game in the same folder as the appimage. +* Execute `soh.appimage`. You may have to `chmod +x` the appimage via terminal. + +#### macOS +* Run `soh.app`. When prompted, select your supported copy of the game. +* You should see a notification saying `Processing OTR`, then, once the process is complete, you should get a notification saying `OTR Successfully Generated`, then the game should start. + +#### Nintendo Switch +* Run one of the PC releases to generate an `oot.otr` and/or `oot-mq.otr` file. After launching the game on PC, you will be able to find these files in the same directory as `soh.exe` or `soh.appimage`. On macOS, these files can be found in `/Users//Library/Application Support/com.shipofharkinian.soh/` +* Copy the files to your sd card ``` -Build team: `zelda@srd022j` -Build date: `03-02-21 00:49:18` (year-month-day) -sha1: cee6bc3c2a634b41728f2af8da54d9bf8cc14099 -``` -#### Ocarina of Time PAL GameCube -``` -sha1: 0227d7c0074f2d0ac935631990da8ec5914597b4 -``` -#### Ocarina of Time Debug PAL GC MQ (Dungeons will be Master Quest) -``` -Build team: `zelda@srd022j` -Build date: `03-02-21 00:16:31` (year-month-day) -sha1: 079b855b943d6ad8bd1eb026c0ed169ecbdac7da (Produced by decomp) -sha1: 50bebedad9e0f10746a52b07239e47fa6c284d03 (Alternate) +sdcard +└── switch + └── soh + ├── oot-mq.otr + ├── oot.otr + ├── soh.nro + └── soh.otr ``` +* Launch via Atmosphere's `Game+R` launcher method. + +### 4. Play! Congratulations, you are now sailing with the Ship of Harkinian! Have fun! -## About Versions +# Configuration -The Ship of Harkinian's versioning system is a unique system, comprising of a three-numbered version (`x.y.z`) and a version codename. The main version number `x` signifies major feature updates that require a new `oot.otr` file. The version number `y` signifies major feature updates and bugfixes that do not require a new `oot.otr` file. The version number `z` signifies minor updates such as a collection of bugfixes. - -The version codename consists of a sci-fi film character followed by a phonetic alphabet code word. The film character represents a major release version which increments with the major `x` or `y` version bumps. The code word represents a minor release version which increments with the minor `z` version bump. - -## Additional Setup Information - -### Windows Rom Extraction - -* Open `OTRGui.exe` and click on "Open OOT ROM", then select your supported copy of the game (see section "Supported Games"). -* If a second button already exits then `oot.otr` already exists. To prevent overwriting the old `oot.otr` use this button to choose a new game directory. The new directory must not already contain an `oot.otr` to prevent an error. -* When the process completes, you should have an `oot.otr` or `oot-mq.otr` file in your main directory, depending on the version of the game used to build it. - (*NOTE:* You can have both `.otr` files, if you want to! This even allows you to shuffle MQ and vanilla dungeons in the randomizer) - -This process can take up to several minutes, depending on your system hardware. - -Close `OTRGui.exe` when the `Done!` message appears. -If you get another message, then you might have selected the wrong rom. See section "Supported Games". - -### Linux Rom Extraction - -* Place one of the supported roms in the same folder as the appimage (See section "Supported Games"). -* Execute `soh.appimage`. You may have to `chmod +x` the appimage via terminal. -* When the process completes, you should have an `oot.otr` or `oot-mq.otr` file in the same directory as the appimage, and the game should start automatically. - (*NOTE:* You can provide both a vanilla and MQ ROM, if you want to! This even allows you to shuffle MQ and vanilla dungeons in the randomizer) - -This process can take up to several minutes, depending on your system hardware. - -If you get any errors, then you might have selected the wrong rom. See section "Supported Games". - -### MacOS Rom Extraction - -* Run `soh.app`, and when prompted, select one of the supported roms listed above. -* You should see a notification saying `Processing OTR`, then, once the process is complete, you should get a notification saying `OTR Successfully Generated`, then the game should start. - -This process can take up to several minutes, depending on your system hardware. - -If you get an error saying `Incompatible ROM hash`, you have selected the wrong rom. See section "Supported Games". - -### Nintendo Switch Rom Extraction - -* Download the latest PC release of the Ship of Harkinian, and follow the instructions above for generating the `oot.otr` archive on that platform. -* Place the `.nro` and the `oot.otr` archive into a folder called `soh` in your Switch folder on your Switch - -### Nintendo Wii U Rom Extraction - -* Download the latest PC release of the Ship of Harkinian, and follow the instructions above for generating the `oot.otr` archive on that platform. -* Copy the `.rpx` and the `oot.otr` archive to `wiiu/apps/soh` - ---- - -If you're having any trouble, feel free to join our [Discord Server](https://discord.com/invite/BtBmd55HVH) and ask for help in the Support text channels. Please keep in mind that we do not condone piracy. - -### Running The Ship of Harkinian - -For Windows, launch `soh.exe`. For Linux, execute the appimage. For MacOS, launch the app. For Switch, launch the app via Atmosphere's `Game+R` launcher method. For Wii U, launch the `.rpx` file through the homebrew Mii Maker exploit. - -Default keyboard configuration: +### Default keyboard configuration | N64 | A | B | Z | Start | Analog stick | C buttons | D-Pad | | - | - | - | - | - | - | - | - | | Keyboard | X | C | Z | Space | WASD | Arrow keys | TFGH | -Other shortcuts: +### Other shortcuts | Keys | Action | | - | - | | F1 | Toggle menubar | @@ -110,89 +77,32 @@ Other shortcuts: | Alt+Enter | Fullscreen (DirectX) | | Ctrl+R | Reset | +### Graphics Backends Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (MacOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `shipofharkinian.json` file by finding the line `gfxbackend:""` and changing the value to `sdl` for OpenGL. DirectX 11 is the default on Windows. -### Custom Music +# Custom Assets -We support importing custom [Seq64](https://github.com/sauraen/seq64) files to replace the in game music and fanfares (Sound effect and instrument replacement is currently not supported). +Custom assets are packed in `.otr` files. To use custom assets, place them in the `mods` folder. -First you will need to prepare a folder with the desired sequences. Every sequence requires two files with the same name and different extensions - a `.seq` Seq64 file and a `.meta` plaintext file. These files can be categorically nested in folders if desired, - Retro will recursively search each subfolder it finds. +If you're interested in creating and/or packing your own custom asset `.otr` files, check out [**retro**](https://github.com/HarbourMasters64/retro)! -The `.meta` file requires two lines - the first line is the name that will be displayed in the SFX editor, and the second line is the instrument set number in `base16` format. For example, if there is a sequence file `Foo.seq` then you need a meta file `Foo.meta` that could contain: -``` -Awesome Name -C -``` +# Development +### Building -Once you have prepared your sequences folder: -1. Download and open [Retro](https://github.com/HarbourMasters/retro/releases). -1. Choose the "Create OTR" option. -1. Choose the "Custom Sequences" option. -1. Using the file selection screen, choose the sequences folder you prepared in the previous instructions. -1. Click the "Stage Files" button. - (*NOTE:* SoH can handle 1024 custom sequence in total. This includes the original music. Keep that in mind!) -1. Click the "Finalize OTR" text in the green footer. -1. Click "Generate OTR" and, using the file selection screen, save the file to the `mods` folder of your SoH installation. - - This `mods` folder should be in the same folder as your `oot.otr` file. +If you want to manually compile SoH, please consult the [building instructions](docs/BUILDING.md). -Assuming you have done everything correctly, boot up SoH and select the SFX Editor from the enhancements dropdown menu. You should now be able to swap out any of the in game sequences/fanfares for the sequences added in your newly generated OTR file. If you have any trouble with this process, please reach out in the support section of the Discord. +### Playtesting +If you want to playtest a continuous integration build, you can find them at the links below. Keep in mind that these are for playtesting only, and you will likely encounter bugs and possibly crashes. -## Building The Ship of Harkinian +* [Windows](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-windows.zip) +* [macOS](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-mac.zip) +* [Linux (performance)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-performance.zip) _(requires `glibc 2.35` or newer, but will be more performant than the compatibility build.)_ +* [Linux (compatibility)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatiblity.zip) _(compatible with most Linux distributions, but may not be as performant as the performance build.)_ +* [Switch](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-switch.zip) -If you want to manually compile SoH, please consult the [building instructions](BUILDING.md). - -## Nightly Builds -If you want to playtest a nightly build, you can find them at the links below. However, keep in mind that these are for playtesting only, and you will likely encounter bugs. Rarely, these builds will crash. - -Nightly builds of Ship of Harkinian are available here: [Windows](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-windows.zip), [macOS](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-mac.zip), [Linux (compatibility*)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatiblity.zip), [Linux (performance*)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-performance.zip), [Switch](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-switch.zip), [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip) - -_*compatibility: compatible with most Linux distributions, but may not be as performant as the perf build._\ -_*performance: requires `glibc 2.35` or newer, but will be more performant than the compat build._ - -## Take The Survey -Want to use cartridge readers in tandem with OTRGui? -Take [this survey](https://retroarchopenhardware.com/survey.php) to increase chances of this becoming reality. - -## 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 - -## 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 - -## Video Credits - Kenix | Producer / Writer - briaguya | Writer - rainbow_fash | Executive Producer - ReveriePass | Editor - MicTheMicrophone | Gwonam / The King - Amphibibro | Link - AceHeart | Zelda + + + + Powered by libultraship + + diff --git a/ZAPDTR/ZAPD/Globals.h b/ZAPDTR/ZAPD/Globals.h index c599266ef..0fe8e0545 100644 --- a/ZAPDTR/ZAPD/Globals.h +++ b/ZAPDTR/ZAPD/Globals.h @@ -22,6 +22,7 @@ typedef bool (*ExporterSetFuncBool)(ZFileMode fileMode); typedef void (*ExporterSetFuncVoid)(int argc, char* argv[], int& i); typedef void (*ExporterSetFuncVoid2)(const std::string& buildMode, ZFileMode& fileMode); typedef void (*ExporterSetFuncVoid3)(); +typedef void (*ExporterSetFuncVoid4)(tinyxml2::XMLElement* reader); typedef void (*ExporterSetResSave)(ZResource* res, BinaryWriter& writer); class ExporterSet @@ -39,6 +40,8 @@ public: ExporterSetFuncVoid3 endXMLFunc = nullptr; ExporterSetResSave resSaveFunc = nullptr; ExporterSetFuncVoid3 endProgramFunc = nullptr; + + ExporterSetFuncVoid4 processCompilableFunc = nullptr; }; class Globals diff --git a/ZAPDTR/ZAPD/ZFile.cpp b/ZAPDTR/ZAPD/ZFile.cpp index 46264732c..1f4b92bcf 100644 --- a/ZAPDTR/ZAPD/ZFile.cpp +++ b/ZAPDTR/ZAPD/ZFile.cpp @@ -128,6 +128,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) if (reader->Attribute("RangeEnd") != nullptr) rangeEnd = StringHelper::StrToL(reader->Attribute("RangeEnd"), 16); + if (reader->Attribute("Compilable") != nullptr) + isCompilable = true; + if (rangeStart > rangeEnd) HANDLE_ERROR_PROCESS( WarningType::Always, @@ -261,16 +264,19 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) } nameSet.insert(nameXml); } - + std::string nodeName = std::string(child->Name()); if (nodeMap.find(nodeName) != nodeMap.end()) { ZResource* nRes = nodeMap[nodeName](this); - if (mode == ZFileMode::Extract || mode == ZFileMode::ExternalFile || mode == ZFileMode::ExtractDirectory) - nRes->ExtractFromXML(child, rawDataIndex); - + if (mode == ZFileMode::Extract || mode == ZFileMode::ExternalFile || + mode == ZFileMode::ExtractDirectory) + { + if (!isCompilable) + nRes->ExtractFromXML(child, rawDataIndex); + } switch (nRes->GetResourceType()) { case ZResourceType::Texture: diff --git a/ZAPDTR/ZAPD/ZFile.h b/ZAPDTR/ZAPD/ZFile.h index 7860aa4d3..ae7409061 100644 --- a/ZAPDTR/ZAPD/ZFile.h +++ b/ZAPDTR/ZAPD/ZFile.h @@ -36,6 +36,7 @@ public: std::vector resources; int workerID; + bool isCompilable = false; // Default to using virtual addresses uint32_t segment = 0x80; diff --git a/BUILDING.md b/docs/BUILDING.md similarity index 100% rename from BUILDING.md rename to docs/BUILDING.md diff --git a/docs/CREDITS.md b/docs/CREDITS.md new file mode 100644 index 000000000..10462b49d --- /dev/null +++ b/docs/CREDITS.md @@ -0,0 +1,45 @@ +# Credits + +## 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 + +## 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 + +## Video Credits + Kenix | Producer / Writer + briaguya | Writer + rainbow_fash | Executive Producer + ReveriePass | Editor + MicTheMicrophone | Gwonam / The King + Amphibibro | Link + AceHeart | Zelda diff --git a/docs/CUSTOM_MUSIC.md b/docs/CUSTOM_MUSIC.md new file mode 100644 index 000000000..f12ed0ecd --- /dev/null +++ b/docs/CUSTOM_MUSIC.md @@ -0,0 +1,24 @@ +### Custom Music + +We support importing custom [Seq64](https://github.com/sauraen/seq64) files to replace the in game music and fanfares (Sound effect and instrument replacement is currently not supported). + +First you will need to prepare a folder with the desired sequences. Every sequence requires two files with the same name and different extensions - a `.seq` Seq64 file and a `.meta` plaintext file. These files can be categorically nested in folders if desired, - Retro will recursively search each subfolder it finds. + +The `.meta` file requires two lines - the first line is the name that will be displayed in the SFX editor, and the second line is the instrument set number in `base16` format. For example, if there is a sequence file `Foo.seq` then you need a meta file `Foo.meta` that could contain: +``` +Awesome Name +C +``` + +Once you have prepared your sequences folder: +1. Download and open [Retro](https://github.com/HarbourMasters/retro/releases). +1. Choose the "Create OTR" option. +1. Choose the "Custom Sequences" option. +1. Using the file selection screen, choose the sequences folder you prepared in the previous instructions. +1. Click the "Stage Files" button. + (*NOTE:* SoH can handle 1024 custom sequence in total. This includes the original music. Keep that in mind!) +1. Click the "Finalize OTR" text in the green footer. +1. Click "Generate OTR" and, using the file selection screen, save the file to the `mods` folder of your SoH installation. + - This `mods` folder should be in the same folder as your `oot.otr` file. + +Assuming you have done everything correctly, boot up SoH and select the SFX Editor from the enhancements dropdown menu. You should now be able to swap out any of the in game sequences/fanfares for the sequences added in your newly generated OTR file. If you have any trouble with this process, please reach out in the support section of the Discord. diff --git a/docs/VERSIONING.md b/docs/VERSIONING.md new file mode 100644 index 000000000..d866997cc --- /dev/null +++ b/docs/VERSIONING.md @@ -0,0 +1,5 @@ +## About Versions + +The Ship of Harkinian's versioning system is a unique system, comprising of a three-numbered version (`x.y.z`) and a version codename. The main version number `x` signifies major feature updates that require a new `oot.otr` file. The version number `y` signifies major feature updates and bugfixes that do not require a new `oot.otr` file. The version number `z` signifies minor updates such as a collection of bugfixes. + +The version codename consists of a sci-fi film character followed by a phonetic alphabet code word. The film character represents a major release version which increments with the major `x` or `y` version bumps. The code word represents a minor release version which increments with the minor `z` version bump. diff --git a/docs/poweredbylus.darkmode.png b/docs/poweredbylus.darkmode.png new file mode 100644 index 000000000..2e2660814 Binary files /dev/null and b/docs/poweredbylus.darkmode.png differ diff --git a/docs/poweredbylus.lightmode.png b/docs/poweredbylus.lightmode.png new file mode 100644 index 000000000..740675417 Binary files /dev/null and b/docs/poweredbylus.lightmode.png differ diff --git a/docs/shiptitle.darkmode.png b/docs/shiptitle.darkmode.png new file mode 100644 index 000000000..56d75ff70 Binary files /dev/null and b/docs/shiptitle.darkmode.png differ diff --git a/docs/shiptitle.lightmode.png b/docs/shiptitle.lightmode.png new file mode 100644 index 000000000..e5e2d822c Binary files /dev/null and b/docs/shiptitle.lightmode.png differ diff --git a/libultraship b/libultraship index 61125df58..2ddffdb5b 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 61125df584a2ed31ae33250ac3cde8e1c7f1254b +Subproject commit 2ddffdb5b60377a09a4a198a8fd67726951bbb27 diff --git a/soh/assets/textures/boss_title_cards/.gitempty b/soh/assets/textures/boss_title_cards/.gitempty new file mode 100644 index 000000000..e69de29bb diff --git a/soh/assets/textures/boss_title_cards/object_bv.h b/soh/assets/textures/boss_title_cards/object_bv.h index f8c9dae49..fcf117dc1 100644 --- a/soh/assets/textures/boss_title_cards/object_bv.h +++ b/soh/assets/textures/boss_title_cards/object_bv.h @@ -1,23 +1,12 @@ #pragma once -#define dgBarinadeTitleCardENGTex "__OTR__textures/object_bv/gBarinadeTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBarinadeTitleCardENGTex[] = dgBarinadeTitleCardENGTex; -#else -static const char gBarinadeTitleCardENGTex[] __attribute__((aligned (2))) = dgBarinadeTitleCardENGTex; -#endif - -#define dgBarinadeTitleCardGERTex "__OTR__textures/object_bv/gBarinadeTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBarinadeTitleCardGERTex[] = dgBarinadeTitleCardGERTex; -#else -static const char gBarinadeTitleCardGERTex[] __attribute__((aligned (2))) = dgBarinadeTitleCardGERTex; -#endif - -#define dgBarinadeTitleCardFRATex "__OTR__textures/object_bv/gBarinadeTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBarinadeTitleCardFRATex[] = dgBarinadeTitleCardFRATex; -#else -static const char gBarinadeTitleCardFRATex[] __attribute__((aligned (2))) = dgBarinadeTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgBarinadeTitleCardENGTex "__OTR__textures/object_bv/gBarinadeTitleCardENGTex" +static const ALIGN_ASSET(2) char gBarinadeTitleCardENGTex[] = dgBarinadeTitleCardENGTex; + +#define dgBarinadeTitleCardGERTex "__OTR__textures/object_bv/gBarinadeTitleCardGERTex" +static const ALIGN_ASSET(2) char gBarinadeTitleCardGERTex[] = dgBarinadeTitleCardGERTex; + +#define dgBarinadeTitleCardFRATex "__OTR__textures/object_bv/gBarinadeTitleCardFRATex" +static const ALIGN_ASSET(2) char gBarinadeTitleCardFRATex[] = dgBarinadeTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_fd.h b/soh/assets/textures/boss_title_cards/object_fd.h index a911fef4d..af5dcef4b 100644 --- a/soh/assets/textures/boss_title_cards/object_fd.h +++ b/soh/assets/textures/boss_title_cards/object_fd.h @@ -1,23 +1,12 @@ #pragma once -#define dgVolvagiaBossTitleCardENGTex "__OTR__textures/object_fd/gVolvagiaBossTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gVolvagiaBossTitleCardENGTex[] = dgVolvagiaBossTitleCardENGTex; -#else -static const char gVolvagiaBossTitleCardENGTex[] __attribute__((aligned (2))) = dgVolvagiaBossTitleCardENGTex; -#endif - -#define dgVolvagiaBossTitleCardGERTex "__OTR__textures/object_fd/gVolvagiaBossTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gVolvagiaBossTitleCardGERTex[] = dgVolvagiaBossTitleCardGERTex; -#else -static const char gVolvagiaBossTitleCardGERTex[] __attribute__((aligned (2))) = dgVolvagiaBossTitleCardGERTex; -#endif - -#define dgVolvagiaBossTitleCardFRATex "__OTR__textures/object_fd/gVolvagiaBossTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gVolvagiaBossTitleCardFRATex[] = dgVolvagiaBossTitleCardFRATex; -#else -static const char gVolvagiaBossTitleCardFRATex[] __attribute__((aligned (2))) = dgVolvagiaBossTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgVolvagiaBossTitleCardENGTex "__OTR__textures/object_fd/gVolvagiaBossTitleCardENGTex" +static const ALIGN_ASSET(2) char gVolvagiaBossTitleCardENGTex[] = dgVolvagiaBossTitleCardENGTex; + +#define dgVolvagiaBossTitleCardGERTex "__OTR__textures/object_fd/gVolvagiaBossTitleCardGERTex" +static const ALIGN_ASSET(2) char gVolvagiaBossTitleCardGERTex[] = dgVolvagiaBossTitleCardGERTex; + +#define dgVolvagiaBossTitleCardFRATex "__OTR__textures/object_fd/gVolvagiaBossTitleCardFRATex" +static const ALIGN_ASSET(2) char gVolvagiaBossTitleCardFRATex[] = dgVolvagiaBossTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_fhg.h b/soh/assets/textures/boss_title_cards/object_fhg.h index d52366a3f..3ff7e31d5 100644 --- a/soh/assets/textures/boss_title_cards/object_fhg.h +++ b/soh/assets/textures/boss_title_cards/object_fhg.h @@ -1,23 +1,12 @@ #pragma once -#define dgPhantomGanonTitleCardENGTex "__OTR__textures/object_fhg/gPhantomGanonTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gPhantomGanonTitleCardENGTex[] = dgPhantomGanonTitleCardENGTex; -#else -static const char gPhantomGanonTitleCardENGTex[] __attribute__((aligned (2))) = dgPhantomGanonTitleCardENGTex; -#endif - -#define dgPhantomGanonTitleCardGERTex "__OTR__textures/object_fhg/gPhantomGanonTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gPhantomGanonTitleCardGERTex[] = dgPhantomGanonTitleCardGERTex; -#else -static const char gPhantomGanonTitleCardGERTex[] __attribute__((aligned (2))) = dgPhantomGanonTitleCardGERTex; -#endif - -#define dgPhantomGanonTitleCardFRATex "__OTR__textures/object_fhg/gPhantomGanonTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gPhantomGanonTitleCardFRATex[] = dgPhantomGanonTitleCardFRATex; -#else -static const char gPhantomGanonTitleCardFRATex[] __attribute__((aligned (2))) = dgPhantomGanonTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgPhantomGanonTitleCardENGTex "__OTR__textures/object_fhg/gPhantomGanonTitleCardENGTex" +static const ALIGN_ASSET(2) char gPhantomGanonTitleCardENGTex[] = dgPhantomGanonTitleCardENGTex; + +#define dgPhantomGanonTitleCardGERTex "__OTR__textures/object_fhg/gPhantomGanonTitleCardGERTex" +static const ALIGN_ASSET(2) char gPhantomGanonTitleCardGERTex[] = dgPhantomGanonTitleCardGERTex; + +#define dgPhantomGanonTitleCardFRATex "__OTR__textures/object_fhg/gPhantomGanonTitleCardFRATex" +static const ALIGN_ASSET(2) char gPhantomGanonTitleCardFRATex[] = dgPhantomGanonTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_ganon.h b/soh/assets/textures/boss_title_cards/object_ganon.h index d941ea335..55ee44622 100644 --- a/soh/assets/textures/boss_title_cards/object_ganon.h +++ b/soh/assets/textures/boss_title_cards/object_ganon.h @@ -1,23 +1,12 @@ #pragma once -#define dgGanondorfTitleCardENGTex "__OTR__textures/object_ganon/gGanondorfTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanondorfTitleCardENGTex[] = dgGanondorfTitleCardENGTex; -#else -static const char gGanondorfTitleCardENGTex[] __attribute__((aligned (2))) = dgGanondorfTitleCardENGTex; -#endif - -#define dgGanondorfTitleCardGERTex "__OTR__textures/object_ganon/gGanondorfTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanondorfTitleCardGERTex[] = dgGanondorfTitleCardGERTex; -#else -static const char gGanondorfTitleCardGERTex[] __attribute__((aligned (2))) = dgGanondorfTitleCardGERTex; -#endif - -#define dgGanondorfTitleCardFRATex "__OTR__textures/object_ganon/gGanondorfTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanondorfTitleCardFRATex[] = dgGanondorfTitleCardFRATex; -#else -static const char gGanondorfTitleCardFRATex[] __attribute__((aligned (2))) = dgGanondorfTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgGanondorfTitleCardENGTex "__OTR__textures/object_ganon/gGanondorfTitleCardENGTex" +static const ALIGN_ASSET(2) char gGanondorfTitleCardENGTex[] = dgGanondorfTitleCardENGTex; + +#define dgGanondorfTitleCardGERTex "__OTR__textures/object_ganon/gGanondorfTitleCardGERTex" +static const ALIGN_ASSET(2) char gGanondorfTitleCardGERTex[] = dgGanondorfTitleCardGERTex; + +#define dgGanondorfTitleCardFRATex "__OTR__textures/object_ganon/gGanondorfTitleCardFRATex" +static const ALIGN_ASSET(2) char gGanondorfTitleCardFRATex[] = dgGanondorfTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_ganon2.h b/soh/assets/textures/boss_title_cards/object_ganon2.h index fe052cf10..2b9a7277f 100644 --- a/soh/assets/textures/boss_title_cards/object_ganon2.h +++ b/soh/assets/textures/boss_title_cards/object_ganon2.h @@ -1,23 +1,12 @@ #pragma once -#define dgGanonTitleCardENGTex "__OTR__textures/object_ganon2/gGanonTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanonTitleCardENGTex[] = dgGanonTitleCardENGTex; -#else -static const char gGanonTitleCardENGTex[] __attribute__((aligned (2))) = dgGanonTitleCardENGTex; -#endif - -#define dgGanonTitleCardGERTex "__OTR__textures/object_ganon2/gGanonTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanonTitleCardGERTex[] = dgGanonTitleCardGERTex; -#else -static const char gGanonTitleCardGERTex[] __attribute__((aligned (2))) = dgGanonTitleCardGERTex; -#endif - -#define dgGanonTitleCardFRATex "__OTR__textures/object_ganon2/gGanonTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGanonTitleCardFRATex[] = dgGanonTitleCardFRATex; -#else -static const char gGanonTitleCardFRATex[] __attribute__((aligned (2))) = dgGanonTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgGanonTitleCardENGTex "__OTR__textures/object_ganon2/gGanonTitleCardENGTex" +static const ALIGN_ASSET(2) char gGanonTitleCardENGTex[] = dgGanonTitleCardENGTex; + +#define dgGanonTitleCardGERTex "__OTR__textures/object_ganon2/gGanonTitleCardGERTex" +static const ALIGN_ASSET(2) char gGanonTitleCardGERTex[] = dgGanonTitleCardGERTex; + +#define dgGanonTitleCardFRATex "__OTR__textures/object_ganon2/gGanonTitleCardFRATex" +static const ALIGN_ASSET(2) char gGanonTitleCardFRATex[] = dgGanonTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_goma.h b/soh/assets/textures/boss_title_cards/object_goma.h index bd6f5792f..b4aa348a5 100644 --- a/soh/assets/textures/boss_title_cards/object_goma.h +++ b/soh/assets/textures/boss_title_cards/object_goma.h @@ -1,23 +1,12 @@ #pragma once -#define dgGohmaTitleCardENGTex "__OTR__textures/object_goma/gGohmaTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGohmaTitleCardENGTex[] = dgGohmaTitleCardENGTex; -#else -static const char gGohmaTitleCardENGTex[] __attribute__((aligned (2))) = dgGohmaTitleCardENGTex; -#endif - -#define dgGohmaTitleCardGERTex "__OTR__textures/object_goma/gGohmaTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGohmaTitleCardGERTex[] = dgGohmaTitleCardGERTex; -#else -static const char gGohmaTitleCardGERTex[] __attribute__((aligned (2))) = dgGohmaTitleCardGERTex; -#endif - -#define dgGohmaTitleCardFRATex "__OTR__textures/object_goma/gGohmaTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gGohmaTitleCardFRATex[] = dgGohmaTitleCardFRATex; -#else -static const char gGohmaTitleCardFRATex[] __attribute__((aligned (2))) = dgGohmaTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgGohmaTitleCardENGTex "__OTR__textures/object_goma/gGohmaTitleCardENGTex" +static const ALIGN_ASSET(2) char gGohmaTitleCardENGTex[] = dgGohmaTitleCardENGTex; + +#define dgGohmaTitleCardGERTex "__OTR__textures/object_goma/gGohmaTitleCardGERTex" +static const ALIGN_ASSET(2) char gGohmaTitleCardGERTex[] = dgGohmaTitleCardGERTex; + +#define dgGohmaTitleCardFRATex "__OTR__textures/object_goma/gGohmaTitleCardFRATex" +static const ALIGN_ASSET(2) char gGohmaTitleCardFRATex[] = dgGohmaTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_kingdodongo.h b/soh/assets/textures/boss_title_cards/object_kingdodongo.h index 683ebd575..f911f3467 100644 --- a/soh/assets/textures/boss_title_cards/object_kingdodongo.h +++ b/soh/assets/textures/boss_title_cards/object_kingdodongo.h @@ -1,23 +1,12 @@ #pragma once -#define dgKingDodongoTitleCardENGTex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gKingDodongoTitleCardENGTex[] = dgKingDodongoTitleCardENGTex; -#else -static const char gKingDodongoTitleCardENGTex[] __attribute__((aligned (2))) = dgKingDodongoTitleCardENGTex; -#endif - -#define dgKingDodongoTitleCardGERTex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gKingDodongoTitleCardGERTex[] = dgKingDodongoTitleCardGERTex; -#else -static const char gKingDodongoTitleCardGERTex[] __attribute__((aligned (2))) = dgKingDodongoTitleCardGERTex; -#endif - -#define dgKingDodongoTitleCardFRATex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gKingDodongoTitleCardFRATex[] = dgKingDodongoTitleCardFRATex; -#else -static const char gKingDodongoTitleCardFRATex[] __attribute__((aligned (2))) = dgKingDodongoTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgKingDodongoTitleCardENGTex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardENGTex" +static const ALIGN_ASSET(2) char gKingDodongoTitleCardENGTex[] = dgKingDodongoTitleCardENGTex; + +#define dgKingDodongoTitleCardGERTex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardGERTex" +static const ALIGN_ASSET(2) char gKingDodongoTitleCardGERTex[] = dgKingDodongoTitleCardGERTex; + +#define dgKingDodongoTitleCardFRATex "__OTR__textures/object_kingdodongo/gKingDodongoTitleCardFRATex" +static const ALIGN_ASSET(2) char gKingDodongoTitleCardFRATex[] = dgKingDodongoTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_mo.h b/soh/assets/textures/boss_title_cards/object_mo.h index 56bd90c73..acd0da7d8 100644 --- a/soh/assets/textures/boss_title_cards/object_mo.h +++ b/soh/assets/textures/boss_title_cards/object_mo.h @@ -1,23 +1,12 @@ #pragma once -#define dgMorphaTitleCardENGTex "__OTR__textures/object_mo/gMorphaTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gMorphaTitleCardENGTex[] = dgMorphaTitleCardENGTex; -#else -static const char gMorphaTitleCardENGTex[] __attribute__((aligned (2))) = dgMorphaTitleCardENGTex; -#endif - -#define dgMorphaTitleCardGERTex "__OTR__textures/object_mo/gMorphaTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gMorphaTitleCardGERTex[] = dgMorphaTitleCardGERTex; -#else -static const char gMorphaTitleCardGERTex[] __attribute__((aligned (2))) = dgMorphaTitleCardGERTex; -#endif - -#define dgMorphaTitleCardFRATex "__OTR__textures/object_mo/gMorphaTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gMorphaTitleCardFRATex[] = dgMorphaTitleCardFRATex; -#else -static const char gMorphaTitleCardFRATex[] __attribute__((aligned (2))) = dgMorphaTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgMorphaTitleCardENGTex "__OTR__textures/object_mo/gMorphaTitleCardENGTex" +static const ALIGN_ASSET(2) char gMorphaTitleCardENGTex[] = dgMorphaTitleCardENGTex; + +#define dgMorphaTitleCardGERTex "__OTR__textures/object_mo/gMorphaTitleCardGERTex" +static const ALIGN_ASSET(2) char gMorphaTitleCardGERTex[] = dgMorphaTitleCardGERTex; + +#define dgMorphaTitleCardFRATex "__OTR__textures/object_mo/gMorphaTitleCardFRATex" +static const ALIGN_ASSET(2) char gMorphaTitleCardFRATex[] = dgMorphaTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_sst.h b/soh/assets/textures/boss_title_cards/object_sst.h index d15eca871..ad6b3e03f 100644 --- a/soh/assets/textures/boss_title_cards/object_sst.h +++ b/soh/assets/textures/boss_title_cards/object_sst.h @@ -1,23 +1,12 @@ #pragma once -#define dgBongoTitleCardENGTex "__OTR__textures/object_sst/gBongoTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBongoTitleCardENGTex[] = dgBongoTitleCardENGTex; -#else -static const char gBongoTitleCardENGTex[] __attribute__((aligned (2))) = dgBongoTitleCardENGTex; -#endif - -#define dgBongoTitleCardGERTex "__OTR__textures/object_sst/gBongoTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBongoTitleCardGERTex[] = dgBongoTitleCardGERTex; -#else -static const char gBongoTitleCardGERTex[] __attribute__((aligned (2))) = dgBongoTitleCardGERTex; -#endif - -#define dgBongoTitleCardFRATex "__OTR__textures/object_sst/gBongoTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gBongoTitleCardFRATex[] = dgBongoTitleCardFRATex; -#else -static const char gBongoTitleCardFRATex[] __attribute__((aligned (2))) = dgBongoTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgBongoTitleCardENGTex "__OTR__textures/object_sst/gBongoTitleCardENGTex" +static const ALIGN_ASSET(2) char gBongoTitleCardENGTex[] = dgBongoTitleCardENGTex; + +#define dgBongoTitleCardGERTex "__OTR__textures/object_sst/gBongoTitleCardGERTex" +static const ALIGN_ASSET(2) char gBongoTitleCardGERTex[] = dgBongoTitleCardGERTex; + +#define dgBongoTitleCardFRATex "__OTR__textures/object_sst/gBongoTitleCardFRATex" +static const ALIGN_ASSET(2) char gBongoTitleCardFRATex[] = dgBongoTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/textures/boss_title_cards/object_tw.h b/soh/assets/textures/boss_title_cards/object_tw.h index fd9f156ae..39c070141 100644 --- a/soh/assets/textures/boss_title_cards/object_tw.h +++ b/soh/assets/textures/boss_title_cards/object_tw.h @@ -1,23 +1,12 @@ #pragma once -#define dgTwinrovaTitleCardENGTex "__OTR__textures/object_tw/gTwinrovaTitleCardENGTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gTwinrovaTitleCardENGTex[] = dgTwinrovaTitleCardENGTex; -#else -static const char gTwinrovaTitleCardENGTex[] __attribute__((aligned (2))) = dgTwinrovaTitleCardENGTex; -#endif - -#define dgTwinrovaTitleCardGERTex "__OTR__textures/object_tw/gTwinrovaTitleCardGERTex" -#ifdef _WIN32 -static const __declspec(align(2)) char gTwinrovaTitleCardGERTex[] = dgTwinrovaTitleCardGERTex; -#else -static const char gTwinrovaTitleCardGERTex[] __attribute__((aligned (2))) = dgTwinrovaTitleCardGERTex; -#endif - -#define dgTwinrovaTitleCardFRATex "__OTR__textures/object_tw/gTwinrovaTitleCardFRATex" -#ifdef _WIN32 -static const __declspec(align(2)) char gTwinrovaTitleCardFRATex[] = dgTwinrovaTitleCardFRATex; -#else -static const char gTwinrovaTitleCardFRATex[] __attribute__((aligned (2))) = dgTwinrovaTitleCardFRATex; -#endif - +#include "align_asset_macro.h" + +#define dgTwinrovaTitleCardENGTex "__OTR__textures/object_tw/gTwinrovaTitleCardENGTex" +static const ALIGN_ASSET(2) char gTwinrovaTitleCardENGTex[] = dgTwinrovaTitleCardENGTex; + +#define dgTwinrovaTitleCardGERTex "__OTR__textures/object_tw/gTwinrovaTitleCardGERTex" +static const ALIGN_ASSET(2) char gTwinrovaTitleCardGERTex[] = dgTwinrovaTitleCardGERTex; + +#define dgTwinrovaTitleCardFRATex "__OTR__textures/object_tw/gTwinrovaTitleCardFRATex" +static const ALIGN_ASSET(2) char gTwinrovaTitleCardFRATex[] = dgTwinrovaTitleCardFRATex; \ No newline at end of file diff --git a/soh/assets/xml/GC_MQ_D/textures/boss_title_cards.xml b/soh/assets/xml/GC_MQ_D/textures/boss_title_cards.xml new file mode 100644 index 000000000..3667d2bdf --- /dev/null +++ b/soh/assets/xml/GC_MQ_D/textures/boss_title_cards.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/soh/assets/xml/GC_NMQ_D/textures/boss_title_cards.xml b/soh/assets/xml/GC_NMQ_D/textures/boss_title_cards.xml new file mode 100644 index 000000000..3667d2bdf --- /dev/null +++ b/soh/assets/xml/GC_NMQ_D/textures/boss_title_cards.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/soh/assets/xml/GC_NMQ_PAL_F/textures/boss_title_cards.xml b/soh/assets/xml/GC_NMQ_PAL_F/textures/boss_title_cards.xml new file mode 100644 index 000000000..3667d2bdf --- /dev/null +++ b/soh/assets/xml/GC_NMQ_PAL_F/textures/boss_title_cards.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/soh/include/functions.h b/soh/include/functions.h index 42aab2813..7854b9835 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -28,6 +28,7 @@ f64 sqrt(f64 d); //#pragma intrinsic(sqrt) void gSPSegment(void* value, int segNum, uintptr_t target); +void gSPSegmentLoadRes(void* value, int segNum, uintptr_t target); 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); @@ -840,7 +841,7 @@ void CollisionCheck_SpawnShieldParticlesMetal2(PlayState* play, Vec3f* v); void CollisionCheck_SpawnShieldParticlesWood(PlayState* play, Vec3f* b, Vec3f* actorPos); s32 CollisionCheck_CylSideVsLineSeg(f32 radius, f32 height, f32 offset, Vec3f* actorPos, Vec3f* itemPos, Vec3f* itemProjPos, Vec3f* out1, Vec3f* out2); -u8 CollisionCheck_GetSwordDamage(s32 dmgFlags); +u8 CollisionCheck_GetSwordDamage(s32 dmgFlags, PlayState* play); void SaveContext_Init(void); s32 func_800635D0(s32); void func_800636C0(void); diff --git a/soh/include/tables/actor_table.h b/soh/include/tables/actor_table.h index cdbebbc63..64d9099e8 100644 --- a/soh/include/tables/actor_table.h +++ b/soh/include/tables/actor_table.h @@ -481,3 +481,4 @@ /* 0x01D4 */ DEFINE_ACTOR(En_Mm2, ACTOR_EN_MM2, ALLOCTYPE_NORMAL) /* 0x01D5 */ DEFINE_ACTOR(Bg_Jya_Block, ACTOR_BG_JYA_BLOCK, ALLOCTYPE_NORMAL) /* 0x01D6 */ DEFINE_ACTOR(Obj_Warp2block, ACTOR_OBJ_WARP2BLOCK, ALLOCTYPE_NORMAL) +/* 0x01D7 */ DEFINE_ACTOR(En_Partner, ACTOR_EN_PARTNER, ALLOCTYPE_NORMAL) \ No newline at end of file diff --git a/soh/include/z64.h b/soh/include/z64.h index 0e2b147ff..09332cd94 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -624,12 +624,15 @@ typedef enum { /* 10 */ TEXT_STATE_AWAITING_NEXT } TextState; +// Increased char buffer because texture paths could be bigger than (16 * 16 / 2) +#define FONT_CHAR_MULTIPLIER 256 + typedef struct { /* 0x0000 */ uintptr_t msgOffset; /* 0x0004 */ u32 msgLength; - /* 0x0008 */ u8 charTexBuf[FONT_CHAR_TEX_SIZE * 120]; - /* 0x3C08 */ u8 iconBuf[FONT_CHAR_TEX_SIZE]; - /* 0x3C88 */ u8 fontBuf[FONT_CHAR_TEX_SIZE * 320]; + /* 0x0008 */ u8 charTexBuf[FONT_CHAR_TEX_SIZE * FONT_CHAR_MULTIPLIER]; + /* 0x3C08 */ u8 iconBuf[FONT_CHAR_TEX_SIZE * FONT_CHAR_MULTIPLIER]; + /* 0x3C88 */ u8 fontBuf[FONT_CHAR_TEX_SIZE * FONT_CHAR_MULTIPLIER]; union { /* 0xDC88 */ char msgBuf[1280]; /* 0xDC88 */ u16 msgBufWide[640]; @@ -737,9 +740,10 @@ typedef struct { /* 0x0128 */ Vtx* actionVtx; /* 0x012C */ Vtx* beatingHeartVtx; /* 0x0130 */ u8* parameterSegment; - /* 0x0134 */ u8* doActionSegment; + /* 0x0134 */ char** doActionSegment; /* 0x0138 */ u8* iconItemSegment; - /* 0x013C */ u8* mapSegment; + /* 0x013C */ char** mapSegment; + char** mapSegmentName; /* 0x0140 */ u8 mapPalette[32]; /* 0x0160 */ DmaRequest dmaRequest_160; /* 0x0180 */ DmaRequest dmaRequest_180; diff --git a/soh/include/z64player.h b/soh/include/z64player.h index 1d3c3e971..7ce699678 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -678,6 +678,8 @@ typedef struct Player { // Upstream TODO: Rename this to make it more obvious it is apart of an enhancement /* */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still? // #endregion + u8 ivanFloating; + u8 ivanDamageMultiplier; } Player; // size = 0xA94 #endif diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index 952186786..981bc1840 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef __SWITCH__ #include @@ -28,6 +29,7 @@ #include "soh/SaveManager.h" #include "OTRGlobals.h" #include "soh/Enhancements/presets.h" +#include "soh/resource/type/Skeleton.h" #ifdef ENABLE_CROWD_CONTROL #include "Enhancements/crowd-control/CrowdControl.h" @@ -36,6 +38,7 @@ #include "Enhancements/game-interactor/GameInteractor.h" #include "Enhancements/cosmetics/authenticGfxPatches.h" +bool ShouldClearTextureCacheAtEndOfFrame = false; bool isBetaQuestEnabled = false; extern "C" { @@ -791,6 +794,34 @@ namespace GameMenuBar { if (ImGui::BeginMenu("Graphics")) { + if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", true, false)) { + ShouldClearTextureCacheAtEndOfFrame = true; + } + UIWidgets::PaddedEnhancementCheckbox("Disable LOD", "gDisableLOD", true, false); + UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); + if (UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false)) { + if (CVarGetInteger("gDisableDrawDistance", 0) == 0) { + CVarSetInteger("gDisableKokiriDrawDistance", 0); + } + } + UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); + if (CVarGetInteger("gDisableDrawDistance", 0) == 1) { + UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false); + UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); + } + UIWidgets::PaddedEnhancementCheckbox("N64 Mode", "gLowResMode", true, false); + UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); + UIWidgets::PaddedEnhancementCheckbox("Glitch line-up tick", "gDrawLineupTick", true, false); + UIWidgets::Tooltip("Displays a tick in the top center of the screen to help with glitch line-ups in SoH, as traditional UI based line-ups do not work outside of 4:3"); + UIWidgets::PaddedEnhancementCheckbox("Enable 3D Dropped items/projectiles", "gNewDrops", true, false); + UIWidgets::Tooltip("Change most 2D items and projectiles on the overworld to their 3D versions"); + UIWidgets::PaddedEnhancementCheckbox("Disable Black Bar Letterboxes", "gDisableBlackBars", true, false); + UIWidgets::Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that were covered up by the black bars\nPlease disable this setting before reporting a bug"); + UIWidgets::PaddedEnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon", true, false); + UIWidgets::Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); + UIWidgets::PaddedEnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon", true, false); + UIWidgets::Tooltip("Always shows dungeon entrance icons on the minimap"); + UIWidgets::Spacer(0); if (ImGui::BeginMenu("Animated Link in Pause Menu")) { ImGui::Text("Rotation"); UIWidgets::EnhancementRadioButton("Disabled", "gPauseLiveLinkRotation", 0); @@ -834,37 +865,14 @@ namespace GameMenuBar { ImGui::EndMenu(); } - UIWidgets::PaddedEnhancementCheckbox("Disable LOD", "gDisableLOD", true, false); - UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); - if (UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false)) { - if (CVarGetInteger("gDisableDrawDistance", 0) == 0) { - CVarSetInteger("gDisableKokiriDrawDistance", 0); - } - } - UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); - if (CVarGetInteger("gDisableDrawDistance", 0) == 1) { - UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false); - UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); - } - UIWidgets::PaddedEnhancementCheckbox("N64 Mode", "gLowResMode", true, false); - UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); - UIWidgets::PaddedEnhancementCheckbox("Glitch line-up tick", "gDrawLineupTick", true, false); - UIWidgets::Tooltip("Displays a tick in the top center of the screen to help with glitch line-ups in SoH, as traditional UI based line-ups do not work outside of 4:3"); - UIWidgets::PaddedEnhancementCheckbox("Enable 3D Dropped items/projectiles", "gNewDrops", true, false); - UIWidgets::Tooltip("Change most 2D items and projectiles on the overworld to their 3D versions"); - UIWidgets::PaddedEnhancementCheckbox("Disable Black Bar Letterboxes", "gDisableBlackBars", true, false); - UIWidgets::Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that were covered up by the black bars\nPlease disable this setting before reporting a bug"); - UIWidgets::PaddedEnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon", true, false); - UIWidgets::Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); - UIWidgets::PaddedEnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon", true, false); - UIWidgets::Tooltip("Always shows dungeon entrance icons on the minimap"); UIWidgets::PaddedText("Fix Vanishing Paths", true, false); UIWidgets::EnhancementCombobox("gDirtPathFix", zFightingOptions, 0); UIWidgets::Tooltip("Disabled: Paths vanish more the higher the resolution (Z-fighting is based on resolution)\n" "Consistent: Certain paths vanish the same way in all resolutions\n" "No Vanish: Paths do not vanish, Link seems to sink in to some paths\n" "This might affect other decal effects\n"); - + UIWidgets::PaddedEnhancementSliderInt("Text Spacing: %d", "##TEXTSPACING", "gTextSpacing", 4, 6, "", 6, true, true, true); + UIWidgets::Tooltip("Space between text characters (useful for HD font textures)"); ImGui::EndMenu(); } @@ -922,9 +930,9 @@ namespace GameMenuBar { if (ImGui::BeginMenu("Restoration")) { - UIWidgets::PaddedEnhancementCheckbox("Hide Build Info", "gHideBuildInfo", true, false); - UIWidgets::Tooltip("Hides the game version and build details in the boot logo start screen"); - UIWidgets::EnhancementCheckbox("Red Ganon blood", "gRedGanonBlood"); + UIWidgets::EnhancementCheckbox("Authentic Logo Screen", "gAuthenticLogo"); + UIWidgets::Tooltip("Hide the game version and build details and display the authentic model and texture on the boot logo start screen"); + UIWidgets::PaddedEnhancementCheckbox("Red Ganon blood", "gRedGanonBlood", true, false); UIWidgets::Tooltip("Restore the original red blood from NTSC 1.0/1.1. Disable for green blood"); UIWidgets::PaddedEnhancementCheckbox("Fish while hovering", "gHoverFishing", true, false); UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows casting the Fishing Rod while using the Hover Boots"); @@ -941,7 +949,30 @@ namespace GameMenuBar { ImGui::EndMenu(); } - UIWidgets::PaddedSeparator(); + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Extra Modes")) { + UIWidgets::PaddedEnhancementCheckbox("Ivan the Fairy (Coop Mode)", "gIvanCoopModeEnabled", true, false); + UIWidgets::Tooltip("Enables Ivan the Fairy upon the next map change. Player 2 can control Ivan and " + "press the C-Buttons to use items and mess with Player 1!"); + + UIWidgets::Spacer(0); + + UIWidgets::PaddedEnhancementCheckbox("Rupee Dash Mode", "gRupeeDash", true, false); + + if (CVarGetInteger("gRupeeDash", 0)) { + UIWidgets::Tooltip("Rupees reduced over time, Link suffers damage when the count hits 0."); + UIWidgets::PaddedEnhancementSliderInt( + "Rupee Dash Interval: %d", "##DashInterval", "gDashInterval", 3, 5, "", 5, true, true, false, + !CVarGetInteger("gRupeeDash", 0), + "This option is disabled because \"Rupee Dash Mode\" is turned off"); + UIWidgets::Tooltip("Interval between Rupee reduction in Rupee Dash Mode"); + } + + ImGui::EndMenu(); + } + + UIWidgets::PaddedSeparator(false, true); // Autosave enum value of 1 is the default in presets and the old checkbox "on" state for backwards compatibility UIWidgets::PaddedText("Autosave", false, true); diff --git a/soh/soh/GbiWrap.cpp b/soh/soh/GbiWrap.cpp index e06f802bc..074a638e7 100644 --- a/soh/soh/GbiWrap.cpp +++ b/soh/soh/GbiWrap.cpp @@ -21,6 +21,7 @@ uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); size_t GetResourceTexSizeByName(const char* name); char* ResourceMgr_LoadTexOrDListByName(char* filePath); +char* ResourceMgr_LoadIfDListByName(char* filePath); char* ResourceMgr_LoadPlayerAnimByName(char* animPath); char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc); Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc); @@ -30,6 +31,7 @@ Vtx* ResourceMgr_LoadVtxByName(char* path); CollisionHeader* ResourceMgr_LoadColByName(char* path); uint64_t GetPerfCounter(); int ResourceMgr_OTRSigCheck(char* imgData); +void ResourceMgr_PushCurrentDirectory(char* path); } @@ -39,8 +41,30 @@ extern "C" void gSPSegment(void* value, int segNum, uintptr_t target) { int res = ResourceMgr_OTRSigCheck(imgData); - if (res) + // OTRTODO: Disabled for now to fix an issue with HD Textures. + // With HD textures, we need to pass the path to F3D, not the raw texture data. + // Otherwise the needed metadata is not available for proper rendering... + // This should *not* cause any crashes, but some testing may be needed... + // UPDATE: To maintain compatability it will still do the old behavior if the resource is a display list. + // That should not affect HD textures. + if (res) { + uintptr_t desiredTarget = (uintptr_t)ResourceMgr_LoadIfDListByName(imgData); + + if (desiredTarget != NULL) + target = desiredTarget; + } + + __gSPSegment(value, segNum, target); +} + +extern "C" void gSPSegmentLoadRes(void* value, int segNum, uintptr_t target) { + char* imgData = (char*)target; + + int res = ResourceMgr_OTRSigCheck(imgData); + + if (res) { target = (uintptr_t)ResourceMgr_LoadTexOrDListByName(imgData); + } __gSPSegment(value, segNum, target); } @@ -57,8 +81,12 @@ extern "C" void gDPSetTextureImageFB(Gfx* pkt, u32 format, u32 size, u32 width, extern "C" void gSPDisplayList(Gfx* pkt, Gfx* dl) { char* imgData = (char*)dl; - if (ResourceMgr_OTRSigCheck(imgData) == 1) + if (ResourceMgr_OTRSigCheck(imgData) == 1) { + + //ResourceMgr_PushCurrentDirectory(imgData); + //gsSPPushCD(pkt++, imgData); dl = ResourceMgr_LoadGfxByName(imgData); + } __gSPDisplayList(pkt, dl); } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 988810659..a3940504a 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1,4 +1,4 @@ -#include "OTRGlobals.h" +#include "OTRGlobals.h" #include "OTRAudio.h" #include #include @@ -694,7 +694,7 @@ extern "C" uint32_t GetGIID(uint32_t itemID) { } extern "C" void OTRExtScanner() { - auto lst = *OTRGlobals::Instance->context->GetResourceManager()->GetArchive()->ListFiles("*.*").get(); + auto lst = *OTRGlobals::Instance->context->GetResourceManager()->GetArchive()->ListFiles("*").get(); for (auto& rPath : lst) { std::vector raw = StringHelper::Split(rPath, "."); @@ -834,14 +834,16 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) { OTRGlobals::Instance->context->MainLoop(run_one_game_iter); } +extern bool ShouldClearTextureCacheAtEndOfFrame; + extern "C" void Graph_StartFrame() { #ifndef __WIIU__ - // Why -1? + using Ship::KbScancode; int32_t dwScancode = OTRGlobals::Instance->context->GetLastScancode(); OTRGlobals::Instance->context->SetLastScancode(-1); - switch (dwScancode - 1) { - case SDL_SCANCODE_F5: { + switch (dwScancode) { + case KbScancode::LUS_KB_F5: { const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); const SaveStateReturn stateReturn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); @@ -858,7 +860,7 @@ extern "C" void Graph_StartFrame() { } break; } - case SDL_SCANCODE_F6: { + case KbScancode::LUS_KB_F6: { unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); slot++; if (slot > 5) { @@ -868,7 +870,7 @@ extern "C" void Graph_StartFrame() { SPDLOG_INFO("Set SaveState slot to {}.", slot); break; } - case SDL_SCANCODE_F7: { + case KbScancode::LUS_KB_F7: { const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); const SaveStateReturn stateReturn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); @@ -892,9 +894,16 @@ extern "C" void Graph_StartFrame() { break; } - case SDL_SCANCODE_F9: { + case KbScancode::LUS_KB_F9: { // Toggle TTS CVarSetInteger("gA11yTTS", !CVarGetInteger("gA11yTTS", 0)); + break; + } + case KbScancode::LUS_KB_TAB: { + // Toggle HD Assets + CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0)); + ShouldClearTextureCacheAtEndOfFrame = true; + break; } } #endif @@ -963,6 +972,12 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { } } + if (ShouldClearTextureCacheAtEndOfFrame) { + gfx_texture_cache_clear(); + Ship::SkeletonPatcher::UpdateSkeletons(); + ShouldClearTextureCacheAtEndOfFrame = false; + } + // OTRTODO: FIGURE OUT END FRAME POINT /* if (OTRGlobals::Instance->context->lastScancode != -1) OTRGlobals::Instance->context->lastScancode = -1;*/ @@ -1036,6 +1051,7 @@ extern "C" void ResourceMgr_DirtyDirectory(const char* resName) { } // OTRTODO: There is probably a more elegant way to go about this... +// Kenix: This is definitely leaking memory when it's called. extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) { auto lst = OTRGlobals::Instance->context->GetResourceManager()->GetArchive()->ListFiles(searchMask); char** result = (char**)malloc(lst->size() * sizeof(char*)); @@ -1051,6 +1067,15 @@ extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) return result; } +extern "C" uint8_t ResourceMgr_FileExists(const char* filePath) { + std::string path = filePath; + if(path.substr(0, 7) == "__OTR__"){ + path = path.substr(7); + } + + return ExtensionCache.contains(path); +} + extern "C" void ResourceMgr_LoadFile(const char* resName) { OTRGlobals::Instance->context->GetResourceManager()->LoadResource(resName); } @@ -1095,7 +1120,7 @@ extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) { return res->InitData->Type == Ship::ResourceType::SOH_Background; } -extern "C" char* ResourceMgr_LoadJPEG(char* data, int dataSize) +extern "C" char* ResourceMgr_LoadJPEG(char* data, size_t dataSize) { static char* finalBuffer = 0; @@ -1149,6 +1174,15 @@ extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) { } } +extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { + auto res = GetResourceByNameHandlingMQ(filePath); + + if (res->InitData->Type == Ship::ResourceType::DisplayList) + return (char*)&((std::static_pointer_cast(res))->Instructions[0]); + + return nullptr; +} + extern "C" Sprite* GetSeedTexture(uint8_t index) { return OTRGlobals::Instance->gRandomizer->GetSeedTexture(index); } @@ -1159,6 +1193,11 @@ extern "C" char* ResourceMgr_LoadPlayerAnimByName(const char* animPath) { return (char*)&anim->limbRotData[0]; } +extern "C" void ResourceMgr_PushCurrentDirectory(char* path) +{ + gfx_push_current_dir(path); +} + extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) { auto res = std::static_pointer_cast(GetResourceByNameHandlingMQ(path)); @@ -1351,8 +1390,29 @@ extern "C" AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path) { return (AnimationHeaderCommon*)GetResourceDataByName(path, false); } -extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path) { - return (SkeletonHeader*)GetResourceDataByName(path, false); +extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime) +{ + SkeletonHeader* skelHeader = (SkeletonHeader*)GetResourceDataByName(path, false); + + // This function is only called when a skeleton is initialized. + // Therefore we can take this oppurtunity to take note of the Skeleton that is created... + if (skelAnime != nullptr) { + auto stringPath = std::string(path); + Ship::SkeletonPatcher::RegisterSkeleton(stringPath, skelAnime); + } + + + return skelHeader; +} + +extern "C" void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime) { + if (skelAnime != nullptr) + Ship::SkeletonPatcher::UnregisterSkeleton(skelAnime); +} + +extern "C" void ResourceMgr_ClearSkeletons(SkelAnime* skelAnime) { + if (skelAnime != nullptr) + Ship::SkeletonPatcher::ClearSkeletons(); } extern "C" s32* ResourceMgr_LoadCSByName(const char* path) { @@ -1916,3 +1976,7 @@ extern "C" void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex) { extern "C" void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex) { SetLastEntranceOverrideForTracker(entranceIndex); } + +extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement) { + gfx_register_blended_texture(name, mask, replacement); +} diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 830d4f9e3..d1e69843f 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -60,11 +60,12 @@ uint32_t ResourceMgr_GetNumGameVersions(); uint32_t ResourceMgr_GetGameVersion(int index); void ResourceMgr_LoadDirectory(const char* resName); char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize); +uint8_t ResourceMgr_FileExists(const char* resName); char* GetResourceDataByNameHandlingMQ(const char* path); void ResourceMgr_LoadFile(const char* resName); char* ResourceMgr_LoadFileFromDisk(const char* filePath); uint8_t ResourceMgr_ResourceIsBackground(char* texPath); -char* ResourceMgr_LoadJPEG(char* data, int dataSize); +char* ResourceMgr_LoadJPEG(char* data, size_t dataSize); uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); char* ResourceMgr_LoadTexOrDListByName(const char* filePath); @@ -87,7 +88,9 @@ void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size); void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size); uint64_t GetPerfCounter(); -struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path); +struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime); +void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime); +void ResourceMgr_ClearSkeletons(); s32* ResourceMgr_LoadCSByName(const char* path); int ResourceMgr_OTRSigCheck(char* imgData); uint64_t osGetTime(void); @@ -139,6 +142,7 @@ void Entrance_ClearEntranceTrackingData(void); void Entrance_InitEntranceTrackingData(void); void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex); void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex); +void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); uint32_t GetGIID(uint32_t itemID); #endif diff --git a/soh/soh/resource/importer/SkeletonFactory.cpp b/soh/soh/resource/importer/SkeletonFactory.cpp index 3bca7873d..a10702f8a 100644 --- a/soh/soh/resource/importer/SkeletonFactory.cpp +++ b/soh/soh/resource/importer/SkeletonFactory.cpp @@ -26,6 +26,28 @@ std::shared_ptr SkeletonFactory::ReadResource(std::shared_ptr SkeletonFactory::ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) { + auto resource = std::make_shared(resourceMgr, initData); + std::shared_ptr factory = nullptr; + + switch ((Version)resource->InitData->ResourceVersion) { + case Version::Deckard: + factory = std::make_shared(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton with version {}", resource->InitData->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + void SkeletonFactoryV0::ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) { @@ -77,4 +99,59 @@ void SkeletonFactoryV0::ParseFileBinary(std::shared_ptr reader, SPDLOG_ERROR("unknown skeleton type {}", (uint32_t)skeleton->type); } } +void SkeletonFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) +{ + std::shared_ptr skel = std::static_pointer_cast(resource); + + std::string skeletonType = reader->Attribute("Type"); + // std::string skeletonLimbType = reader->Attribute("LimbType"); + int numLimbs = reader->IntAttribute("LimbCount"); + int numDLs = reader->IntAttribute("DisplayListCount"); + + if (skeletonType == "Flex") { + skel->type = SkeletonType::Flex; + } else if (skeletonType == "Curve") { + skel->type = SkeletonType::Curve; + } else if (skeletonType == "Normal") { + skel->type = SkeletonType::Normal; + } + + skel->type = SkeletonType::Flex; + skel->limbType = LimbType::LOD; + + // if (skeletonLimbType == "Standard") + // skel->limbType = LimbType::Standard; + // else if (skeletonLimbType == "LOD") + // skel->limbType = LimbType::LOD; + // else if (skeletonLimbType == "Curve") + // skel->limbType = LimbType::Curve; + // else if (skeletonLimbType == "Skin") + // skel->limbType = LimbType::Skin; + // else if (skeletonLimbType == "Legacy") + // Sskel->limbType = LimbType::Legacy; + + auto child = reader->FirstChildElement(); + + skel->limbCount = numLimbs; + skel->dListCount = numDLs; + + while (child != nullptr) { + std::string childName = child->Name(); + + if (childName == "SkeletonLimb") { + std::string limbName = child->Attribute("Path"); + skel->limbTable.push_back(limbName); + + auto limb = GetResourceDataByName(limbName.c_str(), true); + skel->skeletonHeaderSegments.push_back(limb); + } + + child = child->NextSiblingElement(); + } + + skel->skeletonData.flexSkeletonHeader.sh.limbCount = skel->limbCount; + skel->skeletonData.flexSkeletonHeader.sh.segment = (void**)skel->skeletonHeaderSegments.data(); + skel->skeletonData.flexSkeletonHeader.dListCount = skel->dListCount; +} + } // namespace Ship diff --git a/soh/soh/resource/importer/SkeletonFactory.h b/soh/soh/resource/importer/SkeletonFactory.h index 56cb80dad..09e293a97 100644 --- a/soh/soh/resource/importer/SkeletonFactory.h +++ b/soh/soh/resource/importer/SkeletonFactory.h @@ -10,11 +10,16 @@ class SkeletonFactory : public ResourceFactory std::shared_ptr ReadResource(std::shared_ptr resourceMgr, std::shared_ptr initData, std::shared_ptr reader) override; + std::shared_ptr ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) override; }; class SkeletonFactoryV0 : public ResourceVersionFactory { public: void ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) override; }; }; // namespace Ship + diff --git a/soh/soh/resource/importer/SkeletonLimbFactory.cpp b/soh/soh/resource/importer/SkeletonLimbFactory.cpp index 652f2450f..4b3ce4885 100644 --- a/soh/soh/resource/importer/SkeletonLimbFactory.cpp +++ b/soh/soh/resource/importer/SkeletonLimbFactory.cpp @@ -26,6 +26,28 @@ std::shared_ptr SkeletonLimbFactory::ReadResource(std::shared_ptr SkeletonLimbFactory::ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) { + auto resource = std::make_shared(resourceMgr, initData); + std::shared_ptr factory = nullptr; + + switch ((Version)resource->InitData->ResourceVersion) { + case Version::Deckard: + factory = std::make_shared(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton Limb with version {}", resource->InitData->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + void Ship::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) { @@ -190,4 +212,59 @@ void Ship::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr } } } +void SkeletonLimbFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) +{ + std::shared_ptr skelLimb = std::static_pointer_cast(resource); + + std::string limbType = reader->Attribute("Type"); + + // OTRTODO + skelLimb->limbType = LimbType::LOD; + + // skelLimb->legTransX = reader->FloatAttribute("LegTransX"); + // skelLimb->legTransY = reader->FloatAttribute("LegTransY"); + // skelLimb->legTransZ = reader->FloatAttribute("LegTransZ"); + skelLimb->rotX = reader->IntAttribute("RotX"); + skelLimb->rotY = reader->IntAttribute("RotY"); + skelLimb->rotZ = reader->IntAttribute("RotZ"); + + // skelLimb->transX = reader->IntAttribute("TransX"); + // skelLimb->transY = reader->IntAttribute("TransY"); + // skelLimb->transZ = reader->IntAttribute("TransZ"); + + skelLimb->transX = (int)reader->FloatAttribute("LegTransX"); + skelLimb->transY = (int)reader->FloatAttribute("LegTransY"); + skelLimb->transZ = (int)reader->FloatAttribute("LegTransZ"); + + skelLimb->childIndex = reader->IntAttribute("ChildIndex"); + skelLimb->siblingIndex = reader->IntAttribute("SiblingIndex"); + + // skelLimb->childPtr = reader->Attribute("ChildLimb"); + // skelLimb->siblingPtr = reader->Attribute("SiblingLimb"); + skelLimb->dListPtr = reader->Attribute("DisplayList1"); + + if (std::string(reader->Attribute("DisplayList1")) == "gEmptyDL") { + skelLimb->dListPtr = ""; + } + + auto& limbData = skelLimb->limbData; + + limbData.lodLimb.jointPos.x = skelLimb->transX; + limbData.lodLimb.jointPos.y = skelLimb->transY; + limbData.lodLimb.jointPos.z = skelLimb->transZ; + + if (skelLimb->dListPtr != "") { + limbData.lodLimb.dLists[0] = (Gfx*)GetResourceDataByName((const char*)skelLimb->dListPtr.c_str(), true); + } else { + limbData.lodLimb.dLists[0] = nullptr; + } + + limbData.lodLimb.dLists[1] = nullptr; + + limbData.lodLimb.child = skelLimb->childIndex; + limbData.lodLimb.sibling = skelLimb->siblingIndex; + + // skelLimb->dList2Ptr = reader->Attribute("DisplayList2"); +} + } // namespace Ship diff --git a/soh/soh/resource/importer/SkeletonLimbFactory.h b/soh/soh/resource/importer/SkeletonLimbFactory.h index 517ab4a85..6d33b72e0 100644 --- a/soh/soh/resource/importer/SkeletonLimbFactory.h +++ b/soh/soh/resource/importer/SkeletonLimbFactory.h @@ -10,11 +10,16 @@ class SkeletonLimbFactory : public ResourceFactory std::shared_ptr ReadResource(std::shared_ptr resourceMgr, std::shared_ptr initData, std::shared_ptr reader) override; + std::shared_ptr ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) override; }; class SkeletonLimbFactoryV0 : public ResourceVersionFactory { public: void ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) override; }; }; // namespace Ship + diff --git a/soh/soh/resource/importer/TextFactory.cpp b/soh/soh/resource/importer/TextFactory.cpp index a73f350f9..5718de3f2 100644 --- a/soh/soh/resource/importer/TextFactory.cpp +++ b/soh/soh/resource/importer/TextFactory.cpp @@ -28,6 +28,28 @@ std::shared_ptr TextFactory::ReadResource(std::shared_ptr return resource; } +std::shared_ptr TextFactory::ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) { + auto resource = std::make_shared(resourceMgr, initData); + std::shared_ptr factory = nullptr; + + switch ((Version)resource->InitData->ResourceVersion) { + case Version::Deckard: + factory = std::make_shared(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Text with version {}", resource->InitData->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + void Ship::TextFactoryV0::ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) { std::shared_ptr text = std::static_pointer_cast(resource); @@ -46,4 +68,28 @@ void Ship::TextFactoryV0::ParseFileBinary(std::shared_ptr reader, text->messages.push_back(entry); } } +void TextFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) { + std::shared_ptr txt = std::static_pointer_cast(resource); + + auto child = reader->FirstChildElement(); + + while (child != nullptr) { + std::string childName = child->Name(); + + if (childName == "TextEntry") { + MessageEntry entry; + entry.id = child->IntAttribute("ID"); + entry.textboxType = child->IntAttribute("TextboxType"); + entry.textboxYPos = child->IntAttribute("TextboxYPos"); + entry.msg = child->Attribute("Message"); + entry.msg += "\x2"; + + txt->messages.push_back(entry); + int bp = 0; + } + + child = child->NextSiblingElement(); + } +} + } // namespace Ship diff --git a/soh/soh/resource/importer/TextFactory.h b/soh/soh/resource/importer/TextFactory.h index b1eac4a6a..6f67daca7 100644 --- a/soh/soh/resource/importer/TextFactory.h +++ b/soh/soh/resource/importer/TextFactory.h @@ -10,11 +10,16 @@ class TextFactory : public ResourceFactory std::shared_ptr ReadResource(std::shared_ptr resourceMgr, std::shared_ptr initData, std::shared_ptr reader) override; + std::shared_ptr ReadResourceXML(std::shared_ptr resourceMgr, + std::shared_ptr initData, + tinyxml2::XMLElement* reader) override; }; class TextFactoryV0 : public ResourceVersionFactory { public: void ParseFileBinary(std::shared_ptr reader, std::shared_ptr resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr resource) override; }; }; // namespace Ship + diff --git a/soh/soh/resource/type/Skeleton.cpp b/soh/soh/resource/type/Skeleton.cpp index 137041c67..52f5f5a5d 100644 --- a/soh/soh/resource/type/Skeleton.cpp +++ b/soh/soh/resource/type/Skeleton.cpp @@ -1,4 +1,7 @@ +#include "resource/ResourceMgr.h" #include "Skeleton.h" +#include "soh/OTRGlobals.h" +#include "libultraship/libultraship.h" namespace Ship { void* Skeleton::GetPointer() { @@ -17,4 +20,61 @@ size_t Skeleton::GetPointerSize() { return 0; } } + +std::vector SkeletonPatcher::skeletons; + + +void SkeletonPatcher::RegisterSkeleton(std::string& path, SkelAnime* skelAnime) { + SkeletonPatchInfo info; + + info.skelAnime = skelAnime; + + static const std::string sOtr = "__OTR__"; + + if (path.starts_with(sOtr)) { + path = path.substr(sOtr.length()); + } + + // Determine if we're using an alternate skeleton + if (path.starts_with(Ship::Resource::gAltAssetPrefix)) { + info.vanillaSkeletonPath = path.substr(Ship::Resource::gAltAssetPrefix.length(), + path.size() - Ship::Resource::gAltAssetPrefix.length()); + } else { + info.vanillaSkeletonPath = path; + } + + skeletons.push_back(info); +} + +void SkeletonPatcher::UnregisterSkeleton(SkelAnime* skelAnime) { + + // TODO: Should probably just use a dictionary here... + for (int i = 0; i < skeletons.size(); i++) + { + auto skel = skeletons[i]; + + if (skel.skelAnime == skelAnime) { + skeletons.erase(skeletons.begin() + i); + break; + } + } +} +void SkeletonPatcher::ClearSkeletons() +{ + skeletons.clear(); +} + +void SkeletonPatcher::UpdateSkeletons() { + bool isHD = CVarGetInteger("gAltAssets", 0); + for (auto skel : skeletons) + { + Skeleton* newSkel = + (Skeleton*)OTRGlobals::Instance->context->GetResourceManager() + ->LoadResource((isHD ? Ship::Resource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true) + .get(); + + if (newSkel != nullptr) + skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment; + } +} } // namespace Ship diff --git a/soh/soh/resource/type/Skeleton.h b/soh/soh/resource/type/Skeleton.h index eef2bca58..e6f7cd91f 100644 --- a/soh/soh/resource/type/Skeleton.h +++ b/soh/soh/resource/type/Skeleton.h @@ -3,6 +3,7 @@ #include #include "Resource.h" #include "SkeletonLimb.h" +#include namespace Ship { @@ -68,4 +69,23 @@ class Skeleton : public Resource { std::vector limbTable; std::vector skeletonHeaderSegments; }; + +// TODO: CLEAN THIS UP LATER +struct SkeletonPatchInfo +{ + SkelAnime* skelAnime; + std::string vanillaSkeletonPath; +}; + +class SkeletonPatcher { + public: + static void RegisterSkeleton(std::string& path, SkelAnime* skelAnime); + static void UnregisterSkeleton(SkelAnime* skelAnime); + static void ClearSkeletons(); + static void UpdateSkeletons(); + + static std::vector skeletons; +}; + + } // namespace Ship \ No newline at end of file diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index bb3437216..bb51843a4 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -22,6 +22,8 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { return nullptr; // Allocate room for an additional message + // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table is + // already null. MessageTableEntry* table = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * (file->messages.size() + 1)); for (size_t i = 0; i < file->messages.size(); i++) { @@ -29,6 +31,8 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { if (file->messages[i].id == 0x2066) { // Create a new message based on the Owl Text uint32_t kaeporaMsgSize = file->messages[i].msg.size(); + // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table + // is already null. char* kaeporaOg = (char*)malloc(sizeof(char) * kaeporaMsgSize); char* kaeporaPatch = (char*)malloc(sizeof(char) * kaeporaMsgSize); file->messages[i].msg.copy(kaeporaOg, kaeporaMsgSize, 0); @@ -68,25 +72,38 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { _message_0xFFFC_nes = (char*)file->messages[i].msg.c_str(); } - return table; + return table; } extern "C" void OTRMessage_Init() { - sNesMessageEntryTablePtr = OTRMessage_LoadTable("text/nes_message_data_static/nes_message_data_static", true); - sGerMessageEntryTablePtr = OTRMessage_LoadTable("text/ger_message_data_static/ger_message_data_static", false); - sFraMessageEntryTablePtr = OTRMessage_LoadTable("text/fra_message_data_static/fra_message_data_static", false); + // OTRTODO: Added a lot of null checks here so that we don't malloc the table multiple times causing a memory leak. + // We really ought to fix the implementation such that we aren't malloc'ing new tables. + // Once we fix the implementation, remove these NULL checks. + if (sNesMessageEntryTablePtr == NULL) { + sNesMessageEntryTablePtr = OTRMessage_LoadTable("text/nes_message_data_static/nes_message_data_static", true); + } + if (sGerMessageEntryTablePtr == NULL) { + sGerMessageEntryTablePtr = OTRMessage_LoadTable("text/ger_message_data_static/ger_message_data_static", false); + } + if (sFraMessageEntryTablePtr == NULL) { + sFraMessageEntryTablePtr = OTRMessage_LoadTable("text/fra_message_data_static/fra_message_data_static", false); + } - auto file2 = std::static_pointer_cast(OTRGlobals::Instance->context->GetResourceManager()->LoadResource("text/staff_message_data_static/staff_message_data_static")); + if (sStaffMessageEntryTablePtr == NULL) { + auto file2 = + std::static_pointer_cast(OTRGlobals::Instance->context->GetResourceManager()->LoadResource( + "text/staff_message_data_static/staff_message_data_static")); + // OTRTODO: Should not be malloc'ing here. It's fine for now since we check that the message table is already null. + sStaffMessageEntryTablePtr = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * file2->messages.size()); - sStaffMessageEntryTablePtr = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * file2->messages.size()); - - for (size_t i = 0; i < file2->messages.size(); i++) - { - sStaffMessageEntryTablePtr[i].textId = file2->messages[i].id; - sStaffMessageEntryTablePtr[i].typePos = (file2->messages[i].textboxType << 4) | file2->messages[i].textboxYPos; - sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); - sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); + for (size_t i = 0; i < file2->messages.size(); i++) { + sStaffMessageEntryTablePtr[i].textId = file2->messages[i].id; + sStaffMessageEntryTablePtr[i].typePos = + (file2->messages[i].textboxType << 4) | file2->messages[i].textboxYPos; + sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); + sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); + } } CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID); diff --git a/soh/src/code/game.c b/soh/src/code/game.c index 546901d3e..26b26e94c 100644 --- a/soh/src/code/game.c +++ b/soh/src/code/game.c @@ -1,6 +1,7 @@ #include #include "global.h" #include "vt.h" +#include "libultraship/bridge.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" SpeedMeter D_801664D0; @@ -13,6 +14,7 @@ u16 sLastButtonPressed; // Forward declared, because this in a C++ header. int gfx_create_framebuffer(uint32_t width, uint32_t height); +void gfx_texture_cache_clear(); void GameState_FaultPrint(void) { static char sBtnChars[] = "ABZSuldr*+LRudlr"; @@ -459,6 +461,14 @@ void GameState_Destroy(GameState* gameState) { Fault_RemoveClient(&sGameFaultClient); osSyncPrintf("game デストラクタ終了\n"); // "game destructor end" + + // Performing clear skeletons before unload resources fixes an actor heap corruption crash due to the skeleton patching system. + ResourceMgr_ClearSkeletons(); + + if (CVarGetInteger("gAltAssets", 0)) { + UnloadResourceDirectory("alt/*"); + gfx_texture_cache_clear(); + } } GameStateFunc GameState_GetInit(GameState* gameState) { diff --git a/soh/src/code/gfxprint.c b/soh/src/code/gfxprint.c index 2dfc21da9..f7aa20a76 100644 --- a/soh/src/code/gfxprint.c +++ b/soh/src/code/gfxprint.c @@ -128,6 +128,7 @@ u8 sGfxPrintFontData[(16 * 256) / 2] = { // Can be used to set GFXP_FLAG_ENLARGE by default static u8 sDefaultSpecialFlags; +static const char rGfxPrintFontData[] = "__OTR__alt/textures/font/sGfxPrintFontData"; void GfxPrint_Setup(GfxPrint* this) { s32 width = 16; @@ -140,13 +141,26 @@ void GfxPrint_Setup(GfxPrint* this) { G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | G_RM_XLU_SURF | G_RM_XLU_SURF2); gDPSetCombineMode(this->dList++, G_CC_DECALRGBA, G_CC_DECALRGBA); - gDPLoadTextureBlock_4b(this->dList++, sGfxPrintFontData, G_IM_FMT_CI, 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); + + bool useAltTexture = ResourceMgr_FileExists(rGfxPrintFontData) && CVarGetInteger("gAltAssets", 0); + if (!useAltTexture) { + gDPLoadTextureBlock_4b(this->dList++, sGfxPrintFontData, G_IM_FMT_CI, 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); + } else { + gDPLoadTextureBlock_4b(this->dList++, rGfxPrintFontData, G_IM_FMT_CI, width * 4, 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); + } + gDPLoadTLUT(this->dList++, 64, 256, sGfxPrintFontTLUT); for (i = 1; i < 4; i++) { - gDPSetTile(this->dList++, G_IM_FMT_CI, G_IM_SIZ_4b, 1, 0, i * 2, i, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, - G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); + if (useAltTexture) { + gDPSetTile(this->dList++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 1, 0, i * 2, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); + } else { + gDPSetTile(this->dList++, G_IM_FMT_CI, G_IM_SIZ_4b, 1, 0, i * 2, i, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); + } gDPSetTileSize(this->dList++, i * 2, 0, 0, 60, 1020); } @@ -174,7 +188,7 @@ void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a) { } void GfxPrint_SetPosPx(GfxPrint* this, s32 x, s32 y) { - this->posX = this->baseX + (x * 4); + this->posX = this->baseX + (x * 4) + CVarGetInteger("gGfxPrintCharStartOffset", 0); this->posY = this->baseY + (y * 4); } @@ -189,6 +203,8 @@ void GfxPrint_SetBasePosPx(GfxPrint* this, s32 x, s32 y) { void GfxPrint_PrintCharImpl(GfxPrint* this, u8 c) { u32 tile = (c & 0xFF) * 2; + u8 offset = ((c * 2) & 0x7) / 2; + u8 useAltTexture = ResourceMgr_FileExists(rGfxPrintFontData) && CVarGetInteger("gAltAssets", 0); if (this->flags & GFXP_FLAG_UPDATE) { this->flags &= ~GFXP_FLAG_UPDATE; @@ -226,11 +242,12 @@ void GfxPrint_PrintCharImpl(GfxPrint* this, u8 c) { gSPTextureRectangle(this->dList++, (this->posX) << 1, (this->posY) << 1, (this->posX + 32) << 1, (this->posY + 32) << 1, tile, (u16)(c & 4) * 64, (u16)(c >> 3) * 256, 1 << 9, 1 << 9); } else { - gSPTextureRectangle(this->dList++, this->posX, this->posY, this->posX + 32, this->posY + 32, tile, - (u16)(c & 4) * 64, (u16)(c >> 3) * 256, 1 << 10, 1 << 10); + gSPTextureRectangle(this->dList++, this->posX, this->posY, this->posX + 32, this->posY + 32, + useAltTexture ? 0 : tile, (useAltTexture ? ((128 * 4) * offset) : 0) + (u16)((c & 4) * 64), + (u16)(c >> 3) * 256, 1 << 10, 1 << 10); } - this->posX += 32; + this->posX += CVarGetInteger("gGfxPrintCharSpacing", 32); } void GfxPrint_PrintStringWithSize(GfxPrint* this, const void* buffer, u32 charSize, u32 charCount) { diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index ae2db5b78..21d4e8702 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -799,9 +799,22 @@ void func_8002CDE4(PlayState* play, TitleCardContext* titleCtx) { void TitleCard_InitBossName(PlayState* play, TitleCardContext* titleCtx, void* texture, s16 x, s16 y, u8 width, u8 height, s16 hasTranslation) { - - if (ResourceMgr_OTRSigCheck(texture)) - texture = GetResourceDataByName(texture, false); + static char newName[512]; + + if (gSaveContext.language != LANGUAGE_ENG) { + size_t length = strlen(texture); + strcpy(newName, texture); + if (gSaveContext.language == LANGUAGE_FRA) { + newName[length - 6] = 'F'; + newName[length - 5] = 'R'; + newName[length - 4] = 'A'; + } else if (gSaveContext.language == LANGUAGE_GER) { + newName[length - 6] = 'G'; + newName[length - 5] = 'E'; + newName[length - 4] = 'R'; + } + texture = newName; + } titleCtx->texture = texture; titleCtx->isBossCard = true; @@ -1005,7 +1018,7 @@ void TitleCard_InitPlaceName(PlayState* play, TitleCardContext* titleCtx, void* } - char newName[512]; + static char newName[512]; if (gSaveContext.language != LANGUAGE_ENG) { size_t length = strlen(texture); @@ -1023,7 +1036,7 @@ void TitleCard_InitPlaceName(PlayState* play, TitleCardContext* titleCtx, void* texture = newName; } - titleCtx->texture = GetResourceDataByName(texture, false); + titleCtx->texture = texture; titleCtx->isBossCard = false; titleCtx->hasTranslation = false; titleCtx->x = x; @@ -1067,14 +1080,9 @@ void TitleCard_Update(PlayState* play, TitleCardContext* titleCtx) { void TitleCard_Draw(PlayState* play, TitleCardContext* titleCtx) { s32 width; s32 height; - s32 unused; s32 titleX; s32 doubleWidth; s32 titleY; - s32 titleSecondY; - s32 textureLanguageOffset; - s32 shiftTopY; - s32 shiftBottomY; if (titleCtx->alpha != 0) { width = titleCtx->width; @@ -1107,52 +1115,21 @@ void TitleCard_Draw(PlayState* play, TitleCardContext* titleCtx) { OPEN_DISPS(play->state.gfxCtx); - height = (width * height > 0x1000) ? 0x1000 / width : height; - titleSecondY = titleY + (height * 4); - - textureLanguageOffset = 0x0; - shiftTopY = 0x0; - shiftBottomY = 0x1000; - - //if this card is bosses cards, has translation and that is not using English language. - if (titleCtx->isBossCard && titleCtx->hasTranslation && gSaveContext.language != LANGUAGE_ENG) { - textureLanguageOffset = (width * height * gSaveContext.language); - if (gSaveContext.language == LANGUAGE_GER) { - shiftTopY = 0x400; - shiftBottomY = 0x1400; - } else if (gSaveContext.language == LANGUAGE_FRA) { - shiftTopY = 0x800; - shiftBottomY = 0x1800; - } - } - // WORLD_OVERLAY_DISP Goes over POLY_XLU_DISP but under POLY_KAL_DISP WORLD_OVERLAY_DISP = Gfx_SetupDL_52NoCD(WORLD_OVERLAY_DISP); gDPSetPrimColor(WORLD_OVERLAY_DISP++, 0, 0, (u8)titleCtx->intensityR, (u8)titleCtx->intensityG, (u8)titleCtx->intensityB, (u8)titleCtx->alpha); - gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftTopY, G_IM_FMT_IA, + gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture, 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); - //Removing the -1 there remove the gap between top and bottom textures. gSPWideTextureRectangle(WORLD_OVERLAY_DISP++, titleX, titleY, ((doubleWidth * 2) + titleX) - 4, titleY + (height * 4), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); height = titleCtx->height - height; - // If texture is bigger than 0x1000, display the rest - if (height > 0) { - gDPLoadTextureBlock(WORLD_OVERLAY_DISP++, (uintptr_t)titleCtx->texture + textureLanguageOffset + shiftBottomY, - 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); - //Removing the -1 there remove the gap between top and bottom textures. - gSPWideTextureRectangle(WORLD_OVERLAY_DISP++, titleX, titleSecondY, ((doubleWidth * 2) + titleX) - 4, - titleSecondY + (height * 4), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - } - CLOSE_DISPS(play->state.gfxCtx); } } diff --git a/soh/src/code/z_cheap_proc.c b/soh/src/code/z_cheap_proc.c index a5d0a8bc9..cf52db2d3 100644 --- a/soh/src/code/z_cheap_proc.c +++ b/soh/src/code/z_cheap_proc.c @@ -6,7 +6,11 @@ void Gfx_DrawDListOpa(PlayState* play, Gfx* dlist) { Gfx_SetupDL_25Opa(play->state.gfxCtx); gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); - gSPDisplayList(POLY_OPA_DISP++, dlist); + + if (ResourceMgr_OTRSigCheck(dlist) == 1) + gsSPPushCD(POLY_OPA_DISP++, dlist); + + gSPDisplayList(POLY_OPA_DISP++, dlist); CLOSE_DISPS(play->state.gfxCtx); } @@ -17,6 +21,10 @@ void Gfx_DrawDListXlu(PlayState* play, Gfx* dlist) { Gfx_SetupDL_25Xlu(play->state.gfxCtx); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); + + if (ResourceMgr_OTRSigCheck(dlist) == 1) + gsSPPushCD(POLY_XLU_DISP++, dlist); + gSPDisplayList(POLY_XLU_DISP++, dlist); CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/code/z_collision_check.c b/soh/src/code/z_collision_check.c index 785e68836..d04a097cf 100644 --- a/soh/src/code/z_collision_check.c +++ b/soh/src/code/z_collision_check.c @@ -3045,6 +3045,10 @@ void CollisionCheck_ApplyDamage(PlayState* play, CollisionCheckContext* colChkCt if (!(collider->acFlags & AC_HARD)) { collider->actor->colChkInfo.damage += damage; } + + if (CVarGetInteger("gIvanCoopModeEnabled", 0)) { + collider->actor->colChkInfo.damage *= GET_PLAYER(play)->ivanDamageMultiplier; + } } /** @@ -3649,7 +3653,7 @@ s32 CollisionCheck_CylSideVsLineSeg(f32 radius, f32 height, f32 offset, Vec3f* a * Gets damage from a sword strike using generic values, and returns 0 if the attack is * not sword-type. Used by bosses to require that a sword attack deal the killing blow. */ -u8 CollisionCheck_GetSwordDamage(s32 dmgFlags) { +u8 CollisionCheck_GetSwordDamage(s32 dmgFlags, PlayState* play) { u8 damage = 0; if (dmgFlags & 0x00400100) { @@ -3662,6 +3666,10 @@ u8 CollisionCheck_GetSwordDamage(s32 dmgFlags) { damage = 8; } + if (CVarGetInteger("gIvanCoopModeEnabled", 0)) { + damage *= GET_PLAYER(play)->ivanDamageMultiplier; + } + KREG(7) = damage; return damage; } diff --git a/soh/src/code/z_construct.c b/soh/src/code/z_construct.c index 44b0ee5e7..1aae3fcf8 100644 --- a/soh/src/code/z_construct.c +++ b/soh/src/code/z_construct.c @@ -41,18 +41,16 @@ void func_801109B0(PlayState* play) { DmaMgr_SendRequest1(interfaceCtx->parameterSegment, (uintptr_t)_parameter_staticSegmentRomStart, parameterSize, __FILE__, 162); - interfaceCtx->doActionSegment = GAMESTATE_ALLOC_MC(&play->state, 0x480); + interfaceCtx->doActionSegment = GAMESTATE_ALLOC_MC(&play->state, 3 * sizeof(char*)); osSyncPrintf("DOアクション テクスチャ初期=%x\n", 0x480); // "DO Action Texture Initialization" osSyncPrintf("parameter->do_actionSegment=%x\n", interfaceCtx->doActionSegment); ASSERT(interfaceCtx->doActionSegment != NULL); - uint32_t attackDoActionTexSize = GetResourceTexSizeByName(gAttackDoActionENGTex, false); - memcpy(interfaceCtx->doActionSegment, GetResourceDataByName(gAttackDoActionENGTex, false), attackDoActionTexSize); - memcpy(interfaceCtx->doActionSegment + (attackDoActionTexSize / 2), GetResourceDataByName(gCheckDoActionENGTex, false), attackDoActionTexSize); - - memcpy(interfaceCtx->doActionSegment + attackDoActionTexSize, GetResourceDataByName(gReturnDoActionENGTex, false), GetResourceTexSizeByName(gReturnDoActionENGTex, false)); + interfaceCtx->doActionSegment[0] = gAttackDoActionENGTex; + interfaceCtx->doActionSegment[1] = gCheckDoActionENGTex; + interfaceCtx->doActionSegment[2] = gReturnDoActionENGTex; interfaceCtx->iconItemSegment = GAMESTATE_ALLOC_MC( &play->state, 0x1000 * ARRAY_COUNT(gSaveContext.equips.buttonItems)); diff --git a/soh/src/code/z_fcurve_data_skelanime.c b/soh/src/code/z_fcurve_data_skelanime.c index 2ae49c3dd..a0eeace16 100644 --- a/soh/src/code/z_fcurve_data_skelanime.c +++ b/soh/src/code/z_fcurve_data_skelanime.c @@ -15,7 +15,7 @@ s32 SkelCurve_Init(PlayState* play, SkelAnimeCurve* skelCurve, SkelCurveLimbList TransformUpdateIndex* transUpdIdx) { if (ResourceMgr_OTRSigCheck(limbListSeg)) - limbListSeg = ResourceMgr_LoadSkeletonByName(limbListSeg); + limbListSeg = ResourceMgr_LoadSkeletonByName(limbListSeg, NULL); SkelCurveLimb** limbs; SkelCurveLimbList* limbList = SEGMENTED_TO_VIRTUAL(limbListSeg); diff --git a/soh/src/code/z_kanfont.c b/soh/src/code/z_kanfont.c index 0eea9be34..2dd9cda80 100644 --- a/soh/src/code/z_kanfont.c +++ b/soh/src/code/z_kanfont.c @@ -174,7 +174,7 @@ void Font_LoadChar(Font* font, u8 character, u16 codePointIndex) { //__FILE__, __LINE__); if (character < 0x8B) - memcpy(&font->charTexBuf[codePointIndex], GetResourceDataByName(fntTbl[character], false), FONT_CHAR_TEX_SIZE); + memcpy(&font->charTexBuf[codePointIndex], fntTbl[character], strlen(fntTbl[character]) + 1); } /** @@ -183,7 +183,7 @@ void Font_LoadChar(Font* font, u8 character, u16 codePointIndex) { * The different icons are given in the MessageBoxIcon enum. */ void Font_LoadMessageBoxIcon(Font* font, u16 icon) { - memcpy(font->iconBuf, GetResourceDataByName(msgStaticTbl[4 + icon], false), FONT_CHAR_TEX_SIZE); + memcpy(font->iconBuf, msgStaticTbl[4 + icon], strlen(msgStaticTbl[4 + icon]) + 1); } /** @@ -218,7 +218,7 @@ void Font_LoadOrderedFont(Font* font) { osSyncPrintf("nes_mes_buf[%d]=%d\n", codePointIndex, font->msgBuf[codePointIndex]); offset = (font->msgBuf[codePointIndex] - '\x20') * FONT_CHAR_TEX_SIZE; - memcpy(fontBuf, GetResourceDataByName(fntTbl[offset / FONT_CHAR_TEX_SIZE], false), FONT_CHAR_TEX_SIZE); + memcpy(fontBuf, fntTbl[offset / FONT_CHAR_TEX_SIZE], strlen(fntTbl[offset / FONT_CHAR_TEX_SIZE]) + 1); //DmaMgr_SendRequest1(fontBuf, fontStatic + offset, FONT_CHAR_TEX_SIZE, __FILE__, __LINE__); fontBufIndex += FONT_CHAR_TEX_SIZE / 8; } diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index 690c81e21..af1c1784d 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -413,8 +413,8 @@ void Map_InitData(PlayState* play, s16 room) { //gMapData->owMinimapTexSize[mapIndex], __FILE__, __LINE__); if (sEntranceIconMapIndex < 24) { - const char* textureName = minimapTableOW[sEntranceIconMapIndex]; - memcpy(play->interfaceCtx.mapSegment, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); + play->interfaceCtx.mapSegment[0] = GetResourceDataByName(minimapTableOW[sEntranceIconMapIndex], true); + play->interfaceCtx.mapSegmentName[0] = minimapTableOW[sEntranceIconMapIndex]; } interfaceCtx->unk_258 = mapIndex; @@ -447,9 +447,8 @@ void Map_InitData(PlayState* play, s16 room) { //((gMapData->dgnMinimapTexIndexOffset[mapIndex] + room) * 0xFF0), //0xFF0, __FILE__, __LINE__); - const char* textureName = minimapTableDangeon[gMapData->dgnMinimapTexIndexOffset[mapIndex] + room]; - memcpy(play->interfaceCtx.mapSegment, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); - + play->interfaceCtx.mapSegment[0] = GetResourceDataByName(minimapTableDangeon[gMapData->dgnMinimapTexIndexOffset[mapIndex] + room], true); + play->interfaceCtx.mapSegmentName[0] = minimapTableDangeon[gMapData->dgnMinimapTexIndexOffset[mapIndex] + room]; R_COMPASS_OFFSET_X = gMapData->roomCompassOffsetX[mapIndex][room]; R_COMPASS_OFFSET_Y = gMapData->roomCompassOffsetY[mapIndex][room]; Map_SetFloorPalettesData(play, VREG(30)); @@ -519,7 +518,8 @@ void Map_Init(PlayState* play) { interfaceCtx->unk_258 = -1; interfaceCtx->unk_25A = -1; - interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 0x1000); + interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*)); + interfaceCtx->mapSegmentName = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*)); // "MAP texture initialization scene_data_ID=%d mapSegment=%x" osSyncPrintf("\n\n\nMAP テクスチャ初期化 scene_data_ID=%d\nmapSegment=%x\n\n", play->sceneNum, interfaceCtx->mapSegment, play); @@ -639,20 +639,20 @@ void Minimap_DrawCompassIcons(PlayState* play) { if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; Matrix_Translate( - OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), + OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), (R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; Matrix_Translate( - OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), + OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), (R_COMPASS_OFFSET_Y +((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None Matrix_Translate( - (R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f), + (R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f), (R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 4) {//Hidden Matrix_Translate( - (R_COMPASS_OFFSET_X+(9999*10) + tempX / 10.0f), + (R_COMPASS_OFFSET_X+(9999*10) + tempX / 10.0f), (R_COMPASS_OFFSET_Y+(9999*10) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW); } } else { @@ -677,20 +677,20 @@ void Minimap_DrawCompassIcons(PlayState* play) { if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; Matrix_Translate( - OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), + OTRGetDimensionFromLeftEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), (R_COMPASS_OFFSET_Y + ((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; Matrix_Translate( - OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), + OTRGetDimensionFromRightEdge((R_COMPASS_OFFSET_X + (X_Margins_Minimap*10) + tempX + (CVarGetInteger("gMinimapPosX", 0)*10)) / 10.0f), (R_COMPASS_OFFSET_Y +((Y_Margins_Minimap*10)*-1) - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None Matrix_Translate( - (R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f), + (R_COMPASS_OFFSET_X + tempX + (CVarGetInteger("gMinimapPosX", 0)*10) / 10.0f), (R_COMPASS_OFFSET_Y - tempZ + ((CVarGetInteger("gMinimapPosY", 0)*10)*-1)) / 10.0f, 0.0f, MTXMODE_NEW); } else if (CVarGetInteger("gMinimapPosType", 0) == 4) {//Hidden Matrix_Translate( - (R_COMPASS_OFFSET_X+(9999*10) + tempX / 10.0f), + (R_COMPASS_OFFSET_X+(9999*10) + tempX / 10.0f), (R_COMPASS_OFFSET_Y+(9999*10) - tempZ) / 10.0f, 0.0f, MTXMODE_NEW); } } else { @@ -756,8 +756,7 @@ void Minimap_Draw(PlayState* play) { if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); - gSPInvalidateTexCache(OVERLAY_DISP++, interfaceCtx->mapSegment); - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegment, G_IM_FMT_I, 96, 85, 0, + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], 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); @@ -767,7 +766,7 @@ void Minimap_Draw(PlayState* play) { dgnMiniMapY = R_DGN_MINIMAP_Y+CVarGetInteger("gMinimapPosY", 0)+Y_Margins_Minimap; if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; - dgnMiniMapX = OTRGetDimensionFromLeftEdge(R_DGN_MINIMAP_X+CVarGetInteger("gMinimapPosX", 0)+X_Margins_Minimap); + dgnMiniMapX = OTRGetDimensionFromLeftEdge(R_DGN_MINIMAP_X+CVarGetInteger("gMinimapPosX", 0)+X_Margins_Minimap); } else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; dgnMiniMapX = OTRGetDimensionFromRightEdge(R_DGN_MINIMAP_X+CVarGetInteger("gMinimapPosX", 0)+X_Margins_Minimap); @@ -827,7 +826,7 @@ void Minimap_Draw(PlayState* play) { gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegment, G_IM_FMT_IA, + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_IA, gMapData->owMinimapWidth[mapIndex], gMapData->owMinimapHeight[mapIndex], 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); @@ -897,7 +896,7 @@ void Minimap_Draw(PlayState* play) { //No idea why and how Original value work but this does actually fix them all. PosY = PosY+1024; } - + if (((gMapData->owEntranceFlag[sEntranceIconMapIndex] == 0xFFFF) || ((gMapData->owEntranceFlag[sEntranceIconMapIndex] != 0xFFFF) && (gSaveContext.infTable[26] & gBitFlags[gMapData->owEntranceFlag[mapIndex]]) @@ -912,9 +911,9 @@ void Minimap_Draw(PlayState* play) { } s16 entranceX = OTRGetRectDimensionFromRightEdge(270 + X_Margins_Minimap); - s16 entranceY = 154 + Y_Margins_Minimap; + s16 entranceY = 154 + Y_Margins_Minimap; if (CVarGetInteger("gMinimapPosType", 0) != 0) { - entranceY = 154 + Y_Margins_Minimap + CVarGetInteger("gMinimapPosY", 0); + entranceY = 154 + Y_Margins_Minimap + CVarGetInteger("gMinimapPosY", 0); if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gMinimapUseMargins", 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; entranceX = OTRGetRectDimensionFromLeftEdge(270 + X_Margins_Minimap + CVarGetInteger("gMinimapPosX", 0)); @@ -932,15 +931,15 @@ void Minimap_Draw(PlayState* play) { 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); - gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + 32) << 2, (entranceY + 8) << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + 32) << 2, (entranceY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } else if ((play->sceneNum == SCENE_SPOT08) && CVarGetInteger("gAlwaysShowDungeonMinimapIcon", 0) != 0){ - + 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); - gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + 32) << 2, (entranceY + 8) << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + 32) << 2, (entranceY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 1a8c777a2..762e06b55 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -32,10 +32,10 @@ s16 sMessageHasSetSfx = false; u16 sOcarinaSongBitFlags = 0; // ocarina bit flags -MessageTableEntry* sNesMessageEntryTablePtr; -MessageTableEntry* sGerMessageEntryTablePtr; -MessageTableEntry* sFraMessageEntryTablePtr; -MessageTableEntry* sStaffMessageEntryTablePtr; +MessageTableEntry* sNesMessageEntryTablePtr = NULL; +MessageTableEntry* sGerMessageEntryTablePtr = NULL; +MessageTableEntry* sFraMessageEntryTablePtr = NULL; +MessageTableEntry* sStaffMessageEntryTablePtr = NULL; char* _message_0xFFFC_nes; @@ -562,7 +562,6 @@ void Message_DrawTextboxIcon(PlayState* play, Gfx** p, s16 x, s16 y) { *p = gfx; } -#define MESSAGE_SPACE_WIDTH 6 f32 sFontWidths[144] = { 8.0f, // ' ' 8.0f, // '!' @@ -865,7 +864,7 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { Message_SetTextColor(msgCtx, msgCtx->msgBufDecoded[++i] & 0xF); break; case ' ': - msgCtx->textPosX += MESSAGE_SPACE_WIDTH; + msgCtx->textPosX += CVarGetInteger("gTextSpacing", 6); break; case MESSAGE_BOX_BREAK: if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) { @@ -1131,7 +1130,7 @@ void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { R_TEXTBOX_ICON_YPOS = y + 6; R_TEXTBOX_ICON_SIZE = 32; memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, - GetResourceDataByName(gItemIcons[itemId], false), GetResourceTexSizeByName(gItemIcons[itemId], false)); + gItemIcons[itemId], strlen(gItemIcons[itemId]) + 1); // "Item 32-0" osSyncPrintf("アイテム32-0\n"); } else { @@ -1139,7 +1138,7 @@ void Message_LoadItemIcon(PlayState* play, u16 itemId, s16 y) { R_TEXTBOX_ICON_YPOS = y + 10; R_TEXTBOX_ICON_SIZE = 24; memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, - GetResourceDataByName(gItemIcons[itemId], false), GetResourceTexSizeByName(gItemIcons[itemId], false)); + gItemIcons[itemId], strlen(gItemIcons[itemId]) + 1); // "Item 24" osSyncPrintf("アイテム24=%d (%d) {%d}\n", itemId, itemId - ITEM_KOKIRI_EMERALD, 84); } @@ -1525,10 +1524,8 @@ void Message_Decode(PlayState* play) { msgCtx->textboxBackgroundYOffsetIdx = (font->msgBuf[msgCtx->msgBufPos + 3] & 0xF0) >> 4; msgCtx->textboxBackgroundUnkArg = font->msgBuf[msgCtx->msgBufPos + 3] & 0xF; - memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, - GetResourceDataByName(gRedMessageXLeftTex, false), GetResourceTexSizeByName(gRedMessageXLeftTex, false)); - memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + 0x900, - GetResourceDataByName(gRedMessageXRightTex, false), GetResourceTexSizeByName(gRedMessageXRightTex, false)); + memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE, gRedMessageXLeftTex, strlen(gRedMessageXLeftTex) + 1); + memcpy((uintptr_t)msgCtx->textboxSegment + MESSAGE_STATIC_TEX_SIZE + 0x900, gRedMessageXRightTex, strlen(gRedMessageXRightTex) + 1); msgCtx->msgBufPos += 3; R_TEXTBOX_BG_YPOS = R_TEXTBOX_Y + 8; @@ -1674,7 +1671,7 @@ void Message_OpenText(PlayState* play, u16 textId) { osSyncPrintf("吹き出し種類=%d\n", msgCtx->textBoxType); if (textBoxType < TEXTBOX_TYPE_NONE_BOTTOM) { const char* textureName = msgStaticTbl[messageStaticIndices[textBoxType]]; - memcpy(msgCtx->textboxSegment, GetResourceDataByName(textureName, false), MESSAGE_STATIC_TEX_SIZE); + memcpy(msgCtx->textboxSegment, textureName, strlen(textureName) + 1); if (textBoxType == TEXTBOX_TYPE_BLACK) { msgCtx->textboxColorRed = 0; msgCtx->textboxColorGreen = 0; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 68db893fb..8198caebf 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -16,30 +16,9 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -static uint16_t _doActionTexWidth, _doActionTexHeight = -1; -static uint16_t DO_ACTION_TEX_WIDTH() { - return 48; - - // TODO: Figure out why Ship::Texture is not returning a valid width - if (_doActionTexWidth == -1) - _doActionTexWidth = GetResourceTexWidthByName(gCheckDoActionENGTex, false); - return _doActionTexWidth; -} -static uint16_t DO_ACTION_TEX_HEIGHT() { - return 16; - - // TODO: Figure out why Ship::Texture is not returning a valid height - if (_doActionTexHeight == -1) - _doActionTexHeight = GetResourceTexHeightByName(gCheckDoActionENGTex, false); - return _doActionTexHeight; -} - -static uint32_t _doActionTexSize = -1; -static uint32_t DO_ACTION_TEX_SIZE() { - if (_doActionTexSize == -1) - _doActionTexSize = GetResourceTexSizeByName(gCheckDoActionENGTex, false); - return _doActionTexSize; -} +#define DO_ACTION_TEX_WIDTH() 48 +#define DO_ACTION_TEX_HEIGHT() 16 +#define DO_ACTION_TEX_SIZE() ((DO_ACTION_TEX_WIDTH() * DO_ACTION_TEX_HEIGHT()) / 2) // The button statuses include the A button when most things are only the equip item buttons // So, when indexing into it with a item button index, we need to adjust @@ -225,6 +204,8 @@ static const char* actionsTbl[] = gNum8DoActionENGTex, }; +static const char gDoEmptyTexture[] = "__OTR__textures/virtual/gEmptyTexture"; + // original name: "alpha_change" void Interface_ChangeAlpha(u16 alphaType) { if (alphaType != gSaveContext.unk_13EA) { @@ -2848,11 +2829,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { } void func_80086D5C(s32* buf, u16 size) { - u16 i; - - //buf = GetResourceDataByName(buf, false); - - for (i = 0; i < size; i++) { + for (u16 i = 0; i < size; i++) { buf[i] = 0; } } @@ -2865,46 +2842,25 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l char* doAction = actionsTbl[action]; - char newName[512]; + static char newName[4][512]; if (gSaveContext.language != LANGUAGE_ENG) { size_t length = strlen(doAction); - strcpy(newName, doAction); + strcpy(newName[loadOffset], doAction); if (gSaveContext.language == LANGUAGE_FRA) { - newName[length - 6] = 'F'; - newName[length - 5] = 'R'; - newName[length - 4] = 'A'; + newName[loadOffset][length - 6] = 'F'; + newName[loadOffset][length - 5] = 'R'; + newName[loadOffset][length - 4] = 'A'; } else if (gSaveContext.language == LANGUAGE_GER) { - newName[length - 6] = 'G'; - newName[length - 5] = 'E'; - newName[length - 4] = 'R'; + newName[loadOffset][length - 6] = 'G'; + newName[loadOffset][length - 5] = 'E'; + newName[loadOffset][length - 4] = 'R'; } - doAction = newName; - } - - /* - if (gSaveContext.language != LANGUAGE_ENG) { - action += DO_ACTION_MAX; - } - - if (gSaveContext.language == LANGUAGE_FRA) { - action += DO_ACTION_MAX; - }*/ - - - if (action != DO_ACTION_NONE) { - //osCreateMesgQueue(&interfaceCtx->loadQueue, &interfaceCtx->loadMsg, OS_MESG_BLOCK); - memcpy(interfaceCtx->doActionSegment + (loadOffset * DO_ACTION_TEX_SIZE()), GetResourceDataByName(doAction, false), - DO_ACTION_TEX_SIZE()); - //DmaMgr_SendRequest2(&interfaceCtx->dmaRequest_160, - //interfaceCtx->doActionSegment + (loadOffset * DO_ACTION_TEX_SIZE), - //(uintptr_t)_do_action_staticSegmentRomStart + (action * DO_ACTION_TEX_SIZE), DO_ACTION_TEX_SIZE, - //0, &interfaceCtx->loadQueue, NULL, __FILE__, __LINE__); - //osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); - } else { - gSegments[7] = VIRTUAL_TO_PHYSICAL(interfaceCtx->doActionSegment); - //func_80086D5C(SEGMENTED_TO_VIRTUAL(sDoActionTextures[loadOffset]), DO_ACTION_TEX_SIZE / 4); - func_80086D5C(interfaceCtx->doActionSegment + (loadOffset * DO_ACTION_TEX_SIZE()), DO_ACTION_TEX_SIZE() / 4); + doAction = newName[loadOffset]; } + + char* segment = interfaceCtx->doActionSegment[loadOffset]; + interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gDoEmptyTexture; + gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; } void Interface_SetDoAction(PlayState* play, u16 action) { @@ -2950,7 +2906,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { InterfaceContext* interfaceCtx = &play->interfaceCtx; char* doAction = actionsTbl[action]; - char newName[512]; + static char newName[512]; if (gSaveContext.language != LANGUAGE_ENG) { size_t length = strlen(doAction); @@ -2967,24 +2923,10 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { doAction = newName; } - /*if (gSaveContext.language != LANGUAGE_ENG) { - action += DO_ACTION_MAX; - } - - if (gSaveContext.language == LANGUAGE_FRA) { - action += DO_ACTION_MAX; - }*/ - interfaceCtx->unk_1FC = action; - - - - // OTRTODO - osCreateMesgQueue(&interfaceCtx->loadQueue, &interfaceCtx->loadMsg, OS_MESG_BLOCK); - memcpy(interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE(), GetResourceDataByName(doAction, false), DO_ACTION_TEX_SIZE()); - //DmaMgr_SendRequest2(&interfaceCtx->dmaRequest_160, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE, - //(uintptr_t)_do_action_staticSegmentRomStart + (action * DO_ACTION_TEX_SIZE), DO_ACTION_TEX_SIZE, 0, - //&interfaceCtx->loadQueue, NULL, __FILE__, __LINE__); + + char* segment = interfaceCtx->doActionSegment[1]; + interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gDoEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); interfaceCtx->unk_1FA = 1; @@ -4040,28 +3982,8 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, 0); gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - - //There is probably a more elegant way to do it. - char* doAction = actionsTbl[3]; - char newName[512]; - if (gSaveContext.language != LANGUAGE_ENG) { - size_t length = strlen(doAction); - strcpy(newName, doAction); - if (gSaveContext.language == LANGUAGE_FRA) { - newName[length - 6] = 'F'; - newName[length - 5] = 'R'; - newName[length - 4] = 'A'; - } else if (gSaveContext.language == LANGUAGE_GER) { - newName[length - 6] = 'G'; - newName[length - 5] = 'E'; - newName[length - 4] = 'R'; - } - doAction = newName; - } - - memcpy(interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE() * 2, GetResourceDataByName(doAction, false), DO_ACTION_TEX_SIZE()); - - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE() * 2, G_IM_FMT_IA, + Interface_LoadActionLabel(interfaceCtx, 3, 2); + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment[2], G_IM_FMT_IA, DO_ACTION_TEX_WIDTH(), DO_ACTION_TEX_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); @@ -4076,7 +3998,7 @@ void Interface_DrawItemButtons(PlayState* play) { gSPMatrix(OVERLAY_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[4], 4, 0); - Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE() * 2); + Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment[2]); gDPPipeSync(OVERLAY_DISP++); } } @@ -4900,10 +4822,6 @@ void Interface_Draw(PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - // Invalidate Do Action textures as they may have changed - gSPInvalidateTexCache(OVERLAY_DISP++, interfaceCtx->doActionSegment); - gSPInvalidateTexCache(OVERLAY_DISP++, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE()); - gSPSegment(OVERLAY_DISP++, 0x02, interfaceCtx->parameterSegment); gSPSegment(OVERLAY_DISP++, 0x07, interfaceCtx->doActionSegment); gSPSegment(OVERLAY_DISP++, 0x08, interfaceCtx->iconItemSegment); @@ -5211,7 +5129,7 @@ void Interface_Draw(PlayState* play) { PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->bAlpha); - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE(), G_IM_FMT_IA, + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->doActionSegment[1], G_IM_FMT_IA, DO_ACTION_TEX_WIDTH(), DO_ACTION_TEX_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); @@ -5301,7 +5219,7 @@ void Interface_Draw(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); if (fullUi) { - gDPLoadTextureBlock(OVERLAY_DISP++, GetResourceDataByName("__OTR__textures/parameter_static/gDPad", false), + gDPLoadTextureBlock(OVERLAY_DISP++, "__OTR__textures/parameter_static/gDPad", G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 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); gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, @@ -5417,9 +5335,9 @@ void Interface_Draw(PlayState* play) { gSPVertex(OVERLAY_DISP++, &interfaceCtx->actionVtx[4], 4, 0); if ((interfaceCtx->unk_1EC < 2) || (interfaceCtx->unk_1EC == 3)) { - Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment); + Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment[0]); } else { - Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment + DO_ACTION_TEX_SIZE()); + Interface_DrawActionLabel(play->state.gfxCtx, interfaceCtx->doActionSegment[1]); } gDPPipeSync(OVERLAY_DISP++); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 488207a97..9ac45cdcc 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -682,6 +682,12 @@ void Play_Init(GameState* thisx) { DmaMgr_DmaRomToRam(0x03FEB000, D_8012D1F0, sizeof(D_801614D0)); } #endif + + if (CVarGetInteger("gIvanCoopModeEnabled", 0)) { + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_PARTNER, GET_PLAYER(play)->actor.world.pos.x, + GET_PLAYER(play)->actor.world.pos.y + Player_GetHeight(GET_PLAYER(play)) + 5.0f, + GET_PLAYER(play)->actor.world.pos.z, 0, 0, 0, 1, true); + } } void Play_Update(PlayState* play) { diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 8df5b5a91..01d5e0409 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -330,6 +330,12 @@ void Player_SetBootData(PlayState* play, Player* this) { } } +// Custom method used to determine if we're using a custom model for link +uint8_t Player_IsCustomLinkModel() { + return (LINK_IS_ADULT && GetResourceIsCustomByName(gLinkAdultSkel, true)) || + (LINK_IS_CHILD && GetResourceIsCustomByName(gLinkChildSkel, true)); +} + s32 Player_InBlockingCsMode(PlayState* play, Player* this) { return (this->stateFlags1 & 0x20000080) || (this->csMode != 0) || (play->sceneLoadFlag == 0x14) || (this->stateFlags1 & 1) || (this->stateFlags3 & 0x80) || @@ -788,6 +794,11 @@ void func_8008F470(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dLis gDPSetEnvColor(POLY_OPA_DISP++, color->r, color->g, color->b, 0); + // If we have a custom link model, always use the most detailed LOD + if (Player_IsCustomLinkModel()) { + lod = 0; + } + sDListsLodOffset = lod * 2; SkelAnime_DrawFlexLod(play, skeleton, jointTable, dListCount, overrideLimbDraw, postLimbDraw, data, lod); @@ -1024,7 +1035,8 @@ s32 func_8008FCC8(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s s32 func_80090014(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) { Player* this = (Player*)thisx; - if (!func_8008FCC8(play, limbIndex, dList, pos, rot, thisx)) { + if (!func_8008FCC8(play, limbIndex, dList, pos, rot, thisx)) + { if (limbIndex == PLAYER_LIMB_L_HAND) { Gfx** dLists = this->leftHandDLists; @@ -1072,7 +1084,12 @@ s32 func_80090014(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s } else if (limbIndex == PLAYER_LIMB_WAIST) { - *dList = ResourceMgr_LoadGfxByName(this->waistDLists[sDListsLodOffset]); + + if (!Player_IsCustomLinkModel()) { + *dList = ResourceMgr_LoadGfxByName( + this->waistDLists[sDListsLodOffset]); // NOTE: This needs to be disabled when using custom + // characters - they're not going to have LODs anyways... + } } } @@ -1678,6 +1695,10 @@ s32 func_80091880(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s } } else if (limbIndex == PLAYER_LIMB_WAIST) { type = gPlayerModelTypes[modelGroup][4]; + + if (Player_IsCustomLinkModel()) { + return 0; + } } else { return 0; } diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index d10a5089e..f30bb5b03 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -1,3 +1,7 @@ +#ifdef WIN32 +#include +#endif + #include "global.h" #include "vt.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h" @@ -222,42 +226,29 @@ void func_80095D04(PlayState* play, Room* room, u32 flags) { s32 swapAndConvertJPEG(void* data) { OSTime time; + if (BE32SWAP(*(u32*)data) == JPEG_MARKER) { + size_t size = 320 * 240 * 2; - if (BE32SWAP(*(u32*)data) == JPEG_MARKER) - { - char* decodedJpeg = ResourceMgr_LoadJPEG(data, 320 * 240 * 2); - //char* decodedJpeg = ResourceMgr_LoadJPEG(data, 480 * 240 * 2); + char *decodedJpeg = ResourceMgr_LoadJPEG(data, size); - osSyncPrintf("JPEGデータを展開します\n"); // "Expanding jpeg data" - osSyncPrintf("JPEGデータアドレス %08x\n", data); // "Jpeg data address %08x" - // "Work buffer address (Z buffer) %08x" - osSyncPrintf("ワークバッファアドレス(Zバッファ)%08x\n", gZBuffer); + osSyncPrintf("Expanding jpeg data\n"); + osSyncPrintf("Work buffer address (Z buffer) %08x\n", gZBuffer); time = osGetTime(); - //if (!Jpeg_Decode(data, gZBuffer, gGfxSPTaskOutputBuffer, sizeof(gGfxSPTaskOutputBuffer))) - if (1) - { - memcpy(data, decodedJpeg, 320 * 240 * 2); - //memcpy(data, decodedJpeg, 480 * 240 * 2); - time = osGetTime() - time; + memcpy(data, decodedJpeg, size); + time = osGetTime() - time; - // "Success... I think. time = %6.3f ms" - osSyncPrintf("成功…だと思う。 time = %6.3f ms \n", OS_CYCLES_TO_USEC(time) / 1000.0f); - // "Writing back to original address from work buffer." - osSyncPrintf("ワークバッファから元のアドレスに書き戻します。\n"); - // "If the original buffer size isn't at least 150kb, it will be out of control." - osSyncPrintf("元のバッファのサイズが150キロバイト無いと暴走するでしょう。\n"); - - //bcopy(gZBuffer, data, sizeof(gZBuffer)); - } else { - osSyncPrintf("失敗!なんで〜\n"); // "Failure! Why is it 〜" - } + osSyncPrintf("Success... I think. time = %6.3f ms", OS_CYCLES_TO_USEC(time) / 1000.0f); + osSyncPrintf("Writing back to original address from work buffer."); + osSyncPrintf("If the original buffer size isn't at least 150kb, it will be out of control."); + return 1; } return 0; } + void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 mode0, u16 tlutCount, f32 frameX, f32 frameY) { Gfx* displayListHead; @@ -265,7 +256,6 @@ void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 h s32 temp; displayListHead = *displayList; - swapAndConvertJPEG(SEGMENTED_TO_VIRTUAL(source)); bg = (uObjBg*)(displayListHead + 1); gSPBranchList(displayListHead, (u8*)bg + sizeof(uObjBg)); @@ -413,7 +403,7 @@ BgImage* func_80096A74(PolygonType1* polygon1, PlayState* play) { // camera (such as din's fire) on scenes with prerendered backgrounds return NULL; } - + // jfifid camId2 = func_80041C10(&play->colCtx, camId, BGCHECK_SCENE)[2].y; if (camId2 >= 0) { diff --git a/soh/src/code/z_skelanime.c b/soh/src/code/z_skelanime.c index d0404ae17..908a83bcf 100644 --- a/soh/src/code/z_skelanime.c +++ b/soh/src/code/z_skelanime.c @@ -1077,7 +1077,7 @@ void SkelAnime_InitLink(PlayState* play, SkelAnime* skelAnime, FlexSkeletonHeade LinkAnimationHeader* animation, s32 flags, Vec3s* jointTable, Vec3s* morphTable, s32 limbBufCount) { if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg) != 0) - skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg); + skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, skelAnime); FlexSkeletonHeader* skeletonHeader = SEGMENTED_TO_VIRTUAL(skeletonHeaderSeg); s32 headerJointCount = skeletonHeader->sh.limbCount; @@ -1429,7 +1429,7 @@ s32 LinkAnimation_OnFrame(SkelAnime* skelAnime, f32 frame) { s32 SkelAnime_Init(PlayState* play, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg, AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg)) - skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg); + skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, skelAnime); SkeletonHeader* skeletonHeader = SEGMENTED_TO_VIRTUAL(skeletonHeaderSeg); @@ -1462,7 +1462,7 @@ s32 SkelAnime_Init(PlayState* play, SkelAnime* skelAnime, SkeletonHeader* skelet s32 SkelAnime_InitFlex(PlayState* play, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { if (ResourceMgr_OTRSigCheck(skeletonHeaderSeg) != 0) - skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg); + skeletonHeaderSeg = ResourceMgr_LoadSkeletonByName(skeletonHeaderSeg, skelAnime); FlexSkeletonHeader* skeletonHeader = SEGMENTED_TO_VIRTUAL(skeletonHeaderSeg); @@ -1921,6 +1921,8 @@ void SkelAnime_Free(SkelAnime* skelAnime, PlayState* play) { } else { osSyncPrintf("morf_joint あきまへん!!\n"); // "morf_joint is freed !!" } + + ResourceMgr_UnregisterSkeleton(skelAnime); } /** diff --git a/soh/src/code/z_skin_awb.c b/soh/src/code/z_skin_awb.c index f3a2e6390..eea1967a9 100644 --- a/soh/src/code/z_skin_awb.c +++ b/soh/src/code/z_skin_awb.c @@ -38,7 +38,7 @@ void Skin_InitAnimatedLimb(PlayState* play, Skin* skin, s32 limbIndex) { */ void Skin_Init(PlayState* play, Skin* skin, SkeletonHeader* skeletonHeader, AnimationHeader* animationHeader) { if (ResourceMgr_OTRSigCheck(skeletonHeader)) - skeletonHeader = ResourceMgr_LoadSkeletonByName(skeletonHeader); + skeletonHeader = ResourceMgr_LoadSkeletonByName(skeletonHeader, NULL); s32 limbCount; s32 i; diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index b616a292f..2ae04e344 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -1,4 +1,5 @@ #include "z_boss_dodongo.h" +#include "textures/boss_title_cards/object_kingdodongo.h" #include "objects/object_kingdodongo/object_kingdodongo.h" #include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "scenes/dungeons/ddan_boss/ddan_boss_room_1.h" @@ -49,6 +50,14 @@ const ActorInit Boss_Dodongo_InitVars = { #include "z_boss_dodongo_data.c" +static u8 sMaskTex16x16[16 * 16] = { { 0 } }; +static u8 sMaskTex8x16[8 * 16] = { { 0 } }; +static u8 sMaskTex16x32[16 * 32] = { { 0 } }; +static u8 sMaskTex32x16[32 * 16] = { { 0 } }; +static u8 sMaskTex8x8[8 * 8] = { { 0 } }; +static u8 sMaskTex8x32[8 * 32] = { { 0 } }; +static u8 sMaskTexLava[32 * 64] = { { 0 } }; + static InitChainEntry sInitChain[] = { ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE), ICHAIN_S8(naviEnemyId, 0x0C, ICHAIN_CONTINUE), @@ -56,65 +65,24 @@ static InitChainEntry sInitChain[] = { ICHAIN_F32(targetArrowOffset, 8200.0f, ICHAIN_STOP), }; -void func_808C1190(s16* arg0, u8* arg1, s16 arg2) { - arg0 = GetResourceDataByName(arg0, false); - - if (arg2[arg1] != 0) { - arg0[arg2 / 2] = 0; - } -} - -void func_808C11D0(s16* arg0, u8* arg1, s16 arg2) { - arg0 = GetResourceDataByName(arg0, false); - - if (arg1[arg2] != 0) { - arg0[arg2] = 0; - } -} - -void func_808C1200(s16* arg0, u8* arg1, s16 arg2) { - arg0 = GetResourceDataByName(arg0, false); - - if (arg1[arg2] != 0) { - arg0[arg2] = 0; - } -} - -void func_808C1230(s16* arg0, u8* arg1, s16 arg2) { - s16 index; - - arg0 = GetResourceDataByName(arg0, false); - - if (arg1[arg2] != 0) { - index = ((arg2 & 0xF) + ((arg2 & 0xF0) * 2)); - arg0[index + 16] = 0; - arg0[index] = 0; - } -} - -void func_808C1278(s16* arg0, u8* arg1, s16 arg2) { - s16 index; - - arg0 = GetResourceDataByName(arg0, false); - - if (arg1[arg2] != 0) { - index = ((arg2 & 0xF) * 2) + ((arg2 & 0xF0) * 2); - arg0[index + 1] = 0; - arg0[index] = 0; - } -} - void func_808C12C4(u8* arg1, s16 arg2) { - func_808C1190(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_015890), arg1, arg2); - func_808C1200(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_017210), arg1, arg2); - func_808C11D0(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_015D90), arg1, arg2); - func_808C11D0(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_016390), arg1, arg2); - func_808C11D0(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_016590), arg1, arg2); - func_808C11D0(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_016790), arg1, arg2); - func_808C1230(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_015990), arg1, arg2); - func_808C1230(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_015F90), arg1, arg2); - func_808C1278(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_016990), arg1, arg2); - func_808C1278(SEGMENTED_TO_VIRTUAL(object_kingdodongo_Tex_016E10), arg1, arg2); + if (arg2[arg1] != 0) { + sMaskTex8x16[arg2 / 2] = 1; + + sMaskTex8x32[arg2] = 1; + + sMaskTex16x16[arg2] = 1; + + sMaskTex16x16[arg2] = 1; + + s16 index = ((arg2 & 0xF) + ((arg2 & 0xF0) * 2)); + sMaskTex16x32[index + 16] = 1; + sMaskTex16x32[index] = 1; + + index = ((arg2 & 0xF) * 2) + ((arg2 & 0xF0) * 2); + sMaskTex32x16[index + 1] = 1; + sMaskTex32x16[index] = 1; + } } void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) { @@ -228,13 +196,47 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) { Actor_Spawn(&play->actorCtx, play, ACTOR_BG_BREAKWALL, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, 0x6000, true); Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -690.0f, -1523.76f, -3304.0f, 0, 0, 0, 0, true); - for (i = 0; i < 2048; i++) { - temp_v0 = i; - temp_s1_3[temp_v0] = temp_s2[temp_v0]; + for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) { + sMaskTexLava[i] = 1; + } + } else { + for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) { + sMaskTexLava[i] = 0; } } this->actor.flags &= ~ACTOR_FLAG_0; + + for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) { + sMaskTex8x16[i] = 0; + } + for (int i = 0; i < ARRAY_COUNT(sMaskTex8x32); i++) { + sMaskTex8x32[i] = 0; + } + for (int i = 0; i < ARRAY_COUNT(sMaskTex16x16); i++) { + sMaskTex16x16[i] = 0; + } + for (int i = 0; i < ARRAY_COUNT(sMaskTex16x32); i++) { + sMaskTex16x32[i] = 0; + } + for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) { + sMaskTex32x16[i] = 0; + } + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016390, sMaskTex16x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016590, sMaskTex16x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016790, sMaskTex16x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015990, sMaskTex16x32, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015F90, sMaskTex16x32, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL); + Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL); + + // OTRTODO: This is causing OOB memory reads with HD assets + // commenting this out means the lava will stay lava even after beating king d + // + // Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaFloorRockTex); } void BossDodongo_Destroy(Actor* thisx, PlayState* play) { @@ -421,7 +423,7 @@ void BossDodongo_IntroCutscene(BossDodongo* this, PlayState* play) { if (this->unk_198 == 0x5A) { if (!(gSaveContext.eventChkInf[7] & 2)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gKingDodongoTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gKingDodongoTitleCardENGTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_FIRE_BOSS); } @@ -1011,7 +1013,8 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) { } } - func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224); + // TODO The lave floor bubbles with an effect that modifies the texture. This needs to be recreated shader-side. + //func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224); } if (this->unk_1C6 != 0) { @@ -1022,7 +1025,7 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) { for (i2 = 0; i2 < 20; i2++) { s16 new_var = this->unk_1C2 & 0x7FF; - ptr1[new_var] = ptr2[new_var]; + sMaskTexLava[new_var] = 1; this->unk_1C2 += 37; } Math_SmoothStepToF(&this->unk_224, 0.0f, 1.0f, 0.01f, 0.0f); @@ -1139,6 +1142,18 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_25Opa(play->state.gfxCtx); + if ((this->csState == 9) && (this->unk_1DA < 854)) { + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex8x16); + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex8x32); + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex16x16); + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex16x32); + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16); + } + + if (this->unk_1C6 != 0) { + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava); + } + if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) { POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099); } else { @@ -1274,7 +1289,7 @@ void BossDodongo_UpdateDamage(BossDodongo* this, PlayState* play) { this->collider.elements->info.bumperFlags &= ~2; item1 = this->collider.elements[0].info.acHitInfo; if ((this->actionFunc == BossDodongo_Vulnerable) || (this->actionFunc == BossDodongo_LayDown)) { - swordDamage = damage = CollisionCheck_GetSwordDamage(item1->toucher.dmgFlags); + swordDamage = damage = CollisionCheck_GetSwordDamage(item1->toucher.dmgFlags, play); if (damage != 0) { Audio_PlayActorSound2(&this->actor, NA_SE_EN_DODO_K_DAMAGE); @@ -1700,8 +1715,6 @@ void BossDodongo_DrawEffects(PlayState* play) { Gfx_SetupDL_25Xlu(play->state.gfxCtx); unkMtx = &play->billboardMtxF; - gSPInvalidateTexCache(POLY_XLU_DISP++, gDodongosCavernBossLavaFloorTex); - for (i = 0; i < 80; i++, eff++) { FrameInterpolation_RecordOpenChild(eff, eff->epoch); if (eff->unk_24 == 1) { 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 51e3402d8..b29232095 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 @@ -5,6 +5,7 @@ */ #include "z_boss_fd.h" +#include "textures/boss_title_cards/object_fd.h" #include "objects/object_fd/object_fd.h" #include "overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.h" #include "overlays/actors/ovl_Bg_Vb_Sima/z_bg_vb_sima.h" @@ -499,7 +500,7 @@ void BossFd_Fly(BossFd* this, PlayState* play) { } if ((this->timers[3] == 130) && !(gSaveContext.eventChkInf[7] & 8)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gVolvagiaBossTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gVolvagiaBossTitleCardENGTex), 160, 180, 128, 40, true); } if (this->timers[3] <= 100) { this->camData.eyeVel.x = this->camData.eyeVel.y = this->camData.eyeVel.z = 2.0f; 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 a8577c2da..9280071f5 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 @@ -869,7 +869,7 @@ void BossFd2_CollisionCheck(BossFd2* this, PlayState* play) { u8 canKill = false; u8 damage; - if ((damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags)) == 0) { + if ((damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags, play)) == 0) { damage = (hurtbox->toucher.dmgFlags & 0x00001000) ? 4 : 2; } else { canKill = true; 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 413014834..ec59ae35b 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 @@ -4,6 +4,7 @@ #include "overlays/actors/ovl_En_Zl3/z_en_zl3.h" #include "overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.h" #include "overlays/actors/ovl_En_Bom/z_en_bom.h" +#include "textures/boss_title_cards/object_ganon.h" #include "assets/objects/object_ganon/object_ganon.h" #include "assets/objects/object_ganon_anime1/object_ganon_anime1.h" #include "assets/objects/object_ganon_anime2/object_ganon_anime2.h" @@ -119,6 +120,8 @@ EnZl3* sBossGanonZelda; GanondorfEffect sBossGanonEffectBuf[200]; +static u8 sWindowShatterTex[2048] = { {0} }; + void BossGanonEff_SpawnWindowShard(PlayState* play, Vec3f* pos, Vec3f* velocity, f32 scale) { static Color_RGB8 shardColors[] = { { 255, 175, 85 }, { 155, 205, 155 }, { 155, 125, 55 } }; s16 i; @@ -453,6 +456,13 @@ void BossGanon_Init(Actor* thisx, PlayState* play2) { Collider_SetCylinder(play, &this->collider, thisx, &sLightBallCylinderInit); } } + + for (int i = 0; i < ARRAY_COUNT(sWindowShatterTex); i++) { + sWindowShatterTex[i] = 0; + } + + Gfx_RegisterBlendedTexture(ganon_boss_sceneTex_006C18, sWindowShatterTex, NULL); + Gfx_RegisterBlendedTexture(ganon_boss_sceneTex_007418, sWindowShatterTex, NULL); } void BossGanon_Destroy(Actor* thisx, PlayState* play) { @@ -1095,7 +1105,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) { if (!(gSaveContext.eventChkInf[7] & 0x100)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gGanondorfTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gGanondorfTitleCardENGTex), 160, 180, 128, 40, true); } gSaveContext.eventChkInf[7] |= 0x100; @@ -1210,14 +1220,12 @@ void BossGanon_SetupTowerCutscene(BossGanon* this, PlayState* play) { void BossGanon_ShatterWindows(u8 windowShatterState) { s16 i; - u8* tex1 = GetResourceDataByNameHandlingMQ(SEGMENTED_TO_VIRTUAL(ganon_boss_sceneTex_006C18)); - u8* tex2 = GetResourceDataByNameHandlingMQ(SEGMENTED_TO_VIRTUAL(ganon_boss_sceneTex_007418)); u8* templateTex = GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGanondorfWindowShatterTemplateTex), false); - for (i = 0; i < 2048; i++) { - if ((tex1[i] != 0) && (Rand_ZeroOne() < 0.03f)) { + for (i = 0; i < ARRAY_COUNT(sWindowShatterTex); i++) { + if ((sWindowShatterTex[i] != 1) && (Rand_ZeroOne() < 0.03f)) { if ((templateTex[i] == 0) || (windowShatterState == GDF_WINDOW_SHATTER_FULL)) { - tex1[i] = tex2[i] = 1; + sWindowShatterTex[i] = 1; } } } @@ -2776,7 +2784,7 @@ void BossGanon_UpdateDamage(BossGanon* this, PlayState* play) { Rand_ZeroFloat(200.0f) + 500.0f, 0x1E); } - damage = flags = CollisionCheck_GetSwordDamage(acHitInfo->toucher.dmgFlags); + damage = flags = CollisionCheck_GetSwordDamage(acHitInfo->toucher.dmgFlags, play); if (flags == 0) { damage = 2; @@ -3866,10 +3874,9 @@ void BossGanon_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - // Invalidate textures if they have changed + // Invalidate texture mask if it has changed if (this->windowShatterState != GDF_WINDOW_SHATTER_OFF) { - gSPInvalidateTexCache(POLY_OPA_DISP++, ganon_boss_sceneTex_006C18); - gSPInvalidateTexCache(POLY_OPA_DISP++, ganon_boss_sceneTex_007418); + gSPInvalidateTexCache(POLY_OPA_DISP++, sWindowShatterTex); } Gfx_SetupDL_25Opa(play->state.gfxCtx); 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 f4c239d6d..a1cfaa684 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 @@ -2,6 +2,7 @@ #include "overlays/actors/ovl_Demo_Gj/z_demo_gj.h" #include "overlays/actors/ovl_En_Zl3/z_en_zl3.h" #include "objects/object_ganon/object_ganon.h" +#include "textures/boss_title_cards/object_ganon2.h" #include "objects/object_ganon2/object_ganon2.h" #include "objects/object_ganon_anime3/object_ganon_anime3.h" #include "objects/object_geff/object_geff.h" @@ -708,7 +709,7 @@ void func_808FD5F4(BossGanon2* this, PlayState* play) { if (this->csTimer == 80) { BossGanon2_SetObjectSegment(this, play, OBJECT_GANON2, false); TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gGanonTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gGanonTitleCardENGTex), 160, 180, 128, 40, true); //It has translation but they are all the same. they all say "GANON" only } this->unk_3A4.x = ((this->actor.world.pos.x + 500.0f) - 350.0f) + 100.0f; @@ -3155,4 +3156,4 @@ void BossGanon2_Reset(void) { memset(D_809105D8, 0, sizeof(D_809105D8)); memset(D_80910608, 0, sizeof(D_80910608)); memset(sBossGanon2Particles, 0, sizeof(sBossGanon2Particles)); -} \ No newline at end of file +} 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 ee63f6a64..642dd4559 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 @@ -181,6 +181,8 @@ static u8 sDecayMaskTotal[16 * 16] = { }; // clang-format on +static u8 sDecayTex[16 * 16] = { { 0 } }; + // These are Phantom Ganon's body textures, but I don't know which is which. static void* sLimbTex_rgba16_8x8[] = { gPhantomGanonLimbTex_00A800, gPhantomGanonLimbTex_00AE80, gPhantomGanonLimbTex_00AF00, @@ -208,66 +210,9 @@ static InitChainEntry sInitChain[] = { static Vec3f sAudioVec = { 0.0f, 0.0f, 50.0f }; -void BossGanondrof_ClearPixels8x8(s16* texture, u8* mask, s16 index) -{ - if (mask[index]) { - WriteTextureDataInt16ByName(texture, index / 4, 0, true); - } -} - -void BossGanondrof_ClearPixels16x8(s16* texture, u8* mask, s16 index) { - if (mask[index]) { - WriteTextureDataInt16ByName(texture, index / 2, 0, false); - - } -} - -void BossGanondrof_ClearPixels16x16(s16* texture, u8* mask, s16 index, s16 bpp) { - if (mask[index]) { - WriteTextureDataInt16ByName(texture, index, 0, false); - } -} - -void BossGanondrof_ClearPixels32x16(s16* texture, u8* mask, s16 index) { - if (mask[index]) { - s16 i = (index & 0xF) + ((index & 0xF0) << 1); - - WriteTextureDataInt16ByName(texture, i + 0x10, 0, false); - WriteTextureDataInt16ByName(texture, i, 0, false); - } -} - -void BossGanondrof_ClearPixels16x32(s16* texture, u8* mask, s16 index) { - if (mask[index]) { - s16 i = ((index & 0xF) * 2) + ((index & 0xF0) * 2); - - WriteTextureDataInt16ByName(texture, i + 1, 0, false); - WriteTextureDataInt16ByName(texture, i, 0, false); - } - -} - void BossGanondrof_ClearPixels(u8* mask, s16 index) { - s16 i; - - for (i = 0; i < 5; i++) { - // ARRAY_COUNT can't be used here because the arrays aren't guaranteed to be the same size. - BossGanondrof_ClearPixels8x8(SEGMENTED_TO_VIRTUAL(sLimbTex_rgba16_8x8[i]), mask, index); - BossGanondrof_ClearPixels16x8(SEGMENTED_TO_VIRTUAL(sLimbTex_rgba16_16x8[i]), mask, index); - } - - for (i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x16); i++) { - BossGanondrof_ClearPixels16x16(SEGMENTED_TO_VIRTUAL(sLimbTex_rgba16_16x16[i]), mask, index, 2); - } - - for (i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x32); i++) { - BossGanondrof_ClearPixels16x32(SEGMENTED_TO_VIRTUAL(sLimbTex_rgba16_16x32[i]), mask, index); - } - - BossGanondrof_ClearPixels32x16(SEGMENTED_TO_VIRTUAL(gPhantomGanonLimbTex_00B380), mask, index); - BossGanondrof_ClearPixels16x32(SEGMENTED_TO_VIRTUAL(gPhantomGanonEyeTex), mask, index); - for (i = 0; i < ARRAY_COUNT(sMouthTex_ci8_16x16); i++) { - BossGanondrof_ClearPixels16x16(SEGMENTED_TO_VIRTUAL(sMouthTex_ci8_16x16[i]), mask, index, 1); + if (mask[index]) { + sDecayTex[index] = 1; } } @@ -311,6 +256,26 @@ void BossGanondrof_Init(Actor* thisx, PlayState* play) { Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_FHG, this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, this->actor.params); } + + for (int i = 0; i < ARRAY_COUNT(sDecayTex); i++) { + sDecayTex[i] = 0; + } + + for (int i = 0; i < 5; i++) { + Gfx_RegisterBlendedTexture(sLimbTex_rgba16_8x8[i], sDecayTex, NULL); + Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x8[i], sDecayTex, NULL); + } + for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x16); i++) { + Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x16[i], sDecayTex, NULL); + } + for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x32); i++) { + Gfx_RegisterBlendedTexture(sLimbTex_rgba16_16x32[i], sDecayTex, NULL); + } + Gfx_RegisterBlendedTexture(gPhantomGanonLimbTex_00B380, sDecayTex, NULL); + Gfx_RegisterBlendedTexture(gPhantomGanonEyeTex, sDecayTex, NULL); + for (int i = 0; i < ARRAY_COUNT(sMouthTex_ci8_16x16); i++) { + Gfx_RegisterBlendedTexture(sMouthTex_ci8_16x16[i], sDecayTex, NULL); + } } void BossGanondrof_Destroy(Actor* thisx, PlayState* play) { @@ -1271,7 +1236,7 @@ void BossGanondrof_CollisionCheck(BossGanondrof* this, PlayState* play) { if (dmgFlags & 0x80) { return; } - dmg = CollisionCheck_GetSwordDamage(dmgFlags); + dmg = CollisionCheck_GetSwordDamage(dmgFlags, play); (dmg == 0) ? (dmg = 2) : (canKill = true); if (((s8)this->actor.colChkInfo.health > 2) || canKill) { this->actor.colChkInfo.health -= dmg; @@ -1512,21 +1477,7 @@ void BossGanondrof_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); if (this->work[GND_BODY_DECAY_FLAG]) { - for (int i = 0; i < 5; i++) { - gSPInvalidateTexCache(POLY_OPA_DISP++, sLimbTex_rgba16_8x8[i]); - gSPInvalidateTexCache(POLY_OPA_DISP++, sLimbTex_rgba16_16x8[i]); - } - for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x16); i++) { - gSPInvalidateTexCache(POLY_OPA_DISP++, sLimbTex_rgba16_16x16[i]); - } - for (int i = 0; i < ARRAY_COUNT(sLimbTex_rgba16_16x32); i++) { - gSPInvalidateTexCache(POLY_OPA_DISP++, sLimbTex_rgba16_16x32[i]); - } - gSPInvalidateTexCache(POLY_OPA_DISP++, gPhantomGanonLimbTex_00B380); - gSPInvalidateTexCache(POLY_OPA_DISP++, gPhantomGanonEyeTex); - for (int i = 0; i < ARRAY_COUNT(sMouthTex_ci8_16x16); i++) { - gSPInvalidateTexCache(POLY_OPA_DISP++, sMouthTex_ci8_16x16[i]); - } + gSPInvalidateTexCache(POLY_OPA_DISP++, sDecayTex); } osSyncPrintf("MOVE P = %x\n", this->actor.update); diff --git a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c index 732e0b514..0bc49d3f0 100644 --- a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c +++ b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c @@ -1,4 +1,5 @@ #include "z_boss_goma.h" +#include "textures/boss_title_cards/object_goma.h" #include "objects/object_goma/object_goma.h" #include "overlays/actors/ovl_En_Goma/z_en_goma.h" #include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h" @@ -255,6 +256,9 @@ static u8 sClearPixelTableSecondPass[16 * 16] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; +static u8 sClearPixelTex16[16 * 16] = { { 0 } }; +static u8 sClearPixelTex32[32 * 32] = { { 0 } }; + // indexed by limb (where the root limb is 1) static u8 sDeadLimbLifetime[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -289,47 +293,20 @@ static u8 sDeadLimbLifetime[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -/** - * Sets the `i`th pixel of a 16x16 RGBA16 image to 0 (transparent black) - * according to the `clearPixelTable` - */ -void BossGoma_ClearPixels16x16Rgba16(s16* rgba16image, u8* clearPixelTable, s16 i) -{ - if (clearPixelTable[i]) { - rgba16image[i] = 0; - } -} - -/** - * Sets the `i`th 2x2 pixels block of a 32x32 RGBA16 image to 0 (transparent black) - * according to the `clearPixelTable` - */ -void BossGoma_ClearPixels32x32Rgba16(s16* rgba16image, u8* clearPixelTable, s16 i) { - s16* targetPixel; - - if (clearPixelTable[i]) { - // address of the top left pixel in a 2x2 pixels block located at - // (i & 0xF, i >> 4) in a 16x16 grid of 2x2 pixels - targetPixel = rgba16image + ((i & 0xF) * 2 + (i & 0xF0) * 4); - // set the 2x2 block of pixels to 0 - targetPixel[0] = 0; - targetPixel[1] = 0; - targetPixel[32 + 0] = 0; - targetPixel[32 + 1] = 0; - } -} - /** * Clear pixels from Gohma's textures */ void BossGoma_ClearPixels(u8* clearPixelTable, s16 i) { - BossGoma_ClearPixels16x16Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaBodyTex), false), clearPixelTable, i); - BossGoma_ClearPixels16x16Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaShellUndersideTex), false), clearPixelTable, i); - BossGoma_ClearPixels16x16Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaDarkShellTex), false), clearPixelTable, i); - BossGoma_ClearPixels16x16Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaEyeTex), false), clearPixelTable, i); + if (clearPixelTable[i]) { + sClearPixelTex16[i] = 1; - BossGoma_ClearPixels32x32Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaShellTex), false), clearPixelTable, i); - BossGoma_ClearPixels32x32Rgba16(GetResourceDataByName(SEGMENTED_TO_VIRTUAL(gGohmaIrisTex), false), clearPixelTable, i); + u8* targetPixel = sClearPixelTex32 + ((i & 0xF) * 2 + (i & 0xF0) * 4); + // set the 2x2 block of pixels to 0 + targetPixel[0] = 1; + targetPixel[1] = 1; + targetPixel[32 + 0] = 1; + targetPixel[32 + 1] = 1; + } } static InitChainEntry sInitChain[] = { @@ -365,6 +342,21 @@ void BossGoma_Init(Actor* thisx, PlayState* play) { 0, WARP_DUNGEON_CHILD); Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 141.0f, -640.0f, -84.0f, 0, 0, 0, 0, true); } + + for (int i = 0; i < ARRAY_COUNT(sClearPixelTex16); i++) { + sClearPixelTex16[i] = 0; + } + + for (int i = 0; i < ARRAY_COUNT(sClearPixelTex32); i++) { + sClearPixelTex32[i] = 0; + } + + Gfx_RegisterBlendedTexture(gGohmaBodyTex, sClearPixelTex16, NULL); + Gfx_RegisterBlendedTexture(gGohmaShellUndersideTex, sClearPixelTex16, NULL); + Gfx_RegisterBlendedTexture(gGohmaDarkShellTex, sClearPixelTex16, NULL); + Gfx_RegisterBlendedTexture(gGohmaEyeTex, sClearPixelTex16, NULL); + Gfx_RegisterBlendedTexture(gGohmaShellTex, sClearPixelTex32, NULL); + Gfx_RegisterBlendedTexture(gGohmaIrisTex, sClearPixelTex32, NULL); } void BossGoma_PlayEffectsAndSfx(BossGoma* this, PlayState* play, s16 arg2, s16 amountMinus1) { @@ -928,7 +920,7 @@ void BossGoma_Encounter(BossGoma* this, PlayState* play) { if (!(gSaveContext.eventChkInf[7] & 1)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gGohmaTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gGohmaTitleCardENGTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); @@ -1831,7 +1823,7 @@ void BossGoma_UpdateHit(BossGoma* this, PlayState* play) { BossGoma_SetupFallStruckDown(this); Audio_PlayActorSound2(&this->actor, NA_SE_EN_GOMA_DAM2); } else if (this->actionFunc == BossGoma_FloorStunned && - (damage = CollisionCheck_GetSwordDamage(acHitInfo->toucher.dmgFlags)) != 0) { + (damage = CollisionCheck_GetSwordDamage(acHitInfo->toucher.dmgFlags, play)) != 0) { this->actor.colChkInfo.health -= damage; if ((s8)this->actor.colChkInfo.health > 0) { @@ -2137,12 +2129,8 @@ void BossGoma_Draw(Actor* thisx, PlayState* play) { // Invalidate Texture Cache since Goma modifies her own texture if (this->visualState == VISUALSTATE_DEFEATED) { - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaBodyTex); - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaShellUndersideTex); - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaDarkShellTex); - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaEyeTex); - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaShellTex); - gSPInvalidateTexCache(POLY_OPA_DISP++, gGohmaIrisTex); + gSPInvalidateTexCache(POLY_OPA_DISP++, sClearPixelTex16); + gSPInvalidateTexCache(POLY_OPA_DISP++, sClearPixelTex32); } if (this->noBackfaceCulling) { 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 3df8252fb..bcd457172 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 @@ -5,6 +5,7 @@ */ #include "z_boss_mo.h" +#include "textures/boss_title_cards/object_mo.h" #include "objects/object_mo/object_mo.h" #include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "objects/gameplay_keep/gameplay_keep.h" @@ -1437,7 +1438,7 @@ void BossMo_IntroCs(BossMo* this, PlayState* play) { } if (this->timers[2] == 130) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gMorphaTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gMorphaTitleCardENGTex), 160, 180, 128, 40, true); gSaveContext.eventChkInf[7] |= 0x10; } break; @@ -1767,7 +1768,7 @@ void BossMo_CoreCollisionCheck(BossMo* this, PlayState* play) { // "hit 2 !!" osSyncPrintf("Core_Damage_check 当り 2 !!\n"); if ((this->work[MO_TENT_ACTION_STATE] != MO_CORE_UNDERWATER) && (this->work[MO_TENT_INVINC_TIMER] == 0)) { - u8 damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags); + u8 damage = CollisionCheck_GetSwordDamage(hurtbox->toucher.dmgFlags, play); if ((damage != 0) && (this->work[MO_TENT_ACTION_STATE] < MO_CORE_ATTACK)) { // "sword hit !!" diff --git a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c index 36781cb81..4f1d8244f 100644 --- a/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c +++ b/soh/src/overlays/actors/ovl_Boss_Sst/z_boss_sst.c @@ -5,6 +5,7 @@ */ #include "z_boss_sst.h" +#include "textures/boss_title_cards/object_sst.h" #include "objects/object_sst/object_sst.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "overlays/actors/ovl_Bg_Sst_Floor/z_bg_sst_floor.h" @@ -608,7 +609,7 @@ void BossSst_HeadIntro(BossSst* this, PlayState* play) { } else if (revealStateTimer == 85) { if (!(gSaveContext.eventChkInf[7] & 0x80)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gBongoTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gBongoTitleCardENGTex), 160, 180, 128, 40, true); } Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); Animation_MorphToPlayOnce(&this->skelAnime, &gBongoHeadEyeCloseAnim, -5.0f); 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 8797a86f2..d513fa6bb 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 @@ -1,5 +1,6 @@ #include "z_boss_tw.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "textures/boss_title_cards/object_tw.h" #include "objects/object_tw/object_tw.h" #include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "soh/frame_interpolation.h" @@ -2181,7 +2182,7 @@ void BossTw_TwinrovaIntroCS(BossTw* this, PlayState* play) { play->envCtx.unk_BE = 1; play->envCtx.unk_BD = 1; play->envCtx.unk_D8 = 0.0f; - TitleCard_InitBossName(play, &play->actorCtx.titleCtx, SEGMENTED_TO_VIRTUAL(gTwinrovaTitleCardTex), 160, 180, 128, 40, true); + TitleCard_InitBossName(play, &play->actorCtx.titleCtx, SEGMENTED_TO_VIRTUAL(gTwinrovaTitleCardENGTex), 160, 180, 128, 40, true); gSaveContext.eventChkInf[7] |= 0x20; Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS); } @@ -3080,7 +3081,7 @@ void BossTw_TwinrovaUpdate(Actor* thisx, PlayState* play2) { this->collider.base.acFlags &= ~AC_HIT; swordDamage = false; - damage = CollisionCheck_GetSwordDamage(info->toucher.dmgFlags); + damage = CollisionCheck_GetSwordDamage(info->toucher.dmgFlags, play); if (damage == 0) { damage = 2; 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 6e79660e7..808f9ee12 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 @@ -8,6 +8,7 @@ #include +#include "textures/boss_title_cards/object_bv.h" #include "objects/object_bv/object_bv.h" #include "overlays/actors/ovl_En_Boom/z_en_boom.h" #include "objects/gameplay_keep/gameplay_keep.h" @@ -985,7 +986,7 @@ void BossVa_BodyIntro(BossVa* this, PlayState* play) { if (!(gSaveContext.eventChkInf[7] & 0x40)) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gBarinadeTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gBarinadeTitleCardENGTex), 160, 180, 128, 40, true); } if (Rand_ZeroOne() < 0.1f) { diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index 6b1261d25..4e864e582 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -756,16 +756,16 @@ void EnBox_UpdateSizeAndTexture(EnBox* this, PlayState* play) { void EnBox_CreateExtraChestTextures() { if (hasCreatedRandoChestTextures) return; Gfx gTreasureChestChestTextures[] = { - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gSkullTreasureChestFrontTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gSkullTreasureChestSideAndTopTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gGoldTreasureChestFrontTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gGoldTreasureChestSideAndTopTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gKeyTreasureChestFrontTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gKeyTreasureChestSideAndTopTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gChristmasRedTreasureChestFrontTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gChristmasRedTreasureChestSideAndTopTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gChristmasGreenTreasureChestFrontTex", false)), - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, GetResourceDataByName("__OTR__objects/object_box/gChristmasGreenTreasureChestSideAndTopTex", false)), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gSkullTreasureChestFrontTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gSkullTreasureChestSideAndTopTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gGoldTreasureChestFrontTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gGoldTreasureChestSideAndTopTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gKeyTreasureChestFrontTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gKeyTreasureChestSideAndTopTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gChristmasRedTreasureChestFrontTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gChristmasRedTreasureChestSideAndTopTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gChristmasGreenTreasureChestFrontTex"), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, "__OTR__objects/object_box/gChristmasGreenTreasureChestSideAndTopTex"), }; Gfx* frontCmd = ResourceMgr_LoadGfxByName(gTreasureChestChestFrontDL); @@ -839,7 +839,7 @@ void EnBox_CreateExtraChestTextures() { gChristmasGreenTreasureChestChestSideAndLidDL[29] = gTreasureChestChestTextures[9]; gChristmasGreenTreasureChestChestSideAndLidDL[45] = gTreasureChestChestTextures[8]; - ResourceMgr_ListFiles("assets/objects/object_box/gChristmas*", &hasChristmasChestTexturesAvailable); + ResourceMgr_ListFiles("objects/object_box/gChristmas*", &hasChristmasChestTexturesAvailable); hasCreatedRandoChestTextures = 1; } diff --git a/soh/src/overlays/actors/ovl_En_Ganon_Mant/z_en_ganon_mant.c b/soh/src/overlays/actors/ovl_En_Ganon_Mant/z_en_ganon_mant.c index 457d689f1..066ce12c0 100644 --- a/soh/src/overlays/actors/ovl_En_Ganon_Mant/z_en_ganon_mant.c +++ b/soh/src/overlays/actors/ovl_En_Ganon_Mant/z_en_ganon_mant.c @@ -96,7 +96,7 @@ static u16 sVerticesMap[GANON_MANT_NUM_STRANDS * GANON_MANT_NUM_JOINTS] = { #define MANT_TEX_WIDTH 32 #define MANT_TEX_HEIGHT 64 -//static u64 sForceAlignment = 0; +static u8 sMaskTex[MANT_TEX_WIDTH * MANT_TEX_HEIGHT] = { {0} }; #include "overlays/ovl_En_Ganon_Mant/ovl_En_Ganon_Mant.h" @@ -104,6 +104,12 @@ void EnGanonMant_Init(Actor* thisx, PlayState* play) { EnGanonMant* this = (EnGanonMant*)thisx; this->actor.flags &= ~ACTOR_FLAG_0; + + for (int i = 0; i < ARRAY_COUNT(sMaskTex); i++) { + sMaskTex[i] = 0; + } + + Gfx_RegisterBlendedTexture(gMantTex, sMaskTex, NULL); } void EnGanonMant_Destroy(Actor* thisx, PlayState* play) { @@ -127,8 +133,6 @@ void EnGanonMant_Tear(EnGanonMant* this) { s16 count = shape->count; s16* tearAreaSizes = shape->tearAreaSizes; - u8* gMantTexProper = GetResourceDataByName(gMantTex, false); - for (i = 0; i < count; i++) { if ((0 <= tx && tx < MANT_TEX_WIDTH) && (0 <= ty && ty < MANT_TEX_HEIGHT)) { for (areaX = 0; areaX <= tearAreaSizes[i]; areaX++) { @@ -136,7 +140,7 @@ void EnGanonMant_Tear(EnGanonMant* this) { for (areaY = 0; areaY <= tearAreaSizes[i]; areaY++) { texIdx = (s16)((s16)tx + ((s16)ty * MANT_TEX_WIDTH)) + ((s16)areaX + ((s16)areaY * MANT_TEX_WIDTH)); if (texIdx < MANT_TEX_WIDTH * MANT_TEX_HEIGHT) { - ((u16*)gMantTexProper)[texIdx] = 0; + sMaskTex[texIdx] = 1; } } } @@ -365,8 +369,8 @@ void EnGanonMant_DrawCloak(PlayState* play, EnGanonMant* this) { OPEN_DISPS(play->state.gfxCtx); - // Invalidate cape texture as it may have been torn - gSPInvalidateTexCache(POLY_OPA_DISP++, gMantTex); + // Invalidate cape texture mask as it may have been torn + gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex); Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_NEW); @@ -379,9 +383,9 @@ void EnGanonMant_DrawCloak(PlayState* play, EnGanonMant* this) { // set vertices, vertices are double buffered to prevent // modification of vertices as they are being drawn if (this->frameTimer % 2 != 0) { - gSPSegment(POLY_OPA_DISP++, 0x0C, gMant1Vtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, gMant1Vtx); } else { - gSPSegment(POLY_OPA_DISP++, 0x0C, gMant2Vtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, gMant2Vtx); } // draw cloak 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 3ad2e9eee..48de7b549 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 @@ -644,7 +644,7 @@ void EnGoma_UpdateHit(EnGoma* this, PlayState* play) { this->hurtTimer = 8; } } else { - swordDamage = CollisionCheck_GetSwordDamage(dmgFlags); + swordDamage = CollisionCheck_GetSwordDamage(dmgFlags, play); if (swordDamage) { EffectSsSibuki_SpawnBurst(play, &this->actor.focus.pos); diff --git a/soh/src/overlays/actors/ovl_En_Jsjutan/z_en_jsjutan.c b/soh/src/overlays/actors/ovl_En_Jsjutan/z_en_jsjutan.c index b3ca9f13a..60c51c036 100644 --- a/soh/src/overlays/actors/ovl_En_Jsjutan/z_en_jsjutan.c +++ b/soh/src/overlays/actors/ovl_En_Jsjutan/z_en_jsjutan.c @@ -418,15 +418,15 @@ void EnJsjutan_Draw(Actor* thisx, PlayState* play2) { G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); // Draws the carpet's shadow texture. - gSPSegment(POLY_OPA_DISP++, 0x0C, sShadowTex); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, sShadowTex); gSPDisplayList(POLY_OPA_DISP++, sShadowMaterialDL); gDPPipeSync(POLY_OPA_DISP++); // Draws the carpet's shadow vertices. Swaps them between frames to get a smoother result. if (play->gameplayFrames % 2 != 0) { - gSPSegment(POLY_OPA_DISP++, 0x0C, gShadowOddVtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, gShadowOddVtx); } else { - gSPSegment(POLY_OPA_DISP++, 0x0C, sShadowEvenVtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, sShadowEvenVtx); } gSPDisplayList(POLY_OPA_DISP++, sModelDL); @@ -443,9 +443,9 @@ void EnJsjutan_Draw(Actor* thisx, PlayState* play2) { // Draws the carpet vertices. if (play->gameplayFrames % 2 != 0) { - gSPSegment(POLY_OPA_DISP++, 0x0C, sCarpetOddVtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, sCarpetOddVtx); } else { - gSPSegment(POLY_OPA_DISP++, 0x0C, sCarpetEvenVtx); + gSPSegmentLoadRes(POLY_OPA_DISP++, 0x0C, sCarpetEvenVtx); } gSPDisplayList(POLY_OPA_DISP++, sModelDL); diff --git a/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c b/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c index 052c77f5f..0dd77b716 100644 --- a/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c +++ b/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c @@ -572,52 +572,22 @@ void EnMag_DrawImageRGBA32(Gfx** gfxp, s16 centerX, s16 centerY, const char* sou s32 pad; s32 i; - source = GetResourceDataByName(source, false); - Gfx_SetupDL_56Ptr(&gfx); - - curTexture = source; + rectLeft = centerX - (width / 2); rectTop = centerY - (height / 2); - textureHeight = 4096 / (width << 2); - remainingSize = (width * height) << 2; - textureSize = (width * textureHeight) << 2; - textureCount = remainingSize / textureSize; - if ((remainingSize % textureSize) != 0) { - textureCount += 1; - } - - gDPSetTileCustom(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 0, G_TX_NOMIRROR | G_TX_CLAMP, + + gDPSetTileCustom(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, 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); - - remainingSize -= textureSize; - - for (i = 0; i < textureCount; i++) { - gDPSetTextureImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, curTexture); - - gDPLoadSync(gfx++); - gDPLoadTile(gfx++, G_TX_LOADTILE, 0, 0, (width - 1) << 2, (textureHeight - 1) << 2); - - gSPTextureRectangle(gfx++, rectLeft << 2, rectTop << 2, (rectLeft + (s32)width) << 2, - (rectTop + textureHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - - curTexture += textureSize; - rectTop += textureHeight; - - if ((remainingSize - textureSize) < 0) { - if (remainingSize > 0) { - textureHeight = remainingSize / (s32)(width << 2); - remainingSize -= textureSize; - - gDPSetTileCustom(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 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); - } - } else { - remainingSize -= textureSize; - } - } - + + gDPSetTextureImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, source); + + gDPLoadSync(gfx++); + gDPLoadTile(gfx++, G_TX_LOADTILE, 0, 0, (width - 1) << 2, (height - 1) << 2); + + gSPTextureRectangle(gfx++, rectLeft << 2, rectTop << 2, (rectLeft + (s32)width) << 2, + (rectTop + height) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + *gfxp = gfx; } diff --git a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c new file mode 100644 index 000000000..c284af550 --- /dev/null +++ b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c @@ -0,0 +1,878 @@ +/* + * File: z_en_partner.c + * Overlay: ovl_En_Partner + * Description: Navi Coop Partner + */ + +#include "z_en_partner.h" +#include "objects/gameplay_keep/gameplay_keep.h" +#include +#include "overlays/actors/ovl_En_Si/z_en_si.h" +#include +#include +#include + +#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5 | ACTOR_FLAG_10 | ACTOR_FLAG_26) + +void EnPartner_Init(Actor* thisx, PlayState* play); +void EnPartner_Destroy(Actor* thisx, PlayState* play); +void EnPartner_Update(Actor* thisx, PlayState* play); +void EnPartner_Draw(Actor* thisx, PlayState* play); +void EnPartner_SpawnSparkles(EnPartner* this, PlayState* play, s32 sparkleLife); + +const ActorInit En_Partner_InitVars = { + ACTOR_EN_PARTNER, + ACTORCAT_ITEMACTION, + FLAGS, + OBJECT_GAMEPLAY_KEEP, + sizeof(EnPartner), + (ActorFunc)EnPartner_Init, + (ActorFunc)EnPartner_Destroy, + (ActorFunc)EnPartner_Update, + (ActorFunc)EnPartner_Draw, + NULL, +}; + +static InitChainEntry sInitChain[] = { + ICHAIN_VEC3F_DIV1000(scale, 8, ICHAIN_STOP), +}; + +static Color_RGBAf sInnerColors[] = { + { 255.0f, 255.0f, 255.0f, 255.0f }, +}; + +static Color_RGBAf sOuterColors[] = { + { 0.0f, 255.0f, 0.0f, 255.0f }, +}; + +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_PLAYER, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_2, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00020002, 0x00, 0x01 }, + { 0x4FC00748, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { 12, 27, 0, { 0, 0, 0 } }, +}; + +static CollisionCheckInfoInit sCCInfoInit = { 0, 12, 60, MASS_HEAVY }; + +void EnPartner_Init(Actor* thisx, PlayState* play) { + EnPartner* this = (EnPartner*)thisx; + s32 pad; + Player* player = GET_PLAYER(play); + s32 i; + + this->usedItem = 0xFF; + this->canMove = 1; + this->shouldDraw = 1; + this->hookshotTarget = NULL; + GET_PLAYER(play)->ivanFloating = 0; + + this->innerColor.r = 255.0f; + this->innerColor.g = 255.0f; + this->innerColor.b = 255.0f; + this->innerColor.a = 255.0f; + + this->outerColor.r = 0.0f; + this->outerColor.g = 255.0f; + this->outerColor.b = 0.0f; + this->outerColor.a = 255.0f; + + this->usedItemButton = 0xFF; + + Collider_InitCylinder(play, &this->collider); + Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit); + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sCCInfoInit); + this->actor.colChkInfo.mass = MASS_HEAVY; + this->collider.base.ocFlags1 |= OC1_TYPE_PLAYER; + this->collider.info.toucher.damage = 1; + GET_PLAYER(play)->ivanDamageMultiplier = 1; + + Actor_ProcessInitChain(thisx, sInitChain); + SkelAnime_Init(play, &this->skelAnime, &gFairySkel, &gFairyAnim, this->jointTable, this->morphTable, 15); + ActorShape_Init(&thisx->shape, 1000.0f, ActorShadow_DrawCircle, 15.0f); + thisx->shape.shadowAlpha = 0xFF; + + Lights_PointGlowSetInfo(&this->lightInfoGlow, thisx->world.pos.x, thisx->world.pos.y, thisx->world.pos.z, 200, 255, + 200, 0); + this->lightNodeGlow = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfoGlow); + + Lights_PointNoGlowSetInfo(&this->lightInfoNoGlow, thisx->world.pos.x, thisx->world.pos.y, thisx->world.pos.z, 200, + 255, 200, 0); + this->lightNodeNoGlow = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfoNoGlow); + + thisx->room = -1; +} + +void EnPartner_Destroy(Actor* thisx, PlayState* play) { + s32 pad; + EnPartner* this = (EnPartner*)thisx; + + LightContext_RemoveLight(play, &play->lightCtx, this->lightNodeGlow); + LightContext_RemoveLight(play, &play->lightCtx, this->lightNodeNoGlow); + + Collider_DestroyCylinder(play, &this->collider); +} + +void EnPartner_UpdateLights(EnPartner* this, PlayState* play) { + s16 glowLightRadius = 100; + s16 lightRadius = 200; + + if (this->shouldDraw == 0) { + glowLightRadius = 0; + lightRadius = 0; + } + + Player* player; + + player = GET_PLAYER(play); + Lights_PointNoGlowSetInfo(&this->lightInfoNoGlow, player->actor.world.pos.x, (s16)(player->actor.world.pos.y) + 69, + player->actor.world.pos.z, 200, 255, 200, lightRadius); + + Lights_PointGlowSetInfo(&this->lightInfoGlow, this->actor.world.pos.x, this->actor.world.pos.y + 9, + this->actor.world.pos.z, 200, 255, 200, glowLightRadius); + + Actor_SetScale(&this->actor, this->actor.scale.x); +} + +void EnPartner_SpawnSparkles(EnPartner* this, PlayState* play, s32 sparkleLife) { + static Vec3f sparkleVelocity = { 0.0f, -0.05f, 0.0f }; + static Vec3f sparkleAccel = { 0.0f, -0.025f, 0.0f }; + s32 pad; + Vec3f sparklePos; + Color_RGBA8 primColor; + Color_RGBA8 envColor; + + sparklePos.x = Rand_CenteredFloat(6.0f) + this->actor.world.pos.x; + sparklePos.y = (Rand_ZeroOne() * 6.0f) + this->actor.world.pos.y + 5; + sparklePos.z = Rand_CenteredFloat(6.0f) + this->actor.world.pos.z; + + primColor.r = this->innerColor.r; + primColor.g = this->innerColor.g; + primColor.b = this->innerColor.b; + + envColor.r = this->outerColor.r; + envColor.g = this->outerColor.g; + envColor.b = this->outerColor.b; + + EffectSsKiraKira_SpawnDispersed(play, &sparklePos, &sparkleVelocity, &sparkleAccel, &primColor, &envColor, + 1500, sparkleLife); +} + +Vec3f Vec3fNormalize(Vec3f vec) { + f32 norm = sqrt((vec.x * vec.x) + (vec.y * vec.y) + (vec.z * vec.z)); + + if (norm != 0.0f) { + vec.x /= norm; + vec.y /= norm; + vec.z /= norm; + } else { + vec.x = vec.y = vec.z = 0.0f; + } + + return vec; +} + +void CenterIvanOnLink(Actor* thisx, PlayState* play) { + EnPartner* this = (EnPartner*)thisx; + this->actor.world.pos = GET_PLAYER(play)->actor.world.pos; + this->actor.world.pos.y += Player_GetHeight(GET_PLAYER(play)) + 5.0f; +} + +static u8 magicArrowCosts[] = { 0, 4, 4, 8 }; + +void UseBow(Actor* thisx, PlayState* play, u8 started, u8 arrowType) { + EnPartner* this = (EnPartner*)thisx; + + if (started == 1) { + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + this->canMove = 0; + } else if (started == 0) { + if (this->itemTimer <= 0) { + if (AMMO(ITEM_BOW) > 0) { + if (arrowType >= 1 && !func_80087708(play, magicArrowCosts[arrowType], 0)) { + func_80078884(NA_SE_SY_ERROR); + this->canMove = 1; + return; + } + + this->itemTimer = 10; + + Actor* newarrow = Actor_SpawnAsChild( + &play->actorCtx, &this->actor, play, ACTOR_EN_ARROW, this->actor.world.pos.x, + this->actor.world.pos.y + 7, this->actor.world.pos.z, 0, this->actor.world.rot.y, 0, ARROW_NORMAL); + + switch (arrowType) { + case 1: + newarrow->params = ARROW_FIRE; + break; + case 2: + newarrow->params = ARROW_ICE; + break; + case 3: + newarrow->params = ARROW_LIGHT; + break; + } + + GET_PLAYER(play)->unk_A73 = 4; + newarrow->parent = NULL; + Inventory_ChangeAmmo(ITEM_BOW, -1); + } + } + } +} + +void UseSlingshot(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (started == 1) { + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + this->canMove = 0; + } else if (started == 0) { + if (this->itemTimer <= 0) { + if (AMMO(ITEM_SLINGSHOT) > 0) { + this->itemTimer = 10; + Actor* newarrow = Actor_SpawnAsChild( + &play->actorCtx, &this->actor, play, ACTOR_EN_ARROW, this->actor.world.pos.x, + this->actor.world.pos.y + 7, this->actor.world.pos.z, 0, this->actor.world.rot.y, 0, ARROW_SEED); + GET_PLAYER(play)->unk_A73 = 4; + newarrow->parent = NULL; + Inventory_ChangeAmmo(ITEM_SLINGSHOT, -1); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + } +} + +void UseBombs(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + if (AMMO(ITEM_BOMB) > 0 && play->actorCtx.actorLists[ACTORCAT_EXPLOSIVE].length < 3) { + this->itemTimer = 10; + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, this->actor.world.pos.x, this->actor.world.pos.y + 7, + this->actor.world.pos.z, 0, 0, 0, 0, false); + Inventory_ChangeAmmo(ITEM_BOMB, -1); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + } +} + +static Vec3f D_80854A40 = { 0.0f, 40.0f, 45.0f }; + +void UseHammer(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + this->itemTimer = 10; + static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f }; + Vec3f shockwavePos = this->actor.world.pos; + + func_808429B4(play, 27767, 7, 20); + func_8002F7DC(&this->actor, NA_SE_IT_HAMMER_HIT); + + EffectSsBlast_SpawnWhiteShockwave(play, &shockwavePos, &zeroVec, &zeroVec); + + if (this->actor.xzDistToPlayer < 100.0f && this->actor.yDistToPlayer < 35.0f) { + func_8002F71C(play, &this->actor, 8.0f, this->actor.yawTowardsPlayer, 8.0f); + } + } + } +} + +void UseBombchus(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + if (AMMO(ITEM_BOMBCHU) > 0) { + this->itemTimer = 10; + EnBom* bomb = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, this->actor.world.pos.x, this->actor.world.pos.y + 7, + this->actor.world.pos.z, 0, 0, 0, 0, false); + bomb->timer = 0; + Inventory_ChangeAmmo(ITEM_BOMBCHU, -1); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + } +} + +static Vec3f D_808547A4 = { 0.0f, 0.5f, 0.0f }; +static Vec3f D_808547B0 = { 0.0f, 0.5f, 0.0f }; + +static Color_RGBA8 D_808547BC = { 255, 255, 100, 255 }; +static Color_RGBA8 D_808547C0 = { 255, 50, 0, 0 }; + +void UseDekuStick(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + if (AMMO(ITEM_STICK) > 0) { + func_808328EC(this, NA_SE_EV_FLAME_IGNITION); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + + if (started == 2) { + if (AMMO(ITEM_STICK) > 0) { + this->stickWeaponInfo.tip = this->actor.world.pos; + this->stickWeaponInfo.tip.y += 7.0f; + + func_8002836C(play, &this->stickWeaponInfo.tip, &D_808547A4, &D_808547B0, &D_808547BC, &D_808547C0, + 200.0f, 0, 8); + + CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.base); + + if (this->damageTimer <= 0) { + Inventory_ChangeAmmo(ITEM_STICK, -1); + this->damageTimer = 20; + } else { + this->damageTimer--; + } + } + } + } +} + +void UseNuts(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + if (AMMO(ITEM_NUT) > 0) { + this->itemTimer = 10; + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ARROW, this->actor.world.pos.x, this->actor.world.pos.y + 7, + this->actor.world.pos.z, 0x1000, this->actor.world.rot.y, 0, ARROW_NUT, false); + Inventory_ChangeAmmo(ITEM_NUT, -1); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + } +} + +void UseHookshot(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + this->canMove = 0; + this->hookshotTarget = + Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_OBJ_HSBLOCK, this->actor.world.pos.x, + this->actor.world.pos.y + 7.5f, this->actor.world.pos.z, this->actor.world.rot.x, + this->actor.world.rot.y, this->actor.world.rot.z, 2); + this->hookshotTarget->scale.x = 0.05f; + this->hookshotTarget->scale.y = 0.05f; + this->hookshotTarget->scale.z = 0.05f; + } else if (started == 0) { + Actor_Kill(this->hookshotTarget); + this->hookshotTarget = NULL; + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + this->canMove = 1; + } else if (started == 2) { + this->hookshotTarget->shape.rot.y = this->actor.world.rot.y; + } + } +} + +void UseOcarina(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + Audio_PlaySoundTransposed(&this->actor.projectedPos, NA_SE_VO_NA_HELLO_2, -6); + } + } +} + +void UseBoomerang(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + this->itemTimer = 20; + spawn_boomerang_ivan(&this->actor, play); + } + } +} + +void UseLens(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + func_80078884(NA_SE_SY_GLASSMODE_ON); + this->shouldDraw = 0; + } + + if (started == 0) { + func_80078884(NA_SE_SY_GLASSMODE_OFF); + this->shouldDraw = 1; + } + } +} + +void UseBeans(Actor* thisx, PlayState* play, u8 started) { + EnPartner* this = (EnPartner*)thisx; + + if (this->itemTimer <= 0) { + if (started == 1) { + this->entry = ItemTable_Retrieve(GI_BEAN); + if (play->actorCtx.titleCtx.alpha <= 0) { + if (gSaveContext.rupees >= 100 && GiveItemEntryWithoutActor(play, this->entry)) { + Rupees_ChangeBy(-100); + } else { + func_80078884(NA_SE_SY_ERROR); + } + } + } + } +} + +void UseSpell(Actor* thisx, PlayState* play, u8 started, u8 spellType) { + EnPartner* this = (EnPartner*)thisx; + + if (gSaveContext.magic > 0) { + if (this->itemTimer <= 0 && this->usedSpell == 0) { + if (started == 1) { + this->usedSpell = spellType; + } + } + + if (started == 0 && this->usedSpell != 0) { + this->itemTimer = 10; + gSaveContext.magicState = 5; + + switch (this->usedSpell) { + case 1: + GET_PLAYER(play)->ivanDamageMultiplier = 1; + break; + case 3: + GET_PLAYER(play)->ivanFloating = 0; + break; + } + + this->usedSpell = 0; + } + + if (started == 2) { + if (this->usedSpell != 0) { + Vec3f spE4[3]; + Vec3f newBasePos[3]; + + switch (this->usedSpell) { + case 1: //Din's + GET_PLAYER(play)->ivanDamageMultiplier = 2; + break; + case 2: //Nayru's + GET_PLAYER(play)->invincibilityTimer = -10; + break; + case 3: //Farore's + GET_PLAYER(play)->hoverBootsTimer = 10; + GET_PLAYER(play)->ivanFloating = 1; + break; + } + + gSaveContext.magicState = 3; + this->magicTimer--; + if (this->magicTimer <= 0) { + gSaveContext.magic--; + this->magicTimer = 20; + if (gSaveContext.magic <= 0) { + gSaveContext.magic = 0; + + this->itemTimer = 10; + this->usedSpell = 0; + gSaveContext.magicState = 5; + } + } + } + } + } +} + +void UseItem(uint8_t usedItem, u8 started, Actor* thisx, PlayState* play) { + EnPartner* this = (EnPartner*)thisx; + + if (this->usedItem != 0xFF && this->itemTimer <= 0) { + switch (usedItem) { + case SLOT_STICK: + UseDekuStick(this, play, started); + break; + case SLOT_BOMB: + UseBombs(this, play, started); + break; + case SLOT_BOMBCHU: + UseBombchus(this, play, started); + break; + case SLOT_NUT: + UseNuts(this, play, started); + break; + case SLOT_BOW: + UseBow(this, play, started, 0); + break; + case SLOT_ARROW_FIRE: + UseBow(this, play, started, 1); + break; + case SLOT_ARROW_ICE: + UseBow(this, play, started, 2); + break; + case SLOT_ARROW_LIGHT: + UseBow(this, play, started, 3); + break; + case SLOT_SLINGSHOT: + UseSlingshot(this, play, started); + break; + case SLOT_OCARINA: + UseOcarina(this, play, started); + break; + case SLOT_HOOKSHOT: + UseHookshot(this, play, started); + break; + case SLOT_DINS_FIRE: + UseSpell(this, play, started, 1); + break; + case SLOT_NAYRUS_LOVE: + UseSpell(this, play, started, 2); + break; + case SLOT_FARORES_WIND: + UseSpell(this, play, started, 3); + break; + case SLOT_HAMMER: + UseHammer(this, play, started); + break; + case SLOT_BOOMERANG: + UseBoomerang(this, play, started); + break; + case SLOT_LENS: + UseLens(this, play, started); + break; + case SLOT_BEAN: + UseBeans(this, play, started); + break; + } + } + + if (started == 0) { + this->usedItem = 0xFF; + } +} + +void EnPartner_Update(Actor* thisx, PlayState* play) { + s32 pad; + EnPartner* this = (EnPartner*)thisx; + + Input sControlInput = play->state.input[this->actor.params]; + + f32 relX = sControlInput.cur.stick_x / 10.0f; + f32 relY = sControlInput.cur.stick_y / 10.0f; + + Vec3f camForward = { GET_ACTIVE_CAM(play)->at.x - GET_ACTIVE_CAM(play)->eye.x, 0.0f, + GET_ACTIVE_CAM(play)->at.z - GET_ACTIVE_CAM(play)->eye.z }; + camForward = Vec3fNormalize(camForward); + + Vec3f camRight = { -camForward.z, 0.0f, camForward.x }; + + this->actor.velocity.x = 0; + this->actor.velocity.y = 0; + this->actor.velocity.z = 0; + + this->actor.velocity.x += camRight.x * relX; + this->actor.velocity.z += camRight.z * relX; + this->actor.velocity.x += camForward.x * relY; + this->actor.velocity.z += camForward.z * relY; + + if (this->actor.velocity.x != 0 || this->actor.velocity.z != 0) { + int16_t finalDir = Math_Atan2S(-this->actor.velocity.x, this->actor.velocity.z) - 0x4000; + Math_SmoothStepToS(&this->actor.world.rot.y, finalDir, 2, 10000, 0); + Math_SmoothStepToS(&this->actor.shape.rot.y, finalDir, 2, 10000, 0); + } + + if (!this->canMove) { + relX = 0; + relY = 0; + } + + Math_SmoothStepToF(&this->actor.speedXZ, sqrtf(SQ(relX) + SQ(relY)), 1.0f, 1.3f, 0.0f); + + if (this->shouldDraw == 1) { + thisx->shape.shadowAlpha = 0xFF; + EnPartner_SpawnSparkles(this, play, 12); + } else { + thisx->shape.shadowAlpha = 0; + } + + if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_A) && this->canMove) { + Math_SmoothStepToF(&this->yVelocity, 6.0f, 1.0f, 1.5f, 0.0f); + } else if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_B) && this->canMove) { + Math_SmoothStepToF(&this->yVelocity, -6.0f, 1.0f, 1.5f, 0.0f); + } else { + Math_SmoothStepToF(&this->yVelocity, 0.0f, 1.0f, 1.5f, 0.0f); + } + + this->actor.gravity = this->yVelocity; + + if (this->canMove == 1) { + Actor_MoveForward(&this->actor); + Actor_UpdateBgCheckInfo(play, &this->actor, 19.0f, 20.0f, 0.0f, 5); + } + + if (this->usedSpell != 0) { + func_8002F974(thisx, NA_SE_PL_MAGIC_SOUL_NORMAL - SFX_FLAG); + } + + if (!Player_InCsMode(play)) { + // Collect drops & rupees + Actor* itemActor = play->actorCtx.actorLists[ACTORCAT_MISC].head; + while (itemActor != NULL) { + if (itemActor->id == ACTOR_EN_ITEM00) { + if (itemActor->params == ITEM00_RUPEE_GREEN || itemActor->params == ITEM00_RUPEE_BLUE || + itemActor->params == ITEM00_RUPEE_RED || itemActor->params == ITEM00_RUPEE_PURPLE || + itemActor->params == ITEM00_RUPEE_ORANGE || itemActor->params == ITEM00_HEART || + itemActor->params == ITEM00_BOMBS_A || itemActor->params == ITEM00_BOMBS_B || + itemActor->params == ITEM00_ARROWS_SINGLE || itemActor->params == ITEM00_ARROWS_SMALL || + itemActor->params == ITEM00_ARROWS_MEDIUM || itemActor->params == ITEM00_ARROWS_LARGE || + itemActor->params == ITEM00_BOMBCHU || itemActor->params == ITEM00_MAGIC_SMALL || + itemActor->params == ITEM00_MAGIC_LARGE || itemActor->params == ITEM00_NUTS || + itemActor->params == ITEM00_STICK) { + f32 distanceToObject = Actor_WorldDistXYZToActor(&this->actor, itemActor); + if (distanceToObject <= 20.0f) { + itemActor->world.pos = GET_PLAYER(play)->actor.world.pos; + break; + } + } + } + itemActor = itemActor->next; + } + + itemActor = play->actorCtx.actorLists[ACTORCAT_ITEMACTION].head; + while (itemActor != NULL) { + if (itemActor->id == ACTOR_EN_SI) { + f32 distanceToObject = Actor_WorldDistXYZToActor(&this->actor, itemActor); + if (distanceToObject <= 20.0f) { + EnSi* ensi = (EnSi*)itemActor; + ensi->collider.base.ocFlags2 = OC2_HIT_PLAYER; + break; + } + } + itemActor = itemActor->next; + } + } + + if (this->itemTimer > 0) { + this->itemTimer--; + if (this->itemTimer <= 0) { + this->canMove = 1; + } + } + + if (!Player_InCsMode(play)) { + uint8_t pressed = 0; + uint8_t released = 0; + uint8_t current = 0; + + if (this->usedItem == 0xFF && this->itemTimer <= 0) { + if (CHECK_BTN_ALL(sControlInput.press.button, BTN_CLEFT)) { + this->usedItem = gSaveContext.equips.cButtonSlots[0]; + this->usedItemButton = 0; + pressed = 1; + } else if (CHECK_BTN_ALL(sControlInput.press.button, BTN_CDOWN)) { + this->usedItem = gSaveContext.equips.cButtonSlots[1]; + this->usedItemButton = 1; + pressed = 1; + } else if (CHECK_BTN_ALL(sControlInput.press.button, BTN_CRIGHT)) { + this->usedItem = gSaveContext.equips.cButtonSlots[2]; + this->usedItemButton = 2; + pressed = 1; + } + } + + if (this->usedItem != 0xFF) { + if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_CLEFT) && this->usedItemButton == 0) { + current = 1; + } else if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_CDOWN) && this->usedItemButton == 1) { + current = 1; + } else if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_CRIGHT) && this->usedItemButton == 2) { + current = 1; + } + } + + if (this->usedItem != 0xFF) { + if (CHECK_BTN_ALL(sControlInput.rel.button, BTN_CLEFT) && this->usedItemButton == 0) { + released = 1; + } else if (CHECK_BTN_ALL(sControlInput.rel.button, BTN_CDOWN) && this->usedItemButton == 1) { + released = 1; + } else if (CHECK_BTN_ALL(sControlInput.rel.button, BTN_CRIGHT) && this->usedItemButton == 2) { + released = 1; + } + } + + if (pressed == 1) { + UseItem(this->usedItem, 1, this, play); + } else if (released == 1) { + UseItem(this->usedItem, 0, this, play); + this->usedItemButton = 0xFF; + } else if (current == 1) { + UseItem(this->usedItem, 2, this, play); + } + } else { + UseItem(this->usedItem, 0, this, play); + this->usedItem = 0xFF; + this->itemTimer = 10; + } + + if (CHECK_BTN_ALL(sControlInput.press.button, BTN_Z) && this->canMove) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_FAIRY_DASH); + } + + if (CHECK_BTN_ALL(sControlInput.cur.button, BTN_Z) && this->canMove) { + CenterIvanOnLink(this, play); + } else if (this->canMove == 1 && this->hookshotTarget == NULL) { + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + } + + SkelAnime_Update(&this->skelAnime); + + EnPartner_UpdateLights(this, play); +} + +s32 EnPartner_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx, + Gfx** gfx) { + static Vec3f zeroVec = { 0.0f, 0.0f, 0.0f }; + s32 pad; + f32 scale; + Vec3f mtxMult; + EnPartner* this = (EnPartner*)thisx; + + if (limbIndex == 8) { + scale = ((Math_SinS(4096) * 0.1f) + 1.0f) * 0.012f; + scale *= (this->actor.scale.x * 124.99999f); + Matrix_MultVec3f(&zeroVec, &mtxMult); + Matrix_Translate(mtxMult.x, mtxMult.y, mtxMult.z, MTXMODE_NEW); + Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); + } + + return false; +} + +void DrawOrb(Actor* thisx, PlayState* play, u8 color) { + EnPartner* this = (EnPartner*)thisx; + Vec3f pos; + Player* player = GET_PLAYER(play); + s32 pad; + f32 sp6C = play->state.frames & 0x1F; + + pos = this->actor.world.pos; + pos.y += 5.0f; + + pos.x -= (this->actor.scale.x * 300.0f * Math_SinS(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play))) * + Math_CosS(Camera_GetCamDirPitch(GET_ACTIVE_CAM(play)))); + pos.y -= (this->actor.scale.x * 300.0f * Math_SinS(Camera_GetCamDirPitch(GET_ACTIVE_CAM(play)))); + pos.z -= (this->actor.scale.x * 300.0f * Math_CosS(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play))) * + Math_CosS(Camera_GetCamDirPitch(GET_ACTIVE_CAM(play)))); + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_25Xlu(play->state.gfxCtx); + + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 255, 255); + + switch (color) { + case 1: + gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 255); + break; + case 2: + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 255, 255); + break; + case 3: + gDPSetEnvColor(POLY_XLU_DISP++, 0, 255, 0, 255); + break; + } + + Matrix_Translate(pos.x, pos.y, pos.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x * 3.0f, this->actor.scale.y * 3.0f, this->actor.scale.z * 3.0f, MTXMODE_APPLY); + Matrix_Mult(&play->billboardMtxF, MTXMODE_APPLY); + Matrix_Push(); + gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + Matrix_RotateZ(sp6C * (M_PI / 32), MTXMODE_APPLY); + gSPDisplayList(POLY_XLU_DISP++, gEffFlash1DL); + Matrix_Pop(); + Matrix_RotateZ(-sp6C * (M_PI / 32), MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gEffFlash1DL); + + CLOSE_DISPS(play->state.gfxCtx); +} + + +void EnPartner_Draw(Actor* thisx, PlayState* play) { + s32 pad; + f32 alphaScale; + s32 envAlpha; + EnPartner* this = (EnPartner*)thisx; + s32 pad1; + Gfx* dListHead; + Player* player = GET_PLAYER(play); + + if (play->pauseCtx.state != 0 && this->usedItem != 0xFF) { + UseItem(this->usedItem, 0, this, play); + this->usedItem = 0xFF; + } + + if (this->shouldDraw == 0) { + return; + } + + dListHead = Graph_Alloc(play->state.gfxCtx, sizeof(Gfx) * 4); + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_27Xlu(play->state.gfxCtx); + + envAlpha = (50) & 0x1FF; + envAlpha = (envAlpha > 255) ? 511 - envAlpha : envAlpha; + + alphaScale = 1.0f; + + gSPSegment(POLY_XLU_DISP++, 0x08, dListHead); + gDPPipeSync(dListHead++); + gDPSetPrimColor(dListHead++, 0, 0x01, (u8)this->innerColor.r, (u8)this->innerColor.g, (u8)this->innerColor.b, + (u8)(this->innerColor.a * alphaScale)); + + gDPSetRenderMode(dListHead++, G_RM_PASS, G_RM_ZB_CLD_SURF2); + + gSPEndDisplayList(dListHead++); + gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b, + (u8)(envAlpha * alphaScale)); + POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + EnPartner_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); + + CLOSE_DISPS(play->state.gfxCtx); + + if (this->usedSpell > 0) { + DrawOrb(this, play, this->usedSpell); + } +} diff --git a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.h b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.h new file mode 100644 index 000000000..8e3e1cf20 --- /dev/null +++ b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.h @@ -0,0 +1,48 @@ +#ifndef Z_EN_PARTNER_H +#define Z_EN_PARTNER_H + +#include +#include "global.h" +#include + +struct EnPartner; + +typedef void (*EnPartnerActionFunc)(struct EnPartner*, PlayState*); + +typedef struct EnPartner { + Actor actor; + + SkelAnime skelAnime; + + Vec3s jointTable[15]; + Vec3s morphTable[15]; + + ColliderCylinder collider; + + Color_RGBAf innerColor; + Color_RGBAf outerColor; + LightInfo lightInfoGlow; + LightNode* lightNodeGlow; + LightInfo lightInfoNoGlow; + LightNode* lightNodeNoGlow; + + f32 yVelocity; + + u8 canMove; + u8 usedItem; + u8 usedItemButton; + u8 usedSpell; + u8 damageTimer; + s16 magicTimer; + + u8 shouldDraw; + s16 itemTimer; + + GetItemEntry entry; + WeaponInfo stickWeaponInfo; + + EnBoom* boomerangActor; + Actor* hookshotTarget; +} EnPartner; + +#endif \ No newline at end of file diff --git a/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c b/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c index ce7c8f342..1d6ac8f88 100644 --- a/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c +++ b/soh/src/overlays/actors/ovl_En_fHG/z_en_fhg.c @@ -5,6 +5,7 @@ */ #include "z_en_fhg.h" +#include "textures/boss_title_cards/object_fhg.h" #include "objects/object_fhg/object_fhg.h" #include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h" #include "overlays/actors/ovl_Boss_Ganondrof/z_boss_ganondrof.h" @@ -332,7 +333,7 @@ void EnfHG_Intro(EnfHG* this, PlayState* play) { Math_ApproachF(&this->cameraSpeedMod, 1.0f, 1.0f, 0.05f); if (this->timers[0] == 75) { TitleCard_InitBossName(play, &play->actorCtx.titleCtx, - SEGMENTED_TO_VIRTUAL(gPhantomGanonTitleCardTex), 160, 180, 128, 40, true); + SEGMENTED_TO_VIRTUAL(gPhantomGanonTitleCardENGTex), 160, 180, 128, 40, true); } if (this->timers[0] == 0) { this->cutsceneState = INTRO_RETREAT; 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 8b94847dd..58147efd5 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -24,6 +24,7 @@ #include "soh/Enhancements/item-tables/ItemTableTypes.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h" +#include typedef enum { /* 0x00 */ KNOB_ANIM_ADULT_L, @@ -136,6 +137,7 @@ s32 func_80835800(Player* this, PlayState* play); s32 func_80835884(Player* this, PlayState* play); // Start aiming boomerang s32 func_808358F0(Player* this, PlayState* play); // Aim boomerang s32 func_808359FC(Player* this, PlayState* play); // Throw boomerang +s32 spawn_boomerang_ivan(EnPartner* this, PlayState* play); // Throw boomerang Ivan s32 func_80835B60(Player* this, PlayState* play); // Boomerang active s32 func_80835C08(Player* this, PlayState* play); void func_80835F44(PlayState* play, Player* this, s32 item); @@ -2799,6 +2801,27 @@ s32 func_808359FC(Player* this, PlayState* play) { return 1; } +s32 spawn_boomerang_ivan(EnPartner* this, PlayState* play) { + if (!CVarGetInteger("gIvanCoopModeEnabled", 0)) { + return 0; + } + + f32 posX = (Math_SinS(this->actor.shape.rot.y) * 1.0f) + this->actor.world.pos.x; + f32 posZ = (Math_CosS(this->actor.shape.rot.y) * 1.0f) + this->actor.world.pos.z; + s32 yaw = this->actor.shape.rot.y; + EnBoom* boomerang = + (EnBoom*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOOM, posX, this->actor.world.pos.y + 7.0f, posZ, + this->actor.focus.rot.x, yaw, 0, 0, true); + + this->boomerangActor = &boomerang->actor; + if (boomerang != NULL) { + boomerang->returnTimer = 20; + Audio_PlayActorSound2(&this->actor, NA_SE_IT_BOOMERANG_THROW); + } + + return 1; +} + s32 func_80835B60(Player* this, PlayState* play) { if (func_80834758(play, this)) { return 1; @@ -6998,7 +7021,10 @@ void func_8084029C(Player* this, f32 arg1) { arg1 = 7.25f; } - if ((this->currentBoots == PLAYER_BOOTS_HOVER) && !(this->actor.bgCheckFlags & 1) && (this->hoverBootsTimer != 0)) { + if ((this->currentBoots == PLAYER_BOOTS_HOVER || + (CVarGetInteger("gIvanCoopModeEnabled", 0) && this->ivanFloating)) && + !(this->actor.bgCheckFlags & 1) && + (this->hoverBootsTimer != 0 || (CVarGetInteger("gIvanCoopModeEnabled", 0) && this->ivanFloating))) { func_8002F8F0(&this->actor, NA_SE_PL_HOBBERBOOTS_LV - SFX_FLAG); } else if (func_8084021C(this->unk_868, arg1, 29.0f, 10.0f) || func_8084021C(this->unk_868, arg1, 29.0f, 24.0f)) { func_808327F8(this, this->linearVelocity); @@ -9591,6 +9617,8 @@ void Player_InitCommon(Player* this, PlayState* play, FlexSkeletonHeader* skelHe Collider_SetQuad(play, &this->meleeWeaponQuads[1], &this->actor, &D_80854650); Collider_InitQuad(play, &this->shieldQuad); Collider_SetQuad(play, &this->shieldQuad, &this->actor, &D_808546A0); + + this->ivanDamageMultiplier = 1; } static void (*D_80854738[])(PlayState* play, Player* this) = { @@ -9925,13 +9953,16 @@ void func_808473D4(PlayState* play, Player* this) { s32 func_80847A78(Player* this) { s32 cond; - if ((this->currentBoots == PLAYER_BOOTS_HOVER) && (this->hoverBootsTimer != 0)) { + if ((this->currentBoots == PLAYER_BOOTS_HOVER || + (CVarGetInteger("gIvanCoopModeEnabled", 0) && this->ivanFloating)) && + (this->hoverBootsTimer != 0)) { this->hoverBootsTimer--; } else { this->hoverBootsTimer = 0; } - cond = (this->currentBoots == PLAYER_BOOTS_HOVER) && + cond = (this->currentBoots == PLAYER_BOOTS_HOVER || + (CVarGetInteger("gIvanCoopModeEnabled", 0) && this->ivanFloating)) && ((this->actor.yDistToWater >= 0.0f) || (func_80838144(D_808535E4) >= 0) || func_8083816C(D_808535E4)); if (cond && (this->actor.bgCheckFlags & 1) && (this->hoverBootsTimer != 0)) { @@ -11123,7 +11154,9 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, if (CVarGetInteger("gFixIceTrapWithBunnyHood", 1)) Matrix_Pop(); } - if ((this->currentBoots == PLAYER_BOOTS_HOVER) && !(this->actor.bgCheckFlags & 1) && + if ((this->currentBoots == PLAYER_BOOTS_HOVER || + (CVarGetInteger("gIvanCoopModeEnabled", 0) && this->ivanFloating)) && + !(this->actor.bgCheckFlags & 1) && !(this->stateFlags1 & PLAYER_STATE1_23) && (this->hoverBootsTimer != 0)) { s32 sp5C; s32 hoverBootsTimer = this->hoverBootsTimer; @@ -11207,8 +11240,9 @@ void Player_Draw(Actor* thisx, PlayState* play2) { lod = 1; } - if (CVarGetInteger("gDisableLOD", 0) != 0) + if (CVarGetInteger("gDisableLOD", 0) != 0) { lod = 0; + } func_80093C80(play); Gfx_SetupDL_25Xlu(play->state.gfxCtx); 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 316956de3..171766609 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 @@ -42,65 +42,6 @@ void FileChoose_DrawTextureI8(GraphicsContext* gfxCtx, const void* texture, s16 CLOSE_DISPS(gfxCtx); } -void FileChoose_DrawRawImageRGBA32(GraphicsContext* gfxCtx, s16 centerX, s16 centerY, const char* source, u32 width, u32 height) { - u8* curTexture; - s32 textureCount; - u32 rectLeft; - u32 rectTop; - u32 textureHeight; - s32 remainingSize; - s32 textureSize; - s32 pad; - s32 i; - - OPEN_DISPS(gfxCtx); - - source = GetResourceDataByName(source, false); - - curTexture = source; - rectLeft = centerX - (width / 2); - rectTop = centerY - (height / 2); - textureHeight = 4096 / (width << 2); - remainingSize = (width * height) << 2; - textureSize = (width * textureHeight) << 2; - textureCount = remainingSize / textureSize; - if ((remainingSize % textureSize) != 0) { - textureCount += 1; - } - - gDPSetTileCustom(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 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); - - remainingSize -= textureSize; - - for (i = 0; i < textureCount; i++) { - gDPSetTextureImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, curTexture); - - gDPLoadSync(POLY_OPA_DISP++); - gDPLoadTile(POLY_OPA_DISP++, G_TX_LOADTILE, 0, 0, (width - 1) << 2, (textureHeight - 1) << 2); - - gSPTextureRectangle(POLY_OPA_DISP++, rectLeft << 2, rectTop << 2, (rectLeft + (s32)width) << 2, - (rectTop + textureHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - - curTexture += textureSize; - rectTop += textureHeight; - - if ((remainingSize - textureSize) < 0) { - if (remainingSize > 0) { - textureHeight = remainingSize / (s32)(width << 2); - remainingSize -= textureSize; - - gDPSetTileCustom(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 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); - } - } else { - remainingSize -= textureSize; - } - } - CLOSE_DISPS(gfxCtx); -} - void FileChoose_DrawImageRGBA32(GraphicsContext* gfxCtx, s16 centerX, s16 centerY, const char* source, u32 width, u32 height) { u8* curTexture; s32 textureCount; @@ -114,49 +55,19 @@ void FileChoose_DrawImageRGBA32(GraphicsContext* gfxCtx, s16 centerX, s16 center OPEN_DISPS(gfxCtx); - source = GetResourceDataByName(source, false); - - curTexture = source; rectLeft = centerX - (width / 2); rectTop = centerY - (height / 2); - textureHeight = 4096 / (width << 2); - remainingSize = (width * height) << 2; - textureSize = (width * textureHeight) << 2; - textureCount = remainingSize / textureSize; - if ((remainingSize % textureSize) != 0) { - textureCount += 1; - } - - gDPSetTileCustom(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 0, G_TX_NOMIRROR | G_TX_CLAMP, + + gDPSetTileCustom(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, 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); - - remainingSize -= textureSize; - - for (i = 0; i < textureCount; i++) { - gDPSetTextureImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, curTexture); - - gDPLoadSync(POLY_OPA_DISP++); - gDPLoadTile(POLY_OPA_DISP++, G_TX_LOADTILE, 0, 0, (width - 1) << 2, (textureHeight - 1) << 2); - - gSPTextureRectangle(POLY_OPA_DISP++, rectLeft << 2, rectTop << 2, (rectLeft + (s32)width) << 2, - (rectTop + textureHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - - curTexture += textureSize; - rectTop += textureHeight; - - if ((remainingSize - textureSize) < 0) { - if (remainingSize > 0) { - textureHeight = remainingSize / (s32)(width << 2); - remainingSize -= textureSize; - - gDPSetTileCustom(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, textureHeight, 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); - } - } else { - remainingSize -= textureSize; - } - } + + gDPSetTextureImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_32b, width, source); + + gDPLoadSync(POLY_OPA_DISP++); + gDPLoadTile(POLY_OPA_DISP++, G_TX_LOADTILE, 0, 0, (width - 1) << 2, (height - 1) << 2); + + gSPTextureRectangle(POLY_OPA_DISP++, rectLeft << 2, rectTop << 2, (rectLeft + (s32)width) << 2, + (rectTop + height) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); CLOSE_DISPS(gfxCtx); } @@ -1479,7 +1390,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { char* tex = (this->configMode == CM_QUEST_MENU || this->configMode == CM_ROTATE_TO_NAME_ENTRY || this->configMode == CM_START_QUEST_MENU || this->configMode == CM_QUEST_TO_MAIN || this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU) - ? GetResourceDataByName(FileChoose_GetQuestChooseTitleTexName(gSaveContext.language), false) + ? FileChoose_GetQuestChooseTitleTexName(gSaveContext.language) : sTitleLabels[gSaveContext.language][this->titleLabel]; OPEN_DISPS(this->state.gfxCtx); @@ -1549,7 +1460,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { FileChoose_DrawTextureI8(this->state.gfxCtx, gTitleTheLegendOfTextTex, 72, 8, 156, 108, 72, 8, 1024, 1024); FileChoose_DrawTextureI8(this->state.gfxCtx, gTitleOcarinaOfTimeTMTextTex, 96, 8, 154, 163, 96, 8, 1024, 1024); FileChoose_DrawImageRGBA32(this->state.gfxCtx, 160, 135, ResourceMgr_GameHasOriginal() ? gTitleZeldaShieldLogoTex : gTitleZeldaShieldLogoMQTex, 160, 160); - FileChoose_DrawRawImageRGBA32(this->state.gfxCtx, 182, 180, "__OTR__objects/object_mag/gTitleRandomizerSubtitleTex", 128, 32); + FileChoose_DrawImageRGBA32(this->state.gfxCtx, 182, 180, "__OTR__objects/object_mag/gTitleRandomizerSubtitleTex", 128, 32); break; } } else if (this->configMode != CM_ROTATE_TO_NAME_ENTRY) { @@ -1625,7 +1536,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { this->nameAlpha[i]); } gDPLoadTextureBlock(POLY_OPA_DISP++, - GetResourceDataByName("__OTR__textures/title_static/gFileSelRANDButtonTex", false), + "__OTR__textures/title_static/gFileSelRANDButtonTex", G_IM_FMT_IA, G_IM_SIZ_16b, 44, 16, 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); gSP1Quadrangle(POLY_OPA_DISP++, 8, 10, 11, 9, 0); @@ -1642,7 +1553,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { this->nameAlpha[i]); } gDPLoadTextureBlock(POLY_OPA_DISP++, - GetResourceDataByName("__OTR__textures/title_static/gFileSelMQButtonTex", false), + "__OTR__textures/title_static/gFileSelMQButtonTex", G_IM_FMT_IA, G_IM_SIZ_16b, 44, 16, 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); gSP1Quadrangle(POLY_OPA_DISP++, 8, 10, 11, 9, 0); diff --git a/soh/src/overlays/gamestates/ovl_title/z_title.c b/soh/src/overlays/gamestates/ovl_title/z_title.c index 2597b695b..2ba99231a 100644 --- a/soh/src/overlays/gamestates/ovl_title/z_title.c +++ b/soh/src/overlays/gamestates/ovl_title/z_title.c @@ -128,6 +128,12 @@ void Title_SetupView(TitleContext* this, f32 x, f32 y, f32 z) { func_800AAA50(view, 0xF); } +#define dgShipLogoDL "__OTR__textures/nintendo_rogo_static/gShipLogoDL" +static const ALIGN_ASSET(2) char gShipLogoDL[] = dgShipLogoDL; + +#define dnintendo_rogo_static_Tex_LUS_000000 "__OTR__textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000" +static const ALIGN_ASSET(2) char nintendo_rogo_static_Tex_LUS_000000[] = dnintendo_rogo_static_Tex_LUS_000000; + void Title_Draw(TitleContext* this) { static s16 sTitleRotY = 0; static Lights1 sTitleLights = gdSPDefLights1(0x64, 0x64, 0x64, 0xFF, 0xFF, 0xFF, 0x45, 0x45, 0x45); @@ -152,8 +158,6 @@ void Title_Draw(TitleContext* this) { v1.z = 0; v2.z = 1119.0837; - char* n64LogoTex = GetResourceDataByName(nintendo_rogo_static_Tex_000000, false); - func_8002EABC(&v1, &v2, &v3, this->state.gfxCtx); gSPSetLights1(POLY_OPA_DISP++, sTitleLights); Title_SetupView(this, 0, 150.0, 300.0); @@ -163,7 +167,11 @@ void Title_Draw(TitleContext* this) { Matrix_RotateZYX(0, sTitleRotY, 0, MTXMODE_APPLY); gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(this->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(POLY_OPA_DISP++, gNintendo64LogoDL); + if (CVarGetInteger("gAuthenticLogo", 0)) { + gSPDisplayList(POLY_OPA_DISP++, gNintendo64LogoDL); + } else { + gSPDisplayList(POLY_OPA_DISP++, gShipLogoDL); + } Gfx_SetupDL_39Opa(this->state.gfxCtx); gDPPipeSync(POLY_OPA_DISP++); gDPSetCycleType(POLY_OPA_DISP++, G_CYC_2CYCLE); @@ -184,9 +192,12 @@ void Title_Draw(TitleContext* this) { for (idx = 0, y = 94; idx < 16; idx++, y += 2) { - gDPLoadTextureBlock(POLY_OPA_DISP++, &n64LogoTex[0x180 * idx], G_IM_FMT_I, - G_IM_SIZ_8b, 192, 2, 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); + gDPLoadMultiTile(POLY_OPA_DISP++, CVarGetInteger("gAuthenticLogo", 0) ? nintendo_rogo_static_Tex_000000 : nintendo_rogo_static_Tex_LUS_000000, 0, G_TX_RENDERTILE, G_IM_FMT_I, G_IM_SIZ_8b, 192, 32, + 0, idx * 2, 192 - 1, (idx + 1) * 2 - 1, 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); + + gDPSetTileSize(POLY_OPA_DISP++, 0, 0, 0, (192 - 1) << G_TEXTURE_IMAGE_FRAC, + (2 - 1) << G_TEXTURE_IMAGE_FRAC); gDPSetTileSize(POLY_OPA_DISP++, 1, this->uls, (this->ult & 0x7F) - idx * 4, 0, 0); gSPTextureRectangle(POLY_OPA_DISP++, 388, y << 2, 1156, (y + 2) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); @@ -226,7 +237,7 @@ void Title_Main(GameState* thisx) { Title_Calc(this); Title_Draw(this); - if (!CVarGetInteger("gHideBuildInfo", 0)) { + if (!CVarGetInteger("gAuthenticLogo", 0)) { Gfx* gfx = POLY_OPA_DISP; s32 pad; 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 db487b3fc..4d1c65ad4 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 @@ -341,15 +341,15 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[60], 8, 0); // The dungeon map textures are recreated each frame, so always invalidate them - gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment); - gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment + 0x800); + gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]); + gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]); - gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegment, G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | G_TX_NOMIRROR, + gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 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); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); - gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegment + 0x800, G_IM_FMT_CI, 48, 85, 0, + gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 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); @@ -513,9 +513,10 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[188], 32, 0); for (j = t = i = 0; i < 8; i++, t++, j += 4) { - gDPLoadTextureBlock(POLY_KAL_DISP++, (u8*)GetResourceDataByName(gWorldMapImageTex, false) + t * 216 * 9, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 9, - 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); + gDPLoadMultiTile(POLY_KAL_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 128, 0, t * 9, 216 - 1, + (t + 1) * 9 - 1, 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); + gDPSetTileSize(POLY_KAL_DISP++, G_TX_RENDERTILE, 0, 0, (216 - 1) << G_TEXTURE_IMAGE_FRAC, (9 - 1) << G_TEXTURE_IMAGE_FRAC); gSP1Quadrangle(POLY_KAL_DISP++, j, j + 2, j + 3, j + 1, 0); } @@ -524,16 +525,20 @@ void KaleidoScope_DrawWorldMap(PlayState* play, GraphicsContext* gfxCtx) { for (j = i = 0; i < 6; i++, t++, j += 4) { - gDPLoadTextureBlock(POLY_KAL_DISP++, (u8*)GetResourceDataByName(gWorldMapImageTex, false) + t * 216 * 9, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 9, - 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); + gDPLoadMultiTile(POLY_KAL_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 128, + 0, t * 9, 216 - 1, (t + 1) * 9 - 1, 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); + gDPSetTileSize(POLY_KAL_DISP++, G_TX_RENDERTILE, 0, 0, (216 - 1) << G_TEXTURE_IMAGE_FRAC, + (9 - 1) << G_TEXTURE_IMAGE_FRAC); gSP1Quadrangle(POLY_KAL_DISP++, j, j + 2, j + 3, j + 1, 0); } - gDPLoadTextureBlock(POLY_KAL_DISP++, (u8*)GetResourceDataByName(gWorldMapImageTex, false) + t * 216 * 9, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 2, 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); + gDPLoadMultiTile(POLY_KAL_DISP++, gWorldMapImageTex, 0, G_TX_RENDERTILE, G_IM_FMT_CI, G_IM_SIZ_8b, 216, 128, 0, + t * 9, 216 - 1, (t * 9 + 2) - 1, 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); + gDPSetTileSize(POLY_KAL_DISP++, G_TX_RENDERTILE, 0, 0, (216 - 1) << G_TEXTURE_IMAGE_FRAC, + (2 - 1) << G_TEXTURE_IMAGE_FRAC); gSP1Quadrangle(POLY_KAL_DISP++, j, j + 2, j + 3, j + 1, 0); } else if (HREG(15) == 1) { 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 213fc5ce8..dfd7fae49 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 @@ -820,7 +820,7 @@ Gfx* KaleidoScope_QuadTextureIA8(Gfx* gfx, void* texture, s16 width, s16 height, return gfx; } -void KaleidoScope_OverridePalIndexCI4(u8* texture, ptrdiff_t size, s32 targetIndex, s32 newIndex) { +void KaleidoScope_OverridePalIndexCI4(u8* texture, s32 size, s32 targetIndex, s32 newIndex) { s32 i; targetIndex &= 0xF; @@ -2079,7 +2079,7 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { } const char* textureName = mapNameTextures[sp2A]; - memcpy(pauseCtx->nameSegment, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); + memcpy(pauseCtx->nameSegment, textureName, strlen(textureName) + 1); } else { osSyncPrintf("zoom_name=%d\n", pauseCtx->namedItem); @@ -2093,7 +2093,7 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { osSyncPrintf("J_N=%d point=%d\n", gSaveContext.language, sp2A); const char* textureName = iconNameTextures[sp2A]; - memcpy(pauseCtx->nameSegment, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); + memcpy(pauseCtx->nameSegment, textureName, strlen(textureName) + 1); } pauseCtx->nameDisplayTimer = 0; @@ -3045,31 +3045,6 @@ uint32_t _bswap32(uint32_t a) return a; } -void KaleidoScope_GrayOutTextureRGBA32(u32* texture, u16 pixelCount) { - u32 rgb; - u16 gray; - u16 i; - - texture = GetResourceDataByName(texture, false); - - for (i = 0; i < pixelCount; i++) { - uint32_t px = texture[i]; - if ((px & 0xFFFFFF00) != 0) { - u8 a = (px & 0xFF000000) >> 24; - u8 b = (px & 0x00FF0000) >> 16; - u8 g = (px & 0x0000FF00) >> 8; - u8 r = (px & 0x000000FF) >> 0; - gray = (r + g + b) / 7; - - r = gray; - g = gray; - b = gray; - - texture[i] = (a << 24) + (b << 16) + (g << 8) + (r << 0); - } - } -} - void func_808265BC(PlayState* play) { PauseContext* pauseCtx = &play->pauseCtx; @@ -3194,11 +3169,10 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx) { void KaleidoScope_LoadDungeonMap(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; - char* firstTextureName = sDungeonMapTexs[R_MAP_TEX_INDEX]; - char* secondTextureName = sDungeonMapTexs[R_MAP_TEX_INDEX + 1]; - - memcpy(interfaceCtx->mapSegment, GetResourceDataByName(firstTextureName, false), GetResourceTexSizeByName(firstTextureName, false)); - memcpy(interfaceCtx->mapSegment + 0x800, GetResourceDataByName(secondTextureName, false), GetResourceTexSizeByName(secondTextureName, false)); + interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX]; + interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1]; + interfaceCtx->mapSegment[0] = GetResourceDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX], true); + interfaceCtx->mapSegment[1] = GetResourceDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX + 1], true); } void KaleidoScope_UpdateDungeonMap(PlayState* play) { @@ -3212,13 +3186,15 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) { if ((play->sceneNum >= SCENE_YDAN) && (play->sceneNum <= SCENE_TAKARAYA)) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { - KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment, 2040, interfaceCtx->mapPaletteIndex, 14); + // HDTODO: Handle Runtime Modified Textures (HD) + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], 2040, interfaceCtx->mapPaletteIndex, 14); } } if ((play->sceneNum >= SCENE_YDAN) && (play->sceneNum <= SCENE_TAKARAYA)) { if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) { - KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment + 0x800, 2040, interfaceCtx->mapPaletteIndex, 14); + // HDTODO: Handle Runtime Modified Textures (HD) + KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], 2040, interfaceCtx->mapPaletteIndex, 14); } } } @@ -3375,19 +3351,13 @@ void KaleidoScope_Update(PlayState* play) osSyncPrintf("サイズ=%x\n", size2 + size1 + size0 + size + 0x800); if (((void)0, gSaveContext.worldMapArea) < 22) { - if (gSaveContext.language == LANGUAGE_ENG) { - const char* textureName = mapNameTextures[36 + gSaveContext.worldMapArea]; - memcpy(pauseCtx->nameSegment + 0x400, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); - } else if (gSaveContext.language == LANGUAGE_GER) { - const char* textureName = mapNameTextures[58 + gSaveContext.worldMapArea]; - memcpy(pauseCtx->nameSegment + 0x400, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); - } else { - const char* textureName = mapNameTextures[80 + gSaveContext.worldMapArea]; - memcpy(pauseCtx->nameSegment + 0x400, GetResourceDataByName(textureName, false), GetResourceTexSizeByName(textureName, false)); - } + const uint8_t offsets[] = { 36, 58, 80 }; + const char* textureName = mapNameTextures[offsets[gSaveContext.language] + gSaveContext.worldMapArea]; + memcpy(pauseCtx->nameSegment + 0x400, textureName, strlen(textureName) + 1); } // OTRTODO - player on pause #if 1 + // HDTODO: Remove sPreRenderCvg stuff? sPreRenderCvg = (void*)(((uintptr_t)pauseCtx->nameSegment + 0x400 + 0xA00 + 0xF) & ~0xF); PreRender_Init(&sPlayerPreRender); @@ -4260,6 +4230,6 @@ void KaleidoScope_Update(PlayState* play) osSyncPrintf(VT_RST); break; } - + GameInteractor_ExecuteOnKaleidoscopeUpdate(sInDungeonScene); }