Revert "Revert "Merge branch 'develop-zhora' into rando-settings-overhaul""

This reverts commit 109485188cfc8c47698ebb53b009cf852a17ef58.
This commit is contained in:
aMannus 2022-07-19 12:47:04 +02:00
parent 1c384c5b3e
commit 0e4169ee84
130 changed files with 2507 additions and 1259 deletions

1
.gitignore vendored
View File

@ -405,3 +405,4 @@ tags
oot.otr oot.otr
*.sav *.sav
shipofharkinian.ini shipofharkinian.ini
shipofharkinian.json

View File

@ -12,7 +12,7 @@
8. Build the solution. 8. Build the solution.
9. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`. 9. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`.
10. Run `soh/soh.sln` 10. Run `soh/soh.sln`
11. Switch the solution to `Release x86`. 11. Switch the solution to `Release x86` or `Release x64`.
12. Build the solution. 12. Build the solution.
13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`. 13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`.
14. Launch `soh.exe`. 14. Launch `soh.exe`.
@ -63,9 +63,10 @@ make setup -j8 DEBUG=0
# Compile the code (watch the -j parameter as above) # Compile the code (watch the -j parameter as above)
make -j8 DEBUG=0 make -j8 DEBUG=0
# Create macOS app bundle # Create macOS app bundle
make filledappbundle make appbundle
``` ```
9. Launch soh app in the soh folder! 9. Copy your OTR file to ~/Library/Application\ Support/com.shipofharkinian.soh
10. Launch soh app in the soh folder!
# Compatible Roms # Compatible Roms
``` ```

9
Jenkinsfile vendored
View File

