Merge branch 'develop' of garrettjoecox.github.com:HarbourMasters/Shipwright into develop-rando-merge

This commit is contained in:
Garrett Cox 2024-02-02 09:15:34 -06:00
commit 04c106d8f7
73 changed files with 2237 additions and 989 deletions

View File

@ -1 +1 @@
libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev ninja-build
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev ninja-build

View File

@ -13,22 +13,37 @@ jobs:
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-soh-otr-ccache
key: ${{ runner.os }}-otr-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-otr-ccache-${{ github.ref }}
${{ runner.os }}-otr-ccache-
- name: Install dependencies
if: ${{ !vars.LINUX_RUNNER }}
run: |
sudo apt-get update
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt)
- name: Cache build folders
uses: actions/cache@v4
with:
key: ${{ runner.os }}-otr-build-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-otr-build-${{ github.ref }}
${{ runner.os }}-otr-build-
path: |
build-cmake
SDL2-2.28.5
- name: Install latest SDL
if: ${{ !vars.LINUX_RUNNER }}
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
tar -xzf SDL2-2.26.1.tar.gz
cd SDL2-2.26.1
./configure
if [ ! -d "SDL2-2.28.5" ]; then
wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
tar -xzf SDL2-2.28.5.tar.gz
fi
cd SDL2-2.28.5
./configure --enable-hidapi-libusb
make -j 10
sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
@ -37,7 +52,7 @@ jobs:
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-cmake --config Release --target GenerateSohOtr
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: soh.otr
path: soh.otr
@ -50,9 +65,12 @@ jobs:
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-ccache
key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-ccache-${{ github.ref }}
${{ runner.os }}-ccache-
- name: Install gtar wrapper
if: ${{ !vars.MAC_RUNNER }}
run: |
@ -85,7 +103,7 @@ jobs:
sudo port install $(cat .github/workflows/macports-deps.txt)
brew install ninja
- name: Download soh.otr
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: soh.otr
- name: Build SoH
@ -99,7 +117,7 @@ jobs:
mv _packages/*.dmg SoH.dmg
mv README.md readme.txt
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: soh-mac
path: |
@ -128,17 +146,32 @@ jobs:
sudo apt-get update
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt)
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ matrix.os }}-ccache
key: ${{ matrix.os }}-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ matrix.os }}-ccache-${{ github.ref }}
${{ matrix.os }}-ccache-
- name: Cache build folders
uses: actions/cache@v4
with:
key: ${{ matrix.os }}-build-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ matrix.os }}-build-${{ github.ref }}
${{ matrix.os }}-build-
path: |
SDL2-2.28.5
SDL2_net-2.2.0
- name: Install latest SDL
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
tar -xzf SDL2-2.26.1.tar.gz
cd SDL2-2.26.1
./configure
if [ ! -d "SDL2-2.28.5" ]; then
wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
tar -xzf SDL2-2.28.5.tar.gz
fi
cd SDL2-2.28.5
./configure --enable-hidapi-libusb
make -j 10
sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
@ -146,15 +179,17 @@ jobs:
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
tar -xzf SDL2_net-2.2.0.tar.gz
if [ ! -d "SDL2_net-2.2.0" ]; then
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
tar -xzf SDL2_net-2.2.0.tar.gz
fi
cd SDL2_net-2.2.0
./configure
make -j 10
sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
- name: Download soh.otr
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: soh.otr
- name: Build SoH
@ -170,7 +205,7 @@ jobs:
CC: gcc-${{ matrix.gcc }}
CXX: g++-${{ matrix.gcc }}
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: soh-linux-${{ matrix.archive-suffix }}
path: |
@ -180,7 +215,7 @@ jobs:
needs: generate-soh-otr
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
container:
image: devkitpro/devkita64:latest
image: devkitpro/devkita64:20240120
steps:
- name: Install dependencies
run: |
@ -193,9 +228,12 @@ jobs:
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-switch-ccache
key: ${{ runner.os }}-switch-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-switch-ccache-${{ github.ref }}
${{ runner.os }}-switch-ccache-
- name: Build SoH
run: |
cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
@ -204,11 +242,11 @@ jobs:
mv build-switch/soh/*.nro soh.nro
mv README.md readme.txt
- name: Download soh.otr
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: soh.otr
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: soh-switch
path: |
@ -230,9 +268,12 @@ jobs:
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-wiiu-ccache
key: ${{ runner.os }}-wiiu-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-wiiu-ccache-${{ github.ref }}
${{ 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
@ -245,11 +286,11 @@ jobs:
DEVKITPRO: /opt/devkitpro
DEVKITPPC: /opt/devkitpro/devkitPPC
- name: Download soh.otr
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: soh.otr
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: soh-wiiu
path: |
@ -270,15 +311,25 @@ jobs:
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-ccache
- name: vcpkg
uses: johnwason/vcpkg-action@v5
variant: sccache
max-size: "1G"
key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-ccache-${{ github.ref }}
${{ runner.os }}-ccache-
- name: Cache build folder
uses: actions/cache@v4
with:
pkgs: zlib bzip2 libpng sdl2 sdl2-net glew glfw3
token: ${{ github.token }}
triplet: 'x64-windows-static'
save-always: true
key: ${{ runner.os }}-build-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-build-${{ github.ref }}
${{ runner.os }}-build-
path: |
build-windows
vcpkg
- name: Configure Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Build SoH
@ -286,7 +337,7 @@ jobs:
VCPKG_ROOT: ${{github.workspace}}/vcpkg
run: |
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DBUILD_REMOTE_CONTROL=1
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DBUILD_REMOTE_CONTROL=1
cmake --build build-windows --config Release --parallel 10
mkdir soh-windows
@ -299,12 +350,12 @@ jobs:
mv ./build-windows/gamecontrollerdb.txt ./soh-windows/gamecontrollerdb.txt
mv ./x64/Release/assets ./soh-windows
- name: Download soh.otr
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: soh.otr
path: soh-windows
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: soh-windows
path: soh-windows

View File

@ -8,5 +8,9 @@ if(MSVC)
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc")
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Z7")
else()
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
endif()
endif()

View File

@ -14,13 +14,17 @@ add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(CMake/automate-vcpkg.cmake)
include(CMake/automate-vcpkg.cmake)
set(VCPKG_TRIPLET x64-windows-static)
set(VCPKG_TARGET_TRIPLET x64-windows-static)
set(VCPKG_TRIPLET x64-windows-static)
set(VCPKG_TARGET_TRIPLET x64-windows-static)
vcpkg_bootstrap()
vcpkg_install_packages(zlib bzip2 libpng sdl2 sdl2-net glew glfw3)
vcpkg_bootstrap()
vcpkg_install_packages(zlib bzip2 libpng sdl2 sdl2-net glew glfw3)
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
endif()
endif()
################################################################################

@ -1 +1 @@
Subproject commit 04b85b95fab07a394b62dcd28a502a3040f08e0c
Subproject commit 44adc47b4da529e72d968b14cab94aefd8260f22

View File

@ -92,7 +92,7 @@ If you want to playtest a continuous integration build, you can find them at the
* [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.)_
* [Linux (compatibility)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatibility.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)
* [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip)

View File

@ -188,4 +188,4 @@ Assuming all went well, you can now push your changes to your fork with the foll
```bash
git push origin <YOUR BRANCH NAME>
```
```

@ -1 +1 @@
Subproject commit 15d57d806e39d7f19783e26acc1a062d402169c7
Subproject commit 0833afad66e96d2ec4bbc410186d7247dc243ee2

View File

@ -8,5 +8,9 @@ if(MSVC)
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc")
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Z7")
else()
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
endif()
endif()

View File

@ -328,7 +328,7 @@ endif()
include(FetchContent)
FetchContent_Declare(
Boost
URL https://sourceforge.net/projects/boost/files/boost/1.81.0/boost_1_81_0.tar.gz
URL https://archives.boost.io/release/1.81.0/source/boost_1_81_0.tar.gz
URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6
SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it)
DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change

View File

@ -4,4 +4,4 @@
*.cfg
*.vtx.inc
*.dlist.inc
*.txt
!*.png

View File

@ -0,0 +1,15 @@
Complete triforce:
DL name: gTriforcePieceCompletedDL
Export Path: objects/object_triforce_completed
Shard 0:
DL name: gTriforcePiece0DL
Export Path: objects/object_triforce_piece_0
Shard 1:
DL name: gTriforcePiece1DL
Export Path: objects/object_triforce_piece_1
Shard 2:
DL name: gTriforcePiece2DL
Export Path: objects/object_triforce_piece_2

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

View File

@ -2210,6 +2210,14 @@ s8 PadUtils_GetRelYImpl(Input* input);
s8 PadUtils_GetRelX(Input* input);
s8 PadUtils_GetRelY(Input* input);
void PadUtils_UpdateRelXY(Input* input);
s8 PadUtils_GetCurRX(Input* input);
s8 PadUtils_GetCurRY(Input* input);
void PadUtils_SetRelRXY(Input* input, s32 x, s32 y);
s8 PadUtils_GetRelRXImpl(Input* input);
s8 PadUtils_GetRelRYImpl(Input* input);
s8 PadUtils_GetRelRX(Input* input);
s8 PadUtils_GetRelRY(Input* input);
void PadUtils_UpdateRelRXY(Input* input);
s32 PadSetup_Init(OSMesgQueue* mq, u8* outMask, OSContStatus* status);
f32 Math_FTanF(f32 x);
f32 Math_FFloorF(f32 x);

View File

@ -744,7 +744,6 @@ typedef struct {
/* 0x0134 */ char** doActionSegment;
/* 0x0138 */ u8* iconItemSegment;
/* 0x013C */ char** mapSegment;
char** mapSegmentName;
/* 0x0140 */ u8 mapPalette[32];
/* 0x0160 */ DmaRequest dmaRequest_160;
/* 0x0180 */ DmaRequest dmaRequest_180;
@ -815,6 +814,10 @@ typedef struct {
/* 0x026C */ u8 dinsNayrus; // "m_magic"; din's fire and nayru's love
/* 0x026D */ u8 all; // "another"; enables all item restrictions
} restrictions;
// #region SOH [General]
/* */ char* mapSegmentName[2]; // Tracks the map segment texture by OTR sig name
/* */ u8 mapPalettesPulse[40][32]; // Used to have unique pointers per map pulse color for the shader backend. 40 for map pulse timer x2
// #endregion
} InterfaceContext; // size = 0x270
typedef struct {

View File

@ -12,6 +12,7 @@
#include <Utils/StringHelper.h>
#include "../../UIWidgets.hpp"
#include "AudioCollection.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
Vec3f pos = { 0.0f, 0.0f, 0.0f };
f32 freqScale = 1.0f;
@ -78,7 +79,12 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
void RandomizeGroup(SeqType type) {
std::vector<u16> values;
// An empty IncludedSequences set means that the AudioEditor window has never been drawn
if (AudioCollection::Instance->GetIncludedSequences().empty()) {
AudioCollection::Instance->InitializeShufflePool();
}
// use a while loop to add duplicates if we don't have enough included sequences
while (values.size() < AuthenticCountBySequenceType(type)) {
for (const auto& seqData : AudioCollection::Instance->GetIncludedSequences()) {
@ -123,6 +129,34 @@ void ResetGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
}
}
void LockGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
for (const auto& [defaultValue, seqData] : map) {
if (seqData.category == type) {
// Only save authentic sequence CVars
if (seqData.category == SEQ_FANFARE && defaultValue >= MAX_AUTHENTIC_SEQID) {
continue;
}
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
CVarSetInteger(cvarLockKey.c_str(), 1);
}
}
}
void UnlockGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
for (const auto& [defaultValue, seqData] : map) {
if (seqData.category == type) {
// Only save authentic sequence CVars
if (seqData.category == SEQ_FANFARE && defaultValue >= MAX_AUTHENTIC_SEQID) {
continue;
}
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
CVarSetInteger(cvarLockKey.c_str(), 0);
}
}
}
void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequenceType) {
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(sfxKey);
const std::string hiddenKey = "##" + cvarKey;
@ -163,6 +197,8 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
const std::string hiddenTabId = "##" + tabId;
const std::string resetAllButton = "Reset All" + hiddenTabId;
const std::string randomizeAllButton = "Randomize All" + hiddenTabId;
const std::string lockAllButton = "Lock All" + hiddenTabId;
const std::string unlockAllButton = "Unlock All" + hiddenTabId;
if (ImGui::Button(resetAllButton.c_str())) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
@ -184,6 +220,28 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
ReplayCurrentBGM();
}
}
ImGui::SameLine();
if (ImGui::Button(lockAllButton.c_str())) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
LockGroup(map, type);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
ReplayCurrentBGM();
}
}
ImGui::SameLine();
if (ImGui::Button(unlockAllButton.c_str())) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
UnlockGroup(map, type);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
ReplayCurrentBGM();
}
}
ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
@ -350,6 +408,19 @@ void DrawTypeChip(SeqType type) {
ImGui::EndDisabled();
}
void AudioEditorRegisterOnSceneInitHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (CVarGetInteger("gAudioEditor.RandomizeAllOnNewScene", 0)) {
AudioEditor_RandomizeAll();
}
});
}
void AudioEditor::InitElement() {
AudioEditorRegisterOnSceneInitHook();
}
void AudioEditor::DrawElement() {
AudioCollection::Instance->InitializeShufflePool();
@ -359,6 +430,28 @@ void AudioEditor::DrawElement() {
return;
}
float buttonSegments = ImGui::GetContentRegionAvail().x / 4;
if (ImGui::Button("Randomize All Groups", ImVec2(buttonSegments, 30.0f))) {
AudioEditor_RandomizeAll();
}
UIWidgets::Tooltip("Randomizes all unlocked music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Reset All Groups", ImVec2(buttonSegments, 30.0f))) {
AudioEditor_ResetAll();
}
UIWidgets::Tooltip("Resets all unlocked music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Lock All Groups", ImVec2(buttonSegments, 30.0f))) {
AudioEditor_LockAll();
}
UIWidgets::Tooltip("Locks all music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Unlock All Groups", ImVec2(buttonSegments, 30.0f))) {
AudioEditor_UnlockAll();
}
UIWidgets::Tooltip("Unlocks all music and sound effects across tab groups");
if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
if (ImGui::BeginTabItem("Background Music")) {
Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD);
@ -422,8 +515,8 @@ void AudioEditor::DrawElement() {
ImGui::PopItemWidth();
ImGui::NewLine();
ImGui::PopItemWidth();
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %f", "##linkVoiceFreqMultiplier",
"gLinkVoiceFreqMultiplier", 0.4, 2.5, "", 1.0, false, false);
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %.1f %%", "##linkVoiceFreqMultiplier",
"gLinkVoiceFreqMultiplier", 0.4, 2.5, "", 1.0, true, true);
ImGui::SameLine();
const std::string resetButton = "Reset##linkVoiceFreqMultiplier";
if (ImGui::Button(resetButton.c_str())) {
@ -431,6 +524,10 @@ void AudioEditor::DrawElement() {
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
ImGui::NewLine();
UIWidgets::EnhancementCheckbox("Randomize All Music and Sound Effects on New Scene", "gAudioEditor.RandomizeAllOnNewScene");
UIWidgets::Tooltip("Enables randomizing all unlocked music and sound effects when you enter a new scene.");
ImGui::NewLine();
ImGui::PushItemWidth(-FLT_MIN);
UIWidgets::PaddedSeparator();
@ -625,3 +722,19 @@ void AudioEditor_ResetAll() {
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
ReplayCurrentBGM();
}
void AudioEditor_LockAll() {
for (auto type : allTypes) {
LockGroup(AudioCollection::Instance->GetAllSequences(), type);
}
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
void AudioEditor_UnlockAll() {
for (auto type : allTypes) {
UnlockGroup(AudioCollection::Instance->GetAllSequences(), type);
}
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}

View File

@ -14,13 +14,15 @@ class AudioEditor : public LUS::GuiWindow {
using LUS::GuiWindow::GuiWindow;
void DrawElement() override;
void InitElement() override {};
void InitElement() override;
void UpdateElement() override {};
~AudioEditor() {};
};
void AudioEditor_RandomizeAll();
void AudioEditor_ResetAll();
void AudioEditor_LockAll();
void AudioEditor_UnlockAll();
extern "C" {
#endif

View File

@ -1,353 +0,0 @@
#include "GameControlEditor.h"
#include <string>
#include <list>
#include <unordered_map>
#include <utility>
#include <iterator>
#include <variables.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <ImGui/imgui.h>
#include <ImGui/imgui_internal.h>
#include <libultraship/bridge.h>
#include <libultraship/libultra/controller.h>
#include <Utils/StringHelper.h>
#include <libultraship/libultraship.h>
#include "macros.h"
#include "../../UIWidgets.hpp"
namespace GameControlEditor {
const ImGuiTableFlags PANEL_TABLE_FLAGS =
ImGuiTableFlags_BordersH |
ImGuiTableFlags_BordersV;
const ImGuiTableColumnFlags PANEL_TABLE_COLUMN_FLAGS =
ImGuiTableColumnFlags_IndentEnable |
ImGuiTableColumnFlags_NoSort;
namespace TableHelper {
void InitHeader(bool has_header = true) {
if (has_header) {
ImGui::TableHeadersRow();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding(); //This is to adjust Vertical pos of item in a cell to be normlized.
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextCol() {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextLine() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
}
void DrawHelpIcon(const std::string& helptext) {
// place the ? button to the most of the right side of the cell it is using.
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 15);
ImGui::SmallButton("?");
UIWidgets::Tooltip(helptext.c_str());
}
typedef uint32_t N64ButtonMask;
// Used together for an incomplete linked hash map implementation in order to
// map button masks to their names and original mapping on N64
static std::list<std::pair<N64ButtonMask, const char*>> buttons;
static std::unordered_map<N64ButtonMask, decltype(buttons)::iterator> buttonNames;
void addButtonName(N64ButtonMask mask, const char* name) {
buttons.push_back(std::make_pair(mask, name));
buttonNames[mask] = std::prev(buttons.end());
}
typedef struct {
const char* label;
const char* cVarName;
N64ButtonMask defaultBtn;
} CustomButtonMap;
// Ocarina button maps
static CustomButtonMap ocarinaD5 = {"D5", "gOcarinaD5BtnMap", BTN_CUP};
static CustomButtonMap ocarinaB4 = {"B4", "gOcarinaB4BtnMap", BTN_CLEFT};
static CustomButtonMap ocarinaA4 = {"A4", "gOcarinaA4BtnMap", BTN_CRIGHT};
static CustomButtonMap ocarinaF4 = {"F4", "gOcarinaF4BtnMap", BTN_CDOWN};
static CustomButtonMap ocarinaD4 = {"D4", "gOcarinaD4BtnMap", BTN_A};
static CustomButtonMap ocarinaSongDisable = {"Disable songs", "gOcarinaDisableBtnMap", BTN_L};
static CustomButtonMap ocarinaSharp = {"Pitch up", "gOcarinaSharpBtnMap", BTN_R};
static CustomButtonMap ocarinaFlat = {"Pitch down", "gOcarinaFlatBtnMap", BTN_Z};
void GameControlEditorWindow::InitElement() {
addButtonName(BTN_A, "A");
addButtonName(BTN_B, "B");
addButtonName(BTN_CUP, "C Up");
addButtonName(BTN_CDOWN, "C Down");
addButtonName(BTN_CLEFT, "C Left");
addButtonName(BTN_CRIGHT, "C Right");
addButtonName(BTN_L, "L");
addButtonName(BTN_Z, "Z");
addButtonName(BTN_R, "R");
addButtonName(BTN_START, "Start");
addButtonName(BTN_DUP, "D-pad up");
addButtonName(BTN_DDOWN, "D-pad down");
addButtonName(BTN_DLEFT, "D-pad left");
addButtonName(BTN_DRIGHT, "D-pad right");
addButtonName(0, "None");
}
// Draw a button mapping setting consisting of a padded label and button dropdown.
// excludedButtons indicates which buttons are unavailable to choose from.
void DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons) {
N64ButtonMask currentButton = CVarGetInteger(mapping.cVarName, mapping.defaultBtn);
const char* preview;
if (buttonNames.contains(currentButton)) {
preview = buttonNames[currentButton]->second;
} else {
preview = "Unknown";
}
UIWidgets::Spacer(0);
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 textSize = ImGui::CalcTextSize(mapping.label);
ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4);
ImGui::SetCursorPosX(cursorPos.x + abs(textSize.x - labelWidth));
ImGui::Text("%s", mapping.label);
ImGui::SameLine();
ImGui::SetCursorPosY(cursorPos.y);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
if (ImGui::BeginCombo(StringHelper::Sprintf("##%s", mapping.cVarName).c_str(), preview)) {
for (auto i = buttons.begin(); i != buttons.end(); i++) {
if ((i->first & excludedButtons) != 0) {
continue;
}
if (ImGui::Selectable(i->second, i->first == currentButton)) {
CVarSetInteger(mapping.cVarName, i->first);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
}
ImGui::EndCombo();
}
UIWidgets::Spacer(0);
}
void DrawOcarinaControlPanel(GameControlEditorWindow* window) {
if (!ImGui::CollapsingHeader("Ocarina Controls")) {
return;
}
if (!ImGui::BeginTable("tableCustomOcarinaControls", 1, PANEL_TABLE_FLAGS)) {
return;
}
ImGui::TableSetupColumn("Custom Ocarina Controls", PANEL_TABLE_COLUMN_FLAGS | ImGuiTableColumnFlags_WidthStretch);
TableHelper::InitHeader(false);
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
UIWidgets::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls");
if (CVarGetInteger("gCustomOcarinaControls", 0) == 1) {
if (ImGui::BeginTable("tableCustomMainOcarinaControls", 2, ImGuiTableFlags_SizingStretchProp)) {
float labelWidth;
N64ButtonMask disableMask = BTN_B;
if (CVarGetInteger("gDpadOcarina", 0)) {
disableMask |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
}
ImGui::TableSetupColumn("Notes##CustomOcarinaNotes", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Modifiers##CustomOcaranaModifiers", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
window->BeginGroupPanelPublic("Notes", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize("D5").x + 10;
DrawMapping(ocarinaD5, labelWidth, disableMask);
DrawMapping(ocarinaB4, labelWidth, disableMask);
DrawMapping(ocarinaA4, labelWidth, disableMask);
DrawMapping(ocarinaF4, labelWidth, disableMask);
DrawMapping(ocarinaD4, labelWidth, disableMask);
ImGui::Dummy(ImVec2(0, 5));
float cursorY = ImGui::GetCursorPosY();
window->EndGroupPanelPublic(0);
TableHelper::NextCol();
window->BeginGroupPanelPublic("Modifiers", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize(ocarinaSongDisable.label).x + 10;
DrawMapping(ocarinaSongDisable, labelWidth, disableMask);
DrawMapping(ocarinaSharp, labelWidth, disableMask);
DrawMapping(ocarinaFlat, labelWidth, disableMask);
window->EndGroupPanelPublic(cursorY - ImGui::GetCursorPosY() + 2);
ImGui::EndTable();
}
} else {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextWrapped("To modify the main ocarina controls, select the \"Customize Ocarina Controls\" checkbox.");
UIWidgets::Spacer(0);
}
window->BeginGroupPanelPublic("Alternate controls", ImGui::GetContentRegionAvail());
if (ImGui::BeginTable("tableOcarinaAlternateControls", 2, ImGuiTableFlags_SizingFixedSame)) {
ImGui::TableSetupColumn("D-pad", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Right stick", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
UIWidgets::EnhancementCheckbox("Play with D-pad", "gDpadOcarina");
TableHelper::NextCol();
UIWidgets::EnhancementCheckbox("Play with camera stick", "gRStickOcarina");
UIWidgets::Spacer(0);
ImGui::EndTable();
}
window->EndGroupPanelPublic(0);
ImGui::EndTable();
}
void DrawCameraControlPanel(GameControlEditorWindow* window) {
if (!ImGui::CollapsingHeader("Camera Controls")) {
return;
}
UIWidgets::Spacer(0);
window->BeginGroupPanelPublic("Aiming/First-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Right Stick Aiming", "gRightStickAiming");
DrawHelpIcon("Allows for aiming with the right stick in:\n-First-Person/C-Up view\n-Weapon Aiming");
if (CVarGetInteger("gRightStickAiming", 0)) {
UIWidgets::PaddedEnhancementCheckbox("Allow moving while in first person mode", "gMoveWhileFirstPerson");
DrawHelpIcon("Changes the left stick to move the player while in first person mode");
}
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming X Axis", "gInvertAimingXAxis");
DrawHelpIcon("Inverts the Camera X Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming Y Axis", "gInvertAimingYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
DrawHelpIcon("Inverts the Camera Y Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming Y Axis", "gInvertShieldAimingYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
DrawHelpIcon("Inverts the Shield Aiming Y Axis");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming X Axis", "gInvertShieldAimingXAxis");
DrawHelpIcon("Inverts the Shield Aiming X Axis");
UIWidgets::PaddedEnhancementCheckbox("Disable Auto-Centering in First-Person View", "gDisableAutoCenterViewFirstPerson");
DrawHelpIcon("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming");
if (UIWidgets::PaddedEnhancementCheckbox("Enable Custom Aiming/First-Person sensitivity", "gEnableFirstPersonSensitivity", true, false)) {
if (!CVarGetInteger("gEnableFirstPersonSensitivity", 0)) {
CVarClear("gFirstPersonCameraSensitivityX");
CVarClear("gFirstPersonCameraSensitivityY");
}
}
if (CVarGetInteger("gEnableFirstPersonSensitivity", 0)) {
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Horizontal Sensitivity: %d %%", "##FirstPersonSensitivity Horizontal",
"gFirstPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true);
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Vertical Sensitivity: %d %%", "##FirstPersonSensitivity Vertical",
"gFirstPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true);
}
UIWidgets::Spacer(0);
window->EndGroupPanelPublic(0);
UIWidgets::Spacer(0);
window->BeginGroupPanelPublic("Third-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera");
DrawHelpIcon("Enables free camera control\nNote: You must remap C buttons off of the right stick in the "
"controller config menu, and map the camera stick to the right stick.");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis");
DrawHelpIcon("Inverts the Camera X Axis in:\n-Free camera");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free camera");
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal",
"gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical",
"gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
"gFreeCameraDistMax", 100, 900, "", 185, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Transition Speed: %d", "##CamTranSpeed",
"gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true);
window->EndGroupPanelPublic(0);
}
void DrawDpadControlPanel(GameControlEditorWindow* window) {
if (!ImGui::CollapsingHeader("D-Pad Controls")) {
return;
}
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
window->BeginGroupPanelPublic("D-Pad Options", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("D-pad Support on Pause Screen", "gDpadPause");
DrawHelpIcon("Navigate Pause with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up to equip instead of navigate\n"
"To make the cursor only move a single space no matter how long a direction is held, manually set gDpadHoldChange to 0");
UIWidgets::PaddedEnhancementCheckbox("D-pad Support in Text Boxes", "gDpadText");
DrawHelpIcon("Navigate choices in text boxes, shop item selection, and the file select / name entry screens with the D-pad\n"
"To make the cursor only move a single space during name entry no matter how long a direction is held, manually set gDpadHoldChange to 0");
UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips");
DrawHelpIcon("Equip items and equipment on the D-pad\nIf used with D-pad on Pause Screen, you must hold C-Up to equip instead of navigate");
window->EndGroupPanelPublic(0);
}
void DrawMiscControlPanel(GameControlEditorWindow* window) {
if (!ImGui::CollapsingHeader("Miscellaneous Controls")) {
return;
}
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
window->BeginGroupPanelPublic("Misc Controls", ImGui::GetContentRegionAvail());
UIWidgets::PaddedText("Allow the cursor to be on any slot");
static const char* cursorOnAnySlot[3] = { "Only in Rando", "Always", "Never" };
UIWidgets::EnhancementCombobox("gPauseAnyCursor", cursorOnAnySlot, PAUSE_ANY_CURSOR_RANDO_ONLY);
DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select "
"certain items.");
UIWidgets::Spacer(0);
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false);
DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above");
if (CVarGetInteger("gEnableWalkModify", 0)) {
UIWidgets::Spacer(5);
window->BeginGroupPanelPublic("Walk Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Toggle modifier instead of holding", "gWalkSpeedToggle", true, false);
UIWidgets::PaddedEnhancementCheckbox("Don't affect jump distance/velocity", "gWalkModifierDoesntChangeJump", true, false);
UIWidgets::PaddedEnhancementSliderFloat("Modifier 1: %d %%", "##WalkMod1", "gWalkModifierOne", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
window->EndGroupPanelPublic(0);
}
ImGui::EndDisabled();
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL");
DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up");
window->EndGroupPanelPublic(0);
}
void GameControlEditorWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Game Controls Configuration", &mIsVisible)) {
DrawOcarinaControlPanel(this);
DrawCameraControlPanel(this);
DrawDpadControlPanel(this);
DrawMiscControlPanel(this);
}
ImGui::End();
}
void GameControlEditorWindow::BeginGroupPanelPublic(const char* name, const ImVec2& size) {
BeginGroupPanel(name, size);
}
void GameControlEditorWindow::EndGroupPanelPublic(float minHeight) {
EndGroupPanel(minHeight);
}
}

View File

@ -1,21 +0,0 @@
#pragma once
#include <libultraship/libultraship.h>
namespace GameControlEditor {
class GameControlEditorWindow : public LUS::GuiWindow {
public:
using LUS::GuiWindow::GuiWindow;
void BeginGroupPanelPublic(const char* name, const ImVec2& size);
void EndGroupPanelPublic(float minHeight);
void InitElement() override;
void DrawElement() override;
void UpdateElement() override {};
};
static int CurrentPort = 0;
static int BtnReading = -1;
} // namespace GameControlEditor

View File

@ -22,6 +22,22 @@ void SohInputEditorWindow::InitElement() {
mButtonsBitmasks = { BTN_A, BTN_B, BTN_START, BTN_L, BTN_R, BTN_Z, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT };
mDpadBitmasks = { BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
mModifierButtonsBitmasks = { BTN_MODIFIER1, BTN_MODIFIER2 };
addButtonName(BTN_A, "A");
addButtonName(BTN_B, "B");
addButtonName(BTN_CUP, "C Up");
addButtonName(BTN_CDOWN, "C Down");
addButtonName(BTN_CLEFT, "C Left");
addButtonName(BTN_CRIGHT, "C Right");
addButtonName(BTN_L, "L");
addButtonName(BTN_Z, "Z");
addButtonName(BTN_R, "R");
addButtonName(BTN_START, "Start");
addButtonName(BTN_DUP, "D-pad up");
addButtonName(BTN_DDOWN, "D-pad down");
addButtonName(BTN_DLEFT, "D-pad left");
addButtonName(BTN_DRIGHT, "D-pad right");
addButtonName(0, "None");
}
#define INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID 95237929
@ -1017,14 +1033,6 @@ void SohInputEditorWindow::DrawAddLEDMappingButton(uint8_t port) {
}
}
void SohInputEditorWindow::DrawHelpIcon(const std::string& helptext) {
// place the ? button to the most of the right side of the cell it is using.
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - SCALE_IMGUI_SIZE(22));
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - SCALE_IMGUI_SIZE(15));
ImGui::SmallButton("?");
UIWidgets::Tooltip(helptext.c_str());
}
void SohInputEditorWindow::DrawLEDSection(uint8_t port) {
for (auto [id, mapping] :
LUS::Context::GetInstance()->GetControlDeck()->GetControllerByPort(port)->GetLED()->GetAllLEDMappings()) {
@ -1063,11 +1071,11 @@ void SohInputEditorWindow::DrawLEDSection(uint8_t port) {
};
UIWidgets::PaddedText("Source");
UIWidgets::EnhancementCombobox("gLedColorSource", ledSources, LED_SOURCE_TUNIC_ORIGINAL);
DrawHelpIcon("Health\n- Red when health critical (13-20% depending on max health)\n- Yellow when "
"health < 40%. Green otherwise.\n\n"
"Tunics: colors will mirror currently equipped tunic, whether original or the current "
"values in Cosmetics Editor.\n\n"
"Custom: single, solid color");
UIWidgets::Tooltip("Health\n- Red when health critical (13-20% depending on max health)\n- Yellow when "
"health < 40%. Green otherwise.\n\n"
"Tunics: colors will mirror currently equipped tunic, whether original or the current "
"values in Cosmetics Editor.\n\n"
"Custom: single, solid color");
if (CVarGetInteger("gLedColorSource", 1) == LED_SOURCE_CUSTOM) {
UIWidgets::Spacer(3);
auto port1Color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
@ -1085,14 +1093,14 @@ void SohInputEditorWindow::DrawLEDSection(uint8_t port) {
ImGui::SameLine();
ImGui::Text("Custom Color");
}
UIWidgets::PaddedEnhancementSliderFloat("Brightness: %d%%", "##LED_Brightness", "gLedBrightness", 0.0f,
UIWidgets::PaddedEnhancementSliderFloat("Brightness: %.1f %%", "##LED_Brightness", "gLedBrightness", 0.0f,
1.0f, "", 1.0f, true, true);
DrawHelpIcon("Sets the brightness of controller LEDs. 0% brightness = LEDs off.");
UIWidgets::Tooltip("Sets the brightness of controller LEDs. 0% brightness = LEDs off.");
UIWidgets::PaddedEnhancementCheckbox(
"Critical Health Override", "gLedCriticalOverride", true, true,
CVarGetInteger("gLedColorSource", LED_SOURCE_TUNIC_ORIGINAL) == LED_SOURCE_HEALTH,
"Override redundant for health source.", UIWidgets::CheckboxGraphics::Cross, true);
DrawHelpIcon("Shows red color when health is critical, otherwise displays according to color source.");
UIWidgets::Tooltip("Shows red color when health is critical, otherwise displays according to color source.");
}
ImGui::TreePop();
}
@ -1430,6 +1438,273 @@ void SohInputEditorWindow::DrawLEDDeviceIcons(uint8_t portIndex) {
}
}
const ImGuiTableFlags PANEL_TABLE_FLAGS =
ImGuiTableFlags_BordersH |
ImGuiTableFlags_BordersV;
const ImGuiTableColumnFlags PANEL_TABLE_COLUMN_FLAGS =
ImGuiTableColumnFlags_IndentEnable |
ImGuiTableColumnFlags_NoSort;
namespace TableHelper {
void InitHeader(bool has_header = true) {
if (has_header) {
ImGui::TableHeadersRow();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding(); //This is to adjust Vertical pos of item in a cell to be normlized.
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextCol() {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextLine() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
}
typedef uint32_t N64ButtonMask;
void SohInputEditorWindow::addButtonName(N64ButtonMask mask, const char* name) {
buttons.push_back(std::make_pair(mask, name));
buttonNames[mask] = std::prev(buttons.end());
}
// Ocarina button maps
static CustomButtonMap ocarinaD5 = {"D5", "gOcarinaD5BtnMap", BTN_CUP};
static CustomButtonMap ocarinaB4 = {"B4", "gOcarinaB4BtnMap", BTN_CLEFT};
static CustomButtonMap ocarinaA4 = {"A4", "gOcarinaA4BtnMap", BTN_CRIGHT};
static CustomButtonMap ocarinaF4 = {"F4", "gOcarinaF4BtnMap", BTN_CDOWN};
static CustomButtonMap ocarinaD4 = {"D4", "gOcarinaD4BtnMap", BTN_A};
static CustomButtonMap ocarinaSongDisable = {"Disable songs", "gOcarinaDisableBtnMap", BTN_L};
static CustomButtonMap ocarinaSharp = {"Pitch up", "gOcarinaSharpBtnMap", BTN_R};
static CustomButtonMap ocarinaFlat = {"Pitch down", "gOcarinaFlatBtnMap", BTN_Z};
// Draw a button mapping setting consisting of a padded label and button dropdown.
// excludedButtons indicates which buttons are unavailable to choose from.
void SohInputEditorWindow::DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons) {
N64ButtonMask currentButton = CVarGetInteger(mapping.cVarName, mapping.defaultBtn);
const char* preview;
if (buttonNames.contains(currentButton)) {
preview = buttonNames[currentButton]->second;
} else {
preview = "Unknown";
}
UIWidgets::Spacer(0);
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 textSize = ImGui::CalcTextSize(mapping.label);
ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4);
ImGui::SetCursorPosX(cursorPos.x + abs(textSize.x - labelWidth));
ImGui::Text("%s", mapping.label);
ImGui::SameLine();
ImGui::SetCursorPosY(cursorPos.y);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
if (ImGui::BeginCombo(StringHelper::Sprintf("##%s", mapping.cVarName).c_str(), preview)) {
for (auto i = buttons.begin(); i != buttons.end(); i++) {
if ((i->first & excludedButtons) != 0) {
continue;
}
if (ImGui::Selectable(i->second, i->first == currentButton)) {
CVarSetInteger(mapping.cVarName, i->first);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
}
ImGui::EndCombo();
}
UIWidgets::Spacer(0);
}
void SohInputEditorWindow::DrawOcarinaControlPanel() {
if (!ImGui::BeginTable("tableCustomOcarinaControls", 1, PANEL_TABLE_FLAGS)) {
return;
}
ImGui::TableSetupColumn("Custom Ocarina Controls", PANEL_TABLE_COLUMN_FLAGS | ImGuiTableColumnFlags_WidthStretch);
TableHelper::InitHeader(false);
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
UIWidgets::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls");
if (CVarGetInteger("gCustomOcarinaControls", 0) == 1) {
if (ImGui::BeginTable("tableCustomMainOcarinaControls", 2, ImGuiTableFlags_SizingStretchProp)) {
float labelWidth;
N64ButtonMask disableMask = BTN_B;
if (CVarGetInteger("gDpadOcarina", 0)) {
disableMask |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
}
ImGui::TableSetupColumn("Notes##CustomOcarinaNotes", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Modifiers##CustomOcaranaModifiers", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
LUS::GuiWindow::BeginGroupPanel("Notes", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize("D5").x + 10;
DrawMapping(ocarinaD5, labelWidth, disableMask);
DrawMapping(ocarinaB4, labelWidth, disableMask);
DrawMapping(ocarinaA4, labelWidth, disableMask);
DrawMapping(ocarinaF4, labelWidth, disableMask);
DrawMapping(ocarinaD4, labelWidth, disableMask);
ImGui::Dummy(ImVec2(0, 5));
float cursorY = ImGui::GetCursorPosY();
LUS::GuiWindow::EndGroupPanel(0);
TableHelper::NextCol();
LUS::GuiWindow::BeginGroupPanel("Modifiers", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize(ocarinaSongDisable.label).x + 10;
DrawMapping(ocarinaSongDisable, labelWidth, disableMask);
DrawMapping(ocarinaSharp, labelWidth, disableMask);
DrawMapping(ocarinaFlat, labelWidth, disableMask);
LUS::GuiWindow::EndGroupPanel(cursorY - ImGui::GetCursorPosY() + 2);
ImGui::EndTable();
}
} else {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextWrapped("To modify the main ocarina controls, select the \"Customize Ocarina Controls\" checkbox.");
UIWidgets::Spacer(0);
}
LUS::GuiWindow::BeginGroupPanel("Alternate controls", ImGui::GetContentRegionAvail());
if (ImGui::BeginTable("tableOcarinaAlternateControls", 2, ImGuiTableFlags_SizingFixedSame)) {
ImGui::TableSetupColumn("D-pad", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Right stick", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
UIWidgets::EnhancementCheckbox("Play with D-pad", "gDpadOcarina");
TableHelper::NextCol();
UIWidgets::EnhancementCheckbox("Play with camera stick", "gRStickOcarina");
UIWidgets::Spacer(0);
ImGui::EndTable();
}
LUS::GuiWindow::EndGroupPanel(0);
ImGui::EndTable();
}
void SohInputEditorWindow::DrawCameraControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
LUS::GuiWindow::BeginGroupPanel("Aiming/First-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Right Stick Aiming", "gRightStickAiming");
UIWidgets::Tooltip("Allows for aiming with the right stick in:\n-First-Person/C-Up view\n-Weapon Aiming");
if (CVarGetInteger("gRightStickAiming", 0)) {
UIWidgets::PaddedEnhancementCheckbox("Allow moving while in first person mode", "gMoveWhileFirstPerson");
UIWidgets::Tooltip("Changes the left stick to move the player while in first person mode");
}
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming X Axis", "gInvertAimingXAxis");
UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming Y Axis", "gInvertAimingYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming Y Axis", "gInvertShieldAimingYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Shield Aiming Y Axis");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming X Axis", "gInvertShieldAimingXAxis");
UIWidgets::Tooltip("Inverts the Shield Aiming X Axis");
UIWidgets::PaddedEnhancementCheckbox("Invert Z-Weapon Aiming Y Axis", "gInvertZAimingYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Z-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Disable Auto-Centering in First-Person View", "gDisableAutoCenterViewFirstPerson");
UIWidgets::Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming");
if (UIWidgets::PaddedEnhancementCheckbox("Enable Custom Aiming/First-Person sensitivity", "gEnableFirstPersonSensitivity", true, false)) {
if (!CVarGetInteger("gEnableFirstPersonSensitivity", 0)) {
CVarClear("gFirstPersonCameraSensitivityX");
CVarClear("gFirstPersonCameraSensitivityY");
}
}
if (CVarGetInteger("gEnableFirstPersonSensitivity", 0)) {
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Horizontal Sensitivity: %.0f %%", "##FirstPersonSensitivity Horizontal",
"gFirstPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true);
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Vertical Sensitivity: %.0f %%", "##FirstPersonSensitivity Vertical",
"gFirstPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true);
}
UIWidgets::Spacer(0);
LUS::GuiWindow::EndGroupPanel(0);
UIWidgets::Spacer(0);
cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
LUS::GuiWindow::BeginGroupPanel("Third-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera");
UIWidgets::Tooltip("Enables free camera control\nNote: You must remap C buttons off of the right stick in the "
"controller config menu, and map the camera stick to the right stick.");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis");
UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-Free camera");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Free camera");
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Horizontal Sensitivity: %.0f %%", "##ThirdPersonSensitivity Horizontal",
"gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Vertical Sensitivity: %.0f %%", "##ThirdPersonSensitivity Vertical",
"gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
"gFreeCameraDistMax", 100, 900, "", 185, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Transition Speed: %d", "##CamTranSpeed",
"gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true);
LUS::GuiWindow::EndGroupPanel(0);
}
void SohInputEditorWindow::DrawDpadControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
LUS::GuiWindow::BeginGroupPanel("D-Pad Options", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("D-pad Support on Pause Screen", "gDpadPause");
UIWidgets::Tooltip("Navigate Pause with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up to equip instead of navigate\n"
"To make the cursor only move a single space no matter how long a direction is held, manually set gDpadHoldChange to 0");
UIWidgets::PaddedEnhancementCheckbox("D-pad Support in Text Boxes", "gDpadText");
UIWidgets::Tooltip("Navigate choices in text boxes, shop item selection, and the file select / name entry screens with the D-pad\n"
"To make the cursor only move a single space during name entry no matter how long a direction is held, manually set gDpadHoldChange to 0");
UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips");
UIWidgets::Tooltip("Equip items and equipment on the D-pad\nIf used with D-pad on Pause Screen, you must hold C-Up to equip instead of navigate");
LUS::GuiWindow::EndGroupPanel(0);
}
void SohInputEditorWindow::DrawMiscControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
LUS::GuiWindow::BeginGroupPanel("Misc Controls", ImGui::GetContentRegionAvail());
UIWidgets::PaddedText("Allow the cursor to be on any slot");
static const char* cursorOnAnySlot[3] = { "Only in Rando", "Always", "Never" };
UIWidgets::EnhancementCombobox("gPauseAnyCursor", cursorOnAnySlot, PAUSE_ANY_CURSOR_RANDO_ONLY);
UIWidgets::Tooltip("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select "
"certain items.");
UIWidgets::Spacer(0);
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
UIWidgets::PaddedEnhancementCheckbox("Enable speed modifiers", "gEnableWalkModify", true, false);
UIWidgets::Tooltip("Hold the assigned button to change the maximum walking or swimming speed");
if (CVarGetInteger("gEnableWalkModify", 0)) {
UIWidgets::Spacer(5);
LUS::GuiWindow::BeginGroupPanel("Speed Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Toggle modifier instead of holding", "gWalkSpeedToggle", true, false);
LUS::GuiWindow::BeginGroupPanel("Walk Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Don't affect jump distance/velocity", "gWalkModifierDoesntChangeJump", true, false);
UIWidgets::PaddedEnhancementSliderFloat("Walk Modifier 1: %.0f %%", "##WalkMod1", "gWalkModifierOne", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Walk Modifier 2: %.0f %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
LUS::GuiWindow::EndGroupPanel(0);
LUS::GuiWindow::BeginGroupPanel("Swim Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementSliderFloat("Swim Modifier 1: %.0f %%", "##SwimMod1", "gSwimModifierOne", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Swim Modifier 2: %.0f %%", "##SwimMod2", "gSwimModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true);
LUS::GuiWindow::EndGroupPanel(0);
LUS::GuiWindow::EndGroupPanel(0);
}
ImGui::EndDisabled();
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL");
UIWidgets::Tooltip("Speak to Navi with L but enter first-person camera with C-Up");
LUS::GuiWindow::EndGroupPanel(0);
}
void SohInputEditorWindow::DrawLinkTab() {
uint8_t portIndex = 0;
if (ImGui::BeginTabItem(StringHelper::Sprintf("Link (P1)###port%d", portIndex).c_str())) {
@ -1516,6 +1791,46 @@ void SohInputEditorWindow::DrawLinkTab() {
DrawButtonDeviceIcons(portIndex, mModifierButtonsBitmasks);
}
if (ImGui::CollapsingHeader("Ocarina Controls")) {
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
DrawOcarinaControlPanel();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
}
if (ImGui::CollapsingHeader("Camera Controls")) {
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
DrawCameraControlPanel();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
}
if (ImGui::CollapsingHeader("D-Pad Controls")) {
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
DrawDpadControlPanel();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
}
if (ImGui::CollapsingHeader("Miscellaneous Controls")) {
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
DrawMiscControlPanel();
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();

View File

@ -10,6 +10,15 @@
#include <string>
#include <vector>
#include <set>
#include <list>
typedef uint32_t N64ButtonMask;
typedef struct {
const char* label;
const char* cVarName;
N64ButtonMask defaultBtn;
} CustomButtonMap;
class SohInputEditorWindow : public LUS::GuiWindow {
public:
@ -51,6 +60,17 @@ class SohInputEditorWindow : public LUS::GuiWindow {
void DrawRemoveGyroMappingButton(uint8_t port, std::string id);
void DrawAddGyroMappingButton(uint8_t port);
// Used together for an incomplete linked hash map implementation in order to
// map button masks to their names and original mapping on N64
std::list<std::pair<N64ButtonMask, const char*>> buttons;
std::unordered_map<N64ButtonMask, decltype(buttons)::iterator> buttonNames;
void addButtonName(N64ButtonMask mask, const char* name);
void DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons);
void DrawOcarinaControlPanel();
void DrawCameraControlPanel();
void DrawDpadControlPanel();
void DrawMiscControlPanel();
int32_t mGameInputBlockTimer;
int32_t mMappingInputBlockTimer;
int32_t mRumbleTimer;
@ -84,6 +104,4 @@ class SohInputEditorWindow : public LUS::GuiWindow {
bool mInputEditorPopupOpen;
void DrawSetDefaultsButton(uint8_t portIndex);
void DrawClearAllButton(uint8_t portIndex);
void DrawHelpIcon(const std::string& helptext);
};

View File

@ -67,6 +67,7 @@ typedef enum {
GROUP_EQUIPMENT,
GROUP_CONSUMABLE,
GROUP_HUD,
GROUP_KALEIDO,
GROUP_TITLE,
GROUP_NPC,
GROUP_WORLD,
@ -75,6 +76,7 @@ typedef enum {
GROUP_SPIN_ATTACK,
GROUP_TRAILS,
GROUP_NAVI,
GROUP_IVAN,
} CosmeticGroup;
std::map<CosmeticGroup, const char*> groupLabels = {
@ -85,6 +87,7 @@ std::map<CosmeticGroup, const char*> groupLabels = {
{ GROUP_EQUIPMENT, "Equipment" },
{ GROUP_CONSUMABLE, "Consumables" },
{ GROUP_HUD, "HUD" },
{ GROUP_KALEIDO, "Pause Menu" },
{ GROUP_TITLE, "Title Screen" },
{ GROUP_NPC, "NPCs" },
{ GROUP_WORLD, "World" },
@ -93,6 +96,7 @@ std::map<CosmeticGroup, const char*> groupLabels = {
{ GROUP_SPIN_ATTACK, "Spin Attack" },
{ GROUP_TRAILS, "Trails" },
{ GROUP_NAVI, "Navi" },
{ GROUP_IVAN, "Ivan" }
};
typedef struct {
@ -265,6 +269,38 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
COSMETIC_OPTION("Hud_NameTagActorText", "Nametag Text", GROUP_HUD, ImVec4(255, 255, 255, 255), true, true, false),
COSMETIC_OPTION("Hud_NameTagActorBackground", "Nametag Background", GROUP_HUD, ImVec4(0, 0, 0, 80), true, false, true),
COSMETIC_OPTION("Kal_ItemSelA", "Item Select Color A", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
COSMETIC_OPTION("Kal_ItemSelB", "Item Select Color B", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, false),
COSMETIC_OPTION("Kal_ItemSelC", "Item Select Color C", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, false),
COSMETIC_OPTION("Kal_ItemSelD", "Item Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
COSMETIC_OPTION("Kal_EquipSelA", "Equip Select Color A", GROUP_KALEIDO, ImVec4(10, 50, 40, 255), false, true, false),
COSMETIC_OPTION("Kal_EquipSelB", "Equip Select Color B", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_EquipSelC", "Equip Select Color C", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_EquipSelD", "Equip Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelDunA", "Map Dungeon Color A", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelDunB", "Map Dungeon Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelDunC", "Map Dungeon Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelDunD", "Map Dungeon Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
COSMETIC_OPTION("Kal_QuestStatusA", "Quest StatusColor A", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false),
COSMETIC_OPTION("Kal_QuestStatusB", "Quest StatusColor B", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, false),
COSMETIC_OPTION("Kal_QuestStatusC", "Quest StatusColor C", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, false),
COSMETIC_OPTION("Kal_QuestStatusD", "Quest StatusColor D", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelectA", "Map Color A", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelectB", "Map Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelectC", "Map Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
COSMETIC_OPTION("Kal_MapSelectD", "Map Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
COSMETIC_OPTION("Kal_SaveA", "Save A", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false),
COSMETIC_OPTION("Kal_SaveB", "Save B", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, false),
COSMETIC_OPTION("Kal_SaveC", "Save C", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, false),
COSMETIC_OPTION("Kal_SaveD", "Save D", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false),
COSMETIC_OPTION("Kal_NamePanel", "Name Panel", GROUP_KALEIDO, ImVec4(90,100,130,255), true, true, false),
COSMETIC_OPTION("Title_FileChoose", "File Choose", GROUP_TITLE, ImVec4(100, 150, 255, 255), false, true, false),
COSMETIC_OPTION("Title_NintendoLogo", "Nintendo Logo", GROUP_TITLE, ImVec4( 0, 0, 255, 255), false, true, true),
COSMETIC_OPTION("Title_N64LogoRed", "N64 Red", GROUP_TITLE, ImVec4(150, 0, 0, 255), false, true, true),
@ -316,6 +352,9 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
COSMETIC_OPTION("Navi_EnemySecondary", "Enemy Secondary", GROUP_NAVI, ImVec4(200, 155, 0, 0), false, true, true),
COSMETIC_OPTION("Navi_PropsPrimary", "Props Primary", GROUP_NAVI, ImVec4( 0, 255, 0, 255), false, true, false),
COSMETIC_OPTION("Navi_PropsSecondary", "Props Secondary", GROUP_NAVI, ImVec4( 0, 255, 0, 0), false, true, true),
COSMETIC_OPTION("Ivan_IdlePrimary", "Ivan Idle Primary", GROUP_IVAN, ImVec4(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("Ivan_IdleSecondary", "Ivan Idle Secondary", GROUP_IVAN, ImVec4( 0, 255, 0, 255), false, true, true),
COSMETIC_OPTION("NPC_FireKeesePrimary", "Fire Keese Primary", GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("NPC_FireKeeseSecondary", "Fire Keese Secondary", GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, true),
@ -1491,7 +1530,7 @@ void DrawSillyTab() {
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
}
if (UIWidgets::EnhancementSliderFloat("Link Body Scale: %f", "##Link_BodyScale", "gCosmetics.Link_BodyScale.Value", 0.001f, 0.025f, "", 0.01f, true)) {
if (UIWidgets::EnhancementSliderFloat("Link Body Scale: %.3fx", "##Link_BodyScale", "gCosmetics.Link_BodyScale.Value", 0.001f, 0.025f, "", 0.01f, true)) {
CVarSetInteger("gCosmetics.Link_BodyScale.Changed", 1);
}
ImGui::SameLine();
@ -1506,7 +1545,7 @@ void DrawSillyTab() {
player->actor.scale.z = 0.01f;
}
}
if (UIWidgets::EnhancementSliderFloat("Link Head Scale: %f", "##Link_HeadScale", "gCosmetics.Link_HeadScale.Value", 0.4f, 4.0f, "", 1.0f, false)) {
if (UIWidgets::EnhancementSliderFloat("Link Head Scale: %.2fx", "##Link_HeadScale", "gCosmetics.Link_HeadScale.Value", 0.4f, 4.0f, "", 1.0f, false)) {
CVarSetInteger("gCosmetics.Link_HeadScale.Changed", 1);
}
ImGui::SameLine();
@ -1515,7 +1554,7 @@ void DrawSillyTab() {
CVarClear("gCosmetics.Link_HeadScale.Changed");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (UIWidgets::EnhancementSliderFloat("Link Sword Scale: %f", "##Link_SwordScale", "gCosmetics.Link_SwordScale.Value", 1.0f, 2.5f, "", 1.0f, false)) {
if (UIWidgets::EnhancementSliderFloat("Link Sword Scale: %.3fx", "##Link_SwordScale", "gCosmetics.Link_SwordScale.Value", 1.0f, 2.5f, "", 1.0f, false)) {
CVarSetInteger("gCosmetics.Link_SwordScale.Changed", 1);
}
ImGui::SameLine();
@ -1524,44 +1563,44 @@ void DrawSillyTab() {
CVarClear("gCosmetics.Link_SwordScale.Changed");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementSliderFloat("Bunny Hood Length: %f", "##BunnyHood_EarLength", "gCosmetics.BunnyHood_EarLength", -300.0f, 1000.0f, "", 0.0f, false);
UIWidgets::EnhancementSliderFloat("Bunny Hood Length: %.0f", "##BunnyHood_EarLength", "gCosmetics.BunnyHood_EarLength", -300.0f, 1000.0f, "", 0.0f, false);
ImGui::SameLine();
if (ImGui::Button("Reset##BunnyHood_EarLength")) {
CVarClear("gCosmetics.BunnyHood_EarLength");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementSliderFloat("Bunny Hood Spread: %f", "##BunnyHood_EarSpread", "gCosmetics.BunnyHood_EarSpread", -300.0f, 500.0f, "", 0.0f, false);
UIWidgets::EnhancementSliderFloat("Bunny Hood Spread: %.0f", "##BunnyHood_EarSpread", "gCosmetics.BunnyHood_EarSpread", -300.0f, 500.0f, "", 0.0f, false);
ImGui::SameLine();
if (ImGui::Button("Reset##BunnyHood_EarSpread")) {
CVarClear("gCosmetics.BunnyHood_EarSpread");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementSliderFloat("Goron Neck Length: %f", "##Goron_NeckLength", "gCosmetics.Goron_NeckLength", 0.0f, 5000.0f, "", 0.0f, false);
UIWidgets::EnhancementSliderFloat("Goron Neck Length: %.0f", "##Goron_NeckLength", "gCosmetics.Goron_NeckLength", 0.0f, 5000.0f, "", 0.0f, false);
ImGui::SameLine();
if (ImGui::Button("Reset##Goron_NeckLength")) {
CVarClear("gCosmetics.Goron_NeckLength");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementCheckbox("Unfix Goron Spin", "gUnfixGoronSpin");
UIWidgets::EnhancementSliderFloat("Fairies Size: %f", "##Fairies_Size", "gCosmetics.Fairies_Size", 0.25f, 5.0f, "", 1.0f, false);
UIWidgets::EnhancementSliderFloat("Fairies Size: %.2fx", "##Fairies_Size", "gCosmetics.Fairies_Size", 0.25f, 5.0f, "", 1.0f, false);
ImGui::SameLine();
if (ImGui::Button("Reset##Fairies_Size")) {
CVarClear("gCosmetics.Fairies_Size");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementSliderFloat("N64 Logo Spin Speed: %f", "##N64Logo_SpinSpeed", "gCosmetics.N64Logo_SpinSpeed", 0.25f, 5.0f, "", 1.0f, false);
UIWidgets::EnhancementSliderFloat("N64 Logo Spin Speed: %.2fx", "##N64Logo_SpinSpeed", "gCosmetics.N64Logo_SpinSpeed", 0.25f, 5.0f, "", 1.0f, false);
ImGui::SameLine();
if (ImGui::Button("Reset##N64Logo_SpinSpeed")) {
CVarClear("gCosmetics.N64Logo_SpinSpeed");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
UIWidgets::EnhancementSliderFloat("Moon Size: %f", "##Moon_Size", "gCosmetics.Moon_Size", 0.5f, 2.0f, "", 1.0f, false);
UIWidgets::EnhancementSliderFloat("Moon Size: %.1f %%", "##Moon_Size", "gCosmetics.Moon_Size", 0.5f, 2.0f, "", 1.0f, true);
ImGui::SameLine();
if (ImGui::Button("Reset##Moon_Size")) {
CVarClear("gCosmetics.Moon_Size");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (UIWidgets::EnhancementSliderFloat("Kak Windmill Speed: %f", "##Kak_Windmill_Speed", "gCosmetics.Kak_Windmill_Speed.Value", 100.0f, 6000.0f, "", 100.0f, false)) {
if (UIWidgets::EnhancementSliderFloat("Kak Windmill Speed: %.0f", "##Kak_Windmill_Speed", "gCosmetics.Kak_Windmill_Speed.Value", 100.0f, 6000.0f, "", 100.0f, false)) {
CVarSetInteger("gCosmetics.Kak_Windmill_Speed.Changed", 1);
}
ImGui::SameLine();
@ -1626,6 +1665,8 @@ void RandomizeColor(CosmeticOption& cosmeticOption) {
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_NPCSecondary"), 1.0f);
} else if (cosmeticOption.label == "Props Primary") {
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_PropsSecondary"), 1.0f);
} else if (cosmeticOption.label == "Ivan Idle Primary") {
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Ivan_IdleSecondary"), 0.5f);
} else if (cosmeticOption.label == "Level 1 Secondary") {
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("SpinAttack_Level1Primary"), 2.0f);
} else if (cosmeticOption.label == "Level 2 Secondary") {
@ -1793,15 +1834,12 @@ void CosmeticsEditorWindow::DrawElement() {
}
}
UIWidgets::EnhancementCheckbox("Sync Rainbow colors", "gCosmetics.RainbowSync");
UIWidgets::EnhancementSliderFloat("Rainbow Speed: %f", "##rainbowSpeed", "gCosmetics.RainbowSpeed", 0.03f, 1.0f, "", 0.6f, false);
UIWidgets::EnhancementSliderFloat("Rainbow Speed: %.3f", "##rainbowSpeed", "gCosmetics.RainbowSpeed", 0.03f, 1.0f, "", 0.6f, false, true);
UIWidgets::EnhancementCheckbox("Randomize All on New Scene", "gCosmetics.RandomizeAllOnNewScene");
UIWidgets::Tooltip("Enables randomizing all unlocked cosmetics when you enter a new scene.");
if (ImGui::Button("Randomize All", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
if (!CVarGetInteger(cosmeticOption.lockedCvar, 0) && (!cosmeticOption.advancedOption || CVarGetInteger("gCosmetics.AdvancedMode", 0))) {
RandomizeColor(cosmeticOption);
}
}
ApplyOrResetCustomGfxPatches();
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
CosmeticsEditor_RandomizeAll();
}
ImGui::SameLine();
if (ImGui::Button("Reset All", ImVec2(ImGui::GetContentRegionAvail().x, 30.0f))) {
@ -1861,6 +1899,7 @@ void CosmeticsEditorWindow::DrawElement() {
if (ImGui::BeginTabItem("World & NPCs")) {
DrawCosmeticGroup(GROUP_WORLD);
DrawCosmeticGroup(GROUP_NAVI);
DrawCosmeticGroup(GROUP_IVAN);
DrawCosmeticGroup(GROUP_NPC);
ImGui::EndTabItem();
}
@ -1873,10 +1912,16 @@ void CosmeticsEditorWindow::DrawElement() {
DrawCosmeticGroup(GROUP_TITLE);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("HUD Placement")) {
Draw_Placements();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Pause Menu")) {
DrawCosmeticGroup(GROUP_KALEIDO);
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
ImGui::End();
@ -1894,6 +1939,14 @@ void RegisterOnGameFrameUpdateHook() {
});
}
void Cosmetics_RegisterOnSceneInitHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (CVarGetInteger("gCosmetics.RandomizeAllOnNewScene", 0)) {
CosmeticsEditor_RandomizeAll();
}
});
}
void CosmeticsEditorWindow::InitElement() {
// Convert the `current color` into the format that the ImGui color picker expects
for (auto& [id, cosmeticOption] : cosmeticOptions) {
@ -1911,6 +1964,7 @@ void CosmeticsEditorWindow::InitElement() {
RegisterOnLoadGameHook();
RegisterOnGameFrameUpdateHook();
Cosmetics_RegisterOnSceneInitHook();
}
void CosmeticsEditor_RandomizeAll() {

View File

@ -8,6 +8,7 @@ extern "C" {
#include "objects/object_gi_soldout/object_gi_soldout.h"
#include "objects/object_ik/object_ik.h"
#include "objects/object_link_child/object_link_child.h"
#include "objects/object_ru2/object_ru2.h"
uint32_t ResourceMgr_GameHasMasterQuest();
uint32_t ResourceMgr_GameHasOriginal();
@ -187,10 +188,25 @@ void PatchIronKnuckleTextureOverflow() {
}
}
void PatchPrincessRutoEaring() {
// FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings.
// Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so
// it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the
// earring texture loads into the same place in TMEM as the brick texture, so when it comes to rendering, TEXEL1
// uses the earring texture with different clamp settings, and it displays without noticeable error. However, both
// texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses
// our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces
// TEXEL1 with TEXEL0, which is most likely the original intention, and all is well.
ResourceMgr_PatchGfxByName(gAdultRutoHeadDL, "RutoEaringTileFix", 162,
gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED,
TEXEL0, 0, PRIM_LOD_FRAC, COMBINED));
}
void ApplyAuthenticGfxPatches() {
PatchDekuStickTextureOverflow();
PatchFreezardTextureOverflow();
PatchIronKnuckleTextureOverflow();
PatchPrincessRutoEaring();
}
// Patches the Sold Out GI DL to render the texture in the mirror boundary

View File

@ -154,6 +154,7 @@ typedef enum {
TEXT_CARPET_SALESMAN_1 = 0x6077,
TEXT_CARPET_SALESMAN_2 = 0x6078,
TEXT_MARKET_GUARD_NIGHT = 0x7003,
TEXT_FISHERMAN_LEAVE = 0x409E,
TEXT_SHEIK_NEED_HOOK = 0x700F,
TEXT_SHEIK_HAVE_HOOK = 0x7010,
TEXT_ALTAR_CHILD = 0x7040,

View File

@ -25,6 +25,8 @@
#include "src/overlays/actors/ovl_En_Firefly/z_en_firefly.h"
#include "src/overlays/actors/ovl_En_Xc/z_en_xc.h"
#include "src/overlays//actors/ovl_Fishing/z_fishing.h"
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
extern "C" {
#include <z64.h>
@ -690,6 +692,62 @@ void RegisterMirrorModeHandler() {
});
}
void UpdatePatchHand() {
if ((CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && LINK_IS_CHILD) {
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92, gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2", 93, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1", 84, gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2", 85, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1", 51, gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2", 52, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1", 104, gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2", 105, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1", 79, gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2", 80, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1", 76, gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2", 77, gsSPEndDisplayList());
} else {
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2");
}
if ((CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && LINK_IS_ADULT) {
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword", 13, gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot", 13, gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang", 50, gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield", 49, gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
} else {
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword");
ResourceMgr_UnpatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot");
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang");
ResourceMgr_UnpatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield");
}
}
void RegisterPatchHandHandler() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int32_t sceneNum) {
UpdatePatchHand();
});
}
void RegisterResetNaviTimer() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int32_t sceneNum) {
if (CVarGetInteger("gEnhancements.ResetNaviTimer", 0)) {
gSaveContext.naviTimer = 0;
}
});
}
f32 triforcePieceScale;
void RegisterTriforceHunt() {
@ -1134,21 +1192,43 @@ void RegisterBossSouls() {
default: break;
}
//Deletes all actors in the boss category if the soul isn't found.
//Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses,
//so ignore any "boss" if `rand_inf` doesn't change from RAND_INF_MAX.
if (rand_inf != RAND_INF_MAX) {
if (!Flags_GetRandomizerInf(rand_inf) && actual->category == ACTORCAT_BOSS) {
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
//Deletes all actors in the boss category if the soul isn't found.
//Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses,
//so ignore any "boss" if `rand_inf` doesn't change from RAND_INF_MAX.
if (rand_inf != RAND_INF_MAX) {
if (!Flags_GetRandomizerInf(rand_inf) && actual->category == ACTORCAT_BOSS) {
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
}
//Special case for Phantom Ganon's horse (and fake), as they're considered "background actors",
//but still control the boss fight flow.
if (!Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL) && actual->id == ACTOR_EN_FHG) {
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
}
}
//Special case for Phantom Ganon's horse (and fake), as they're considered "background actors",
//but still control the boss fight flow.
if (!Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL) && actual->id == ACTOR_EN_FHG) {
Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
}
}
});
}
void UpdateHurtContainerModeState(bool newState) {
static bool hurtEnabled = false;
if (hurtEnabled == newState) {
return;
}
hurtEnabled = newState;
uint16_t getHeartPieces = gSaveContext.sohStats.heartPieces / 4;
uint16_t getHeartContainers = gSaveContext.sohStats.heartContainers;
if (hurtEnabled) {
gSaveContext.healthCapacity = 320 - ((getHeartPieces + getHeartContainers) * 16);
} else {
gSaveContext.healthCapacity = 48 + ((getHeartPieces + getHeartContainers) * 16);
}
}
void RegisterHurtContainerModeHandler() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int32_t fileNum) {
UpdateHurtContainerModeState(CVarGetInteger("gHurtContainer", 0));
});
}
void RegisterRandomizedEnemySizes() {
@ -1540,6 +1620,7 @@ void InitMods() {
RegisterBonkDamage();
RegisterMenuPathFix();
RegisterMirrorModeHandler();
RegisterResetNaviTimer();
RegisterTriforceHunt();
RegisterGrantGanonsBossKey();
RegisterEnemyDefeatCounts();
@ -1552,4 +1633,6 @@ void InitMods() {
RegisterNoWallet();
RegisterFishsanity();
NameTag_RegisterHooks();
RegisterPatchHandHandler();
RegisterHurtContainerModeHandler();
}

View File

@ -9,9 +9,11 @@ extern "C" {
void UpdateDirtPathFixState(int32_t sceneNum);
void UpdateMirrorModeState(int32_t sceneNum);
void UpdateHurtContainerModeState(bool newState);
void PatchToTMedallions();
void UpdatePermanentHeartLossState();
void InitMods();
void UpdatePatchHand();
#ifdef __cplusplus
}

View File

@ -12,6 +12,14 @@ void clearCvars(std::vector<const char*> cvarsToClear) {
}
}
std::string FormatLocations(std::vector<RandomizerCheck> locs) {
std::string locString = "";
for (auto loc: locs) {
locString += std::to_string(loc) + ",";
}
return locString;
}
void applyPreset(std::vector<PresetEntry> entries) {
for(auto& [cvar, type, value] : entries) {
switch (type) {
@ -24,6 +32,9 @@ void applyPreset(std::vector<PresetEntry> entries) {
case PRESET_ENTRY_TYPE_STRING:
CVarSetString(cvar, std::get<const char*>(value));
break;
case PRESET_ENTRY_TYPE_CPP_STRING:
CVarSetString(cvar, std::get<std::string>(value).c_str());
break;
}
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include <variant>
#include <cstdint>
@ -11,6 +12,7 @@ enum PresetEntryType {
PRESET_ENTRY_TYPE_S32,
PRESET_ENTRY_TYPE_FLOAT,
PRESET_ENTRY_TYPE_STRING,
PRESET_ENTRY_TYPE_CPP_STRING,
};
enum PresetType {
@ -36,15 +38,19 @@ enum RandomizerPreset {
typedef struct PresetEntry {
const char* cvar;
PresetEntryType type;
std::variant<int32_t, float, const char*> value;
std::variant<int32_t, float, const char*, std::string> value;
} PresetEntry;
std::string FormatLocations(std::vector<RandomizerCheck> locs);
#define PRESET_ENTRY_S32(cvar, value) \
{ cvar, PRESET_ENTRY_TYPE_S32, value }
#define PRESET_ENTRY_FLOAT(cvar, value) \
{ cvar, PRESET_ENTRY_TYPE_FLOAT, value }
#define PRESET_ENTRY_STRING(cvar, value) \
{ cvar, PRESET_ENTRY_TYPE_STRING, value }
#define PRESET_ENTRY_CPP_STRING(cvar, value) \
{ cvar, PRESET_ENTRY_TYPE_CPP_STRING, value }
void DrawPresetSelector(PresetType presetType);
void clearCvars(std::vector<const char*> cvarsToClear);
@ -70,6 +76,7 @@ const std::vector<const char*> enhancementsCvars = {
"gForgeTime",
"gClimbSpeed",
"gFasterBlockPush",
"gCrawlSpeed",
"gFasterHeavyBlockLift",
"gNoForcedNavi",
"gSkulltulaFreeze",
@ -138,6 +145,7 @@ const std::vector<const char*> enhancementsCvars = {
"gInjectItemCounts",
"gDayGravePull",
"gDampeAllNight",
"gQuitFishingAtDoor",
"gSkipSwimDeepEndAnim",
"gSkipScarecrow",
"gBlueFireArrows",
@ -186,6 +194,14 @@ const std::vector<const char*> enhancementsCvars = {
"gBombchuBowlingNoSmallCucco",
"gBombchuBowlingNoBigCucco",
"gBombchuBowlingAmmunition",
"gCustomizeOcarinaGame",
"gInstantOcarinaGameWin",
"gOcarinaGameNoteSpeed",
"gOcarinaUnlimitedFailTime",
"gOcarinaGameStartingNotes",
"gOcarinaGameRoundOneNotes",
"gOcarinaGameRoundTwoNotes",
"gOcarinaGameRoundThreeNotes",
"gCreditsFix",
"gSilverRupeeJingleExtend",
"gStaticExplosionRadius",
@ -258,6 +274,8 @@ const std::vector<const char*> cheatCvars = {
"gWalkSpeedToggle",
"gWalkModifierOne",
"gWalkModifierTwo",
"gSwimModifierOne",
"gSwimModifierTwo",
"gGoronPot",
"gDampeWin",
"gCustomizeShootingGallery",
@ -790,6 +808,13 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
// Adult Minimum Weight (8 to 13)
PRESET_ENTRY_S32("gAdultMinimumWeightFish", 6),
// Customize Lost Woods Ocarina Game Behavior
PRESET_ENTRY_S32("gCustomizeOcarinaGame", 1),
// Start With Five Notes
PRESET_ENTRY_S32("gOcarinaGameStartingNotes", 5),
// Round One Notes
PRESET_ENTRY_S32("gOcarinaGameRoundOneNotes", 5),
// Visual Stone of Agony
PRESET_ENTRY_S32("gVisualAgony", 1),
// Pull grave during the day
@ -878,7 +903,8 @@ const std::vector<PresetEntry> spockRacePresetEntries = {
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"),
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations(
{ RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })),
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
@ -970,7 +996,8 @@ const std::vector<PresetEntry> spockRaceNoLogicPresetEntries = {
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"),
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations(
{ RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })),
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
@ -1023,7 +1050,7 @@ const std::vector<PresetEntry> s6PresetEntries = {
PRESET_ENTRY_S32("gRandomizeBigPoeTargetCount", 1),
PRESET_ENTRY_S32("gRandomizeCuccosToReturn", 4),
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "48,"),
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations({ RC_DEKU_THEATER_MASK_OF_TRUTH })),
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_CLOSED_DEKU),
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
PRESET_ENTRY_S32("gRandomizeGerudoFortress", RO_GF_FAST),

View File

@ -38,7 +38,7 @@ void AreaTable_Init_FireTemple() {
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->BossKeyFireTemple && ((logic->IsAdult && randoCtx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}));}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->BossKeyFireTemple && ((logic->IsAdult && (randoCtx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}))) || logic->CanUse(RG_HOVER_BOOTS));}}),
});
areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", RA_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {

View File

@ -284,7 +284,7 @@ namespace Rando {
Fish = HasBottle && FishAccess;
Fairy = HasBottle && FairyAccess;
FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20);
FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20) && (BombBag || ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC));
CanPlayBowling = ChildsWallet && ((ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && FoundBombchus) || (!ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && BombBag));
// TODO: Implement Ammo Drop Setting in place of bombchu drops
HasBombchus = (BuyBombchus || (ctx->GetOption(RSK_ENABLE_BOMBCHU_DROPS).Is(RO_AMMO_DROPS_ON/*_PLUS_BOMBCHU*/) && FoundBombchus));

View File

@ -460,10 +460,31 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
void DrawItemCount(ItemTrackerItem item) {
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
int textSize = CVarGetInteger("gTrackers.ItemTracker.ItemTrackerTextSize", 13);
ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item);
ImVec2 p = ImGui::GetCursorScreenPos();
int32_t trackerNumberDisplayMode = CVarGetInteger("gItemTrackerCapacityTrack", ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY);
int32_t trackerKeyNumberDisplayMode = CVarGetInteger("gItemTrackerKeyTrack", KEYS_COLLECTED_MAX);
float textScalingFactor = static_cast<float>(iconSize) / 36.0f;
uint32_t actualItemId = INV_CONTENT(item.id);
bool hasItem = actualItemId != ITEM_NONE;
if (CVarGetInteger("gTrackers.ItemTracker.HookshotIdentifier", 0)) {
if ((actualItemId == ITEM_HOOKSHOT || actualItemId == ITEM_LONGSHOT) && hasItem) {
// Calculate the scaled position for the text
ImVec2 textPos = ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(item.id == ITEM_HOOKSHOT ? "H" : "L").x *
textScalingFactor / 2) + 8 * textScalingFactor, p.y - 22 * textScalingFactor);
ImGui::SetCursorScreenPos(textPos);
ImGui::SetWindowFontScale(textScalingFactor);
ImGui::Text(item.id == ITEM_HOOKSHOT ? "H" : "L");
ImGui::SetWindowFontScale(1.0f); // Reset font scale to the original state
}
}
ImGui::SetWindowFontScale(textSize / 13.0f);
if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) {
std::string currentString = "";
@ -816,7 +837,7 @@ void DrawDungeonItem(ItemTrackerItem item) {
ImVec2 p = ImGui::GetCursorScreenPos();
std::string dungeonName = itemTrackerDungeonShortNames[item.data];
ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + 16)));
ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + CVarGetInteger("gTrackers.ItemTracker.ItemTrackerTextSize", 13) + 3)));
ImGui::PushStyleColor(ImGuiCol_Text, dungeonColor);
ImGui::Text("%s", dungeonName.c_str());
ImGui::PopStyleColor();
@ -945,7 +966,7 @@ void DrawItemsInACircle(std::vector<ItemTrackerItem> items) {
float angle = (float)i / items.size() * 2.0f * M_PI;
float x = (radius / 2.0f) * cos(angle) + max.x / 2.0f;
float y = (radius / 2.0f) * sin(angle) + max.y / 2.0f;
ImGui::SetCursorPos(ImVec2(x - 14, y + 4));
ImGui::SetCursorPos(ImVec2(x - (CVarGetInteger("gItemTrackerIconSize", 36) - 8) / 2.0f, y + 4));
items[i].drawFunc(items[i]);
}
}
@ -1331,6 +1352,7 @@ void ItemTrackerSettingsWindow::DrawElement() {
UIWidgets::PaddedSeparator();
UIWidgets::EnhancementSliderInt("Icon size : %dpx", "##ITEMTRACKERICONSIZE", "gItemTrackerIconSize", 25, 128, "", 36);
UIWidgets::EnhancementSliderInt("Icon margins : %dpx", "##ITEMTRACKERSPACING", "gItemTrackerIconSpacing", -5, 50, "", 12);
UIWidgets::EnhancementSliderInt("Text size : %dpx", "##ITEMTRACKERTEXTSIZE", "gTrackers.ItemTracker.ItemTrackerTextSize", 1, 30, "", 13);
UIWidgets::Spacer(0);
@ -1371,7 +1393,7 @@ void ItemTrackerSettingsWindow::DrawElement() {
shouldUpdateVectors = true;
}
if (CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) {
if (UIWidgets::PaddedEnhancementCheckbox("Circle display", "gItemTrackerDungeonRewardsCircle", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true)) {
if (UIWidgets::PaddedEnhancementCheckbox("Circle display", "gItemTrackerDungeonRewardsCircle", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, false)) {
shouldUpdateVectors = true;
}
}
@ -1416,6 +1438,10 @@ void ItemTrackerSettingsWindow::DrawElement() {
shouldUpdateVectors = true;
}
}
UIWidgets::EnhancementCheckbox("Show Hookshot Identifiers", "gTrackers.ItemTracker.HookshotIdentifier");
UIWidgets::InsertHelpHoverText("Shows an 'H' or an 'L' to more easiely distinguish between Hookshot and Longshot.");
UIWidgets::Spacer(0);
ImGui::PopStyleVar(1);
ImGui::EndTable();

View File

@ -207,6 +207,9 @@ extern "C" void Randomizer_InitSaveFile() {
gSaveContext.randomizerInf[i] = 0;
}
// Reset triforce pieces collected
gSaveContext.triforcePiecesCollected = 0;
gSaveContext.cutsceneIndex = 0; // no intro cutscene
// Starts pending ice traps out at 0 before potentially incrementing them down the line.
gSaveContext.pendingIceTrapCount = 0;
@ -458,8 +461,5 @@ extern "C" void Randomizer_InitSaveFile() {
gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth
}
// Reset triforce pieces collected
gSaveContext.triforcePiecesCollected = 0;
SetStartingItems();
}

View File

@ -115,7 +115,7 @@ void AdvancedResolutionSettingsWindow::DrawElement() {
const bool disabled_resolutionSlider = (CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0) &&
CVarGetInteger("gAdvancedResolution.Enabled", 0)) ||
CVarGetInteger("gLowResMode", 0);
if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f,
if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %.1f%%", "##IMul", "gInternalResolution", 0.5f,
2.0f, "", 1.0f, true, true, disabled_resolutionSlider)) {
LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(
CVarGetFloat("gInternalResolution", 1));

View File

@ -29,7 +29,6 @@
#include <dr_libs/wav.h>
#include <AudioPlayer.h>
#include "Enhancements/speechsynthesizer/SpeechSynthesizer.h"
#include "Enhancements/controls/GameControlEditor.h"
#include "Enhancements/controls/SohInputEditorWindow.h"
#include "Enhancements/cosmetics/CosmeticsEditor.h"
#include "Enhancements/audio/AudioCollection.h"
@ -320,6 +319,8 @@ OTRGlobals::OTRGlobals() {
context->InitWindow(sohInputEditorWindow);
context->InitAudio();
SPDLOG_INFO("Starting Ship of Harkinian version {}", (char*)gBuildVersion);
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Room, "Room", std::make_shared<LUS::SceneFactory>()); // Is room scene? maybe?
@ -1219,8 +1220,7 @@ extern "C" uint64_t GetUnixTimestamp() {
auto time = std::chrono::system_clock::now();
auto since_epoch = time.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch);
long now = millis.count();
return now;
return (uint64_t)millis.count();
}
// C->C++ Bridge
@ -2690,6 +2690,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger("gMarketSneak", 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT);
}
if (textId == TEXT_FISHERMAN_LEAVE && CVarGetInteger("gQuitFishingAtDoor", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_FISHERMAN_LEAVE);
}
font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition();
switch (gSaveContext.language) {
case LANGUAGE_FRA:
@ -2735,6 +2738,24 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla
gfx_register_blended_texture(name, mask, replacement);
}
extern "C" void Gfx_UnregisterBlendedTexture(const char* name) {
gfx_unregister_blended_texture(name);
}
extern "C" void Gfx_TextureCacheDelete(const uint8_t* texAddr) {
char* imgName = (char*)texAddr;
if (texAddr == nullptr) {
return;
}
if (ResourceMgr_OTRSigCheck(imgName)) {
texAddr = (const uint8_t*)GetResourceDataByNameHandlingMQ(imgName);
}
gfx_texture_cache_delete(texAddr);
}
void SoH_ProcessDroppedFiles(std::string filePath) {
try {
std::ifstream configStream(filePath);

View File

@ -185,6 +185,8 @@ void Entrance_InitEntranceTrackingData(void);
void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex);
void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex);
void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement);
void Gfx_UnregisterBlendedTexture(const char* name);
void Gfx_TextureCacheDelete(const uint8_t* addr);
void SaveManager_ThreadPoolWait();
void CheckTracker_OnMessageClose();

View File

@ -116,7 +116,6 @@ namespace SohGui {
std::shared_ptr<LUS::GuiWindow> mInputEditorWindow;
std::shared_ptr<AudioEditor> mAudioEditorWindow;
std::shared_ptr<GameControlEditor::GameControlEditorWindow> mGameControlEditorWindow;
std::shared_ptr<CosmeticsEditorWindow> mCosmeticsEditorWindow;
std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
std::shared_ptr<ColViewerWindow> mColViewerWindow;
@ -164,8 +163,6 @@ namespace SohGui {
mAudioEditorWindow = std::make_shared<AudioEditor>("gAudioEditor.WindowOpen", "Audio Editor");
gui->AddGuiWindow(mAudioEditorWindow);
mGameControlEditorWindow = std::make_shared<GameControlEditor::GameControlEditorWindow>("gGameControlEditorEnabled", "Game Control Editor");
gui->AddGuiWindow(mGameControlEditorWindow);
mCosmeticsEditorWindow = std::make_shared<CosmeticsEditorWindow>("gCosmeticsEditorEnabled", "Cosmetics Editor");
gui->AddGuiWindow(mCosmeticsEditorWindow);
mActorViewerWindow = std::make_shared<ActorViewerWindow>("gActorViewerEnabled", "Actor Viewer");
@ -211,7 +208,6 @@ namespace SohGui {
mColViewerWindow = nullptr;
mActorViewerWindow = nullptr;
mCosmeticsEditorWindow = nullptr;
mGameControlEditorWindow = nullptr;
mAudioEditorWindow = nullptr;
mInputEditorWindow = nullptr;
mStatsWindow = nullptr;

View File

@ -11,7 +11,6 @@
#include <stdio.h>
#include "SohMenuBar.h"
#include "Enhancements/audio/AudioEditor.h"
#include "Enhancements/controls/GameControlEditor.h"
#include "Enhancements/cosmetics/CosmeticsEditor.h"
#include "Enhancements/debugger/actorViewer.h"
#include "Enhancements/debugger/colViewer.h"

View File

@ -21,7 +21,6 @@
#include "Enhancements/audio/AudioEditor.h"
#include "Enhancements/controls/GameControlEditor.h"
#include "Enhancements/cosmetics/CosmeticsEditor.h"
#include "Enhancements/debugger/actorViewer.h"
#include "Enhancements/debugger/colViewer.h"
@ -180,24 +179,23 @@ void DrawShipMenu() {
}
extern std::shared_ptr<LUS::GuiWindow> mInputEditorWindow;
extern std::shared_ptr<GameControlEditor::GameControlEditorWindow> mGameControlEditorWindow;
extern std::shared_ptr<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow> mAdvancedResolutionSettingsWindow;
void DrawSettingsMenu() {
if (ImGui::BeginMenu("Settings"))
{
if (ImGui::BeginMenu("Audio")) {
UIWidgets::PaddedEnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true);
if (UIWidgets::PaddedEnhancementSliderFloat("Main Music Volume: %d %%", "##Main_Music_Vol", "gMainMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
UIWidgets::PaddedEnhancementSliderFloat("Master Volume: %.1f %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true);
if (UIWidgets::PaddedEnhancementSliderFloat("Main Music Volume: %.1f %%", "##Main_Music_Vol", "gMainMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
Audio_SetGameVolume(SEQ_BGM_MAIN, CVarGetFloat("gMainMusicVolume", 1.0f));
}
if (UIWidgets::PaddedEnhancementSliderFloat("Sub Music Volume: %d %%", "##Sub_Music_Vol", "gSubMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
if (UIWidgets::PaddedEnhancementSliderFloat("Sub Music Volume: %.1f %%", "##Sub_Music_Vol", "gSubMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
Audio_SetGameVolume(SEQ_BGM_SUB, CVarGetFloat("gSubMusicVolume", 1.0f));
}
if (UIWidgets::PaddedEnhancementSliderFloat("Sound Effects Volume: %d %%", "##Sound_Effect_Vol", "gSFXMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
if (UIWidgets::PaddedEnhancementSliderFloat("Sound Effects Volume: %.1f %%", "##Sound_Effect_Vol", "gSFXMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
Audio_SetGameVolume(SEQ_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f));
}
if (UIWidgets::PaddedEnhancementSliderFloat("Fanfare Volume: %d %%", "##Fanfare_Vol", "gFanfareVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
if (UIWidgets::PaddedEnhancementSliderFloat("Fanfare Volume: %.1f %%", "##Fanfare_Vol", "gFanfareVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, true)) {
Audio_SetGameVolume(SEQ_FANFARE, CVarGetFloat("gFanfareVolume", 1.0f));
}
@ -241,11 +239,6 @@ void DrawSettingsMenu() {
mInputEditorWindow->ToggleVisibility();
}
}
if (mGameControlEditorWindow) {
if (ImGui::Button(GetWindowButtonText("Additional Controller Options", CVarGetInteger("gGameControlEditorEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
mGameControlEditorWindow->ToggleVisibility();
}
}
UIWidgets::PaddedSeparator();
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(3);
@ -255,7 +248,7 @@ void DrawSettingsMenu() {
#endif
UIWidgets::PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false);
UIWidgets::Tooltip("Shows currently pressed inputs on the bottom right of the screen");
UIWidgets::PaddedEnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false, true, true, false);
UIWidgets::PaddedEnhancementSliderFloat("Input Scale: %.2f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false, true, true, false);
UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", "gSimulatedInputLag", 0, 6, "", 0, true, true, false);
UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later");
@ -269,12 +262,14 @@ void DrawSettingsMenu() {
#ifndef __APPLE__
const bool disabled_resolutionSlider = CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0) &&
CVarGetInteger("gAdvancedResolution.Enabled", 0);
if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f,
if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %.1f %%", "##IMul", "gInternalResolution", 0.5f,
2.0f, "", 1.0f, true, true, disabled_resolutionSlider)) {
LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1));
}
UIWidgets::Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing");
#endif
UIWidgets::Tooltip("Resolution scale. Multiplies output resolution by this value, on each axis relative to window size.\n"
"Lower values may improve performance.\n"
"Values above 100% can be used for super-sampling, as an intensive but highly effective form of anti-aliasing.\n\n"
"Default: 100%");
if (mAdvancedResolutionSettingsWindow) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
@ -288,14 +283,28 @@ void DrawSettingsMenu() {
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(3);
}
#ifndef __WIIU__
if (UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, true, true, false)) {
LUS::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger("gMSAAValue", 1));
};
UIWidgets::Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel");
#else
// macOS: Internal resolution is currently disabled in libultraship.
ImGui::BeginGroup();
ImGui::Text("Internal Resolution: 100.0%%");
UIWidgets::Spacer(0);
ImGui::Text(" " ICON_FA_INFO_CIRCLE " Not available on this system.");
UIWidgets::Spacer(0);
ImGui::EndGroup();
#endif
#ifndef __WIIU__
if (UIWidgets::PaddedEnhancementSliderInt(
(CVarGetInteger("gMSAAValue", 1) == 1) ? "Anti-aliasing (MSAA): Off" : "Anti-aliasing (MSAA): %d",
"##IMSAA", "gMSAAValue", 1, 8, "", 1, true, true, false)) {
LUS::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger("gMSAAValue", 1));
}
UIWidgets::Tooltip("Activates MSAA (multi-sample anti-aliasing) from 2x up to 8x, to smooth the edges of rendered geometry.\n"
"Higher sample count will result in smoother edges on models, but may reduce performance.\n\n"
"Recommended: 2x or 4x");
#endif
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
{ // FPS Slider
const int minFps = 20;
static int maxFps;
@ -369,26 +378,27 @@ void DrawSettingsMenu() {
bool matchingRefreshRate =
CVarGetInteger("gMatchRefreshRate", 0) && LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() != LUS::WindowBackend::DX11;
UIWidgets::PaddedEnhancementSliderInt(
(currentFps == 20) ? "FPS: Original (20)" : "FPS: %d",
(currentFps == 20) ? "Frame Rate: Original (20 fps)" : "Frame Rate: %d fps",
"##FPSInterpolation", "gInterpolationFPS", minFps, maxFps, "", 20, true, true, false, matchingRefreshRate);
#endif
if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
UIWidgets::Tooltip(
"Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely "
"visual and does not impact game logic, execution of glitches etc.\n\n"
"A higher target FPS than your monitor's refresh rate will waste resources, and might give a worse result."
);
"Uses Matrix Interpolation to create extra frames, resulting in smoother graphics.\n"
"This is purely visual and does not impact game logic, execution of glitches etc.\n"
"Higher frame rate settings may impact CPU performance."
"\n\n " ICON_FA_INFO_CIRCLE
" There is no need to set this above your monitor's refresh rate. Doing so will waste resources and may give a worse result.");
} else {
UIWidgets::Tooltip(
"Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely "
"visual and does not impact game logic, execution of glitches etc."
);
"Uses Matrix Interpolation to create extra frames, resulting in smoother graphics.\n"
"This is purely visual and does not impact game logic, execution of glitches etc.\n"
"Higher frame rate settings may impact CPU performance.");
}
} // END FPS Slider
if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
UIWidgets::Spacer(0);
if (ImGui::Button("Match Refresh Rate")) {
if (ImGui::Button("Match Frame Rate to Refresh Rate")) {
int hz = LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
if (hz >= 20 && hz <= 360) {
CVarSetInteger("gInterpolationFPS", hz);
@ -396,17 +406,22 @@ void DrawSettingsMenu() {
}
}
} else {
UIWidgets::PaddedEnhancementCheckbox("Match Refresh Rate", "gMatchRefreshRate", true, false);
UIWidgets::PaddedEnhancementCheckbox("Match Frame Rate to Refresh Rate", "gMatchRefreshRate", true, false);
}
UIWidgets::Tooltip("Matches interpolation value to the current game's window refresh rate");
UIWidgets::Tooltip("Matches interpolation value to the game window's current refresh rate.");
if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
UIWidgets::PaddedEnhancementSliderInt(CVarGetInteger("gExtraLatencyThreshold", 80) == 0 ? "Jitter fix: Off" : "Jitter fix: >= %d FPS",
"##ExtraLatencyThreshold", "gExtraLatencyThreshold", 0, 360, "", 80, true, true, false);
UIWidgets::Tooltip("When Interpolation FPS setting is at least this threshold, add one frame of input lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the CPU to work on one frame while GPU works on the previous frame.\nThis setting should be used when your computer is too slow to do CPU + GPU work in time.");
UIWidgets::Tooltip(
"(For DirectX backend only)\n\n"
"When Interpolation FPS (Frame Rate) setting is at least this threshold, add one frame of delay (e.g. 16.6 ms for 60 FPS) in order to avoid jitter."
"This setting allows the CPU to work on one frame while GPU works on the previous frame.\n"
"This setting should be used when your computer is too slow to do CPU + GPU work in time.");
}
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
ImGui::Text("ImGui Menu Scale");
ImGui::SameLine();
ImGui::TextColored({ 0.85f, 0.35f, 0.0f, 1.0f }, "(Experimental)");
@ -455,6 +470,7 @@ void DrawSettingsMenu() {
if (LUS::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) {
UIWidgets::PaddedEnhancementCheckbox("Enable Vsync", "gVsyncEnabled", true, false);
UIWidgets::Tooltip("Activate vertical sync, to prevent screen tearing.");
}
if (LUS::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen()) {
@ -462,17 +478,21 @@ void DrawSettingsMenu() {
}
if (LUS::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports()) {
UIWidgets::PaddedEnhancementCheckbox("Allow multi-windows", "gEnableMultiViewports", true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::PaddedEnhancementCheckbox("Allow multi-windows (Needs reload)", "gEnableMultiViewports", true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Allows windows to be able to be dragged off of the main game window. Requires a reload to take effect.");
}
// If more filters are added to LUS, make sure to add them to the filters list here
ImGui::Text("Texture Filter (Needs reload)");
ImGui::Text("Texture Filtering (Needs reload)");
UIWidgets::EnhancementCombobox("gTextureFilter", filters, FILTER_THREE_POINT);
UIWidgets::Tooltip("Texture filtering, aka texture smoothing. Requires a reload to take effect.\n\n"
"Three-Point: Replicates real N64 texture filtering.\n"
"Bilinear: If Three-Point causes poor performance, try this.\n"
"Nearest: Disables texture smoothing. (Not recommended)");
UIWidgets::Spacer(0);
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// Draw LUS settings menu (such as Overlays Text Font)
LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->DrawSettings();
ImGui::EndMenu();
@ -527,22 +547,61 @@ void DrawEnhancementsMenu() {
{
if (ImGui::BeginMenu("Time Savers"))
{
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 8.0f);
ImGui::BeginTable("##timeSaversMenu", 2, ImGuiTableFlags_SizingFixedFit);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextColumn();
UIWidgets::Spacer(0);
ImGui::Text("Speed-ups:");
UIWidgets::PaddedSeparator();
UIWidgets::PaddedEnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "", 1, true, false, true);
UIWidgets::PaddedEnhancementCheckbox("Skip Text", "gSkipText", false, true);
UIWidgets::Tooltip("Holding down B skips text");
UIWidgets::PaddedEnhancementSliderInt("King Zora Speed: %dx", "##MWEEPSPEED", "gMweepSpeed", 1, 5, "", 1, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Biggoron Forge Time: %d days", "##FORGETIME", "gForgeTime", 0, 3, "", 3, true, false, true);
UIWidgets::Tooltip("Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword");
UIWidgets::PaddedEnhancementSliderInt("Vine/Ladder Climb speed +%d", "##CLIMBSPEED", "gClimbSpeed", 0, 12, "", 0, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Block pushing speed +%d", "##BLOCKSPEED", "gFasterBlockPush", 0, 5, "", 0, true, false, true);
UIWidgets::PaddedEnhancementCheckbox("Faster Heavy Block Lift", "gFasterHeavyBlockLift", true, false);
UIWidgets::PaddedEnhancementSliderInt("Crawl speed %dx", "##CRAWLSPEED", "gCrawlSpeed", 1, 5, "", 1, true, false, true);
UIWidgets::PaddedEnhancementCheckbox("Faster Heavy Block Lift", "gFasterHeavyBlockLift", false, false);
UIWidgets::Tooltip("Speeds up lifting silver rocks and obelisks");
UIWidgets::PaddedEnhancementCheckbox("Link as default file name", "gLinkDefaultName", true, false);
UIWidgets::Tooltip("Allows you to have \"Link\" as a premade file name");
UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false);
UIWidgets::Tooltip("Skip pickup messages for new consumable items and bottle swipes");
UIWidgets::PaddedEnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback", true, false);
UIWidgets::Tooltip("Skip the part where the Ocarina playback is called when you play a song");
bool forceSkipScarecrow = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_SCARECROWS_SONG);
static const char* forceSkipScarecrowText = "This setting is forcefully enabled because a savefile\nwith \"Skip Scarecrow Song\" is loaded";
UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", "gSkipScarecrow", true, false,
forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", "gSkipArrowAnimation", true, false);
UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", "gSkipSaveConfirmation", true, false);
UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen");
UIWidgets::PaddedEnhancementCheckbox("Faster Farore's Wind", "gFastFarores", true, false);
UIWidgets::Tooltip("Greatly decreases cast time of Farore's Wind magic spell.");
UIWidgets::PaddedEnhancementCheckbox("Skip water take breath animation", "gSkipSwimDeepEndAnim", true, false);
UIWidgets::Tooltip("Skips Link's taking breath animation after coming up from water. This setting does not interfere with getting items from underwater.");
ImGui::TableNextColumn();
UIWidgets::Spacer(0);
ImGui::Text("Changes:");
UIWidgets::PaddedSeparator();
UIWidgets::PaddedEnhancementSliderInt("Biggoron Forge Time: %d days", "##FORGETIME", "gForgeTime", 0, 3, "", 3, true, false, true);
UIWidgets::Tooltip("Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword");
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", false, false);
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
"This doesn't work if the save was made in a grotto.");
UIWidgets::PaddedEnhancementCheckbox("No Forced Navi", "gNoForcedNavi", true, false);
UIWidgets::Tooltip("Prevent forced Navi conversations");
UIWidgets::PaddedEnhancementCheckbox("Navi Timer Resets", "gEnhancements.ResetNaviTimer", true, false);
UIWidgets::Tooltip("Resets the Navi timer on scene change. If you have already talked to her, she will try and talk to you again, instead of needing a save warp or death. ");
UIWidgets::PaddedEnhancementCheckbox("No Skulltula Freeze", "gSkulltulaFreeze", true, false);
UIWidgets::Tooltip("Stops the game from freezing the player when picking up Gold Skulltulas");
UIWidgets::PaddedEnhancementCheckbox("Nighttime GS Always Spawn", "gNightGSAlwaysSpawn", true, false);
UIWidgets::Tooltip("Nighttime Skulltulas will spawn during both day and night.");
UIWidgets::PaddedEnhancementCheckbox("Dampe Appears All Night", "gDampeAllNight", true, false);
UIWidgets::Tooltip("Makes Dampe appear anytime during the night, not just his usual working hours.");
UIWidgets::PaddedEnhancementCheckbox("Fast Chests", "gFastChests", true, false);
UIWidgets::Tooltip("Kick open every chest");
UIWidgets::PaddedText("Chest size & texture matches contents", true, false);
@ -566,36 +625,16 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Chests of Agony", "gChestSizeDependsStoneOfAgony", true, false);
UIWidgets::Tooltip("Only change the size/texture of chests if you have the Stone of Agony.");
}
UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false);
UIWidgets::Tooltip("Skip pickup messages for new consumable items and bottle swipes");
UIWidgets::PaddedEnhancementCheckbox("Ask to Equip New Items", "gAskToEquip", true, false);
UIWidgets::Tooltip("Adds a prompt to equip newly-obtained swords, shields and tunics");
UIWidgets::PaddedEnhancementCheckbox("Better Owl", "gBetterOwl", true, false);
UIWidgets::Tooltip("The default response to Kaepora Gaebora is always that you understood what he said");
UIWidgets::PaddedEnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback", true, false);
bool forceSkipScarecrow = IS_RANDO &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_SCARECROWS_SONG);
static const char* forceSkipScarecrowText =
"This setting is forcefully enabled because a savefile\nwith \"Skip Scarecrow Song\" is loaded";
UIWidgets::Tooltip("Skip the part where the Ocarina playback is called when you play a song");
UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", "gSkipScarecrow", true, false,
forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false);
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
"This doesn't work if the save was made in a grotto.");
UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", "gSkipArrowAnimation", true, false);
UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", "gSkipSaveConfirmation", true, false);
UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen");
UIWidgets::PaddedEnhancementCheckbox("Exit Market at Night", "gMarketSneak", true, false);
UIWidgets::Tooltip("Allows exiting Hyrule Castle Market Town to Hyrule Field at night by speaking "
"to the guard next to the gate.");
UIWidgets::PaddedEnhancementCheckbox("Faster Farore's Wind", "gFastFarores", true, false);
UIWidgets::Tooltip("Greatly decreases cast time of Farore's Wind magic spell.");
UIWidgets::PaddedEnhancementCheckbox("Nighttime GS Always Spawn", "gNightGSAlwaysSpawn", true, false);
UIWidgets::Tooltip("Nighttime Skulltulas will spawn during both day and night.");
UIWidgets::PaddedEnhancementCheckbox("Dampe Appears All Night", "gDampeAllNight", true, false);
UIWidgets::Tooltip("Makes Dampe appear anytime during the night, not just his usual working hours.");
UIWidgets::Tooltip("Allows exiting Hyrule Castle Market Town to Hyrule Field at night by speaking to the guard next to the gate.");
UIWidgets::PaddedEnhancementCheckbox("Link as default file name", "gLinkDefaultName", true, false);
UIWidgets::Tooltip("Allows you to have \"Link\" as a premade file name");
UIWidgets::PaddedEnhancementCheckbox("Quit Fishing At Door", "gQuitFishingAtDoor", true, false);
UIWidgets::Tooltip("Fisherman asks if you want to quit at the door when you still have the rod");
UIWidgets::PaddedText("Time Travel with the Song of Time", true, false);
UIWidgets::EnhancementCombobox("gTimeTravel", timeTravelOptions, 0);
UIWidgets::Tooltip("Allows Link to freely change age by playing the Song of Time.\n"
@ -606,8 +645,8 @@ void DrawEnhancementsMenu() {
"- Obtained the Master Sword\n"
"- Not within range of Time Block\n"
"- Not within range of Ocarina playing spots");
UIWidgets::PaddedEnhancementCheckbox("Skip water take breath animation", "gSkipSwimDeepEndAnim", true, false);
UIWidgets::Tooltip("Skips Link's taking breath animation after coming up from water. This setting does not interfere with getting items from underwater.");
ImGui::EndTable();
ImGui::EndMenu();
}
@ -660,83 +699,6 @@ void DrawEnhancementsMenu() {
if (ImGui::BeginMenu("Difficulty Options"))
{
UIWidgets::PaddedEnhancementCheckbox("Delete File On Death", "gDeleteFileOnDeath", true, false);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
UIWidgets::Tooltip("Dying will delete your file\n\n " ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSABLE\nUSE AT YOUR OWN RISK!");
ImGui::PopStyleColor();
if (UIWidgets::PaddedEnhancementCheckbox("Permanent heart loss", "gPermanentHeartLoss", true, false)) {
UpdatePermanentHeartLossState();
}
UIWidgets::Tooltip("When you lose 4 quarters of a heart you will permanently lose that heart container.\n\nDisabling this after the fact will restore your heart containers.");
ImGui::Text("Damage Multiplier");
UIWidgets::EnhancementCombobox("gDamageMul", allPowers, 0);
UIWidgets::Tooltip(
"Modifies all sources of damage not affected by other sliders\n"
"2x: Can survive all common attacks from the start of the game\n"
"4x: Dies in 1 hit to any substantial attack from the start of the game\n"
"8x: Can only survive trivial damage from the start of the game\n"
"16x: Can survive all common attacks with max health without double defense\n"
"32x: Can survive all common attacks with max health and double defense\n"
"64x: Can survive trivial damage with max health without double defense\n"
"128x: Can survive trivial damage with max health and double defense\n"
"256x: Cannot survive damage"
);
UIWidgets::PaddedText("Fall Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gFallDamageMul", subPowers, 0);
UIWidgets::Tooltip(
"Modifies all fall damage\n"
"2x: Can survive all fall damage from the start of the game\n"
"4x: Can only survive short fall damage from the start of the game\n"
"8x: Cannot survive any fall damage from the start of the game\n"
"16x: Can survive all fall damage with max health without double defense\n"
"32x: Can survive all fall damage with max health and double defense\n"
"64x: Can survive short fall damage with double defense\n"
"128x: Cannot survive fall damage"
);
UIWidgets::PaddedText("Void Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gVoidDamageMul", subSubPowers, 0);
UIWidgets::Tooltip(
"Modifies damage taken after falling into a void\n"
"2x: Can survive void damage from the start of the game\n"
"4x: Cannot survive void damage from the start of the game\n"
"8x: Can survive void damage twice with max health without double defense\n"
"16x: Can survive void damage with max health without double defense\n"
"32x: Can survive void damage with max health and double defense\n"
"64x: Cannot survive void damage"
);
UIWidgets::PaddedText("Bonk Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gBonkDamageMul", bonkDamageValues, BONK_DAMAGE_NONE);
UIWidgets::Tooltip("Modifies damage taken after bonking.");
UIWidgets::PaddedEnhancementCheckbox("Spawn with full health", "gFullHealthSpawn", true, false);
UIWidgets::Tooltip("Respawn with full health instead of 3 Hearts");
UIWidgets::PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false);
UIWidgets::Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
bool forceEnableBombchuDrops = IS_RANDO &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_ENABLE_BOMBCHU_DROPS) == 1;
static const char* forceEnableBombchuDropsText =
"This setting is forcefully enabled because a savefile\nwith \"Enable Bombchu Drops\" is loaded.";
UIWidgets::PaddedEnhancementCheckbox("Enable Bombchu Drops", "gBombchuDrops", true, false,
forceEnableBombchuDrops, forceEnableBombchuDropsText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Bombchus will sometimes drop in place of bombs");
UIWidgets::PaddedEnhancementCheckbox("Trees Drop Sticks", "gTreeStickDrops", true, false);
UIWidgets::Tooltip("Bonking into trees will have a chance to drop up to 3 sticks. Must already have obtained sticks.");
UIWidgets::PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false);
UIWidgets::Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
UIWidgets::PaddedEnhancementCheckbox("Hyper Bosses", "gHyperBosses", true, false);
UIWidgets::Tooltip("All major bosses move and act twice as fast.");
UIWidgets::PaddedEnhancementCheckbox("Hyper Enemies", "gHyperEnemies", true, false);
UIWidgets::Tooltip("All regular enemies and mini-bosses move and act twice as fast.");
UIWidgets::PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false);
UIWidgets::Tooltip("Always get the heart piece/purple rupee from the spinning Goron pot");
UIWidgets::PaddedEnhancementCheckbox("Always Win Dampe Digging Game", "gDampeWin", true, false, SaveManager::Instance->IsRandoFile(),
"This setting is always enabled in randomizer files", UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Always win the heart piece/purple rupee on the first dig in Dampe's grave digging game, just like in rando\nIn a rando file, this is unconditionally enabled");
UIWidgets::PaddedEnhancementCheckbox("All Dogs are Richard", "gAllDogsRichard", true, false);
UIWidgets::Tooltip("All dogs can be traded in and will count as Richard.");
UIWidgets::PaddedEnhancementSliderInt("Cuccos Stay Put Multiplier: %dx", "##CuccoStayDurationMultiplier", "gCuccoStayDurationMultiplier", 1, 5, "", 1, true, true, false);
UIWidgets::Tooltip("Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider.");
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Potion Values"))
{
UIWidgets::EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect");
@ -881,6 +843,118 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("The minimum weight for the unique fishing reward as an adult");
ImGui::EndMenu();
}
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Lost Woods Ocarina Game")) {
UIWidgets::EnhancementCheckbox("Customize Behavior", "gCustomizeOcarinaGame");
UIWidgets::Tooltip("Turn on/off changes to the lost woods ocarina game behavior");
bool disabled = !CVarGetInteger("gCustomizeOcarinaGame", 0);
static const char* disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off";
UIWidgets::PaddedEnhancementCheckbox("Instant Win", "gInstantOcarinaGameWin", true, false, disabled, disabledTooltip);
UIWidgets::Tooltip("Skips the lost woods ocarina game");
UIWidgets::PaddedEnhancementSliderInt("Note Play Speed: %dx", "##OcarinaGameNoteSpeed", "gOcarinaGameNoteSpeed", 1, 5, "", 1, true, true, false, disabled, disabledTooltip);
UIWidgets::Tooltip("Adjust the speed that the skull kids play notes");
UIWidgets::PaddedEnhancementCheckbox("Unlimited Playback Time", "gOcarinaUnlimitedFailTime", true, false, disabled, disabledTooltip);
UIWidgets::Tooltip("Removes the timer to play back the song");
UIWidgets::PaddedEnhancementSliderInt("Number of Starting Notes: %d", "##OcarinaGameStartingNotes", "gOcarinaGameStartingNotes", 1, 8, "", 3, true, true, false,
disabled, disabledTooltip);
UIWidgets::Tooltip("Adjust the number of notes the skull kids play to start the first round");
int roundMin = CVarGetInteger("gOcarinaGameStartingNotes", 3);
UIWidgets::PaddedEnhancementSliderInt("Round One Notes: %d", "##OcarinaGameRoundOne",
"gOcarinaGameRoundOneNotes", roundMin, 8, "", 5, true, true,
false,
disabled, disabledTooltip);
UIWidgets::Tooltip("Adjust the number of notes you need to play to end the first round");
UIWidgets::PaddedEnhancementSliderInt("Round Two Notes: %d", "##OcarinaGameRoundTwoNotes",
"gOcarinaGameRoundTwoNotes", roundMin, 8, "", 6, true, true,
false,
disabled, disabledTooltip);
UIWidgets::Tooltip("Adjust the number of notes you need to play to end the second round");
UIWidgets::PaddedEnhancementSliderInt("Round Three Notes: %d", "##OcarinaGameRoundThreeNotes",
"gOcarinaGameRoundThreeNotes", roundMin, 8, "", 8, true, true,
false,
disabled, disabledTooltip);
UIWidgets::Tooltip("Adjust the number of notes you need to play to end the third round");
ImGui::EndMenu();
}
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Delete File On Death", "gDeleteFileOnDeath", true, false);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
UIWidgets::Tooltip("Dying will delete your file\n\n " ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSABLE\nUSE AT YOUR OWN RISK!");
ImGui::PopStyleColor();
if (UIWidgets::PaddedEnhancementCheckbox("Permanent heart loss", "gPermanentHeartLoss", true, false)) {
UpdatePermanentHeartLossState();
}
UIWidgets::Tooltip("When you lose 4 quarters of a heart you will permanently lose that heart container.\n\nDisabling this after the fact will restore your heart containers.");
ImGui::Text("Damage Multiplier");
UIWidgets::EnhancementCombobox("gDamageMul", allPowers, 0);
UIWidgets::Tooltip(
"Modifies all sources of damage not affected by other sliders\n"
"2x: Can survive all common attacks from the start of the game\n"
"4x: Dies in 1 hit to any substantial attack from the start of the game\n"
"8x: Can only survive trivial damage from the start of the game\n"
"16x: Can survive all common attacks with max health without double defense\n"
"32x: Can survive all common attacks with max health and double defense\n"
"64x: Can survive trivial damage with max health without double defense\n"
"128x: Can survive trivial damage with max health and double defense\n"
"256x: Cannot survive damage"
);
UIWidgets::PaddedText("Fall Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gFallDamageMul", subPowers, 0);
UIWidgets::Tooltip(
"Modifies all fall damage\n"
"2x: Can survive all fall damage from the start of the game\n"
"4x: Can only survive short fall damage from the start of the game\n"
"8x: Cannot survive any fall damage from the start of the game\n"
"16x: Can survive all fall damage with max health without double defense\n"
"32x: Can survive all fall damage with max health and double defense\n"
"64x: Can survive short fall damage with double defense\n"
"128x: Cannot survive fall damage"
);
UIWidgets::PaddedText("Void Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gVoidDamageMul", subSubPowers, 0);
UIWidgets::Tooltip(
"Modifies damage taken after falling into a void\n"
"2x: Can survive void damage from the start of the game\n"
"4x: Cannot survive void damage from the start of the game\n"
"8x: Can survive void damage twice with max health without double defense\n"
"16x: Can survive void damage with max health without double defense\n"
"32x: Can survive void damage with max health and double defense\n"
"64x: Cannot survive void damage"
);
UIWidgets::PaddedText("Bonk Damage Multiplier", true, false);
UIWidgets::EnhancementCombobox("gBonkDamageMul", bonkDamageValues, BONK_DAMAGE_NONE);
UIWidgets::Tooltip("Modifies damage taken after bonking.");
UIWidgets::PaddedEnhancementCheckbox("Spawn with full health", "gFullHealthSpawn", true, false);
UIWidgets::Tooltip("Respawn with full health instead of 3 Hearts");
UIWidgets::PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false);
UIWidgets::Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
bool forceEnableBombchuDrops = IS_RANDO &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_ENABLE_BOMBCHU_DROPS) == 1;
static const char* forceEnableBombchuDropsText =
"This setting is forcefully enabled because a savefile\nwith \"Enable Bombchu Drops\" is loaded.";
UIWidgets::PaddedEnhancementCheckbox("Enable Bombchu Drops", "gBombchuDrops", true, false,
forceEnableBombchuDrops, forceEnableBombchuDropsText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Bombchus will sometimes drop in place of bombs");
UIWidgets::PaddedEnhancementCheckbox("Trees Drop Sticks", "gTreeStickDrops", true, false);
UIWidgets::Tooltip("Bonking into trees will have a chance to drop up to 3 sticks. Must already have obtained sticks.");
UIWidgets::PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false);
UIWidgets::Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
UIWidgets::PaddedEnhancementCheckbox("Hyper Bosses", "gHyperBosses", true, false);
UIWidgets::Tooltip("All major bosses move and act twice as fast.");
UIWidgets::PaddedEnhancementCheckbox("Hyper Enemies", "gHyperEnemies", true, false);
UIWidgets::Tooltip("All regular enemies and mini-bosses move and act twice as fast.");
UIWidgets::PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false);
UIWidgets::Tooltip("Always get the heart piece/purple rupee from the spinning Goron pot");
UIWidgets::PaddedEnhancementCheckbox("Always Win Dampe Digging Game", "gDampeWin", true, false, SaveManager::Instance->IsRandoFile(),
"This setting is always enabled in randomizer files", UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Always win the heart piece/purple rupee on the first dig in Dampe's grave digging game, just like in rando\nIn a rando file, this is unconditionally enabled");
UIWidgets::PaddedEnhancementCheckbox("All Dogs are Richard", "gAllDogsRichard", true, false);
UIWidgets::Tooltip("All dogs can be traded in and will count as Richard.");
UIWidgets::PaddedEnhancementSliderInt("Cuccos Stay Put Multiplier: %dx", "##CuccoStayDurationMultiplier", "gCuccoStayDurationMultiplier", 1, 5, "", 1, true, true, false);
UIWidgets::Tooltip("Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider.");
ImGui::EndMenu();
}
@ -974,37 +1048,9 @@ void DrawEnhancementsMenu() {
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::PaddedEnhancementCheckbox("Show Gauntlets in First Person", "gFPSGauntlets", true, false);
UIWidgets::Tooltip("Renders Gauntlets when using the Bow and Hookshot like in OOT3D");
if (UIWidgets::PaddedEnhancementCheckbox("Color Temple of Time's Medallions", "gToTMedallionsColors", true, false)) {
PatchToTMedallions();
}
UIWidgets::Tooltip("When medallions are collected, the medallion imprints around the Master Sword pedestal in the Temple of Time will become colored");
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Animated Link in Pause Menu")) {
ImGui::Text("Rotation");
UIWidgets::EnhancementRadioButton("Disabled", "gPauseLiveLinkRotation", 0);
@ -1048,6 +1094,49 @@ void DrawEnhancementsMenu() {
ImGui::EndMenu();
}
UIWidgets::Spacer(0);
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");
}
if (UIWidgets::PaddedEnhancementCheckbox("Show Age-Dependent Equipment", "gEnhancements.EquimentAlwaysVisible", true,
false)) {
UpdatePatchHand();
}
UIWidgets::Tooltip("Makes all equipment visible, regardless of Age.");
if (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0) == 1) {
UIWidgets::PaddedEnhancementCheckbox("Scale Adult Equipment as Child", "gEnhancements.ScaleAdultEquimentAsChild", true, false);
UIWidgets::Tooltip("Scales all of the Adult Equipment, as well and moving some a bit, to fit on Child Link Better. May not work properly with some mods.");
}
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::PaddedEnhancementCheckbox("Show Gauntlets in First Person", "gFPSGauntlets", true, false);
UIWidgets::Tooltip("Renders Gauntlets when using the Bow and Hookshot like in OOT3D");
if (UIWidgets::PaddedEnhancementCheckbox("Color Temple of Time's Medallions", "gToTMedallionsColors", true, false)) {
PatchToTMedallions();
}
UIWidgets::Tooltip("When medallions are collected, the medallion imprints around the Master Sword pedestal in the Temple of Time will become colored");
UIWidgets::PaddedEnhancementCheckbox("Show locked door chains on both sides of locked doors", "gShowDoorLocksOnBothSides", true, false);
UIWidgets::PaddedText("Fix Vanishing Paths", true, false);
if (UIWidgets::EnhancementCombobox("gSceneSpecificDirtPathFix", zFightingOptions, ZFIGHT_FIX_DISABLED) && gPlayState != NULL) {
UpdateDirtPathFixState(gPlayState->sceneNum);
@ -1147,6 +1236,7 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Quick Putaway", "gQuickPutaway", true, false);
UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows putting away an item without an animation and performing Putaway Ocarina Items");
UIWidgets::PaddedEnhancementCheckbox("Restore old Gold Skulltula cutscene", "gGsCutscene", true, false);
UIWidgets::Tooltip("Restore pre-release behavior where defeating a Gold Skulltula will play a cutscene showing it die.");
UIWidgets::PaddedEnhancementCheckbox("Quick Bongo Kill", "gQuickBongoKill", true, false);
UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows bypassing Bongo Bongo's intro cutscene to quickly kill him");
UIWidgets::PaddedEnhancementCheckbox("Original RBA Values", "gRestoreRBAValues", true, false);
@ -1209,8 +1299,6 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Shadow Tag Mode", "gShadowTag", true, false);
UIWidgets::Tooltip("A wallmaster follows Link everywhere, don't get caught!");
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementCheckbox("Additional Traps", "gAddTraps.enabled", true, false);
UIWidgets::Tooltip("Enables additional Trap variants.");
@ -1242,6 +1330,14 @@ void DrawEnhancementsMenu() {
}
}
UIWidgets::Spacer(0);
if (UIWidgets::PaddedEnhancementCheckbox("Hurt Container Mode", "gHurtContainer", true, false)) {
UpdateHurtContainerModeState(CVarGetInteger("gHurtContainer", 0));
}
UIWidgets::Tooltip("Changes Heart Piece and Heart Container functionality.\n\n"
"- Each Heart Container or full Heart Piece reduces Links hearts by 1.\n"
"- Can be enabled retroactively after a File has already started.");
ImGui::EndMenu();
}
@ -1299,6 +1395,51 @@ void DrawCheatsMenu() {
if (ImGui::BeginMenu("Cheats"))
{
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 8.0f);
ImGui::BeginTable("##cheatsMenu", 2, ImGuiTableFlags_SizingFixedFit);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextColumn();
UIWidgets::Spacer(2.0f);
ImGui::Text("Inventory:");
UIWidgets::PaddedSeparator();
UIWidgets::PaddedEnhancementCheckbox("Super Tunic", "gSuperTunic", true, false);
UIWidgets::Tooltip("Makes every tunic have the effects of every other tunic");
UIWidgets::PaddedEnhancementCheckbox("Easy ISG", "gEzISG", true, false);
UIWidgets::Tooltip("Passive Infinite Sword Glitch\nIt makes your sword's swing effect and hitbox stay active indefinitely");
UIWidgets::PaddedEnhancementCheckbox("Easy QPA", "gEzQPA", true, false);
UIWidgets::Tooltip("Gives you the glitched damage value of the quick put away glitch.");
UIWidgets::PaddedEnhancementCheckbox("Timeless Equipment", "gTimelessEquipment", true, false);
UIWidgets::Tooltip("Allows any item to be equipped, regardless of age\nAlso allows Child to use Adult strength upgrades");
UIWidgets::PaddedEnhancementCheckbox("Unrestricted Items", "gNoRestrictItems", true, false);
UIWidgets::Tooltip("Allows you to use any item at any location");
UIWidgets::PaddedEnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield", true, false);
UIWidgets::Tooltip("Prevents the Deku Shield from burning on contact with fire");
UIWidgets::PaddedEnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded", true, false);
UIWidgets::Tooltip("This allows you to put up your shield with any two-handed weapon in hand except for Deku Sticks");
UIWidgets::Spacer(2.0f);
ImGui::Text("Deku Sticks:");
UIWidgets::EnhancementCombobox("gDekuStickCheat", DekuStickCheat, DEKU_STICK_NORMAL);
UIWidgets::Spacer(2.0f);
UIWidgets::EnhancementSliderFloat("Bomb Timer Multiplier: %.2fx", "##gBombTimerMultiplier", "gBombTimerMultiplier", 0.1f, 5.0f, "", 1.0f, false);
UIWidgets::PaddedEnhancementCheckbox("Hookshot Everything", "gHookshotEverything", true, false);
UIWidgets::Tooltip("Makes every surface in the game hookshot-able");
UIWidgets::Spacer(0);
UIWidgets::EnhancementSliderFloat("Hookshot Reach Multiplier: %.2fx", "##gCheatHookshotReachMultiplier", "gCheatHookshotReachMultiplier", 1.0f, 5.0f, "", 1.0f, false);
UIWidgets::Spacer(2.0f);
if (ImGui::Button("Change Age")) {
CVarSetInteger("gSwitchAge", 1);
}
UIWidgets::Tooltip("Switches Link's age and reloads the area.");
UIWidgets::Spacer(2.0f);
if (ImGui::Button("Clear Cutscene Pointer")) {
GameInteractor::RawAction::ClearCutscenePointer();
}
UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps.");
ImGui::TableNextColumn();
UIWidgets::Spacer(2.0f);
if (ImGui::BeginMenu("Infinite...")) {
UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney");
@ -1311,51 +1452,8 @@ void DrawCheatsMenu() {
ImGui::EndMenu();
}
UIWidgets::PaddedEnhancementCheckbox("No Clip", "gNoClip", true, false);
UIWidgets::Tooltip("Allows you to walk through walls");
UIWidgets::PaddedEnhancementCheckbox("Climb Everything", "gClimbEverything", true, false);
UIWidgets::Tooltip("Makes every surface in the game climbable");
UIWidgets::PaddedEnhancementCheckbox("Hookshot Everything", "gHookshotEverything", true, false);
UIWidgets::Tooltip("Makes every surface in the game hookshot-able");
UIWidgets::Spacer(2.0f);
UIWidgets::EnhancementSliderFloat("Hookshot Reach Multiplier: %.1fx", "##gCheatHookshotReachMultiplier", "gCheatHookshotReachMultiplier", 1.0f, 5.0f, "", 1.0f, false);
UIWidgets::EnhancementSliderFloat("Bomb Timer Multiplier: %.1fx", "##gBombTimerMultiplier", "gBombTimerMultiplier", 0.1f, 5.0f, "", 1.0f, false);
UIWidgets::PaddedEnhancementCheckbox("Moon Jump on L", "gMoonJumpOnL", true, false);
UIWidgets::Tooltip("Holding L makes you float into the air");
UIWidgets::PaddedEnhancementCheckbox("Super Tunic", "gSuperTunic", true, false);
UIWidgets::Tooltip("Makes every tunic have the effects of every other tunic");
UIWidgets::PaddedEnhancementCheckbox("Easy ISG", "gEzISG", true, false);
UIWidgets::Tooltip("Passive Infinite Sword Glitch\nIt makes your sword's swing effect and hitbox stay active indefinitely");
UIWidgets::PaddedEnhancementCheckbox("Easy QPA", "gEzQPA", true, false);
UIWidgets::Tooltip("Gives you the glitched damage value of the quick put away glitch.");
UIWidgets::PaddedEnhancementCheckbox("Timeless Equipment", "gTimelessEquipment", true, false);
UIWidgets::Tooltip("Allows any item to be equipped, regardless of age\nAlso allows Child to use Adult strength upgrades");
UIWidgets::PaddedEnhancementCheckbox("Easy Frame Advancing", "gCheatEasyPauseBufferEnabled", true, false);
UIWidgets::Tooltip("Continue holding START button when unpausing to only advance a single frame and then re-pause");
const bool bEasyFrameAdvanceEnabled = CVarGetInteger("gCheatEasyPauseBufferEnabled", 0);
UIWidgets::PaddedEnhancementCheckbox("Easy Input Buffering", "gCheatEasyInputBufferingEnabled", true, false, bEasyFrameAdvanceEnabled, "Forced enabled when Easy Frame Advancing is enabled");
UIWidgets::Tooltip("Inputs that are held down while the Subscreen is closing will be pressed when the game is resumed");
UIWidgets::PaddedEnhancementCheckbox("Unrestricted Items", "gNoRestrictItems", true, false);
UIWidgets::Tooltip("Allows you to use any item at any location");
UIWidgets::PaddedEnhancementCheckbox("Freeze Time", "gFreezeTime", true, false);
UIWidgets::Tooltip("Freezes the time of day");
UIWidgets::PaddedEnhancementCheckbox("Drops Don't Despawn", "gDropsDontDie", true, false);
UIWidgets::Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time");
UIWidgets::PaddedEnhancementCheckbox("Fish Don't despawn", "gNoFishDespawn", true, false);
UIWidgets::Tooltip("Prevents fish from automatically despawning after a while when dropped");
UIWidgets::PaddedEnhancementCheckbox("Bugs Don't despawn", "gNoBugsDespawn", true, false);
UIWidgets::Tooltip("Prevents bugs from automatically despawning after a while when dropped");
UIWidgets::PaddedEnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield", true, false);
UIWidgets::Tooltip("Prevents the Deku Shield from burning on contact with fire");
UIWidgets::PaddedEnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded", true, false);
UIWidgets::Tooltip("This allows you to put up your shield with any two-handed weapon in hand except for Deku Sticks");
UIWidgets::PaddedEnhancementCheckbox("Time Sync", "gTimeSync", true, false);
UIWidgets::Tooltip("This syncs the ingame time with the real world time");
ImGui::Text("Deku Sticks:");
UIWidgets::EnhancementCombobox("gDekuStickCheat", DekuStickCheat, DEKU_STICK_NORMAL);
UIWidgets::PaddedEnhancementCheckbox("No ReDead/Gibdo Freeze", "gNoRedeadFreeze", true, false);
UIWidgets::Tooltip("Prevents ReDeads and Gibdos from being able to freeze you with their scream");
UIWidgets::Spacer(2.0f);
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Save States")) {
ImGui::TextColored({ 0.85f, 0.85f, 0.0f, 1.0f }, " " ICON_FA_EXCLAMATION_TRIANGLE);
ImGui::SameLine();
@ -1367,19 +1465,47 @@ void DrawCheatsMenu() {
UIWidgets::PaddedText("they WILL break across transitions and", true, false);
UIWidgets::PaddedText("load zones (like doors). Support for", true, false);
UIWidgets::PaddedText("related issues will not be provided.", true, false);
if (UIWidgets::PaddedEnhancementCheckbox("I promise I have read the warning", "gSaveStatePromise", true, false)) {
if (UIWidgets::PaddedEnhancementCheckbox("I promise I have read the warning", "gSaveStatePromise", true,
false)) {
CVarSetInteger("gSaveStatesEnabled", 0);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (CVarGetInteger("gSaveStatePromise", 0) == 1) {
UIWidgets::PaddedEnhancementCheckbox("I understand, enable save states", "gSaveStatesEnabled", true, false);
UIWidgets::PaddedEnhancementCheckbox("I understand, enable save states", "gSaveStatesEnabled", true,
false);
UIWidgets::Tooltip("F5 to save, F6 to change slots, F7 to load");
}
ImGui::EndMenu();
}
UIWidgets::Spacer(2.0f);
UIWidgets::Spacer(2.0f);
ImGui::Text("Behavior:");
UIWidgets::PaddedSeparator();
UIWidgets::PaddedEnhancementCheckbox("No Clip", "gNoClip", true, false);
UIWidgets::Tooltip("Allows you to walk through walls");
UIWidgets::PaddedEnhancementCheckbox("Climb Everything", "gClimbEverything", true, false);
UIWidgets::Tooltip("Makes every surface in the game climbable");
UIWidgets::PaddedEnhancementCheckbox("Moon Jump on L", "gMoonJumpOnL", true, false);
UIWidgets::Tooltip("Holding L makes you float into the air");
UIWidgets::PaddedEnhancementCheckbox("Easy Frame Advancing", "gCheatEasyPauseBufferEnabled", true, false);
UIWidgets::Tooltip("Continue holding START button when unpausing to only advance a single frame and then re-pause");
const bool bEasyFrameAdvanceEnabled = CVarGetInteger("gCheatEasyPauseBufferEnabled", 0);
UIWidgets::PaddedEnhancementCheckbox("Easy Input Buffering", "gCheatEasyInputBufferingEnabled", true, false, bEasyFrameAdvanceEnabled, "Forced enabled when Easy Frame Advancing is enabled", UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Inputs that are held down while the Subscreen is closing will be pressed when the game is resumed");
UIWidgets::PaddedEnhancementCheckbox("Drops Don't Despawn", "gDropsDontDie", true, false);
UIWidgets::Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time");
UIWidgets::PaddedEnhancementCheckbox("Fish Don't despawn", "gNoFishDespawn", true, false);
UIWidgets::Tooltip("Prevents fish from automatically despawning after a while when dropped");
UIWidgets::PaddedEnhancementCheckbox("Bugs Don't despawn", "gNoBugsDespawn", true, false);
UIWidgets::Tooltip("Prevents bugs from automatically despawning after a while when dropped");
UIWidgets::PaddedEnhancementCheckbox("Freeze Time", "gFreezeTime", true, false);
UIWidgets::Tooltip("Freezes the time of day");
UIWidgets::PaddedEnhancementCheckbox("Time Sync", "gTimeSync", true, false);
UIWidgets::Tooltip("This syncs the ingame time with the real world time");
UIWidgets::PaddedEnhancementCheckbox("No ReDead/Gibdo Freeze", "gNoRedeadFreeze", true, false);
UIWidgets::Tooltip("Prevents ReDeads and Gibdos from being able to freeze you with their scream");
{
static int32_t betaQuestEnabled = CVarGetInteger("gEnableBetaQuest", 0);
static int32_t lastBetaQuestEnabled = betaQuestEnabled;
@ -1443,19 +1569,8 @@ void DrawCheatsMenu() {
}
}
UIWidgets::Spacer(2.0f);
if (ImGui::Button("Change Age")) {
CVarSetInteger("gSwitchAge", 1);
}
UIWidgets::Tooltip("Switches Link's age and reloads the area.");
if (ImGui::Button("Clear Cutscene Pointer")) {
GameInteractor::RawAction::ClearCutscenePointer();
}
UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps.");
ImGui::EndTable();
ImGui::EndDisabled();
ImGui::EndMenu();
}
}

View File

@ -297,6 +297,7 @@ namespace UIWidgets {
bool EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) {
bool changed = false;
int val = CVarGetInteger(cvarName, defaultValue);
const int oldVal = val;
if (disabled) {
DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
@ -348,9 +349,11 @@ namespace UIWidgets {
changed = true;
}
if (changed) {
if (changed && (oldVal != val)) {
CVarSetInteger(cvarName, val);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} else {
changed = false;
}
return changed;
@ -359,15 +362,46 @@ namespace UIWidgets {
bool EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) {
bool changed = false;
float val = CVarGetFloat(cvarName, defaultValue);
const float oldVal = val;
if (disabled) {
DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
// Calculate how much precision to save based on the given range of the slider, limited to 6 decimal places
// Precision is also used when adding/subtracting using the +/- buttons
const float sliderWidth = std::min((ImGui::GetContentRegionAvail().x - 2.0f * (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth);
const float diff = (max - min) / sliderWidth;
int ticks = 0;
float increment = 1.0f;
if (diff < 1.0f) {
ticks++;
increment = 0.1f;
}
if (diff < 0.1f) {
ticks++;
increment = 0.01f;
}
if (diff < 0.01f) {
ticks++;
increment = 0.001f;
}
if (diff < 0.001f) {
ticks++;
increment = 0.0001f;
}
if (diff < 0.0001f) {
ticks++;
increment = 0.00001f;
}
if (diff < 0.00001f) {
ticks++;
increment = 0.000001f;
}
if (!isPercentage) {
ImGui::Text(text, val);
} else {
ImGui::Text(text, static_cast<int>(100 * val));
ImGui::Text(text, val * 100.0f);
}
Spacer(0);
@ -375,22 +409,15 @@ namespace UIWidgets {
if (PlusMinusButton) {
std::string MinusBTNName = " - ##" + std::string(cvarName);
if (ImGui::Button(MinusBTNName.c_str())) {
if (isPercentage) {
val -= 0.01f;
} else {
val -= 0.1f;
}
val -= increment;
changed = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
}
ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth));
ImGui::PushItemWidth(sliderWidth);
if (ImGui::SliderFloat(id, &val, min, max, format, ImGuiSliderFlags_AlwaysClamp)) {
if (isPercentage) {
val = roundf(val * 100) / 100;
}
changed = true;
}
ImGui::PopItemWidth();
@ -400,11 +427,7 @@ namespace UIWidgets {
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNName.c_str())) {
if (isPercentage) {
val += 0.01f;
} else {
val += 0.1f;
}
val += increment;
changed = true;
}
}
@ -424,9 +447,14 @@ namespace UIWidgets {
changed = true;
}
if (changed) {
if (changed && !(abs(oldVal - val) < 0.000001f)) {
std::stringstream ss;
ss << std::setprecision(ticks + 1) << val;
val = std::stof(ss.str());
CVarSetFloat(cvarName, val);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} else {
changed = false;
}
return changed;

View File

@ -9,6 +9,7 @@
#define UIWidgets_hpp
#include <string>
#include <sstream>
#include <vector>
#include <span>
#include <stdint.h>

View File

@ -24,6 +24,27 @@ CollisionHeaderFactory::ReadResource(std::shared_ptr<ResourceInitData> initData,
return resource;
}
std::shared_ptr<IResource>
CollisionHeaderFactory::ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) {
auto resource = std::make_shared<CollisionHeader>(initData);
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
switch (resource->GetInitData()->ResourceVersion) {
case 0:
factory = std::make_shared<CollisionHeaderFactoryV0>();
break;
}
if (factory == nullptr) {
SPDLOG_ERROR("Failed to load Collision Header with version {}", resource->GetInitData()->ResourceVersion);
return nullptr;
}
factory->ParseFileXML(reader, resource);
return resource;
}
void LUS::CollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader,
std::shared_ptr<IResource> resource)
{
@ -139,4 +160,119 @@ void LUS::CollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader
}
collisionHeader->collisionHeaderData.waterBoxes = collisionHeader->waterBoxes.data();
}
void LUS::CollisionHeaderFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) {
std::shared_ptr<CollisionHeader> collisionHeader = std::static_pointer_cast<CollisionHeader>(resource);
collisionHeader->collisionHeaderData.minBounds.x = reader->IntAttribute("MinBoundsX");
collisionHeader->collisionHeaderData.minBounds.y = reader->IntAttribute("MinBoundsY");
collisionHeader->collisionHeaderData.minBounds.z = reader->IntAttribute("MinBoundsZ");
collisionHeader->collisionHeaderData.maxBounds.x = reader->IntAttribute("MaxBoundsX");
collisionHeader->collisionHeaderData.maxBounds.y = reader->IntAttribute("MaxBoundsY");
collisionHeader->collisionHeaderData.maxBounds.z = reader->IntAttribute("MaxBoundsZ");
Vec3s zero;
zero.x = 0;
zero.y = 0;
zero.z = 0;
collisionHeader->camPosDataZero = zero;
auto child = reader->FirstChildElement();
while (child != nullptr) {
std::string childName = child->Name();
if (childName == "Vertex") {
Vec3s vtx;
vtx.x = child->IntAttribute("X");
vtx.y = child->IntAttribute("Y");
vtx.z = child->IntAttribute("Z");
collisionHeader->vertices.push_back(vtx);
} else if (childName == "Polygon") {
CollisionPoly polygon;
polygon.type = child->UnsignedAttribute("Type");
polygon.flags_vIA = child->UnsignedAttribute("VertexA");
polygon.flags_vIB = child->UnsignedAttribute("VertexB");
polygon.vIC = child->UnsignedAttribute("VertexC");
polygon.normal.x = child->IntAttribute("NormalX");
polygon.normal.y = child->IntAttribute("NormalY");
polygon.normal.z = child->IntAttribute("NormalZ");
polygon.dist = child->IntAttribute("Dist");
collisionHeader->polygons.push_back(polygon);
} else if (childName == "PolygonType") {
SurfaceType surfaceType;
surfaceType.data[0] = child->UnsignedAttribute("Data1");
surfaceType.data[1] = child->UnsignedAttribute("Data2");
collisionHeader->surfaceTypes.push_back(surfaceType);
} else if (childName == "CameraData") {
CamData camDataEntry;
camDataEntry.cameraSType = child->UnsignedAttribute("SType");
camDataEntry.numCameras = child->IntAttribute("NumData");
collisionHeader->camData.push_back(camDataEntry);
int32_t camPosDataIdx = child->IntAttribute("CameraPosDataSeg");
collisionHeader->camPosDataIndices.push_back(camPosDataIdx);
} else if (childName == "CameraPositionData") {
//each camera position data is made up of 3 Vec3s
Vec3s pos;
pos.x = child->IntAttribute("PosX");
pos.y = child->IntAttribute("PosY");
pos.z = child->IntAttribute("PosZ");
collisionHeader->camPosData.push_back(pos);
Vec3s rot;
rot.x = child->IntAttribute("RotX");
rot.y = child->IntAttribute("RotY");
rot.z = child->IntAttribute("RotZ");
collisionHeader->camPosData.push_back(rot);
Vec3s other;
other.x = child->IntAttribute("FOV");
other.y = child->IntAttribute("JfifID");
other.z = child->IntAttribute("Unknown");
collisionHeader->camPosData.push_back(other);
} else if (childName == "WaterBox") {
WaterBox waterBox;
waterBox.xMin = child->IntAttribute("XMin");
waterBox.ySurface = child->IntAttribute("Ysurface");
waterBox.zMin = child->IntAttribute("ZMin");
waterBox.xLength = child->IntAttribute("XLength");
waterBox.zLength = child->IntAttribute("ZLength");
waterBox.properties = child->IntAttribute("Properties");
collisionHeader->waterBoxes.push_back(waterBox);
}
child = child->NextSiblingElement();
}
for (size_t i = 0; i < collisionHeader->camData.size(); i++) {
int32_t idx = collisionHeader->camPosDataIndices[i];
if (collisionHeader->camPosData.size() > 0) {
collisionHeader->camData[i].camPosData = &collisionHeader->camPosData[idx];
} else {
collisionHeader->camData[i].camPosData = &collisionHeader->camPosDataZero;
}
}
collisionHeader->collisionHeaderData.numVertices = collisionHeader->vertices.size();
collisionHeader->collisionHeaderData.numPolygons = collisionHeader->polygons.size();
collisionHeader->surfaceTypesCount = collisionHeader->surfaceTypes.size();
collisionHeader->camDataCount = collisionHeader->camData.size();
collisionHeader->camPosCount = collisionHeader->camPosData.size();
collisionHeader->collisionHeaderData.numWaterBoxes = collisionHeader->waterBoxes.size();
collisionHeader->collisionHeaderData.vtxList = collisionHeader->vertices.data();
collisionHeader->collisionHeaderData.polyList = collisionHeader->polygons.data();
collisionHeader->collisionHeaderData.surfaceTypeList = collisionHeader->surfaceTypes.data();
collisionHeader->collisionHeaderData.cameraDataList = collisionHeader->camData.data();
collisionHeader->collisionHeaderData.cameraDataListLen = collisionHeader->camDataCount;
collisionHeader->collisionHeaderData.waterBoxes = collisionHeader->waterBoxes.data();
}
}

View File

@ -8,10 +8,13 @@ class CollisionHeaderFactory : public ResourceFactory {
public:
std::shared_ptr<IResource>
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
std::shared_ptr<IResource>
ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) override;
};
class CollisionHeaderFactoryV0 : public ResourceVersionFactory {
public:
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) override;
};
}; // namespace LUS

View File

@ -15,7 +15,34 @@ extern "C" MessageTableEntry* sFraMessageEntryTablePtr;
extern "C" MessageTableEntry* sStaffMessageEntryTablePtr;
//extern "C" MessageTableEntry* _message_0xFFFC_nes;
MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) {
static void SetMessageEntry(MessageTableEntry& entry, const LUS::MessageEntry& msgEntry) {
entry.textId = msgEntry.id;
entry.typePos = (msgEntry.textboxType << 4) | msgEntry.textboxYPos;
entry.segment = msgEntry.msg.c_str();
entry.msgSize = msgEntry.msg.size();
}
static void OTRMessage_LoadCustom(const std::string& folderPath, MessageTableEntry*& table, size_t tableSize) {
auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles(folderPath).get();
for (auto& tPath : lst) {
auto file = std::static_pointer_cast<LUS::Text>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(tPath));
for (size_t j = 0; j < file->messages.size(); ++j) {
// Check if same text ID exists already
auto existingEntry = std::find_if(table, table + tableSize, [id = file->messages[j].id](const auto& entry) {
return entry.textId == id;
});
if (existingEntry != table + tableSize) {
// Replace existing message
SetMessageEntry(*existingEntry, file->messages[j]);
}
}
}
}
MessageTableEntry* OTRMessage_LoadTable(const std::string& filePath, bool isNES) {
auto file = std::static_pointer_cast<LUS::Text>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(filePath));
if (file == nullptr)
@ -63,14 +90,12 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) {
table[file->messages.size()].msgSize = kaeporaMsgSize;
}
table[i].textId = file->messages[i].id;
table[i].typePos = (file->messages[i].textboxType << 4) | file->messages[i].textboxYPos;
table[i].segment = file->messages[i].msg.c_str();
table[i].msgSize = file->messages[i].msg.size();
SetMessageEntry(table[i], file->messages[i]);
if (isNES && file->messages[i].id == 0xFFFC)
_message_0xFFFC_nes = (char*)file->messages[i].msg.c_str();
}
OTRMessage_LoadCustom("override/" + filePath.substr(0, filePath.find_last_of('/')) + "/*", table, file->messages.size() + 1);
// Assert that the first message starts at the first text ID
assert(table[0].textId == 0x0001);
@ -101,12 +126,9 @@ extern "C" void OTRMessage_Init()
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();
SetMessageEntry(sStaffMessageEntryTablePtr[i], file2->messages[i]);
}
OTRMessage_LoadCustom("override/text/staff_message_data_static/*", sStaffMessageEntryTablePtr, file2->messages.size());
// Assert staff credits start at the first credits ID
assert(sStaffMessageEntryTablePtr[0].textId == 0x0500);
@ -160,4 +182,9 @@ extern "C" void OTRMessage_Init()
CustomMessage("You look bored. Wanna go out for a&walk?\x1B&%gYes&No%w",
"Du siehst gelangweilt aus.&Willst du einen Spaziergang machen?\x1B&%gJa&Nein%w",
"Tu as l'air de t'ennuyer. Tu veux&aller faire un tour?\x1B&%gOui&Non%w"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_FISHERMAN_LEAVE,
CustomMessage("Hey! Hey!&You can't take the rod out of here!&I'm serious!^Do you want to quit?&\x1B&%gYes&No%w",
"Hey! Hey!&Du kannst die Angel doch nicht&einfach mitnehmen!&Ganz im Ernst!^Möchtest du aufhören?&\x1B&%gJa&Nein%w", //TODO Used AI translation as placeholder
"Holà! Holà!&Les cannes ne sortent pas d'ici!&Je suis sérieux!^Voulez-vous arrêter?&\x1B&%gOui&Non%w")); //TODO Used AI translation as placeholder
}

View File

@ -149,6 +149,13 @@ bool Scene_CommandMeshHeader(PlayState* play, LUS::ISceneCommand* cmd) {
extern "C" void* func_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId);
bool OTRfunc_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId) {
objectCtx->status[bankIndex].id = -objectId;
return false;
}
bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) {
// LUS::SetObjectList* cmdObj = static_pointer_cast<LUS::SetObjectList>(cmd);
LUS::SetObjectList* cmdObj = (LUS::SetObjectList*)cmd;
@ -164,49 +171,30 @@ bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) {
void* nextPtr;
k = 0;
// i = play->objectCtx.unk_09;
i = 0;
i = play->objectCtx.unk_09;
firstStatus = &play->objectCtx.status[0];
status = &play->objectCtx.status[i];
for (int i = 0; i < cmdObj->objects.size(); i++) {
bool alreadyIncluded = false;
for (int j = 0; j < play->objectCtx.num; j++) {
if (play->objectCtx.status[j].id == cmdObj->objects[i]) {
alreadyIncluded = true;
break;
// Loop until a mismatch in the object lists
// Then clear all object ids past that in the context object list and kill actors for those objects
for (i = play->objectCtx.unk_09, k = 0; i < play->objectCtx.num; i++, k++) {
if (play->objectCtx.status[i].id != cmdObj->objects[k]) {
for (j = i; j < play->objectCtx.num; j++) {
play->objectCtx.status[j].id = OBJECT_INVALID;
}
}
if (!alreadyIncluded) {
play->objectCtx.status[play->objectCtx.num++].id = cmdObj->objects[i];
func_80031A28(play, &play->actorCtx);
break;
}
}
/*
while (i < play->objectCtx.num) {
if (status->id != *objectEntry) {
status2 = &play->objectCtx.status[i];
for (j = i; j < play->objectCtx.num; j++) {
status2->id = OBJECT_INVALID;
status2++;
}
play->objectCtx.num = i;
func_80031A28(play, &play->actorCtx);
continue;
// Continuing from the last index, add the remaining object ids from the command object list
for (; k < cmdObj->objects.size(); k++, i++) {
if (i < OBJECT_EXCHANGE_BANK_MAX - 1) {
OTRfunc_800982FC(&play->objectCtx, i, cmdObj->objects[k]);
}
i++;
k++;
objectEntry++;
status++;
}
play->objectCtx.num = i;
*/
return false;
}

View File

@ -2065,16 +2065,40 @@ void func_800EE404(void) {
void Audio_OcaMemoryGameStart(u8 minigameRound) {
u8 i;
// #region SOH [Enhancement]
if (CVarGetInteger("gCustomizeOcarinaGame", 0)) {
u8 startingNotes = 3;
u8 roundOneCount = CVarGetInteger("gOcarinaGameRoundOneNotes", 5);
u8 roundTwoCount = CVarGetInteger("gOcarinaGameRoundTwoNotes", 6);
u8 roundThreeCount = CVarGetInteger("gOcarinaGameRoundThreeNotes", 8);
u8 modMinigameNoteCnts[] = { roundOneCount, roundTwoCount, roundThreeCount };
if (minigameRound > 2) {
minigameRound = 2;
}
sOcaMinigameAppendPos = 0;
sOcaMinigameEndPos = sOcaMinigameNoteCnts[minigameRound];
startingNotes = CVarGetInteger("gOcarinaGameStartingNotes", 3);
for (i = 0; i < 3; i++) {
Audio_OcaMemoryGameGenNote();
if (minigameRound > 2) {
minigameRound = 2;
}
sOcaMinigameAppendPos = 0;
sOcaMinigameEndPos = modMinigameNoteCnts[minigameRound];
for (i = 0; i < startingNotes; i++) {
Audio_OcaMemoryGameGenNote();
}
// #endregion
} else {
if (minigameRound > 2) {
minigameRound = 2;
}
sOcaMinigameAppendPos = 0;
sOcaMinigameEndPos = sOcaMinigameNoteCnts[minigameRound];
for (i = 0; i < 3; i++) {
Audio_OcaMemoryGameGenNote();
}
}
}
@ -2093,11 +2117,24 @@ s32 Audio_OcaMemoryGameGenNote(void) {
rndNote = sOcarinaNoteValues[(rnd + 1) % 5];
}
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].noteIdx = rndNote;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].unk_02 = 0x2D;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].volume = 0x50;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].vibrato = 0;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].tone = 0;
// #region SOH [Enhancement]
if (CVarGetInteger("gCustomizeOcarinaGame", 0)) {
int noteSpeed = 0x2D;
noteSpeed = noteSpeed / CVarGetInteger("gOcarinaGameNoteSpeed", 1);
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].noteIdx = rndNote;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].unk_02 = noteSpeed;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].volume = 0x50;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].vibrato = 0;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].tone = 0;
// #endregion
} else {
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].noteIdx = rndNote;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].unk_02 = 0x2D;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].volume = 0x50;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].vibrato = 0;
sOcarinaSongs[OCARINA_SONG_MEMORY_GAME][sOcaMinigameAppendPos].tone = 0;
}
sOcaMinigameAppendPos++;

View File

@ -297,6 +297,11 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
PadUtils_UpdateRelXY(input);
input->press.stick_x += (s8)(input->cur.stick_x - input->prev.stick_x);
input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y);
// #region SOH [Enhancement]
PadUtils_UpdateRelRXY(input);
input->press.right_stick_x += (s8)(input->cur.right_stick_x - input->prev.right_stick_x);
input->press.right_stick_y += (s8)(input->cur.right_stick_y - input->prev.right_stick_y);
// #endregion
}
uint8_t rumble = (padMgr->rumbleEnable[0] > 0);
@ -389,6 +394,11 @@ void PadMgr_RequestPadData(PadMgr* padMgr, Input* inputs, s32 mode) {
PadUtils_UpdateRelXY(newInput);
newInput->press.stick_x += (s8)(newInput->cur.stick_x - newInput->prev.stick_x);
newInput->press.stick_y += (s8)(newInput->cur.stick_y - newInput->prev.stick_y);
// #region SOH [Enhancement]
PadUtils_UpdateRelRXY(newInput);
newInput->press.right_stick_x += (s8)(newInput->cur.right_stick_x - newInput->prev.right_stick_x);
newInput->press.right_stick_y += (s8)(newInput->cur.right_stick_y - newInput->prev.right_stick_y);
// #endregion
}
ogInput++;
newInput++;

View File

@ -92,3 +92,60 @@ void PadUtils_UpdateRelXY(Input* input) {
PadUtils_SetRelXY(input, relX, relY);
}
// #region SOH [Enhancement]
s8 PadUtils_GetCurRX(Input* input) {
return input->cur.right_stick_x;
}
s8 PadUtils_GetCurRY(Input* input) {
return input->cur.right_stick_y;
}
void PadUtils_SetRelRXY(Input* input, s32 x, s32 y) {
input->rel.right_stick_x = x;
input->rel.right_stick_y = y;
}
s8 PadUtils_GetRelRXImpl(Input* input) {
return input->rel.right_stick_x;
}
s8 PadUtils_GetRelRYImpl(Input* input) {
return input->rel.right_stick_y;
}
s8 PadUtils_GetRelRX(Input* input) {
return PadUtils_GetRelRXImpl(input);
}
s8 PadUtils_GetRelRY(Input* input) {
return PadUtils_GetRelRYImpl(input);
}
void PadUtils_UpdateRelRXY(Input* input) {
s32 curX = PadUtils_GetCurRX(input);
s32 curY = PadUtils_GetCurRY(input);
s32 relX;
s32 relY;
if (curX > 7) {
relX = (curX < 0x43) ? curX - 7 : 0x43 - 7;
} else if (curX < -7) {
relX = (curX > -0x43) ? curX + 7 : -0x43 + 7;
} else {
relX = 0;
}
if (curY > 7) {
relY = (curY < 0x43) ? curY - 7 : 0x43 - 7;
} else if (curY < -7) {
relY = (curY > -0x43) ? curY + 7 : -0x43 + 7;
} else {
relY = 0;
}
PadUtils_SetRelRXY(input, relX, relY);
}
// #endregion

View File

@ -1239,8 +1239,7 @@ void Actor_Init(Actor* actor, PlayState* play) {
CollisionCheck_InitInfo(&actor->colChkInfo);
actor->floorBgId = BGCHECK_SCENE;
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
//if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex))
{
if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
//Actor_SetObjectDependency(play, actor);
actor->init(actor, play);
actor->init = NULL;
@ -2881,11 +2880,19 @@ s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) {
if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) {
var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3;
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 2.0f) &&
(((arg2->y + actor->uncullZoneDownward) * var) > -2.0f) &&
(((arg2->y - actor->uncullZoneScale) * var) < 2.0f)) {
// #region SoH [Widescreen support]
// Doors will cull quite noticeably on wider screens. For these actors the zone is increased
f32 limit = 1.0f;
if (((actor->id == ACTOR_EN_DOOR) || (actor->id == ACTOR_DOOR_SHUTTER)) && CVarGetInteger("gIncreaseDoorUncullZones", 1)) {
limit = 2.0f;
}
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < limit) &&
(((arg2->y + actor->uncullZoneDownward) * var) > -limit) &&
(((arg2->y - actor->uncullZoneScale) * var) < limit)) {
return true;
}
// #endregion
}
return false;
@ -3149,6 +3156,9 @@ void Actor_FreeOverlay(ActorDBEntry* dbEntry) {
osSyncPrintf(VT_RST);
}
// SoH: Flag to check if actors are being spawned from the actor entry list
// This flag is checked against to allow actors which dont have an objectBankIndex in the objectCtx slot/status array to spawn
// An example of what this fixes, is that it allows hookshot to be used as child
int gMapLoading = 0;
Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 posX, f32 posY, f32 posZ,

