Merge remote-tracking branch 'origin/develop' into merge-macready-805
2
.github/workflows/apt-deps.txt
vendored
@ -1 +1 @@
|
||||
libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev ninja-build
|
||||
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev ninja-build
|
||||
|
151
.github/workflows/generate-builds.yml
vendored
@ -13,33 +13,37 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-soh-otr-ccache
|
||||
key: ${{ runner.os }}-otr-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-otr-ccache-${{ github.ref }}
|
||||
${{ runner.os }}-otr-ccache-
|
||||
- name: Install dependencies
|
||||
if: ${{ !vars.LINUX_RUNNER }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt)
|
||||
- name: Cache build folders
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ runner.os }}-otr-build-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-otr-build-${{ github.ref }}
|
||||
${{ runner.os }}-otr-build-
|
||||
path: |
|
||||
build-cmake
|
||||
SDL2-2.28.5
|
||||
- name: Install latest SDL
|
||||
if: ${{ !vars.LINUX_RUNNER }}
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
|
||||
tar -xzf SDL2-2.26.1.tar.gz
|
||||
cd SDL2-2.26.1
|
||||
./configure
|
||||
make -j 10
|
||||
sudo make install
|
||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||
- name: Install latest SDL_net
|
||||
if: ${{ !vars.LINUX_RUNNER }}
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
|
||||
tar -xzf SDL2_net-2.2.0.tar.gz
|
||||
cd SDL2_net-2.2.0
|
||||
./configure
|
||||
if [ ! -d "SDL2-2.28.5" ]; then
|
||||
wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
|
||||
tar -xzf SDL2-2.28.5.tar.gz
|
||||
fi
|
||||
cd SDL2-2.28.5
|
||||
./configure --enable-hidapi-libusb
|
||||
make -j 10
|
||||
sudo make install
|
||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||
@ -48,7 +52,7 @@ jobs:
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
|
||||
cmake --build build-cmake --config Release --target GenerateSohOtr
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
path: soh.otr
|
||||
@ -61,9 +65,12 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-ccache
|
||||
key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-${{ github.ref }}
|
||||
${{ runner.os }}-ccache-
|
||||
- name: Install gtar wrapper
|
||||
if: ${{ !vars.MAC_RUNNER }}
|
||||
run: |
|
||||
@ -96,13 +103,13 @@ jobs:
|
||||
sudo port install $(cat .github/workflows/macports-deps.txt)
|
||||
brew install ninja
|
||||
- name: Download soh.otr
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
- name: Build SoH
|
||||
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 -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
|
||||
mv soh.otr build-cmake/soh
|
||||
(cd build-cmake && cpack)
|
||||
@ -110,7 +117,7 @@ jobs:
|
||||
mv _packages/*.dmg SoH.dmg
|
||||
mv README.md readme.txt
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh-mac
|
||||
path: |
|
||||
@ -139,17 +146,32 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $(cat .github/workflows/apt-deps.txt)
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ matrix.os }}-ccache
|
||||
key: ${{ matrix.os }}-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-ccache-${{ github.ref }}
|
||||
${{ matrix.os }}-ccache-
|
||||
- name: Cache build folders
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ matrix.os }}-build-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-build-${{ github.ref }}
|
||||
${{ matrix.os }}-build-
|
||||
path: |
|
||||
SDL2-2.28.5
|
||||
SDL2_net-2.2.0
|
||||
- name: Install latest SDL
|
||||
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
|
||||
tar -xzf SDL2-2.26.1.tar.gz
|
||||
cd SDL2-2.26.1
|
||||
./configure
|
||||
if [ ! -d "SDL2-2.28.5" ]; then
|
||||
wget https://www.libsdl.org/release/SDL2-2.28.5.tar.gz
|
||||
tar -xzf SDL2-2.28.5.tar.gz
|
||||
fi
|
||||
cd SDL2-2.28.5
|
||||
./configure --enable-hidapi-libusb
|
||||
make -j 10
|
||||
sudo make install
|
||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||
@ -157,21 +179,23 @@ jobs:
|
||||
if: ${{ (matrix.os == 'ubuntu-20.04' && !vars.LINUX_COMPATIBILITY_RUNNER) || (matrix.os == 'ubuntu-22.04' && !vars.LINUX_PERFORMANCE_RUNNER) }}
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
|
||||
tar -xzf SDL2_net-2.2.0.tar.gz
|
||||
if [ ! -d "SDL2_net-2.2.0" ]; then
|
||||
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
|
||||
tar -xzf SDL2_net-2.2.0.tar.gz
|
||||
fi
|
||||
cd SDL2_net-2.2.0
|
||||
./configure
|
||||
make -j 10
|
||||
sudo make install
|
||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||
- name: Download soh.otr
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
- name: Build SoH
|
||||
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
|
||||
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
|
||||
(cd build-cmake && cpack -G External)
|
||||
|
||||
@ -181,7 +205,7 @@ jobs:
|
||||
CC: gcc-${{ matrix.gcc }}
|
||||
CXX: g++-${{ matrix.gcc }}
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh-linux-${{ matrix.archive-suffix }}
|
||||
path: |
|
||||
@ -197,6 +221,9 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build
|
||||
sudo apt-get remove -y cmake
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh -O /tmp/cmake.sh
|
||||
sudo sh /tmp/cmake.sh --prefix=/usr/local/ --exclude-subdir
|
||||
- name: Fix dubious ownership error
|
||||
if: ${{ vars.LINUX_RUNNER }}
|
||||
run: git config --global --add safe.directory '*'
|
||||
@ -204,9 +231,12 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-switch-ccache
|
||||
key: ${{ runner.os }}-switch-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-switch-ccache-${{ github.ref }}
|
||||
${{ runner.os }}-switch-ccache-
|
||||
- name: Build SoH
|
||||
run: |
|
||||
cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
@ -215,11 +245,11 @@ jobs:
|
||||
mv build-switch/soh/*.nro soh.nro
|
||||
mv README.md readme.txt
|
||||
- name: Download soh.otr
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh-switch
|
||||
path: |
|
||||
@ -237,13 +267,19 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build
|
||||
sudo apt-get remove -y cmake
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh -O /tmp/cmake.sh
|
||||
sudo sh /tmp/cmake.sh --prefix=/usr/local/ --exclude-subdir
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-wiiu-ccache
|
||||
key: ${{ runner.os }}-wiiu-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-wiiu-ccache-${{ github.ref }}
|
||||
${{ runner.os }}-wiiu-ccache-
|
||||
- name: Build SoH
|
||||
run: |
|
||||
cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
@ -256,11 +292,11 @@ jobs:
|
||||
DEVKITPRO: /opt/devkitpro
|
||||
DEVKITPPC: /opt/devkitpro/devkitPPC
|
||||
- name: Download soh.otr
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh-wiiu
|
||||
path: |
|
||||
@ -281,16 +317,33 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: ccache
|
||||
uses: dcvz/ccache-action@27b9f33213c0079872f064f6b6ba0233dfa16ba2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-ccache
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
variant: sccache
|
||||
max-size: "1G"
|
||||
key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-${{ github.ref }}
|
||||
${{ runner.os }}-ccache-
|
||||
- name: Cache build folder
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
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
|
||||
env:
|
||||
VCPKG_ROOT: D:/a/vcpkg
|
||||
VCPKG_ROOT: ${{github.workspace}}/vcpkg
|
||||
run: |
|
||||
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
|
||||
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DBUILD_REMOTE_CONTROL=1
|
||||
cmake --build build-windows --config Release --parallel 10
|
||||
|
||||
mkdir soh-windows
|
||||
@ -303,12 +356,12 @@ jobs:
|
||||
mv ./build-windows/gamecontrollerdb.txt ./soh-windows/gamecontrollerdb.txt
|
||||
mv ./x64/Release/assets ./soh-windows
|
||||
- name: Download soh.otr
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: soh.otr
|
||||
path: soh-windows
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soh-windows
|
||||
path: soh-windows
|
||||
|
2
.github/workflows/macports-deps.txt
vendored
@ -1 +1 @@
|
||||
libsdl2 +universal libpng +universal glew +universal
|
||||
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal
|
||||
|
61
.github/workflows/test-builds-on-distros.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
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 sdl2_net boost
|
||||
pacman -Syu --noconfirm
|
||||
pacman -S --noconfirm ${{ matrix.cc }} git cmake ninja lsb-release sdl2 libpng 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 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 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 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 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
|
||||
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
|
||||
- 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 }}
|
@ -8,5 +8,9 @@ if(MSVC)
|
||||
|
||||
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc")
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
|
||||
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Z7")
|
||||
else()
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
|
||||
endif()
|
||||
endif()
|
@ -13,20 +13,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>:/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")
|
||||
include(CMake/automate-vcpkg.cmake)
|
||||
include(CMake/automate-vcpkg.cmake)
|
||||
|
||||
set(VCPKG_TRIPLET x64-windows-static)
|
||||
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
||||
set(VCPKG_TRIPLET x64-windows-static)
|
||||
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
||||
|
||||
vcpkg_bootstrap()
|
||||
vcpkg_install_packages(zlib bzip2 libpng sdl2 sdl2-net glew glfw3)
|
||||
vcpkg_bootstrap()
|
||||
vcpkg_install_packages(zlib bzip2 libpng sdl2 sdl2-net glew glfw3)
|
||||
|
||||
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 04b85b95fab07a394b62dcd28a502a3040f08e0c
|
||||
Subproject commit e93bd2be062b13106fdb29d98cf4ada4d7ad6827
|
@ -92,7 +92,7 @@ If you want to playtest a continuous integration build, you can find them at the
|
||||
* [Windows](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-windows.zip)
|
||||
* [macOS](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-mac.zip)
|
||||
* [Linux (performance)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-performance.zip) _(requires `glibc 2.35` or newer, but will be more performant than the compatibility build.)_
|
||||
* [Linux (compatibility)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatiblity.zip) _(compatible with most Linux distributions, but may not be as performant as the performance build.)_
|
||||
* [Linux (compatibility)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatibility.zip) _(compatible with most Linux distributions, but may not be as performant as the performance build.)_
|
||||
* [Switch](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-switch.zip)
|
||||
* [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip)
|
||||
|
||||
|
@ -84,17 +84,49 @@ cd "build/x64"
|
||||
```
|
||||
|
||||
## 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 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 libboost-dev libopengl-dev
|
||||
```
|
||||
#### Arch
|
||||
```sh
|
||||
# using gcc
|
||||
pacman -S gcc git cmake ninja lsb-release sdl2 libpng 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 sdl2_net boost
|
||||
```
|
||||
#### Fedora
|
||||
```sh
|
||||
# using gcc
|
||||
dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel boost-devel
|
||||
|
||||
# or using clang
|
||||
dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel boost-devel
|
||||
```
|
||||
#### openSUSE
|
||||
```sh
|
||||
# using gcc
|
||||
zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel boost
|
||||
|
||||
# or using clang
|
||||
zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel boost
|
||||
```
|
||||
|
||||
### 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
|
||||
# Clone the repo
|
||||
git clone https://github.com/HarbourMasters/Shipwright.git
|
||||
cd Shipwright
|
||||
# Clone the submodule libultraship
|
||||
# Clone the submodules
|
||||
git submodule update --init
|
||||
# Copy the baserom to the OTRExporter folder
|
||||
cp <path to your ROM> OTRExporter
|
||||
|
@ -188,4 +188,4 @@ Assuming all went well, you can now push your changes to your fork with the foll
|
||||
|
||||
```bash
|
||||
git push origin <YOUR BRANCH NAME>
|
||||
```
|
||||
```
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 96c8a8929c18c1bffd7d92a35a589f74cf16fc59
|
||||
Subproject commit a516b66ce0c89fe4e33c55b1fbfbde845d0bf129
|
@ -21,12 +21,17 @@ fi
|
||||
while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do
|
||||
for romfile in "$SHIP_HOME"/*.*64
|
||||
do
|
||||
if [[ -e $romfile ]]; then
|
||||
if [[ -e "$romfile" ]] || [[ -L "$romfile" ]]; then
|
||||
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"
|
||||
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"
|
||||
ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')
|
||||
|
||||
|
@ -8,5 +8,9 @@ if(MSVC)
|
||||
|
||||
set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc")
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
|
||||
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Z7")
|
||||
else()
|
||||
set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi")
|
||||
endif()
|
||||
endif()
|
@ -154,7 +154,7 @@ list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/gfx.*")
|
||||
# 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.ccpak")
|
||||
if (!BUILD_CROWD_CONTROL)
|
||||
if (!BUILD_REMOTE_CONTROL)
|
||||
list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*")
|
||||
endif()
|
||||
|
||||
@ -354,9 +354,15 @@ endif()
|
||||
find_package(SDL2)
|
||||
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
if (BUILD_CROWD_CONTROL)
|
||||
if (BUILD_REMOTE_CONTROL)
|
||||
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()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||
@ -408,9 +414,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
"$<$<CONFIG:Release>:"
|
||||
"NDEBUG"
|
||||
">"
|
||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>"
|
||||
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
|
||||
"INCLUDE_GAME_PRINTF;"
|
||||
"ENABLE_CROWD_CONTROL;"
|
||||
"UNICODE;"
|
||||
"_UNICODE"
|
||||
STORMLIB_NO_AUTO_LINK
|
||||
@ -455,7 +460,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
|
||||
"$<$<CONFIG:Release>:"
|
||||
"NDEBUG"
|
||||
">"
|
||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>"
|
||||
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
|
||||
"SPDLOG_ACTIVE_LEVEL=0;"
|
||||
"_CONSOLE;"
|
||||
"_CRT_SECURE_NO_WARNINGS;"
|
||||
@ -624,6 +629,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||
-Wno-parentheses
|
||||
-Wno-narrowing
|
||||
-Wno-missing-braces
|
||||
-Wno-int-conversion
|
||||
-Wno-implicit-int
|
||||
$<$<COMPILE_LANGUAGE:C>:
|
||||
-Werror-implicit-function-declaration
|
||||
-Wno-incompatible-pointer-types
|
||||
@ -689,7 +696,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
"glu32;"
|
||||
"SDL2::SDL2;"
|
||||
"SDL2::SDL2main;"
|
||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net-static>"
|
||||
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net-static>"
|
||||
"glfw;"
|
||||
"winmm;"
|
||||
"imm32;"
|
||||
@ -742,7 +749,7 @@ else()
|
||||
"ZAPDUtils;"
|
||||
"ZAPDLib;"
|
||||
SDL2::SDL2
|
||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net>"
|
||||
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
|
||||
${CMAKE_DL_LIBS}
|
||||
Threads::Threads
|
||||
)
|
||||
|
@ -28,4 +28,10 @@
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</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>
|
||||
|
2
soh/assets/.gitignore
vendored
@ -4,4 +4,4 @@
|
||||
*.cfg
|
||||
*.vtx.inc
|
||||
*.dlist.inc
|
||||
*.txt
|
||||
!*.png
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"0": "Abre Mojo",
|
||||
"0": "Arbre Mojo",
|
||||
"1": "Caverne Dodongo",
|
||||
"2": "Ventre de Jabu-Jabu",
|
||||
"3": "Temple de la Forêt",
|
||||
@ -58,9 +58,9 @@
|
||||
"56": "Laboratoire du Lac",
|
||||
"57": "", // Tente du Marathonien (No title card)
|
||||
"58": "Cabane du fossoyeur",
|
||||
"59": "Fountaine Royale des Fées",
|
||||
"60": "Fountaine des Fées",
|
||||
"61": "Fountaine Royale des Fées",
|
||||
"59": "Fontaine Royale des Fées",
|
||||
"60": "Fontaine des Fées",
|
||||
"61": "Fontaine Royale des Fées",
|
||||
"62": "", // Grottes (No title card)
|
||||
"63": "", // Tombe 1 (No title card)
|
||||
"64": "", // Tombe 2 (No title card)
|
||||
@ -109,4 +109,4 @@
|
||||
"107": "",
|
||||
"108": "", // Debug: SRD Room (No title card)
|
||||
"109": "" // Debug: Treasure Chest Warp (No title card)
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
soh/assets/custom/textures/buttons/ABtnOutline.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
soh/assets/custom/textures/buttons/AnalogStick.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
soh/assets/custom/textures/buttons/AnalogStickOutline.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
soh/assets/custom/textures/buttons/BBtnOutline.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
soh/assets/custom/textures/buttons/CDownOutline.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
soh/assets/custom/textures/buttons/CLeftOutline.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
soh/assets/custom/textures/buttons/CRightOutline.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
soh/assets/custom/textures/buttons/CUpOutline.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
soh/assets/custom/textures/buttons/DPadDown.png
Normal file
After Width: | Height: | Size: 946 B |
BIN
soh/assets/custom/textures/buttons/DPadDownOutline.png
Normal file
After Width: | Height: | Size: 984 B |
BIN
soh/assets/custom/textures/buttons/DPadLeft.png
Normal file
After Width: | Height: | Size: 929 B |
BIN
soh/assets/custom/textures/buttons/DPadLeftOutline.png
Normal file
After Width: | Height: | Size: 953 B |
BIN
soh/assets/custom/textures/buttons/DPadRight.png
Normal file
After Width: | Height: | Size: 922 B |
BIN
soh/assets/custom/textures/buttons/DPadRightOutline.png
Normal file
After Width: | Height: | Size: 954 B |
BIN
soh/assets/custom/textures/buttons/DPadUp.png
Normal file
After Width: | Height: | Size: 968 B |
BIN
soh/assets/custom/textures/buttons/DPadUpOutline.png
Normal file
After Width: | Height: | Size: 993 B |
BIN
soh/assets/custom/textures/buttons/InputViewerBackground.png
Normal file
After Width: | Height: | Size: 941 B |
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 1.0 KiB |
BIN
soh/assets/custom/textures/buttons/LBtnOutline.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 992 B |
BIN
soh/assets/custom/textures/buttons/RBtnOutline.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
soh/assets/custom/textures/buttons/RightStick.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
soh/assets/custom/textures/buttons/RightStickOutline.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 973 B |
BIN
soh/assets/custom/textures/buttons/StartBtnOutline.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1005 B |
BIN
soh/assets/custom/textures/buttons/ZBtnOutline.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
15
soh/assets/sources/triforce-hunt/paths.txt
Normal 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
|
BIN
soh/assets/sources/triforce-hunt/textures/noise_tex.png
Normal file
After Width: | Height: | Size: 660 B |
BIN
soh/assets/sources/triforce-hunt/triforce_complete.blend
Normal file
BIN
soh/assets/sources/triforce-hunt/triforce_shard_0.blend
Normal file
BIN
soh/assets/sources/triforce-hunt/triforce_shard_1.blend
Normal file
BIN
soh/assets/sources/triforce-hunt/triforce_shard_2.blend
Normal file
@ -1250,7 +1250,7 @@ s32 Object_IsLoaded(ObjectContext* objectCtx, s32 bankIndex);
|
||||
void func_800981B8(ObjectContext* objectCtx);
|
||||
s32 Scene_ExecuteCommands(PlayState* play, SceneCmd* sceneCmd);
|
||||
void TransitionActor_InitContext(GameState* state, TransitionActorContext* transiActorCtx);
|
||||
void func_800994A0(PlayState* play);
|
||||
void Scene_SetTransitionForNextEntrance(PlayState* play);
|
||||
void Scene_Draw(PlayState* play);
|
||||
void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable,
|
||||
OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg, s32 dListIndex);
|
||||
@ -1537,7 +1537,7 @@ void KaleidoScopeCall_Draw(PlayState* play);
|
||||
void func_800BC490(PlayState* play, s16 point);
|
||||
s32 func_800BC56C(PlayState* play, s16 arg1);
|
||||
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);
|
||||
void Play_Destroy(GameState* thisx);
|
||||
void Play_Init(GameState* thisx);
|
||||
@ -2171,7 +2171,7 @@ void func_800FA18C(u8, u8);
|
||||
void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer);
|
||||
void func_800FA3DC(void);
|
||||
u8 func_800FAD34(void);
|
||||
void func_800FADF8(void);
|
||||
void Audio_ResetActiveSequences(void);
|
||||
void func_800FAEB4(void);
|
||||
void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a);
|
||||
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_GetRelY(Input* input);
|
||||
void PadUtils_UpdateRelXY(Input* input);
|
||||
s8 PadUtils_GetCurRX(Input* input);
|
||||
s8 PadUtils_GetCurRY(Input* input);
|
||||
void PadUtils_SetRelRXY(Input* input, s32 x, s32 y);
|
||||
s8 PadUtils_GetRelRXImpl(Input* input);
|
||||
s8 PadUtils_GetRelRYImpl(Input* input);
|
||||
s8 PadUtils_GetRelRX(Input* input);
|
||||
s8 PadUtils_GetRelRY(Input* input);
|
||||
void PadUtils_UpdateRelRXY(Input* input);
|
||||
s32 PadSetup_Init(OSMesgQueue* mq, u8* outMask, OSContStatus* status);
|
||||
f32 Math_FTanF(f32 x);
|
||||
f32 Math_FFloorF(f32 x);
|
||||
@ -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_RandoRestoreSwordless(void);
|
||||
|
||||
//Pause Warp
|
||||
void PauseWarp_HandleSelection();
|
||||
void PauseWarp_Execute();
|
||||
|
||||
// #endregion
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -86,6 +86,8 @@
|
||||
#define R_ITEM_ICON_X(i) ZREG(82 + i)
|
||||
#define R_ITEM_ICON_Y(i) ZREG(86 + 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_SPEED CREG(19)
|
||||
#define R_A_BTN_Y XREG(16)
|
||||
|
1934
soh/include/tables/entrance_table.h
Normal file
@ -107,7 +107,7 @@ extern "C"
|
||||
extern s16 gLinkObjectIds[2];
|
||||
extern u32 gObjectTableSize;
|
||||
extern RomFile gObjectTable[OBJECT_ID_MAX];
|
||||
extern EntranceInfo gEntranceTable[1556];
|
||||
extern EntranceInfo gEntranceTable[ENTR_MAX];
|
||||
extern SceneTableEntry gSceneTable[SCENE_ID_MAX];
|
||||
extern u16 gSramSlotOffsets[];
|
||||
// 4 16-colors palettes
|
||||
@ -224,7 +224,7 @@ extern "C"
|
||||
extern u16 gAudioSfxSwapSource[10];
|
||||
extern u16 gAudioSfxSwapTarget[10];
|
||||
extern u8 gAudioSfxSwapMode[10];
|
||||
extern unk_D_8016E750 D_8016E750[4];
|
||||
extern ActiveSequence gActiveSeqs[4];
|
||||
extern AudioContext gAudioContext;
|
||||
extern void(*D_801755D0)(void);
|
||||
|
||||
|
@ -1122,6 +1122,82 @@ typedef struct {
|
||||
/* 0x4C */ u32 unk_4C;
|
||||
} 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 {
|
||||
union {
|
||||
TransitionFade fade;
|
||||
@ -1384,14 +1460,14 @@ typedef struct PlayState {
|
||||
/* 0x11E0C */ ElfMessage* cUpElfMsgs;
|
||||
/* 0x11E10 */ void* specialEffects;
|
||||
/* 0x11E14 */ u8 skyboxId;
|
||||
/* 0x11E15 */ s8 sceneLoadFlag; // "fade_direction"
|
||||
/* 0x11E15 */ s8 transitionTrigger; // "fade_direction"
|
||||
/* 0x11E16 */ s16 unk_11E16;
|
||||
/* 0x11E18 */ s16 unk_11E18;
|
||||
/* 0x11E1A */ s16 nextEntranceIndex;
|
||||
/* 0x11E1C */ char unk_11E1C[0x40];
|
||||
/* 0x11E5C */ s8 shootingGalleryStatus;
|
||||
/* 0x11E5D */ s8 bombchuBowlingStatus; // "bombchu_game_flag"
|
||||
/* 0x11E5E */ u8 fadeTransition;
|
||||
/* 0x11E5E */ u8 transitionType;
|
||||
/* 0x11E60 */ CollisionCheckContext colChkCtx;
|
||||
/* 0x120FC */ u16 envFlags[20];
|
||||
/* 0x12124 */ PreRender pauseBgPreRender;
|
||||
@ -1513,6 +1589,20 @@ typedef struct {
|
||||
uint16_t bossRushArrowOffset;
|
||||
} 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 {
|
||||
DPM_UNK = 0,
|
||||
DPM_PLAYER = 1,
|
||||
|
@ -970,43 +970,43 @@ typedef struct {
|
||||
} AudioContextInitSizes; // size = 0xC
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ f32 unk_00;
|
||||
/* 0x04 */ f32 unk_04;
|
||||
/* 0x08 */ f32 unk_08;
|
||||
/* 0x0C */ u16 unk_0C;
|
||||
/* 0x10 */ f32 unk_10;
|
||||
/* 0x14 */ f32 unk_14;
|
||||
/* 0x18 */ f32 unk_18;
|
||||
/* 0x1C */ u16 unk_1C;
|
||||
} unk_50_s; // size = 0x20
|
||||
/* 0x00 */ f32 volCur;
|
||||
/* 0x04 */ f32 volTarget;
|
||||
/* 0x08 */ f32 volStep;
|
||||
/* 0x0C */ u16 volTimer;
|
||||
/* 0x10 */ f32 freqScaleCur;
|
||||
/* 0x14 */ f32 freqScaleTarget;
|
||||
/* 0x18 */ f32 freqScaleStep;
|
||||
/* 0x1C */ u16 freqScaleTimer;
|
||||
} ActiveSequenceChannelData; // size = 0x20
|
||||
|
||||
typedef struct {
|
||||
/* 0x000 */ f32 volCur;
|
||||
/* 0x004 */ f32 volTarget;
|
||||
/* 0x008 */ f32 unk_08;
|
||||
/* 0x00C */ u16 unk_0C;
|
||||
/* 0x00E */ u8 volScales[0x4];
|
||||
/* 0x008 */ f32 volStep;
|
||||
/* 0x00C */ u16 volTimer;
|
||||
/* 0x00E */ u8 volScales[4];
|
||||
/* 0x012 */ u8 volFadeTimer;
|
||||
/* 0x013 */ u8 fadeVolUpdate;
|
||||
/* 0x014 */ u32 unk_14;
|
||||
/* 0x018 */ u16 unk_18;
|
||||
/* 0x01C */ f32 unk_1C;
|
||||
/* 0x020 */ f32 unk_20;
|
||||
/* 0x024 */ f32 unk_24;
|
||||
/* 0x028 */ u16 unk_28;
|
||||
/* 0x02C */ u32 unk_2C[8];
|
||||
/* 0x04C */ u8 unk_4C;
|
||||
/* 0x04D */ u8 unk_4D;
|
||||
/* 0x04E */ u8 unk_4E;
|
||||
/* 0x050 */ unk_50_s unk_50[0x10];
|
||||
/* 0x250 */ u16 unk_250;
|
||||
/* 0x252 */ u16 unk_252;
|
||||
/* 0x254 */ u16 unk_254;
|
||||
/* 0x256 */ u16 unk_256;
|
||||
/* 0x258 */ u16 unk_258;
|
||||
/* 0x25C */ u32 unk_25C;
|
||||
/* 0x260 */ u8 unk_260;
|
||||
} unk_D_8016E750; // size = 0x264
|
||||
/* 0x014 */ u32 tempoCmd;
|
||||
/* 0x018 */ u16 tempoOriginal; // stores the original tempo before modifying it (to reset back to)
|
||||
/* 0x01C */ f32 tempoCur;
|
||||
/* 0x020 */ f32 tempoTarget;
|
||||
/* 0x024 */ f32 tempoStep;
|
||||
/* 0x028 */ u16 tempoTimer;
|
||||
/* 0x02C */ u32 setupCmd[8]; // a queue of cmds to execute once the player is disabled
|
||||
/* 0x04C */ u8 setupCmdTimer; // only execute setup commands when the timer is at 0.
|
||||
/* 0x04D */ u8 setupCmdNum; // number of setup commands requested once the player is disabled
|
||||
/* 0x04E */ u8 setupFadeTimer;
|
||||
/* 0x050 */ ActiveSequenceChannelData channelData[16];
|
||||
/* 0x250 */ u16 freqScaleChannelFlags;
|
||||
/* 0x252 */ u16 volChannelFlags;
|
||||
/* 0x254 */ u16 seqId; // active seqId currently playing. Resets when sequence stops
|
||||
/* 0x256 */ u16 prevSeqId; // last seqId played on a player. Does not reset when sequence stops
|
||||
/* 0x258 */ u16 channelPortMask;
|
||||
/* 0x25C */ u32 startSeqCmd; // This name comes from MM
|
||||
/* 0x260 */ u8 isWaitingForFonts; // This name comes from MM
|
||||
} ActiveSequence; // size = 0x264
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ BANK_PLAYER,
|
||||
|
@ -30,6 +30,14 @@ typedef enum {
|
||||
/* 13 */ SKYBOX_DMA_PAL2_START
|
||||
} SkyboxDmaState;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SANDSTORM_OFF,
|
||||
/* 1 */ SANDSTORM_FILL,
|
||||
/* 2 */ SANDSTORM_UNFILL,
|
||||
/* 3 */ SANDSTORM_ACTIVE,
|
||||
/* 4 */ SANDSTORM_DISSIPATE
|
||||
} SandstormState;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u8 state;
|
||||
/* 0x01 */ u8 flashRed;
|
||||
|
@ -132,16 +132,6 @@ typedef enum {
|
||||
/* 0x40 */ PLAYER_IA_MASK_GERUDO,
|
||||
/* 0x41 */ PLAYER_IA_MASK_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
|
||||
} PlayerItemAction;
|
||||
|
||||
@ -355,7 +345,7 @@ typedef enum {
|
||||
#define PLAYER_LIMB_BUF_COUNT LIMB_BUF_COUNT(PLAYER_LIMB_MAX)
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ f32 unk_00;
|
||||
/* 0x00 */ f32 ceilingCheckHeight;
|
||||
/* 0x04 */ f32 unk_04;
|
||||
/* 0x08 */ f32 unk_08;
|
||||
/* 0x0C */ f32 unk_0C;
|
||||
@ -369,7 +359,7 @@ typedef struct {
|
||||
/* 0x2C */ f32 unk_2C;
|
||||
/* 0x30 */ f32 unk_30;
|
||||
/* 0x34 */ f32 unk_34;
|
||||
/* 0x38 */ f32 unk_38;
|
||||
/* 0x38 */ f32 wallCheckRadius;
|
||||
/* 0x3C */ f32 unk_3C;
|
||||
/* 0x40 */ f32 unk_40;
|
||||
/* 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_HOOKSHOT_TRAVELLING (1 << 7) //Travelling to target
|
||||
|
||||
typedef void (*PlayerFunc674)(struct Player*, struct PlayState*);
|
||||
typedef s32 (*PlayerFunc82C)(struct Player*, struct PlayState*);
|
||||
typedef void (*PlayerActionFunc)(struct Player*, struct PlayState*);
|
||||
typedef s32 (*UpperActionFunc)(struct Player*, struct PlayState*);
|
||||
typedef void (*PlayerFuncA74)(struct PlayState*, struct Player*);
|
||||
|
||||
typedef struct Player {
|
||||
/* 0x0000 */ Actor actor;
|
||||
/* 0x014C */ s8 currentTunic; // current tunic from `PlayerTunic`
|
||||
/* 0x014D */ s8 currentSwordItemId;
|
||||
/* 0x014E */ s8 currentShield; // current shield from `PlayerShield`
|
||||
/* 0x014F */ s8 currentBoots; // current boots from `PlayerBoots`
|
||||
/* 0x0150 */ s8 heldItemButton; // Button index 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
|
||||
/* 0x0153 */ s8 prevBoots; // previous boots from `PlayerBoots`
|
||||
/* 0x0154 */ s8 itemAction; // the difference between this and heldItemAction is unclear
|
||||
/* 0x0155 */ char unk_155[0x003];
|
||||
/* 0x0158 */ u8 modelGroup;
|
||||
/* 0x0159 */ u8 nextModelGroup;
|
||||
/* 0x015A */ s8 unk_15A;
|
||||
/* 0x015B */ u8 modelAnimType;
|
||||
/* 0x015C */ u8 leftHandType;
|
||||
/* 0x015D */ u8 rightHandType;
|
||||
/* 0x015E */ u8 sheathType;
|
||||
/* 0x015F */ u8 currentMask; // current mask equipped from `PlayerMask`
|
||||
/* 0x0160 */ Gfx** rightHandDLists;
|
||||
/* 0x0164 */ Gfx** leftHandDLists;
|
||||
/* 0x0168 */ Gfx** sheathDLists;
|
||||
/* 0x016C */ Gfx** waistDLists;
|
||||
/* 0x0170 */ u8 giObjectLoading;
|
||||
/* 0x0000 */ Actor actor;
|
||||
/* 0x014C */ s8 currentTunic; // current tunic from `PlayerTunic`
|
||||
/* 0x014D */ s8 currentSwordItemId;
|
||||
/* 0x014E */ s8 currentShield; // current shield from `PlayerShield`
|
||||
/* 0x014F */ s8 currentBoots; // current boots from `PlayerBoots`
|
||||
/* 0x0150 */ s8 heldItemButton; // Button index 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
|
||||
/* 0x0153 */ s8 prevBoots; // previous boots from `PlayerBoots`
|
||||
/* 0x0154 */ s8 itemAction; // the difference between this and heldItemAction is unclear
|
||||
/* 0x0155 */ char unk_155[0x003];
|
||||
/* 0x0158 */ u8 modelGroup;
|
||||
/* 0x0159 */ u8 nextModelGroup;
|
||||
/* 0x015A */ s8 itemChangeType;
|
||||
/* 0x015B */ u8 modelAnimType;
|
||||
/* 0x015C */ u8 leftHandType;
|
||||
/* 0x015D */ u8 rightHandType;
|
||||
/* 0x015E */ u8 sheathType;
|
||||
/* 0x015F */ u8 currentMask; // current mask equipped from `PlayerMask`
|
||||
/* 0x0160 */ Gfx** rightHandDLists;
|
||||
/* 0x0164 */ Gfx** leftHandDLists;
|
||||
/* 0x0168 */ Gfx** sheathDLists;
|
||||
/* 0x016C */ Gfx** waistDLists;
|
||||
/* 0x0170 */ u8 giObjectLoading;
|
||||
/* 0x0174 */ DmaRequest giObjectDmaRequest;
|
||||
/* 0x0194 */ OSMesgQueue giObjectLoadQueue;
|
||||
/* 0x01AC */ OSMesg giObjectLoadMsg;
|
||||
/* 0x01B0 */ void* giObjectSegment; // also used for title card textures
|
||||
/* 0x01B4 */ SkelAnime skelAnime;
|
||||
/* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x03A8 */ s16 unk_3A8[2];
|
||||
/* 0x03AC */ Actor* heldActor;
|
||||
/* 0x03B0 */ Vec3f leftHandPos;
|
||||
/* 0x03BC */ Vec3s unk_3BC;
|
||||
/* 0x03C4 */ Actor* unk_3C4;
|
||||
/* 0x03C8 */ Vec3f unk_3C8;
|
||||
/* 0x03D4 */ char unk_3D4[0x058];
|
||||
/* 0x042C */ s8 doorType;
|
||||
/* 0x042D */ s8 doorDirection;
|
||||
/* 0x042E */ s16 doorTimer;
|
||||
/* 0x0430 */ Actor* doorActor;
|
||||
/* 0x0434 */ s16 getItemId; // Upstream TODO: Document why this is s16 while it's s8 upstream
|
||||
/* 0x0436 */ u16 getItemDirection;
|
||||
/* 0x0438 */ Actor* interactRangeActor;
|
||||
/* 0x043C */ s8 mountSide;
|
||||
/* 0x043D */ char unk_43D[0x003];
|
||||
/* 0x0440 */ Actor* rideActor;
|
||||
/* 0x0444 */ u8 csMode;
|
||||
/* 0x0445 */ u8 prevCsMode;
|
||||
/* 0x0446 */ u8 unk_446;
|
||||
/* 0x0447 */ u8 unk_447;
|
||||
/* 0x0448 */ Actor* unk_448;
|
||||
/* 0x044C */ char unk_44C[0x004];
|
||||
/* 0x0450 */ Vec3f unk_450;
|
||||
/* 0x045C */ Vec3f unk_45C;
|
||||
/* 0x0468 */ char unk_468[0x002];
|
||||
/* 0x046A */ s16 doorBgCamIndex;
|
||||
/* 0x046C */ s16 subCamId;
|
||||
/* 0x046E */ char unk_46E[0x02A];
|
||||
/* 0x01AC */ OSMesg giObjectLoadMsg;
|
||||
/* 0x01B0 */ void* giObjectSegment; // also used for title card textures
|
||||
/* 0x01B4 */ SkelAnime skelAnime;
|
||||
/* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x03A8 */ s16 unk_3A8[2];
|
||||
/* 0x03AC */ Actor* heldActor;
|
||||
/* 0x03B0 */ Vec3f leftHandPos;
|
||||
/* 0x03BC */ Vec3s unk_3BC;
|
||||
/* 0x03C4 */ Actor* unk_3C4;
|
||||
/* 0x03C8 */ Vec3f unk_3C8;
|
||||
/* 0x03D4 */ char unk_3D4[0x058];
|
||||
/* 0x042C */ s8 doorType;
|
||||
/* 0x042D */ s8 doorDirection;
|
||||
/* 0x042E */ s16 doorTimer;
|
||||
/* 0x0430 */ Actor* doorActor;
|
||||
/* 0x0434 */ s16 getItemId; // Upstream TODO: Document why this is s16 while it's s8 upstream
|
||||
/* 0x0436 */ u16 getItemDirection;
|
||||
/* 0x0438 */ Actor* interactRangeActor;
|
||||
/* 0x043C */ s8 mountSide;
|
||||
/* 0x043D */ char unk_43D[0x003];
|
||||
/* 0x0440 */ Actor* rideActor;
|
||||
/* 0x0444 */ u8 csAction;
|
||||
/* 0x0445 */ u8 prevCsAction;
|
||||
/* 0x0446 */ u8 cueId;
|
||||
/* 0x0447 */ u8 unk_447;
|
||||
/* 0x0448 */ Actor* csActor; // Actor involved in a `csAction`. Typically the actor that invoked the cutscene.
|
||||
/* 0x044C */ char unk_44C[0x004];
|
||||
/* 0x0450 */ Vec3f unk_450;
|
||||
/* 0x045C */ Vec3f unk_45C;
|
||||
/* 0x0468 */ char unk_468[0x002];
|
||||
/* 0x046A */ s16 doorBgCamIndex;
|
||||
/* 0x046C */ s16 subCamId;
|
||||
/* 0x046E */ char unk_46E[0x02A];
|
||||
/* 0x0498 */ ColliderCylinder cylinder;
|
||||
/* 0x04E4 */ ColliderQuad meleeWeaponQuads[2];
|
||||
/* 0x05E4 */ ColliderQuad shieldQuad;
|
||||
/* 0x0664 */ Actor* unk_664;
|
||||
/* 0x0668 */ char unk_668[0x004];
|
||||
/* 0x066C */ s32 unk_66C;
|
||||
/* 0x0670 */ s32 meleeWeaponEffectIndex;
|
||||
/* 0x0674 */ PlayerFunc674 func_674;
|
||||
/* 0x0664 */ Actor* unk_664;
|
||||
/* 0x0668 */ char unk_668[0x004];
|
||||
/* 0x066C */ s32 unk_66C;
|
||||
/* 0x0670 */ s32 meleeWeaponEffectIndex;
|
||||
/* 0x0674 */ PlayerActionFunc actionFunc;
|
||||
/* 0x0678 */ PlayerAgeProperties* ageProperties;
|
||||
/* 0x067C */ u32 stateFlags1;
|
||||
/* 0x0680 */ u32 stateFlags2;
|
||||
/* 0x0684 */ Actor* unk_684;
|
||||
/* 0x0688 */ Actor* boomerangActor;
|
||||
/* 0x068C */ Actor* naviActor;
|
||||
/* 0x0690 */ s16 naviTextId;
|
||||
/* 0x0692 */ u8 stateFlags3;
|
||||
/* 0x0693 */ s8 exchangeItemId;
|
||||
/* 0x0694 */ Actor* targetActor;
|
||||
/* 0x0698 */ f32 targetActorDistance;
|
||||
/* 0x069C */ char unk_69C[0x004];
|
||||
/* 0x06A0 */ f32 unk_6A0;
|
||||
/* 0x06A4 */ f32 unk_6A4;
|
||||
/* 0x06A8 */ Actor* unk_6A8;
|
||||
/* 0x06AC */ s8 unk_6AC;
|
||||
/* 0x06AD */ u8 unk_6AD;
|
||||
/* 0x06AE */ u16 unk_6AE;
|
||||
/* 0x06B0 */ s16 unk_6B0;
|
||||
/* 0x06B2 */ char unk_6B4[0x004];
|
||||
/* 0x06B6 */ s16 unk_6B6;
|
||||
/* 0x06B8 */ s16 unk_6B8;
|
||||
/* 0x06BA */ s16 unk_6BA;
|
||||
/* 0x06BC */ s16 unk_6BC;
|
||||
/* 0x06BE */ s16 unk_6BE;
|
||||
/* 0x06C0 */ s16 unk_6C0;
|
||||
/* 0x06C2 */ s16 unk_6C2;
|
||||
/* 0x06C4 */ f32 unk_6C4;
|
||||
/* 0x06C8 */ SkelAnime skelAnime2;
|
||||
/* 0x070C */ Vec3s jointTable2[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x079C */ Vec3s morphTable2[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x082C */ PlayerFunc82C func_82C;
|
||||
/* 0x0830 */ f32 unk_830;
|
||||
/* 0x0834 */ s16 unk_834;
|
||||
/* 0x0836 */ s8 unk_836;
|
||||
/* 0x0837 */ u8 unk_837;
|
||||
/* 0x0838 */ f32 linearVelocity;
|
||||
/* 0x083C */ s16 currentYaw;
|
||||
/* 0x083E */ s16 targetYaw;
|
||||
/* 0x0840 */ u16 unk_840;
|
||||
/* 0x0842 */ s8 meleeWeaponAnimation;
|
||||
/* 0x0843 */ s8 meleeWeaponState;
|
||||
/* 0x0844 */ s8 unk_844;
|
||||
/* 0x0845 */ u8 unk_845;
|
||||
/* 0x0846 */ u8 unk_846;
|
||||
/* 0x0847 */ s8 unk_847[4];
|
||||
/* 0x084B */ s8 unk_84B[4];
|
||||
/* 0x084F */ s8 unk_84F;
|
||||
/* 0x0850 */ s16 unk_850; // multipurpose timer
|
||||
/* 0x0854 */ f32 unk_854;
|
||||
/* 0x0858 */ f32 unk_858;
|
||||
/* 0x085C */ f32 unk_85C; // stick length among other things
|
||||
/* 0x0860 */ s16 unk_860; // stick flame timer among other things
|
||||
/* 0x0862 */ s16 unk_862; // get item draw ID + 1
|
||||
/* 0x0864 */ f32 unk_864;
|
||||
/* 0x0868 */ f32 unk_868;
|
||||
/* 0x086C */ f32 unk_86C;
|
||||
/* 0x0870 */ f32 unk_870;
|
||||
/* 0x0874 */ f32 unk_874;
|
||||
/* 0x0878 */ f32 unk_878;
|
||||
/* 0x087C */ s16 unk_87C;
|
||||
/* 0x087E */ s16 unk_87E;
|
||||
/* 0x0880 */ f32 unk_880;
|
||||
/* 0x0884 */ f32 wallHeight; // height used to determine whether link can climb or grab a ledge at the top
|
||||
/* 0x0888 */ f32 wallDistance; // distance to the colliding wall plane
|
||||
/* 0x088C */ u8 unk_88C;
|
||||
/* 0x088D */ u8 unk_88D;
|
||||
/* 0x088E */ u8 unk_88E;
|
||||
/* 0x088F */ u8 unk_88F;
|
||||
/* 0x0890 */ u8 unk_890;
|
||||
/* 0x0891 */ u8 shockTimer;
|
||||
/* 0x0892 */ u8 unk_892;
|
||||
/* 0x0893 */ u8 hoverBootsTimer;
|
||||
/* 0x0894 */ s16 fallStartHeight; // last truncated Y position before falling
|
||||
/* 0x0896 */ s16 fallDistance; // truncated Y distance the player has fallen so far (positive is down)
|
||||
/* 0x0898 */ s16 unk_898;
|
||||
/* 0x089A */ s16 unk_89A;
|
||||
/* 0x089C */ s16 unk_89C;
|
||||
/* 0x089E */ u16 unk_89E;
|
||||
/* 0x08A0 */ u8 unk_8A0;
|
||||
/* 0x08A1 */ u8 unk_8A1;
|
||||
/* 0x08A2 */ s16 unk_8A2;
|
||||
/* 0x08A4 */ f32 unk_8A4;
|
||||
/* 0x08A8 */ f32 unk_8A8;
|
||||
/* 0x08AC */ f32 windSpeed; // Pushing player, examples include water currents, floor conveyors, climbing sloped surfaces // Upstream TODO: pushedSpeed
|
||||
/* 0x08B0 */ s16 windDirection; // Yaw direction of player being pushed // Upstream TODO: pushedYaw
|
||||
/* 0x067C */ u32 stateFlags1;
|
||||
/* 0x0680 */ u32 stateFlags2;
|
||||
/* 0x0684 */ Actor* unk_684;
|
||||
/* 0x0688 */ Actor* boomerangActor;
|
||||
/* 0x068C */ Actor* naviActor;
|
||||
/* 0x0690 */ s16 naviTextId;
|
||||
/* 0x0692 */ u8 stateFlags3;
|
||||
/* 0x0693 */ s8 exchangeItemId;
|
||||
/* 0x0694 */ Actor* targetActor;
|
||||
/* 0x0698 */ f32 targetActorDistance;
|
||||
/* 0x069C */ char unk_69C[0x004];
|
||||
/* 0x06A0 */ f32 unk_6A0;
|
||||
/* 0x06A4 */ f32 closestSecretDistSq;
|
||||
/* 0x06A8 */ Actor* unk_6A8;
|
||||
/* 0x06AC */ s8 unk_6AC;
|
||||
/* 0x06AD */ u8 unk_6AD;
|
||||
/* 0x06AE */ u16 unk_6AE;
|
||||
/* 0x06B0 */ s16 unk_6B0;
|
||||
/* 0x06B2 */ char unk_6B4[0x004];
|
||||
/* 0x06B6 */ s16 unk_6B6;
|
||||
/* 0x06B8 */ s16 unk_6B8;
|
||||
/* 0x06BA */ s16 unk_6BA;
|
||||
/* 0x06BC */ s16 unk_6BC;
|
||||
/* 0x06BE */ s16 unk_6BE;
|
||||
/* 0x06C0 */ s16 unk_6C0;
|
||||
/* 0x06C2 */ s16 unk_6C2;
|
||||
/* 0x06C4 */ f32 unk_6C4;
|
||||
/* 0x06C8 */ SkelAnime upperSkelAnime;
|
||||
/* 0x070C */ Vec3s upperJointTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x079C */ Vec3s upperMorphTable[PLAYER_LIMB_BUF_COUNT];
|
||||
/* 0x082C */ UpperActionFunc upperActionFunc;
|
||||
/* 0x0830 */ f32 upperAnimBlendWeight;
|
||||
/* 0x0834 */ s16 unk_834;
|
||||
/* 0x0836 */ s8 unk_836;
|
||||
/* 0x0837 */ u8 unk_837;
|
||||
/* 0x0838 */ f32 linearVelocity;
|
||||
/* 0x083C */ s16 yaw; // General yaw value, used both for world and shape rotation. Current or target value depending on context.
|
||||
/* 0x083E */ s16 zTargetYaw; // yaw relating to Z targeting/"parallel" mode
|
||||
/* 0x0840 */ u16 underwaterTimer;
|
||||
/* 0x0842 */ s8 meleeWeaponAnimation;
|
||||
/* 0x0843 */ s8 meleeWeaponState;
|
||||
/* 0x0844 */ s8 unk_844;
|
||||
/* 0x0845 */ u8 unk_845;
|
||||
/* 0x0846 */ u8 unk_846;
|
||||
/* 0x0847 */ s8 unk_847[4];
|
||||
/* 0x084B */ s8 unk_84B[4];
|
||||
|
||||
/* 0x084F */ union {
|
||||
s8 actionVar1;
|
||||
} av1; // "Action Variable 1": context dependent variable that has different meanings depending on what action is currently running
|
||||
|
||||
/* 0x0850 */ union {
|
||||
s16 actionVar2;
|
||||
} av2; // "Action Variable 2": context dependent variable that has different meanings depending on what action is currently running
|
||||
|
||||
/* 0x0854 */ f32 unk_854;
|
||||
/* 0x0858 */ f32 unk_858;
|
||||
/* 0x085C */ f32 unk_85C; // stick length among other things
|
||||
/* 0x0860 */ s16 unk_860; // stick flame timer among other things
|
||||
/* 0x0862 */ s16 unk_862; // get item draw ID + 1
|
||||
/* 0x0864 */ f32 unk_864;
|
||||
/* 0x0868 */ f32 unk_868;
|
||||
/* 0x086C */ f32 unk_86C;
|
||||
/* 0x0870 */ f32 unk_870;
|
||||
/* 0x0874 */ f32 unk_874;
|
||||
/* 0x0878 */ f32 unk_878;
|
||||
/* 0x087C */ s16 unk_87C;
|
||||
/* 0x087E */ s16 unk_87E;
|
||||
/* 0x0880 */ f32 unk_880;
|
||||
/* 0x0884 */ f32 yDistToLedge; // y distance to ground above an interact wall. LEDGE_DIST_MAX if no ground is found
|
||||
/* 0x0888 */ f32 distToInteractWall; // xyz distance to the interact wall
|
||||
/* 0x088C */ u8 ledgeClimbType;
|
||||
/* 0x088D */ u8 ledgeClimbDelayTimer;
|
||||
/* 0x088E */ u8 unk_88E;
|
||||
/* 0x088F */ u8 unk_88F;
|
||||
/* 0x0890 */ u8 unk_890;
|
||||
/* 0x0891 */ u8 bodyShockTimer;
|
||||
/* 0x0892 */ u8 unk_892;
|
||||
/* 0x0893 */ u8 hoverBootsTimer;
|
||||
/* 0x0894 */ s16 fallStartHeight; // last truncated Y position before falling
|
||||
/* 0x0896 */ s16 fallDistance; // truncated Y distance the player has fallen so far (positive is down)
|
||||
/* 0x0898 */ s16 floorPitch; // angle of the floor slope in the direction of current world yaw (positive for ascending slope)
|
||||
/* 0x089A */ s16 floorPitchAlt; // the calculation for this value is bugged and doesn't represent anything meaningful
|
||||
/* 0x089C */ s16 unk_89C;
|
||||
/* 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];
|
||||
/* 0x0908 */ Vec3f bodyPartsPos[PLAYER_BODYPART_MAX];
|
||||
/* 0x09E0 */ MtxF mf_9E0;
|
||||
/* 0x0A20 */ MtxF shieldMf;
|
||||
/* 0x0A60 */ u8 isBurning;
|
||||
/* 0x0A61 */ u8 flameTimers[PLAYER_BODYPART_MAX]; // one flame per body part
|
||||
/* 0x0A73 */ u8 unk_A73;
|
||||
/* 0x0908 */ Vec3f bodyPartsPos[PLAYER_BODYPART_MAX];
|
||||
/* 0x09E0 */ MtxF mf_9E0;
|
||||
/* 0x0A20 */ MtxF shieldMf;
|
||||
/* 0x0A60 */ u8 bodyIsBurning;
|
||||
/* 0x0A61 */ u8 bodyFlameTimers[PLAYER_BODYPART_MAX]; // one flame per body part
|
||||
/* 0x0A73 */ u8 unk_A73;
|
||||
/* 0x0A74 */ PlayerFuncA74 func_A74;
|
||||
/* 0x0A78 */ s8 invincibilityTimer; // prevents damage when nonzero (positive = visible, counts towards zero each frame)
|
||||
/* 0x0A79 */ u8 unk_A79;
|
||||
/* 0x0A7A */ u8 unk_A7A;
|
||||
/* 0x0A7B */ u8 unk_A7B;
|
||||
/* 0x0A7C */ f32 unk_A7C;
|
||||
/* 0x0A80 */ s16 unk_A80;
|
||||
/* 0x0A82 */ u16 unk_A82;
|
||||
/* 0x0A84 */ s16 unk_A84;
|
||||
/* 0x0A86 */ s8 unk_A86;
|
||||
/* 0x0A87 */ u8 unk_A87;
|
||||
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
|
||||
/* 0x0A78 */ s8 invincibilityTimer; // prevents damage when nonzero (positive = visible, counts towards zero each frame)
|
||||
/* 0x0A79 */ u8 floorTypeTimer; // counts up every frame the current floor type is the same as the last frame
|
||||
/* 0x0A7A */ u8 floorProperty;
|
||||
/* 0x0A7B */ u8 prevFloorType;
|
||||
/* 0x0A7C */ f32 prevControlStickMagnitude;
|
||||
/* 0x0A80 */ s16 prevControlStickAngle;
|
||||
/* 0x0A82 */ u16 prevFloorSfxOffset;
|
||||
/* 0x0A84 */ s16 unk_A84;
|
||||
/* 0x0A86 */ s8 unk_A86;
|
||||
/* 0x0A87 */ u8 unk_A87;
|
||||
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
|
||||
// #region SOH [General]
|
||||
// Upstream TODO: Rename these to be more obviously SoH specific
|
||||
/* */ PendingFlag pendingFlag;
|
||||
@ -680,7 +677,7 @@ typedef struct Player {
|
||||
// #endregion
|
||||
// #region SOH [Enhancements]
|
||||
// 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
|
||||
u8 ivanFloating;
|
||||
u8 ivanDamageMultiplier;
|
||||
|
@ -314,8 +314,34 @@ enum SceneID {
|
||||
/* 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
|
||||
|
||||
// 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 {
|
||||
/* 0 */ SDC_DEFAULT,
|
||||
/* 1 */ SDC_HYRULE_FIELD,
|
||||
|
@ -50,11 +50,16 @@ typedef struct {
|
||||
/* 0x004 */ Color_RGBA8_u32 envColor;
|
||||
/* 0x008 */ s32 texX;
|
||||
/* 0x00C */ s32 texY;
|
||||
/* 0x010 */ s32 step;
|
||||
/* 0x014 */ u8 unk_14;
|
||||
/* 0x015 */ u8 typeColor;
|
||||
/* 0x016 */ u8 speed;
|
||||
/* 0x017 */ u8 effect;
|
||||
// /* 0x010 */ s32 step;
|
||||
// /* 0x014 */ u8 unk_14;
|
||||
// /* 0x015 */ u8 typeColor;
|
||||
// /* 0x016 */ u8 speed;
|
||||
// /* 0x017 */ u8 effect;
|
||||
/* 0x010 */ s32 speed;
|
||||
/* 0x014 */ u8 direction;
|
||||
/* 0x015 */ u8 colorType;
|
||||
/* 0x016 */ u8 speedType;
|
||||
/* 0x017 */ u8 appearanceType;
|
||||
/* 0x018 */ u8 isDone;
|
||||
/* 0x019 */ u8 frame;
|
||||
/* 0x01A */ u16 normal;
|
||||
|
@ -33,5 +33,10 @@
|
||||
<string>public.app-category.games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
<key>LSArchitecturePriority</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
<string>x86_64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -14,11 +14,6 @@ if [ ! -e "$SHIP_HOME"/mods ]; then
|
||||
touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt
|
||||
fi
|
||||
|
||||
arch_name="$(uname -m)"
|
||||
launch_arch="arm64"
|
||||
if [ "${arch_name}" = "x86_64" ] && [ "$(sysctl -in sysctl.proc_translated)" != "1" ]; then
|
||||
launch_arch="x86_64"
|
||||
fi
|
||||
"$RESPATH"/soh-macos
|
||||
|
||||
arch -${launch_arch} "$RESPATH"/soh-macos
|
||||
exit
|
||||
|
@ -74,7 +74,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
|
||||
{ ACTOR_EN_BUBBLE, "Shabom" },
|
||||
{ ACTOR_DOOR_SHUTTER, "Shutter Door" },
|
||||
{ ACTOR_EN_DODOJR, "Baby Dodongo" },
|
||||
{ ACTOR_EN_BDFIRE, "Empty" },
|
||||
{ ACTOR_EN_BDFIRE, "King Dodongo's Fire Breath" },
|
||||
{ ACTOR_EN_BOOM, "Boomerang" },
|
||||
{ ACTOR_EN_TORCH2, "Dark Link" },
|
||||
{ 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_EN_YUKABYUN, "Flying Floor Tile" },
|
||||
{ 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_HIDAN_KOUSI, "Sliding Metal Gate" },
|
||||
{ ACTOR_DOOR_TOKI, "Door of Time Collision" },
|
||||
@ -548,6 +548,10 @@ int ActorDB::RetrieveId(const std::string& name) {
|
||||
return entry->second;
|
||||
}
|
||||
|
||||
int ActorDB::GetEntryCount() {
|
||||
return db.size();
|
||||
}
|
||||
|
||||
ActorDB::Entry::Entry() {
|
||||
entry.name = nullptr;
|
||||
entry.desc = nullptr;
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
|
||||
static void AddBuiltInCustomActors();
|
||||
|
||||
int GetEntryCount();
|
||||
private:
|
||||
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);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <Utils/StringHelper.h>
|
||||
#include "../../UIWidgets.hpp"
|
||||
#include "AudioCollection.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
|
||||
Vec3f pos = { 0.0f, 0.0f, 0.0f };
|
||||
f32 freqScale = 1.0f;
|
||||
@ -78,7 +79,12 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
|
||||
|
||||
void RandomizeGroup(SeqType type) {
|
||||
std::vector<u16> values;
|
||||
|
||||
|
||||
// An empty IncludedSequences set means that the AudioEditor window has never been drawn
|
||||
if (AudioCollection::Instance->GetIncludedSequences().empty()) {
|
||||
AudioCollection::Instance->InitializeShufflePool();
|
||||
}
|
||||
|
||||
// use a while loop to add duplicates if we don't have enough included sequences
|
||||
while (values.size() < AuthenticCountBySequenceType(type)) {
|
||||
for (const auto& seqData : AudioCollection::Instance->GetIncludedSequences()) {
|
||||
@ -123,6 +129,34 @@ void ResetGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
|
||||
}
|
||||
}
|
||||
|
||||
void LockGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
|
||||
for (const auto& [defaultValue, seqData] : map) {
|
||||
if (seqData.category == type) {
|
||||
// Only save authentic sequence CVars
|
||||
if (seqData.category == SEQ_FANFARE && defaultValue >= MAX_AUTHENTIC_SEQID) {
|
||||
continue;
|
||||
}
|
||||
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
|
||||
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
|
||||
CVarSetInteger(cvarLockKey.c_str(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnlockGroup(const std::map<u16, SequenceInfo>& map, SeqType type) {
|
||||
for (const auto& [defaultValue, seqData] : map) {
|
||||
if (seqData.category == type) {
|
||||
// Only save authentic sequence CVars
|
||||
if (seqData.category == SEQ_FANFARE && defaultValue >= MAX_AUTHENTIC_SEQID) {
|
||||
continue;
|
||||
}
|
||||
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
|
||||
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
|
||||
CVarSetInteger(cvarLockKey.c_str(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequenceType) {
|
||||
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(sfxKey);
|
||||
const std::string hiddenKey = "##" + cvarKey;
|
||||
@ -163,6 +197,8 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
|
||||
const std::string hiddenTabId = "##" + tabId;
|
||||
const std::string resetAllButton = "Reset All" + hiddenTabId;
|
||||
const std::string randomizeAllButton = "Randomize All" + hiddenTabId;
|
||||
const std::string lockAllButton = "Lock All" + hiddenTabId;
|
||||
const std::string unlockAllButton = "Unlock All" + hiddenTabId;
|
||||
if (ImGui::Button(resetAllButton.c_str())) {
|
||||
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
|
||||
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
|
||||
@ -184,6 +220,28 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
|
||||
ReplayCurrentBGM();
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(lockAllButton.c_str())) {
|
||||
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
|
||||
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
|
||||
LockGroup(map, type);
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
|
||||
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
|
||||
ReplayCurrentBGM();
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(unlockAllButton.c_str())) {
|
||||
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
|
||||
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
|
||||
UnlockGroup(map, type);
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
auto curReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
|
||||
if (type == SEQ_BGM_WORLD && prevReplacement != curReplacement) {
|
||||
ReplayCurrentBGM();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit);
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
|
||||
@ -350,6 +408,19 @@ void DrawTypeChip(SeqType type) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
|
||||
void AudioEditorRegisterOnSceneInitHook() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
|
||||
if (CVarGetInteger("gAudioEditor.RandomizeAllOnNewScene", 0)) {
|
||||
AudioEditor_RandomizeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AudioEditor::InitElement() {
|
||||
AudioEditorRegisterOnSceneInitHook();
|
||||
}
|
||||
|
||||
void AudioEditor::DrawElement() {
|
||||
AudioCollection::Instance->InitializeShufflePool();
|
||||
|
||||
@ -359,6 +430,28 @@ void AudioEditor::DrawElement() {
|
||||
return;
|
||||
}
|
||||
|
||||
float buttonSegments = ImGui::GetContentRegionAvail().x / 4;
|
||||
if (ImGui::Button("Randomize All Groups", ImVec2(buttonSegments, 30.0f))) {
|
||||
AudioEditor_RandomizeAll();
|
||||
}
|
||||
UIWidgets::Tooltip("Randomizes all unlocked music and sound effects across tab groups");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset All Groups", ImVec2(buttonSegments, 30.0f))) {
|
||||
AudioEditor_ResetAll();
|
||||
}
|
||||
UIWidgets::Tooltip("Resets all unlocked music and sound effects across tab groups");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Lock All Groups", ImVec2(buttonSegments, 30.0f))) {
|
||||
AudioEditor_LockAll();
|
||||
}
|
||||
UIWidgets::Tooltip("Locks all music and sound effects across tab groups");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Unlock All Groups", ImVec2(buttonSegments, 30.0f))) {
|
||||
AudioEditor_UnlockAll();
|
||||
}
|
||||
UIWidgets::Tooltip("Unlocks all music and sound effects across tab groups");
|
||||
|
||||
|
||||
if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
|
||||
if (ImGui::BeginTabItem("Background Music")) {
|
||||
Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD);
|
||||
@ -422,8 +515,8 @@ void AudioEditor::DrawElement() {
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NewLine();
|
||||
ImGui::PopItemWidth();
|
||||
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %f", "##linkVoiceFreqMultiplier",
|
||||
"gLinkVoiceFreqMultiplier", 0.4, 2.5, "", 1.0, false, false);
|
||||
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %.1f %%", "##linkVoiceFreqMultiplier",
|
||||
"gLinkVoiceFreqMultiplier", 0.4, 2.5, "", 1.0, true, true);
|
||||
ImGui::SameLine();
|
||||
const std::string resetButton = "Reset##linkVoiceFreqMultiplier";
|
||||
if (ImGui::Button(resetButton.c_str())) {
|
||||
@ -431,6 +524,10 @@ void AudioEditor::DrawElement() {
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
UIWidgets::EnhancementCheckbox("Randomize All Music and Sound Effects on New Scene", "gAudioEditor.RandomizeAllOnNewScene");
|
||||
UIWidgets::Tooltip("Enables randomizing all unlocked music and sound effects when you enter a new scene.");
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::PushItemWidth(-FLT_MIN);
|
||||
UIWidgets::PaddedSeparator();
|
||||
@ -625,3 +722,19 @@ void AudioEditor_ResetAll() {
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
ReplayCurrentBGM();
|
||||
}
|
||||
|
||||
void AudioEditor_LockAll() {
|
||||
for (auto type : allTypes) {
|
||||
LockGroup(AudioCollection::Instance->GetAllSequences(), type);
|
||||
}
|
||||
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
|
||||
void AudioEditor_UnlockAll() {
|
||||
for (auto type : allTypes) {
|
||||
UnlockGroup(AudioCollection::Instance->GetAllSequences(), type);
|
||||
}
|
||||
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <libultraship/libultraship.h>
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include <ImGui/imgui.h>
|
||||
|
||||
class AudioEditor : public LUS::GuiWindow {
|
||||
@ -11,13 +14,15 @@ class AudioEditor : public LUS::GuiWindow {
|
||||
using LUS::GuiWindow::GuiWindow;
|
||||
|
||||
void DrawElement() override;
|
||||
void InitElement() override {};
|
||||
void InitElement() override;
|
||||
void UpdateElement() override {};
|
||||
~AudioEditor() {};
|
||||
};
|
||||
|
||||
void AudioEditor_RandomizeAll();
|
||||
void AudioEditor_ResetAll();
|
||||
void AudioEditor_LockAll();
|
||||
void AudioEditor_UnlockAll();
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -175,33 +175,33 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
// Gohma & Phantom Ganon
|
||||
if (warpPosX == -100 && warpPosZ == -170) {
|
||||
if (gSaveContext.linkAge == LINK_AGE_CHILD) {
|
||||
play->nextEntranceIndex = 0x040F;
|
||||
play->nextEntranceIndex = ENTR_DEKU_TREE_BOSS_0;
|
||||
} else {
|
||||
play->nextEntranceIndex = 0x000C;
|
||||
play->nextEntranceIndex = ENTR_FOREST_TEMPLE_BOSS_0;
|
||||
}
|
||||
// King Dodongo & Volvagia
|
||||
} else if (warpPosX == 100 && warpPosZ == -170) {
|
||||
if (gSaveContext.linkAge == LINK_AGE_CHILD) {
|
||||
play->nextEntranceIndex = 0x040B;
|
||||
play->nextEntranceIndex = ENTR_DODONGOS_CAVERN_BOSS_0;
|
||||
} else {
|
||||
play->nextEntranceIndex = 0x0305;
|
||||
play->nextEntranceIndex = ENTR_FIRE_TEMPLE_BOSS_0;
|
||||
}
|
||||
// Barinade & Morb
|
||||
} else if (warpPosX == 199 && warpPosZ == 0) {
|
||||
if (gSaveContext.linkAge == LINK_AGE_CHILD) {
|
||||
play->nextEntranceIndex = 0x0301;
|
||||
play->nextEntranceIndex = ENTR_JABU_JABU_BOSS_0;
|
||||
} else {
|
||||
play->nextEntranceIndex = 0x0417;
|
||||
play->nextEntranceIndex = ENTR_WATER_TEMPLE_BOSS_0;
|
||||
}
|
||||
// Twinrova
|
||||
} else if (warpPosX == 100 && warpPosZ == 170) {
|
||||
play->nextEntranceIndex = 0x05EC;
|
||||
play->nextEntranceIndex = ENTR_SPIRIT_TEMPLE_BOSS_2;
|
||||
// Bongo Bongo
|
||||
} else if (warpPosX == -100 && warpPosZ == 170) {
|
||||
play->nextEntranceIndex = 0x0413;
|
||||
play->nextEntranceIndex = ENTR_SHADOW_TEMPLE_BOSS_0;
|
||||
// Ganondork
|
||||
} 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.
|
||||
} else {
|
||||
@ -216,10 +216,10 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) {
|
||||
BossRush_SetEquipment(LINK_AGE_ADULT);
|
||||
// Warp to credits.
|
||||
} 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;
|
||||
play->sceneLoadFlag = 0x14;
|
||||
play->fadeTransition = 3;
|
||||
play->transitionTrigger = TRANS_TRIGGER_START;
|
||||
play->transitionType = TRANS_TYPE_FADE_WHITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,7 +293,7 @@ void BossRush_InitSave() {
|
||||
|
||||
gSaveContext.questId = QUEST_BOSSRUSH;
|
||||
gSaveContext.isBossRushPaused = 1;
|
||||
gSaveContext.entranceIndex = 107;
|
||||
gSaveContext.entranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0;
|
||||
gSaveContext.cutsceneIndex = 0x8000;
|
||||
gSaveContext.isMagicAcquired = 1;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
519
soh/soh/Enhancements/controls/InputViewer.cpp
Normal file
@ -0,0 +1,519 @@
|
||||
#include "InputViewer.h"
|
||||
|
||||
#include "public/bridge/consolevariablebridge.h"
|
||||
#include "libultraship/libultra/controller.h"
|
||||
#include "Context.h"
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include <ImGui/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(LUS::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(LUS::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("gOpenWindows.InputViewer", 0)) {
|
||||
static bool sButtonTexturesLoaded = false;
|
||||
if (!sButtonTexturesLoaded) {
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage(
|
||||
"Input-Viewer-Background", "textures/buttons/InputViewerBackground.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("A-Btn", "textures/buttons/ABtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("B-Btn", "textures/buttons/BBtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("L-Btn", "textures/buttons/LBtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("R-Btn", "textures/buttons/RBtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Z-Btn", "textures/buttons/ZBtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Start-Btn",
|
||||
"textures/buttons/StartBtn.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Left", "textures/buttons/CLeft.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Right", "textures/buttons/CRight.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Up", "textures/buttons/CUp.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Down", "textures/buttons/CDown.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Analog-Stick",
|
||||
"textures/buttons/AnalogStick.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Left",
|
||||
"textures/buttons/DPadLeft.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Right",
|
||||
"textures/buttons/DPadRight.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Up", "textures/buttons/DPadUp.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Down",
|
||||
"textures/buttons/DPadDown.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Right-Stick",
|
||||
"textures/buttons/RightStick.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("A-Btn Outline",
|
||||
"textures/buttons/ABtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("B-Btn Outline",
|
||||
"textures/buttons/BBtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("L-Btn Outline",
|
||||
"textures/buttons/LBtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("R-Btn Outline",
|
||||
"textures/buttons/RBtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Z-Btn Outline",
|
||||
"textures/buttons/ZBtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Start-Btn Outline",
|
||||
"textures/buttons/StartBtnOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Left Outline",
|
||||
"textures/buttons/CLeftOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Right Outline",
|
||||
"textures/buttons/CRightOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Up Outline",
|
||||
"textures/buttons/CUpOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("C-Down Outline",
|
||||
"textures/buttons/CDownOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Analog-Stick Outline",
|
||||
"textures/buttons/AnalogStickOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Left Outline",
|
||||
"textures/buttons/DPadLeftOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Right Outline",
|
||||
"textures/buttons/DPadRightOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Up Outline",
|
||||
"textures/buttons/DPadUpOutline.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Dpad-Down Outline",
|
||||
"textures/buttons/DPadDownOutline.png");
|
||||
LUS::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("gInputViewer.Scale", 1.0f) * 2.0f;
|
||||
#else
|
||||
const float scale = CVarGetFloat("gInputViewer.Scale", 1.0f);
|
||||
#endif
|
||||
const int showAnalogAngles = CVarGetInteger("gInputViewer.AnalogAngles.Enabled", 0);
|
||||
const int buttonOutlineMode = CVarGetInteger("gInputViewer.ButtonOutlineMode", BUTTON_OUTLINE_NOT_PRESSED);
|
||||
|
||||
ImVec2 bgSize = LUS::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("gInputViewer.AnalogAngles.Scale", 1.0f) + 20));
|
||||
ImGui::SetNextWindowContentSize(
|
||||
ImVec2(scaledBGSize.x, scaledBGSize.y + (showAnalogAngles ? 15 : 0) * scale *
|
||||
CVarGetFloat("gInputViewer.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 = LUS::Context::GetInstance()->GetControlDeck()->GetPads();
|
||||
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing;
|
||||
|
||||
if (!CVarGetInteger("gInputViewer.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("gInputViewer.ShowBackground", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
// Background
|
||||
ImGui::Image(
|
||||
LUS::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("gInputViewer.BBtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("B-Btn", "B-Btn Outline", pads[0].button & BTN_B, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.ABtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("A-Btn", "A-Btn Outline", pads[0].button & BTN_A, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
|
||||
// C buttons
|
||||
if (CVarGetInteger("gInputViewer.CUp", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("C-Up", "C-Up Outline", pads[0].button & BTN_CUP, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.CLeft", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("C-Left", "C-Left Outline", pads[0].button & BTN_CLEFT, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.CRight", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("C-Right", "C-Right Outline", pads[0].button & BTN_CRIGHT, scaledBGSize,
|
||||
buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.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("gInputViewer.LBtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("L-Btn", "L-Btn Outline", pads[0].button & BTN_L, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.RBtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("R-Btn", "R-Btn Outline", pads[0].button & BTN_R, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
if (CVarGetInteger("gInputViewer.ZBtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("Z-Btn", "Z-Btn Outline", pads[0].button & BTN_Z, scaledBGSize, buttonOutlineMode);
|
||||
}
|
||||
|
||||
// Start
|
||||
if (CVarGetInteger("gInputViewer.StartBtn", 1)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
RenderButton("Start-Btn", "Start-Btn Outline", pads[0].button & BTN_START, scaledBGSize,
|
||||
buttonOutlineMode);
|
||||
}
|
||||
|
||||
// Dpad
|
||||
if (CVarGetInteger("gInputViewer.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("gInputViewer.AnalogStick.OutlineMode", STICK_MODE_ALWAYS_SHOWN);
|
||||
const float maxStickDistance = CVarGetInteger("gInputViewer.AnalogStick.Movement", 12);
|
||||
if (analogOutlineMode == STICK_MODE_ALWAYS_SHOWN ||
|
||||
(analogOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) {
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetCursorPos(aPos);
|
||||
ImGui::Image(
|
||||
LUS::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("gInputViewer.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(LUS::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("gInputViewer.RightStick.Movement", 7);
|
||||
const int rightOutlineMode =
|
||||
CVarGetInteger("gInputViewer.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(
|
||||
LUS::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("gInputViewer.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(LUS::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("gInputViewer.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("gInputViewer.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("gInputViewer.AnalogAngles.Range1.Min", 8);
|
||||
const int range1Max = CVarGetInteger("gInputViewer.AnalogAngles.Range1.Max", 27);
|
||||
// Walking speed range
|
||||
const int range2Min = CVarGetInteger("gInputViewer.AnalogAngles.Range2.Min", 27);
|
||||
const int range2Max = CVarGetInteger("gInputViewer.AnalogAngles.Range2.Max", 62);
|
||||
|
||||
// Push color based on angle ranges
|
||||
if (CVarGetInteger("gInputViewer.AnalogAngles.Range1.Enabled", 0) &&
|
||||
(rSquared >= (range1Min * range1Min)) && (rSquared < (range1Max * range1Max))) {
|
||||
ImGui::PushStyleColor(
|
||||
ImGuiCol_Text,
|
||||
color2Vec(CVarGetColor("gInputViewer.AnalogAngles.Range1.Color", vec2Color(range1Color))));
|
||||
} else if (CVarGetInteger("gInputViewer.AnalogAngles.Range2.Enabled", 0) &&
|
||||
(rSquared >= (range2Min * range2Min)) && (rSquared < (range2Max * range2Max))) {
|
||||
ImGui::PushStyleColor(
|
||||
ImGuiCol_Text,
|
||||
color2Vec(CVarGetColor("gInputViewer.AnalogAngles.Range2.Color", vec2Color(range2Color))));
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color2Vec(CVarGetColor("gInputViewer.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", "gInputViewer.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", "gInputViewer.EnableDragging", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
|
||||
UIWidgets::PaddedSeparator(true, true);
|
||||
|
||||
// gInputViewer.ShowBackground
|
||||
UIWidgets::EnhancementCheckbox("Show Background Layer", "gInputViewer.ShowBackground", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
|
||||
UIWidgets::PaddedSeparator(true, true);
|
||||
|
||||
if (ImGui::CollapsingHeader("Buttons")) {
|
||||
// gInputViewer.ABtn
|
||||
UIWidgets::EnhancementCheckbox("Show A-Button Layers", "gInputViewer.ABtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.BBtn
|
||||
UIWidgets::EnhancementCheckbox("Show B-Button Layers", "gInputViewer.BBtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.CUp
|
||||
UIWidgets::EnhancementCheckbox("Show C-Up Layers", "gInputViewer.CUp", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.CRight
|
||||
UIWidgets::EnhancementCheckbox("Show C-Right Layers", "gInputViewer.CRight", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.CDown
|
||||
UIWidgets::EnhancementCheckbox("Show C-Down Layers", "gInputViewer.CDown", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.CLeft
|
||||
UIWidgets::EnhancementCheckbox("Show C-Left Layers", "gInputViewer.CLeft", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.LBtn
|
||||
UIWidgets::EnhancementCheckbox("Show L-Button Layers", "gInputViewer.LBtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.RBtn
|
||||
UIWidgets::EnhancementCheckbox("Show R-Button Layers", "gInputViewer.RBtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.ZBtn
|
||||
UIWidgets::EnhancementCheckbox("Show Z-Button Layers", "gInputViewer.ZBtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.StartBtn
|
||||
UIWidgets::EnhancementCheckbox("Show Start Button Layers", "gInputViewer.StartBtn", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, true);
|
||||
// gInputViewer.Dpad
|
||||
UIWidgets::EnhancementCheckbox("Show D-Pad Layers", "gInputViewer.Dpad", false, "",
|
||||
UIWidgets::CheckboxGraphics::Checkmark, false);
|
||||
|
||||
// gInputViewer.ButtonOutlineMode
|
||||
UIWidgets::PaddedText("Button Outlines/Backgrounds", true, false);
|
||||
UIWidgets::EnhancementCombobox("gInputViewer.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("gInputViewer.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("gInputViewer.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",
|
||||
"gInputViewer.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("gInputViewer.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("gInputViewer.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",
|
||||
"gInputViewer.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", "gInputViewer.AnalogAngles.Enabled");
|
||||
UIWidgets::Tooltip("Displays analog stick angle values in the input viewer");
|
||||
if (CVarGetInteger("gInputViewer.AnalogAngles.Enabled", 0)) {
|
||||
// gInputViewer.AnalogAngles.TextColor
|
||||
if (ImGui::ColorEdit4("Text Color", (float*)&textColor)) {
|
||||
CVarSetColor("gInputViewer.AnalogAngles.TextColor", vec2Color(textColor));
|
||||
}
|
||||
// gAnalogAngleScale
|
||||
UIWidgets::EnhancementSliderFloat("Angle Text Scale: %.2f%%", "##AnalogAngleScale",
|
||||
"gInputViewer.AnalogAngles.Scale", 0.1f, 5.0f, "", 1.0f, true, true);
|
||||
// gInputViewer.AnalogAngles.Offset
|
||||
UIWidgets::EnhancementSliderInt("Angle Text Offset: %dpx", "##AnalogAngleOffset",
|
||||
"gInputViewer.AnalogAngles.Offset", 0, 400, "", 0, true);
|
||||
UIWidgets::PaddedSeparator(true, true);
|
||||
// gInputViewer.AnalogAngles.Range1.Enabled
|
||||
UIWidgets::EnhancementCheckbox("Highlight ESS Position", "gInputViewer.AnalogAngles.Range1.Enabled");
|
||||
UIWidgets::Tooltip(
|
||||
"Highlights the angle value text when the analog stick is in ESS position (on flat ground)");
|
||||
if (CVarGetInteger("gInputViewer.AnalogAngles.Range1.Enabled", 0)) {
|
||||
// gInputViewer.AnalogAngles.Range1.Color
|
||||
if (ImGui::ColorEdit4("ESS Color", (float*)&range1Color)) {
|
||||
CVarSetColor("gInputViewer.AnalogAngles.Range1.Color", vec2Color(range1Color));
|
||||
}
|
||||
}
|
||||
|
||||
UIWidgets::PaddedSeparator(true, true);
|
||||
// gInputViewer.AnalogAngles.Range2.Enabled
|
||||
UIWidgets::EnhancementCheckbox("Highlight Walking Speed Angles",
|
||||
"gInputViewer.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("gInputViewer.AnalogAngles.Range2.Enabled", 0)) {
|
||||
// gInputViewer.AnalogAngles.Range2.Color
|
||||
if (ImGui::ColorEdit4("Walking Speed Color", (float*)&range2Color)) {
|
||||
CVarSetColor("gInputViewer.AnalogAngles.Range2.Color", vec2Color(range2Color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
47
soh/soh/Enhancements/controls/InputViewer.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
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 LUS::GuiWindow {
|
||||
public:
|
||||
using LUS::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 LUS::GuiWindow {
|
||||
public:
|
||||
using LUS::GuiWindow::GuiWindow;
|
||||
|
||||
void InitElement() override {};
|
||||
void DrawElement() override;
|
||||
void UpdateElement() override {};
|
||||
|
||||
InputViewerSettingsWindow();
|
||||
~InputViewerSettingsWindow();
|
||||
|
||||
void Draw();
|
||||
};
|
2256
soh/soh/Enhancements/controls/SohInputEditorWindow.cpp
Normal file
107
soh/soh/Enhancements/controls/SohInputEditorWindow.h
Normal 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/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 LUS::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, LUS::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, LUS::Direction direction, std::string id);
|
||||
void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, LUS::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<LUS::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<LUS::Direction, std::vector<std::string>>>>
|
||||
mStickDirectionToMappingIds;
|
||||
|
||||
void UpdateBitmaskToMappingIds(uint8_t port);
|
||||
void UpdateStickDirectionToMappingIds(uint8_t port);
|
||||
|
||||
void GetButtonColorsForLUSDeviceIndex(LUS::LUSDeviceIndex 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, LUS::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);
|
||||
};
|
@ -67,6 +67,7 @@ typedef enum {
|
||||
GROUP_EQUIPMENT,
|
||||
GROUP_CONSUMABLE,
|
||||
GROUP_HUD,
|
||||
GROUP_KALEIDO,
|
||||
GROUP_TITLE,
|
||||
GROUP_NPC,
|
||||
GROUP_WORLD,
|
||||
@ -75,6 +76,7 @@ typedef enum {
|
||||
GROUP_SPIN_ATTACK,
|
||||
GROUP_TRAILS,
|
||||
GROUP_NAVI,
|
||||
GROUP_IVAN,
|
||||
} CosmeticGroup;
|
||||
|
||||
std::map<CosmeticGroup, const char*> groupLabels = {
|
||||
@ -85,6 +87,7 @@ std::map<CosmeticGroup, const char*> groupLabels = {
|
||||
{ GROUP_EQUIPMENT, "Equipment" },
|
||||
{ GROUP_CONSUMABLE, "Consumables" },
|
||||
{ GROUP_HUD, "HUD" },
|
||||
{ GROUP_KALEIDO, "Pause Menu" },
|
||||
{ GROUP_TITLE, "Title Screen" },
|
||||
{ GROUP_NPC, "NPCs" },
|
||||
{ GROUP_WORLD, "World" },
|
||||
@ -93,6 +96,7 @@ std::map<CosmeticGroup, const char*> groupLabels = {
|
||||
{ GROUP_SPIN_ATTACK, "Spin Attack" },
|
||||
{ GROUP_TRAILS, "Trails" },
|
||||
{ GROUP_NAVI, "Navi" },
|
||||
{ GROUP_IVAN, "Ivan" }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -265,6 +269,38 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
|
||||
COSMETIC_OPTION("Hud_NameTagActorText", "Nametag Text", GROUP_HUD, ImVec4(255, 255, 255, 255), true, true, false),
|
||||
COSMETIC_OPTION("Hud_NameTagActorBackground", "Nametag Background", GROUP_HUD, ImVec4(0, 0, 0, 80), true, false, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_ItemSelA", "Item Select Color", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_ItemSelB", "Item Select Color B", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_ItemSelC", "Item Select Color C", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_ItemSelD", "Item Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_EquipSelA", "Equip Select Color", GROUP_KALEIDO, ImVec4(10, 50, 40, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_EquipSelB", "Equip Select Color B", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_EquipSelC", "Equip Select Color C", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_EquipSelD", "Equip Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_MapSelDunA", "Map Dungeon Color", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_MapSelDunB", "Map Dungeon Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_MapSelDunC", "Map Dungeon Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_MapSelDunD", "Map Dungeon Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_QuestStatusA", "Quest Status Color", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_QuestStatusB", "Quest Status Color B", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_QuestStatusC", "Quest Status Color C", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_QuestStatusD", "Quest Status Color D", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_MapSelectA", "Map Color", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelectB", "Map Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_MapSelectC", "Map Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_MapSelectD", "Map Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_SaveA", "Save Color", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_SaveB", "Save Color B", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_SaveC", "Save Color C", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, true),
|
||||
COSMETIC_OPTION("Kal_SaveD", "Save Color D", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_NamePanel", "Name Panel", GROUP_KALEIDO, ImVec4(90,100,130,255), true, true, false),
|
||||
|
||||
COSMETIC_OPTION("Title_FileChoose", "File Choose", GROUP_TITLE, ImVec4(100, 150, 255, 255), false, true, false),
|
||||
COSMETIC_OPTION("Title_NintendoLogo", "Nintendo Logo", GROUP_TITLE, ImVec4( 0, 0, 255, 255), false, true, true),
|
||||
COSMETIC_OPTION("Title_N64LogoRed", "N64 Red", GROUP_TITLE, ImVec4(150, 0, 0, 255), false, true, true),
|
||||
@ -316,6 +352,9 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
|
||||
COSMETIC_OPTION("Navi_EnemySecondary", "Enemy Secondary", GROUP_NAVI, ImVec4(200, 155, 0, 0), false, true, true),
|
||||
COSMETIC_OPTION("Navi_PropsPrimary", "Props Primary", GROUP_NAVI, ImVec4( 0, 255, 0, 255), false, true, false),
|
||||
COSMETIC_OPTION("Navi_PropsSecondary", "Props Secondary", GROUP_NAVI, ImVec4( 0, 255, 0, 0), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("Ivan_IdlePrimary", "Ivan Idle Primary", GROUP_IVAN, ImVec4(255, 255, 255, 255), false, true, false),
|
||||
COSMETIC_OPTION("Ivan_IdleSecondary", "Ivan Idle Secondary", GROUP_IVAN, ImVec4( 0, 255, 0, 255), false, true, true),
|
||||
|
||||
COSMETIC_OPTION("NPC_FireKeesePrimary", "Fire Keese Primary", GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, false),
|
||||
COSMETIC_OPTION("NPC_FireKeeseSecondary", "Fire Keese Secondary", GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, true),
|
||||
@ -1026,12 +1065,16 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) {
|
||||
if (manualChange || CVarGetInteger(npcGoldenSkulltula.rainbowCvar, 0)) {
|
||||
static Color_RGBA8 defaultColor = {npcGoldenSkulltula.defaultColor.x, npcGoldenSkulltula.defaultColor.y, npcGoldenSkulltula.defaultColor.z, npcGoldenSkulltula.defaultColor.w};
|
||||
Color_RGBA8 color = CVarGetColor(npcGoldenSkulltula.cvar, defaultColor);
|
||||
PATCH_GFX(gGiSkulltulaTokenDL, "NPC_GoldenSkulltula1", npcGoldenSkulltula.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenDL, "NPC_GoldenSkulltula2", npcGoldenSkulltula.changedCvar, 6, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenFlameDL, "NPC_GoldenSkulltula3", npcGoldenSkulltula.changedCvar, 32, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenFlameDL, "NPC_GoldenSkulltula4", npcGoldenSkulltula.changedCvar, 33, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(object_st_DL_003FB0, "NPC_GoldenSkulltula5", npcGoldenSkulltula.changedCvar, 118, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(object_st_DL_003FB0, "NPC_GoldenSkulltula6", npcGoldenSkulltula.changedCvar, 119, gsDPSetEnvColor(color.r / 4, color.g / 4, color.b / 4, 255));
|
||||
PATCH_GFX(gSkulltulaTokenDL, "NPC_GoldenSkulltula1", npcGoldenSkulltula.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gSkulltulaTokenDL, "NPC_GoldenSkulltula2", npcGoldenSkulltula.changedCvar, 6, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(gSkulltulaTokenFlameDL, "NPC_GoldenSkulltula3", npcGoldenSkulltula.changedCvar, 32, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gSkulltulaTokenFlameDL, "NPC_GoldenSkulltula4", npcGoldenSkulltula.changedCvar, 33, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenDL, "NPC_GoldenSkulltula5", npcGoldenSkulltula.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenDL, "NPC_GoldenSkulltula6", npcGoldenSkulltula.changedCvar, 6, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenFlameDL, "NPC_GoldenSkulltula7", npcGoldenSkulltula.changedCvar, 32, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(gGiSkulltulaTokenFlameDL, "NPC_GoldenSkulltula8", npcGoldenSkulltula.changedCvar, 33, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255));
|
||||
PATCH_GFX(object_st_DL_003FB0, "NPC_GoldenSkulltula9", npcGoldenSkulltula.changedCvar, 118, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
|
||||
PATCH_GFX(object_st_DL_003FB0, "NPC_GoldenSkulltula10", npcGoldenSkulltula.changedCvar, 119, gsDPSetEnvColor(color.r / 4, color.g / 4, color.b / 4, 255));
|
||||
}
|
||||
|
||||
static CosmeticOption& npcGerudo = cosmeticOptions.at("NPC_Gerudo");
|
||||
@ -1142,6 +1185,43 @@ void DrawScaleSlider(const std::string CvarName,float DefaultValue){
|
||||
//Disabled for now. feature not done and several fixes needed to be merged.
|
||||
//UIWidgets::EnhancementSliderFloat("Scale : %dx", InvisibleLabel.c_str(), CvarLabel.c_str(), 0.1f, 3.0f,"",DefaultValue,true);
|
||||
}
|
||||
void Draw_Table_Dropdown(const char* Header_Title, const char* Table_ID, const char* Column_Title, const char* Slider_Title, const char* Slider_ID, int MinY, int MaxY, int MinX, int MaxX, float Default_Value) {
|
||||
if (ImGui::CollapsingHeader(Header_Title)) {
|
||||
if (ImGui::BeginTable(Table_ID, 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn(Column_Title, FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider(Slider_Title, Slider_ID);
|
||||
DrawPositionsRadioBoxes(Slider_ID);
|
||||
DrawPositionSlider(Slider_ID, MinY, MaxY, MinX, MaxX);
|
||||
DrawScaleSlider(Slider_ID, Default_Value);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
void C_Button_Dropdown(const char* Header_Title, const char* Table_ID, const char* Column_Title, const char* Slider_Title, const char* Slider_ID, const char* Int_Type, float Slider_Scale_Value) {
|
||||
if (ImGui::CollapsingHeader(Header_Title)) {
|
||||
if (ImGui::BeginTable(Table_ID, 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn(Column_Title, FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider(Slider_Title, Slider_ID);
|
||||
DrawPositionsRadioBoxes(Slider_ID);
|
||||
s16 Min_X_CU = 0;
|
||||
s16 Max_X_CU = ImGui::GetWindowViewport()->Size.x/2;
|
||||
if(CVarGetInteger(Int_Type,0) == 2){
|
||||
Max_X_CU = 294;
|
||||
} else if(CVarGetInteger(Int_Type,0) == 3){
|
||||
Max_X_CU = ImGui::GetWindowViewport()->Size.x/2;
|
||||
} else if(CVarGetInteger(Int_Type,0) == 4){
|
||||
Min_X_CU = (ImGui::GetWindowViewport()->Size.x/2)*-1;
|
||||
}
|
||||
DrawPositionSlider(Slider_ID, 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CU, Max_X_CU);
|
||||
DrawScaleSlider(Slider_ID, Slider_Scale_Value);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
void Draw_Placements(){
|
||||
if (ImGui::BeginTable("tableMargins", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("General margins settings", FlagsCell, TablesCellsWidth);
|
||||
@ -1208,126 +1288,13 @@ void Draw_Placements(){
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("B Button position")) {
|
||||
if (ImGui::BeginTable("tablebbtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("B Button settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("B Button", "gBBtn");
|
||||
DrawPositionsRadioBoxes("gBBtn");
|
||||
DrawPositionSlider("gBBtn", 0, ImGui::GetWindowViewport()->Size.y/4+50, -1, ImGui::GetWindowViewport()->Size.x-50);
|
||||
DrawScaleSlider("gBBtn",0.95f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("A Button position")) {
|
||||
if (ImGui::BeginTable("tableabtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("A Button settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("A Button", "gABtn");
|
||||
DrawPositionsRadioBoxes("gABtn");
|
||||
DrawPositionSlider("gABtn", -10, ImGui::GetWindowViewport()->Size.y/4+50, -20, ImGui::GetWindowViewport()->Size.x-50);
|
||||
DrawScaleSlider("gABtn",0.95f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Start Button position")) {
|
||||
if (ImGui::BeginTable("tablestartbtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Start Button settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Start Button", "gStartBtn");
|
||||
DrawPositionsRadioBoxes("gStartBtn");
|
||||
DrawPositionSlider("gStartBtn", 0, ImGui::GetWindowViewport()->Size.y/2, 0, ImGui::GetWindowViewport()->Size.x/2+70);
|
||||
DrawScaleSlider("gStartBtn",0.75f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("C Button Up position")) {
|
||||
if (ImGui::BeginTable("tablecubtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("C Button Up settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("C Button Up", "gCBtnU");
|
||||
DrawPositionsRadioBoxes("gCBtnU");
|
||||
s16 Min_X_CU = 0;
|
||||
s16 Max_X_CU = ImGui::GetWindowViewport()->Size.x/2;
|
||||
if(CVarGetInteger("gCBtnUPosType",0) == 2){
|
||||
Max_X_CU = 294;
|
||||
} else if(CVarGetInteger("gCBtnUPosType",0) == 3){
|
||||
Max_X_CU = ImGui::GetWindowViewport()->Size.x/2;
|
||||
} else if(CVarGetInteger("gCBtnUPosType",0) == 4){
|
||||
Min_X_CU = (ImGui::GetWindowViewport()->Size.x/2)*-1;
|
||||
}
|
||||
DrawPositionSlider("gCBtnU", 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CU, Max_X_CU);
|
||||
DrawScaleSlider("gCBtnU",0.5f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("C Button Down position")) {
|
||||
if (ImGui::BeginTable("tablecdbtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("C Button Down settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("C Button Down", "gCBtnD");
|
||||
DrawPositionsRadioBoxes("gCBtnD");
|
||||
s16 Min_X_CD = 0;
|
||||
s16 Max_X_CD = ImGui::GetWindowViewport()->Size.x/2;
|
||||
if(CVarGetInteger("gCBtnDPosType",0) == 2){
|
||||
Max_X_CD = 294;
|
||||
} else if(CVarGetInteger("gCBtnDPosType",0) == 3){
|
||||
Max_X_CD = ImGui::GetWindowViewport()->Size.x/2;
|
||||
} else if(CVarGetInteger("gCBtnDPosType",0) == 4){
|
||||
Min_X_CD = (ImGui::GetWindowViewport()->Size.x/2)*-1;
|
||||
}
|
||||
DrawPositionSlider("gCBtnD", 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CD, Max_X_CD);
|
||||
DrawScaleSlider("gCBtnD",0.87f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("C Button Left position")) {
|
||||
if (ImGui::BeginTable("tableclbtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("C Button Left settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("C Button Left", "gCBtnL");
|
||||
DrawPositionsRadioBoxes("gCBtnL");
|
||||
s16 Min_X_CL = 0;
|
||||
s16 Max_X_CL = ImGui::GetWindowViewport()->Size.x/2;
|
||||
if(CVarGetInteger("gCBtnLPosType",0) == 2){
|
||||
Max_X_CL = 294;
|
||||
} else if(CVarGetInteger("gCBtnLPosType",0) == 3){
|
||||
Max_X_CL = ImGui::GetWindowViewport()->Size.x/2;
|
||||
} else if(CVarGetInteger("gCBtnLPosType",0) == 4){
|
||||
Min_X_CL = (ImGui::GetWindowViewport()->Size.x/2)*-1;
|
||||
}
|
||||
DrawPositionSlider("gCBtnL", 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CL, Max_X_CL);
|
||||
DrawScaleSlider("gCBtnL",0.87f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("C Button Right position")) {
|
||||
if (ImGui::BeginTable("tablecrnbtn", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("C Button Right settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("C Button Right", "gCBtnR");
|
||||
DrawPositionsRadioBoxes("gCBtnR");
|
||||
s16 Min_X_CR = 0;
|
||||
s16 Max_X_CR = ImGui::GetWindowViewport()->Size.x/2;
|
||||
if(CVarGetInteger("gCBtnRPosType",0) == 2){
|
||||
Max_X_CR = 294;
|
||||
} else if(CVarGetInteger("gCBtnRPosType",0) == 3){
|
||||
Max_X_CR = ImGui::GetWindowViewport()->Size.x/2;
|
||||
} else if(CVarGetInteger("gCBtnRPosType",0) == 4){
|
||||
Min_X_CR = (ImGui::GetWindowViewport()->Size.x/2)*-1;
|
||||
}
|
||||
DrawPositionSlider("gCBtnR", 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CR, Max_X_CR);
|
||||
DrawScaleSlider("gCBtnR",0.87f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
Draw_Table_Dropdown("B Button position", "tablebbtn", "B Button settings", "B Button", "gBBtn", 0, ImGui::GetWindowViewport()->Size.y/4+50, -1, ImGui::GetWindowViewport()->Size.x-50, 0.95f);
|
||||
Draw_Table_Dropdown("A Button position", "tableabtn", "A Button settings", "A Button", "gABtn", -10, ImGui::GetWindowViewport()->Size.y/4+50, -20, ImGui::GetWindowViewport()->Size.x-50, 0.95f);
|
||||
Draw_Table_Dropdown("Start Button position", "tablestartbtn", "Start Button settings", "Start Button", "gStartBtn", 0, ImGui::GetWindowViewport()->Size.y/2, 0, ImGui::GetWindowViewport()->Size.x/2+70, 0.75f);
|
||||
C_Button_Dropdown("C Button Up position", "tablecubtn", "C Button Up settings", "C Button Up", "gCBtnU", "gCBtnUPosType", 0.5f);
|
||||
C_Button_Dropdown("C Button Down position", "tablecdbtn", "C Button Down settings", "C Button Down", "gCBtnD", "gCBtnDPosType", 0.87f);
|
||||
C_Button_Dropdown("C Button Left position", "tableclbtn", "C Button Left settings", "C Button Left", "gCBtnL", "gCBtnLPosType", 0.87f);
|
||||
C_Button_Dropdown("C Button Right position", "tablecrbtn", "C Button Right settings", "C Button Right", "gCBtnR", "gCBtnRPosType", 0.87f);
|
||||
if (CVarGetInteger("gDpadEquips",0) && ImGui::CollapsingHeader("DPad items position")) {
|
||||
if (ImGui::BeginTable("tabledpaditems", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("DPad items settings", FlagsCell, TablesCellsWidth);
|
||||
@ -1347,115 +1314,15 @@ void Draw_Placements(){
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Minimaps position")) {
|
||||
if (ImGui::BeginTable("tableminimapspos", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("minimaps settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Minimap", "gMinimap");
|
||||
DrawPositionsRadioBoxes("gMinimap", false);
|
||||
DrawPositionSlider("gMinimap", (ImGui::GetWindowViewport()->Size.y/3)*-1, ImGui::GetWindowViewport()->Size.y/3, ImGui::GetWindowViewport()->Size.x*-1, ImGui::GetWindowViewport()->Size.x/2);
|
||||
DrawScaleSlider("gMinimap",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Small Keys counter position")) {
|
||||
if (ImGui::BeginTable("tablesmolekeys", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Small Keys counter settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Small Keys counter", "gSKC");
|
||||
DrawPositionsRadioBoxes("gSKC");
|
||||
DrawPositionSlider("gSKC", 0, ImGui::GetWindowViewport()->Size.y/3, -1, ImGui::GetWindowViewport()->Size.x/2);
|
||||
DrawScaleSlider("gSKC",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Rupee counter position")) {
|
||||
if (ImGui::BeginTable("tablerupeecount", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Rupee counter settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Rupee counter", "gRC");
|
||||
DrawPositionsRadioBoxes("gRC");
|
||||
DrawPositionSlider("gRC", -2, ImGui::GetWindowViewport()->Size.y/3, -3, ImGui::GetWindowViewport()->Size.x/2);
|
||||
DrawScaleSlider("gRC",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Carrots position")) {
|
||||
if (ImGui::BeginTable("tableCarrots", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Carrots settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Carrots", "gCarrots");
|
||||
DrawPositionsRadioBoxes("gCarrots");
|
||||
DrawPositionSlider("gCarrots", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+25);
|
||||
DrawScaleSlider("gCarrots",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Timers position")) {
|
||||
if (ImGui::BeginTable("tabletimers", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Timers settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Timers", "gTimers");
|
||||
DrawPositionsRadioBoxes("gTimers");
|
||||
DrawPositionSlider("gTimers", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50);
|
||||
DrawScaleSlider("gTimers",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Archery Scores position")) {
|
||||
if (ImGui::BeginTable("tablearchery", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Archery Scores settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Archery scores", "gAS");
|
||||
DrawPositionsRadioBoxes("gAS", false);
|
||||
DrawPositionSlider("gAS", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50);
|
||||
DrawScaleSlider("gAS",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Title cards (Maps) position")) {
|
||||
if (ImGui::BeginTable("tabletcmaps", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Titlecard maps settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Title cards (overworld)", "gTCM");
|
||||
DrawPositionsRadioBoxes("gTCM");
|
||||
DrawPositionSlider("gTCM", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10);
|
||||
DrawScaleSlider("gTCM",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Title cards (Bosses) position")) {
|
||||
if (ImGui::BeginTable("tabletcbosses", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Title cards (Bosses) settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("Title cards (Bosses)", "gTCB");
|
||||
DrawPositionsRadioBoxes("gTCB");
|
||||
DrawPositionSlider("gTCB", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10);
|
||||
DrawScaleSlider("gTCB",1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("In-game Gameplay Timer position")) {
|
||||
if (ImGui::BeginTable("tablegameplaytimer", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("In-game Gameplay Timer settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("In-game Gameplay Timer", "gIGT");
|
||||
DrawPositionsRadioBoxes("gIGT");
|
||||
DrawPositionSlider("gIGT", 0, ImGui::GetWindowViewport()->Size.y / 2, -50,
|
||||
ImGui::GetWindowViewport()->Size.x / 2 + 10);
|
||||
DrawScaleSlider("gIGT", 1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
Draw_Table_Dropdown("Minimaps position", "tableminimapspos", "minimaps settings", "Minimap", "gMinimap", (ImGui::GetWindowViewport()->Size.y/3)*-1, ImGui::GetWindowViewport()->Size.y/3, ImGui::GetWindowViewport()->Size.x*-1, ImGui::GetWindowViewport()->Size.x/2, 1.0f);
|
||||
Draw_Table_Dropdown("Small Keys counter position", "tablesmolekeys", "Small Keys counter settings", "Small Keys counter", "gSKC", 0, ImGui::GetWindowViewport()->Size.y/3, -1, ImGui::GetWindowViewport()->Size.x/2, 1.0f);
|
||||
Draw_Table_Dropdown("Rupee counter position", "tablerupeecount", "Rupee counter settings", "Rupee counter", "gRC", -2, ImGui::GetWindowViewport()->Size.y/3, -3, ImGui::GetWindowViewport()->Size.x/2, 1.0f);
|
||||
Draw_Table_Dropdown("Carrots position", "tableCarrots", "Carrots settings", "Carrots", "gCarrots", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+25, 1.0f);
|
||||
Draw_Table_Dropdown("Timers position", "tabletimers", "Timers settings", "Timers", "gTimers", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50, 1.0f);
|
||||
Draw_Table_Dropdown("Archery Scores position", "tablearchery", "Archery Scores settings", "Archery scores", "gAS", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50, 1.0f);
|
||||
Draw_Table_Dropdown("Title cards (Maps) position", "tabletcmaps", "Titlecard maps settings", "Title cards (overworld)", "gTCM", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10, 1.0f);
|
||||
Draw_Table_Dropdown("Title cards (Bosses) position", "tabletcbosses", "Title cards (Bosses) settings", "Title cards (Bosses)", "gTCB", 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10, 1.0f);
|
||||
Draw_Table_Dropdown("In-game Gameplay Timer position", "tablegameplaytimer", "In-game Gameplay Timer settings", "In-game Gameplay Timer", "gIGT", 0, ImGui::GetWindowViewport()->Size.y / 2, -50, ImGui::GetWindowViewport()->Size.x / 2 + 10, 1.0f);
|
||||
if (ImGui::CollapsingHeader("Enemy Health Bar position")) {
|
||||
if (ImGui::BeginTable("enemyhealthbar", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("Enemy Health Bar settings", FlagsCell, TablesCellsWidth);
|
||||
@ -1483,7 +1350,21 @@ void Draw_Placements(){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Reset_Option_Single(const char* Button_Title, const char* name) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(Button_Title)) {
|
||||
CVarClear(name);
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
}
|
||||
void Reset_Option_Double(const char* Button_Title, const char* name) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(Button_Title)) {
|
||||
CVarClear((std::string(name) + ".Value").c_str());
|
||||
CVarClear((std::string(name) + ".Changed").c_str());
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
}
|
||||
void DrawSillyTab() {
|
||||
ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0));
|
||||
if (CVarGetInteger("gLetItSnow", 0)) {
|
||||
@ -1491,7 +1372,7 @@ void DrawSillyTab() {
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Body Scale: %f", "##Link_BodyScale", "gCosmetics.Link_BodyScale.Value", 0.001f, 0.025f, "", 0.01f, true)) {
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Body Scale: %.3fx", "##Link_BodyScale", "gCosmetics.Link_BodyScale.Value", 0.001f, 0.025f, "", 0.01f, true)) {
|
||||
CVarSetInteger("gCosmetics.Link_BodyScale.Changed", 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -1506,70 +1387,31 @@ void DrawSillyTab() {
|
||||
player->actor.scale.z = 0.01f;
|
||||
}
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Head Scale: %f", "##Link_HeadScale", "gCosmetics.Link_HeadScale.Value", 0.4f, 4.0f, "", 1.0f, false)) {
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Head Scale: %.2fx", "##Link_HeadScale", "gCosmetics.Link_HeadScale.Value", 0.4f, 4.0f, "", 1.0f, false)) {
|
||||
CVarSetInteger("gCosmetics.Link_HeadScale.Changed", 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Link_HeadScale")) {
|
||||
CVarClear("gCosmetics.Link_HeadScale.Value");
|
||||
CVarClear("gCosmetics.Link_HeadScale.Changed");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Double("Reset##Link_HeadScale", "gCosmetics.Link_HeadScale");
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Sword Scale: %f", "##Link_SwordScale", "gCosmetics.Link_SwordScale.Value", 1.0f, 2.5f, "", 1.0f, false)) {
|
||||
CVarSetInteger("gCosmetics.Link_SwordScale.Changed", 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Link_SwordScale")) {
|
||||
CVarClear("gCosmetics.Link_SwordScale.Value");
|
||||
CVarClear("gCosmetics.Link_SwordScale.Changed");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Double("Reset##Link_SwordScale", "gCosmetics.Link_SwordScale");
|
||||
UIWidgets::EnhancementSliderFloat("Bunny Hood Length: %f", "##BunnyHood_EarLength", "gCosmetics.BunnyHood_EarLength", -300.0f, 1000.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##BunnyHood_EarLength")) {
|
||||
CVarClear("gCosmetics.BunnyHood_EarLength");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Single("Reset##BunnyHood_EarLength", "gCosmetics.BunnyHood_EarLength");
|
||||
UIWidgets::EnhancementSliderFloat("Bunny Hood Spread: %f", "##BunnyHood_EarSpread", "gCosmetics.BunnyHood_EarSpread", -300.0f, 500.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##BunnyHood_EarSpread")) {
|
||||
CVarClear("gCosmetics.BunnyHood_EarSpread");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("Goron Neck Length: %f", "##Goron_NeckLength", "gCosmetics.Goron_NeckLength", 0.0f, 5000.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Goron_NeckLength")) {
|
||||
CVarClear("gCosmetics.Goron_NeckLength");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Single("Reset##BunnyHood_EarSpread", "gCosmetics.BunnyHood_EarSpread");
|
||||
UIWidgets::EnhancementSliderFloat("Goron Neck Length: %f", "##Goron_NeckLength", "gCosmetics.Goron_NeckLength", 0.0f, 1000.0f, "", 0.0f, false);
|
||||
Reset_Option_Single("Reset##Goron_NeckLength", "gCosmetics.Goron_NeckLength");
|
||||
UIWidgets::EnhancementCheckbox("Unfix Goron Spin", "gUnfixGoronSpin");
|
||||
UIWidgets::EnhancementSliderFloat("Fairies Size: %f", "##Fairies_Size", "gCosmetics.Fairies_Size", 0.25f, 5.0f, "", 1.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Fairies_Size")) {
|
||||
CVarClear("gCosmetics.Fairies_Size");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Single("Reset##Fairies_Size", "gCosmetics.Fairies_Size");
|
||||
UIWidgets::EnhancementSliderFloat("N64 Logo Spin Speed: %f", "##N64Logo_SpinSpeed", "gCosmetics.N64Logo_SpinSpeed", 0.25f, 5.0f, "", 1.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##N64Logo_SpinSpeed")) {
|
||||
CVarClear("gCosmetics.N64Logo_SpinSpeed");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Single("Reset##N64Logo_SpinSpeed", "gCosmetics.N64Logo_SpinSpeed");
|
||||
UIWidgets::EnhancementSliderFloat("Moon Size: %f", "##Moon_Size", "gCosmetics.Moon_Size", 0.5f, 2.0f, "", 1.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Moon_Size")) {
|
||||
CVarClear("gCosmetics.Moon_Size");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Single("Reset##Moon_Size", "gCosmetics.Moon_Size");
|
||||
if (UIWidgets::EnhancementSliderFloat("Kak Windmill Speed: %f", "##Kak_Windmill_Speed", "gCosmetics.Kak_Windmill_Speed.Value", 100.0f, 6000.0f, "", 100.0f, false)) {
|
||||
CVarSetInteger("gCosmetics.Kak_Windmill_Speed.Changed", 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Kak_Windmill_Speed")) {
|
||||
CVarClear("gCosmetics.Kak_Windmill_Speed.Value");
|
||||
CVarClear("gCosmetics.Kak_Windmill_Speed.Changed");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
Reset_Option_Double("Reset##Kak_Windmill_Speed", "gCosmetics.Kak_Windmill_Speed");
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
@ -1592,6 +1434,104 @@ void CopyMultipliedColor(CosmeticOption& cosmeticOptionSrc, CosmeticOption& cosm
|
||||
CVarSetInteger((cosmeticOptionTarget.changedCvar), 1);
|
||||
}
|
||||
|
||||
void ToggleRainbow(CosmeticOption& cosmeticOption, bool state) {
|
||||
if (state) {
|
||||
CVarSetInteger(cosmeticOption.rainbowCvar, 1);
|
||||
CVarSetInteger(cosmeticOption.changedCvar, 1);
|
||||
} else {
|
||||
CVarClear(cosmeticOption.rainbowCvar);
|
||||
CVarClear(cosmeticOption.changedCvar);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplySideEffects(CosmeticOption& cosmeticOption) {
|
||||
if (CVarGetInteger("gCosmetics.AdvancedMode", 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This bit is kind of experimental, not sure how I feel about it yet, but it allows for
|
||||
// advanced cosmetic options to be changed based on a non-advanced option.
|
||||
if (cosmeticOption.label == "Bow Body") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Equipment_BowTips"), 0.5f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Equipment_BowHandle"), 1.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOption, 4.0f);
|
||||
} else if (cosmeticOption.label == "Idle Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_IdleSecondary"), 0.5f);
|
||||
} else if (cosmeticOption.label == "Enemy Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_EnemySecondary"), 0.5f);
|
||||
} else if (cosmeticOption.label == "NPC Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_NPCSecondary"), 1.0f);
|
||||
} else if (cosmeticOption.label == "Props Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_PropsSecondary"), 1.0f);
|
||||
} else if (cosmeticOption.label == "Ivan Idle Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Ivan_IdleSecondary"), 0.5f);
|
||||
} else if (cosmeticOption.label == "Level 1 Secondary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("SpinAttack_Level1Primary"), 2.0f);
|
||||
} else if (cosmeticOption.label == "Level 2 Secondary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("SpinAttack_Level2Primary"), 2.0f);
|
||||
} else if (cosmeticOption.label == "Item Select Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_ItemSelB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_ItemSelC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_ItemSelD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_ItemSelB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_ItemSelC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_ItemSelD"), 1.0f);
|
||||
}
|
||||
} else if (cosmeticOption.label == "Equip Select Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_EquipSelB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_EquipSelC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_EquipSelD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_EquipSelB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_EquipSelC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_EquipSelD"), 1.0f);
|
||||
}
|
||||
} else if (cosmeticOption.label == "Map Dungeon Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelDunB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelDunC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelDunD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelDunB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelDunC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelDunD"), 1.0f);
|
||||
}
|
||||
} else if (cosmeticOption.label == "Quest Status Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_QuestStatusB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_QuestStatusC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_QuestStatusD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_QuestStatusB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_QuestStatusC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_QuestStatusD"), 1.0f);
|
||||
}
|
||||
} else if (cosmeticOption.label == "Map Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelectB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelectC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_MapSelectD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelectB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelectC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_MapSelectD"), 1.0f);
|
||||
}
|
||||
} else if (cosmeticOption.label == "Save Color") {
|
||||
if (CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_SaveB"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_SaveC"), true);
|
||||
ToggleRainbow(cosmeticOptions.at("Kal_SaveD"), true);
|
||||
} else {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_SaveB"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_SaveC"), 2.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Kal_SaveD"), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RandomizeColor(CosmeticOption& cosmeticOption) {
|
||||
Color_RGBA8 newColor;
|
||||
newColor.r = Random(0, 255);
|
||||
@ -1611,26 +1551,7 @@ void RandomizeColor(CosmeticOption& cosmeticOption) {
|
||||
CVarSetColor(cosmeticOption.cvar, newColor);
|
||||
CVarSetInteger((cosmeticOption.rainbowCvar), 0);
|
||||
CVarSetInteger((cosmeticOption.changedCvar), 1);
|
||||
|
||||
// This bit is kind of experimental, not sure how I feel about it yet, but it allows for
|
||||
// advanced cosmetic options to be changed based on a non-advanced option.
|
||||
if (cosmeticOption.label == "Bow Body") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Equipment_BowTips"), 0.5f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Equipment_BowHandle"), 1.0f);
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOption, 4.0f);
|
||||
} else if (cosmeticOption.label == "Idle Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_IdleSecondary"), 0.5f);
|
||||
} else if (cosmeticOption.label == "Enemy Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_EnemySecondary"), 0.5f);
|
||||
} else if (cosmeticOption.label == "NPC Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_NPCSecondary"), 1.0f);
|
||||
} else if (cosmeticOption.label == "Props Primary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("Navi_PropsSecondary"), 1.0f);
|
||||
} else if (cosmeticOption.label == "Level 1 Secondary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("SpinAttack_Level1Primary"), 2.0f);
|
||||
} else if (cosmeticOption.label == "Level 2 Secondary") {
|
||||
CopyMultipliedColor(cosmeticOption, cosmeticOptions.at("SpinAttack_Level2Primary"), 2.0f);
|
||||
}
|
||||
ApplySideEffects(cosmeticOption);
|
||||
}
|
||||
|
||||
void ResetColor(CosmeticOption& cosmeticOption) {
|
||||
@ -1650,7 +1571,7 @@ void ResetColor(CosmeticOption& cosmeticOption) {
|
||||
CVarClear((std::string(cosmeticOption.cvar) + ".A").c_str());
|
||||
CVarClear((std::string(cosmeticOption.cvar) + ".Type").c_str());
|
||||
|
||||
// This portion should match 1:1 the multiplied colors in `RandomizeColor()`
|
||||
// This portion should match 1:1 the multiplied colors in `ApplySideEffect()`
|
||||
if (cosmeticOption.label == "Bow Body") {
|
||||
ResetColor(cosmeticOptions.at("Equipment_BowTips"));
|
||||
ResetColor(cosmeticOptions.at("Equipment_BowHandle"));
|
||||
@ -1666,6 +1587,30 @@ void ResetColor(CosmeticOption& cosmeticOption) {
|
||||
ResetColor(cosmeticOptions.at("SpinAttack_Level1Primary"));
|
||||
} else if (cosmeticOption.label == "Level 2 Secondary") {
|
||||
ResetColor(cosmeticOptions.at("SpinAttack_Level2Primary"));
|
||||
} else if (cosmeticOption.label == "Item Select Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_ItemSelB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_ItemSelC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_ItemSelD"));
|
||||
} else if (cosmeticOption.label == "Equip Select Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_EquipSelB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_EquipSelC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_EquipSelD"));
|
||||
} else if (cosmeticOption.label == "Map Dungeon Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelDunB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelDunC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelDunD"));
|
||||
} else if (cosmeticOption.label == "Quest Status Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_QuestStatusB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_QuestStatusC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_QuestStatusD"));
|
||||
} else if (cosmeticOption.label == "Map Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelectB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelectC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_MapSelectD"));
|
||||
} else if (cosmeticOption.label == "Save Color") {
|
||||
ResetColor(cosmeticOptions.at("Kal_SaveB"));
|
||||
ResetColor(cosmeticOptions.at("Kal_SaveC"));
|
||||
ResetColor(cosmeticOptions.at("Kal_SaveD"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1686,6 +1631,7 @@ void DrawCosmeticRow(CosmeticOption& cosmeticOption) {
|
||||
CVarSetColor(cosmeticOption.cvar, color);
|
||||
CVarSetInteger((cosmeticOption.rainbowCvar), 0);
|
||||
CVarSetInteger((cosmeticOption.changedCvar), 1);
|
||||
ApplySideEffects(cosmeticOption);
|
||||
ApplyOrResetCustomGfxPatches();
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
@ -1703,6 +1649,7 @@ void DrawCosmeticRow(CosmeticOption& cosmeticOption) {
|
||||
if (ImGui::Checkbox(("Rainbow##" + cosmeticOption.label).c_str(), &isRainbow)) {
|
||||
CVarSetInteger((cosmeticOption.rainbowCvar), isRainbow);
|
||||
CVarSetInteger((cosmeticOption.changedCvar), 1);
|
||||
ApplySideEffects(cosmeticOption);
|
||||
ApplyOrResetCustomGfxPatches();
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
@ -1759,7 +1706,7 @@ static const char* colorSchemes[2] = {
|
||||
};
|
||||
|
||||
void CosmeticsEditorWindow::DrawElement() {
|
||||
ImGui::SetNextWindowSize(ImVec2(480, 520), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 520), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Cosmetics Editor", &mIsVisible)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
@ -1793,15 +1740,12 @@ void CosmeticsEditorWindow::DrawElement() {
|
||||
}
|
||||
}
|
||||
UIWidgets::EnhancementCheckbox("Sync Rainbow colors", "gCosmetics.RainbowSync");
|
||||
UIWidgets::EnhancementSliderFloat("Rainbow Speed: %f", "##rainbowSpeed", "gCosmetics.RainbowSpeed", 0.03f, 1.0f, "", 0.6f, false);
|
||||
UIWidgets::EnhancementSliderFloat("Rainbow Speed: %.3f", "##rainbowSpeed", "gCosmetics.RainbowSpeed", 0.03f, 1.0f, "", 0.6f, false, true);
|
||||
UIWidgets::EnhancementCheckbox("Randomize All on New Scene", "gCosmetics.RandomizeAllOnNewScene");
|
||||
UIWidgets::Tooltip("Enables randomizing all unlocked cosmetics when you enter a new scene.");
|
||||
|
||||
if (ImGui::Button("Randomize All", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) {
|
||||
for (auto& [id, cosmeticOption] : cosmeticOptions) {
|
||||
if (!CVarGetInteger(cosmeticOption.lockedCvar, 0) && (!cosmeticOption.advancedOption || CVarGetInteger("gCosmetics.AdvancedMode", 0))) {
|
||||
RandomizeColor(cosmeticOption);
|
||||
}
|
||||
}
|
||||
ApplyOrResetCustomGfxPatches();
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
CosmeticsEditor_RandomizeAll();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset All", ImVec2(ImGui::GetContentRegionAvail().x, 30.0f))) {
|
||||
@ -1861,6 +1805,7 @@ void CosmeticsEditorWindow::DrawElement() {
|
||||
if (ImGui::BeginTabItem("World & NPCs")) {
|
||||
DrawCosmeticGroup(GROUP_WORLD);
|
||||
DrawCosmeticGroup(GROUP_NAVI);
|
||||
DrawCosmeticGroup(GROUP_IVAN);
|
||||
DrawCosmeticGroup(GROUP_NPC);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
@ -1873,10 +1818,16 @@ void CosmeticsEditorWindow::DrawElement() {
|
||||
DrawCosmeticGroup(GROUP_TITLE);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("HUD Placement")) {
|
||||
Draw_Placements();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Pause Menu")) {
|
||||
DrawCosmeticGroup(GROUP_KALEIDO);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::End();
|
||||
@ -1894,6 +1845,14 @@ void RegisterOnGameFrameUpdateHook() {
|
||||
});
|
||||
}
|
||||
|
||||
void Cosmetics_RegisterOnSceneInitHook() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
|
||||
if (CVarGetInteger("gCosmetics.RandomizeAllOnNewScene", 0)) {
|
||||
CosmeticsEditor_RandomizeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CosmeticsEditorWindow::InitElement() {
|
||||
// Convert the `current color` into the format that the ImGui color picker expects
|
||||
for (auto& [id, cosmeticOption] : cosmeticOptions) {
|
||||
@ -1911,6 +1870,7 @@ void CosmeticsEditorWindow::InitElement() {
|
||||
|
||||
RegisterOnLoadGameHook();
|
||||
RegisterOnGameFrameUpdateHook();
|
||||
Cosmetics_RegisterOnSceneInitHook();
|
||||
}
|
||||
|
||||
void CosmeticsEditor_RandomizeAll() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifdef ENABLE_CROWD_CONTROL
|
||||
#ifdef ENABLE_REMOTE_CONTROL
|
||||
|
||||
#include "CrowdControl.h"
|
||||
#include "CrowdControlTypes.h"
|
||||
@ -17,25 +17,17 @@ extern "C" {
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
void CrowdControl::Init() {
|
||||
SDLNet_Init();
|
||||
}
|
||||
|
||||
void CrowdControl::Shutdown() {
|
||||
SDLNet_Quit();
|
||||
}
|
||||
|
||||
void CrowdControl::Enable() {
|
||||
if (isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDLNet_ResolveHost(&ip, "127.0.0.1", 43384) == -1) {
|
||||
SPDLOG_ERROR("[CrowdControl] SDLNet_ResolveHost: {}", SDLNet_GetError());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -45,87 +37,42 @@ void CrowdControl::Disable() {
|
||||
}
|
||||
|
||||
isEnabled = false;
|
||||
ccThreadReceive.join();
|
||||
ccThreadProcess.join();
|
||||
GameInteractor::Instance->DisableRemoteInteractor();
|
||||
}
|
||||
|
||||
void CrowdControl::ListenToServer() {
|
||||
while (isEnabled) {
|
||||
while (!connected && isEnabled) {
|
||||
SPDLOG_TRACE("[CrowdControl] Attempting to make connection to server...");
|
||||
tcpsock = SDLNet_TCP_Open(&ip);
|
||||
void CrowdControl::HandleRemoteData(nlohmann::json payload) {
|
||||
Effect* incomingEffect = ParseMessage(payload);
|
||||
if (!incomingEffect) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcpsock) {
|
||||
connected = true;
|
||||
SPDLOG_TRACE("[CrowdControl] Connection to server established!");
|
||||
// If effect is not a timed effect, execute and return result.
|
||||
if (!incomingEffect->timeRemaining) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
|
||||
if (tcpsock) {
|
||||
SDLNet_TCP_AddSocket(socketSet, tcpsock);
|
||||
}
|
||||
|
||||
// Listen to socket messages
|
||||
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 (!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(incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (socketsReady == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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...");
|
||||
activeEffectsMutex.lock();
|
||||
activeEffects.push_back(incomingEffect);
|
||||
activeEffectsMutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,13 +94,13 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
if (effect->timeRemaining <= 0) {
|
||||
it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect),
|
||||
activeEffects.end());
|
||||
GameInteractor::RemoveEffect(effect->giEffect);
|
||||
GameInteractor::RemoveEffect(dynamic_cast<RemovableGameInteractionEffect*>(effect->giEffect));
|
||||
delete effect;
|
||||
} else {
|
||||
// If we have a success after previously being paused, tell CC to resume timer.
|
||||
if (effect->isPaused) {
|
||||
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
|
||||
// the result is different from the last time this was ran.
|
||||
// Timed events are put on a thread that runs once per second.
|
||||
@ -161,7 +108,7 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
effect->timeRemaining -= 1000;
|
||||
if (result != effect->lastExecutionResult) {
|
||||
effect->lastExecutionResult = result;
|
||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Success);
|
||||
EmitMessage(effect->id, effect->timeRemaining, EffectResult::Success);
|
||||
}
|
||||
}
|
||||
it++;
|
||||
@ -169,7 +116,7 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
} else { // Timed effects only do Success or Retry
|
||||
if (!effect->isPaused && effect->timeRemaining > 0) {
|
||||
effect->isPaused = true;
|
||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Paused);
|
||||
EmitMessage(effect->id, effect->timeRemaining, EffectResult::Paused);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
@ -182,7 +129,7 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
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;
|
||||
|
||||
payload["id"] = eventId;
|
||||
@ -190,8 +137,9 @@ void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRema
|
||||
payload["timeRemaining"] = timeRemaining;
|
||||
payload["status"] = status;
|
||||
|
||||
std::string jsonPayload = payload.dump();
|
||||
SDLNet_TCP_Send(socket, jsonPayload.c_str(), jsonPayload.size() + 1);
|
||||
SPDLOG_INFO("[CrowdControl] Sending payload:\n{}", payload.dump());
|
||||
|
||||
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||
}
|
||||
|
||||
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
|
||||
@ -229,13 +177,14 @@ CrowdControl::EffectResult CrowdControl::TranslateGiEnum(GameInteractionEffectQu
|
||||
return result;
|
||||
}
|
||||
|
||||
CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
nlohmann::json dataReceived = nlohmann::json::parse(payload, nullptr, false);
|
||||
if (dataReceived.is_discarded()) {
|
||||
SPDLOG_ERROR("Error parsing JSON");
|
||||
CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
|
||||
if (!dataReceived.contains("id") || !dataReceived.contains("type")) {
|
||||
SPDLOG_ERROR("[CrowdControl] Invalid payload received:\n{}", dataReceived);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SPDLOG_INFO("[CrowdControl] Received payload:\n{}", dataReceived.dump());
|
||||
|
||||
Effect* effect = new Effect();
|
||||
effect->lastExecutionResult = EffectResult::Initiate;
|
||||
effect->id = dataReceived["id"];
|
||||
@ -333,13 +282,13 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
effect->category = kEffectCatDamageTaken;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||
effect->giEffect->parameters[0] = 2;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
|
||||
break;
|
||||
case kEffectTakeDoubleDamage:
|
||||
effect->category = kEffectCatDamageTaken;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||
effect->giEffect->parameters[0] = -2;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
|
||||
break;
|
||||
case kEffectOneHitKo:
|
||||
effect->category = kEffectCatDamageTaken;
|
||||
@ -356,37 +305,37 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
effect->category = kEffectCatSpeed;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||
effect->giEffect->parameters[0] = 2;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
|
||||
break;
|
||||
case kEffectDecreaseSpeed:
|
||||
effect->category = kEffectCatSpeed;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||
effect->giEffect->parameters[0] = -2;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
|
||||
break;
|
||||
case kEffectLowGravity:
|
||||
effect->category = kEffectCatGravity;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectHighGravity:
|
||||
effect->category = kEffectCatGravity;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectForceIronBoots:
|
||||
effect->category = kEffectCatBoots;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectForceHoverBoots:
|
||||
effect->category = kEffectCatBoots;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectSlipperyFloor:
|
||||
effect->category = kEffectCatSlipperyFloor;
|
||||
@ -412,23 +361,23 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
// Hurt or Heal Link
|
||||
case kEffectEmptyHeart:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
break;
|
||||
case kEffectFillHeart:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
break;
|
||||
case kEffectKnockbackLinkWeak:
|
||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||
effect->giEffect->parameters[0] = 1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
|
||||
break;
|
||||
case kEffectKnockbackLinkStrong:
|
||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||
effect->giEffect->parameters[0] = 3;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 3;
|
||||
break;
|
||||
case kEffectKnockbackLinkMega:
|
||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||
effect->giEffect->parameters[0] = 6;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 6;
|
||||
break;
|
||||
case kEffectBurnLink:
|
||||
effect->giEffect = new GameInteractionEffect::BurnPlayer();
|
||||
@ -441,109 +390,109 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
break;
|
||||
case kEffectKillLink:
|
||||
effect->giEffect = new GameInteractionEffect::SetPlayerHealth();
|
||||
effect->giEffect->parameters[0] = 0;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 0;
|
||||
break;
|
||||
|
||||
// Give Items and Consumables
|
||||
case kEffectAddHeartContainer:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->giEffect->parameters[0] = 1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
|
||||
break;
|
||||
case kEffectFillMagic:
|
||||
effect->giEffect = new GameInteractionEffect::FillMagic();
|
||||
break;
|
||||
case kEffectAddRupees:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
break;
|
||||
case kEffectGiveDekuShield:
|
||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->giEffect->parameters[0] = ITEM_SHIELD_DEKU;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_DEKU;
|
||||
break;
|
||||
case kEffectGiveHylianShield:
|
||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->giEffect->parameters[0] = ITEM_SHIELD_HYLIAN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_HYLIAN;
|
||||
break;
|
||||
case kEffectRefillSticks:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_STICK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
|
||||
break;
|
||||
case kEffectRefillNuts:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_NUT;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
|
||||
break;
|
||||
case kEffectRefillBombs:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_BOMB;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
|
||||
break;
|
||||
case kEffectRefillSeeds:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_SLINGSHOT;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
|
||||
break;
|
||||
case kEffectRefillArrows:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_BOW;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
|
||||
break;
|
||||
case kEffectRefillBombchus:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter;
|
||||
effect->giEffect->parameters[1] = ITEM_BOMBCHU;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
|
||||
break;
|
||||
|
||||
// Take Items and Consumables
|
||||
case kEffectRemoveHeartContainer:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->giEffect->parameters[0] = -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -1;
|
||||
break;
|
||||
case kEffectEmptyMagic:
|
||||
effect->giEffect = new GameInteractionEffect::EmptyMagic();
|
||||
break;
|
||||
case kEffectRemoveRupees:
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
break;
|
||||
case kEffectTakeDekuShield:
|
||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->giEffect->parameters[0] = -ITEM_SHIELD_DEKU;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_DEKU;
|
||||
break;
|
||||
case kEffectTakeHylianShield:
|
||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->giEffect->parameters[0] = -ITEM_SHIELD_HYLIAN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_HYLIAN;
|
||||
break;
|
||||
case kEffectTakeSticks:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_STICK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
|
||||
break;
|
||||
case kEffectTakeNuts:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_NUT;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
|
||||
break;
|
||||
case kEffectTakeBombs:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_BOMB;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
|
||||
break;
|
||||
case kEffectTakeSeeds:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_SLINGSHOT;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
|
||||
break;
|
||||
case kEffectTakeArrows:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_BOW;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
|
||||
break;
|
||||
case kEffectTakeBombchus:
|
||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
||||
effect->giEffect->parameters[1] = ITEM_BOMBCHU;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
|
||||
break;
|
||||
|
||||
// Link Size Modifiers
|
||||
@ -551,25 +500,25 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
effect->category = kEffectCatLinkSize;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectMinishLink:
|
||||
effect->category = kEffectCatLinkSize;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectPaperLink:
|
||||
effect->category = kEffectCatLinkSize;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectSquishedLink:
|
||||
effect->category = kEffectCatLinkSize;
|
||||
effect->timeRemaining = 30000;
|
||||
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;
|
||||
case kEffectInvisibleLink:
|
||||
effect->category = kEffectCatLinkSize;
|
||||
@ -585,11 +534,11 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
break;
|
||||
case kEffectSetTimeToDawn:
|
||||
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
||||
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DAWN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DAWN;
|
||||
break;
|
||||
case kEffectSetTimeToDusk:
|
||||
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
||||
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DUSK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DUSK;
|
||||
break;
|
||||
|
||||
// Visual Effects
|
||||
@ -632,186 +581,186 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
effect->category = kEffectCatRandomButtons;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::PressRandomButton();
|
||||
effect->giEffect->parameters[0] = 30;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 30;
|
||||
break;
|
||||
case kEffectClearCbuttons:
|
||||
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
||||
effect->giEffect->parameters[0] = GI_BUTTONS_CBUTTONS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_CBUTTONS;
|
||||
break;
|
||||
case kEffectClearDpad:
|
||||
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
||||
effect->giEffect->parameters[0] = GI_BUTTONS_DPAD;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_DPAD;
|
||||
break;
|
||||
|
||||
// Teleport Player
|
||||
case kEffectTpLinksHouse:
|
||||
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;
|
||||
case kEffectTpMinuet:
|
||||
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;
|
||||
case kEffectTpBolero:
|
||||
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;
|
||||
case kEffectTpSerenade:
|
||||
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;
|
||||
case kEffectTpRequiem:
|
||||
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;
|
||||
case kEffectTpNocturne:
|
||||
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;
|
||||
case kEffectTpPrelude:
|
||||
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;
|
||||
|
||||
// Tunic Color (Bidding War)
|
||||
case kEffectTunicRed:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||
break;
|
||||
case kEffectTunicGreen:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||
break;
|
||||
case kEffectTunicBlue:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||
break;
|
||||
case kEffectTunicOrange:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||
break;
|
||||
case kEffectTunicYellow:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||
break;
|
||||
case kEffectTunicPurple:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||
break;
|
||||
case kEffectTunicPink:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||
break;
|
||||
case kEffectTunicBrown:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||
break;
|
||||
case kEffectTunicBlack:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||
break;
|
||||
|
||||
// Navi Color (Bidding War)
|
||||
case kEffectNaviRed:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||
break;
|
||||
case kEffectNaviGreen:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||
break;
|
||||
case kEffectNaviBlue:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||
break;
|
||||
case kEffectNaviOrange:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||
break;
|
||||
case kEffectNaviYellow:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||
break;
|
||||
case kEffectNaviPurple:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||
break;
|
||||
case kEffectNaviPink:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||
break;
|
||||
case kEffectNaviBrown:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||
break;
|
||||
case kEffectNaviBlack:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||
break;
|
||||
|
||||
// Link's Hair Color (Bidding War)
|
||||
case kEffectHairRed:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||
break;
|
||||
case kEffectHairGreen:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||
break;
|
||||
case kEffectHairBlue:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||
break;
|
||||
case kEffectHairOrange:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||
break;
|
||||
case kEffectHairYellow:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||
break;
|
||||
case kEffectHairPurple:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||
break;
|
||||
case kEffectHairPink:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||
break;
|
||||
case kEffectHairBrown:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||
break;
|
||||
case kEffectHairBlack:
|
||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifdef ENABLE_CROWD_CONTROL
|
||||
#ifdef ENABLE_REMOTE_CONTROL
|
||||
|
||||
#ifndef _CROWDCONTROL_C
|
||||
#define _CROWDCONTROL_C
|
||||
@ -73,33 +73,24 @@ class CrowdControl {
|
||||
EffectResult lastExecutionResult;
|
||||
} Effect;
|
||||
|
||||
std::thread ccThreadReceive;
|
||||
std::thread ccThreadProcess;
|
||||
|
||||
TCPsocket tcpsock;
|
||||
IPaddress ip;
|
||||
|
||||
bool isEnabled;
|
||||
bool connected;
|
||||
|
||||
char received[512];
|
||||
|
||||
std::vector<Effect*> activeEffects;
|
||||
std::mutex activeEffectsMutex;
|
||||
|
||||
void ListenToServer();
|
||||
void HandleRemoteData(nlohmann::json payload);
|
||||
void ProcessActiveEffects();
|
||||
|
||||
void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status);
|
||||
Effect* ParseMessage(char payload[512]);
|
||||
void EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status);
|
||||
Effect* ParseMessage(nlohmann::json payload);
|
||||
EffectResult ExecuteEffect(Effect* effect);
|
||||
EffectResult CanApplyEffect(Effect *effect);
|
||||
EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult);
|
||||
|
||||
public:
|
||||
static CrowdControl* Instance;
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Enable();
|
||||
void Disable();
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ typedef enum {
|
||||
TEXT_CARPET_SALESMAN_1 = 0x6077,
|
||||
TEXT_CARPET_SALESMAN_2 = 0x6078,
|
||||
TEXT_MARKET_GUARD_NIGHT = 0x7003,
|
||||
TEXT_FISHERMAN_LEAVE = 0x409E,
|
||||
TEXT_SHEIK_NEED_HOOK = 0x700F,
|
||||
TEXT_SHEIK_HAVE_HOOK = 0x7010,
|
||||
TEXT_SCRUB_RANDOM = 0x9000,
|
||||
@ -54,6 +55,22 @@ typedef enum {
|
||||
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_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;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
#include <Window.h>
|
||||
#include <Context.h>
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include <ImGui/imgui.h>
|
||||
#include <ImGui/imgui_internal.h>
|
||||
#undef PATH_HACK
|
||||
#undef Path
|
||||
@ -99,7 +103,7 @@ static bool ActorSpawnHandler(std::shared_ptr<LUS::Console> Console, const std::
|
||||
|
||||
static bool KillPlayerHandler(std::shared_ptr<LUS::Console> Console, const std::vector<std::string>&, std::string* output) {
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
||||
effect->parameters[0] = 0;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = 0;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
INFO_MESSAGE("[SOH] You've met with a terrible fate, haven't you?");
|
||||
@ -130,7 +134,7 @@ static bool SetPlayerHealthHandler(std::shared_ptr<LUS::Console> Console, const
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
||||
effect->parameters[0] = health;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = health;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
INFO_MESSAGE("[SOH] Player health updated to %d", health);
|
||||
@ -247,8 +251,8 @@ static bool AddAmmoHandler(std::shared_ptr<LUS::Console> Console, const std::vec
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->parameters[0] = amount;
|
||||
effect->parameters[1] = it->second;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = amount;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[1] = it->second;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -287,8 +291,8 @@ static bool TakeAmmoHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||
effect->parameters[0] = -amount;
|
||||
effect->parameters[1] = it->second;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -amount;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[1] = it->second;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -397,9 +401,9 @@ static bool EntranceHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
||||
}
|
||||
|
||||
gPlayState->nextEntranceIndex = entrance;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->fadeTransition = 11;
|
||||
gSaveContext.nextTransitionType = 11;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_INSTANT;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_INSTANT;
|
||||
}
|
||||
|
||||
static bool VoidHandler(std::shared_ptr<LUS::Console> Console, const std::vector<std::string>& args, std::string* output) {
|
||||
@ -407,10 +411,10 @@ static bool VoidHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].tempSwchFlags = gPlayState->actorCtx.flags.tempSwch;
|
||||
gSaveContext.respawn[RESPAWN_MODE_DOWN].tempCollectFlags = gPlayState->actorCtx.flags.tempCollect;
|
||||
gSaveContext.respawnFlag = 1;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex;
|
||||
gPlayState->fadeTransition = 2;
|
||||
gSaveContext.nextTransitionType = 2;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_BLACK;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK;
|
||||
} else {
|
||||
ERROR_MESSAGE("gPlayState == nullptr");
|
||||
return 1;
|
||||
@ -421,9 +425,9 @@ static bool VoidHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
||||
static bool ReloadHandler(std::shared_ptr<LUS::Console> Console, const std::vector<std::string>& args, std::string* output) {
|
||||
if (gPlayState != nullptr) {
|
||||
gPlayState->nextEntranceIndex = gSaveContext.entranceIndex;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->fadeTransition = 11;
|
||||
gSaveContext.nextTransitionType = 11;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_INSTANT;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_INSTANT;
|
||||
} else {
|
||||
ERROR_MESSAGE("gPlayState == nullptr");
|
||||
return 1;
|
||||
@ -457,9 +461,9 @@ static bool FWHandler(std::shared_ptr<LUS::Console> Console, const std::vector<s
|
||||
break;
|
||||
case 1: //warp
|
||||
if (gSaveContext.respawn[RESPAWN_MODE_TOP].data > 0) {
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_TOP].entranceIndex;
|
||||
gPlayState->fadeTransition = 5;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_WHITE_FAST;
|
||||
} else {
|
||||
ERROR_MESSAGE("Farore's wind not set!");
|
||||
return 1;
|
||||
@ -577,7 +581,7 @@ static bool InvisibleHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::InvisibleLink();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::InvisibleLink();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -604,8 +608,8 @@ static bool GiantLinkHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->parameters[0] = GI_LINK_SIZE_GIANT;
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_GIANT;
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -632,8 +636,8 @@ static bool MinishLinkHandler(std::shared_ptr<LUS::Console> Console, const std::
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->parameters[0] = GI_LINK_SIZE_MINISH;
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_MINISH;
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -666,7 +670,7 @@ static bool AddHeartContainerHandler(std::shared_ptr<LUS::Console> Console, cons
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->parameters[0] = hearts;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = hearts;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
INFO_MESSAGE("[SOH] Added %d heart containers", hearts);
|
||||
@ -697,7 +701,7 @@ static bool RemoveHeartContainerHandler(std::shared_ptr<LUS::Console> Console, c
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->parameters[0] = -hearts;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -hearts;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
INFO_MESSAGE("[SOH] Removed %d heart containers", hearts);
|
||||
@ -717,7 +721,7 @@ static bool GravityHandler(std::shared_ptr<LUS::Console> Console, const std::vec
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyGravity();
|
||||
|
||||
try {
|
||||
effect->parameters[0] = LUS::Math::clamp(std::stoi(args[1], nullptr, 10), GI_GRAVITY_LEVEL_LIGHT, GI_GRAVITY_LEVEL_HEAVY);
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = LUS::Math::clamp(std::stoi(args[1], nullptr, 10), GI_GRAVITY_LEVEL_LIGHT, GI_GRAVITY_LEVEL_HEAVY);
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Gravity value must be a number.");
|
||||
return 1;
|
||||
@ -747,7 +751,7 @@ static bool NoUIHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::NoUI();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::NoUI();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -782,7 +786,7 @@ static bool DefenseModifierHandler(std::shared_ptr<LUS::Console> Console, const
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||
|
||||
try {
|
||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Defense modifier value must be a number.");
|
||||
return 1;
|
||||
@ -790,7 +794,7 @@ static bool DefenseModifierHandler(std::shared_ptr<LUS::Console> Console, const
|
||||
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
INFO_MESSAGE("[SOH] Defense modifier set to %d", effect->parameters[0]);
|
||||
INFO_MESSAGE("[SOH] Defense modifier set to %d", dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0]);
|
||||
return 0;
|
||||
} else {
|
||||
INFO_MESSAGE("[SOH] Command failed: Could not set defense modifier.");
|
||||
@ -812,7 +816,7 @@ static bool DamageHandler(std::shared_ptr<LUS::Console> Console, const std::vect
|
||||
return 1;
|
||||
}
|
||||
|
||||
effect->parameters[0] = -value;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -value;
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
||||
return 1;
|
||||
@ -842,7 +846,7 @@ static bool HealHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
||||
return 1;
|
||||
}
|
||||
|
||||
effect->parameters[0] = value;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = value;
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
||||
return 1;
|
||||
@ -898,7 +902,7 @@ static bool NoZHandler(std::shared_ptr<LUS::Console> Console, const std::vector<
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::DisableZTargeting();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::DisableZTargeting();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -926,7 +930,7 @@ static bool OneHitKOHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::OneHitKO();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::OneHitKO();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -954,7 +958,7 @@ static bool PacifistHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::PacifistMode();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::PacifistMode();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -982,8 +986,8 @@ static bool PaperLinkHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->parameters[0] = GI_LINK_SIZE_PAPER;
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_PAPER;
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -1011,7 +1015,7 @@ static bool RainstormHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::WeatherRainstorm();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::WeatherRainstorm();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -1039,7 +1043,7 @@ static bool ReverseControlsHandler(std::shared_ptr<LUS::Console> Console, const
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ReverseControls();
|
||||
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ReverseControls();
|
||||
GameInteractionEffectQueryResult result =
|
||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||
|
||||
@ -1062,7 +1066,7 @@ static bool UpdateRupeesHandler(std::shared_ptr<LUS::Console> Console, const std
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRupees();
|
||||
|
||||
try {
|
||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Rupee value must be a number.");
|
||||
return 1;
|
||||
@ -1086,7 +1090,7 @@ static bool SpeedModifierHandler(std::shared_ptr<LUS::Console> Console, const st
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||
|
||||
try {
|
||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Speed modifier value must be a number.");
|
||||
return 1;
|
||||
@ -1121,7 +1125,7 @@ static bool BootsHandler(std::shared_ptr<LUS::Console> Console, const std::vecto
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ForceEquipBoots();
|
||||
effect->parameters[0] = it->second;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -1152,7 +1156,7 @@ static bool GiveShieldHandler(std::shared_ptr<LUS::Console> Console, const std::
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->parameters[0] = it->second;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -1177,7 +1181,7 @@ static bool TakeShieldHandler(std::shared_ptr<LUS::Console> Console, const std::
|
||||
}
|
||||
|
||||
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
||||
effect->parameters[0] = it->second * -1;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second * -1;
|
||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||
|
||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||
@ -1203,7 +1207,7 @@ static bool KnockbackHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
||||
return 1;
|
||||
}
|
||||
|
||||
effect->parameters[0] = value;
|
||||
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = value;
|
||||
} catch (std::invalid_argument const& ex) {
|
||||
ERROR_MESSAGE("[SOH] Knockback value must be a number.");
|
||||
return 1;
|
||||
|
271
soh/soh/Enhancements/debugger/MessageViewer.cpp
Normal 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("gBetterOwl", 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);
|
||||
}
|
||||
|
||||
|
62
soh/soh/Enhancements/debugger/MessageViewer.h
Normal 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 LUS::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
|
@ -8,6 +8,7 @@
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <libultraship/libultraship.h>
|
||||
@ -24,6 +25,7 @@ extern PlayState* gPlayState;
|
||||
#include "textures/icon_item_24_static/icon_item_24_static.h"
|
||||
}
|
||||
|
||||
#define DEKUNUTS_FLOWER 10
|
||||
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
|
||||
|
||||
typedef struct {
|
||||
@ -107,6 +109,783 @@ 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) {
|
||||
int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE);
|
||||
auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
|
||||
@ -163,6 +942,9 @@ void ActorViewerWindow::DrawElement() {
|
||||
static std::string filler = "Please select";
|
||||
static std::vector<Actor*> list;
|
||||
static u16 lastSceneId = 0;
|
||||
static char searchString[64] = "";
|
||||
static s16 currentSelectedInDropdown;
|
||||
static std::vector<u16> actors;
|
||||
|
||||
if (gPlayState != nullptr) {
|
||||
needs_reset = lastSceneId != gPlayState->sceneNum;
|
||||
@ -173,6 +955,11 @@ void ActorViewerWindow::DrawElement() {
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
|
||||
searchString[i] = 0;
|
||||
}
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
|
||||
@ -316,9 +1103,48 @@ void ActorViewerWindow::DrawElement() {
|
||||
if (ImGui::TreeNode("New...")) {
|
||||
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::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one);
|
||||
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
|
||||
if (ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one)) {
|
||||
newActor.params = 0;
|
||||
}
|
||||
|
||||
UIWidgets::EnhancementCheckbox("Advanced mode", "gActorViewerAdvancedParams");
|
||||
UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input");
|
||||
|
||||
if (CVarGetInteger("gActorViewerAdvancedParams", 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);
|
||||
|
||||
@ -401,6 +1227,11 @@ void ActorViewerWindow::DrawElement() {
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
|
||||
searchString[i] = 0;
|
||||
}
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,7 +515,7 @@ void DrawInfoTab() {
|
||||
UIWidgets::InsertHelpHoverText("Z-Targeting behavior");
|
||||
|
||||
if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT)) {
|
||||
ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U16, &gSaveContext.triforcePiecesCollected);
|
||||
ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8, &gSaveContext.triforcePiecesCollected);
|
||||
UIWidgets::InsertHelpHoverText("Currently obtained Triforce Pieces. For Triforce Hunt.");
|
||||
}
|
||||
|
||||
@ -1573,7 +1573,7 @@ void DrawPlayerTab() {
|
||||
ImGui::InputScalar("Y Velocity", ImGuiDataType_Float, &player->actor.velocity.y);
|
||||
UIWidgets::InsertHelpHoverText("Link's speed along the Y plane. Caps at -20");
|
||||
|
||||
ImGui::InputScalar("Wall Height", ImGuiDataType_Float, &player->wallHeight);
|
||||
ImGui::InputScalar("Wall Height", ImGuiDataType_Float, &player->yDistToLedge);
|
||||
UIWidgets::InsertHelpHoverText("Height used to determine whether Link can climb or grab a ledge at the top");
|
||||
|
||||
ImGui::InputScalar("Invincibility Timer", ImGuiDataType_S8, &player->invincibilityTimer);
|
||||
|
@ -505,6 +505,7 @@ const std::vector<FlagTable> flagTables = {
|
||||
{ RAND_INF_CHILD_FISHING, "RAND_INF_CHILD_FISHING" },
|
||||
{ RAND_INF_ADULT_FISHING, "RAND_INF_ADULT_FISHING" },
|
||||
{ RAND_INF_10_BIG_POES, "RAND_INF_10_BIG_POES" },
|
||||
{ RAND_INF_GRANT_GANONS_BOSSKEY, "RAND_INF_GRANT_GANONS_BOSSKEY" },
|
||||
} },
|
||||
};
|
||||
|
||||
|
@ -18,15 +18,13 @@ extern "C" {
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
extern PlayState* gPlayState;
|
||||
|
||||
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
|
||||
}
|
||||
|
||||
char searchString[64] = "";
|
||||
int displayListsSearchResultsCount;
|
||||
char** displayListsSearchResults;
|
||||
char* activeDisplayList = nullptr;
|
||||
std::string activeDisplayList = "";
|
||||
std::vector<std::string> displayListSearchResults;
|
||||
int16_t searchDebounceFrames = -1;
|
||||
bool doSearch = false;
|
||||
|
||||
std::map<int, std::string> cmdMap = {
|
||||
{ G_SETPRIMCOLOR, "gsDPSetPrimColor" },
|
||||
@ -36,8 +34,61 @@ std::map<int, std::string> cmdMap = {
|
||||
{ G_SETINTENSITY, "gsDPSetGrayscaleColor" },
|
||||
{ G_LOADTLUT, "gsDPLoadTLUT" },
|
||||
{ G_ENDDL, "gsSPEndDisplayList" },
|
||||
{ G_TEXTURE, "gsSPTexture" },
|
||||
{ G_SETTIMG, "gsDPSetTextureImage" },
|
||||
{ G_SETTIMG_OTR_HASH, "gsDPSetTextureImage" },
|
||||
{ G_SETTIMG_OTR_FILEPATH, "gsDPSetTextureImage" },
|
||||
{ G_RDPTILESYNC, "gsDPTileSync" },
|
||||
{ G_SETTILE, "gsDPSetTile" },
|
||||
{ G_RDPLOADSYNC, "gsDPLoadSync" },
|
||||
{ G_LOADBLOCK, "gsDPLoadBlock" },
|
||||
{ G_SETTILESIZE, "gsDPSetTileSize" },
|
||||
{ G_DL, "gsSPDisplayList" },
|
||||
{ G_DL_OTR_FILEPATH, "gsSPDisplayList" },
|
||||
{ G_DL_OTR_HASH, "gsSPDisplayList" },
|
||||
{ G_MTX, "gsSPMatrix" },
|
||||
{ G_MTX_OTR, "gsSPMatrix" },
|
||||
{ G_VTX, "gsSPVertex" },
|
||||
{ G_VTX_OTR_FILEPATH, "gsSPVertex" },
|
||||
{ G_VTX_OTR_HASH, "gsSPVertex" },
|
||||
{ G_GEOMETRYMODE, "gsSPSetGeometryMode" },
|
||||
{ G_SETOTHERMODE_H, "gsSPSetOtherMode_H" },
|
||||
{ G_SETOTHERMODE_L, "gsSPSetOtherMode_L" },
|
||||
{ G_TRI1, "gsSP1Triangle" },
|
||||
{ G_TRI1_OTR, "gsSP1Triangle" },
|
||||
{ G_TRI2, "gsSP2Triangles" },
|
||||
{ G_SETCOMBINE, "gsDPSetCombineLERP" },
|
||||
{ G_CULLDL, "gsSPCullDisplayList" },
|
||||
{ G_NOOP, "gsDPNoOp" },
|
||||
{ G_SPNOOP, "gsSPNoOp" },
|
||||
{ G_MARKER, "LUS Custom Marker" },
|
||||
};
|
||||
|
||||
void PerformDisplayListSearch() {
|
||||
auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles("*" + std::string(searchString) + "*DL*");
|
||||
|
||||
displayListSearchResults.clear();
|
||||
|
||||
// Filter the file results even further as StormLib can only use wildcard searching
|
||||
for (size_t i = 0; i < result->size(); i++) {
|
||||
std::string val = result->at(i);
|
||||
if (val.ends_with("DL") || val.find("DL_") != std::string::npos) {
|
||||
displayListSearchResults.push_back(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the final list
|
||||
std::sort(displayListSearchResults.begin(), displayListSearchResults.end(), [](const std::string& a, const std::string& b) {
|
||||
return std::lexicographical_compare(
|
||||
a.begin(), a.end(),
|
||||
b.begin(), b.end(),
|
||||
[](char c1, char c2) {
|
||||
return std::tolower(c1) < std::tolower(c2);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void DLViewerWindow::DrawElement() {
|
||||
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Display List Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||
@ -45,22 +96,48 @@ void DLViewerWindow::DrawElement() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Debounce the search field as listing otr files is expensive
|
||||
if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) {
|
||||
displayListsSearchResults = ResourceMgr_ListFiles(("*" + std::string(searchString) + "*DL").c_str(), &displayListsSearchResultsCount);
|
||||
doSearch = true;
|
||||
searchDebounceFrames = 30;
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Active Display List", activeDisplayList)) {
|
||||
for (int i = 0; i < displayListsSearchResultsCount; i++) {
|
||||
if (ImGui::Selectable(displayListsSearchResults[i])) {
|
||||
activeDisplayList = displayListsSearchResults[i];
|
||||
if (doSearch) {
|
||||
if (searchDebounceFrames == 0) {
|
||||
doSearch = false;
|
||||
PerformDisplayListSearch();
|
||||
}
|
||||
|
||||
searchDebounceFrames--;
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Active Display List", activeDisplayList.c_str())) {
|
||||
for (size_t i = 0; i < displayListSearchResults.size(); i++) {
|
||||
if (ImGui::Selectable(displayListSearchResults[i].c_str())) {
|
||||
activeDisplayList = displayListSearchResults[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (activeDisplayList != nullptr) {
|
||||
|
||||
if (activeDisplayList == "") {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto res = std::static_pointer_cast<LUS::DisplayList>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(activeDisplayList));
|
||||
for (int i = 0; i < res->Instructions.size(); i++) {
|
||||
|
||||
if (res->GetInitData()->Type != static_cast<uint32_t>(LUS::ResourceType::DisplayList)) {
|
||||
ImGui::Text("Resource type is not a Display List. Please choose another.");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Total Instruction Size: %lu", res->Instructions.size());
|
||||
|
||||
for (size_t i = 0; i < res->Instructions.size(); i++) {
|
||||
std::string id = "##CMD" + std::to_string(i);
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[i];
|
||||
int cmd = gfx->words.w0 >> 24;
|
||||
@ -70,10 +147,11 @@ void DLViewerWindow::DrawElement() {
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushItemWidth(25.0f);
|
||||
ImGui::Text("%d", i);
|
||||
ImGui::Text("%lu", i);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(150.0f);
|
||||
ImGui::PushItemWidth(175.0f);
|
||||
|
||||
if (ImGui::BeginCombo(("CMD" + id).c_str(), cmdLabel.c_str())) {
|
||||
if (ImGui::Selectable("gsDPSetPrimColor") && cmd != G_SETPRIMCOLOR) {
|
||||
*gfx = gsDPSetPrimColor(0, 0, 0, 0, 0, 255);
|
||||
@ -92,8 +170,10 @@ void DLViewerWindow::DrawElement() {
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
if (gfx->words.w0 >> 24 == G_SETPRIMCOLOR || gfx->words.w0 >> 24 == G_SETINTENSITY || gfx->words.w0 >> 24 == G_SETENVCOLOR) {
|
||||
|
||||
if (cmd == G_SETPRIMCOLOR || cmd == G_SETINTENSITY || cmd == G_SETENVCOLOR) {
|
||||
uint8_t r = _SHIFTR(gfx->words.w1, 24, 8);
|
||||
uint8_t g = _SHIFTR(gfx->words.w1, 16, 8);
|
||||
uint8_t b = _SHIFTR(gfx->words.w1, 8, 8);
|
||||
@ -117,21 +197,141 @@ void DLViewerWindow::DrawElement() {
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
if (gfx->words.w0 >> 24 == G_RDPPIPESYNC) {
|
||||
if (cmd == G_RDPPIPESYNC) {
|
||||
}
|
||||
if (gfx->words.w0 >> 24 == G_SETGRAYSCALE) {
|
||||
if (cmd == G_SETGRAYSCALE) {
|
||||
bool* state = (bool*)&gfx->words.w1;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox(("state" + id).c_str(), state)) {
|
||||
//
|
||||
}
|
||||
}
|
||||
if (cmd == G_SETTILE) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("LINE: %u", _SHIFTR(gfx->words.w0, 9, 9));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("TMEM: %u", _SHIFTR(gfx->words.w0, 0, 9));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("TILE: %u", _SHIFTR(gfx->words.w1, 24, 3));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("PAL: %u", _SHIFTR(gfx->words.w1, 20, 4));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("CMT: %u", _SHIFTR(gfx->words.w1, 18, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("MASKT: %u", _SHIFTR(gfx->words.w1, 14, 4));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SHIFT: %u", _SHIFTR(gfx->words.w1, 10, 4));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("CMS: %u", _SHIFTR(gfx->words.w1, 8, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("MASKS: %u", _SHIFTR(gfx->words.w1, 4, 4));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SHIFTS: %u", _SHIFTR(gfx->words.w1, 0, 4));
|
||||
}
|
||||
if (cmd == G_SETTIMG) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
if (cmd == G_SETTIMG_OTR_HASH) {
|
||||
gfx++;
|
||||
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
|
||||
const char* fileName = ResourceGetNameByCrc(hash);
|
||||
|
||||
gfx--;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Texture Name: %s", fileName);
|
||||
}
|
||||
if (cmd == G_SETTIMG_OTR_FILEPATH) {
|
||||
char* fileName = (char*)gfx->words.w1;
|
||||
gfx++;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Texture Name: %s", fileName);
|
||||
}
|
||||
if (cmd == G_VTX) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
|
||||
}
|
||||
if (cmd == G_VTX_OTR_HASH) {
|
||||
gfx++;
|
||||
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
|
||||
const char* fileName = ResourceGetNameByCrc(hash);
|
||||
|
||||
gfx--;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Vertex Name: %s", fileName);
|
||||
}
|
||||
if (cmd == G_VTX_OTR_FILEPATH) {
|
||||
char* fileName = (char*)gfx->words.w1;
|
||||
|
||||
gfx++;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Vertex Name: %s", fileName);
|
||||
}
|
||||
if (cmd == G_DL) {
|
||||
}
|
||||
if (cmd == G_DL_OTR_HASH) {
|
||||
gfx++;
|
||||
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
|
||||
const char* fileName = ResourceGetNameByCrc(hash);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("DL Name: %s", fileName);
|
||||
}
|
||||
if (cmd == G_DL_OTR_FILEPATH) {
|
||||
char* fileName = (char*)gfx->words.w1;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("DL Name: %s", fileName);
|
||||
}
|
||||
|
||||
// Skip second half of instructions that are over 128-bit wide
|
||||
if (cmd == G_SETTIMG_OTR_HASH || cmd == G_DL_OTR_HASH || cmd == G_VTX_OTR_HASH ||
|
||||
cmd == G_BRANCH_Z_OTR || cmd == G_MARKER || cmd == G_MTX_OTR) {
|
||||
i++;
|
||||
ImGui::Text("%lu - Reserved - Second half of %s", i, cmdLabel.c_str());
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
ImGui::Text("Error displaying DL instructions.");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void DLViewerWindow::InitElement() {
|
||||
displayListsSearchResults = ResourceMgr_ListFiles("*DL", &displayListsSearchResultsCount);
|
||||
PerformDisplayListSearch();
|
||||
}
|
||||
|
219
soh/soh/Enhancements/debugger/valueViewer.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
#include "valueViewer.h"
|
||||
#include "../../UIWidgets.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
extern PlayState* gPlayState;
|
||||
void GfxPrint_SetColor(GfxPrint* printer, u32 r, u32 g, u32 b, u32 a);
|
||||
void GfxPrint_SetPos(GfxPrint* printer, s32 x, s32 y);
|
||||
s32 GfxPrint_Printf(GfxPrint* printer, const char* fmt, ...);
|
||||
}
|
||||
|
||||
ImVec4 WHITE = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
std::vector<ValueTableElement> valueTable = {
|
||||
{ "Time", "gSaveContext.dayTime", "TIME:", TYPE_U16, false, []() -> void* { return &gSaveContext.dayTime; }, WHITE },
|
||||
{ "Age", "gSaveContext.linkAge", "AGE:", TYPE_S32, false, []() -> void* { return &gSaveContext.linkAge; }, WHITE },
|
||||
{ "Health", "gSaveContext.health", "HP:", TYPE_S16, false, []() -> void* { return &gSaveContext.health; }, WHITE },
|
||||
{ "Navi Timer", "gSaveContext.naviTimer", "NAVI:", TYPE_U16, false, []() -> void* { return &gSaveContext.naviTimer; }, WHITE },
|
||||
{ "Scene ID", "play->sceneNum", "SCENE:", TYPE_S16, true, []() -> void* { return &gPlayState->sceneNum; }, WHITE },
|
||||
{ "Room ID", "play->roomCtx.curRoom.num", "ROOM:", TYPE_S8, true, []() -> void* { return &gPlayState->roomCtx.curRoom.num; }, WHITE },
|
||||
{ "Entrance ID", "gSaveContext.entranceIndex", "ENTR:", TYPE_S32, false, []() -> void* { return &gSaveContext.entranceIndex; }, WHITE },
|
||||
{ "Cutscene ID", "gSaveContext.cutsceneIndex", "CUTS:", TYPE_S32, false, []() -> void* { return &gSaveContext.cutsceneIndex; }, WHITE },
|
||||
{ "Link X", "Player->actor.world.pos.x", "X:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.world.pos.x; }, WHITE },
|
||||
{ "Link Y", "Player->actor.world.pos.y", "Y:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.world.pos.y; }, WHITE },
|
||||
{ "Link Z", "Player->actor.world.pos.z", "Z:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.world.pos.z; }, WHITE },
|
||||
{ "Link Yaw", "Player->actor.world.rot.y", "ROT:", TYPE_S16, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.world.rot.y; }, WHITE },
|
||||
{ "Link Velocity", "Player->linearVelocity", "V:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->linearVelocity; }, WHITE },
|
||||
{ "Link X Velocity", "Player->actor.velocity.x", "XV:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.velocity.x; }, WHITE },
|
||||
{ "Link Y Velocity", "Player->actor.velocity.y", "YV:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.velocity.y; }, WHITE },
|
||||
{ "Link Z Velocity", "Player->actor.velocity.z", "ZV:", TYPE_FLOAT, true, []() -> void* { return &GET_PLAYER(gPlayState)->actor.velocity.z; }, WHITE },
|
||||
{ "Text ID", "play->msgCtx.textId", "TEXTID:", TYPE_U16, true, []() -> void* { return &gPlayState->msgCtx.textId; }, WHITE },
|
||||
{ "Analog Stick X", "play->state.input->cur.stick_x", "AX:", TYPE_S8, true, []() -> void* { return &gPlayState->state.input->cur.stick_x; }, WHITE },
|
||||
{ "Analog Stick Y", "play->state.input->cur.stick_y", "AY:", TYPE_S8, true, []() -> void* { return &gPlayState->state.input->cur.stick_y; }, WHITE },
|
||||
/* TODO: Find these (from GZ)
|
||||
"XZ Units Traveled (Camera based speed variable)" f32 0x801C9018
|
||||
"Movement Angle" x16 0x801DBB1C
|
||||
"Camera Angle" u16 0x801C907C
|
||||
"Time of Day" x16 0x8011AC8C
|
||||
"Global Frame Counter" s32 0x801C8DFC
|
||||
"Lit Deku Stick Timer" u16 0x801DBB40
|
||||
"Cutscene Pointer" u32 0x801CAAC8
|
||||
"Get Item Value" s8 0x801DB714
|
||||
"Last RNG Value" x32 0x80105A80
|
||||
"Last Item Button Pressed" u8 0x801DB430
|
||||
"Last Damage Value" x32 0x801DB7DC
|
||||
"Temp B Value" u8 0x8011C062
|
||||
"Framerate Divisor" u8 0x801C7861
|
||||
"Heads Up Display (HUD)" u16 0x8011C068
|
||||
"Analog Stick Angle" s16 0x803AA698
|
||||
"Deku Tree Warp Timer (Reload Room)" u16 0x801F0352
|
||||
"Dodongo's Cavern Warp Timer" u16 0x801E30B2
|
||||
"Jabu-Jabu Warp Timer" u16 0x802008B2
|
||||
"Forest Temple Warp Timer" u16 0x801EC5B2
|
||||
"Fire Temple Warp Timer" u16 0x801F3E42
|
||||
"Water Temple Warp Timer" u16 0x801F8762
|
||||
"Shadow Temple Warp Timer" u16 0x801F48A2
|
||||
"Spirit Temple Warp Timer" u16 0x801FD562
|
||||
"Deku Tree Warp Timer" u16 0x801F83A2
|
||||
*/
|
||||
};
|
||||
|
||||
extern "C" void ValueViewer_Draw(GfxPrint* printer) {
|
||||
for (int i = 0; i < valueTable.size(); i++) {
|
||||
ValueTableElement& element = valueTable[i];
|
||||
if (!element.isActive || !element.isPrinted || (gPlayState == NULL && element.requiresPlayState)) continue;
|
||||
GfxPrint_SetColor(printer, element.color.x * 255, element.color.y * 255, element.color.z * 255, element.color.w * 255);
|
||||
GfxPrint_SetPos(printer, element.x, element.y);
|
||||
switch (element.type) {
|
||||
case TYPE_S8:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%d"), element.prefix.c_str(), *(s8*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U8:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%u"), element.prefix.c_str(), *(u8*)element.valueFn());
|
||||
break;
|
||||
case TYPE_S16:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%d"), element.prefix.c_str(), *(s16*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U16:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%u"), element.prefix.c_str(), *(u16*)element.valueFn());
|
||||
break;
|
||||
case TYPE_S32:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%d"), element.prefix.c_str(), *(s32*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U32:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s0x%x" : "%s%u"), element.prefix.c_str(), *(u32*)element.valueFn());
|
||||
break;
|
||||
case TYPE_CHAR:
|
||||
GfxPrint_Printf(printer, "%s%c", element.prefix.c_str(), *(char*)element.valueFn());
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
GfxPrint_Printf(printer, "%s%s", element.prefix.c_str(), (char*)element.valueFn());
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
GfxPrint_Printf(printer, (element.typeFormat ? "%s%4.1f" : "%s%f"), element.prefix.c_str(), *(float*)element.valueFn());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ValueViewerWindow::DrawElement() {
|
||||
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Value Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable Printing", "gValueViewer.EnablePrinting");
|
||||
|
||||
ImGui::BeginGroup();
|
||||
static int selectedElement = -1;
|
||||
std::string selectedElementText = (selectedElement == -1) ? "Select a value" : (
|
||||
std::string(valueTable[selectedElement].name) + " (" + std::string(valueTable[selectedElement].path) + ")"
|
||||
);
|
||||
if (ImGui::BeginCombo("##valueViewerElement", selectedElementText.c_str())) {
|
||||
for (int i = 0; i < valueTable.size(); i++) {
|
||||
if (valueTable[i].isActive) continue;
|
||||
bool isSelected = (selectedElement == i);
|
||||
std::string elementText = (
|
||||
std::string(valueTable[i].name) + " (" + std::string(valueTable[i].path) + ")"
|
||||
);
|
||||
if (ImGui::Selectable(elementText.c_str(), isSelected)) {
|
||||
selectedElement = i;
|
||||
}
|
||||
if (isSelected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (selectedElement != -1 && ImGui::Button("+")) {
|
||||
valueTable[selectedElement].isActive = true;
|
||||
selectedElement = -1;
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
for (int i = 0; i < valueTable.size(); i++) {
|
||||
ValueTableElement& element = valueTable[i];
|
||||
if (!element.isActive || (gPlayState == NULL && element.requiresPlayState)) continue;
|
||||
if (ImGui::Button(("x##" + std::string(element.name)).c_str())) {
|
||||
element.isActive = false;
|
||||
element.isPrinted = false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s:", element.name);
|
||||
ImGui::SameLine();
|
||||
switch (element.type) {
|
||||
case TYPE_S8:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%d", *(s8*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U8:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%u", *(u8*)element.valueFn());
|
||||
break;
|
||||
case TYPE_S16:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%d", *(s16*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U16:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%u", *(u16*)element.valueFn());
|
||||
break;
|
||||
case TYPE_S32:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%d", *(s32*)element.valueFn());
|
||||
break;
|
||||
case TYPE_U32:
|
||||
ImGui::Text(element.typeFormat ? "0x%x" : "%u", *(u32*)element.valueFn());
|
||||
break;
|
||||
case TYPE_CHAR:
|
||||
ImGui::Text("%c", *(char*)element.valueFn());
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
ImGui::Text("%s", (char*)element.valueFn());
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
ImGui::Text(element.typeFormat ? "%4.1f" : "%f", *(float*)element.valueFn());
|
||||
break;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
if (element.type <= TYPE_U32) {
|
||||
ImGui::Checkbox(("Hex##" + std::string(element.name)).c_str(), &element.typeFormat);
|
||||
ImGui::SameLine();
|
||||
} else if (element.type == TYPE_FLOAT) {
|
||||
ImGui::Checkbox(("Trim##" + std::string(element.name)).c_str(), &element.typeFormat);
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
if (CVarGetInteger("gValueViewer.EnablePrinting", 0)) {
|
||||
ImGui::Checkbox(("Print##" + std::string(element.name)).c_str(), &element.isPrinted);
|
||||
if (element.isPrinted) {
|
||||
char* prefix = (char*)element.prefix.c_str();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(80.0f);
|
||||
if (ImGui::InputText(("Prefix##" + std::string(element.name)).c_str(), prefix, 10)) {
|
||||
element.prefix = prefix;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorEdit3(("##color" + std::string(element.name)).c_str(), (float*)&element.color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(("Position##" + std::string(element.name)).c_str())) {
|
||||
ImGui::OpenPopup(("Position Picker##" + std::string(element.name)).c_str());
|
||||
}
|
||||
if (ImGui::BeginPopup(("Position Picker##" + std::string(element.name)).c_str())) {
|
||||
ImGui::DragInt("X", (int*)&element.x, 1.0f, 0, 44);
|
||||
ImGui::DragInt("Y", (int*)&element.y, 1.0f, 0, 29);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ValueViewerWindow::InitElement() {
|
||||
}
|
53
soh/soh/Enhancements/debugger/valueViewer.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
typedef enum {
|
||||
TYPE_S8,
|
||||
TYPE_U8,
|
||||
TYPE_S16,
|
||||
TYPE_U16,
|
||||
TYPE_S32,
|
||||
TYPE_U32,
|
||||
TYPE_CHAR,
|
||||
TYPE_STRING,
|
||||
TYPE_FLOAT,
|
||||
} ValueType;
|
||||
|
||||
typedef void* (*ValueFn)();
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const char* path;
|
||||
std::string prefix;
|
||||
ValueType type;
|
||||
bool requiresPlayState;
|
||||
ValueFn valueFn;
|
||||
ImVec4 color;
|
||||
bool isActive;
|
||||
bool isPrinted;
|
||||
bool typeFormat;
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
} ValueTableElement;
|
||||
|
||||
class ValueViewerWindow : public LUS::GuiWindow {
|
||||
public:
|
||||
using GuiWindow::GuiWindow;
|
||||
|
||||
void InitElement() override;
|
||||
void DrawElement() override;
|
||||
void UpdateElement() override {};
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#endif
|
||||
|
||||
void ValueViewer_Draw(GfxPrint* printer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -78,4 +78,10 @@ typedef enum {
|
||||
DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE,
|
||||
} DekuStickType;
|
||||
|
||||
typedef enum {
|
||||
SWORD_TOGGLE_NONE,
|
||||
SWORD_TOGGLE_CHILD,
|
||||
SWORD_TOGGLE_BOTH_AGES,
|
||||
} SwordToggleMode;
|
||||
|
||||
#endif
|
||||
|
@ -31,11 +31,11 @@ GameInteractionEffectQueryResult GameInteractionEffectBase::Apply() {
|
||||
}
|
||||
|
||||
/// For most effects, CanBeRemoved is the same as CanBeApplied. When its not: please override `CanBeRemoved`.
|
||||
GameInteractionEffectQueryResult GameInteractionEffectBase::CanBeRemoved() {
|
||||
GameInteractionEffectQueryResult RemovableGameInteractionEffect::CanBeRemoved() {
|
||||
return CanBeApplied();
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractionEffectBase::Remove() {
|
||||
GameInteractionEffectQueryResult RemovableGameInteractionEffect::Remove() {
|
||||
GameInteractionEffectQueryResult result = CanBeRemoved();
|
||||
if (result != GameInteractionEffectQueryResult::Possible) {
|
||||
return result;
|
||||
|
@ -15,38 +15,46 @@ enum GameInteractionEffectQueryResult {
|
||||
class GameInteractionEffectBase {
|
||||
public:
|
||||
virtual GameInteractionEffectQueryResult CanBeApplied() = 0;
|
||||
virtual GameInteractionEffectQueryResult CanBeRemoved();
|
||||
GameInteractionEffectQueryResult Apply();
|
||||
GameInteractionEffectQueryResult Remove();
|
||||
int32_t parameters[3];
|
||||
|
||||
protected:
|
||||
protected:
|
||||
virtual void _Apply() = 0;
|
||||
};
|
||||
|
||||
class RemovableGameInteractionEffect: public GameInteractionEffectBase {
|
||||
public:
|
||||
virtual GameInteractionEffectQueryResult CanBeRemoved();
|
||||
GameInteractionEffectQueryResult Remove();
|
||||
protected:
|
||||
virtual void _Remove() {};
|
||||
};
|
||||
|
||||
class ParameterizedGameInteractionEffect {
|
||||
public:
|
||||
int32_t parameters[3];
|
||||
};
|
||||
|
||||
namespace GameInteractionEffect {
|
||||
class SetSceneFlag: public GameInteractionEffectBase {
|
||||
class SetSceneFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class UnsetSceneFlag: public GameInteractionEffectBase {
|
||||
class UnsetSceneFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SetFlag: public GameInteractionEffectBase {
|
||||
class SetFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class UnsetFlag: public GameInteractionEffectBase {
|
||||
class UnsetFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ModifyHeartContainers: public GameInteractionEffectBase {
|
||||
class ModifyHeartContainers: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
@ -61,29 +69,29 @@ namespace GameInteractionEffect {
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ModifyRupees: public GameInteractionEffectBase {
|
||||
class ModifyRupees: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class NoUI: public GameInteractionEffectBase {
|
||||
class NoUI: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyGravity: public GameInteractionEffectBase {
|
||||
class ModifyGravity: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyHealth: public GameInteractionEffectBase {
|
||||
class ModifyHealth: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SetPlayerHealth: public GameInteractionEffectBase {
|
||||
class SetPlayerHealth: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
@ -103,98 +111,98 @@ namespace GameInteractionEffect {
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class KnockbackPlayer: public GameInteractionEffectBase {
|
||||
class KnockbackPlayer: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ModifyLinkSize: public GameInteractionEffectBase {
|
||||
class ModifyLinkSize: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class InvisibleLink : public GameInteractionEffectBase {
|
||||
class InvisibleLink : public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class PacifistMode : public GameInteractionEffectBase {
|
||||
class PacifistMode : public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class DisableZTargeting: public GameInteractionEffectBase {
|
||||
class DisableZTargeting: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class WeatherRainstorm: public GameInteractionEffectBase {
|
||||
class WeatherRainstorm: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ReverseControls: public GameInteractionEffectBase {
|
||||
class ReverseControls: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ForceEquipBoots: public GameInteractionEffectBase {
|
||||
class ForceEquipBoots: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyRunSpeedModifier: public GameInteractionEffectBase {
|
||||
class ModifyRunSpeedModifier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class OneHitKO : public GameInteractionEffectBase {
|
||||
class OneHitKO : public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyDefenseModifier: public GameInteractionEffectBase {
|
||||
class ModifyDefenseModifier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class GiveOrTakeShield: public GameInteractionEffectBase {
|
||||
class GiveOrTakeShield: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class TeleportPlayer: public GameInteractionEffectBase {
|
||||
class TeleportPlayer: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ClearAssignedButtons: public GameInteractionEffectBase {
|
||||
class ClearAssignedButtons: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SetTimeOfDay: public GameInteractionEffectBase {
|
||||
class SetTimeOfDay: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SetCollisionViewer: public GameInteractionEffectBase {
|
||||
class SetCollisionViewer: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class SetCosmeticsColor: public GameInteractionEffectBase {
|
||||
class SetCosmeticsColor: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
@ -204,52 +212,52 @@ namespace GameInteractionEffect {
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class PressButton: public GameInteractionEffectBase {
|
||||
class PressButton: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class PressRandomButton: public GameInteractionEffectBase {
|
||||
class PressRandomButton: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class AddOrTakeAmmo: public GameInteractionEffectBase {
|
||||
class AddOrTakeAmmo: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class RandomBombFuseTimer: public GameInteractionEffectBase {
|
||||
class RandomBombFuseTimer: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class DisableLedgeGrabs: public GameInteractionEffectBase {
|
||||
class DisableLedgeGrabs: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class RandomWind: public GameInteractionEffectBase {
|
||||
class RandomWind: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class RandomBonks: public GameInteractionEffectBase {
|
||||
class RandomBonks: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class PlayerInvincibility: public GameInteractionEffectBase {
|
||||
class PlayerInvincibility: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class SlipperyFloor: public GameInteractionEffectBase {
|
||||
class SlipperyFloor: public RemovableGameInteractionEffect {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
|
@ -31,7 +31,7 @@ GameInteractionEffectQueryResult GameInteractor::ApplyEffect(GameInteractionEffe
|
||||
return effect->Apply();
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractor::RemoveEffect(GameInteractionEffectBase* effect) {
|
||||
GameInteractionEffectQueryResult GameInteractor::RemoveEffect(RemovableGameInteractionEffect* effect) {
|
||||
return effect->Remove();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,12 @@
|
||||
|
||||
#include "GameInteractionEffect.h"
|
||||
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
||||
#include <z64.h>
|
||||
|
||||
typedef enum {
|
||||
GI_SCHEME_SAIL,
|
||||
GI_SCHEME_CROWD_CONTROL,
|
||||
} GIScheme;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ GI_LINK_SIZE_NORMAL,
|
||||
@ -52,13 +58,13 @@ typedef enum {
|
||||
} GIColors;
|
||||
|
||||
typedef enum {
|
||||
/* */ GI_TP_DEST_LINKSHOUSE = 187,
|
||||
/* */ GI_TP_DEST_MINUET = 1536,
|
||||
/* */ GI_TP_DEST_BOLERO = 1270,
|
||||
/* */ GI_TP_DEST_SERENADE = 1540,
|
||||
/* */ GI_TP_DEST_REQUIEM = 497,
|
||||
/* */ GI_TP_DEST_NOCTURNE = 1384,
|
||||
/* */ GI_TP_DEST_PRELUDE = 1524,
|
||||
/* */ GI_TP_DEST_LINKSHOUSE = ENTR_LINKS_HOUSE_0,
|
||||
/* */ GI_TP_DEST_MINUET = ENTR_SACRED_FOREST_MEADOW_2,
|
||||
/* */ GI_TP_DEST_BOLERO = ENTR_DEATH_MOUNTAIN_CRATER_4,
|
||||
/* */ GI_TP_DEST_SERENADE = ENTR_LAKE_HYLIA_8,
|
||||
/* */ GI_TP_DEST_REQUIEM = ENTR_DESERT_COLOSSUS_5,
|
||||
/* */ GI_TP_DEST_NOCTURNE = ENTR_GRAVEYARD_7,
|
||||
/* */ GI_TP_DEST_PRELUDE = ENTR_TEMPLE_OF_TIME_7,
|
||||
} GITeleportDestinations;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -91,11 +97,16 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#ifdef ENABLE_REMOTE_CONTROL
|
||||
#include <SDL2/SDL_net.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#endif
|
||||
|
||||
#define DEFINE_HOOK(name, type) \
|
||||
struct name { \
|
||||
typedef std::function<type> fn; \
|
||||
@ -132,17 +143,50 @@ public:
|
||||
static void SetPacifistMode(bool active);
|
||||
};
|
||||
|
||||
#ifdef ENABLE_REMOTE_CONTROL
|
||||
bool isRemoteInteractorEnabled;
|
||||
bool isRemoteInteractorConnected;
|
||||
|
||||
void EnableRemoteInteractor();
|
||||
void DisableRemoteInteractor();
|
||||
void RegisterRemoteDataHandler(std::function<void(char payload[512])> method);
|
||||
void RegisterRemoteJsonHandler(std::function<void(nlohmann::json)> method);
|
||||
void RegisterRemoteConnectedHandler(std::function<void()> method);
|
||||
void RegisterRemoteDisconnectedHandler(std::function<void()> method);
|
||||
void TransmitDataToRemote(const char* payload);
|
||||
void TransmitJsonToRemote(nlohmann::json packet);
|
||||
#endif
|
||||
|
||||
// Effects
|
||||
static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase* effect);
|
||||
static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase* effect);
|
||||
static GameInteractionEffectQueryResult RemoveEffect(GameInteractionEffectBase* effect);
|
||||
static GameInteractionEffectQueryResult RemoveEffect(RemovableGameInteractionEffect* effect);
|
||||
|
||||
// Game Hooks
|
||||
template <typename H> struct RegisteredGameHooks { inline static std::vector<typename H::fn> functions; };
|
||||
template <typename H> void RegisterGameHook(typename H::fn h) { RegisteredGameHooks<H>::functions.push_back(h); }
|
||||
uint32_t nextHookId = 1;
|
||||
template <typename H> struct RegisteredGameHooks { inline static std::unordered_map<uint32_t, typename H::fn> functions; };
|
||||
template <typename H> struct HooksToUnregister { inline static std::vector<uint32_t> hooks; };
|
||||
template <typename H> uint32_t RegisterGameHook(typename H::fn h) {
|
||||
// Ensure hook id is unique and not 0, which is reserved for invalid hooks
|
||||
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
||||
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
|
||||
this->nextHookId++;
|
||||
}
|
||||
|
||||
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
|
||||
return this->nextHookId++;
|
||||
}
|
||||
template <typename H> void UnregisterGameHook(uint32_t id) {
|
||||
HooksToUnregister<H>::hooks.push_back(id);
|
||||
}
|
||||
|
||||
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
|
||||
for (auto& fn : RegisteredGameHooks<H>::functions) {
|
||||
fn(std::forward<Args>(args)...);
|
||||
for (auto& hookId : HooksToUnregister<H>::hooks) {
|
||||
RegisteredGameHooks<H>::functions.erase(hookId);
|
||||
}
|
||||
HooksToUnregister<H>::hooks.clear();
|
||||
for (auto& hook : RegisteredGameHooks<H>::functions) {
|
||||
hook.second(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,6 +240,7 @@ public:
|
||||
|
||||
DEFINE_HOOK(OnFileDropped, void(std::string filePath));
|
||||
DEFINE_HOOK(OnAssetAltChange, void());
|
||||
DEFINE_HOOK(OnKaleidoUpdate, void());
|
||||
|
||||
// Helpers
|
||||
static bool IsSaveLoaded(bool allowDbgSave = false);
|
||||
@ -239,6 +284,21 @@ public:
|
||||
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams);
|
||||
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams);
|
||||
};
|
||||
|
||||
private:
|
||||
#ifdef ENABLE_REMOTE_CONTROL
|
||||
IPaddress remoteIP;
|
||||
TCPsocket remoteSocket;
|
||||
std::thread remoteThreadReceive;
|
||||
std::function<void(char payload[512])> remoteDataHandler;
|
||||
std::function<void(nlohmann::json)> remoteJsonHandler;
|
||||
std::function<void()> remoteConnectedHandler;
|
||||
std::function<void()> remoteDisconnectedHandler;
|
||||
|
||||
void ReceiveFromServer();
|
||||
void HandleRemoteData(char payload[512]);
|
||||
void HandleRemoteJson(std::string payload);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
@ -187,3 +187,9 @@ void GameInteractor_ExecuteOnSetGameLanguage() {
|
||||
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnAssetAltChange>(fn);
|
||||
}
|
||||
|
||||
//MARK: Pause Menu
|
||||
|
||||
void GameInteractor_ExecuteOnKaleidoUpdate() {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnKaleidoUpdate>();
|
||||
}
|
||||
|
@ -60,6 +60,9 @@ void GameInteractor_ExecuteOnSetGameLanguage();
|
||||
// MARK: - System
|
||||
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void));
|
||||
|
||||
//Mark: - Pause Menu
|
||||
void GameInteractor_ExecuteOnKaleidoUpdate();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -111,9 +111,9 @@ void GameInteractor::RawAction::FreezePlayer() {
|
||||
void GameInteractor::RawAction::BurnPlayer() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
for (int i = 0; i < 18; i++) {
|
||||
player->flameTimers[i] = Rand_S16Offset(0, 200);
|
||||
player->bodyFlameTimers[i] = Rand_S16Offset(0, 200);
|
||||
}
|
||||
player->isBurning = true;
|
||||
player->bodyIsBurning = true;
|
||||
func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -326,9 +326,9 @@ void GameInteractor::RawAction::UpdateActor(void* refActor) {
|
||||
void GameInteractor::RawAction::TeleportPlayer(int32_t nextEntrance) {
|
||||
Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
|
||||
gPlayState->nextEntranceIndex = nextEntrance;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->fadeTransition = 2;
|
||||
gSaveContext.nextTransitionType = 2;
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_BLACK;
|
||||
gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK;
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::ClearAssignedButtons(uint8_t buttonSet) {
|
||||
@ -520,7 +520,7 @@ void GameInteractor::RawAction::SetRandomWind(bool active) {
|
||||
if (active) {
|
||||
GameInteractor::State::RandomWindActive = 1;
|
||||
if (GameInteractor::State::RandomWindSecondsSinceLastDirectionChange == 0) {
|
||||
player->windDirection = (rand() % 49152) - 32767;
|
||||
player->pushedYaw = (rand() % 49152) - 32767;
|
||||
GameInteractor::State::RandomWindSecondsSinceLastDirectionChange = 5;
|
||||
} else {
|
||||
GameInteractor::State::RandomWindSecondsSinceLastDirectionChange--;
|
||||
@ -528,8 +528,8 @@ void GameInteractor::RawAction::SetRandomWind(bool active) {
|
||||
} else {
|
||||
GameInteractor::State::RandomWindActive = 0;
|
||||
GameInteractor::State::RandomWindSecondsSinceLastDirectionChange = 0;
|
||||
player->windSpeed = 0.0f;
|
||||
player->windDirection = 0.0f;
|
||||
player->pushedSpeed = 0.0f;
|
||||
player->pushedYaw = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|