@ -125,6 +125,11 @@ pipeline {
agent { agent {
label "SoH-Mac-Builders" label "SoH-Mac-Builders"
} }
environment {
CC = 'clang -arch arm64 -arch x86_64'
CXX = 'clang++ -arch arm64 -arch x86_64'
MACOSX_DEPLOYMENT_TARGET = 10.15
}
steps { steps {
checkout([ checkout([
$class: 'GitSCM', $class: 'GitSCM',
@ -137,8 +142,8 @@ pipeline {
sh ''' sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
cd soh cd soh
export CC="clang -arch arm64 -arch x86_64"; export CXX="clang++ -arch arm64 -arch x86_64"; make setup -j4 OPTFLAGS=-O2 DEBUG=0 LD="ld" make setup -j4 OPTFLAGS=-O2 DEBUG=0 LD="ld"
export CC="clang -arch arm64 -arch x86_64"; export CXX="clang++ -arch arm64 -arch x86_64"; make -j4 DEBUG=0 OPTFLAGS=-O2 LD="ld" make -j4 DEBUG=0 OPTFLAGS=-O2 LD="ld"
make -j4 appbundle make -j4 appbundle
mv ../README.md readme.txt mv ../README.md readme.txt
7z a soh-mac.7z soh.app readme.txt 7z a soh-mac.7z soh.app readme.txt

View File

@ -4,10 +4,15 @@ import os, sys, shutil
import shutil import shutil
from rom_info import Z64Rom from rom_info import Z64Rom
import rom_chooser import rom_chooser
import struct
def BuildOTR(xmlPath, rom): def BuildOTR(xmlPath, rom):
shutil.copytree("assets", "Extract/assets") shutil.copytree("assets", "Extract/assets")
checksum = int(Z64Rom(rom).checksum.value, 16)
with open("Extract/version", "wb") as f:
f.write(struct.pack('<L', checksum))
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out"
execStr += " ed -i %s -b %s -fl CFG/filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom) execStr += " ed -i %s -b %s -fl CFG/filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom)

View File

@ -64,7 +64,7 @@ Other shortcuts:
| Alt+Enter | Fullscreen (DirectX) | | Alt+Enter | Fullscreen (DirectX) |
| Ctrl+R | Reset | | Ctrl+R | Reset |
Currently, DirectX 11 and OpenGL are supported. Change the renderer by opening the `shipofharkinian.ini` configuration file in notepad and add `sdl` to `gfx backend` for OpenGL or leave blank for DirectX. Currently, DirectX 11 and OpenGL are supported. Change the renderer by opening the `shipofharkinian.json` configuration file in notepad and add `sdl` to the quotes in `"GfxBackend": ""` for OpenGL or leave blank for DirectX.
## Take The Survey ## Take The Survey
Want to use cartridge readers in tandem with the OTRGui? Want to use cartridge readers in tandem with the OTRGui?

View File

@ -45,11 +45,11 @@ ifneq ($(DEPRECATION_ON),0)
endif endif
# CXXFLAGS += -DTEXTURE_DEBUG # CXXFLAGS += -DTEXTURE_DEBUG
LDFLAGS := -lm -ldl \ LDFLAGS := -Llib/libgfxd -L../libultraship -L../StormLib/build \
-L../StormLib/build -L../libultraship -lbz2 -pthread -lultraship -lstorm -pthread -lgfxd -lultraship ZAPDUtils/ZAPDUtils.a -lstorm -lbz2 -lm -ldl
ifeq ($(UNAME), Darwin) ifeq ($(UNAME), Darwin)
LDFLAGS += $(shell pkg-config --libs glew libpng zlib) $(shell sdl2-config --libs) -framework OpenGL LDFLAGS += $(shell pkg-config --libs glew libpng zlib) $(shell sdl2-config --libs) -framework OpenGL -framework Foundation
INC += $(shell pkg-config --cflags libpng) INC += $(shell pkg-config --cflags libpng)
else else
LDFLAGS += -lpng -lGL -lGLEW -lX11 -lz -lSDL2 -lpulse LDFLAGS += -lpng -lGL -lGLEW -lX11 -lz -lSDL2 -lpulse
@ -137,4 +137,4 @@ ZAPDUtils:
# Linking # Linking
ZAPD.out: $(O_FILES) lib/libgfxd/libgfxd.a ExporterTest ZAPDUtils StormLib ZAPD.out: $(O_FILES) lib/libgfxd/libgfxd.a ExporterTest ZAPDUtils StormLib
$(CXX) $(CXXFLAGS) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a ../StormLib/build/libstorm.a $(EXPORTERS) $(LDFLAGS) $(OUTPUT_OPTION) $(CXX) $(CXXFLAGS) $(O_FILES) $(EXPORTERS) $(LDFLAGS) $(OUTPUT_OPTION)

View File

@ -2,8 +2,8 @@
curl -sSfLO "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" curl -sSfLO "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
chmod a+x linuxdeploy*.AppImage chmod a+x linuxdeploy*.AppImage
curl -sSfLO "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" curl -sSfL https://github.com$(curl https://github.com/probonopd/go-appimage/releases | grep "mkappimage-.*-x86_64.AppImage" | head -n 1 | cut -d '"' -f 2) -o mkappimage.AppImage
chmod a+x appimagetool*.AppImage chmod a+x mkappimage.AppImage
mkdir -p AppDir/usr/bin mkdir -p AppDir/usr/bin
cp appimage/{soh.desktop,soh.sh} AppDir/ cp appimage/{soh.desktop,soh.sh} AppDir/
@ -30,5 +30,5 @@ export UPD_INFO="gh-releases-zsync|HarbourMasters|Shipwright-linux|develop|SOH-L
cd /soh cd /soh
./appimagetool-x86_64.AppImage --appimage-extract-and-run ./AppDir "SOH-Linux.AppImage" VERSION=Linux ./mkappimage.AppImage --appimage-extract-and-run ./AppDir # "SOH-Linux-x86_64.AppImage"
mv SOH-Linux-x86_64.AppImage SOH-Linux.AppImage # Keep Original Name

View File

@ -3,6 +3,7 @@ HERE="$(dirname "$(readlink -f "${0}")")"/../..
export PATH="$HERE"/bin:"$HERE"/usr/bin:"$PATH" export PATH="$HERE"/bin:"$HERE"/usr/bin:"$PATH"
export LD_LIBRARY_PATH="$HERE"/usr/lib:"$LD_LIBRARY_PATH" export LD_LIBRARY_PATH="$HERE"/usr/lib:"$LD_LIBRARY_PATH"
export ZENITY=$(command -v zenity)
while [[ ! -e "$PWD"/oot.otr ]]; do while [[ ! -e "$PWD"/oot.otr ]]; do
export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)"
@ -14,24 +15,38 @@ while [[ ! -e "$PWD"/oot.otr ]]; do
ln -s "$OLDPWD"/*.*64 "$ASSETDIR"/tmp/rom.z64 ln -s "$OLDPWD"/*.*64 "$ASSETDIR"/tmp/rom.z64
cp -r "$ASSETDIR"/assets/game/ship_of_harkinian "$ASSETDIR"/Extract/assets/ cp -r "$ASSETDIR"/assets/game/ship_of_harkinian "$ASSETDIR"/Extract/assets/
cd "$ASSETDIR" cd "$ASSETDIR"
case $(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }') in ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')
case "$ROMHASH" in
cee6bc3c2a634b41728f2af8da54d9bf8cc14099) cee6bc3c2a634b41728f2af8da54d9bf8cc14099)
ROM=GC_NMQ_D;; ROM=GC_NMQ_D;;
0227d7c0074f2d0ac935631990da8ec5914597b4) 0227d7c0074f2d0ac935631990da8ec5914597b4)
ROM=GC_NMQ_PAL_F;; ROM=GC_NMQ_PAL_F;;
*) *)
if [ -n "$ZENITY" ]; then
zenity --error --timeout=10 --text="ROM hash <b>$ROMHASH</b> does not match" --title="Incorrect ROM file" --width=500 --width=200
else
echo -e "\nrom hash does not match\n" echo -e "\nrom hash does not match\n"
fi
exit;; exit;;
esac esac
if [ -n "$ZENITY" ]; then
(echo "# 25%"; echo "25"; sleep 2; echo "# 50%"; echo "50"; sleep 3; echo "# 75%"; echo "75"; sleep 2; echo "# 100%"; echo "100"; sleep 3) |
zenity --progress --title="OTR Generating..." --timeout=10 --percentage=0 --icon-name=soh --window-icon=soh.png --height=80 --width=400 &
else
echo "Processing..." echo "Processing..."
fi
assets/extractor/ZAPD.out ed -eh -i assets/extractor/xmls/"${ROM}" -b tmp/rom.z64 -fl assets/extractor/filelists -o placeholder -osf placeholder -gsf 1 -rconf assets/extractor/Config_"${ROM}".xml -se OTR > /dev/null 2>&1 assets/extractor/ZAPD.out ed -eh -i assets/extractor/xmls/"${ROM}" -b tmp/rom.z64 -fl assets/extractor/filelists -o placeholder -osf placeholder -gsf 1 -rconf assets/extractor/Config_"${ROM}".xml -se OTR > /dev/null 2>&1
cp "$ASSETDIR"/oot.otr "$OLDPWD" cp "$ASSETDIR"/oot.otr "$OLDPWD"
echo "Restart $APPIMAGE to play!" echo "Restart $APPIMAGE to play!"
sleep 3 sleep 3
rm -r "$ASSETDIR" rm -r "$ASSETDIR"
break break
else
if [ -n "$ZENITY" ]; then
zenity --error --timeout=5 --text="Place ROM in $OWD" --title="Missing ROM file" --width=500 --width=200
else else
echo -e "\nPlace ROM in this folder\n" echo -e "\nPlace ROM in this folder\n"
fi
exit exit
fi fi
done done

View File

@ -11,6 +11,15 @@ DEBUG ?= 1
OPTFLAGS ?= -O0 OPTFLAGS ?= -O0
LTO ?= 0 LTO ?= 0
# flag to save whether the compiler being used is clang or gcc by checking CXX --version
CXX_IS_CLANG ?= $(shell $(CXX) --version | grep -c clang)
ifeq ($(CXX_IS_CLANG),1)
MXX := $(CXX)
else
MXX ?= clang++
endif
WARN := -Wall -Wextra -Werror \ WARN := -Wall -Wextra -Werror \
-Wno-unused-variable \ -Wno-unused-variable \
-Wno-unused-parameter \ -Wno-unused-parameter \
@ -29,8 +38,7 @@ WARN := -Wall -Wextra -Werror \
CWARN := CWARN :=
CXXWARN := -Wno-deprecated-enum-enum-conversion -Wno-deprecated-copy CXXWARN := -Wno-deprecated-enum-enum-conversion -Wno-deprecated-copy
COMPILER_VERSION := $(shell $(CXX) --version) ifneq ($(CXX_IS_CLANG),1)
ifneq '' '$(findstring g++,$(COMPILER_VERSION))'
WARN += -Wno-error=stringop-overflow WARN += -Wno-error=stringop-overflow
CXXWARN += -Wno-error=maybe-uninitialized CXXWARN += -Wno-error=maybe-uninitialized
endif endif
@ -39,12 +47,17 @@ CXXFLAGS := $(WARN) $(CXXWARN) -std=c++20 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG
CFLAGS := $(WARN) $(CWARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 CFLAGS := $(WARN) $(CWARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0
CPPFLAGS := -MMD CPPFLAGS := -MMD
ifeq ($(UNAME), Darwin) #APPLE MMFLAGS := -Wno-deprecated-declarations -ObjC++ -fobjc-weak -fobjc-arc
CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL
# if not using clang, ask clang to use gcc standard library
ifneq ($(CXX_IS_CLANG),1)
STD_ISYSTEM=$(shell ${CXX} -xc++ -E -v - < /dev/null 2>&1 | grep "> search starts here" -A2 | tail -n 2 | head -n 1)
CXX_ISYSTEM=$(shell ${CXX} -xc++ -E -v - < /dev/null 2>&1 | grep "> search starts here" -A2 | tail -n 2 | tail -n 1)
MMFLAGS += -stdlib++-isystem ${STD_ISYSTEM} -cxx-isystem ${CXX_ISYSTEM}
endif endif
ifeq ($(UNAME), Linux) ifeq ($(UNAME), Darwin) #APPLE
WARN += -Wno-error=stringop-overflow # This is required with clang on Linux. CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL -framework Foundation
endif endif
ifneq ($(DEBUG),0) ifneq ($(DEBUG),0)
@ -69,6 +82,7 @@ CXX_FILES := \
$(shell find libultraship/Lib/Fast3D -name "*.cpp") \ $(shell find libultraship/Lib/Fast3D -name "*.cpp") \
$(shell find libultraship -maxdepth 1 -name "*.cpp") \ $(shell find libultraship -maxdepth 1 -name "*.cpp") \
$(shell find libultraship/Lib/ImGui -maxdepth 1 -name "*.cpp") \ $(shell find libultraship/Lib/ImGui -maxdepth 1 -name "*.cpp") \
$(shell find libultraship/Lib/Mercury -maxdepth 1 -name "*.cpp") \
libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \ libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \
libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \ libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \
libultraship/Lib/StrHash64.cpp \ libultraship/Lib/StrHash64.cpp \
@ -78,12 +92,19 @@ C_FILES := \
libultraship/mixer.c \ libultraship/mixer.c \
libultraship/Lib/stb/stb_impl.c libultraship/Lib/stb/stb_impl.c
MM_FILES := \
libultraship/OSXFolderManager.mm
FMT_FILES := $(shell find libultraship/ -type f \( -name "*.cpp" -o -name "*.h" \) -a -not -path "libultraship/Lib/*") FMT_FILES := $(shell find libultraship/ -type f \( -name "*.cpp" -o -name "*.h" \) -a -not -path "libultraship/Lib/*")
O_FILES := \ O_FILES := \
$(CXX_FILES:%.cpp=build/%.o) \ $(CXX_FILES:%.cpp=build/%.o) \
$(C_FILES:%.c=build/%.o) $(C_FILES:%.c=build/%.o)
ifeq ($(UNAME), Darwin) #APPLE
O_FILES += $(MM_FILES:%.mm=build/%.o)
endif
D_FILES := $(O_FILES:%.o=%.d) D_FILES := $(O_FILES:%.o=%.d)
LIB := libultraship.a LIB := libultraship.a
@ -94,6 +115,7 @@ INC_DIRS := $(addprefix -I, \
libultraship/Lib/spdlog \ libultraship/Lib/spdlog \
libultraship/Lib/spdlog/include \ libultraship/Lib/spdlog/include \
libultraship/Lib/ImGui \ libultraship/Lib/ImGui \
libultraship/Lib/Mercury \
libultraship \ libultraship \
../StormLib/src \ ../StormLib/src \
) )
@ -117,6 +139,9 @@ build/%.o: %.cpp
build/%.o: %.c build/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@ $(CC) $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
build/%.o: %.mm
$(MXX) $(MMFLAGS) $(CXXFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
$(LIB): $(O_FILES) $(LIB): $(O_FILES)
$(AR) rcs $@ $^ $(AR) rcs $@ $^

View File

@ -1,164 +0,0 @@
#include "ConfigFile.h"
#include "spdlog/spdlog.h"
#include "GlobalCtx2.h"
#include "Window.h"
#include "GameSettings.h"
namespace Ship {
ConfigFile::ConfigFile(std::shared_ptr<GlobalCtx2> Context, const std::string& Path) : Context(Context), Path(Path), File(Path.c_str()) {
if (Path.empty()) {
SPDLOG_ERROR("ConfigFile received an empty file name");
exit(EXIT_FAILURE);
}
if (!File.read(Val)) {
if (!CreateDefaultConfig()) {
SPDLOG_ERROR("Failed to create default configs");
exit(EXIT_FAILURE);
}
}
}
ConfigFile::~ConfigFile() {
if (!Save()) {
SPDLOG_ERROR("Failed to save configs!!!");
}
SPDLOG_INFO("destruct configfile");
}
mINI::INIMap<std::string>& ConfigFile::operator[](const std::string& Section) {
return Val[Section];
}
mINI::INIMap<std::string> ConfigFile::get(const std::string& Section) {
return Val.get(Section);
}
bool ConfigFile::has(const std::string& Section) {
return Val.has(Section);
}
bool ConfigFile::remove(const std::string& Section) {
return Val.remove(Section);
}
void ConfigFile::clear() {
Val.clear();
}
std::size_t ConfigFile::size() const {
return Val.size();
}
bool ConfigFile::Save() {
return File.write(Val);
}
bool ConfigFile::CreateDefaultConfig() {
(*this)["ARCHIVE"]["Main Archive"] = "oot.otr";
(*this)["ARCHIVE"]["Patches Directory"] = "";
(*this)["SAVE"]["Save Filename"] = "oot_save.sav";
(*this)["CONTROLLERS"]["CONTROLLER 1"] = "Auto";
(*this)["CONTROLLERS"]["CONTROLLER 2"] = "Unplugged";
(*this)["CONTROLLERS"]["CONTROLLER 3"] = "Unplugged";
(*this)["CONTROLLERS"]["CONTROLLER 4"] = "Unplugged";
(*this)["KEYBOARD SHORTCUTS"]["KEY_FULLSCREEN"] = std::to_string(0x044);
(*this)["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"] = std::to_string(0x029);
(*this)["WINDOW"]["WINDOW WIDTH"] = std::to_string(640);
(*this)["WINDOW"]["WINDOW HEIGHT"] = std::to_string(480);
(*this)["WINDOW"]["FULLSCREEN WIDTH"] = std::to_string(1920);
(*this)["WINDOW"]["FULLSCREEN HEIGHT"] = std::to_string(1080);
(*this)["WINDOW"]["FULLSCREEN"] = std::to_string(false);
(*this)["WINDOW"]["GFX BACKEND"] = "";
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CLEFT)] = std::to_string(0x14B);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CDOWN)] = std::to_string(0x150);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CUP)] = std::to_string(0x148);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_R)] = std::to_string(0x013);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_L)] = std::to_string(0x012);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DRIGHT)] = std::to_string(0x023);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DLEFT)] = std::to_string(0x021);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DDOWN)] = std::to_string(0x022);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DUP)] = std::to_string(0x014);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_START)] = std::to_string(0x039);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_Z)] = std::to_string(0x02C);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_B)] = std::to_string(0x02E);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_A)] = std::to_string(0x02D);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKUP)] = std::to_string(0x011);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CLEFT)] = std::to_string(0x14B);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CDOWN)] = std::to_string(0x150);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CUP)] = std::to_string(0x148);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_R)] = std::to_string(0x013);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_L)] = std::to_string(0x012);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DRIGHT)] = std::to_string(0x023);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DLEFT)] = std::to_string(0x021);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DDOWN)] = std::to_string(0x022);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DUP)] = std::to_string(0x014);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_START)] = std::to_string(0x039);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_Z)] = std::to_string(0x02C);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_B)] = std::to_string(0x02E);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_A)] = std::to_string(0x02D);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
(*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKUP)] = std::to_string(0x011);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CLEFT)] = std::to_string(0x14B);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CDOWN)] = std::to_string(0x150);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CUP)] = std::to_string(0x148);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_R)] = std::to_string(0x013);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_L)] = std::to_string(0x012);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DRIGHT)] = std::to_string(0x023);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DLEFT)] = std::to_string(0x021);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DDOWN)] = std::to_string(0x022);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DUP)] = std::to_string(0x014);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_START)] = std::to_string(0x039);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_Z)] = std::to_string(0x02C);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_B)] = std::to_string(0x02E);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_A)] = std::to_string(0x02D);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
(*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKUP)] = std::to_string(0x011);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CLEFT)] = std::to_string(0x14B);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CDOWN)] = std::to_string(0x150);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CUP)] = std::to_string(0x148);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_R)] = std::to_string(0x013);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_L)] = std::to_string(0x012);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DRIGHT)] = std::to_string(0x023);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DLEFT)] = std::to_string(0x021);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DDOWN)] = std::to_string(0x022);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DUP)] = std::to_string(0x014);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_START)] = std::to_string(0x039);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_Z)] = std::to_string(0x02C);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_B)] = std::to_string(0x02E);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_A)] = std::to_string(0x02D);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKUP)] = std::to_string(0x011);
(*this)["ENHANCEMENT SETTINGS"]["TEXT_SPEED"] = "1";
(*this)["SDL CONTROLLER 1"]["GUID"] = "";
(*this)["SDL CONTROLLER 2"]["GUID"] = "";
(*this)["SDL CONTROLLER 3"]["GUID"] = "";
(*this)["SDL CONTROLLER 4"]["GUID"] = "";
return File.generate(Val);
}
}

View File

@ -1,42 +0,0 @@
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
#pragma once
#include <string>
#include <memory>
#include "Lib/mINI/src/mini/ini.h"
#include "UltraController.h"
#include "LUSMacros.h"
namespace Ship {
class GlobalCtx2;
class ConfigFile {
public:
ConfigFile(std::shared_ptr<GlobalCtx2> Context, const std::string& Path);
~ConfigFile();
bool Save();
// Expose the ini values.
mINI::INIMap<std::string>& operator[](const std::string& Section);
mINI::INIMap<std::string> get(const std::string& Section);
bool has(const std::string& Section);
bool remove(const std::string& Section);
void clear();
std::size_t size() const;
std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
protected:
bool CreateDefaultConfig();
private:
mINI::INIStructure Val;
std::weak_ptr<GlobalCtx2> Context;
std::string Path;
mINI::INIFile File;
};
}
#endif

View File

@ -0,0 +1,146 @@
#include "ControlDeck.h"
#include "Window.h"
#include "Controller.h"
#include "DisconnectedController.h"
#include "KeyboardController.h"
#include "SDLController.h"
#include <Utils/StringHelper.h>
uint8_t* controllerBits;
void Ship::ControlDeck::Init(uint8_t* bits) {
ScanPhysicalDevices();
controllerBits = bits;
}
void Ship::ControlDeck::ScanPhysicalDevices() {
virtualDevices.clear();
physicalDevices.clear();
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
auto sdl = std::make_shared<SDLController>(i);
sdl->Open();
physicalDevices.push_back(sdl);
}
}
physicalDevices.push_back(std::make_shared<KeyboardController>());
physicalDevices.push_back(std::make_shared<DisconnectedController>());
for (const auto& device : physicalDevices) {
for (int i = 0; i < MAXCONTROLLERS; i++) {
device->CreateDefaultBinding(i);
}
}
for (int i = 0; i < MAXCONTROLLERS; i++) {
virtualDevices.push_back(i == 0 ? 0 : static_cast<int>(physicalDevices.size()) - 1);
}
LoadControllerSettings();
}
void Ship::ControlDeck::SetPhysicalDevice(int slot, int deviceSlot) {
const std::shared_ptr<Controller> backend = physicalDevices[deviceSlot];
virtualDevices[slot] = deviceSlot;
*controllerBits |= (backend->Connected()) << slot;
}
void Ship::ControlDeck::WriteToPad(OSContPad* pad) const {
for (size_t i = 0; i < virtualDevices.size(); i++) {
physicalDevices[virtualDevices[i]]->Read(&pad[i], i);
}
}
#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__)
void Ship::ControlDeck::LoadControllerSettings() {
std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
for (auto const& val : Config->rjson["Controllers"]["Deck"].items()) {
int slot = std::stoi(val.key().substr(5));
for (size_t dev = 0; dev < physicalDevices.size(); dev++) {
std::string guid = physicalDevices[dev]->GetGuid();
if(guid != val.value()) continue;
virtualDevices[slot] = dev;
}
}
for (size_t i = 0; i < virtualDevices.size(); i++) {
std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
Config->setString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int)i), backend->GetGuid());
}
for (const auto& device : physicalDevices) {
std::string guid = device->GetGuid();
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", slot)))) continue;
auto& profile = device->profiles[slot];
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
profile.Mappings.clear();
profile.Thresholds.clear();
profile.UseRumble = Config->getBool(NESTED("Rumble.Enabled", ""));
profile.RumbleStrength = Config->getFloat(NESTED("Rumble.Strength", ""));
profile.UseGyro = Config->getBool(NESTED("Gyro.Enabled", ""));
for (auto const& val : rawProfile["Thresholds"].items()) {
profile.Thresholds[static_cast<ControllerThresholds>(std::stoi(val.key()))] = val.value();
}
for (auto const& val : rawProfile["Mappings"].items()) {
device->SetButtonMapping(slot, std::stoi(val.key().substr(4)), val.value());
}
}
}
}
void Ship::ControlDeck::SaveControllerSettings() {
std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
for (size_t i = 0; i < virtualDevices.size(); i++) {
std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
Config->setString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int)i), backend->GetGuid());
}
for (const auto& device : physicalDevices) {
int slot = 0;
std::string guid = device->GetGuid();
for (const auto& profile : device->profiles) {
if (!device->Connected()) continue;
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
Config->setBool(NESTED("Rumble.Enabled", ""), profile.UseRumble);
Config->setFloat(NESTED("Rumble.Strength", ""), profile.RumbleStrength);
Config->setBool(NESTED("Gyro.Enabled", ""), profile.UseGyro);
for (auto const& val : rawProfile["Mappings"].items()) {
Config->setInt(NESTED("Mappings.%s", val.key().c_str()), -1);
}
for (auto const& [key, val] : profile.Thresholds) {
Config->setFloat(NESTED("Thresholds.%d", key), val);
}
for (auto const& [key, val] : profile.Mappings) {
Config->setInt(NESTED("Mappings.BTN_%d", val), key);
}
slot++;
}
}
Config->save();
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "Controller.h"
#include <vector>
#include <string>
namespace Ship {
class ControlDeck {
public:
std::vector<int> virtualDevices;
std::vector<std::shared_ptr<Controller>> physicalDevices = {};
void Init(uint8_t* controllerBits);
void ScanPhysicalDevices();
void WriteToPad(OSContPad* pad) const;
void LoadControllerSettings();
void SaveControllerSettings();
void SetPhysicalDevice(int slot, int deviceSlot);
};
}

View File

@ -1,96 +1,80 @@
#include "Controller.h" #include "Controller.h"
#include "GlobalCtx2.h"
#include "stox.h"
#include <memory> #include <memory>
#include <algorithm>
#if __APPLE__
#include <SDL_events.h>
#else
#include <SDL2/SDL_events.h>
#endif
namespace Ship { namespace Ship {
Controller::Controller(int32_t dwControllerNumber) : dwControllerNumber(dwControllerNumber) {
dwPressedButtons = 0; Controller::Controller() : isRumbling(false), wStickX(0), wStickY(0), wGyroX(0), wGyroY(0), dwPressedButtons(0){
wStickX = 0;
wStickY = 0;
wGyroX = 0;
wGyroY = 0;
Attachment = nullptr; Attachment = nullptr;
profiles.resize(MAXCONTROLLERS);
for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons.push_back(0);
}
} }
void Controller::Read(OSContPad* pad) { void Controller::Read(OSContPad* pad, int32_t slot) {
ReadFromSource(); ReadFromSource(slot);
pad->button |= dwPressedButtons & 0xFFFF; SDL_PumpEvents();
if (pad->stick_x == 0) { // Button Inputs
if (dwPressedButtons & BTN_STICKLEFT) { pad->button |= dwPressedButtons[slot] & 0xFFFF;
// Stick Inputs
if (wStickX == 0) {
if (dwPressedButtons[slot] & BTN_STICKLEFT) {
pad->stick_x = -128; pad->stick_x = -128;
} } else if (dwPressedButtons[slot] & BTN_STICKRIGHT) {
else if (dwPressedButtons & BTN_STICKRIGHT) {
pad->stick_x = 127; pad->stick_x = 127;
} }
else { } else {
pad->stick_x = wStickX; pad->stick_x = wStickX;
} }
}
if (pad->stick_y == 0) { if (wStickY == 0) {
if (dwPressedButtons & BTN_STICKDOWN) { if (dwPressedButtons[slot] & BTN_STICKDOWN) {
pad->stick_y = -128; pad->stick_y = -128;
} } else if (dwPressedButtons[slot] & BTN_STICKUP) {
else if (dwPressedButtons & BTN_STICKUP) {
pad->stick_y = 127; pad->stick_y = 127;
} }
else { } else {
pad->stick_y = wStickY; pad->stick_y = wStickY;
} }
// Stick Inputs
if (wCamX == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKLEFT) {
pad->cam_x = -128 * 10.0f;
} else if (dwPressedButtons[slot] & BTN_VSTICKRIGHT) {
pad->cam_x = 127 * 10.0f;
}
} else {
pad->cam_x = wCamX;
} }
if (wCamY == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKDOWN) {
pad->cam_y = -128 * 10.0f;
} else if (dwPressedButtons[slot] & BTN_VSTICKUP) {
pad->cam_y = 127 * 10.0f;
}
} else {
pad->cam_y = wCamY;
}
// Gyro
pad->gyro_x = wGyroX; pad->gyro_x = wGyroX;
pad->gyro_y = wGyroY; pad->gyro_y = wGyroY;
} }
void Controller::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) { void Controller::SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode) {
// Update the config value. std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
std::string ConfSection = GetBindingConfSection(); std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig(); Mappings[dwScancode] = n64Button;
ConfigFile& Conf = *pConf.get();
Conf[ConfSection][szButtonName] = dwScancode;
// Reload the button mapping from Config
LoadBinding();
}
void Controller::LoadBinding() {
std::string ConfSection = GetBindingConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CRIGHT)])] = BTN_CRIGHT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CLEFT)])] = BTN_CLEFT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CDOWN)])] = BTN_CDOWN;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CUP)])] = BTN_CUP;
//ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CRIGHT + "_2")])] = BTN_CRIGHT;
//ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CLEFT + "_2")])] = BTN_CLEFT;
//ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CDOWN + "_2")])] = BTN_CDOWN;
//ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CUP + "_2")])] = BTN_CUP;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_R)])] = BTN_R;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_L)])] = BTN_L;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DRIGHT)])] = BTN_DRIGHT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DLEFT)])] = BTN_DLEFT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DDOWN)])] = BTN_DDOWN;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DUP)])] = BTN_DUP;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_START)])] = BTN_START;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_Z)])] = BTN_Z;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_B)])] = BTN_B;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_A)])] = BTN_A;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKRIGHT)])] = BTN_STICKRIGHT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKLEFT)])] = BTN_STICKLEFT;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKDOWN)])] = BTN_STICKDOWN;
ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKUP)])] = BTN_STICKUP;
}
std::string Controller::GetConfSection() {
return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1);
}
std::string Controller::GetBindingConfSection() {
return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1);
} }
} }

View File

@ -1,51 +1,81 @@
#pragma once #pragma once
#include <memory>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <optional>
#include "stdint.h" #include "stdint.h"
#include "UltraController.h" #include "UltraController.h"
#include "ControllerAttachment.h" #include "ControllerAttachment.h"
#include <vector>
#include <unordered_map>
#define EXTENDED_SCANCODE_BIT (1 << 8) #define EXTENDED_SCANCODE_BIT (1 << 8)
#define AXIS_SCANCODE_BIT (1 << 9) #define AXIS_SCANCODE_BIT (1 << 9)
namespace Ship { namespace Ship {
enum ControllerThresholds {
LEFT_STICK = 1,
RIGHT_STICK = 2,
LEFT_TRIGGER = 3,
RIGHT_TRIGGER = 4,
DRIFT_X = 5,
DRIFT_Y = 6,
SENSITIVITY = 7,
GYRO_SENSITIVITY = 8
};
struct DeviceProfile {
bool UseRumble = false;
bool UseGyro = false;
float RumbleStrength = 1.0f;
std::unordered_map<ControllerThresholds, float> Thresholds;
std::map<int32_t, int32_t> Mappings;
};
class Controller { class Controller {
public: public:
Controller(int32_t dwControllerNumber); virtual ~Controller() = default;
Controller();
void Read(OSContPad* pad); void Read(OSContPad* pad, int32_t slot);
virtual void ReadFromSource() = 0; virtual void ReadFromSource(int32_t slot) = 0;
virtual void WriteToSource(ControllerCallback* controller) = 0; virtual void WriteToSource(int32_t slot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0; virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0; virtual bool CanRumble() const = 0;
virtual bool CanGyro() const = 0;
virtual void CreateDefaultBinding(int32_t slot) = 0;
bool isRumbling; bool isRumbling;
std::vector<DeviceProfile> profiles;
void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode); virtual void ClearRawPress() = 0;
virtual int32_t ReadRawPress() = 0;
void SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode);
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; } std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
int32_t GetControllerNumber() { return dwControllerNumber; }
virtual bool HasPadConf() const = 0; std::string GetGuid() { return GUID; }
virtual std::optional<std::string> GetPadConfSection() = 0; virtual const char* GetButtonName(int slot, int n64Button) = 0;
virtual const char* GetControllerName() = 0;
protected:
int32_t dwPressedButtons;
std::map<int32_t, int32_t> ButtonMapping;
int8_t wStickX; int8_t wStickX;
int8_t wStickY; int8_t wStickY;
float wGyroX; float wGyroX;
float wGyroY; float wGyroY;
float wCamX;
float wCamY;
protected:
std::vector<int32_t> dwPressedButtons;
std::string GUID;
virtual std::string GetControllerType() = 0;
virtual std::string GetConfSection() = 0;
virtual std::string GetBindingConfSection() = 0;
void LoadBinding(); void LoadBinding();
private: private:
std::shared_ptr<ControllerAttachment> Attachment; std::shared_ptr<ControllerAttachment> Attachment;
int32_t dwControllerNumber;
}; };
struct ControllerEntry {
uint8_t* controllerBits;
Controller* entryIO;
};
} }

View File

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <PR/ultra64/gbi.h> #include <PR/ultra64/gbi.h>
#include "imgui_internal.h"
std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars; std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
@ -70,7 +71,7 @@ extern "C" void CVar_SetString(const char* name, const char* value) {
cvar = std::make_unique<CVar>(); cvar = std::make_unique<CVar>();
} }
cvar->type = CVAR_TYPE_STRING; cvar->type = CVAR_TYPE_STRING;
cvar->value.valueStr = value; cvar->value.valueStr = ImStrdup(value);
} }
extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) { extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) {

View File

@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <optional>
#include "Controller.h"
class DisconnectedController final : public Ship::Controller {
public:
DisconnectedController() {
GUID = "Disconnected";
}
std::map<std::vector<std::string>, int32_t> ReadButtonPress();
void ReadFromSource(int32_t slot) override {}
const char* GetControllerName() override { return "Disconnected"; }
const char* GetButtonName(int slot, int n64Button) override { return "None"; }
void WriteToSource(int32_t slot, ControllerCallback* controller) override { }
bool Connected() const override { return false; }
bool CanRumble() const override { return false; }
bool CanGyro() const override { return false; }
void ClearRawPress() override {}
int32_t ReadRawPress() override { return -1; }
bool HasPadConf() const { return true; }
std::optional<std::string> GetPadConfSection() { return "Unk"; }
void CreateDefaultBinding(int32_t slot) override {}
protected:
std::string GetControllerType() { return "Unk"; }
std::string GetConfSection() { return "Unk"; }
std::string GetBindingConfSection() { return "Unk"; }
};

View File

@ -7,7 +7,6 @@
#include <PR/ultra64/pi.h> #include <PR/ultra64/pi.h>
#include <PR/ultra64/message.h> #include <PR/ultra64/message.h>
#include "ConfigFile.h"
#include "Cvar.h" #include "Cvar.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "ImGuiImpl.h" #include "ImGuiImpl.h"
@ -33,18 +32,6 @@ namespace Game {
Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1)); Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1));
} }
void LoadPadSettings() {
const std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf;
for (const auto& [i, controllers] : Ship::Window::Controllers) {
for (const auto& controller : controllers) {
if (auto padConfSection = controller->GetPadConfSection()) {
}
}
}
}
void LoadSettings() { void LoadSettings() {
DebugConsole_LoadCVars(); DebugConsole_LoadCVars();
} }
@ -58,6 +45,7 @@ namespace Game {
ModInternal::RegisterHook<ModInternal::GfxInit>([] { ModInternal::RegisterHook<ModInternal::GfxInit>([] {
gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT));
SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0);
SohImGui::controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
UpdateAudio(); UpdateAudio();
}); });
} }

View File

@ -8,6 +8,9 @@
#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/sohconsole_sink.h" #include "spdlog/sinks/sohconsole_sink.h"
#include "ModManager.h" #include "ModManager.h"
#ifdef __APPLE__
#include "OSXFolderManager.h"
#endif
namespace Ship { namespace Ship {
std::weak_ptr<GlobalCtx2> GlobalCtx2::Context; std::weak_ptr<GlobalCtx2> GlobalCtx2::Context;
@ -29,7 +32,23 @@ namespace Ship {
return GetInstance(); return GetInstance();
} }
GlobalCtx2::GlobalCtx2(const std::string& Name) : Name(Name), MainPath(""), PatchesPath("") { std::string GlobalCtx2::GetAppDirectoryPath() {
#ifdef __APPLE__
FolderManager folderManager;
std::string fpath = std::string(folderManager.pathForDirectory(NSApplicationSupportDirectory, NSUserDomainMask));
fpath.append("/com.shipofharkinian.soh");
return fpath;
#endif
return ".";
}
std::string GlobalCtx2::GetPathRelativeToAppDirectory(const char* path) {
return GlobalCtx2::GetAppDirectoryPath() + "/" + path;
}
GlobalCtx2::GlobalCtx2(std::string Name) : Name(std::move(Name)) {
} }
@ -40,22 +59,19 @@ namespace Ship {
void GlobalCtx2::InitWindow() { void GlobalCtx2::InitWindow() {
InitLogging(); InitLogging();
Config = std::make_shared<ConfigFile>(GlobalCtx2::GetInstance(), "shipofharkinian.ini"); Config = std::make_shared<Mercury>(GetPathRelativeToAppDirectory("shipofharkinian.json"));
MainPath = (*Config)["ARCHIVE"]["Main Archive"]; Config->reload();
if (MainPath.empty()) {
MainPath = "oot.otr"; MainPath = Config->getString("Game.Main Archive", GetPathRelativeToAppDirectory("oot.otr"));
} PatchesPath = Config->getString("Game.Patches Archive", GetAppDirectoryPath() + "/mods");
PatchesPath = (*Config)["ARCHIVE"]["Patches Directory"];
if (PatchesPath.empty()) { ResMan = std::make_shared<ResourceMgr>(GetInstance(), MainPath, PatchesPath);
PatchesPath = "./"; Win = std::make_shared<Window>(GetInstance());
}
ResMan = std::make_shared<ResourceMgr>(GlobalCtx2::GetInstance(), MainPath, PatchesPath);
Win = std::make_shared<Window>(GlobalCtx2::GetInstance());
if (!ResMan->DidLoadSuccessfully()) if (!ResMan->DidLoadSuccessfully())
{ {
#ifdef _WIN32 #ifdef _WIN32
MessageBox(NULL, L"Main OTR file not found!", L"Uh oh", MB_OK); MessageBox(nullptr, L"Main OTR file not found!", L"Uh oh", MB_OK);
#else #else
SPDLOG_ERROR("Main OTR file not found!"); SPDLOG_ERROR("Main OTR file not found!");
#endif #endif
@ -67,11 +83,13 @@ namespace Ship {
void GlobalCtx2::InitLogging() { void GlobalCtx2::InitLogging() {
try { try {
auto logPath = GetPathRelativeToAppDirectory(("logs/" + GetName() + ".log").c_str());
// Setup Logging // Setup Logging
spdlog::init_thread_pool(8192, 1); spdlog::init_thread_pool(8192, 1);
auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>(); auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>();
auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("logs/" + GetName() + ".log", 1024 * 1024 * 10, 10); auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
SohConsoleSink->set_level(spdlog::level::trace); SohConsoleSink->set_level(spdlog::level::trace);
ConsoleSink->set_level(spdlog::level::trace); ConsoleSink->set_level(spdlog::level::trace);
FileSink->set_level(spdlog::level::trace); FileSink->set_level(spdlog::level::trace);
@ -87,7 +105,7 @@ namespace Ship {
} }
} }
void GlobalCtx2::WriteSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size) { void GlobalCtx2::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, const size_t size) {
std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary);
saveFile.seekp(addr); saveFile.seekp(addr);
saveFile.write((char*)dramAddr, size); saveFile.write((char*)dramAddr, size);

View File

@ -6,8 +6,9 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <fstream>
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "ConfigFile.h" #include "Lib/Mercury/Mercury.h"
namespace Ship { namespace Ship {
class ResourceMgr; class ResourceMgr;
@ -22,12 +23,15 @@ namespace Ship {
std::shared_ptr<Window> GetWindow() { return Win; } std::shared_ptr<Window> GetWindow() { return Win; }
std::shared_ptr<ResourceMgr> GetResourceManager() { return ResMan; } std::shared_ptr<ResourceMgr> GetResourceManager() { return ResMan; }
std::shared_ptr<spdlog::logger> GetLogger() { return Logger; } std::shared_ptr<spdlog::logger> GetLogger() { return Logger; }
std::shared_ptr<ConfigFile> GetConfig() { return Config; } std::shared_ptr<Mercury> GetConfig() { return Config; }
void WriteSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size); static std::string GetAppDirectoryPath();
static std::string GetPathRelativeToAppDirectory(const char* path);
void WriteSaveFile(const std::filesystem::path& savePath, uintptr_t addr, void* dramAddr, size_t size);
void ReadSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size); void ReadSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size);
GlobalCtx2(const std::string& Name); GlobalCtx2(std::string Name);
~GlobalCtx2(); ~GlobalCtx2();
protected: protected:
@ -38,7 +42,7 @@ namespace Ship {
static std::weak_ptr <GlobalCtx2> Context; static std::weak_ptr <GlobalCtx2> Context;
std::shared_ptr<spdlog::logger> Logger; std::shared_ptr<spdlog::logger> Logger;
std::shared_ptr<Window> Win; std::shared_ptr<Window> Win;
std::shared_ptr<ConfigFile> Config; // Config needs to be after the Window because we call the Window during it's destructor. std::shared_ptr<Mercury> Config; // Config needs to be after the Window because we call the Window during it's destructor.
std::shared_ptr<ResourceMgr> ResMan; std::shared_ptr<ResourceMgr> ResMan;
std::string Name; std::string Name;
std::string MainPath; std::string MainPath;

View File

@ -5,6 +5,7 @@
#include <functional> #include <functional>
#include "UltraController.h" #include "UltraController.h"
#include "Controller.h"
#define DEFINE_HOOK(name, type) struct name { typedef std::function<type> fn; } #define DEFINE_HOOK(name, type) struct name { typedef std::function<type> fn; }
@ -28,12 +29,11 @@ namespace ModInternal {
} }
DEFINE_HOOK(ControllerRead, void(OSContPad* cont_pad)); DEFINE_HOOK(ControllerRead, void(OSContPad* cont_pad));
DEFINE_HOOK(ControllerRawInput, void(Ship::Controller* backend, uint32_t raw));
DEFINE_HOOK(AudioInit, void()); DEFINE_HOOK(AudioInit, void());
DEFINE_HOOK(LoadTexture, void(const char* path, uint8_t** texture)); DEFINE_HOOK(LoadTexture, void(const char* path, uint8_t** texture));
DEFINE_HOOK(GfxInit, void()); DEFINE_HOOK(GfxInit, void());
DEFINE_HOOK(ExitGame, void());
} }

View File

@ -12,6 +12,7 @@
#include "GameSettings.h" #include "GameSettings.h"
#include "Console.h" #include "Console.h"
#include "Hooks.h" #include "Hooks.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include "Lib/ImGui/imgui_internal.h" #include "Lib/ImGui/imgui_internal.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "ResourceMgr.h" #include "ResourceMgr.h"
@ -63,8 +64,11 @@ namespace SohImGui {
ImGuiIO* io; ImGuiIO* io;
Console* console = new Console; Console* console = new Console;
GameOverlay* overlay = new GameOverlay; GameOverlay* overlay = new GameOverlay;
InputEditor* controller = new InputEditor;
static ImVector<ImRect> s_GroupPanelLabelStack;
bool p_open = false; bool p_open = false;
bool needs_save = false; bool needs_save = false;
int lastBackendID = 0;
const char* filters[3] = { const char* filters[3] = {
"Three-Point", "Three-Point",
@ -72,10 +76,45 @@ namespace SohImGui {
"None" "None"
}; };
std::pair<const char*, const char*> backends[] = {
#ifdef _WIN32
{ "dx11", "DirectX" },
#endif
{ "sdl", "OpenGL" }
};
const char* powers[9] = {
"Vanilla (1x)",
"Double (2x)",
"Quadruple (4x)",
"Octuple (8x)",
"Hexadecuple (16x)",
"Duotrigintuple (32x)",
"Quattuorsexagintuple (64x)",
"Octoviginticentuple (128x)",
"Hexaquinquagintiducentuple (256x)"
};
std::map<std::string, std::vector<std::string>> hiddenwindowCategories; std::map<std::string, std::vector<std::string>> hiddenwindowCategories;
std::map<std::string, std::vector<std::string>> windowCategories; std::map<std::string, std::vector<std::string>> windowCategories;
std::map<std::string, CustomWindow> customWindows; std::map<std::string, CustomWindow> customWindows;
int GetBackendID(std::shared_ptr<Mercury> cfg) {
std::string backend = cfg->getString("Window.GfxBackend");
if (backend.empty()) {
return 0;
}
for (size_t i = 0; i < (sizeof(backends) / sizeof(backends[0])); i++) {
if(backend == backends[i].first) {
return i;
}
}
return 0;
}
int ClampFloatToInt(float value, int min, int max) { int ClampFloatToInt(float value, int min, int max) {
return fmin(fmax(value, min), max); return fmin(fmax(value, min), max);
} }
@ -300,15 +339,23 @@ namespace SohImGui {
io = &ImGui::GetIO(); io = &ImGui::GetIO();
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io->Fonts->AddFontDefault(); io->Fonts->AddFontDefault();
lastBackendID = GetBackendID(GlobalCtx2::GetInstance()->GetConfig());
if (CVar_GetS32("gOpenMenuBar", 0) != 1) { if (CVar_GetS32("gOpenMenuBar", 0) != 1) {
SohImGui::overlay->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu"); SohImGui::overlay->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu");
} }
auto imguiIniPath = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("imgui.ini");
auto imguiLogPath = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("imgui_log.txt");
io->IniFilename = strcpy(new char[imguiIniPath.length() + 1], imguiIniPath.c_str());
io->LogFilename = strcpy(new char[imguiLogPath.length() + 1], imguiLogPath.c_str());
if (UseViewports()) { if (UseViewports()) {
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
} }
console->Init(); console->Init();
overlay->Init(); overlay->Init();
controller->Init();
ImGuiWMInit(); ImGuiWMInit();
ImGuiBackendInit(); ImGuiBackendInit();
@ -329,23 +376,17 @@ namespace SohImGui {
LoadTexture("C-Down", "assets/ship_of_harkinian/buttons/CDown.png"); LoadTexture("C-Down", "assets/ship_of_harkinian/buttons/CDown.png");
}); });
for (const auto& [i, controllers] : Ship::Window::Controllers)
{
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", i).c_str(), 0);
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", i).c_str(), 0);
needs_save = true;
}
ModInternal::RegisterHook<ModInternal::ControllerRead>([](OSContPad* cont_pad) { ModInternal::RegisterHook<ModInternal::ControllerRead>([](OSContPad* cont_pad) {
pads = cont_pad; pads = cont_pad;
}); });
Game::InitSettings(); Game::InitSettings();
CVar_SetS32("gRandoGenerating", 0); CVar_SetS32("gRandoGenerating", 0);
CVar_SetS32("gNewSeedGenerated", 0); CVar_SetS32("gNewSeedGenerated", 0);
CVar_SetS32("gNewFileDropped", 0); CVar_SetS32("gNewFileDropped", 0);
CVar_SetString("gDroppedFile", ""); CVar_SetString("gDroppedFile", "None");
Game::SaveSettings(); // Game::SaveSettings();
} }
void Update(EventImpl event) { void Update(EventImpl event) {
@ -436,11 +477,21 @@ namespace SohImGui {
} }
} }
void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue) void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton)
{ {
int val = CVar_GetS32(cvarName, defaultValue); int val = CVar_GetS32(cvarName, defaultValue);
ImGui::Text(text, val); ImGui::Text(text, val);
if(PlusMinusButton) {
std::string MinusBTNName = " - ##";
MinusBTNName += cvarName;
if (ImGui::Button(MinusBTNName.c_str())) {
val--;
CVar_SetS32(cvarName, val);
needs_save = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
}
if (ImGui::SliderInt(id, &val, min, max, format)) if (ImGui::SliderInt(id, &val, min, max, format))
{ {
@ -448,6 +499,18 @@ namespace SohImGui {
needs_save = true; needs_save = true;
} }
if(PlusMinusButton) {
std::string PlusBTNName = " + ##";
PlusBTNName += cvarName;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNName.c_str())) {
val++;
CVar_SetS32(cvarName, val);
needs_save = true;
}
}
if (val < min) if (val < min)
{ {
val = min; val = min;
@ -463,7 +526,7 @@ namespace SohImGui {
} }
} }
void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage) void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton)
{ {
float val = CVar_GetFloat(cvarName, defaultValue); float val = CVar_GetFloat(cvarName, defaultValue);
@ -472,12 +535,36 @@ namespace SohImGui {
else else
ImGui::Text(text, static_cast<int>(100 * val)); ImGui::Text(text, static_cast<int>(100 * val));
if(PlusMinusButton) {
std::string MinusBTNName = " - ##";
MinusBTNName += cvarName;
if (ImGui::Button(MinusBTNName.c_str())) {
val -= 0.1f;
CVar_SetFloat(cvarName, val);
needs_save = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
}
if (ImGui::SliderFloat(id, &val, min, max, format)) if (ImGui::SliderFloat(id, &val, min, max, format))
{ {
CVar_SetFloat(cvarName, val); CVar_SetFloat(cvarName, val);
needs_save = true; needs_save = true;
} }
if(PlusMinusButton) {
std::string PlusBTNName = " + ##";
PlusBTNName += cvarName;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNName.c_str())) {
val += 0.1f;
CVar_SetFloat(cvarName, val);
needs_save = true;
}
}
if (val < min) if (val < min)
{ {
val = min; val = min;
@ -638,6 +725,8 @@ namespace SohImGui {
ImGui::NewFrame(); ImGui::NewFrame();
const std::shared_ptr<Window> wnd = GlobalCtx2::GetInstance()->GetWindow(); const std::shared_ptr<Window> wnd = GlobalCtx2::GetInstance()->GetWindow();
const std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize; ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize;
@ -674,18 +763,14 @@ namespace SohImGui {
needs_save = true; needs_save = true;
GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = menu_bar; GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = menu_bar;
ShowCursor(menu_bar, Dialogues::dMenubar); ShowCursor(menu_bar, Dialogues::dMenubar);
GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->SaveControllerSettings();
if (CVar_GetS32("gControlNav", 0)) { if (CVar_GetS32("gControlNav", 0)) {
if (CVar_GetS32("gOpenMenuBar", 0)) { if (CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard; io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
} } else {
else
{
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
} }
} } else {
else
{
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
} }
} }
@ -725,6 +810,10 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::Separator();
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Audio")) { if (ImGui::BeginMenu("Audio")) {
EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true); EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true);
@ -736,11 +825,16 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Controller")) if (ImGui::BeginMenu("Controller"))
{ {
EnhancementCheckbox("Use Controller Navigation", "gControlNav"); EnhancementCheckbox("Use Controller Navigation", "gControlNav");
Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar"); Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar");
EnhancementCheckbox("Controller Configuration", "gControllerConfigurationEnabled");
controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
ImGui::Separator(); ImGui::Separator();
// TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected // TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected
@ -754,44 +848,14 @@ namespace SohImGui {
EnhancementCheckbox("Show Inputs", "gInputEnabled"); EnhancementCheckbox("Show Inputs", "gInputEnabled");
Tooltip("Shows currently pressed inputs on the bottom right of the screen"); Tooltip("Shows currently pressed inputs on the bottom right of the screen");
EnhancementCheckbox("Rumble Enabled", "gRumbleEnabled");
EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false); EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false);
Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
ImGui::Separator();
for (const auto& [i, controllers] : Ship::Window::Controllers)
{
bool hasPad = std::find_if(controllers.begin(), controllers.end(), [](const auto& c) {
return c->HasPadConf() && c->Connected();
}) != controllers.end();
if (!hasPad) continue;
auto menuLabel = "Controller " + std::to_string(i + 1);
if (ImGui::BeginMenu(menuLabel.c_str()))
{
EnhancementSliderFloat("Gyro Sensitivity: %d %%", "##GYROSCOPE", StringHelper::Sprintf("gCont%i_GyroSensitivity", i).c_str(), 0.0f, 1.0f, "", 1.0f, true);
if (ImGui::Button("Recalibrate Gyro"))
{
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", i).c_str(), 0);
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", i).c_str(), 0);
needs_save = true;
}
ImGui::Separator();
EnhancementSliderFloat("Rumble Strength: %d %%", "##RUMBLE", StringHelper::Sprintf("gCont%i_RumbleStrength", i).c_str(), 0.0f, 1.0f, "", 1.0f, true);
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::Separator();
}
ImGui::EndMenu(); ImGui::SetCursorPosY(0.0f);
}
if (ImGui::BeginMenu("Graphics")) if (ImGui::BeginMenu("Graphics"))
{ {
@ -818,6 +882,16 @@ namespace SohImGui {
ImGui::Text("Jitter fix: >= %d FPS", fps); ImGui::Text("Jitter fix: >= %d FPS", fps);
} }
std::string MinusBTNELT = " - ##ExtraLatencyThreshold";
std::string PlusBTNELT = " + ##ExtraLatencyThreshold";
if (ImGui::Button(MinusBTNELT.c_str())) {
val--;
CVar_SetS32(cvar, val);
needs_save = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::SliderInt("##ExtraLatencyThreshold", &val, 0, 250, "", ImGuiSliderFlags_AlwaysClamp)) if (ImGui::SliderInt("##ExtraLatencyThreshold", &val, 0, 250, "", ImGuiSliderFlags_AlwaysClamp))
{ {
CVar_SetS32(cvar, val); CVar_SetS32(cvar, val);
@ -830,6 +904,26 @@ namespace SohImGui {
"to work on one frame while GPU works on the previous frame.\n" "to work on one frame while GPU works on the previous frame.\n"
"This setting should be used when your computer is too slow\n" "This setting should be used when your computer is too slow\n"
"to do CPU + GPU work in time."); "to do CPU + GPU work in time.");
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNELT.c_str())) {
val++;
CVar_SetS32(cvar, val);
needs_save = true;
}
}
ImGui::Text("Renderer API (Needs reload)");
if (ImGui::BeginCombo("##RApi", backends[lastBackendID].second)) {
for (uint8_t i = 0; i < sizeof(backends) / sizeof(backends[0]); i++) {
if (ImGui::Selectable(backends[i].second, i == lastBackendID)) {
pConf->setString("Window.GfxBackend", backends[i].first);
lastBackendID = i;
}
}
ImGui::EndCombo();
} }
EXPERIMENTAL(); EXPERIMENTAL();
@ -841,6 +935,8 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Languages")) { if (ImGui::BeginMenu("Languages")) {
EnhancementRadioButton("English", "gLanguages", 0); EnhancementRadioButton("English", "gLanguages", 0);
EnhancementRadioButton("German", "gLanguages", 1); EnhancementRadioButton("German", "gLanguages", 1);
@ -848,6 +944,8 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Enhancements")) if (ImGui::BeginMenu("Enhancements"))
{ {
if (ImGui::BeginMenu("Gameplay")) if (ImGui::BeginMenu("Gameplay"))
@ -881,12 +979,36 @@ namespace SohImGui {
if (ImGui::BeginMenu("Difficulty Options")) if (ImGui::BeginMenu("Difficulty Options"))
{ {
EnhancementSliderInt("Damage Multiplier %dx", "##DAMAGEMUL", "gDamageMul", 1, 4, ""); ImGui::Text("Damage Multiplier");
Tooltip("Modifies all sources of damage not affected by other sliders"); EnhancementCombobox("gDamageMul", powers, 9, 0);
EnhancementSliderInt("Fall Damage Multiplier %dx", "##FALLDAMAGEMUL", "gFallDamageMul", 1, 4, ""); Tooltip("Modifies all sources of damage not affected by other sliders\n\
Tooltip("Modifies all fall damage"); 2x: Can survive all common attacks from the start of the game\n\
EnhancementSliderInt("Void Damage Multiplier %dx", "##VOIDDAMAGEMUL", "gVoidDamageMul", 1, 4, ""); 4x: Dies in 1 hit to any substantial attack from the start of the game\n\
Tooltip("Modifies damage taken after falling into a void"); 8x: Can only survive trivial damage from the start of the game\n\
16x: Can survive all common attacks with max health without double defense\n\
32x: Can survive all common attacks with max health and double defense\n\
64x: Can survive trivial damage with max health without double defense\n\
128x: Can survive trivial damage with max health and double defense\n\
256x: Cannot survive damage");
ImGui::Text("Fall Damage Multiplier");
EnhancementCombobox("gFallDamageMul", powers, 8, 0);
Tooltip("Modifies all fall damage\n\
2x: Can survive all fall damage from the start of the game\n\
4x: Can only survive short fall damage from the start of the game\n\
8x: Cannot survive any fall damage from the start of the game\n\
16x: Can survive all fall damage with max health without double defense\n\
32x: Can survive all fall damage with max health and double defense\n\
64x: Can survive short fall damage with double defense\n\
128x: Cannot survive fall damage");
ImGui::Text("Void Damage Multiplier");
EnhancementCombobox("gVoidDamageMul", powers, 7, 0);
Tooltip("Modifies damage taken after falling into a void\n\
2x: Can survive void damage from the start of the game\n\
4x: Cannot survive void damage from the start of the game\n\
8x: Can survive void damage twice with max health without double defense\n\
16x: Can survive void damage with max health without double defense\n\
32x: Can survive void damage with max health and double defense\n\
64x: Cannot survive void damage");
EnhancementCheckbox("No Random Drops", "gNoRandomDrops"); EnhancementCheckbox("No Random Drops", "gNoRandomDrops");
Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses"); Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
@ -897,54 +1019,54 @@ namespace SohImGui {
{ {
EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect"); EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect");
Tooltip("Enable the following changes to the amount of health restored by Red Potions"); Tooltip("Enable the following changes to the amount of health restored by Red Potions");
EnhancementSliderInt("Red Potion Health: %d", "##REDPOTIONHEALTH", "gRedPotionHealth", 1, 100, ""); EnhancementSliderInt("Red Potion Health: %d", "##REDPOTIONHEALTH", "gRedPotionHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Red Potions"); Tooltip("Changes the amount of health restored by Red Potions");
EnhancementCheckbox("Red Potion Percent Restore", "gRedPercentRestore"); EnhancementCheckbox("Red Potion Percent Restore", "gRedPercentRestore");
Tooltip("Toggles from Red Potions restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Red Potions restoring a fixed amount of health to a percent of the player's current max health");
EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect"); EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect");
Tooltip("Enable the following changes to the amount of mana restored by Green Potions"); Tooltip("Enable the following changes to the amount of mana restored by Green Potions");
EnhancementSliderInt("Green Potion Mana: %d", "##GREENPOTIONMANA", "gGreenPotionMana", 1, 100, ""); EnhancementSliderInt("Green Potion Mana: %d", "##GREENPOTIONMANA", "gGreenPotionMana", 1, 100, "", 0, true);
Tooltip("Changes the amount of mana restored by Green Potions, base max mana is 48, max upgraded mana is 96"); Tooltip("Changes the amount of mana restored by Green Potions, base max mana is 48, max upgraded mana is 96");
EnhancementCheckbox("Green Potion Percent Restore", "gGreenPercentRestore"); EnhancementCheckbox("Green Potion Percent Restore", "gGreenPercentRestore");
Tooltip("Toggles from Green Potions restoring a fixed amount of mana to a percent of the player's current max mana"); Tooltip("Toggles from Green Potions restoring a fixed amount of mana to a percent of the player's current max mana");
EnhancementCheckbox("Change Blue Potion Effects", "gBluePotionEffects"); EnhancementCheckbox("Change Blue Potion Effects", "gBluePotionEffects");
Tooltip("Enable the following changes to the amount of health and mana restored by Blue Potions"); Tooltip("Enable the following changes to the amount of health and mana restored by Blue Potions");
EnhancementSliderInt("Blue Potion Health: %d", "##BLUEPOTIONHEALTH", "gBluePotionHealth", 1, 100, ""); EnhancementSliderInt("Blue Potion Health: %d", "##BLUEPOTIONHEALTH", "gBluePotionHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Blue Potions"); Tooltip("Changes the amount of health restored by Blue Potions");
EnhancementCheckbox("Blue Potion Health Percent Restore", "gBlueHealthPercentRestore"); EnhancementCheckbox("Blue Potion Health Percent Restore", "gBlueHealthPercentRestore");
Tooltip("Toggles from Blue Potions restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Blue Potions restoring a fixed amount of health to a percent of the player's current max health");
EnhancementSliderInt("Blue Potion Mana: %d", "##BLUEPOTIONMANA", "gBluePotionMana", 1, 100, ""); EnhancementSliderInt("Blue Potion Mana: %d", "##BLUEPOTIONMANA", "gBluePotionMana", 1, 100, "", 0, true);
Tooltip("Changes the amount of mana restored by Blue Potions, base max mana is 48, max upgraded mana is 96"); Tooltip("Changes the amount of mana restored by Blue Potions, base max mana is 48, max upgraded mana is 96");
EnhancementCheckbox("Blue Potion Mana Percent Restore", "gBlueManaPercentRestore"); EnhancementCheckbox("Blue Potion Mana Percent Restore", "gBlueManaPercentRestore");
Tooltip("Toggles from Blue Potions restoring a fixed amount of mana to a percent of the player's current max mana"); Tooltip("Toggles from Blue Potions restoring a fixed amount of mana to a percent of the player's current max mana");
EnhancementCheckbox("Change Milk Effect", "gMilkEffect"); EnhancementCheckbox("Change Milk Effect", "gMilkEffect");
Tooltip("Enable the following changes to the amount of health restored by Milk"); Tooltip("Enable the following changes to the amount of health restored by Milk");
EnhancementSliderInt("Milk Health: %d", "##MILKHEALTH", "gMilkHealth", 1, 100, ""); EnhancementSliderInt("Milk Health: %d", "##MILKHEALTH", "gMilkHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Milk"); Tooltip("Changes the amount of health restored by Milk");
EnhancementCheckbox("Milk Percent Restore", "gMilkPercentRestore"); EnhancementCheckbox("Milk Percent Restore", "gMilkPercentRestore");
Tooltip("Toggles from Milk restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Milk restoring a fixed amount of health to a percent of the player's current max health");
EnhancementCheckbox("Separate Half Milk Effect", "gSeparateHalfMilkEffect"); EnhancementCheckbox("Separate Half Milk Effect", "gSeparateHalfMilkEffect");
Tooltip("Enable the following changes to the amount of health restored by Half Milk\nIf this is disabled, Half Milk will behave the same as Full Milk."); Tooltip("Enable the following changes to the amount of health restored by Half Milk\nIf this is disabled, Half Milk will behave the same as Full Milk.");
EnhancementSliderInt("Half Milk Health: %d", "##HALFMILKHEALTH", "gHalfMilkHealth", 1, 100, ""); EnhancementSliderInt("Half Milk Health: %d", "##HALFMILKHEALTH", "gHalfMilkHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Half Milk"); Tooltip("Changes the amount of health restored by Half Milk");
EnhancementCheckbox("Half Milk Percent Restore", "gHalfMilkPercentRestore"); EnhancementCheckbox("Half Milk Percent Restore", "gHalfMilkPercentRestore");
Tooltip("Toggles from Half Milk restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Half Milk restoring a fixed amount of health to a percent of the player's current max health");
EnhancementCheckbox("Change Fairy Effect", "gFairyEffect"); EnhancementCheckbox("Change Fairy Effect", "gFairyEffect");
Tooltip("Enable the following changes to the amount of health restored by Fairies"); Tooltip("Enable the following changes to the amount of health restored by Fairies");
EnhancementSliderInt("Fairy: %d", "##FAIRYHEALTH", "gFairyHealth", 1, 100, ""); EnhancementSliderInt("Fairy: %d", "##FAIRYHEALTH", "gFairyHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Fairies"); Tooltip("Changes the amount of health restored by Fairies");
EnhancementCheckbox("Fairy Percent Restore", "gFairyPercentRestore"); EnhancementCheckbox("Fairy Percent Restore", "gFairyPercentRestore");
Tooltip("Toggles from Fairies restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Fairies restoring a fixed amount of health to a percent of the player's current max health");
EnhancementCheckbox("Change Fairy Revive Effect", "gFairyReviveEffect"); EnhancementCheckbox("Change Fairy Revive Effect", "gFairyReviveEffect");
Tooltip("Enable the following changes to the amount of health restored by Fairy Revivals"); Tooltip("Enable the following changes to the amount of health restored by Fairy Revivals");
EnhancementSliderInt("Fairy Revival: %d", "##FAIRYREVIVEHEALTH", "gFairyReviveHealth", 1, 100, ""); EnhancementSliderInt("Fairy Revival: %d", "##FAIRYREVIVEHEALTH", "gFairyReviveHealth", 1, 100, "", 0, true);
Tooltip("Changes the amount of health restored by Fairy Revivals"); Tooltip("Changes the amount of health restored by Fairy Revivals");
EnhancementCheckbox("Fairy Revive Percent Restore", "gFairyRevivePercentRestore"); EnhancementCheckbox("Fairy Revive Percent Restore", "gFairyRevivePercentRestore");
Tooltip("Toggles from Fairy Revivals restoring a fixed amount of health to a percent of the player's current max health"); Tooltip("Toggles from Fairy Revivals restoring a fixed amount of health to a percent of the player's current max health");
@ -1033,7 +1155,7 @@ namespace SohImGui {
EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16); EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16);
Tooltip("Randomize the animation played on the menu after a certain time"); Tooltip("Randomize the animation played on the menu after a certain time");
if (CVar_GetS32("gPauseLiveLink", 0) >= 16) { if (CVar_GetS32("gPauseLiveLink", 0) >= 16) {
EnhancementSliderInt("Frame to wait: %d", "##MinFrameCount", "gMinFrameCount", 1, 1000, ""); EnhancementSliderInt("Frame to wait: %d", "##MinFrameCount", "gMinFrameCount", 1, 1000, "", 0, true);
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -1105,6 +1227,16 @@ namespace SohImGui {
ImGui::Text("Frame interpolation: %d FPS", fps); ImGui::Text("Frame interpolation: %d FPS", fps);
} }
std::string MinusBTNFPSI = " - ##FPSInterpolation";
std::string PlusBTNFPSI = " + ##FPSInterpolation";
if (ImGui::Button(MinusBTNFPSI.c_str())) {
val--;
CVar_SetS32(fps_cvar, val);
needs_save = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::SliderInt("##FPSInterpolation", &val, 20, 250, "", ImGuiSliderFlags_AlwaysClamp)) if (ImGui::SliderInt("##FPSInterpolation", &val, 20, 250, "", ImGuiSliderFlags_AlwaysClamp))
{ {
CVar_SetS32(fps_cvar, val); CVar_SetS32(fps_cvar, val);
@ -1117,6 +1249,14 @@ namespace SohImGui {
"and might give a worse result.\n" "and might give a worse result.\n"
"For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20\n" "For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20\n"
"Ctrl+Click for keyboard input"); "Ctrl+Click for keyboard input");
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNFPSI.c_str())) {
val++;
CVar_SetS32(fps_cvar, val);
needs_save = true;
}
} }
if (impl.backend == Backend::DX11) if (impl.backend == Backend::DX11)
{ {
@ -1143,9 +1283,14 @@ namespace SohImGui {
EnhancementCheckbox("Skip Text", "gSkipText"); EnhancementCheckbox("Skip Text", "gSkipText");
Tooltip("Holding down B skips text\nKnown to cause a cutscene softlock in Water Temple\nSoftlock can be fixed by pressing D-Right in Debug mode"); Tooltip("Holding down B skips text\nKnown to cause a cutscene softlock in Water Temple\nSoftlock can be fixed by pressing D-Right in Debug mode");
EnhancementCheckbox("Free Camera", "gFreeCamera");
Tooltip("Enables camera control\nNote: You must remap C buttons off of\nthe right stick in the controller\nconfig menu, and map the camera stick\nto the right stick.");
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Cheats")) if (ImGui::BeginMenu("Cheats"))
{ {
if (ImGui::BeginMenu("Infinite...")) { if (ImGui::BeginMenu("Infinite...")) {
@ -1183,6 +1328,8 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Developer Tools")) if (ImGui::BeginMenu("Developer Tools"))
{ {
EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled");
@ -1203,6 +1350,7 @@ namespace SohImGui {
} }
for (const auto& category : windowCategories) { for (const auto& category : windowCategories) {
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu(category.first.c_str())) { if (ImGui::BeginMenu(category.first.c_str())) {
for (const std::string& name : category.second) { for (const std::string& name : category.second) {
std::string varName(name); std::string varName(name);
@ -1224,12 +1372,13 @@ namespace SohImGui {
for (const auto& category : hiddenwindowCategories) { for (const auto& category : hiddenwindowCategories) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::SetNextWindowSize(ImVec2 (0,0)); ImGui::SetNextWindowSize(ImVec2 (0,0));
ImGui::SetNextWindowPos(ImVec2 (-100,-100)); ImGuiWindowFlags HiddenWndFlags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings |
ImGui::Begin(category.first.c_str(), nullptr, ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNavFocus); ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoDecoration;
ImGui::Begin(category.first.c_str(), nullptr, HiddenWndFlags);
ImGui::End(); ImGui::End();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
if (CVar_GetS32("gStatsEnabled", 0)) { if (CVar_GetS32("gStatsEnabled", 0)) {
const float framerate = ImGui::GetIO().Framerate; const float framerate = ImGui::GetIO().Framerate;
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
@ -1248,6 +1397,7 @@ namespace SohImGui {
} }
console->Draw(); console->Draw();
controller->DrawHud();
for (auto& windowIter : customWindows) { for (auto& windowIter : customWindows) {
CustomWindow& window = windowIter.second; CustomWindow& window = windowIter.second;
@ -1413,4 +1563,124 @@ namespace SohImGui {
#endif #endif
return reinterpret_cast<ImTextureID>(id); return reinterpret_cast<ImTextureID>(id);
} }
void BeginGroupPanel(const char* name, const ImVec2& size)
{
ImGui::BeginGroup();
// auto cursorPos = ImGui::GetCursorScreenPos();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::BeginGroup();
ImVec2 effectiveSize = size;
if (size.x < 0.0f)
effectiveSize.x = ImGui::GetContentRegionAvail().x;
else
effectiveSize.x = size.x;
ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f));
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::BeginGroup();
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::SameLine(0.0f, 0.0f);
ImGui::TextUnformatted(name);
auto labelMin = ImGui::GetItemRectMin();
auto labelMax = ImGui::GetItemRectMax();
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
ImGui::BeginGroup();
//ImGui::GetWindowDrawList()->AddRect(labelMin, labelMax, IM_COL32(255, 0, 255, 255));
ImGui::PopStyleVar(2);
#if IMGUI_VERSION_NUM >= 17301
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f;
#else
ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x -= frameHeight * 0.5f;
#endif
ImGui::GetCurrentWindow()->Size.x -= frameHeight;
auto itemWidth = ImGui::CalcItemWidth();
ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight));
s_GroupPanelLabelStack.push_back(ImRect(labelMin, labelMax));
}
void EndGroupPanel(float minHeight) {
ImGui::PopItemWidth();
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
auto frameHeight = ImGui::GetFrameHeight();
ImGui::EndGroup();
//ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64), 4.0f);
ImGui::EndGroup();
ImGui::SameLine(0.0f, 0.0f);
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
ImGui::Dummy(ImVec2(0.0, std::max(frameHeight - frameHeight * 0.5f - itemSpacing.y, minHeight)));
ImGui::EndGroup();
auto itemMin = ImGui::GetItemRectMin();
auto itemMax = ImGui::GetItemRectMax();
//ImGui::GetWindowDrawList()->AddRectFilled(itemMin, itemMax, IM_COL32(255, 0, 0, 64), 4.0f);
auto labelRect = s_GroupPanelLabelStack.back();
s_GroupPanelLabelStack.pop_back();
ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f));
labelRect.Min.x -= itemSpacing.x;
labelRect.Max.x += itemSpacing.x;
for (int i = 0; i < 4; ++i)
{
switch (i)
{
// left half-plane
case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
// right half-plane
case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
// top
case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, -FLT_MAX), ImVec2(labelRect.Max.x, labelRect.Min.y), true); break;
// bottom
case 3: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
}
ImGui::GetWindowDrawList()->AddRect(
frameRect.Min, frameRect.Max,
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)),
halfFrame.x);
ImGui::PopClipRect();
}
ImGui::PopStyleVar(2);
#if IMGUI_VERSION_NUM >= 17301
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f;
ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f;
#else
ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x += frameHeight * 0.5f;
#endif
ImGui::GetCurrentWindow()->Size.x += frameHeight;
ImGui::Dummy(ImVec2(0.0f, 0.0f));
ImGui::EndGroup();
}
} }

View File

@ -3,6 +3,7 @@
#include "GameOverlay.h" #include "GameOverlay.h"
#include "Lib/ImGui/imgui.h" #include "Lib/ImGui/imgui.h"
#include "Console.h" #include "Console.h"
#include "InputEditor.h"
struct GameAsset { struct GameAsset {
uint32_t textureId; uint32_t textureId;
@ -59,6 +60,7 @@ namespace SohImGui {
} CustomWindow; } CustomWindow;
extern Console* console; extern Console* console;
extern Ship::InputEditor* controller;
extern Ship::GameOverlay* overlay; extern Ship::GameOverlay* overlay;
extern bool needs_save; extern bool needs_save;
void Init(WindowImpl window_impl); void Init(WindowImpl window_impl);
@ -68,8 +70,8 @@ namespace SohImGui {
void EnhancementRadioButton(const char* text, const char* cvarName, int id); void EnhancementRadioButton(const char* text, const char* cvarName, int id);
void EnhancementCheckbox(const char* text, const char* cvarName); void EnhancementCheckbox(const char* text, const char* cvarName);
void EnhancementButton(const char* text, const char* cvarName); void EnhancementButton(const char* text, const char* cvarName);
void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0); void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false);
void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage); void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = false);
void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue); void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue);
void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false);
void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0); void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0);
@ -90,4 +92,6 @@ namespace SohImGui {
void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha); void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha);
ImTextureID GetTextureByID(int id); ImTextureID GetTextureByID(int id);
ImTextureID GetTextureByName(const std::string& name); ImTextureID GetTextureByName(const std::string& name);
void BeginGroupPanel(const char* name, const ImVec2 & size = ImVec2(0.0f, 0.0f));
void EndGroupPanel(float minHeight = 0.0f);
} }

View File

@ -0,0 +1,279 @@
#include "InputEditor.h"
#include "Controller.h"
#include "Window.h"
#include "Lib/ImGui/imgui.h"
#include "ImGuiImpl.h"
#include "Utils/StringHelper.h"
#include "Lib/ImGui/imgui_internal.h"
#include "Cvar.h"
namespace Ship {
extern "C" uint8_t __enableGameInput;
#define SEPARATION() ImGui::Dummy(ImVec2(0, 5))
void InputEditor::Init() {
BtnReading = -1;
}
std::shared_ptr<Controller> GetControllerPerSlot(int slot) {
const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
return Window::ControllerApi->physicalDevices[vDevices[slot]];
}
void InputEditor::DrawButton(const char* label, int n64Btn) {
const std::shared_ptr<Controller> backend = GetControllerPerSlot(CurrentPort);
float size = 40;
bool readingMode = BtnReading == n64Btn;
bool disabled = BtnReading != -1 && !readingMode || !backend->Connected();
ImVec2 len = ImGui::CalcTextSize(label);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - size));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
if(disabled) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
}
if(readingMode) {
const int32_t btn = backend->ReadRawPress();
if(btn != -1) {
backend->SetButtonMapping(CurrentPort, n64Btn, btn);
BtnReading = -1;
}
}
const char* BtnName = backend->GetButtonName(CurrentPort, n64Btn);
if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName, n64Btn).c_str())) {
BtnReading = n64Btn;
backend->ClearRawPress();
}
if(disabled) {
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
}
void InputEditor::DrawVirtualStick(const char* label, ImVec2 stick) {
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
ImGui::BeginChild(label, ImVec2(68, 75), false);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
const ImVec2 p = ImGui::GetCursorScreenPos();
float sz = 45.0f;
float rad = sz * 0.5f;
ImVec2 pos = ImVec2(p.x + sz * 0.5f + 12, p.y + sz * 0.5f + 11);
float stickX = (stick.x / 83.0f) * (rad * 0.5f);
float stickY = -(stick.y / 83.0f) * (rad * 0.5f);
ImVec4 rect = ImVec4(p.x + 2, p.y + 2, 65, 65);
draw_list->AddRect(ImVec2(rect.x, rect.y), ImVec2(rect.x + rect.z, rect.y + rect.w), ImColor(100, 100, 100, 255), 0.0f, 0, 1.5f);
draw_list->AddCircleFilled(pos, rad, ImColor(130, 130, 130, 255), 8);
draw_list->AddCircleFilled(ImVec2(pos.x + stickX, pos.y + stickY), 5, ImColor(15, 15, 15, 255), 7);
ImGui::EndChild();
}
void InputEditor::DrawControllerSchema() {
const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
const std::vector<std::shared_ptr<Controller>> devices = Window::ControllerApi->physicalDevices;
std::shared_ptr<Controller> Backend = devices[vDevices[CurrentPort]];
DeviceProfile& profile =Backend->profiles[CurrentPort];
float sensitivity = profile.Thresholds[SENSITIVITY];
bool IsKeyboard = Backend->GetGuid() == "Keyboard" || !Backend->Connected();
const char* ControllerName = Backend->GetControllerName();
if (ControllerName != nullptr && ImGui::BeginCombo("##ControllerEntries", ControllerName)) {
for (uint8_t i = 0; i < devices.size(); i++) {
if (ImGui::Selectable(devices[i]->GetControllerName(), i == vDevices[CurrentPort])) {
Window::ControllerApi->SetPhysicalDevice(CurrentPort, i);
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
if(ImGui::Button("Refresh")) {
Window::ControllerApi->ScanPhysicalDevices();
}
SohImGui::BeginGroupPanel("Buttons", ImVec2(150, 20));
DrawButton("A", BTN_A);
DrawButton("B", BTN_B);
DrawButton("L", BTN_L);
DrawButton("R", BTN_R);
DrawButton("Z", BTN_Z);
DrawButton("START", BTN_START);
SEPARATION();
SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 48.0f);
ImGui::SameLine();
SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20));
DrawButton("Up", BTN_DUP);
DrawButton("Down", BTN_DDOWN);
DrawButton("Left", BTN_DLEFT);
DrawButton("Right", BTN_DRIGHT);
SEPARATION();
SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 94.0f);
ImGui::SameLine();
SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20));
DrawButton("Up", BTN_STICKUP);
DrawButton("Down", BTN_STICKDOWN);
DrawButton("Left", BTN_STICKLEFT);
DrawButton("Right", BTN_STICKRIGHT);
if (!IsKeyboard) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->wStickX, Backend->wStickY));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
ImGui::Text("Deadzone");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[LEFT_STICK], 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::EndChild();
} else {
ImGui::Dummy(ImVec2(0, 6));
}
SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f);
ImGui::SameLine();
if (!IsKeyboard) {
ImGui::SameLine();
SohImGui::BeginGroupPanel("Camera Stick", ImVec2(150, 20));
DrawButton("Up", BTN_VSTICKUP);
DrawButton("Down", BTN_VSTICKDOWN);
DrawButton("Left", BTN_VSTICKLEFT);
DrawButton("Right", BTN_VSTICKRIGHT);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->wCamX / sensitivity, Backend->wCamY / sensitivity));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
ImGui::Text("Deadzone");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[RIGHT_STICK], 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::Text("Sensitivity");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MSensitivity", &profile.Thresholds[SENSITIVITY], 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::EndChild();
SohImGui::EndGroupPanel(14.0f);
}
if(Backend->CanGyro()) {
ImGui::SameLine();
SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Enable Gyro", &profile.UseGyro);
ImGui::SetCursorPosX(cursorX);
ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile.Thresholds[GYRO_SENSITIVITY]));
ImGui::PushItemWidth(135.0f);
ImGui::SetCursorPosX(cursorX);
ImGui::SliderFloat("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
ImGui::PopItemWidth();
ImGui::Dummy(ImVec2(0, 1));
ImGui::SetCursorPosX(cursorX);
if (ImGui::Button("Recalibrate Gyro##RGyro")) {
profile.Thresholds[DRIFT_X] = 0.0f;
profile.Thresholds[DRIFT_Y] = 0.0f;
}
ImGui::SetCursorPosX(cursorX);
DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->wGyroY, 10.0f * Backend->wGyroX));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
ImGui::Text("Drift X");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftX", &profile.Thresholds[DRIFT_X], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth();
ImGui::Text("Drift Y");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftY", &profile.Thresholds[DRIFT_Y], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth();
ImGui::EndChild();
SohImGui::EndGroupPanel(14.0f);
}
ImGui::SameLine();
const ImVec2 cursor = ImGui::GetCursorPos();
SohImGui::BeginGroupPanel("C-Buttons", ImVec2(158, 20));
DrawButton("Up", BTN_CUP);
DrawButton("Down", BTN_CDOWN);
DrawButton("Left", BTN_CLEFT);
DrawButton("Right", BTN_CRIGHT);
ImGui::Dummy(ImVec2(0, 5));
SohImGui::EndGroupPanel();
ImGui::SetCursorPosX(cursor.x);
ImGui::SetCursorPosY(cursor.y + 120);
SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Rumble Enabled", &profile.UseRumble);
if (Backend->CanRumble()) {
ImGui::SetCursorPosX(cursorX);
ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile.RumbleStrength));
ImGui::SetCursorPosX(cursorX);
ImGui::PushItemWidth(135.0f);
ImGui::SliderFloat("##RStrength", &profile.RumbleStrength, 0.0f, 1.0f, "");
ImGui::PopItemWidth();
}
ImGui::Dummy(ImVec2(0, 5));
SohImGui::EndGroupPanel(IsKeyboard ? 0.0f : 2.0f);
}
void InputEditor::DrawHud() {
__enableGameInput = true;
if (!this->Opened) {
BtnReading = -1;
CVar_SetS32("gControllerConfigurationEnabled", 0);
return;
}
ImGui::SetNextWindowSizeConstraints(ImVec2(641, 250), ImVec2(1200, 290));
//OTRTODO: Disable this stupid workaround ( ReadRawPress() only works when the window is on the main viewport )
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
ImGui::Begin("Controller Configuration", &this->Opened, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
ImGui::BeginTabBar("##Controllers");
for (int i = 0; i < 4; i++) {
if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i + 1).c_str())) {
CurrentPort = i;
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
// Draw current cfg
DrawControllerSchema();
ImGui::End();
}
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <string>
#include "Lib/ImGui/imgui.h"
namespace Ship {
class InputEditor {
int CurrentPort = 0;
int BtnReading = -1;
public:
bool Opened = false;
void Init();
void DrawButton(const char* label, int n64Btn);
void DrawVirtualStick(const char* label, ImVec2 stick);
void DrawControllerSchema();
void DrawHud();
};
}

View File

@ -1,56 +1,105 @@
#include "KeyboardController.h" #include "KeyboardController.h"
#if __APPLE__
#include <SDL_keyboard.h>
#else
#include <SDL2/SDL_keyboard.h>
#endif
#include "Hooks.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "Window.h"
namespace Ship { namespace Ship {
KeyboardController::KeyboardController(int32_t dwControllerNumber) : Controller(dwControllerNumber) {
LoadBinding();
}
KeyboardController::~KeyboardController() {
KeyboardController::KeyboardController() : Controller(), lastScancode(-1) {
GUID = "Keyboard";
} }
bool KeyboardController::PressButton(int32_t dwScancode) { bool KeyboardController::PressButton(int32_t dwScancode) {
if (ButtonMapping.contains(dwScancode)) {
dwPressedButtons |= ButtonMapping[dwScancode]; lastKey = dwScancode;
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] |= profiles[slot].Mappings[dwScancode];
return true; return true;
} }
}
return false; return false;
} }
bool KeyboardController::ReleaseButton(int32_t dwScancode) { bool KeyboardController::ReleaseButton(int32_t dwScancode) {
if (ButtonMapping.contains(dwScancode)) { for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons &= ~ButtonMapping[dwScancode]; if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] &= ~profiles[slot].Mappings[dwScancode];
return true; return true;
} }
}
return false; return false;
} }
void KeyboardController::ReleaseAllButtons() { void KeyboardController::ReleaseAllButtons() {
dwPressedButtons = 0; for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons[slot] = 0;
}
} }
void KeyboardController::ReadFromSource() { void KeyboardController::ReadFromSource(int32_t slot) {
wStickX = 0; wStickX = 0;
wStickY = 0; wStickY = 0;
wCamX = 0;
wCamY = 0;
} }
void KeyboardController::WriteToSource(ControllerCallback* controller) int32_t KeyboardController::ReadRawPress() {
return lastKey;
}
void KeyboardController::WriteToSource(int32_t slot, ControllerCallback* controller)
{ {
} }
std::string KeyboardController::GetControllerType() { const char* KeyboardController::GetButtonName(int slot, int n64Button) {
return "KEYBOARD"; std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
return pair.second == n64Button;
});
if (find == Mappings.end()) return "Unknown";
const char* name = GlobalCtx2::GetInstance()->GetWindow()->GetKeyName(find->first);
return strlen(name) == 0 ? "Unknown" : name;
} }
std::string KeyboardController::GetConfSection() {
return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1); void KeyboardController::CreateDefaultBinding(int32_t slot) {
DeviceProfile& profile = profiles[slot];
profile.Mappings[0x14D] = BTN_CRIGHT;
profile.Mappings[0x14B] = BTN_CLEFT;
profile.Mappings[0x150] = BTN_CDOWN;
profile.Mappings[0x148] = BTN_CUP;
profile.Mappings[0x13] = BTN_R;
profile.Mappings[0x12] = BTN_L;
profile.Mappings[0x023] = BTN_DRIGHT;
profile.Mappings[0x021] = BTN_DLEFT;
profile.Mappings[0x022] = BTN_DDOWN;
profile.Mappings[0x014] = BTN_DUP;
profile.Mappings[0x039] = BTN_START;
profile.Mappings[0x02C] = BTN_Z;
profile.Mappings[0x02E] = BTN_B;
profile.Mappings[0x02D] = BTN_A;
profile.Mappings[0x020] = BTN_STICKRIGHT;
profile.Mappings[0x01E] = BTN_STICKLEFT;
profile.Mappings[0x01F] = BTN_STICKDOWN;
profile.Mappings[0x011] = BTN_STICKUP;
} }
std::string KeyboardController::GetBindingConfSection() { const char* KeyboardController::GetControllerName() {
return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1); return "Keyboard";
} }
} }

View File

@ -5,24 +5,34 @@
namespace Ship { namespace Ship {
class KeyboardController : public Controller { class KeyboardController : public Controller {
public: public:
KeyboardController(int32_t dwControllerNumber); KeyboardController();
~KeyboardController();
void ReadFromSource();
void WriteToSource(ControllerCallback* controller);
bool Connected() const { return true; }
bool CanRumble() const { return false; }
void ReadFromSource(int32_t slot) override;
void WriteToSource(int32_t slot, ControllerCallback* controller) override;
bool Connected() const override { return true; }
bool CanRumble() const override { return false; }
bool CanGyro() const override { return false; }
const char* GetControllerName() override;
const char* GetButtonName(int slot, int n64Button) override;
bool PressButton(int32_t dwScancode); bool PressButton(int32_t dwScancode);
bool ReleaseButton(int32_t dwScancode); bool ReleaseButton(int32_t dwScancode);
void ClearRawPress() override {
lastKey = -1;
}
int32_t ReadRawPress() override;
void ReleaseAllButtons(); void ReleaseAllButtons();
bool HasPadConf() const { return false; } void SetLastScancode(int32_t key) {
std::optional<std::string> GetPadConfSection() { return {}; } lastScancode = key;
}
int32_t GetLastScancode() { return lastScancode; }
void CreateDefaultBinding(int32_t slot) override;
protected: protected:
std::string GetControllerType(); int32_t lastScancode;
std::string GetConfSection(); int32_t lastKey = -1;
std::string GetBindingConfSection();
}; };
} }

View File

@ -114,7 +114,9 @@ typedef struct {
/* 0x04 */ u8 err_no; /* 0x04 */ u8 err_no;
/* 0x05 */ f32 gyro_x; /* 0x05 */ f32 gyro_x;
/* 0x09 */ f32 gyro_y; /* 0x09 */ f32 gyro_y;
} OSContPad; // size = 0x0D /* 0x1C */ f32 cam_x;
/* 0x20 */ f32 cam_y;
} OSContPad; // size = 0x24
typedef struct { typedef struct {
/* 0x00 */ u8 rumble; /* 0x00 */ u8 rumble;

View File

@ -28,6 +28,7 @@
#include "gfx_pc.h" #include "gfx_pc.h"
#include "../../ImGuiImpl.h" #include "../../ImGuiImpl.h"
#include "../../Cvar.h" #include "../../Cvar.h"
#include "../../Hooks.h"
#define DECLARE_GFX_DXGI_FUNCTIONS #define DECLARE_GFX_DXGI_FUNCTIONS
#include "gfx_dxgi.h" #include "gfx_dxgi.h"
@ -228,9 +229,8 @@ static void onkeyup(WPARAM w_param, LPARAM l_param) {
} }
} }
char fileName[256];
static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param) { static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param) {
char fileName[256];
SohImGui::EventImpl event_impl; SohImGui::EventImpl event_impl;
event_impl.win32 = { h_wnd, static_cast<int>(message), static_cast<int>(w_param), static_cast<int>(l_param) }; event_impl.win32 = { h_wnd, static_cast<int>(message), static_cast<int>(w_param), static_cast<int>(l_param) };
SohImGui::Update(event_impl); SohImGui::Update(event_impl);
@ -240,6 +240,7 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
dxgi.current_height = (uint32_t)(l_param >> 16); dxgi.current_height = (uint32_t)(l_param >> 16);
break; break;
case WM_DESTROY: case WM_DESTROY:
ModInternal::ExecuteHooks<ModInternal::ExitGame>();
exit(0); exit(0);
case WM_PAINT: case WM_PAINT:
if (dxgi.in_paint) { if (dxgi.in_paint) {
@ -718,6 +719,12 @@ void ThrowIfFailed(HRESULT res, HWND h_wnd, const char *message) {
} }
} }
const char* gfx_dxgi_get_key_name(int scancode) {
TCHAR* Text = new TCHAR[64];
GetKeyNameText(scancode << 16, Text, 64);
return (char*) Text;
}
extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = { extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
gfx_dxgi_init, gfx_dxgi_init,
gfx_dxgi_set_keyboard_callbacks, gfx_dxgi_set_keyboard_callbacks,
@ -734,6 +741,7 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
gfx_dxgi_set_target_fps, gfx_dxgi_set_target_fps,
gfx_dxgi_set_maximum_frame_latency, gfx_dxgi_set_maximum_frame_latency,
gfx_dxgi_get_detected_hz, gfx_dxgi_get_detected_hz,
gfx_dxgi_get_key_name
}; };
#endif #endif

View File

@ -23,6 +23,7 @@
#include "../../ImGuiImpl.h" #include "../../ImGuiImpl.h"
#include "../../Cvar.h" #include "../../Cvar.h"
#include "../../Hooks.h"
#include "gfx_window_manager_api.h" #include "gfx_window_manager_api.h"
#include "gfx_screen_config.h" #include "gfx_screen_config.h"
@ -108,7 +109,7 @@ static void set_fullscreen(bool on, bool call_callback) {
SDL_GetDesktopDisplayMode(0, &mode); SDL_GetDesktopDisplayMode(0, &mode);
window_width = mode.w; window_width = mode.w;
window_height = mode.h; window_height = mode.h;
//SDL_ShowCursor(false); SDL_ShowCursor(false);
} else { } else {
window_width = DESIRED_SCREEN_WIDTH; window_width = DESIRED_SCREEN_WIDTH;
window_height = DESIRED_SCREEN_HEIGHT; window_height = DESIRED_SCREEN_HEIGHT;
@ -229,6 +230,15 @@ static int translate_scancode(int scancode) {
} }
} }
static int untranslate_scancode(int translatedScancode) {
for (int i = 0; i < 512; i++) {
if (inverted_scancode_table[i] == translatedScancode) {
return i;
}
}
return 0;
}
static void gfx_sdl_onkeydown(int scancode) { static void gfx_sdl_onkeydown(int scancode) {
int key = translate_scancode(scancode); int key = translate_scancode(scancode);
if (on_key_down_callback != NULL) { if (on_key_down_callback != NULL) {
@ -270,6 +280,7 @@ static void gfx_sdl_handle_events(void) {
Game::SaveSettings(); Game::SaveSettings();
break; break;
case SDL_QUIT: case SDL_QUIT:
ModInternal::ExecuteHooks<ModInternal::ExitGame>();
SDL_Quit(); // bandaid fix for linux window closing issue SDL_Quit(); // bandaid fix for linux window closing issue
exit(0); exit(0);
} }
@ -339,6 +350,10 @@ static float gfx_sdl_get_detected_hz(void) {
return 0; return 0;
} }
static const char* gfx_sdl_get_key_name(int scancode) {
return SDL_GetScancodeName((SDL_Scancode) untranslate_scancode(scancode));
}
struct GfxWindowManagerAPI gfx_sdl = { struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_init, gfx_sdl_init,
gfx_sdl_set_keyboard_callbacks, gfx_sdl_set_keyboard_callbacks,
@ -354,7 +369,8 @@ struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_get_time, gfx_sdl_get_time,
gfx_sdl_set_target_fps, gfx_sdl_set_target_fps,
gfx_sdl_set_maximum_frame_latency, gfx_sdl_set_maximum_frame_latency,
gfx_sdl_get_detected_hz gfx_sdl_get_detected_hz,
gfx_sdl_get_key_name
}; };
#endif #endif

View File

@ -20,6 +20,7 @@ struct GfxWindowManagerAPI {
void (*set_target_fps)(int fps); void (*set_target_fps)(int fps);
void (*set_maximum_frame_latency)(int latency); void (*set_maximum_frame_latency)(int latency);
float (*get_detected_hz)(void); float (*get_detected_hz)(void);
const char* (*get_key_name)(int scancode);
}; };
#endif #endif

View File

@ -0,0 +1,134 @@
#include "Mercury.h"
#include <fstream>
#include <sstream>
#include <string>
#include <filesystem>
#include <unordered_map>
#include <any>
namespace fs = std::filesystem;
using json = nlohmann::json;
std::unordered_map<std::string, std::any> ramMap;
Mercury::Mercury(std::string path) : path_(std::move(path)) {
this->reload();
}
std::vector<std::string> split(const std::string& s, const char delimiter) {
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
while (getline(ss, item, delimiter)) {
result.push_back(item);
}
return result;
}
std::string Mercury::formatNestedKey(const std::string& key) {
const std::vector<std::string> dots = split(key, '.');
std::string tmp;
if (dots.size() > 1)
for (const auto& dot : dots) {
tmp += "/" + dot;
}
else
tmp = "/" + dots[0];
return tmp;
}
json Mercury::nested(const std::string& key) {
std::vector<std::string> dots = split(key, '.');
if (!this->vjson.is_object())
return this->vjson;
json gjson = this->vjson.unflatten();
if (dots.size() > 1) {
for (auto& key : dots) {
if (key == "*" || gjson.contains(key))
gjson = gjson[key];
}
return gjson;
}
return gjson[key];
}
std::string Mercury::getString(const std::string& key, const std::string& def) {
json n = this->nested(key);
if (n.is_string() && !n.get<std::string>().empty())
return n;
return def;
}
float Mercury::getFloat(const std::string& key, float def) {
json n = this->nested(key);
if (n.is_number_float())
return n;
return def;
}
bool Mercury::getBool(const std::string& key, bool def) {
json n = this->nested(key);
if (n.is_boolean())
return n;
return def;
}
int Mercury::getInt(const std::string& key, int def) {
json n = this->nested(key);
if (n.is_number_integer())
return n;
return def;
}
bool Mercury::contains(const std::string& key) {
return !this->nested(key).is_null();
}
void Mercury::setString(const std::string& key, const std::string& value) {
this->vjson[formatNestedKey(key)] = value;
}
void Mercury::setFloat(const std::string& key, float value) {
this->vjson[formatNestedKey(key)] = value;
}
void Mercury::setBool(const std::string& key, bool value) {
this->vjson[formatNestedKey(key)] = value;
}
void Mercury::setInt(const std::string& key, int value) {
this->vjson[formatNestedKey(key)] = value;
}
void Mercury::setUInt(const std::string& key, uint32_t value) {
this->vjson[formatNestedKey(key)] = value;
}
void Mercury::erase(const std::string& key) {
this->vjson.erase(formatNestedKey(key));
}
void Mercury::reload() {
if (this->path_ == "None" || !fs::exists(this->path_) || !fs::is_regular_file(this->path_)) {
this->isNewInstance = true;
this->vjson = json::object();
return;
}
std::ifstream ifs(this->path_);
try {
this->rjson = json::parse(ifs);
this->vjson = this->rjson.flatten();
}
catch (...) {
this->vjson = json::object();
}
}
void Mercury::save() const {
std::ofstream file(this->path_);
file << this->vjson.unflatten().dump(4);
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <any>
#include <vector>
#include <string>
#include "../nlohmann/json.hpp"
class Mercury {
protected:
std::string path_;
public:
explicit Mercury(std::string path);
nlohmann::json vjson;
nlohmann::json rjson;
nlohmann::json nested(const std::string& key);
static std::string formatNestedKey(const std::string& key);
std::string getString(const std::string& key, const std::string& def = "");
float getFloat(const std::string& key, float defValue = 0.0f);
bool getBool(const std::string& key, bool defValue = false);
int getInt(const std::string& key, int defValue = 0);
bool contains(const std::string& key);
template< typename T > std::vector<T> getArray(const std::string& key);
void setString(const std::string& key, const std::string& value);
void setFloat(const std::string& key, float value);
void setBool(const std::string& key, bool value);
void setInt(const std::string& key, int value);
void setUInt(const std::string& key, uint32_t value);
void erase(const std::string& key);
void set(const std::string& key, std::any value);
template< typename T > void setArray(const std::string& key, std::vector<T> array);
void reload();
void save() const;
bool isNewInstance = false;
};
template< typename T >
std::vector<T> Mercury::getArray(const std::string& key) {
if (nlohmann::json tmp = this->nested(key); tmp.is_array())
return tmp.get<std::vector<T>>();
return std::vector<T>();
};
template <typename T>
void Mercury::setArray(const std::string& key, std::vector<T> array) {
this->vjson[formatNestedKey(key)] = nlohmann::json(array);
}

View File

@ -0,0 +1,60 @@
//
// OSXFolderManager.h
// libultraship
//
// Created by David Chavez on 28.06.22.
//
#ifndef OSXFolderManager_h
#define OSXFolderManager_h
#include <stdio.h>
namespace Ship {
enum {
NSApplicationDirectory = 1,
NSDemoApplicationDirectory,
NSDeveloperApplicationDirectory,
NSAdminApplicationDirectory,
NSLibraryDirectory,
NSDeveloperDirectory,
NSUserDirectory,
NSDocumentationDirectory,
NSDocumentDirectory,
NSCoreServiceDirectory,
NSAutosavedInformationDirectory = 11,
NSDesktopDirectory = 12,
NSCachesDirectory = 13,
NSApplicationSupportDirectory = 14,
NSDownloadsDirectory = 15,
NSInputMethodsDirectory = 16,
NSMoviesDirectory = 17,
NSMusicDirectory = 18,
NSPicturesDirectory = 19,
NSPrinterDescriptionDirectory = 20,
NSSharedPublicDirectory = 21,
NSPreferencePanesDirectory = 22,
NSApplicationScriptsDirectory = 23,
NSItemReplacementDirectory = 99,
NSAllApplicationsDirectory = 100,
NSAllLibrariesDirectory = 101,
NSTrashDirectory = 102
};
typedef unsigned long SearchPathDirectory;
enum {
NSUserDomainMask = 1, // user's home directory --- place to install user's personal items (~)
NSLocalDomainMask = 2, // local to the current machine --- place to install items available to everyone on this machine (/Library)
NSNetworkDomainMask = 4, // publically available location in the local area network --- place to install items available on the network (/Network)
NSSystemDomainMask = 8, // provided by Apple, unmodifiable (/System)
NSAllDomainsMask = 0x0ffff // all domains: all of the above and future items
};
typedef unsigned long SearchPathDomainMask;
class FolderManager {
public:
const char *pathForDirectory(SearchPathDirectory directory, SearchPathDomainMask domainMask);
const char *pathForDirectoryAppropriateForItemAtPath(SearchPathDirectory directory, SearchPathDomainMask domainMask, const char *itemPath, bool create = false);
};
};
#endif /* OSXFolderManager_h */

View File

@ -0,0 +1,37 @@
//
// OSXFolderManager.m
// libultraship
//
// Created by David Chavez on 28.06.22.
//
#include "OSXFolderManager.h"
#import <Foundation/Foundation.h>
using namespace Ship;
const char * FolderManager::pathForDirectory(SearchPathDirectory directory, SearchPathDomainMask domainMask) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *URLs = [fileManager URLsForDirectory:(NSSearchPathDirectory)directory inDomains:domainMask];
if (URLs.count == 0) return NULL;
NSURL *URL = [URLs objectAtIndex:0];
NSString *path = URL.path;
// `fileSystemRepresentation` on an `NSString` gives a path suitable for POSIX APIs
return path.fileSystemRepresentation;
}
const char * FolderManager::pathForDirectoryAppropriateForItemAtPath(SearchPathDirectory directory,
SearchPathDomainMask domainMask, const char *itemPath, bool create) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *nsPath = [fileManager stringWithFileSystemRepresentation:itemPath length:strlen(itemPath)];
NSURL *itemURL = (nsPath ? [NSURL fileURLWithPath:nsPath] : nil);
NSURL *URL = [fileManager URLForDirectory:(NSSearchPathDirectory)directory
inDomain:domainMask
appropriateForURL:itemURL
create:create error:NULL];
return URL.path.fileSystemRepresentation;
}

View File

@ -63,8 +63,7 @@ namespace Ship
Deckard = 0, Deckard = 0,
Roy = 1, Roy = 1,
Rachael = 2, Rachael = 2,
Leon = 3, Zhora = 3,
Zhora = 4,
// ... // ...
}; };

View File

@ -1,103 +1,36 @@
#include "SDLController.h" #include "SDLController.h"
#include "GameSettings.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "stox.h"
#include "Window.h" #include "Window.h"
#include "Cvar.h"
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
extern "C" uint8_t __osMaxControllers; extern "C" uint8_t __osMaxControllers;
namespace Ship { namespace Ship {
SDLController::SDLController(int32_t dwControllerNumber) : Controller(dwControllerNumber), Cont(nullptr), guid(INVALID_SDL_CONTROLLER_GUID) {
}
SDLController::~SDLController() {
Close();
}
bool SDLController::IsGuidInUse(const std::string& guid) {
// Check if the GUID is loaded in any other controller;
for (size_t i = 0; i < __osMaxControllers; i++) {
for (size_t j = 0; j < Window::Controllers[i].size(); j++) {
SDLController* OtherCont = dynamic_cast<SDLController*>(Window::Controllers[i][j].get());
if (OtherCont != nullptr && OtherCont->GetGuid().compare(guid) == 0) {
return true;
}
}
}
return false;
}
bool SDLController::Open() { bool SDLController::Open() {
std::string ConfSection = GetConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
for (int i = 0; i < SDL_NumJoysticks(); i++) { const auto NewCont = SDL_GameControllerOpen(physicalSlot);
if (SDL_IsGameController(i)) {
// Get the GUID from SDL
char GuidBuf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), GuidBuf, sizeof(GuidBuf));
auto NewGuid = std::string(GuidBuf);
// Invalid GUID read. Go to next.
if (NewGuid.compare(INVALID_SDL_CONTROLLER_GUID) == 0) {
SPDLOG_ERROR("SDL Controller returned invalid guid");
continue;
}
// The GUID is in use, we want to use a different physical controller. Go to next.
if (IsGuidInUse(NewGuid)) {
continue;
}
// If the GUID is blank from the config, OR if the config GUID matches, load the controller.
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
auto NewCont = SDL_GameControllerOpen(i);
// We failed to load the controller. Go to next. // We failed to load the controller. Go to next.
if (NewCont == nullptr) { if (NewCont == nullptr) {
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError()); SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
continue; return false;
} }
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) {
{
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE); SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
supportsGyro = true;
} }
guid = NewGuid; char GuidBuf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf));
GUID = std::string(GuidBuf);
Cont = NewCont; Cont = NewCont;
wCamX = 0;
wCamY = 0;
std::string BindingConfSection = GetBindingConfSection(); return true;
std::string PadConfSection = *GetPadConfSection();
std::shared_ptr<ConfigFile> config = GlobalCtx2::GetInstance()->GetConfig();
if (!config->has(BindingConfSection)) {
CreateDefaultBinding();
}
if (!config->has(PadConfSection)) {
CreateDefaultPadConf();
}
LoadBinding();
LoadAxisThresholds();
// Update per-controller settings in ImGui menu after opening controller.
Game::LoadPadSettings();
break;
}
}
}
return Cont != nullptr;
} }
bool SDLController::Close() { bool SDLController::Close() {
@ -108,31 +41,14 @@ namespace Ship {
SDL_GameControllerClose(Cont); SDL_GameControllerClose(Cont);
} }
Cont = nullptr; Cont = nullptr;
guid = "";
ButtonMapping.clear();
ThresholdMapping.clear();
dwPressedButtons = 0;
wStickX = 0; wStickX = 0;
wStickY = 0; wStickY = 0;
return true; return true;
} }
void SDLController::LoadAxisThresholds() {
std::string ConfSection = GetBindingConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
ThresholdMapping[SDL_CONTROLLER_AXIS_LEFTX] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"]); void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity) {
ThresholdMapping[SDL_CONTROLLER_AXIS_LEFTY] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"]);
ThresholdMapping[SDL_CONTROLLER_AXIS_RIGHTX] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"]);
ThresholdMapping[SDL_CONTROLLER_AXIS_RIGHTY] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"]);
ThresholdMapping[SDL_CONTROLLER_AXIS_TRIGGERLEFT] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"]);
ThresholdMapping[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"]);
}
void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold) {
//scale {-32768 ... +32767} to {-84 ... +84} //scale {-32768 ... +32767} to {-84 ... +84}
auto ax = wAxisValueX * 85.0 / 32767.0; auto ax = wAxisValueX * 85.0 / 32767.0;
auto ay = wAxisValueY * 85.0 / 32767.0; auto ay = wAxisValueY * 85.0 / 32767.0;
@ -163,14 +79,59 @@ namespace Ship {
ay *= scale; ay *= scale;
} }
if (!isRightStick) {
wStickX = +ax; wStickX = +ax;
wStickY = -ay; wStickY = -ay;
} else {
wCamX = +ax * sensitivity;
wCamY = -ay * sensitivity;
}
} }
void SDLController::ReadFromSource() {
std::string ConfSection = GetBindingConfSection(); int32_t SDLController::ReadRawPress() {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig(); SDL_GameControllerUpdate();
ConfigFile& Conf = *pConf.get();
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
return i;
}
}
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
const auto Axis = static_cast<SDL_GameControllerAxis>(i);
const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis) / 32767.0f;
if (AxisValue < -0.7f) {
return -(Axis + AXIS_SCANCODE_BIT);
}
if (AxisValue > 0.7f) {
return (Axis + AXIS_SCANCODE_BIT);
}
}
return -1;
}
ControllerThresholds SDLAxisToThreshold( uint32_t axis ){
switch(axis){
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_LEFTY:
return LEFT_STICK;
case SDL_CONTROLLER_AXIS_RIGHTX:
case SDL_CONTROLLER_AXIS_RIGHTY:
return RIGHT_STICK;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
return LEFT_TRIGGER;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
return RIGHT_TRIGGER;
default: return DRIFT_X;
}
}
void SDLController::ReadFromSource(int32_t slot) {
DeviceProfile& profile = profiles[slot];
SDL_GameControllerUpdate(); SDL_GameControllerUpdate();
@ -187,17 +148,14 @@ namespace Ship {
} }
} }
if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO)) if (supportsGyro && profile.UseGyro) {
{
size_t contNumber = GetControllerNumber();
float gyroData[3]; float gyroData[3];
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3); SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
const char* contName = SDL_GameControllerName(Cont); float gyro_drift_x = profile.Thresholds[DRIFT_X] / 100.0f;
float gyro_drift_x = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), 0.0f); float gyro_drift_y = profile.Thresholds[DRIFT_Y] / 100.0f;
float gyro_drift_y = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), 0.0f); const float gyro_sensitivity = profile.Thresholds[GYRO_SENSITIVITY];
const float gyro_sensitivity = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroSensitivity", contNumber).c_str(), 1.0f);
if (gyro_drift_x == 0) { if (gyro_drift_x == 0) {
gyro_drift_x = gyroData[0]; gyro_drift_x = gyroData[0];
@ -207,8 +165,8 @@ namespace Ship {
gyro_drift_y = gyroData[1]; gyro_drift_y = gyroData[1];
} }
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), gyro_drift_x); profile.Thresholds[DRIFT_X] = gyro_drift_x * 100.0f;
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), gyro_drift_y); profile.Thresholds[DRIFT_Y] = gyro_drift_y * 100.0f;
wGyroX = gyroData[0] - gyro_drift_x; wGyroX = gyroData[0] - gyro_drift_x;
wGyroY = gyroData[1] - gyro_drift_y; wGyroY = gyroData[1] - gyro_drift_y;
@ -217,29 +175,35 @@ namespace Ship {
wGyroY *= gyro_sensitivity; wGyroY *= gyro_sensitivity;
} }
dwPressedButtons[slot] = 0;
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) { for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (ButtonMapping.contains(i)) { if (profile.Mappings.contains(i)) {
if (SDL_GameControllerGetButton(Cont, (SDL_GameControllerButton)i)) { if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
dwPressedButtons |= ButtonMapping[i]; dwPressedButtons[slot] |= profile.Mappings[i];
} }
else { else {
dwPressedButtons &= ~ButtonMapping[i]; dwPressedButtons[slot] &= ~profile.Mappings[i];
} }
} }
} }
SDL_GameControllerAxis StickAxisX = SDL_CONTROLLER_AXIS_INVALID; SDL_GameControllerAxis LStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis StickAxisY = SDL_CONTROLLER_AXIS_INVALID; SDL_GameControllerAxis LStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
int32_t StickDeadzone = 0; int32_t LStickDeadzone = 0;
SDL_GameControllerAxis RStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis RStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
int32_t RStickDeadzone = 0;
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) { for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
auto Axis = (SDL_GameControllerAxis)i; const auto Axis = static_cast<SDL_GameControllerAxis>(i);
auto PosScancode = i + AXIS_SCANCODE_BIT; const auto PosScancode = i + AXIS_SCANCODE_BIT;
auto NegScancode = -PosScancode; const auto NegScancode = -PosScancode;
auto AxisThreshold = ThresholdMapping[i]; const auto AxisThreshold = static_cast<int>(profile.Thresholds[SDLAxisToThreshold(i)]);
auto PosButton = ButtonMapping[PosScancode]; const auto PosButton = profile.Mappings[PosScancode];
auto NegButton = ButtonMapping[NegScancode]; const auto NegButton = profile.Mappings[NegScancode];
auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis); const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
#ifdef TARGET_WEB #ifdef TARGET_WEB
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562 // Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
@ -252,94 +216,176 @@ namespace Ship {
} }
#endif #endif
// If the axis is NOT mapped to the control stick.
if (!( if (!(
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT || PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN || PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT || NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) { NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
if (AxisValue > AxisThreshold) {
dwPressedButtons |= PosButton; if (AxisValue > 0x1E00) {
dwPressedButtons &= ~NegButton; dwPressedButtons[slot] |= PosButton;
dwPressedButtons[slot] &= ~NegButton;
} }
else if (AxisValue < -AxisThreshold) { else if (AxisValue < -0x1E00) {
dwPressedButtons &= ~PosButton; dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons |= NegButton; dwPressedButtons[slot] |= NegButton;
} }
else { else {
dwPressedButtons &= ~PosButton; dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons &= ~NegButton; dwPressedButtons[slot] &= ~NegButton;
} }
} }
else { else {
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) { if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) { if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis); SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis);
} }
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisThreshold);
} }
StickDeadzone = AxisThreshold; LStickDeadzone = AxisThreshold;
StickAxisX = Axis; LStickAxisX = Axis;
} }
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) { if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) { if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis); SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis);
} }
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
} }
StickDeadzone = AxisThreshold; LStickDeadzone = AxisThreshold;
StickAxisY = Axis; LStickAxisY = Axis;
} }
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) { if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) { if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis); SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis);
} }
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
} }
StickDeadzone = AxisThreshold; LStickDeadzone = AxisThreshold;
StickAxisX = Axis; LStickAxisX = Axis;
} }
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) { if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) { if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis); SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis);
} }
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
} }
StickDeadzone = AxisThreshold; LStickDeadzone = AxisThreshold;
StickAxisY = Axis; LStickAxisY = Axis;
} }
} }
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) { if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
auto AxisValueX = SDL_GameControllerGetAxis(Cont, StickAxisX); const auto AxisValueX = SDL_GameControllerGetAxis(Cont, LStickAxisX);
auto AxisValueY = SDL_GameControllerGetAxis(Cont, StickAxisY); const auto AxisValueY = SDL_GameControllerGetAxis(Cont, LStickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone); NormalizeStickAxis(AxisValueX, AxisValueY, LStickDeadzone, false, profile.Thresholds[SENSITIVITY]);
} }
}
// Right Stick
// If the axis is NOT mapped to the control stick.
if (!(
PosButton == BTN_VSTICKLEFT || PosButton == BTN_VSTICKRIGHT ||
PosButton == BTN_VSTICKUP || PosButton == BTN_VSTICKDOWN ||
NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT ||
NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN)) {
if (AxisValue > 0x1E00) {
dwPressedButtons[slot] |= PosButton;
dwPressedButtons[slot] &= ~NegButton;
}
else if (AxisValue < -0x1E00) {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] |= NegButton;
}
else {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton;
} }
void SDLController::WriteToSource(ControllerCallback* controller)
{
if (CanRumble()) {
if (controller->rumble > 0) {
float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f);
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
} else { } else {
if (PosButton == BTN_VSTICKLEFT || PosButton == BTN_VSTICKRIGHT) {
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisX != Axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", RStickAxisX, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisThreshold);
}
RStickDeadzone = AxisThreshold;
RStickAxisX = Axis;
}
if (PosButton == BTN_VSTICKUP || PosButton == BTN_VSTICKDOWN) {
if (RStickAxisY != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != Axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", RStickAxisY, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
}
RStickDeadzone = AxisThreshold;
RStickAxisY = Axis;
}
if (NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT) {
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisX != Axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", RStickAxisX, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
}
RStickDeadzone = AxisThreshold;
RStickAxisX = Axis;
}
if (NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN) {
if (RStickAxisY != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != Axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", RStickAxisY, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
}
RStickDeadzone = AxisThreshold;
RStickAxisY = Axis;
}
}
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, RStickAxisX);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, RStickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, RStickDeadzone, true, profile.Thresholds[SENSITIVITY]);
}
}
}
void SDLController::WriteToSource(int32_t slot, ControllerCallback* controller)
{
if (CanRumble() && profiles[slot].UseRumble) {
if (controller->rumble > 0) {
float rumble_strength = profiles[slot].RumbleStrength;
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
}
else {
SDL_GameControllerRumble(Cont, 0, 0, 0); SDL_GameControllerRumble(Cont, 0, 0, 0);
} }
} }
@ -362,73 +408,74 @@ namespace Ship {
} }
} }
void SDLController::CreateDefaultBinding() { const char* AxisNames[] = {
std::string ConfSection = GetBindingConfSection(); "Left Stick X",
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig(); "Left Stick Y",
ConfigFile& Conf = *pConf.get(); "Right Stick X",
"Right Stick Y",
"Left Trigger",
"Right Trigger",
"Start Button"
};
Conf[ConfSection][STR(BTN_CRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT)); char buffer[50];
Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT)); const char* SDLController::GetButtonName(int slot, int n64Button) {
Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT)); std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
Conf[ConfSection][STR(BTN_CUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT)); const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
//Conf[ConfSection][STR(BTN_CRIGHT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_X); return pair.second == n64Button;
//Conf[ConfSection][STR(BTN_CLEFT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_Y); });
//Conf[ConfSection][STR(BTN_CDOWN + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
//Conf[ConfSection][STR(BTN_CUP + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
Conf[ConfSection][STR(BTN_R)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_L)] = std::to_string(SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
Conf[ConfSection][STR(BTN_DRIGHT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
Conf[ConfSection][STR(BTN_DLEFT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_LEFT);
Conf[ConfSection][STR(BTN_DDOWN)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
Conf[ConfSection][STR(BTN_DUP)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_UP);
Conf[ConfSection][STR(BTN_START)] = std::to_string(SDL_CONTROLLER_BUTTON_START);
Conf[ConfSection][STR(BTN_Z)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_B)] = std::to_string(SDL_CONTROLLER_BUTTON_B);
Conf[ConfSection][STR(BTN_A)] = std::to_string(SDL_CONTROLLER_BUTTON_A);
Conf[ConfSection][STR(BTN_STICKRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_STICKLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_STICKDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_STICKUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0); if (find == Mappings.end()) return "Unknown";
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"] = std::to_string(16.0);
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"] = std::to_string(0x4000);
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"] = std::to_string(0x4000);
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"] = std::to_string(0x1E00);
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"] = std::to_string(0x1E00);
Conf.Save(); int btn = abs(find->first);
if(btn >= AXIS_SCANCODE_BIT) {
btn -= AXIS_SCANCODE_BIT;
snprintf(buffer, sizeof(buffer), "%s%s", AxisNames[btn], find->first > 0 ? "+" : "-");
return buffer;
} }
void SDLController::CreateDefaultPadConf() { snprintf(buffer, sizeof(buffer), "Button %d", btn);
std::string ConfSection = *GetPadConfSection(); return buffer;
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
Conf.Save();
} }
void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) { const char* SDLController::GetControllerName() {
if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) { return SDL_GameControllerNameForIndex(physicalSlot);
return;
} }
Controller::SetButtonMapping(szButtonName, dwScancode); void SDLController::CreateDefaultBinding(int32_t slot) {
} DeviceProfile& profile = profiles[slot];
profile.Mappings.clear();
std::string SDLController::GetControllerType() { profile.UseRumble = true;
return "SDL"; profile.RumbleStrength = 1.0f;
} profile.UseGyro = false;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
std::string SDLController::GetConfSection() { profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1); profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN;
} profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT] = BTN_R;
std::string SDLController::GetBindingConfSection() { profile.Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
return GetControllerType() + " CONTROLLER BINDING " + guid; profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT;
} profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN;
std::optional<std::string> SDLController::GetPadConfSection() { profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
return GetControllerType() + " CONTROLLER PAD " + guid; profile.Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT] = BTN_Z;
profile.Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B;
profile.Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A;
profile.Mappings[(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKRIGHT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKLEFT;
profile.Mappings[SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT] = BTN_STICKDOWN;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT)] = BTN_STICKUP;
profile.Thresholds[LEFT_STICK] = 16.0f;
profile.Thresholds[RIGHT_STICK] = 16.0f;
profile.Thresholds[LEFT_TRIGGER] = 0x1E00;
profile.Thresholds[RIGHT_TRIGGER] = 0x1E00;
profile.Thresholds[DRIFT_X] = 0.0f;
profile.Thresholds[DRIFT_Y] = 0.0f;
profile.Thresholds[SENSITIVITY] = 16.0f;
profile.Thresholds[GYRO_SENSITIVITY] = 1.0f;
} }
} }

View File

@ -6,46 +6,35 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#endif #endif
#define INVALID_SDL_CONTROLLER_GUID (std::string("00000000000000000000000000000000"))
namespace Ship { namespace Ship {
class SDLController : public Controller { class SDLController : public Controller {
public: public:
SDLController(int32_t dwControllerNumber); SDLController(int slot) : Controller(), Cont(nullptr), physicalSlot(slot) { }
~SDLController(); void ReadFromSource(int32_t slot) override;
const char* GetControllerName() override;
void ReadFromSource(); const char* GetButtonName(int slot, int n64Button) override;
void WriteToSource(ControllerCallback* controller); void WriteToSource(int32_t slot, ControllerCallback* controller) override;
bool Connected() const { return Cont != nullptr; } bool Connected() const override { return Cont != nullptr; }
bool CanRumble() const { bool CanGyro() const override { return supportsGyro; }
bool CanRumble() const override {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18) #if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont); return SDL_GameControllerHasRumble(Cont);
#endif #endif
return true; return true;
} }
std::string GetGuid() { return guid; }; bool Open();
void ClearRawPress() override {}
bool HasPadConf() const { return true; } int32_t ReadRawPress() override;
std::optional<std::string> GetPadConfSection();
protected: protected:
std::string GetControllerType(); void CreateDefaultBinding(int32_t slot) override;
void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
std::string GetConfSection();
std::string GetBindingConfSection();
void CreateDefaultBinding();
void CreateDefaultPadConf();
static bool IsGuidInUse(const std::string& guid);
private: private:
SDL_GameController* Cont; SDL_GameController* Cont;
std::string guid; int physicalSlot;
std::map<int32_t, int16_t> ThresholdMapping; bool supportsGyro;
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity);
void LoadAxisThresholds();
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold);
bool Open();
bool Close(); bool Close();
}; };
} }

View File

@ -101,6 +101,10 @@
#define BTN_STICKRIGHT 0x20000 #define BTN_STICKRIGHT 0x20000
#define BTN_STICKDOWN 0x40000 #define BTN_STICKDOWN 0x40000
#define BTN_STICKUP 0x80000 #define BTN_STICKUP 0x80000
#define BTN_VSTICKUP 0x100000
#define BTN_VSTICKDOWN 0x200000
#define BTN_VSTICKLEFT 0x400000
#define BTN_VSTICKRIGHT 0x800000
typedef struct { typedef struct {
/* 0x00 */ int32_t ram[15]; /* 0x00 */ int32_t ram[15];
@ -120,7 +124,9 @@ typedef struct {
/* 0x04 */ uint8_t err_no; /* 0x04 */ uint8_t err_no;
/* 0x05 */ float gyro_x; /* 0x05 */ float gyro_x;
/* 0x09 */ float gyro_y; /* 0x09 */ float gyro_y;
} OSContPad; // size = 0x0D /* 0x1C */ float cam_x;
/* 0x20 */ float cam_y;
} OSContPad; // size = 0x24
typedef struct { typedef struct {
/* 0x00 */ uint8_t rumble; /* 0x00 */ uint8_t rumble;

View File

@ -38,8 +38,7 @@ extern "C" {
uint8_t __enableGameInput = 1; uint8_t __enableGameInput = 1;
int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) { int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) {
std::shared_ptr<Ship::ConfigFile> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig(); *controllerBits = 0;
Ship::ConfigFile& Conf = *pConf.get();
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) { if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
SPDLOG_ERROR("Failed to initialize SDL game controllers ({})", SDL_GetError()); SPDLOG_ERROR("Failed to initialize SDL game controllers ({})", SDL_GetError());
@ -54,43 +53,7 @@ extern "C" {
SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError()); SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError());
} }
// TODO: This for loop is debug. Burn it with fire. Ship::Window::ControllerApi->Init(controllerBits);
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
// Get the GUID from SDL
char buf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), buf, sizeof(buf));
auto guid = std::string(buf);
auto name = std::string(SDL_GameControllerNameForIndex(i));
SPDLOG_INFO("Found Controller \"{}\" with ID \"{}\"", name, guid);
}
}
for (int32_t i = 0; i < __osMaxControllers; i++) {
std::string ControllerType = Conf["CONTROLLERS"]["CONTROLLER " + std::to_string(i+1)];
mINI::INIStringUtil::toLower(ControllerType);
if (ControllerType == "auto") {
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
} else if (ControllerType == "keyboard") {
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
} else if (ControllerType == "usb") {
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
} else if (ControllerType == "unplugged") {
// Do nothing for unplugged controllers
} else {
SPDLOG_ERROR("Invalid Controller Type: {}", ControllerType);
}
}
*controllerBits = 0;
for (size_t i = 0; i < __osMaxControllers; i++) {
if (Ship::Window::Controllers[i].size() > 0) {
*controllerBits |= 1 << i;
}
}
return 0; return 0;
} }
@ -103,17 +66,14 @@ extern "C" {
pad->button = 0; pad->button = 0;
pad->stick_x = 0; pad->stick_x = 0;
pad->stick_y = 0; pad->stick_y = 0;
pad->cam_x = 0;
pad->cam_y = 0;
pad->err_no = 0; pad->err_no = 0;
pad->gyro_x = 0; pad->gyro_x = 0;
pad->gyro_y = 0; pad->gyro_y = 0;
if (__enableGameInput) if (__enableGameInput) {
{ Ship::Window::ControllerApi->WriteToPad(pad);
for (size_t i = 0; i < __osMaxControllers; i++) {
for (size_t j = 0; j < Ship::Window::Controllers[i].size(); j++) {
Ship::Window::Controllers[i][j]->Read(&pad[i]);
}
}
} }
ModInternal::ExecuteHooks<ModInternal::ControllerRead>(pad); ModInternal::ExecuteHooks<ModInternal::ControllerRead>(pad);
@ -129,16 +89,11 @@ extern "C" {
if (hashStr != nullptr) { if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str())); auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
//if (res != nullptr)
return (Vtx*)res->vertices.data(); return (Vtx*)res->vertices.data();
//else
//return (Vtx*)Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(hashStr)->buffer.get();
} }
else {
return nullptr; return nullptr;
} }
}
int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc) { int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc) {
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc); const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
@ -146,9 +101,9 @@ extern "C" {
if (hashStr != nullptr) { if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str())); auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (int32_t*)res->mtx.data(); return (int32_t*)res->mtx.data();
} else {
return nullptr;
} }
return nullptr;
} }
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc) { Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc) {
@ -233,7 +188,7 @@ extern GfxWindowManagerAPI gfx_sdl;
void SetWindowManager(GfxWindowManagerAPI** WmApi, GfxRenderingAPI** RenderingApi, const std::string& gfx_backend); void SetWindowManager(GfxWindowManagerAPI** WmApi, GfxRenderingAPI** RenderingApi, const std::string& gfx_backend);
namespace Ship { namespace Ship {
std::map<size_t, std::vector<std::shared_ptr<Controller>>> Window::Controllers;
int32_t Window::lastScancode; int32_t Window::lastScancode;
Window::Window(std::shared_ptr<GlobalCtx2> Context) : Context(Context), APlayer(nullptr) { Window::Window(std::shared_ptr<GlobalCtx2> Context) : Context(Context), APlayer(nullptr) {
@ -248,26 +203,55 @@ namespace Ship {
SPDLOG_INFO("destruct window"); SPDLOG_INFO("destruct window");
} }
void Window::CreateDefaults() {
const std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
if (pConf->isNewInstance) {
pConf->setInt("Window.Width", 640);
pConf->setInt("Window.Height", 480);
pConf->setBool("Window.Options", false);
pConf->setString("Window.GfxBackend", "");
pConf->setBool("Window.Fullscreen.Enabled", false);
pConf->setInt("Window.Fullscreen.Width", 1920);
pConf->setInt("Window.Fullscreen.Height", 1080);
pConf->setString("Game.SaveName", "");
pConf->setString("Game.Main Archive", "");
pConf->setString("Game.Patches Archive", "");
pConf->setInt("Shortcuts.Fullscreen", 0x044);
pConf->setInt("Shortcuts.Console", 0x029);
pConf->save();
}
}
void Window::Init() { void Window::Init() {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig(); std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
CreateDefaults();
SetAudioPlayer(); SetAudioPlayer();
bIsFullscreen = Ship::stob(Conf["WINDOW"]["FULLSCREEN"]); bIsFullscreen = pConf->getBool("Window.Fullscreen.Enabled", false);
if (bIsFullscreen) { if (bIsFullscreen) {
dwWidth = Ship::stoi(Conf["WINDOW"]["FULLSCREEN WIDTH"], 1920); dwWidth = pConf->getInt("Window.Fullscreen.Width", 1920);
dwHeight = Ship::stoi(Conf["WINDOW"]["FULLSCREEN HEIGHT"], 1080); dwHeight = pConf->getInt("Window.Fullscreen.Height", 1080);
} else { } else {
dwWidth = Ship::stoi(Conf["WINDOW"]["WINDOW WIDTH"], 640); dwWidth = pConf->getInt("Window.Width", 640);
dwHeight = Ship::stoi(Conf["WINDOW"]["WINDOW HEIGHT"], 480); dwHeight = pConf->getInt("Window.Height", 480);
} }
dwMenubar = Ship::stoi(Conf["WINDOW"]["menubar"], 0);
const std::string& gfx_backend = Conf["WINDOW"]["GFX BACKEND"]; dwMenubar = pConf->getBool("Window.Options", false);
const std::string& gfx_backend = pConf->getString("Window.GfxBackend");
SetWindowManager(&WmApi, &RenderingApi, gfx_backend); SetWindowManager(&WmApi, &RenderingApi, gfx_backend);
gfx_init(WmApi, RenderingApi, GetContext()->GetName().c_str(), bIsFullscreen, dwWidth, dwHeight); gfx_init(WmApi, RenderingApi, GetContext()->GetName().c_str(), bIsFullscreen, dwWidth, dwHeight);
WmApi->set_fullscreen_changed_callback(Window::OnFullscreenChanged); WmApi->set_fullscreen_changed_callback(OnFullscreenChanged);
WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp); WmApi->set_keyboard_callbacks(KeyDown, KeyUp, AllKeysUp);
ModInternal::RegisterHook<ModInternal::ExitGame>([]() {
ControllerApi->SaveControllerSettings();
});
} }
void Window::StartFrame() { void Window::StartFrame() {
@ -318,48 +302,41 @@ namespace Ship {
void Window::MainLoop(void (*MainFunction)(void)) { void Window::MainLoop(void (*MainFunction)(void)) {
WmApi->main_loop(MainFunction); WmApi->main_loop(MainFunction);
} }
bool Window::KeyUp(int32_t dwScancode) {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_FULLSCREEN"])) { bool Window::KeyUp(int32_t dwScancode) {
std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
if (dwScancode == pConf->getInt("Shortcuts.Fullscreen", 0x044)) {
GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen(); GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen();
} }
// OTRTODO: Rig with Kirito's console? // OTRTODO: Rig with Kirito's console?
//if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) { //if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) {
// ToggleConsole(); // ToggleConsole();
//} //}
lastScancode = -1;
bool bIsProcessed = false; bool bIsProcessed = false;
for (size_t i = 0; i < __osMaxControllers; i++) { const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
for (size_t j = 0; j < Controllers[i].size(); j++) {
KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
if (pad != nullptr) { if (pad != nullptr) {
if (pad->ReleaseButton(dwScancode)) { if (pad->ReleaseButton(dwScancode)) {
bIsProcessed = true; bIsProcessed = true;
} }
} }
}
}
return bIsProcessed; return bIsProcessed;
} }
bool Window::KeyDown(int32_t dwScancode) { bool Window::KeyDown(int32_t dwScancode) {
bool bIsProcessed = false; bool bIsProcessed = false;
for (size_t i = 0; i < __osMaxControllers; i++) {
for (size_t j = 0; j < Controllers[i].size(); j++) { const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
if (pad != nullptr) { if (pad != nullptr) {
if (pad->PressButton(dwScancode)) { if (pad->PressButton(dwScancode)) {
bIsProcessed = true; bIsProcessed = true;
} }
} }
}
}
lastScancode = dwScancode; lastScancode = dwScancode;
@ -368,21 +345,17 @@ namespace Ship {
void Window::AllKeysUp(void) { void Window::AllKeysUp(void) {
for (size_t i = 0; i < __osMaxControllers; i++) { const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
for (size_t j = 0; j < Controllers[i].size(); j++) {
KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
if (pad != nullptr) { if (pad != nullptr) {
pad->ReleaseAllButtons(); pad->ReleaseAllButtons();
} }
} }
}
}
void Window::OnFullscreenChanged(bool bIsFullscreen) { void Window::OnFullscreenChanged(bool bIsFullscreen) {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig(); std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
GlobalCtx2::GetInstance()->GetWindow()->bIsFullscreen = bIsFullscreen; GlobalCtx2::GetInstance()->GetWindow()->bIsFullscreen = bIsFullscreen;
Conf["WINDOW"]["FULLSCREEN"] = std::to_string(bIsFullscreen); pConf->setBool("Window.Fullscreen.Enabled", bIsFullscreen);
GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(!bIsFullscreen); GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(!bIsFullscreen);
} }

View File

@ -5,17 +5,22 @@
#include "UltraController.h" #include "UltraController.h"
#include "Controller.h" #include "Controller.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "ControlDeck.h"
#include <string>
#include "Lib/Fast3D/gfx_window_manager_api.h"
namespace Ship { namespace Ship {
class AudioPlayer; class AudioPlayer;
class Window { class Window {
public: public:
static std::map<size_t, std::vector<std::shared_ptr<Controller>>> Controllers;
static int32_t lastScancode; static int32_t lastScancode;
inline static ControlDeck* ControllerApi = new ControlDeck;
Window(std::shared_ptr<GlobalCtx2> Context); Window(std::shared_ptr<GlobalCtx2> Context);
~Window(); ~Window();
void CreateDefaults();
void MainLoop(void (*MainFunction)(void)); void MainLoop(void (*MainFunction)(void));
void Init(); void Init();
void StartFrame(); void StartFrame();
@ -31,9 +36,11 @@ namespace Ship {
bool IsFullscreen() { return bIsFullscreen; } bool IsFullscreen() { return bIsFullscreen; }
uint32_t GetCurrentWidth(); uint32_t GetCurrentWidth();
uint32_t GetCurrentHeight(); uint32_t GetCurrentHeight();
ControlDeck* GetControlDeck() { return ControllerApi; };
uint32_t dwMenubar; uint32_t dwMenubar;
std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); } std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
std::shared_ptr<AudioPlayer> GetAudioPlayer() { return APlayer; } std::shared_ptr<AudioPlayer> GetAudioPlayer() { return APlayer; }
const char* GetKeyName(int scancode) { return WmApi->get_key_name(scancode); }
protected: protected:
private: private:
@ -46,11 +53,10 @@ namespace Ship {
std::weak_ptr<GlobalCtx2> Context; std::weak_ptr<GlobalCtx2> Context;
std::shared_ptr<AudioPlayer> APlayer; std::shared_ptr<AudioPlayer> APlayer;
GfxWindowManagerAPI* WmApi;
GfxRenderingAPI* RenderingApi; GfxRenderingAPI* RenderingApi;
GfxWindowManagerAPI* WmApi;
bool bIsFullscreen; bool bIsFullscreen;
uint32_t dwWidth; uint32_t dwWidth;
uint32_t dwHeight; uint32_t dwHeight;
}; };
} }

View File

@ -256,13 +256,16 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="Audio.cpp" /> <ClCompile Include="Audio.cpp" />
<ClCompile Include="Blob.cpp" /> <ClCompile Include="Blob.cpp" />
<ClCompile Include="ControlDeck.cpp" />
<ClCompile Include="Cvar.cpp" /> <ClCompile Include="Cvar.cpp" />
<ClCompile Include="Environment.cpp" /> <ClCompile Include="Environment.cpp" />
<ClCompile Include="Factories\AudioFactory.cpp" /> <ClCompile Include="Factories\AudioFactory.cpp" />
<ClCompile Include="InputEditor.cpp" />
<ClCompile Include="GameOverlay.cpp" /> <ClCompile Include="GameOverlay.cpp" />
<ClCompile Include="GameSettings.cpp" /> <ClCompile Include="GameSettings.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" /> <ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" /> <ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" />
<ClCompile Include="Lib\Mercury\Mercury.cpp" />
<ClCompile Include="luslog.cpp" /> <ClCompile Include="luslog.cpp" />
<ClCompile Include="mixer.c" /> <ClCompile Include="mixer.c" />
<ClCompile Include="ModManager.cpp" /> <ClCompile Include="ModManager.cpp" />
@ -279,7 +282,6 @@
<ClCompile Include="Factories\TextureFactory.cpp" /> <ClCompile Include="Factories\TextureFactory.cpp" />
<ClCompile Include="Factories\VtxFactory.cpp" /> <ClCompile Include="Factories\VtxFactory.cpp" />
<ClCompile Include="Array.cpp" /> <ClCompile Include="Array.cpp" />
<ClCompile Include="ConfigFile.cpp" />
<ClCompile Include="Controller.cpp" /> <ClCompile Include="Controller.cpp" />
<ClCompile Include="Hooks.cpp" /> <ClCompile Include="Hooks.cpp" />
<ClCompile Include="ImGuiImpl.cpp" /> <ClCompile Include="ImGuiImpl.cpp" />
@ -342,13 +344,18 @@
<ClCompile Include="SDLController.cpp" /> <ClCompile Include="SDLController.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Lib\Mercury\Mercury.h" />
<ClInclude Include="Lib\nlohmann\json.hpp" />
<ClInclude Include="abi.h" /> <ClInclude Include="abi.h" />
<ClInclude Include="Audio.h" /> <ClInclude Include="Audio.h" />
<ClInclude Include="AudioPlayer.h" /> <ClInclude Include="AudioPlayer.h" />
<ClInclude Include="Blob.h" /> <ClInclude Include="Blob.h" />
<ClInclude Include="ControlDeck.h" />
<ClInclude Include="Cvar.h" /> <ClInclude Include="Cvar.h" />
<ClInclude Include="DisconnectedController.h" />
<ClInclude Include="Environment.h" /> <ClInclude Include="Environment.h" />
<ClInclude Include="Factories\AudioFactory.h" /> <ClInclude Include="Factories\AudioFactory.h" />
<ClInclude Include="InputEditor.h" />
<ClInclude Include="GameOverlay.h" /> <ClInclude Include="GameOverlay.h" />
<ClInclude Include="GameSettings.h" /> <ClInclude Include="GameSettings.h" />
<ClInclude Include="GameVersions.h" /> <ClInclude Include="GameVersions.h" />
@ -404,7 +411,6 @@
<ClInclude Include="Vertex.h" /> <ClInclude Include="Vertex.h" />
<ClInclude Include="stox.h" /> <ClInclude Include="stox.h" />
<ClInclude Include="Lib\mINI\src\mini\ini.h" /> <ClInclude Include="Lib\mINI\src\mini\ini.h" />
<ClInclude Include="ConfigFile.h" />
<ClInclude Include="Controller.h" /> <ClInclude Include="Controller.h" />
<ClInclude Include="KeyboardController.h" /> <ClInclude Include="KeyboardController.h" />
<ClInclude Include="Factories\CollisionHeaderFactory.h" /> <ClInclude Include="Factories\CollisionHeaderFactory.h" />

View File

@ -31,9 +31,6 @@
<Filter Include="Source Files\Globals"> <Filter Include="Source Files\Globals">
<UniqueIdentifier>{c0f07350-c627-444e-9f66-23e19407ad9a}</UniqueIdentifier> <UniqueIdentifier>{c0f07350-c627-444e-9f66-23e19407ad9a}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source Files\Config">
<UniqueIdentifier>{9cf4833f-e90c-4a9d-8747-d47cde657beb}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Resources\Files"> <Filter Include="Source Files\Resources\Files">
<UniqueIdentifier>{2aa34c3b-6148-480f-a4fc-19c4e0f8c822}</UniqueIdentifier> <UniqueIdentifier>{2aa34c3b-6148-480f-a4fc-19c4e0f8c822}</UniqueIdentifier>
</Filter> </Filter>
@ -94,6 +91,15 @@
<Filter Include="Source Files\Lib\dr_libs"> <Filter Include="Source Files\Lib\dr_libs">
<UniqueIdentifier>{db6e02cc-fc4c-4138-8219-1d281ad93ec2}</UniqueIdentifier> <UniqueIdentifier>{db6e02cc-fc4c-4138-8219-1d281ad93ec2}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source Files\Lib\nlohmann">
<UniqueIdentifier>{2be7c90f-ba21-455d-8a11-6f99452be15c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Lib\Mercury">
<UniqueIdentifier>{7e415dd2-403b-4d4d-b4f2-3e311f91db19}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Controller\InputEditor">
<UniqueIdentifier>{010dc29b-d1f6-4793-a4e7-4156aa4fcdd6}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Factories\MaterialFactory.cpp"> <ClCompile Include="Factories\MaterialFactory.cpp">
@ -165,9 +171,6 @@
<ClCompile Include="MemoryPack.cpp"> <ClCompile Include="MemoryPack.cpp">
<Filter>Source Files\Controller\Attachment</Filter> <Filter>Source Files\Controller\Attachment</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="ConfigFile.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="CollisionHeader.cpp"> <ClCompile Include="CollisionHeader.cpp">
<Filter>Source Files\Resources\Files</Filter> <Filter>Source Files\Resources\Files</Filter>
</ClCompile> </ClCompile>
@ -354,6 +357,15 @@
<ClCompile Include="Factories\AudioFactory.cpp"> <ClCompile Include="Factories\AudioFactory.cpp">
<Filter>Source Files\Resources\Factories</Filter> <Filter>Source Files\Resources\Factories</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="InputEditor.cpp">
<Filter>Source Files\Controller\InputEditor</Filter>
</ClCompile>
<ClCompile Include="ControlDeck.cpp">
<Filter>Source Files\Controller</Filter>
</ClCompile>
<ClCompile Include="Lib\Mercury\Mercury.cpp">
<Filter>Source Files\Lib\Mercury</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h"> <ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@ -386,9 +398,6 @@
<ClInclude Include="MemoryPack.h"> <ClInclude Include="MemoryPack.h">
<Filter>Source Files\Controller\Attachment</Filter> <Filter>Source Files\Controller\Attachment</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ConfigFile.h">
<Filter>Source Files\Config</Filter>
</ClInclude>
<ClInclude Include="ResourceMgr.h"> <ClInclude Include="ResourceMgr.h">
<Filter>Source Files\Resources</Filter> <Filter>Source Files\Resources</Filter>
</ClInclude> </ClInclude>
@ -659,5 +668,20 @@
<ClInclude Include="Lib\dr_libs\wav.h"> <ClInclude Include="Lib\dr_libs\wav.h">
<Filter>Source Files\Lib\dr_libs</Filter> <Filter>Source Files\Lib\dr_libs</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="InputEditor.h">
<Filter>Source Files\Controller\InputEditor</Filter>
</ClInclude>
<ClInclude Include="ControlDeck.h">
<Filter>Source Files\Controller</Filter>
</ClInclude>
<ClInclude Include="DisconnectedController.h">
<Filter>Source Files\Controller</Filter>
</ClInclude>
<ClInclude Include="Lib\nlohmann\json.hpp">
<Filter>Source Files\Lib\nlohmann</Filter>
</ClInclude>
<ClInclude Include="Lib\Mercury\Mercury.h">
<Filter>Source Files\Lib\Mercury</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/HarbourMasters/soh.git remote = https://github.com/HarbourMasters/soh.git
branch = master branch = master
commit = ba904bbd0d724784f8f37ff4bea378f6fe26151b commit = 75ccbade8ba26485266a8c8aa7d81e495d0ca4dd
parent = 0bb0e7b53bd80bdc7f78e08c441691737e039b2b parent = 8417db65c73cb3d117f2a0f9040105022a45480c
method = rebase method = rebase
cmdver = 0.4.1 cmdver = 0.4.1

View File

@ -120,6 +120,7 @@ ifeq ($(UNAME), Darwin) #APPLE
LDLIBS += \ LDLIBS += \
$(addprefix -framework , \ $(addprefix -framework , \
OpenGL \ OpenGL \
Foundation \
) \ ) \
$(shell sdl2-config --libs) $(shell pkg-config --libs glew) $(shell sdl2-config --libs) $(shell pkg-config --libs glew)
endif endif
@ -224,9 +225,6 @@ appbundle: macosx/$(APPNAME).icns
cp macosx/PkgInfo $(APPBUNDLECONTENTS)/ cp macosx/PkgInfo $(APPBUNDLECONTENTS)/
cp macosx/$(APPNAME).icns $(APPBUNDLEICON)/ cp macosx/$(APPNAME).icns $(APPBUNDLEICON)/
cp $(TARGET) $(APPBUNDLEEXE)/soh cp $(TARGET) $(APPBUNDLEEXE)/soh
cp macosx/launcher.sh $(APPBUNDLEEXE)/launcher.sh
clang -ObjC macosx/appsupport.m -arch arm64 -arch x86_64 -framework Foundation -o macosx/appsupport
cp macosx/appsupport $(APPBUNDLEEXE)/appsupport
otool -l $(TARGET) | grep -A 2 LC_RPATH | tail -n 1 | awk '{print $2}' | dylibbundler -od -b -x $(APPBUNDLEEXE)/soh -d $(APPBUNDLECONTENTS)/libs otool -l $(TARGET) | grep -A 2 LC_RPATH | tail -n 1 | awk '{print $2}' | dylibbundler -od -b -x $(APPBUNDLEEXE)/soh -d $(APPBUNDLECONTENTS)/libs
macosx/$(APPNAME).icns: macosx/$(APPNAME)Icon.png macosx/$(APPNAME).icns: macosx/$(APPNAME)Icon.png
@ -244,7 +242,3 @@ macosx/$(APPNAME).icns: macosx/$(APPNAME)Icon.png
cp macosx/$(APPNAME)Icon.png macosx/$(APPNAME).iconset/icon_512x512@2x.png cp macosx/$(APPNAME)Icon.png macosx/$(APPNAME).iconset/icon_512x512@2x.png
iconutil -c icns -o macosx/$(APPNAME).icns macosx/$(APPNAME).iconset iconutil -c icns -o macosx/$(APPNAME).icns macosx/$(APPNAME).iconset
rm -r macosx/$(APPNAME).iconset rm -r macosx/$(APPNAME).iconset
filledappbundle: appbundle
cp ./oot.otr $(APPBUNDLEEXE)/oot.otr

View File

@ -559,6 +559,7 @@ void ActorOverlayTable_Cleanup(void);
u16 DynaSSNodeList_GetNextNodeIdx(DynaSSNodeList*); u16 DynaSSNodeList_GetNextNodeIdx(DynaSSNodeList*);
void func_80038A28(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest); void func_80038A28(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest);
f32 CollisionPoly_GetPointDistanceFromPlane(CollisionPoly* poly, Vec3f* point); f32 CollisionPoly_GetPointDistanceFromPlane(CollisionPoly* poly, Vec3f* point);
CollisionHeader* BgCheck_GetCollisionHeader(CollisionContext* colCtx, s32 bgId);
void CollisionPoly_GetVerticesByBgId(CollisionPoly* poly, s32 bgId, CollisionContext* colCtx, Vec3f* dest); void CollisionPoly_GetVerticesByBgId(CollisionPoly* poly, s32 bgId, CollisionContext* colCtx, Vec3f* dest);
s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos, s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
f32 checkHeight, CollisionPoly** outPoly); f32 checkHeight, CollisionPoly** outPoly);

View File

@ -1203,6 +1203,9 @@ typedef struct GlobalContext {
/* 0x00790 */ Camera* cameraPtrs[NUM_CAMS]; /* 0x00790 */ Camera* cameraPtrs[NUM_CAMS];
/* 0x007A0 */ s16 activeCamera; /* 0x007A0 */ s16 activeCamera;
/* 0x007A2 */ s16 nextCamera; /* 0x007A2 */ s16 nextCamera;
/* 0x007A2 */ bool manualCamera;
/* 0x007A2 */ f32 camX;
/* 0x007A2 */ f32 camY;
/* 0x007A4 */ SequenceContext sequenceCtx; /* 0x007A4 */ SequenceContext sequenceCtx;
/* 0x007A8 */ LightContext lightCtx; /* 0x007A8 */ LightContext lightCtx;
/* 0x007B8 */ FrameAdvanceContext frameAdvCtx; /* 0x007B8 */ FrameAdvanceContext frameAdvCtx;

View File

@ -3,7 +3,7 @@
#include "ultra64.h" #include "ultra64.h"
#include "z64math.h" #include "z64math.h"
#include <randomizerTypes.h> #include "soh/Enhancements/randomizer/randomizerTypes.h"
typedef struct { typedef struct {
/* 0x00 */ u8 buttonItems[8]; /* 0x00 */ u8 buttonItems[8];

View File

@ -7,9 +7,9 @@
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Ship of Harkinian</string> <string>Ship of Harkinian</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>launcher.sh</string> <string>soh</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>2.0.0</string> <string>3.0.0</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>soh.icns</string> <string>soh.icns</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -22,14 +22,14 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.0.0</string> <string>3.0.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>ZOoT</string> <string>ZOoT</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2.0.0</string> <string>3.0.0</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright 2022 HarbourMasters.</string> <string>Copyright 2022 HarbourMasters.</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.3</string> <string>10.15</string>
</dict> </dict>
</plist> </plist>

View File

@ -1,26 +0,0 @@
#import <Foundation/Foundation.h>
int main(void) {
NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
//If there isn't an App Support Directory yet ...
if (![[NSFileManager defaultManager] fileExistsAtPath:appSupportDir isDirectory:NULL]) {
NSError *error = nil;
//Create one
if (![[NSFileManager defaultManager] createDirectoryAtPath:appSupportDir withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"%@", error.localizedDescription);
}
else {
// *** OPTIONAL *** Mark the directory as excluded from iCloud backups
NSURL *url = [NSURL fileURLWithPath:appSupportDir];
if (![url setResourceValue:@YES
forKey:NSURLIsExcludedFromBackupKey
error:&error])
{
NSLog(@"Error excluding %@ from backup %@", url.lastPathComponent, error.localizedDescription);
}
else {
NSLog(@"Yay");
}
}
}
printf("%s\n", [appSupportDir UTF8String]);
}

View File

@ -1,9 +0,0 @@
#!/bin/bash
APPPATH="${0%/*}"
cd "${APPPATH}"
APPPATH=$(pwd)
APPSUPPORT=$(./appsupport)
mkdir -p "${APPSUPPORT}/com.shipofharkinian.soh"
cd "${APPSUPPORT}/com.shipofharkinian.soh"
cp "${APPPATH}/oot.otr" .
${APPPATH}/soh

View File

@ -1,19 +0,0 @@
#include <Lib/spdlog/include/spdlog/spdlog.h>
void GenerateRandomizer() {
int ret = Playthrough::Playthrough_Init(std::hash<std::string>{}(Settings::seed));
if (ret < 0) {
if (ret == -1) { // Failed to generate after 5 tries
SPDLOG_ERROR(
"\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be "
"successful.");
return;
} else {
SPDLOG_ERROR("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret);
return;
}
}
const auto& randomizerHash = GetRandomizerHash();
}

View File

@ -143,7 +143,7 @@
<ClCompile> <ClCompile>
<WarningLevel>TurnOffAllWarnings</WarningLevel> <WarningLevel>TurnOffAllWarnings</WarningLevel>
<SDLCheck>false</SDLCheck> <SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>INCLUDE_GAME_PRINTF;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_DX11;%(PreprocessorDefinitions)GLEW_STATIC </PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_DX11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -941,6 +941,7 @@
<ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark.c" /> <ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark.c" />
<ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark_data.c" /> <ClCompile Include="src\overlays\misc\ovl_kaleido_scope\z_lmap_mark_data.c" />
<ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" /> <ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="soh\Enhancements\cosmetics\CosmeticsEditor.h" /> <ClInclude Include="soh\Enhancements\cosmetics\CosmeticsEditor.h" />
@ -982,7 +983,7 @@
<ClInclude Include="soh\Enhancements\randomizer\3drando\tinyxml2.h" /> <ClInclude Include="soh\Enhancements\randomizer\3drando\tinyxml2.h" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\trial.hpp" /> <ClInclude Include="soh\Enhancements\randomizer\3drando\trial.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp" /> <ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp" />
<ClInclude Include="randomizerTypes.h" /> <ClInclude Include="soh\Enhancements\randomizer\randomizerTypes.h" />
<ClInclude Include="soh\Enhancements\randomizer\randomizer_item_tracker.h" /> <ClInclude Include="soh\Enhancements\randomizer\randomizer_item_tracker.h" />
<ClInclude Include="soh\frame_interpolation.h" /> <ClInclude Include="soh\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" /> <ClInclude Include="include\alloca.h" />
@ -1038,7 +1039,6 @@
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" /> <ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h" /> <ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h" />
<ClInclude Include="soh\gameconsole.h" /> <ClInclude Include="soh\gameconsole.h" />
<ClInclude Include="soh\Lib\nlohmann\json.hpp" />
<ClInclude Include="soh\OTRAudio.h" /> <ClInclude Include="soh\OTRAudio.h" />
<ClInclude Include="soh\OTRGlobals.h" /> <ClInclude Include="soh\OTRGlobals.h" />
<ClInclude Include="soh\SaveManager.h" /> <ClInclude Include="soh\SaveManager.h" />

View File

@ -82,12 +82,6 @@
<Filter Include="Source Files\soh\Enhancements\debugger"> <Filter Include="Source Files\soh\Enhancements\debugger">
<UniqueIdentifier>{04fc1c52-49ff-48e2-ae23-2c00867374f8}</UniqueIdentifier> <UniqueIdentifier>{04fc1c52-49ff-48e2-ae23-2c00867374f8}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source Files\soh\Lib">
<UniqueIdentifier>{dbcf07c4-80b1-4c88-ac54-2bbdd8f53ee4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\soh\Lib\nlohmann">
<UniqueIdentifier>{9c880c8e-492b-48f6-b230-1fd269ea74b1}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\boot\assert.c"> <ClCompile Include="src\boot\assert.c">
@ -3947,9 +3941,6 @@
<ClInclude Include="soh\OTRAudio.h"> <ClInclude Include="soh\OTRAudio.h">
<Filter>Source Files\soh</Filter> <Filter>Source Files\soh</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="soh\Lib\nlohmann\json.hpp">
<Filter>Source Files\soh\Lib\nlohmann</Filter>
</ClInclude>
<ClInclude Include="soh\SaveManager.h"> <ClInclude Include="soh\SaveManager.h">
<Filter>Source Files\soh</Filter> <Filter>Source Files\soh</Filter>
</ClInclude> </ClInclude>
@ -4061,7 +4052,7 @@
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp"> <ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="randomizerTypes.h"> <ClInclude Include="soh\Enhancements\randomizer\randomizerTypes.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="soh\Enhancements\gfx.h"> <ClInclude Include="soh\Enhancements\gfx.h">

View File

@ -30,7 +30,6 @@ void BootCommands_Init()
CVar_RegisterS32("gHoverFishing", 0); CVar_RegisterS32("gHoverFishing", 0);
CVar_RegisterS32("gN64WeirdFrames", 0); CVar_RegisterS32("gN64WeirdFrames", 0);
CVar_RegisterS32("gBombchusOOB", 0); CVar_RegisterS32("gBombchusOOB", 0);
CVar_RegisterS32("gRumbleEnabled", 0);
CVar_RegisterS32("gUniformLR", 0); CVar_RegisterS32("gUniformLR", 0);
CVar_RegisterS32("gTwoHandedIdle", 0); CVar_RegisterS32("gTwoHandedIdle", 0);
CVar_RegisterS32("gDekuNutUpgradeFix", 0); CVar_RegisterS32("gDekuNutUpgradeFix", 0);

View File

@ -178,28 +178,28 @@ void Draw_Npcs(){
ImGui::TableSetupColumn("Outer colors##Navi", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort, TablesCellsWidth/2); ImGui::TableSetupColumn("Outer colors##Navi", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort, TablesCellsWidth/2);
Table_InitHeader(); Table_InitHeader();
Draw_HelpIcon("Inner color for Navi (idle flying around)"); Draw_HelpIcon("Inner color for Navi (idle flying around)");
SohImGui::EnhancementColor("Navi Idle", "gNavi_Idle_Inner_", navi_idle_i_col, ImVec4(255, 255, 255, 255), false); SohImGui::EnhancementColor("Navi Idle (Primary)", "gNavi_Idle_Inner_", navi_idle_i_col, ImVec4(255, 255, 255, 255), false);
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Outer color for Navi (idle flying around)"); Draw_HelpIcon("Outer color for Navi (idle flying around)");
SohImGui::EnhancementColor("Navi Idle", "gNavi_Idle_Outer_", navi_idle_o_col, ImVec4(0, 0, 255, 255), false); SohImGui::EnhancementColor("Navi Idle (Secondary)", "gNavi_Idle_Outer_", navi_idle_o_col, ImVec4(0, 0, 255, 255), false);
Table_NextLine(); Table_NextLine();
Draw_HelpIcon("Inner color for Navi (when Navi fly around NPCs)"); Draw_HelpIcon("Inner color for Navi (when Navi fly around NPCs)");
SohImGui::EnhancementColor("Navi NPC", "gNavi_NPC_Inner_", navi_npc_i_col, ImVec4(150, 150, 255, 255), false); SohImGui::EnhancementColor("Navi NPC (Primary)", "gNavi_NPC_Inner_", navi_npc_i_col, ImVec4(150, 150, 255, 255), false);
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Outer color for Navi (when Navi fly around NPCs)"); Draw_HelpIcon("Outer color for Navi (when Navi fly around NPCs)");
SohImGui::EnhancementColor("Navi NPC", "gNavi_NPC_Outer_", navi_npc_o_col, ImVec4(150, 150, 255, 255), false); SohImGui::EnhancementColor("Navi NPC (Secondary)", "gNavi_NPC_Outer_", navi_npc_o_col, ImVec4(150, 150, 255, 255), false);
Table_NextLine(); Table_NextLine();
Draw_HelpIcon("Inner color for Navi (when Navi fly around Enemies or Bosses)"); Draw_HelpIcon("Inner color for Navi (when Navi fly around Enemies or Bosses)");
SohImGui::EnhancementColor("Navi Enemy", "gNavi_Enemy_Inner_", navi_enemy_i_col, ImVec4(255, 255, 0, 255), false); SohImGui::EnhancementColor("Navi Enemy (Primary)", "gNavi_Enemy_Inner_", navi_enemy_i_col, ImVec4(255, 255, 0, 255), false);
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Outer color for Navi (when Navi fly around Enemies or Bosses)"); Draw_HelpIcon("Outer color for Navi (when Navi fly around Enemies or Bosses)");
SohImGui::EnhancementColor("Navi Enemy", "gNavi_Enemy_Outer_", navi_enemy_o_col, ImVec4(220, 155, 0, 255), false); SohImGui::EnhancementColor("Navi Enemy (Secondary)", "gNavi_Enemy_Outer_", navi_enemy_o_col, ImVec4(220, 155, 0, 255), false);
Table_NextLine(); Table_NextLine();
Draw_HelpIcon("Inner color for Navi (when Navi fly around props (signs etc))"); Draw_HelpIcon("Inner color for Navi (when Navi fly around props (signs etc))");
SohImGui::EnhancementColor("Navi Prop", "gNavi_Prop_Inner_", navi_prop_i_col, ImVec4(0, 255, 0, 255), false); SohImGui::EnhancementColor("Navi Prop (Primary)", "gNavi_Prop_Inner_", navi_prop_i_col, ImVec4(0, 255, 0, 255), false);
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Outer color for Navi (when Navi fly around props (signs etc))"); Draw_HelpIcon("Outer color for Navi (when Navi fly around props (signs etc))");
SohImGui::EnhancementColor("Navi Prop", "gNavi_Prop_Outer_", navi_prop_o_col, ImVec4(0, 255, 0, 255), false); SohImGui::EnhancementColor("Navi Prop (Secondary)", "gNavi_Prop_Outer_", navi_prop_o_col, ImVec4(0, 255, 0, 255), false);
ImGui::EndTable(); ImGui::EndTable();
} }
SohImGui::EnhancementCheckbox("Custom colors for Keese", "gUseKeeseCol"); SohImGui::EnhancementCheckbox("Custom colors for Keese", "gUseKeeseCol");
@ -212,10 +212,10 @@ void Draw_Npcs(){
SohImGui::EnhancementColor("Fire Primary color", "gKeese1_Ef_Prim", Keese1_primcol, ImVec4(255, 255, 100, 255)); SohImGui::EnhancementColor("Fire Primary color", "gKeese1_Ef_Prim", Keese1_primcol, ImVec4(255, 255, 100, 255));
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Affects the primary color of the Ice itself of the Keese"); Draw_HelpIcon("Affects the primary color of the Ice itself of the Keese");
SohImGui::EnhancementColor("Fire Primary color", "gKeese2_Ef_Prim", Keese2_primcol, ImVec4(100, 200, 255, 255)); SohImGui::EnhancementColor("Ice Primary color", "gKeese2_Ef_Prim", Keese2_primcol, ImVec4(100, 200, 255, 255));
Table_NextLine(); Table_NextLine();
Draw_HelpIcon("Affects the secondary color of the Fire itself of the Keese"); Draw_HelpIcon("Affects the secondary color of the Fire itself of the Keese");
SohImGui::EnhancementColor("Ice Secondary color", "gKeese1_Ef_Env", Keese1_envcol, ImVec4(255, 50, 0, 255)); SohImGui::EnhancementColor("Fire Secondary color", "gKeese1_Ef_Env", Keese1_envcol, ImVec4(255, 50, 0, 255));
Table_NextCol(); Table_NextCol();
Draw_HelpIcon("Affects the secondary color of the Ice itself of the Keese"); Draw_HelpIcon("Affects the secondary color of the Ice itself of the Keese");
SohImGui::EnhancementColor("Ice Secondary color", "gKeese2_Ef_Env", Keese2_envcol, ImVec4(0, 0, 255, 255)); SohImGui::EnhancementColor("Ice Secondary color", "gKeese2_Ef_Env", Keese2_envcol, ImVec4(0, 0, 255, 255));

View File

@ -16,6 +16,7 @@
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
#include <Utils/File.h> #include <Utils/File.h>
#include "Window.h"
#include "Lib/ImGui/imgui_internal.h" #include "Lib/ImGui/imgui_internal.h"
#undef PATH_HACK #undef PATH_HACK
#undef Path #undef Path
@ -498,10 +499,10 @@ template <typename Numeric> bool is_number(const std::string& s) {
return ((std::istringstream(s) >> n >> std::ws).eof()); return ((std::istringstream(s) >> n >> std::ws).eof());
} }
void DebugConsole_LoadCVars() void DebugConsole_LoadLegacyCVars() {
{ auto cvarsConfig = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("cvars.cfg");
if (File::Exists("cvars.cfg")) { if (File::Exists(cvarsConfig)) {
const auto lines = File::ReadAllLines("cvars.cfg"); const auto lines = File::ReadAllLines(cvarsConfig);
for (const std::string& line : lines) { for (const std::string& line : lines) {
std::vector<std::string> cfg = StringHelper::Split(line, " = "); std::vector<std::string> cfg = StringHelper::Split(line, " = ");
@ -519,21 +520,58 @@ void DebugConsole_LoadCVars()
CVar_SetS32(cfg[0].c_str(), std::stoi(cfg[1])); CVar_SetS32(cfg[0].c_str(), std::stoi(cfg[1]));
} }
} }
fs::remove(cvarsConfig);
} }
} }
void DebugConsole_LoadCVars() {
std::shared_ptr<Mercury> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
pConf->reload();
for (const auto& item : pConf->rjson["CVars"].items()) {
auto value = item.value();
switch (value.type()) {
case nlohmann::detail::value_t::array:
break;
case nlohmann::detail::value_t::string:
CVar_SetString(item.key().c_str(), value.get<std::string>().c_str());
break;
case nlohmann::detail::value_t::boolean:
CVar_SetS32(item.key().c_str(), value.get<bool>());
break;
case nlohmann::detail::value_t::number_unsigned:
case nlohmann::detail::value_t::number_integer:
CVar_SetS32(item.key().c_str(), value.get<int>());
break;
case nlohmann::detail::value_t::number_float:
CVar_SetFloat(item.key().c_str(), value.get<float>());
break;
default: ;
}
if (item.key() == "gOpenMenuBar") {
int bp = 0;
}
}
DebugConsole_LoadLegacyCVars();
}
void DebugConsole_SaveCVars() void DebugConsole_SaveCVars()
{ {
std::string output; std::shared_ptr<Mercury> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
for (const auto &cvar : cvars) { for (const auto &cvar : cvars) {
if (cvar.second->type == CVAR_TYPE_STRING) const std::string key = StringHelper::Sprintf("CVars.%s", cvar.first.c_str());
output += StringHelper::Sprintf("%s = \"%s\"\n", cvar.first.c_str(), cvar.second->value.valueStr);
if (cvar.second->type == CVAR_TYPE_STRING && cvar.second->value.valueStr != nullptr)
pConf->setString(key, std::string(cvar.second->value.valueStr));
else if (cvar.second->type == CVAR_TYPE_S32) else if (cvar.second->type == CVAR_TYPE_S32)
output += StringHelper::Sprintf("%s = %i\n", cvar.first.c_str(), cvar.second->value.valueS32); pConf->setInt(key, cvar.second->value.valueS32);
else if (cvar.second->type == CVAR_TYPE_FLOAT) else if (cvar.second->type == CVAR_TYPE_FLOAT)
output += StringHelper::Sprintf("%s = %f\n", cvar.first.c_str(), cvar.second->value.valueFloat); pConf->setFloat(key, cvar.second->value.valueFloat);
} }
File::WriteAllText("cvars.cfg", output); pConf->save();
} }

View File

@ -529,7 +529,7 @@ void DrawColCheckList(std::vector<Gfx>& dl, Collider** objects, int32_t count) {
Mtx m; Mtx m;
MtxF mt; MtxF mt;
SkinMatrix_SetTranslate(&mt, cyl->dim.pos.x, cyl->dim.pos.y, cyl->dim.pos.z); SkinMatrix_SetTranslate(&mt, cyl->dim.pos.x, cyl->dim.pos.y + cyl->dim.yShift, cyl->dim.pos.z);
MtxF ms; MtxF ms;
int32_t radius = cyl->dim.radius == 0 ? 1 : cyl->dim.radius; int32_t radius = cyl->dim.radius == 0 ? 1 : cyl->dim.radius;
SkinMatrix_SetScale(&ms, radius / 128.0f, cyl->dim.height / 128.0f, radius / 128.0f); SkinMatrix_SetScale(&ms, radius / 128.0f, cyl->dim.height / 128.0f, radius / 128.0f);

View File

@ -1561,6 +1561,18 @@ void DrawPlayerTab() {
ImGui::InputScalar("C Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[2], &one, NULL); ImGui::InputScalar("C Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[2], &one, NULL);
ImGui::SameLine(); ImGui::SameLine();
ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL); ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL);
if (CVar_GetS32("gDpadEquips", 0)) {
ImGui::NewLine();
ImGui::Text("Current D-pad Equips");
ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working
ImGui::SameLine();
ImGui::InputScalar("D-pad Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[5], &one, NULL);
// Intentionnal to not put everything on the same line, else it's taking too much for lower resolution.
ImGui::InputScalar("D-pad Left", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[6], &one, NULL);
ImGui::SameLine();
ImGui::InputScalar("D-pad Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[7], &one, NULL);
}
}); });
} else { } else {

View File

@ -14,7 +14,7 @@
#include "location_access.hpp" #include "location_access.hpp"
#include "debug.hpp" #include "debug.hpp"
#include <Lib/spdlog/include/spdlog/spdlog.h> #include <Lib/spdlog/include/spdlog/spdlog.h>
#include "randomizerTypes.h" #include "soh/Enhancements/randomizer/randomizerTypes.h"
namespace { namespace {
bool seedChanged; bool seedChanged;

View File

@ -2,7 +2,7 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "randomizerTypes.h" #include "soh/Enhancements/randomizer/randomizerTypes.h"
#define MAIN_MENU 0 #define MAIN_MENU 0
#define OPTION_SUB_MENU 1 #define OPTION_SUB_MENU 1

View File

@ -6,7 +6,7 @@
#include "logic.hpp" #include "logic.hpp"
#include "random.hpp" #include "random.hpp"
#include "spoiler_log.hpp" #include "spoiler_log.hpp"
#include "randomizerTypes.h" #include "soh/Enhancements/randomizer/randomizerTypes.h"
namespace Playthrough { namespace Playthrough {

View File

@ -7,6 +7,9 @@
// #include <soh/Enhancements/randomizer.h> // #include <soh/Enhancements/randomizer.h>
#include <Cvar.h> #include <Cvar.h>
#include <GameSettings.h> #include <GameSettings.h>
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include <GlobalCtx2.h>
#define TICKS_PER_SEC 268123480.0 #define TICKS_PER_SEC 268123480.0
@ -18,7 +21,7 @@ void RandoMain::GenerateRando(std::unordered_map<RandomizerSettingKey, u8> cvarS
// std::string settingsFileName = "./randomizer/latest_settings.json"; // std::string settingsFileName = "./randomizer/latest_settings.json";
// CVar_SetString("gLoadedPreset", settingsFileName.c_str()); // CVar_SetString("gLoadedPreset", settingsFileName.c_str());
std::string fileName = GenerateRandomizer(cvarSettings); std::string fileName = Ship::GlobalCtx2::GetPathRelativeToAppDirectory(GenerateRandomizer(cvarSettings).c_str());
CVar_SetString("gSpoilerLog", fileName.c_str()); CVar_SetString("gSpoilerLog", fileName.c_str());
Game::SaveSettings(); Game::SaveSettings();

View File

@ -11,7 +11,7 @@
#include "utils.hpp" #include "utils.hpp"
#include "shops.hpp" #include "shops.hpp"
#include "hints.hpp" #include "hints.hpp"
#include "soh/Lib/nlohmann/json.hpp" #include "Lib/nlohmann/json.hpp"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -26,6 +26,10 @@
#include <filesystem> #include <filesystem>
#include <variables.h> #include <variables.h>
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include "GlobalCtx2.h"
using json = nlohmann::json; using json = nlohmann::json;
json jsonData; json jsonData;
@ -721,12 +725,13 @@ const char* SpoilerLog_Write(int language) {
//WriteShuffledEntrances(spoilerLog); //WriteShuffledEntrances(spoilerLog);
WriteAllLocations(language); WriteAllLocations(language);
if (!std::filesystem::exists("./Randomizer")) { if (!std::filesystem::exists(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Randomizer"))) {
std::filesystem::create_directory("./Randomizer"); std::filesystem::create_directory(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Randomizer"));
} }
std::string jsonString = jsonData.dump(4); std::string jsonString = jsonData.dump(4);
std::ofstream jsonFile("./Randomizer/" + Settings::seed + ".json"); std::ofstream jsonFile(Ship::GlobalCtx2::GetPathRelativeToAppDirectory(
(std::string("Randomizer/") + std::string(Settings::seed) + std::string(".json")).c_str()));
jsonFile << std::setw(4) << jsonString << std::endl; jsonFile << std::setw(4) << jsonString << std::endl;
jsonFile.close(); jsonFile.close();

View File

@ -1,11 +1,10 @@
#ifndef RANDOMIZER_H #pragma once
#define RANDOMIZER_H
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include "../../../include/ultra64.h" #include "../../../include/ultra64.h"
#include "../../../include/z64item.h" #include "../../../include/z64item.h"
#include <randomizerTypes.h> #include "soh/Enhancements/randomizer/randomizerTypes.h"
class Randomizer { class Randomizer {
private: private:
@ -54,5 +53,3 @@ void Rando_Init(void);
} }
#endif #endif
#endif

View File

@ -57,7 +57,6 @@ OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance; SaveManager* SaveManager::Instance;
OTRGlobals::OTRGlobals() { OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian"); context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
gSaveStateMgr = std::make_shared<SaveStateMgr>(); gSaveStateMgr = std::make_shared<SaveStateMgr>();
gRandomizer = std::make_shared<Randomizer>(); gRandomizer = std::make_shared<Randomizer>();
@ -1154,34 +1153,27 @@ extern "C" s32* ResourceMgr_LoadCSByName(const char* path)
return (s32*)res->commands.data(); return (s32*)res->commands.data();
} }
std::filesystem::path GetSaveFile(Ship::ConfigFile& Conf) { std::filesystem::path GetSaveFile(std::shared_ptr<Mercury> Conf) {
std::string fileName = Conf.get("SAVE").get("Save Filename"); const std::string fileName = Conf->getString("Game.SaveName", Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.sav"));
if (fileName.empty()) {
Conf["SAVE"]["Save Filename"] = "oot_save.sav";
Conf.Save();
}
std::filesystem::path saveFile = std::filesystem::absolute(fileName); std::filesystem::path saveFile = std::filesystem::absolute(fileName);
if (!std::filesystem::exists(saveFile.parent_path())) { if (!exists(saveFile.parent_path())) {
std::filesystem::create_directories(saveFile.parent_path()); create_directories(saveFile.parent_path());
} }
return saveFile; return saveFile;
} }
std::filesystem::path GetSaveFile() { std::filesystem::path GetSaveFile() {
std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig(); const std::shared_ptr<Mercury> pConf = OTRGlobals::Instance->context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
return GetSaveFile(Conf); return GetSaveFile(pConf);
} }
void OTRGlobals::CheckSaveFile(size_t sramSize) { void OTRGlobals::CheckSaveFile(size_t sramSize) const {
std::shared_ptr<Ship::ConfigFile> pConf = context->GetConfig(); const std::shared_ptr<Mercury> pConf = Instance->context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
std::filesystem::path savePath = GetSaveFile(Conf); std::filesystem::path savePath = GetSaveFile(pConf);
std::fstream saveFile(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); std::fstream saveFile(savePath, std::fstream::in | std::fstream::out | std::fstream::binary);
if (saveFile.fail()) { if (saveFile.fail()) {
saveFile.open(savePath, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app); saveFile.open(savePath, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app);
@ -1200,25 +1192,6 @@ extern "C" void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size) {
OTRGlobals::Instance->context->WriteSaveFile(GetSaveFile(), addr, dramAddr, size); OTRGlobals::Instance->context->WriteSaveFile(GetSaveFile(), addr, dramAddr, size);
} }
/* Remember to free after use of value */
extern "C" char* Config_getValue(char* category, char* key) {
std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
std::string data = Conf.get(std::string(category)).get(std::string(key));
char* retval = (char*)malloc(data.length()+1);
strcpy(retval, data.c_str());
return retval;
}
extern "C" bool Config_setValue(char* category, char* key, char* value) {
std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
Conf[std::string(category)][std::string(key)] = std::string(value);
return Conf.Save();
}
std::wstring StringToU16(const std::string& s) { std::wstring StringToU16(const std::string& s) {
std::vector<unsigned long> result; std::vector<unsigned long> result;
size_t i = 0; size_t i = 0;
@ -1320,11 +1293,10 @@ extern "C" uint32_t OTRGetCurrentHeight() {
} }
extern "C" void OTRControllerCallback(ControllerCallback* controller) { extern "C" void OTRControllerCallback(ControllerCallback* controller) {
auto controllers = OTRGlobals::Instance->context->GetWindow()->Controllers; const auto controllers = Ship::Window::ControllerApi->virtualDevices;
for (size_t i = 0; i < controllers.size(); i++) {
for (int j = 0; j < controllers[i].size(); j++) { for (int i = 0; i < controllers.size(); ++i) {
OTRGlobals::Instance->context->GetWindow()->Controllers[i][j]->WriteToSource(controller); Ship::Window::ControllerApi->physicalDevices[controllers[i]]->WriteToSource(i, controller);
}
} }
} }
@ -1378,11 +1350,11 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) {
} }
extern "C" int Controller_ShouldRumble(size_t i) { extern "C" int Controller_ShouldRumble(size_t i) {
for (const auto& controller : Ship::Window::Controllers.at(i))
{
float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", i).c_str(), 1.0f);
if (controller->CanRumble() && rumble_strength > 0.001f) { const auto controllers = Ship::Window::ControllerApi->virtualDevices;
for (const auto virtual_entry : controllers) {
if (Ship::Window::ControllerApi->physicalDevices[virtual_entry]->CanRumble()) {
return 1; return 1;
} }
} }
@ -1395,23 +1367,23 @@ extern "C" void* getN64WeirdFrame(s32 i) {
return &weirdFrameBytes[i + sizeof(n64WeirdFrames)]; return &weirdFrameBytes[i + sizeof(n64WeirdFrames)];
} }
extern "C" s16 GetItemModelFromId(s16 itemId) { extern "C" s16 Randomizer_GetItemModelFromId(s16 itemId) {
return OTRGlobals::Instance->gRandomizer->GetItemModelFromId(itemId); return OTRGlobals::Instance->gRandomizer->GetItemModelFromId(itemId);
} }
extern "C" s32 GetItemIDFromGetItemID(s32 getItemId) { extern "C" s32 Randomizer_GetItemIDFromGetItemID(s32 getItemId) {
return OTRGlobals::Instance->gRandomizer->GetItemIDFromGetItemID(getItemId); return OTRGlobals::Instance->gRandomizer->GetItemIDFromGetItemID(getItemId);
} }
extern "C" void LoadRandomizerSettings(const char* spoilerFileName) { extern "C" void Randomizer_LoadSettings(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadRandomizerSettings(spoilerFileName); OTRGlobals::Instance->gRandomizer->LoadRandomizerSettings(spoilerFileName);
} }
extern "C" void LoadHintLocations(const char* spoilerFileName) { extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName); OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName);
} }
extern "C" void LoadItemLocations(const char* spoilerFileName, bool silent) { extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) {
OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent); OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent);
} }
@ -1419,11 +1391,11 @@ extern "C" bool SpoilerFileExists(const char* spoilerFileName) {
return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName); return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName);
} }
extern "C" u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey) {
return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(randoSettingKey); return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(randoSettingKey);
} }
extern "C" RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) { extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) {
return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams);
} }
@ -1499,33 +1471,33 @@ extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBuff
return CopyStringToCharBuffer(scrubText, buffer, maxBufferSize); return CopyStringToCharBuffer(scrubText, buffer, maxBufferSize);
} }
extern "C" int CopyAltarMessage(char* buffer, const int maxBufferSize) { extern "C" int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize) {
const std::string& altarText = (LINK_IS_ADULT) ? OTRGlobals::Instance->gRandomizer->GetAdultAltarText() const std::string& altarText = (LINK_IS_ADULT) ? OTRGlobals::Instance->gRandomizer->GetAdultAltarText()
: OTRGlobals::Instance->gRandomizer->GetChildAltarText(); : OTRGlobals::Instance->gRandomizer->GetChildAltarText();
return CopyStringToCharBuffer(altarText, buffer, maxBufferSize); return CopyStringToCharBuffer(altarText, buffer, maxBufferSize);
} }
extern "C" int CopyGanonText(char* buffer, const int maxBufferSize) { extern "C" int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize) {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonText(); const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonText();
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize); return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
} }
extern "C" int CopyGanonHintText(char* buffer, const int maxBufferSize) { extern "C" int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize) {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonHintText(); const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonHintText();
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize); return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
} }
extern "C" int CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) { extern "C" int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) {
// we don't want to make a copy of the std::string returned from GetHintFromCheck // we don't want to make a copy of the std::string returned from GetHintFromCheck
// so we're just going to let RVO take care of it // so we're just going to let RVO take care of it
const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check); const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check);
return CopyStringToCharBuffer(hintText, buffer, maxBufferSize); return CopyStringToCharBuffer(hintText, buffer, maxBufferSize);
} }
extern "C" s32 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { extern "C" s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) {
return OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum); return OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum);
} }
extern "C" s32 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) { extern "C" s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
return OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId); return OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId);
} }

View File

@ -23,7 +23,7 @@ public:
~OTRGlobals(); ~OTRGlobals();
private: private:
void CheckSaveFile(size_t sramSize); void CheckSaveFile(size_t sramSize) const;
}; };
#endif #endif
@ -61,8 +61,6 @@ SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
CollisionHeader* ResourceMgr_LoadColByName(const char* path); CollisionHeader* ResourceMgr_LoadColByName(const char* path);
void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size); void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size);
void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size); void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size);
char* Config_getValue(char* category, char* key);
bool Config_setValue(char* category, char* key, char* value);
uint64_t GetPerfCounter(); uint64_t GetPerfCounter();
struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path); struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path);
@ -86,19 +84,19 @@ void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples);
int Controller_ShouldRumble(size_t i); int Controller_ShouldRumble(size_t i);
void* getN64WeirdFrame(s32 i); void* getN64WeirdFrame(s32 i);
Sprite* GetSeedTexture(uint8_t index); Sprite* GetSeedTexture(uint8_t index);
void LoadRandomizerSettings(const char* spoilerFileName); void Randomizer_LoadSettings(const char* spoilerFileName);
u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
int CopyAltarMessage(char* buffer, const int maxBufferSize); int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize);
int CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize); int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize);
int CopyGanonText(char* buffer, const int maxBufferSize); int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize);
int CopyGanonHintText(char* buffer, const int maxBufferSize); int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize);
void LoadHintLocations(const char* spoilerFileName); void Randomizer_LoadHintLocations(const char* spoilerFileName);
void LoadItemLocations(const char* spoilerFileName, bool silent); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
s16 GetItemModelFromId(s16 itemId); s16 Randomizer_GetItemModelFromId(s16 itemId);
s32 GetItemIDFromGetItemID(s32 getItemId); s32 Randomizer_GetItemIDFromGetItemID(s32 getItemId);
s32 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
s32 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
#endif #endif
#endif #endif

View File

@ -1,4 +1,5 @@
#include "SaveManager.h" #include "SaveManager.h"
#include "OTRGlobals.h"
#include "z64.h" #include "z64.h"
#include "functions.h" #include "functions.h"
@ -14,11 +15,9 @@
extern "C" SaveContext gSaveContext; extern "C" SaveContext gSaveContext;
static const std::filesystem::path sSavePath("Save"); // TODO maybe let this be user-configurable?
static const std::filesystem::path sGlobalPath = sSavePath / "global.sav";
std::filesystem::path SaveManager::GetFileName(int fileNum) { std::filesystem::path SaveManager::GetFileName(int fileNum) {
return sSavePath / (std::string("file") + std::to_string(fileNum + 1) + ".sav"); const std::filesystem::path sSavePath(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Save"));
return sSavePath / ("file" + std::to_string(fileNum + 1) + ".sav");
} }
SaveManager::SaveManager() { SaveManager::SaveManager() {
@ -128,15 +127,20 @@ void SaveManager::SaveRandomizer() {
} }
void SaveManager::Init() { void SaveManager::Init() {
const std::filesystem::path sSavePath(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Save"));
const std::filesystem::path sGlobalPath = sSavePath / std::string("global.sav");
auto sOldSavePath = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.sav");
auto sOldBackupSavePath = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.bak");
// If the save directory does not exist, create it // If the save directory does not exist, create it
if (!std::filesystem::exists(sSavePath)) { if (!std::filesystem::exists(sSavePath)) {
std::filesystem::create_directory(sSavePath); std::filesystem::create_directory(sSavePath);
} }
// If there is a lingering unversioned save, convert it // If there is a lingering unversioned save, convert it
if (std::filesystem::exists("oot_save.sav")) { if (std::filesystem::exists(sOldSavePath)) {
ConvertFromUnversioned(); ConvertFromUnversioned();
std::filesystem::rename("oot_save.sav", "oot_save.bak"); std::filesystem::rename(sOldSavePath, sOldBackupSavePath);
} }
// If the global save file exist, load it. Otherwise, create it. // If the global save file exist, load it. Otherwise, create it.

View File

@ -1,4 +1,4 @@
const char gBuildVersion[] = "ROY ALFA (2.0.0)"; const char gBuildVersion[] = "RACHAEL ALFA (3.0.0)";
const char gBuildTeam[] = "github.com/harbourmasters"; const char gBuildTeam[] = "github.com/harbourmasters";
const char gBuildDate[] = __DATE__ " " __TIME__; const char gBuildDate[] = __DATE__ " " __TIME__;
const char gBuildMakeOption[] = ""; const char gBuildMakeOption[] = "";

View File

@ -1176,9 +1176,13 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) {
if (seqPlayer->defaultFont != 0xFF) if (seqPlayer->defaultFont != 0xFF)
{ {
SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqPlayer->seqId]); SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqPlayer->seqId]);
int8_t idx = (sDat.numFonts - result - 1);
command = sDat.fonts[abs(idx)]; // The game apparantely would sometimes do negative array lookups, the result of which would get rejected by AudioHeap_SearchCaches, never
// changing the actual fontid.
if (result > sDat.numFonts)
break;
command = sDat.fonts[(sDat.numFonts - result - 1)];
} }
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, command)) if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, command))

View File

@ -409,7 +409,9 @@ void GameState_Update(GameState* gameState) {
// Unrestricted Items // Unrestricted Items
if (CVar_GetS32("gNoRestrictItems", 0) != 0) { if (CVar_GetS32("gNoRestrictItems", 0) != 0) {
if (gGlobalCtx) { if (gGlobalCtx) {
u8 sunsBackup = gGlobalCtx->interfaceCtx.restrictions.sunsSong;
memset(&gGlobalCtx->interfaceCtx.restrictions, 0, sizeof(gGlobalCtx->interfaceCtx.restrictions)); memset(&gGlobalCtx->interfaceCtx.restrictions, 0, sizeof(gGlobalCtx->interfaceCtx.restrictions));
gGlobalCtx->interfaceCtx.restrictions.sunsSong = sunsBackup;
} }
} }

View File

@ -269,7 +269,7 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y); input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y);
} }
controllerCallback.rumble = CVar_GetS32("gRumbleEnabled", 0) && (padMgr->rumbleEnable[0] > 0); controllerCallback.rumble = (padMgr->rumbleEnable[0] > 0);
if (HealthMeter_IsCritical()) { if (HealthMeter_IsCritical()) {
controllerCallback.ledColor = 0; controllerCallback.ledColor = 0;

View File

@ -5983,7 +5983,7 @@ s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* ar
} }
s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) { s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) {
if (GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) { if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
// RANDOTODO update this logic when we implement keysanity // RANDOTODO update this logic when we implement keysanity
// because 3drando replaces the keys not the rupees // because 3drando replaces the keys not the rupees
if (ogDrawId == GID_RUPEE_GREEN || if (ogDrawId == GID_RUPEE_GREEN ||
@ -5993,27 +5993,27 @@ s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx)
switch(room) { switch(room) {
case 1: case 1:
if(!Flags_GetCollectible(globalCtx, 0x1B)) { if(!Flags_GetCollectible(globalCtx, 0x1B)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, GI_RUPEE_GREEN); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, GI_RUPEE_GREEN);
} }
break; break;
case 2: case 2:
if(!Flags_GetCollectible(globalCtx, 0x1C)) { if(!Flags_GetCollectible(globalCtx, 0x1C)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, GI_RUPEE_GREEN); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, GI_RUPEE_GREEN);
} }
break; break;
case 3: case 3:
if(!Flags_GetCollectible(globalCtx, 0x1D)) { if(!Flags_GetCollectible(globalCtx, 0x1D)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, GI_RUPEE_BLUE); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, GI_RUPEE_BLUE);
} }
break; break;
case 4: case 4:
if(!Flags_GetCollectible(globalCtx, 0x1E)) { if(!Flags_GetCollectible(globalCtx, 0x1E)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, GI_RUPEE_BLUE); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, GI_RUPEE_BLUE);
} }
break; break;
case 5: case 5:
if(!Flags_GetCollectible(globalCtx, 0x1F)) { if(!Flags_GetCollectible(globalCtx, 0x1F)) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, GI_RUPEE_RED); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, GI_RUPEE_RED);
} }
break; break;
} }
@ -6021,7 +6021,7 @@ s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx)
} }
if(ogDrawId == GID_HEART_PIECE) { if(ogDrawId == GID_HEART_PIECE) {
return GetRandomizedItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_REWARD, GI_HEART_PIECE); return Randomizer_GetItemIdFromKnownCheck(RC_MARKET_TREASURE_CHEST_GAME_REWARD, GI_HEART_PIECE);
} }
return GI_NONE; return GI_NONE;
@ -6031,7 +6031,7 @@ s16 GetChestGameRandoGiDrawId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) {
s32 randoGetItemId = GetChestGameRandoGetItemId(room, ogDrawId, globalCtx); s32 randoGetItemId = GetChestGameRandoGetItemId(room, ogDrawId, globalCtx);
if(randoGetItemId != GI_NONE) { if(randoGetItemId != GI_NONE) {
return GetItemModelFromId(randoGetItemId); return Randomizer_GetItemModelFromId(randoGetItemId);
} }
return ogDrawId; return ogDrawId;

View File

@ -1409,7 +1409,115 @@ s32 Camera_Noop(Camera* camera) {
return true; return true;
} }
s32 SetCameraManual(Camera* camera) {
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y;
if ((fabsf(newCamX) >= 15.0f || fabsf(newCamY) >= 15.0f) && camera->globalCtx->manualCamera == false) {
camera->globalCtx->manualCamera = true;
VecSph eyeAdjustment;
OLib_Vec3fDiffToVecSphGeo(&eyeAdjustment, &camera->at, &camera->eye);
camera->globalCtx->camX = eyeAdjustment.yaw;
camera->globalCtx->camY = eyeAdjustment.pitch;
}
if (camera->globalCtx->manualCamera) {
return 1;
}
return 0;
}
s32 Camera_Free(Camera* camera) {
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
VecSph spA8;
CamColChk sp6C;
Parallel1* para1 = (Parallel1*)camera->paramData;
f32 playerHeight;
at->x = Camera_LERPCeilF(camera->player->actor.world.pos.x, camera->at.x, 0.5f, 1.0f);
at->y = Camera_LERPCeilF(camera->player->actor.world.pos.y + (camera->player->rideActor != NULL
? Player_GetHeight(camera->player) / 2
: Player_GetHeight(camera->player)) /
1.2f,
camera->at.y, 0.5f, 1.0f);
at->z = Camera_LERPCeilF(camera->player->actor.world.pos.z, camera->at.z, 0.5f, 1.0f);
playerHeight = Player_GetHeight(camera->player);
if (RELOAD_PARAMS) {
OLib_Vec3fDiffToVecSphGeo(&spA8, &camera->at, &camera->eye);
camera->globalCtx->camX = spA8.yaw;
camera->globalCtx->camY = spA8.pitch;
CameraModeValue* values = sCameraSettings[camera->setting].cameraModes[camera->mode].values;
f32 yNormal = (1.0f + PCT(OREG(46))) - (PCT(OREG(46)) * (68.0f / playerHeight));
para1->yOffset = NEXTPCT * playerHeight * yNormal;
para1->distTarget = NEXTPCT * playerHeight * yNormal;
para1->pitchTarget = DEGF_TO_BINANG(NEXTSETTING);
para1->yawTarget = DEGF_TO_BINANG(NEXTSETTING);
para1->unk_08 = NEXTSETTING;
para1->unk_0C = NEXTSETTING;
para1->fovTarget = NEXTSETTING;
para1->unk_14 = NEXTPCT;
para1->interfaceFlags = NEXTSETTING;
para1->unk_18 = NEXTPCT * playerHeight * yNormal;
para1->unk_1C = NEXTPCT;
}
if (R_RELOAD_CAM_PARAMS) {
Camera_CopyPREGToModeValues(camera);
}
sCameraInterfaceFlags = 1;
camera->animState = 1;
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y;
camera->globalCtx->camX += newCamX;
camera->globalCtx->camY += newCamY;
if (camera->globalCtx->camY > 0x32A4) {
camera->globalCtx->camY = 0x32A4;
}
if (camera->globalCtx->camY < -0x228C) {
camera->globalCtx->camY = -0x228C;
}
camera->dist = Camera_LERPCeilF(para1->distTarget, camera->dist, 1.0f / camera->rUpdateRateInv, 0.0f);
OLib_Vec3fDiffToVecSphGeo(&spA8, at, eyeNext);
spA8.r = camera->dist;
spA8.yaw = camera->globalCtx->camX;
spA8.pitch = camera->globalCtx->camY;
Camera_Vec3fVecSphGeoAdd(eyeNext, at, &spA8);
if (camera->status == CAM_STAT_ACTIVE) {
sp6C.pos = *eyeNext;
Camera_BGCheckInfo(camera, at, &sp6C);
*eye = sp6C.pos;
}
camera->fov = Camera_LERPCeilF(65.0f, camera->fov, camera->fovUpdateRate, 1.0f);
camera->roll = Camera_LERPCeilS(0, camera->roll, 0.5, 0xA);
return 1;
}
s32 Camera_Normal1(Camera* camera) { s32 Camera_Normal1(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -1637,6 +1745,11 @@ s32 Camera_Normal1(Camera* camera) {
} }
s32 Camera_Normal2(Camera* camera) { s32 Camera_Normal2(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -1803,6 +1916,11 @@ s32 Camera_Normal2(Camera* camera) {
// riding epona // riding epona
s32 Camera_Normal3(Camera* camera) { s32 Camera_Normal3(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -1997,6 +2115,8 @@ s32 Camera_Parallel1(Camera* camera) {
OLib_Vec3fDiffToVecSphGeo(&atToEyeDir, at, eye); OLib_Vec3fDiffToVecSphGeo(&atToEyeDir, at, eye);
OLib_Vec3fDiffToVecSphGeo(&atToEyeNextDir, at, eyeNext); OLib_Vec3fDiffToVecSphGeo(&atToEyeNextDir, at, eyeNext);
camera->globalCtx->manualCamera = false;
switch (camera->animState) { switch (camera->animState) {
case 0: case 0:
case 0xA: case 0xA:
@ -2162,6 +2282,11 @@ s32 Camera_Parallel0(Camera* camera) {
* Generic jump, jumping off ledges * Generic jump, jumping off ledges
*/ */
s32 Camera_Jump1(Camera* camera) { s32 Camera_Jump1(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -2307,6 +2432,11 @@ s32 Camera_Jump1(Camera* camera) {
// Climbing ladders/vines // Climbing ladders/vines
s32 Camera_Jump2(Camera* camera) { s32 Camera_Jump2(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -2489,6 +2619,11 @@ s32 Camera_Jump2(Camera* camera) {
// swimming // swimming
s32 Camera_Jump3(Camera* camera) { s32 Camera_Jump3(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -2946,6 +3081,11 @@ s32 Camera_Battle3(Camera* camera) {
* setting value. * setting value.
*/ */
s32 Camera_Battle4(Camera* camera) { s32 Camera_Battle4(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;
@ -4476,6 +4616,11 @@ s32 Camera_Data4(Camera* camera) {
* Hanging off of a ledge * Hanging off of a ledge
*/ */
s32 Camera_Unique1(Camera* camera) { s32 Camera_Unique1(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye; Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at; Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext; Vec3f* eyeNext = &camera->eyeNext;

View File

@ -2124,7 +2124,7 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) {
// If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall // If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall
// and exit. // and exit.
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_TOWER_ESCAPE)) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
return; return;
} }
gSaveContext.cutsceneIndex = 0xFFF0; gSaveContext.cutsceneIndex = 0xFFF0;

View File

@ -509,7 +509,7 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) {
} }
if ((gSaveContext.n64ddFlag || getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) { if ((gSaveContext.n64ddFlag || getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) {
getItemId = GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); getItemId = Randomizer_GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
func_8002F554(&this->actor, globalCtx, getItemId); func_8002F554(&this->actor, globalCtx, getItemId);
} }
@ -548,7 +548,7 @@ void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) {
} }
if (this->actor.params == ITEM00_HEART_PIECE) { if (this->actor.params == ITEM00_HEART_PIECE) {
if ((CVar_GetS32("gNewDrops", 0) !=0) && !gSaveContext.n64ddFlag) { if (CVar_GetS32("gNewDrops", 0) && !gSaveContext.n64ddFlag) {
this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 20.0f + 50.0f; this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 20.0f + 50.0f;
} else { } else {
this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 150.0f + 850.0f; this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 150.0f + 850.0f;
@ -881,7 +881,7 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
if ((getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) { if ((getItemId != GI_NONE) && !Actor_HasParent(&this->actor, globalCtx)) {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
getItemId = GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); getItemId = Randomizer_GetRandomizedItemId(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
} }
func_8002F554(&this->actor, globalCtx, getItemId); func_8002F554(&this->actor, globalCtx, getItemId);
} }
@ -1297,14 +1297,14 @@ void EnItem00_DrawRupee(EnItem00* this, GlobalContext* globalCtx) {
* Draw Function used for most collectible types of En_Item00 (ammo, bombs, sticks, nuts, magic...). * Draw Function used for most collectible types of En_Item00 (ammo, bombs, sticks, nuts, magic...).
*/ */
void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) { void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) {
if ((gSaveContext.n64ddFlag && this->getItemId != GI_NONE) || this->actor.params == ITEM00_SMALL_KEY) { if (gSaveContext.n64ddFlag && (this->getItemId != GI_NONE || this->actor.params == ITEM00_SMALL_KEY)) {
f32 mtxScale = 16.0f; f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
s32 randoGetItemId = GetRandomizedItemId(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); s32 randoGetItemId = Randomizer_GetRandomizedItemId(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) { if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
} }
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId)); GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else { } else {
s32 texIndex = this->actor.params - 3; s32 texIndex = this->actor.params - 3;
@ -1360,11 +1360,11 @@ void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
f32 mtxScale = 16.0f; f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
s32 randoGetItemId = GetRandomizedItemId(GI_HEART_PIECE, this->actor.id, this->ogParams, globalCtx->sceneNum); s32 randoGetItemId = Randomizer_GetRandomizedItemId(GI_HEART_PIECE, this->actor.id, this->ogParams, globalCtx->sceneNum);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) { if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
} }
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId)); GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else { } else {
s32 pad; s32 pad;

View File

@ -89,6 +89,7 @@ void TransitionWipe_Draw(void* thisx, Gfx** gfxP) {
TransitionWipe* this = (TransitionWipe*)thisx; TransitionWipe* this = (TransitionWipe*)thisx;
s32 pad[4]; s32 pad[4];
Gfx* tex; Gfx* tex;
Gfx* wipeDl = sWipeDList;
modelView = this->modelView[this->frame]; modelView = this->modelView[this->frame];

View File

@ -1676,11 +1676,11 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
// if we're rando'd and talking to a gossip stone // if we're rando'd and talking to a gossip stone
if (gSaveContext.n64ddFlag && if (gSaveContext.n64ddFlag &&
textId == 0x2053 && textId == 0x2053 &&
GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 && Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 &&
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 || (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 ||
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 && (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 &&
Player_GetMask(globalCtx) == PLAYER_MASK_TRUTH) || Player_GetMask(globalCtx) == PLAYER_MASK_TRUTH) ||
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 && (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 &&
CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
s16 actorParams = msgCtx->talkActor->params; s16 actorParams = msgCtx->talkActor->params;
@ -1700,14 +1700,14 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
} }
} }
RandomizerCheck hintCheck = GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams); RandomizerCheck hintCheck = Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams);
// Pass the sizeof the message buffer so we don't hardcode any sizes and can rely on globals. // Pass the sizeof the message buffer so we don't hardcode any sizes and can rely on globals.
// If no hint can be found, this just returns 0 size and doesn't modify the buffer, so no worries. // If no hint can be found, this just returns 0 size and doesn't modify the buffer, so no worries.
msgCtx->msgLength = font->msgLength = CopyHintFromCheck(hintCheck, font->msgBuf, sizeof(font->msgBuf)); msgCtx->msgLength = font->msgLength = Randomizer_CopyHintFromCheck(hintCheck, font->msgBuf, sizeof(font->msgBuf));
} else if (gSaveContext.n64ddFlag && (textId == 0x7040 || textId == 0x7088)) { } else if (gSaveContext.n64ddFlag && (textId == 0x7040 || textId == 0x7088)) {
// rando hints at altar // rando hints at altar
msgCtx->msgLength = font->msgLength = CopyAltarMessage(font->msgBuf, sizeof(font->msgBuf)); msgCtx->msgLength = font->msgLength = Randomizer_CopyAltarMessage(font->msgBuf, sizeof(font->msgBuf));
} else if (textId == 0x00b4 && CVar_GetS32("gInjectSkulltulaCount", 0) != 0) { } else if (textId == 0x00b4 && CVar_GetS32("gInjectSkulltulaCount", 0) != 0) {
switch (gSaveContext.language) { switch (gSaveContext.language) {
case LANGUAGE_FRA: case LANGUAGE_FRA:
@ -1731,9 +1731,9 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
msgCtx->msgLength = font->msgLength = CopyScrubMessage(textId, font->msgBuf, sizeof(font->msgBuf)); msgCtx->msgLength = font->msgLength = CopyScrubMessage(textId, font->msgBuf, sizeof(font->msgBuf));
} else if (gSaveContext.n64ddFlag && textId == 0x70CC) { } else if (gSaveContext.n64ddFlag && textId == 0x70CC) {
if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) { if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) {
msgCtx->msgLength = font->msgLength = CopyGanonText(font->msgBuf, sizeof(font->msgBuf)); msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonText(font->msgBuf, sizeof(font->msgBuf));
} else { } else {
msgCtx->msgLength = font->msgLength = CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf)); msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf));
} }
} else { } else {
msgCtx->msgLength = font->msgLength; msgCtx->msgLength = font->msgLength;
@ -2237,14 +2237,14 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
} }
} else { } else {
osSyncPrintf("Na_StartOcarinaSinglePlayCheck2( message->ocarina_no );\n"); osSyncPrintf("Na_StartOcarinaSinglePlayCheck2( message->ocarina_no );\n");
func_800ECC04((1 << msgCtx->ocarinaAction) + 0x8000); func_800ECC04((1 << (msgCtx->ocarinaAction % 32)) + 0x8000);
} }
msgCtx->msgMode = MSGMODE_OCARINA_PLAYING; msgCtx->msgMode = MSGMODE_OCARINA_PLAYING;
} else if (msgCtx->msgMode == MSGMODE_SONG_DEMONSTRATION_STARTING) { } else if (msgCtx->msgMode == MSGMODE_SONG_DEMONSTRATION_STARTING) {
msgCtx->stateTimer = 20; msgCtx->stateTimer = 20;
msgCtx->msgMode = MSGMODE_SONG_DEMONSTRATION_SELECT_INSTRUMENT; msgCtx->msgMode = MSGMODE_SONG_DEMONSTRATION_SELECT_INSTRUMENT;
} else { } else {
func_800ECC04((1 << (msgCtx->ocarinaAction + 0x11)) + 0x8000); func_800ECC04((1 << ((msgCtx->ocarinaAction + 0x11) % 32)) + 0x8000);
// "Performance Check" // "Performance Check"
osSyncPrintf("演奏チェック=%d\n", msgCtx->ocarinaAction - OCARINA_ACTION_PLAYBACK_MINUET); osSyncPrintf("演奏チェック=%d\n", msgCtx->ocarinaAction - OCARINA_ACTION_PLAYBACK_MINUET);
msgCtx->msgMode = MSGMODE_SONG_PLAYBACK; msgCtx->msgMode = MSGMODE_SONG_PLAYBACK;
@ -3228,6 +3228,8 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
* the last value being saved in a static variable. * the last value being saved in a static variable.
*/ */
void Message_DrawDebugVariableChanged(s16* var, GraphicsContext* gfxCtx) { void Message_DrawDebugVariableChanged(s16* var, GraphicsContext* gfxCtx) {
if (!CVar_GetS32("gDebugEnabled", 0)) { return; }
static s16 sVarLastValue = 0; static s16 sVarLastValue = 0;
static s16 sFillTimer = 0; static s16 sFillTimer = 0;
s32 pad; s32 pad;

View File

@ -1710,6 +1710,8 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
} else { } else {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS]; gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
} }
} else {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
} }
return ITEM_NONE; return ITEM_NONE;
} else if (item == ITEM_KEY_SMALL) { } else if (item == ITEM_KEY_SMALL) {
@ -1808,13 +1810,13 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
return ITEM_NONE; return ITEM_NONE;
} else if (item == ITEM_WALLET_ADULT) { } else if (item == ITEM_WALLET_ADULT) {
Inventory_ChangeUpgrade(UPG_WALLET, 1); Inventory_ChangeUpgrade(UPG_WALLET, 1);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(200); Rupees_ChangeBy(200);
} }
return ITEM_NONE; return ITEM_NONE;
} else if (item == ITEM_WALLET_GIANT) { } else if (item == ITEM_WALLET_GIANT) {
Inventory_ChangeUpgrade(UPG_WALLET, 2); Inventory_ChangeUpgrade(UPG_WALLET, 2);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(500); Rupees_ChangeBy(500);
} }
return ITEM_NONE; return ITEM_NONE;

View File

@ -198,7 +198,7 @@ void GivePlayerRandoRewardSongOfTime(GlobalContext* globalCtx, RandomizerCheck c
if (gSaveContext.entranceIndex == 0x050F && player != NULL && !Player_InBlockingCsMode(globalCtx, player) && if (gSaveContext.entranceIndex == 0x050F && player != NULL && !Player_InBlockingCsMode(globalCtx, player) &&
!Flags_GetTreasure(globalCtx, 0x1F) && gSaveContext.nextTransition == 0xFF) { !Flags_GetTreasure(globalCtx, 0x1F) && gSaveContext.nextTransition == 0xFF) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_SONG_OF_TIME); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GiveItemWithoutActor(globalCtx, getItemId); GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetTreasure(globalCtx, 0x1F); Flags_SetTreasure(globalCtx, 0x1F);
} }
@ -212,7 +212,7 @@ void GivePlayerRandoRewardNocturne(GlobalContext* globalCtx, RandomizerCheck che
gSaveContext.entranceIndex == 0x0195) && LINK_IS_ADULT && CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) && gSaveContext.entranceIndex == 0x0195) && LINK_IS_ADULT && CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) &&
CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) && player != NULL && CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) && player != NULL &&
!Player_InBlockingCsMode(globalCtx, player) && !Flags_GetEventChkInf(0xAA)) { !Player_InBlockingCsMode(globalCtx, player) && !Flags_GetEventChkInf(0xAA)) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_NOCTURNE_OF_SHADOW); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_NOCTURNE_OF_SHADOW);
GiveItemWithoutActor(globalCtx, getItemId); GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xAA); Flags_SetEventChkInf(0xAA);
} }
@ -224,7 +224,7 @@ void GivePlayerRandoRewardRequiem(GlobalContext* globalCtx, RandomizerCheck chec
if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) { if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) {
if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC) && player != NULL && if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC) && player != NULL &&
!Player_InBlockingCsMode(globalCtx, player)) { !Player_InBlockingCsMode(globalCtx, player)) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_SONG_OF_TIME); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GiveItemWithoutActor(globalCtx, getItemId); GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xAC); Flags_SetEventChkInf(0xAC);
} }
@ -238,7 +238,7 @@ void GivePlayerRandoRewardZeldaLightArrowsGift(GlobalContext* globalCtx, Randomi
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TOKINOMA) && (gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TOKINOMA) &&
!Flags_GetTreasure(globalCtx, 0x1E) && player != NULL && !Player_InBlockingCsMode(globalCtx, player) && !Flags_GetTreasure(globalCtx, 0x1E) && player != NULL && !Player_InBlockingCsMode(globalCtx, player) &&
globalCtx->sceneLoadFlag == 0 && player->getItemId == GI_NONE) { globalCtx->sceneLoadFlag == 0 && player->getItemId == GI_NONE) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_ARROW_LIGHT); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_ARROW_LIGHT);
GiveItemWithoutActor(globalCtx, getItemId); GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetTreasure(globalCtx, 0x1E); Flags_SetTreasure(globalCtx, 0x1E);
} }
@ -247,7 +247,7 @@ void GivePlayerRandoRewardZeldaLightArrowsGift(GlobalContext* globalCtx, Randomi
void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck check) { void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx); Player* player = GET_PLAYER(globalCtx);
if (gSaveContext.entranceIndex == 0x05E0) { if (gSaveContext.entranceIndex == 0x05E0) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_ZELDAS_LULLABY); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_ZELDAS_LULLABY);
if ((!Flags_GetEventChkInf(0xC1) || (player->getItemId == getItemId && getItemId != GI_ICE_TRAP)) && if ((!Flags_GetEventChkInf(0xC1) || (player->getItemId == getItemId && getItemId != GI_ICE_TRAP)) &&
player != NULL && !Player_InBlockingCsMode(globalCtx, player)) { player != NULL && !Player_InBlockingCsMode(globalCtx, player)) {
@ -271,7 +271,7 @@ void Gameplay_Init(GameState* thisx) {
u8 tempSetupIndex; u8 tempSetupIndex;
s32 pad[2]; s32 pad[2];
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_CHILD_STEALTH)) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH)) {
if (gSaveContext.entranceIndex == 0x7A) { if (gSaveContext.entranceIndex == 0x7A) {
gSaveContext.entranceIndex = 0x400; gSaveContext.entranceIndex = 0x400;
} else if (gSaveContext.entranceIndex == 0x296) { } else if (gSaveContext.entranceIndex == 0x296) {
@ -530,6 +530,10 @@ void Gameplay_Update(GlobalContext* globalCtx) {
ActorOverlayTable_LogPrint(); ActorOverlayTable_LogPrint();
} }
if (CVar_GetS32("gFreeCamera", 0) && Player_InCsMode(globalCtx)) {
globalCtx->manualCamera = false;
}
gSegments[4] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[globalCtx->objectCtx.mainKeepIndex].segment); gSegments[4] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[globalCtx->objectCtx.mainKeepIndex].segment);
gSegments[5] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[globalCtx->objectCtx.subKeepIndex].segment); gSegments[5] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[globalCtx->objectCtx.subKeepIndex].segment);
gSegments[2] = VIRTUAL_TO_PHYSICAL(globalCtx->sceneSegment); gSegments[2] = VIRTUAL_TO_PHYSICAL(globalCtx->sceneSegment);

View File

@ -416,7 +416,7 @@ void GiveLinkDungeonReward(GetItemID getItemId) {
} }
void GiveLinksPocketMedallion() { void GiveLinksPocketMedallion() {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
GiveLinkDungeonReward(getItemId); GiveLinkDungeonReward(getItemId);
} }
@ -644,7 +644,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
// Give Link's pocket item // Give Link's pocket item
GiveLinksPocketMedallion(); GiveLinksPocketMedallion();
int openForest = GetRandoSettingValue(RSK_FOREST); int openForest = Randomizer_GetSettingValue(RSK_FOREST);
switch (openForest) { switch (openForest) {
case 0: // closed case 0: // closed
break; break;
@ -657,28 +657,28 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
break; break;
} }
int doorOfTime = GetRandoSettingValue(RSK_DOOR_OF_TIME); int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME);
switch (doorOfTime) { switch (doorOfTime) {
case 0: // open case 0: // open
gSaveContext.eventChkInf[4] |= 0x800; gSaveContext.eventChkInf[4] |= 0x800;
break; break;
} }
int kakGate = GetRandoSettingValue(RSK_KAK_GATE); int kakGate = Randomizer_GetSettingValue(RSK_KAK_GATE);
switch (kakGate) { switch (kakGate) {
case 1: // open case 1: // open
gSaveContext.infTable[7] |= 0x40; gSaveContext.infTable[7] |= 0x40;
break; break;
} }
if(GetRandoSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword(); if(Randomizer_GetSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword();
if(GetRandoSettingValue(RSK_STARTING_DEKU_SHIELD)) GiveLinkDekuShield(); if(Randomizer_GetSettingValue(RSK_STARTING_DEKU_SHIELD)) GiveLinkDekuShield();
if(GetRandoSettingValue(RSK_STARTING_OCARINA)) { if(Randomizer_GetSettingValue(RSK_STARTING_OCARINA)) {
INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY;
} }
if(GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES)) { if(Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES)) {
uint32_t mapBitMask = 1 << 1; uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2; uint32_t compassBitMask = 1 << 2;
uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask; uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask;
@ -687,13 +687,13 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
} }
} }
if (GetRandoSettingValue(RSK_STARTING_CONSUMABLES)) { if (Randomizer_GetSettingValue(RSK_STARTING_CONSUMABLES)) {
GiveLinkDekuSticks(10); GiveLinkDekuSticks(10);
GiveLinkDekuNuts(20); GiveLinkDekuNuts(20);
} }
if(GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA)) { if(Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) {
s32 giid = GetRandomizedItemIdFromKnownCheck(RC_SONG_FROM_IMPA, GI_ZELDAS_LULLABY); s32 giid = Randomizer_GetItemIdFromKnownCheck(RC_SONG_FROM_IMPA, GI_ZELDAS_LULLABY);
if(giid >= GI_ZELDAS_LULLABY && giid <= GI_PRELUDE_OF_LIGHT) { if(giid >= GI_ZELDAS_LULLABY && giid <= GI_PRELUDE_OF_LIGHT) {
GiveLinkSong(giid); GiveLinkSong(giid);
@ -780,7 +780,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
} else if (giid == GI_DOUBLE_DEFENSE) { } else if (giid == GI_DOUBLE_DEFENSE) {
GiveLinkDoubleDefense(); GiveLinkDoubleDefense();
} else { } else {
s32 iid = GetItemIDFromGetItemID(giid); s32 iid = Randomizer_GetItemIDFromGetItemID(giid);
if (iid != -1) INV_CONTENT(iid) = iid; if (iid != -1) INV_CONTENT(iid) = iid;
} }
@ -801,18 +801,18 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA; INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
} }
if (GetRandoSettingValue(RSK_FULL_WALLETS)) { if (Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
GiveLinkRupees(9001); GiveLinkRupees(9001);
} }
// For Ganon's boss key "Start With" is 0 // For Ganon's boss key "Start With" is 0
if(GetRandoSettingValue(RSK_GANONS_BOSS_KEY) == 0) { if(Randomizer_GetSettingValue(RSK_GANONS_BOSS_KEY) == 0) {
gSaveContext.inventory.dungeonItems[10] |= 1; gSaveContext.inventory.dungeonItems[10] |= 1;
} }
HIGH_SCORE(HS_POE_POINTS) = 1000 - (100 * GetRandoSettingValue(RSK_BIG_POE_COUNT)); HIGH_SCORE(HS_POE_POINTS) = 1000 - (100 * Randomizer_GetSettingValue(RSK_BIG_POE_COUNT));
if(GetRandoSettingValue(RSK_SKIP_EPONA_RACE)) { if(Randomizer_GetSettingValue(RSK_SKIP_EPONA_RACE)) {
gSaveContext.eventChkInf[1] |= (1 << 8); gSaveContext.eventChkInf[1] |= (1 << 8);
} }
@ -826,6 +826,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
// Go away ruto (water temple first cutscene) // Go away ruto (water temple first cutscene)
gSaveContext.sceneFlags[05].swch |= (1 << 0x10); gSaveContext.sceneFlags[05].swch |= (1 << 0x10);
// Opens locked Water Temple door to prevent softlocks
// West door on the middle level that leads to the water raising thing
// Happens in 3DS rando and N64 rando as well
gSaveContext.sceneFlags[05].swch |= (1 << 0x15);
// Skip intro cutscene when bombing mud wall in Dodongo's cavern // Skip intro cutscene when bombing mud wall in Dodongo's cavern
// this also makes the lower jaw render, and the eyes react to explosives // this also makes the lower jaw render, and the eyes react to explosives
Flags_SetEventChkInf(0xB0); Flags_SetEventChkInf(0xB0);
@ -834,7 +839,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.infTable[25] |= 0x20; gSaveContext.infTable[25] |= 0x20;
// fast gerudo fortress // fast gerudo fortress
if (GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 1 || GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 2) { if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == 1 || Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == 2) {
gSaveContext.eventChkInf[9] |= 2; gSaveContext.eventChkInf[9] |= 2;
gSaveContext.eventChkInf[9] |= 4; gSaveContext.eventChkInf[9] |= 4;
gSaveContext.eventChkInf[9] |= 8; gSaveContext.eventChkInf[9] |= 8;
@ -853,14 +858,14 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
} }
// open gerudo fortress // open gerudo fortress
if (GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 2) { if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == 2) {
gSaveContext.eventChkInf[9] |= 1; gSaveContext.eventChkInf[9] |= 1;
gSaveContext.sceneFlags[12].swch |= (1 << 0x01); gSaveContext.sceneFlags[12].swch |= (1 << 0x01);
gSaveContext.sceneFlags[12].swch |= (1 << 0x05); gSaveContext.sceneFlags[12].swch |= (1 << 0x05);
gSaveContext.sceneFlags[12].swch |= (1 << 0x11); gSaveContext.sceneFlags[12].swch |= (1 << 0x11);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0C); gSaveContext.sceneFlags[12].collect |= (1 << 0x0C);
if (!GetRandoSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
GiveLinkGerudoCard(); GiveLinkGerudoCard();
} }
} }

View File

@ -69,7 +69,7 @@ const ActorInit Bg_Dy_Yoseizo_InitVars = {
void GivePlayerRandoRewardGreatFairy(BgDyYoseizo* this, GlobalContext* globalCtx) { void GivePlayerRandoRewardGreatFairy(BgDyYoseizo* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx); Player* player = GET_PLAYER(globalCtx);
GetItemID getItemId = GetRandomizedItemId(GI_NONE, this->actor.id, this->fountainType + 1, globalCtx->sceneNum); GetItemID getItemId = Randomizer_GetRandomizedItemId(GI_NONE, this->actor.id, this->fountainType + 1, globalCtx->sceneNum);
if (this->actor.parent == GET_PLAYER(globalCtx) && !Flags_GetTreasure(globalCtx, this->fountainType + 1) && if (this->actor.parent == GET_PLAYER(globalCtx) && !Flags_GetTreasure(globalCtx, this->fountainType + 1) &&
!Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) { !Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) {

View File

@ -46,7 +46,7 @@ void BgGateShutter_Init(Actor* thisx, GlobalContext* globalCtx) {
this->somePos.z = thisx->world.pos.z; this->somePos.z = thisx->world.pos.z;
if (((gSaveContext.infTable[7] & 0x40) || if (((gSaveContext.infTable[7] & 0x40) ||
(!gSaveContext.n64ddFlag && (gSaveContext.eventChkInf[4] & 0x20)) || (!gSaveContext.n64ddFlag && (gSaveContext.eventChkInf[4] & 0x20)) ||
(gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_KAK_GATE))) && (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_KAK_GATE))) &&
(globalCtx->sceneNum == SCENE_SPOT01)) { (globalCtx->sceneNum == SCENE_SPOT01)) {
thisx->world.pos.x = -89.0f; thisx->world.pos.x = -89.0f;
thisx->world.pos.z = -1375.0f; thisx->world.pos.z = -1375.0f;

View File

@ -50,7 +50,7 @@ void BgGjyoBridge_Init(Actor* thisx, GlobalContext* globalCtx) {
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, thisx, colHeader); this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, thisx, colHeader);
int bridge = GetRandoSettingValue(RSK_RAINBOW_BRIDGE); int bridge = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE);
if (gSaveContext.eventChkInf[4] & 0x2000 || (gSaveContext.n64ddFlag && bridge == 0)) { if (gSaveContext.eventChkInf[4] & 0x2000 || (gSaveContext.n64ddFlag && bridge == 0)) {
this->actionFunc = func_808787A4; this->actionFunc = func_808787A4;
} else { } else {
@ -176,12 +176,12 @@ void BgGjyoBridge_TriggerCutscene(BgGjyoBridge* this, GlobalContext* globalCtx)
LaunchBridgeCutscene(this, globalCtx); LaunchBridgeCutscene(this, globalCtx);
} }
} else { } else {
int bridge = GetRandoSettingValue(RSK_RAINBOW_BRIDGE); int bridge = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE);
int bridgeStoneCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_STONE_COUNT); int bridgeStoneCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_STONE_COUNT);
int bridgeMedallionCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT); int bridgeMedallionCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT);
int bridgeRewardCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_REWARD_COUNT); int bridgeRewardCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_REWARD_COUNT);
int bridgeDungeonCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT); int bridgeDungeonCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT);
int bridgeTokenCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_TOKEN_COUNT); int bridgeTokenCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_TOKEN_COUNT);
if (CheckPlayerPosition(player, globalCtx)) { if (CheckPlayerPosition(player, globalCtx)) {
switch (bridge) { switch (bridge) {

View File

@ -1504,7 +1504,7 @@ void BossGanon_DeathAndTowerCutscene(BossGanon* this, GlobalContext* globalCtx)
if (this->csTimer == 180) { if (this->csTimer == 180) {
globalCtx->sceneLoadFlag = 0x14; globalCtx->sceneLoadFlag = 0x14;
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_TOWER_ESCAPE)) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
Flags_SetEventChkInf(0xC7); Flags_SetEventChkInf(0xC7);
globalCtx->nextEntranceIndex = 0x517; globalCtx->nextEntranceIndex = 0x517;
} }

View File

@ -899,12 +899,12 @@ void func_80986BF8(DemoIm* this, GlobalContext* globalCtx) {
} }
void GivePlayerRandoRewardImpa(Actor* impa, GlobalContext* globalCtx, RandomizerCheck check) { void GivePlayerRandoRewardImpa(Actor* impa, GlobalContext* globalCtx, RandomizerCheck check) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_ZELDAS_LULLABY); GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_ZELDAS_LULLABY);
if (impa->parent != NULL && impa->parent->id == GET_PLAYER(globalCtx)->actor.id && if (impa->parent != NULL && impa->parent->id == GET_PLAYER(globalCtx)->actor.id &&
!Flags_GetTreasure(globalCtx, 0x1F)) { !Flags_GetTreasure(globalCtx, 0x1F)) {
Flags_SetTreasure(globalCtx, 0x1F); Flags_SetTreasure(globalCtx, 0x1F);
} else if (!Flags_GetTreasure(globalCtx, 0x1F) && !GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA)) { } else if (!Flags_GetTreasure(globalCtx, 0x1F) && !Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) {
func_8002F434(impa, globalCtx, getItemId, 75.0f, 50.0f); func_8002F434(impa, globalCtx, getItemId, 75.0f, 50.0f);
} else if (!Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) { } else if (!Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) {
gSaveContext.eventChkInf[5] |= 0x200; gSaveContext.eventChkInf[5] |= 0x200;

View File

@ -788,7 +788,14 @@ void DemoKankyo_DrawWarpSparkles(Actor* thisx, GlobalContext* globalCtx) {
this->unk_150[i].unk_0.y = (s16)((Rand_ZeroOne() - 0.5f) * 16.0f * temp_f22); this->unk_150[i].unk_0.y = (s16)((Rand_ZeroOne() - 0.5f) * 16.0f * temp_f22);
this->unk_150[i].unk_0.z = (s16)((Rand_ZeroOne() - 0.5f) * 16.0f * temp_f22); this->unk_150[i].unk_0.z = (s16)((Rand_ZeroOne() - 0.5f) * 16.0f * temp_f22);
this->unk_150[i].unk_23 = 0; this->unk_150[i].unk_23 = 0;
// Skip the first part of warp song cutscenes in rando
if (gSaveContext.n64ddFlag && this->actor.params == DEMOKANKYO_WARP_OUT) {
this->unk_150[i].unk_22 = 2;
} else {
this->unk_150[i].unk_22++; this->unk_150[i].unk_22++;
}
case 1: case 1:
if (this->actor.params == DEMOKANKYO_WARP_OUT) { if (this->actor.params == DEMOKANKYO_WARP_OUT) {
if (func_800BB2B4(&camPos, &sWarpRoll, &sWarpFoV, sWarpOutCameraPoints, &this->unk_150[i].unk_20, if (func_800BB2B4(&camPos, &sWarpRoll, &sWarpFoV, sWarpOutCameraPoints, &this->unk_150[i].unk_20,

View File

@ -128,7 +128,7 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) {
this->collider2.dim.yShift = 300; this->collider2.dim.yShift = 300;
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
int trialsToComplete = GetRandoSettingValue(RSK_TRIAL_COUNT); int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT);
if (trialsToComplete <= TrialsDoneCount()) { if (trialsToComplete <= TrialsDoneCount()) {
Actor_Kill(thisx); Actor_Kill(thisx);
return; return;

View File

@ -462,7 +462,7 @@ s32 DoorWarp1_PlayerInRange(DoorWarp1* this, GlobalContext* globalCtx) {
} }
void GivePlayerRandoReward(DoorWarp1* this, Player* player, GlobalContext* globalCtx, u8 ruto, u8 adult) { void GivePlayerRandoReward(DoorWarp1* this, Player* player, GlobalContext* globalCtx, u8 ruto, u8 adult) {
GetItemID getItemId = GetRandomizedItemId(GI_NONE, this->actor.id, this->actor.params, globalCtx->sceneNum); GetItemID getItemId = Randomizer_GetRandomizedItemId(GI_NONE, this->actor.id, this->actor.params, globalCtx->sceneNum);
if (this->actor.parent != NULL && this->actor.parent->id == GET_PLAYER(globalCtx)->actor.id && if (this->actor.parent != NULL && this->actor.parent->id == GET_PLAYER(globalCtx)->actor.id &&
!Flags_GetTreasure(globalCtx, 0x1F)) { !Flags_GetTreasure(globalCtx, 0x1F)) {

View File

@ -127,7 +127,7 @@ void func_809B0558(EnAni* this, GlobalContext* globalCtx) {
gSaveContext.itemGetInf[1] |= 0x20; gSaveContext.itemGetInf[1] |= 0x20;
} else { } else {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
s32 getItemId = GetRandomizedItemIdFromKnownCheck(RC_KAK_MAN_ON_ROOF, GI_HEART_PIECE); s32 getItemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_MAN_ON_ROOF, GI_HEART_PIECE);
func_8002F434(&this->actor, globalCtx, getItemId, 10000.0f, 200.0f); func_8002F434(&this->actor, globalCtx, getItemId, 10000.0f, 200.0f);
} else { } else {
func_8002F434(&this->actor, globalCtx, GI_HEART_PIECE, 10000.0f, 200.0f); func_8002F434(&this->actor, globalCtx, GI_HEART_PIECE, 10000.0f, 200.0f);
@ -141,7 +141,7 @@ void func_809B05F0(EnAni* this, GlobalContext* globalCtx) {
} }
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
s32 getItemId = GetRandomizedItemIdFromKnownCheck(RC_KAK_MAN_ON_ROOF, GI_HEART_PIECE); s32 getItemId = Randomizer_GetItemIdFromKnownCheck(RC_KAK_MAN_ON_ROOF, GI_HEART_PIECE);
func_8002F434(&this->actor, globalCtx, getItemId, 10000.0f, 200.0f); func_8002F434(&this->actor, globalCtx, getItemId, 10000.0f, 200.0f);
} else { } else {
func_8002F434(&this->actor, globalCtx, GI_HEART_PIECE, 10000.0f, 200.0f); func_8002F434(&this->actor, globalCtx, GI_HEART_PIECE, 10000.0f, 200.0f);

View File

@ -186,14 +186,14 @@ void EnBomBowlPit_GivePrize(EnBomBowlPit* this, GlobalContext* globalCtx) {
switch (this->prizeIndex) { switch (this->prizeIndex) {
case EXITEM_BOMB_BAG_BOWLING: case EXITEM_BOMB_BAG_BOWLING:
this->getItemId = this->getItemId =
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20); Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20);
break; break;
case EXITEM_HEART_PIECE_BOWLING: case EXITEM_HEART_PIECE_BOWLING:
this->getItemId = this->getItemId =
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE); Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
break; break;
case EXITEM_BOMBCHUS_BOWLING: case EXITEM_BOMBCHUS_BOWLING:
this->getItemId = GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10); this->getItemId = Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10);
break; break;
} }
} }

View File

@ -421,7 +421,7 @@ void EnBox_WaitOpen(EnBox* this, GlobalContext* globalCtx) {
Flags_SetTreasure(globalCtx, this->dyna.actor.params & 0x1F); Flags_SetTreasure(globalCtx, this->dyna.actor.params & 0x1F);
// treasure chest game rando // treasure chest game rando
if (GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) { if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
if (gSaveContext.n64ddFlag && globalCtx->sceneNum == 16 && (this->dyna.actor.params & 0x60) != 0x20) { if (gSaveContext.n64ddFlag && globalCtx->sceneNum == 16 && (this->dyna.actor.params & 0x60) != 0x20) {
if((this->dyna.actor.params & 0xF) < 2) { if((this->dyna.actor.params & 0xF) < 2) {
Flags_SetCollectible(globalCtx, 0x1B); Flags_SetCollectible(globalCtx, 0x1B);
@ -445,10 +445,10 @@ void EnBox_WaitOpen(EnBox* this, GlobalContext* globalCtx) {
func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos); func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos);
if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f && if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f &&
Player_IsFacingActor(&this->dyna.actor, 0x3000, globalCtx)) { Player_IsFacingActor(&this->dyna.actor, 0x3000, globalCtx)) {
int32_t item = GetRandomizedItemId(this->dyna.actor.params >> 5 & 0x7F, this->dyna.actor.id, this->dyna.actor.params, globalCtx->sceneNum); int32_t item = Randomizer_GetRandomizedItemId(this->dyna.actor.params >> 5 & 0x7F, this->dyna.actor.id, this->dyna.actor.params, globalCtx->sceneNum);
// RANDOTODO treasure chest game rando // RANDOTODO treasure chest game rando
if (GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) { if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
if (gSaveContext.n64ddFlag && globalCtx->sceneNum == 16 && (this->dyna.actor.params & 0x60) != 0x20) { if (gSaveContext.n64ddFlag && globalCtx->sceneNum == 16 && (this->dyna.actor.params & 0x60) != 0x20) {
if((this->dyna.actor.params & 0xF) < 2) { if((this->dyna.actor.params & 0xF) < 2) {
if(Flags_GetCollectible(globalCtx, 0x1B)) { if(Flags_GetCollectible(globalCtx, 0x1B)) {
@ -590,7 +590,7 @@ void EnBox_Update(Actor* thisx, GlobalContext* globalCtx) {
} }
if (((!gSaveContext.n64ddFlag && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) || if (((!gSaveContext.n64ddFlag && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) ||
(gSaveContext.n64ddFlag && GetRandomizedItemId(this->dyna.actor.params >> 5 & 0x7F, (gSaveContext.n64ddFlag && Randomizer_GetRandomizedItemId(this->dyna.actor.params >> 5 & 0x7F,
this->dyna.actor.id, this->dyna.actor.params, this->dyna.actor.id, this->dyna.actor.params,
globalCtx->sceneNum) == GI_ICE_TRAP)) && globalCtx->sceneNum) == GI_ICE_TRAP)) &&
this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 &&

View File

@ -453,7 +453,7 @@ void func_809EEA00(EnDivingGame* this, GlobalContext* globalCtx) {
if ((this->unk_292 == Message_GetState(&globalCtx->msgCtx) && Message_ShouldAdvance(globalCtx))) { if ((this->unk_292 == Message_GetState(&globalCtx->msgCtx) && Message_ShouldAdvance(globalCtx))) {
Message_CloseTextbox(globalCtx); Message_CloseTextbox(globalCtx);
this->actor.parent = NULL; this->actor.parent = NULL;
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? GetRandomizedItemIdFromKnownCheck(RC_ZD_DIVING_MINIGAME, GI_SCALE_SILVER) : GI_SCALE_SILVER, 90.0f, 10.0f); func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetItemIdFromKnownCheck(RC_ZD_DIVING_MINIGAME, GI_SCALE_SILVER) : GI_SCALE_SILVER, 90.0f, 10.0f);
this->actionFunc = func_809EEA90; this->actionFunc = func_809EEA90;
} }
} }
@ -463,7 +463,7 @@ void func_809EEA90(EnDivingGame* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) { if (Actor_HasParent(&this->actor, globalCtx)) {
this->actionFunc = func_809EEAF8; this->actionFunc = func_809EEAF8;
} else { } else {
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? GetRandomizedItemIdFromKnownCheck(RC_ZD_DIVING_MINIGAME, GI_SCALE_SILVER) : GI_SCALE_SILVER, 90.0f, 10.0f); func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetItemIdFromKnownCheck(RC_ZD_DIVING_MINIGAME, GI_SCALE_SILVER) : GI_SCALE_SILVER, 90.0f, 10.0f);
} }
} }

View File

@ -371,7 +371,7 @@ void EnDns_Talk(EnDns* this, GlobalContext* globalCtx) {
void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) { void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) {
if (this->actor.params == 0x9) { if (this->actor.params == 0x9) {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
func_8002F434(&this->actor, globalCtx, GetRandomizedItemId(GI_STICK_UPGRADE_30, this->actor.id, this->actor.params, globalCtx->sceneNum), 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, Randomizer_GetRandomizedItemId(GI_STICK_UPGRADE_30, this->actor.id, this->actor.params, globalCtx->sceneNum), 130.0f, 100.0f);
} else if (CUR_UPG_VALUE(UPG_STICKS) < 2) { } else if (CUR_UPG_VALUE(UPG_STICKS) < 2) {
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f);
} else { } else {
@ -379,14 +379,14 @@ void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) {
} }
} else if (this->actor.params == 0xA) { } else if (this->actor.params == 0xA) {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
func_8002F434(&this->actor, globalCtx, GetRandomizedItemId(GI_NUT_UPGRADE_40, this->actor.id, this->actor.params, globalCtx->sceneNum), 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, Randomizer_GetRandomizedItemId(GI_NUT_UPGRADE_40, this->actor.id, this->actor.params, globalCtx->sceneNum), 130.0f, 100.0f);
} else if (CUR_UPG_VALUE(UPG_NUTS) < 2) { } else if (CUR_UPG_VALUE(UPG_NUTS) < 2) {
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f);
} else { } else {
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f);
} }
} else { } else {
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? GetRandomizedItemId(this->dnsItemEntry->getItemId, this->actor.id, this->actor.params, globalCtx->sceneNum) : this->dnsItemEntry->getItemId, 130.0f, 100.0f); func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetRandomizedItemId(this->dnsItemEntry->getItemId, this->actor.id, this->actor.params, globalCtx->sceneNum) : this->dnsItemEntry->getItemId, 130.0f, 100.0f);
} }
} }

View File

@ -139,13 +139,13 @@ void EnDntDemo_Judge(EnDntDemo* this, GlobalContext* globalCtx) {
switch (Player_GetMask(globalCtx)) { switch (Player_GetMask(globalCtx)) {
case PLAYER_MASK_SKULL: case PLAYER_MASK_SKULL:
if (!Flags_GetTreasure(globalCtx, 0x1F)) { if (!Flags_GetTreasure(globalCtx, 0x1F)) {
GiveItemWithoutActor(globalCtx, GetRandomizedItemIdFromKnownCheck(RC_DEKU_THEATER_SKULL_MASK, GI_STICK_UPGRADE_30)); GiveItemWithoutActor(globalCtx, Randomizer_GetItemIdFromKnownCheck(RC_DEKU_THEATER_SKULL_MASK, GI_STICK_UPGRADE_30));
Flags_SetTreasure(globalCtx, 0x1F); Flags_SetTreasure(globalCtx, 0x1F);
} }
break; break;
case PLAYER_MASK_TRUTH: case PLAYER_MASK_TRUTH:
if (!Flags_GetTreasure(globalCtx, 0x1E)) { if (!Flags_GetTreasure(globalCtx, 0x1E)) {
GiveItemWithoutActor(globalCtx, GetRandomizedItemIdFromKnownCheck(RC_DEKU_THEATER_MASK_OF_TRUTH, GI_NUT_UPGRADE_40)); GiveItemWithoutActor(globalCtx, Randomizer_GetItemIdFromKnownCheck(RC_DEKU_THEATER_MASK_OF_TRUTH, GI_NUT_UPGRADE_40));
Flags_SetTreasure(globalCtx, 0x1E); Flags_SetTreasure(globalCtx, 0x1E);
} }
break; break;

View File

@ -548,7 +548,7 @@ void func_809FEC70(EnDu* this, GlobalContext* globalCtx) {
EnDu_SetupAction(this, func_809FECE4); EnDu_SetupAction(this, func_809FECE4);
} else { } else {
f32 xzRange = this->actor.xzDistToPlayer + 1.0f; f32 xzRange = this->actor.xzDistToPlayer + 1.0f;
func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? GetRandomizedItemIdFromKnownCheck(RC_GC_DARUNIAS_JOY, GI_BRACELET) : GI_BRACELET, xzRange, fabsf(this->actor.yDistToPlayer) + 1.0f); func_8002F434(&this->actor, globalCtx, gSaveContext.n64ddFlag ? Randomizer_GetItemIdFromKnownCheck(RC_GC_DARUNIAS_JOY, GI_BRACELET) : GI_BRACELET, xzRange, fabsf(this->actor.yDistToPlayer) + 1.0f);
} }
} }

View File

@ -138,8 +138,8 @@ void EnExItem_WaitForObject(EnExItem* this, GlobalContext* globalCtx) {
case EXITEM_BOMB_BAG_BOWLING: case EXITEM_BOMB_BAG_BOWLING:
this->unk_17C = func_8002EBCC; this->unk_17C = func_8002EBCC;
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
this->giDrawId = GetItemModelFromId( this->giDrawId = Randomizer_GetItemModelFromId(
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20)); Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20));
} else { } else {
this->giDrawId = GID_BOMB_BAG_30; this->giDrawId = GID_BOMB_BAG_30;
} }
@ -173,8 +173,8 @@ void EnExItem_WaitForObject(EnExItem* this, GlobalContext* globalCtx) {
case EXITEM_BOMBCHUS_BOWLING: case EXITEM_BOMBCHUS_BOWLING:
this->unk_17C = func_8002EBCC; this->unk_17C = func_8002EBCC;
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
this->giDrawId = GetItemModelFromId( this->giDrawId = Randomizer_GetItemModelFromId(
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10)); Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10));
} else { } else {
this->giDrawId = GID_BOMBCHU; this->giDrawId = GID_BOMBCHU;
} }
@ -229,7 +229,7 @@ void EnExItem_WaitForObject(EnExItem* this, GlobalContext* globalCtx) {
this->scale = 0.5f; this->scale = 0.5f;
this->unkFloat = 0.5f; this->unkFloat = 0.5f;
this->actor.velocity.y = 10.0f; this->actor.velocity.y = 10.0f;
if (!gSaveContext.n64ddFlag || !GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) { if (!gSaveContext.n64ddFlag || !Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
switch (this->type) { switch (this->type) {
case EXITEM_GREEN_RUPEE_CHEST: case EXITEM_GREEN_RUPEE_CHEST:
this->giDrawId = GID_RUPEE_GREEN; this->giDrawId = GID_RUPEE_GREEN;
@ -404,7 +404,7 @@ void EnExItem_TargetPrizeApproach(EnExItem* this, GlobalContext* globalCtx) {
this->actor.parent = NULL; this->actor.parent = NULL;
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
GET_PLAYER(globalCtx)->stateFlags1 &= ~(PLAYER_STATE1_10 | PLAYER_STATE1_11); GET_PLAYER(globalCtx)->stateFlags1 &= ~(PLAYER_STATE1_10 | PLAYER_STATE1_11);
getItemId = GetRandomizedItemIdFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50); getItemId = Randomizer_GetItemIdFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50);
} else { } else {
if (CUR_UPG_VALUE(UPG_BULLET_BAG) == 1) { if (CUR_UPG_VALUE(UPG_BULLET_BAG) == 1) {
getItemId = GI_BULLET_BAG_40; getItemId = GI_BULLET_BAG_40;
@ -424,7 +424,7 @@ void EnExItem_TargetPrizeGive(EnExItem* this, GlobalContext* globalCtx) {
this->actionFunc = EnExItem_TargetPrizeFinish; this->actionFunc = EnExItem_TargetPrizeFinish;
} else { } else {
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
getItemId = GetRandomizedItemIdFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50); getItemId = Randomizer_GetItemIdFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50);
} else { } else {
getItemId = (CUR_UPG_VALUE(UPG_BULLET_BAG) == 2) ? GI_BULLET_BAG_50 : GI_BULLET_BAG_40; getItemId = (CUR_UPG_VALUE(UPG_BULLET_BAG) == 2) ? GI_BULLET_BAG_50 : GI_BULLET_BAG_40;
} }
@ -510,12 +510,12 @@ void EnExItem_DrawItems(EnExItem* this, GlobalContext* globalCtx) {
switch (this->type) { switch (this->type) {
case EXITEM_BOMB_BAG_BOWLING: case EXITEM_BOMB_BAG_BOWLING:
case EXITEM_BOMB_BAG_COUNTER: case EXITEM_BOMB_BAG_COUNTER:
randoGetItemId = GetRandomizedItemIdFromKnownCheck( randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20); RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20);
break; break;
case EXITEM_BOMBCHUS_BOWLING: case EXITEM_BOMBCHUS_BOWLING:
case EXITEM_BOMBCHUS_COUNTER: case EXITEM_BOMBCHUS_COUNTER:
randoGetItemId = GetRandomizedItemIdFromKnownCheck( randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10); RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10);
break; break;
} }
@ -532,12 +532,12 @@ void EnExItem_DrawHeartPiece(EnExItem* this, GlobalContext* globalCtx) {
func_8002ED80(&this->actor, globalCtx, 0); func_8002ED80(&this->actor, globalCtx, 0);
if (gSaveContext.n64ddFlag) { if (gSaveContext.n64ddFlag) {
s32 randoGetItemId = GetRandomizedItemIdFromKnownCheck( s32 randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE); RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) { if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
} }
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId)); GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else { } else {
GetItem_Draw(globalCtx, GID_HEART_PIECE); GetItem_Draw(globalCtx, GID_HEART_PIECE);
} }

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