View File

@ -1902,7 +1902,7 @@ s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResul
s32 bgId2;
f32 nx, ny, nz; // unit normal of polygon
if (CVarGetInteger("gNoClip", 0) != 0) {
if (CVarGetInteger("gNoClip", 0) && actor != NULL && actor->id == ACTOR_PLAYER) {
return false;
}

View File

@ -7887,7 +7887,7 @@ s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags) {
}
}
// Clear free camera if an action is performed that would move the camera (targeting, first person, talking)
// Clear free look if an action is performed that would move the camera (targeting, first person, talking)
if (CVarGetInteger("gFreeCamera", 0) && SetCameraManual(camera) == 1 &&
((mode >= CAM_MODE_TARGET && mode <= CAM_MODE_BATTLE) ||
(mode >= CAM_MODE_FIRSTPERSON && mode <= CAM_MODE_CLIMBZ) || mode == CAM_MODE_HANGZ ||
@ -7933,7 +7933,8 @@ s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags) {
return -5;
}
if (setting == CAM_SET_NONE || setting >= CAM_SET_MAX) {
//modified from "==" to "<=" to not crash when "setting" is a negative value
if (setting <= CAM_SET_NONE || setting >= CAM_SET_MAX) {
osSyncPrintf(VT_COL(RED, WHITE) "camera: error: illegal camera set (%d) !!!!\n" VT_RST, setting);
return -99;
}

View File

@ -524,7 +524,6 @@ void Map_Init(PlayState* play) {
interfaceCtx->unk_25A = -1;
interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*));
interfaceCtx->mapSegmentName = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*));
// " texture initialization scene_data_ID=%d mapSegment=%x"
osSyncPrintf("\n\n\n テクスチャ初期化 scene_data_ID=%d\nmapSegment=%x\n\n", play->sceneNum,
interfaceCtx->mapSegment, play);

