Merge remote-tracking branch 'origin/develop' into merge-macready-may6

This commit is contained in:
Adam Bird 2024-05-06 12:22:48 -04:00
commit 439574d0d9
603 changed files with 25974 additions and 20371 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 libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build

View File

@ -13,42 +13,60 @@ jobs:
with: with:
submodules: true submodules: true
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2.11
with: 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 - name: Install dependencies
if: ${{ !vars.LINUX_RUNNER }} if: ${{ !vars.LINUX_RUNNER }}
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) 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 - name: Install latest SDL
if: ${{ !vars.LINUX_RUNNER }} if: ${{ !vars.LINUX_RUNNER }}
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz if [ ! -d "SDL2-2.28.5" ]; then
tar -xzf SDL2-2.26.1.tar.gz wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
cd SDL2-2.26.1 tar -xzf SDL2-2.28.5.tar.gz
./configure fi
cd SDL2-2.28.5
./configure --enable-hidapi-libusb
make -j 10 make -j 10
sudo make install sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
- name: Install latest SDL_net - name: Install latest tinyxml2
if: ${{ !vars.LINUX_RUNNER }}
run: | run: |
sudo apt-get remove libtinyxml2-dev
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" 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 if [ ! -d "tinyxml2-10.0.0" ]; then
tar -xzf SDL2_net-2.2.0.tar.gz wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz
cd SDL2_net-2.2.0 tar -xzf 10.0.0.tar.gz
./configure fi
make -j 10 cd tinyxml2-10.0.0
mkdir build
cd build
cmake ..
make
sudo make install sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
- name: Generate soh.otr - name: Generate soh.otr
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" 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 --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-cmake --config Release --target GenerateSohOtr cmake --build build-cmake --config Release --target GenerateSohOtr
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: soh.otr name: soh.otr
path: soh.otr path: soh.otr
@ -61,9 +79,12 @@ jobs:
with: with:
submodules: true submodules: true
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2.11
with: 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 - name: Install gtar wrapper
if: ${{ !vars.MAC_RUNNER }} if: ${{ !vars.MAC_RUNNER }}
run: | run: |
@ -85,24 +106,24 @@ jobs:
if [ -d /opt/local/ ]; then if [ -d /opt/local/ ]; then
echo "MacPorts already installed" echo "MacPorts already installed"
else else
wget https://github.com/macports/macports-base/releases/download/v2.7.2/MacPorts-2.7.2-12-Monterey.pkg wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-12-Monterey.pkg
sudo installer -pkg ./MacPorts-2.7.2-12-Monterey.pkg -target / sudo installer -pkg ./MacPorts-2.9.3-12-Monterey.pkg -target /
fi fi
echo "/opt/local/bin:/opt/local/sbin" >> $GITHUB_PATH echo "/opt/local/bin:/opt/local/sbin" >> $GITHUB_PATH
- name: Install dependencies - name: Install dependencies
if: ${{ !vars.MAC_RUNNER }} if: ${{ !vars.MAC_RUNNER }}
run: | run: |
brew uninstall --ignore-dependencies libpng brew uninstall --ignore-dependencies libpng libzip
sudo port install $(cat .github/workflows/macports-deps.txt) sudo port install $(cat .github/workflows/macports-deps.txt)
brew install ninja brew install ninja
- name: Download soh.otr - name: Download soh.otr
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4
with: with:
name: soh.otr name: soh.otr
- name: Build SoH - name: Build SoH
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" 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 -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DBUILD_REMOTE_CONTROL=1
cmake --build build-cmake --config Release --parallel 10 cmake --build build-cmake --config Release --parallel 10
mv soh.otr build-cmake/soh mv soh.otr build-cmake/soh
(cd build-cmake && cpack) (cd build-cmake && cpack)
@ -110,7 +131,7 @@ jobs:
mv _packages/*.dmg SoH.dmg mv _packages/*.dmg SoH.dmg
mv README.md readme.txt mv README.md readme.txt
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: soh-mac name: soh-mac
path: | path: |
@ -139,39 +160,101 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) sudo apt-get install -y $(cat .github/workflows/apt-deps.txt)
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2.11
with: 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 - name: Install latest SDL
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }} if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz if [ ! -d "SDL2-2.28.5" ]; then
tar -xzf SDL2-2.26.1.tar.gz wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
cd SDL2-2.26.1 tar -xzf SDL2-2.28.5.tar.gz
./configure fi
cd SDL2-2.28.5
./configure --enable-hidapi-libusb
make -j 10 make -j 10
sudo make install sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
- name: Install latest libzip
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) }}
run: |
sudo apt-get remove libzip-dev zipcmp zipmerge ziptool
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
if [ ! -d "libzip-1.10.1" ]; then
wget https://libzip.org/download/libzip-1.10.1.tar.gz
tar -xzvf libzip-1.10.1.tar.gz
fi
cd libzip-1.10.1
mkdir build
cd build
cmake ..
make
sudo make install
- name: Install latest nlohmann
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) }}
run: |
sudo apt-get remove nlohmann-json3-dev
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
if [ ! -d "json-3.11.3" ]; then
wget https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.tar.gz
tar -xzvf v3.11.3.tar.gz
fi
cd json-3.11.3
mkdir build
cd build
cmake ..
make
sudo make install
- name: Install latest tinyxml2
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
run: |
sudo apt-get remove libtinyxml2-dev
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
if [ ! -d "tinyxml2-10.0.0" ]; then
wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz
tar -xzf 10.0.0.tar.gz
fi
cd tinyxml2-10.0.0
mkdir build
cd build
cmake ..
make
sudo make install
- name: Install latest SDL_net - name: Install latest SDL_net
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }} if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" 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 if [ ! -d "SDL2_net-2.2.0" ]; then
tar -xzf SDL2_net-2.2.0.tar.gz 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 cd SDL2_net-2.2.0
./configure ./configure
make -j 10 make -j 10
sudo make install sudo make install
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/ sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
- name: Download soh.otr - name: Download soh.otr
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4
with: with:
name: soh.otr name: soh.otr
- name: Build SoH - name: Build SoH
run: | run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" 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 --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1
cmake --build build-cmake --config Release -j3 cmake --build build-cmake --config Release -j3
(cd build-cmake && cpack -G External) (cd build-cmake && cpack -G External)
@ -181,92 +264,12 @@ jobs:
CC: gcc-${{ matrix.gcc }} CC: gcc-${{ matrix.gcc }}
CXX: g++-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }}
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: soh-linux-${{ matrix.archive-suffix }} name: soh-linux-${{ matrix.archive-suffix }}
path: | path: |
soh.appimage soh.appimage
readme.txt readme.txt
build-switch:
needs: generate-soh-otr
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
container:
image: devkitpro/devkita64:20240120
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ninja-build
- name: Fix dubious ownership error
if: ${{ vars.LINUX_RUNNER }}
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v3
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ 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
cmake --build build-switch --target soh_nro -j3
mv build-switch/soh/*.nro soh.nro
mv README.md readme.txt
- name: Download soh.otr
uses: actions/download-artifact@v3
with:
name: soh.otr
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: soh-switch
path: |
soh.nro
soh.otr
readme.txt
build-wiiu:
needs: generate-soh-otr
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
container:
image: devkitpro/devkitppc:20230110
steps:
- name: Install dependencies
if: ${{ !vars.LINUX_RUNNER }}
run: |
sudo apt-get install -y ninja-build
- uses: actions/checkout@v3
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-wiiu-ccache
- name: Build SoH
run: |
cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
cmake --build build-wiiu --target soh_wuhb --config Release -j3
mv build-wiiu/soh/*.rpx soh.rpx
mv build-wiiu/soh/*.wuhb soh.wuhb
mv README.md readme.txt
env:
DEVKITPRO: /opt/devkitpro
DEVKITPPC: /opt/devkitpro/devkitPPC
- name: Download soh.otr
uses: actions/download-artifact@v3
with:
name: soh.otr
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: soh-wiiu
path: |
soh.rpx
soh.wuhb
soh.otr
readme.txt
build-windows: build-windows:
needs: generate-soh-otr needs: generate-soh-otr
runs-on: ${{ (vars.WINDOWS_RUNNER && fromJSON(vars.WINDOWS_RUNNER)) || 'windows-latest' }} runs-on: ${{ (vars.WINDOWS_RUNNER && fromJSON(vars.WINDOWS_RUNNER)) || 'windows-latest' }}
@ -280,16 +283,33 @@ jobs:
with: with:
submodules: true submodules: true
- name: ccache - name: ccache
uses: dcvz/ccache-action@27b9f33213c0079872f064f6b6ba0233dfa16ba2 uses: hendrikmuhs/ccache-action@v1.2.11
with: with:
key: ${{ runner.os }}-ccache variant: sccache
- uses: ilammy/msvc-dev-cmd@v1 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:
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 - name: Build SoH
env: env:
VCPKG_ROOT: D:/a/vcpkg VCPKG_ROOT: ${{github.workspace}}/vcpkg
run: | run: |
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH" 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 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 cmake --build build-windows --config Release --parallel 10
mkdir soh-windows mkdir soh-windows
@ -302,12 +322,12 @@ jobs:
mv ./build-windows/gamecontrollerdb.txt ./soh-windows/gamecontrollerdb.txt mv ./build-windows/gamecontrollerdb.txt ./soh-windows/gamecontrollerdb.txt
mv ./x64/Release/assets ./soh-windows mv ./x64/Release/assets ./soh-windows
- name: Download soh.otr - name: Download soh.otr
uses: actions/download-artifact@v3 uses: actions/download-artifact@v4
with: with:
name: soh.otr name: soh.otr
path: soh-windows path: soh-windows
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: soh-windows name: soh-windows
path: soh-windows path: soh-windows

View File

@ -1 +1 @@
libsdl2 +universal libpng +universal glew +universal libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal libzip +universal nlohmann-json +universal tinyxml2 +universal

View File

@ -0,0 +1,66 @@
# todo:
# nlohmann
# tinyxml2
# spdlog
name: test-builds-on-distros
on:
workflow_dispatch: # by request
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
matrix:
image: ["archlinux:base", "opensuse/tumbleweed:latest", "ubuntu:mantic", "debian:bookworm", "fedora:39"]
cc: ["gcc", "clang"]
include:
- cxx: g++
cc: gcc
- cxx: clang++
cc: clang
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
container:
image: ${{ matrix.image }}
steps:
- name: Install dependencies (pacman)
if: ${{ matrix.image == 'archlinux:base' }}
run: |
echo arch
echo pacman -S ${{ matrix.cc }} git cmake ninja lsb-release sdl2 libpng libzip sdl2_net boost
pacman -Syu --noconfirm
pacman -S --noconfirm ${{ matrix.cc }} git cmake ninja lsb-release sdl2 libpng libzip sdl2_net boost
- name: Install dependencies (dnf)
if: ${{ matrix.image == 'fedora:39' }}
run: |
echo fedora
echo dnf install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools boost-devel
dnf -y upgrade
dnf -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools boost-devel
- name: Install dependencies (apt)
if: ${{ matrix.image == 'ubuntu:mantic' || matrix.image == 'debian:bookworm' }}
run: |
echo debian based
echo apt-get install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'g++') || '' }} git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool libboost-dev libopengl-dev
apt-get update
apt-get -y full-upgrade
apt-get -y install ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'g++') || '' }} git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool libboost-dev libopengl-dev
- name: Install dependencies (zypper)
if: ${{ matrix.image == 'opensuse/tumbleweed:latest' }}
run: |
echo openSUSE
echo zypper in ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} ${{ matrix.cc == 'clang' && 'libstdc++-devel' || '' }} git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools
zypper --non-interactive dup
zypper --non-interactive in ${{ matrix.cc }} ${{ (matrix.cxx == 'g++' && 'gcc-c++') || '' }} ${{ matrix.cc == 'clang' && 'libstdc++-devel' || '' }} git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools
- uses: actions/checkout@v3
with:
submodules: true
- name: Build SoH
run: |
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 -DBUILD_REMOTE_CONTROL=1
cmake --build build-cmake --config Release -j3
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}

2
.gitignore vendored
View File

@ -448,5 +448,5 @@ _packages
*/extract_assets_cmake* */extract_assets_cmake*
/build* /build*
soh/build.c soh/src/boot/build.c
soh/properties.h soh/properties.h

View File

@ -8,5 +8,9 @@ if(MSVC)
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") 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_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() endif()

24
CMake/lus-cvars.cmake Normal file
View File

@ -0,0 +1,24 @@
set(CVAR_VSYNC_ENABLED "${CVAR_PREFIX_SETTING}.VsyncEnabled" CACHE STRING "")
set(CVAR_Z_FIGHTING_MODE "${CVAR_PREFIX_SETTING}.ZFightingMode" CACHE STRING "")
set(CVAR_NEW_FILE_DROPPED "${CVAR_PREFIX_GENERAL}.NewFileDropped" CACHE STRING "")
set(CVAR_DROPPED_FILE "${CVAR_PREFIX_GENERAL}.DroppedFile" CACHE STRING "")
set(CVAR_INTERNAL_RESOLUTION "${CVAR_PREFIX_SETTING}.InternalResolution" CACHE STRING "")
set(CVAR_MSAA_VALUE "${CVAR_PREFIX_SETTING}.MSAAValue" CACHE STRING "")
set(CVAR_SDL_WINDOWED_FULLSCREEN "${CVAR_PREFIX_SETTING}.SdlWindowedFullscreen" CACHE STRING "")
set(CVAR_TEXTURE_FILTER "${CVAR_PREFIX_SETTING}.TextureFilter" CACHE STRING "")
set(CVAR_IMGUI_CONTROLLER_NAV "${CVAR_PREFIX_SETTING}.ControlNav" CACHE STRING "")
set(CVAR_CONSOLE_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.Console" CACHE STRING "")
set(CVAR_CONTROLLER_CONFIGURATION_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.ControllerConfiguration" CACHE STRING "")
set(CVAR_CONTROLLER_DISCONNECTED_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.ControllerDisconnected" CACHE STRING "")
set(CVAR_CONTROLLER_REORDERING_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.ControllerReordering" CACHE STRING "")
set(CVAR_GFX_DEBUGGER_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.GfxDebugger" CACHE STRING "")
set(CVAR_STATS_WINDOW_OPEN "${CVAR_PREFIX_WINDOW}.Stats" CACHE STRING "")
set(CVAR_ENABLE_MULTI_VIEWPORTS "${CVAR_PREFIX_SETTING}.EnableMultiViewports" CACHE STRING "")
set(CVAR_LOW_RES_MODE "${CVAR_PREFIX_SETTING}.LowResMode" CACHE STRING "")
set(CVAR_SIMULATED_INPUT_LAG "${CVAR_PREFIX_SETTING}.SimulatedInputLag" CACHE STRING "")
set(CVAR_ALT_ASSETS "${CVAR_PREFIX_ENHANCEMENT}.AltAssets" CACHE STRING "")
set(CVAR_GAME_OVERLAY_FONT "${CVAR_PREFIX_SETTING}.OverlayFont" CACHE STRING "")
set(CVAR_MENU_BAR_OPEN "${CVAR_PREFIX_SETTING}.OpenMenuBar" CACHE STRING "")
set(CVAR_PREFIX_CONTROLLERS "${CVAR_PREFIX_SETTING}.Controllers" CACHE STRING "")
set(CVAR_PREFIX_ADVANCED_RESOLUTION "${CVAR_PREFIX_SETTING}.AdvancedResolution" CACHE STRING "")
include("libultraship/cmake/cvars.cmake")

26
CMake/soh-cvars.cmake Normal file
View File

@ -0,0 +1,26 @@
set(CVAR_PREFIX_RANDOMIZER_ENHANCEMENT "gRandoEnhancements")
set(CVAR_PREFIX_RANDOMIZER_SETTING "gRandoSettings")
set(CVAR_PREFIX_COSMETIC "gCosmetics")
set(CVAR_PREFIX_AUDIO "gAudioEditor")
set(CVAR_PREFIX_CHEAT "gCheats")
set(CVAR_PREFIX_ENHANCEMENT "gEnhancements")
set(CVAR_PREFIX_SETTING "gSettings")
set(CVAR_PREFIX_WINDOW "gOpenWindows")
set(CVAR_PREFIX_TRACKER "gTrackers")
set(CVAR_PREFIX_DEVELOPER_TOOLS "gDeveloperTools")
set(CVAR_PREFIX_GENERAL "gGeneral")
set(CVAR_PREFIX_REMOTE "gRemote")
add_compile_definitions(
CVAR_PREFIX_RANDOMIZER_ENHANCEMENT="${CVAR_PREFIX_RANDOMIZER_ENHANCEMENT}"
CVAR_PREFIX_RANDOMIZER_SETTING="${CVAR_PREFIX_RANDOMIZER_SETTING}"
CVAR_PREFIX_COSMETIC="${CVAR_PREFIX_COSMETIC}"
CVAR_PREFIX_AUDIO="${CVAR_PREFIX_AUDIO}"
CVAR_PREFIX_CHEAT="${CVAR_PREFIX_CHEAT}"
CVAR_PREFIX_ENHANCEMENT="${CVAR_PREFIX_ENHANCEMENT}"
CVAR_PREFIX_SETTING="${CVAR_PREFIX_SETTING}"
CVAR_PREFIX_WINDOW="${CVAR_PREFIX_WINDOW}"
CVAR_PREFIX_TRACKER="${CVAR_PREFIX_TRACKER}"
CVAR_PREFIX_DEVELOPER_TOOLS="${CVAR_PREFIX_DEVELOPER_TOOLS}"
CVAR_PREFIX_GENERAL="${CVAR_PREFIX_GENERAL}"
CVAR_PREFIX_REMOTE="${CVAR_PREFIX_REMOTE}"
)

View File

@ -6,6 +6,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
project(Ship VERSION 8.0.5 LANGUAGES C CXX) project(Ship VERSION 8.0.5 LANGUAGES C CXX)
include(CMake/soh-cvars.cmake)
include(CMake/lus-cvars.cmake)
set(PROJECT_BUILD_NAME "MacReady Foxtrot" CACHE STRING "") set(PROJECT_BUILD_NAME "MacReady Foxtrot" CACHE STRING "")
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
@ -13,20 +15,18 @@ set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>) add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/utf-8>) add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
if (CMAKE_SYSTEM_NAME MATCHES "Windows|Linux")
if(NOT DEFINED BUILD_CROWD_CONTROL)
set(BUILD_CROWD_CONTROL ON)
endif()
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows") if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(CMake/automate-vcpkg.cmake) include(CMake/automate-vcpkg.cmake)
set(VCPKG_TRIPLET x64-windows-static) set(VCPKG_TRIPLET x64-windows-static)
set(VCPKG_TARGET_TRIPLET x64-windows-static) set(VCPKG_TARGET_TRIPLET x64-windows-static)
vcpkg_bootstrap() vcpkg_bootstrap()
vcpkg_install_packages(zlib bzip2 libpng sdl2 sdl2-net glew glfw3) vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog)
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
endif()
endif() endif()
################################################################################ ################################################################################

@ -1 +1 @@
Subproject commit 04b85b95fab07a394b62dcd28a502a3040f08e0c Subproject commit 3cea9ee7c017d842aa4d9ceeb8d3ffbf29c6effb

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) * [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) * [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 (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) * [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) * [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip)

2
ZAPDTR

@ -1 +1 @@
Subproject commit eff29036118349e142ee8efca80fd975a2a2b6ff Subproject commit f38a9c92eb99368c0607acf356d5651ebdc96f51

View File

@ -84,41 +84,66 @@ cd "build/x64"
``` ```
## Linux ## Linux
Requires `gcc >= 10, x11, curl, python3, sdl2 >= 2.0.22, libpng, glew >= 2.2, ninja, cmake, lld, pulseaudio-libs` ### Install dependencies
#### Debian/Ubuntu
```sh
# using gcc
apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool libboost-dev libopengl-dev
**Important: For maximum performance make sure you have ninja build tools installed!** # or using clang
apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool libboost-dev libopengl-dev
```
#### Arch
```sh
# using gcc
pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip sdl2_net boost
_Note: If you're using Visual Studio Code, the [cpack plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._ # or using clang
pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip sdl2_net boost
```
#### Fedora
```sh
# using gcc
dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools boost-devel
# or using clang
dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools boost-devel
```
#### openSUSE
```sh
# using gcc
zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools
# or using clang
zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools
```
### Build
_Note: If you're using Visual Studio Code, the [CMake Tools plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._
```bash ```bash
# Clone the repo # Clone the repo and enter the directory
git clone https://github.com/HarbourMasters/Shipwright.git git clone https://github.com/HarbourMasters/Shipwright.git
cd Shipwright cd Shipwright
# Clone the submodule libultraship
# Clone the submodules
git submodule update --init git submodule update --init
# Copy the baserom to the OTRExporter folder
cp <path to your ROM> OTRExporter
# Generate Ninja project # Generate Ninja project
cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -DPython3_EXECUTABLE=$(which python3) (if you are using non-standard Python installations such as PyEnv) cmake -H. -Bbuild-cmake -GNinja # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging) -DPython3_EXECUTABLE=$(which python3) (if you are using non-standard Python installations such as PyEnv)
# Extract assets & generate OTR (run this anytime you need to regenerate OTR)
cmake --build build-cmake --target ExtractAssets # Generate soh.otr
cmake --build build-cmake --target GenerateSohOtr
# Compile the project # Compile the project
cmake --build build-cmake # --config Release (if you're packaging) cmake --build build-cmake # --config Release (if you're packaging)
# Now you can run the executable in ./build-cmake/soh/soh.elf # Now you can run the executable in ./build-cmake/soh/soh.elf
# To develop the project open the repository in VSCode (or your preferred editor) # To develop the project open the repository in VSCode (or your preferred editor)
# If you need to clean the project you can run
cmake --build build-cmake --target clean
# If you need to regenerate the asset headers to check them into source
cmake --build build-cmake --target ExtractAssetHeaders
# If you need a newer soh.otr only
cmake --build build-cmake --target GenerateSohOtr
``` ```
### Generating a distributable ### Generate a distributable
After compiling the project you can generate a distributable by running of the following: After compiling the project you can generate a distributable by running of the following:
```bash ```bash
# Go to build folder # Go to build folder
@ -129,6 +154,20 @@ cpack -G ZIP
cpack -G External (creates appimage) cpack -G External (creates appimage)
``` ```
### Additional CMake Targets
#### Clean
```bash
# If you need to clean the project you can run
cmake --build build-cmake --target clean
```
#### Regenerate Asset Headers
```bash
# If you need to regenerate the asset headers to check them into source
cp <path to your ROM> OTRExporter
cmake --build build-cmake --target ExtractAssetHeaders
```
## macOS ## macOS
Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc) Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc)

View File

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

@ -1 +1 @@
Subproject commit 96c8a8929c18c1bffd7d92a35a589f74cf16fc59 Subproject commit 7d71a290657a2d3b09a83e8b33025e807f4fb38e

View File

