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
*.sav
shipofharkinian.ini
shipofharkinian.json

View File

@ -12,7 +12,7 @@
8. Build the solution.
9. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`.
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.
13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`.
14. Launch `soh.exe`.
@ -63,9 +63,10 @@ make setup -j8 DEBUG=0
# Compile the code (watch the -j parameter as above)
make -j8 DEBUG=0
# 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
```

9
Jenkinsfile vendored
View File

@ -125,6 +125,11 @@ pipeline {
agent {
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 {
checkout([
$class: 'GitSCM',
@ -137,8 +142,8 @@ pipeline {
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
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"
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 setup -j4 OPTFLAGS=-O2 DEBUG=0 LD="ld"
make -j4 DEBUG=0 OPTFLAGS=-O2 LD="ld"
make -j4 appbundle
mv ../README.md readme.txt
7z a soh-mac.7z soh.app readme.txt

View File

@ -4,10 +4,15 @@ import os, sys, shutil
import shutil
from rom_info import Z64Rom
import rom_chooser
import struct
def BuildOTR(xmlPath, rom):
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 += " 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) |
| 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
Want to use cartridge readers in tandem with the OTRGui?

View File

@ -45,11 +45,11 @@ ifneq ($(DEPRECATION_ON),0)
endif
# CXXFLAGS += -DTEXTURE_DEBUG
LDFLAGS := -lm -ldl \
-L../StormLib/build -L../libultraship -lbz2 -pthread -lultraship -lstorm
LDFLAGS := -Llib/libgfxd -L../libultraship -L../StormLib/build \
-pthread -lgfxd -lultraship ZAPDUtils/ZAPDUtils.a -lstorm -lbz2 -lm -ldl
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)
else
LDFLAGS += -lpng -lGL -lGLEW -lX11 -lz -lSDL2 -lpulse
@ -137,4 +137,4 @@ ZAPDUtils:
# Linking
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"
chmod a+x linuxdeploy*.AppImage
curl -sSfLO "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod a+x appimagetool*.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 mkappimage.AppImage
mkdir -p AppDir/usr/bin
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
./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 LD_LIBRARY_PATH="$HERE"/usr/lib:"$LD_LIBRARY_PATH"
export ZENITY=$(command -v zenity)
while [[ ! -e "$PWD"/oot.otr ]]; do
export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)"
@ -14,16 +15,26 @@ while [[ ! -e "$PWD"/oot.otr ]]; do
ln -s "$OLDPWD"/*.*64 "$ASSETDIR"/tmp/rom.z64
cp -r "$ASSETDIR"/assets/game/ship_of_harkinian "$ASSETDIR"/Extract/assets/
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)
ROM=GC_NMQ_D;;
0227d7c0074f2d0ac935631990da8ec5914597b4)
ROM=GC_NMQ_PAL_F;;
*)
echo -e "\nrom hash does not match\n"
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"
fi
exit;;
esac
echo "Processing..."
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..."
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
cp "$ASSETDIR"/oot.otr "$OLDPWD"
echo "Restart $APPIMAGE to play!"
@ -31,7 +42,11 @@ while [[ ! -e "$PWD"/oot.otr ]]; do
rm -r "$ASSETDIR"
break
else
echo -e "\nPlace ROM in this folder\n"
if [ -n "$ZENITY" ]; then
zenity --error --timeout=5 --text="Place ROM in $OWD" --title="Missing ROM file" --width=500 --width=200
else
echo -e "\nPlace ROM in this folder\n"
fi
exit
fi
done

View File

@ -2,7 +2,7 @@
CXX ?= g++
CC ?= gcc
AR := ar
AR := ar
FORMAT := clang-format-11
UNAME := $(shell uname)
@ -11,6 +11,15 @@ DEBUG ?= 1
OPTFLAGS ?= -O0
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 \
-Wno-unused-variable \
-Wno-unused-parameter \
@ -29,8 +38,7 @@ WARN := -Wall -Wextra -Werror \
CWARN :=
CXXWARN := -Wno-deprecated-enum-enum-conversion -Wno-deprecated-copy
COMPILER_VERSION := $(shell $(CXX) --version)
ifneq '' '$(findstring g++,$(COMPILER_VERSION))'
ifneq ($(CXX_IS_CLANG),1)
WARN += -Wno-error=stringop-overflow
CXXWARN += -Wno-error=maybe-uninitialized
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
CPPFLAGS := -MMD
ifeq ($(UNAME), Darwin) #APPLE
CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL
MMFLAGS := -Wno-deprecated-declarations -ObjC++ -fobjc-weak -fobjc-arc
# 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
ifeq ($(UNAME), Linux)
WARN += -Wno-error=stringop-overflow # This is required with clang on Linux.
ifeq ($(UNAME), Darwin) #APPLE
CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL -framework Foundation
endif
ifneq ($(DEBUG),0)
@ -69,6 +82,7 @@ CXX_FILES := \
$(shell find libultraship/Lib/Fast3D -name "*.cpp") \
$(shell find libultraship -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_sdl.cpp \
libultraship/Lib/StrHash64.cpp \
@ -78,12 +92,19 @@ C_FILES := \
libultraship/mixer.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/*")
O_FILES := \
$(CXX_FILES:%.cpp=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)
LIB := libultraship.a
@ -94,6 +115,7 @@ INC_DIRS := $(addprefix -I, \
libultraship/Lib/spdlog \
libultraship/Lib/spdlog/include \
libultraship/Lib/ImGui \
libultraship/Lib/Mercury \
libultraship \
../StormLib/src \
)
@ -117,6 +139,9 @@ build/%.o: %.cpp
build/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
build/%.o: %.mm
$(MXX) $(MMFLAGS) $(CXXFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
$(LIB): $(O_FILES)
$(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 "GlobalCtx2.h"
#include "stox.h"
#include <memory>
#include <algorithm>
#if __APPLE__
#include <SDL_events.h>
#else
#include <SDL2/SDL_events.h>
#endif
namespace Ship {
Controller::Controller(int32_t dwControllerNumber) : dwControllerNumber(dwControllerNumber) {
dwPressedButtons = 0;
wStickX = 0;
wStickY = 0;
wGyroX = 0;
wGyroY = 0;
Controller::Controller() : isRumbling(false), wStickX(0), wStickY(0), wGyroX(0), wGyroY(0), dwPressedButtons(0){
Attachment = nullptr;
profiles.resize(MAXCONTROLLERS);
for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons.push_back(0);
}
}
void Controller::Read(OSContPad* pad) {
ReadFromSource();
void Controller::Read(OSContPad* pad, int32_t slot) {
ReadFromSource(slot);
pad->button |= dwPressedButtons & 0xFFFF;
SDL_PumpEvents();
if (pad->stick_x == 0) {
if (dwPressedButtons & BTN_STICKLEFT) {
// Button Inputs
pad->button |= dwPressedButtons[slot] & 0xFFFF;
// Stick Inputs
if (wStickX == 0) {
if (dwPressedButtons[slot] & BTN_STICKLEFT) {
pad->stick_x = -128;
}
else if (dwPressedButtons & BTN_STICKRIGHT) {
} else if (dwPressedButtons[slot] & BTN_STICKRIGHT) {
pad->stick_x = 127;
}
else {
pad->stick_x = wStickX;
}
} else {
pad->stick_x = wStickX;
}
if (pad->stick_y == 0) {
if (dwPressedButtons & BTN_STICKDOWN) {
if (wStickY == 0) {
if (dwPressedButtons[slot] & BTN_STICKDOWN) {
pad->stick_y = -128;
}
else if (dwPressedButtons & BTN_STICKUP) {
} else if (dwPressedButtons[slot] & BTN_STICKUP) {
pad->stick_y = 127;
}
else {
pad->stick_y = wStickY;
}
} else {
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_y = wGyroY;
}
void Controller::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
// Update the config value.
std::string ConfSection = GetBindingConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
Conf[ConfSection][szButtonName] = dwScancode;
// Reload the button mapping from Config
LoadBinding();
void Controller::SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
Mappings[dwScancode] = n64Button;
}
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
#include <memory>
#include <map>
#include <memory>
#include <string>
#include <optional>
#include "stdint.h"
#include "UltraController.h"
#include "ControllerAttachment.h"
#include <vector>
#include <unordered_map>
#define EXTENDED_SCANCODE_BIT (1 << 8)
#define AXIS_SCANCODE_BIT (1 << 9)
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 {
public:
Controller(int32_t dwControllerNumber);
void Read(OSContPad* pad);
virtual void ReadFromSource() = 0;
virtual void WriteToSource(ControllerCallback* controller) = 0;
virtual ~Controller() = default;
Controller();
void Read(OSContPad* pad, int32_t slot);
virtual void ReadFromSource(int32_t slot) = 0;
virtual void WriteToSource(int32_t slot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0;
virtual bool CanGyro() const = 0;
virtual void CreateDefaultBinding(int32_t slot) = 0;
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; }
int32_t GetControllerNumber() { return dwControllerNumber; }
virtual bool HasPadConf() const = 0;
virtual std::optional<std::string> GetPadConfSection() = 0;
std::string GetGuid() { return GUID; }
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 wStickY;
float wGyroX;
float wGyroY;
virtual std::string GetControllerType() = 0;
virtual std::string GetConfSection() = 0;
virtual std::string GetBindingConfSection() = 0;
float wCamX;
float wCamY;
protected:
std::vector<int32_t> dwPressedButtons;
std::string GUID;
void LoadBinding();
private:
std::shared_ptr<ControllerAttachment> Attachment;
int32_t dwControllerNumber;
};
struct ControllerEntry {
uint8_t* controllerBits;
Controller* entryIO;
};
}

View File

@ -5,6 +5,7 @@
#include <memory>
#include <utility>
#include <PR/ultra64/gbi.h>
#include "imgui_internal.h"
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->type = CVAR_TYPE_STRING;
cvar->value.valueStr = value;
cvar->value.valueStr = ImStrdup(value);
}
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/message.h>
#include "ConfigFile.h"
#include "Cvar.h"
#include "GlobalCtx2.h"
#include "ImGuiImpl.h"
@ -33,18 +32,6 @@ namespace Game {
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() {
DebugConsole_LoadCVars();
}
@ -58,6 +45,7 @@ namespace Game {
ModInternal::RegisterHook<ModInternal::GfxInit>([] {
gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT));
SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0);
SohImGui::controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
UpdateAudio();
});
}

View File

@ -8,6 +8,9 @@
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/sohconsole_sink.h"
#include "ModManager.h"
#ifdef __APPLE__
#include "OSXFolderManager.h"
#endif
namespace Ship {
std::weak_ptr<GlobalCtx2> GlobalCtx2::Context;
@ -29,7 +32,23 @@ namespace Ship {
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() {
InitLogging();
Config = std::make_shared<ConfigFile>(GlobalCtx2::GetInstance(), "shipofharkinian.ini");
MainPath = (*Config)["ARCHIVE"]["Main Archive"];
if (MainPath.empty()) {
MainPath = "oot.otr";
}
PatchesPath = (*Config)["ARCHIVE"]["Patches Directory"];
if (PatchesPath.empty()) {
PatchesPath = "./";
}
ResMan = std::make_shared<ResourceMgr>(GlobalCtx2::GetInstance(), MainPath, PatchesPath);
Win = std::make_shared<Window>(GlobalCtx2::GetInstance());
Config = std::make_shared<Mercury>(GetPathRelativeToAppDirectory("shipofharkinian.json"));
Config->reload();
MainPath = Config->getString("Game.Main Archive", GetPathRelativeToAppDirectory("oot.otr"));
PatchesPath = Config->getString("Game.Patches Archive", GetAppDirectoryPath() + "/mods");
ResMan = std::make_shared<ResourceMgr>(GetInstance(), MainPath, PatchesPath);
Win = std::make_shared<Window>(GetInstance());
if (!ResMan->DidLoadSuccessfully())
{
#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
SPDLOG_ERROR("Main OTR file not found!");
#endif
@ -67,11 +83,13 @@ namespace Ship {
void GlobalCtx2::InitLogging() {
try {
auto logPath = GetPathRelativeToAppDirectory(("logs/" + GetName() + ".log").c_str());
// Setup Logging
spdlog::init_thread_pool(8192, 1);
auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_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);
ConsoleSink->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);
saveFile.seekp(addr);
saveFile.write((char*)dramAddr, size);
@ -107,4 +125,4 @@ namespace Ship {
saveFile.close();
}
}
}

View File

@ -6,8 +6,9 @@
#ifdef __cplusplus
#include <filesystem>
#include <memory>
#include <fstream>
#include "spdlog/spdlog.h"
#include "ConfigFile.h"
#include "Lib/Mercury/Mercury.h"
namespace Ship {
class ResourceMgr;
@ -22,12 +23,15 @@ namespace Ship {
std::shared_ptr<Window> GetWindow() { return Win; }
std::shared_ptr<ResourceMgr> GetResourceManager() { return ResMan; }
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);
GlobalCtx2(const std::string& Name);
GlobalCtx2(std::string Name);
~GlobalCtx2();
protected:
@ -38,7 +42,7 @@ namespace Ship {
static std::weak_ptr <GlobalCtx2> Context;
std::shared_ptr<spdlog::logger> Logger;
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::string Name;
std::string MainPath;

View File

@ -5,6 +5,7 @@
#include <functional>
#include "UltraController.h"
#include "Controller.h"
#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(ControllerRawInput, void(Ship::Controller* backend, uint32_t raw));
DEFINE_HOOK(AudioInit, void());
DEFINE_HOOK(LoadTexture, void(const char* path, uint8_t** texture));
DEFINE_HOOK(GfxInit, void());
DEFINE_HOOK(ExitGame, void());
}

View File

@ -12,6 +12,7 @@
#include "GameSettings.h"
#include "Console.h"
#include "Hooks.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include "Lib/ImGui/imgui_internal.h"
#include "GlobalCtx2.h"
#include "ResourceMgr.h"
@ -63,8 +64,11 @@ namespace SohImGui {
ImGuiIO* io;
Console* console = new Console;
GameOverlay* overlay = new GameOverlay;
InputEditor* controller = new InputEditor;
static ImVector<ImRect> s_GroupPanelLabelStack;
bool p_open = false;
bool needs_save = false;
int lastBackendID = 0;
const char* filters[3] = {
"Three-Point",
@ -72,10 +76,45 @@ namespace SohImGui {
"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>> windowCategories;
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) {
return fmin(fmax(value, min), max);
}
@ -300,15 +339,23 @@ namespace SohImGui {
io = &ImGui::GetIO();
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io->Fonts->AddFontDefault();
lastBackendID = GetBackendID(GlobalCtx2::GetInstance()->GetConfig());
if (CVar_GetS32("gOpenMenuBar", 0) != 1) {
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()) {
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
console->Init();
overlay->Init();
controller->Init();
ImGuiWMInit();
ImGuiBackendInit();
@ -329,23 +376,17 @@ namespace SohImGui {
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) {
pads = cont_pad;
});
Game::InitSettings();
CVar_SetS32("gRandoGenerating", 0);
CVar_SetS32("gNewSeedGenerated", 0);
CVar_SetS32("gNewFileDropped", 0);
CVar_SetString("gDroppedFile", "");
Game::SaveSettings();
CVar_SetString("gDroppedFile", "None");
// Game::SaveSettings();
}
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);
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))
{
@ -448,6 +499,18 @@ namespace SohImGui {
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)
{
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);
@ -472,12 +535,36 @@ namespace SohImGui {
else
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))
{
CVar_SetFloat(cvarName, val);
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)
{
val = min;
@ -494,7 +581,7 @@ namespace SohImGui {
}
void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue) {
if (ImGui::BeginCombo(name.c_str(), items[static_cast<int>(CVar_GetS32(cvarName, defaultValue))].c_str())) {
for (int settingIndex = 0; settingIndex < (int) items.size(); settingIndex++) {
if (ImGui::Selectable(items[settingIndex].c_str())) {
@ -638,6 +725,8 @@ namespace SohImGui {
ImGui::NewFrame();
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_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize;
@ -674,36 +763,32 @@ namespace SohImGui {
needs_save = true;
GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = menu_bar;
ShowCursor(menu_bar, Dialogues::dMenubar);
GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->SaveControllerSettings();
if (CVar_GetS32("gControlNav", 0)) {
if (CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
} else {
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
else
{
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
}
else
{
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
} else {
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
}
#if __APPLE__
if ((ImGui::IsKeyDown(ImGuiKey_LeftSuper) ||
ImGui::IsKeyDown(ImGuiKey_RightSuper)) &&
ImGui::IsKeyDown(ImGuiKey_RightSuper)) &&
ImGui::IsKeyPressed(ImGuiKey_R, false)) {
console->Commands["reset"].handler(emptyArgs);
}
#else
if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) ||
ImGui::IsKeyDown(ImGuiKey_RightCtrl)) &&
ImGui::IsKeyDown(ImGuiKey_RightCtrl)) &&
ImGui::IsKeyPressed(ImGuiKey_R, false)) {
console->Commands["reset"].handler(emptyArgs);
}
#endif
if (ImGui::BeginMenuBar()) {
if (DefaultAssets.contains("Game_Icon")) {
ImGui::SetCursorPos(ImVec2(5, 2.5f));
@ -723,7 +808,11 @@ namespace SohImGui {
console->Commands["reset"].handler(emptyArgs);
}
ImGui::EndMenu();
}
}
ImGui::Separator();
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Audio")) {
EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true);
@ -736,11 +825,16 @@ namespace SohImGui {
ImGui::EndMenu();
}
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Controller"))
{
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");
EnhancementCheckbox("Controller Configuration", "gControllerConfigurationEnabled");
controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
ImGui::Separator();
// TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected
@ -754,45 +848,15 @@ namespace SohImGui {
EnhancementCheckbox("Show Inputs", "gInputEnabled");
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);
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::Separator();
}
Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
ImGui::EndMenu();
}
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Graphics"))
{
EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true);
@ -818,6 +882,16 @@ namespace SohImGui {
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))
{
CVar_SetS32(cvar, val);
@ -830,6 +904,26 @@ namespace SohImGui {
"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"
"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();
@ -841,6 +935,8 @@ namespace SohImGui {
ImGui::EndMenu();
}
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Languages")) {
EnhancementRadioButton("English", "gLanguages", 0);
EnhancementRadioButton("German", "gLanguages", 1);
@ -848,6 +944,8 @@ namespace SohImGui {
ImGui::EndMenu();
}
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Enhancements"))
{
if (ImGui::BeginMenu("Gameplay"))
@ -881,70 +979,94 @@ namespace SohImGui {
if (ImGui::BeginMenu("Difficulty Options"))
{
EnhancementSliderInt("Damage Multiplier %dx", "##DAMAGEMUL", "gDamageMul", 1, 4, "");
Tooltip("Modifies all sources of damage not affected by other sliders");
EnhancementSliderInt("Fall Damage Multiplier %dx", "##FALLDAMAGEMUL", "gFallDamageMul", 1, 4, "");
Tooltip("Modifies all fall damage");
EnhancementSliderInt("Void Damage Multiplier %dx", "##VOIDDAMAGEMUL", "gVoidDamageMul", 1, 4, "");
Tooltip("Modifies damage taken after falling into a void");
ImGui::Text("Damage Multiplier");
EnhancementCombobox("gDamageMul", powers, 9, 0);
Tooltip("Modifies all sources of damage not affected by other sliders\n\
2x: Can survive all common attacks from the start of the game\n\
4x: Dies in 1 hit to any substantial attack from the start of the game\n\
8x: Can only survive trivial damage from the start of the game\n\
16x: Can survive all common attacks with max health without double defense\n\
32x: Can survive all common attacks with max health and double defense\n\
64x: Can survive trivial damage with max health without double defense\n\
128x: Can survive trivial damage with max health and double defense\n\
256x: Cannot survive damage");
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");
Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
EnhancementCheckbox("No Heart Drops", "gNoHeartDrops");
Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
if (ImGui::BeginMenu("Potion Values"))
{
EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect");
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");
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");
EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect");
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");
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");
EnhancementCheckbox("Change Blue Potion Effects", "gBluePotionEffects");
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");
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");
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");
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");
EnhancementCheckbox("Change Milk Effect", "gMilkEffect");
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");
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");
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.");
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");
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");
EnhancementCheckbox("Change Fairy Effect", "gFairyEffect");
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");
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");
EnhancementCheckbox("Change Fairy Revive Effect", "gFairyReviveEffect");
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");
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");
@ -978,7 +1100,7 @@ namespace SohImGui {
ImGui::EndMenu();
}
EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony");
Tooltip("Displays an icon and plays a sound when Stone of Agony\nshould be activated, for those without rumble");
EnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots");
@ -1033,7 +1155,7 @@ namespace SohImGui {
EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16);
Tooltip("Randomize the animation played on the menu after a certain time");
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();
@ -1105,6 +1227,16 @@ namespace SohImGui {
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))
{
CVar_SetS32(fps_cvar, val);
@ -1117,6 +1249,14 @@ namespace SohImGui {
"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"
"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)
{
@ -1143,9 +1283,14 @@ namespace SohImGui {
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");
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::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Cheats"))
{
if (ImGui::BeginMenu("Infinite...")) {
@ -1183,6 +1328,8 @@ namespace SohImGui {
ImGui::EndMenu();
}
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu("Developer Tools"))
{
EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled");
@ -1203,6 +1350,7 @@ namespace SohImGui {
}
for (const auto& category : windowCategories) {
ImGui::SetCursorPosY(0.0f);
if (ImGui::BeginMenu(category.first.c_str())) {
for (const std::string& name : category.second) {
std::string varName(name);
@ -1224,12 +1372,13 @@ namespace SohImGui {
for (const auto& category : hiddenwindowCategories) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::SetNextWindowSize(ImVec2 (0,0));
ImGui::SetNextWindowPos(ImVec2 (-100,-100));
ImGui::Begin(category.first.c_str(), nullptr, ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNavFocus);
ImGuiWindowFlags HiddenWndFlags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings |
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::PopStyleColor();
}
if (CVar_GetS32("gStatsEnabled", 0)) {
const float framerate = ImGui::GetIO().Framerate;
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
@ -1248,6 +1397,7 @@ namespace SohImGui {
}
console->Draw();
controller->DrawHud();
for (auto& windowIter : customWindows) {
CustomWindow& window = windowIter.second;
@ -1413,4 +1563,124 @@ namespace SohImGui {
#endif
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 "Lib/ImGui/imgui.h"
#include "Console.h"
#include "InputEditor.h"
struct GameAsset {
uint32_t textureId;
@ -59,23 +60,24 @@ namespace SohImGui {
} CustomWindow;
extern Console* console;
extern Ship::InputEditor* controller;
extern Ship::GameOverlay* overlay;
extern bool needs_save;
void Init(WindowImpl window_impl);
void Update(EventImpl event);
void Tooltip(const char* text);
void EnhancementRadioButton(const char* text, const char* cvarName, int id);
void EnhancementCheckbox(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 EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage);
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, bool PlusMinusButton = false);
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 EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0);
void DrawMainMenuAndCalculateGameSize(void);
void DrawFramebufferAndGameInput(void);
void Render(void);
void CancelFrame(void);
@ -90,4 +92,6 @@ namespace SohImGui {
void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha);
ImTextureID GetTextureByID(int id);
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"
#if __APPLE__
#include <SDL_keyboard.h>
#else
#include <SDL2/SDL_keyboard.h>
#endif
#include "Hooks.h"
#include "GlobalCtx2.h"
#include "Window.h"
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) {
if (ButtonMapping.contains(dwScancode)) {
dwPressedButtons |= ButtonMapping[dwScancode];
return true;
lastKey = dwScancode;
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] |= profiles[slot].Mappings[dwScancode];
return true;
}
}
return false;
}
bool KeyboardController::ReleaseButton(int32_t dwScancode) {
if (ButtonMapping.contains(dwScancode)) {
dwPressedButtons &= ~ButtonMapping[dwScancode];
return true;
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] &= ~profiles[slot].Mappings[dwScancode];
return true;
}
}
return false;
}
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;
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() {
return "KEYBOARD";
const char* KeyboardController::GetButtonName(int slot, int n64Button) {
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() {
return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1);
const char* KeyboardController::GetControllerName() {
return "Keyboard";
}
}

View File

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

View File

@ -112,9 +112,11 @@ typedef struct {
/* 0x02 */ s8 stick_x;
/* 0x03 */ s8 stick_y;
/* 0x04 */ u8 err_no;
/* 0x05 */ f32 gyro_x;
/* 0x09 */ f32 gyro_y;
} OSContPad; // size = 0x0D
/* 0x05 */ f32 gyro_x;
/* 0x09 */ f32 gyro_y;
/* 0x1C */ f32 cam_x;
/* 0x20 */ f32 cam_y;
} OSContPad; // size = 0x24
typedef struct {
/* 0x00 */ u8 rumble;

View File

@ -28,6 +28,7 @@
#include "gfx_pc.h"
#include "../../ImGuiImpl.h"
#include "../../Cvar.h"
#include "../../Hooks.h"
#define DECLARE_GFX_DXGI_FUNCTIONS
#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) {
char fileName[256];
SohImGui::EventImpl event_impl;
event_impl.win32 = { h_wnd, static_cast<int>(message), static_cast<int>(w_param), static_cast<int>(l_param) };
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);
break;
case WM_DESTROY:
ModInternal::ExecuteHooks<ModInternal::ExitGame>();
exit(0);
case WM_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 = {
gfx_dxgi_init,
gfx_dxgi_set_keyboard_callbacks,
@ -734,6 +741,7 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
gfx_dxgi_set_target_fps,
gfx_dxgi_set_maximum_frame_latency,
gfx_dxgi_get_detected_hz,
gfx_dxgi_get_key_name
};
#endif

View File

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

View File

@ -20,6 +20,7 @@ struct GfxWindowManagerAPI {
void (*set_target_fps)(int fps);
void (*set_maximum_frame_latency)(int latency);
float (*get_detected_hz)(void);
const char* (*get_key_name)(int scancode);
};
#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,
Roy = 1,
Rachael = 2,
Leon = 3,
Zhora = 4,
Zhora = 3,
// ...
};

View File

@ -1,103 +1,36 @@
#include "SDLController.h"
#include "GameSettings.h"
#include "GlobalCtx2.h"
#include "spdlog/spdlog.h"
#include "stox.h"
#include "Window.h"
#include "Cvar.h"
#include <Utils/StringHelper.h>
extern "C" uint8_t __osMaxControllers;
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() {
std::string ConfSection = GetConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
for (int i = 0; i < SDL_NumJoysticks(); i++) {
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);
const auto NewCont = SDL_GameControllerOpen(physicalSlot);
// 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.
if (NewCont == nullptr) {
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
continue;
}
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
{
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
}
guid = NewGuid;
Cont = NewCont;
std::string BindingConfSection = GetBindingConfSection();
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;
}
}
// We failed to load the controller. Go to next.
if (NewCont == nullptr) {
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
return false;
}
return Cont != nullptr;
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) {
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
supportsGyro = true;
}
char GuidBuf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf));
GUID = std::string(GuidBuf);
Cont = NewCont;
wCamX = 0;
wCamY = 0;
return true;
}
bool SDLController::Close() {
@ -108,31 +41,14 @@ namespace Ship {
SDL_GameControllerClose(Cont);
}
Cont = nullptr;
guid = "";
ButtonMapping.clear();
ThresholdMapping.clear();
dwPressedButtons = 0;
wStickX = 0;
wStickY = 0;
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"]);
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) {
void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity) {
//scale {-32768 ... +32767} to {-84 ... +84}
auto ax = wAxisValueX * 85.0 / 32767.0;
auto ay = wAxisValueY * 85.0 / 32767.0;
@ -163,14 +79,59 @@ namespace Ship {
ay *= scale;
}
wStickX = +ax;
wStickY = -ay;
if (!isRightStick) {
wStickX = +ax;
wStickY = -ay;
} else {
wCamX = +ax * sensitivity;
wCamY = -ay * sensitivity;
}
}
void SDLController::ReadFromSource() {
std::string ConfSection = GetBindingConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
int32_t SDLController::ReadRawPress() {
SDL_GameControllerUpdate();
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();
@ -187,17 +148,14 @@ namespace Ship {
}
}
if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO))
{
size_t contNumber = GetControllerNumber();
if (supportsGyro && profile.UseGyro) {
float gyroData[3];
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
const char* contName = SDL_GameControllerName(Cont);
float gyro_drift_x = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), 0.0f);
float gyro_drift_y = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), 0.0f);
const float gyro_sensitivity = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroSensitivity", contNumber).c_str(), 1.0f);
float gyro_drift_x = profile.Thresholds[DRIFT_X] / 100.0f;
float gyro_drift_y = profile.Thresholds[DRIFT_Y] / 100.0f;
const float gyro_sensitivity = profile.Thresholds[GYRO_SENSITIVITY];
if (gyro_drift_x == 0) {
gyro_drift_x = gyroData[0];
@ -207,8 +165,8 @@ namespace Ship {
gyro_drift_y = gyroData[1];
}
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), gyro_drift_x);
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), gyro_drift_y);
profile.Thresholds[DRIFT_X] = gyro_drift_x * 100.0f;
profile.Thresholds[DRIFT_Y] = gyro_drift_y * 100.0f;
wGyroX = gyroData[0] - gyro_drift_x;
wGyroY = gyroData[1] - gyro_drift_y;
@ -217,29 +175,35 @@ namespace Ship {
wGyroY *= gyro_sensitivity;
}
dwPressedButtons[slot] = 0;
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (ButtonMapping.contains(i)) {
if (SDL_GameControllerGetButton(Cont, (SDL_GameControllerButton)i)) {
dwPressedButtons |= ButtonMapping[i];
if (profile.Mappings.contains(i)) {
if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
dwPressedButtons[slot] |= profile.Mappings[i];
}
else {
dwPressedButtons &= ~ButtonMapping[i];
dwPressedButtons[slot] &= ~profile.Mappings[i];
}
}
}
SDL_GameControllerAxis StickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis StickAxisY = SDL_CONTROLLER_AXIS_INVALID;
int32_t StickDeadzone = 0;
SDL_GameControllerAxis LStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis LStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
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++) {
auto Axis = (SDL_GameControllerAxis)i;
auto PosScancode = i + AXIS_SCANCODE_BIT;
auto NegScancode = -PosScancode;
auto AxisThreshold = ThresholdMapping[i];
auto PosButton = ButtonMapping[PosScancode];
auto NegButton = ButtonMapping[NegScancode];
auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
const auto Axis = static_cast<SDL_GameControllerAxis>(i);
const auto PosScancode = i + AXIS_SCANCODE_BIT;
const auto NegScancode = -PosScancode;
const auto AxisThreshold = static_cast<int>(profile.Thresholds[SDLAxisToThreshold(i)]);
const auto PosButton = profile.Mappings[PosScancode];
const auto NegButton = profile.Mappings[NegScancode];
const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
#ifdef TARGET_WEB
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
@ -252,94 +216,176 @@ namespace Ship {
}
#endif
// If the axis is NOT mapped to the control stick.
if (!(
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
if (AxisValue > AxisThreshold) {
dwPressedButtons |= PosButton;
dwPressedButtons &= ~NegButton;
if (AxisValue > 0x1E00) {
dwPressedButtons[slot] |= PosButton;
dwPressedButtons[slot] &= ~NegButton;
}
else if (AxisValue < -AxisThreshold) {
dwPressedButtons &= ~PosButton;
dwPressedButtons |= NegButton;
else if (AxisValue < -0x1E00) {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] |= NegButton;
}
else {
dwPressedButtons &= ~PosButton;
dwPressedButtons &= ~NegButton;
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton;
}
}
else {
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis);
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis);
}
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisThreshold);
}
StickDeadzone = AxisThreshold;
StickAxisX = Axis;
LStickDeadzone = AxisThreshold;
LStickAxisX = Axis;
}
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis);
if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis);
}
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
StickDeadzone = AxisThreshold;
StickAxisY = Axis;
LStickDeadzone = AxisThreshold;
LStickAxisY = Axis;
}
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis);
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis);
}
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
StickDeadzone = AxisThreshold;
StickAxisX = Axis;
LStickDeadzone = AxisThreshold;
LStickAxisX = Axis;
}
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis);
if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis);
}
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
StickDeadzone = AxisThreshold;
StickAxisY = Axis;
LStickDeadzone = AxisThreshold;
LStickAxisY = Axis;
}
}
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
auto AxisValueX = SDL_GameControllerGetAxis(Cont, StickAxisX);
auto AxisValueY = SDL_GameControllerGetAxis(Cont, StickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone);
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, LStickAxisX);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, LStickAxisY);
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;
}
} 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(ControllerCallback* controller)
void SDLController::WriteToSource(int32_t slot, ControllerCallback* controller)
{
if (CanRumble()) {
if (CanRumble() && profiles[slot].UseRumble) {
if (controller->rumble > 0) {
float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f);
float rumble_strength = profiles[slot].RumbleStrength;
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
} else {
}
else {
SDL_GameControllerRumble(Cont, 0, 0, 0);
}
}
@ -362,73 +408,74 @@ namespace Ship {
}
}
void SDLController::CreateDefaultBinding() {
std::string ConfSection = GetBindingConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
const char* AxisNames[] = {
"Left Stick X",
"Left Stick Y",
"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));
Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
Conf[ConfSection][STR(BTN_CUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
//Conf[ConfSection][STR(BTN_CRIGHT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_X);
//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));
char buffer[50];
const char* SDLController::GetButtonName(int slot, int n64Button) {
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;
});
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0);
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);
if (find == Mappings.end()) return "Unknown";
Conf.Save();
}
int btn = abs(find->first);
void SDLController::CreateDefaultPadConf() {
std::string ConfSection = *GetPadConfSection();
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
if(btn >= AXIS_SCANCODE_BIT) {
btn -= AXIS_SCANCODE_BIT;
Conf.Save();
}
void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) {
return;
snprintf(buffer, sizeof(buffer), "%s%s", AxisNames[btn], find->first > 0 ? "+" : "-");
return buffer;
}
Controller::SetButtonMapping(szButtonName, dwScancode);
snprintf(buffer, sizeof(buffer), "Button %d", btn);
return buffer;
}
std::string SDLController::GetControllerType() {
return "SDL";
}
std::string SDLController::GetConfSection() {
return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1);
const char* SDLController::GetControllerName() {
return SDL_GameControllerNameForIndex(physicalSlot);
}
std::string SDLController::GetBindingConfSection() {
return GetControllerType() + " CONTROLLER BINDING " + guid;
}
void SDLController::CreateDefaultBinding(int32_t slot) {
DeviceProfile& profile = profiles[slot];
profile.Mappings.clear();
std::optional<std::string> SDLController::GetPadConfSection() {
return GetControllerType() + " CONTROLLER PAD " + guid;
profile.UseRumble = true;
profile.RumbleStrength = 1.0f;
profile.UseGyro = false;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
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;
profile.Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
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;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
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>
#endif
#define INVALID_SDL_CONTROLLER_GUID (std::string("00000000000000000000000000000000"))
namespace Ship {
class SDLController : public Controller {
public:
SDLController(int32_t dwControllerNumber);
~SDLController();
void ReadFromSource();
void WriteToSource(ControllerCallback* controller);
bool Connected() const { return Cont != nullptr; }
bool CanRumble() const {
SDLController(int slot) : Controller(), Cont(nullptr), physicalSlot(slot) { }
void ReadFromSource(int32_t slot) override;
const char* GetControllerName() override;
const char* GetButtonName(int slot, int n64Button) override;
void WriteToSource(int32_t slot, ControllerCallback* controller) override;
bool Connected() const override { return Cont != nullptr; }
bool CanGyro() const override { return supportsGyro; }
bool CanRumble() const override {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont);
#endif
return true;
}
std::string GetGuid() { return guid; };
bool HasPadConf() const { return true; }
std::optional<std::string> GetPadConfSection();
bool Open();
void ClearRawPress() override {}
int32_t ReadRawPress() override;
protected:
std::string GetControllerType();
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);
void CreateDefaultBinding(int32_t slot) override;
private:
SDL_GameController* Cont;
std::string guid;
std::map<int32_t, int16_t> ThresholdMapping;
void LoadAxisThresholds();
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold);
bool Open();
int physicalSlot;
bool supportsGyro;
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity);
bool Close();
};
}

View File

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

View File

@ -38,8 +38,7 @@ extern "C" {
uint8_t __enableGameInput = 1;
int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) {
std::shared_ptr<Ship::ConfigFile> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
*controllerBits = 0;
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
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());
}
// TODO: This for loop is debug. Burn it with fire.
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;
}
}
Ship::Window::ControllerApi->Init(controllerBits);
return 0;
}
@ -103,17 +66,14 @@ extern "C" {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
pad->cam_x = 0;
pad->cam_y = 0;
pad->err_no = 0;
pad->gyro_x = 0;
pad->gyro_y = 0;
if (__enableGameInput)
{
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]);
}
}
if (__enableGameInput) {
Ship::Window::ControllerApi->WriteToPad(pad);
}
ModInternal::ExecuteHooks<ModInternal::ControllerRead>(pad);
@ -129,15 +89,10 @@ extern "C" {
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (Vtx*)res->vertices.data();
}
//if (res != nullptr)
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) {
@ -146,9 +101,9 @@ extern "C" {
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (int32_t*)res->mtx.data();
} else {
return nullptr;
}
return nullptr;
}
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);
namespace Ship {
std::map<size_t, std::vector<std::shared_ptr<Controller>>> Window::Controllers;
int32_t Window::lastScancode;
Window::Window(std::shared_ptr<GlobalCtx2> Context) : Context(Context), APlayer(nullptr) {
@ -248,26 +203,55 @@ namespace Ship {
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() {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
CreateDefaults();
SetAudioPlayer();
bIsFullscreen = Ship::stob(Conf["WINDOW"]["FULLSCREEN"]);
bIsFullscreen = pConf->getBool("Window.Fullscreen.Enabled", false);
if (bIsFullscreen) {
dwWidth = Ship::stoi(Conf["WINDOW"]["FULLSCREEN WIDTH"], 1920);
dwHeight = Ship::stoi(Conf["WINDOW"]["FULLSCREEN HEIGHT"], 1080);
dwWidth = pConf->getInt("Window.Fullscreen.Width", 1920);
dwHeight = pConf->getInt("Window.Fullscreen.Height", 1080);
} else {
dwWidth = Ship::stoi(Conf["WINDOW"]["WINDOW WIDTH"], 640);
dwHeight = Ship::stoi(Conf["WINDOW"]["WINDOW HEIGHT"], 480);
dwWidth = pConf->getInt("Window.Width", 640);
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);
gfx_init(WmApi, RenderingApi, GetContext()->GetName().c_str(), bIsFullscreen, dwWidth, dwHeight);
WmApi->set_fullscreen_changed_callback(Window::OnFullscreenChanged);
WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp);
WmApi->set_fullscreen_changed_callback(OnFullscreenChanged);
WmApi->set_keyboard_callbacks(KeyDown, KeyUp, AllKeysUp);
ModInternal::RegisterHook<ModInternal::ExitGame>([]() {
ControllerApi->SaveControllerSettings();
});
}
void Window::StartFrame() {
@ -318,30 +302,26 @@ namespace Ship {
void Window::MainLoop(void (*MainFunction)(void)) {
WmApi->main_loop(MainFunction);
}
bool Window::KeyUp(int32_t dwScancode) {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_FULLSCREEN"])) {
if (dwScancode == pConf->getInt("Shortcuts.Fullscreen", 0x044)) {
GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen();
}
// OTRTODO: Rig with Kirito's console?
//if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) {
// ToggleConsole();
//}
lastScancode = -1;
bool bIsProcessed = false;
for (size_t i = 0; i < __osMaxControllers; i++) {
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->ReleaseButton(dwScancode)) {
bIsProcessed = true;
}
}
const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
if (pad != nullptr) {
if (pad->ReleaseButton(dwScancode)) {
bIsProcessed = true;
}
}
@ -350,14 +330,11 @@ namespace Ship {
bool Window::KeyDown(int32_t dwScancode) {
bool bIsProcessed = false;
for (size_t i = 0; i < __osMaxControllers; i++) {
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->PressButton(dwScancode)) {
bIsProcessed = true;
}
}
const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
if (pad != nullptr) {
if (pad->PressButton(dwScancode)) {
bIsProcessed = true;
}
}
@ -368,21 +345,17 @@ namespace Ship {
void Window::AllKeysUp(void) {
for (size_t i = 0; i < __osMaxControllers; i++) {
for (size_t j = 0; j < Controllers[i].size(); j++) {
KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
if (pad != nullptr) {
pad->ReleaseAllButtons();
}
}
const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
if (pad != nullptr) {
pad->ReleaseAllButtons();
}
}
void Window::OnFullscreenChanged(bool bIsFullscreen) {
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
ConfigFile& Conf = *pConf.get();
std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
GlobalCtx2::GetInstance()->GetWindow()->bIsFullscreen = bIsFullscreen;
Conf["WINDOW"]["FULLSCREEN"] = std::to_string(bIsFullscreen);
pConf->setBool("Window.Fullscreen.Enabled", bIsFullscreen);
GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(!bIsFullscreen);
}

View File

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

View File

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

View File

@ -31,9 +31,6 @@
<Filter Include="Source Files\Globals">
<UniqueIdentifier>{c0f07350-c627-444e-9f66-23e19407ad9a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Config">
<UniqueIdentifier>{9cf4833f-e90c-4a9d-8747-d47cde657beb}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Resources\Files">
<UniqueIdentifier>{2aa34c3b-6148-480f-a4fc-19c4e0f8c822}</UniqueIdentifier>
</Filter>
@ -94,6 +91,15 @@
<Filter Include="Source Files\Lib\dr_libs">
<UniqueIdentifier>{db6e02cc-fc4c-4138-8219-1d281ad93ec2}</UniqueIdentifier>
</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>
<ClCompile Include="Factories\MaterialFactory.cpp">
@ -165,9 +171,6 @@
<ClCompile Include="MemoryPack.cpp">
<Filter>Source Files\Controller\Attachment</Filter>
</ClCompile>
<ClCompile Include="ConfigFile.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="CollisionHeader.cpp">
<Filter>Source Files\Resources\Files</Filter>
</ClCompile>
@ -354,6 +357,15 @@
<ClCompile Include="Factories\AudioFactory.cpp">
<Filter>Source Files\Resources\Factories</Filter>
</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>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@ -386,9 +398,6 @@
<ClInclude Include="MemoryPack.h">
<Filter>Source Files\Controller\Attachment</Filter>
</ClInclude>
<ClInclude Include="ConfigFile.h">
<Filter>Source Files\Config</Filter>
</ClInclude>
<ClInclude Include="ResourceMgr.h">
<Filter>Source Files\Resources</Filter>
</ClInclude>
@ -659,5 +668,20 @@
<ClInclude Include="Lib\dr_libs\wav.h">
<Filter>Source Files\Lib\dr_libs</Filter>
</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>
</Project>

View File

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

View File

@ -120,6 +120,7 @@ ifeq ($(UNAME), Darwin) #APPLE
LDLIBS += \
$(addprefix -framework , \
OpenGL \
Foundation \
) \
$(shell sdl2-config --libs) $(shell pkg-config --libs glew)
endif
@ -224,9 +225,6 @@ appbundle: macosx/$(APPNAME).icns
cp macosx/PkgInfo $(APPBUNDLECONTENTS)/
cp macosx/$(APPNAME).icns $(APPBUNDLEICON)/
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
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
iconutil -c icns -o macosx/$(APPNAME).icns 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*);
void func_80038A28(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest);
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);
s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
f32 checkHeight, CollisionPoly** outPoly);

View File

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

View File

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

View File

@ -7,9 +7,9 @@
<key>CFBundleName</key>
<string>Ship of Harkinian</string>
<key>CFBundleExecutable</key>
<string>launcher.sh</string>
<string>soh</string>
<key>CFBundleGetInfoString</key>
<string>2.0.0</string>
<string>3.0.0</string>
<key>CFBundleIconFile</key>
<string>soh.icns</string>
<key>CFBundleIdentifier</key>
@ -22,14 +22,14 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.0.0</string>
<string>3.0.0</string>
<key>CFBundleSignature</key>
<string>ZOoT</string>
<key>CFBundleVersion</key>
<string>2.0.0</string>
<string>3.0.0</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 2022 HarbourMasters.</string>
<key>LSMinimumSystemVersion</key>
<string>10.3</string>
<string>10.15</string>
</dict>
</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>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<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>
<LanguageStandard>stdcpp20</LanguageStandard>
<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_data.c" />
<ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" />
</ItemGroup>
<ItemGroup>
<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\trial.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\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" />
@ -1038,7 +1039,6 @@
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h" />
<ClInclude Include="soh\gameconsole.h" />
<ClInclude Include="soh\Lib\nlohmann\json.hpp" />
<ClInclude Include="soh\OTRAudio.h" />
<ClInclude Include="soh\OTRGlobals.h" />
<ClInclude Include="soh\SaveManager.h" />

View File

@ -82,12 +82,6 @@
<Filter Include="Source Files\soh\Enhancements\debugger">
<UniqueIdentifier>{04fc1c52-49ff-48e2-ae23-2c00867374f8}</UniqueIdentifier>
</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>
<ClCompile Include="src\boot\assert.c">
@ -3947,9 +3941,6 @@
<ClInclude Include="soh\OTRAudio.h">
<Filter>Source Files\soh</Filter>
</ClInclude>
<ClInclude Include="soh\Lib\nlohmann\json.hpp">
<Filter>Source Files\soh\Lib\nlohmann</Filter>
</ClInclude>
<ClInclude Include="soh\SaveManager.h">
<Filter>Source Files\soh</Filter>
</ClInclude>
@ -4061,7 +4052,7 @@
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="randomizerTypes.h">
<ClInclude Include="soh\Enhancements\randomizer\randomizerTypes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\gfx.h">

View File

@ -20,7 +20,7 @@ extern BootCommandFunc BootCommands_Command_LoadFileSelect(char** argv, s32 argc
static BootCommand sCommands[] = { { "--skiplogo", BootCommands_Command_SkipLogo },
{ "--loadfileselect", BootCommands_Command_LoadFileSelect } };
void BootCommands_Init()
void BootCommands_Init()
{
CVar_RegisterS32("gDisableLOD", 0);
CVar_RegisterS32("gDebugEnabled", 0);
@ -30,7 +30,6 @@ void BootCommands_Init()
CVar_RegisterS32("gHoverFishing", 0);
CVar_RegisterS32("gN64WeirdFrames", 0);
CVar_RegisterS32("gBombchusOOB", 0);
CVar_RegisterS32("gRumbleEnabled", 0);
CVar_RegisterS32("gUniformLR", 0);
CVar_RegisterS32("gTwoHandedIdle", 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);
Table_InitHeader();
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();
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();
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();
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();
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();
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();
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();
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();
}
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));
Table_NextCol();
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();
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();
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));

View File

@ -16,6 +16,7 @@
#include <Utils/StringHelper.h>
#include <Utils/File.h>
#include "Window.h"
#include "Lib/ImGui/imgui_internal.h"
#undef PATH_HACK
#undef Path
@ -315,7 +316,7 @@ static bool SaveStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
switch (rtn) {
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", slot);
return CMD_SUCCESS;
@ -329,7 +330,7 @@ static bool SaveStateHandler(const std::vector<std::string>& args) {
static bool LoadStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", slot);
@ -342,7 +343,7 @@ static bool LoadStateHandler(const std::vector<std::string>& args) {
return CMD_FAILED;
case SaveStateReturn::FAIL_WRONG_GAMESTATE:
ERROR("[SOH] Can not load a state outside of \"GamePlay\"");
return CMD_FAILED;
return CMD_FAILED;
}
}
@ -360,7 +361,7 @@ static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
ERROR("[SOH] SaveState slot value must be a number.");
return CMD_FAILED;
}
if (slot < 0) {
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
return CMD_FAILED;
@ -498,10 +499,10 @@ template <typename Numeric> bool is_number(const std::string& s) {
return ((std::istringstream(s) >> n >> std::ws).eof());
}
void DebugConsole_LoadCVars()
{
if (File::Exists("cvars.cfg")) {
const auto lines = File::ReadAllLines("cvars.cfg");
void DebugConsole_LoadLegacyCVars() {
auto cvarsConfig = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("cvars.cfg");
if (File::Exists(cvarsConfig)) {
const auto lines = File::ReadAllLines(cvarsConfig);
for (const std::string& line : lines) {
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]));
}
}
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()
{
std::string output;
std::shared_ptr<Mercury> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
for (const auto &cvar : cvars) {
if (cvar.second->type == CVAR_TYPE_STRING)
output += StringHelper::Sprintf("%s = \"%s\"\n", cvar.first.c_str(), cvar.second->value.valueStr);
const std::string key = StringHelper::Sprintf("CVars.%s", cvar.first.c_str());
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)
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)
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;
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;
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);

View File

@ -1561,6 +1561,18 @@ void DrawPlayerTab() {
ImGui::InputScalar("C Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[2], &one, NULL);
ImGui::SameLine();
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 {

View File

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

View File

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

View File

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

View File

@ -7,6 +7,9 @@
// #include <soh/Enhancements/randomizer.h>
#include <Cvar.h>
#include <GameSettings.h>
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include <GlobalCtx2.h>
#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";
// 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());
Game::SaveSettings();

View File

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

View File

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

View File

@ -57,7 +57,6 @@ OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance;
OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
gSaveStateMgr = std::make_shared<SaveStateMgr>();
gRandomizer = std::make_shared<Randomizer>();
@ -1154,34 +1153,27 @@ extern "C" s32* ResourceMgr_LoadCSByName(const char* path)
return (s32*)res->commands.data();
}
std::filesystem::path GetSaveFile(Ship::ConfigFile& Conf) {
std::string fileName = Conf.get("SAVE").get("Save Filename");
if (fileName.empty()) {
Conf["SAVE"]["Save Filename"] = "oot_save.sav";
Conf.Save();
}
std::filesystem::path GetSaveFile(std::shared_ptr<Mercury> Conf) {
const std::string fileName = Conf->getString("Game.SaveName", Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.sav"));
std::filesystem::path saveFile = std::filesystem::absolute(fileName);
if (!std::filesystem::exists(saveFile.parent_path())) {
std::filesystem::create_directories(saveFile.parent_path());
if (!exists(saveFile.parent_path())) {
create_directories(saveFile.parent_path());
}
return saveFile;
}
std::filesystem::path GetSaveFile() {
std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
const std::shared_ptr<Mercury> pConf = OTRGlobals::Instance->context->GetConfig();
return GetSaveFile(Conf);
return GetSaveFile(pConf);
}
void OTRGlobals::CheckSaveFile(size_t sramSize) {
std::shared_ptr<Ship::ConfigFile> pConf = context->GetConfig();
Ship::ConfigFile& Conf = *pConf.get();
void OTRGlobals::CheckSaveFile(size_t sramSize) const {
const std::shared_ptr<Mercury> pConf = Instance->context->GetConfig();
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);
if (saveFile.fail()) {
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);
}
/* 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::vector<unsigned long> result;
size_t i = 0;
@ -1320,11 +1293,10 @@ extern "C" uint32_t OTRGetCurrentHeight() {
}
extern "C" void OTRControllerCallback(ControllerCallback* controller) {
auto controllers = OTRGlobals::Instance->context->GetWindow()->Controllers;
for (size_t i = 0; i < controllers.size(); i++) {
for (int j = 0; j < controllers[i].size(); j++) {
OTRGlobals::Instance->context->GetWindow()->Controllers[i][j]->WriteToSource(controller);
}
const auto controllers = Ship::Window::ControllerApi->virtualDevices;
for (int i = 0; i < controllers.size(); ++i) {
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) {
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;
}
}
@ -1395,23 +1367,23 @@ extern "C" void* getN64WeirdFrame(s32 i) {
return &weirdFrameBytes[i + sizeof(n64WeirdFrames)];
}
extern "C" s16 GetItemModelFromId(s16 itemId) {
extern "C" s16 Randomizer_GetItemModelFromId(s16 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);
}
extern "C" void LoadRandomizerSettings(const char* spoilerFileName) {
extern "C" void Randomizer_LoadSettings(const char* 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);
}
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);
}
@ -1419,11 +1391,11 @@ extern "C" bool SpoilerFileExists(const char* 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);
}
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);
}
@ -1499,33 +1471,33 @@ extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBuff
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()
: OTRGlobals::Instance->gRandomizer->GetChildAltarText();
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();
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();
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
// so we're just going to let RVO take care of it
const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check);
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);
}
extern "C" s32 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
extern "C" s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
return OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId);
}

View File

@ -23,7 +23,7 @@ public:
~OTRGlobals();
private:
void CheckSaveFile(size_t sramSize);
void CheckSaveFile(size_t sramSize) const;
};
#endif
@ -61,8 +61,6 @@ SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
void Ctx_ReadSaveFile(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();
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);
void* getN64WeirdFrame(s32 i);
Sprite* GetSeedTexture(uint8_t index);
void LoadRandomizerSettings(const char* spoilerFileName);
u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
int CopyAltarMessage(char* buffer, const int maxBufferSize);
int CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize);
int CopyGanonText(char* buffer, const int maxBufferSize);
int CopyGanonHintText(char* buffer, const int maxBufferSize);
void LoadHintLocations(const char* spoilerFileName);
void LoadItemLocations(const char* spoilerFileName, bool silent);
s16 GetItemModelFromId(s16 itemId);
s32 GetItemIDFromGetItemID(s32 getItemId);
s32 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
s32 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
void Randomizer_LoadSettings(const char* spoilerFileName);
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize);
int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize);
int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize);
int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize);
void Randomizer_LoadHintLocations(const char* spoilerFileName);
void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
s16 Randomizer_GetItemModelFromId(s16 itemId);
s32 Randomizer_GetItemIDFromGetItemID(s32 getItemId);
s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
#endif
#endif

View File

@ -1,4 +1,5 @@
#include "SaveManager.h"
#include "OTRGlobals.h"
#include "z64.h"
#include "functions.h"
@ -14,11 +15,9 @@
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) {
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() {
@ -128,15 +127,20 @@ void SaveManager::SaveRandomizer() {
}
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 (!std::filesystem::exists(sSavePath)) {
std::filesystem::create_directory(sSavePath);
}
// If there is a lingering unversioned save, convert it
if (std::filesystem::exists("oot_save.sav")) {
if (std::filesystem::exists(sOldSavePath)) {
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.

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 gBuildDate[] = __DATE__ " " __TIME__;
const char gBuildMakeOption[] = "";

View File

@ -1176,9 +1176,13 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) {
if (seqPlayer->defaultFont != 0xFF)
{
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))

View File

@ -409,7 +409,9 @@ void GameState_Update(GameState* gameState) {
// Unrestricted Items
if (CVar_GetS32("gNoRestrictItems", 0) != 0) {
if (gGlobalCtx) {
u8 sunsBackup = gGlobalCtx->interfaceCtx.restrictions.sunsSong;
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);
}
controllerCallback.rumble = CVar_GetS32("gRumbleEnabled", 0) && (padMgr->rumbleEnable[0] > 0);
controllerCallback.rumble = (padMgr->rumbleEnable[0] > 0);
if (HealthMeter_IsCritical()) {
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) {
if (GetRandoSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME)) {
// RANDOTODO update this logic when we implement keysanity
// because 3drando replaces the keys not the rupees
if (ogDrawId == GID_RUPEE_GREEN ||
@ -5993,27 +5993,27 @@ s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx)
switch(room) {
case 1:
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;
case 2:
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;
case 3:
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;
case 4:
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;
case 5:
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;
}
@ -6021,7 +6021,7 @@ s32 GetChestGameRandoGetItemId(s8 room, s16 ogDrawId, GlobalContext* globalCtx)
}
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;
@ -6031,7 +6031,7 @@ s16 GetChestGameRandoGiDrawId(s8 room, s16 ogDrawId, GlobalContext* globalCtx) {
s32 randoGetItemId = GetChestGameRandoGetItemId(room, ogDrawId, globalCtx);
if(randoGetItemId != GI_NONE) {
return GetItemModelFromId(randoGetItemId);
return Randomizer_GetItemModelFromId(randoGetItemId);
}
return ogDrawId;

View File

@ -1409,7 +1409,115 @@ s32 Camera_Noop(Camera* camera) {
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) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -1637,6 +1745,11 @@ s32 Camera_Normal1(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* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -1803,6 +1916,11 @@ s32 Camera_Normal2(Camera* camera) {
// riding epona
s32 Camera_Normal3(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -1997,6 +2115,8 @@ s32 Camera_Parallel1(Camera* camera) {
OLib_Vec3fDiffToVecSphGeo(&atToEyeDir, at, eye);
OLib_Vec3fDiffToVecSphGeo(&atToEyeNextDir, at, eyeNext);
camera->globalCtx->manualCamera = false;
switch (camera->animState) {
case 0:
case 0xA:
@ -2162,6 +2282,11 @@ s32 Camera_Parallel0(Camera* camera) {
* Generic jump, jumping off ledges
*/
s32 Camera_Jump1(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -2307,6 +2432,11 @@ s32 Camera_Jump1(Camera* camera) {
// Climbing ladders/vines
s32 Camera_Jump2(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -2489,6 +2619,11 @@ s32 Camera_Jump2(Camera* camera) {
// swimming
s32 Camera_Jump3(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -2946,6 +3081,11 @@ s32 Camera_Battle3(Camera* camera) {
* setting value.
*/
s32 Camera_Battle4(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f* eyeNext = &camera->eyeNext;
@ -4476,6 +4616,11 @@ s32 Camera_Data4(Camera* camera) {
* Hanging off of a ledge
*/
s32 Camera_Unique1(Camera* camera) {
if (CVar_GetS32("gFreeCamera", 0) && SetCameraManual(camera) == 1) {
Camera_Free(camera);
return 1;
}
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
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
// and exit.
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
return;
}
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)) {
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);
}
@ -548,7 +548,7 @@ void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) {
}
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;
} else {
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 (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);
}
@ -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...).
*/
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;
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) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
}
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId));
GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else {
s32 texIndex = this->actor.params - 3;
@ -1360,11 +1360,11 @@ void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) {
if (gSaveContext.n64ddFlag) {
f32 mtxScale = 16.0f;
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) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
}
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId));
GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else {
s32 pad;

View File

@ -89,6 +89,7 @@ void TransitionWipe_Draw(void* thisx, Gfx** gfxP) {
TransitionWipe* this = (TransitionWipe*)thisx;
s32 pad[4];
Gfx* tex;
Gfx* wipeDl = sWipeDList;
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 (gSaveContext.n64ddFlag &&
textId == 0x2053 &&
GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 &&
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 ||
(GetRandoSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 &&
Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) != 0 &&
(Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 1 ||
(Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 2 &&
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)))) {
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.
// 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)) {
// 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) {
switch (gSaveContext.language) {
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));
} else if (gSaveContext.n64ddFlag && textId == 0x70CC) {
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 {
msgCtx->msgLength = font->msgLength = CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf));
msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf));
}
} else {
msgCtx->msgLength = font->msgLength;
@ -2237,14 +2237,14 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) {
}
} else {
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;
} else if (msgCtx->msgMode == MSGMODE_SONG_DEMONSTRATION_STARTING) {
msgCtx->stateTimer = 20;
msgCtx->msgMode = MSGMODE_SONG_DEMONSTRATION_SELECT_INSTRUMENT;
} else {
func_800ECC04((1 << (msgCtx->ocarinaAction + 0x11)) + 0x8000);
func_800ECC04((1 << ((msgCtx->ocarinaAction + 0x11) % 32)) + 0x8000);
// "Performance Check"
osSyncPrintf("演奏チェック=%d\n", msgCtx->ocarinaAction - OCARINA_ACTION_PLAYBACK_MINUET);
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.
*/
void Message_DrawDebugVariableChanged(s16* var, GraphicsContext* gfxCtx) {
if (!CVar_GetS32("gDebugEnabled", 0)) { return; }
static s16 sVarLastValue = 0;
static s16 sFillTimer = 0;
s32 pad;

View File

@ -1710,6 +1710,8 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
} else {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
}
} else {
gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS];
}
return ITEM_NONE;
} else if (item == ITEM_KEY_SMALL) {
@ -1808,13 +1810,13 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
return ITEM_NONE;
} else if (item == ITEM_WALLET_ADULT) {
Inventory_ChangeUpgrade(UPG_WALLET, 1);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) {
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(200);
}
return ITEM_NONE;
} else if (item == ITEM_WALLET_GIANT) {
Inventory_ChangeUpgrade(UPG_WALLET, 2);
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_FULL_WALLETS)) {
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(500);
}
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) &&
!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);
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) &&
CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) && player != NULL &&
!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);
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.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC) && player != NULL &&
!Player_InBlockingCsMode(globalCtx, player)) {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(check, GI_SONG_OF_TIME);
GiveItemWithoutActor(globalCtx, getItemId);
Flags_SetEventChkInf(0xAC);
}
@ -238,7 +238,7 @@ void GivePlayerRandoRewardZeldaLightArrowsGift(GlobalContext* globalCtx, Randomi
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TOKINOMA) &&
!Flags_GetTreasure(globalCtx, 0x1E) && player != NULL && !Player_InBlockingCsMode(globalCtx, player) &&
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);
Flags_SetTreasure(globalCtx, 0x1E);
}
@ -247,7 +247,7 @@ void GivePlayerRandoRewardZeldaLightArrowsGift(GlobalContext* globalCtx, Randomi
void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck check) {
Player* player = GET_PLAYER(globalCtx);
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)) &&
player != NULL && !Player_InBlockingCsMode(globalCtx, player)) {
@ -271,7 +271,7 @@ void Gameplay_Init(GameState* thisx) {
u8 tempSetupIndex;
s32 pad[2];
if (gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_SKIP_CHILD_STEALTH)) {
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH)) {
if (gSaveContext.entranceIndex == 0x7A) {
gSaveContext.entranceIndex = 0x400;
} else if (gSaveContext.entranceIndex == 0x296) {
@ -530,6 +530,10 @@ void Gameplay_Update(GlobalContext* globalCtx) {
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[5] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[globalCtx->objectCtx.subKeepIndex].segment);
gSegments[2] = VIRTUAL_TO_PHYSICAL(globalCtx->sceneSegment);

View File

@ -416,7 +416,7 @@ void GiveLinkDungeonReward(GetItemID getItemId) {
}
void GiveLinksPocketMedallion() {
GetItemID getItemId = GetRandomizedItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
GetItemID getItemId = Randomizer_GetItemIdFromKnownCheck(RC_LINKS_POCKET, RG_NONE);
GiveLinkDungeonReward(getItemId);
}
@ -644,7 +644,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
// Give Link's pocket item
GiveLinksPocketMedallion();
int openForest = GetRandoSettingValue(RSK_FOREST);
int openForest = Randomizer_GetSettingValue(RSK_FOREST);
switch (openForest) {
case 0: // closed
break;
@ -657,28 +657,28 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
break;
}
int doorOfTime = GetRandoSettingValue(RSK_DOOR_OF_TIME);
int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME);
switch (doorOfTime) {
case 0: // open
gSaveContext.eventChkInf[4] |= 0x800;
break;
}
int kakGate = GetRandoSettingValue(RSK_KAK_GATE);
int kakGate = Randomizer_GetSettingValue(RSK_KAK_GATE);
switch (kakGate) {
case 1: // open
gSaveContext.infTable[7] |= 0x40;
break;
}
if(GetRandoSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword();
if(GetRandoSettingValue(RSK_STARTING_DEKU_SHIELD)) GiveLinkDekuShield();
if(Randomizer_GetSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword();
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;
}
if(GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES)) {
if(Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES)) {
uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2;
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);
GiveLinkDekuNuts(20);
}
if(GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA)) {
s32 giid = GetRandomizedItemIdFromKnownCheck(RC_SONG_FROM_IMPA, GI_ZELDAS_LULLABY);
if(Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) {
s32 giid = Randomizer_GetItemIdFromKnownCheck(RC_SONG_FROM_IMPA, GI_ZELDAS_LULLABY);
if(giid >= GI_ZELDAS_LULLABY && giid <= GI_PRELUDE_OF_LIGHT) {
GiveLinkSong(giid);
@ -780,7 +780,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
} else if (giid == GI_DOUBLE_DEFENSE) {
GiveLinkDoubleDefense();
} else {
s32 iid = GetItemIDFromGetItemID(giid);
s32 iid = Randomizer_GetItemIDFromGetItemID(giid);
if (iid != -1) INV_CONTENT(iid) = iid;
}
@ -801,18 +801,18 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
}
if (GetRandoSettingValue(RSK_FULL_WALLETS)) {
if (Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
GiveLinkRupees(9001);
}
// 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;
}
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);
}
@ -826,6 +826,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
// Go away ruto (water temple first cutscene)
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
// this also makes the lower jaw render, and the eyes react to explosives
Flags_SetEventChkInf(0xB0);
@ -834,7 +839,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.infTable[25] |= 0x20;
// 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] |= 4;
gSaveContext.eventChkInf[9] |= 8;
@ -853,14 +858,14 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
}
// open gerudo fortress
if (GetRandoSettingValue(RSK_GERUDO_FORTRESS) == 2) {
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == 2) {
gSaveContext.eventChkInf[9] |= 1;
gSaveContext.sceneFlags[12].swch |= (1 << 0x01);
gSaveContext.sceneFlags[12].swch |= (1 << 0x05);
gSaveContext.sceneFlags[12].swch |= (1 << 0x11);
gSaveContext.sceneFlags[12].collect |= (1 << 0x0C);
if (!GetRandoSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
GiveLinkGerudoCard();
}
}

View File

@ -69,7 +69,7 @@ const ActorInit Bg_Dy_Yoseizo_InitVars = {
void GivePlayerRandoRewardGreatFairy(BgDyYoseizo* this, GlobalContext* 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) &&
!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;
if (((gSaveContext.infTable[7] & 0x40) ||
(!gSaveContext.n64ddFlag && (gSaveContext.eventChkInf[4] & 0x20)) ||
(gSaveContext.n64ddFlag && GetRandoSettingValue(RSK_KAK_GATE))) &&
(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_KAK_GATE))) &&
(globalCtx->sceneNum == SCENE_SPOT01)) {
thisx->world.pos.x = -89.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);
int bridge = GetRandoSettingValue(RSK_RAINBOW_BRIDGE);
int bridge = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE);
if (gSaveContext.eventChkInf[4] & 0x2000 || (gSaveContext.n64ddFlag && bridge == 0)) {
this->actionFunc = func_808787A4;
} else {
@ -176,12 +176,12 @@ void BgGjyoBridge_TriggerCutscene(BgGjyoBridge* this, GlobalContext* globalCtx)
LaunchBridgeCutscene(this, globalCtx);
}
} else {
int bridge = GetRandoSettingValue(RSK_RAINBOW_BRIDGE);
int bridgeStoneCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_STONE_COUNT);
int bridgeMedallionCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT);
int bridgeRewardCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_REWARD_COUNT);
int bridgeDungeonCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT);
int bridgeTokenCount = GetRandoSettingValue(RSK_RAINBOW_BRIDGE_TOKEN_COUNT);
int bridge = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE);
int bridgeStoneCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_STONE_COUNT);
int bridgeMedallionCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT);
int bridgeRewardCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_REWARD_COUNT);
int bridgeDungeonCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT);
int bridgeTokenCount = Randomizer_GetSettingValue(RSK_RAINBOW_BRIDGE_TOKEN_COUNT);
if (CheckPlayerPosition(player, globalCtx)) {
switch (bridge) {

View File

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

View File

@ -899,12 +899,12 @@ void func_80986BF8(DemoIm* this, GlobalContext* globalCtx) {
}
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 &&
!Flags_GetTreasure(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);
} else if (!Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) {
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.z = (s16)((Rand_ZeroOne() - 0.5f) * 16.0f * temp_f22);
this->unk_150[i].unk_23 = 0;
this->unk_150[i].unk_22++;
// 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++;
}
case 1:
if (this->actor.params == DEMOKANKYO_WARP_OUT) {
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;
if (gSaveContext.n64ddFlag) {
int trialsToComplete = GetRandoSettingValue(RSK_TRIAL_COUNT);
int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT);
if (trialsToComplete <= TrialsDoneCount()) {
Actor_Kill(thisx);
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) {
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 &&
!Flags_GetTreasure(globalCtx, 0x1F)) {

View File

@ -127,7 +127,7 @@ void func_809B0558(EnAni* this, GlobalContext* globalCtx) {
gSaveContext.itemGetInf[1] |= 0x20;
} else {
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);
} else {
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) {
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);
} else {
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) {
case EXITEM_BOMB_BAG_BOWLING:
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;
case EXITEM_HEART_PIECE_BOWLING:
this->getItemId =
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
break;
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;
}
}

View File

@ -421,7 +421,7 @@ void EnBox_WaitOpen(EnBox* this, GlobalContext* globalCtx) {
Flags_SetTreasure(globalCtx, this->dyna.actor.params & 0x1F);
// 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((this->dyna.actor.params & 0xF) < 2) {
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);
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)) {
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
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((this->dyna.actor.params & 0xF) < 2) {
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)) ||
(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,
globalCtx->sceneNum) == GI_ICE_TRAP)) &&
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))) {
Message_CloseTextbox(globalCtx);
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;
}
}
@ -463,7 +463,7 @@ void func_809EEA90(EnDivingGame* this, GlobalContext* globalCtx) {
if (Actor_HasParent(&this->actor, globalCtx)) {
this->actionFunc = func_809EEAF8;
} 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) {
if (this->actor.params == 0x9) {
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) {
func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f);
} else {
@ -379,14 +379,14 @@ void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) {
}
} else if (this->actor.params == 0xA) {
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) {
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f);
} else {
func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f);
}
} 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)) {
case PLAYER_MASK_SKULL:
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);
}
break;
case PLAYER_MASK_TRUTH:
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);
}
break;

View File

@ -548,7 +548,7 @@ void func_809FEC70(EnDu* this, GlobalContext* globalCtx) {
EnDu_SetupAction(this, func_809FECE4);
} else {
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:
this->unk_17C = func_8002EBCC;
if (gSaveContext.n64ddFlag) {
this->giDrawId = GetItemModelFromId(
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20));
this->giDrawId = Randomizer_GetItemModelFromId(
Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20));
} else {
this->giDrawId = GID_BOMB_BAG_30;
}
@ -173,8 +173,8 @@ void EnExItem_WaitForObject(EnExItem* this, GlobalContext* globalCtx) {
case EXITEM_BOMBCHUS_BOWLING:
this->unk_17C = func_8002EBCC;
if (gSaveContext.n64ddFlag) {
this->giDrawId = GetItemModelFromId(
GetRandomizedItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10));
this->giDrawId = Randomizer_GetItemModelFromId(
Randomizer_GetItemIdFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10));
} else {
this->giDrawId = GID_BOMBCHU;
}
@ -229,7 +229,7 @@ void EnExItem_WaitForObject(EnExItem* this, GlobalContext* globalCtx) {
this->scale = 0.5f;
this->unkFloat = 0.5f;
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) {
case EXITEM_GREEN_RUPEE_CHEST:
this->giDrawId = GID_RUPEE_GREEN;
@ -404,7 +404,7 @@ void EnExItem_TargetPrizeApproach(EnExItem* this, GlobalContext* globalCtx) {
this->actor.parent = NULL;
if (gSaveContext.n64ddFlag) {
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 {
if (CUR_UPG_VALUE(UPG_BULLET_BAG) == 1) {
getItemId = GI_BULLET_BAG_40;
@ -424,7 +424,7 @@ void EnExItem_TargetPrizeGive(EnExItem* this, GlobalContext* globalCtx) {
this->actionFunc = EnExItem_TargetPrizeFinish;
} else {
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 {
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) {
case EXITEM_BOMB_BAG_BOWLING:
case EXITEM_BOMB_BAG_COUNTER:
randoGetItemId = GetRandomizedItemIdFromKnownCheck(
randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20);
break;
case EXITEM_BOMBCHUS_BOWLING:
case EXITEM_BOMBCHUS_COUNTER:
randoGetItemId = GetRandomizedItemIdFromKnownCheck(
randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10);
break;
}
@ -532,12 +532,12 @@ void EnExItem_DrawHeartPiece(EnExItem* this, GlobalContext* globalCtx) {
func_8002ED80(&this->actor, globalCtx, 0);
if (gSaveContext.n64ddFlag) {
s32 randoGetItemId = GetRandomizedItemIdFromKnownCheck(
s32 randoGetItemId = Randomizer_GetItemIdFromKnownCheck(
RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
if (randoGetItemId >= GI_MINUET_OF_FOREST && randoGetItemId <= GI_DOUBLE_DEFENSE) {
EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemId);
}
GetItem_Draw(globalCtx, GetItemModelFromId(randoGetItemId));
GetItem_Draw(globalCtx, Randomizer_GetItemModelFromId(randoGetItemId));
} else {
GetItem_Draw(globalCtx, GID_HEART_PIECE);
}

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