View File

@ -3361,8 +3361,13 @@ void Message_Update(PlayState* play) {
}
if ((s32)(gSaveContext.inventory.questItems & 0xF0000000) == 0x40000000) {
gSaveContext.inventory.questItems ^= 0x40000000;
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
if (!CVarGetInteger("gHurtContainer", 0)) {
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
} else {
gSaveContext.healthCapacity -= 0x10;
gSaveContext.health -= 0x10;
}
}
if (msgCtx->ocarinaAction != OCARINA_ACTION_CHECK_NOWARP_DONE) {
if (sLastPlayedSong == OCARINA_SONG_SARIAS) {

View File

@ -69,7 +69,13 @@ s32 OnePointCutscene_SetInfo(PlayState* play, s16 camIdx, s16 csId, Actor* actor
PosRot sp8C;
f32 tempRand;
Unique9OnePointCs* csInfo = ONEPOINT_CS_INFO(csCam);
// #region SOH [Enhancement]
//the default is 90, lower values necessary to prevent camera swing as animation speeds up
s16 camCrawlTemp = CVarGetInteger("gCrawlSpeed", 1);
s16 camCrawlTimer = D_8012042C / camCrawlTemp;
// #endregion
switch (csId) {
case 1020:
if (timer < 20) {
@ -330,13 +336,26 @@ s32 OnePointCutscene_SetInfo(PlayState* play, s16 camIdx, s16 csId, Actor* actor
case 9601:
Play_CameraChangeSetting(play, camIdx, CAM_SET_CS_3);
Play_CameraChangeSetting(play, MAIN_CAM, mainCam->prevSetting);
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, D_8012042C, D_80120308, D_80120398);
if (CVarGetInteger("gCrawlSpeed", 1) > 1) {
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, camCrawlTimer, D_80120308, D_80120398);
} else {
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, D_8012042C, D_80120308, D_80120398);
}
break;
case 9602:
Play_CameraChangeSetting(play, camIdx, CAM_SET_CS_3);
Play_CameraChangeSetting(play, MAIN_CAM, mainCam->prevSetting);
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, D_8012042C, D_80120308, D_80120434);
break;
// #region SOH [Enhancement]
if (CVarGetInteger("gCrawlSpeed", 1) > 1) {
Play_CameraChangeSetting(play, camIdx, CAM_SET_CS_3);
Play_CameraChangeSetting(play, MAIN_CAM, mainCam->prevSetting);
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, camCrawlTimer, D_80120308, D_80120434);
break;
// #endregion
} else {
Play_CameraChangeSetting(play, camIdx, CAM_SET_CS_3);
Play_CameraChangeSetting(play, MAIN_CAM, mainCam->prevSetting);
OnePointCutscene_SetCsCamPoints(csCam, D_80120430 | 0x1000, D_8012042C, D_80120308, D_80120434);
break;
}
case 4175:
csInfo->keyFrames = D_8012147C;
csInfo->keyFrameCnt = 4;

View File

@ -2278,8 +2278,13 @@ u8 Item_Give(PlayState* play, u8 item) {
gSaveContext.sohStats.heartPieces++;
return Return_Item(item, MOD_NONE, ITEM_NONE);
} else if (item == ITEM_HEART_CONTAINER) {
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
if (!CVarGetInteger("gHurtContainer", 0)) {
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
} else {
gSaveContext.healthCapacity -= 0x10;
gSaveContext.health -= 0x10;
}
gSaveContext.sohStats.heartContainers++;
return Return_Item(item, MOD_NONE, ITEM_NONE);
} else if (item == ITEM_HEART) {
@ -3615,7 +3620,7 @@ void Interface_DrawLineupTick(PlayState* play) {
s16 width = 32;
s16 height = 32;
s16 x = -8 + (SCREEN_WIDTH / 2);
s16 y = CVarGetInteger("gOpenMenuBar", 0) ? -4 : -6;
s16 y = -6;
OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gEmptyCDownArrowTex, width, height, x, y, width, height, 2 << 10, 2 << 10);

View File

@ -600,13 +600,23 @@ void Player_SetModelsForHoldingShield(Player* this) {
if ((CVarGetInteger("gShieldTwoHanded", 0) && (this->heldItemAction != PLAYER_IA_DEKU_STICK) ||
!Player_HoldsTwoHandedWeapon(this)) && !Player_IsChildWithHylianShield(this)) {
this->rightHandType = PLAYER_MODELTYPE_RH_SHIELD;
this->rightHandDLists = &sPlayerDListGroups[PLAYER_MODELTYPE_RH_SHIELD][gSaveContext.linkAge];
if (LINK_IS_CHILD && (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && (this->currentShield == PLAYER_SHIELD_MIRROR)) {
this->rightHandDLists = &sPlayerDListGroups[PLAYER_MODELTYPE_RH_SHIELD][0];
} else if (LINK_IS_ADULT && (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && (this->currentShield == PLAYER_SHIELD_DEKU)) {
this->rightHandDLists = &sPlayerDListGroups[PLAYER_MODELTYPE_RH_SHIELD][1];
} else {
this->rightHandDLists = &sPlayerDListGroups[PLAYER_MODELTYPE_RH_SHIELD][gSaveContext.linkAge];
}
if (this->sheathType == PLAYER_MODELTYPE_SHEATH_18) {
this->sheathType = PLAYER_MODELTYPE_SHEATH_16;
} else if (this->sheathType == PLAYER_MODELTYPE_SHEATH_19) {
this->sheathType = PLAYER_MODELTYPE_SHEATH_17;
}
this->sheathDLists = &sPlayerDListGroups[this->sheathType][gSaveContext.linkAge];
if ((CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && LINK_IS_CHILD &&
gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI) {
this->sheathDLists = &sPlayerDListGroups[this->sheathType][0];
}
this->modelAnimType = PLAYER_ANIMTYPE_2;
this->itemAction = -1;
}
@ -617,12 +627,40 @@ void Player_SetModels(Player* this, s32 modelGroup) {
// Left hand
this->leftHandType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_LEFT_HAND];
this->leftHandDLists = &sPlayerDListGroups[this->leftHandType][gSaveContext.linkAge];
if (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
if (LINK_IS_CHILD &&
(this->leftHandType == PLAYER_MODELTYPE_LH_HAMMER ||
((this->leftHandType == PLAYER_MODELTYPE_LH_SWORD || this->leftHandType == PLAYER_MODELTYPE_LH_BGS) &&
(gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI)))) {
this->leftHandDLists = &sPlayerDListGroups[this->leftHandType][0];
}
if (LINK_IS_ADULT && (this->leftHandType == PLAYER_MODELTYPE_LH_BOOMERANG ||
(this->leftHandType == PLAYER_MODELTYPE_LH_SWORD && gSaveContext.equips.buttonItems[0] == ITEM_SWORD_KOKIRI))) {
this->leftHandDLists = &sPlayerDListGroups[this->leftHandType][1];
}
}
// Right hand
this->rightHandType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_RIGHT_HAND];
this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][gSaveContext.linkAge];
if (CVarGetInteger("gBowSlingShotAmmoFix", 0) && this->rightHandType == 11) { // If holding Bow/Slingshot
this->rightHandType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_RIGHT_HAND];
this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][gSaveContext.linkAge];
if (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
if (LINK_IS_CHILD &&
(this->rightHandType == PLAYER_MODELTYPE_RH_HOOKSHOT ||
(this->rightHandType == PLAYER_MODELTYPE_RH_SHIELD && this->currentShield == PLAYER_SHIELD_MIRROR))) {
this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][0];
}
if (LINK_IS_ADULT &&
(this->rightHandType == PLAYER_MODELTYPE_RH_SHIELD && this->currentShield == PLAYER_SHIELD_DEKU)) {
this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][1];
}
}
if ((CVarGetInteger("gBowSlingShotAmmoFix", 0) || CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && this->rightHandType == 11) { // If holding Bow/Slingshot
this->rightHandDLists = &sPlayerDListGroups[this->rightHandType][Player_HoldsSlingshot(this)];
}
@ -630,6 +668,23 @@ void Player_SetModels(Player* this, s32 modelGroup) {
this->sheathType = gPlayerModelTypes[modelGroup][PLAYER_MODELGROUPENTRY_SHEATH];
this->sheathDLists = &sPlayerDListGroups[this->sheathType][gSaveContext.linkAge];
if (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
if (LINK_IS_CHILD &&
(this->currentShield == PLAYER_SHIELD_HYLIAN || this->currentShield == PLAYER_SHIELD_MIRROR) &&
((gSaveContext.equips.buttonItems[0] == ITEM_SWORD_MASTER) ||
(gSaveContext.equips.buttonItems[0] == ITEM_SWORD_BGS))) {
this->sheathDLists = &sPlayerDListGroups[this->sheathType][0];
} else if (LINK_IS_CHILD && this->currentShield == PLAYER_SHIELD_MIRROR && gSaveContext.equips.buttonItems[0] == ITEM_SWORD_KOKIRI &&
this->sheathType == PLAYER_MODELTYPE_SHEATH_18) {
this->sheathDLists = &sPlayerDListGroups[this->sheathType][0];
} else if (LINK_IS_ADULT && this->currentShield == PLAYER_SHIELD_DEKU) {
this->sheathDLists = &sPlayerDListGroups[this->sheathType][1];
} else if (LINK_IS_CHILD && this->sheathType == PLAYER_MODELTYPE_SHEATH_17 &&
((gSaveContext.equips.buttonItems[0] == ITEM_SWORD_MASTER) || (gSaveContext.equips.buttonItems[0] == ITEM_SWORD_BGS))) {
this->sheathDLists = &sPlayerDListGroups[this->sheathType][0];
}
}
// Waist
this->waistDLists = &sPlayerDListGroups[gPlayerModelTypes[modelGroup][4]][gSaveContext.linkAge];
@ -1187,6 +1242,42 @@ void func_8008F87C(PlayState* play, Player* this, SkelAnime* skelAnime, Vec3f* p
s32 Player_OverrideLimbDrawGameplayCommon(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) {
Player* this = (Player*)thisx;
if (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0) && CVarGetInteger("gEnhancements.ScaleAdultEquimentAsChild", 0) && LINK_IS_CHILD) {
if (limbIndex == PLAYER_LIMB_L_HAND) {
if ((gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI && sLeftHandType == PLAYER_MODELTYPE_LH_SWORD) ||
(sLeftHandType == PLAYER_MODELTYPE_LH_BGS) || (sLeftHandType == PLAYER_MODELTYPE_LH_HAMMER)) {
Matrix_Scale(0.8, 0.8, 0.8, MTXMODE_APPLY);
}
}
if (limbIndex == PLAYER_LIMB_R_HAND) {
if ((this->currentShield == PLAYER_SHIELD_MIRROR && sRightHandType == PLAYER_MODELTYPE_RH_SHIELD) ||
(this->currentShield == PLAYER_SHIELD_HYLIAN && (gSaveContext.equips.buttonItems[0] == ITEM_SWORD_MASTER ||
gSaveContext.equips.buttonItems[0] == ITEM_SWORD_BGS)) || (sRightHandType == PLAYER_MODELTYPE_RH_HOOKSHOT) ||
(sRightHandType == PLAYER_MODELTYPE_RH_BOW_SLINGSHOT && Player_HoldsBow(this))) {
Matrix_Scale(0.8, 0.8, 0.8, MTXMODE_APPLY);
}
}
if (limbIndex == PLAYER_LIMB_SHEATH) {
if ((this->currentShield == PLAYER_SHIELD_MIRROR ||
(this->currentShield == PLAYER_SHIELD_HYLIAN &&
(gSaveContext.equips.buttonItems[0] == ITEM_SWORD_MASTER ||
gSaveContext.equips.buttonItems[0] == ITEM_SWORD_BGS))) &&
((this->sheathType == PLAYER_MODELTYPE_SHEATH_16) || (this->sheathType == PLAYER_MODELTYPE_SHEATH_17) ||
(this->sheathType == PLAYER_MODELTYPE_SHEATH_18) ||
(this->sheathType == PLAYER_MODELTYPE_SHEATH_19))) {
Matrix_Translate(218, -100, 62, MTXMODE_APPLY);
Matrix_Scale(0.8, 0.8, 0.8, MTXMODE_APPLY);
}
if ((this->currentShield == PLAYER_SHIELD_DEKU &&
gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI &&
(this->sheathType == PLAYER_MODELTYPE_SHEATH_16 ||
this->sheathType == PLAYER_MODELTYPE_SHEATH_17))) {
Matrix_Translate(218, -100, 62, MTXMODE_APPLY);
Matrix_Scale(0.8, 0.8, 0.8, MTXMODE_APPLY);
}
}
}
if (limbIndex == PLAYER_LIMB_ROOT) {
sLeftHandType = this->leftHandType;
@ -1305,9 +1396,11 @@ s32 Player_OverrideLimbDrawGameplayDefault(PlayState* play, s32 limbIndex, Gfx**
(gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI)) {
dLists += PLAYER_SHIELD_MAX * 4;
}
} else if (!LINK_IS_ADULT && ((this->sheathType == PLAYER_MODELTYPE_SHEATH_16) || (this->sheathType == PLAYER_MODELTYPE_SHEATH_17)) &&
(gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI)) {
dLists = &sSheathWithSwordDLs[PLAYER_SHIELD_MAX * 4];
} else if (!CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
if (!LINK_IS_ADULT && ((this->sheathType == PLAYER_MODELTYPE_SHEATH_16) || (this->sheathType == PLAYER_MODELTYPE_SHEATH_17)) &&
(gSaveContext.equips.buttonItems[0] != ITEM_SWORD_KOKIRI)) {
dLists = &sSheathWithSwordDLs[PLAYER_SHIELD_MAX * 4];
}
}
if (dLists[sDListsLodOffset] != NULL) {
@ -1345,7 +1438,7 @@ s32 Player_OverrideLimbDrawGameplayFirstPerson(PlayState* play, s32 limbIndex, G
*dList = sFirstPersonLeftForearmDLs[gSaveContext.linkAge];
} else if (limbIndex == PLAYER_LIMB_L_HAND) {
s32 handOutDlIndex = gSaveContext.linkAge;
if (CVarGetInteger("gBowSlingShotAmmoFix", 0) && LINK_IS_ADULT && Player_HoldsSlingshot(this)) {
if ((CVarGetInteger("gBowSlingShotAmmoFix", 0) || CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) && LINK_IS_ADULT && Player_HoldsSlingshot(this)) {
handOutDlIndex = 1;
}
*dList = sFirstPersonLeftHandDLs[handOutDlIndex];
@ -1355,7 +1448,7 @@ s32 Player_OverrideLimbDrawGameplayFirstPerson(PlayState* play, s32 limbIndex, G
*dList = sFirstPersonForearmDLs[gSaveContext.linkAge];
} else if (limbIndex == PLAYER_LIMB_R_HAND) {
s32 firstPersonWeaponIndex = gSaveContext.linkAge;
if (CVarGetInteger("gBowSlingShotAmmoFix", 0)) {
if (CVarGetInteger("gBowSlingShotAmmoFix", 0) || CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
if (Player_HoldsBow(this)) {
firstPersonWeaponIndex = 0;
} else if (Player_HoldsSlingshot(this)) {
@ -1759,7 +1852,7 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve
Matrix_Get(&this->shieldMf);
} else if ((this->rightHandType == PLAYER_MODELTYPE_RH_BOW_SLINGSHOT) || (this->rightHandType == PLAYER_MODELTYPE_RH_BOW_SLINGSHOT_2)) {
s32 stringModelToUse = gSaveContext.linkAge;
if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){
if (CVarGetInteger("gBowSlingShotAmmoFix", 0) || CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0)) {
stringModelToUse = Player_HoldsSlingshot(this);
}
BowStringData* stringData = &sBowStringData[stringModelToUse];

View File

@ -83,9 +83,10 @@ void Object_UpdateBank(ObjectContext* objectCtx) {
RomFile* objectFile;
size_t size;
/*
for (i = 0; i < objectCtx->num; i++) {
if (status->id < 0) {
/*
if (status->dmaRequest.vromAddr == 0) {
osCreateMesgQueue(&status->loadQueue, &status->loadMsg, 1);
objectFile = &gObjectTable[-status->id];
@ -96,10 +97,12 @@ void Object_UpdateBank(ObjectContext* objectCtx) {
} else if (!osRecvMesg(&status->loadQueue, NULL, OS_MESG_NOBLOCK)) {
status->id = -status->id;
}
*/
status->id = -status->id;
}
status++;
}
*/
}
s32 Object_GetIndex(ObjectContext* objectCtx, s16 objectId) {

View File

@ -10,10 +10,6 @@
#include <stdlib.h> // malloc
#include <string.h> // memcpy
// OTRTODO: Replace usage of this method when we can clear the cache
// for a single texture without the need of a DL opcode in the render code
void gfx_texture_cache_clear();
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
#define LAVA_TEX_WIDTH 32
@ -123,7 +119,9 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() {
sMaskTexLava[i] = maskVal;
}
}
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, NULL);
Gfx_TextureCacheDelete(sMaskTexLava);
return;
}
@ -165,7 +163,9 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() {
}
}
gfx_texture_cache_clear();
Gfx_TextureCacheDelete(sMaskTexLava);
Gfx_TextureCacheDelete(sLavaWavyTex);
Gfx_TextureCacheDelete(sLavaFloorModifiedTex);
}
void func_808C12C4(u8* arg1, s16 arg2) {
@ -228,6 +228,7 @@ void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
}
free(sp54);
Gfx_TextureCacheDelete(sLavaWavyTexRaw);
}
// Modified to support CPU modified texture with the resource system
@ -255,6 +256,8 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
temp_s3[i + temp2] = sp54[i + i2];
}
}
Gfx_TextureCacheDelete(sLavaWavyTex);
}
void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) {
@ -373,6 +376,13 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
// Clear cache for masks
Gfx_TextureCacheDelete(sMaskTex8x16);
Gfx_TextureCacheDelete(sMaskTex8x32);
Gfx_TextureCacheDelete(sMaskTex16x16);
Gfx_TextureCacheDelete(sMaskTex16x32);
Gfx_TextureCacheDelete(sMaskTex32x16);
BossDodongo_RegisterBlendedLavaTextureUpdate();
// Register alt listener to update the blended lava for the replacement texture based on alt path
@ -1206,6 +1216,7 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) {
}
} else {
sMaskTexLava[new_var] = 1;
Gfx_TextureCacheDelete(sMaskTexLava);
}
this->unk_1C2 += 37;
@ -1345,18 +1356,6 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) {
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16);
}
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava);
// Using WORK_DISP to invalidate these textures as they are used in drawing the scene textures which happens
// before actors are drawn. WORK_DISP comes before POLAY_OPA_DISP. It is probably not meant for this, but it
// at least works for now.
// Alternatively, having a way to invalidate just these pointers from the Update func should be sufficient.
if (sLavaFloorModifiedTexRaw != NULL) {
gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTexRaw);
} else {
gSPInvalidateTexCache(WORK_DISP++, sLavaWavyTex);
}
if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) {
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099);
} else {

View File

@ -192,11 +192,11 @@ void DemoGj_Explode(DemoGj* this, PlayState* play, Vec3f* initialPos, Vec3f* dir
phi_s0 = 0x21;
}
Gfx* gfx = ResourceMgr_LoadGfxByName(gGanonRubbleDL);
// SoH [Port] Changed from &gGanonsCastleRubbleAroundArenaDL[28] to gGanonRubbleDL as it seems this was an error in the original rom/decomp
// Other calls to EffectSsKakera_Spawn with OBJECT_GEFF use gGanonRubbleDL, so this change is to match that
EffectSsKakera_Spawn(play, &explosionPos, &velocity, initialPos, -200, phi_s0, 10, 10, 0,
Rand_ZeroOne() * 20.0f + 20.0f, 20, 300, (s32)(Rand_ZeroOne() * 30.0f) + 30, -1,
OBJECT_GEFF, gfx);
OBJECT_GEFF, gGanonRubbleDL);
theta += 0x2AAA;
}