@ -21,12 +21,17 @@ fi
while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do
for romfile in "$SHIP_HOME"/*.*64 for romfile in "$SHIP_HOME"/*.*64
do do
if [[ -e $romfile ]]; then if [[ -e "$romfile" ]] || [[ -L "$romfile" ]]; then
export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)"
ln -s "$HERE"/usr/bin/{assets,soh.elf,ZAPD} "$ASSETDIR" ln -s "$SHIP_BIN_DIR"/{assets,soh.elf,ZAPD} "$ASSETDIR"
export OLDPWD="$PWD" export OLDPWD="$PWD"
mkdir -p "$ASSETDIR"/tmp mkdir -p "$ASSETDIR"/tmp
ln -s "$romfile" "$ASSETDIR"/tmp/rom.z64 if [[ -e "$romfile" ]]; then
ln -s "$romfile" "$ASSETDIR"/tmp/rom.z64
else
ORIG_ROM_PATH=$(readlink "$romfile")
ln -s "$ORIG_ROM_PATH" "$ASSETDIR"/tmp/rom.z64
fi
cd "$ASSETDIR" cd "$ASSETDIR"
ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }') ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')

View File

@ -8,5 +8,9 @@ if(MSVC)
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") 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_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() endif()

View File

@ -92,10 +92,6 @@ if (NOT TARGET libultraship)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libultraship ${CMAKE_BINARY_DIR}/libultraship) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libultraship ${CMAKE_BINARY_DIR}/libultraship)
endif() endif()
if (NOT TARGET ZAPDUtils)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils ${CMAKE_BINARY_DIR}/ZAPDUtils)
endif()
if (NOT TARGET ZAPDLib) if (NOT TARGET ZAPDLib)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD)
endif() endif()
@ -105,8 +101,8 @@ set(PROJECT_NAME soh)
################################################################################ ################################################################################
# Sources # Sources
################################################################################ ################################################################################
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/build.c.in ${CMAKE_BINARY_DIR}/build.c @ONLY) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/build.c.in ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/build.c @ONLY)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/properties.h.in ${CMAKE_CURRENT_SOURCE_DIR}/properties.h @ONLY) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/properties.h.in ${CMAKE_CURRENT_SOURCE_DIR}/properties.h @ONLY)
set(Header_Files "resource.h") set(Header_Files "resource.h")
source_group("headers" FILES ${Header_Files}) source_group("headers" FILES ${Header_Files})
@ -154,7 +150,7 @@ list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/gfx.*")
# handle crowd control removals # handle crowd control removals
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs") list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs")
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak") list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak")
if (!BUILD_CROWD_CONTROL) if (!BUILD_REMOTE_CONTROL)
list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*") list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*")
endif() endif()
@ -217,8 +213,6 @@ source_group("soh\\resource\\importer\\scenecommand" REGULAR_EXPRESSION "soh/res
# src (decomp) {{{ # src (decomp) {{{
file(GLOB_RECURSE src__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.c" "src/*.h") file(GLOB_RECURSE src__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.c" "src/*.h")
list(APPEND src__ ${CMAKE_BINARY_DIR}/build.c)
list(APPEND src__ ${CMAKE_CURRENT_SOURCE_DIR}/properties.h)
list(APPEND src__ ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc) list(APPEND src__ ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc)
list(FILTER src__ EXCLUDE REGEX "src/dmadata/*") list(FILTER src__ EXCLUDE REGEX "src/dmadata/*")
list(FILTER src__ EXCLUDE REGEX "src/elf_message/*") list(FILTER src__ EXCLUDE REGEX "src/elf_message/*")
@ -238,7 +232,6 @@ list(REMOVE_ITEM src__ "src/libultra/gu/sqrtf.c")
list(REMOVE_ITEM src__ "src/libultra/gu/us2dex.c") list(REMOVE_ITEM src__ "src/libultra/gu/us2dex.c")
source_group("src" REGULAR_EXPRESSION "src/*") source_group("src" REGULAR_EXPRESSION "src/*")
source_group("src\\build" FILES ${CMAKE_BINARY_DIR}/build.c ${CMAKE_CURRENT_SOURCE_DIR}/properties.h ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc)
source_group("src\\boot" REGULAR_EXPRESSION "src/boot/*") source_group("src\\boot" REGULAR_EXPRESSION "src/boot/*")
source_group("src\\buffers" REGULAR_EXPRESSION "src/buffers/*") source_group("src\\buffers" REGULAR_EXPRESSION "src/buffers/*")
source_group("src\\code" REGULAR_EXPRESSION "src/code/*") source_group("src\\code" REGULAR_EXPRESSION "src/code/*")
@ -354,9 +347,15 @@ endif()
find_package(SDL2) find_package(SDL2)
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS}) set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
if (BUILD_CROWD_CONTROL) if (BUILD_REMOTE_CONTROL)
find_package(SDL2_net) find_package(SDL2_net)
set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS})
if(NOT SDL2_net_FOUND)
message(STATUS "SDL2_net not found (it's possible the version installed is too old). Disabling BUILD_REMOTE_CONTROL.")
set(BUILD_REMOTE_CONTROL 0)
else()
set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS})
endif()
endif() endif()
target_include_directories(${PROJECT_NAME} PRIVATE assets target_include_directories(${PROJECT_NAME} PRIVATE assets
@ -385,10 +384,8 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern/tinyxml2 ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern/tinyxml2
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/ ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/libjpeg/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/libjpeg/include/
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/spdlog/include/
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic/Fast3D/U64/PR ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic/Fast3D/U64/PR
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD/resource/type ${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD/resource/type
${SDL2-INCLUDE} ${SDL2-INCLUDE}
${SDL2-NET-INCLUDE} ${SDL2-NET-INCLUDE}
@ -408,13 +405,13 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"$<$<CONFIG:Release>:" "$<$<CONFIG:Release>:"
"NDEBUG" "NDEBUG"
">" ">"
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>" "$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
"INCLUDE_GAME_PRINTF;" "INCLUDE_GAME_PRINTF;"
"ENABLE_CROWD_CONTROL;"
"UNICODE;" "UNICODE;"
"_UNICODE" "_UNICODE"
STORMLIB_NO_AUTO_LINK STORMLIB_NO_AUTO_LINK
"_CRT_SECURE_NO_WARNINGS;" "_CRT_SECURE_NO_WARNINGS;"
NOMINMAX
) )
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
target_compile_definitions(${PROJECT_NAME} PRIVATE target_compile_definitions(${PROJECT_NAME} PRIVATE
@ -432,6 +429,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"UNICODE;" "UNICODE;"
"_UNICODE" "_UNICODE"
STORMLIB_NO_AUTO_LINK STORMLIB_NO_AUTO_LINK
NOMINMAX
) )
endif() endif()
elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS") elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
@ -455,7 +453,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
"$<$<CONFIG:Release>:" "$<$<CONFIG:Release>:"
"NDEBUG" "NDEBUG"
">" ">"
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>" "$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
"SPDLOG_ACTIVE_LEVEL=0;" "SPDLOG_ACTIVE_LEVEL=0;"
"_CONSOLE;" "_CONSOLE;"
"_CRT_SECURE_NO_WARNINGS;" "_CRT_SECURE_NO_WARNINGS;"
@ -624,6 +622,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
-Wno-parentheses -Wno-parentheses
-Wno-narrowing -Wno-narrowing
-Wno-missing-braces -Wno-missing-braces
-Wno-int-conversion
-Wno-implicit-int
$<$<COMPILE_LANGUAGE:C>: $<$<COMPILE_LANGUAGE:C>:
-Werror-implicit-function-declaration -Werror-implicit-function-declaration
-Wno-incompatible-pointer-types -Wno-incompatible-pointer-types
@ -643,15 +643,6 @@ endif()
################################################################################ ################################################################################
# Pre build events # Pre build events
################################################################################ ################################################################################
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_custom_command_if(
TARGET ${PROJECT_NAME}
PRE_BUILD
COMMANDS
COMMAND $<CONFIG:Debug> copy /b $<SHELL_PATH:${CMAKE_BINARY_DIR}/>build.c +,,
)
endif()
if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
@ -670,7 +661,6 @@ endif()
# Dependencies # Dependencies
################################################################################ ################################################################################
add_dependencies(${PROJECT_NAME} add_dependencies(${PROJECT_NAME}
ZAPDUtils
libultraship libultraship
) )
if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
@ -684,12 +674,11 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
set(ADDITIONAL_LIBRARY_DEPENDENCIES set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;" "libultraship;"
"ZAPDUtils;"
"ZAPDLib;" "ZAPDLib;"
"glu32;" "glu32;"
"SDL2::SDL2;" "SDL2::SDL2;"
"SDL2::SDL2main;" "SDL2::SDL2main;"
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net-static>" "$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net-static>"
"glfw;" "glfw;"
"winmm;" "winmm;"
"imm32;" "imm32;"
@ -699,7 +688,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
set(ADDITIONAL_LIBRARY_DEPENDENCIES set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;" "libultraship;"
"ZAPDUtils;"
"ZAPDLib;" "ZAPDLib;"
"glu32;" "glu32;"
"SDL2::SDL2;" "SDL2::SDL2;"
@ -717,7 +705,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;" "libultraship;"
"ZAPDUtils;"
SDL2::SDL2 SDL2::SDL2
-lglad -lglad
Threads::Threads Threads::Threads
@ -739,10 +726,9 @@ else()
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;" "libultraship;"
"ZAPDUtils;"
"ZAPDLib;" "ZAPDLib;"
SDL2::SDL2 SDL2::SDL2
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net>" "$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
${CMAKE_DL_LIBS} ${CMAKE_DL_LIBS}
Threads::Threads Threads::Threads
) )

View File

@ -28,4 +28,10 @@
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application> </application>
</compatibility> </compatibility>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- legacy -->
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to pm if pmv2 is not available -->
</asmv3:windowsSettings>
</asmv3:application>
</assembly> </assembly>

View File

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

View File

@ -1,5 +1,5 @@
{ {
"0": "Abre Mojo", "0": "Arbre Mojo",
"1": "Caverne Dodongo", "1": "Caverne Dodongo",
"2": "Ventre de Jabu-Jabu", "2": "Ventre de Jabu-Jabu",
"3": "Temple de la Forêt", "3": "Temple de la Forêt",
@ -58,9 +58,9 @@
"56": "Laboratoire du Lac", "56": "Laboratoire du Lac",
"57": "", // Tente du Marathonien (No title card) "57": "", // Tente du Marathonien (No title card)
"58": "Cabane du fossoyeur", "58": "Cabane du fossoyeur",
"59": "Fountaine Royale des Fées", "59": "Fontaine Royale des Fées",
"60": "Fountaine des Fées", "60": "Fontaine des Fées",
"61": "Fountaine Royale des Fées", "61": "Fontaine Royale des Fées",
"62": "", // Grottes (No title card) "62": "", // Grottes (No title card)
"63": "", // Tombe 1 (No title card) "63": "", // Tombe 1 (No title card)
"64": "", // Tombe 2 (No title card) "64": "", // Tombe 2 (No title card)
@ -109,4 +109,4 @@
"107": "", "107": "",
"108": "", // Debug: SRD Room (No title card) "108": "", // Debug: SRD Room (No title card)
"109": "" // Debug: Treasure Chest Warp (No title card) "109": "" // Debug: Treasure Chest Warp (No title card)
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

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

@ -1230,8 +1230,8 @@ Gfx* Gfx_EnvColor(GraphicsContext* gfxCtx, s32 r, s32 g, s32 b, s32 a);
void Gfx_SetupFrame(GraphicsContext* gfxCtx, u8 r, u8 g, u8 b); void Gfx_SetupFrame(GraphicsContext* gfxCtx, u8 r, u8 g, u8 b);
void func_80095974(GraphicsContext* gfxCtx); void func_80095974(GraphicsContext* gfxCtx);
void func_80095AA0(PlayState* play, Room* room, Input* arg2, UNK_TYPE arg3); void func_80095AA0(PlayState* play, Room* room, Input* arg2, UNK_TYPE arg3);
void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 mode0, void Room_DrawBackground2D(Gfx** gfxP, void* tex, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 tlutMode,
u16 tlutCount, f32 frameX, f32 frameY); u16 tlutCount, f32 offsetX, f32 offsetY);
void func_80096FD4(PlayState* play, Room* room); void func_80096FD4(PlayState* play, Room* room);
u32 func_80096FE8(PlayState* play, RoomContext* roomCtx); u32 func_80096FE8(PlayState* play, RoomContext* roomCtx);
s32 func_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum); s32 func_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum);
@ -1250,7 +1250,7 @@ s32 Object_IsLoaded(ObjectContext* objectCtx, s32 bankIndex);
void func_800981B8(ObjectContext* objectCtx); void func_800981B8(ObjectContext* objectCtx);
s32 Scene_ExecuteCommands(PlayState* play, SceneCmd* sceneCmd); s32 Scene_ExecuteCommands(PlayState* play, SceneCmd* sceneCmd);
void TransitionActor_InitContext(GameState* state, TransitionActorContext* transiActorCtx); void TransitionActor_InitContext(GameState* state, TransitionActorContext* transiActorCtx);
void func_800994A0(PlayState* play); void Scene_SetTransitionForNextEntrance(PlayState* play);
void Scene_Draw(PlayState* play); void Scene_Draw(PlayState* play);
void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable, void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable,
OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg, s32 dListIndex); OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg, s32 dListIndex);
@ -1537,7 +1537,7 @@ void KaleidoScopeCall_Draw(PlayState* play);
void func_800BC490(PlayState* play, s16 point); void func_800BC490(PlayState* play, s16 point);
s32 func_800BC56C(PlayState* play, s16 arg1); s32 func_800BC56C(PlayState* play, s16 arg1);
void func_800BC590(PlayState* play); void func_800BC590(PlayState* play);
void func_800BC5E0(PlayState* play, s32 arg1); void Gameplay_SetupTransition(PlayState* play, s32 arg1);
Gfx* Play_SetFog(PlayState* play, Gfx* gfx); Gfx* Play_SetFog(PlayState* play, Gfx* gfx);
void Play_Destroy(GameState* thisx); void Play_Destroy(GameState* thisx);
void Play_Init(GameState* thisx); void Play_Init(GameState* thisx);
@ -1828,8 +1828,8 @@ MtxF* Matrix_CheckFloats(MtxF* mf, char* file, s32 line);
void Matrix_SetTranslateScaleMtx2(Mtx* mtx, f32 scaleX, f32 scaleY, f32 scaleZ, f32 translateX, f32 translateY, void Matrix_SetTranslateScaleMtx2(Mtx* mtx, f32 scaleX, f32 scaleY, f32 scaleZ, f32 translateX, f32 translateY,
f32 translateZ); f32 translateZ);
uintptr_t SysUcode_GetUCodeBoot(void); uintptr_t SysUcode_GetUCodeBoot(void);
uintptr_t SysUcode_GetUCodeBootSize(void); size_t SysUcode_GetUCodeBootSize(void);
uintptr_t SysUcode_GetUCode(void); uint32_t SysUcode_GetUCode(void);
uintptr_t SysUcode_GetUCodeData(void); uintptr_t SysUcode_GetUCodeData(void);
void func_800D2E30(UnkRumbleStruct* arg0); void func_800D2E30(UnkRumbleStruct* arg0);
void func_800D3140(UnkRumbleStruct* arg0); void func_800D3140(UnkRumbleStruct* arg0);
@ -2171,7 +2171,7 @@ void func_800FA18C(u8, u8);
void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer); void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer);
void func_800FA3DC(void); void func_800FA3DC(void);
u8 func_800FAD34(void); u8 func_800FAD34(void);
void func_800FADF8(void); void Audio_ResetActiveSequences(void);
void func_800FAEB4(void); void func_800FAEB4(void);
void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a); void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a);
void GfxPrint_SetPosPx(GfxPrint* this, s32 x, s32 y); void GfxPrint_SetPosPx(GfxPrint* this, s32 x, s32 y);
@ -2210,6 +2210,14 @@ s8 PadUtils_GetRelYImpl(Input* input);
s8 PadUtils_GetRelX(Input* input); s8 PadUtils_GetRelX(Input* input);
s8 PadUtils_GetRelY(Input* input); s8 PadUtils_GetRelY(Input* input);
void PadUtils_UpdateRelXY(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); s32 PadSetup_Init(OSMesgQueue* mq, u8* outMask, OSContStatus* status);
f32 Math_FTanF(f32 x); f32 Math_FTanF(f32 x);
f32 Math_FFloorF(f32 x); f32 Math_FFloorF(f32 x);
@ -2459,6 +2467,10 @@ void Message_DrawText(PlayState* play, Gfx** gfxP);
void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH); void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH);
void Interface_RandoRestoreSwordless(void); void Interface_RandoRestoreSwordless(void);
//Pause Warp
void PauseWarp_HandleSelection();
void PauseWarp_Execute();
// #endregion // #endregion
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -86,6 +86,8 @@
#define R_ITEM_ICON_X(i) ZREG(82 + i) #define R_ITEM_ICON_X(i) ZREG(82 + i)
#define R_ITEM_ICON_Y(i) ZREG(86 + i) #define R_ITEM_ICON_Y(i) ZREG(86 + i)
#define R_ITEM_ICON_DD(i) ZREG(90 + i) #define R_ITEM_ICON_DD(i) ZREG(90 + i)
#define R_TRANS_DBG_ENABLED CREG(11)
#define R_TRANS_DBG_TYPE CREG(12)
#define R_ENV_WIND_DIR(i) CREG(16 + i) #define R_ENV_WIND_DIR(i) CREG(16 + i)
#define R_ENV_WIND_SPEED CREG(19) #define R_ENV_WIND_SPEED CREG(19)
#define R_A_BTN_Y XREG(16) #define R_A_BTN_Y XREG(16)

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,7 @@ extern "C"
extern s16 gLinkObjectIds[2]; extern s16 gLinkObjectIds[2];
extern u32 gObjectTableSize; extern u32 gObjectTableSize;
extern RomFile gObjectTable[OBJECT_ID_MAX]; extern RomFile gObjectTable[OBJECT_ID_MAX];
extern EntranceInfo gEntranceTable[1556]; extern EntranceInfo gEntranceTable[ENTR_MAX];
extern SceneTableEntry gSceneTable[SCENE_ID_MAX]; extern SceneTableEntry gSceneTable[SCENE_ID_MAX];
extern u16 gSramSlotOffsets[]; extern u16 gSramSlotOffsets[];
// 4 16-colors palettes // 4 16-colors palettes
@ -224,7 +224,7 @@ extern "C"
extern u16 gAudioSfxSwapSource[10]; extern u16 gAudioSfxSwapSource[10];
extern u16 gAudioSfxSwapTarget[10]; extern u16 gAudioSfxSwapTarget[10];
extern u8 gAudioSfxSwapMode[10]; extern u8 gAudioSfxSwapMode[10];
extern unk_D_8016E750 D_8016E750[4]; extern ActiveSequence gActiveSeqs[4];
extern AudioContext gAudioContext; extern AudioContext gAudioContext;
extern void(*D_801755D0)(void); extern void(*D_801755D0)(void);

View File

@ -1122,6 +1122,82 @@ typedef struct {
/* 0x4C */ u32 unk_4C; /* 0x4C */ u32 unk_4C;
} PreRender; // size = 0x50 } PreRender; // size = 0x50
#define TRANS_TRIGGER_OFF 0 // transition is not active
#define TRANS_TRIGGER_START 20 // start transition (exiting an area)
#define TRANS_TRIGGER_END -20 // transition is ending (arriving in a new area)
typedef enum {
/* 0 */ TRANS_MODE_OFF,
/* 1 */ TRANS_MODE_SETUP,
/* 2 */ TRANS_MODE_INSTANCE_INIT,
/* 3 */ TRANS_MODE_INSTANCE_RUNNING,
/* 4 */ TRANS_MODE_FILL_WHITE_INIT,
/* 5 */ TRANS_MODE_FILL_IN,
/* 6 */ TRANS_MODE_FILL_OUT,
/* 7 */ TRANS_MODE_FILL_BROWN_INIT,
/* 8 */ TRANS_MODE_08, // unused
/* 9 */ TRANS_MODE_09, // unused
/* 10 */ TRANS_MODE_INSTANT,
/* 11 */ TRANS_MODE_INSTANCE_WAIT,
/* 12 */ TRANS_MODE_SANDSTORM_INIT,
/* 13 */ TRANS_MODE_SANDSTORM,
/* 14 */ TRANS_MODE_SANDSTORM_END_INIT,
/* 15 */ TRANS_MODE_SANDSTORM_END,
/* 16 */ TRANS_MODE_CS_BLACK_FILL_INIT,
/* 17 */ TRANS_MODE_CS_BLACK_FILL
} TransitionMode;
typedef enum {
/* 0 */ TRANS_TYPE_WIPE,
/* 1 */ TRANS_TYPE_TRIFORCE,
/* 2 */ TRANS_TYPE_FADE_BLACK,
/* 3 */ TRANS_TYPE_FADE_WHITE,
/* 4 */ TRANS_TYPE_FADE_BLACK_FAST,
/* 5 */ TRANS_TYPE_FADE_WHITE_FAST,
/* 6 */ TRANS_TYPE_FADE_BLACK_SLOW,
/* 7 */ TRANS_TYPE_FADE_WHITE_SLOW,
/* 8 */ TRANS_TYPE_WIPE_FAST,
/* 9 */ TRANS_TYPE_FILL_WHITE2,
/* 10 */ TRANS_TYPE_FILL_WHITE,
/* 11 */ TRANS_TYPE_INSTANT,
/* 12 */ TRANS_TYPE_FILL_BROWN,
/* 13 */ TRANS_TYPE_FADE_WHITE_CS_DELAYED,
/* 14 */ TRANS_TYPE_SANDSTORM_PERSIST,
/* 15 */ TRANS_TYPE_SANDSTORM_END,
/* 16 */ TRANS_TYPE_CS_BLACK_FILL,
/* 17 */ TRANS_TYPE_FADE_WHITE_INSTANT,
/* 18 */ TRANS_TYPE_FADE_GREEN,
/* 19 */ TRANS_TYPE_FADE_BLUE,
// transition types 20 - 31 are unused
// transition types 32 - 55 are constructed using the TRANS_TYPE_CIRCLE macro
/* 56 */ TRANS_TYPE_MAX = 56
} TransitionType;
#define TRANS_NEXT_TYPE_DEFAULT 0xFF // when `nextTransitionType` is set to default, the type will be taken from the entrance table for the ending transition
typedef enum {
/* 0 */ TCA_NORMAL,
/* 1 */ TCA_WAVE,
/* 2 */ TCA_RIPPLE,
/* 3 */ TCA_STARBURST
} TransitionCircleAppearance;
typedef enum {
/* 0 */ TCC_BLACK,
/* 1 */ TCC_WHITE,
/* 2 */ TCC_GRAY,
/* 3 */ TCC_SPECIAL // color varies depending on appearance. unused and appears broken
} TransitionCircleColor;
typedef enum {
/* 0 */ TCS_FAST,
/* 1 */ TCS_SLOW
} TransitionCircleSpeed;
#define TC_SET_PARAMS (1 << 7)
#define TRANS_TYPE_CIRCLE(appearance, color, speed) ((1 << 5) | ((color & 3) << 3) | ((appearance & 3) << 1) | (speed & 1))
typedef struct { typedef struct {
union { union {
TransitionFade fade; TransitionFade fade;
@ -1384,14 +1460,14 @@ typedef struct PlayState {
/* 0x11E0C */ ElfMessage* cUpElfMsgs; /* 0x11E0C */ ElfMessage* cUpElfMsgs;
/* 0x11E10 */ void* specialEffects; /* 0x11E10 */ void* specialEffects;
/* 0x11E14 */ u8 skyboxId; /* 0x11E14 */ u8 skyboxId;
/* 0x11E15 */ s8 sceneLoadFlag; // "fade_direction" /* 0x11E15 */ s8 transitionTrigger; // "fade_direction"
/* 0x11E16 */ s16 unk_11E16; /* 0x11E16 */ s16 unk_11E16;
/* 0x11E18 */ s16 unk_11E18; /* 0x11E18 */ s16 unk_11E18;
/* 0x11E1A */ s16 nextEntranceIndex; /* 0x11E1A */ s16 nextEntranceIndex;
/* 0x11E1C */ char unk_11E1C[0x40]; /* 0x11E1C */ char unk_11E1C[0x40];
/* 0x11E5C */ s8 shootingGalleryStatus; /* 0x11E5C */ s8 shootingGalleryStatus;
/* 0x11E5D */ s8 bombchuBowlingStatus; // "bombchu_game_flag" /* 0x11E5D */ s8 bombchuBowlingStatus; // "bombchu_game_flag"
/* 0x11E5E */ u8 fadeTransition; /* 0x11E5E */ u8 transitionType;
/* 0x11E60 */ CollisionCheckContext colChkCtx; /* 0x11E60 */ CollisionCheckContext colChkCtx;
/* 0x120FC */ u16 envFlags[20]; /* 0x120FC */ u16 envFlags[20];
/* 0x12124 */ PreRender pauseBgPreRender; /* 0x12124 */ PreRender pauseBgPreRender;
@ -1513,6 +1589,20 @@ typedef struct {
uint16_t bossRushArrowOffset; uint16_t bossRushArrowOffset;
} FileChooseContext; // size = 0x1CAE0 } FileChooseContext; // size = 0x1CAE0
// Macros for `EntranceInfo.field`
#define ENTRANCE_INFO_CONTINUE_BGM_FLAG (1 << 15)
#define ENTRANCE_INFO_DISPLAY_TITLE_CARD_FLAG (1 << 14)
#define ENTRANCE_INFO_END_TRANS_TYPE_MASK 0x3F80
#define ENTRANCE_INFO_END_TRANS_TYPE_SHIFT 7
#define ENTRANCE_INFO_END_TRANS_TYPE(field) \
(((field) >> ENTRANCE_INFO_END_TRANS_TYPE_SHIFT) \
& (ENTRANCE_INFO_END_TRANS_TYPE_MASK >> ENTRANCE_INFO_END_TRANS_TYPE_SHIFT))
#define ENTRANCE_INFO_START_TRANS_TYPE_MASK 0x7F
#define ENTRANCE_INFO_START_TRANS_TYPE_SHIFT 0
#define ENTRANCE_INFO_START_TRANS_TYPE(field) \
(((field) >> ENTRANCE_INFO_START_TRANS_TYPE_SHIFT) \
& (ENTRANCE_INFO_START_TRANS_TYPE_MASK >> ENTRANCE_INFO_START_TRANS_TYPE_SHIFT))
typedef enum { typedef enum {
DPM_UNK = 0, DPM_UNK = 0,
DPM_PLAYER = 1, DPM_PLAYER = 1,

View File

@ -970,43 +970,43 @@ typedef struct {
} AudioContextInitSizes; // size = 0xC } AudioContextInitSizes; // size = 0xC
typedef struct { typedef struct {
/* 0x00 */ f32 unk_00; /* 0x00 */ f32 volCur;
/* 0x04 */ f32 unk_04; /* 0x04 */ f32 volTarget;
/* 0x08 */ f32 unk_08; /* 0x08 */ f32 volStep;
/* 0x0C */ u16 unk_0C; /* 0x0C */ u16 volTimer;
/* 0x10 */ f32 unk_10; /* 0x10 */ f32 freqScaleCur;
/* 0x14 */ f32 unk_14; /* 0x14 */ f32 freqScaleTarget;
/* 0x18 */ f32 unk_18; /* 0x18 */ f32 freqScaleStep;
/* 0x1C */ u16 unk_1C; /* 0x1C */ u16 freqScaleTimer;
} unk_50_s; // size = 0x20 } ActiveSequenceChannelData; // size = 0x20
typedef struct { typedef struct {
/* 0x000 */ f32 volCur; /* 0x000 */ f32 volCur;
/* 0x004 */ f32 volTarget; /* 0x004 */ f32 volTarget;
/* 0x008 */ f32 unk_08; /* 0x008 */ f32 volStep;
/* 0x00C */ u16 unk_0C; /* 0x00C */ u16 volTimer;
/* 0x00E */ u8 volScales[0x4]; /* 0x00E */ u8 volScales[4];
/* 0x012 */ u8 volFadeTimer; /* 0x012 */ u8 volFadeTimer;
/* 0x013 */ u8 fadeVolUpdate; /* 0x013 */ u8 fadeVolUpdate;
/* 0x014 */ u32 unk_14; /* 0x014 */ u32 tempoCmd;
/* 0x018 */ u16 unk_18; /* 0x018 */ u16 tempoOriginal; // stores the original tempo before modifying it (to reset back to)
/* 0x01C */ f32 unk_1C; /* 0x01C */ f32 tempoCur;
/* 0x020 */ f32 unk_20; /* 0x020 */ f32 tempoTarget;
/* 0x024 */ f32 unk_24; /* 0x024 */ f32 tempoStep;
/* 0x028 */ u16 unk_28; /* 0x028 */ u16 tempoTimer;
/* 0x02C */ u32 unk_2C[8]; /* 0x02C */ u32 setupCmd[8]; // a queue of cmds to execute once the player is disabled
/* 0x04C */ u8 unk_4C; /* 0x04C */ u8 setupCmdTimer; // only execute setup commands when the timer is at 0.
/* 0x04D */ u8 unk_4D; /* 0x04D */ u8 setupCmdNum; // number of setup commands requested once the player is disabled
/* 0x04E */ u8 unk_4E; /* 0x04E */ u8 setupFadeTimer;
/* 0x050 */ unk_50_s unk_50[0x10]; /* 0x050 */ ActiveSequenceChannelData channelData[16];
/* 0x250 */ u16 unk_250; /* 0x250 */ u16 freqScaleChannelFlags;
/* 0x252 */ u16 unk_252; /* 0x252 */ u16 volChannelFlags;
/* 0x254 */ u16 unk_254; /* 0x254 */ u16 seqId; // active seqId currently playing. Resets when sequence stops
/* 0x256 */ u16 unk_256; /* 0x256 */ u16 prevSeqId; // last seqId played on a player. Does not reset when sequence stops
/* 0x258 */ u16 unk_258; /* 0x258 */ u16 channelPortMask;
/* 0x25C */ u32 unk_25C; /* 0x25C */ u32 startSeqCmd; // This name comes from MM
/* 0x260 */ u8 unk_260; /* 0x260 */ u8 isWaitingForFonts; // This name comes from MM
} unk_D_8016E750; // size = 0x264 } ActiveSequence; // size = 0x264
typedef enum { typedef enum {
/* 0 */ BANK_PLAYER, /* 0 */ BANK_PLAYER,

View File

@ -30,6 +30,14 @@ typedef enum {
/* 13 */ SKYBOX_DMA_PAL2_START /* 13 */ SKYBOX_DMA_PAL2_START
} SkyboxDmaState; } SkyboxDmaState;
typedef enum {
/* 0 */ SANDSTORM_OFF,
/* 1 */ SANDSTORM_FILL,
/* 2 */ SANDSTORM_UNFILL,
/* 3 */ SANDSTORM_ACTIVE,
/* 4 */ SANDSTORM_DISSIPATE
} SandstormState;
typedef struct { typedef struct {
/* 0x00 */ u8 state; /* 0x00 */ u8 state;
/* 0x01 */ u8 flashRed; /* 0x01 */ u8 flashRed;

View File

@ -132,16 +132,6 @@ typedef enum {
/* 0x40 */ PLAYER_IA_MASK_GERUDO, /* 0x40 */ PLAYER_IA_MASK_GERUDO,
/* 0x41 */ PLAYER_IA_MASK_TRUTH, /* 0x41 */ PLAYER_IA_MASK_TRUTH,
/* 0x42 */ PLAYER_IA_LENS_OF_TRUTH, /* 0x42 */ PLAYER_IA_LENS_OF_TRUTH,
// Upstream TODO: Document why these entries were added
/* 0x43 */ PLAYER_IA_SHIELD_DEKU,
/* 0x44 */ PLAYER_IA_SHIELD_HYLIAN,
/* 0x45 */ PLAYER_IA_SHIELD_MIRROR,
/* 0x46 */ PLAYER_IA_TUNIC_KOKIRI,
/* 0x47 */ PLAYER_IA_TUNIC_GORON,
/* 0x48 */ PLAYER_IA_TUNIC_ZORA,
/* 0x49 */ PLAYER_IA_BOOTS_KOKIRI,
/* 0x4A */ PLAYER_IA_BOOTS_IRON,
/* 0x4B */ PLAYER_IA_BOOTS_HOVER,
/* 0x4C */ PLAYER_IA_MAX /* 0x4C */ PLAYER_IA_MAX
} PlayerItemAction; } PlayerItemAction;
@ -355,7 +345,7 @@ typedef enum {
#define PLAYER_LIMB_BUF_COUNT LIMB_BUF_COUNT(PLAYER_LIMB_MAX) #define PLAYER_LIMB_BUF_COUNT LIMB_BUF_COUNT(PLAYER_LIMB_MAX)
typedef struct { typedef struct {
/* 0x00 */ f32 unk_00; /* 0x00 */ f32 ceilingCheckHeight;
/* 0x04 */ f32 unk_04; /* 0x04 */ f32 unk_04;
/* 0x08 */ f32 unk_08; /* 0x08 */ f32 unk_08;
/* 0x0C */ f32 unk_0C; /* 0x0C */ f32 unk_0C;
@ -369,7 +359,7 @@ typedef struct {
/* 0x2C */ f32 unk_2C; /* 0x2C */ f32 unk_2C;
/* 0x30 */ f32 unk_30; /* 0x30 */ f32 unk_30;
/* 0x34 */ f32 unk_34; /* 0x34 */ f32 unk_34;
/* 0x38 */ f32 unk_38; /* 0x38 */ f32 wallCheckRadius;
/* 0x3C */ f32 unk_3C; /* 0x3C */ f32 unk_3C;
/* 0x40 */ f32 unk_40; /* 0x40 */ f32 unk_40;
/* 0x44 */ Vec3s unk_44; /* 0x44 */ Vec3s unk_44;
@ -494,185 +484,192 @@ typedef struct {
#define PLAYER_STATE3_RESTORE_NAYRUS_LOVE (1 << 6) // Set by ocarina effects actors when destroyed to signal Nayru's Love may be restored (see `ACTOROVL_ALLOC_ABSOLUTE`) #define PLAYER_STATE3_RESTORE_NAYRUS_LOVE (1 << 6) // Set by ocarina effects actors when destroyed to signal Nayru's Love may be restored (see `ACTOROVL_ALLOC_ABSOLUTE`)
#define PLAYER_STATE3_HOOKSHOT_TRAVELLING (1 << 7) //Travelling to target #define PLAYER_STATE3_HOOKSHOT_TRAVELLING (1 << 7) //Travelling to target
typedef void (*PlayerFunc674)(struct Player*, struct PlayState*); typedef void (*PlayerActionFunc)(struct Player*, struct PlayState*);
typedef s32 (*PlayerFunc82C)(struct Player*, struct PlayState*); typedef s32 (*UpperActionFunc)(struct Player*, struct PlayState*);
typedef void (*PlayerFuncA74)(struct PlayState*, struct Player*); typedef void (*PlayerFuncA74)(struct PlayState*, struct Player*);
typedef struct Player { typedef struct Player {
/* 0x0000 */ Actor actor; /* 0x0000 */ Actor actor;
/* 0x014C */ s8 currentTunic; // current tunic from `PlayerTunic` /* 0x014C */ s8 currentTunic; // current tunic from `PlayerTunic`
/* 0x014D */ s8 currentSwordItemId; /* 0x014D */ s8 currentSwordItemId;
/* 0x014E */ s8 currentShield; // current shield from `PlayerShield` /* 0x014E */ s8 currentShield; // current shield from `PlayerShield`
/* 0x014F */ s8 currentBoots; // current boots from `PlayerBoots` /* 0x014F */ s8 currentBoots; // current boots from `PlayerBoots`
/* 0x0150 */ s8 heldItemButton; // Button index for the item currently used /* 0x0150 */ s8 heldItemButton; // Button index for the item currently used
/* 0x0151 */ s8 heldItemAction; // Item action for the item currently used /* 0x0151 */ s8 heldItemAction; // Item action for the item currently used
/* 0x0152 */ u8 heldItemId; // Item id for the item currently used /* 0x0152 */ u8 heldItemId; // Item id for the item currently used
/* 0x0153 */ s8 prevBoots; // previous boots from `PlayerBoots` /* 0x0153 */ s8 prevBoots; // previous boots from `PlayerBoots`
/* 0x0154 */ s8 itemAction; // the difference between this and heldItemAction is unclear /* 0x0154 */ s8 itemAction; // the difference between this and heldItemAction is unclear
/* 0x0155 */ char unk_155[0x003]; /* 0x0155 */ char unk_155[0x003];
/* 0x0158 */ u8 modelGroup; /* 0x0158 */ u8 modelGroup;
/* 0x0159 */ u8 nextModelGroup; /* 0x0159 */ u8 nextModelGroup;
/* 0x015A */ s8 unk_15A; /* 0x015A */ s8 itemChangeType;
/* 0x015B */ u8 modelAnimType; /* 0x015B */ u8 modelAnimType;
/* 0x015C */ u8 leftHandType; /* 0x015C */ u8 leftHandType;
/* 0x015D */ u8 rightHandType; /* 0x015D */ u8 rightHandType;
/* 0x015E */ u8 sheathType; /* 0x015E */ u8 sheathType;
/* 0x015F */ u8 currentMask; // current mask equipped from `PlayerMask` /* 0x015F */ u8 currentMask; // current mask equipped from `PlayerMask`
/* 0x0160 */ Gfx** rightHandDLists; /* 0x0160 */ Gfx** rightHandDLists;
/* 0x0164 */ Gfx** leftHandDLists; /* 0x0164 */ Gfx** leftHandDLists;
/* 0x0168 */ Gfx** sheathDLists; /* 0x0168 */ Gfx** sheathDLists;
/* 0x016C */ Gfx** waistDLists; /* 0x016C */ Gfx** waistDLists;
/* 0x0170 */ u8 giObjectLoading; /* 0x0170 */ u8 giObjectLoading;
/* 0x0174 */ DmaRequest giObjectDmaRequest; /* 0x0174 */ DmaRequest giObjectDmaRequest;
/* 0x0194 */ OSMesgQueue giObjectLoadQueue; /* 0x0194 */ OSMesgQueue giObjectLoadQueue;
/* 0x01AC */ OSMesg giObjectLoadMsg; /* 0x01AC */ OSMesg giObjectLoadMsg;
/* 0x01B0 */ void* giObjectSegment; // also used for title card textures /* 0x01B0 */ void* giObjectSegment; // also used for title card textures
/* 0x01B4 */ SkelAnime skelAnime; /* 0x01B4 */ SkelAnime skelAnime;
/* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT]; /* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT];
/* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT]; /* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT];
/* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT]; /* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT];
/* 0x03A8 */ s16 unk_3A8[2]; /* 0x03A8 */ s16 unk_3A8[2];
/* 0x03AC */ Actor* heldActor; /* 0x03AC */ Actor* heldActor;
/* 0x03B0 */ Vec3f leftHandPos; /* 0x03B0 */ Vec3f leftHandPos;
/* 0x03BC */ Vec3s unk_3BC; /* 0x03BC */ Vec3s unk_3BC;
/* 0x03C4 */ Actor* unk_3C4; /* 0x03C4 */ Actor* unk_3C4;
/* 0x03C8 */ Vec3f unk_3C8; /* 0x03C8 */ Vec3f unk_3C8;
/* 0x03D4 */ char unk_3D4[0x058]; /* 0x03D4 */ char unk_3D4[0x058];
/* 0x042C */ s8 doorType; /* 0x042C */ s8 doorType;
/* 0x042D */ s8 doorDirection; /* 0x042D */ s8 doorDirection;
/* 0x042E */ s16 doorTimer; /* 0x042E */ s16 doorTimer;
/* 0x0430 */ Actor* doorActor; /* 0x0430 */ Actor* doorActor;
/* 0x0434 */ s16 getItemId; // Upstream TODO: Document why this is s16 while it's s8 upstream /* 0x0434 */ s16 getItemId; // Upstream TODO: Document why this is s16 while it's s8 upstream
/* 0x0436 */ u16 getItemDirection; /* 0x0436 */ u16 getItemDirection;
/* 0x0438 */ Actor* interactRangeActor; /* 0x0438 */ Actor* interactRangeActor;
/* 0x043C */ s8 mountSide; /* 0x043C */ s8 mountSide;
/* 0x043D */ char unk_43D[0x003]; /* 0x043D */ char unk_43D[0x003];
/* 0x0440 */ Actor* rideActor; /* 0x0440 */ Actor* rideActor;
/* 0x0444 */ u8 csMode; /* 0x0444 */ u8 csAction;
/* 0x0445 */ u8 prevCsMode; /* 0x0445 */ u8 prevCsAction;
/* 0x0446 */ u8 unk_446; /* 0x0446 */ u8 cueId;
/* 0x0447 */ u8 unk_447; /* 0x0447 */ u8 unk_447;
/* 0x0448 */ Actor* unk_448; /* 0x0448 */ Actor* csActor; // Actor involved in a `csAction`. Typically the actor that invoked the cutscene.
/* 0x044C */ char unk_44C[0x004]; /* 0x044C */ char unk_44C[0x004];
/* 0x0450 */ Vec3f unk_450; /* 0x0450 */ Vec3f unk_450;
/* 0x045C */ Vec3f unk_45C; /* 0x045C */ Vec3f unk_45C;
/* 0x0468 */ char unk_468[0x002]; /* 0x0468 */ char unk_468[0x002];
/* 0x046A */ s16 doorBgCamIndex; /* 0x046A */ s16 doorBgCamIndex;
/* 0x046C */ s16 subCamId; /* 0x046C */ s16 subCamId;
/* 0x046E */ char unk_46E[0x02A]; /* 0x046E */ char unk_46E[0x02A];
/* 0x0498 */ ColliderCylinder cylinder; /* 0x0498 */ ColliderCylinder cylinder;
/* 0x04E4 */ ColliderQuad meleeWeaponQuads[2]; /* 0x04E4 */ ColliderQuad meleeWeaponQuads[2];
/* 0x05E4 */ ColliderQuad shieldQuad; /* 0x05E4 */ ColliderQuad shieldQuad;
/* 0x0664 */ Actor* unk_664; /* 0x0664 */ Actor* unk_664;
/* 0x0668 */ char unk_668[0x004]; /* 0x0668 */ char unk_668[0x004];
/* 0x066C */ s32 unk_66C; /* 0x066C */ s32 unk_66C;
/* 0x0670 */ s32 meleeWeaponEffectIndex; /* 0x0670 */ s32 meleeWeaponEffectIndex;
/* 0x0674 */ PlayerFunc674 func_674; /* 0x0674 */ PlayerActionFunc actionFunc;
/* 0x0678 */ PlayerAgeProperties* ageProperties; /* 0x0678 */ PlayerAgeProperties* ageProperties;
/* 0x067C */ u32 stateFlags1; /* 0x067C */ u32 stateFlags1;
/* 0x0680 */ u32 stateFlags2; /* 0x0680 */ u32 stateFlags2;
/* 0x0684 */ Actor* unk_684; /* 0x0684 */ Actor* unk_684;
/* 0x0688 */ Actor* boomerangActor; /* 0x0688 */ Actor* boomerangActor;
/* 0x068C */ Actor* naviActor; /* 0x068C */ Actor* naviActor;
/* 0x0690 */ s16 naviTextId; /* 0x0690 */ s16 naviTextId;
/* 0x0692 */ u8 stateFlags3; /* 0x0692 */ u8 stateFlags3;
/* 0x0693 */ s8 exchangeItemId; /* 0x0693 */ s8 exchangeItemId;
/* 0x0694 */ Actor* targetActor; /* 0x0694 */ Actor* targetActor;
/* 0x0698 */ f32 targetActorDistance; /* 0x0698 */ f32 targetActorDistance;
/* 0x069C */ char unk_69C[0x004]; /* 0x069C */ char unk_69C[0x004];
/* 0x06A0 */ f32 unk_6A0; /* 0x06A0 */ f32 unk_6A0;
/* 0x06A4 */ f32 unk_6A4; /* 0x06A4 */ f32 closestSecretDistSq;
/* 0x06A8 */ Actor* unk_6A8; /* 0x06A8 */ Actor* unk_6A8;
/* 0x06AC */ s8 unk_6AC; /* 0x06AC */ s8 unk_6AC;
/* 0x06AD */ u8 unk_6AD; /* 0x06AD */ u8 unk_6AD;
/* 0x06AE */ u16 unk_6AE; /* 0x06AE */ u16 unk_6AE;
/* 0x06B0 */ s16 unk_6B0; /* 0x06B0 */ s16 unk_6B0;
/* 0x06B2 */ char unk_6B4[0x004]; /* 0x06B2 */ char unk_6B4[0x004];
/* 0x06B6 */ s16 unk_6B6; /* 0x06B6 */ s16 unk_6B6;
/* 0x06B8 */ s16 unk_6B8; /* 0x06B8 */ s16 unk_6B8;
/* 0x06BA */ s16 unk_6BA; /* 0x06BA */ s16 unk_6BA;
/* 0x06BC */ s16 unk_6BC; /* 0x06BC */ s16 unk_6BC;
/* 0x06BE */ s16 unk_6BE; /* 0x06BE */ s16 unk_6BE;
/* 0x06C0 */ s16 unk_6C0; /* 0x06C0 */ s16 unk_6C0;
/* 0x06C2 */ s16 unk_6C2; /* 0x06C2 */ s16 unk_6C2;
/* 0x06C4 */ f32 unk_6C4; /* 0x06C4 */ f32 unk_6C4;
/* 0x06C8 */ SkelAnime skelAnime2; /* 0x06C8 */ SkelAnime upperSkelAnime;
/* 0x070C */ Vec3s jointTable2[PLAYER_LIMB_BUF_COUNT]; /* 0x070C */ Vec3s upperJointTable[PLAYER_LIMB_BUF_COUNT];
/* 0x079C */ Vec3s morphTable2[PLAYER_LIMB_BUF_COUNT]; /* 0x079C */ Vec3s upperMorphTable[PLAYER_LIMB_BUF_COUNT];
/* 0x082C */ PlayerFunc82C func_82C; /* 0x082C */ UpperActionFunc upperActionFunc;
/* 0x0830 */ f32 unk_830; /* 0x0830 */ f32 upperAnimBlendWeight;
/* 0x0834 */ s16 unk_834; /* 0x0834 */ s16 unk_834;
/* 0x0836 */ s8 unk_836; /* 0x0836 */ s8 unk_836;
/* 0x0837 */ u8 unk_837; /* 0x0837 */ u8 unk_837;
/* 0x0838 */ f32 linearVelocity; /* 0x0838 */ f32 linearVelocity;
/* 0x083C */ s16 currentYaw; /* 0x083C */ s16 yaw; // General yaw value, used both for world and shape rotation. Current or target value depending on context.
/* 0x083E */ s16 targetYaw; /* 0x083E */ s16 zTargetYaw; // yaw relating to Z targeting/"parallel" mode
/* 0x0840 */ u16 unk_840; /* 0x0840 */ u16 underwaterTimer;
/* 0x0842 */ s8 meleeWeaponAnimation; /* 0x0842 */ s8 meleeWeaponAnimation;
/* 0x0843 */ s8 meleeWeaponState; /* 0x0843 */ s8 meleeWeaponState;
/* 0x0844 */ s8 unk_844; /* 0x0844 */ s8 unk_844;
/* 0x0845 */ u8 unk_845; /* 0x0845 */ u8 unk_845;
/* 0x0846 */ u8 unk_846; /* 0x0846 */ u8 unk_846;
/* 0x0847 */ s8 unk_847[4]; /* 0x0847 */ s8 unk_847[4];
/* 0x084B */ s8 unk_84B[4]; /* 0x084B */ s8 unk_84B[4];
/* 0x084F */ s8 unk_84F;
/* 0x0850 */ s16 unk_850; // multipurpose timer /* 0x084F */ union {
/* 0x0854 */ f32 unk_854; s8 actionVar1;
/* 0x0858 */ f32 unk_858; } av1; // "Action Variable 1": context dependent variable that has different meanings depending on what action is currently running
/* 0x085C */ f32 unk_85C; // stick length among other things
/* 0x0860 */ s16 unk_860; // stick flame timer among other things /* 0x0850 */ union {
/* 0x0862 */ s16 unk_862; // get item draw ID + 1 s16 actionVar2;
/* 0x0864 */ f32 unk_864; } av2; // "Action Variable 2": context dependent variable that has different meanings depending on what action is currently running
/* 0x0868 */ f32 unk_868;
/* 0x086C */ f32 unk_86C; /* 0x0854 */ f32 unk_854;
/* 0x0870 */ f32 unk_870; /* 0x0858 */ f32 unk_858;
/* 0x0874 */ f32 unk_874; /* 0x085C */ f32 unk_85C; // stick length among other things
/* 0x0878 */ f32 unk_878; /* 0x0860 */ s16 unk_860; // stick flame timer among other things
/* 0x087C */ s16 unk_87C; /* 0x0862 */ s16 unk_862; // get item draw ID + 1
/* 0x087E */ s16 unk_87E; /* 0x0864 */ f32 unk_864;
/* 0x0880 */ f32 unk_880; /* 0x0868 */ f32 unk_868;
/* 0x0884 */ f32 wallHeight; // height used to determine whether link can climb or grab a ledge at the top /* 0x086C */ f32 unk_86C;
/* 0x0888 */ f32 wallDistance; // distance to the colliding wall plane /* 0x0870 */ f32 unk_870;
/* 0x088C */ u8 unk_88C; /* 0x0874 */ f32 unk_874;
/* 0x088D */ u8 unk_88D; /* 0x0878 */ f32 unk_878;
/* 0x088E */ u8 unk_88E; /* 0x087C */ s16 unk_87C;
/* 0x088F */ u8 unk_88F; /* 0x087E */ s16 unk_87E;
/* 0x0890 */ u8 unk_890; /* 0x0880 */ f32 unk_880;
/* 0x0891 */ u8 shockTimer; /* 0x0884 */ f32 yDistToLedge; // y distance to ground above an interact wall. LEDGE_DIST_MAX if no ground is found
/* 0x0892 */ u8 unk_892; /* 0x0888 */ f32 distToInteractWall; // xyz distance to the interact wall
/* 0x0893 */ u8 hoverBootsTimer; /* 0x088C */ u8 ledgeClimbType;
/* 0x0894 */ s16 fallStartHeight; // last truncated Y position before falling /* 0x088D */ u8 ledgeClimbDelayTimer;
/* 0x0896 */ s16 fallDistance; // truncated Y distance the player has fallen so far (positive is down) /* 0x088E */ u8 unk_88E;
/* 0x0898 */ s16 unk_898; /* 0x088F */ u8 unk_88F;
/* 0x089A */ s16 unk_89A; /* 0x0890 */ u8 unk_890;
/* 0x089C */ s16 unk_89C; /* 0x0891 */ u8 bodyShockTimer;
/* 0x089E */ u16 unk_89E; /* 0x0892 */ u8 unk_892;
/* 0x08A0 */ u8 unk_8A0; /* 0x0893 */ u8 hoverBootsTimer;
/* 0x08A1 */ u8 unk_8A1; /* 0x0894 */ s16 fallStartHeight; // last truncated Y position before falling
/* 0x08A2 */ s16 unk_8A2; /* 0x0896 */ s16 fallDistance; // truncated Y distance the player has fallen so far (positive is down)
/* 0x08A4 */ f32 unk_8A4; /* 0x0898 */ s16 floorPitch; // angle of the floor slope in the direction of current world yaw (positive for ascending slope)
/* 0x08A8 */ f32 unk_8A8; /* 0x089A */ s16 floorPitchAlt; // the calculation for this value is bugged and doesn't represent anything meaningful
/* 0x08AC */ f32 windSpeed; // Pushing player, examples include water currents, floor conveyors, climbing sloped surfaces // Upstream TODO: pushedSpeed /* 0x089C */ s16 unk_89C;
/* 0x08B0 */ s16 windDirection; // Yaw direction of player being pushed // Upstream TODO: pushedYaw /* 0x089E */ u16 floorSfxOffset;
/* 0x08A0 */ u8 unk_8A0;
/* 0x08A1 */ u8 unk_8A1;
/* 0x08A2 */ s16 unk_8A2;
/* 0x08A4 */ f32 unk_8A4;
/* 0x08A8 */ f32 unk_8A8;
/* 0x08AC */ f32 pushedSpeed; // Pushing player, examples include water currents, floor conveyors, climbing sloped surfaces
/* 0x08B0 */ s16 pushedYaw; // Yaw direction of player being pushed
/* 0x08B4 */ WeaponInfo meleeWeaponInfo[3]; /* 0x08B4 */ WeaponInfo meleeWeaponInfo[3];
/* 0x0908 */ Vec3f bodyPartsPos[PLAYER_BODYPART_MAX]; /* 0x0908 */ Vec3f bodyPartsPos[PLAYER_BODYPART_MAX];
/* 0x09E0 */ MtxF mf_9E0; /* 0x09E0 */ MtxF mf_9E0;
/* 0x0A20 */ MtxF shieldMf; /* 0x0A20 */ MtxF shieldMf;
/* 0x0A60 */ u8 isBurning; /* 0x0A60 */ u8 bodyIsBurning;
/* 0x0A61 */ u8 flameTimers[PLAYER_BODYPART_MAX]; // one flame per body part /* 0x0A61 */ u8 bodyFlameTimers[PLAYER_BODYPART_MAX]; // one flame per body part
/* 0x0A73 */ u8 unk_A73; /* 0x0A73 */ u8 unk_A73;
/* 0x0A74 */ PlayerFuncA74 func_A74; /* 0x0A74 */ PlayerFuncA74 func_A74;
/* 0x0A78 */ s8 invincibilityTimer; // prevents damage when nonzero (positive = visible, counts towards zero each frame) /* 0x0A78 */ s8 invincibilityTimer; // prevents damage when nonzero (positive = visible, counts towards zero each frame)
/* 0x0A79 */ u8 unk_A79; /* 0x0A79 */ u8 floorTypeTimer; // counts up every frame the current floor type is the same as the last frame
/* 0x0A7A */ u8 unk_A7A; /* 0x0A7A */ u8 floorProperty;
/* 0x0A7B */ u8 unk_A7B; /* 0x0A7B */ u8 prevFloorType;
/* 0x0A7C */ f32 unk_A7C; /* 0x0A7C */ f32 prevControlStickMagnitude;
/* 0x0A80 */ s16 unk_A80; /* 0x0A80 */ s16 prevControlStickAngle;
/* 0x0A82 */ u16 unk_A82; /* 0x0A82 */ u16 prevFloorSfxOffset;
/* 0x0A84 */ s16 unk_A84; /* 0x0A84 */ s16 unk_A84;
/* 0x0A86 */ s8 unk_A86; /* 0x0A86 */ s8 unk_A86;
/* 0x0A87 */ u8 unk_A87; /* 0x0A87 */ u8 unk_A87;
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
// #region SOH [General] // #region SOH [General]
// Upstream TODO: Rename these to be more obviously SoH specific // Upstream TODO: Rename these to be more obviously SoH specific
/* */ PendingFlag pendingFlag; /* */ PendingFlag pendingFlag;
@ -680,7 +677,7 @@ typedef struct Player {
// #endregion // #endregion
// #region SOH [Enhancements] // #region SOH [Enhancements]
// Upstream TODO: Rename this to make it more obvious it is apart of an enhancement // Upstream TODO: Rename this to make it more obvious it is apart of an enhancement
/* */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still? /* */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still?
// #endregion // #endregion
u8 ivanFloating; u8 ivanFloating;
u8 ivanDamageMultiplier; u8 ivanDamageMultiplier;

View File

@ -314,8 +314,34 @@ enum SceneID {
/* 0x6E */ SCENE_ID_MAX /* 0x6E */ SCENE_ID_MAX
}; };
// this define exists to preserve shiftability for an unused scene that is
// listed in the entrance table
#define SCENE_UNUSED_6E SCENE_ID_MAX
#undef DEFINE_SCENE #undef DEFINE_SCENE
// Entrance Index Enum
#define DEFINE_ENTRANCE(enum, _1, _2, _3, _4, _5, _6) enum,
typedef enum {
#include "tables/entrance_table.h"
/* 0x614 */ ENTR_MAX
} EntranceIndex;
#define ENTR_LOAD_OPENING -1
typedef enum {
/* 0x7FF9 */ ENTR_RETURN_YOUSEI_IZUMI_YOKO = 0x7FF9, // Great Fairy Fountain (spells)
/* 0x7FFA */ ENTR_RETURN_SYATEKIJYOU, // Shooting gallery
/* 0x7FFB */ ENTR_RETURN_2, // unused
/* 0x7FFC */ ENTR_RETURN_SHOP1, // Bazaar
/* 0x7FFD */ ENTR_RETURN_4, // unused
/* 0x7FFE */ ENTR_RETURN_DAIYOUSEI_IZUMI, // Great Fairy Fountain (magic, double magic, double defense)
/* 0x7FFF */ ENTR_RETURN_GROTTO // Grottos and normal Fairy Fountain
} ReturnEntranceIndex;
#undef DEFINE_ENTRANCE
typedef enum { typedef enum {
/* 0 */ SDC_DEFAULT, /* 0 */ SDC_DEFAULT,
/* 1 */ SDC_HYRULE_FIELD, /* 1 */ SDC_HYRULE_FIELD,

View File

@ -50,11 +50,16 @@ typedef struct {
/* 0x004 */ Color_RGBA8_u32 envColor; /* 0x004 */ Color_RGBA8_u32 envColor;
/* 0x008 */ s32 texX; /* 0x008 */ s32 texX;
/* 0x00C */ s32 texY; /* 0x00C */ s32 texY;
/* 0x010 */ s32 step; // /* 0x010 */ s32 step;
/* 0x014 */ u8 unk_14; // /* 0x014 */ u8 unk_14;
/* 0x015 */ u8 typeColor; // /* 0x015 */ u8 typeColor;
/* 0x016 */ u8 speed; // /* 0x016 */ u8 speed;
/* 0x017 */ u8 effect; // /* 0x017 */ u8 effect;
/* 0x010 */ s32 speed;
/* 0x014 */ u8 direction;
/* 0x015 */ u8 colorType;
/* 0x016 */ u8 speedType;
/* 0x017 */ u8 appearanceType;
/* 0x018 */ u8 isDone; /* 0x018 */ u8 isDone;
/* 0x019 */ u8 frame; /* 0x019 */ u8 frame;
/* 0x01A */ u16 normal; /* 0x01A */ u16 normal;

View File

@ -33,5 +33,10 @@
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.15</string> <string>10.15</string>
<key>LSArchitecturePriority</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -14,11 +14,6 @@ if [ ! -e "$SHIP_HOME"/mods ]; then
touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt
fi fi
arch_name="$(uname -m)" "$RESPATH"/soh-macos
launch_arch="arm64"
if [ "${arch_name}" = "x86_64" ] && [ "$(sysctl -in sysctl.proc_translated)" != "1" ]; then
launch_arch="x86_64"
fi
arch -${launch_arch} "$RESPATH"/soh-macos
exit exit

View File

@ -74,7 +74,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_EN_BUBBLE, "Shabom" }, { ACTOR_EN_BUBBLE, "Shabom" },
{ ACTOR_DOOR_SHUTTER, "Shutter Door" }, { ACTOR_DOOR_SHUTTER, "Shutter Door" },
{ ACTOR_EN_DODOJR, "Baby Dodongo" }, { ACTOR_EN_DODOJR, "Baby Dodongo" },
{ ACTOR_EN_BDFIRE, "Empty" }, { ACTOR_EN_BDFIRE, "King Dodongo's Fire Breath" },
{ ACTOR_EN_BOOM, "Boomerang" }, { ACTOR_EN_BOOM, "Boomerang" },
{ ACTOR_EN_TORCH2, "Dark Link" }, { ACTOR_EN_TORCH2, "Dark Link" },
{ ACTOR_EN_BILI, "Biri" }, { ACTOR_EN_BILI, "Biri" },
@ -132,7 +132,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" }, { ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" },
{ ACTOR_EN_YUKABYUN, "Flying Floor Tile" }, { ACTOR_EN_YUKABYUN, "Flying Floor Tile" },
{ ACTOR_BG_TOKI_SWD, "Master Sword" }, { ACTOR_BG_TOKI_SWD, "Master Sword" },
{ ACTOR_EN_FHG_FIRE, "Empty" }, { ACTOR_EN_FHG_FIRE, "Phantom Ganon's Lighting Attack" },
{ ACTOR_BG_MJIN, "Warp Song Pad" }, { ACTOR_BG_MJIN, "Warp Song Pad" },
{ ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" }, { ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" },
{ ACTOR_DOOR_TOKI, "Door of Time Collision" }, { ACTOR_DOOR_TOKI, "Door of Time Collision" },
@ -548,6 +548,10 @@ int ActorDB::RetrieveId(const std::string& name) {
return entry->second; return entry->second;
} }
int ActorDB::GetEntryCount() {
return db.size();
}
ActorDB::Entry::Entry() { ActorDB::Entry::Entry() {
entry.name = nullptr; entry.name = nullptr;
entry.desc = nullptr; entry.desc = nullptr;

View File

@ -64,6 +64,7 @@ public:
static void AddBuiltInCustomActors(); static void AddBuiltInCustomActors();
int GetEntryCount();
private: private:
Entry& AddEntry(const std::string& name, const std::string& desc, size_t index); Entry& AddEntry(const std::string& name, const std::string& desc, size_t index);
Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init); Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init);

View File

@ -2,9 +2,10 @@
#include "sequence.h" #include "sequence.h"
#include "sfx.h" #include "sfx.h"
#include <vector> #include <vector>
#include <Utils/StringHelper.h> #include <utils/StringHelper.h>
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include <libultraship/classes.h> #include <libultraship/classes.h>
#include <soh/OTRGlobals.h>
#include <locale> #include <locale>
#include <filesystem> #include <filesystem>
@ -330,11 +331,13 @@ AudioCollection::AudioCollection() {
} }
std::string AudioCollection::GetCvarKey(std::string sfxKey) { std::string AudioCollection::GetCvarKey(std::string sfxKey) {
return "gAudioEditor.ReplacedSequences." + sfxKey + ".value"; auto prefix = CVAR_AUDIO("ReplacedSequences.");
return prefix + sfxKey + ".value";
} }
std::string AudioCollection::GetCvarLockKey(std::string sfxKey) { std::string AudioCollection::GetCvarLockKey(std::string sfxKey) {
return "gAudioEditor.ReplacedSequences." + sfxKey + ".locked"; auto prefix = std::string(CVAR_AUDIO("ReplacedSequences."));
return prefix + sfxKey + ".locked";
} }
void AudioCollection::AddToCollection(char* otrPath, uint16_t seqNum) { void AudioCollection::AddToCollection(char* otrPath, uint16_t seqNum) {
@ -362,7 +365,7 @@ uint16_t AudioCollection::GetReplacementSequence(uint16_t seqId) {
// for Hyrule Field instead. Otherwise, leave it alone, so that without any sfx editor modifications we will // for Hyrule Field instead. Otherwise, leave it alone, so that without any sfx editor modifications we will
// play the normal track as usual. // play the normal track as usual.
if (seqId == NA_BGM_FIELD_MORNING) { if (seqId == NA_BGM_FIELD_MORNING) {
if (CVarGetInteger("gAudioEditor.ReplacedSequences.NA_BGM_FIELD_LOGIC.value", NA_BGM_FIELD_LOGIC) != NA_BGM_FIELD_LOGIC) { if (CVarGetInteger(CVAR_AUDIO("ReplacedSequences.NA_BGM_FIELD_LOGIC.value"), NA_BGM_FIELD_LOGIC) != NA_BGM_FIELD_LOGIC) {
seqId = NA_BGM_FIELD_LOGIC; seqId = NA_BGM_FIELD_LOGIC;
} }
} }
@ -381,19 +384,19 @@ uint16_t AudioCollection::GetReplacementSequence(uint16_t seqId) {
} }
void AudioCollection::RemoveFromShufflePool(SequenceInfo* seqInfo) { void AudioCollection::RemoveFromShufflePool(SequenceInfo* seqInfo) {
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo->sfxKey; const std::string cvarKey = std::string(CVAR_AUDIO("Excluded.")) + seqInfo->sfxKey;
excludedSequences.insert(seqInfo); excludedSequences.insert(seqInfo);
includedSequences.erase(seqInfo); includedSequences.erase(seqInfo);
CVarSetInteger(cvarKey.c_str(), 1); CVarSetInteger(cvarKey.c_str(), 1);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} }
void AudioCollection::AddToShufflePool(SequenceInfo* seqInfo) { void AudioCollection::AddToShufflePool(SequenceInfo* seqInfo) {
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo->sfxKey; const std::string cvarKey = std::string(CVAR_AUDIO("Excluded.")) + seqInfo->sfxKey;
includedSequences.insert(seqInfo); includedSequences.insert(seqInfo);
excludedSequences.erase(seqInfo); excludedSequences.erase(seqInfo);
CVarClear(cvarKey.c_str()); CVarClear(cvarKey.c_str());
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} }
void AudioCollection::InitializeShufflePool() { void AudioCollection::InitializeShufflePool() {
@ -401,7 +404,7 @@ void AudioCollection::InitializeShufflePool() {
for (auto& [seqId, seqInfo] : sequenceMap) { for (auto& [seqId, seqInfo] : sequenceMap) {
if (!seqInfo.canBeUsedAsReplacement) continue; if (!seqInfo.canBeUsedAsReplacement) continue;
const std::string cvarKey = "gAudioEditor.Excluded." + seqInfo.sfxKey; const std::string cvarKey = std::string(CVAR_AUDIO("Excluded.")) + seqInfo.sfxKey;
if (CVarGetInteger(cvarKey.c_str(), 0)) { if (CVarGetInteger(cvarKey.c_str(), 0)) {
excludedSequences.insert(&seqInfo); excludedSequences.insert(&seqInfo);
} else { } else {

View File

@ -1,3 +1,4 @@
#pragma once
#ifdef __cplusplus #ifdef __cplusplus
#include <map> #include <map>
#include <string> #include <string>

View File

@ -9,9 +9,10 @@
#include <functions.h> #include <functions.h>
#include "../randomizer/3drando/random.hpp" #include "../randomizer/3drando/random.hpp"
#include "../../OTRGlobals.h" #include "../../OTRGlobals.h"
#include <Utils/StringHelper.h> #include <utils/StringHelper.h>
#include "../../UIWidgets.hpp" #include "../../UIWidgets.hpp"
#include "AudioCollection.h" #include "AudioCollection.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
Vec3f pos = { 0.0f, 0.0f, 0.0f }; Vec3f pos = { 0.0f, 0.0f, 0.0f };
f32 freqScale = 1.0f; f32 freqScale = 1.0f;
@ -78,7 +79,12 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
void RandomizeGroup(SeqType type) { void RandomizeGroup(SeqType type) {
std::vector<u16> values; 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 // use a while loop to add duplicates if we don't have enough included sequences
while (values.size() < AuthenticCountBySequenceType(type)) { while (values.size() < AuthenticCountBySequenceType(type)) {
for (const auto& seqData : AudioCollection::Instance->GetIncludedSequences()) { for (const auto& seqData : AudioCollection::Instance->GetIncludedSequences()) {
@ -123,23 +129,51 @@ 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) { void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequenceType) {
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(sfxKey); const std::string cvarKey = AudioCollection::Instance->GetCvarKey(sfxKey);
const std::string hiddenKey = "##" + cvarKey; const std::string hiddenKey = "##" + cvarKey;
const std::string stopButton = ICON_FA_STOP + hiddenKey; const std::string stopButton = ICON_FA_STOP + hiddenKey;
const std::string previewButton = ICON_FA_PLAY + hiddenKey; const std::string previewButton = ICON_FA_PLAY + hiddenKey;
if (CVarGetInteger("gAudioEditor.Playing", 0) == sequenceId) { if (CVarGetInteger(CVAR_AUDIO("Playing"), 0) == sequenceId) {
if (ImGui::Button(stopButton.c_str())) { if (ImGui::Button(stopButton.c_str())) {
func_800F5C2C(); func_800F5C2C();
CVarSetInteger("gAudioEditor.Playing", 0); CVarSetInteger(CVAR_AUDIO("Playing"), 0);
} }
UIWidgets::Tooltip("Stop Preview"); UIWidgets::Tooltip("Stop Preview");
} else { } else {
if (ImGui::Button(previewButton.c_str())) { if (ImGui::Button(previewButton.c_str())) {
if (CVarGetInteger("gAudioEditor.Playing", 0) != 0) { if (CVarGetInteger(CVAR_AUDIO("Playing"), 0) != 0) {
func_800F5C2C(); func_800F5C2C();
CVarSetInteger("gAudioEditor.Playing", 0); CVarSetInteger(CVAR_AUDIO("Playing"), 0);
} else { } else {
if (sequenceType == SEQ_SFX || sequenceType == SEQ_VOICE) { if (sequenceType == SEQ_SFX || sequenceType == SEQ_VOICE) {
Audio_PlaySoundGeneral(sequenceId, &pos, 4, &freqScale, &freqScale, &reverbAdd); Audio_PlaySoundGeneral(sequenceId, &pos, 4, &freqScale, &freqScale, &reverbAdd);
@ -149,7 +183,7 @@ void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequence
} else { } else {
// TODO: Cant do both here, so have to click preview button twice // TODO: Cant do both here, so have to click preview button twice
PreviewSequence(sequenceId); PreviewSequence(sequenceId);
CVarSetInteger("gAudioEditor.Playing", sequenceId); CVarSetInteger(CVAR_AUDIO("Playing"), sequenceId);
} }
} }
} }
@ -163,11 +197,13 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
const std::string hiddenTabId = "##" + tabId; const std::string hiddenTabId = "##" + tabId;
const std::string resetAllButton = "Reset All" + hiddenTabId; const std::string resetAllButton = "Reset All" + hiddenTabId;
const std::string randomizeAllButton = "Randomize 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())) { if (ImGui::Button(resetAllButton.c_str())) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN); auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM); auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
ResetGroup(map, type); ResetGroup(map, type);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM); auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) { if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
ReplayCurrentBGM(); ReplayCurrentBGM();
@ -178,7 +214,29 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN); auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM); auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
RandomizeGroup(type); RandomizeGroup(type);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
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);
Ship::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);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM); auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) { if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
ReplayCurrentBGM(); ReplayCurrentBGM();
@ -223,7 +281,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
if (ImGui::Selectable(seqData.label.c_str())) { if (ImGui::Selectable(seqData.label.c_str())) {
CVarSetInteger(cvarKey.c_str(), value); CVarSetInteger(cvarKey.c_str(), value);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
UpdateCurrentBGM(defaultValue, type); UpdateCurrentBGM(defaultValue, type);
} }
@ -243,7 +301,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
if (ImGui::Button(resetButton.c_str())) { if (ImGui::Button(resetButton.c_str())) {
CVarClear(cvarKey.c_str()); CVarClear(cvarKey.c_str());
CVarClear(cvarLockKey.c_str()); CVarClear(cvarLockKey.c_str());
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
UpdateCurrentBGM(defaultValue, seqData.category); UpdateCurrentBGM(defaultValue, seqData.category);
} }
UIWidgets::Tooltip("Reset to default"); UIWidgets::Tooltip("Reset to default");
@ -264,7 +322,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
if (locked) { if (locked) {
CVarClear(cvarLockKey.c_str()); CVarClear(cvarLockKey.c_str());
} }
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
UpdateCurrentBGM(defaultValue, type); UpdateCurrentBGM(defaultValue, type);
} }
} }
@ -277,7 +335,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
} else { } else {
CVarSetInteger(cvarLockKey.c_str(), 1); CVarSetInteger(cvarLockKey.c_str(), 1);
} }
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} }
UIWidgets::Tooltip(locked ? "Sound locked" : "Sound unlocked"); UIWidgets::Tooltip(locked ? "Sound locked" : "Sound unlocked");
} }
@ -350,6 +408,19 @@ void DrawTypeChip(SeqType type) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
void AudioEditorRegisterOnSceneInitHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (CVarGetInteger(CVAR_AUDIO("RandomizeAllOnNewScene"), 0)) {
AudioEditor_RandomizeAll();
}
});
}
void AudioEditor::InitElement() {
AudioEditorRegisterOnSceneInitHook();
}
void AudioEditor::DrawElement() { void AudioEditor::DrawElement() {
AudioCollection::Instance->InitializeShufflePool(); AudioCollection::Instance->InitializeShufflePool();
@ -359,6 +430,28 @@ void AudioEditor::DrawElement() {
return; 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::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
if (ImGui::BeginTabItem("Background Music")) { if (ImGui::BeginTabItem("Background Music")) {
Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD); Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD);
@ -399,18 +492,18 @@ void AudioEditor::DrawElement() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) { if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) {
ImGui::PushItemWidth(-FLT_MIN); ImGui::PushItemWidth(-FLT_MIN);
UIWidgets::EnhancementCheckbox("Disable Enemy Proximity Music", "gEnemyBGMDisable"); UIWidgets::EnhancementCheckbox("Disable Enemy Proximity Music", CVAR_AUDIO("EnemyBGMDisable"));
UIWidgets::InsertHelpHoverText( UIWidgets::InsertHelpHoverText(
"Disables the music change when getting close to enemies. Useful for hearing " "Disables the music change when getting close to enemies. Useful for hearing "
"your custom music for each scene more often."); "your custom music for each scene more often.");
UIWidgets::EnhancementCheckbox("Disable Leading Music in Lost Woods", "gLostWoodsConsistentVolume"); UIWidgets::EnhancementCheckbox("Disable Leading Music in Lost Woods", CVAR_AUDIO("LostWoodsConsistentVolume"));
UIWidgets::InsertHelpHoverText( UIWidgets::InsertHelpHoverText(
"Disables the volume shifting in the Lost Woods. Useful for hearing " "Disables the volume shifting in the Lost Woods. Useful for hearing "
"your custom music in the Lost Woods if you don't need the navigation assitance " "your custom music in the Lost Woods if you don't need the navigation assitance "
"the volume changing provides. If toggling this while in the Lost Woods, reload " "the volume changing provides. If toggling this while in the Lost Woods, reload "
"the area for the effect to kick in." "the area for the effect to kick in."
); );
UIWidgets::EnhancementCheckbox("Display Sequence Name on Overlay", "gSeqNameOverlay"); UIWidgets::EnhancementCheckbox("Display Sequence Name on Overlay", CVAR_AUDIO("SeqNameOverlay"));
UIWidgets::InsertHelpHoverText( UIWidgets::InsertHelpHoverText(
"Displays the name of the current sequence in the corner of the screen whenever a new sequence " "Displays the name of the current sequence in the corner of the screen whenever a new sequence "
"is loaded to the main sequence player (does not apply to fanfares or enemy BGM)." "is loaded to the main sequence player (does not apply to fanfares or enemy BGM)."
@ -418,24 +511,28 @@ void AudioEditor::DrawElement() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
UIWidgets::EnhancementSliderInt("Overlay Duration: %d seconds", "##SeqNameOverlayDuration", UIWidgets::EnhancementSliderInt("Overlay Duration: %d seconds", "##SeqNameOverlayDuration",
"gSeqNameOverlayDuration", 1, 10, "", 5); CVAR_AUDIO("SeqNameOverlayDuration"), 1, 10, "", 5);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::NewLine(); ImGui::NewLine();
ImGui::PopItemWidth(); ImGui::PopItemWidth();
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %f", "##linkVoiceFreqMultiplier", UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %.1f %%", "##linkVoiceFreqMultiplier",
"gLinkVoiceFreqMultiplier", 0.4, 2.5, "", 1.0, false, false); CVAR_AUDIO("LinkVoiceFreqMultiplier"), 0.4, 2.5, "", 1.0, true, true);
ImGui::SameLine(); ImGui::SameLine();
const std::string resetButton = "Reset##linkVoiceFreqMultiplier"; const std::string resetButton = "Reset##linkVoiceFreqMultiplier";
if (ImGui::Button(resetButton.c_str())) { if (ImGui::Button(resetButton.c_str())) {
CVarSetFloat("gLinkVoiceFreqMultiplier", 1.0f); CVarSetFloat(CVAR_AUDIO("LinkVoiceFreqMultiplier"), 1.0f);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
} }
ImGui::NewLine();
UIWidgets::EnhancementCheckbox("Randomize All Music and Sound Effects on New Scene", CVAR_AUDIO("RandomizeAllOnNewScene"));
UIWidgets::Tooltip("Enables randomizing all unlocked music and sound effects when you enter a new scene.");
ImGui::NewLine(); ImGui::NewLine();
ImGui::PushItemWidth(-FLT_MIN); ImGui::PushItemWidth(-FLT_MIN);
UIWidgets::PaddedSeparator(); UIWidgets::PaddedSeparator();
UIWidgets::PaddedText("The following options are experimental and may cause music\nto sound odd or have other undesireable effects."); UIWidgets::PaddedText("The following options are experimental and may cause music\nto sound odd or have other undesireable effects.");
UIWidgets::EnhancementCheckbox("Lower Octaves of Unplayable High Notes", "gExperimentalOctaveDrop"); UIWidgets::EnhancementCheckbox("Lower Octaves of Unplayable High Notes", CVAR_AUDIO("ExperimentalOctaveDrop"));
UIWidgets::InsertHelpHoverText("Some custom sequences may have notes that are too high for the game's audio " UIWidgets::InsertHelpHoverText("Some custom sequences may have notes that are too high for the game's audio "
"engine to play. Enabling this checkbox will cause these notes to drop a " "engine to play. Enabling this checkbox will cause these notes to drop a "
"couple of octaves so they can still harmonize with the other notes of the " "couple of octaves so they can still harmonize with the other notes of the "
@ -613,7 +710,14 @@ void AudioEditor_RandomizeAll() {
RandomizeGroup(type); RandomizeGroup(type);
} }
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
ReplayCurrentBGM();
}
void AudioEditor_RandomizeGroup(SeqType group) {
RandomizeGroup(group);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
ReplayCurrentBGM(); ReplayCurrentBGM();
} }
@ -622,6 +726,29 @@ void AudioEditor_ResetAll() {
ResetGroup(AudioCollection::Instance->GetAllSequences(), type); ResetGroup(AudioCollection::Instance->GetAllSequences(), type);
} }
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
ReplayCurrentBGM(); ReplayCurrentBGM();
} }
void AudioEditor_ResetGroup(SeqType group) {
ResetGroup(AudioCollection::Instance->GetAllSequences(), group);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
ReplayCurrentBGM();
}
void AudioEditor_LockAll() {
for (auto type : allTypes) {
LockGroup(AudioCollection::Instance->GetAllSequences(), type);
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
void AudioEditor_UnlockAll() {
for (auto type : allTypes) {
UnlockGroup(AudioCollection::Instance->GetAllSequences(), type);
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}

View File

@ -4,20 +4,28 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <libultraship/libultraship.h> #include <libultraship/libultraship.h>
#include <ImGui/imgui.h> #ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui.h>
#include "AudioCollection.h"
class AudioEditor : public LUS::GuiWindow { class AudioEditor : public Ship::GuiWindow {
public: public:
using LUS::GuiWindow::GuiWindow; using GuiWindow::GuiWindow;
void DrawElement() override; void DrawElement() override;
void InitElement() override {}; void InitElement() override;
void UpdateElement() override {}; void UpdateElement() override {};
~AudioEditor() {}; ~AudioEditor() {};
}; };
void AudioEditor_RandomizeAll(); void AudioEditor_RandomizeAll();
void AudioEditor_RandomizeGroup(SeqType group);
void AudioEditor_ResetAll(); void AudioEditor_ResetAll();
void AudioEditor_ResetGroup(SeqType group);
void AudioEditor_LockAll();
void AudioEditor_UnlockAll();
extern "C" { extern "C" {
#endif #endif

View File

@ -9,6 +9,7 @@
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <z64.h> #include <z64.h>
#include "soh/OTRGlobals.h"
uint8_t gLoadFileSelect = 0, gSkipLogoTest = 0; uint8_t gLoadFileSelect = 0, gSkipLogoTest = 0;
@ -21,15 +22,15 @@ static BootCommand sCommands[] = { { "--skiplogo", BootCommands_Command_SkipLogo
void BootCommands_Init() void BootCommands_Init()
{ {
// Clears vars to prevent randomizer menu from being disabled // Clears vars to prevent randomizer menu from being disabled
CVarClear("gRandoGenerating"); // Clear when a crash happened during rando seed generation CVarClear(CVAR_GENERAL("RandoGenerating")); // Clear when a crash happened during rando seed generation
CVarClear("gNewSeedGenerated"); CVarClear(CVAR_GENERAL("NewSeedGenerated"));
CVarClear("gOnFileSelectNameEntry"); // Clear when soh is killed on the file name entry page CVarClear(CVAR_GENERAL("OnFileSelectNameEntry")); // Clear when soh is killed on the file name entry page
CVarClear("gBetterDebugWarpScreenMQMode"); CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQMode"));
CVarClear("gBetterDebugWarpScreenMQModeScene"); CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQModeScene"));
CVarClear("gCheatEasyPauseBufferLastInputs"); CVarClear(CVAR_GENERAL("CheatEasyPauseBufferLastInputs"));
CVarClear("gCheatEasyPauseBufferTimer"); CVarClear(CVAR_GENERAL("CheatEasyPauseBufferTimer"));
#if defined(__SWITCH__) || defined(__WIIU__) #if defined(__SWITCH__) || defined(__WIIU__)
CVarRegisterInteger("gControlNav", 1); // always enable controller nav on switch/wii u CVarRegisterInteger(CVAR_IMGUI_CONTROLLER_NAV, 1); // always enable controller nav on switch/wii u
#endif #endif
} }

View File

@ -175,33 +175,33 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
// Gohma & Phantom Ganon // Gohma & Phantom Ganon
if (warpPosX == -100 && warpPosZ == -170) { if (warpPosX == -100 && warpPosZ == -170) {
if (gSaveContext.linkAge == LINK_AGE_CHILD) { if (gSaveContext.linkAge == LINK_AGE_CHILD) {
play->nextEntranceIndex = 0x040F; play->nextEntranceIndex = ENTR_DEKU_TREE_BOSS_0;
} else { } else {
play->nextEntranceIndex = 0x000C; play->nextEntranceIndex = ENTR_FOREST_TEMPLE_BOSS_0;
} }
// King Dodongo & Volvagia // King Dodongo & Volvagia
} else if (warpPosX == 100 && warpPosZ == -170) { } else if (warpPosX == 100 && warpPosZ == -170) {
if (gSaveContext.linkAge == LINK_AGE_CHILD) { if (gSaveContext.linkAge == LINK_AGE_CHILD) {
play->nextEntranceIndex = 0x040B; play->nextEntranceIndex = ENTR_DODONGOS_CAVERN_BOSS_0;
} else { } else {
play->nextEntranceIndex = 0x0305; play->nextEntranceIndex = ENTR_FIRE_TEMPLE_BOSS_0;
} }
// Barinade & Morb // Barinade & Morb
} else if (warpPosX == 199 && warpPosZ == 0) { } else if (warpPosX == 199 && warpPosZ == 0) {
if (gSaveContext.linkAge == LINK_AGE_CHILD) { if (gSaveContext.linkAge == LINK_AGE_CHILD) {
play->nextEntranceIndex = 0x0301; play->nextEntranceIndex = ENTR_JABU_JABU_BOSS_0;
} else { } else {
play->nextEntranceIndex = 0x0417; play->nextEntranceIndex = ENTR_WATER_TEMPLE_BOSS_0;
} }
// Twinrova // Twinrova
} else if (warpPosX == 100 && warpPosZ == 170) { } else if (warpPosX == 100 && warpPosZ == 170) {
play->nextEntranceIndex = 0x05EC; play->nextEntranceIndex = ENTR_SPIRIT_TEMPLE_BOSS_2;
// Bongo Bongo // Bongo Bongo
} else if (warpPosX == -100 && warpPosZ == 170) { } else if (warpPosX == -100 && warpPosZ == 170) {
play->nextEntranceIndex = 0x0413; play->nextEntranceIndex = ENTR_SHADOW_TEMPLE_BOSS_0;
// Ganondork // Ganondork
} else if (warpPosX == -199 && warpPosZ == 0) { } else if (warpPosX == -199 && warpPosZ == 0) {
play->nextEntranceIndex = 0x041F; play->nextEntranceIndex = ENTR_GANONDORF_BOSS_0;
} }
// If coming from a boss room, teleport back to Chamber of Sages and set flag. // If coming from a boss room, teleport back to Chamber of Sages and set flag.
} else { } else {
@ -216,10 +216,10 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
BossRush_SetEquipment(LINK_AGE_ADULT); BossRush_SetEquipment(LINK_AGE_ADULT);
// Warp to credits. // Warp to credits.
} else if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) { } else if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) {
play->nextEntranceIndex = 0x6B; play->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
gSaveContext.nextCutsceneIndex = 0xFFF2; gSaveContext.nextCutsceneIndex = 0xFFF2;
play->sceneLoadFlag = 0x14; play->transitionTrigger = TRANS_TRIGGER_START;
play->fadeTransition = 3; play->transitionType = TRANS_TYPE_FADE_WHITE;
} }
} }
} }
@ -293,7 +293,7 @@ void BossRush_InitSave() {
gSaveContext.questId = QUEST_BOSSRUSH; gSaveContext.questId = QUEST_BOSSRUSH;
gSaveContext.isBossRushPaused = 1; gSaveContext.isBossRushPaused = 1;
gSaveContext.entranceIndex = 107; gSaveContext.entranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
gSaveContext.cutsceneIndex = 0x8000; gSaveContext.cutsceneIndex = 0x8000;
gSaveContext.isMagicAcquired = 1; gSaveContext.isMagicAcquired = 1;

View File

@ -1,413 +0,0 @@
#include "GameControlEditor.h"
#include <string>
#include <list>
#include <unordered_map>
#include <utility>
#include <iterator>
#include <variables.h>
#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 "../../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();
}
// CurrentPort is indexed started at 1 here due to the Generic tab, instead of 0 like in InputEditorWindow
// Therefore CurrentPort - 1 must always be used inside this function instead of CurrentPort
void DrawCustomButtons() {
auto inputEditorWindow = std::reinterpret_pointer_cast<LUS::InputEditorWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Input Editor"));
inputEditorWindow->DrawControllerSelect(CurrentPort - 1);
inputEditorWindow->DrawButton("Modifier 1", BTN_MODIFIER1, CurrentPort - 1, &BtnReading);
inputEditorWindow->DrawButton("Modifier 2", BTN_MODIFIER2, CurrentPort - 1, &BtnReading);
}
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");
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("gFirstPersonCameraSensitivity");
}
}
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("Free Look/Third-person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Enable Free Look", "gFreeCamera");
DrawHelpIcon("Enables free look 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 X Axis", "gInvertXAxis");
DrawHelpIcon("Inverts the Camera X Axis in:\n-Free Look");
UIWidgets::PaddedEnhancementCheckbox("Invert Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free Look");
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementSliderFloat("Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal",
"gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
DrawHelpIcon("Changes the sensitivity of the X axis control for Free Look");
UIWidgets::PaddedEnhancementSliderFloat("Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical",
"gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
DrawHelpIcon("Changes the sensitivity of the Y axis control for Free Look");
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
"gFreeCameraDistMax", 100, 900, "", 185, true, false, true);
DrawHelpIcon("How far the camera sits from Link while in Free Look mode");
UIWidgets::PaddedEnhancementSliderInt("Transition Speed: %d", "##CamTranSpeed",
"gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true);
DrawHelpIcon("How quickly the camera changes to the distance specified above");
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 DrawLEDControlPanel(GameControlEditorWindow* window) {
window->BeginGroupPanelPublic("LED Colors", ImGui::GetContentRegionAvail());
static const char* ledSources[] = { "Original Tunic Colors", "Cosmetics Tunic Colors", "Health Colors",
"Original Navi Targeting Colors", "Cosmetics Navi Targeting Colors", "Custom" };
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");
if (CVarGetInteger("gLedColorSource", 1) == LED_SOURCE_CUSTOM) {
UIWidgets::Spacer(3);
auto port1Color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
ImVec4 colorVec = { port1Color.r / 255.0f, port1Color.g / 255.0f, port1Color.b / 255.0f, 1.0f };
if (ImGui::ColorEdit3("", (float*)&colorVec, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) {
Color_RGB8 color;
color.r = colorVec.x * 255.0;
color.g = colorVec.y * 255.0;
color.b = colorVec.z * 255.0;
CVarSetColor24("gLedPort1Color", color);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
ImGui::SameLine();
ImGui::Text("Custom Color");
}
UIWidgets::PaddedEnhancementSliderFloat("Brightness: %d%%", "##LED_Brightness", "gLedBrightness",
0.0f, 1.0f, "", 1.0f, true, true);
DrawHelpIcon("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.");
window->EndGroupPanelPublic(0);
}
void GameControlEditorWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Game Controls Configuration", &mIsVisible)) {
ImGui::BeginTabBar("##CustomControllers");
if (ImGui::BeginTabItem("Generic")) {
CurrentPort = 0;
ImGui::EndTabItem();
}
for (int i = 1; i <= 4; i++) {
if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i).c_str())) {
CurrentPort = i;
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
if (CurrentPort == 0) {
DrawOcarinaControlPanel(this);
DrawCameraControlPanel(this);
DrawDpadControlPanel(this);
DrawMiscControlPanel(this);
} else {
DrawCustomButtons();
if (CurrentPort == 1 && LUS::Context::GetInstance()->GetControlDeck()->GetDeviceFromPortIndex(0)->CanSetLed()) {
DrawLEDControlPanel(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

@ -0,0 +1,520 @@
#include "InputViewer.h"
#include "public/bridge/consolevariablebridge.h"
#include "libultraship/libultra/controller.h"
#include "Context.h"
#include "soh/OTRGlobals.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui.h>
#include <spdlog/spdlog.h>
#include <cmath>
#include "../../UIWidgets.hpp"
// Text colors
static ImVec4 textColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
static ImVec4 range1Color = ImVec4(1.0f, 0.7f, 0, 1.0f);
static ImVec4 range2Color = ImVec4(0, 1.0f, 0, 1.0f);
static const char* buttonOutlineOptions[4] = { "Always Shown", "Shown Only While Not Pressed",
"Shown Only While Pressed", "Always Hidden" };
static const char* stickModeOptions[3] = { "Always", "While In Use", "Never" };
static Color_RGBA8 vec2Color(ImVec4 vec) {
Color_RGBA8 color;
color.r = vec.x * 255.0;
color.g = vec.y * 255.0;
color.b = vec.z * 255.0;
color.a = vec.w * 255.0;
return color;
}
static ImVec4 color2Vec(Color_RGBA8 color) {
return ImVec4(color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
}
InputViewer::~InputViewer() {
SPDLOG_TRACE("destruct input viewer");
}
void InputViewer::RenderButton(std::string btnTexture, std::string btnOutlineTexture, int state, ImVec2 size,
int outlineMode) {
const ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetNextItemAllowOverlap();
// Render Outline based on settings
if (outlineMode == BUTTON_OUTLINE_ALWAYS_SHOWN || (outlineMode == BUTTON_OUTLINE_NOT_PRESSED && !state) ||
(outlineMode == BUTTON_OUTLINE_PRESSED && state)) {
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(btnOutlineTexture), size,
ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
// Render button if pressed
if (state) {
ImGui::SetCursorPos(pos);
ImGui::SetNextItemAllowOverlap();
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(btnTexture), size,
ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
}
void InputViewer::DrawElement() {
if (CVarGetInteger(CVAR_WINDOW("InputViewer"), 0)) {
static bool sButtonTexturesLoaded = false;
if (!sButtonTexturesLoaded) {
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage(
"Input-Viewer-Background", "textures/buttons/InputViewerBackground.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("A-Btn", "textures/buttons/ABtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("B-Btn", "textures/buttons/BBtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("L-Btn", "textures/buttons/LBtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("R-Btn", "textures/buttons/RBtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Z-Btn", "textures/buttons/ZBtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Start-Btn",
"textures/buttons/StartBtn.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Left", "textures/buttons/CLeft.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Right", "textures/buttons/CRight.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Up", "textures/buttons/CUp.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Down", "textures/buttons/CDown.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Analog-Stick",
"textures/buttons/AnalogStick.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Left",
"textures/buttons/DPadLeft.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Right",
"textures/buttons/DPadRight.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Up", "textures/buttons/DPadUp.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Down",
"textures/buttons/DPadDown.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Right-Stick",
"textures/buttons/RightStick.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("A-Btn Outline",
"textures/buttons/ABtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("B-Btn Outline",
"textures/buttons/BBtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("L-Btn Outline",
"textures/buttons/LBtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("R-Btn Outline",
"textures/buttons/RBtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Z-Btn Outline",
"textures/buttons/ZBtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Start-Btn Outline",
"textures/buttons/StartBtnOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Left Outline",
"textures/buttons/CLeftOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Right Outline",
"textures/buttons/CRightOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Up Outline",
"textures/buttons/CUpOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Down Outline",
"textures/buttons/CDownOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Analog-Stick Outline",
"textures/buttons/AnalogStickOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Left Outline",
"textures/buttons/DPadLeftOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Right Outline",
"textures/buttons/DPadRightOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Up Outline",
"textures/buttons/DPadUpOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Down Outline",
"textures/buttons/DPadDownOutline.png");
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Right-Stick Outline",
"textures/buttons/RightStickOutline.png");
sButtonTexturesLoaded = true;
}
ImVec2 mainPos = ImGui::GetWindowPos();
ImVec2 size = ImGui::GetContentRegionAvail();
#ifdef __WIIU__
const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f) * 2.0f;
#else
const float scale = CVarGetFloat(CVAR_INPUT_VIEWER("Scale"), 1.0f);
#endif
const int showAnalogAngles = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), 0);
const int buttonOutlineMode = CVarGetInteger(CVAR_INPUT_VIEWER("ButtonOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED);
ImVec2 bgSize = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureSize("Input-Viewer-Background");
ImVec2 scaledBGSize = ImVec2(bgSize.x * scale, bgSize.y * scale);
ImGui::SetNextWindowSize(ImVec2(
scaledBGSize.x + 20,
scaledBGSize.y +
(showAnalogAngles ? ImGui::CalcTextSize("X").y : 0) * scale * CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f) + 20));
ImGui::SetNextWindowContentSize(
ImVec2(scaledBGSize.x, scaledBGSize.y + (showAnalogAngles ? 15 : 0) * scale *
CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f)));
ImGui::SetNextWindowPos(
ImVec2(mainPos.x + size.x - scaledBGSize.x - 30, mainPos.y + size.y - scaledBGSize.y - 30),
ImGuiCond_FirstUseEver);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
OSContPad* pads = Ship::Context::GetInstance()->GetControlDeck()->GetPads();
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoFocusOnAppearing;
if (!CVarGetInteger(CVAR_INPUT_VIEWER("EnableDragging"), 1)) {
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
}
if (pads != nullptr && ImGui::Begin("Input Viewer", nullptr, windowFlags)) {
ImGui::SetCursorPos(ImVec2(10, 10));
const ImVec2 aPos = ImGui::GetCursorPos();
if (CVarGetInteger(CVAR_INPUT_VIEWER("ShowBackground"), 1)) {
ImGui::SetNextItemAllowOverlap();
// Background
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Input-Viewer-Background"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
// A/B
if (CVarGetInteger(CVAR_INPUT_VIEWER("BBtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("B-Btn", "B-Btn Outline", pads[0].button & BTN_B, scaledBGSize, buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("ABtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("A-Btn", "A-Btn Outline", pads[0].button & BTN_A, scaledBGSize, buttonOutlineMode);
}
// C buttons
if (CVarGetInteger(CVAR_INPUT_VIEWER("CUp"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("C-Up", "C-Up Outline", pads[0].button & BTN_CUP, scaledBGSize, buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("CLeft"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("C-Left", "C-Left Outline", pads[0].button & BTN_CLEFT, scaledBGSize, buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("CRight"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("C-Right", "C-Right Outline", pads[0].button & BTN_CRIGHT, scaledBGSize,
buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("CDown"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("C-Down", "C-Down Outline", pads[0].button & BTN_CDOWN, scaledBGSize, buttonOutlineMode);
}
// L/R/Z
if (CVarGetInteger(CVAR_INPUT_VIEWER("LBtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("L-Btn", "L-Btn Outline", pads[0].button & BTN_L, scaledBGSize, buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("RBtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("R-Btn", "R-Btn Outline", pads[0].button & BTN_R, scaledBGSize, buttonOutlineMode);
}
if (CVarGetInteger(CVAR_INPUT_VIEWER("ZBtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Z-Btn", "Z-Btn Outline", pads[0].button & BTN_Z, scaledBGSize, buttonOutlineMode);
}
// Start
if (CVarGetInteger(CVAR_INPUT_VIEWER("StartBtn"), 1)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Start-Btn", "Start-Btn Outline", pads[0].button & BTN_START, scaledBGSize,
buttonOutlineMode);
}
// Dpad
if (CVarGetInteger(CVAR_INPUT_VIEWER("Dpad"), 0)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Dpad-Left", "Dpad-Left Outline", pads[0].button & BTN_DLEFT, scaledBGSize,
buttonOutlineMode);
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Dpad-Right", "Dpad-Right Outline", pads[0].button & BTN_DRIGHT, scaledBGSize,
buttonOutlineMode);
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Dpad-Up", "Dpad-Up Outline", pads[0].button & BTN_DUP, scaledBGSize, buttonOutlineMode);
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
RenderButton("Dpad-Down", "Dpad-Down Outline", pads[0].button & BTN_DDOWN, scaledBGSize,
buttonOutlineMode);
}
const bool analogStickIsInDeadzone = !pads[0].stick_x && !pads[0].stick_y;
const bool rightStickIsInDeadzone = !pads[0].right_stick_x && !pads[0].right_stick_y;
// Analog Stick
const int analogOutlineMode =
CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), STICK_MODE_ALWAYS_SHOWN);
const float maxStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.Movement"), 12);
if (analogOutlineMode == STICK_MODE_ALWAYS_SHOWN ||
(analogOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Analog-Stick Outline"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
const int analogStickMode =
CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), STICK_MODE_ALWAYS_SHOWN);
if (analogStickMode == STICK_MODE_ALWAYS_SHOWN ||
(analogStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(
ImVec2(aPos.x + maxStickDistance * ((float)(pads[0].stick_x) / MAX_AXIS_RANGE) * scale,
aPos.y - maxStickDistance * ((float)(pads[0].stick_y) / MAX_AXIS_RANGE) * scale));
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Analog-Stick"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
// Right Stick
const float maxRightStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.Movement"), 7);
const int rightOutlineMode =
CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), STICK_MODE_ALWAYS_HIDDEN);
if (rightOutlineMode == STICK_MODE_ALWAYS_SHOWN ||
(rightOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Right-Stick Outline"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
const int rightStickMode =
CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), STICK_MODE_ALWAYS_HIDDEN);
if (rightStickMode == STICK_MODE_ALWAYS_SHOWN ||
(rightStickMode == STICK_MODE_HIDDEN_IN_DEADZONE && !rightStickIsInDeadzone)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(
ImVec2(aPos.x + maxRightStickDistance * ((float)(pads[0].right_stick_x) / MAX_AXIS_RANGE) * scale,
aPos.y - maxRightStickDistance * ((float)(pads[0].right_stick_y) / MAX_AXIS_RANGE) * scale));
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Right-Stick"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
}
// Analog stick angle text
if (showAnalogAngles) {
ImGui::SetCursorPos(ImVec2(aPos.x + 10 + CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Offset"), 0) * scale,
scaledBGSize.y + aPos.y + 10));
// Scale font with input viewer scale
float oldFontScale = ImGui::GetFont()->Scale;
ImGui::GetFont()->Scale *= scale * CVarGetFloat(CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 1.0f);
ImGui::PushFont(ImGui::GetFont());
// Calculate polar R coordinate from X and Y angles, squared to avoid sqrt
const float rSquared = pads[0].stick_x * pads[0].stick_x + pads[0].stick_y * pads[0].stick_y;
// ESS range
const int range1Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Min"), 8);
const int range1Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Max"), 27);
// Walking speed range
const int range2Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Min"), 27);
const int range2Max = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Max"), 62);
// Push color based on angle ranges
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), 0) &&
(rSquared >= (range1Min * range1Min)) && (rSquared < (range1Max * range1Max))) {
ImGui::PushStyleColor(
ImGuiCol_Text,
color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color"), vec2Color(range1Color))));
} else if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0) &&
(rSquared >= (range2Min * range2Min)) && (rSquared < (range2Max * range2Max))) {
ImGui::PushStyleColor(
ImGuiCol_Text,
color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color"), vec2Color(range2Color))));
} else {
ImGui::PushStyleColor(ImGuiCol_Text, color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor"),
vec2Color(textColor))));
}
// Render text
ImGui::Text("X: %-3d Y: %-3d", pads[0].stick_x, pads[0].stick_y);
// Restore original color
ImGui::PopStyleColor();
// Restore original font scale
ImGui::GetFont()->Scale = oldFontScale;
ImGui::PopFont();
}
ImGui::End();
}
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}
}
InputViewerSettingsWindow::~InputViewerSettingsWindow() {
SPDLOG_TRACE("destruct input viewer settings window");
}
void InputViewerSettingsWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(450, 525), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Input Viewer Settings", &mIsVisible)) {
// gInputViewer.Scale
UIWidgets::EnhancementSliderFloat("Input Viewer Scale: %.2f", "##Input", CVAR_INPUT_VIEWER("Scale"), 0.1f, 5.0f, "",
1.0f, false, true);
UIWidgets::Tooltip("Sets the on screen size of the input viewer");
// gInputViewer.EnableDragging
UIWidgets::EnhancementCheckbox("Enable Dragging", CVAR_INPUT_VIEWER("EnableDragging"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.ShowBackground
UIWidgets::EnhancementCheckbox("Show Background Layer", CVAR_INPUT_VIEWER("ShowBackground"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
UIWidgets::PaddedSeparator(true, true);
if (ImGui::CollapsingHeader("Buttons")) {
// gInputViewer.ABtn
UIWidgets::EnhancementCheckbox("Show A-Button Layers", CVAR_INPUT_VIEWER("ABtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.BBtn
UIWidgets::EnhancementCheckbox("Show B-Button Layers", CVAR_INPUT_VIEWER("BBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.CUp
UIWidgets::EnhancementCheckbox("Show C-Up Layers", CVAR_INPUT_VIEWER("CUp"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.CRight
UIWidgets::EnhancementCheckbox("Show C-Right Layers", CVAR_INPUT_VIEWER("CRight"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.CDown
UIWidgets::EnhancementCheckbox("Show C-Down Layers", CVAR_INPUT_VIEWER("CDown"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.CLeft
UIWidgets::EnhancementCheckbox("Show C-Left Layers", CVAR_INPUT_VIEWER("CLeft"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.LBtn
UIWidgets::EnhancementCheckbox("Show L-Button Layers", CVAR_INPUT_VIEWER("LBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.RBtn
UIWidgets::EnhancementCheckbox("Show R-Button Layers", CVAR_INPUT_VIEWER("RBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.ZBtn
UIWidgets::EnhancementCheckbox("Show Z-Button Layers", CVAR_INPUT_VIEWER("ZBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.StartBtn
UIWidgets::EnhancementCheckbox("Show Start Button Layers", CVAR_INPUT_VIEWER("StartBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
// gInputViewer.Dpad
UIWidgets::EnhancementCheckbox("Show D-Pad Layers", CVAR_INPUT_VIEWER("Dpad"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, false);
// gInputViewer.ButtonOutlineMode
UIWidgets::PaddedText("Button Outlines/Backgrounds", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("ButtonOutlineMode"), buttonOutlineOptions,
BUTTON_OUTLINE_NOT_PRESSED);
UIWidgets::Tooltip(
"Sets the desired visibility behavior for the button outline/background layers. Useful for "
"custom input viewers.");
UIWidgets::PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Analog Stick")) {
// gInputViewer.AnalogStick.VisibilityMode
UIWidgets::PaddedText("Analog Stick Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), stickModeOptions,
STICK_MODE_ALWAYS_SHOWN);
UIWidgets::Tooltip(
"Determines the conditions under which the moving layer of the analog stick texture is visible.");
// gInputViewer.AnalogStick.OutlineMode
UIWidgets::PaddedText("Analog Stick Outline/Background Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), stickModeOptions,
STICK_MODE_ALWAYS_SHOWN);
UIWidgets::Tooltip(
"Determines the conditions under which the analog stick outline/background texture is visible.");
// gInputViewer.AnalogStick.Movement
UIWidgets::EnhancementSliderInt("Analog Stick Movement: %dpx", "##AnalogMovement",
CVAR_INPUT_VIEWER("AnalogStick.Movement"), 0, 200, "", 12, true);
UIWidgets::Tooltip(
"Sets the distance to move the analog stick in the input viewer. Useful for custom input viewers.");
UIWidgets::PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Additional (\"Right\") Stick")) {
// gInputViewer.RightStick.VisibilityMode
UIWidgets::PaddedText("Right Stick Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), stickModeOptions,
STICK_MODE_HIDDEN_IN_DEADZONE);
UIWidgets::Tooltip(
"Determines the conditions under which the moving layer of the right stick texture is visible.");
// gInputViewer.RightStick.OutlineMode
UIWidgets::PaddedText("Right Stick Outline/Background Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), stickModeOptions,
STICK_MODE_HIDDEN_IN_DEADZONE);
UIWidgets::Tooltip(
"Determines the conditions under which the right stick outline/background texture is visible.");
// gInputViewer.RightStick.Movement
UIWidgets::EnhancementSliderInt("Right Stick Movement: %dpx", "##RightMovement",
CVAR_INPUT_VIEWER("RightStick.Movement"), 0, 200, "", 7, true);
UIWidgets::Tooltip(
"Sets the distance to move the right stick in the input viewer. Useful for custom input viewers.");
UIWidgets::PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Analog Angle Values")) {
// gAnalogAngles
UIWidgets::EnhancementCheckbox("Show Analog Stick Angle Values", CVAR_INPUT_VIEWER("AnalogAngles.Enabled"));
UIWidgets::Tooltip("Displays analog stick angle values in the input viewer");
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), 0)) {
// gInputViewer.AnalogAngles.TextColor
if (ImGui::ColorEdit4("Text Color", (float*)&textColor)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor"), vec2Color(textColor));
}
// gAnalogAngleScale
UIWidgets::EnhancementSliderFloat("Angle Text Scale: %.2f%%", "##AnalogAngleScale",
CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 0.1f, 5.0f, "", 1.0f, true, true);
// gInputViewer.AnalogAngles.Offset
UIWidgets::EnhancementSliderInt("Angle Text Offset: %dpx", "##AnalogAngleOffset",
CVAR_INPUT_VIEWER("AnalogAngles.Offset"), 0, 400, "", 0, true);
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.AnalogAngles.Range1.Enabled
UIWidgets::EnhancementCheckbox("Highlight ESS Position", CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"));
UIWidgets::Tooltip(
"Highlights the angle value text when the analog stick is in ESS position (on flat ground)");
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), 0)) {
// gInputViewer.AnalogAngles.Range1.Color
if (ImGui::ColorEdit4("ESS Color", (float*)&range1Color)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color"), vec2Color(range1Color));
}
}
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.AnalogAngles.Range2.Enabled
UIWidgets::EnhancementCheckbox("Highlight Walking Speed Angles",
CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"));
UIWidgets::Tooltip("Highlights the angle value text when the analog stick is at an angle that would "
"produce a walking speed (on flat ground)\n\n"
"Useful for 1.0 Empty Jumpslash Quick Put Away");
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0)) {
// gInputViewer.AnalogAngles.Range2.Color
if (ImGui::ColorEdit4("Walking Speed Color", (float*)&range2Color)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color"), vec2Color(range2Color));
}
}
}
}
ImGui::End();
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <libultraship/libultraship.h>
#define CVAR_INPUT_VIEWER(var) "gInputViewer." var
typedef enum {
BUTTON_OUTLINE_ALWAYS_SHOWN,
BUTTON_OUTLINE_NOT_PRESSED,
BUTTON_OUTLINE_PRESSED,
BUTTON_OUTLINE_ALWAYS_HIDDEN
} ButtonOutlineMode;
typedef enum {
STICK_MODE_ALWAYS_SHOWN,
STICK_MODE_HIDDEN_IN_DEADZONE,
STICK_MODE_ALWAYS_HIDDEN,
} StickMode;
class InputViewer : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void InitElement() override {};
void DrawElement() override;
void UpdateElement() override {};
InputViewer();
~InputViewer();
void Draw();
private:
void RenderButton(std::string btn, std::string btnOutline, int state, ImVec2 size, int outlineMode);
};
class InputViewerSettingsWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void InitElement() override {};
void DrawElement() override;
void UpdateElement() override {};
InputViewerSettingsWindow();
~InputViewerSettingsWindow();
void Draw();
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
#pragma once
#include "stdint.h"
#include <libultraship/libultraship.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui.h>
#include <unordered_map>
#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 Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~SohInputEditorWindow();
void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading);
void DrawInputChip(const char* buttonName, ImVec4 color);
void DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone = 0, bool gyro = false);
void DrawControllerSchema();
bool TestingRumble();
protected:
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
private:
void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, Ship::Direction direction,
ImVec4 color);
void DrawButtonLine(const char* buttonName, uint8_t port, uint16_t bitmask, ImVec4 color);
void DrawButtonLineEditMappingButton(uint8_t port, uint16_t bitmask, std::string id);
void DrawButtonLineAddMappingButton(uint8_t port, uint16_t bitmask);
void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction, std::string id);
void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction);
void DrawStickSection(uint8_t port, uint8_t stick, int32_t id, ImVec4 color);
void DrawRumbleSection(uint8_t port);
void DrawRemoveRumbleMappingButton(uint8_t port, std::string id);
void DrawAddRumbleMappingButton(uint8_t port);
void DrawLEDSection(uint8_t port);
void DrawRemoveLEDMappingButton(uint8_t port, std::string id);
void DrawAddLEDMappingButton(uint8_t port);
void DrawGyroSection(uint8_t port);
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;
std::shared_ptr<Ship::ControllerRumbleMapping> mRumbleMappingToTest;
// mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... }
std::unordered_map<uint8_t, std::unordered_map<uint16_t, std::vector<std::string>>> mBitmaskToMappingIds;
// mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... }
std::unordered_map<uint8_t,
std::unordered_map<uint8_t, std::unordered_map<Ship::Direction, std::vector<std::string>>>>
mStickDirectionToMappingIds;
void UpdateBitmaskToMappingIds(uint8_t port);
void UpdateStickDirectionToMappingIds(uint8_t port);
void GetButtonColorsForLUSDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor);
void DrawLinkTab();
void DrawIvanTab();
void DrawDebugPortTab(uint8_t portIndex, std::string customName = "");
void DrawDevicesTab();
std::set<uint16_t> mButtonsBitmasks;
std::set<uint16_t> mDpadBitmasks;
std::set<uint16_t> mModifierButtonsBitmasks;
void DrawButtonDeviceIcons(uint8_t portIndex, std::set<uint16_t> bitmasks);
void DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick);
void DrawRumbleDeviceIcons(uint8_t portIndex);
void DrawGyroDeviceIcons(uint8_t portIndex);
void DrawLEDDeviceIcons(uint8_t portIndex);
bool mInputEditorPopupOpen;
void DrawSetDefaultsButton(uint8_t portIndex);
void DrawClearAllButton(uint8_t portIndex);
};

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,29 @@
ResourceMgr_UnpatchGfxByName(path, name); \ ResourceMgr_UnpatchGfxByName(path, name); \
} }
// Not to be confused with tabs, groups are 1:1 with the boxes shown in the UI, grouping them allows us to reset/randomize
// every item in a group at once. If you are looking for tabs they are rendered manually in ImGui in `DrawCosmeticsEditor`
typedef enum {
COSMETICS_GROUP_LINK,
COSMETICS_GROUP_MIRRORSHIELD,
COSMETICS_GROUP_SWORDS,
COSMETICS_GROUP_GLOVES,
COSMETICS_GROUP_EQUIPMENT,
COSMETICS_GROUP_CONSUMABLE,
COSMETICS_GROUP_HUD,
COSMETICS_GROUP_KALEIDO,
COSMETICS_GROUP_TITLE,
COSMETICS_GROUP_NPC,
COSMETICS_GROUP_WORLD,
COSMETICS_GROUP_MAGIC,
COSMETICS_GROUP_ARROWS,
COSMETICS_GROUP_SPIN_ATTACK,
COSMETICS_GROUP_TRAILS,
COSMETICS_GROUP_NAVI,
COSMETICS_GROUP_IVAN,
COSMETICS_GROUP_MAX
} CosmeticGroup;
typedef struct { typedef struct {
const std::string Name; const std::string Name;
const std::string ToolTip; const std::string ToolTip;
@ -26,10 +49,12 @@ static ImGuiTableColumnFlags FlagsCell = ImGuiTableColumnFlags_WidthStretch | Im
void InitCosmeticsEditor();//Init the menu itself void InitCosmeticsEditor();//Init the menu itself
ImVec4 GetRandomValue(int MaximumPossible); ImVec4 GetRandomValue(int MaximumPossible);
void CosmeticsEditor_RandomizeAll(); void CosmeticsEditor_RandomizeAll();
void CosmeticsEditor_RandomizeGroup(CosmeticGroup group);
void CosmeticsEditor_ResetAll(); void CosmeticsEditor_ResetAll();
void CosmeticsEditor_ResetGroup(CosmeticGroup group);
void ApplyOrResetCustomGfxPatches(bool manualChange = true); void ApplyOrResetCustomGfxPatches(bool manualChange = true);
class CosmeticsEditorWindow : public LUS::GuiWindow { class CosmeticsEditorWindow : public Ship::GuiWindow {
public: public:
using GuiWindow::GuiWindow; using GuiWindow::GuiWindow;

View File

@ -1,5 +1,6 @@
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include <string> #include <string>
#include "soh/OTRGlobals.h"
extern "C" { extern "C" {
#include <libultraship/libultra.h> #include <libultraship/libultra.h>
@ -81,7 +82,7 @@ void PatchDekuStickTextureOverflow() {
const char* dlist = gLinkChildLinkDekuStickDL; const char* dlist = gLinkChildLinkDekuStickDL;
int start = 5; int start = 5;
if (!CVarGetInteger("gFixTexturesOOB", 0)) { if (!CVarGetInteger(CVAR_ENHANCEMENT("FixTexturesOOB"), 0)) {
// Unpatch the other texture fix // Unpatch the other texture fix
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
int instruction = start + (i == 0 ? 0 : i + 1); int instruction = start + (i == 0 ? 0 : i + 1);
@ -121,7 +122,7 @@ void PatchFreezardTextureOverflow() {
char patchNameBuf[24]; char patchNameBuf[24];
// Patch using custom overflowed texture // Patch using custom overflowed texture
if (!CVarGetInteger("gFixTexturesOOB", 0)) { if (!CVarGetInteger(CVAR_ENHANCEMENT("FixTexturesOOB"), 0)) {
// Unpatch the other texture fix // Unpatch the other texture fix
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
int instruction = start + (i == 0 ? 0 : i + 1); int instruction = start + (i == 0 ? 0 : i + 1);
@ -163,7 +164,7 @@ void PatchIronKnuckleTextureOverflow() {
// Until this is solved, Iron Knuckle will be hardcoded to always display with the "authentic" texture fix // Until this is solved, Iron Knuckle will be hardcoded to always display with the "authentic" texture fix
// Patch using custom overflowed texture // Patch using custom overflowed texture
// if (!CVarGetInteger("gFixTexturesOOB", 0)) { // if (!CVarGetInteger(CVAR_ENHANCEMENT("FixTexturesOOB"), 0)) {
// Unpatch the other texture fix // Unpatch the other texture fix
for (size_t i = 0; i < 7; i++) { for (size_t i = 0; i < 7; i++) {
int instruction = start + (i == 0 ? 0 : i + 1); int instruction = start + (i == 0 ? 0 : i + 1);
@ -222,7 +223,7 @@ void PatchMirroredSoldOutGI() {
G_TX_NOMIRROR | G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD), G_TX_NOMIRROR | G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
}; };
if (CVarGetInteger("gMirroredWorld", 0)) { if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) {
if (mirroredSoldOutVtx == nullptr) { if (mirroredSoldOutVtx == nullptr) {
// Copy the original vertices that we want to modify (4 at the beginning of the resource) // Copy the original vertices that we want to modify (4 at the beginning of the resource)
mirroredSoldOutVtx = (Vtx*)malloc(sizeof(Vtx) * 4); mirroredSoldOutVtx = (Vtx*)malloc(sizeof(Vtx) * 4);
@ -269,7 +270,7 @@ void PatchMirroredSunSongEtching() {
G_TX_NOMIRROR | G_TX_CLAMP, 7, 5, G_TX_NOLOD, G_TX_NOLOD) G_TX_NOMIRROR | G_TX_CLAMP, 7, 5, G_TX_NOLOD, G_TX_NOLOD)
}; };
if (CVarGetInteger("gMirroredWorld", 0)) { if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) {
if (mirroredSunSongVtx == nullptr) { if (mirroredSunSongVtx == nullptr) {
// Copy the original vertices that we want to modify (4 at the beginning of the resource) // Copy the original vertices that we want to modify (4 at the beginning of the resource)
mirroredSunSongVtx = (Vtx*)malloc(sizeof(Vtx) * 4); mirroredSunSongVtx = (Vtx*)malloc(sizeof(Vtx) * 4);

View File

@ -1,4 +1,4 @@
#ifdef ENABLE_CROWD_CONTROL #ifdef ENABLE_REMOTE_CONTROL
#include "CrowdControl.h" #include "CrowdControl.h"
#include "CrowdControlTypes.h" #include "CrowdControlTypes.h"
@ -17,25 +17,17 @@ extern "C" {
extern PlayState* gPlayState; extern PlayState* gPlayState;
} }
void CrowdControl::Init() {
SDLNet_Init();
}
void CrowdControl::Shutdown() {
SDLNet_Quit();
}
void CrowdControl::Enable() { void CrowdControl::Enable() {
if (isEnabled) { if (isEnabled) {
return; return;
} }
if (SDLNet_ResolveHost(&ip, "127.0.0.1", 43384) == -1) {
SPDLOG_ERROR("[CrowdControl] SDLNet_ResolveHost: {}", SDLNet_GetError());
}
isEnabled = true; isEnabled = true;
ccThreadReceive = std::thread(&CrowdControl::ListenToServer, this); GameInteractor::Instance->EnableRemoteInteractor();
GameInteractor::Instance->RegisterRemoteJsonHandler([&](nlohmann::json payload) {
HandleRemoteData(payload);
});
ccThreadProcess = std::thread(&CrowdControl::ProcessActiveEffects, this); ccThreadProcess = std::thread(&CrowdControl::ProcessActiveEffects, this);
} }
@ -45,87 +37,42 @@ void CrowdControl::Disable() {
} }
isEnabled = false; isEnabled = false;
ccThreadReceive.join();
ccThreadProcess.join(); ccThreadProcess.join();
GameInteractor::Instance->DisableRemoteInteractor();
} }
void CrowdControl::ListenToServer() { void CrowdControl::HandleRemoteData(nlohmann::json payload) {
while (isEnabled) { Effect* incomingEffect = ParseMessage(payload);
while (!connected && isEnabled) { if (!incomingEffect) {
SPDLOG_TRACE("[CrowdControl] Attempting to make connection to server..."); return;
tcpsock = SDLNet_TCP_Open(&ip); }
if (tcpsock) { // If effect is not a timed effect, execute and return result.
connected = true; if (!incomingEffect->timeRemaining) {
SPDLOG_TRACE("[CrowdControl] Connection to server established!"); EffectResult result = CrowdControl::ExecuteEffect(incomingEffect);
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result);
} else {
// If another timed effect is already active that conflicts with the incoming effect.
bool isConflictingEffectActive = false;
for (Effect* effect : activeEffects) {
if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) {
isConflictingEffectActive = true;
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry);
break; break;
} }
} }
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1); if (!isConflictingEffectActive) {
if (tcpsock) { // Check if effect can be applied, if it can't, let CC know.
SDLNet_TCP_AddSocket(socketSet, tcpsock); EffectResult result = CrowdControl::CanApplyEffect(incomingEffect);
} if (result == EffectResult::Retry || result == EffectResult::Failure) {
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result);
// Listen to socket messages return;
while (connected && tcpsock && isEnabled) {
// we check first if socket has data, to not block in the TCP_Recv
int socketsReady = SDLNet_CheckSockets(socketSet, 0);
if (socketsReady == -1) {
SPDLOG_ERROR("[CrowdControl] SDLNet_CheckSockets: {}", SDLNet_GetError());
break;
} }
if (socketsReady == 0) { activeEffectsMutex.lock();
continue; activeEffects.push_back(incomingEffect);
} activeEffectsMutex.unlock();
int len = SDLNet_TCP_Recv(tcpsock, &received, sizeof(received));
if (!len || !tcpsock || len == -1) {
SPDLOG_ERROR("[CrowdControl] SDLNet_TCP_Recv: {}", SDLNet_GetError());
break;
}
Effect* incomingEffect = ParseMessage(received);
if (!incomingEffect) {
continue;
}
// If effect is not a timed effect, execute and return result.
if (!incomingEffect->timeRemaining) {
EffectResult result = CrowdControl::ExecuteEffect(incomingEffect);
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
} else {
// If another timed effect is already active that conflicts with the incoming effect.
bool isConflictingEffectActive = false;
for (Effect* effect : activeEffects) {
if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) {
isConflictingEffectActive = true;
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry);
break;
}
}
if (!isConflictingEffectActive) {
// Check if effect can be applied, if it can't, let CC know.
EffectResult result = CrowdControl::CanApplyEffect(incomingEffect);
if (result == EffectResult::Retry || result == EffectResult::Failure) {
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
continue;
}
activeEffectsMutex.lock();
activeEffects.push_back(incomingEffect);
activeEffectsMutex.unlock();
}
}
}
if (connected) {
SDLNet_TCP_Close(tcpsock);
connected = false;
SPDLOG_TRACE("[CrowdControl] Ending Listen thread...");
} }
} }
} }
@ -147,13 +94,13 @@ void CrowdControl::ProcessActiveEffects() {
if (effect->timeRemaining <= 0) { if (effect->timeRemaining <= 0) {
it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect), it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect),
activeEffects.end()); activeEffects.end());
GameInteractor::RemoveEffect(effect->giEffect); GameInteractor::RemoveEffect(dynamic_cast<RemovableGameInteractionEffect*>(effect->giEffect));
delete effect; delete effect;
} else { } else {
// If we have a success after previously being paused, tell CC to resume timer. // If we have a success after previously being paused, tell CC to resume timer.
if (effect->isPaused) { if (effect->isPaused) {
effect->isPaused = false; effect->isPaused = false;
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Resumed); EmitMessage(effect->id, effect->timeRemaining, EffectResult::Resumed);
// If not paused before, subtract time from the timer and send a Success event if // If not paused before, subtract time from the timer and send a Success event if
// the result is different from the last time this was ran. // the result is different from the last time this was ran.
// Timed events are put on a thread that runs once per second. // Timed events are put on a thread that runs once per second.
@ -161,7 +108,7 @@ void CrowdControl::ProcessActiveEffects() {
effect->timeRemaining -= 1000; effect->timeRemaining -= 1000;
if (result != effect->lastExecutionResult) { if (result != effect->lastExecutionResult) {
effect->lastExecutionResult = result; effect->lastExecutionResult = result;
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Success); EmitMessage(effect->id, effect->timeRemaining, EffectResult::Success);
} }
} }
it++; it++;
@ -169,7 +116,7 @@ void CrowdControl::ProcessActiveEffects() {
} else { // Timed effects only do Success or Retry } else { // Timed effects only do Success or Retry
if (!effect->isPaused && effect->timeRemaining > 0) { if (!effect->isPaused && effect->timeRemaining > 0) {
effect->isPaused = true; effect->isPaused = true;
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Paused); EmitMessage(effect->id, effect->timeRemaining, EffectResult::Paused);
} }
it++; it++;
} }
@ -182,7 +129,7 @@ void CrowdControl::ProcessActiveEffects() {
SPDLOG_TRACE("[CrowdControl] Ending Process thread..."); SPDLOG_TRACE("[CrowdControl] Ending Process thread...");
} }
void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status) { void CrowdControl::EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status) {
nlohmann::json payload; nlohmann::json payload;
payload["id"] = eventId; payload["id"] = eventId;
@ -190,8 +137,9 @@ void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRema
payload["timeRemaining"] = timeRemaining; payload["timeRemaining"] = timeRemaining;
payload["status"] = status; payload["status"] = status;
std::string jsonPayload = payload.dump(); SPDLOG_INFO("[CrowdControl] Sending payload:\n{}", payload.dump());
SDLNet_TCP_Send(socket, jsonPayload.c_str(), jsonPayload.size() + 1);
GameInteractor::Instance->TransmitJsonToRemote(payload);
} }
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) { CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
@ -229,13 +177,14 @@ CrowdControl::EffectResult CrowdControl::TranslateGiEnum(GameInteractionEffectQu
return result; return result;
} }
CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) { CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
nlohmann::json dataReceived = nlohmann::json::parse(payload, nullptr, false); if (!dataReceived.contains("id") || !dataReceived.contains("type")) {
if (dataReceived.is_discarded()) { SPDLOG_ERROR("[CrowdControl] Invalid payload received:\n{}", dataReceived.dump());
SPDLOG_ERROR("Error parsing JSON");
return nullptr; return nullptr;
} }
SPDLOG_INFO("[CrowdControl] Received payload:\n{}", dataReceived.dump());
Effect* effect = new Effect(); Effect* effect = new Effect();
effect->lastExecutionResult = EffectResult::Initiate; effect->lastExecutionResult = EffectResult::Initiate;
effect->id = dataReceived["id"]; effect->id = dataReceived["id"];
@ -333,13 +282,13 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
effect->category = kEffectCatDamageTaken; effect->category = kEffectCatDamageTaken;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier(); effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
effect->giEffect->parameters[0] = 2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
break; break;
case kEffectTakeDoubleDamage: case kEffectTakeDoubleDamage:
effect->category = kEffectCatDamageTaken; effect->category = kEffectCatDamageTaken;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier(); effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
effect->giEffect->parameters[0] = -2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
break; break;
case kEffectOneHitKo: case kEffectOneHitKo:
effect->category = kEffectCatDamageTaken; effect->category = kEffectCatDamageTaken;
@ -356,37 +305,37 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
effect->category = kEffectCatSpeed; effect->category = kEffectCatSpeed;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
effect->giEffect->parameters[0] = 2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
break; break;
case kEffectDecreaseSpeed: case kEffectDecreaseSpeed:
effect->category = kEffectCatSpeed; effect->category = kEffectCatSpeed;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
effect->giEffect->parameters[0] = -2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
break; break;
case kEffectLowGravity: case kEffectLowGravity:
effect->category = kEffectCatGravity; effect->category = kEffectCatGravity;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyGravity(); effect->giEffect = new GameInteractionEffect::ModifyGravity();
effect->giEffect->parameters[0] = GI_GRAVITY_LEVEL_LIGHT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_LIGHT;
break; break;
case kEffectHighGravity: case kEffectHighGravity:
effect->category = kEffectCatGravity; effect->category = kEffectCatGravity;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyGravity(); effect->giEffect = new GameInteractionEffect::ModifyGravity();
effect->giEffect->parameters[0] = GI_GRAVITY_LEVEL_HEAVY; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_HEAVY;
break; break;
case kEffectForceIronBoots: case kEffectForceIronBoots:
effect->category = kEffectCatBoots; effect->category = kEffectCatBoots;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ForceEquipBoots(); effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_IRON; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_IRON;
break; break;
case kEffectForceHoverBoots: case kEffectForceHoverBoots:
effect->category = kEffectCatBoots; effect->category = kEffectCatBoots;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ForceEquipBoots(); effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_HOVER; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_HOVER;
break; break;
case kEffectSlipperyFloor: case kEffectSlipperyFloor:
effect->category = kEffectCatSlipperyFloor; effect->category = kEffectCatSlipperyFloor;
@ -412,23 +361,23 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
// Hurt or Heal Link // Hurt or Heal Link
case kEffectEmptyHeart: case kEffectEmptyHeart:
effect->giEffect = new GameInteractionEffect::ModifyHealth(); effect->giEffect = new GameInteractionEffect::ModifyHealth();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
break; break;
case kEffectFillHeart: case kEffectFillHeart:
effect->giEffect = new GameInteractionEffect::ModifyHealth(); effect->giEffect = new GameInteractionEffect::ModifyHealth();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
break; break;
case kEffectKnockbackLinkWeak: case kEffectKnockbackLinkWeak:
effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
effect->giEffect->parameters[0] = 1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
break; break;
case kEffectKnockbackLinkStrong: case kEffectKnockbackLinkStrong:
effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
effect->giEffect->parameters[0] = 3; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 3;
break; break;
case kEffectKnockbackLinkMega: case kEffectKnockbackLinkMega:
effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
effect->giEffect->parameters[0] = 6; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 6;
break; break;
case kEffectBurnLink: case kEffectBurnLink:
effect->giEffect = new GameInteractionEffect::BurnPlayer(); effect->giEffect = new GameInteractionEffect::BurnPlayer();
@ -441,109 +390,109 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
break; break;
case kEffectKillLink: case kEffectKillLink:
effect->giEffect = new GameInteractionEffect::SetPlayerHealth(); effect->giEffect = new GameInteractionEffect::SetPlayerHealth();
effect->giEffect->parameters[0] = 0; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 0;
break; break;
// Give Items and Consumables // Give Items and Consumables
case kEffectAddHeartContainer: case kEffectAddHeartContainer:
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers(); effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
effect->giEffect->parameters[0] = 1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
break; break;
case kEffectFillMagic: case kEffectFillMagic:
effect->giEffect = new GameInteractionEffect::FillMagic(); effect->giEffect = new GameInteractionEffect::FillMagic();
break; break;
case kEffectAddRupees: case kEffectAddRupees:
effect->giEffect = new GameInteractionEffect::ModifyRupees(); effect->giEffect = new GameInteractionEffect::ModifyRupees();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
break; break;
case kEffectGiveDekuShield: case kEffectGiveDekuShield:
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
effect->giEffect->parameters[0] = ITEM_SHIELD_DEKU; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_DEKU;
break; break;
case kEffectGiveHylianShield: case kEffectGiveHylianShield:
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
effect->giEffect->parameters[0] = ITEM_SHIELD_HYLIAN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_HYLIAN;
break; break;
case kEffectRefillSticks: case kEffectRefillSticks:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_STICK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
break; break;
case kEffectRefillNuts: case kEffectRefillNuts:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_NUT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
break; break;
case kEffectRefillBombs: case kEffectRefillBombs:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_BOMB; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
break; break;
case kEffectRefillSeeds: case kEffectRefillSeeds:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_SLINGSHOT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
break; break;
case kEffectRefillArrows: case kEffectRefillArrows:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_BOW; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
break; break;
case kEffectRefillBombchus: case kEffectRefillBombchus:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
effect->giEffect->parameters[1] = ITEM_BOMBCHU; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
break; break;
// Take Items and Consumables // Take Items and Consumables
case kEffectRemoveHeartContainer: case kEffectRemoveHeartContainer:
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers(); effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
effect->giEffect->parameters[0] = -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -1;
break; break;
case kEffectEmptyMagic: case kEffectEmptyMagic:
effect->giEffect = new GameInteractionEffect::EmptyMagic(); effect->giEffect = new GameInteractionEffect::EmptyMagic();
break; break;
case kEffectRemoveRupees: case kEffectRemoveRupees:
effect->giEffect = new GameInteractionEffect::ModifyRupees(); effect->giEffect = new GameInteractionEffect::ModifyRupees();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
break; break;
case kEffectTakeDekuShield: case kEffectTakeDekuShield:
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
effect->giEffect->parameters[0] = -ITEM_SHIELD_DEKU; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_DEKU;
break; break;
case kEffectTakeHylianShield: case kEffectTakeHylianShield:
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
effect->giEffect->parameters[0] = -ITEM_SHIELD_HYLIAN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_HYLIAN;
break; break;
case kEffectTakeSticks: case kEffectTakeSticks:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_STICK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
break; break;
case kEffectTakeNuts: case kEffectTakeNuts:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_NUT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
break; break;
case kEffectTakeBombs: case kEffectTakeBombs:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_BOMB; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
break; break;
case kEffectTakeSeeds: case kEffectTakeSeeds:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_SLINGSHOT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
break; break;
case kEffectTakeArrows: case kEffectTakeArrows:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_BOW; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
break; break;
case kEffectTakeBombchus: case kEffectTakeBombchus:
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
effect->giEffect->parameters[0] = receivedParameter * -1; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
effect->giEffect->parameters[1] = ITEM_BOMBCHU; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
break; break;
// Link Size Modifiers // Link Size Modifiers
@ -551,25 +500,25 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
effect->category = kEffectCatLinkSize; effect->category = kEffectCatLinkSize;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
effect->giEffect->parameters[0] = GI_LINK_SIZE_GIANT; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_GIANT;
break; break;
case kEffectMinishLink: case kEffectMinishLink:
effect->category = kEffectCatLinkSize; effect->category = kEffectCatLinkSize;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
effect->giEffect->parameters[0] = GI_LINK_SIZE_MINISH; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_MINISH;
break; break;
case kEffectPaperLink: case kEffectPaperLink:
effect->category = kEffectCatLinkSize; effect->category = kEffectCatLinkSize;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
effect->giEffect->parameters[0] = GI_LINK_SIZE_PAPER; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_PAPER;
break; break;
case kEffectSquishedLink: case kEffectSquishedLink:
effect->category = kEffectCatLinkSize; effect->category = kEffectCatLinkSize;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
effect->giEffect->parameters[0] = GI_LINK_SIZE_SQUISHED; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_SQUISHED;
break; break;
case kEffectInvisibleLink: case kEffectInvisibleLink:
effect->category = kEffectCatLinkSize; effect->category = kEffectCatLinkSize;
@ -585,11 +534,11 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
break; break;
case kEffectSetTimeToDawn: case kEffectSetTimeToDawn:
effect->giEffect = new GameInteractionEffect::SetTimeOfDay(); effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DAWN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DAWN;
break; break;
case kEffectSetTimeToDusk: case kEffectSetTimeToDusk:
effect->giEffect = new GameInteractionEffect::SetTimeOfDay(); effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DUSK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DUSK;
break; break;
// Visual Effects // Visual Effects
@ -632,186 +581,186 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
effect->category = kEffectCatRandomButtons; effect->category = kEffectCatRandomButtons;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::PressRandomButton(); effect->giEffect = new GameInteractionEffect::PressRandomButton();
effect->giEffect->parameters[0] = 30; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 30;
break; break;
case kEffectClearCbuttons: case kEffectClearCbuttons:
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons(); effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
effect->giEffect->parameters[0] = GI_BUTTONS_CBUTTONS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_CBUTTONS;
break; break;
case kEffectClearDpad: case kEffectClearDpad:
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons(); effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
effect->giEffect->parameters[0] = GI_BUTTONS_DPAD; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_DPAD;
break; break;
// Teleport Player // Teleport Player
case kEffectTpLinksHouse: case kEffectTpLinksHouse:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_LINKSHOUSE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_LINKSHOUSE;
break; break;
case kEffectTpMinuet: case kEffectTpMinuet:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_MINUET; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_MINUET;
break; break;
case kEffectTpBolero: case kEffectTpBolero:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_BOLERO; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_BOLERO;
break; break;
case kEffectTpSerenade: case kEffectTpSerenade:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_SERENADE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_SERENADE;
break; break;
case kEffectTpRequiem: case kEffectTpRequiem:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_REQUIEM; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_REQUIEM;
break; break;
case kEffectTpNocturne: case kEffectTpNocturne:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_NOCTURNE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_NOCTURNE;
break; break;
case kEffectTpPrelude: case kEffectTpPrelude:
effect->giEffect = new GameInteractionEffect::TeleportPlayer(); effect->giEffect = new GameInteractionEffect::TeleportPlayer();
effect->giEffect->parameters[0] = GI_TP_DEST_PRELUDE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_PRELUDE;
break; break;
// Tunic Color (Bidding War) // Tunic Color (Bidding War)
case kEffectTunicRed: case kEffectTunicRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_RED; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break; break;
case kEffectTunicGreen: case kEffectTunicGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_GREEN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break; break;
case kEffectTunicBlue: case kEffectTunicBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_BLUE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break; break;
case kEffectTunicOrange: case kEffectTunicOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_ORANGE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break; break;
case kEffectTunicYellow: case kEffectTunicYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_YELLOW; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break; break;
case kEffectTunicPurple: case kEffectTunicPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_PURPLE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break; break;
case kEffectTunicPink: case kEffectTunicPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_PINK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break; break;
case kEffectTunicBrown: case kEffectTunicBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_BROWN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break; break;
case kEffectTunicBlack: case kEffectTunicBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
effect->giEffect->parameters[1] = GI_COLOR_BLACK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break; break;
// Navi Color (Bidding War) // Navi Color (Bidding War)
case kEffectNaviRed: case kEffectNaviRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_RED; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break; break;
case kEffectNaviGreen: case kEffectNaviGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_GREEN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break; break;
case kEffectNaviBlue: case kEffectNaviBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_BLUE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break; break;
case kEffectNaviOrange: case kEffectNaviOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_ORANGE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break; break;
case kEffectNaviYellow: case kEffectNaviYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_YELLOW; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break; break;
case kEffectNaviPurple: case kEffectNaviPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_PURPLE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break; break;
case kEffectNaviPink: case kEffectNaviPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_PINK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break; break;
case kEffectNaviBrown: case kEffectNaviBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_BROWN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break; break;
case kEffectNaviBlack: case kEffectNaviBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
effect->giEffect->parameters[1] = GI_COLOR_BLACK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break; break;
// Link's Hair Color (Bidding War) // Link's Hair Color (Bidding War)
case kEffectHairRed: case kEffectHairRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_RED; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break; break;
case kEffectHairGreen: case kEffectHairGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_GREEN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break; break;
case kEffectHairBlue: case kEffectHairBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_BLUE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break; break;
case kEffectHairOrange: case kEffectHairOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_ORANGE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break; break;
case kEffectHairYellow: case kEffectHairYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_YELLOW; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break; break;
case kEffectHairPurple: case kEffectHairPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_PURPLE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break; break;
case kEffectHairPink: case kEffectHairPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_PINK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break; break;
case kEffectHairBrown: case kEffectHairBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_BROWN; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break; break;
case kEffectHairBlack: case kEffectHairBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
effect->giEffect->parameters[1] = GI_COLOR_BLACK; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break; break;
default: default:

View File

@ -1,4 +1,4 @@
#ifdef ENABLE_CROWD_CONTROL #ifdef ENABLE_REMOTE_CONTROL
#ifndef _CROWDCONTROL_C #ifndef _CROWDCONTROL_C
#define _CROWDCONTROL_C #define _CROWDCONTROL_C
@ -73,33 +73,24 @@ class CrowdControl {
EffectResult lastExecutionResult; EffectResult lastExecutionResult;
} Effect; } Effect;
std::thread ccThreadReceive;
std::thread ccThreadProcess; std::thread ccThreadProcess;
TCPsocket tcpsock;
IPaddress ip;
bool isEnabled; bool isEnabled;
bool connected;
char received[512];
std::vector<Effect*> activeEffects; std::vector<Effect*> activeEffects;
std::mutex activeEffectsMutex; std::mutex activeEffectsMutex;
void ListenToServer(); void HandleRemoteData(nlohmann::json payload);
void ProcessActiveEffects(); void ProcessActiveEffects();
void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status); void EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status);
Effect* ParseMessage(char payload[512]); Effect* ParseMessage(nlohmann::json payload);
EffectResult ExecuteEffect(Effect* effect); EffectResult ExecuteEffect(Effect* effect);
EffectResult CanApplyEffect(Effect *effect); EffectResult CanApplyEffect(Effect *effect);
EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult); EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult);
public: public:
static CrowdControl* Instance; static CrowdControl* Instance;
void Init();
void Shutdown();
void Enable(); void Enable();
void Disable(); void Disable();
}; };

View File

@ -38,6 +38,7 @@ typedef enum {
TEXT_CARPET_SALESMAN_1 = 0x6077, TEXT_CARPET_SALESMAN_1 = 0x6077,
TEXT_CARPET_SALESMAN_2 = 0x6078, TEXT_CARPET_SALESMAN_2 = 0x6078,
TEXT_MARKET_GUARD_NIGHT = 0x7003, TEXT_MARKET_GUARD_NIGHT = 0x7003,
TEXT_FISHERMAN_LEAVE = 0x409E,
TEXT_SHEIK_NEED_HOOK = 0x700F, TEXT_SHEIK_NEED_HOOK = 0x700F,
TEXT_SHEIK_HAVE_HOOK = 0x7010, TEXT_SHEIK_HAVE_HOOK = 0x7010,
TEXT_SCRUB_RANDOM = 0x9000, TEXT_SCRUB_RANDOM = 0x9000,
@ -54,6 +55,22 @@ typedef enum {
TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210,
TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range
TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range
TEXT_SARIAS_SONG_CHANNELING_POWER = 0x016D,
TEXT_BEAN_SALESMAN_BUY_FOR_10 = 0x405E,
TEXT_BEAN_SALESMAN_BUY_FOR_20 = 0x405F,
TEXT_BEAN_SALESMAN_BUY_FOR_30 = 0x4060,
TEXT_BEAN_SALESMAN_BUY_FOR_40 = 0x4061,
TEXT_BEAN_SALESMAN_BUY_FOR_50 = 0x4062,
TEXT_BEAN_SALESMAN_BUY_FOR_60 = 0x4063,
TEXT_BEAN_SALESMAN_BUY_FOR_70 = 0x4064,
TEXT_BEAN_SALESMAN_BUY_FOR_80 = 0x4065,
TEXT_BEAN_SALESMAN_BUY_FOR_90 = 0x4066,
TEXT_BEAN_SALESMAN_BUY_FOR_100 = 0x4067,
TEXT_BEAN_SALESMAN_OH_WELL = 0x4068,
TEXT_BEAN_SALESMAN_NOT_ENOUGH_MONEY = 0x4069,
TEXT_BEAN_SALESMAN_SET_A_BEAN_TO_C = 0x406A,
TEXT_BEAN_SALESMAN_SOLD_OUT = 0x406B,
TEXT_BEAN_SALESMAN_WANT_TO_PLANT = 0x406C,
} TextIDs; } TextIDs;
#ifdef __cplusplus #ifdef __cplusplus

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,271 @@
#include "MessageViewer.h"
#include <soh/UIWidgets.hpp>
#include <textures/message_static/message_static.h>
#include "../custom-message/CustomMessageManager.h"
#include "functions.h"
#include "macros.h"
#include "message_data_static.h"
#include "variables.h"
#include "soh/util.h"
extern "C" u8 sMessageHasSetSfx;
void MessageViewer::InitElement() {
CustomMessageManager::Instance->AddCustomMessageTable(TABLE_ID);
mTableIdBuf = static_cast<char*>(calloc(MAX_STRING_SIZE, sizeof(char)));
mTextIdBuf = static_cast<char*>(calloc(MAX_STRING_SIZE, sizeof(char)));
mCustomMessageBuf = static_cast<char*>(calloc(MAX_STRING_SIZE, sizeof(char)));
}
void MessageViewer::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Custom Message Debugger", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}
ImGui::Text("Table ID");
ImGui::SameLine();
ImGui::InputText("##TableID", mTableIdBuf, MAX_STRING_SIZE, ImGuiInputTextFlags_CallbackCharFilter, UIWidgets::TextFilters::FilterAlphaNum);
UIWidgets::InsertHelpHoverText("Leave blank for vanilla table");
ImGui::Text("Text ID");
ImGui::SameLine();
switch (mTextIdBase) {
case DECIMAL:
ImGui::InputText("##TextID", mTextIdBuf, MAX_STRING_SIZE, ImGuiInputTextFlags_CharsDecimal);
UIWidgets::InsertHelpHoverText("Decimal Text ID of the message to load. Decimal digits only (0-9).");
break;
case HEXADECIMAL:
default:
ImGui::InputText("##TextID", mTextIdBuf, MAX_STRING_SIZE, ImGuiInputTextFlags_CharsHexadecimal);
UIWidgets::InsertHelpHoverText("Hexadecimal Text ID of the message to load. Hexadecimal digits only (0-9/A-F).");
break;
}
if (ImGui::RadioButton("Hexadecimal", &mTextIdBase, HEXADECIMAL)) {
memset(mTextIdBuf, 0, sizeof(char) * MAX_STRING_SIZE);
}
ImGui::SameLine();
if (ImGui::RadioButton("Decimal", &mTextIdBase, DECIMAL)) {
memset(mTextIdBuf, 0, sizeof(char) * MAX_STRING_SIZE);
}
ImGui::Text("Language");
ImGui::SameLine();
if (ImGui::BeginCombo("##Language", mLanguages[mLanguage])) {
// ReSharper disable CppDFAUnreachableCode
for (size_t i = 0; i < mLanguages.size(); i++) {
if (strlen(mLanguages[i]) > 0) {
if (ImGui::Selectable(mLanguages[i], i == mLanguage)) {
mLanguage = i;
}
}
}
ImGui::EndCombo();
}
UIWidgets::InsertHelpHoverText("Which language to load from the selected text ID");
if (ImGui::Button("Display Message##ExistingMessage")) {
mDisplayExistingMessageClicked = true;
}
ImGui::Text("Custom Message");
UIWidgets::InsertHelpHoverText("Enter a string using Custom Message Syntax to preview it in-game. "
"Any newline (\\n) characters inserted by the Enter key will be stripped "
"from the output.");
ImGui::InputTextMultiline("##CustomMessage", mCustomMessageBuf, MAX_STRING_SIZE);
if (ImGui::Button("Display Message##CustomMessage")) {
mDisplayCustomMessageClicked = true;
}
ImGui::End();
// ReSharper restore CppDFAUnreachableCode
}
void MessageViewer::UpdateElement() {
if (mDisplayExistingMessageClicked) {
mTableId = std::string(mTableIdBuf);
switch (mTextIdBase) {
case DECIMAL:
mTextId = std::stoi(std::string(mTextIdBuf), nullptr, 10);
break;
case HEXADECIMAL:
default:
mTextId = std::stoi(std::string(mTextIdBuf), nullptr, 16);
break;
}
DisplayExistingMessage();
mDisplayExistingMessageClicked = false;
}
if (mDisplayCustomMessageClicked) {
mCustomMessageString = std::string(mCustomMessageBuf);
std::erase(mCustomMessageString, '\n');
DisplayCustomMessage();
mDisplayCustomMessageClicked = false;
}
}
void MessageViewer::DisplayExistingMessage() const {
MessageDebug_StartTextBox(mTableId.c_str(), mTextId, mLanguage);
}
void MessageViewer::DisplayCustomMessage() const {
MessageDebug_DisplayCustomMessage(mCustomMessageString.c_str());
}
extern "C" MessageTableEntry* sNesMessageEntryTablePtr;
extern "C" MessageTableEntry* sGerMessageEntryTablePtr;
extern "C" MessageTableEntry* sFraMessageEntryTablePtr;
extern "C" MessageTableEntry* sStaffMessageEntryTablePtr;
void FindMessage(PlayState* play, const uint16_t textId, const uint8_t language) {
const char* foundSeg;
const char* nextSeg;
MessageTableEntry* messageTableEntry = sNesMessageEntryTablePtr;
Font* font;
u16 bufferId = textId;
// Use the better owl message if better owl is enabled
if (CVarGetInteger(CVAR_ENHANCEMENT("BetterOwl"), 0) != 0 && (bufferId == 0x2066 || bufferId == 0x607B ||
bufferId == 0x10C2 || bufferId == 0x10C6 || bufferId == 0x206A))
{
bufferId = 0x71B3;
}
if (language == LANGUAGE_GER)
messageTableEntry = sGerMessageEntryTablePtr;
else if (language == LANGUAGE_FRA)
messageTableEntry = sFraMessageEntryTablePtr;
// If PAL languages are not present in the OTR file, default to English
if (messageTableEntry == nullptr)
messageTableEntry = sNesMessageEntryTablePtr;
const char* seg = messageTableEntry->segment;
while (messageTableEntry->textId != 0xFFFF) {
font = &play->msgCtx.font;
if (messageTableEntry->textId == bufferId) {
foundSeg = messageTableEntry->segment;
font->charTexBuf[0] = messageTableEntry->typePos;
nextSeg = messageTableEntry->segment;
font->msgOffset = reinterpret_cast<uintptr_t>(messageTableEntry->segment);
font->msgLength = messageTableEntry->msgSize;
return;
}
messageTableEntry++;
}
font = &play->msgCtx.font;
messageTableEntry = sNesMessageEntryTablePtr;
foundSeg = messageTableEntry->segment;
font->charTexBuf[0] = messageTableEntry->typePos;
messageTableEntry++;
nextSeg = messageTableEntry->segment;
font->msgOffset = foundSeg - seg;
font->msgLength = nextSeg - foundSeg;
}
static const char* msgStaticTbl[] =
{
gDefaultMessageBackgroundTex,
gSignMessageBackgroundTex,
gNoteStaffMessageBackgroundTex,
gFadingMessageBackgroundTex,
gMessageContinueTriangleTex,
gMessageEndSquareTex,
gMessageArrowTex
};
void MessageDebug_StartTextBox(const char* tableId, uint16_t textId, uint8_t language) {
PlayState* play = gPlayState;
static int16_t messageStaticIndices[] = { 0, 1, 3, 2 };
const auto player = GET_PLAYER(gPlayState);
player->actor.flags |= ACTOR_FLAG_PLAYER_TALKED_TO;
MessageContext* msgCtx = &play->msgCtx;
msgCtx->ocarinaAction = 0xFFFF;
Font* font = &msgCtx->font;
sMessageHasSetSfx = 0;
for (u32 i = 0; i < FONT_CHAR_TEX_SIZE * 120; i += FONT_CHAR_TEX_SIZE) {
if (&font->charTexBuf[i] != nullptr) {
gSPInvalidateTexCache(play->state.gfxCtx->polyOpa.p++, reinterpret_cast<uintptr_t>(&font->charTexBuf[i]));
}
}
R_TEXT_CHAR_SCALE = 75;
R_TEXT_LINE_SPACING = 12;
R_TEXT_INIT_XPOS = 65;
char* buffer = font->msgBuf;
msgCtx->textId = textId;
if (strlen(tableId) == 0) {
FindMessage(play, textId, language);
msgCtx->msgLength = static_cast<int32_t>(font->msgLength);
const uintptr_t src = font->msgOffset;
memcpy(font->msgBuf, reinterpret_cast<void const *>(src), font->msgLength);
} else {
constexpr int maxBufferSize = sizeof(font->msgBuf);
const CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(tableId, textId);
font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition();
switch (language) {
case LANGUAGE_FRA:
font->msgLength = SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetFrench(), maxBufferSize);
break;
case LANGUAGE_GER:
font->msgLength = SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetGerman(), maxBufferSize);
break;
case LANGUAGE_ENG:
default:
font->msgLength = SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetEnglish(), maxBufferSize);
break;
}
msgCtx->msgLength = static_cast<int32_t>(font->msgLength);
}
msgCtx->textBoxProperties = font->charTexBuf[0];
msgCtx->textBoxType = msgCtx->textBoxProperties >> 4;
msgCtx->textBoxPos = msgCtx->textBoxProperties & 0xF;
const int16_t textBoxType = msgCtx->textBoxType;
// "Text Box Type"
osSyncPrintf("吹き出し種類=%d\n", msgCtx->textBoxType);
if (textBoxType < TEXTBOX_TYPE_NONE_BOTTOM) {
const char* textureName = msgStaticTbl[messageStaticIndices[textBoxType]];
memcpy(msgCtx->textboxSegment, textureName, strlen(textureName) + 1);
if (textBoxType == TEXTBOX_TYPE_BLACK) {
msgCtx->textboxColorRed = 0;
msgCtx->textboxColorGreen = 0;
msgCtx->textboxColorBlue = 0;
} else if (textBoxType == TEXTBOX_TYPE_WOODEN) {
msgCtx->textboxColorRed = 70;
msgCtx->textboxColorGreen = 50;
msgCtx->textboxColorBlue = 30;
} else if (textBoxType == TEXTBOX_TYPE_BLUE) {
msgCtx->textboxColorRed = 0;
msgCtx->textboxColorGreen = 10;
msgCtx->textboxColorBlue = 50;
} else {
msgCtx->textboxColorRed = 255;
msgCtx->textboxColorGreen = 0;
msgCtx->textboxColorBlue = 0;
}
if (textBoxType == TEXTBOX_TYPE_WOODEN) {
msgCtx->textboxColorAlphaTarget = 230;
} else if (textBoxType == TEXTBOX_TYPE_OCARINA) {
msgCtx->textboxColorAlphaTarget = 180;
} else {
msgCtx->textboxColorAlphaTarget = 170;
}
msgCtx->textboxColorAlphaCurrent = 0;
}
msgCtx->choiceNum = msgCtx->textUnskippable = msgCtx->textboxEndType = 0;
msgCtx->msgBufPos = msgCtx->unk_E3D0 = msgCtx->textDrawPos = 0;
msgCtx->talkActor = &player->actor;
msgCtx->msgMode = MSGMODE_TEXT_START;
msgCtx->stateTimer = 0;
msgCtx->textDelayTimer = 0;
msgCtx->ocarinaMode = OCARINA_MODE_00;
}
void MessageDebug_DisplayCustomMessage(const char* customMessage) {
CustomMessageManager::Instance->ClearMessageTable(MessageViewer::TABLE_ID);
CustomMessageManager::Instance->CreateMessage(MessageViewer::TABLE_ID, 0,
CustomMessage(customMessage, customMessage, customMessage));
MessageDebug_StartTextBox(MessageViewer::TABLE_ID, 0, 0);
}

View File

@ -0,0 +1,62 @@
#ifndef CUSTOMMESSAGEDEBUGGER_H
#define CUSTOMMESSAGEDEBUGGER_H
#include "z64.h"
#ifdef __cplusplus
#include "GuiWindow.h"
#include <array>
extern "C" {
#endif
/**
* \brief Pulls a message from the specified message table and kicks off the process of displaying that message
* in a text box on screen.
* \param tableId the tableId string for the table we want to pull from. Empty string for authentic/vanilla messages
* \param textId The textId corresponding to the message to display. Putting in a textId that doesn't exist will
* probably result in a crash.
* \param language The Language to display on the screen.
*/
void MessageDebug_StartTextBox(const char* tableId, uint16_t textId, uint8_t language);
/**
* \brief
* \param customMessage A string using Custom Message Syntax.
*/
void MessageDebug_DisplayCustomMessage(const char* customMessage);
#ifdef __cplusplus
}
class MessageViewer : public Ship::GuiWindow {
public:
static inline const char* TABLE_ID = "MessageViewer";
using GuiWindow::GuiWindow;
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
virtual ~MessageViewer() = default;
private:
void DisplayExistingMessage() const;
void DisplayCustomMessage() const;
static constexpr uint16_t MAX_STRING_SIZE = 1024;
static constexpr std::array<const char*, LANGUAGE_MAX> mLanguages = {"English", "German", "French"};
static constexpr int HEXADECIMAL = 0;
static constexpr int DECIMAL = 1;
char* mTableIdBuf;
std::string mTableId;
char* mTextIdBuf;
uint16_t mTextId;
int mTextIdBase = HEXADECIMAL;
size_t mLanguage = LANGUAGE_ENG;
char* mCustomMessageBuf;
std::string mCustomMessageString;
bool mDisplayExistingMessageClicked = false;
bool mDisplayCustomMessageClicked = false;
};
#endif //__cplusplus
#endif //CUSTOMMESSAGEDEBUGGER_H

View File

@ -8,9 +8,11 @@
#include <array> #include <array>
#include <bit> #include <bit>
#include <map> #include <map>
#include <unordered_map>
#include <string> #include <string>
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include <libultraship/libultraship.h> #include <libultraship/libultraship.h>
#include "soh/OTRGlobals.h"
extern "C" { extern "C" {
#include <z64.h> #include <z64.h>
@ -24,6 +26,7 @@ extern PlayState* gPlayState;
#include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h"
} }
#define DEKUNUTS_FLOWER 10
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer" #define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
typedef struct { typedef struct {
@ -107,8 +110,785 @@ void PopulateActorDropdown(int i, std::vector<Actor*>& data) {
} }
} }
//actors that don't use params at all
static std::vector<u16> noParamsActors = {
ACTOR_ARMS_HOOK,
ACTOR_ARROW_FIRE,
ACTOR_ARROW_ICE,
ACTOR_ARROW_LIGHT,
ACTOR_BG_BOM_GUARD,
ACTOR_BG_DY_YOSEIZO,
ACTOR_BG_GATE_SHUTTER,
ACTOR_BG_GJYO_BRIDGE,
ACTOR_BG_HIDAN_FSLIFT,
ACTOR_BG_HIDAN_RSEKIZOU,
ACTOR_BG_HIDAN_SYOKU,
ACTOR_BG_JYA_GOROIWA,
ACTOR_BG_MIZU_UZU,
ACTOR_BG_MORI_RAKKATENJO,
ACTOR_BG_PUSHBOX,
ACTOR_BG_SPOT01_FUSYA,
ACTOR_BG_SPOT01_IDOHASHIRA,
ACTOR_BG_SPOT01_IDOMIZU,
ACTOR_BG_SPOT01_IDOSOKO,
ACTOR_BG_SPOT11_OASIS,
ACTOR_BG_SPOT15_SAKU,
ACTOR_BG_SPOT18_FUTA,
ACTOR_BG_TOKI_SWD,
ACTOR_BG_TREEMOUTH,
ACTOR_BG_VB_SIMA,
ACTOR_BOSS_DODONGO,
ACTOR_BOSS_FD,
ACTOR_BOSS_GOMA,
ACTOR_DEMO_EXT,
ACTOR_DEMO_SHD,
ACTOR_DEMO_TRE_LGT,
ACTOR_DOOR_TOKI,
ACTOR_EFC_ERUPC,
ACTOR_EN_ANI,
ACTOR_EN_AROW_TRAP,
ACTOR_EN_BIRD,
ACTOR_EN_BLKOBJ,
ACTOR_EN_BOM_BOWL_MAN,
ACTOR_EN_BOM_BOWL_PIT,
ACTOR_EN_BOM_CHU,
ACTOR_EN_BUBBLE,
ACTOR_EN_DIVING_GAME,
ACTOR_EN_DNT_DEMO,
ACTOR_EN_DNT_JIJI,
ACTOR_EN_DS,
ACTOR_EN_DU,
ACTOR_EN_EG,
ACTOR_EN_FU,
ACTOR_EN_GB,
ACTOR_EN_GE3,
ACTOR_EN_GUEST,
ACTOR_EN_HATA,
ACTOR_EN_HORSE_GANON,
ACTOR_EN_HORSE_LINK_CHILD,
ACTOR_EN_HORSE_ZELDA,
ACTOR_EN_HS2,
ACTOR_EN_JS,
ACTOR_EN_KAKASI,
ACTOR_EN_KAKASI3,
ACTOR_EN_MA1,
ACTOR_EN_MA2,
ACTOR_EN_MA3,
ACTOR_EN_MAG,
ACTOR_EN_MK,
ACTOR_EN_MS,
ACTOR_EN_NIW_LADY,
ACTOR_EN_NWC,
ACTOR_EN_OE2,
ACTOR_EN_OKARINA_EFFECT,
ACTOR_EN_RR,
ACTOR_EN_SA,
ACTOR_EN_SCENE_CHANGE,
ACTOR_EN_SKJNEEDLE,
ACTOR_EN_SYATEKI_ITM,
ACTOR_EN_SYATEKI_MAN,
ACTOR_EN_TAKARA_MAN,
ACTOR_EN_TORYO,
ACTOR_EN_VASE,
ACTOR_EN_ZL1,
ACTOR_MAGIC_DARK,
ACTOR_MAGIC_FIRE,
ACTOR_OBJ_DEKUJR,
ACTOR_OCEFF_SPOT,
ACTOR_UNSET_1,
ACTOR_UNSET_3,
ACTOR_UNSET_5,
ACTOR_UNSET_6,
ACTOR_UNSET_17,
ACTOR_UNSET_1A,
ACTOR_UNSET_1F,
ACTOR_UNSET_22,
ACTOR_UNSET_31,
ACTOR_UNSET_36,
ACTOR_UNSET_53,
ACTOR_UNSET_73,
ACTOR_UNSET_74,
ACTOR_UNSET_75,
ACTOR_UNSET_76,
ACTOR_UNSET_78,
ACTOR_UNSET_79,
ACTOR_UNSET_7A,
ACTOR_UNSET_7B,
ACTOR_UNSET_7E,
ACTOR_UNSET_7F,
ACTOR_UNSET_83,
ACTOR_UNSET_A0,
ACTOR_UNSET_B2,
ACTOR_UNSET_CE,
ACTOR_UNSET_D8,
ACTOR_UNSET_EA,
ACTOR_UNSET_EB,
ACTOR_UNSET_F2,
ACTOR_UNSET_F3,
ACTOR_UNSET_FB,
ACTOR_UNSET_109,
ACTOR_UNSET_10D,
ACTOR_UNSET_10E,
ACTOR_UNSET_128,
ACTOR_UNSET_129,
ACTOR_UNSET_134,
ACTOR_UNSET_154,
ACTOR_UNSET_15D,
ACTOR_UNSET_161,
ACTOR_UNSET_180,
ACTOR_UNSET_1AA
};
static std::unordered_map<u16, std::function<s16(s16)>> actorSpecificData;
void CreateActorSpecificData() {
if (!actorSpecificData.empty()) {
return;
}
actorSpecificData[ACTOR_EN_DEKUNUTS] = [](s16 params) -> s16 {
bool isFlower = params == DEKUNUTS_FLOWER;
s16 shotsPerRound = (params >> 8) & 0xFF;
if (shotsPerRound == 0xFF || shotsPerRound == 0) {
shotsPerRound = 1;
}
ImGui::Checkbox("Flower", &isFlower);
if (!isFlower) {
ImGui::InputScalar("Shots Per Round", ImGuiDataType_S16, &shotsPerRound);
}
return isFlower ? DEKUNUTS_FLOWER : (shotsPerRound << 8);
};
actorSpecificData[ACTOR_EN_TITE] = [](s16 params) -> s16 {
static const char* items[] = { "Blue", "Red" };
if (params == 0) {
params = -2;
}
//the + 2 is because the params are -2 & -1 instead of 0 & 1
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_AM] = [](s16 params) -> s16 {
static const char* items[] = { "Statue", "Enemy" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_ICE_TURARA] = [](s16 params) -> s16 {
static const char* items[] = { "Stalagmite", "Stalactite", "Stalactite (Regrow)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_BREAKWALL] = [](s16 params) -> s16 {
static const char* items[] = { "DC Entrance", "Wall", "KD Floor", "KD Lava Cover" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TEST] = [](s16 params) -> s16 {
static const char* items[] = { "Invisible", "1", "2", "Ceiling", "4", "5" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TANA] = [](s16 params) -> s16 {
static const char* items[] = { "Wooden", "Stone (1)", "Stone (2)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_XC] = [](s16 params) -> s16 {
static const char* items[] = { "0", "1", "2", "3", "4", "5", "Minuet", "Bolero", "Serenade", "9" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_SHOT_SUN] = [](s16 params) -> s16 {
static const char* items[] = { "Sun's Song", "Song of Storms", "LH Sun" };
if (params == 0) {
params = 0x40;
}
//the - 0x40 is because the params are 0x40 & 0x41 instead of 0 & 1
int selectedItem = params - 0x40;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem + 0x40;
}
return params;
};
actorSpecificData[ACTOR_EN_HONOTRAP] = [](s16 params) -> s16 {
static const char* items[] = { "Eye", "Flame Move", "Flame Drop" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_REEBA] = [](s16 params) -> s16 {
bool isBig = params != 0;
ImGui::Checkbox("Big", &isBig);
return isBig;
};
actorSpecificData[ACTOR_EN_TK] = [](s16 params) -> s16 {
bool canTurn = params >= 0;
ImGui::Checkbox("Can Turn", &canTurn);
return canTurn ? 0 : -1;
};
actorSpecificData[ACTOR_EN_ITEM00] = [](s16 params) -> s16 {
bool autoCollect = params & 0x8000;
ImGui::Checkbox("Automatically Collect", &autoCollect);
u8 collectibleFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item", &selectedItem, items, IM_ARRAYSIZE(items));
return autoCollect * 0x8000 + (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_OBJ_COMB] = [](s16 params) -> s16 {
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item Drop", &selectedItem, items, IM_ARRAYSIZE(items));
u8 collectibleFlag = (params & 0x3F00) >> 8;
if (selectedItem == 6) {
ImGui::InputScalar("PoH Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
}
return (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_GM] = [](s16 params) -> s16 {
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
if (switchFlag > 0x3F) {
switchFlag = 0x3F;
}
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_GIRLA] = [](s16 params) -> s16 {
static const char* items[] = {
"Deku Nuts (5)",
"Arrows (30)",
"Arrows (50)",
"Bombs (5) (25 Rupees)",
"Deku Nuts (10)",
"Deku Stick",
"Bombs (10)",
"Fish",
"Red Potion (30 Rupees)",
"Green Potion",
"Blue Potion",
"Longsword",
"Hylian Shield",
"Deku Shield",
"Goron Tunic",
"Zora Tunic",
"Heart",
"Milk Bottle",
"Weird Egg",
"19",
"20",
"Bomchu (10) [1]",
"Bomchu (20) [1]",
"Bomchu (20) [2]",
"Bomchu (10) [2]",
"Bomchu (10) [3]",
"Bomchu (20) [3]",
"Bomchu (20) [4]",
"Bomchu (10) [4]",
"Deku Seeds (30)",
"Keaton Mask",
"Spooky Mask",
"Skull Mask",
"Bunny Hood",
"Mask Of Truth",
"Zora Mask",
"Goron Mask",
"Gerudo Mask",
"Sold Out",
"Blue Fire",
"Bugs",
"Big Poe",
"Poe",
"Fairy",
"Arrows (10)",
"Bombs (20)",
"Bombs (30)",
"Bombs (5) (35 Rupees)",
"Red Potion (40 Rupees)",
"Red Potion (50 Rupees)",
"Randomizer Item"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_FIRE_ROCK] = [](s16 params) -> s16 {
static const char* items[] = {
"Spawned Falling (1)",
"Broken Piece (1)",
"Broken Piece (2)",
"Spawned Falling (2)",
//"INVALID",
"Ceiling Spot Spawner",
"On Floor"
};
int selectedItem = params > 3 ? params - 1 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem > 3 ? selectedItem + 1 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_EX_ITEM] = [](s16 params) -> s16 {
static const char* items[] = {
"Bomb Bag Bowling",
"Heart Piece Bowling",
"Bombchus Bowling",
"Bombs Bowling",
"Purple Rupee Bowling",
"Bomb Bag Counter",
"Heart Piece Counter",
"Bombchus Counter",
"Bombs Counter",
"Purple Rupee Counter",
"Green Rupee Chest",
"Blue Rupee Chest",
"Red Rupee Chest",
"13",
"14",
"Small Key Chest",
"Magic Fire",
"Magic Wind",
"Magic Dark",
"Bullet Bag"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_ELF] = [](s16 params) -> s16 {
static const char* items[] = {
"Navi",
"Revive Bottle",
"Heal Timed",
"Kokiri",
"Spawner",
"Revive Death",
"Heal",
"Heal Big"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_CLEAR_TAG] = [](s16 params) -> s16 {
static const char* items[] = {
"Cutscene", //0
"Normal", //1
"Laser" //100
};
int selectedItem = params == 100 ? 2 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem == 2 ? 100 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_BOMBF] = [](s16 params) -> s16 {
static const char* items[] = { "Flower", "Body", "Explosion" };
//the + 1 is because the params are -1, 0 & 1 instead of 0, 1 & 2
int selectedItem = params + 1;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 1;
}
return params;
};
actorSpecificData[ACTOR_EN_BOM] = [](s16 params) -> s16 {
static const char* items[] = { "Body", "Explosion" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_DOOR_WARP1] = [](s16 params) -> s16 {
static const char* items[] = {
"Blue Crystal", // -2
"Dungeon Adult",
"Dungeon Child",
"Clear Flag", // Activate on temp clear flag
"Sages", // Used by sages warping into chamber of sages during their cutscene
"Purple Crystal",
"Yellow", // The colored variants don't warp, they are cutscene setpieces
"Blue Ruto",
"Destination", // Spawning in after having taken a warp
"UNK 7",
"Orange",
"Green",
"Red"
};
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_DY_EXTRA] = [](s16 params) -> s16 {
static const char* items[] = { "Orange", "Green" };
int selectedItem = params;
if (ImGui::Combo("Color", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_SKB] = [](s16 params) -> s16 {
u8 size = params;
ImGui::InputScalar("Size", ImGuiDataType_U8, &size);
return size;
};
actorSpecificData[ACTOR_EN_WF] = [](s16 params) -> s16 {
static const char* items[] = { "Normal", "White" };
int selectedItem = params;
ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items));
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
return (switchFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_BOX] = [](s16 params) -> s16 {
/*
trasureFlag = params & 0x1F; //0b0000 0000 0001 1111
itemId = (params >> 5) & 0x7F; //0b0000 1111 1110 0000
type = (params >> 12) & 0xF; //0b1111 0000 0000 0000
*/
u8 treasureFlag = params & 0x1F;
ImGui::InputScalar("Treasure Flag", ImGuiDataType_U8, &treasureFlag);
if (treasureFlag > 0x1F) {
treasureFlag = 0x1F;
}
u8 itemId = (params >> 5) & 0x7F;
ImGui::InputScalar("Item Id", ImGuiDataType_U8, &itemId);
if (itemId > 0x7F) {
itemId = 0x7F;
}
static const char* items[] = {
"Big (Default)",
"Room Clear Big",
"Decorated Big",
"Switch Flag Fall Big",
"4",
"Small",
"6",
"Room Clear Small",
"Switch Flag Fall Small",
"9",
"10",
"Switch Flag Big"
};
int type = (params >> 12) & 0xF;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 0xF) {
type = 0xF;
}
return (type << 12) + (itemId << 5) + treasureFlag;
};
actorSpecificData[ACTOR_EN_DOOR] = [](s16 params) -> s16 {
/**
* Actor Parameters
*
* | | | |
* | Transition Index | Type | Double Door | Switch Flag OR Text Id - 0x0200
* |------------------|-------|-------------|---------------------------------
* | 0 0 0 0 0 0 | 0 0 0 | 0 | 0 0 0 0 0 0
* | 6 | 3 | 1 | 6
* |
*
* Transition Index 1111110000000000 Set by the actor engine when the door is spawned
* Type 0000001110000000
* Double Door 0000000001000000
* Switch Flag 0000000000111111 For use with the `DOOR_LOCKED` type
* Text id - 0x0200 0000000000111111 For use with the `DOOR_CHECKABLE` type
*
*/
u8 transitionIndex = params >> 10;
ImGui::InputScalar("Transition Index", ImGuiDataType_U8, &transitionIndex);
if (transitionIndex > 0x3F) {
transitionIndex = 0x3F;
}
static const char* items[] = {
"Room Load", // loads rooms
"Locked", // small key locked door
"Room Load (2)", // loads rooms
"Scene Exit", // doesn't load rooms, used for doors paired with scene transition polygons
"Ajar", // open slightly but slams shut if Link gets too close
"Checkable", // doors that display a textbox when interacting
"Evening", // unlocked between 18:00 and 21:00, Dampé's hut
"Room Load (7)" // loads rooms
};
int type = (params >> 7) & 7;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 7) {
type = 7;
}
bool doubleDoor = ((params >> 6) & 1) != 0;
ImGui::Checkbox("Double Door", &doubleDoor);
u8 lowerBits = params & 0x3F;
if (type == 1) {
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else if (type == 5) {
ImGui::InputScalar("Text ID - 0x200", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else {
lowerBits = 0;
}
return (transitionIndex << 10) + (type << 7) + (doubleDoor << 6) + lowerBits;
};
actorSpecificData[ACTOR_EN_PO_DESERT] = [](s16 params) -> s16 {
u8 switchFlag = params >> 8;
ImGui::InputScalar("Path", ImGuiDataType_U8, &switchFlag);
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_KANBAN] = [](s16 params) -> s16 {
bool piece = params == (s16)0xFFDD;
bool fishingSign = params == 0x300;
if (ImGui::Checkbox("Piece", &piece)) {
fishingSign = false;
}
if (ImGui::Checkbox("Fishing Sign", &fishingSign)) {
piece = false;
}
u8 textId = params;
if (!piece && !fishingSign) {
if (ImGui::InputScalar("Text ID", ImGuiDataType_U8, &textId)) {
textId |= 0x300;
}
}
return piece ? (s16)0xFFDD : (fishingSign ? 0x300 : textId);
};
actorSpecificData[ACTOR_EN_KUSA] = [](s16 params) -> s16 {
static const char* items[] = {
"0",
"1",
"2"
};
int type = params & 3;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
bool bugs = ((params >> 4) & 1) != 0;
ImGui::Checkbox("Bugs", &bugs);
u8 drop = (params >> 8) & 0xF;
if (type == 2) {
ImGui::InputScalar("Random Drop Params", ImGuiDataType_U8, &drop);
if (drop > 0xD) {
drop = 0xD;
}
} else {
drop = 0;
}
return (drop << 8) + (bugs << 4) + type;
};
actorSpecificData[ActorDB::Instance->RetrieveId("En_Partner")] = [](s16 params) -> s16 {
static const char* items[] = {
"Port 1",
"Port 2",
"Port 3",
"Port 4"
};
int selectedItem = params;
if (ImGui::Combo("Controller Port", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
}
std::vector<u16> GetActorsWithDescriptionContainingString(std::string s) {
std::locale loc;
for (size_t i = 0; i < s.length(); i += 1) {
s[i] = std::tolower(s[i], loc);
}
std::vector<u16> actors;
for (int i = 0; i < ActorDB::Instance->GetEntryCount(); i += 1) {
ActorDB::Entry actorEntry = ActorDB::Instance->RetrieveEntry(i);
std::string desc = actorEntry.desc;
for (size_t j = 0; j < desc.length(); j += 1) {
desc[j] = std::tolower(desc[j], loc);
}
if (desc.find(s) != std::string::npos) {
actors.push_back((u16)i);
}
}
return actors;
}
void ActorViewer_AddTagForActor(Actor* actor) { void ActorViewer_AddTagForActor(Actor* actor) {
int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE); int val = CVarGetInteger(CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), ACTORVIEWER_NAMETAGS_NONE);
auto entry = ActorDB::Instance->RetrieveEntry(actor->id); auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
std::string tag; std::string tag;
@ -163,6 +943,9 @@ void ActorViewerWindow::DrawElement() {
static std::string filler = "Please select"; static std::string filler = "Please select";
static std::vector<Actor*> list; static std::vector<Actor*> list;
static u16 lastSceneId = 0; static u16 lastSceneId = 0;
static char searchString[64] = "";
static s16 currentSelectedInDropdown;
static std::vector<u16> actors;
if (gPlayState != nullptr) { if (gPlayState != nullptr) {
needs_reset = lastSceneId != gPlayState->sceneNum; needs_reset = lastSceneId != gPlayState->sceneNum;
@ -173,6 +956,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select"; filler = "Please Select";
list.clear(); list.clear();
needs_reset = false; needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
} }
lastSceneId = gPlayState->sceneNum; lastSceneId = gPlayState->sceneNum;
if (ImGui::BeginCombo("Actor Type", acMapping[category])) { if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
@ -316,9 +1104,48 @@ void ActorViewerWindow::DrawElement() {
if (ImGui::TreeNode("New...")) { if (ImGui::TreeNode("New...")) {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10); ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
if (ImGui::InputText("Search Actor", searchString, ARRAY_COUNT(searchString))) {
actors = GetActorsWithDescriptionContainingString(std::string(searchString));
currentSelectedInDropdown = -1;
}
if (searchString[0] != 0 && !actors.empty()) {
std::string preview = currentSelectedInDropdown == -1 ? "Please Select" : ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
if (ImGui::BeginCombo("Results", preview.c_str())) {
for (u8 i = 0; i < actors.size(); i++) {
if (ImGui::Selectable(
ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(),
i == currentSelectedInDropdown
)) {
currentSelectedInDropdown = i;
newActor.id = actors[i];
}
}
ImGui::EndCombo();
}
}
ImGui::Text("%s", GetActorDescription(newActor.id).c_str()); ImGui::Text("%s", GetActorDescription(newActor.id).c_str());
ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one); if (ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one)) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one); newActor.params = 0;
}
UIWidgets::EnhancementCheckbox("Advanced mode", CVAR_DEVELOPER_TOOLS("ActorViewer.AdvancedParams"));
UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input");
if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ActorViewer.AdvancedParams"), 0)) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else if (std::find(noParamsActors.begin(), noParamsActors.end(), newActor.id) == noParamsActors.end()) {
CreateActorSpecificData();
if (actorSpecificData.find(newActor.id) == actorSpecificData.end()) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else {
DrawGroupWithBorder([&]() {
ImGui::Text("Actor Specific Data");
newActor.params = actorSpecificData[newActor.id](newActor.params);
});
}
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 6); ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
@ -388,7 +1215,7 @@ void ActorViewerWindow::DrawElement() {
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
ImGui::Text("Actor Name Tags"); ImGui::Text("Actor Name Tags");
if (UIWidgets::EnhancementCombobox("gDebugActorViewerNameTags", nameTagOptions, ACTORVIEWER_NAMETAGS_NONE)) { if (UIWidgets::EnhancementCombobox(CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), nameTagOptions, ACTORVIEWER_NAMETAGS_NONE)) {
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG); NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
ActorViewer_AddTagForAllActors(); ActorViewer_AddTagForAllActors();
} }
@ -401,6 +1228,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select"; filler = "Please Select";
list.clear(); list.clear();
needs_reset = false; needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
} }
} }

View File

@ -2,7 +2,7 @@
#include <libultraship/libultraship.h> #include <libultraship/libultraship.h>
class ActorViewerWindow : public LUS::GuiWindow { class ActorViewerWindow : public Ship::GuiWindow {
public: public:
using GuiWindow::GuiWindow; using GuiWindow::GuiWindow;

View File

@ -7,6 +7,7 @@
#include <cmath> #include <cmath>
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include <libultraship/libultraship.h> #include <libultraship/libultraship.h>
#include "soh/OTRGlobals.h"
extern "C" { extern "C" {
#include <z64.h> #include <z64.h>
@ -57,17 +58,17 @@ void ColViewerWindow::DrawElement() {
ImGui::End(); ImGui::End();
return; return;
} }
UIWidgets::EnhancementCheckbox("Enabled", "gColViewerEnabled"); UIWidgets::EnhancementCheckbox("Enabled", CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"));
UIWidgets::LabeledRightAlignedEnhancementCombobox("Scene", "gColViewerScene", ColRenderSettingNames, COLVIEW_DISABLED); UIWidgets::LabeledRightAlignedEnhancementCombobox("Scene", CVAR_DEVELOPER_TOOLS("ColViewer.Scene"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Bg Actors", "gColViewerBgActors", ColRenderSettingNames, COLVIEW_DISABLED); UIWidgets::LabeledRightAlignedEnhancementCombobox("Bg Actors", CVAR_DEVELOPER_TOOLS("ColViewer.BGActors"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Col Check", "gColViewerColCheck", ColRenderSettingNames, COLVIEW_DISABLED); UIWidgets::LabeledRightAlignedEnhancementCombobox("Col Check", CVAR_DEVELOPER_TOOLS("ColViewer.ColCheck"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Waterbox", "gColViewerWaterbox", ColRenderSettingNames, COLVIEW_DISABLED); UIWidgets::LabeledRightAlignedEnhancementCombobox("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.Waterbox"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::EnhancementCheckbox("Apply as decal", "gColViewerDecal"); UIWidgets::EnhancementCheckbox("Apply as decal", CVAR_DEVELOPER_TOOLS("ColViewer.Decal"));
UIWidgets::InsertHelpHoverText("Applies the collision as a decal display. This can be useful if there is z-fighting occuring " UIWidgets::InsertHelpHoverText("Applies the collision as a decal display. This can be useful if there is z-fighting occuring "
"with the scene geometry, but can cause other artifacts."); "with the scene geometry, but can cause other artifacts.");
UIWidgets::EnhancementCheckbox("Shaded", "gColViewerShaded"); UIWidgets::EnhancementCheckbox("Shaded", CVAR_DEVELOPER_TOOLS("ColViewer.Shaded"));
UIWidgets::InsertHelpHoverText("Applies the scene's shading to the collision display."); UIWidgets::InsertHelpHoverText("Applies the scene's shading to the collision display.");
// This has to be duplicated in both code paths due to the nature of ImGui::IsItemHovered() // This has to be duplicated in both code paths due to the nature of ImGui::IsItemHovered()
@ -75,20 +76,20 @@ void ColViewerWindow::DrawElement() {
if (ImGui::TreeNode("Colors")) { if (ImGui::TreeNode("Colors")) {
UIWidgets::InsertHelpHoverText(colorHelpText); UIWidgets::InsertHelpHoverText(colorHelpText);
UIWidgets::EnhancementColor("Normal", "gColViewerColorNormal", scene_col, ImVec4(255, 255, 255, 255), false); UIWidgets::EnhancementColor("Normal", CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), scene_col, ImVec4(255, 255, 255, 255), false);
UIWidgets::EnhancementColor("Hookshot", "gColViewerColorHookshot", hookshot_col, ImVec4(128, 128, 255, 255), UIWidgets::EnhancementColor("Hookshot", CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), hookshot_col, ImVec4(128, 128, 255, 255),
false); false);
UIWidgets::EnhancementColor("Entrance", "gColViewerColorEntrance", entrance_col, ImVec4(0, 255, 0, 255), false); UIWidgets::EnhancementColor("Entrance", CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), entrance_col, ImVec4(0, 255, 0, 255), false);
UIWidgets::EnhancementColor("Special Surface (Grass/Sand/Etc)", "gColViewerColorSpecialSurface", UIWidgets::EnhancementColor("Special Surface (Grass/Sand/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"),
specialSurface_col, ImVec4(192, 255, 192, 255), false); specialSurface_col, ImVec4(192, 255, 192, 255), false);
UIWidgets::EnhancementColor("Interactable (Vines/Crawlspace/Etc)", "gColViewerColorInteractable", UIWidgets::EnhancementColor("Interactable (Vines/Crawlspace/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"),
interactable_col, ImVec4(192, 0, 192, 255), false); interactable_col, ImVec4(192, 0, 192, 255), false);
UIWidgets::EnhancementColor("Slope", "gColViewerColorSlope", slope_col, ImVec4(255, 255, 128, 255), false); UIWidgets::EnhancementColor("Slope", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), slope_col, ImVec4(255, 255, 128, 255), false);
UIWidgets::EnhancementColor("Void", "gColViewerColorVoid", void_col, ImVec4(255, 0, 0, 255), false); UIWidgets::EnhancementColor("Void", CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), void_col, ImVec4(255, 0, 0, 255), false);
UIWidgets::EnhancementColor("OC", "gColViewerColorOC", oc_col, ImVec4(255, 255, 255, 255), false); UIWidgets::EnhancementColor("OC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), oc_col, ImVec4(255, 255, 255, 255), false);
UIWidgets::EnhancementColor("AC", "gColViewerColorAC", ac_col, ImVec4(0, 0, 255, 255), false); UIWidgets::EnhancementColor("AC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), ac_col, ImVec4(0, 0, 255, 255), false);
UIWidgets::EnhancementColor("AT", "gColViewerColorAT", at_col, ImVec4(255, 0, 0, 255), false); UIWidgets::EnhancementColor("AT", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), at_col, ImVec4(255, 0, 0, 255), false);
UIWidgets::EnhancementColor("Waterbox", "gColViewerColorWaterbox", waterbox_col, ImVec4(0, 0, 255, 255), false); UIWidgets::EnhancementColor("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), waterbox_col, ImVec4(0, 0, 255, 255), false);
ImGui::TreePop(); ImGui::TreePop();
} else { } else {
@ -308,7 +309,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
alpha = 0xFF; alpha = 0xFF;
} }
if (CVarGetInteger("gColViewerDecal", 0) != 0) { if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Decal"), 0) != 0) {
rm |= ZMODE_DEC; rm |= ZMODE_DEC;
} else if (setting == ColRenderSetting::Transparent) { } else if (setting == ColRenderSetting::Transparent) {
rm |= ZMODE_XLU; rm |= ZMODE_XLU;
@ -320,7 +321,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
gfx.push_back(gsDPSetCycleType(G_CYC_1CYCLE)); gfx.push_back(gsDPSetCycleType(G_CYC_1CYCLE));
gfx.push_back(gsDPSetRenderMode(rm | blc1, rm | blc2)); gfx.push_back(gsDPSetRenderMode(rm | blc1, rm | blc2));
if (CVarGetInteger("gColViewerShaded", 0) != 0) { if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Shaded"), 0) != 0) {
gfx.push_back(gsDPSetCombineMode(G_CC_MODULATERGB_PRIM_ENVA, G_CC_MODULATERGB_PRIM_ENVA)); gfx.push_back(gsDPSetCombineMode(G_CC_MODULATERGB_PRIM_ENVA, G_CC_MODULATERGB_PRIM_ENVA));
gfx.push_back(gsSPLoadGeometryMode(G_CULL_BACK | G_ZBUFFER | G_LIGHTING)); gfx.push_back(gsSPLoadGeometryMode(G_CULL_BACK | G_ZBUFFER | G_LIGHTING));
} else { } else {
@ -333,16 +334,13 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
// Draws a dynapoly structure (scenes or Bg Actors) // Draws a dynapoly structure (scenes or Bg Actors)
void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) { void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
uint32_t colorR = CVarGetInteger("gColViewerColorNormalR", 255); Color_RGBA8 color = {255, 255, 255, 255};
uint32_t colorG = CVarGetInteger("gColViewerColorNormalG", 255);
uint32_t colorB = CVarGetInteger("gColViewerColorNormalB", 255);
uint32_t colorA = 255;
uint32_t lastColorR = colorR; uint32_t lastColorR = color.r;
uint32_t lastColorG = colorG; uint32_t lastColorG = color.g;
uint32_t lastColorB = colorB; uint32_t lastColorB = color.b;
dl.push_back(gsDPSetPrimColor(0, 0, colorR, colorG, colorB, colorA)); dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
// This keeps track of if we have processed a poly, but not drawn it yet so we can batch them. // This keeps track of if we have processed a poly, but not drawn it yet so we can batch them.
// This saves several hundred commands in larger scenes // This saves several hundred commands in larger scenes
@ -352,49 +350,35 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
CollisionPoly* poly = &col->polyList[i]; CollisionPoly* poly = &col->polyList[i];
if (SurfaceType_IsHookshotSurface(&gPlayState->colCtx, poly, bgId)) { if (SurfaceType_IsHookshotSurface(&gPlayState->colCtx, poly, bgId)) {
colorR = CVarGetInteger("gColViewerColorHookshotR", 128); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), { 128, 128, 255, 255 });
colorG = CVarGetInteger("gColViewerColorHookshotG", 128);
colorB = CVarGetInteger("gColViewerColorHookshotB", 255);
} else if (func_80041D94(&gPlayState->colCtx, poly, bgId) > 0x01) { } else if (func_80041D94(&gPlayState->colCtx, poly, bgId) > 0x01) {
colorR = CVarGetInteger("gColViewerColorInteractableR", 192); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"), {192, 0, 192, 255});
colorG = CVarGetInteger("gColViewerColorInteractableG", 0);
colorB = CVarGetInteger("gColViewerColorInteractableB", 192);
} else if (func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x0C) { } else if (func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x0C) {
colorR = CVarGetInteger("gColViewerColorVoidR", 255); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), { 255, 0, 0, 255 });
colorG = CVarGetInteger("gColViewerColorVoidG", 0);
colorB = CVarGetInteger("gColViewerColorVoidB", 0);
} else if (SurfaceType_GetSceneExitIndex(&gPlayState->colCtx, poly, bgId) || } else if (SurfaceType_GetSceneExitIndex(&gPlayState->colCtx, poly, bgId) ||
func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x05) { func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x05) {
colorR = CVarGetInteger("gColViewerColorEntranceR", 0); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), { 0, 255, 0, 255 });
colorG = CVarGetInteger("gColViewerColorEntranceG", 255);
colorB = CVarGetInteger("gColViewerColorEntranceB", 0);
} else if (func_80041D4C(&gPlayState->colCtx, poly, bgId) != 0 || } else if (func_80041D4C(&gPlayState->colCtx, poly, bgId) != 0 ||
SurfaceType_IsWallDamage(&gPlayState->colCtx, poly, bgId)) { SurfaceType_IsWallDamage(&gPlayState->colCtx, poly, bgId)) {
colorR = CVarGetInteger("gColViewerColorSpecialSurfaceR", 192); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"), { 192, 255, 192, 255 });
colorG = CVarGetInteger("gColViewerColorSpecialSurfaceG", 255);
colorB = CVarGetInteger("gColViewerColorSpecialSurfaceB", 192);
} else if (SurfaceType_GetSlope(&gPlayState->colCtx, poly, bgId) == 0x01) { } else if (SurfaceType_GetSlope(&gPlayState->colCtx, poly, bgId) == 0x01) {
colorR = CVarGetInteger("gColViewerColorSlopeR", 255); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), { 255, 255, 128, 255 });
colorG = CVarGetInteger("gColViewerColorSlopeG", 255);
colorB = CVarGetInteger("gColViewerColorSlopeB", 128);
} else { } else {
colorR = CVarGetInteger("gColViewerColorNormalR", 255); color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), { 255, 255, 255, 255 });
colorG = CVarGetInteger("gColViewerColorNormalG", 255);
colorB = CVarGetInteger("gColViewerColorNormalB", 255);
} }
if (colorR != lastColorR || colorG != lastColorG || colorB != lastColorB) { if (color.r != lastColorR || color.g != lastColorG || color.b != lastColorB) {
// Color changed, flush previous poly // Color changed, flush previous poly
if (previousPoly) { if (previousPoly) {
dl.push_back(gsSPVertex((uintptr_t)&vtxDl.at(vtxDl.size() - 3), 3, 0)); dl.push_back(gsSPVertex((uintptr_t)&vtxDl.at(vtxDl.size() - 3), 3, 0));
dl.push_back(gsSP1Triangle(0, 1, 2, 0)); dl.push_back(gsSP1Triangle(0, 1, 2, 0));
previousPoly = false; previousPoly = false;
} }
dl.push_back(gsDPSetPrimColor(0, 0, colorR, colorG, colorB, colorA)); dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
} }
lastColorR = colorR; lastColorR = color.r;
lastColorG = colorG; lastColorG = color.g;
lastColorB = colorB; lastColorB = color.b;
Vec3s* va = &col->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)]; Vec3s* va = &col->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)];
Vec3s* vb = &col->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)]; Vec3s* vb = &col->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)];
@ -428,9 +412,9 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
// Draws the scene // Draws the scene
void DrawSceneCollision() { void DrawSceneCollision() {
ColRenderSetting showSceneColSetting = (ColRenderSetting)CVarGetInteger("gColViewerScene", COLVIEW_DISABLED); ColRenderSetting showSceneColSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Scene"), COLVIEW_DISABLED);
if (showSceneColSetting == ColRenderSetting::Disabled || !CVarGetInteger("gColViewerEnabled", 0)) { if (showSceneColSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return; return;
} }
@ -443,8 +427,8 @@ void DrawSceneCollision() {
// Draws all Bg Actors // Draws all Bg Actors
void DrawBgActorCollision() { void DrawBgActorCollision() {
ColRenderSetting showBgActorSetting = (ColRenderSetting)CVarGetInteger("gColViewerBgActors", COLVIEW_DISABLED); ColRenderSetting showBgActorSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.BGActors"), COLVIEW_DISABLED);
if (showBgActorSetting == ColRenderSetting::Disabled || !CVarGetInteger("gColViewerEnabled", 0)) { if (showBgActorSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return; return;
} }
@ -568,8 +552,8 @@ void DrawColCheckList(std::vector<Gfx>& dl, Collider** objects, int32_t count) {
// Draws all Col Check objects // Draws all Col Check objects
void DrawColCheckCollision() { void DrawColCheckCollision() {
ColRenderSetting showColCheckSetting = (ColRenderSetting)CVarGetInteger("gColViewerColCheck", COLVIEW_DISABLED); ColRenderSetting showColCheckSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.ColCheck"), COLVIEW_DISABLED);
if (showColCheckSetting == ColRenderSetting::Disabled || !CVarGetInteger("gColViewerEnabled", 0)) { if (showColCheckSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return; return;
} }
@ -578,15 +562,14 @@ void DrawColCheckCollision() {
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH)); dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
CollisionCheckContext& col = gPlayState->colChkCtx; CollisionCheckContext& col = gPlayState->colChkCtx;
Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), { 255, 255, 255, 255 });
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorOCR", 255), CVarGetInteger("gColViewerColorOCG", 255), dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
CVarGetInteger("gColViewerColorOCB", 255), 255));
DrawColCheckList(dl, col.colOC, col.colOCCount); DrawColCheckList(dl, col.colOC, col.colOCCount);
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorACR", 0), CVarGetInteger("gColViewerColorACG", 0), color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), { 0, 0, 255, 255 });
CVarGetInteger("gColViewerColorACB", 255), 255)); dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
DrawColCheckList(dl, col.colAC, col.colACCount); DrawColCheckList(dl, col.colAC, col.colACCount);
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorATR", 255), CVarGetInteger("gColViewerColorATG", 0), color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), { 0, 0, 255, 255 });
CVarGetInteger("gColViewerColorATB", 0), 255)); dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
DrawColCheckList(dl, col.colAT, col.colATCount); DrawColCheckList(dl, col.colAT, col.colATCount);
} }
@ -621,8 +604,8 @@ extern "C" f32 zdWaterBoxMinY;
// Draws all waterboxes // Draws all waterboxes
void DrawWaterboxList() { void DrawWaterboxList() {
ColRenderSetting showWaterboxSetting = (ColRenderSetting)CVarGetInteger("gColViewerWaterbox", COLVIEW_DISABLED); ColRenderSetting showWaterboxSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Waterbox"), COLVIEW_DISABLED);
if (showWaterboxSetting == ColRenderSetting::Disabled || !CVarGetInteger("gColViewerEnabled", 0)) { if (showWaterboxSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return; return;
} }
@ -630,9 +613,9 @@ void DrawWaterboxList() {
InitGfx(dl, showWaterboxSetting); InitGfx(dl, showWaterboxSetting);
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH)); dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorWaterboxR", 0), Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), { 0, 0, 255, 255 });
CVarGetInteger("gColViewerColorWaterboxG", 0),
CVarGetInteger("gColViewerColorWaterboxB", 255), 255)); dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
CollisionHeader* col = gPlayState->colCtx.colHeader; CollisionHeader* col = gPlayState->colCtx.colHeader;
for (int32_t waterboxIndex = 0; waterboxIndex < col->numWaterBoxes; waterboxIndex++) { for (int32_t waterboxIndex = 0; waterboxIndex < col->numWaterBoxes; waterboxIndex++) {
@ -693,7 +676,7 @@ extern "C" void DrawColViewer() {
OPEN_DISPS(gPlayState->state.gfxCtx); OPEN_DISPS(gPlayState->state.gfxCtx);
uint8_t mirroredWorld = CVarGetInteger("gMirroredWorld", 0); uint8_t mirroredWorld = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0);
// Col viewer needs inverted culling in mirror mode for both OPA and XLU buffers // Col viewer needs inverted culling in mirror mode for both OPA and XLU buffers
if (mirroredWorld) { if (mirroredWorld) {
gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING);

View File

@ -14,7 +14,7 @@ typedef enum {
} ColViewerRenderSetting; } ColViewerRenderSetting;
#ifdef __cplusplus #ifdef __cplusplus
class ColViewerWindow : public LUS::GuiWindow { class ColViewerWindow : public Ship::GuiWindow {
public: public:
using GuiWindow::GuiWindow; using GuiWindow::GuiWindow;

Some files were not shown because too many files have changed in this diff Show More