Merge remote-tracking branch 'upstream/develop' into Child-Holds-Hylian-Shield
6
.github/workflows/generate-builds.yml
vendored
@ -221,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 '*'
|
||||
@ -264,6 +267,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
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
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 }}
|
@ -1 +1 @@
|
||||
Subproject commit 44adc47b4da529e72d968b14cab94aefd8260f22
|
||||
Subproject commit e93bd2be062b13106fdb29d98cf4ada4d7ad6827
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0833afad66e96d2ec4bbc410186d7247dc243ee2
|
||||
Subproject commit a516b66ce0c89fe4e33c55b1fbfbde845d0bf129
|
@ -356,7 +356,13 @@ set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
if (BUILD_REMOTE_CONTROL)
|
||||
find_package(SDL2_net)
|
||||
|
||||
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
|
||||
@ -623,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
|
||||
|
@ -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>
|
||||
|
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 |
@ -2467,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
|
||||
|
@ -345,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;
|
||||
@ -359,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;
|
||||
@ -542,7 +542,7 @@ typedef struct Player {
|
||||
/* 0x0445 */ u8 prevCsAction;
|
||||
/* 0x0446 */ u8 cueId;
|
||||
/* 0x0447 */ u8 unk_447;
|
||||
/* 0x0448 */ Actor* csActor;
|
||||
/* 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;
|
||||
@ -595,8 +595,8 @@ typedef struct Player {
|
||||
/* 0x0836 */ s8 unk_836;
|
||||
/* 0x0837 */ u8 unk_837;
|
||||
/* 0x0838 */ f32 linearVelocity;
|
||||
/* 0x083C */ s16 currentYaw;
|
||||
/* 0x083E */ s16 targetYaw;
|
||||
/* 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;
|
||||
@ -605,8 +605,15 @@ typedef struct Player {
|
||||
/* 0x0846 */ u8 unk_846;
|
||||
/* 0x0847 */ s8 unk_847[4];
|
||||
/* 0x084B */ s8 unk_84B[4];
|
||||
/* 0x084F */ s8 unk_84F;
|
||||
/* 0x0850 */ s16 unk_850; // multipurpose timer
|
||||
|
||||
/* 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
|
||||
@ -622,13 +629,13 @@ typedef struct Player {
|
||||
/* 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; // distance to the colliding wall plane
|
||||
/* 0x088C */ u8 unk_88C;
|
||||
/* 0x088D */ u8 unk_88D;
|
||||
/* 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 shockTimer;
|
||||
/* 0x0891 */ u8 bodyShockTimer;
|
||||
/* 0x0892 */ u8 unk_892;
|
||||
/* 0x0893 */ u8 hoverBootsTimer;
|
||||
/* 0x0894 */ s16 fallStartHeight; // last truncated Y position before falling
|
||||
@ -648,17 +655,17 @@ typedef struct Player {
|
||||
/* 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
|
||||
/* 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;
|
||||
/* 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;
|
||||
|
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();
|
||||
};
|
@ -269,35 +269,35 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
|
||||
COSMETIC_OPTION("Hud_NameTagActorText", "Nametag Text", GROUP_HUD, ImVec4(255, 255, 255, 255), true, true, false),
|
||||
COSMETIC_OPTION("Hud_NameTagActorBackground", "Nametag Background", GROUP_HUD, ImVec4(0, 0, 0, 80), true, false, true),
|
||||
|
||||
COSMETIC_OPTION("Kal_ItemSelA", "Item Select Color A", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_ItemSelB", "Item Select Color B", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_ItemSelC", "Item Select Color C", GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_ItemSelD", "Item Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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 A", GROUP_KALEIDO, ImVec4(10, 50, 40, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_EquipSelB", "Equip Select Color B", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_EquipSelC", "Equip Select Color C", GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_EquipSelD", "Equip Select Color D", GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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 A", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelDunB", "Map Dungeon Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelDunC", "Map Dungeon Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelDunD", "Map Dungeon Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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 StatusColor A", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_QuestStatusB", "Quest StatusColor B", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_QuestStatusC", "Quest StatusColor C", GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_QuestStatusD", "Quest StatusColor D", GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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 A", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelectB", "Map Color B", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelectC", "Map Color C", GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_MapSelectD", "Map Color D", GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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 A", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_SaveB", "Save B", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_SaveC", "Save C", GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_SaveD", "Save D", GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false),
|
||||
COSMETIC_OPTION("Kal_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),
|
||||
|
||||
@ -1065,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");
|
||||
@ -1181,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);
|
||||
@ -1247,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);
|
||||
@ -1386,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);
|
||||
@ -1522,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)) {
|
||||
@ -1548,67 +1390,28 @@ void DrawSillyTab() {
|
||||
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();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderFloat("Link Sword Scale: %.3fx", "##Link_SwordScale", "gCosmetics.Link_SwordScale.Value", 1.0f, 2.5f, "", 1.0f, false)) {
|
||||
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();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("Bunny Hood Length: %.0f", "##BunnyHood_EarLength", "gCosmetics.BunnyHood_EarLength", -300.0f, 1000.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##BunnyHood_EarLength")) {
|
||||
CVarClear("gCosmetics.BunnyHood_EarLength");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("Bunny Hood Spread: %.0f", "##BunnyHood_EarSpread", "gCosmetics.BunnyHood_EarSpread", -300.0f, 500.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##BunnyHood_EarSpread")) {
|
||||
CVarClear("gCosmetics.BunnyHood_EarSpread");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("Goron Neck Length: %.0f", "##Goron_NeckLength", "gCosmetics.Goron_NeckLength", 0.0f, 5000.0f, "", 0.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Goron_NeckLength")) {
|
||||
CVarClear("gCosmetics.Goron_NeckLength");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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: %.2fx", "##Fairies_Size", "gCosmetics.Fairies_Size", 0.25f, 5.0f, "", 1.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Fairies_Size")) {
|
||||
CVarClear("gCosmetics.Fairies_Size");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("N64 Logo Spin Speed: %.2fx", "##N64Logo_SpinSpeed", "gCosmetics.N64Logo_SpinSpeed", 0.25f, 5.0f, "", 1.0f, false);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##N64Logo_SpinSpeed")) {
|
||||
CVarClear("gCosmetics.N64Logo_SpinSpeed");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
UIWidgets::EnhancementSliderFloat("Moon Size: %.1f %%", "##Moon_Size", "gCosmetics.Moon_Size", 0.5f, 2.0f, "", 1.0f, true);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset##Moon_Size")) {
|
||||
CVarClear("gCosmetics.Moon_Size");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderFloat("Kak Windmill Speed: %.0f", "##Kak_Windmill_Speed", "gCosmetics.Kak_Windmill_Speed.Value", 100.0f, 6000.0f, "", 100.0f, false)) {
|
||||
UIWidgets::EnhancementSliderFloat("Fairies Size: %f", "##Fairies_Size", "gCosmetics.Fairies_Size", 0.25f, 5.0f, "", 1.0f, false);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -1631,25 +1434,20 @@ void CopyMultipliedColor(CosmeticOption& cosmeticOptionSrc, CosmeticOption& cosm
|
||||
CVarSetInteger((cosmeticOptionTarget.changedCvar), 1);
|
||||
}
|
||||
|
||||
void RandomizeColor(CosmeticOption& cosmeticOption) {
|
||||
Color_RGBA8 newColor;
|
||||
newColor.r = Random(0, 255);
|
||||
newColor.g = Random(0, 255);
|
||||
newColor.b = Random(0, 255);
|
||||
newColor.a = 255;
|
||||
// For alpha supported options, retain the last set alpha instead of overwriting
|
||||
if (cosmeticOption.supportsAlpha) {
|
||||
newColor.a = cosmeticOption.currentColor.w * 255;
|
||||
void ToggleRainbow(CosmeticOption& cosmeticOption, bool state) {
|
||||
if (state) {
|
||||
CVarSetInteger(cosmeticOption.rainbowCvar, 1);
|
||||
CVarSetInteger(cosmeticOption.changedCvar, 1);
|
||||
} else {
|
||||
CVarClear(cosmeticOption.rainbowCvar);
|
||||
CVarClear(cosmeticOption.changedCvar);
|
||||
}
|
||||
}
|
||||
|
||||
cosmeticOption.currentColor.x = newColor.r / 255.0;
|
||||
cosmeticOption.currentColor.y = newColor.g / 255.0;
|
||||
cosmeticOption.currentColor.z = newColor.b / 255.0;
|
||||
cosmeticOption.currentColor.w = newColor.a / 255.0;
|
||||
|
||||
CVarSetColor(cosmeticOption.cvar, newColor);
|
||||
CVarSetInteger((cosmeticOption.rainbowCvar), 0);
|
||||
CVarSetInteger((cosmeticOption.changedCvar), 1);
|
||||
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.
|
||||
@ -1671,7 +1469,89 @@ void RandomizeColor(CosmeticOption& cosmeticOption) {
|
||||
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);
|
||||
newColor.g = Random(0, 255);
|
||||
newColor.b = Random(0, 255);
|
||||
newColor.a = 255;
|
||||
// For alpha supported options, retain the last set alpha instead of overwriting
|
||||
if (cosmeticOption.supportsAlpha) {
|
||||
newColor.a = cosmeticOption.currentColor.w * 255;
|
||||
}
|
||||
|
||||
cosmeticOption.currentColor.x = newColor.r / 255.0;
|
||||
cosmeticOption.currentColor.y = newColor.g / 255.0;
|
||||
cosmeticOption.currentColor.z = newColor.b / 255.0;
|
||||
cosmeticOption.currentColor.w = newColor.a / 255.0;
|
||||
|
||||
CVarSetColor(cosmeticOption.cvar, newColor);
|
||||
CVarSetInteger((cosmeticOption.rainbowCvar), 0);
|
||||
CVarSetInteger((cosmeticOption.changedCvar), 1);
|
||||
ApplySideEffects(cosmeticOption);
|
||||
}
|
||||
|
||||
void ResetColor(CosmeticOption& cosmeticOption) {
|
||||
@ -1691,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"));
|
||||
@ -1707,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"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,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();
|
||||
}
|
||||
@ -1744,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();
|
||||
}
|
||||
@ -1800,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;
|
||||
|
@ -55,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
|
||||
|
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
|
@ -9,7 +9,6 @@
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <libultraship/libultraship.h>
|
||||
#include "dlViewer.h"
|
||||
|
||||
@ -66,16 +65,14 @@ std::map<int, std::string> cmdMap = {
|
||||
};
|
||||
|
||||
void PerformDisplayListSearch() {
|
||||
auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*" + std::string(searchString) + "*DL*");
|
||||
|
||||
std::regex dlSearch(".*((DL)|(DL_.*))$");
|
||||
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 (std::regex_search(val.c_str(), dlSearch)) {
|
||||
if (val.ends_with("DL") || val.find("DL_") != std::string::npos) {
|
||||
displayListSearchResults.push_back(val);
|
||||
}
|
||||
}
|
||||
@ -99,8 +96,6 @@ void DLViewerWindow::DrawElement() {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("%d", searchDebounceFrames);
|
||||
|
||||
// Debounce the search field as listing otr files is expensive
|
||||
if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) {
|
||||
doSearch = true;
|
||||
@ -134,7 +129,7 @@ void DLViewerWindow::DrawElement() {
|
||||
try {
|
||||
auto res = std::static_pointer_cast<LUS::DisplayList>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(activeDisplayList));
|
||||
|
||||
if (res->GetInitData()->Type != LUS::ResourceType::DisplayList) {
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -37,12 +37,19 @@ GameInteractionEffectQueryResult GameInteractor::RemoveEffect(RemovableGameInter
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
bool GameInteractor::IsSaveLoaded() {
|
||||
bool GameInteractor::IsSaveLoaded(bool allowDbgSave) {
|
||||
Player* player;
|
||||
if (gPlayState != NULL) {
|
||||
player = GET_PLAYER(gPlayState);
|
||||
}
|
||||
return (gPlayState == NULL || player == NULL || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) ? false : true;
|
||||
|
||||
// Checking for normal game mode prevents debug saves from reporting true on title screen
|
||||
if (gPlayState == NULL || player == NULL || gSaveContext.gameMode != GAMEMODE_NORMAL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Valid save file or debug save
|
||||
return (gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2) || (allowDbgSave && gSaveContext.fileNum == 0xFF);
|
||||
}
|
||||
|
||||
bool GameInteractor::IsGameplayPaused() {
|
||||
|
@ -163,11 +163,30 @@ public:
|
||||
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)...);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,9 +240,10 @@ public:
|
||||
|
||||
DEFINE_HOOK(OnFileDropped, void(std::string filePath));
|
||||
DEFINE_HOOK(OnAssetAltChange, void());
|
||||
DEFINE_HOOK(OnKaleidoUpdate, void());
|
||||
|
||||
// Helpers
|
||||
static bool IsSaveLoaded();
|
||||
static bool IsSaveLoaded(bool allowDbgSave = false);
|
||||
static bool IsGameplayPaused();
|
||||
static bool CanSpawnActor();
|
||||
static bool CanAddOrTakeAmmo(int16_t amount, int16_t item);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "src/overlays/actors/ovl_En_Tp/z_en_tp.h"
|
||||
#include "src/overlays/actors/ovl_En_Firefly/z_en_firefly.h"
|
||||
#include "src/overlays/actors/ovl_En_Xc/z_en_xc.h"
|
||||
#include "src/overlays/actors/ovl_Obj_Switch/z_obj_switch.h"
|
||||
#include "objects/object_link_boy/object_link_boy.h"
|
||||
#include "objects/object_link_child/object_link_child.h"
|
||||
|
||||
@ -33,6 +34,7 @@ extern "C" {
|
||||
#include "functions.h"
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
|
||||
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
|
||||
|
||||
@ -63,7 +65,7 @@ void ReloadSceneTogglingLinkAge() {
|
||||
|
||||
void RegisterInfiniteMoney() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
|
||||
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
@ -74,7 +76,7 @@ void RegisterInfiniteMoney() {
|
||||
|
||||
void RegisterInfiniteHealth() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
|
||||
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
||||
gSaveContext.health = gSaveContext.healthCapacity;
|
||||
@ -85,7 +87,7 @@ void RegisterInfiniteHealth() {
|
||||
|
||||
void RegisterInfiniteAmmo() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
|
||||
// Deku Sticks
|
||||
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
||||
@ -122,7 +124,7 @@ void RegisterInfiniteAmmo() {
|
||||
|
||||
void RegisterInfiniteMagic() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
|
||||
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
|
||||
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
|
||||
@ -133,7 +135,7 @@ void RegisterInfiniteMagic() {
|
||||
|
||||
void RegisterInfiniteNayrusLove() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
|
||||
gSaveContext.nayrusLoveTimer = 0x44B;
|
||||
}
|
||||
@ -142,7 +144,7 @@ void RegisterInfiniteNayrusLove() {
|
||||
|
||||
void RegisterMoonJumpOnL() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
|
||||
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
@ -157,7 +159,7 @@ void RegisterMoonJumpOnL() {
|
||||
|
||||
void RegisterInfiniteISG() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
|
||||
if (CVarGetInteger("gEzISG", 0) != 0) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
@ -169,7 +171,7 @@ void RegisterInfiniteISG() {
|
||||
//Permanent quick put away (QPA) glitched damage value
|
||||
void RegisterEzQPA() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
|
||||
if (CVarGetInteger("gEzQPA", 0) != 0) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
@ -181,7 +183,7 @@ void RegisterEzQPA() {
|
||||
|
||||
void RegisterUnrestrictedItems() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
|
||||
if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
|
||||
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
|
||||
@ -209,11 +211,14 @@ void RegisterFreezeTime() {
|
||||
/// Switches Link's age and respawns him at the last entrance he entered.
|
||||
void RegisterSwitchAge() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
static bool warped = false;
|
||||
|
||||
if (!GameInteractor::IsSaveLoaded(true)) {
|
||||
CVarClear("gSwitchAge");
|
||||
warped = false;
|
||||
return;
|
||||
}
|
||||
static bool warped = false;
|
||||
|
||||
static Vec3f playerPos;
|
||||
static int16_t playerYaw;
|
||||
static RoomContext* roomCtx;
|
||||
@ -247,7 +252,7 @@ void RegisterSwitchAge() {
|
||||
void RegisterOcarinaTimeTravel() {
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOcarinaSongAction>([]() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
if (!GameInteractor::IsSaveLoaded(true)) {
|
||||
CVarClear("gTimeTravel");
|
||||
return;
|
||||
}
|
||||
@ -518,8 +523,20 @@ void RegisterDaytimeGoldSkultullas() {
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterHyperBosses() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
|
||||
bool IsHyperBossesActive() {
|
||||
return CVarGetInteger("gHyperBosses", 0) ||
|
||||
(IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES);
|
||||
}
|
||||
|
||||
void UpdateHyperBossesState() {
|
||||
static uint32_t actorUpdateHookId = 0;
|
||||
if (actorUpdateHookId != 0) {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(actorUpdateHookId);
|
||||
actorUpdateHookId = 0;
|
||||
}
|
||||
|
||||
if (IsHyperBossesActive()) {
|
||||
actorUpdateHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
|
||||
// Run the update function a second time to make bosses move and act twice as fast.
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
@ -541,13 +558,8 @@ void RegisterHyperBosses() {
|
||||
actor->id == ACTOR_BOSS_GANON || // Ganondorf
|
||||
actor->id == ACTOR_BOSS_GANON2; // Ganon
|
||||
|
||||
uint8_t hyperBossesActive =
|
||||
CVarGetInteger("gHyperBosses", 0) ||
|
||||
(IS_BOSS_RUSH &&
|
||||
gSaveContext.bossRushOptions[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES);
|
||||
|
||||
// Don't apply during cutscenes because it causes weird behaviour and/or crashes on some bosses.
|
||||
if (hyperBossesActive && isBossActor && !Player_InBlockingCsMode(gPlayState, player)) {
|
||||
if (IsHyperBossesActive() && isBossActor && !Player_InBlockingCsMode(gPlayState, player)) {
|
||||
// Barinade needs to be updated in sequence to avoid unintended behaviour.
|
||||
if (actor->id == ACTOR_BOSS_VA) {
|
||||
// params -1 is BOSSVA_BODY
|
||||
@ -563,10 +575,25 @@ void RegisterHyperBosses() {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterHyperEnemies() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
|
||||
void RegisterHyperBosses() {
|
||||
UpdateHyperBossesState();
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int16_t fileNum) {
|
||||
UpdateHyperBossesState();
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateHyperEnemiesState() {
|
||||
static uint32_t actorUpdateHookId = 0;
|
||||
if (actorUpdateHookId != 0) {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(actorUpdateHookId);
|
||||
actorUpdateHookId = 0;
|
||||
}
|
||||
|
||||
if (CVarGetInteger("gHyperEnemies", 0)) {
|
||||
actorUpdateHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
|
||||
// Run the update function a second time to make enemies and minibosses move and act twice as fast.
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
@ -582,6 +609,7 @@ void RegisterHyperEnemies() {
|
||||
GameInteractor::RawAction::UpdateActor(actor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterBonkDamage() {
|
||||
@ -1259,6 +1287,34 @@ void RegisterRandomizedEnemySizes() {
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterOpenAllHours() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
if (CVarGetInteger("gEnhancements.OpenAllHours", 0) && (actor->id == ACTOR_EN_DOOR)) {
|
||||
switch (actor->params) {
|
||||
case 4753: // Night Market Bazaar
|
||||
case 1678: // Night Potion Shop
|
||||
case 2689: // Day Bombchu Shop
|
||||
case 2703: // Night Slingshot Game
|
||||
case 653: // Day Chest Game
|
||||
case 6801: // Night Kak Bazaar
|
||||
case 7822: // Night Kak Potion Shop
|
||||
case 4751: // Night Kak Archery Game
|
||||
case 3728: // Night Mask Shop
|
||||
{
|
||||
actor->params = (actor->params & 0xFC00) | (DOOR_SCENEEXIT << 7) | 0x3F;
|
||||
EnDoor* enDoor = static_cast<EnDoor*>(refActor);
|
||||
EnDoor_SetupType(enDoor, gPlayState);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PatchToTMedallions() {
|
||||
// TODO: Refactor the DemoEffect_UpdateJewelAdult and DemoEffect_UpdateJewelChild from z_demo_effect
|
||||
// effects to take effect in there
|
||||
@ -1341,6 +1397,40 @@ void RegisterToTMedallions() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void RegisterFloorSwitchesHook() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
if (actor->id != ACTOR_OBJ_SWITCH || !CVarGetInteger("gEnhancements.FixFloorSwitches", 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ObjSwitch* switchActor = reinterpret_cast<ObjSwitch*>(actor);
|
||||
s32 type = (switchActor->dyna.actor.params & 7);
|
||||
|
||||
if (switchActor->dyna.actor.params == 0x1200 || switchActor->dyna.actor.params == 0x3A00) {
|
||||
switchActor->dyna.actor.world.pos.y -= 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterPauseMenuHooks() {
|
||||
static bool pauseWarpHooksRegistered = false;
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([&]() {
|
||||
if (!GameInteractor::IsSaveLoaded() || !CVarGetInteger("gPauseWarp", 0)) {
|
||||
pauseWarpHooksRegistered = false;
|
||||
return;
|
||||
}
|
||||
if (!pauseWarpHooksRegistered) {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnKaleidoUpdate>([]() {PauseWarp_HandleSelection();});
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
PauseWarp_Execute();
|
||||
});
|
||||
pauseWarpHooksRegistered = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InitMods() {
|
||||
RegisterTTS();
|
||||
RegisterInfiniteMoney();
|
||||
@ -1362,7 +1452,7 @@ void InitMods() {
|
||||
RegisterPermanentHeartLoss();
|
||||
RegisterDeleteFileOnDeath();
|
||||
RegisterHyperBosses();
|
||||
RegisterHyperEnemies();
|
||||
UpdateHyperEnemiesState();
|
||||
RegisterBonkDamage();
|
||||
RegisterMenuPathFix();
|
||||
RegisterMirrorModeHandler();
|
||||
@ -1373,10 +1463,13 @@ void InitMods() {
|
||||
RegisterAltTrapTypes();
|
||||
RegisterRandomizerSheikSpawn();
|
||||
RegisterRandomizedEnemySizes();
|
||||
RegisterOpenAllHours();
|
||||
RegisterToTMedallions();
|
||||
NameTag_RegisterHooks();
|
||||
RegisterPatchChildHylianShieldHandler();
|
||||
RegisterChildHylianShielStatedHandler();
|
||||
RegisterFloorSwitchesHook();
|
||||
RegisterPatchHandHandler();
|
||||
RegisterHurtContainerModeHandler();
|
||||
RegisterPauseMenuHooks();
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ void UpdateMirrorModeState(int32_t sceneNum);
|
||||
void UpdateHurtContainerModeState(bool newState);
|
||||
void PatchToTMedallions();
|
||||
void UpdatePermanentHeartLossState();
|
||||
void UpdateHyperEnemiesState();
|
||||
void UpdateHyperBossesState();
|
||||
void InitMods();
|
||||
void UpdatePatchChildHylianShield();
|
||||
void UpdateChildHylianShieldState();
|
||||
|
92
soh/soh/Enhancements/pausewarp.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include "custom-message/CustomMessageTypes.h"
|
||||
#include "global.h"
|
||||
#include "z64.h"
|
||||
#include "game-interactor/GameInteractor.h"
|
||||
|
||||
static const int songMessageMap[] = {
|
||||
TEXT_WARP_MINUET_OF_FOREST,
|
||||
TEXT_WARP_BOLERO_OF_FIRE,
|
||||
TEXT_WARP_SERENADE_OF_WATER,
|
||||
TEXT_WARP_REQUIEM_OF_SPIRIT,
|
||||
TEXT_WARP_NOCTURNE_OF_SHADOW,
|
||||
TEXT_WARP_PRELUDE_OF_LIGHT
|
||||
};
|
||||
|
||||
static const int ocarinaSongMap[] = {
|
||||
OCARINA_SONG_MINUET,
|
||||
OCARINA_SONG_BOLERO,
|
||||
OCARINA_SONG_SERENADE,
|
||||
OCARINA_SONG_REQUIEM,
|
||||
OCARINA_SONG_NOCTURNE,
|
||||
OCARINA_SONG_PRELUDE
|
||||
};
|
||||
|
||||
static const int entranceIndexMap[] = {
|
||||
ENTR_SACRED_FOREST_MEADOW_2, // Minuet
|
||||
ENTR_DEATH_MOUNTAIN_CRATER_4, // Bolero
|
||||
ENTR_LAKE_HYLIA_8, // Serenade
|
||||
ENTR_DESERT_COLOSSUS_5, // Requiem
|
||||
ENTR_GRAVEYARD_7, // Nocturne
|
||||
ENTR_TEMPLE_OF_TIME_7 // Prelude
|
||||
};
|
||||
|
||||
static const int songAudioMap[] = {
|
||||
NA_BGM_OCA_MINUET,
|
||||
NA_BGM_OCA_BOLERO,
|
||||
NA_BGM_OCA_SERENADE,
|
||||
NA_BGM_OCA_REQUIEM,
|
||||
NA_BGM_OCA_NOCTURNE,
|
||||
NA_BGM_OCA_LIGHT
|
||||
};
|
||||
|
||||
static bool isWarpActive = false;
|
||||
|
||||
void PauseWarp_Execute() {
|
||||
if (!isWarpActive || gPlayState->msgCtx.msgMode != MSGMODE_NONE) {
|
||||
return;
|
||||
}
|
||||
isWarpActive = false;
|
||||
GET_PLAYER(gPlayState)->stateFlags1 &= ~PLAYER_STATE1_IN_CUTSCENE;
|
||||
if (gPlayState->msgCtx.choiceIndex != 0) {
|
||||
return;
|
||||
}
|
||||
if (IS_RANDO) {
|
||||
Entrance_SetWarpSongEntrance();
|
||||
return;
|
||||
}
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_WHITE_FAST;
|
||||
for (int i = 0; i < ARRAY_COUNT(ocarinaSongMap); i++) {
|
||||
if (gPlayState->msgCtx.lastPlayedSong == ocarinaSongMap[i]) {
|
||||
gPlayState->nextEntranceIndex = entranceIndexMap[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_OFF;
|
||||
}
|
||||
|
||||
void ActivateWarp(PauseContext* pauseCtx, int song) {
|
||||
Audio_OcaSetInstrument(0);
|
||||
Interface_SetDoAction(gPlayState, DO_ACTION_NONE);
|
||||
pauseCtx->state = 0x12;
|
||||
WREG(2) = -6240;
|
||||
func_800F64E0(0);
|
||||
pauseCtx->unk_1E4 = 0;
|
||||
int idx = song - QUEST_SONG_MINUET;
|
||||
gPlayState->msgCtx.lastPlayedSong = ocarinaSongMap[idx];
|
||||
Audio_SetSoundBanksMute(0x20);
|
||||
Audio_PlayFanfare(songAudioMap[idx]);
|
||||
Message_StartTextbox(gPlayState, songMessageMap[idx], NULL);
|
||||
GET_PLAYER(gPlayState)->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE;
|
||||
isWarpActive = true;
|
||||
}
|
||||
|
||||
void PauseWarp_HandleSelection() {
|
||||
if (gSaveContext.inventory.items[SLOT_OCARINA] != ITEM_NONE) {
|
||||
int aButtonPressed = CHECK_BTN_ALL(gPlayState->state.input->press.button, BTN_A);
|
||||
int song = gPlayState->pauseCtx.cursorPoint[PAUSE_QUEST];
|
||||
if (aButtonPressed && CHECK_QUEST_ITEM(song) && song >= QUEST_SONG_MINUET && song <= QUEST_SONG_PRELUDE) {
|
||||
ActivateWarp(&gPlayState->pauseCtx, song);
|
||||
}
|
||||
}
|
||||
}
|
@ -262,6 +262,24 @@ const std::vector<const char*> enhancementsCvars = {
|
||||
"gToTMedallionsColors",
|
||||
"gEnhancements.ChildHoldsHylianShield",
|
||||
"gEnhancements.RotateScaleChildHylianShield",
|
||||
"gCuccoStayDurationMultiplier",
|
||||
"gDeleteFileOnDeath",
|
||||
"gEnemySizeScalesHealth",
|
||||
"gEnhancements.BetterAmmoRendering",
|
||||
"gEnhancements.EquimentAlwaysVisible",
|
||||
"gEnhancements.FixDaruniaDanceSpeed",
|
||||
"gEnhancements.OpenAllHours",
|
||||
"gEnhancements.ResetNaviTimer",
|
||||
"gEnhancements.ScaleAdultEquimentAsChild",
|
||||
"gEnhancements.LeeverSpawnRate",
|
||||
"gEnhancements.SwordToggle",
|
||||
"gEnhancements.FixFloorSwitches",
|
||||
"gFixZoraHintDialogue",
|
||||
"gHurtContainer",
|
||||
"gPauseWarp",
|
||||
"gPermanentHeartLoss",
|
||||
"gRemoveExplosiveLimit",
|
||||
"gToggleStrength",
|
||||
};
|
||||
|
||||
const std::vector<const char*> cheatCvars = {
|
||||
@ -314,6 +332,7 @@ const std::vector<const char*> cheatCvars = {
|
||||
"gSwitchAge",
|
||||
"gSwitchTimeline",
|
||||
"gNoRedeadFreeze",
|
||||
"gNoKeeseGuayTarget",
|
||||
"gBombTimerMultiplier",
|
||||
"gNoFishDespawn",
|
||||
"gNoBugsDespawn",
|
||||
@ -333,6 +352,7 @@ const std::vector<const char*> cheatCvars = {
|
||||
"gCosmetics.Link_HeadScale.Value",
|
||||
"gCosmetics.Link_SwordScale.Changed",
|
||||
"gCosmetics.Link_SwordScale.Value",
|
||||
"gEnhancements.RememberMapToggleState",
|
||||
};
|
||||
|
||||
const std::vector<const char*> randomizerCvars = {
|
||||
@ -527,6 +547,8 @@ const std::vector<PresetEntry> vanillaPlusPresetEntries = {
|
||||
PRESET_ENTRY_S32("gNaviTextFix", 1),
|
||||
// Extend Silver Rupee Jingle
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
// Fix some Floor Switches
|
||||
PRESET_ENTRY_S32("gEnhancements.FixFloorSwitches", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
@ -598,6 +620,8 @@ const std::vector<PresetEntry> enhancedPresetEntries = {
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
// Fix enemies not spawning on ground over water
|
||||
PRESET_ENTRY_S32("gEnemySpawnsOverWaterboxes", 1),
|
||||
// Fix some Floor Switches
|
||||
PRESET_ENTRY_S32("gEnhancements.FixFloorSwitches", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
@ -720,6 +744,8 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
PRESET_ENTRY_S32("gNaviTextFix", 1),
|
||||
// Extend Silver Rupee Jingle
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
// Fix some Floor Switches
|
||||
PRESET_ENTRY_S32("gEnhancements.FixFloorSwitches", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
|
@ -26,7 +26,6 @@ typedef struct {
|
||||
AreaKey parentRegion;
|
||||
AreaKey connectedRegion;
|
||||
int16_t index;
|
||||
int16_t blueWarp;
|
||||
} EntranceLinkInfo;
|
||||
|
||||
EntranceLinkInfo NO_RETURN_ENTRANCE = {EntranceType::None, NONE, NONE, -1};
|
||||
@ -40,6 +39,11 @@ using EntranceInfoPair = std::pair<EntranceLinkInfo, EntranceLinkInfo>;
|
||||
using EntrancePair = std::pair<Entrance*, Entrance*>;
|
||||
using EntrancePools = std::map<EntranceType, std::vector<Entrance*>>;
|
||||
|
||||
// Construct entrance name from parent and connected region keys
|
||||
std::string EntranceNameByRegions(uint32_t parentRegion, uint32_t connectedRegion) {
|
||||
return AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName;
|
||||
}
|
||||
|
||||
//The entrance randomization algorithm used here is a direct copy of
|
||||
//the algorithm used in the original N64 randomizer (except now in C++ instead
|
||||
//of python). It may be easier to understand the algorithm by looking at the
|
||||
@ -77,26 +81,22 @@ void SetAllEntrancesData(std::vector<EntranceInfoPair>& entranceShuffleTable) {
|
||||
//set data
|
||||
Entrance* forwardEntrance = AreaTable(forwardEntry.parentRegion)->GetExit(forwardEntry.connectedRegion);
|
||||
forwardEntrance->SetIndex(forwardEntry.index);
|
||||
forwardEntrance->SetBlueWarp(forwardEntry.blueWarp);
|
||||
forwardEntrance->SetType(forwardEntry.type);
|
||||
forwardEntrance->SetAsPrimary();
|
||||
|
||||
// When decouple entrances is on, mark it for entrances except boss rooms
|
||||
if (Settings::DecoupleEntrances && forwardEntry.type != EntranceType::ChildBoss &&
|
||||
forwardEntry.type != EntranceType::AdultBoss) {
|
||||
// When decouple entrances is on, mark the forward entrance
|
||||
if (Settings::DecoupleEntrances) {
|
||||
forwardEntrance->SetDecoupled();
|
||||
}
|
||||
|
||||
if (returnEntry.parentRegion != NONE) {
|
||||
Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion);
|
||||
returnEntrance->SetIndex(returnEntry.index);
|
||||
returnEntrance->SetBlueWarp(returnEntry.blueWarp);
|
||||
returnEntrance->SetType(returnEntry.type);
|
||||
forwardEntrance->BindTwoWay(returnEntrance);
|
||||
|
||||
// Mark reverse entrance as decoupled
|
||||
if (Settings::DecoupleEntrances && returnEntry.type != EntranceType::ChildBoss &&
|
||||
returnEntry.type != EntranceType::AdultBoss) {
|
||||
if (Settings::DecoupleEntrances) {
|
||||
returnEntrance->SetDecoupled();
|
||||
}
|
||||
}
|
||||
@ -687,23 +687,23 @@ int ShuffleAllEntrances() {
|
||||
curNumRandomizedEntrances = 0;
|
||||
|
||||
std::vector<EntranceInfoPair> entranceShuffleTable = {
|
||||
//Parent Region Connected Region index blue warp
|
||||
//Parent Region Connected Region index
|
||||
{{EntranceType::Dungeon, KF_OUTSIDE_DEKU_TREE, DEKU_TREE_ENTRYWAY, 0x0000},
|
||||
{EntranceType::Dungeon, DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE, 0x0209, 0x0457}},
|
||||
{EntranceType::Dungeon, DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE, 0x0209}},
|
||||
{{EntranceType::Dungeon, DEATH_MOUNTAIN_TRAIL, DODONGOS_CAVERN_ENTRYWAY, 0x0004},
|
||||
{EntranceType::Dungeon, DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL, 0x0242, 0x047A}},
|
||||
{EntranceType::Dungeon, DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL, 0x0242}},
|
||||
{{EntranceType::Dungeon, ZORAS_FOUNTAIN, JABU_JABUS_BELLY_ENTRYWAY, 0x0028},
|
||||
{EntranceType::Dungeon, JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN, 0x0221, 0x010E}},
|
||||
{EntranceType::Dungeon, JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN, 0x0221}},
|
||||
{{EntranceType::Dungeon, SACRED_FOREST_MEADOW, FOREST_TEMPLE_ENTRYWAY, 0x0169},
|
||||
{EntranceType::Dungeon, FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW, 0x0215, 0x0608}},
|
||||
{EntranceType::Dungeon, FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW, 0x0215}},
|
||||
{{EntranceType::Dungeon, DMC_CENTRAL_LOCAL, FIRE_TEMPLE_ENTRYWAY, 0x0165},
|
||||
{EntranceType::Dungeon, FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL, 0x024A, 0x0564}},
|
||||
{EntranceType::Dungeon, FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL, 0x024A}},
|
||||
{{EntranceType::Dungeon, LAKE_HYLIA, WATER_TEMPLE_ENTRYWAY, 0x0010},
|
||||
{EntranceType::Dungeon, WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA, 0x021D, 0x060C}},
|
||||
{EntranceType::Dungeon, WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA, 0x021D}},
|
||||
{{EntranceType::Dungeon, DESERT_COLOSSUS, SPIRIT_TEMPLE_ENTRYWAY, 0x0082},
|
||||
{EntranceType::Dungeon, SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY, 0x01E1, 0x0610}},
|
||||
{EntranceType::Dungeon, SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY, 0x01E1}},
|
||||
{{EntranceType::Dungeon, GRAVEYARD_WARP_PAD_REGION, SHADOW_TEMPLE_ENTRYWAY, 0x0037},
|
||||
{EntranceType::Dungeon, SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION, 0x0205, 0x0580}},
|
||||
{EntranceType::Dungeon, SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION, 0x0205}},
|
||||
{{EntranceType::Dungeon, KAKARIKO_VILLAGE, BOTTOM_OF_THE_WELL_ENTRYWAY, 0x0098},
|
||||
{EntranceType::Dungeon, BOTTOM_OF_THE_WELL_ENTRYWAY, KAKARIKO_VILLAGE, 0x02A6}},
|
||||
{{EntranceType::Dungeon, ZORAS_FOUNTAIN, ICE_CAVERN_ENTRYWAY, 0x0088},
|
||||
@ -947,21 +947,30 @@ int ShuffleAllEntrances() {
|
||||
{{EntranceType::WarpSong, PRELUDE_OF_LIGHT_WARP, TEMPLE_OF_TIME, 0x05F4}, NO_RETURN_ENTRANCE},
|
||||
|
||||
{{EntranceType::ChildBoss, DEKU_TREE_BOSS_ENTRYWAY, DEKU_TREE_BOSS_ROOM, 0x040F},
|
||||
{EntranceType::ChildBoss, DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY, 0x0252, 0x0457}},
|
||||
{EntranceType::ChildBoss, DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY, 0x0252}},
|
||||
{{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ENTRYWAY, DODONGOS_CAVERN_BOSS_ROOM, 0x040B},
|
||||
{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY, 0x00C5, 0x047A}},
|
||||
{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY, 0x00C5}},
|
||||
{{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ENTRYWAY, JABU_JABUS_BELLY_BOSS_ROOM, 0x0301},
|
||||
{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY, 0x0407, 0x010E}},
|
||||
{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY, 0x0407}},
|
||||
{{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ENTRYWAY, FOREST_TEMPLE_BOSS_ROOM, 0x000C},
|
||||
{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY, 0x024E, 0x0608}},
|
||||
{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY, 0x024E}},
|
||||
{{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ENTRYWAY, FIRE_TEMPLE_BOSS_ROOM, 0x0305},
|
||||
{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY, 0x0175, 0x0564}},
|
||||
{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY, 0x0175}},
|
||||
{{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ENTRYWAY, WATER_TEMPLE_BOSS_ROOM, 0x0417},
|
||||
{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY, 0x0423, 0x060C}},
|
||||
{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY, 0x0423}},
|
||||
{{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ENTRYWAY, SPIRIT_TEMPLE_BOSS_ROOM, 0x008D},
|
||||
{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY, 0x02F5, 0x0610}},
|
||||
{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY, 0x02F5}},
|
||||
{{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ENTRYWAY, SHADOW_TEMPLE_BOSS_ROOM, 0x0413},
|
||||
{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY, 0x02B2, 0x0580}},
|
||||
{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY, 0x02B2}},
|
||||
|
||||
{{EntranceType::BlueWarp, DEKU_TREE_BOSS_ROOM, KF_OUTSIDE_DEKU_TREE, 0x0457}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, DODONGOS_CAVERN_BOSS_ROOM, DEATH_MOUNTAIN_TRAIL, 0x047A}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, JABU_JABUS_BELLY_BOSS_ROOM, ZORAS_FOUNTAIN, 0x010E}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, FOREST_TEMPLE_BOSS_ROOM, SACRED_FOREST_MEADOW, 0x0608}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, FIRE_TEMPLE_BOSS_ROOM, DMC_CENTRAL_LOCAL, 0x0564}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, WATER_TEMPLE_BOSS_ROOM, LAKE_HYLIA, 0x060C}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, SPIRIT_TEMPLE_BOSS_ROOM, DESERT_COLOSSUS, 0x0610}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::BlueWarp, SHADOW_TEMPLE_BOSS_ROOM, GRAVEYARD_WARP_PAD_REGION, 0x0580}, NO_RETURN_ENTRANCE},
|
||||
};
|
||||
|
||||
std::map<std::string, PriorityEntrance> priorityEntranceTable = {
|
||||
@ -1011,6 +1020,11 @@ int ShuffleAllEntrances() {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::Boss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;});
|
||||
}
|
||||
if (Settings::DecoupleEntrances) {
|
||||
for (Entrance* entrance : entrancePools[EntranceType::Boss]) {
|
||||
entrancePools[EntranceType::BossReverse].push_back(entrance->GetReverse());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss);
|
||||
entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss);
|
||||
@ -1019,6 +1033,14 @@ int ShuffleAllEntrances() {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::ChildBoss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;});
|
||||
}
|
||||
if (Settings::DecoupleEntrances) {
|
||||
for (Entrance* entrance : entrancePools[EntranceType::ChildBoss]) {
|
||||
entrancePools[EntranceType::ChildBossReverse].push_back(entrance->GetReverse());
|
||||
}
|
||||
for (Entrance* entrance : entrancePools[EntranceType::AdultBoss]) {
|
||||
entrancePools[EntranceType::AdultBossReverse].push_back(entrance->GetReverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1082,10 +1104,13 @@ int ShuffleAllEntrances() {
|
||||
SetShuffledEntrances(oneWayEntrancePools);
|
||||
|
||||
//combine entrance pools if mixing pools. Only continue if more than one pool is selected.
|
||||
int totalMixedPools = (Settings::MixDungeons ? 1 : 0) + (Settings::MixOverworld ? 1 : 0) + (Settings::MixInteriors ? 1 : 0) + (Settings::MixGrottos ? 1 : 0);
|
||||
int totalMixedPools = (Settings::MixDungeons ? 1 : 0) + (Settings::MixBosses ? 1 : 0) +
|
||||
(Settings::MixOverworld ? 1 : 0) + (Settings::MixInteriors ? 1 : 0) +
|
||||
(Settings::MixGrottos ? 1 : 0);
|
||||
if (totalMixedPools < 2) {
|
||||
Settings::MixedEntrancePools.SetSelectedIndex(OFF);
|
||||
Settings::MixDungeons.SetSelectedIndex(OFF);
|
||||
Settings::MixBosses.SetSelectedIndex(OFF);
|
||||
Settings::MixOverworld.SetSelectedIndex(OFF);
|
||||
Settings::MixInteriors.SetSelectedIndex(OFF);
|
||||
Settings::MixGrottos.SetSelectedIndex(OFF);
|
||||
@ -1099,6 +1124,12 @@ int ShuffleAllEntrances() {
|
||||
poolsToMix.insert(EntranceType::DungeonReverse);
|
||||
}
|
||||
}
|
||||
if (Settings::MixBosses) {
|
||||
poolsToMix.insert(EntranceType::Boss);
|
||||
if (Settings::DecoupleEntrances) {
|
||||
poolsToMix.insert(EntranceType::BossReverse);
|
||||
}
|
||||
}
|
||||
if (Settings::MixOverworld) {
|
||||
poolsToMix.insert(EntranceType::Overworld);
|
||||
}
|
||||
@ -1232,6 +1263,87 @@ int ShuffleAllEntrances() {
|
||||
}
|
||||
}
|
||||
|
||||
// Determine blue warp targets
|
||||
if (true /* Settings.BlueWarps.Is(BLUEWARPS_DUNGEON) */) { // RANDOTODO: add bluewarp shuffle
|
||||
// If a boss room is inside a boss door, make the blue warp go outside the dungeon's entrance
|
||||
std::map<std::string, Entrance*> bossExits = {
|
||||
{ EntranceNameByRegions(DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE)) },
|
||||
{ EntranceNameByRegions(DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL)) },
|
||||
{ EntranceNameByRegions(JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN)) },
|
||||
{ EntranceNameByRegions(FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW)) },
|
||||
{ EntranceNameByRegions(FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL)) },
|
||||
{ EntranceNameByRegions(WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA)) },
|
||||
{ EntranceNameByRegions(SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY)) },
|
||||
{ EntranceNameByRegions(SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION)) },
|
||||
};
|
||||
|
||||
// If a boss room is inside a dungeon entrance (or inside a dungeon which is inside a dungeon entrance), make the blue warp go to that dungeon's blue warp target
|
||||
std::map<std::string, Entrance*> dungeonExits = {
|
||||
{ EntranceNameByRegions(DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE),
|
||||
GetEntrance(EntranceNameByRegions(DEKU_TREE_BOSS_ROOM, KF_OUTSIDE_DEKU_TREE)) },
|
||||
{ EntranceNameByRegions(DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL),
|
||||
GetEntrance(EntranceNameByRegions(DODONGOS_CAVERN_BOSS_ROOM, DEATH_MOUNTAIN_TRAIL)) },
|
||||
{ EntranceNameByRegions(JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN),
|
||||
GetEntrance(EntranceNameByRegions(JABU_JABUS_BELLY_BOSS_ROOM, ZORAS_FOUNTAIN)) },
|
||||
{ EntranceNameByRegions(FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW),
|
||||
GetEntrance(EntranceNameByRegions(FOREST_TEMPLE_BOSS_ROOM, SACRED_FOREST_MEADOW)) },
|
||||
{ EntranceNameByRegions(FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL),
|
||||
GetEntrance(EntranceNameByRegions(FIRE_TEMPLE_BOSS_ROOM, DMC_CENTRAL_LOCAL)) },
|
||||
{ EntranceNameByRegions(WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA),
|
||||
GetEntrance(EntranceNameByRegions(WATER_TEMPLE_BOSS_ROOM, LAKE_HYLIA)) },
|
||||
{ EntranceNameByRegions(SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY),
|
||||
GetEntrance(EntranceNameByRegions(SPIRIT_TEMPLE_BOSS_ROOM, DESERT_COLOSSUS)) },
|
||||
{ EntranceNameByRegions(SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION),
|
||||
GetEntrance(EntranceNameByRegions(SHADOW_TEMPLE_BOSS_ROOM, GRAVEYARD_WARP_PAD_REGION)) },
|
||||
};
|
||||
|
||||
// Pair <BlueWarp exit, BossRoom reverse exit>
|
||||
std::vector<EntrancePair> bossRoomExitPairs = {
|
||||
{ GetEntrance(EntranceNameByRegions(DEKU_TREE_BOSS_ROOM, KF_OUTSIDE_DEKU_TREE)),
|
||||
GetEntrance(EntranceNameByRegions(DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(DODONGOS_CAVERN_BOSS_ROOM, DEATH_MOUNTAIN_TRAIL)),
|
||||
GetEntrance(EntranceNameByRegions(DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(JABU_JABUS_BELLY_BOSS_ROOM, ZORAS_FOUNTAIN)),
|
||||
GetEntrance(EntranceNameByRegions(JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(FOREST_TEMPLE_BOSS_ROOM, SACRED_FOREST_MEADOW)),
|
||||
GetEntrance(EntranceNameByRegions(FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(FIRE_TEMPLE_BOSS_ROOM, DMC_CENTRAL_LOCAL)),
|
||||
GetEntrance(EntranceNameByRegions(FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(WATER_TEMPLE_BOSS_ROOM, LAKE_HYLIA)),
|
||||
GetEntrance(EntranceNameByRegions(WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(SPIRIT_TEMPLE_BOSS_ROOM, DESERT_COLOSSUS)),
|
||||
GetEntrance(EntranceNameByRegions(SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY)) },
|
||||
{ GetEntrance(EntranceNameByRegions(SHADOW_TEMPLE_BOSS_ROOM, GRAVEYARD_WARP_PAD_REGION)),
|
||||
GetEntrance(EntranceNameByRegions(SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY)) },
|
||||
};
|
||||
|
||||
for (EntrancePair pair : bossRoomExitPairs) {
|
||||
Entrance* target = pair.second->GetReplacement() != nullptr ? pair.second->GetReplacement() : pair.second;
|
||||
|
||||
if (!Settings::DecoupleEntrances) {
|
||||
while (bossExits.find(target->GetName()) != bossExits.end()) {
|
||||
Entrance* next = bossExits.at(target->GetName());
|
||||
target = next->GetReplacement() != nullptr ? next->GetReplacement() : next;
|
||||
}
|
||||
|
||||
if (dungeonExits.find(target->GetName()) != dungeonExits.end()) {
|
||||
target = dungeonExits.at(target->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
pair.first->Connect(target->GetOriginalConnectedRegionKey());
|
||||
pair.first->SetReplacement(target);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the world one last time to ensure all special conditions are still valid
|
||||
if (!ValidateWorld(nullptr)) {
|
||||
return ENTRANCE_SHUFFLE_FAILURE;
|
||||
@ -1259,8 +1371,8 @@ void CreateEntranceOverrides() {
|
||||
auto message = "Setting " + entrance->to_string() + "\n";
|
||||
SPDLOG_DEBUG(message);
|
||||
|
||||
uint8_t type = (uint8_t)entrance->GetType();
|
||||
int16_t originalIndex = entrance->GetIndex();
|
||||
int16_t originalBlueWarp = entrance->GetBlueWarp();
|
||||
int16_t replacementIndex = entrance->GetReplacement()->GetIndex();
|
||||
|
||||
int16_t destinationIndex = -1;
|
||||
@ -1274,9 +1386,9 @@ void CreateEntranceOverrides() {
|
||||
}
|
||||
|
||||
entranceOverrides.push_back({
|
||||
.type = type,
|
||||
.index = originalIndex,
|
||||
.destination = destinationIndex,
|
||||
.blueWarp = originalBlueWarp,
|
||||
.override = replacementIndex,
|
||||
.overrideDestination = replacementDestinationIndex,
|
||||
});
|
||||
|
@ -18,12 +18,16 @@ enum class EntranceType {
|
||||
OwlDrop,
|
||||
Spawn,
|
||||
WarpSong,
|
||||
BlueWarp,
|
||||
Dungeon,
|
||||
GanonDungeon,
|
||||
DungeonReverse,
|
||||
Boss,
|
||||
BossReverse,
|
||||
ChildBoss,
|
||||
ChildBossReverse,
|
||||
AdultBoss,
|
||||
AdultBossReverse,
|
||||
Interior,
|
||||
InteriorReverse,
|
||||
SpecialInterior,
|
||||
@ -40,6 +44,7 @@ public:
|
||||
|
||||
Entrance(uint32_t connectedRegion_, std::vector<ConditionFn> conditions_met_)
|
||||
: connectedRegion(connectedRegion_) {
|
||||
originalConnectedRegion = connectedRegion_;
|
||||
conditions_met.resize(2);
|
||||
for (size_t i = 0; i < conditions_met_.size(); i++) {
|
||||
conditions_met[i] = conditions_met_[i];
|
||||
@ -134,6 +139,10 @@ public:
|
||||
return connectedRegion;
|
||||
}
|
||||
|
||||
uint32_t GetOriginalConnectedRegionKey() const {
|
||||
return originalConnectedRegion;
|
||||
}
|
||||
|
||||
Area* GetConnectedRegion() const {
|
||||
return AreaTable(connectedRegion);
|
||||
}
|
||||
@ -198,14 +207,6 @@ public:
|
||||
index = newIndex;
|
||||
}
|
||||
|
||||
int16_t GetBlueWarp() const {
|
||||
return blueWarp;
|
||||
}
|
||||
|
||||
void SetBlueWarp(int16_t newBlueWarp) {
|
||||
blueWarp = newBlueWarp;
|
||||
}
|
||||
|
||||
Entrance* GetAssumed() const {
|
||||
return assumed;
|
||||
}
|
||||
@ -251,7 +252,7 @@ public:
|
||||
AreaTable(ROOT)->AddExit(ROOT, connectedRegion, []{return true;});
|
||||
Entrance* targetEntrance = AreaTable(ROOT)->GetExit(connectedRegion);
|
||||
targetEntrance->SetReplacement(this);
|
||||
targetEntrance->SetName(GetParentRegion()->regionName + " -> " + GetConnectedRegion()->regionName);
|
||||
targetEntrance->SetName(AreaTable(ROOT)->regionName + " -> " + GetConnectedRegion()->regionName);
|
||||
return targetEntrance;
|
||||
}
|
||||
|
||||
@ -266,6 +267,7 @@ public:
|
||||
private:
|
||||
uint32_t parentRegion;
|
||||
uint32_t connectedRegion;
|
||||
uint32_t originalConnectedRegion;
|
||||
std::vector<ConditionFn> conditions_met;
|
||||
|
||||
//Entrance Randomizer stuff
|
||||
@ -275,7 +277,6 @@ private:
|
||||
Entrance* assumed = nullptr;
|
||||
Entrance* replacement = nullptr;
|
||||
int16_t index = 0xFFFF;
|
||||
int16_t blueWarp = 0;
|
||||
bool shuffled = false;
|
||||
bool primary = false;
|
||||
bool addedToPool = false;
|
||||
@ -285,6 +286,7 @@ private:
|
||||
|
||||
int ShuffleAllEntrances();
|
||||
void CreateEntranceOverrides();
|
||||
std::string EntranceNameByRegions(uint32_t parentRegion, uint32_t connectedRegion);
|
||||
|
||||
extern std::vector<std::list<Entrance*>> playthroughEntrances;
|
||||
extern bool noRandomEntrances;
|
||||
|
@ -294,7 +294,12 @@ std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowe
|
||||
}
|
||||
|
||||
// Add shuffled entrances to the entrance playthrough
|
||||
if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !noRandomEntrances) {
|
||||
// Include bluewarps when unshuffled but dungeon or boss shuffle is on
|
||||
if (mode == SearchMode::GeneratePlaythrough &&
|
||||
(exit.IsShuffled() || (exit.GetType() == EntranceType::BlueWarp &&
|
||||
(Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) ||
|
||||
Settings::ShuffleBossEntrances.IsNot(SHUFFLEBOSSES_OFF)))) &&
|
||||
!exit.IsAddedToPool() && !noRandomEntrances) {
|
||||
entranceSphere.push_back(&exit);
|
||||
exit.AddToPool();
|
||||
// Don't list a two-way coupled entrance from both directions
|
||||
|
@ -503,3 +503,16 @@ std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrima
|
||||
}
|
||||
return entrancesToShuffle;
|
||||
}
|
||||
|
||||
// Get the specific entrance by name
|
||||
Entrance* GetEntrance(const std::string name) {
|
||||
for (uint32_t area : Areas::GetAllAreas()) {
|
||||
for (auto& exit : AreaTable(area)->exits) {
|
||||
if (exit.GetName() == name) {
|
||||
return &exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -242,6 +242,7 @@ namespace Areas {
|
||||
void AreaTable_Init();
|
||||
Area* AreaTable(const uint32_t areaKey);
|
||||
std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary = true);
|
||||
Entrance* GetEntrance(const std::string name);
|
||||
|
||||
// Overworld
|
||||
void AreaTable_Init_LostWoods();
|
||||
|
@ -267,5 +267,6 @@ void AreaTable_Init_DekuTree() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(DEKU_TREE_BOSS_ENTRYWAY, { [] { return true; } }),
|
||||
Entrance(KF_OUTSIDE_DEKU_TREE, { [] { return DekuTreeClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -309,5 +309,6 @@ void AreaTable_Init_DodongosCavern() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(DODONGOS_CAVERN_BOSS_ENTRYWAY, { [] { return true; } }),
|
||||
Entrance(DEATH_MOUNTAIN_TRAIL, { [] { return DodongosCavernClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -420,5 +420,6 @@ void AreaTable_Init_FireTemple() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(DMC_CENTRAL_LOCAL, { [] { return FireTempleClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ void AreaTable_Init_ForestTemple() {
|
||||
Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}),
|
||||
Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && CanJumpslash && GoronBracelet);}}),
|
||||
Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
||||
Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
||||
Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return IsAdult && (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
||||
});
|
||||
|
||||
areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
||||
@ -433,5 +433,6 @@ void AreaTable_Init_ForestTemple() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(SACRED_FOREST_MEADOW, { [] { return ForestTempleClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -179,17 +179,17 @@ void AreaTable_Init_JabuJabusBelly() {
|
||||
//Locations
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, {[]{return (IsAdult && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT))) || ChildCanAccess(JABU_JABUS_BELLY_MQ_BOSS_AREA);}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_COMPASS_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_COMPASS_CHEST, {[]{return (IsChild || CanDive || CanUse(IRON_BOOTS) || LogicJabuAlcoveJumpDive) && (CanUse(SLINGSHOT) || CanUse(BOW) || CanUse(HOOKSHOT) || HasBombchus || (LogicJabuMQRangJump && CanUse(BOOMERANG)));}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, {[]{return CanUse(SLINGSHOT);}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, {[]{return CanUse(SLINGSHOT);}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, {[]{return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(SLINGSHOT) || CanUse(BOW) || CanUse(STICKS) || Bombs;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {[]{return CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(BOOMERANG));}}),
|
||||
//Trick: CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(BOOMERANG))
|
||||
}, {
|
||||
//Exits
|
||||
Entrance(JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return true;}}),
|
||||
Entrance(JABU_JABUS_BELLY_MQ_DEPTHS, {[]{return HasExplosives && IsChild && CanUse(BOOMERANG);}}),
|
||||
Entrance(JABU_JABUS_BELLY_MQ_DEPTHS, {[]{return HasExplosives && CanUse(SLINGSHOT) && CanUse(BOOMERANG);}}),
|
||||
});
|
||||
|
||||
areaTable[JABU_JABUS_BELLY_MQ_DEPTHS] = Area("Jabu Jabus Belly MQ Depths", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {
|
||||
@ -209,8 +209,8 @@ void AreaTable_Init_JabuJabusBelly() {
|
||||
}, {
|
||||
//Locations
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return true;}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return CanUse(SLINGSHOT);}}),
|
||||
LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return CanUse(BOOMERANG) || (LogicJabuNearBossRanged && CanUse(HOOKSHOT));}}),
|
||||
}, {
|
||||
//Exits
|
||||
Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}),
|
||||
@ -245,5 +245,6 @@ void AreaTable_Init_JabuJabusBelly() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(ZORAS_FOUNTAIN, { [] { return JabuJabusBellyClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -209,5 +209,6 @@ void AreaTable_Init_ShadowTemple() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(SHADOW_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(GRAVEYARD_WARP_PAD_REGION, { [] { return ShadowTempleClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -271,5 +271,6 @@ void AreaTable_Init_SpiritTemple() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(DESERT_COLOSSUS, { [] { return SpiritTempleClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -331,5 +331,6 @@ void AreaTable_Init_WaterTemple() {
|
||||
{
|
||||
// Exits
|
||||
Entrance(WATER_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }),
|
||||
Entrance(LAKE_HYLIA, { [] { return WaterTempleClear; } }),
|
||||
});
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ namespace Settings {
|
||||
Option ShuffleOverworldSpawns = Option::Bool("Overworld Spawns", {"Off", "On"});
|
||||
Option MixedEntrancePools = Option::Bool("Mixed Entrance Pools", {"Off", "On"});
|
||||
Option MixDungeons = Option::Bool("Mix Dungeons", {"Off", "On"});
|
||||
Option MixBosses = Option::Bool("Mix Bosses", {"Off", "On"});
|
||||
Option MixOverworld = Option::Bool("Mix Overworld", {"Off", "On"});
|
||||
Option MixInteriors = Option::Bool("Mix Interiors", {"Off", "On"});
|
||||
Option MixGrottos = Option::Bool("Mix Grottos", {"Off", "On"});
|
||||
@ -135,6 +136,7 @@ namespace Settings {
|
||||
&ShuffleOverworldSpawns,
|
||||
&MixedEntrancePools,
|
||||
&MixDungeons,
|
||||
&MixBosses,
|
||||
&MixOverworld,
|
||||
&MixInteriors,
|
||||
&MixGrottos,
|
||||
@ -1298,6 +1300,7 @@ namespace Settings {
|
||||
ctx.shuffleOverworldSpawns = (ShuffleOverworldSpawns) ? 1 : 0;
|
||||
ctx.mixedEntrancePools = (MixedEntrancePools) ? 1 : 0;
|
||||
ctx.mixDungeons = (MixDungeons) ? 1 : 0;
|
||||
ctx.mixBosses = (MixBosses) ? 1 : 0;
|
||||
ctx.mixOverworld = (MixOverworld) ? 1 : 0;
|
||||
ctx.mixInteriors = (MixInteriors) ? 1 : 0;
|
||||
ctx.mixGrottos = (MixGrottos) ? 1 : 0;
|
||||
@ -1891,6 +1894,13 @@ namespace Settings {
|
||||
MixDungeons.SetSelectedIndex(OFF);
|
||||
}
|
||||
|
||||
if (ShuffleBossEntrances.Is(SHUFFLEBOSSES_FULL)) {
|
||||
MixBosses.Unhide();
|
||||
} else {
|
||||
MixBosses.Hide();
|
||||
MixBosses.SetSelectedIndex(OFF);
|
||||
}
|
||||
|
||||
if (ShuffleOverworldEntrances) {
|
||||
MixOverworld.Unhide();
|
||||
} else {
|
||||
@ -1914,6 +1924,8 @@ namespace Settings {
|
||||
} else {
|
||||
MixDungeons.Hide();
|
||||
MixDungeons.SetSelectedIndex(OFF);
|
||||
MixBosses.Hide();
|
||||
MixBosses.SetSelectedIndex(OFF);
|
||||
MixOverworld.Hide();
|
||||
MixOverworld.SetSelectedIndex(OFF);
|
||||
MixInteriors.Hide();
|
||||
@ -2190,6 +2202,7 @@ namespace Settings {
|
||||
|
||||
if (!MixedEntrancePools) {
|
||||
MixDungeons.SetSelectedIndex(OFF);
|
||||
MixBosses.SetSelectedIndex(OFF);
|
||||
MixOverworld.SetSelectedIndex(OFF);
|
||||
MixInteriors.SetSelectedIndex(OFF);
|
||||
MixGrottos.SetSelectedIndex(OFF);
|
||||
@ -2344,6 +2357,7 @@ namespace Settings {
|
||||
ShuffleOverworldSpawns.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_SPAWNS]);
|
||||
MixedEntrancePools.SetSelectedIndex(cvarSettings[RSK_MIXED_ENTRANCE_POOLS]);
|
||||
MixDungeons.SetSelectedIndex(cvarSettings[RSK_MIX_DUNGEON_ENTRANCES]);
|
||||
MixBosses.SetSelectedIndex(cvarSettings[RSK_MIX_BOSS_ENTRANCES]);
|
||||
MixOverworld.SetSelectedIndex(cvarSettings[RSK_MIX_OVERWORLD_ENTRANCES]);
|
||||
MixInteriors.SetSelectedIndex(cvarSettings[RSK_MIX_INTERIOR_ENTRANCES]);
|
||||
MixGrottos.SetSelectedIndex(cvarSettings[RSK_MIX_GROTTO_ENTRANCES]);
|
||||
|
@ -397,6 +397,7 @@ typedef struct {
|
||||
uint8_t shuffleOverworldSpawns;
|
||||
uint8_t mixedEntrancePools;
|
||||
uint8_t mixDungeons;
|
||||
uint8_t mixBosses;
|
||||
uint8_t mixOverworld;
|
||||
uint8_t mixInteriors;
|
||||
uint8_t mixGrottos;
|
||||
@ -784,6 +785,7 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettin
|
||||
extern Option ShuffleOverworldSpawns;
|
||||
extern Option MixedEntrancePools;
|
||||
extern Option MixDungeons;
|
||||
extern Option MixBosses;
|
||||
extern Option MixOverworld;
|
||||
extern Option MixInteriors;
|
||||
extern Option MixGrottos;
|
||||
|
@ -307,35 +307,36 @@ static void WriteLocation(
|
||||
static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance) {
|
||||
int16_t originalIndex = entrance->GetIndex();
|
||||
int16_t destinationIndex = -1;
|
||||
int16_t originalBlueWarp = entrance->GetBlueWarp();
|
||||
int16_t replacementBlueWarp = -1;
|
||||
int16_t replacementIndex = entrance->GetReplacement()->GetIndex();
|
||||
int16_t replacementDestinationIndex = -1;
|
||||
std::string name = entrance->GetName();
|
||||
std::string text = entrance->GetConnectedRegion()->regionName + " from " + entrance->GetReplacement()->GetParentRegion()->regionName;
|
||||
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
// Track the reverse destination, useful for savewarp handling
|
||||
if (entrance->GetReverse() != nullptr) {
|
||||
destinationIndex = entrance->GetReverse()->GetIndex();
|
||||
// When decouple is off we track the replacement's reverse destination, useful for recording visited entrances
|
||||
if (!entrance->IsDecoupled()) {
|
||||
replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex();
|
||||
replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp();
|
||||
}
|
||||
}
|
||||
|
||||
json entranceJson = json::object({
|
||||
{"type", entrance->GetType()},
|
||||
{"index", originalIndex},
|
||||
{"destination", destinationIndex},
|
||||
{"blueWarp", originalBlueWarp},
|
||||
{"override", replacementIndex},
|
||||
{"overrideDestination", replacementDestinationIndex},
|
||||
});
|
||||
|
||||
jsonData["entrances"].push_back(entranceJson);
|
||||
|
||||
// When decoupled entrances is off, handle saving reverse entrances with blue warps
|
||||
// When decoupled entrances is off, handle saving reverse entrances
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
json reverseEntranceJson = json::object({
|
||||
{"type", entrance->GetReverse()->GetType()},
|
||||
{"index", replacementDestinationIndex},
|
||||
{"destination", replacementIndex},
|
||||
{"blueWarp", replacementBlueWarp},
|
||||
{"override", destinationIndex},
|
||||
{"overrideDestination", originalIndex},
|
||||
});
|
||||
|
@ -315,6 +315,7 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
|
||||
{ "World Settings:Overworld Spawns", RSK_SHUFFLE_OVERWORLD_SPAWNS },
|
||||
{ "World Settings:Mixed Entrance Pools", RSK_MIXED_ENTRANCE_POOLS },
|
||||
{ "World Settings:Mix Dungeons", RSK_MIX_DUNGEON_ENTRANCES },
|
||||
{ "World Settings:Mix Bosses", RSK_MIX_BOSS_ENTRANCES },
|
||||
{ "World Settings:Mix Overworld", RSK_MIX_OVERWORLD_ENTRANCES },
|
||||
{ "World Settings:Mix Interiors", RSK_MIX_INTERIOR_ENTRANCES },
|
||||
{ "World Settings:Mix Grottos", RSK_MIX_GROTTO_ENTRANCES },
|
||||
@ -548,13 +549,18 @@ void Randomizer::LoadMerchantMessages(const char* spoilerFileName) {
|
||||
"\x12\x38\x82" "Aufgeben! Ich verkaufe dir einen&%g{{item}}%w&für %r{{price}} Rubine%w!\x07\x10\xA3",
|
||||
"\x12\x38\x82" "J'abandonne! Tu veux bien m'acheter&un %g{{item}}%w?&Ça fera %r{{price}} Rubis%w!\x07\x10\xA3"));
|
||||
CustomMessageManager::Instance->CreateMessage(
|
||||
Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN,
|
||||
Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_10,
|
||||
CustomMessage("I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth "
|
||||
"beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w",
|
||||
"Möchten Sie einen geheimnisvollen&Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w",
|
||||
"J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça "
|
||||
"me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&"
|
||||
"%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w"));
|
||||
CustomMessageManager::Instance->CreateMessage(
|
||||
Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_100,
|
||||
CustomMessage("I never thought I'd say this, but I'm &selling the last %rMagic Bean%w. %r99%w Rupees...\x1B&%gYes&No%w",
|
||||
"\x1B&%gJa&Nein%w",
|
||||
"Je te vends mon dernier %rHaricot&magique%w pour %r99 Rubis%w.\x1B&%gAcheter&Ne pas acheter%w"));
|
||||
|
||||
|
||||
//Setup for merchant text boxes
|
||||
@ -566,7 +572,7 @@ void Randomizer::LoadMerchantMessages(const char* spoilerFileName) {
|
||||
"Wie wäre es mit %g&{{item}}%w für %y200 Rubine?%w\x1B&%gJa!&Nein!%w",
|
||||
"Veux-tu acheter %g&{{item}}%w pour %y200 rubis?%w\x1B&%gOui&Non&w"));
|
||||
|
||||
//Granny Shopy
|
||||
//Granny Shop
|
||||
//RANDOTODO: Implement obscure/ambiguous hints
|
||||
CustomMessageManager::Instance->CreateMessage(
|
||||
Randomizer::merchantMessageTableID, TEXT_GRANNYS_SHOP,
|
||||
@ -899,6 +905,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
|
||||
case RSK_SHUFFLE_OVERWORLD_SPAWNS:
|
||||
case RSK_MIXED_ENTRANCE_POOLS:
|
||||
case RSK_MIX_DUNGEON_ENTRANCES:
|
||||
case RSK_MIX_BOSS_ENTRANCES:
|
||||
case RSK_MIX_OVERWORLD_ENTRANCES:
|
||||
case RSK_MIX_INTERIOR_ENTRANCES:
|
||||
case RSK_MIX_GROTTO_ENTRANCES:
|
||||
@ -1562,9 +1569,9 @@ void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent)
|
||||
|
||||
// set all the entrances to be 0 to indicate an unshuffled entrance
|
||||
for (auto &entranceOveride : gSaveContext.entranceOverrides) {
|
||||
entranceOveride.type = 0;
|
||||
entranceOveride.index = 0;
|
||||
entranceOveride.destination = 0;
|
||||
entranceOveride.blueWarp = 0;
|
||||
entranceOveride.override = 0;
|
||||
entranceOveride.overrideDestination = 0;
|
||||
}
|
||||
@ -1579,12 +1586,12 @@ void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent)
|
||||
json entranceJson = *it;
|
||||
|
||||
for (auto entranceIt = entranceJson.begin(); entranceIt != entranceJson.end(); ++entranceIt) {
|
||||
if (entranceIt.key() == "index") {
|
||||
if (entranceIt.key() == "type") {
|
||||
gSaveContext.entranceOverrides[i].type = entranceIt.value();
|
||||
} else if (entranceIt.key() == "index") {
|
||||
gSaveContext.entranceOverrides[i].index = entranceIt.value();
|
||||
} else if (entranceIt.key() == "destination") {
|
||||
gSaveContext.entranceOverrides[i].destination = entranceIt.value();
|
||||
} else if (entranceIt.key() == "blueWarp") {
|
||||
gSaveContext.entranceOverrides[i].blueWarp = entranceIt.value();
|
||||
} else if (entranceIt.key() == "override") {
|
||||
gSaveContext.entranceOverrides[i].override = entranceIt.value();
|
||||
} else if (entranceIt.key() == "overrideDestination") {
|
||||
@ -3008,6 +3015,7 @@ void GenerateRandomizerImgui(std::string seed = "") {
|
||||
cvarSettings[RSK_SHUFFLE_OVERWORLD_SPAWNS] = CVarGetInteger("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIXED_ENTRANCE_POOLS] = CVarGetInteger("gRandomizeMixedEntrances", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIX_DUNGEON_ENTRANCES] = CVarGetInteger("gRandomizeMixDungeons", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIX_BOSS_ENTRANCES] = CVarGetInteger("gRandomizeMixBosses", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIX_OVERWORLD_ENTRANCES] = CVarGetInteger("gRandomizeMixOverworld", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIX_INTERIOR_ENTRANCES] = CVarGetInteger("gRandomizeMixInteriors", RO_GENERIC_OFF);
|
||||
cvarSettings[RSK_MIX_GROTTO_ENTRANCES] = CVarGetInteger("gRandomizeMixGrottos", RO_GENERIC_OFF);
|
||||
@ -3706,7 +3714,8 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
// Mixed Entrance Pools
|
||||
UIWidgets::EnhancementCheckbox("Mixed Entrance Pools", "gRandomizeMixedEntrances");
|
||||
UIWidgets::InsertHelpHoverText(
|
||||
"Shuffle entrances into a mixed pool instead of separate ones.\n"
|
||||
"Shuffle entrances into a mixed pool instead of separate ones. Has no affect on pools whose "
|
||||
"entrances aren't shuffled, and \"Shuffle Boss Entrances\" must be set to \"Full\" to include them.\n"
|
||||
"\n"
|
||||
"For example, enabling the settings to shuffle grotto, dungeon, and overworld entrances and "
|
||||
"selecting grotto and dungeon entrances here will allow a dungeon to be inside a grotto or "
|
||||
@ -3720,6 +3729,13 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
UIWidgets::EnhancementCheckbox("Mix Dungeons", "gRandomizeMixDungeons");
|
||||
UIWidgets::InsertHelpHoverText("Dungeon entrances will be part of the mixed pool");
|
||||
}
|
||||
if (CVarGetInteger("gRandomizeShuffleBossEntrances", RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) ==
|
||||
RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL) {
|
||||
UIWidgets::Spacer(0);
|
||||
ImGui::SetCursorPosX(20);
|
||||
UIWidgets::EnhancementCheckbox("Mix Bosses", "gRandomizeMixBosses");
|
||||
UIWidgets::InsertHelpHoverText("Boss entrances will be part of the mixed pool");
|
||||
}
|
||||
if (CVarGetInteger("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF)) {
|
||||
UIWidgets::Spacer(0);
|
||||
ImGui::SetCursorPosX(20);
|
||||
@ -4707,7 +4723,11 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
excludedLocationString += std::to_string(excludedLocationIt);
|
||||
excludedLocationString += ",";
|
||||
}
|
||||
if (excludedLocationString == "") {
|
||||
CVarClear("gRandomizeExcludedLocations");
|
||||
} else {
|
||||
CVarSetString("gRandomizeExcludedLocations", excludedLocationString.c_str());
|
||||
}
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -4893,7 +4913,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
enabledTrickString += std::to_string(enabledTrickIt);
|
||||
enabledTrickString += ",";
|
||||
}
|
||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
||||
CVarClear("gRandomizeEnabledTricks");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -5097,7 +5117,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
enabledTrickString += std::to_string(enabledTrickIt);
|
||||
enabledTrickString += ",";
|
||||
}
|
||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
||||
CVarClear("gRandomizeEnabledTricks");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
|
||||
@ -5135,7 +5155,11 @@ void RandomizerSettingsWindow::DrawElement() {
|
||||
enabledTrickString += std::to_string(enabledTrickIt);
|
||||
enabledTrickString += ",";
|
||||
}
|
||||
if (enabledTrickString == "") {
|
||||
CVarClear("gRandomizeEnabledTricks");
|
||||
} else {
|
||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
||||
}
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
DrawTagChips(*rtObject.rtTags);
|
||||
@ -5374,7 +5398,7 @@ CustomMessage Randomizer::GetSheikMessage(s16 scene, u16 originalTextId) {
|
||||
}
|
||||
|
||||
CustomMessage Randomizer::GetSariaMessage(u16 originalTextId) {
|
||||
if (originalTextId == TEXT_SARIA_SFM || (originalTextId >= TEXT_SARIAS_SONG_TEXT_START && originalTextId <= TEXT_SARIAS_SONG_TEXT_END)) {
|
||||
if (originalTextId == TEXT_SARIA_SFM || (originalTextId >= TEXT_SARIAS_SONG_FACE_TO_FACE && originalTextId <= TEXT_SARIAS_SONG_CHANNELING_POWER)) {
|
||||
CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_SARIAS_SONG_FACE_TO_FACE);
|
||||
CustomMessage messageEntry2 = messageEntry;
|
||||
std::string code = originalTextId == TEXT_SARIA_SFM ? "" : "\x0B";
|
||||
|
@ -1467,6 +1467,7 @@ typedef enum {
|
||||
RSK_SHUFFLE_OVERWORLD_SPAWNS,
|
||||
RSK_MIXED_ENTRANCE_POOLS,
|
||||
RSK_MIX_DUNGEON_ENTRANCES,
|
||||
RSK_MIX_BOSS_ENTRANCES,
|
||||
RSK_MIX_OVERWORLD_ENTRANCES,
|
||||
RSK_MIX_INTERIOR_ENTRANCES,
|
||||
RSK_MIX_GROTTO_ENTRANCES,
|
||||
|
@ -762,7 +762,6 @@ void InitTrackerData(bool isDebug) {
|
||||
}
|
||||
}
|
||||
UpdateAllOrdering();
|
||||
UpdateInventoryChecks();
|
||||
}
|
||||
|
||||
void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) {
|
||||
|
@ -39,17 +39,12 @@ s16 dynamicExitList[] = {
|
||||
// Owl Flights : 0x492064 and 0x492080
|
||||
|
||||
static s16 entranceOverrideTable[ENTRANCE_TABLE_SIZE] = {0};
|
||||
// Boss scenes (normalize boss scene range to 0 on lookup) to the replaced dungeon scene it is connected to
|
||||
static s16 dungeonBossSceneOverrides[SHUFFLEABLE_BOSS_COUNT] = {0};
|
||||
// Boss scenes (normalize boss scene range to 0 on lookup) mapped to save/death warp entrance
|
||||
static s16 bossSceneSaveDeathWarps[SHUFFLEABLE_BOSS_COUNT] = {0};
|
||||
static ActorEntry modifiedLinkActorEntry = {0};
|
||||
|
||||
EntranceInfo originalEntranceTable[ENTRANCE_TABLE_SIZE] = {0};
|
||||
|
||||
typedef struct {
|
||||
s16 blueWarp;
|
||||
s16 destination;
|
||||
} BlueWarpReplacement;
|
||||
|
||||
typedef struct {
|
||||
s16 entryway;
|
||||
s16 exit;
|
||||
@ -62,39 +57,24 @@ typedef struct {
|
||||
|
||||
static DungeonEntranceInfo dungeons[] = {
|
||||
//entryway exit, boss, reverse, bluewarp, dungeon scene, boss scene
|
||||
{ DEKU_TREE_ENTRANCE, ENTR_KOKIRI_FOREST_1, ENTR_DEKU_TREE_BOSS_0, ENTR_DEKU_TREE_1, ENTR_KOKIRI_FOREST_11, SCENE_DEKU_TREE, SCENE_DEKU_TREE_BOSS },
|
||||
{ DODONGOS_CAVERN_ENTRANCE, ENTR_DEATH_MOUNTAIN_TRAIL_3, ENTR_DODONGOS_CAVERN_BOSS_0, ENTR_DODONGOS_CAVERN_1, ENTR_DEATH_MOUNTAIN_TRAIL_5, SCENE_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN_BOSS },
|
||||
{ JABU_JABUS_BELLY_ENTRANCE, ENTR_ZORAS_FOUNTAIN_1, ENTR_JABU_JABU_BOSS_0, ENTR_JABU_JABU_1, ENTR_ZORAS_FOUNTAIN_0, SCENE_JABU_JABU, SCENE_JABU_JABU_BOSS },
|
||||
{ FOREST_TEMPLE_ENTRANCE, ENTR_SACRED_FOREST_MEADOW_1, ENTR_FOREST_TEMPLE_BOSS_0, ENTR_FOREST_TEMPLE_1, ENTR_SACRED_FOREST_MEADOW_3, SCENE_FOREST_TEMPLE, SCENE_FOREST_TEMPLE_BOSS },
|
||||
{ FIRE_TEMPLE_ENTRANCE, ENTR_DEATH_MOUNTAIN_CRATER_2, ENTR_FIRE_TEMPLE_BOSS_0, ENTR_FIRE_TEMPLE_1, ENTR_DEATH_MOUNTAIN_CRATER_5, SCENE_FIRE_TEMPLE, SCENE_FIRE_TEMPLE_BOSS },
|
||||
{ WATER_TEMPLE_ENTRANCE, ENTR_LAKE_HYLIA_2, ENTR_WATER_TEMPLE_BOSS_0, ENTR_WATER_TEMPLE_1, ENTR_LAKE_HYLIA_9, SCENE_WATER_TEMPLE, SCENE_WATER_TEMPLE_BOSS },
|
||||
{ SPIRIT_TEMPLE_ENTRANCE, ENTR_DESERT_COLOSSUS_1, ENTR_SPIRIT_TEMPLE_BOSS_0, ENTR_SPIRIT_TEMPLE_1, ENTR_DESERT_COLOSSUS_8, SCENE_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE_BOSS },
|
||||
{ SHADOW_TEMPLE_ENTRANCE, ENTR_GRAVEYARD_1, ENTR_SHADOW_TEMPLE_BOSS_0, ENTR_SHADOW_TEMPLE_1, ENTR_GRAVEYARD_8, SCENE_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE_BOSS },
|
||||
{ ENTR_DEKU_TREE_0, ENTR_KOKIRI_FOREST_1, ENTR_DEKU_TREE_BOSS_0, ENTR_DEKU_TREE_1, ENTR_KOKIRI_FOREST_11, SCENE_DEKU_TREE, SCENE_DEKU_TREE_BOSS },
|
||||
{ ENTR_DODONGOS_CAVERN_0, ENTR_DEATH_MOUNTAIN_TRAIL_3, ENTR_DODONGOS_CAVERN_BOSS_0, ENTR_DODONGOS_CAVERN_1, ENTR_DEATH_MOUNTAIN_TRAIL_5, SCENE_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN_BOSS },
|
||||
{ ENTR_JABU_JABU_0, ENTR_ZORAS_FOUNTAIN_1, ENTR_JABU_JABU_BOSS_0, ENTR_JABU_JABU_1, ENTR_ZORAS_FOUNTAIN_0, SCENE_JABU_JABU, SCENE_JABU_JABU_BOSS },
|
||||
{ ENTR_FOREST_TEMPLE_0, ENTR_SACRED_FOREST_MEADOW_1, ENTR_FOREST_TEMPLE_BOSS_0, ENTR_FOREST_TEMPLE_1, ENTR_SACRED_FOREST_MEADOW_3, SCENE_FOREST_TEMPLE, SCENE_FOREST_TEMPLE_BOSS },
|
||||
{ ENTR_FIRE_TEMPLE_0, ENTR_DEATH_MOUNTAIN_CRATER_2, ENTR_FIRE_TEMPLE_BOSS_0, ENTR_FIRE_TEMPLE_1, ENTR_DEATH_MOUNTAIN_CRATER_5, SCENE_FIRE_TEMPLE, SCENE_FIRE_TEMPLE_BOSS },
|
||||
{ ENTR_WATER_TEMPLE_0, ENTR_LAKE_HYLIA_2, ENTR_WATER_TEMPLE_BOSS_0, ENTR_WATER_TEMPLE_1, ENTR_LAKE_HYLIA_9, SCENE_WATER_TEMPLE, SCENE_WATER_TEMPLE_BOSS },
|
||||
{ ENTR_SPIRIT_TEMPLE_0, ENTR_DESERT_COLOSSUS_1, ENTR_SPIRIT_TEMPLE_BOSS_0, ENTR_SPIRIT_TEMPLE_1, ENTR_DESERT_COLOSSUS_8, SCENE_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE_BOSS },
|
||||
{ ENTR_SHADOW_TEMPLE_0, ENTR_GRAVEYARD_1, ENTR_SHADOW_TEMPLE_BOSS_0, ENTR_SHADOW_TEMPLE_1, ENTR_GRAVEYARD_8, SCENE_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE_BOSS },
|
||||
};
|
||||
|
||||
//These variables store the new entrance indices for dungeons so that
|
||||
//savewarping and game overs respawn players at the proper entrance.
|
||||
//By default, these will be their vanilla values.
|
||||
static s16 newDekuTreeEntrance = DEKU_TREE_ENTRANCE;
|
||||
static s16 newDodongosCavernEntrance = DODONGOS_CAVERN_ENTRANCE;
|
||||
static s16 newJabuJabusBellyEntrance = JABU_JABUS_BELLY_ENTRANCE;
|
||||
static s16 newForestTempleEntrance = FOREST_TEMPLE_ENTRANCE;
|
||||
static s16 newFireTempleEntrance = FIRE_TEMPLE_ENTRANCE;
|
||||
static s16 newWaterTempleEntrance = WATER_TEMPLE_ENTRANCE;
|
||||
static s16 newSpiritTempleEntrance = SPIRIT_TEMPLE_ENTRANCE;
|
||||
static s16 newShadowTempleEntrance = SHADOW_TEMPLE_ENTRANCE;
|
||||
static s16 newBottomOfTheWellEntrance = BOTTOM_OF_THE_WELL_ENTRANCE;
|
||||
static s16 newGerudoTrainingGroundsEntrance = GERUDO_TRAINING_GROUNDS_ENTRANCE;
|
||||
static s16 newIceCavernEntrance = ICE_CAVERN_ENTRANCE;
|
||||
|
||||
static s8 hasCopiedEntranceTable = 0;
|
||||
static s8 hasModifiedEntranceTable = 0;
|
||||
|
||||
void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance);
|
||||
|
||||
u8 Entrance_EntranceIsNull(EntranceOverride* entranceOverride) {
|
||||
return entranceOverride->index == 0 && entranceOverride->destination == 0 && entranceOverride->blueWarp == 0
|
||||
&& entranceOverride->override == 0 && entranceOverride->overrideDestination == 0;
|
||||
return entranceOverride->index == 0 && entranceOverride->destination == 0 && entranceOverride->override == 0 &&
|
||||
entranceOverride->overrideDestination == 0;
|
||||
}
|
||||
|
||||
static void Entrance_SeparateOGCFairyFountainExit(void) {
|
||||
@ -113,6 +93,28 @@ static void Entrance_SeparateAdultSpawnAndPrelude() {
|
||||
}
|
||||
}
|
||||
|
||||
// Fix Adult dungeon blue warps as Child by assigning the child values for the warp pads
|
||||
static void Entrance_ReplaceChildTempleWarps() {
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF ||
|
||||
Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) {
|
||||
// Forest Temple
|
||||
gEntranceTable[ENTR_SACRED_FOREST_MEADOW_3] = gEntranceTable[ENTR_SACRED_FOREST_MEADOW_2];
|
||||
gEntranceTable[ENTR_SACRED_FOREST_MEADOW_3_1] = gEntranceTable[ENTR_SACRED_FOREST_MEADOW_2_1];
|
||||
// Fire Temple
|
||||
gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_5] = gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_4];
|
||||
gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_5_1] = gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_4_1];
|
||||
// Water Temple
|
||||
gEntranceTable[ENTR_LAKE_HYLIA_9] = gEntranceTable[ENTR_LAKE_HYLIA_8];
|
||||
gEntranceTable[ENTR_LAKE_HYLIA_9_1] = gEntranceTable[ENTR_LAKE_HYLIA_8_1];
|
||||
// Shadow Temple
|
||||
gEntranceTable[ENTR_GRAVEYARD_8] = gEntranceTable[ENTR_GRAVEYARD_7];
|
||||
gEntranceTable[ENTR_GRAVEYARD_8_1] = gEntranceTable[ENTR_GRAVEYARD_7_1];
|
||||
// Spirit Temple
|
||||
gEntranceTable[ENTR_DESERT_COLOSSUS_8] = gEntranceTable[ENTR_DESERT_COLOSSUS_5];
|
||||
gEntranceTable[ENTR_DESERT_COLOSSUS_8_1] = gEntranceTable[ENTR_DESERT_COLOSSUS_5_1];
|
||||
}
|
||||
}
|
||||
|
||||
void Entrance_CopyOriginalEntranceTable(void) {
|
||||
if (!hasCopiedEntranceTable) {
|
||||
memcpy(originalEntranceTable, gEntranceTable, sizeof(EntranceInfo) * ENTRANCE_TABLE_SIZE);
|
||||
@ -130,9 +132,6 @@ void Entrance_ResetEntranceTable(void) {
|
||||
void Entrance_Init(void) {
|
||||
s32 index;
|
||||
|
||||
size_t blueWarpRemapIdx = 0;
|
||||
BlueWarpReplacement bluewarps[SHUFFLEABLE_BOSS_COUNT] = {0};
|
||||
|
||||
Entrance_CopyOriginalEntranceTable();
|
||||
|
||||
// Skip Child Stealth if given by settings
|
||||
@ -149,6 +148,7 @@ void Entrance_Init(void) {
|
||||
|
||||
Entrance_SeparateOGCFairyFountainExit();
|
||||
Entrance_SeparateAdultSpawnAndPrelude();
|
||||
Entrance_ReplaceChildTempleWarps();
|
||||
|
||||
// Initialize the entrance override table with each index leading to itself. An
|
||||
// index referring to itself means that the entrance is not currently shuffled.
|
||||
@ -156,9 +156,9 @@ void Entrance_Init(void) {
|
||||
entranceOverrideTable[i] = i;
|
||||
}
|
||||
|
||||
// Initialize all boss rooms connected to their vanilla dungeon
|
||||
// Initialize all boss room save/death warps with their vanilla dungeon entryway
|
||||
for (s16 i = 1; i < SHUFFLEABLE_BOSS_COUNT; i++) {
|
||||
dungeonBossSceneOverrides[i] = i;
|
||||
bossSceneSaveDeathWarps[i] = dungeons[i].entryway;
|
||||
}
|
||||
|
||||
// Initialize the grotto exit and load lists
|
||||
@ -172,9 +172,30 @@ void Entrance_Init(void) {
|
||||
}
|
||||
|
||||
s16 originalIndex = gSaveContext.entranceOverrides[i].index;
|
||||
s16 blueWarpIndex = gSaveContext.entranceOverrides[i].blueWarp;
|
||||
s16 originalDestination = gSaveContext.entranceOverrides[i].destination;
|
||||
s16 overrideIndex = gSaveContext.entranceOverrides[i].override;
|
||||
|
||||
int16_t bossScene = -1;
|
||||
int16_t saveWarpEntrance = originalDestination; // Default save warp to the original return entrance
|
||||
|
||||
// Search for boss room overrides and look for the matching save/death warp value to use
|
||||
// If the boss room is in a dungeon, use the dungeons entryway as the save warp
|
||||
// Otherwise use the "exit" value for the entrance that lead to the boss room
|
||||
for (int j = 0; j <= SHUFFLEABLE_BOSS_COUNT; j++) {
|
||||
if (overrideIndex == dungeons[j].bossDoor) {
|
||||
bossScene = dungeons[j].bossScene;
|
||||
}
|
||||
|
||||
if (index == dungeons[j].bossDoor) {
|
||||
saveWarpEntrance = dungeons[j].entryway;
|
||||
}
|
||||
}
|
||||
|
||||
// Found a boss scene and a valid save/death warp value
|
||||
if (bossScene != -1 && saveWarpEntrance != -1) {
|
||||
bossSceneSaveDeathWarps[bossScene - SCENE_DEKU_TREE_BOSS] = saveWarpEntrance;
|
||||
}
|
||||
|
||||
//Overwrite grotto related indices
|
||||
if (originalIndex >= ENTRANCE_RANDO_GROTTO_EXIT_START) {
|
||||
Grotto_SetExitOverride(originalIndex, overrideIndex);
|
||||
@ -189,36 +210,6 @@ void Entrance_Init(void) {
|
||||
// Overwrite the indices which we want to shuffle, leaving the rest as they are
|
||||
entranceOverrideTable[originalIndex] = overrideIndex;
|
||||
|
||||
if (blueWarpIndex != 0) {
|
||||
// When boss shuffle is enabled, we need to know what dungeon the boss room is connected to for
|
||||
// death/save warping, and for the blue warp
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) {
|
||||
s16 bossScene = -1;
|
||||
s16 replacedDungeonScene = -1;
|
||||
s16 replacedDungeonExit = -1;
|
||||
// Search for the boss scene and replaced blue warp exits
|
||||
for (s16 j = 0; j <= SHUFFLEABLE_BOSS_COUNT; j++) {
|
||||
if (blueWarpIndex == dungeons[j].blueWarp) {
|
||||
bossScene = dungeons[j].bossScene;
|
||||
}
|
||||
if (overrideIndex == dungeons[j].bossDoorReverse) {
|
||||
replacedDungeonScene = dungeons[j].scene;
|
||||
replacedDungeonExit = dungeons[j].exit;
|
||||
}
|
||||
}
|
||||
|
||||
// assign the boss scene override
|
||||
if (bossScene != -1 && replacedDungeonScene != -1 && replacedDungeonExit != -1) {
|
||||
dungeonBossSceneOverrides[bossScene - SCENE_DEKU_TREE_BOSS] = replacedDungeonScene;
|
||||
bluewarps[blueWarpRemapIdx].blueWarp = blueWarpIndex;
|
||||
bluewarps[blueWarpRemapIdx].destination = replacedDungeonExit;
|
||||
blueWarpRemapIdx++;
|
||||
}
|
||||
} else {
|
||||
entranceOverrideTable[blueWarpIndex] = overrideIndex;
|
||||
}
|
||||
}
|
||||
|
||||
//Override both land and water entrances for Hyrule Field -> ZR Front and vice versa
|
||||
if (originalIndex == ENTR_ZORAS_RIVER_0) { //Hyrule Field -> ZR Front land entrance
|
||||
entranceOverrideTable[ENTR_ZORAS_RIVER_3] = overrideIndex;
|
||||
@ -227,14 +218,6 @@ void Entrance_Init(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we have remapped blue warps from boss shuffle, handle setting those and grabbing the override for
|
||||
// the replaced dungeons exit in the event that dungeon shuffle is also turned on
|
||||
for (size_t i = 0; i < ARRAY_COUNT(bluewarps); i++) {
|
||||
if (bluewarps[i].blueWarp != 0 && bluewarps[i].destination != 0) {
|
||||
entranceOverrideTable[bluewarps[i].blueWarp] = Entrance_GetOverride(bluewarps[i].destination);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop playing background music during shuffled entrance transitions
|
||||
// so that we don't get duplicated or overlapping music tracks
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) {
|
||||
@ -328,40 +311,39 @@ void Entrance_SetGameOverEntrance(void) {
|
||||
|
||||
s16 scene = gPlayState->sceneNum;
|
||||
|
||||
// When in a boss room and boss shuffle is on, get the connected dungeon's original boss room entrance
|
||||
// then run the normal game over overrides on it
|
||||
// When in a boss room and boss shuffle is on, use the boss scene to find the death warp entrance
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF &&
|
||||
scene >= SCENE_DEKU_TREE_BOSS && scene <= SCENE_SHADOW_TEMPLE_BOSS) {
|
||||
// Normalize boss scene range to 0 on lookup
|
||||
scene = dungeonBossSceneOverrides[scene - SCENE_DEKU_TREE_BOSS];
|
||||
gSaveContext.entranceIndex = dungeons[scene].bossDoor;
|
||||
// Normalize boss scene range to 0 on lookup and handle for grotto entrances
|
||||
gSaveContext.entranceIndex = Grotto_OverrideSpecialEntrance(bossSceneSaveDeathWarps[scene - SCENE_DEKU_TREE_BOSS]);
|
||||
return;
|
||||
}
|
||||
|
||||
//Set the current entrance depending on which entrance the player last came through
|
||||
switch (gSaveContext.entranceIndex) {
|
||||
case ENTR_DEKU_TREE_BOSS_0 : //Deku Tree Boss Room
|
||||
gSaveContext.entranceIndex = newDekuTreeEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_DEKU_TREE_0;
|
||||
return;
|
||||
case ENTR_DODONGOS_CAVERN_BOSS_0 : //Dodongos Cavern Boss Room
|
||||
gSaveContext.entranceIndex = newDodongosCavernEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_DODONGOS_CAVERN_0;
|
||||
return;
|
||||
case ENTR_JABU_JABU_BOSS_0 : //Jabu Jabus Belly Boss Room
|
||||
gSaveContext.entranceIndex = newJabuJabusBellyEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_JABU_JABU_0;
|
||||
return;
|
||||
case ENTR_FOREST_TEMPLE_BOSS_0 : //Forest Temple Boss Room
|
||||
gSaveContext.entranceIndex = newForestTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_FOREST_TEMPLE_0;
|
||||
return;
|
||||
case ENTR_FIRE_TEMPLE_BOSS_0 : //Fire Temple Boss Room
|
||||
gSaveContext.entranceIndex = newFireTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_FIRE_TEMPLE_0;
|
||||
return;
|
||||
case ENTR_WATER_TEMPLE_BOSS_0 : //Water Temple Boss Room
|
||||
gSaveContext.entranceIndex = newWaterTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_WATER_TEMPLE_0;
|
||||
return;
|
||||
case ENTR_SPIRIT_TEMPLE_BOSS_0 : //Spirit Temple Boss Room
|
||||
gSaveContext.entranceIndex = newSpiritTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_SPIRIT_TEMPLE_0;
|
||||
return;
|
||||
case ENTR_SHADOW_TEMPLE_BOSS_0 : //Shadow Temple Boss Room
|
||||
gSaveContext.entranceIndex = newShadowTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_SHADOW_TEMPLE_0;
|
||||
return;
|
||||
case ENTR_GANONDORF_BOSS_0 : //Ganondorf Boss Room
|
||||
gSaveContext.entranceIndex = ENTR_GANONS_TOWER_0; // Inside Ganon's Castle -> Ganon's Tower Climb
|
||||
@ -374,46 +356,46 @@ void Entrance_SetSavewarpEntrance(void) {
|
||||
|
||||
s16 scene = gSaveContext.savedSceneNum;
|
||||
|
||||
// When in a boss room and boss shuffle is on, use the boss scene override to remap to its
|
||||
// connected dungeon and use that for the final entrance
|
||||
// When in a boss room and boss shuffle is on, use the boss scene to find the savewarp entrance
|
||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF &&
|
||||
scene >= SCENE_DEKU_TREE_BOSS && scene <= SCENE_SHADOW_TEMPLE_BOSS) {
|
||||
// Normalize boss scene range to 0 on lookup
|
||||
scene = dungeonBossSceneOverrides[scene - SCENE_DEKU_TREE_BOSS];
|
||||
// Normalize boss scene range to 0 on lookup and handle for grotto entrances
|
||||
gSaveContext.entranceIndex = Grotto_OverrideSpecialEntrance(bossSceneSaveDeathWarps[scene - SCENE_DEKU_TREE_BOSS]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scene == SCENE_DEKU_TREE || scene == SCENE_DEKU_TREE_BOSS) {
|
||||
gSaveContext.entranceIndex = newDekuTreeEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_DEKU_TREE_0;
|
||||
} else if (scene == SCENE_DODONGOS_CAVERN || scene == SCENE_DODONGOS_CAVERN_BOSS) {
|
||||
gSaveContext.entranceIndex = newDodongosCavernEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_DODONGOS_CAVERN_0;
|
||||
} else if (scene == SCENE_JABU_JABU || scene == SCENE_JABU_JABU_BOSS) {
|
||||
gSaveContext.entranceIndex = newJabuJabusBellyEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_JABU_JABU_0;
|
||||
} else if (scene == SCENE_FOREST_TEMPLE || scene == SCENE_FOREST_TEMPLE_BOSS) { //Forest Temple Boss Room
|
||||
gSaveContext.entranceIndex = newForestTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_FOREST_TEMPLE_0;
|
||||
} else if (scene == SCENE_FIRE_TEMPLE || scene == SCENE_FIRE_TEMPLE_BOSS) { //Fire Temple Boss Room
|
||||
gSaveContext.entranceIndex = newFireTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_FIRE_TEMPLE_0;
|
||||
} else if (scene == SCENE_WATER_TEMPLE || scene == SCENE_WATER_TEMPLE_BOSS) { //Water Temple Boss Room
|
||||
gSaveContext.entranceIndex = newWaterTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_WATER_TEMPLE_0;
|
||||
} else if (scene == SCENE_SPIRIT_TEMPLE || scene == SCENE_SPIRIT_TEMPLE_BOSS) { //Spirit Temple Boss Room
|
||||
gSaveContext.entranceIndex = newSpiritTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_SPIRIT_TEMPLE_0;
|
||||
} else if (scene == SCENE_SHADOW_TEMPLE || scene == SCENE_SHADOW_TEMPLE_BOSS) { //Shadow Temple Boss Room
|
||||
gSaveContext.entranceIndex = newShadowTempleEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_SHADOW_TEMPLE_0;
|
||||
} else if (scene == SCENE_BOTTOM_OF_THE_WELL) { // BOTW
|
||||
gSaveContext.entranceIndex = newBottomOfTheWellEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_BOTTOM_OF_THE_WELL_0;
|
||||
} else if (scene == SCENE_GERUDO_TRAINING_GROUND) { // GTG
|
||||
gSaveContext.entranceIndex = newGerudoTrainingGroundsEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_GERUDO_TRAINING_GROUND_0;
|
||||
} else if (scene == SCENE_ICE_CAVERN) { // Ice cavern
|
||||
gSaveContext.entranceIndex = newIceCavernEntrance;
|
||||
gSaveContext.entranceIndex = ENTR_ICE_CAVERN_0;
|
||||
} else if (scene == SCENE_INSIDE_GANONS_CASTLE) {
|
||||
gSaveContext.entranceIndex = GANONS_CASTLE_ENTRANCE;
|
||||
gSaveContext.entranceIndex = ENTR_INSIDE_GANONS_CASTLE_0;
|
||||
} else if (scene == SCENE_GANONS_TOWER || scene == SCENE_INSIDE_GANONS_CASTLE_COLLAPSE || scene == SCENE_GANONS_TOWER_COLLAPSE_INTERIOR || scene == SCENE_GANON_BOSS || scene == SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR) {
|
||||
gSaveContext.entranceIndex = ENTR_GANONS_TOWER_0; // Inside Ganon's Castle -> Ganon's Tower Climb
|
||||
} else if (scene == SCENE_THIEVES_HIDEOUT) { // Theives hideout
|
||||
gSaveContext.entranceIndex = ENTR_THIEVES_HIDEOUT_0; // Gerudo Fortress -> Thieve's Hideout spawn 0
|
||||
} else if (scene == SCENE_LINKS_HOUSE) {
|
||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE);
|
||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(ENTR_LINKS_HOUSE_0);
|
||||
} else if (LINK_IS_CHILD) {
|
||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); // Child Overworld Spawn
|
||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(ENTR_LINKS_HOUSE_0); // Child Overworld Spawn
|
||||
} else {
|
||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(ENTR_HYRULE_FIELD_10); // Adult Overworld Spawn (Normally 0x5F4 (ENTR_TEMPLE_OF_TIME_7), but 0x282 (ENTR_HYRULE_FIELD_10) has been repurposed to differentiate from Prelude which also uses 0x5F4)
|
||||
}
|
||||
@ -494,7 +476,7 @@ void Entrance_OverrideBlueWarp(void) {
|
||||
void Entrance_OverrideCutsceneEntrance(u16 cutsceneCmd) {
|
||||
switch (cutsceneCmd) {
|
||||
case 24: // Dropping a fish for Jabu Jabu
|
||||
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(newJabuJabusBellyEntrance);
|
||||
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(ENTR_JABU_JABU_0);
|
||||
gPlayState->transitionTrigger = TRANS_TRIGGER_START;
|
||||
gPlayState->transitionType = TRANS_TYPE_FADE_BLACK;
|
||||
// In case Jabu's mouth leads to a grotto return
|
||||
@ -513,8 +495,8 @@ void Entrance_EnableFW(void) {
|
||||
gPlayState->sceneNum == SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR || gPlayState->sceneNum == SCENE_GROTTOS ||
|
||||
gPlayState->sceneNum == SCENE_FISHING_POND || gPlayState->sceneNum == SCENE_GANON_BOSS ||
|
||||
gSaveContext.eventInf[0] & 0x1 || // Ingo's Minigame state
|
||||
player->stateFlags1 & 0x08A02000 || // Swimming, riding horse, Down A, hanging from a ledge
|
||||
player->stateFlags2 & 0x00040000 // Blank A
|
||||
player->stateFlags1 & (PLAYER_STATE1_HANGING_OFF_LEDGE | PLAYER_STATE1_CLIMBING_LADDER | PLAYER_STATE1_ON_HORSE | PLAYER_STATE1_IN_WATER) || // Swimming, riding horse, Down A, hanging from a ledge
|
||||
player->stateFlags2 & PLAYER_STATE2_CRAWLING // Blank A
|
||||
// Shielding, spinning and getting skull tokens still disable buttons automatically
|
||||
) {
|
||||
return;
|
||||
|
@ -8,20 +8,6 @@
|
||||
|
||||
#define ENTRANCE_TABLE_SIZE ENTR_MAX
|
||||
|
||||
#define DEKU_TREE_ENTRANCE ENTR_DEKU_TREE_0
|
||||
#define DODONGOS_CAVERN_ENTRANCE ENTR_DODONGOS_CAVERN_0
|
||||
#define JABU_JABUS_BELLY_ENTRANCE ENTR_JABU_JABU_0
|
||||
#define FOREST_TEMPLE_ENTRANCE ENTR_FOREST_TEMPLE_0
|
||||
#define FIRE_TEMPLE_ENTRANCE ENTR_FIRE_TEMPLE_0
|
||||
#define WATER_TEMPLE_ENTRANCE ENTR_WATER_TEMPLE_0
|
||||
#define SPIRIT_TEMPLE_ENTRANCE ENTR_SPIRIT_TEMPLE_0
|
||||
#define SHADOW_TEMPLE_ENTRANCE ENTR_SHADOW_TEMPLE_0
|
||||
#define BOTTOM_OF_THE_WELL_ENTRANCE ENTR_BOTTOM_OF_THE_WELL_0
|
||||
#define GERUDO_TRAINING_GROUNDS_ENTRANCE ENTR_GERUDO_TRAINING_GROUND_0
|
||||
#define ICE_CAVERN_ENTRANCE ENTR_ICE_CAVERN_0
|
||||
#define GANONS_CASTLE_ENTRANCE ENTR_INSIDE_GANONS_CASTLE_0
|
||||
#define LINK_HOUSE_SAVEWARP_ENTRANCE ENTR_LINKS_HOUSE_0
|
||||
|
||||
#define ENTRANCE_RANDO_GROTTO_LOAD_START 0x0700
|
||||
#define ENTRANCE_RANDO_GROTTO_EXIT_START 0x0800
|
||||
#define MAX_ENTRANCE_RANDO_USED_INDEX 0x0820
|
||||
@ -66,7 +52,7 @@ typedef enum {
|
||||
#define ENTRANCE_RANDO_GROTTO_LOAD(index) ENTRANCE_RANDO_GROTTO_LOAD_START + index
|
||||
#define ENTRANCE_RANDO_GROTTO_EXIT(index) ENTRANCE_RANDO_GROTTO_EXIT_START + index
|
||||
|
||||
#define ENTRANCE_OVERRIDES_MAX_COUNT 259 // 11 one-way entrances + 124 two-way entrances (x2)
|
||||
#define ENTRANCE_OVERRIDES_MAX_COUNT 267 // 19 one-way entrances + 124 two-way entrances (x2)
|
||||
#define SHUFFLEABLE_BOSS_COUNT 8
|
||||
|
||||
#define SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT 66 // Max entrance rando index is 0x0820, (2080 / 32 == 65) + 1
|
||||
@ -79,9 +65,9 @@ typedef enum {
|
||||
(((startTransType) << ENTRANCE_INFO_START_TRANS_TYPE_SHIFT) & ENTRANCE_INFO_START_TRANS_TYPE_MASK))
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
int16_t index;
|
||||
int16_t destination;
|
||||
int16_t blueWarp;
|
||||
int16_t override;
|
||||
int16_t overrideDestination;
|
||||
} EntranceOverride;
|
||||
|
@ -104,6 +104,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_KOKIRI_FOREST_1, ENTR_DEKU_TREE_0, SINGLE_SCENE_INFO(SCENE_DEKU_TREE), "Deku Tree", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, ""},
|
||||
{ ENTR_DEKU_TREE_BOSS_0, ENTR_DEKU_TREE_1, SINGLE_SCENE_INFO(SCENE_DEKU_TREE), "Deku Tree Boss Door", "Gohma", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_DEKU_TREE_1, ENTR_DEKU_TREE_BOSS_0, SINGLE_SCENE_INFO(SCENE_DEKU_TREE_BOSS), "Gohma", "Deku Tree Boss Door", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_KOKIRI_FOREST_11, -1, SINGLE_SCENE_INFO(SCENE_DEKU_TREE_BOSS), "Gohma", "Deku Tree Blue Warp", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
|
||||
// Lost Woods
|
||||
{ ENTR_KOKIRI_FOREST_2, ENTR_LOST_WOODS_9, SINGLE_SCENE_INFO(SCENE_LOST_WOODS), "Lost Woods Bridge", "KF", ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_OVERWORLD, "lw"},
|
||||
@ -131,6 +132,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_SACRED_FOREST_MEADOW_1, ENTR_FOREST_TEMPLE_0, SINGLE_SCENE_INFO(SCENE_FOREST_TEMPLE), "Forest Temple", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON},
|
||||
{ ENTR_FOREST_TEMPLE_BOSS_0, ENTR_FOREST_TEMPLE_1, SINGLE_SCENE_INFO(SCENE_FOREST_TEMPLE), "Forest Temple Boss Door", "Phantom Ganon", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_FOREST_TEMPLE_1, ENTR_FOREST_TEMPLE_BOSS_0, SINGLE_SCENE_INFO(SCENE_FOREST_TEMPLE_BOSS), "Phantom Ganon", "Forest Temple Boss Door", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_SACRED_FOREST_MEADOW_3, -1, SINGLE_SCENE_INFO(SCENE_FOREST_TEMPLE_BOSS), "Phantom Ganon", "Forest Temple Blue Warp", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
|
||||
// Kakariko Village
|
||||
{ ENTR_HYRULE_FIELD_1, ENTR_KAKARIKO_VILLAGE_0, SINGLE_SCENE_INFO(SCENE_KAKARIKO_VILLAGE), "Kakariko", "Hyrule Field", ENTRANCE_GROUP_KAKARIKO, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"},
|
||||
@ -179,6 +181,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_GRAVEYARD_1, ENTR_SHADOW_TEMPLE_0, SINGLE_SCENE_INFO(SCENE_SHADOW_TEMPLE), "Shadow Temple", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON},
|
||||
{ ENTR_SHADOW_TEMPLE_BOSS_0, ENTR_SHADOW_TEMPLE_1, SINGLE_SCENE_INFO(SCENE_SHADOW_TEMPLE), "Shadow Temple Boss Door", "Bongo-Bongo", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_SHADOW_TEMPLE_1, ENTR_SHADOW_TEMPLE_BOSS_0, SINGLE_SCENE_INFO(SCENE_SHADOW_TEMPLE_BOSS), "Bongo-Bongo", "Shadow Temple Boss Door", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_GRAVEYARD_8, -1, SINGLE_SCENE_INFO(SCENE_SHADOW_TEMPLE_BOSS), "Bongo-Bongo", "Shadow Temple Blue Warp", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
|
||||
// Death Mountain Trail
|
||||
{ ENTR_GORON_CITY_0, ENTR_DEATH_MOUNTAIN_TRAIL_1, SINGLE_SCENE_INFO(SCENE_DEATH_MOUNTAIN_TRAIL), "DMT", "Goron City", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_GORON_CITY, ENTRANCE_TYPE_OVERWORLD, "gc"},
|
||||
@ -194,6 +197,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_DEATH_MOUNTAIN_TRAIL_3, ENTR_DODONGOS_CAVERN_0, SINGLE_SCENE_INFO(SCENE_DODONGOS_CAVERN), "Dodongo's Cavern", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc"},
|
||||
{ ENTR_DODONGOS_CAVERN_BOSS_0, ENTR_DODONGOS_CAVERN_1, SINGLE_SCENE_INFO(SCENE_DODONGOS_CAVERN), "Dodongo's Cavern Boss Door", "King Dodongo", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1},
|
||||
{ ENTR_DODONGOS_CAVERN_1, ENTR_DODONGOS_CAVERN_BOSS_0, SINGLE_SCENE_INFO(SCENE_DODONGOS_CAVERN_BOSS), "King Dodongo", "Dodongo's Cavern Boss Door", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1},
|
||||
{ ENTR_DEATH_MOUNTAIN_TRAIL_5, -1, SINGLE_SCENE_INFO(SCENE_DODONGOS_CAVERN_BOSS), "King Dodongo", "Dodongo's Cavern Blue Warp", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_ONE_WAY, "dc,bw", 1},
|
||||
|
||||
// Death Mountain Crater
|
||||
{ ENTR_GORON_CITY_1, ENTR_DEATH_MOUNTAIN_CRATER_1, SINGLE_SCENE_INFO(SCENE_DEATH_MOUNTAIN_CRATER), "DMC", "Goron City", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_GORON_CITY, ENTRANCE_TYPE_OVERWORLD, "gc"},
|
||||
@ -208,6 +212,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_DEATH_MOUNTAIN_CRATER_2, ENTR_FIRE_TEMPLE_0, SINGLE_SCENE_INFO(SCENE_FIRE_TEMPLE), "Fire Temple", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON},
|
||||
{ ENTR_FIRE_TEMPLE_BOSS_0, ENTR_FIRE_TEMPLE_1, SINGLE_SCENE_INFO(SCENE_FIRE_TEMPLE), "Fire Temple Boss Door", "Volvagia", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_FIRE_TEMPLE_1, ENTR_FIRE_TEMPLE_BOSS_0, SINGLE_SCENE_INFO(SCENE_FIRE_TEMPLE_BOSS), "Volvagia", "Fire Temple Boss Door", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_DEATH_MOUNTAIN_CRATER_5, -1, SINGLE_SCENE_INFO(SCENE_FIRE_TEMPLE_BOSS), "Volvagia", "Fire Temple Blue Warp", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
|
||||
// Goron City
|
||||
{ ENTR_DEATH_MOUNTAIN_TRAIL_1, ENTR_GORON_CITY_0, SINGLE_SCENE_INFO(SCENE_GORON_CITY), "Goron City", "DMT", ENTRANCE_GROUP_GORON_CITY, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_OVERWORLD, "gc"},
|
||||
@ -247,6 +252,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_ZORAS_FOUNTAIN_1, ENTR_JABU_JABU_0, SINGLE_SCENE_INFO(SCENE_JABU_JABU), "Jabu Jabu's Belly", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON},
|
||||
{ ENTR_JABU_JABU_BOSS_0, ENTR_JABU_JABU_1, SINGLE_SCENE_INFO(SCENE_JABU_JABU), "Jabu Jabu's Belly Boss Door", "Barinade", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_JABU_JABU_1, ENTR_JABU_JABU_BOSS_0, SINGLE_SCENE_INFO(SCENE_JABU_JABU_BOSS), "Barinade", "Jabu Jabu's Belly Boss Door", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_ZORAS_FOUNTAIN_0, -1, SINGLE_SCENE_INFO(SCENE_JABU_JABU_BOSS), "Barinade", "Jabu Jabu's Belly Blue Warp", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
{ ENTR_ZORAS_FOUNTAIN_3, ENTR_ICE_CAVERN_0, SINGLE_SCENE_INFO(SCENE_ICE_CAVERN), "Ice Cavern", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON},
|
||||
|
||||
// Hyrule Field
|
||||
@ -298,6 +304,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_LAKE_HYLIA_2, ENTR_WATER_TEMPLE_0, SINGLE_SCENE_INFO(SCENE_WATER_TEMPLE), "Water Temple", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh"},
|
||||
{ ENTR_WATER_TEMPLE_BOSS_0, ENTR_WATER_TEMPLE_1, SINGLE_SCENE_INFO(SCENE_WATER_TEMPLE), "Water Temple Boss Door", "Morpha", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1},
|
||||
{ ENTR_WATER_TEMPLE_1, ENTR_WATER_TEMPLE_BOSS_0, SINGLE_SCENE_INFO(SCENE_WATER_TEMPLE_BOSS), "Morpha", "Water Temple Boss Door", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1},
|
||||
{ ENTR_LAKE_HYLIA_9, -1, SINGLE_SCENE_INFO(SCENE_WATER_TEMPLE_BOSS), "Morpha", "Water Temple Blue Warp", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_ONE_WAY, "lh,bw", 1},
|
||||
|
||||
// Gerudo Area
|
||||
{ ENTR_HYRULE_FIELD_5, ENTR_GERUDO_VALLEY_0, SINGLE_SCENE_INFO(SCENE_GERUDO_VALLEY), "GV", "Hyrule Field", ENTRANCE_GROUP_GERUDO_VALLEY, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"},
|
||||
@ -328,6 +335,7 @@ const EntranceData entranceData[] = {
|
||||
{ ENTR_DESERT_COLOSSUS_1, ENTR_SPIRIT_TEMPLE_0, SINGLE_SCENE_INFO(SCENE_SPIRIT_TEMPLE), "Spirit Temple", "Desert Colossus", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "dc"},
|
||||
{ ENTR_SPIRIT_TEMPLE_BOSS_0, ENTR_SPIRIT_TEMPLE_1, SINGLE_SCENE_INFO(SCENE_SPIRIT_TEMPLE), "Spirit Temple Boss Door", "Twinrova", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_SPIRIT_TEMPLE_1, ENTR_SPIRIT_TEMPLE_BOSS_0, SINGLE_SCENE_INFO(SCENE_SPIRIT_TEMPLE_BOSS), "Twinrova", "Spirit Temple Boss Door", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "", 1},
|
||||
{ ENTR_DESERT_COLOSSUS_8, -1, SINGLE_SCENE_INFO(SCENE_SPIRIT_TEMPLE_BOSS), "Twinrova", "Spirit Temple Blue Warp", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
|
||||
|
||||
// Market
|
||||
{ ENTR_HYRULE_FIELD_7, ENTR_MARKET_ENTRANCE_DAY_1, {SCENE_NO_SPAWN(SCENE_MARKET_ENTRANCE_DAY), SCENE_NO_SPAWN(SCENE_MARKET_ENTRANCE_NIGHT), SCENE_NO_SPAWN(SCENE_MARKET_ENTRANCE_RUINS)}, "Market Entrance", "Hyrule Field", ENTRANCE_GROUP_MARKET, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"},
|
||||
@ -797,6 +805,11 @@ void EntranceTrackerWindow::DrawElement() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// RANDOTODO: Only show blue warps if bluewarp shuffle is on
|
||||
if (original->metaTag.ends_with("bw") || override->metaTag.ends_with("bw")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isDiscovered = IsEntranceDiscovered(entrance.index);
|
||||
|
||||
bool showOriginal = (!destToggle ? CVarGetInteger("gEntranceTrackerShowTo", 0) : CVarGetInteger("gEntranceTrackerShowFrom", 0)) || isDiscovered;
|
||||
|
@ -30,6 +30,8 @@ void DrawBottle(ItemTrackerItem item);
|
||||
void DrawQuest(ItemTrackerItem item);
|
||||
void DrawSong(ItemTrackerItem item);
|
||||
|
||||
int itemTrackerSectionId;
|
||||
|
||||
bool shouldUpdateVectors = true;
|
||||
|
||||
std::vector<ItemTrackerItem> mainWindowItems = {};
|
||||
@ -282,11 +284,6 @@ void ItemTrackerOnFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
void SaveNotes(uint32_t fileNum) {
|
||||
CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str());
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
|
||||
bool IsValidSaveFile() {
|
||||
bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2;
|
||||
return validSave;
|
||||
@ -755,7 +752,7 @@ void DrawNotes(bool resizeable = false) {
|
||||
}
|
||||
if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) {
|
||||
notesNeedSave = false;
|
||||
SaveNotes(gSaveContext.fileNum);
|
||||
SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true);
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
@ -980,6 +977,26 @@ void UpdateVectors() {
|
||||
shouldUpdateVectors = false;
|
||||
}
|
||||
|
||||
void ItemTrackerInitFile(bool isDebug) {
|
||||
itemTrackerNotes.clear();
|
||||
itemTrackerNotes.push_back(0);
|
||||
}
|
||||
|
||||
void ItemTrackerSaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
||||
SaveManager::Instance->SaveData("personalNotes", std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str());
|
||||
}
|
||||
|
||||
void ItemTrackerLoadFile() {
|
||||
std::string initialTrackerNotes = "";
|
||||
SaveManager::Instance->LoadData("personalNotes", initialTrackerNotes);
|
||||
itemTrackerNotes.resize(initialTrackerNotes.length() + 1);
|
||||
if (initialTrackerNotes != "") {
|
||||
SohUtils::CopyStringToCharArray(itemTrackerNotes.Data, initialTrackerNotes.c_str(), itemTrackerNotes.size());
|
||||
} else {
|
||||
itemTrackerNotes.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ItemTrackerWindow::DrawElement() {
|
||||
UpdateVectors();
|
||||
|
||||
@ -1249,14 +1266,9 @@ void ItemTrackerWindow::InitElement() {
|
||||
itemTrackerNotes.push_back(0);
|
||||
}
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadFile>([](uint32_t fileNum) {
|
||||
const char* initialTrackerNotes = CVarGetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), "");
|
||||
itemTrackerNotes.resize(strlen(initialTrackerNotes) + 1);
|
||||
strcpy(itemTrackerNotes.Data, initialTrackerNotes);
|
||||
});
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnDeleteFile>([](uint32_t fileNum) {
|
||||
CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), "");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
});
|
||||
SaveManager::Instance->AddInitFunction(ItemTrackerInitFile);
|
||||
itemTrackerSectionId = SaveManager::Instance->AddSaveFunction("itemTrackerData", 1, ItemTrackerSaveFile, true, -1);
|
||||
SaveManager::Instance->AddLoadFunction("itemTrackerData", 1, ItemTrackerLoadFile);
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(ItemTrackerOnFrame);
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ void RegisterOnInterfaceUpdateHook() {
|
||||
|
||||
prevTimer = timer;
|
||||
|
||||
if (!GameInteractor::IsSaveLoaded()) return;
|
||||
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||
|
||||
static int16_t lostHealth = 0;
|
||||
static int16_t prevHealth = 0;
|
||||
@ -1037,24 +1037,24 @@ void InitTTSBank() {
|
||||
break;
|
||||
}
|
||||
|
||||
auto sceneFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/scenes" + languageSuffix);
|
||||
auto sceneFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/scenes" + languageSuffix);
|
||||
if (sceneFile != nullptr) {
|
||||
sceneMap = nlohmann::json::parse(sceneFile->Buffer, nullptr, true, true);
|
||||
sceneMap = nlohmann::json::parse(*sceneFile->Buffer.get(), nullptr, true, true);
|
||||
}
|
||||
|
||||
auto miscFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/misc" + languageSuffix);
|
||||
auto miscFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/misc" + languageSuffix);
|
||||
if (miscFile != nullptr) {
|
||||
miscMap = nlohmann::json::parse(miscFile->Buffer, nullptr, true, true);
|
||||
miscMap = nlohmann::json::parse(*miscFile->Buffer.get(), nullptr, true, true);
|
||||
}
|
||||
|
||||
auto kaleidoFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/kaleidoscope" + languageSuffix);
|
||||
auto kaleidoFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/kaleidoscope" + languageSuffix);
|
||||
if (kaleidoFile != nullptr) {
|
||||
kaleidoMap = nlohmann::json::parse(kaleidoFile->Buffer, nullptr, true, true);
|
||||
kaleidoMap = nlohmann::json::parse(*kaleidoFile->Buffer.get(), nullptr, true, true);
|
||||
}
|
||||
|
||||
auto fileChooseFile = LUS::Context::GetInstance()->GetResourceManager()->LoadFile("accessibility/texts/filechoose" + languageSuffix);
|
||||
auto fileChooseFile = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFileRaw("accessibility/texts/filechoose" + languageSuffix);
|
||||
if (fileChooseFile != nullptr) {
|
||||
fileChooseMap = nlohmann::json::parse(fileChooseFile->Buffer, nullptr, true, true);
|
||||
fileChooseMap = nlohmann::json::parse(*fileChooseFile->Buffer.get(), nullptr, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,8 @@ void Extractor::ShowSizeErrorBox() const {
|
||||
}
|
||||
|
||||
void Extractor::ShowCrcErrorBox() const {
|
||||
ShowErrorBox("Rom CRC invalid", "Rom CRC did not match the list of known good roms. Please find another.");
|
||||
ShowErrorBox("Rom CRC invalid", "Rom CRC did not match the list of known compatible roms. Please find another.\n\n"
|
||||
"Visit https://ship.equipment/ to validate your ROM and see a list of compatible versions");
|
||||
}
|
||||
|
||||
void Extractor::ShowCompressedErrorBox() const {
|
||||
@ -479,7 +480,8 @@ bool Extractor::Run(std::string searchPath, RomSearchMode searchMode) {
|
||||
ShowCrcErrorBox();
|
||||
} else {
|
||||
ShowErrorBox("Rom CRC invalid",
|
||||
"Rom CRC did not match the list of known good roms. Trying the next one...");
|
||||
"Rom CRC did not match the list of known compatible roms. Trying the next one...\n\n"
|
||||
"Visit https://ship.equipment/ to validate your ROM and see a list of compatible versions");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ GameInteractorSail* GameInteractorSail::Instance;
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
// Resource Types/Factories
|
||||
#include "soh/resource/type/SohResourceType.h"
|
||||
#include "soh/resource/type/Animation.h"
|
||||
#include "soh/resource/type/AudioSample.h"
|
||||
#include "soh/resource/type/AudioSequence.h"
|
||||
@ -319,19 +320,24 @@ OTRGlobals::OTRGlobals() {
|
||||
|
||||
SPDLOG_INFO("Starting Ship of Harkinian version {}", (char*)gBuildVersion);
|
||||
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Room, "Room", std::make_shared<LUS::SceneFactory>()); // Is room scene? maybe?
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_CollisionHeader, "CollisionHeader", std::make_shared<LUS::CollisionHeaderFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Skeleton, "Skeleton", std::make_shared<LUS::SkeletonFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_SkeletonLimb, "SkeletonLimb", std::make_shared<LUS::SkeletonLimbFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Path, "Path", std::make_shared<LUS::PathFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Cutscene, "Cutscene", std::make_shared<LUS::CutsceneFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Text, "Text", std::make_shared<LUS::TextFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSample, "AudioSample", std::make_shared<LUS::AudioSampleFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSoundFont, "AudioSoundFont", std::make_shared<LUS::AudioSoundFontFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_AudioSequence, "AudioSequence", std::make_shared<LUS::AudioSequenceFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Background, "Background", std::make_shared<LUS::BackgroundFactory>());
|
||||
auto loader = context->GetResourceManager()->GetResourceLoader();
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAnimationV0>(), RESOURCE_FORMAT_BINARY, "Animation", static_cast<uint32_t>(SOH::ResourceType::SOH_Animation), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryPlayerAnimationV0>(), RESOURCE_FORMAT_BINARY, "PlayerAnimation", static_cast<uint32_t>(SOH::ResourceType::SOH_PlayerAnimation), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinarySceneV0>(), RESOURCE_FORMAT_BINARY, "Room", static_cast<uint32_t>(SOH::ResourceType::SOH_Room), 0); // Is room scene? maybe?
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryCollisionHeaderV0>(), RESOURCE_FORMAT_BINARY, "CollisionHeader", static_cast<uint32_t>(SOH::ResourceType::SOH_CollisionHeader), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLCollisionHeaderV0>(), RESOURCE_FORMAT_XML, "CollisionHeader", static_cast<uint32_t>(SOH::ResourceType::SOH_CollisionHeader), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinarySkeletonV0>(), RESOURCE_FORMAT_BINARY, "Skeleton", static_cast<uint32_t>(SOH::ResourceType::SOH_Skeleton), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLSkeletonV0>(), RESOURCE_FORMAT_XML, "Skeleton", static_cast<uint32_t>(SOH::ResourceType::SOH_Skeleton), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinarySkeletonLimbV0>(), RESOURCE_FORMAT_BINARY, "SkeletonLimb", static_cast<uint32_t>(SOH::ResourceType::SOH_SkeletonLimb), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLSkeletonLimbV0>(), RESOURCE_FORMAT_XML, "SkeletonLimb", static_cast<uint32_t>(SOH::ResourceType::SOH_SkeletonLimb), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryPathV0>(), RESOURCE_FORMAT_BINARY, "Path", static_cast<uint32_t>(SOH::ResourceType::SOH_Path), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryCutsceneV0>(), RESOURCE_FORMAT_BINARY, "Cutscene", static_cast<uint32_t>(SOH::ResourceType::SOH_Cutscene), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryTextV0>(), RESOURCE_FORMAT_BINARY, "Text", static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLTextV0>(), RESOURCE_FORMAT_XML, "Text", static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSampleV2>(), RESOURCE_FORMAT_BINARY, "AudioSample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 2);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSoundFontV2>(), RESOURCE_FORMAT_BINARY, "AudioSoundFont", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 2);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSequenceV2>(), RESOURCE_FORMAT_BINARY, "AudioSequence", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 2);
|
||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryBackgroundV0>(), RESOURCE_FORMAT_BINARY, "Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
|
||||
|
||||
gSaveStateMgr = std::make_shared<SaveStateMgr>();
|
||||
gRandomizer = std::make_shared<Randomizer>();
|
||||
@ -354,7 +360,7 @@ OTRGlobals::OTRGlobals() {
|
||||
cameraStrings[i] = dup;
|
||||
}
|
||||
|
||||
auto versions = context->GetResourceManager()->GetArchive()->GetGameVersions();
|
||||
auto versions = context->GetResourceManager()->GetArchiveManager()->GetGameVersions();
|
||||
|
||||
for (uint32_t version : versions) {
|
||||
if (!ValidHashes.contains(version)) {
|
||||
@ -534,7 +540,7 @@ extern "C" void VanillaItemTable_Init() {
|
||||
static GetItemEntry getItemTable[] = {
|
||||
GET_ITEM(ITEM_BOMBS_5, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBS_5),
|
||||
GET_ITEM(ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_NUTS_5),
|
||||
GET_ITEM(ITEM_BOMBCHU, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBCHUS_10),
|
||||
GET_ITEM(ITEM_BOMBCHU, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_BOMBCHUS_10),
|
||||
GET_ITEM(ITEM_BOW, OBJECT_GI_BOW, GID_BOW, 0x31, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_BOW),
|
||||
GET_ITEM(ITEM_SLINGSHOT, OBJECT_GI_PACHINKO, GID_SLINGSHOT, 0x30, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_SLINGSHOT),
|
||||
GET_ITEM(ITEM_BOOMERANG, OBJECT_GI_BOOMERANG, GID_BOOMERANG, 0x35, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_BOOMERANG),
|
||||
@ -637,8 +643,8 @@ extern "C" void VanillaItemTable_Init() {
|
||||
GET_ITEM(ITEM_BOMBS_20, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBS_20),
|
||||
GET_ITEM(ITEM_BOMBS_30, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBS_30),
|
||||
GET_ITEM(ITEM_SEEDS_30, OBJECT_GI_SEED, GID_SEEDS, 0xDC, 0x50, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_SEEDS_30),
|
||||
GET_ITEM(ITEM_BOMBCHUS_5, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBCHUS_5),
|
||||
GET_ITEM(ITEM_BOMBCHUS_20, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BOMBCHUS_20),
|
||||
GET_ITEM(ITEM_BOMBCHUS_5, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_BOMBCHUS_5),
|
||||
GET_ITEM(ITEM_BOMBCHUS_20, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_MAJOR, MOD_NONE, GI_BOMBCHUS_20),
|
||||
GET_ITEM(ITEM_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, GI_FISH),
|
||||
GET_ITEM(ITEM_BUG, OBJECT_GI_INSECT, GID_BUG, 0x7A, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BUGS),
|
||||
GET_ITEM(ITEM_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0x5D, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, GI_BLUE_FIRE),
|
||||
@ -836,7 +842,7 @@ extern "C" RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID) {
|
||||
}
|
||||
|
||||
extern "C" void OTRExtScanner() {
|
||||
auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*").get();
|
||||
auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles().get();
|
||||
|
||||
for (auto& rPath : lst) {
|
||||
std::vector<std::string> raw = StringHelper::Split(rPath, ".");
|
||||
@ -859,11 +865,11 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
|
||||
OTRVersion version = {};
|
||||
|
||||
// Use a temporary archive instance to load the otr and read the version file
|
||||
auto archive = std::make_shared<LUS::Archive>(otrPath, "", std::unordered_set<uint32_t>(), false);
|
||||
if (archive->IsMainMPQValid()) {
|
||||
auto t = archive->LoadFile("portVersion", false);
|
||||
auto archive = LUS::OtrArchive(otrPath);
|
||||
if (archive.LoadRaw()) {
|
||||
auto t = archive.LoadFileRaw("portVersion");
|
||||
if (t != nullptr && t->IsLoaded) {
|
||||
auto stream = std::make_shared<LUS::MemoryStream>(t->Buffer.data(), t->Buffer.size());
|
||||
auto stream = std::make_shared<LUS::MemoryStream>(t->Buffer->data(), t->Buffer->size());
|
||||
auto reader = std::make_shared<LUS::BinaryReader>(stream);
|
||||
LUS::Endianness endianness = (LUS::Endianness)reader->ReadUByte();
|
||||
reader->SetEndianness(endianness);
|
||||
@ -871,10 +877,9 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
|
||||
version.minor = reader->ReadUInt16();
|
||||
version.patch = reader->ReadUInt16();
|
||||
}
|
||||
archive.UnloadRaw();
|
||||
}
|
||||
|
||||
archive = nullptr;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
@ -1391,7 +1396,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
|
||||
// Actually update the CVar now before runing the alt asset update listeners
|
||||
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
|
||||
gfx_texture_cache_clear();
|
||||
LUS::SkeletonPatcher::UpdateSkeletons();
|
||||
SOH::SkeletonPatcher::UpdateSkeletons();
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
||||
}
|
||||
|
||||
@ -1412,15 +1417,15 @@ extern "C" uint16_t OTRGetPixelDepth(float x, float y) {
|
||||
}
|
||||
|
||||
extern "C" uint32_t ResourceMgr_GetNumGameVersions() {
|
||||
return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions().size();
|
||||
return LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions().size();
|
||||
}
|
||||
|
||||
extern "C" uint32_t ResourceMgr_GetGameVersion(int index) {
|
||||
return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index];
|
||||
return LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index];
|
||||
}
|
||||
|
||||
extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) {
|
||||
uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index];
|
||||
uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index];
|
||||
|
||||
switch (version) {
|
||||
case OOT_NTSC_US_10:
|
||||
@ -1443,7 +1448,7 @@ extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) {
|
||||
}
|
||||
|
||||
extern "C" uint32_t ResourceMgr_GetGameRegion(int index) {
|
||||
uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index];
|
||||
uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions()[index];
|
||||
|
||||
switch (version) {
|
||||
case OOT_NTSC_US_10:
|
||||
@ -1529,7 +1534,7 @@ extern "C" void ResourceMgr_UnloadResource(const char* resName) {
|
||||
// OTRTODO: There is probably a more elegant way to go about this...
|
||||
// Kenix: This is definitely leaking memory when it's called.
|
||||
extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) {
|
||||
auto lst = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles(searchMask);
|
||||
auto lst = LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles(searchMask);
|
||||
char** result = (char**)malloc(lst->size() * sizeof(char*));
|
||||
|
||||
for (size_t i = 0; i < lst->size(); i++) {
|
||||
@ -1619,7 +1624,7 @@ extern "C" uint8_t ResourceMgr_TexIsRaw(const char* texPath) {
|
||||
|
||||
extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) {
|
||||
auto res = GetResourceByNameHandlingMQ(texPath);
|
||||
return res->GetInitData()->Type == LUS::ResourceType::SOH_Background;
|
||||
return res->GetInitData()->Type == static_cast<uint32_t>(SOH::ResourceType::SOH_Background);
|
||||
}
|
||||
|
||||
extern "C" char* ResourceMgr_LoadJPEG(char* data, size_t dataSize)
|
||||
@ -1667,9 +1672,9 @@ extern "C" uint16_t ResourceMgr_LoadTexHeightByName(char* texPath);
|
||||
extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) {
|
||||
auto res = GetResourceByNameHandlingMQ(filePath);
|
||||
|
||||
if (res->GetInitData()->Type == LUS::ResourceType::DisplayList)
|
||||
if (res->GetInitData()->Type == static_cast<uint32_t>(LUS::ResourceType::DisplayList))
|
||||
return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]);
|
||||
else if (res->GetInitData()->Type == LUS::ResourceType::Array)
|
||||
else if (res->GetInitData()->Type == static_cast<uint32_t>(LUS::ResourceType::Array))
|
||||
return (char*)(std::static_pointer_cast<LUS::Array>(res))->Vertices.data();
|
||||
else {
|
||||
return (char*)GetResourceDataByNameHandlingMQ(filePath);
|
||||
@ -1679,7 +1684,7 @@ extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) {
|
||||
extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) {
|
||||
auto res = GetResourceByNameHandlingMQ(filePath);
|
||||
|
||||
if (res->GetInitData()->Type == LUS::ResourceType::DisplayList)
|
||||
if (res->GetInitData()->Type == static_cast<uint32_t>(LUS::ResourceType::DisplayList))
|
||||
return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]);
|
||||
|
||||
return nullptr;
|
||||
@ -1690,7 +1695,7 @@ extern "C" Sprite* GetSeedTexture(uint8_t index) {
|
||||
}
|
||||
|
||||
extern "C" char* ResourceMgr_LoadPlayerAnimByName(const char* animPath) {
|
||||
auto anim = std::static_pointer_cast<LUS::PlayerAnimation>(GetResourceByNameHandlingMQ(animPath));
|
||||
auto anim = std::static_pointer_cast<SOH::PlayerAnimation>(GetResourceByNameHandlingMQ(animPath));
|
||||
|
||||
return (char*)&anim->limbRotData[0];
|
||||
}
|
||||
@ -1954,7 +1959,7 @@ extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, Skel
|
||||
// Therefore we can take this oppurtunity to take note of the Skeleton that is created...
|
||||
if (skelAnime != nullptr) {
|
||||
auto stringPath = std::string(path);
|
||||
LUS::SkeletonPatcher::RegisterSkeleton(stringPath, skelAnime);
|
||||
SOH::SkeletonPatcher::RegisterSkeleton(stringPath, skelAnime);
|
||||
}
|
||||
|
||||
return skelHeader;
|
||||
@ -1962,12 +1967,12 @@ extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, Skel
|
||||
|
||||
extern "C" void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime) {
|
||||
if (skelAnime != nullptr)
|
||||
LUS::SkeletonPatcher::UnregisterSkeleton(skelAnime);
|
||||
SOH::SkeletonPatcher::UnregisterSkeleton(skelAnime);
|
||||
}
|
||||
|
||||
extern "C" void ResourceMgr_ClearSkeletons(SkelAnime* skelAnime) {
|
||||
if (skelAnime != nullptr)
|
||||
LUS::SkeletonPatcher::ClearSkeletons();
|
||||
SOH::SkeletonPatcher::ClearSkeletons();
|
||||
}
|
||||
|
||||
extern "C" s32* ResourceMgr_LoadCSByName(const char* path) {
|
||||
@ -2589,10 +2594,11 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
|
||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetGoronMessage(choice);
|
||||
} else if (Randomizer_GetSettingValue(RSK_FROGS_HINT) && textId == TEXT_FROGS_UNDERWATER) {
|
||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetFrogsMessage(textId);
|
||||
} else if (Randomizer_GetSettingValue(RSK_SARIA_HINT)) {
|
||||
if ((gPlayState->sceneNum == SCENE_SACRED_FOREST_MEADOW && textId == TEXT_SARIA_SFM) || (textId >= TEXT_SARIAS_SONG_TEXT_START && textId <= TEXT_SARIAS_SONG_TEXT_END)) {
|
||||
} else if (Randomizer_GetSettingValue(RSK_SARIA_HINT) &&
|
||||
(gPlayState->sceneNum == SCENE_SACRED_FOREST_MEADOW && textId == TEXT_SARIA_SFM) || (textId >= TEXT_SARIAS_SONG_FACE_TO_FACE && textId <= TEXT_SARIAS_SONG_CHANNELING_POWER)) {
|
||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetSariaMessage(textId);
|
||||
}
|
||||
} else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_100) {
|
||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_100);
|
||||
}
|
||||
}
|
||||
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {
|
||||
|
@ -184,9 +184,9 @@ void SaveManager::LoadRandomizerVersion2() {
|
||||
|
||||
SaveManager::Instance->LoadArray("entrances", ARRAY_COUNT(gSaveContext.entranceOverrides), [&](size_t i) {
|
||||
SaveManager::Instance->LoadStruct("", [&]() {
|
||||
SaveManager::Instance->LoadData("type", gSaveContext.entranceOverrides[i].type);
|
||||
SaveManager::Instance->LoadData("index", gSaveContext.entranceOverrides[i].index);
|
||||
SaveManager::Instance->LoadData("destination", gSaveContext.entranceOverrides[i].destination);
|
||||
SaveManager::Instance->LoadData("blueWarp", gSaveContext.entranceOverrides[i].blueWarp);
|
||||
SaveManager::Instance->LoadData("override", gSaveContext.entranceOverrides[i].override);
|
||||
SaveManager::Instance->LoadData("overrideDestination", gSaveContext.entranceOverrides[i].overrideDestination);
|
||||
});
|
||||
@ -292,9 +292,9 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
|
||||
|
||||
SaveManager::Instance->SaveArray("entrances", ARRAY_COUNT(saveContext->entranceOverrides), [&](size_t i) {
|
||||
SaveManager::Instance->SaveStruct("", [&]() {
|
||||
SaveManager::Instance->SaveData("type", saveContext->entranceOverrides[i].type);
|
||||
SaveManager::Instance->SaveData("index", saveContext->entranceOverrides[i].index);
|
||||
SaveManager::Instance->SaveData("destination", saveContext->entranceOverrides[i].destination);
|
||||
SaveManager::Instance->SaveData("blueWarp", saveContext->entranceOverrides[i].blueWarp);
|
||||
SaveManager::Instance->SaveData("override", saveContext->entranceOverrides[i].override);
|
||||
SaveManager::Instance->SaveData("overrideDestination", saveContext->entranceOverrides[i].overrideDestination);
|
||||
});
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "Enhancements/cosmetics/authenticGfxPatches.h"
|
||||
#include "Enhancements/resolution-editor/ResolutionEditor.h"
|
||||
#include "Enhancements/debugger/MessageViewer.h"
|
||||
|
||||
bool ToggleAltAssetsAtEndOfFrame = false;
|
||||
bool isBetaQuestEnabled = false;
|
||||
@ -116,12 +117,15 @@ namespace SohGui {
|
||||
std::shared_ptr<LUS::GuiWindow> mInputEditorWindow;
|
||||
|
||||
std::shared_ptr<AudioEditor> mAudioEditorWindow;
|
||||
std::shared_ptr<InputViewer> mInputViewer;
|
||||
std::shared_ptr<InputViewerSettingsWindow> mInputViewerSettings;
|
||||
std::shared_ptr<CosmeticsEditorWindow> mCosmeticsEditorWindow;
|
||||
std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
||||
std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
||||
std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
|
||||
std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
||||
std::shared_ptr<ValueViewerWindow> mValueViewerWindow;
|
||||
std::shared_ptr<MessageViewer> mMessageViewerWindow;
|
||||
std::shared_ptr<GameplayStatsWindow> mGameplayStatsWindow;
|
||||
std::shared_ptr<CheckTracker::CheckTrackerSettingsWindow> mCheckTrackerSettingsWindow;
|
||||
std::shared_ptr<CheckTracker::CheckTrackerWindow> mCheckTrackerWindow;
|
||||
@ -163,6 +167,10 @@ namespace SohGui {
|
||||
|
||||
mAudioEditorWindow = std::make_shared<AudioEditor>("gAudioEditor.WindowOpen", "Audio Editor");
|
||||
gui->AddGuiWindow(mAudioEditorWindow);
|
||||
mInputViewer = std::make_shared<InputViewer>("gOpenWindows.InputViewer", "Input Viewer");
|
||||
gui->AddGuiWindow(mInputViewer);
|
||||
mInputViewerSettings = std::make_shared<InputViewerSettingsWindow>("gOpenWindows.InputViewerSettings", "Input Viewer Settings");
|
||||
gui->AddGuiWindow(mInputViewerSettings);
|
||||
mCosmeticsEditorWindow = std::make_shared<CosmeticsEditorWindow>("gCosmeticsEditorEnabled", "Cosmetics Editor");
|
||||
gui->AddGuiWindow(mCosmeticsEditorWindow);
|
||||
mActorViewerWindow = std::make_shared<ActorViewerWindow>("gActorViewerEnabled", "Actor Viewer");
|
||||
@ -175,6 +183,8 @@ namespace SohGui {
|
||||
gui->AddGuiWindow(mDLViewerWindow);
|
||||
mValueViewerWindow = std::make_shared<ValueViewerWindow>("gValueViewer.WindowOpen", "Value Viewer");
|
||||
gui->AddGuiWindow(mValueViewerWindow);
|
||||
mMessageViewerWindow = std::make_shared<MessageViewer>("gMessageViewerEnabled", "Message Viewer");
|
||||
gui->AddGuiWindow(mMessageViewerWindow);
|
||||
mGameplayStatsWindow = std::make_shared<GameplayStatsWindow>("gGameplayStatsEnabled", "Gameplay Stats");
|
||||
gui->AddGuiWindow(mGameplayStatsWindow);
|
||||
mCheckTrackerWindow = std::make_shared<CheckTracker::CheckTrackerWindow>("gCheckTrackerEnabled", "Check Tracker");
|
||||
@ -204,6 +214,7 @@ namespace SohGui {
|
||||
mGameplayStatsWindow = nullptr;
|
||||
mDLViewerWindow = nullptr;
|
||||
mValueViewerWindow = nullptr;
|
||||
mMessageViewerWindow = nullptr;
|
||||
mSaveEditorWindow = nullptr;
|
||||
mColViewerWindow = nullptr;
|
||||
mActorViewerWindow = nullptr;
|
||||
@ -213,5 +224,7 @@ namespace SohGui {
|
||||
mStatsWindow = nullptr;
|
||||
mConsoleWindow = nullptr;
|
||||
mSohMenuBar = nullptr;
|
||||
mInputViewer = nullptr;
|
||||
mInputViewerSettings = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <stdio.h>
|
||||
#include "SohMenuBar.h"
|
||||
#include "Enhancements/audio/AudioEditor.h"
|
||||
#include "Enhancements/controls/InputViewer.h"
|
||||
#include "Enhancements/cosmetics/CosmeticsEditor.h"
|
||||
#include "Enhancements/debugger/actorViewer.h"
|
||||
#include "Enhancements/debugger/colViewer.h"
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
|
||||
#include "Enhancements/audio/AudioEditor.h"
|
||||
#include "Enhancements/controls/InputViewer.h"
|
||||
#include "Enhancements/cosmetics/CosmeticsEditor.h"
|
||||
#include "Enhancements/debugger/actorViewer.h"
|
||||
#include "Enhancements/debugger/colViewer.h"
|
||||
@ -28,6 +29,7 @@
|
||||
#include "Enhancements/debugger/dlViewer.h"
|
||||
#include "Enhancements/debugger/valueViewer.h"
|
||||
#include "Enhancements/gameplaystatswindow.h"
|
||||
#include "Enhancements/debugger/MessageViewer.h"
|
||||
#include "Enhancements/randomizer/randomizer_check_tracker.h"
|
||||
#include "Enhancements/randomizer/randomizer_entrance_tracker.h"
|
||||
#include "Enhancements/randomizer/randomizer_item_tracker.h"
|
||||
@ -103,6 +105,7 @@ static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large
|
||||
"OHKO"
|
||||
};
|
||||
static const char* timeTravelOptions[3] = { "Disabled", "Ocarina of Time", "Any Ocarina" };
|
||||
static const char* swordToggleModes[3] = { "Disabled", "Child Toggle", "Both Ages (May lead to unintended behaviour)"};
|
||||
|
||||
extern "C" SaveContext gSaveContext;
|
||||
|
||||
@ -111,11 +114,11 @@ namespace SohGui {
|
||||
void DrawMenuBarIcon() {
|
||||
static bool gameIconLoaded = false;
|
||||
if (!gameIconLoaded) {
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTexture("Game_Icon", "textures/icons/gIcon.png");
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTextureFromRawImage("Game_Icon", "textures/icons/gIcon.png");
|
||||
gameIconLoaded = true;
|
||||
}
|
||||
|
||||
if (LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon")) {
|
||||
if (LUS::Context::GetInstance()->GetWindow()->GetGui()->HasTextureByName("Game_Icon")) {
|
||||
#ifdef __SWITCH__
|
||||
ImVec2 iconSize = ImVec2(20.0f, 20.0f);
|
||||
float posScale = 1.0f;
|
||||
@ -179,6 +182,8 @@ void DrawShipMenu() {
|
||||
}
|
||||
|
||||
extern std::shared_ptr<LUS::GuiWindow> mInputEditorWindow;
|
||||
extern std::shared_ptr<InputViewer> mInputViewer;
|
||||
extern std::shared_ptr<InputViewerSettingsWindow> mInputViewerSettings;
|
||||
extern std::shared_ptr<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow> mAdvancedResolutionSettingsWindow;
|
||||
|
||||
void DrawSettingsMenu() {
|
||||
@ -201,8 +206,7 @@ void DrawSettingsMenu() {
|
||||
|
||||
static std::unordered_map<LUS::AudioBackend, const char*> audioBackendNames = {
|
||||
{ LUS::AudioBackend::WASAPI, "Windows Audio Session API" },
|
||||
{ LUS::AudioBackend::PULSE, "PulseAudio" },
|
||||
{ LUS::AudioBackend::SDL, "SDL" },
|
||||
{ LUS::AudioBackend::SDL, "SDL" }
|
||||
};
|
||||
|
||||
ImGui::Text("Audio API (Needs reload)");
|
||||
@ -245,11 +249,25 @@ void DrawSettingsMenu() {
|
||||
#ifndef __SWITCH__
|
||||
UIWidgets::EnhancementCheckbox("Menubar Controller Navigation", "gControlNav");
|
||||
UIWidgets::Tooltip("Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: This will disable game inputs while the menubar is visible.\n\nD-pad to move between items, A to select, and X to grab focus on the menu bar");
|
||||
UIWidgets::PaddedSeparator();
|
||||
#endif
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false);
|
||||
UIWidgets::Tooltip("Shows currently pressed inputs on the bottom right of the screen");
|
||||
UIWidgets::PaddedEnhancementSliderFloat("Input Scale: %.2f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false, true, true, false);
|
||||
UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2 (12.0f, 6.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f));
|
||||
if (mInputViewer) {
|
||||
if (ImGui::Button(GetWindowButtonText("Input Viewer", CVarGetInteger("gOpenWindows.InputViewer", 0)).c_str(), ImVec2 (-1.0f, 0.0f))) {
|
||||
mInputViewer->ToggleVisibility();
|
||||
}
|
||||
}
|
||||
if (mInputViewerSettings) {
|
||||
if (ImGui::Button(GetWindowButtonText("Input Viewer Settings", CVarGetInteger("gOpenWindows.InputViewerSettings", 0)).c_str(), ImVec2 (-1.0f, 0.0f))) {
|
||||
mInputViewerSettings->ToggleVisibility();
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", "gSimulatedInputLag", 0, 6, "", 0, true, true, false);
|
||||
UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later");
|
||||
|
||||
@ -631,6 +649,8 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("The default response to Kaepora Gaebora is always that you understood what he said");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Exit Market at Night", "gMarketSneak", true, false);
|
||||
UIWidgets::Tooltip("Allows exiting Hyrule Castle Market Town to Hyrule Field at night by speaking to the guard next to the gate.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Shops and Games Always Open", "gEnhancements.OpenAllHours", true, false);
|
||||
UIWidgets::Tooltip("Shops and minigames are open both day and night. Requires scene reload to take effect.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Link as default file name", "gLinkDefaultName", true, false);
|
||||
UIWidgets::Tooltip("Allows you to have \"Link\" as a premade file name");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Quit Fishing At Door", "gQuitFishingAtDoor", true, false);
|
||||
@ -645,6 +665,8 @@ void DrawEnhancementsMenu() {
|
||||
"- Obtained the Master Sword\n"
|
||||
"- Not within range of Time Block\n"
|
||||
"- Not within range of Ocarina playing spots");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Pause Warp", "gPauseWarp", true, false);
|
||||
UIWidgets::Tooltip("Selection of warp song in pause menu initiates warp. Disables song playback.");
|
||||
|
||||
ImGui::EndTable();
|
||||
ImGui::EndMenu();
|
||||
@ -952,9 +974,13 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("Bonking into trees will have a chance to drop up to 3 sticks. Must already have obtained sticks.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false);
|
||||
UIWidgets::Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Hyper Bosses", "gHyperBosses", true, false);
|
||||
if (UIWidgets::PaddedEnhancementCheckbox("Hyper Bosses", "gHyperBosses", true, false)) {
|
||||
UpdateHyperBossesState();
|
||||
}
|
||||
UIWidgets::Tooltip("All major bosses move and act twice as fast.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Hyper Enemies", "gHyperEnemies", true, false);
|
||||
if (UIWidgets::PaddedEnhancementCheckbox("Hyper Enemies", "gHyperEnemies", true, false)) {
|
||||
UpdateHyperEnemiesState();
|
||||
}
|
||||
UIWidgets::Tooltip("All regular enemies and mini-bosses move and act twice as fast.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false);
|
||||
UIWidgets::Tooltip("Always get the heart piece/purple rupee from the spinning Goron pot");
|
||||
@ -965,6 +991,8 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("All dogs can be traded in and will count as Richard.");
|
||||
UIWidgets::PaddedEnhancementSliderInt("Cuccos Stay Put Multiplier: %dx", "##CuccoStayDurationMultiplier", "gCuccoStayDurationMultiplier", 1, 5, "", 1, true, true, false);
|
||||
UIWidgets::Tooltip("Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider.");
|
||||
UIWidgets::PaddedEnhancementSliderInt("Leever Spawn Rate: %d seconds", "##LeeverSpawnRate", "gEnhancements.LeeverSpawnRate", 0, 10, "", 0, true, true, false);
|
||||
UIWidgets::Tooltip("The time between leever groups spawning.");
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@ -981,6 +1009,8 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("Disables the voice audio when Navi calls you");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Disable Hot/Underwater Warning Text", "gDisableTunicWarningText", true, false);
|
||||
UIWidgets::Tooltip("Disables warning text when you don't have on the Goron/Zora Tunic in Hot/Underwater conditions.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Remember Minimap State Between Areas", "gEnhancements.RememberMapToggleState");
|
||||
UIWidgets::Tooltip("Preserves the minimap visibility state when going between areas rather than defaulting it to \"on\" when going through loading zones.");
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@ -993,6 +1023,17 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("Allows equipping the tunic and boots to c-buttons");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false);
|
||||
UIWidgets::Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen.");
|
||||
if (CVarGetInteger("gEquipmentCanBeRemoved", 0)) {
|
||||
UIWidgets::PaddedText("Sword Toggle Options", true, false);
|
||||
UIWidgets::EnhancementCombobox("gEnhancements.SwordToggle", swordToggleModes, SWORD_TOGGLE_NONE);
|
||||
UIWidgets::Tooltip(
|
||||
"Introduces Options for unequipping Link's sword\n\n"
|
||||
"None: Only Biggoron's Sword/Giant's Knife can be toggled. Doing so will equip the Master Sword.\n\n"
|
||||
"Child Toggle: This will allow for completely unequipping any sword as child link.\n\n"
|
||||
"Both Ages: Any sword can be unequipped as either age. This may lead to swordless glitches as Adult.\n"
|
||||
);
|
||||
}
|
||||
|
||||
UIWidgets::PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false);
|
||||
UIWidgets::Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false);
|
||||
@ -1159,6 +1200,8 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::Tooltip("Space between text characters (useful for HD font textures)");
|
||||
UIWidgets::PaddedEnhancementCheckbox("More info in file select", "gFileSelectMoreInfo", true, false);
|
||||
UIWidgets::Tooltip("Shows what items you have collected in the file select screen, like in N64 randomizer");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Better ammo rendering in pause menu", "gEnhancements.BetterAmmoRendering", true, false);
|
||||
UIWidgets::Tooltip("Ammo counts in the pause menu will work correctly regardless of the position of items in the inventory");
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@ -1225,6 +1268,11 @@ void DrawEnhancementsMenu() {
|
||||
UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed",
|
||||
true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
|
||||
UIWidgets::Tooltip("Fixes Darunia's dancing speed so he dances to the beat of Saria's Song, like in vanilla.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Fix raised Floor Switches", "gEnhancements.FixFloorSwitches", true, false);
|
||||
UIWidgets::Tooltip("Fixes the two raised floor switches, the one in Forest Temple Basement and the one at the top of Fire Temple. \n"
|
||||
"This will lower them, making activating them easier");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Fix Zora hint dialogue", "gFixZoraHintDialogue", true, false);
|
||||
UIWidgets::Tooltip("Fixes one Zora's dialogue giving a hint about bringing Ruto's Letter to King Zora to properly occur before moving King Zora rather than after");
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@ -1516,6 +1564,8 @@ void DrawCheatsMenu() {
|
||||
UIWidgets::Tooltip("This syncs the ingame time with the real world time");
|
||||
UIWidgets::PaddedEnhancementCheckbox("No ReDead/Gibdo Freeze", "gNoRedeadFreeze", true, false);
|
||||
UIWidgets::Tooltip("Prevents ReDeads and Gibdos from being able to freeze you with their scream");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Keese/Guay don't target you", "gNoKeeseGuayTarget", true, false);
|
||||
UIWidgets::Tooltip("Keese and Guay no longer target you and simply ignore you as if you were wearing the skull mask");
|
||||
{
|
||||
static int32_t betaQuestEnabled = CVarGetInteger("gEnableBetaQuest", 0);
|
||||
static int32_t lastBetaQuestEnabled = betaQuestEnabled;
|
||||
@ -1592,6 +1642,7 @@ extern std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
||||
extern std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
||||
extern std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
||||
extern std::shared_ptr<ValueViewerWindow> mValueViewerWindow;
|
||||
extern std::shared_ptr<MessageViewer> mMessageViewerWindow;
|
||||
|
||||
void DrawDeveloperToolsMenu() {
|
||||
if (ImGui::BeginMenu("Developer Tools")) {
|
||||
@ -1691,6 +1742,12 @@ void DrawDeveloperToolsMenu() {
|
||||
mValueViewerWindow->ToggleVisibility();
|
||||
}
|
||||
}
|
||||
UIWidgets::Spacer(0);
|
||||
if (mMessageViewerWindow) {
|
||||
if (ImGui::Button(GetWindowButtonText("Message Viewer", CVarGetInteger("gMessageViewerEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
|
||||
mMessageViewerWindow->ToggleVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(3);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
@ -449,7 +449,7 @@ namespace UIWidgets {
|
||||
|
||||
if (changed && !(abs(oldVal - val) < 0.000001f)) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(ticks + 1) << val;
|
||||
ss << std::setprecision(ticks + 1) << std::setiosflags(std::ios_base::fixed) << val;
|
||||
val = std::stof(ss.str());
|
||||
CVarSetFloat(cvarName, val);
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
|
@ -2,32 +2,14 @@
|
||||
#include "soh/resource/type/Animation.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace LUS {
|
||||
std::shared_ptr<IResource>
|
||||
AnimationFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) {
|
||||
auto resource = std::make_shared<Animation>(initData);
|
||||
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
|
||||
|
||||
switch (resource->GetInitData()->ResourceVersion) {
|
||||
case 0:
|
||||
factory = std::make_shared<AnimationFactoryV0>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (factory == nullptr) {
|
||||
SPDLOG_ERROR("Failed to load Animation with version {}", resource->GetInitData()->ResourceVersion);
|
||||
namespace SOH {
|
||||
std::shared_ptr<LUS::IResource> ResourceFactoryBinaryAnimationV0::ReadResource(std::shared_ptr<LUS::File> file) {
|
||||
if (!FileHasValidFormatAndReader(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
factory->ParseFileBinary(reader, resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void LUS::AnimationFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) {
|
||||
std::shared_ptr<Animation> animation = std::static_pointer_cast<Animation>(resource);
|
||||
|
||||
ResourceVersionFactory::ParseFileBinary(reader, animation);
|
||||
auto animation = std::make_shared<Animation>(file->InitData);
|
||||
auto reader = std::get<std::shared_ptr<LUS::BinaryReader>>(file->Reader);
|
||||
|
||||
AnimationType animType = (AnimationType)reader->ReadUInt32();
|
||||
animation->type = animType;
|
||||
@ -100,5 +82,7 @@ void LUS::AnimationFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> read
|
||||
} else if (animType == AnimationType::Legacy) {
|
||||
SPDLOG_DEBUG("BEYTAH ANIMATION?!");
|
||||
}
|
||||
|
||||
return animation;
|
||||
}
|
||||
} // namespace LUS
|
||||
} // namespace SOH
|
@ -1,17 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceFactory.h"
|
||||
#include "ResourceFactoryBinary.h"
|
||||
|
||||
namespace LUS {
|
||||
class AnimationFactory : public ResourceFactory {
|
||||
namespace SOH {
|
||||
class ResourceFactoryBinaryAnimationV0 : public LUS::ResourceFactoryBinary {
|
||||
public:
|
||||
std::shared_ptr<IResource>
|
||||
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
|
||||
std::shared_ptr<LUS::IResource> ReadResource(std::shared_ptr<LUS::File> file) override;
|
||||
};
|
||||
|
||||
class AnimationFactoryV0 : public ResourceVersionFactory {
|
||||
public:
|
||||
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
|
||||
};
|
||||
}; // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -2,33 +2,14 @@
|
||||
#include "soh/resource/type/AudioSample.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace LUS {
|
||||
std::shared_ptr<IResource>
|
||||
AudioSampleFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) {
|
||||
auto resource = std::make_shared<AudioSample>(initData);
|
||||
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
|
||||
|
||||
switch (resource->GetInitData()->ResourceVersion) {
|
||||
case 2:
|
||||
factory = std::make_shared<AudioSampleFactoryV0>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (factory == nullptr) {
|
||||
SPDLOG_ERROR("Failed to load AudioSample with version {}", resource->GetInitData()->ResourceVersion);
|
||||
namespace SOH {
|
||||
std::shared_ptr<LUS::IResource> ResourceFactoryBinaryAudioSampleV2::ReadResource(std::shared_ptr<LUS::File> file) {
|
||||
if (!FileHasValidFormatAndReader(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
factory->ParseFileBinary(reader, resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void LUS::AudioSampleFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader,
|
||||
std::shared_ptr<IResource> resource)
|
||||
{
|
||||
std::shared_ptr<AudioSample> audioSample = std::static_pointer_cast<AudioSample>(resource);
|
||||
ResourceVersionFactory::ParseFileBinary(reader, audioSample);
|
||||
auto audioSample = std::make_shared<AudioSample>(file->InitData);
|
||||
auto reader = std::get<std::shared_ptr<LUS::BinaryReader>>(file->Reader);
|
||||
|
||||
audioSample->sample.codec = reader->ReadUByte();
|
||||
audioSample->sample.medium = reader->ReadUByte();
|
||||
@ -65,9 +46,10 @@ void LUS::AudioSampleFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> re
|
||||
}
|
||||
audioSample->book.book = audioSample->bookData.data();
|
||||
audioSample->sample.book = &audioSample->book;
|
||||
}
|
||||
} // namespace LUS
|
||||
|
||||
return audioSample;
|
||||
}
|
||||
} // namespace SOH
|
||||
|
||||
/*
|
||||
in ResourceMgr_LoadAudioSample we used to have
|
||||
|
@ -1,19 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceFactory.h"
|
||||
#include "ResourceFactoryBinary.h"
|
||||
|
||||
namespace LUS {
|
||||
class AudioSampleFactory : public ResourceFactory
|
||||
{
|
||||
namespace SOH {
|
||||
class ResourceFactoryBinaryAudioSampleV2 : public LUS::ResourceFactoryBinary {
|
||||
public:
|
||||
std::shared_ptr<IResource>
|
||||
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
|
||||
std::shared_ptr<LUS::IResource> ReadResource(std::shared_ptr<LUS::File> file) override;
|
||||
};
|
||||
|
||||
class AudioSampleFactoryV0 : public ResourceVersionFactory
|
||||
{
|
||||
public:
|
||||
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
|
||||
};
|
||||
}; // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -2,33 +2,14 @@
|
||||
#include "soh/resource/type/AudioSequence.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace LUS {
|
||||
std::shared_ptr<IResource>
|
||||
AudioSequenceFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) {
|
||||
auto resource = std::make_shared<AudioSequence>(initData);
|
||||
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
|
||||
|
||||
switch (resource->GetInitData()->ResourceVersion) {
|
||||
case 2:
|
||||
factory = std::make_shared<AudioSequenceFactoryV0>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (factory == nullptr)
|
||||
{
|
||||
SPDLOG_ERROR("Failed to load AudioSequence with version {}", resource->GetInitData()->ResourceVersion);
|
||||
namespace SOH {
|
||||
std::shared_ptr<LUS::IResource> ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<LUS::File> file) {
|
||||
if (!FileHasValidFormatAndReader(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
factory->ParseFileBinary(reader, resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void LUS::AudioSequenceFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader,
|
||||
std::shared_ptr<IResource> resource) {
|
||||
std::shared_ptr<AudioSequence> audioSequence = std::static_pointer_cast<AudioSequence>(resource);
|
||||
ResourceVersionFactory::ParseFileBinary(reader, audioSequence);
|
||||
auto audioSequence = std::make_shared<AudioSequence>(file->InitData);
|
||||
auto reader = std::get<std::shared_ptr<LUS::BinaryReader>>(file->Reader);
|
||||
|
||||
audioSequence->sequence.seqDataSize = reader->ReadInt32();
|
||||
audioSequence->sequenceData.reserve(audioSequence->sequence.seqDataSize);
|
||||
@ -48,5 +29,7 @@ void LUS::AudioSequenceFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader>
|
||||
for (uint32_t i = 0; i < audioSequence->sequence.numFonts; i++) {
|
||||
audioSequence->sequence.fonts[i] = reader->ReadUByte();
|
||||
}
|
||||
|
||||
return audioSequence;
|
||||
}
|
||||
} // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -1,19 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceFactory.h"
|
||||
#include "ResourceFactoryBinary.h"
|
||||
|
||||
namespace LUS {
|
||||
class AudioSequenceFactory : public ResourceFactory
|
||||
{
|
||||
namespace SOH {
|
||||
class ResourceFactoryBinaryAudioSequenceV2 : public LUS::ResourceFactoryBinary {
|
||||
public:
|
||||
std::shared_ptr<IResource>
|
||||
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
|
||||
std::shared_ptr<LUS::IResource> ReadResource(std::shared_ptr<LUS::File> file) override;
|
||||
};
|
||||
|
||||
class AudioSequenceFactoryV0 : public ResourceVersionFactory
|
||||
{
|
||||
public:
|
||||
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
|
||||
};
|
||||
}; // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -3,33 +3,14 @@
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "libultraship/libultraship.h"
|
||||
|
||||
namespace LUS {
|
||||
std::shared_ptr<IResource>
|
||||
AudioSoundFontFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) {
|
||||
auto resource = std::make_shared<AudioSoundFont>(initData);
|
||||
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
|
||||
|
||||
switch (resource->GetInitData()->ResourceVersion) {
|
||||
case 2:
|
||||
factory = std::make_shared<AudioSoundFontFactoryV0>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (factory == nullptr)
|
||||
{
|
||||
SPDLOG_ERROR("Failed to load AudioSoundFont with version {}", resource->GetInitData()->ResourceVersion);
|
||||
namespace SOH {
|
||||
std::shared_ptr<LUS::IResource> ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<LUS::File> file) {
|
||||
if (!FileHasValidFormatAndReader(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
factory->ParseFileBinary(reader, resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void LUS::AudioSoundFontFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader,
|
||||
std::shared_ptr<IResource> resource) {
|
||||
std::shared_ptr<AudioSoundFont> audioSoundFont = std::static_pointer_cast<AudioSoundFont>(resource);
|
||||
ResourceVersionFactory::ParseFileBinary(reader, audioSoundFont);
|
||||
auto audioSoundFont = std::make_shared<AudioSoundFont>(file->InitData);
|
||||
auto reader = std::get<std::shared_ptr<LUS::BinaryReader>>(file->Reader);
|
||||
|
||||
audioSoundFont->soundFont.fntIndex = reader->ReadInt32();
|
||||
audioSoundFont->medium = reader->ReadInt8();
|
||||
@ -186,5 +167,7 @@ void LUS::AudioSoundFontFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader>
|
||||
audioSoundFont->soundEffects.push_back(soundEffect);
|
||||
}
|
||||
audioSoundFont->soundFont.soundEffects = audioSoundFont->soundEffects.data();
|
||||
|
||||
return audioSoundFont;
|
||||
}
|
||||
} // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -1,19 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceFactory.h"
|
||||
#include "ResourceFactoryBinary.h"
|
||||
|
||||
namespace LUS {
|
||||
class AudioSoundFontFactory : public ResourceFactory
|
||||
{
|
||||
namespace SOH {
|
||||
class ResourceFactoryBinaryAudioSoundFontV2 : public LUS::ResourceFactoryBinary {
|
||||
public:
|
||||
std::shared_ptr<IResource>
|
||||
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
|
||||
std::shared_ptr<LUS::IResource> ReadResource(std::shared_ptr<LUS::File> file) override;
|
||||
};
|
||||
|
||||
class AudioSoundFontFactoryV0 : public ResourceVersionFactory
|
||||
{
|
||||
public:
|
||||
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
|
||||
};
|
||||
}; // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -2,31 +2,14 @@
|
||||
#include "soh/resource/type/Background.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace LUS {
|
||||
std::shared_ptr<IResource>
|
||||
BackgroundFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) {
|
||||
auto resource = std::make_shared<Background>(initData);
|
||||
std::shared_ptr<ResourceVersionFactory> factory = nullptr;
|
||||
|
||||
switch (resource->GetInitData()->ResourceVersion) {
|
||||
case 0:
|
||||
factory = std::make_shared<BackgroundFactoryV0>();
|
||||
break;
|
||||
}
|
||||
|
||||
if (factory == nullptr) {
|
||||
SPDLOG_ERROR("Failed to load Background with version {}", resource->GetInitData()->ResourceVersion);
|
||||
namespace SOH {
|
||||
std::shared_ptr<LUS::IResource> ResourceFactoryBinaryBackgroundV0::ReadResource(std::shared_ptr<LUS::File> file) {
|
||||
if (!FileHasValidFormatAndReader(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
factory->ParseFileBinary(reader, resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void BackgroundFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) {
|
||||
std::shared_ptr<Background> background = std::static_pointer_cast<Background>(resource);
|
||||
ResourceVersionFactory::ParseFileBinary(reader, background);
|
||||
auto background = std::make_shared<Background>(file->InitData);
|
||||
auto reader = std::get<std::shared_ptr<LUS::BinaryReader>>(file->Reader);
|
||||
|
||||
uint32_t dataSize = reader->ReadUInt32();
|
||||
|
||||
@ -35,5 +18,7 @@ void BackgroundFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader,
|
||||
for (uint32_t i = 0; i < dataSize; i++) {
|
||||
background->Data.push_back(reader->ReadUByte());
|
||||
}
|
||||
|
||||
return background;
|
||||
}
|
||||
} // namespace LUS
|
||||
} // namespace SOH
|
||||
|
@ -1,17 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource/Resource.h"
|
||||
#include "resource/ResourceFactory.h"
|
||||
#include "resource/ResourceFactoryBinary.h"
|
||||
|
||||
namespace LUS {
|
||||
class BackgroundFactory : public ResourceFactory {
|
||||
namespace SOH {
|
||||
class ResourceFactoryBinaryBackgroundV0 : public LUS::ResourceFactoryBinary {
|
||||
public:
|
||||
std::shared_ptr<IResource>
|
||||
ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override;
|
||||
std::shared_ptr<LUS::IResource> ReadResource(std::shared_ptr<LUS::File> file) override;
|
||||
};
|
||||
|
||||
class BackgroundFactoryV0 : public ResourceVersionFactory {
|
||||
public:
|
||||
void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override;
|
||||
};
|
||||
}; // namespace LUS
|
||||
} // namespace SOH
|
||||
|