View File

@ -101,6 +101,9 @@ void EnDntJiji_Destroy(Actor* thisx, PlayState* play) {
}
void EnDntJiji_SetFlower(EnDntJiji* this, PlayState* play) {
// SOH: Due to removed object dependencies, parent was still NULL when Init was called. In order to properly set
// stage, redo it here now that we are a frame later.
this->stage = (EnDntDemo*)this->actor.parent;
if (this->actor.bgCheckFlags & 1) {
this->flowerPos = this->actor.world.pos;
this->actionFunc = EnDntJiji_SetupWait;

View File

@ -349,7 +349,15 @@ void EnDoor_Draw(Actor* thisx, PlayState* play) {
}
}
if (this->lockTimer != 0) {
if (CVarGetInteger("gShowDoorLocksOnBothSides", 0)) {
Matrix_Push();
}
Actor_DrawDoorLock(play, this->lockTimer, DOORLOCK_NORMAL);
if (CVarGetInteger("gShowDoorLocksOnBothSides", 0)) {
Matrix_Pop();
Matrix_RotateZYX(0, 0x8000, 0, MTXMODE_APPLY);
Actor_DrawDoorLock(play, this->lockTimer, DOORLOCK_NORMAL);
}
}
CLOSE_DISPS(play->state.gfxCtx);

View File

@ -1027,8 +1027,8 @@ void EnGirlA_BuyEvent_ObtainBombchuPack(PlayState* play, EnGirlA* this) {
Rupees_ChangeBy(-this->basePrice);
// Normally, buying a bombchu pack sets a flag indicating the pack is now sold out
// If they're in logic for rando, skip setting that flag so they can be purchased repeatedly
if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC)) {
// If we're in rando, skip setting that flag so they can be purchased repeatedly
if (IS_RANDO) {
return;
}
@ -1255,8 +1255,7 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, PlayState* play) {
this->itemGiveFunc = itemEntry->itemGiveFunc;
this->buyEventFunc = itemEntry->buyEventFunc;
// If chus are in logic, make the 10 pack affordable without a wallet upgrade
if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) &&
this->getItemId == GI_BOMBCHUS_10) {
if (IS_RANDO && this->getItemId == GI_BOMBCHUS_10) {
this->basePrice = 99;
} else {
this->basePrice = itemEntry->price;

View File

@ -8,6 +8,8 @@
#include "objects/object_tite/object_tite.h"
#include "objects/object_ik/object_ik.h"
#include <string.h> // strcmp
#define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED
void EnPart_Init(Actor* thisx, PlayState* play);
@ -297,11 +299,11 @@ void EnPart_Draw(Actor* thisx, PlayState* play) {
gSPSegment(POLY_OPA_DISP++, 0x08, func_80ACEAC0(play->state.gfxCtx, 255, 255, 255, 180, 180, 180));
gSPSegment(POLY_OPA_DISP++, 0x09, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
gSPSegment(POLY_OPA_DISP++, 0x0A, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
} else if ((thisx->params == 9) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) {
} else if ((thisx->params == 9) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) {
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001300);
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001700);
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_001900);
} else if ((thisx->params == 10) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) {
} else if ((thisx->params == 10) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) {
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001B00);
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001F00);
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_002100);

View File

@ -745,6 +745,28 @@ void EnPartner_Update(Actor* thisx, PlayState* play) {
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
}
if (CVarGetInteger("gCosmetics.Ivan_IdlePrimary.Changed", 0)) {
Color_RGB8 ivanColor1 = CVarGetColor24("gCosmetics.Ivan_IdlePrimary.Value", (Color_RGB8){ 255, 255, 255 });
this->innerColor.r = ivanColor1.r;
this->innerColor.g = ivanColor1.g;
this->innerColor.b = ivanColor1.b;
} else {
this->innerColor.r = 255;
this->innerColor.g = 255;
this->innerColor.b = 255;
}
if (CVarGetInteger("gCosmetics.Ivan_IdleSecondary.Changed", 0)) {
Color_RGB8 ivanColor2 = CVarGetColor24("gCosmetics.Ivan_IdleSecondary.Value", (Color_RGB8){ 0, 255, 0 });
this->outerColor.r = ivanColor2.r;
this->outerColor.g = ivanColor2.g;
this->outerColor.b = ivanColor2.b;
} else {
this->outerColor.r = 0;
this->outerColor.g = 255;
this->outerColor.b = 0;
}
SkelAnime_Update(&this->skelAnime);
EnPartner_UpdateLights(this, play);

View File

@ -821,19 +821,6 @@ void func_80AF3F20(EnRu2* this, PlayState* play) {
void EnRu2_Draw(Actor* thisx, PlayState* play) {
EnRu2* this = (EnRu2*)thisx;
// FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings.
// Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so
// it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the
// earring texture loads into the same place in tmem as the brick texture, so when it comes to rendering, TEXEL1
// uses the earring texture with diffrent clamp settings, and it displays without noticeable error. However, both
// texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses
// our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces
// TEXEL1 with TEXEL0, which is most likely the original intention, and all is well.
Gfx* gfx = ResourceMgr_LoadGfxByName(gAdultRutoHeadDL);
Gfx patch = gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, TEXEL0, 0,
PRIM_LOD_FRAC, COMBINED);
gfx[0xA2] = patch;
if ((this->drawConfig < 0) || (this->drawConfig >= ARRAY_COUNT(sDrawFuncs)) ||
(sDrawFuncs[this->drawConfig] == 0)) {
// "Draw Mode is improper!"

View File

@ -1412,12 +1412,20 @@ void EnSkj_StartOcarinaMinigame(EnSkj* this, PlayState* play) {
EnSkj_TurnPlayer(this, player);
if (dialogState == TEXT_STATE_CLOSING) {
func_8010BD58(play, OCARINA_ACTION_MEMORY_GAME);
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_PLAY_NOTES;
// #region SOH [Enhancement]
if (CVarGetInteger("gInstantOcarinaGameWin", 0) && CVarGetInteger("gCustomizeOcarinaGame", 0)) {
play->msgCtx.ocarinaMode = OCARINA_MODE_0F;
this->songFailTimer = 160;
this->actionFunc = EnSkj_WaitForPlayback;
// #endregion
} else {
func_8010BD58(play, OCARINA_ACTION_MEMORY_GAME);
if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) {
sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_PLAY_NOTES;
this->songFailTimer = 160;
this->actionFunc = EnSkj_WaitForPlayback;
}
}
this->songFailTimer = 160;
this->actionFunc = EnSkj_WaitForPlayback;
}
}
@ -1466,7 +1474,14 @@ void EnSkj_WaitForPlayback(EnSkj* this, PlayState* play) {
break;
case MSGMODE_MEMORY_GAME_PLAYER_PLAYING:
if (this->songFailTimer != 0) {
this->songFailTimer--;
// #region SOH [Enhancement]
if (CVarGetInteger("gOcarinaUnlimitedFailTime", 0) == 1 &&
CVarGetInteger("gCustomizeOcarinaGame", 0) == 1) {
// don't decrement timer
// #endregion
} else {
this->songFailTimer--;
}
} else { // took too long, game failed
func_80078884(NA_SE_SY_OCARINA_ERROR);
Message_CloseTextbox(play);

View File

@ -5249,6 +5249,37 @@ static Vec3s sSinkingLureLocationPos[] = {
{ 553, -48, -508 }, // tip of log beside 3 posts
};
// #region SOH [Enhancement]
void Fishing_QuitAtDoor(Fishing* this, PlayState* play) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) {
Message_CloseTextbox(play);
switch (play->msgCtx.choiceIndex) {
case 0:
if (sFishesCaught == 0) {
Message_ContinueTextbox(play, 0x4085);
} else if (sLinkAge == 1) {
Message_ContinueTextbox(play, 0x4092);
}
if (Message_GetState(&play->msgCtx) == TEXT_STATE_DONE_FADING) {
if (sIsOwnersHatHooked != 0) {
sOwnerHair = 1;
sIsOwnersHatHooked = 0;
}
sFishingPlayingState = 0;
play->interfaceCtx.unk_260 = 0;
}
break;
case 1:
func_800A9F6C(0.0f, 150, 10, 10);
break;
}
}
}
// #endregion
void Fishing_UpdateOwner(Actor* thisx, PlayState* play2) {
PlayState* play = play2;
Fishing* this = (Fishing*)thisx;
@ -5558,6 +5589,12 @@ void Fishing_UpdateOwner(Actor* thisx, PlayState* play2) {
case 11:
player->actor.world.pos.z = 1360.0f;
player->actor.speedXZ = 0.0f;
// #region SOH [Enhancement]
if (CVarGetInteger("gQuitFishingAtDoor", 0)) {
Fishing_QuitAtDoor(this, play);
}
// #endregion
if (Message_GetState(&play->msgCtx) == TEXT_STATE_NONE) {
Camera* mainCam = Play_GetCamera(play, MAIN_CAM);

View File

@ -2912,7 +2912,11 @@ s32 func_808356E8(Player* this, PlayState* play) {
}
void func_808357E8(Player* this, Gfx** dLists) {
this->leftHandDLists = &dLists[gSaveContext.linkAge];
if (LINK_IS_ADULT && (CVarGetInteger("gEnhancements.EquimentAlwaysVisible", 0))) {
this->leftHandDLists = &dLists[1];
} else {
this->leftHandDLists = &dLists[gSaveContext.linkAge];
}
}
s32 func_80835800(Player* this, PlayState* play) {
@ -6983,9 +6987,19 @@ s32 Player_TryEnteringCrawlspace(Player* this, PlayState* play, u32 interactWall
this->actor.world.pos.z = zVertex1 + (distToInteractWall * wallPolyNormZ);
func_80832224(this);
this->actor.prevPos = this->actor.world.pos;
Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_start);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
// #region SOH [Enhancement]
if (CVarGetInteger("gCrawlSpeed", 1) > 1) {
// increase animation speed when entering a tunnel
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_child_tunnel_start,
((CVarGetInteger("gCrawlSpeed", 1) + 1.0f) / 2.0f), 0.0f,
Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_start), ANIMMODE_ONCE,
0.0f);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
// #endregion
} else {
Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_start);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
}
return true;
}
}
@ -7066,16 +7080,39 @@ s32 Player_TryLeavingCrawlspace(Player* this, PlayState* play) {
if (this->linearVelocity > 0.0f) {
this->actor.shape.rot.y = this->actor.wallYaw + 0x8000;
Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_end);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9601, 999, NULL, MAIN_CAM);
// #region SOH [Enhancement]
if (CVarGetInteger("gCrawlSpeed", 1) > 1) {
// animation when exiting a tunnel forward
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_child_tunnel_end,
((CVarGetInteger("gCrawlSpeed", 1) + 1.0f) / 2.0f), 0.0f,
Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_end), ANIMMODE_ONCE,
0.0f);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9601, 999, NULL, MAIN_CAM);
// #endregion
} else {
Player_AnimPlayOnce(play, this, &gPlayerAnim_link_child_tunnel_end);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9601, 999, NULL, MAIN_CAM);
}
} else {
this->actor.shape.rot.y = this->actor.wallYaw;
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_child_tunnel_start, -1.0f,
Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_start), 0.0f, ANIMMODE_ONCE,
0.0f);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9602, 999, NULL, MAIN_CAM);
// #region SOH [Enhancement]
// animation when exiting a tunnel backward
if (CVarGetInteger("gCrawlSpeed",1) > 1) {
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_child_tunnel_start,
-1.0f * ((CVarGetInteger("gCrawlSpeed", 1) + 1.0f) / 2.0f),
Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_start), 0.0f, ANIMMODE_ONCE, 0.0f);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9602, 999, NULL, MAIN_CAM);
// #endregion
}
else {
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_child_tunnel_start, -1.0f,
Animation_GetLastFrame(&gPlayerAnim_link_child_tunnel_start), 0.0f, ANIMMODE_ONCE, 0.0f);
Player_AnimReplaceApplyFlags(play, this, 0x9D);
OnePointCutscene_Init(play, 9602, 999, NULL, MAIN_CAM);
}
}
this->currentYaw = this->actor.shape.rot.y;
@ -7236,11 +7273,41 @@ s32 func_8083FD78(Player* this, f32* arg1, s16* arg2, PlayState* play) {
*arg2 = this->actor.shape.rot.y;
}
if (this->unk_664 != NULL) {
func_8083DB98(this, 1);
// #region SOH [Enhancement]
if (CVarGetInteger("gRightStickAiming", 0) || !CVarGetInteger("gInvertZAimingYAxis", 1)) {
if (this->unk_664 != NULL) {
func_8083DB98(this, 1);
} else {
int8_t relStickY;
// preserves simultaneous left/right-stick aiming
if (CVarGetInteger("gRightStickAiming", 0)) {
if ((sControlInput->rel.stick_y + sControlInput->rel.right_stick_y) >= 0) {
relStickY = (((sControlInput->rel.stick_y) > (sControlInput->rel.right_stick_y))
? (sControlInput->rel.stick_y)
: (sControlInput->rel.right_stick_y));
} else {
relStickY = (((sControlInput->rel.stick_y) < (sControlInput->rel.right_stick_y))
? (sControlInput->rel.stick_y)
: (sControlInput->rel.right_stick_y));
}
} else {
relStickY = sControlInput->rel.stick_y;
}
Math_SmoothStepToS(&this->actor.focus.rot.x,
relStickY * (CVarGetInteger("gInvertZAimingYAxis", 1) ? 1 : -1) * 240.0f, 14, 4000, 30);
func_80836AB8(this, 1);
}
// #endregion
} else {
Math_SmoothStepToS(&this->actor.focus.rot.x, sControlInput->rel.stick_y * 240.0f, 14, 4000, 30);
func_80836AB8(this, 1);
if (this->unk_664 != NULL) {
func_8083DB98(this, 1);
} else {
Math_SmoothStepToS(&this->actor.focus.rot.x, sControlInput->rel.stick_y * 240.0f, 14, 4000, 30);
func_80836AB8(this, 1);
}
}
} else {
if (this->unk_664 != NULL) {
@ -11897,6 +11964,68 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
void func_8084AEEC(Player* this, f32* arg1, f32 arg2, s16 arg3) {
f32 temp1;
f32 temp2;
// #region SOH [Enhancement]
f32 swimMod = 1.0f;
if (CVarGetInteger("gEnableWalkModify", 0) == 1) {
if (CVarGetInteger("gWalkSpeedToggle", 0) == 1) {
if (gWalkSpeedToggle1) {
swimMod *= CVarGetFloat("gSwimModifierOne", 1.0f);
} else if (gWalkSpeedToggle2) {
swimMod *= CVarGetFloat("gSwimModifierTwo", 1.0f);
}
} else {
if (CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER1)) {
swimMod *= CVarGetFloat("gSwimModifierOne", 1.0f);
} else if (CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER2)) {
swimMod *= CVarGetFloat("gSwimModifierTwo", 1.0f);
}
}
temp1 = this->skelAnime.curFrame - 10.0f;
temp2 = (R_RUN_SPEED_LIMIT / 100.0f) * 0.8f * swimMod;
if (*arg1 > temp2) {
*arg1 = temp2;
}
if ((0.0f < temp1) && (temp1 < 10.0f)) {
temp1 *= 6.0f;
} else {
temp1 = 0.0f;
arg2 = 0.0f;
}
Math_AsymStepToF(arg1, arg2 * 0.8f * swimMod, temp1, (fabsf(*arg1) * 0.02f) + 0.05f);
Math_ScaledStepToS(&this->currentYaw, arg3, 1600);
// #endregion
} else {
temp1 = this->skelAnime.curFrame - 10.0f;
temp2 = (R_RUN_SPEED_LIMIT / 100.0f) * 0.8f;
if (*arg1 > temp2) {
*arg1 = temp2;
}
if ((0.0f < temp1) && (temp1 < 10.0f)) {
temp1 *= 6.0f;
} else {
temp1 = 0.0f;
arg2 = 0.0f;
}
Math_AsymStepToF(arg1, arg2 * 0.8f, temp1, (fabsf(*arg1) * 0.02f) + 0.05f);
Math_ScaledStepToS(&this->currentYaw, arg3, 1600);
}
}
// #region SOH [Enhancement]
//Diving uses function func_8084AEEC to calculate changes both xz and y velocity (via func_8084DBC4)
//Provide original calculation for y velocity when swim speed mod is active
void SurfaceWithoutSwimMod(Player* this, f32* arg1, f32 arg2, s16 arg3) {
f32 temp1;
f32 temp2;
temp1 = this->skelAnime.curFrame - 10.0f;
@ -11915,6 +12044,7 @@ void func_8084AEEC(Player* this, f32* arg1, f32 arg2, s16 arg3) {
Math_AsymStepToF(arg1, arg2 * 0.8f, temp1, (fabsf(*arg1) * 0.02f) + 0.05f);
Math_ScaledStepToS(&this->currentYaw, arg3, 1600);
}
// #endregion
void func_8084B000(Player* this) {
f32 phi_f18;
@ -12533,8 +12663,15 @@ void func_8084C760(Player* this, PlayState* play) {
return;
}
// player speed in a tunnel
if (!Player_TryLeavingCrawlspace(this, play)) {
this->linearVelocity = sControlInput->rel.stick_y * 0.03f;
// #region SOH [Enhancement]
if (CVarGetInteger("gCrawlSpeed", 1) > 1) {
this->linearVelocity = sControlInput->rel.stick_y * 0.03f * CVarGetInteger("gCrawlSpeed", 1);
// #endregion
} else {
this->linearVelocity = sControlInput->rel.stick_y * 0.03f;
}
}
}
return;
@ -13069,7 +13206,14 @@ void func_8084DBC4(PlayState* play, Player* this, f32 arg2) {
Player_GetMovementSpeedAndYaw(this, &sp2C, &sp2A, 0.0f, play);
func_8084AEEC(this, &this->linearVelocity, sp2C * 0.5f, sp2A);
func_8084AEEC(this, &this->actor.velocity.y, arg2, this->currentYaw);
// Original implementation of func_8084AEEC (SurfaceWithoutSwimMod) to prevent velocity increases via swim mod which push Link into the air
// #region SOH [Enhancement]
if (CVarGetInteger("gEnableWalkModify", 0)) {
SurfaceWithoutSwimMod(this, &this->actor.velocity.y, arg2, this->currentYaw);
// #endregion
} else {
func_8084AEEC(this, &this->actor.velocity.y, arg2, this->currentYaw);
}
}
void func_8084DC48(Player* this, PlayState* play) {

View File

@ -312,6 +312,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
KaleidoScope_DrawQuadTextureRGBA32(gfxCtx, gQuestIconGoldSkulltulaTex, 24, 24, 8);
}
// Unique index for both pulse phases
uint8_t palettePulseIdx = (mapBgPulseStage ? 40 : 20) - mapBgPulseTimer;
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
stepR = (mapBgPulseR - mapBgPulseColors[mapBgPulseStage][0]) / mapBgPulseTimer;
stepG = (mapBgPulseG - mapBgPulseColors[mapBgPulseStage][1]) / mapBgPulseTimer;
@ -324,6 +327,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
interfaceCtx->mapPalette[28] = (rgba16 & 0xFF00) >> 8;
interfaceCtx->mapPalette[29] = rgba16 & 0xFF;
interfaceCtx->mapPalettesPulse[palettePulseIdx][28] = (rgba16 & 0xFF00) >> 8;
interfaceCtx->mapPalettesPulse[palettePulseIdx][29] = rgba16 & 0xFF;
mapBgPulseTimer--;
if (mapBgPulseTimer == 0) {
mapBgPulseStage ^= 1;
@ -335,7 +341,8 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gDPSetTextureFilter(POLY_KAL_DISP++, G_TF_POINT);
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalette);
// Use a unique palette address per frame so the renderer/shader can cache all variations
gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalettesPulse[palettePulseIdx]);
gDPSetTextureLUT(POLY_KAL_DISP++, G_TT_RGBA16);
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
@ -349,10 +356,6 @@ 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[0]);
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);

View File

@ -1204,8 +1204,6 @@ Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, void** textures) {
return gfx;
}
static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT];
void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
static Color_RGB8 D_8082ACF4[12] = {
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 },
@ -1374,10 +1372,6 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
}
}
// Need to invalidate the blend mask every frame. Ideally this would be done in KaleidoScope_DrawDungeonMap
// but the reference is not shared between files
gSPInvalidateTexCache(POLY_KAL_DISP++, mapBlendMask);
if (pauseCtx->pageIndex) { // pageIndex != PAUSE_ITEM
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA);
@ -1889,11 +1883,17 @@ void KaleidoScope_DrawInfoPanel(PlayState* play) {
gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 90, 100, 130, 255);
const Color_RGBA8 namePanelColor = CVarGetColor("gCosmetics.Kal_NamePanel.Value", (Color_RGBA8){90,100,130,255});
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, namePanelColor.r, namePanelColor.g, namePanelColor.b, namePanelColor.a);
gSPVertex(POLY_KAL_DISP++, &pauseCtx->infoPanelVtx[0], 16, 0);
gSPDisplayList(POLY_KAL_DISP++, gItemNamePanelDL);
if (CVarGetInteger("gUniformLR", 0) == 0) { // Restore the misplace gDPSetPrimColor
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 90, 100, 130, 255);
}
if ((pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT) && (pauseCtx->unk_1E4 == 0)) {
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, D_808321A0, D_808321A2, D_808321A4, D_808321A6);
} else {
@ -1901,6 +1901,7 @@ void KaleidoScope_DrawInfoPanel(PlayState* play) {
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 180, 210, 255, 255);
}
}
gSPDisplayList(POLY_KAL_DISP++, gLButtonIconDL);
@ -2311,15 +2312,15 @@ void KaleidoScope_SetView(PauseContext* pauseCtx, f32 x, f32 y, f32 z) {
func_800AAA50(&pauseCtx->view, 127);
}
static u8 D_8082AE48[][4] = {
static u8 sPageVtxColorR[][4] = {
{ 10, 70, 70, 10 }, { 10, 90, 90, 10 }, { 80, 140, 140, 80 },
{ 80, 120, 120, 80 }, { 80, 140, 140, 80 }, { 50, 110, 110, 50 },
};
static u8 D_8082AE60[][4] = {
static u8 sPageVtxColorG[][4] = {
{ 50, 100, 100, 50 }, { 50, 100, 100, 50 }, { 40, 60, 60, 40 },
{ 80, 120, 120, 80 }, { 40, 60, 60, 40 }, { 50, 110, 110, 50 },
};
static u8 D_8082AE78[][4] = {
static u8 sPageVtxColorB[][4] = {
{ 80, 130, 130, 80 }, { 40, 60, 60, 40 }, { 30, 60, 60, 30 },
{ 50, 70, 70, 50 }, { 30, 60, 60, 30 }, { 50, 110, 110, 50 },
};
@ -2447,10 +2448,87 @@ static s16 D_8082B0E4[] = {
0x0019, 0x000D, 0x0001, 0x0001, 0x000D, 0x0015, 0x000F, 0x000D, 0x000C, 0x0001, 0x0000,
};
s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) {
static const char* gPageVtxColorCvars[][4] = {
{
"gCosmetics.Kal_ItemSelA.Value",
"gCosmetics.Kal_ItemSelB.Value",
"gCosmetics.Kal_ItemSelC.Value",
"gCosmetics.Kal_ItemSelD.Value",
},
{
"gCosmetics.Kal_EquipSelA.Value",
"gCosmetics.Kal_EquipSelB.Value",
"gCosmetics.Kal_EquipSelC.Value",
"gCosmetics.Kal_EquipSelD.Value",
},
{
"gCosmetics.Kal_MapSelDunA.Value",
"gCosmetics.Kal_MapSelDunB.Value",
"gCosmetics.Kal_MapSelDunC.Value",
"gCosmetics.Kal_MapSelDunD.Value",
},
{
"gCosmetics.Kal_QuestStatusA.Value",
"gCosmetics.Kal_QuestStatusB.Value",
"gCosmetics.Kal_QuestStatusC.Value",
"gCosmetics.Kal_QuestStatusD.Value",
},
{
"gCosmetics.Kal_MapSelectA.Value",
"gCosmetics.Kal_MapSelectB.Value",
"gCosmetics.Kal_MapSelectC.Value",
"gCosmetics.Kal_MapSelectD.Value",
},
{
"gCosmetics.Kal_SaveA.Value",
"gCosmetics.Kal_SaveB.Value",
"gCosmetics.Kal_SaveC.Value",
"gCosmetics.Kal_SaveD.Value",
},
};
s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 pageIndex, s16 arg3) {
static s16 D_8082B110 = 0;
static s16 D_8082B114 = 1;
static s16 D_8082B118 = 0;
static const Color_RGBA8 pageColors[][4] = {
{
{ 10, 50, 80, 255 },
{ 70, 100, 130, 255 },
{ 70, 100, 130, 255 },
{ 10, 50, 80, 255 },
},
{
{ 10, 50, 40, 255 },
{ 90, 100, 60, 255 },
{ 90, 100, 60, 255 },
{ 10, 50, 40, 255 },
},
{
{ 80,40,30, 255},
{ 140,60,60,255 },
{ 140,60,60,255 },
{ 80, 40, 30, 255 },
},
{
{ 80,80,50,255 },
{ 120,120,70,255 },
{ 120,120,70,255 },
{ 80, 80, 50, 255 },
},
{
{ 80, 40, 30, 255 },
{ 140,60,60,255 },
{ 140,60,60,255 },
{ 80, 40, 30, 255 },
},
{
{ 50,50,50,255 },
{ 110,110,110,255 },
{ 110,110,110,255 },
{ 50,50,50,255 },
},
};
PauseContext* pauseCtx = &play->pauseCtx;
s16* ptr1;
s16* ptr2;
@ -2460,109 +2538,114 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) {
s16 phi_t0;
s16 phi_a1;
s16 phi_a2;
s16 phi_t3;
s16 phi_t1;
s16 colorIndex; // Also used for other things.
s16 vtxIndex;
phi_t0 = -200;
for (phi_t1 = 0, phi_t3 = 0; phi_t3 < 3; phi_t3++) {
for (vtxIndex = 0, colorIndex = 0; colorIndex < 3; colorIndex++) {
phi_t0 += 80;
for (phi_a1 = 80, phi_a2 = 0; phi_a2 < 5; phi_a2++, phi_t1 += 4, phi_a1 -= 32) {
vtx[phi_t1 + 0].v.ob[0] = vtx[phi_t1 + 2].v.ob[0] = phi_t0;
for (phi_a1 = 80, phi_a2 = 0; phi_a2 < 5; phi_a2++, vtxIndex += 4, phi_a1 -= 32) {
vtx[vtxIndex + 0].v.ob[0] = vtx[vtxIndex + 2].v.ob[0] = phi_t0;
vtx[phi_t1 + 1].v.ob[0] = vtx[phi_t1 + 3].v.ob[0] = vtx[phi_t1 + 0].v.ob[0] + 80;
vtx[vtxIndex + 1].v.ob[0] = vtx[vtxIndex + 3].v.ob[0] = vtx[vtxIndex + 0].v.ob[0] + 80;
vtx[phi_t1 + 0].v.ob[1] = vtx[phi_t1 + 1].v.ob[1] = phi_a1 + pauseCtx->offsetY;
vtx[vtxIndex + 0].v.ob[1] = vtx[vtxIndex + 1].v.ob[1] = phi_a1 + pauseCtx->offsetY;
vtx[phi_t1 + 2].v.ob[1] = vtx[phi_t1 + 3].v.ob[1] = vtx[phi_t1 + 0].v.ob[1] - 32;
vtx[vtxIndex + 2].v.ob[1] = vtx[vtxIndex + 3].v.ob[1] = vtx[vtxIndex + 0].v.ob[1] - 32;
vtx[phi_t1 + 0].v.ob[2] = vtx[phi_t1 + 1].v.ob[2] = vtx[phi_t1 + 2].v.ob[2] = vtx[phi_t1 + 3].v.ob[2] = 0;
vtx[vtxIndex + 0].v.ob[2] = vtx[vtxIndex + 1].v.ob[2] = vtx[vtxIndex + 2].v.ob[2] = vtx[vtxIndex + 3].v.ob[2] = 0;
vtx[phi_t1 + 0].v.flag = 0;
vtx[phi_t1 + 1].v.flag = 0;
vtx[phi_t1 + 2].v.flag = 0;
vtx[phi_t1 + 3].v.flag = 0;
vtx[vtxIndex + 0].v.flag = 0;
vtx[vtxIndex + 1].v.flag = 0;
vtx[vtxIndex + 2].v.flag = 0;
vtx[vtxIndex + 3].v.flag = 0;
vtx[phi_t1 + 0].v.tc[0] = vtx[phi_t1 + 0].v.tc[1] = vtx[phi_t1 + 1].v.tc[1] = vtx[phi_t1 + 2].v.tc[0] = 0;
vtx[vtxIndex + 0].v.tc[0] = vtx[vtxIndex + 0].v.tc[1] = vtx[vtxIndex + 1].v.tc[1] = vtx[vtxIndex + 2].v.tc[0] = 0;
vtx[phi_t1 + 1].v.tc[0] = vtx[phi_t1 + 3].v.tc[0] = 0xA00;
vtx[vtxIndex + 1].v.tc[0] = vtx[vtxIndex + 3].v.tc[0] = 0xA00;
vtx[phi_t1 + 2].v.tc[1] = vtx[phi_t1 + 3].v.tc[1] = 0x400;
vtx[vtxIndex + 2].v.tc[1] = vtx[vtxIndex + 3].v.tc[1] = 0x400;
vtx[phi_t1 + 0].v.cn[0] = vtx[phi_t1 + 2].v.cn[0] = D_8082AE48[arg2][phi_t3 + 0];
//Color in the pages. Pages are drawn in groups. Each group is faded to the next. There are 4 total colors, 1/4 and 2/3 are the same creating a mirrored color set.
// TODO, go from 0,1,2,3 to 0,1,1,0 to only use two colors instead of 4.
Color_RGBA8 color = CVarGetColor(gPageVtxColorCvars[pageIndex][colorIndex], pageColors[pageIndex][colorIndex]);
Color_RGBA8 colorb =
CVarGetColor(gPageVtxColorCvars[pageIndex][colorIndex + 1], pageColors[pageIndex][colorIndex+1]);
vtx[vtxIndex + 0].v.cn[0] = vtx[vtxIndex + 2].v.cn[0] = color.r; // sPageVtxColorR[pageIndex][colorIndex + 0];
vtx[phi_t1 + 0].v.cn[1] = vtx[phi_t1 + 2].v.cn[1] = D_8082AE60[arg2][phi_t3 + 0];
vtx[vtxIndex + 0].v.cn[1] = vtx[vtxIndex + 2].v.cn[1] = color.g;// sPageVtxColorG[pageIndex][colorIndex + 0];
vtx[phi_t1 + 0].v.cn[2] = vtx[phi_t1 + 2].v.cn[2] = D_8082AE78[arg2][phi_t3 + 0];
vtx[vtxIndex + 0].v.cn[2] = vtx[vtxIndex + 2].v.cn[2] = color.b; // sPageVtxColorB[pageIndex][colorIndex + 0];
vtx[phi_t1 + 1].v.cn[0] = vtx[phi_t1 + 3].v.cn[0] = D_8082AE48[arg2][phi_t3 + 1];
vtx[vtxIndex + 1].v.cn[0] = vtx[vtxIndex + 3].v.cn[0] = colorb.r;//sPageVtxColorR[pageIndex][colorIndex + 1];
vtx[phi_t1 + 1].v.cn[1] = vtx[phi_t1 + 3].v.cn[1] = D_8082AE60[arg2][phi_t3 + 1];
vtx[vtxIndex + 1].v.cn[1] = vtx[vtxIndex + 3].v.cn[1] = colorb.g; // sPageVtxColorG[pageIndex][colorIndex + 1];
vtx[phi_t1 + 1].v.cn[2] = vtx[phi_t1 + 3].v.cn[2] = D_8082AE78[arg2][phi_t3 + 1];
vtx[vtxIndex + 1].v.cn[2] = vtx[vtxIndex + 3].v.cn[2] = colorb.b; // sPageVtxColorB[pageIndex][colorIndex + 1];
vtx[phi_t1 + 0].v.cn[3] = vtx[phi_t1 + 2].v.cn[3] = vtx[phi_t1 + 1].v.cn[3] = vtx[phi_t1 + 3].v.cn[3] =
vtx[vtxIndex + 0].v.cn[3] = vtx[vtxIndex + 2].v.cn[3] = vtx[vtxIndex + 1].v.cn[3] = vtx[vtxIndex + 3].v.cn[3] =
pauseCtx->alpha;
}
}
phi_s2 = phi_t1;
phi_s2 = vtxIndex;
if (arg3 != 0) {
ptr1 = D_8082B000[arg2];
ptr2 = D_8082B018[arg2];
ptr3 = D_8082B030[arg2];
ptr4 = D_8082B048[arg2];
ptr1 = D_8082B000[pageIndex];
ptr2 = D_8082B018[pageIndex];
ptr3 = D_8082B030[pageIndex];
ptr4 = D_8082B048[pageIndex];
for (phi_t3 = 0; phi_t3 < arg3; phi_t3++, phi_t1 += 4) {
vtx[phi_t1 + 2].v.ob[0] = vtx[phi_t1 + 0].v.ob[0] = ptr1[phi_t3];
for (colorIndex = 0; colorIndex < arg3; colorIndex++, vtxIndex += 4) {
vtx[vtxIndex + 2].v.ob[0] = vtx[vtxIndex + 0].v.ob[0] = ptr1[colorIndex];
vtx[phi_t1 + 1].v.ob[0] = vtx[phi_t1 + 3].v.ob[0] = vtx[phi_t1 + 0].v.ob[0] + ptr2[phi_t3];
vtx[vtxIndex + 1].v.ob[0] = vtx[vtxIndex + 3].v.ob[0] = vtx[vtxIndex + 0].v.ob[0] + ptr2[colorIndex];
if (!((pauseCtx->state >= 8) && (pauseCtx->state <= 0x11))) {
vtx[phi_t1 + 0].v.ob[1] = vtx[phi_t1 + 1].v.ob[1] = ptr3[phi_t3] + pauseCtx->offsetY;
vtx[vtxIndex + 0].v.ob[1] = vtx[vtxIndex + 1].v.ob[1] = ptr3[colorIndex] + pauseCtx->offsetY;
} else {
vtx[phi_t1 + 0].v.ob[1] = vtx[phi_t1 + 1].v.ob[1] = YREG(60 + phi_t3) + pauseCtx->offsetY;
vtx[vtxIndex + 0].v.ob[1] = vtx[vtxIndex + 1].v.ob[1] = YREG(60 + colorIndex) + pauseCtx->offsetY;
}
vtx[phi_t1 + 2].v.ob[1] = vtx[phi_t1 + 3].v.ob[1] = vtx[phi_t1 + 0].v.ob[1] - ptr4[phi_t3];
vtx[vtxIndex + 2].v.ob[1] = vtx[vtxIndex + 3].v.ob[1] = vtx[vtxIndex + 0].v.ob[1] - ptr4[colorIndex];
vtx[phi_t1 + 0].v.ob[2] = vtx[phi_t1 + 1].v.ob[2] = vtx[phi_t1 + 2].v.ob[2] = vtx[phi_t1 + 3].v.ob[2] = 0;
vtx[vtxIndex + 0].v.ob[2] = vtx[vtxIndex + 1].v.ob[2] = vtx[vtxIndex + 2].v.ob[2] = vtx[vtxIndex + 3].v.ob[2] = 0;
vtx[phi_t1 + 0].v.flag = vtx[phi_t1 + 1].v.flag = vtx[phi_t1 + 2].v.flag = vtx[phi_t1 + 3].v.flag = 0;
vtx[vtxIndex + 0].v.flag = vtx[vtxIndex + 1].v.flag = vtx[vtxIndex + 2].v.flag = vtx[vtxIndex + 3].v.flag = 0;
vtx[phi_t1 + 0].v.tc[0] = vtx[phi_t1 + 0].v.tc[1] = vtx[phi_t1 + 1].v.tc[1] = vtx[phi_t1 + 2].v.tc[0] = 0;
vtx[vtxIndex + 0].v.tc[0] = vtx[vtxIndex + 0].v.tc[1] = vtx[vtxIndex + 1].v.tc[1] = vtx[vtxIndex + 2].v.tc[0] = 0;
vtx[phi_t1 + 1].v.tc[0] = vtx[phi_t1 + 3].v.tc[0] = ptr2[phi_t3] << 5;
vtx[vtxIndex + 1].v.tc[0] = vtx[vtxIndex + 3].v.tc[0] = ptr2[colorIndex] << 5;
vtx[phi_t1 + 2].v.tc[1] = vtx[phi_t1 + 3].v.tc[1] = ptr4[phi_t3] << 5;
vtx[vtxIndex + 2].v.tc[1] = vtx[vtxIndex + 3].v.tc[1] = ptr4[colorIndex] << 5;
vtx[phi_t1 + 0].v.cn[0] = vtx[phi_t1 + 2].v.cn[0] = vtx[phi_t1 + 0].v.cn[1] = vtx[phi_t1 + 2].v.cn[1] =
vtx[phi_t1 + 0].v.cn[2] = vtx[phi_t1 + 2].v.cn[2] = vtx[phi_t1 + 1].v.cn[0] = vtx[phi_t1 + 3].v.cn[0] =
vtx[phi_t1 + 1].v.cn[1] = vtx[phi_t1 + 3].v.cn[1] = vtx[phi_t1 + 1].v.cn[2] =
vtx[phi_t1 + 3].v.cn[2] = 255;
vtx[vtxIndex + 0].v.cn[0] = vtx[vtxIndex + 2].v.cn[0] = vtx[vtxIndex + 0].v.cn[1] = vtx[vtxIndex + 2].v.cn[1] =
vtx[vtxIndex + 0].v.cn[2] = vtx[vtxIndex + 2].v.cn[2] = vtx[vtxIndex + 1].v.cn[0] = vtx[vtxIndex + 3].v.cn[0] =
vtx[vtxIndex + 1].v.cn[1] = vtx[vtxIndex + 3].v.cn[1] = vtx[vtxIndex + 1].v.cn[2] =
vtx[vtxIndex + 3].v.cn[2] = 255;
vtx[phi_t1 + 0].v.cn[3] = vtx[phi_t1 + 2].v.cn[3] = vtx[phi_t1 + 1].v.cn[3] = vtx[phi_t1 + 3].v.cn[3] =
vtx[vtxIndex + 0].v.cn[3] = vtx[vtxIndex + 2].v.cn[3] = vtx[vtxIndex + 1].v.cn[3] = vtx[vtxIndex + 3].v.cn[3] =
pauseCtx->alpha;
}
if (arg2 == 4) {
phi_t1 -= 12;
if (pageIndex == 4) {
vtxIndex -= 12;
phi_t3 = gSaveContext.worldMapArea;
colorIndex = gSaveContext.worldMapArea;
vtx[phi_t1 + 0].v.ob[0] = vtx[phi_t1 + 2].v.ob[0] = D_8082B060[phi_t3];
vtx[vtxIndex + 0].v.ob[0] = vtx[vtxIndex + 2].v.ob[0] = D_8082B060[colorIndex];
if (phi_t3) {}
if (colorIndex) {}
vtx[phi_t1 + 1].v.ob[0] = vtx[phi_t1 + 3].v.ob[0] = vtx[phi_t1 + 0].v.ob[0] + D_8082B08C[phi_t3];
vtx[vtxIndex + 1].v.ob[0] = vtx[vtxIndex + 3].v.ob[0] = vtx[vtxIndex + 0].v.ob[0] + D_8082B08C[colorIndex];
vtx[phi_t1 + 0].v.ob[1] = vtx[phi_t1 + 1].v.ob[1] = D_8082B0B8[phi_t3] + pauseCtx->offsetY;
vtx[vtxIndex + 0].v.ob[1] = vtx[vtxIndex + 1].v.ob[1] = D_8082B0B8[colorIndex] + pauseCtx->offsetY;
vtx[phi_t1 + 2].v.ob[1] = vtx[phi_t1 + 3].v.ob[1] = vtx[phi_t1 + 0].v.ob[1] - D_8082B0E4[phi_t3];
vtx[vtxIndex + 2].v.ob[1] = vtx[vtxIndex + 3].v.ob[1] = vtx[vtxIndex + 0].v.ob[1] - D_8082B0E4[colorIndex];
phi_t1 += 12;
vtxIndex += 12;
if (pauseCtx->tradeQuestLocation != 0xFF) {
if (D_8082B114 == 0) {
@ -2582,14 +2665,14 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) {
D_8082B114--;
}
phi_t3 = phi_s2 + (pauseCtx->tradeQuestLocation * 4) + 64;
colorIndex = phi_s2 + (pauseCtx->tradeQuestLocation * 4) + 64;
phi_a2 = phi_s2 + 116;
vtx[phi_a2 + 0].v.ob[0] = vtx[phi_a2 + 2].v.ob[0] = vtx[phi_t3 + 0].v.ob[0];
vtx[phi_a2 + 0].v.ob[0] = vtx[phi_a2 + 2].v.ob[0] = vtx[colorIndex + 0].v.ob[0];
vtx[phi_a2 + 1].v.ob[0] = vtx[phi_a2 + 3].v.ob[0] = vtx[phi_a2 + 0].v.ob[0] + 8;
vtx[phi_a2 + 0].v.ob[1] = vtx[phi_a2 + 1].v.ob[1] = vtx[phi_t3 + 0].v.ob[1] - D_8082B110 + 10;
vtx[phi_a2 + 0].v.ob[1] = vtx[phi_a2 + 1].v.ob[1] = vtx[colorIndex + 0].v.ob[1] - D_8082B110 + 10;
vtx[phi_a2 + 0].v.ob[2] = vtx[phi_a2 + 1].v.ob[2] = vtx[phi_a2 + 2].v.ob[2] = vtx[phi_a2 + 3].v.ob[2] =
0;
@ -2598,7 +2681,7 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) {
vtx[phi_a2 + 0].v.flag = vtx[phi_a2 + 1].v.flag = vtx[phi_a2 + 2].v.flag = vtx[phi_a2 + 3].v.flag = 0;
vtx[phi_t1].v.tc[0] = vtx[phi_t1].v.tc[1] = vtx[phi_a2 + 1].v.tc[1] = vtx[phi_a2 + 2].v.tc[0] = 0;
vtx[vtxIndex].v.tc[0] = vtx[vtxIndex].v.tc[1] = vtx[phi_a2 + 1].v.tc[1] = vtx[phi_a2 + 2].v.tc[0] = 0;
vtx[phi_a2 + 1].v.tc[0] = vtx[phi_a2 + 3].v.tc[0] = 0x100;
@ -2615,7 +2698,7 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) {
}
}
return phi_t1;
return vtxIndex;
}
static s16 D_8082B11C[] = { 0, 4, 8, 12, 24, 32, 56 };
@ -3325,6 +3408,7 @@ static uint8_t mapLeftTexModified[MAP_48x85_TEX_SIZE];
static uint8_t mapRightTexModified[MAP_48x85_TEX_SIZE];
static uint8_t* mapLeftTexModifiedRaw = NULL;
static uint8_t* mapRightTexModifiedRaw = NULL;
static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT];
// Load dungeon maps into the interface context
// SoH [General] - Modified to account for our resource system and HD textures
@ -3356,19 +3440,16 @@ void KaleidoScope_LoadDungeonMap(PlayState* play) {
size_t size = (width * height) / 2; // account for CI4 size
// Resource size being larger than the calculated CI size means it is most likely not a CI4 texture
// Abort early end undo the blended effect by clearing the mask to avoid crashing
// Abort early and unregister the blended effect to avoid crashing
if (size < ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0])) {
if (mapBlendMask[0] != 0) {
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
mapBlendMask[i] = 0;
}
}
interfaceCtx->mapSegment[0] = NULL;
interfaceCtx->mapSegment[1] = NULL;
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, NULL);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, NULL);
Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[0]);
Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[1]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]);
return;
}
@ -3403,6 +3484,11 @@ void KaleidoScope_LoadDungeonMap(PlayState* play) {
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegment[0]);
Gfx_TextureCacheDelete(interfaceCtx->mapSegment[1]);
}
static uint8_t registeredDungeonMapTextureHook = false;
@ -3443,6 +3529,11 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) {
KaleidoScope_LoadDungeonMap(play);
Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3);
// Copy the map palette values to all pulse palettes
for (uint8_t i = 0; i < ARRAY_COUNT(interfaceCtx->mapPalettesPulse); i++) {
memcpy(interfaceCtx->mapPalettesPulse[i], interfaceCtx->mapPalette, sizeof(interfaceCtx->mapPalette));
}
s32 size = MAP_48x85_TEX_SIZE;
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {