Merge branch 'develop-zhora' of https://github.com/HarbourMasters/Shipwright into get-item-rework

This commit is contained in:
Christopher Leggett 2022-08-10 20:23:27 -04:00
commit 17c9ce7804
No known key found for this signature in database
GPG Key ID: 7093AE5FF7037D79
94 changed files with 2154 additions and 1095 deletions

View File

@ -2,9 +2,27 @@
## Windows ## Windows
1. Requires Visual Studio 2022 Community Edition && `python3, cmake, git` (can be installed via chocolatey or manually) Requires:
2. Clone the Ship of Harkinian repository * At least 8GB of RAM (machines with 4GB have seen complier failures)
3. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice * Visual Studio 2022 Community Edition with the C++ feature set
* One of the Windows SDKs that comes with Visual Studio, for example the current Windows 10 version 10.0.19041.0
* The `MSVC v142 - VS 2019 C++ build tools` component of Visual Studio
* Python 3 (can be installed manually or as part of Visual Studio)
* Git (can be installed manually or as part of Visual Studio)
* Cmake (can be installed via chocolatey or manually)
During installation, check the "Desktop development with C++" feature set:
![image](https://user-images.githubusercontent.com/30329717/183511274-d11aceea-7900-46ec-acb6-3f2cc110021a.png)
Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v142 toolset.
You can also find the v142 toolset by searching through the individual components tab:
![image](https://user-images.githubusercontent.com/30329717/183521169-ead6a73b-a1bf-4e99-aab8-441746d8f08e.png)
While you're there, you can also install Python 3 and Git if needed.
1. Clone the Ship of Harkinian repository
2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice
_Note: Instructions assume using powershell_ _Note: Instructions assume using powershell_
```powershell ```powershell
@ -30,8 +48,10 @@ With the cmake build system you have two options for working on the project:
#### Visual Studio #### Visual Studio
To develop using Visual Studio you only need to use cmake to generate the solution file: To develop using Visual Studio you only need to use cmake to generate the solution file:
```powershell ```powershell
# Generates Ship.sln at `build/x64` # Generates Ship.sln at `build/x64` for Visual Studio 2022
& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64 & 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v142 -A x64
# or for Visual Studio 2019
& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 16 2019" -T v142 -A x64
``` ```
#### Visual Studio Code or another editor #### Visual Studio Code or another editor
@ -53,7 +73,7 @@ cd "build/x64"
``` ```
## Linux ## Linux
1. Requires `gcc >= 10, x11, curl, python3, sdl2 >= 2.0.22, libpng, glew >= 2.2, ninja, cmake, lld` Requires `gcc >= 10, x11, curl, python3, sdl2 >= 2.0.22, libpng, glew >= 2.2, ninja, cmake, lld`
**Important: For maximum performance make sure you have ninja build tools installed!** **Important: For maximum performance make sure you have ninja build tools installed!**
@ -91,7 +111,7 @@ cpack -G External (creates appimage)
``` ```
## macOS ## macOS
1. Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc) Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake` (can be installed via homebrew, macports, etc)
**Important: For maximum performance make sure you have ninja build tools installed!** **Important: For maximum performance make sure you have ninja build tools installed!**

5
CMake/genscript.cmake Normal file
View File

@ -0,0 +1,5 @@
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/extract_assets.py filedata)
string(REGEX REPLACE "zapd_exe = .*exec_cmd =" "zapd_exe = \"${program}\"\n exec_cmd =" filedata "${filedata}")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/extract_assets_cmake2.py" "${filedata}")
file(CHMOD "${CMAKE_CURRENT_SOURCE_DIR}/extract_assets_cmake2.py" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

View File

@ -45,11 +45,16 @@ endif()
################################################################################ ################################################################################
# Global configuration types # Global configuration types
################################################################################ ################################################################################
set(CMAKE_CONFIGURATION_TYPES if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
"Debug" set(CMAKE_C_FLAGS_DEBUG "-O3 -ffast-math")
"Release" set(CMAKE_CXX_FLAGS_DEBUG "-O3 -ffast-math")
CACHE STRING "" FORCE set(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG")
) set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG")
else()
set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_OBJCXX_FLAGS_RELEASE "-O2 -DNDEBUG")
endif()
if(NOT CMAKE_BUILD_TYPE ) if(NOT CMAKE_BUILD_TYPE )
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE)
@ -129,25 +134,19 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
INSTALL(PROGRAMS "${CMAKE_SOURCE_DIR}/scripts/linux/appimage/soh.sh" DESTINATION . COMPONENT appimage) INSTALL(PROGRAMS "${CMAKE_SOURCE_DIR}/scripts/linux/appimage/soh.sh" DESTINATION . COMPONENT appimage)
endif() endif()
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py filedata)
string(REGEX REPLACE "../ZAPDTR/ZAPD.out" "${CMAKE_BINARY_DIR}/ZAPD/ZAPD.out" filedata "${filedata}")
string(REGEX REPLACE "x64" "..\\\\\\\\x64" filedata "${filedata}")
string(REGEX REPLACE "Release" "${CMAKE_BUILD_TYPE}" filedata "${filedata}")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py" "${filedata}")
file(CHMOD "${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
find_package(Python3 COMPONENTS Interpreter) find_package(Python3 COMPONENTS Interpreter)
add_custom_target( add_custom_target(
ExtractAssets ExtractAssets
COMMAND ${CMAKE_COMMAND} -Dprogram=$<TARGET_FILE:ZAPD> -P ${CMAKE_SOURCE_DIR}/CMake/genscript.cmake
COMMAND ${CMAKE_COMMAND} -E rm -f oot.otr COMMAND ${CMAKE_COMMAND} -E rm -f oot.otr
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py
COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_BINARY_DIR}/soh COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${CMAKE_BINARY_DIR}/soh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
COMMENT "Running asset extraction..." COMMENT "Running asset extraction..."
DEPENDS ZAPD DEPENDS ZAPD
BYPRODUCTS oot.otr ${CMAKE_SOURCE_DIR}/oot.otr ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets_cmake2.py
) )
if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(CMAKE_SYSTEM_NAME MATCHES "Linux")

68
Jenkinsfile vendored
View File

@ -8,12 +8,35 @@ pipeline {
} }
stages { stages {
stage('Generate Assets') {
options {
timeout(time: 10)
}
agent {
label "SoH-Mac-Builders"
}
steps {
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
extensions: scm.extensions,
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-cmake --target ExtractAssets --config Release
'''
stash includes: 'soh/assets/**/*', name: 'assets'
}
}
}
stage('Build SoH') { stage('Build SoH') {
parallel { parallel {
stage ('Build Windows') { stage ('Build Windows') {
options {
timeout(time: 20)
}
environment { environment {
PLATFORM='x64' PLATFORM='x64'
PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe' PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe'
@ -34,12 +57,9 @@ pipeline {
]) ])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
bat """ unstash 'assets'
bat """
xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\"
"${env.CMAKE}" -S . -B "build\\${env.PLATFORM}" -G "Visual Studio 17 2022" -T ${env.TOOLSET} -A ${env.PLATFORM} -D Python_EXECUTABLE=${env.PYTHON} -D CMAKE_BUILD_TYPE:STRING=Release "${env.CMAKE}" -S . -B "build\\${env.PLATFORM}" -G "Visual Studio 17 2022" -T ${env.TOOLSET} -A ${env.PLATFORM} -D Python_EXECUTABLE=${env.PYTHON} -D CMAKE_BUILD_TYPE:STRING=Release
"${env.CMAKE}" --build ".\\build\\${env.PLATFORM}" --target ExtractAssets --config Release
"${env.CMAKE}" --build ".\\build\\${env.PLATFORM}" --config Release "${env.CMAKE}" --build ".\\build\\${env.PLATFORM}" --config Release
cd ".\\build\\${env.PLATFORM}" cd ".\\build\\${env.PLATFORM}"
"${env.CPACK}" -G ZIP "${env.CPACK}" -G ZIP
@ -47,8 +67,8 @@ pipeline {
move "_packages\\*.zip" "soh.zip" move "_packages\\*.zip" "soh.zip"
""" """
archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true
} }
archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true
} }
post { post {
always { always {
@ -57,9 +77,6 @@ pipeline {
} }
} }
stage ('Build Linux') { stage ('Build Linux') {
options {
timeout(time: 20)
}
agent { agent {
label "SoH-Linux-Builders" label "SoH-Linux-Builders"
} }
@ -72,9 +89,9 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs userRemoteConfigs: scm.userRemoteConfigs
]) ])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
unstash 'assets'
sh ''' sh '''
if docker ps -aq --filter "name=sohcont" | grep -q .; then docker rm -f sohcont; fi
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
docker build . -t soh docker build . -t soh
docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash
docker exec sohcont scripts/linux/appimage/build.sh docker exec sohcont scripts/linux/appimage/build.sh
@ -86,11 +103,12 @@ pipeline {
''' '''
} }
sh 'sudo docker container stop sohcont'
archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true
} }
post { post {
always { always {
sh 'sudo docker container stop sohcont'
sh 'docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi' // Clean dangling docker images
step([$class: 'WsCleanup']) // Clean workspace step([$class: 'WsCleanup']) // Clean workspace
} }
} }
@ -108,11 +126,9 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs userRemoteConfigs: scm.userRemoteConfigs
]) ])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
unstash 'assets'
sh ''' sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cmake --build build-cmake --target ExtractAssets --
cmake --build build-cmake --config Release -- cmake --build build-cmake --config Release --
(cd build-cmake && cpack) (cd build-cmake && cpack)
@ -131,9 +147,6 @@ pipeline {
} }
} }
stage ('Build Switch') { stage ('Build Switch') {
options {
timeout(time: 20)
}
agent { agent {
label "SoH-Linux-Builders" label "SoH-Linux-Builders"
} }
@ -146,12 +159,12 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs userRemoteConfigs: scm.userRemoteConfigs
]) ])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh ''' unstash 'assets'
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 if docker ps -aq --filter "name=sohswitchcont" | grep -q .; then docker rm -f sohswitchcont; fi
docker build . -t sohswitch docker build . -t sohswitch
docker run --name sohcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash docker run --name sohswitchcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash
docker exec sohcont scripts/switch/build.sh docker exec sohswitchcont scripts/switch/build.sh
mv build-switch/soh/*.nro soh.nro mv build-switch/soh/*.nro soh.nro
mv README.md readme.txt mv README.md readme.txt
@ -160,11 +173,12 @@ pipeline {
''' '''
} }
sh 'sudo docker container stop sohcont'
archiveArtifacts artifacts: 'soh-switch.7z', followSymlinks: false, onlyIfSuccessful: true archiveArtifacts artifacts: 'soh-switch.7z', followSymlinks: false, onlyIfSuccessful: true
} }
post { post {
always { always {
sh 'sudo docker container stop sohswitchcont'
sh 'docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi' // Clean dangling docker images
step([$class: 'WsCleanup']) // Clean workspace step([$class: 'WsCleanup']) // Clean workspace
} }
} }

View File

@ -348,11 +348,14 @@ std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string&
str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str()); str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str());
if (nameSet && nameSet->find(name) == nameSet->end()) { if (nameSet && nameSet->find(name) == nameSet->end()) {
str += StringHelper::Sprintf(R"(
#ifdef _WIN32 #ifdef _WIN32
str += StringHelper::Sprintf("\nstatic const __declspec(align(2)) char %s[] = d%s;", name.c_str(), name.c_str()); static const __declspec(align(2)) char %s[] = d%s;
#else #else
str += StringHelper::Sprintf("\nstatic const char %s[] __attribute__((aligned (2))) = d%s;", name.c_str(), name.c_str()); static const char %s[] __attribute__((aligned (2))) = d%s;
#endif #endif
)", name.c_str(), name.c_str(), name.c_str(), name.c_str());
if (nameSet) { if (nameSet) {
nameSet->insert(name); nameSet->insert(name);
} }

View File

@ -1,39 +1,35 @@
#include "Console.h" #include "Console.h"
#include <iostream>
#include <sstream>
#include "Cvar.h" #include "Cvar.h"
#include "GlobalCtx2.h" #include "GlobalCtx2.h"
#include "ImGuiImpl.h" #include "ImGuiImpl.h"
#include "Lib/ImGui/imgui.h" #include "Lib/ImGui/imgui.h"
#include "Utils/StringHelper.h" #include "Utils/StringHelper.h"
#include "Lib/ImGui/imgui_internal.h" #include "Lib/ImGui/imgui_internal.h"
#include "Utils.h"
namespace Ship { namespace Ship {
std::map<ImGuiKey, std::string> Bindings; std::string BuildUsage(const CommandEntry& entry) {
std::map<ImGuiKey, std::string> BindingToggle; std::string usage;
for (const auto& arg : entry.arguments)
usage += StringHelper::Sprintf(arg.optional ? "[%s] " : "<%s> ", arg.info.c_str());
return usage;
}
static bool HelpCommand(const std::vector<std::string>&) { bool Console::HelpCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
INFO("SoH Commands:"); Console->SendInfoMessage("SoH Commands:");
for (const auto& cmd : SohImGui::console->Commands) { for (const auto& cmd : Console->Commands) {
INFO("%s", (" - " + cmd.first).c_str()); Console->SendInfoMessage(" - " + cmd.first);
} }
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool ClearCommand(const std::vector<std::string>&) { bool Console::ClearCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
SohImGui::console->Log[SohImGui::console->selected_channel].clear(); Console->ClearLogs(Console->GetCurrentChannel());
return CMD_SUCCESS; return CMD_SUCCESS;
} }
std::string toLowerCase(std::string in) { bool Console::BindCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
std::string cpy(in);
std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower);
return cpy;
}
static bool BindCommand(const std::vector<std::string>& args) {
if (args.size() > 2) { if (args.size() > 2) {
const ImGuiIO* io = &ImGui::GetIO();; const ImGuiIO* io = &ImGui::GetIO();;
for (size_t k = 0; k < std::size(io->KeysData); k++) { for (size_t k = 0; k < std::size(io->KeysData); k++) {
@ -44,8 +40,8 @@ namespace Ship {
const char* const delim = " "; const char* const delim = " ";
std::ostringstream imploded; std::ostringstream imploded;
std::copy(args.begin() + 2, args.end(), std::ostream_iterator<std::string>(imploded, delim)); std::copy(args.begin() + 2, args.end(), std::ostream_iterator<std::string>(imploded, delim));
Bindings[k] = imploded.str(); Console->Bindings[k] = imploded.str();
INFO("Binding '%s' to %s", args[1].c_str(), Bindings[k].c_str()); Console->SendInfoMessage("Binding '%s' to %s", args[1].c_str(), Console->Bindings[k].c_str());
break; break;
} }
} }
@ -53,15 +49,15 @@ namespace Ship {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool BindToggleCommand(const std::vector<std::string>& args) { bool Console::BindToggleCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
if (args.size() > 2) { if (args.size() > 2) {
const ImGuiIO* io = &ImGui::GetIO();; const ImGuiIO* io = &ImGui::GetIO();;
for (size_t k = 0; k < std::size(io->KeysData); k++) { for (size_t k = 0; k < std::size(io->KeysData); k++) {
std::string key(ImGui::GetKeyName(k)); std::string key(ImGui::GetKeyName(k));
if (toLowerCase(args[1]) == toLowerCase(key)) { if (toLowerCase(args[1]) == toLowerCase(key)) {
BindingToggle[k] = args[2]; Console->BindingToggle[k] = args[2];
INFO("Binding toggle '%s' to %s", args[1].c_str(), BindingToggle[k].c_str()); Console->SendInfoMessage("Binding toggle '%s' to %s", args[1].c_str(), Console->BindingToggle[k].c_str());
break; break;
} }
} }
@ -69,22 +65,15 @@ namespace Ship {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
std::string BuildUsage(const CommandEntry& entry) {
std::string usage;
for (const auto& arg : entry.arguments)
usage += StringHelper::Sprintf(arg.optional ? "[%s] " : "<%s> ", arg.info.c_str());
return usage;
}
void Console::Init() { void Console::Init() {
this->InputBuffer = new char[MAX_BUFFER_SIZE]; this->inputBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->InputBuffer, ""); strcpy(this->inputBuffer, "");
this->FilterBuffer = new char[MAX_BUFFER_SIZE]; this->filterBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->FilterBuffer, ""); strcpy(this->filterBuffer, "");
this->Commands["help"] = { HelpCommand, "Shows all the commands" }; AddCommand("help", { HelpCommand, "Shows all the commands" });
this->Commands["clear"] = { ClearCommand, "Clear the console history" }; AddCommand("clear", { ClearCommand, "Clear the console history" });
this->Commands["bind"] = { BindCommand, "Binds key to commands" }; AddCommand("bind", { BindCommand, "Binds key to commands" });
this->Commands["bind-toggle"] = { BindToggleCommand, "Bind key as a bool toggle" }; AddCommand("bind-toggle", { BindToggleCommand, "Bind key as a bool toggle" });
} }
void Console::Update() { void Console::Update() {
@ -100,17 +89,21 @@ namespace Ship {
} }
void Console::Draw() { void Console::Draw() {
if (!this->opened) {
CVar_SetS32("gConsoleEnabled", 0);
return;
}
bool input_focus = false; bool input_focus = false;
if (!this->opened) return;
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); ImGui::Begin("Console", &this->opened, ImGuiWindowFlags_NoFocusOnAppearing);
const ImVec2 pos = ImGui::GetWindowPos(); const ImVec2 pos = ImGui::GetWindowPos();
const ImVec2 size = ImGui::GetWindowSize(); const ImVec2 size = ImGui::GetWindowSize();
// SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole); // SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole);
// Renders autocomplete window // Renders autocomplete window
if (this->OpenAutocomplete) { if (this->openAutocomplete) {
ImGui::SetNextWindowSize(ImVec2(350, std::min(static_cast<int>(this->Autocomplete.size()), 3) * 20.f), ImGuiCond_Once); ImGui::SetNextWindowSize(ImVec2(350, std::min(static_cast<int>(this->Autocomplete.size()), 3) * 20.f), ImGuiCond_Once);
ImGui::SetNextWindowPos(ImVec2(pos.x + 8, pos.y + size.y - 1)); ImGui::SetNextWindowPos(ImVec2(pos.x + 8, pos.y + size.y - 1));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3));
@ -125,16 +118,16 @@ namespace Ship {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
if (ImGui::Selectable(preview.c_str())) { if (ImGui::Selectable(preview.c_str())) {
memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); memset(this->inputBuffer, 0, MAX_BUFFER_SIZE);
memcpy(this->InputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size()); memcpy(this->inputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size());
this->OpenAutocomplete = false; this->openAutocomplete = false;
input_focus = true; input_focus = true;
} }
} }
ImGui::EndTable(); ImGui::EndTable();
} }
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
this->OpenAutocomplete = false; this->openAutocomplete = false;
} }
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::EndChild(); ImGui::EndChild();
@ -144,7 +137,7 @@ namespace Ship {
if (ImGui::BeginPopupContextWindow("Context Menu")) { if (ImGui::BeginPopupContextWindow("Context Menu")) {
if (ImGui::MenuItem("Copy Text")) { if (ImGui::MenuItem("Copy Text")) {
ImGui::SetClipboardText(this->Log[this->selected_channel][this->selectedId].text.c_str()); ImGui::SetClipboardText(this->Log[this->currentChannel][this->selectedId].text.c_str());
this->selectedId = -1; this->selectedId = -1;
} }
ImGui::EndPopup(); ImGui::EndPopup();
@ -154,34 +147,44 @@ namespace Ship {
} }
// Renders top bar filters // Renders top bar filters
if (ImGui::Button("Clear")) this->Log[this->selected_channel].clear(); if (ImGui::Button("Clear")) this->Log[this->currentChannel].clear();
ImGui::SameLine();
ImGui::SetNextItemWidth(150); if (CVar_GetS32("gSinkEnabled", 0)) {
if (ImGui::BeginCombo("##channel", this->selected_channel.c_str())) { ImGui::SameLine();
for (const auto& channel : log_channels) { ImGui::SetNextItemWidth(150);
const bool is_selected = (channel == std::string(this->selected_channel)); if (ImGui::BeginCombo("##channel", this->currentChannel.c_str())) {
if (ImGui::Selectable(channel.c_str(), is_selected)) for (const auto& channel : LogChannels) {
this->selected_channel = channel; const bool is_selected = (channel == std::string(this->currentChannel));
if (is_selected) ImGui::SetItemDefaultFocus(); if (ImGui::Selectable(channel.c_str(), is_selected))
this->currentChannel = channel;
if (is_selected) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
} }
ImGui::EndCombo(); } else {
this->currentChannel = "Console";
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(150); ImGui::SetNextItemWidth(150);
if (ImGui::BeginCombo("##level", this->level_filter.c_str())) {
for (const auto& filter : priority_filters) { if (this->currentChannel != "Console") {
const bool is_selected = (filter == std::string(this->level_filter)); if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->levelFilter).data())) {
if (ImGui::Selectable(filter.c_str(), is_selected)) for (const auto& priority_filter : PriorityFilters) {
{ const bool is_selected = priority_filter == this->levelFilter;
this->level_filter = filter; if (ImGui::Selectable(spdlog::level::to_string_view(priority_filter).data(), is_selected))
if (is_selected) ImGui::SetItemDefaultFocus(); {
this->levelFilter = priority_filter;
if (is_selected) ImGui::SetItemDefaultFocus();
}
} }
ImGui::EndCombo();
} }
ImGui::EndCombo(); } else {
this->levelFilter = spdlog::level::trace;
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushItemWidth(-1); ImGui::PushItemWidth(-1);
if (ImGui::InputTextWithHint("##input", "Filter", this->FilterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->FilterBuffer); if (ImGui::InputTextWithHint("##input", "Filter", this->filterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->filterBuffer);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
// Renders console history // Renders console history
@ -195,16 +198,16 @@ namespace Ship {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
if (this->selectedId > 0)--this->selectedId; if (this->selectedId > 0)--this->selectedId;
const std::vector<ConsoleLine> channel = this->Log[this->selected_channel]; const std::vector<ConsoleLine> channel = this->Log[this->currentChannel];
for (int i = 0; i < static_cast<int>(channel.size()); i++) { for (int i = 0; i < static_cast<int>(channel.size()); i++) {
ConsoleLine line = channel[i]; ConsoleLine line = channel[i];
if (!this->filter.empty() && line.text.find(this->filter) == std::string::npos) continue; if (!this->filter.empty() && line.text.find(this->filter) == std::string::npos) continue;
if (this->level_filter != NULLSTR && line.priority != (std::find(priority_filters.begin(), priority_filters.end(), this->level_filter) - priority_filters.begin()) - 1) continue; if (this->levelFilter > line.priority) continue;
std::string id = line.text + "##" + std::to_string(i); std::string id = line.text + "##" + std::to_string(i);
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
const bool is_selected = (this->selectedId == i) || std::find(this->selectedEntries.begin(), this->selectedEntries.end(), i) != this->selectedEntries.end(); const bool is_selected = (this->selectedId == i) || std::find(this->selectedEntries.begin(), this->selectedEntries.end(), i) != this->selectedEntries.end();
ImGui::PushStyleColor(ImGuiCol_Text, this->priority_colors[line.priority]); ImGui::PushStyleColor(ImGuiCol_Text, this->PriorityColours[line.priority]);
if (ImGui::Selectable(id.c_str(), is_selected)) { if (ImGui::Selectable(id.c_str(), is_selected)) {
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected) if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected)
this->selectedEntries.push_back(i); this->selectedEntries.push_back(i);
@ -222,60 +225,64 @@ namespace Ship {
ImGui::SetScrollHereY(1.0f); ImGui::SetScrollHereY(1.0f);
ImGui::EndChild(); ImGui::EndChild();
// Renders input textfield if (this->currentChannel == "Console") {
constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | // Renders input textfield
ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit |
ImGui::PushItemWidth(-53); ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
if (ImGui::InputTextWithHint("##CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { ImGui::PushItemWidth(-53);
input_focus = true; if (ImGui::InputTextWithHint("##CMDInput", ">", this->inputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) {
if (this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') input_focus = true;
this->Dispatch(std::string(this->InputBuffer)); if (this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ')
memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); this->Dispatch(std::string(this->inputBuffer));
} memset(this->inputBuffer, 0, MAX_BUFFER_SIZE);
if (this->CMDHint != NULLSTR) {
if (ImGui::IsItemFocused()) {
ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y + size.y));
ImGui::SameLine();
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(this->CMDHint.c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
} }
}
ImGui::SameLine(); if (this->cmdHint != NULLSTR) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50); if (ImGui::IsItemFocused()) {
if (ImGui::Button("Submit") && !input_focus && this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') { ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y + size.y));
this->Dispatch(std::string(this->InputBuffer)); ImGui::SameLine();
memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); ImGui::BeginTooltip();
} ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(this->cmdHint.c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
ImGui::SetItemDefaultFocus(); ImGui::SameLine();
if (input_focus) ImGui::SetKeyboardFocusHere(-1); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50);
ImGui::PopItemWidth(); if (ImGui::Button("Submit") && !input_focus && this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ') {
this->Dispatch(std::string(this->inputBuffer));
memset(this->inputBuffer, 0, MAX_BUFFER_SIZE);
}
ImGui::SetItemDefaultFocus();
if (input_focus) ImGui::SetKeyboardFocusHere(-1);
ImGui::PopItemWidth();
}
ImGui::End(); ImGui::End();
} }
void Console::Dispatch(const std::string& line) { void Console::Dispatch(const std::string& line) {
this->CMDHint = NULLSTR; this->cmdHint = NULLSTR;
this->History.push_back(line); this->History.push_back(line);
this->Log[this->selected_channel].push_back({ "> " + line }); SendInfoMessage("> " + line);
const std::vector<std::string> cmd_args = StringHelper::Split(line, " "); const std::vector<std::string> cmd_args = StringHelper::Split(line, " ");
if (this->Commands.contains(cmd_args[0])) { if (this->Commands.contains(cmd_args[0])) {
const CommandEntry entry = this->Commands[cmd_args[0]]; const CommandEntry entry = this->Commands[cmd_args[0]];
if (!entry.handler(cmd_args) && !entry.arguments.empty()) if (!entry.handler(shared_from_this(), cmd_args) && !entry.arguments.empty()) {
this->Log[this->selected_channel].push_back({ "[SOH] Usage: " + cmd_args[0] + " " + BuildUsage(entry), ERROR_LVL }); SendErrorMessage("[SOH] Usage: " + cmd_args[0] + " " + BuildUsage(entry));
}
return; return;
} }
this->Log[this->selected_channel].push_back({ "[SOH] Command not found", ERROR_LVL }); SendErrorMessage("[SOH] Command not found");
} }
int Console::CallbackStub(ImGuiInputTextCallbackData* data) { int Console::CallbackStub(ImGuiInputTextCallbackData* data) {
const auto instance = static_cast<Console*>(data->UserData); const auto instance = static_cast<Console*>(data->UserData);
const bool empty_history = instance->History.empty(); const bool empty_history = instance->History.empty();
const int history_index = instance->HistoryIndex; const int history_index = instance->historyIndex;
std::string history; std::string history;
switch (data->EventKey) { switch (data->EventKey) {
@ -283,51 +290,103 @@ namespace Ship {
instance->Autocomplete.clear(); instance->Autocomplete.clear();
for (auto& [cmd, entry] : instance->Commands) for (auto& [cmd, entry] : instance->Commands)
if (cmd.find(std::string(data->Buf)) != std::string::npos) instance->Autocomplete.push_back(cmd); if (cmd.find(std::string(data->Buf)) != std::string::npos) instance->Autocomplete.push_back(cmd);
instance->OpenAutocomplete = !instance->Autocomplete.empty(); instance->openAutocomplete = !instance->Autocomplete.empty();
instance->CMDHint = NULLSTR; instance->cmdHint = NULLSTR;
break; break;
case ImGuiKey_UpArrow: case ImGuiKey_UpArrow:
if (empty_history) break; if (empty_history) break;
if (history_index < static_cast<int>(instance->History.size()) - 1) instance->HistoryIndex += 1; if (history_index < static_cast<int>(instance->History.size()) - 1) instance->historyIndex += 1;
data->DeleteChars(0, data->BufTextLen); data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, instance->History[instance->HistoryIndex].c_str()); data->InsertChars(0, instance->History[instance->historyIndex].c_str());
instance->CMDHint = NULLSTR; instance->cmdHint = NULLSTR;
break; break;
case ImGuiKey_DownArrow: case ImGuiKey_DownArrow:
if (empty_history) break; if (empty_history) break;
if (history_index > -1) instance->HistoryIndex -= 1; if (history_index > -1) instance->historyIndex -= 1;
data->DeleteChars(0, data->BufTextLen); data->DeleteChars(0, data->BufTextLen);
if (history_index >= 0) if (history_index >= 0)
data->InsertChars(0, instance->History[history_index].c_str()); data->InsertChars(0, instance->History[history_index].c_str());
instance->CMDHint = NULLSTR; instance->cmdHint = NULLSTR;
break; break;
case ImGuiKey_Escape: case ImGuiKey_Escape:
instance->HistoryIndex = -1; instance->historyIndex = -1;
data->DeleteChars(0, data->BufTextLen); data->DeleteChars(0, data->BufTextLen);
instance->OpenAutocomplete = false; instance->openAutocomplete = false;
instance->CMDHint = NULLSTR; instance->cmdHint = NULLSTR;
break; break;
default: default:
instance->OpenAutocomplete = false; instance->openAutocomplete = false;
for (auto& [cmd, entry] : instance->Commands) { for (auto& [cmd, entry] : instance->Commands) {
const std::vector<std::string> cmd_args = StringHelper::Split(std::string(data->Buf), " "); const std::vector<std::string> cmd_args = StringHelper::Split(std::string(data->Buf), " ");
if (data->BufTextLen > 2 && !cmd_args.empty() && cmd.find(cmd_args[0]) != std::string::npos) { if (data->BufTextLen > 2 && !cmd_args.empty() && cmd.find(cmd_args[0]) != std::string::npos) {
instance->CMDHint = cmd + " " + BuildUsage(entry); instance->cmdHint = cmd + " " + BuildUsage(entry);
break; break;
} }
instance->CMDHint = NULLSTR; instance->cmdHint = NULLSTR;
} }
} }
return 0; return 0;
} }
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) { void Console::Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, va_list args) {
char buf[1024]; char buf[2048];
va_list args;
va_start(args, fmt);
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0; buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
this->Log[channel].push_back({ std::string(buf), priority }); this->Log[channel].push_back({ std::string(buf), priority });
} }
void Console::Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
Append(channel, priority, fmt, args);
va_end(args);
}
void Console::SendInfoMessage(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
Append("Console", spdlog::level::info, fmt, args);
va_end(args);
}
void Console::SendErrorMessage(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
Append("Console", spdlog::level::err, fmt, args);
va_end(args);
}
void Console::SendInfoMessage(const std::string& str) {
Append("Console", spdlog::level::info, str.c_str());
}
void Console::SendErrorMessage(const std::string& str) {
Append("Console", spdlog::level::err, str.c_str());
}
void Console::ClearLogs(std::string channel) {
Log[channel].clear();
}
void Console::ClearLogs() {
for (auto [key, var] : Log) {
var.clear();
}
}
bool Console::HasCommand(const std::string& command) {
for (const auto& Command : Commands) {
if (Command.first == command) {
return true;
}
}
return false;
}
void Console::AddCommand(const std::string& command, CommandEntry entry) {
if (!HasCommand(command)) {
Commands[command] = entry;
}
}
} }

View File

@ -6,25 +6,18 @@
#include <functional> #include <functional>
#include "Lib/ImGui/imgui.h" #include "Lib/ImGui/imgui.h"
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include "spdlog/spdlog.h"
namespace Ship { namespace Ship {
#define LOG(msg, ...) SohImGui::console->Append("Main", Ship::Priority::LOG_LVL, msg, ##__VA_ARGS__)
#define INFO(msg, ...) SohImGui::console->Append("Main", Ship::Priority::INFO_LVL, msg, ##__VA_ARGS__)
#define WARNING(msg, ...) SohImGui::console->Append("Main", Ship::Priority::WARNING_LVL, msg, ##__VA_ARGS__)
#define ERROR(msg, ...) SohImGui::console->Append("Main", Ship::Priority::ERROR_LVL, msg, ##__VA_ARGS__)
#define CMD_SUCCESS true #define CMD_SUCCESS true
#define CMD_FAILED false #define CMD_FAILED false
#define MAX_BUFFER_SIZE 255 #define MAX_BUFFER_SIZE 255
#define NULLSTR "None" #define NULLSTR "None"
typedef std::function<bool(std::vector<std::string> args)> CommandHandler; class Console;
typedef std::function<bool(std::shared_ptr<Console> Console, std::vector<std::string> args)> CommandHandler;
enum Priority {
INFO_LVL,
LOG_LVL,
WARNING_LVL,
ERROR_LVL
};
enum class ArgumentType { enum class ArgumentType {
TEXT, NUMBER, PLAYER_POS, PLAYER_ROT TEXT, NUMBER, PLAYER_POS, PLAYER_ROT
@ -44,40 +37,68 @@ namespace Ship {
struct ConsoleLine { struct ConsoleLine {
std::string text; std::string text;
Priority priority = Priority::INFO_LVL; spdlog::level::level_enum priority = spdlog::level::info;
std::string channel = "Main"; std::string channel = "Console";
}; };
class Console { class Console : public std::enable_shared_from_this<Console> {
private:
static int CallbackStub(ImGuiInputTextCallbackData* data);
static bool ClearCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args);
static bool HelpCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args);
static bool BindCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args);
static bool BindToggleCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args);
bool opened = false;
int selectedId = -1; int selectedId = -1;
int historyIndex = -1;
std::vector<int> selectedEntries; std::vector<int> selectedEntries;
std::string filter; std::string filter;
std::string level_filter = NULLSTR; std::string currentChannel = "Console";
std::vector<std::string> log_channels = { "Main", "SoH Logging" }; bool openAutocomplete = false;
std::vector<std::string> priority_filters = { "None", "Info", "Log", "Warning", "Error" }; char* inputBuffer = nullptr;
std::vector<ImVec4> priority_colors = { char* filterBuffer = nullptr;
ImVec4(1.0f, 1.0f, 1.0f, 1.0f), std::string cmdHint = NULLSTR;
ImVec4(0.2f, 1.0f, 0.2f, 1.0f), spdlog::level::level_enum levelFilter = spdlog::level::trace;
ImVec4(0.9f, 0.8f, 0.4f, 0.01f),
ImVec4(1.0f, 0.2f, 0.2f, 1.0f)
};
public:
std::map<std::string, std::vector<ConsoleLine>> Log;
std::map<std::string, CommandEntry> Commands;
std::vector<std::string> Autocomplete;
std::vector<std::string> History; std::vector<std::string> History;
std::string CMDHint = NULLSTR; std::vector<std::string> Autocomplete;
char* FilterBuffer = nullptr; std::map<ImGuiKey, std::string> Bindings;
char* InputBuffer = nullptr; std::map<ImGuiKey, std::string> BindingToggle;
bool OpenAutocomplete = false; std::map<std::string, CommandEntry> Commands;
int HistoryIndex = -1; std::map<std::string, std::vector<ConsoleLine>> Log;
std::string selected_channel = "Main"; const std::vector<std::string> LogChannels = { "Console", "Logs" };
bool opened = false; const std::vector<spdlog::level::level_enum> PriorityFilters = { spdlog::level::off, spdlog::level::critical, spdlog::level::err, spdlog::level::warn, spdlog::level::info, spdlog::level::debug, spdlog::level::trace };
const std::vector<ImVec4> PriorityColours = {
ImVec4(0.8f, 0.8f, 0.8f, 1.0f), // TRACE
ImVec4(0.9f, 0.9f, 0.9f, 1.0f), // DEBUG
ImVec4(1.0f, 1.0f, 1.0f, 1.0f), // INFO
ImVec4(1.0f, 0.875f, 0.125f, 1.0f), // WARN
ImVec4(0.65f, 0.18f, 0.25, 1.0f), // ERROR
ImVec4(0.95f, 0.11f, 0.25, 1.0f), // CRITICAL
ImVec4(0.0f, 0.0f, 0.0f, 0.0f) // OFF
};
protected:
void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, va_list args);
public:
void ClearLogs(std::string channel);
void ClearLogs();
void Init(); void Init();
void Update(); void Update();
void Draw(); void Draw();
void Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4);
void Dispatch(const std::string& line); void Dispatch(const std::string& line);
static int CallbackStub(ImGuiInputTextCallbackData* data); void SendInfoMessage(const char* fmt, ...);
void SendErrorMessage(const char* fmt, ...);
void SendInfoMessage(const std::string& str);
void SendErrorMessage(const std::string& str);
void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...);
bool HasCommand(const std::string& command);
void AddCommand(const std::string& command, CommandEntry entry);
std::string GetCurrentChannel() { return currentChannel; }
bool IsOpened() { return opened; }
void Close() { opened = false; }
void Open() { opened = true; }
}; };
} }

View File

@ -6,6 +6,7 @@
#include "KeyboardController.h" #include "KeyboardController.h"
#include "SDLController.h" #include "SDLController.h"
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
#include "Cvar.h"
namespace Ship { namespace Ship {
uint8_t* controllerBits; uint8_t* controllerBits;
@ -51,18 +52,31 @@ namespace Ship {
*controllerBits |= (backend->Connected()) << slot; *controllerBits |= (backend->Connected()) << slot;
} }
void ControlDeck::WriteToPad(OSContPad* pad) const { void ControlDeck::WriteToPad(OSContPad* pad) const {
for (size_t i = 0; i < virtualDevices.size(); i++) {
const std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]]; #ifdef __SWITCH__
if (backend->GetGuid() == "Auto") { bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0);
for (const auto& device : physicalDevices) { #else
device->Read(&pad[i], i); bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0) && CVar_GetS32("gControlNav", 0);
} #endif
continue;
} for (size_t i = 0; i < virtualDevices.size(); i++) {
backend->Read(&pad[i], i); const std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
} if (backend->GetGuid() == "Auto") {
} for (const auto& device : physicalDevices) {
if(shouldBlockGameInput && device->GetGuid() != "Keyboard") {
continue;
}
device->Read(&pad[i], i);
}
continue;
}
if(shouldBlockGameInput && backend->GetGuid() != "Keyboard") {
continue;
}
backend->Read(&pad[i], i);
}
}
#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__) #define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__)

View File

@ -1,4 +1,5 @@
#include "Cutscene.h" #include "Cutscene.h"
#include "spdlog/spdlog.h"
enum class CutsceneCommands enum class CutsceneCommands
{ {
@ -511,9 +512,7 @@ void Ship::CutsceneV0::ParseFileBinary(BinaryReader* reader, Resource* res)
return; return;
} }
default: default:
#ifdef _DEBUG SPDLOG_TRACE("CutsceneV0: Unknown command {}\n", commandId);
printf("CutsceneV0: Unknown command %x\n", commandId);
#endif
// error? // error?
break; break;
} }

View File

@ -4,12 +4,45 @@
#include "File.h" #include "File.h"
#include "Archive.h" #include "Archive.h"
#include "ResourceMgr.h" #include "ResourceMgr.h"
#include "Console.h"
#include "ImGuiImpl.h" #include "ImGuiImpl.h"
#include "Lib/ImGui/imgui_internal.h" #include "Lib/ImGui/imgui_internal.h"
#include "Utils/StringHelper.h" #include "Utils/StringHelper.h"
namespace Ship { namespace Ship {
bool OverlayCommand(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() < 3) {
return CMD_FAILED;
}
if (CVar_Get(args[2].c_str()) != nullptr) {
const char* key = args[2].c_str();
GameOverlay* overlay = SohImGui::overlay;
if (args[1] == "add") {
if (!overlay->RegisteredOverlays.contains(key)) {
overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f });
SohImGui::console->SendInfoMessage("Added overlay: %s", key);
}
else {
SohImGui::console->SendErrorMessage("Overlay already exists: %s", key);
}
}
else if (args[1] == "remove") {
if (overlay->RegisteredOverlays.contains(key)) {
overlay->RegisteredOverlays.erase(key);
SohImGui::console->SendInfoMessage("Removed overlay: %s", key);
}
else {
SohImGui::console->SendErrorMessage("Overlay not found: %s", key);
}
}
}
else {
SohImGui::console->SendErrorMessage("CVar {} does not exist", args[2].c_str());
}
return CMD_SUCCESS;
}
void GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) { void GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
std::shared_ptr<Archive> base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive(); std::shared_ptr<Archive> base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive();
@ -123,7 +156,8 @@ namespace Ship {
this->CurrentFont = DefaultFont; this->CurrentFont = DefaultFont;
} }
} }
SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" };
SohImGui::console->AddCommand("overlay", { OverlayCommand, "Draw an overlay using a cvar value" });
} }
void GameOverlay::DrawSettings() { void GameOverlay::DrawSettings() {
@ -196,39 +230,4 @@ namespace Ship {
ImGui::End(); ImGui::End();
} }
bool OverlayCommand(const std::vector<std::string>& args) {
if (args.size() < 3) {
return CMD_FAILED;
}
if (CVar_Get(args[2].c_str()) != nullptr) {
const char* key = args[2].c_str();
GameOverlay* overlay = SohImGui::overlay;
if (args[1] == "add") {
if (!overlay->RegisteredOverlays.contains(key)) {
overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f });
INFO("Added overlay: %s ", key);
}
else {
ERROR("Overlay already exists: %s", key);
}
}
else if (args[1] == "remove") {
if (overlay->RegisteredOverlays.contains(key)) {
overlay->RegisteredOverlays.erase(key);
INFO("Removed overlay: %s ", key);
}
else {
ERROR("Overlay not found: %s ", key);
}
}
}
else {
ERROR("CVar %s does not exist", args[2].c_str());
}
return CMD_SUCCESS;
}
} }

View File

@ -37,6 +37,4 @@ namespace Ship {
void CleanupNotifications(); void CleanupNotifications();
void LoadFont(const std::string& name, const std::string& path, float fontSize); void LoadFont(const std::string& name, const std::string& path, float fontSize);
}; };
bool OverlayCommand(const std::vector<std::string>& args);
} }

View File

@ -90,12 +90,20 @@ namespace Ship {
// Setup Logging // Setup Logging
spdlog::init_thread_pool(8192, 1); spdlog::init_thread_pool(8192, 1);
auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>(); auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>();
auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
SohConsoleSink->set_level(spdlog::level::trace); SohConsoleSink->set_level(spdlog::level::trace);
#if defined(__linux__)
auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
ConsoleSink->set_level(spdlog::level::trace); ConsoleSink->set_level(spdlog::level::trace);
#endif
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
FileSink->set_level(spdlog::level::trace); FileSink->set_level(spdlog::level::trace);
std::vector<spdlog::sink_ptr> Sinks{ ConsoleSink, FileSink, SohConsoleSink }; std::vector<spdlog::sink_ptr> Sinks{
#if defined(__linux__)
ConsoleSink,
#endif
FileSink,
SohConsoleSink
};
Logger = std::make_shared<spdlog::async_logger>(GetName(), Sinks.begin(), Sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); Logger = std::make_shared<spdlog::async_logger>(GetName(), Sinks.begin(), Sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
GetLogger()->set_level(spdlog::level::trace); GetLogger()->set_level(spdlog::level::trace);
GetLogger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%@] [%l] %v"); GetLogger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%@] [%l] %v");

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,7 @@ namespace SohImGui {
WindowDrawFunc drawFunc; WindowDrawFunc drawFunc;
} CustomWindow; } CustomWindow;
extern Ship::Console* console; extern std::shared_ptr<Ship::Console> console;
extern Ship::InputEditor* controller; extern Ship::InputEditor* controller;
extern Ship::GameOverlay* overlay; extern Ship::GameOverlay* overlay;
extern bool needs_save; extern bool needs_save;
@ -86,6 +86,12 @@ namespace SohImGui {
void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false);
void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0); void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0);
void applyEnhancementPresets(void);
void applyEnhancementPresetDefault(void);
void applyEnhancementPresetVanillaPlus(void);
void applyEnhancementPresetEnhanced(void);
void applyEnhancementPresetRandomizer(void);
void DrawMainMenuAndCalculateGameSize(void); void DrawMainMenuAndCalculateGameSize(void);
void DrawFramebufferAndGameInput(void); void DrawFramebufferAndGameInput(void);
@ -106,6 +112,12 @@ namespace SohImGui {
void EndGroupPanel(float minHeight = 0.0f); void EndGroupPanel(float minHeight = 0.0f);
std::string BreakTooltip(const char* text, int lineLength = 60); std::string BreakTooltip(const char* text, int lineLength = 60);
std::string BreakTooltip(const std::string& text, int lineLength = 60); std::string BreakTooltip(const std::string& text, int lineLength = 60);
void InsertPadding(float extraVerticalPadding = 0.0f);
void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f);
void PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false, bool padTop = true, bool padBottom = true);
void PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true);
void PaddedText(const char* text, bool padTop = true, bool padBottom = true);
std::string GetWindowButtonText(const char* text, bool menuOpen);
} }
#endif #endif

View File

@ -166,10 +166,12 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen, uint32
#ifdef __SWITCH__ #ifdef __SWITCH__
// For Switch we need to set the window width before creating the window // For Switch we need to set the window width before creating the window
Ship::Switch::GetDisplaySize(&window_width, &window_height); Ship::Switch::GetDisplaySize(&window_width, &window_height);
width = window_width;
height = window_height;
#endif #endif
wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
#ifndef __SWITCH__ #ifndef __SWITCH__
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);

View File

@ -31,47 +31,24 @@ public:
{} {}
protected: protected:
void sink_it_(const details::log_msg &msg) override void sink_it_(const details::log_msg &msg) override {
{
const Ship::Priority priority = convert_to_soh(msg.level);
memory_buf_t formatted; memory_buf_t formatted;
if (use_raw_msg_) if (use_raw_msg_) {
{
details::fmt_helper::append_string_view(msg.payload, formatted); details::fmt_helper::append_string_view(msg.payload, formatted);
} }
else else {
{
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
} }
formatted.push_back('\0'); formatted.push_back('\0');
const char *msg_output = formatted.data(); const char* msg_output = formatted.data();
if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened) if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->IsOpened()) {
SohImGui::console->Append("SoH Logging", priority, "%s", msg_output); SohImGui::console->Append("Logs", msg.level, "%s", msg_output);
}
} }
void flush_() override {} void flush_() override {}
private: private:
static Ship::Priority convert_to_soh(spdlog::level::level_enum level)
{
switch (level) {
case spdlog::level::trace:
return Ship::Priority::INFO_LVL;
case spdlog::level::debug:
return Ship::Priority::LOG_LVL;
case spdlog::level::info:
return Ship::Priority::LOG_LVL;
case spdlog::level::warn:
return Ship::Priority::WARNING_LVL;
case spdlog::level::err:
return Ship::Priority::ERROR_LVL;
case spdlog::level::critical:
return Ship::Priority::ERROR_LVL;
default:
break;
}
return Ship::Priority::LOG_LVL;
}
std::string tag_; std::string tag_;
bool use_raw_msg_; bool use_raw_msg_;

View File

@ -1,6 +1,7 @@
#include "Resource.h" #include "Resource.h"
#include "DisplayList.h" #include "DisplayList.h"
#include "ResourceMgr.h" #include "ResourceMgr.h"
#include "spdlog/spdlog.h"
#include "Utils/BinaryReader.h" #include "Utils/BinaryReader.h"
#include "Lib/tinyxml2/tinyxml2.h" #include "Lib/tinyxml2/tinyxml2.h"
#include "Lib/Fast3D/U64/PR/ultra64/gbi.h" #include "Lib/Fast3D/U64/PR/ultra64/gbi.h"
@ -56,9 +57,7 @@ namespace Ship
patches.clear(); patches.clear();
#if _DEBUG
if (file != nullptr) if (file != nullptr)
printf("Deconstructor called on file %s\n", file->path.c_str()); SPDLOG_TRACE("Deconstructor called on file %s\n", file->path.c_str());
#endif
} }
} }

View File

@ -82,19 +82,14 @@ namespace Ship {
break; break;
} }
//Lock.lock();
std::shared_ptr<File> ToLoad = FileLoadQueue.front(); std::shared_ptr<File> ToLoad = FileLoadQueue.front();
FileLoadQueue.pop(); FileLoadQueue.pop();
//Lock.unlock();
OTR->LoadFile(ToLoad->path, true, ToLoad); OTR->LoadFile(ToLoad->path, true, ToLoad);
//Lock.lock();
if (!ToLoad->bHasLoadError) if (!ToLoad->bHasLoadError)
FileCache[ToLoad->path] = ToLoad->bIsLoaded && !ToLoad->bHasLoadError ? ToLoad : nullptr; FileCache[ToLoad->path] = ToLoad->bIsLoaded && !ToLoad->bHasLoadError ? ToLoad : nullptr;
//Lock.unlock();
SPDLOG_DEBUG("Loaded File {} on ResourceMgr thread", ToLoad->path); SPDLOG_DEBUG("Loaded File {} on ResourceMgr thread", ToLoad->path);
ToLoad->FileLoadNotifier.notify_all(); ToLoad->FileLoadNotifier.notify_all();
@ -117,10 +112,8 @@ namespace Ship {
} }
std::shared_ptr<ResourcePromise> ToLoad = nullptr; std::shared_ptr<ResourcePromise> ToLoad = nullptr;
//ResLock.lock();
ToLoad = ResourceLoadQueue.front(); ToLoad = ResourceLoadQueue.front();
ResourceLoadQueue.pop(); ResourceLoadQueue.pop();
//ResLock.unlock();
// Wait for the underlying File to complete loading // Wait for the underlying File to complete loading
{ {
@ -148,9 +141,6 @@ namespace Ship {
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path); SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path);
// Disabled for now because it can cause random crashes
//FileCache[Res->File->path] = nullptr;
//FileCache.erase(FileCache.find(Res->File->path));
Res->file = nullptr; Res->file = nullptr;
} }
else { else {
@ -159,9 +149,6 @@ namespace Ship {
SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path); SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path);
} }
//ResLock.lock();
//ResLock.unlock();
} }
} }
else else

View File

@ -1,5 +1,6 @@
#include "Utils.h" #include "Utils.h"
#include <cstring> #include <cstring>
#include <algorithm>
#ifdef _MSC_VER #ifdef _MSC_VER
#define strdup _strdup #define strdup _strdup
@ -58,4 +59,10 @@ namespace Ship {
return args; return args;
} }
std::string toLowerCase(std::string in) {
std::string cpy(in);
std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower);
return cpy;
}
} }

View File

@ -10,4 +10,5 @@ namespace Ship {
} }
std::vector<std::string> SplitText(const std::string& text, char separator, bool keep_quotes); std::vector<std::string> SplitText(const std::string& text, char separator, bool keep_quotes);
std::string toLowerCase(std::string in);
} }

View File

@ -19,7 +19,7 @@
#include <string> #include <string>
#include <chrono> #include <chrono>
#include "Console.h" #include "Console.h"
#include "Cvar.h" #include "ImGuiImpl.h"
#include <iostream> #include <iostream>
@ -67,10 +67,9 @@ extern "C" {
pad->gyro_x = 0; pad->gyro_x = 0;
pad->gyro_y = 0; pad->gyro_y = 0;
if (!CVar_GetS32("gOpenMenuBar", 0)) { if (SohImGui::controller->Opened) return;
Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->WriteToPad(pad);
}
Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->WriteToPad(pad);
Ship::ExecuteHooks<Ship::ControllerRead>(pad); Ship::ExecuteHooks<Ship::ControllerRead>(pad);
} }

View File

@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-cmake --target ExtractAssets --
cmake --build build-cmake --config Release -- cmake --build build-cmake --config Release --
(cd build-cmake && cpack -G External) (cd build-cmake && cpack -G External)

View File

@ -1,7 +1,4 @@
#!/bin/bash #!/bin/bash
cmake --no-warn-unused-cli -H. -Bbuild-linux -GNinja
cmake --build build-linux --target ExtractAssets
cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake cmake -H. -Bbuild-switch -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake
cmake --build build-switch --target soh_nro cmake --build build-switch --target soh_nro

View File

@ -216,6 +216,13 @@ set(Header_Files__soh__Enhancements__randomizer__3drando
source_group("Header Files\\soh\\Enhancements\\randomizer\\3drando" FILES ${Header_Files__soh__Enhancements__randomizer__3drando}) source_group("Header Files\\soh\\Enhancements\\randomizer\\3drando" FILES ${Header_Files__soh__Enhancements__randomizer__3drando})
set(Header_Files__soh__Enhancements__custom_message
"soh/Enhancements/custom-message/CustomMessageTypes.h"
"soh/Enhancements/custom-message/CustomMessageManager.h"
)
source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message})
set(Header_Files__soh__Enhancements__item_tables set(Header_Files__soh__Enhancements__item_tables
"soh/Enhancements/item-tables/ItemTableManager.h" "soh/Enhancements/item-tables/ItemTableManager.h"
"soh/Enhancements/item-tables/ItemTableTypes.h" "soh/Enhancements/item-tables/ItemTableTypes.h"
@ -334,13 +341,6 @@ set(Source_Files__soh__Enhancements__randomizer__3drando__location_access
) )
source_group("Source Files\\soh\\Enhancements\\randomizer\\3drando\\location_access" FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access}) source_group("Source Files\\soh\\Enhancements\\randomizer\\3drando\\location_access" FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access})
set(Source_Files__soh__Enhancements__item_tables
"soh/Enhancements/item-tables/ItemTableManager.cpp"
)
source_group("Source Files\\soh\\Enhancements\\item-tables" FILES $
{Source_Files_Files__soh__Enhancements__item_tables})
set(Source_Files__src__boot set(Source_Files__src__boot
"src/boot/assert.c" "src/boot/assert.c"
"src/boot/boot_main.c" "src/boot/boot_main.c"
@ -1550,6 +1550,7 @@ set(ALL_FILES
${Header_Files__soh__Enhancements__randomizer} ${Header_Files__soh__Enhancements__randomizer}
${Header_Files__soh__Enhancements__randomizer__3drando} ${Header_Files__soh__Enhancements__randomizer__3drando}
${Header_Files__soh__Enhancements__item_tables} ${Header_Files__soh__Enhancements__item_tables}
${Header_Files__soh__Enhancements__custom_message}
${Source_Files__soh} ${Source_Files__soh}
${Source_Files__soh__Enhancements} ${Source_Files__soh__Enhancements}
${Source_Files__soh__Enhancements__cosmetics} ${Source_Files__soh__Enhancements__cosmetics}
@ -1559,6 +1560,7 @@ set(ALL_FILES
${Source_Files__soh__Enhancements__randomizer__3drando__hint_list} ${Source_Files__soh__Enhancements__randomizer__3drando__hint_list}
${Source_Files__soh__Enhancements__randomizer__3drando__location_access} ${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
${Source_Files__soh__Enhancements__item_tables} ${Source_Files__soh__Enhancements__item_tables}
${Source_Files__soh__Enhancements__custom_message}
${Source_Files__src__boot} ${Source_Files__src__boot}
${Source_Files__src__buffers} ${Source_Files__src__buffers}
${Source_Files__src__code} ${Source_Files__src__code}
@ -1822,7 +1824,6 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive> $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion> $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>
-pthread -pthread
-O3 -ffast-math
) )
target_link_options(${PROJECT_NAME} PRIVATE target_link_options(${PROJECT_NAME} PRIVATE

View File

@ -25,7 +25,7 @@ typedef struct {
/* 0x0C */ Vec3f position; /* 0x0C */ Vec3f position;
/* 0x18 */ Vec3s unkVelocity; /* 0x18 */ Vec3s unkVelocity;
/* 0x1E */ Vec3s unkPosition; /* 0x1E */ Vec3s unkPosition;
/* 0x24 */ s32 epoch; /* 0x24 */ u32 epoch;
} EffectSparkElement; // size = 0x28 } EffectSparkElement; // size = 0x28
typedef struct { typedef struct {
@ -118,7 +118,7 @@ typedef struct {
/* 0x10 */ f32 startX; /* 0x10 */ f32 startX;
/* 0x14 */ s16 yaw; /* 0x14 */ s16 yaw;
/* 0x16 */ s16 pitch; /* 0x16 */ s16 pitch;
/* 0x18 */ s32 epoch; /* 0x18 */ u32 epoch;
} EffectShieldParticleElement; // size = 0x1C } EffectShieldParticleElement; // size = 0x1C
typedef struct { typedef struct {

View File

@ -627,7 +627,8 @@ typedef struct Player {
/* 0x0A87 */ u8 unk_A87; /* 0x0A87 */ u8 unk_A87;
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
/* 0x0A94 */ PendingFlag pendingFlag; /* 0x0A94 */ PendingFlag pendingFlag;
/* 0x0AA0 */ GetItemEntry getItemEntry; /* 0x0AA0 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still?
} Player; // size = 0xAA8 /* 0x0AA1 */ GetItemEntry getItemEntry;
} Player; // size = 0xAA9
#endif #endif

View File

@ -1124,7 +1124,7 @@ void DrawCosmeticsEditor(bool& open) {
return; return;
} }
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Cosmetics Editor", &open, ImGuiWindowFlags_NoFocusOnAppearing)) { if (!ImGui::Begin("Cosmetics Editor", &open)) {
ImGui::End(); ImGui::End();
return; return;
} }
@ -1162,7 +1162,7 @@ void InitCosmeticsEditor() {
//This allow to hide a window without disturbing the player nor adding things in menu //This allow to hide a window without disturbing the player nor adding things in menu
//LoadRainbowColor() will this way run in background once it's window is activated //LoadRainbowColor() will this way run in background once it's window is activated
//ImGui::SetNextItemWidth(0.0f); //ImGui::SetNextItemWidth(0.0f);
SohImGui::AddWindow("Cosmetics", "Rainbowfunction", LoadRainbowColor, true, true); SohImGui::AddWindow("Enhancements", "Rainbowfunction", LoadRainbowColor, true, true);
//Draw the bar in the menu. //Draw the bar in the menu.
SohImGui::AddWindow("Cosmetics", "Cosmetics Editor", DrawCosmeticsEditor); SohImGui::AddWindow("Enhancements", "Cosmetics Editor", DrawCosmeticsEditor);
} }

View File

@ -0,0 +1,151 @@
#include "CustomMessageManager.h"
#include <algorithm>
using namespace std::literals::string_literals;
CustomMessageManager::CustomMessageManager() {
this->textBoxSpecialCharacters = { { "À", 0x80 }, { "î", 0x81 }, { "Â", 0x82 }, { "Ä", 0x83 }, { "Ç", 0x84 },
{ "È", 0x85 }, { "É", 0x86 }, { "Ê", 0x87 }, { "Ë", 0x88 }, { "Ï", 0x89 },
{ "Ô", 0x8A }, { "Ö", 0x8B }, { "Ù", 0x8C }, { "Û", 0x8D }, { "Ü", 0x8E },
{ "ß", 0x8F }, { "à", 0x90 }, { "á", 0x91 }, { "â", 0x92 }, { "ä", 0x93 },
{ "ç", 0x94 }, { "è", 0x95 }, { "é", 0x96 }, { "ê", 0x97 }, { "ë", 0x98 },
{ "ï", 0x99 }, { "ô", 0x9A }, { "ö", 0x9B }, { "ù", 0x9C }, { "û", 0x9D },
{ "ü", 0x9E } };
this->colors = { { "w", QM_WHITE }, { "r", QM_RED }, { "g", QM_GREEN }, { "b", QM_BLUE },
{ "c", QM_LBLUE }, { "p", QM_PINK }, { "y", QM_YELLOW }, { "B", QM_BLACK } };
}
CustomMessageManager::~CustomMessageManager() {
this->textBoxSpecialCharacters.clear();
this->colors.clear();
this->messageTables.clear();
}
void CustomMessageManager::ReplaceSpecialCharacters(std::string& string) {
// add special characters
for (auto specialCharacterPair : this->textBoxSpecialCharacters) {
size_t start_pos = 0;
std::string textBoxSpecialCharacterString = ""s;
textBoxSpecialCharacterString += specialCharacterPair.second;
while ((start_pos = string.find(specialCharacterPair.first, 0)) != std::string::npos) {
string.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString);
start_pos += textBoxSpecialCharacterString.length();
}
}
}
void CustomMessageManager::ReplaceColors(std::string& string) {
for (auto colorPair : colors) {
std::string textToReplace = "%";
textToReplace += colorPair.first;
size_t start_pos = 0;
while ((start_pos = string.find(textToReplace)) != std::string::npos) {
string.replace(start_pos, textToReplace.length(), COLOR(colorPair.second));
start_pos += textToReplace.length();
}
}
}
void CustomMessageManager::FormatCustomMessage(std::string& message, ItemID iid) {
message.insert(0, ITEM_OBTAINED(iid));
size_t start_pos = 0;
std::replace(message.begin(), message.end(), '&', NEWLINE()[0]);
while ((start_pos = message.find('^', start_pos)) != std::string::npos) {
message.replace(start_pos, 1, WAIT_FOR_INPUT() + ITEM_OBTAINED(iid));
start_pos += 3;
}
std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]);
ReplaceSpecialCharacters(message);
ReplaceColors(message);
message += MESSAGE_END();
}
void CustomMessageManager::FormatCustomMessage(std::string& message) {
size_t start_pos = 0;
std::replace(message.begin(), message.end(), '&', NEWLINE()[0]);
std::replace(message.begin(), message.end(), '^', WAIT_FOR_INPUT()[0]);
std::replace(message.begin(), message.end(), '@', PLAYER_NAME()[0]);
ReplaceSpecialCharacters(message);
ReplaceColors(message);
message += MESSAGE_END();
}
bool CustomMessageManager::InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages) {
auto foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return false;
}
auto& messageTable = foundMessageTable->second;
auto messageInsertResult = messageTable.emplace(textID, messages);
return messageInsertResult.second;
}
bool CustomMessageManager::CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messageEntry) {
FormatCustomMessage(messageEntry.english, iid);
FormatCustomMessage(messageEntry.german, iid);
FormatCustomMessage(messageEntry.french, iid);
const uint16_t textID = giid;
return InsertCustomMessage(tableID, textID, messageEntry);
}
bool CustomMessageManager::CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messageEntry) {
FormatCustomMessage(messageEntry.english);
FormatCustomMessage(messageEntry.german);
FormatCustomMessage(messageEntry.french);
return InsertCustomMessage(tableID, textID, messageEntry);
}
CustomMessageEntry CustomMessageManager::RetrieveMessage(std::string tableID, uint16_t textID) {
std::unordered_map<std::string, CustomMessageTable>::const_iterator foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return NULL_CUSTOM_MESSAGE;
}
CustomMessageTable messageTable = foundMessageTable->second;
std::unordered_map<uint16_t, CustomMessageEntry>::const_iterator foundMessage = messageTable.find(textID);
if (foundMessage == messageTable.end()) {
return NULL_CUSTOM_MESSAGE;
}
CustomMessageEntry message = foundMessage->second;
return message;
}
bool CustomMessageManager::ClearMessageTable(std::string tableID) {
auto foundMessageTable = messageTables.find(tableID);
if (foundMessageTable == messageTables.end()) {
return false;
}
auto& messageTable = foundMessageTable->second;
messageTable.clear();
return true;
}
bool CustomMessageManager::AddCustomMessageTable(std::string tableID) {
CustomMessageTable newMessageTable;
return messageTables.emplace(tableID, newMessageTable).second;
}
std::string CustomMessageManager::MESSAGE_END() {
return "\x02"s;
}
std::string CustomMessageManager::ITEM_OBTAINED(uint8_t x) {
return "\x13"s + char(x);
}
std::string CustomMessageManager::NEWLINE() {
return "\x01"s;
}
std::string CustomMessageManager::COLOR(uint8_t x) {
return "\x05"s + char(x);
}
std::string CustomMessageManager::WAIT_FOR_INPUT() {
return "\x04"s;
}
std::string CustomMessageManager::PLAYER_NAME() {
return "\x0F"s;
}

View File

@ -0,0 +1,133 @@
#pragma once
#include <string>
#include <unordered_map>
#include "../../../include/z64item.h"
#undef MESSAGE_END
#define QM_WHITE 0x00
#define QM_RED 0x41
#define QM_GREEN 0x42
#define QM_BLUE 0x43
#define QM_LBLUE 0x44
#define QM_PINK 0x45
#define QM_YELLOW 0x46
#define QM_BLACK 0x47
#ifndef MESSAGE_DATA_STATIC_H
typedef enum {
/* 0 */ TEXTBOX_TYPE_BLACK,
/* 1 */ TEXTBOX_TYPE_WOODEN,
/* 2 */ TEXTBOX_TYPE_BLUE,
/* 3 */ TEXTBOX_TYPE_OCARINA,
/* 4 */ TEXTBOX_TYPE_NONE_BOTTOM,
/* 5 */ TEXTBOX_TYPE_NONE_NO_SHADOW,
/* 11 */ TEXTBOX_TYPE_CREDITS = 11
} TextBoxType;
typedef enum {
/* 0 */ TEXTBOX_BG_CROSS
} TextBoxBackground;
typedef enum {
/* 0 */ TEXTBOX_POS_VARIABLE,
/* 1 */ TEXTBOX_POS_TOP,
/* 2 */ TEXTBOX_POS_MIDDLE,
/* 3 */ TEXTBOX_POS_BOTTOM
} TextBoxPosition;
#endif
typedef struct {
TextBoxType textBoxType;
TextBoxPosition textBoxPos;
std::string english;
std::string german;
std::string french;
} CustomMessageEntry;
// Message Entry without the text type and position, useful for when
// you need an array of these to loop over for registration
// that will all have the same textbox type and position.
typedef struct {
std::string english;
std::string german;
std::string french;
} CustomMessageMinimal;
#define NULL_CUSTOM_MESSAGE \
{ (TextBoxType)(-1), (TextBoxPosition)(-1), "", "", "" }
typedef std::unordered_map<uint16_t, CustomMessageEntry> CustomMessageTable;
class CustomMessageManager {
private:
std::unordered_map<std::string, char> textBoxSpecialCharacters;
std::unordered_map<std::string, char> colors;
std::unordered_map<std::string, CustomMessageTable> messageTables;
void ReplaceSpecialCharacters(std::string &string);
void ReplaceColors(std::string& string);
bool InsertCustomMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages);
std::string MESSAGE_END();
std::string ITEM_OBTAINED(uint8_t x);
std::string NEWLINE();
std::string COLOR(uint8_t x);
std::string WAIT_FOR_INPUT();
std::string PLAYER_NAME();
public:
static CustomMessageManager* Instance;
CustomMessageManager();
~CustomMessageManager();
/*
Formats the provided Custom Message Entry and inserts it into the table with the provided tableID,
with the provided giid (getItemID) as its key. This function also inserts the icon corresponding to
the provided iid (itemID) at the beginning of each page of the textbox.
*/
bool CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messages);
/*
Formats the provided Custom Message Entry and inserts it into the table with the provided tableID,
with the provided textID as its key.
*/
bool CreateMessage(std::string tableID, uint16_t textID, CustomMessageEntry messages);
/*
Retrieves a message from the table with id tableID with the provided textID.
Returns a NULL_CUSTOM_MESSAGE if the message or table does not exist.
*/
CustomMessageEntry RetrieveMessage(std::string tableID, uint16_t textID);
/*
Empties out the message table identified by tableID.
Returns true if successful and false if not (for instance
if a table with the provided tableID does not exist).
*/
bool ClearMessageTable(std::string tableID);
/*
Creates an empty CustomMessageTable accessible at the provided
tableID, returns true if creation was successful and false
if not.
*/
bool AddCustomMessageTable(std::string tableID);
/*
Replaces special characters and certain symbols with control codes
& for newline, ^ for wait-for-input, and @ for the player name,
as well as %<letter> for colors (i.e. %r for red and %w for white).
*/
void FormatCustomMessage(std::string& message, ItemID iid);
/*
Replaces special characters and certain symbols with control codes
& for newline, ^ for wait-for-input, and @ for the player name,
as well as %<letter> for colors (i.e. %r for red and %w for white).
*/
void FormatCustomMessage(std::string& message);
};

View File

@ -0,0 +1,33 @@
#pragma once
typedef enum {
TEXT_GS_NO_FREEZE = 0xB4,
TEXT_GS_FREEZE = 0xB5,
TEXT_RANDOMIZER_CUSTOM_ITEM = 0xF8,
TEXT_SCRUB_POH = 0x10A2,
TEXT_SCRUB_STICK_UPGRADE = 0x10DC,
TEXT_SCRUB_NUT_UPGRADE = 0x10DD,
TEXT_RANDOMIZER_GOSSIP_STONE_HINTS = 0x2053,
TEXT_ALTAR_CHILD = 0x7040,
TEXT_ALTAR_ADULT = 0x7088,
TEXT_GANONDORF = 0x70CC,
TEXT_GANONDORF_NOHINT = 0x70CD
} TextIDs;
#ifdef __cplusplus
typedef struct {
GetItemID giid;
ItemID iid;
std::string english;
std::string german;
std::string french;
} GetItemMessage;
#define GIMESSAGE(giid, iid, english, german, french) \
{ giid, iid, english, german, french }
#define GIMESSAGE_UNTRANSLATED(giid, iid, message) \
{ giid, iid, message, message, message }
#endif

View File

@ -5,6 +5,7 @@
#include "debugconsole.h" #include "debugconsole.h"
#include "../libultraship/ImGuiImpl.h" #include "../libultraship/ImGuiImpl.h"
#include "savestates.h" #include "savestates.h"
#include "Console.h"
#include <vector> #include <vector>
#include <string> #include <string>
@ -32,14 +33,14 @@ extern GlobalContext* gGlobalCtx;
#define CMD_REGISTER SohImGui::BindCmd #define CMD_REGISTER SohImGui::BindCmd
static bool ActorSpawnHandler(const std::vector<std::string>& args) { static bool ActorSpawnHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) { if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) {
ERROR("Not enough arguments passed to actorspawn"); SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn");
return CMD_FAILED; return CMD_FAILED;
} }
if (gGlobalCtx == nullptr) { if (gGlobalCtx == nullptr) {
ERROR("GlobalCtx == nullptr"); SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
return CMD_FAILED; return CMD_FAILED;
} }
@ -75,23 +76,22 @@ static bool ActorSpawnHandler(const std::vector<std::string>& args) {
if (Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, actorId, spawnPoint.pos.x, spawnPoint.pos.y, spawnPoint.pos.z, if (Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, actorId, spawnPoint.pos.x, spawnPoint.pos.y, spawnPoint.pos.z,
spawnPoint.rot.x, spawnPoint.rot.y, spawnPoint.rot.z, params) == NULL) { spawnPoint.rot.x, spawnPoint.rot.y, spawnPoint.rot.z, params) == NULL) {
ERROR("Failed to spawn actor. Actor_Spawn returned NULL"); SohImGui::console->SendErrorMessage("Failed to spawn actor. Actor_Spawn returned NULL");
return CMD_FAILED; return CMD_FAILED;
} }
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool KillPlayerHandler([[maybe_unused]] const std::vector<std::string>&) { static bool KillPlayerHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
gSaveContext.health = 0; gSaveContext.health = 0;
SohImGui::console->SendInfoMessage("[SOH] You've met with a terrible fate, haven't you?");
INFO("[SOH] You've met with a terrible fate, haven't you?");
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool SetPlayerHealthHandler(const std::vector<std::string>& args) { static bool SetPlayerHealthHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) { if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -100,23 +100,23 @@ static bool SetPlayerHealthHandler(const std::vector<std::string>& args) {
try { try {
health = std::stoi(args[1]); health = std::stoi(args[1]);
} catch (std::invalid_argument const& ex) { } catch (std::invalid_argument const& ex) {
ERROR("[SOH] Health value must be an integer."); SohImGui::console->SendErrorMessage("[SOH] Health value must be an integer.");
return CMD_FAILED; return CMD_FAILED;
} }
if (health < 0) { if (health < 0) {
ERROR("[SOH] Health value must be a positive integer"); SohImGui::console->SendErrorMessage("[SOH] Health value must be a positive integer");
return CMD_SUCCESS; return CMD_SUCCESS;
} }
gSaveContext.health = health * 0x10; gSaveContext.health = health * 0x10;
INFO("[SOH] Player health updated to %d", health); SohImGui::console->SendInfoMessage("[SOH] Player health updated to %d", health);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool LoadSceneHandler(const std::vector<std::string>&) { static bool LoadSceneHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
gSaveContext.respawnFlag = 0; gSaveContext.respawnFlag = 0;
gSaveContext.seqId = 0xFF; gSaveContext.seqId = 0xFF;
gSaveContext.gameMode = 0; gSaveContext.gameMode = 0;
@ -124,7 +124,7 @@ static bool LoadSceneHandler(const std::vector<std::string>&) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool RuppeHandler(const std::vector<std::string>& args) { static bool RuppeHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() < 2) if (args.size() < 2)
return CMD_FAILED; return CMD_FAILED;
@ -133,31 +133,32 @@ static bool RuppeHandler(const std::vector<std::string>& args) {
rupeeAmount = std::stoi(args[1]); rupeeAmount = std::stoi(args[1]);
} }
catch (std::invalid_argument const& ex) { catch (std::invalid_argument const& ex) {
ERROR("[SOH] Rupee count must be an integer."); SohImGui::console->SendErrorMessage("[SOH] Rupee count must be an integer.");
return CMD_FAILED; return CMD_FAILED;
} }
if (rupeeAmount < 0) { if (rupeeAmount < 0) {
ERROR("[SOH] Rupee count must be positive"); SohImGui::console->SendErrorMessage("[SOH] Rupee count must be positive");
return CMD_FAILED; return CMD_FAILED;
} }
gSaveContext.rupees = rupeeAmount; gSaveContext.rupees = rupeeAmount;
INFO("Set rupee count to %u", rupeeAmount); SohImGui::console->SendInfoMessage("Set rupee count to %u", rupeeAmount);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool SetPosHandler(const std::vector<std::string> args) { static bool SetPosHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string> args) {
if (gGlobalCtx == nullptr) { if (gGlobalCtx == nullptr) {
ERROR("GlobalCtx == nullptr"); SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
return CMD_FAILED; return CMD_FAILED;
} }
Player* player = GET_PLAYER(gGlobalCtx); Player* player = GET_PLAYER(gGlobalCtx);
if (args.size() == 1) { if (args.size() == 1) {
INFO("Player position is [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, player->actor.world.pos.y, SohImGui::console->SendInfoMessage("Player position is [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x,
player->actor.world.pos.y,
player->actor.world.pos.z); player->actor.world.pos.z);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -168,14 +169,15 @@ static bool SetPosHandler(const std::vector<std::string> args) {
player->actor.world.pos.y = std::stof(args[2]); player->actor.world.pos.y = std::stof(args[2]);
player->actor.world.pos.z = std::stof(args[3]); player->actor.world.pos.z = std::stof(args[3]);
INFO("Set player position to [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, player->actor.world.pos.y, SohImGui::console->SendInfoMessage("Set player position to [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x,
player->actor.world.pos.y,
player->actor.world.pos.z); player->actor.world.pos.z);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool ResetHandler(std::vector<std::string> args) { static bool ResetHandler(std::shared_ptr<Ship::Console> Console, std::vector<std::string> args) {
if (gGlobalCtx == nullptr) { if (gGlobalCtx == nullptr) {
ERROR("GlobalCtx == nullptr"); SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
return CMD_FAILED; return CMD_FAILED;
} }
@ -194,9 +196,9 @@ const static std::map<std::string, uint16_t> ammoItems{
{ "magic_beans", ITEM_BEAN }, { "magic_beans", ITEM_BEAN },
}; };
static bool AmmoHandler(const std::vector<std::string>& args) { static bool AmmoHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 3) { if (args.size() != 3) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -205,19 +207,19 @@ static bool AmmoHandler(const std::vector<std::string>& args) {
try { try {
count = std::stoi(args[2]); count = std::stoi(args[2]);
} catch (std::invalid_argument const& ex) { } catch (std::invalid_argument const& ex) {
ERROR("Ammo count must be an integer"); SohImGui::console->SendErrorMessage("Ammo count must be an integer");
return CMD_FAILED; return CMD_FAILED;
} }
if (count < 0) { if (count < 0) {
ERROR("Ammo count must be positive"); SohImGui::console->SendErrorMessage("Ammo count must be positive");
return CMD_FAILED; return CMD_FAILED;
} }
const auto& it = ammoItems.find(args[1]); const auto& it = ammoItems.find(args[1]);
if (it == ammoItems.end()) { if (it == ammoItems.end()) {
ERROR("Invalid item passed"); SohImGui::console->SendErrorMessage("Invalid item passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -237,9 +239,9 @@ const static std::map<std::string, uint16_t> bottleItems{
{ "big_poe", ITEM_BIG_POE }, { "blue_fire", ITEM_BLUE_FIRE }, { "rutos_letter", ITEM_LETTER_RUTO }, { "big_poe", ITEM_BIG_POE }, { "blue_fire", ITEM_BLUE_FIRE }, { "rutos_letter", ITEM_LETTER_RUTO },
}; };
static bool BottleHandler(const std::vector<std::string>& args) { static bool BottleHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 3) { if (args.size() != 3) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -247,19 +249,19 @@ static bool BottleHandler(const std::vector<std::string>& args) {
try { try {
slot = std::stoi(args[2]); slot = std::stoi(args[2]);
} catch (std::invalid_argument const& ex) { } catch (std::invalid_argument const& ex) {
ERROR("[SOH] Bottle slot must be an integer."); SohImGui::console->SendErrorMessage("[SOH] Bottle slot must be an integer.");
return CMD_FAILED; return CMD_FAILED;
} }
if ((slot < 1) || (slot > 4)) { if ((slot < 1) || (slot > 4)) {
ERROR("Invalid slot passed"); SohImGui::console->SendErrorMessage("Invalid slot passed");
return CMD_FAILED; return CMD_FAILED;
} }
const auto& it = bottleItems.find(args[1]); const auto& it = bottleItems.find(args[1]);
if (it == bottleItems.end()) { if (it == bottleItems.end()) {
ERROR("Invalid item passed"); SohImGui::console->SendErrorMessage("Invalid item passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -269,9 +271,9 @@ static bool BottleHandler(const std::vector<std::string>& args) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool BHandler(const std::vector<std::string>& args) { static bool BHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) { if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -279,9 +281,9 @@ static bool BHandler(const std::vector<std::string>& args) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool ItemHandler(const std::vector<std::string>& args) { static bool ItemHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 3) { if (args.size() != 3) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -290,9 +292,9 @@ static bool ItemHandler(const std::vector<std::string>& args) {
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool EntranceHandler(const std::vector<std::string>& args) { static bool EntranceHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) { if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
@ -301,55 +303,54 @@ static bool EntranceHandler(const std::vector<std::string>& args) {
try { try {
entrance = std::stoi(args[1], nullptr, 16); entrance = std::stoi(args[1], nullptr, 16);
} catch (std::invalid_argument const& ex) { } catch (std::invalid_argument const& ex) {
ERROR("[SOH] Entrance value must be a Hex number."); SohImGui::console->SendErrorMessage("[SOH] Entrance value must be a Hex number.");
return CMD_FAILED; return CMD_FAILED;
} }
gGlobalCtx->nextEntranceIndex = entrance;
gGlobalCtx->nextEntranceIndex = entrance;
gGlobalCtx->sceneLoadFlag = 0x14; gGlobalCtx->sceneLoadFlag = 0x14;
gGlobalCtx->fadeTransition = 11; gGlobalCtx->fadeTransition = 11;
gSaveContext.nextTransition = 11; gSaveContext.nextTransition = 11;
} }
static bool SaveStateHandler(const std::vector<std::string>& args) { static bool SaveStateHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
switch (rtn) { switch (rtn) {
case SaveStateReturn::SUCCESS: case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", slot); SohImGui::console->SendInfoMessage("[SOH] Saved state to slot %u", slot);
return CMD_SUCCESS; return CMD_SUCCESS;
case SaveStateReturn::FAIL_WRONG_GAMESTATE: case SaveStateReturn::FAIL_WRONG_GAMESTATE:
ERROR("[SOH] Can not save a state outside of \"GamePlay\""); SohImGui::console->SendErrorMessage("[SOH] Can not save a state outside of \"GamePlay\"");
return CMD_FAILED; return CMD_FAILED;
} }
} }
static bool LoadStateHandler(const std::vector<std::string>& args) { static bool LoadStateHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
switch (rtn) { switch (rtn) {
case SaveStateReturn::SUCCESS: case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", slot); SohImGui::console->SendInfoMessage("[SOH] Loaded state from slot (%u)", slot);
return CMD_SUCCESS; return CMD_SUCCESS;
case SaveStateReturn::FAIL_INVALID_SLOT: case SaveStateReturn::FAIL_INVALID_SLOT:
ERROR("[SOH] Invalid State Slot Number (%u)", slot); SohImGui::console->SendErrorMessage("[SOH] Invalid State Slot Number (%u)", slot);
return CMD_FAILED; return CMD_FAILED;
case SaveStateReturn::FAIL_STATE_EMPTY: case SaveStateReturn::FAIL_STATE_EMPTY:
ERROR("[SOH] State Slot (%u) is empty", slot); SohImGui::console->SendErrorMessage("[SOH] State Slot (%u) is empty", slot);
return CMD_FAILED; return CMD_FAILED;
case SaveStateReturn::FAIL_WRONG_GAMESTATE: case SaveStateReturn::FAIL_WRONG_GAMESTATE:
ERROR("[SOH] Can not load a state outside of \"GamePlay\""); SohImGui::console->SendErrorMessage("[SOH] Can not load a state outside of \"GamePlay\"");
return CMD_FAILED; return CMD_FAILED;
} }
} }
static bool StateSlotSelectHandler(const std::vector<std::string>& args) { static bool StateSlotSelectHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) { if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed"); SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED; return CMD_FAILED;
} }
int slot; int slot;
@ -357,17 +358,18 @@ static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
try { try {
slot = std::stoi(args[1], nullptr, 10); slot = std::stoi(args[1], nullptr, 10);
} catch (std::invalid_argument const& ex) { } catch (std::invalid_argument const& ex) {
ERROR("[SOH] SaveState slot value must be a number."); SohImGui::console->SendErrorMessage("[SOH] SaveState slot value must be a number.");
return CMD_FAILED; return CMD_FAILED;
} }
if (slot < 0) { if (slot < 0) {
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2"); SohImGui::console->SendErrorMessage("[SOH] Invalid slot passed. Slot must be between 0 and 2");
return CMD_FAILED; return CMD_FAILED;
} }
OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot); OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot);
INFO("[SOH] Slot %u selected", OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot()); SohImGui::console->SendInfoMessage("[SOH] Slot %u selected",
OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot());
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -402,7 +404,7 @@ static int CheckVarType(const std::string& input)
return result; return result;
} }
static bool SetCVarHandler(const std::vector<std::string>& args) { static bool SetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() < 3) if (args.size() < 3)
return CMD_FAILED; return CMD_FAILED;
@ -427,12 +429,12 @@ static bool SetCVarHandler(const std::vector<std::string>& args) {
CVar_Save(); CVar_Save();
//INFO("[SOH] Updated player position to [ %.2f, %.2f, %.2f ]", pos.x, pos.y, pos.z); //SohImGui::console->SendInfoMessage("[SOH] Updated player position to [ %.2f, %.2f, %.2f ]", pos.x, pos.y, pos.z);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static bool GetCVarHandler(const std::vector<std::string>& args) { static bool GetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() < 2) if (args.size() < 2)
return CMD_FAILED; return CMD_FAILED;
@ -441,17 +443,17 @@ static bool GetCVarHandler(const std::vector<std::string>& args) {
if (cvar != nullptr) if (cvar != nullptr)
{ {
if (cvar->type == CVarType::S32) if (cvar->type == CVarType::S32)
INFO("[SOH] Variable %s is %i", args[1].c_str(), cvar->value.valueS32); SohImGui::console->SendInfoMessage("[SOH] Variable %s is %i", args[1].c_str(), cvar->value.valueS32);
else if (cvar->type == CVarType::Float) else if (cvar->type == CVarType::Float)
INFO("[SOH] Variable %s is %f", args[1].c_str(), cvar->value.valueFloat); SohImGui::console->SendInfoMessage("[SOH] Variable %s is %f", args[1].c_str(), cvar->value.valueFloat);
else if (cvar->type == CVarType::String) else if (cvar->type == CVarType::String)
INFO("[SOH] Variable %s is %s", args[1].c_str(), cvar->value.valueStr); SohImGui::console->SendInfoMessage("[SOH] Variable %s is %s", args[1].c_str(), cvar->value.valueStr);
else if (cvar->type == CVarType::RGBA) else if (cvar->type == CVarType::RGBA)
INFO("[SOH] Variable %s is %08X", args[1].c_str(), cvar->value.valueRGBA); SohImGui::console->SendInfoMessage("[SOH] Variable %s is %08X", args[1].c_str(), cvar->value.valueRGBA);
} }
else else
{ {
INFO("[SOH] Could not find variable %s", args[1].c_str()); SohImGui::console->SendInfoMessage("[SOH] Could not find variable %s", args[1].c_str());
} }

View File

@ -156,7 +156,7 @@ static bool AreEntrancesCompatible(Entrance* entrance, Entrance* target, std::ve
//Entrances shouldn't connect to their own scene, fail in this situation //Entrances shouldn't connect to their own scene, fail in this situation
if (entrance->GetParentRegion()->scene != "" && entrance->GetParentRegion()->scene == target->GetConnectedRegion()->scene) { if (entrance->GetParentRegion()->scene != "" && entrance->GetParentRegion()->scene == target->GetConnectedRegion()->scene) {
auto message = "Entrance " + entrance->GetName() + " attempted to connect with own scene target " + target->to_string() + ". Connection failed.\n"; auto message = "Entrance " + entrance->GetName() + " attempted to connect with own scene target " + target->to_string() + ". Connection failed.\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} }
@ -168,7 +168,7 @@ static bool AreEntrancesCompatible(Entrance* entrance, Entrance* target, std::ve
//Change connections between an entrance and a target assumed entrance, in order to test the connections afterwards if necessary //Change connections between an entrance and a target assumed entrance, in order to test the connections afterwards if necessary
static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) { static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
auto message = "Attempting to connect " + entrance->GetName() + " to " + targetEntrance->to_string() + "\n"; auto message = "Attempting to connect " + entrance->GetName() + " to " + targetEntrance->to_string() + "\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
entrance->Connect(targetEntrance->Disconnect()); entrance->Connect(targetEntrance->Disconnect());
entrance->SetReplacement(targetEntrance->GetReplacement()); entrance->SetReplacement(targetEntrance->GetReplacement());
if (entrance->GetReverse() != nullptr /*&& entrances aren't decoupled*/) { if (entrance->GetReverse() != nullptr /*&& entrances aren't decoupled*/) {
@ -208,7 +208,7 @@ static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) {
static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector<Entrance*>& alreadyChecked) { static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector<Entrance*>& alreadyChecked) {
if (entrance == nullptr) { if (entrance == nullptr) {
SPDLOG_INFO("Entrance is nullptr in EntranceUnreachableAs()"); SPDLOG_DEBUG("Entrance is nullptr in EntranceUnreachableAs()");
return true; return true;
} }
@ -247,7 +247,7 @@ static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector<E
} }
static bool ValidateWorld(Entrance* entrancePlaced) { static bool ValidateWorld(Entrance* entrancePlaced) {
SPDLOG_INFO("Validating world\n"); SPDLOG_DEBUG("Validating world\n");
//check certain conditions when certain types of ER are enabled //check certain conditions when certain types of ER are enabled
EntranceType type = EntranceType::None; EntranceType type = EntranceType::None;
@ -285,11 +285,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
if (ElementInContainer(replacementName, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { if (ElementInContainer(replacementName, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) {
auto message = replacementName + " is replaced by an entrance with a potential child access\n"; auto message = replacementName + " is replaced by an entrance with a potential child access\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} else if (ElementInContainer(replacementName, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { } else if (ElementInContainer(replacementName, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) {
auto message = replacementName + " is replaced by an entrance with a potential adult access\n"; auto message = replacementName + " is replaced by an entrance with a potential adult access\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} }
} }
@ -299,11 +299,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
if (ElementInContainer(name, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { if (ElementInContainer(name, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) {
auto message = name + " is potentially accessible as child\n"; auto message = name + " is potentially accessible as child\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} else if (ElementInContainer(name, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { } else if (ElementInContainer(name, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) {
auto message = name + " is potentially accessible as adult\n"; auto message = name + " is potentially accessible as adult\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} }
} }
@ -317,7 +317,7 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
auto impasHouseBackHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE_BACK); auto impasHouseBackHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE_BACK);
if (impasHouseFrontHintRegion != NONE && impasHouseBackHintRegion != NONE && impasHouseBackHintRegion != LINKS_POCKET && impasHouseFrontHintRegion != LINKS_POCKET && impasHouseBackHintRegion != impasHouseFrontHintRegion) { if (impasHouseFrontHintRegion != NONE && impasHouseBackHintRegion != NONE && impasHouseBackHintRegion != LINKS_POCKET && impasHouseFrontHintRegion != LINKS_POCKET && impasHouseBackHintRegion != impasHouseFrontHintRegion) {
auto message = "Kak Impas House entrances are not in the same hint area\n"; auto message = "Kak Impas House entrances are not in the same hint area\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
return false; return false;
} }
} }
@ -328,23 +328,23 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
if (checkOtherEntranceAccess) { if (checkOtherEntranceAccess) {
// At least one valid starting region with all basic refills should be reachable without using any items at the beginning of the seed // At least one valid starting region with all basic refills should be reachable without using any items at the beginning of the seed
if (!AreaTable(KOKIRI_FOREST)->HasAccess() && !AreaTable(KAKARIKO_VILLAGE)->HasAccess()) { if (!AreaTable(KOKIRI_FOREST)->HasAccess() && !AreaTable(KAKARIKO_VILLAGE)->HasAccess()) {
SPDLOG_INFO("Invalid starting area\n"); SPDLOG_DEBUG("Invalid starting area\n");
return false; return false;
} }
// Check that a region where time passes is always reachable as both ages without having collected any items // Check that a region where time passes is always reachable as both ages without having collected any items
if (!Areas::HasTimePassAccess(AGE_CHILD) || !Areas::HasTimePassAccess(AGE_ADULT)) { if (!Areas::HasTimePassAccess(AGE_CHILD) || !Areas::HasTimePassAccess(AGE_ADULT)) {
SPDLOG_INFO("Time passing is not guaranteed as both ages\n"); SPDLOG_DEBUG("Time passing is not guaranteed as both ages\n");
return false; return false;
} }
// The player should be able to get back to ToT after going through time, without having collected any items // The player should be able to get back to ToT after going through time, without having collected any items
// This is important to ensure that the player never loses access to the pedestal after going through time // This is important to ensure that the player never loses access to the pedestal after going through time
if (Settings::ResolvedStartingAge == AGE_CHILD && !AreaTable(TEMPLE_OF_TIME)->Adult()) { if (Settings::ResolvedStartingAge == AGE_CHILD && !AreaTable(TEMPLE_OF_TIME)->Adult()) {
SPDLOG_INFO("Path to Temple of Time as adult is not guaranteed\n"); SPDLOG_DEBUG("Path to Temple of Time as adult is not guaranteed\n");
return false; return false;
} else if (Settings::ResolvedStartingAge == AGE_ADULT && !AreaTable(TEMPLE_OF_TIME)->Child()) { } else if (Settings::ResolvedStartingAge == AGE_ADULT && !AreaTable(TEMPLE_OF_TIME)->Child()) {
SPDLOG_INFO("Path to Temple of Time as child is not guaranteed\n"); SPDLOG_DEBUG("Path to Temple of Time as child is not guaranteed\n");
return false; return false;
} }
} }
@ -353,11 +353,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
// This is important to ensure that players can never lock their only bottles by filling them with Big Poes they can't sell // This is important to ensure that players can never lock their only bottles by filling them with Big Poes they can't sell
if (checkPoeCollectorAccess) { if (checkPoeCollectorAccess) {
if (!AreaTable(MARKET_GUARD_HOUSE)->Adult()) { if (!AreaTable(MARKET_GUARD_HOUSE)->Adult()) {
SPDLOG_INFO("Big Poe Shop access is not guarenteed as adult\n"); SPDLOG_DEBUG("Big Poe Shop access is not guarenteed as adult\n");
return false; return false;
} }
} }
SPDLOG_INFO("All Locations NOT REACHABLE\n"); SPDLOG_DEBUG("All Locations NOT REACHABLE\n");
return false; return false;
} }
return true; return true;
@ -476,7 +476,7 @@ static void ShuffleEntrancePool(std::vector<Entrance*>& entrancePool, std::vecto
} }
if (retries <= 0) { if (retries <= 0) {
SPDLOG_INFO("Entrance placement attempt count exceeded. Restarting randomization completely"); SPDLOG_DEBUG("Entrance placement attempt count exceeded. Restarting randomization completely");
entranceShuffleFailure = true; entranceShuffleFailure = true;
} }
} }
@ -840,7 +840,7 @@ void CreateEntranceOverrides() {
if (noRandomEntrances) { if (noRandomEntrances) {
return; return;
} }
SPDLOG_INFO("\nCREATING ENTRANCE OVERRIDES\n"); SPDLOG_DEBUG("\nCREATING ENTRANCE OVERRIDES\n");
auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false); auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false);
for (Entrance* entrance : allShuffleableEntrances) { for (Entrance* entrance : allShuffleableEntrances) {
@ -851,7 +851,7 @@ void CreateEntranceOverrides() {
} }
auto message = "Setting " + entrance->to_string() + "\n"; auto message = "Setting " + entrance->to_string() + "\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
int16_t originalIndex = entrance->GetIndex(); int16_t originalIndex = entrance->GetIndex();
int16_t destinationIndex = entrance->GetReverse()->GetIndex(); int16_t destinationIndex = entrance->GetReverse()->GetIndex();
@ -868,9 +868,9 @@ void CreateEntranceOverrides() {
}); });
message = "\tOriginal: " + std::to_string(originalIndex) + "\n"; message = "\tOriginal: " + std::to_string(originalIndex) + "\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
message = "\tReplacement " + std::to_string(replacementIndex) + "\n"; message = "\tReplacement " + std::to_string(replacementIndex) + "\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
} }
} }

View File

@ -420,7 +420,7 @@ std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowe
if (!Location(loc)->IsAddedToPool()) { if (!Location(loc)->IsAddedToPool()) {
allLocationsReachable = false; allLocationsReachable = false;
auto message = "Location " + Location(loc)->GetName() + " not reachable\n"; auto message = "Location " + Location(loc)->GetName() + " not reachable\n";
SPDLOG_INFO(message); SPDLOG_DEBUG(message);
#ifndef ENABLE_DEBUG #ifndef ENABLE_DEBUG
break; break;
#endif #endif
@ -567,17 +567,17 @@ static void AssumedFill(const std::vector<uint32_t>& items, const std::vector<ui
if (items.size() > allowedLocations.size()) { if (items.size() > allowedLocations.size()) {
printf("\x1b[2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS"); printf("\x1b[2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS");
SPDLOG_INFO("Items:\n"); SPDLOG_DEBUG("Items:\n");
for (const uint32_t item : items) { for (const uint32_t item : items) {
SPDLOG_INFO("\t"); SPDLOG_DEBUG("\t");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
} }
SPDLOG_INFO("\nAllowed Locations:\n"); SPDLOG_DEBUG("\nAllowed Locations:\n");
for (const uint32_t loc : allowedLocations) { for (const uint32_t loc : allowedLocations) {
SPDLOG_INFO("\t"); SPDLOG_DEBUG("\t");
SPDLOG_INFO(Location(loc)->GetName()); SPDLOG_DEBUG(Location(loc)->GetName());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
} }
placementFailure = true; placementFailure = true;
return; return;
@ -627,9 +627,9 @@ static void AssumedFill(const std::vector<uint32_t>& items, const std::vector<ui
// retry if there are no more locations to place items // retry if there are no more locations to place items
if (accessibleLocations.empty()) { if (accessibleLocations.empty()) {
SPDLOG_INFO("\nCANNOT PLACE "); SPDLOG_DEBUG("\nCANNOT PLACE ");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO(". TRYING AGAIN...\n"); SPDLOG_DEBUG(". TRYING AGAIN...\n");
#ifdef ENABLE_DEBUG #ifdef ENABLE_DEBUG
Areas::DumpWorldGraph(ItemTable(item).GetName().GetEnglish()); Areas::DumpWorldGraph(ItemTable(item).GetName().GetEnglish());
@ -666,7 +666,7 @@ static void AssumedFill(const std::vector<uint32_t>& items, const std::vector<ui
LogicReset(); LogicReset();
GetAccessibleLocations(allLocations, SearchMode::CheckBeatable); GetAccessibleLocations(allLocations, SearchMode::CheckBeatable);
if (playthroughBeatable) { if (playthroughBeatable) {
SPDLOG_INFO("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) + SPDLOG_DEBUG("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) +
" major items remaining.\n\n"); " major items remaining.\n\n");
FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true); FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true);
return; return;
@ -1062,7 +1062,7 @@ int Fill() {
} }
//Unsuccessful placement //Unsuccessful placement
if(retries < 4) { if(retries < 4) {
SPDLOG_INFO("\nGOT STUCK. RETRYING...\n"); SPDLOG_DEBUG("\nGOT STUCK. RETRYING...\n");
Areas::ResetAllLocations(); Areas::ResetAllLocations();
LogicReset(); LogicReset();
ClearProgress(); ClearProgress();

View File

@ -206,23 +206,23 @@ static void AddHint(Text hint, const uint32_t gossipStone, const std::vector<uin
static void CreateLocationHint(const std::vector<uint32_t>& possibleHintLocations) { static void CreateLocationHint(const std::vector<uint32_t>& possibleHintLocations) {
//return if there aren't any hintable locations or gossip stones available //return if there aren't any hintable locations or gossip stones available
if (possibleHintLocations.empty()) { if (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return; return;
} }
uint32_t hintedLocation = RandomElement(possibleHintLocations); uint32_t hintedLocation = RandomElement(possibleHintLocations);
const std::vector<uint32_t> accessibleGossipStones = GetAccessibleGossipStones(hintedLocation); const std::vector<uint32_t> accessibleGossipStones = GetAccessibleGossipStones(hintedLocation);
SPDLOG_INFO("\tLocation: "); SPDLOG_DEBUG("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName()); SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: "); SPDLOG_DEBUG("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
if (accessibleGossipStones.empty()) { if (accessibleGossipStones.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return; return;
} }
@ -235,9 +235,9 @@ static void CreateLocationHint(const std::vector<uint32_t>& possibleHintLocation
Text prefix = Hint(PREFIX).GetText(); Text prefix = Hint(PREFIX).GetText();
Text finalHint = prefix + locationHintText + " #"+itemHintText+"#."; Text finalHint = prefix + locationHintText + " #"+itemHintText+"#.";
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(finalHint.english); SPDLOG_DEBUG(finalHint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
} }
@ -258,24 +258,24 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
// If no more locations can be hinted at for woth, then just try to get another hint // If no more locations can be hinted at for woth, then just try to get another hint
if (possibleHintLocations.empty()) { if (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return; return;
} }
uint32_t hintedLocation = RandomElement(possibleHintLocations); uint32_t hintedLocation = RandomElement(possibleHintLocations);
SPDLOG_INFO("\tLocation: "); SPDLOG_DEBUG("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName()); SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: "); SPDLOG_DEBUG("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
// get an accessible gossip stone // get an accessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) { if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return; return;
} }
Location(hintedLocation)->SetAsHinted(); Location(hintedLocation)->SetAsHinted();
@ -293,9 +293,9 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
locationText = GetHintRegion(parentRegion)->GetHint().GetText(); locationText = GetHintRegion(parentRegion)->GetHint().GetText();
} }
Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText(); Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText();
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(finalWothHint.english); SPDLOG_DEBUG(finalWothHint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalWothHint, gossipStone, { QM_LBLUE }); AddHint(finalWothHint, gossipStone, { QM_LBLUE });
} }
@ -312,18 +312,18 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
uint32_t hintedLocation = RandomElement(barrenLocations, true); uint32_t hintedLocation = RandomElement(barrenLocations, true);
SPDLOG_INFO("\tLocation: "); SPDLOG_DEBUG("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName()); SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: "); SPDLOG_DEBUG("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
// get an accessible gossip stone // get an accessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) { if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return; return;
} }
Location(hintedLocation)->SetAsHinted(); Location(hintedLocation)->SetAsHinted();
@ -341,9 +341,9 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
} }
Text finalBarrenHint = Text finalBarrenHint =
Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText(); Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText();
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(finalBarrenHint.english); SPDLOG_DEBUG(finalBarrenHint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalBarrenHint, gossipStone, { QM_PINK }); AddHint(finalBarrenHint, gossipStone, { QM_PINK });
// get rid of all other locations in this same barren region // get rid of all other locations in this same barren region
@ -359,23 +359,23 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
}); });
//If no more locations can be hinted at, then just try to get another hint //If no more locations can be hinted at, then just try to get another hint
if (possibleHintLocations.empty()) { if (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return; return;
} }
uint32_t hintedLocation = RandomElement(possibleHintLocations); uint32_t hintedLocation = RandomElement(possibleHintLocations);
SPDLOG_INFO("\tLocation: "); SPDLOG_DEBUG("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName()); SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: "); SPDLOG_DEBUG("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
//get an acessible gossip stone //get an acessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) { if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return; return;
} }
Location(hintedLocation)->SetAsHinted(); Location(hintedLocation)->SetAsHinted();
@ -387,16 +387,16 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
Text locationText = AreaTable(parentRegion)->GetHint().GetText(); Text locationText = AreaTable(parentRegion)->GetHint().GetText();
Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#."; Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#.";
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(finalHint.english); SPDLOG_DEBUG(finalHint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
} else { } else {
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#."; Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#.";
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(finalHint.english); SPDLOG_DEBUG(finalHint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN}); AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN});
} }
} }
@ -411,15 +411,15 @@ static void CreateJunkHint() {
LogicReset(); LogicReset();
const std::vector<uint32_t> gossipStones = GetAccessibleLocations(gossipStoneLocations); const std::vector<uint32_t> gossipStones = GetAccessibleLocations(gossipStoneLocations);
if (gossipStones.empty()) { if (gossipStones.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return; return;
} }
uint32_t gossipStone = RandomElement(gossipStones); uint32_t gossipStone = RandomElement(gossipStones);
Text hint = junkHint.GetText(); Text hint = junkHint.GetText();
SPDLOG_INFO("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_INFO(hint.english); SPDLOG_DEBUG(hint.english);
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(hint, gossipStone, {QM_PINK}); AddHint(hint, gossipStone, {QM_PINK});
} }
@ -711,7 +711,7 @@ void CreateAllHints() {
CreateGanonText(); CreateGanonText();
CreateAltarText(); CreateAltarText();
SPDLOG_INFO("\nNOW CREATING HINTS\n"); SPDLOG_DEBUG("\nNOW CREATING HINTS\n");
const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()]; const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()];
uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit; uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit;
@ -768,9 +768,9 @@ void CreateAllHints() {
barrenDungeons.push_back(barrenRegion); barrenDungeons.push_back(barrenRegion);
} }
} }
SPDLOG_INFO("\nBarren Dungeons:\n"); SPDLOG_DEBUG("\nBarren Dungeons:\n");
for (std::string barrenDungeon : barrenDungeons) { for (std::string barrenDungeon : barrenDungeons) {
SPDLOG_INFO(barrenDungeon + "\n"); SPDLOG_DEBUG(barrenDungeon + "\n");
} }
//Get list of all woth dungeons //Get list of all woth dungeons
@ -783,9 +783,9 @@ void CreateAllHints() {
wothDungeons.push_back(wothRegion); wothDungeons.push_back(wothRegion);
} }
} }
SPDLOG_INFO("\nWoth Dungeons:\n"); SPDLOG_DEBUG("\nWoth Dungeons:\n");
for (std::string wothDungeon : wothDungeons) { for (std::string wothDungeon : wothDungeons) {
SPDLOG_INFO(wothDungeon + "\n"); SPDLOG_DEBUG(wothDungeon + "\n");
} }
//Set DungeonInfo array for each dungeon //Set DungeonInfo array for each dungeon
@ -827,9 +827,9 @@ void CreateAllHints() {
//get a random hint type from the remaining hints //get a random hint type from the remaining hints
HintType type = RandomElement(remainingHintTypes, true); HintType type = RandomElement(remainingHintTypes, true);
SPDLOG_INFO("Attempting to make hint of type: "); SPDLOG_DEBUG("Attempting to make hint of type: ");
SPDLOG_INFO(hintTypeNames[static_cast<int>(type)]); SPDLOG_DEBUG(hintTypeNames[static_cast<int>(type)]);
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
//create the appropriate hint for the type //create the appropriate hint for the type
if (type == HintType::Woth) { if (type == HintType::Woth) {

View File

@ -1460,11 +1460,11 @@ void GenerateLocationPool() {
void PlaceItemInLocation(uint32_t locKey, uint32_t item, bool applyEffectImmediately /*= false*/, bool setHidden /*= false*/) { void PlaceItemInLocation(uint32_t locKey, uint32_t item, bool applyEffectImmediately /*= false*/, bool setHidden /*= false*/) {
auto loc = Location(locKey); auto loc = Location(locKey);
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO(" placed at "); SPDLOG_DEBUG(" placed at ");
SPDLOG_INFO(loc->GetName()); SPDLOG_DEBUG(loc->GetName());
SPDLOG_INFO("\n\n"); SPDLOG_DEBUG("\n\n");
if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
ItemTable(item).ApplyEffect(); ItemTable(item).ApplyEffect();
@ -1551,7 +1551,7 @@ void AddExcludedOptions() {
} }
void CreateItemOverrides() { void CreateItemOverrides() {
SPDLOG_INFO("NOW CREATING OVERRIDES\n\n"); SPDLOG_DEBUG("NOW CREATING OVERRIDES\n\n");
for (uint32_t locKey : allLocations) { for (uint32_t locKey : allLocations) {
auto loc = Location(locKey); auto loc = Location(locKey);
ItemOverride_Value val = ItemTable(loc->GetPlaceduint32_t()).Value(); ItemOverride_Value val = ItemTable(loc->GetPlaceduint32_t()).Value();
@ -1563,18 +1563,18 @@ void CreateItemOverrides() {
.key = loc->Key(), .key = loc->Key(),
.value = val, .value = val,
}); });
SPDLOG_INFO("\tScene: "); SPDLOG_DEBUG("\tScene: ");
SPDLOG_INFO(std::to_string(loc->Key().scene)); SPDLOG_DEBUG(std::to_string(loc->Key().scene));
SPDLOG_INFO("\tType: "); SPDLOG_DEBUG("\tType: ");
SPDLOG_INFO(std::to_string(loc->Key().type)); SPDLOG_DEBUG(std::to_string(loc->Key().type));
SPDLOG_INFO("\tFlag: "); SPDLOG_DEBUG("\tFlag: ");
SPDLOG_INFO(std::to_string(loc->Key().flag)); SPDLOG_DEBUG(std::to_string(loc->Key().flag));
SPDLOG_INFO("\t"); SPDLOG_DEBUG("\t");
SPDLOG_INFO(loc->GetName()); SPDLOG_DEBUG(loc->GetName());
SPDLOG_INFO(": "); SPDLOG_DEBUG(": ");
SPDLOG_INFO(loc->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG(loc->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n"); SPDLOG_DEBUG("\n");
} }
SPDLOG_INFO("Overrides Created: "); SPDLOG_DEBUG("Overrides Created: ");
SPDLOG_INFO(std::to_string(overrides.size())); SPDLOG_DEBUG(std::to_string(overrides.size()));
} }

View File

@ -1174,6 +1174,6 @@ void GenerateItemPool() {
} }
void AddJunk() { void AddJunk() {
SPDLOG_INFO("HAD TO PLACE EXTRA JUNK "); SPDLOG_DEBUG("HAD TO PLACE EXTRA JUNK ");
AddItemToMainPool(GetPendingJunkItem()); AddItemToMainPool(GetPendingJunkItem());
} }

View File

@ -26,13 +26,13 @@ Menu* currentMenu;
} // namespace } // namespace
void PrintTopScreen() { void PrintTopScreen() {
SPDLOG_INFO("\x1b[2;11H%sOcarina of Time 3D Randomizer%s", CYAN, RESET); SPDLOG_DEBUG("\x1b[2;11H%sOcarina of Time 3D Randomizer%s", CYAN, RESET);
SPDLOG_INFO("\x1b[3;18H%s%s-%s%s", CYAN, RANDOMIZER_VERSION, COMMIT_NUMBER, RESET); SPDLOG_DEBUG("\x1b[3;18H%s%s-%s%s", CYAN, RANDOMIZER_VERSION, COMMIT_NUMBER, RESET);
SPDLOG_INFO("\x1b[4;10HA/B/D-pad: Navigate Menu\n"); SPDLOG_DEBUG("\x1b[4;10HA/B/D-pad: Navigate Menu\n");
SPDLOG_INFO(" Select: Exit to Homebrew Menu\n"); SPDLOG_DEBUG(" Select: Exit to Homebrew Menu\n");
SPDLOG_INFO(" Y: New Random Seed\n"); SPDLOG_DEBUG(" Y: New Random Seed\n");
SPDLOG_INFO(" X: Input Custom Seed\n"); SPDLOG_DEBUG(" X: Input Custom Seed\n");
SPDLOG_INFO("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str()); SPDLOG_DEBUG("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str());
} }
void MenuInit() { void MenuInit() {
@ -526,7 +526,7 @@ std::string GenerateRandomizer(std::unordered_map<RandomizerSettingKey, uint8_t>
if (ret == -1) { // Failed to generate after 5 tries if (ret == -1) { // Failed to generate after 5 tries
printf("\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be " printf("\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be "
"successful."); "successful.");
SPDLOG_INFO("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n"); SPDLOG_DEBUG("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n");
return ""; return "";
} else { } else {
printf("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret); printf("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret);

View File

@ -13,14 +13,21 @@
#include "3drando/rando_main.hpp" #include "3drando/rando_main.hpp"
#include <soh/Enhancements/debugger/ImGuiHelpers.h> #include <soh/Enhancements/debugger/ImGuiHelpers.h>
#include "Lib/ImGui/imgui_internal.h" #include "Lib/ImGui/imgui_internal.h"
#include <soh/Enhancements/custom-message/CustomMessageManager.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include <soh/Enhancements/item-tables/ItemTableManager.h> #include <soh/Enhancements/item-tables/ItemTableManager.h>
using json = nlohmann::json; using json = nlohmann::json;
using namespace std::literals::string_literals;
std::unordered_map<uint8_t, Sprite> gSeedTextures; std::unordered_map<uint8_t, Sprite> gSeedTextures;
u8 generated; u8 generated;
const std::string Randomizer::getItemMessageTableID = "Randomizer";
const std::string Randomizer::hintMessageTableID = "RandomizerHints";
const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs";
Randomizer::Randomizer() { Randomizer::Randomizer() {
Sprite bowSprite = { dgFairyBowIconTex, 32, 32, G_IM_FMT_RGBA, G_IM_SIZ_32b, 0 }; Sprite bowSprite = { dgFairyBowIconTex, 32, 32, G_IM_FMT_RGBA, G_IM_SIZ_32b, 0 };
gSeedTextures[0] = bowSprite; gSeedTextures[0] = bowSprite;
@ -1477,6 +1484,26 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
ParseHintLocationsFile(spoilerFileName); ParseHintLocationsFile(spoilerFileName);
} }
CustomMessageManager::Instance->ClearMessageTable(Randomizer::hintMessageTableID);
CustomMessageManager::Instance->AddCustomMessageTable(Randomizer::hintMessageTableID);
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, TEXT_ALTAR_CHILD,
{ TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, gSaveContext.childAltarText,
gSaveContext.childAltarText, gSaveContext.childAltarText });
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, TEXT_ALTAR_ADULT,
{ TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, gSaveContext.adultAltarText,
gSaveContext.adultAltarText, gSaveContext.adultAltarText });
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, TEXT_GANONDORF,
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, gSaveContext.ganonHintText,
gSaveContext.ganonHintText, gSaveContext.ganonHintText });
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, TEXT_GANONDORF_NOHINT,
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, gSaveContext.ganonText,
gSaveContext.ganonText, gSaveContext.ganonText });
this->childAltarText = gSaveContext.childAltarText; this->childAltarText = gSaveContext.childAltarText;
this->adultAltarText = gSaveContext.adultAltarText; this->adultAltarText = gSaveContext.adultAltarText;
this->ganonHintText = gSaveContext.ganonHintText; this->ganonHintText = gSaveContext.ganonHintText;
@ -1485,6 +1512,8 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
for (auto hintLocation : gSaveContext.hintLocations) { for (auto hintLocation : gSaveContext.hintLocations) {
if(hintLocation.check == RC_LINKS_POCKET) break; if(hintLocation.check == RC_LINKS_POCKET) break;
this->hintLocations[hintLocation.check] = hintLocation.hintText; this->hintLocations[hintLocation.check] = hintLocation.hintText;
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, hintLocation.check, { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, hintLocation.hintText, hintLocation.hintText, hintLocation.hintText });
} }
} }
@ -1796,57 +1825,8 @@ std::string AltarIconString(char iconChar) {
std::string FormatJsonHintText(std::string jsonHint) { std::string FormatJsonHintText(std::string jsonHint) {
std::string formattedHintMessage = jsonHint; std::string formattedHintMessage = jsonHint;
char newLine = 0x01;
char playerName = 0x0F;
char nextBox = 0x04;
std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '&', newLine);
std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '^', nextBox);
std::replace(formattedHintMessage.begin(), formattedHintMessage.end(), '@', playerName);
std::unordered_map<std::string, char> textBoxSpecialCharacters = { CustomMessageManager::Instance->FormatCustomMessage(formattedHintMessage);
{"À", 0x80 },
{"î", 0x81 },
{"Â", 0x82 },
{"Ä", 0x83 },
{"Ç", 0x84 },
{"È", 0x85 },
{"É", 0x86 },
{"Ê", 0x87 },
{"Ë", 0x88 },
{"Ï", 0x89 },
{"Ô", 0x8A },
{"Ö", 0x8B },
{"Ù", 0x8C },
{"Û", 0x8D },
{"Ü", 0x8E },
{"ß", 0x8F },
{"à", 0x90 },
{"á", 0x91 },
{"â", 0x92 },
{"ä", 0x93 },
{"ç", 0x94 },
{"è", 0x95 },
{"é", 0x96 },
{"ê", 0x97 },
{"ë", 0x98 },
{"ï", 0x99 },
{"ô", 0x9A },
{"ö", 0x9B },
{"ù", 0x9C },
{"û", 0x9D },
{"ü", 0x9E }
};
// add special characters
for (auto specialCharacterPair : textBoxSpecialCharacters) {
size_t start_pos = 0;
std::string textBoxSpecialCharacterString = "";
textBoxSpecialCharacterString += specialCharacterPair.second;
while((start_pos = formattedHintMessage.find(specialCharacterPair.first, start_pos)) != std::string::npos) {
formattedHintMessage.replace(start_pos, specialCharacterPair.first.length(), textBoxSpecialCharacterString);
start_pos += textBoxSpecialCharacterString.length();
}
}
// add icons to altar text // add icons to altar text
for (char iconChar : {'0', '1', '2', '3', '4', '5', '6', '7', '8', 'o', 'c', 'i', 'l', 'b', 'L', 'k'}) { for (char iconChar : {'0', '1', '2', '3', '4', '5', '6', '7', '8', 'o', 'c', 'i', 'l', 'b', 'L', 'k'}) {
@ -2457,10 +2437,6 @@ std::string Randomizer::GetGanonHintText() const {
return ganonHintText; return ganonHintText;
} }
std::string Randomizer::GetHintFromCheck(RandomizerCheck check) {
return this->hintLocations[check];
}
u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) {
return this->randoSettings[randoSettingKey]; return this->randoSettings[randoSettingKey];
} }
@ -3301,7 +3277,10 @@ void GenerateRandomizerImgui() {
cvarSettings[RSK_CUCCO_COUNT] = CVar_GetS32("gRandomizeCuccosToReturn", 7); cvarSettings[RSK_CUCCO_COUNT] = CVar_GetS32("gRandomizeCuccosToReturn", 7);
cvarSettings[RSK_BIG_POE_COUNT] = CVar_GetS32("gRandomizeBigPoeTargetCount", 10); cvarSettings[RSK_BIG_POE_COUNT] = CVar_GetS32("gRandomizeBigPoeTargetCount", 10);
cvarSettings[RSK_SKIP_CHILD_STEALTH] = CVar_GetS32("gRandomizeSkipChildStealth", 0); // If we skip child zelda, skip child stealth is pointless, so this needs to be reflected in the spoiler log
cvarSettings[RSK_SKIP_CHILD_STEALTH] =
!CVar_GetS32("gRandomizeSkipChildZelda", 0) && CVar_GetS32("gRandomizeSkipChildStealth", 0);
cvarSettings[RSK_SKIP_EPONA_RACE] = CVar_GetS32("gRandomizeSkipEponaRace", 0); cvarSettings[RSK_SKIP_EPONA_RACE] = CVar_GetS32("gRandomizeSkipEponaRace", 0);
cvarSettings[RSK_SKIP_TOWER_ESCAPE] = CVar_GetS32("gRandomizeSkipTowerEscape", 0); cvarSettings[RSK_SKIP_TOWER_ESCAPE] = CVar_GetS32("gRandomizeSkipTowerEscape", 0);
@ -4777,6 +4756,60 @@ void DrawRandoEditor(bool& open) {
ImGui::End(); ImGui::End();
}*/ }*/
void CreateGetItemMessages(std::vector<GetItemMessage> messageEntries) {
CustomMessageManager* customMessageManager = CustomMessageManager::Instance;
customMessageManager->AddCustomMessageTable(Randomizer::getItemMessageTableID);
for (GetItemMessage messageEntry : messageEntries) {
customMessageManager->CreateGetItemMessage(Randomizer::getItemMessageTableID, messageEntry.giid, messageEntry.iid,
{ TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM,
messageEntry.english, messageEntry.german,
messageEntry.french });
}
}
void CreateScrubMessages() {
CustomMessageManager* customMessageManager = CustomMessageManager::Instance;
customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID);
const std::vector<u8> prices = { 10, 40 };
for (u8 price : prices) {
customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price,
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM,
"\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" +
std::to_string(price) + " Rupees%w it is!\x07\x10\xA3",
// RANDTODO: Translate the below string to German.
"\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" +
std::to_string(price) + " Rupees%w it is!\x07\x10\xA3",
"\x12\x38\x82J'abandonne! Tu veux bien m'acheter&un %gobjet mystérieux%w?&Ça fera %r" +
std::to_string(price) + " Rubis%w!\x07\x10\xA3"
});
}
}
void Randomizer::CreateCustomMessages() {
// RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED
// with GIMESSAGE(getItemID, itemID, english, german, french).
const std::vector<GetItemMessage> getItemMessages = {
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE,
"You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE,
"You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE,
"You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FISH, ITEM_FISH,
"You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BUGS, ITEM_BUG,
"You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED,
"You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN,
"You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_POE, ITEM_POE,
"You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this..."),
};
CreateGetItemMessages(getItemMessages);
CreateScrubMessages();
}
void InitRandoItemTable() { void InitRandoItemTable() {
GetItemEntry getItemTable[] = { GetItemEntry getItemTable[] = {
@ -4910,6 +4943,7 @@ void InitRandoItemTable() {
void InitRando() { void InitRando() {
SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor); SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor);
Randomizer::CreateCustomMessages();
InitRandoItemTable(); InitRandoItemTable();
} }

View File

@ -4,7 +4,8 @@
#include <string> #include <string>
#include "../../../include/ultra64.h" #include "../../../include/ultra64.h"
#include "../../../include/z64item.h" #include "../../../include/z64item.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h" #include <memory>
#include <soh/Enhancements/randomizer/randomizerTypes.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@ -31,6 +32,10 @@ class Randomizer {
Randomizer(); Randomizer();
~Randomizer(); ~Randomizer();
static const std::string getItemMessageTableID;
static const std::string hintMessageTableID;
static const std::string scrubMessageTableID;
static Sprite* GetSeedTexture(uint8_t index); static Sprite* GetSeedTexture(uint8_t index);
s16 GetItemModelFromId(s16 itemId); s16 GetItemModelFromId(s16 itemId);
s32 GetItemIDFromGetItemID(s32 getItemId); s32 GetItemIDFromGetItemID(s32 getItemId);
@ -44,9 +49,9 @@ class Randomizer {
std::string GetAdultAltarText() const; std::string GetAdultAltarText() const;
std::string GetGanonText() const; std::string GetGanonText() const;
std::string GetGanonHintText() const; std::string GetGanonHintText() const;
std::string GetHintFromCheck(RandomizerCheck check);
GetItemID GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); GetItemID GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
GetItemID GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); GetItemID GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
static void CreateCustomMessages();
bool CheckContainsRandoItem(RandomizerCheck randoCheck); bool CheckContainsRandoItem(RandomizerCheck randoCheck);
}; };

View File

@ -32,7 +32,6 @@
#include "Enhancements/cosmetics/CosmeticsEditor.h" #include "Enhancements/cosmetics/CosmeticsEditor.h"
#include "Enhancements/debugconsole.h" #include "Enhancements/debugconsole.h"
#include "Enhancements/debugger/debugger.h" #include "Enhancements/debugger/debugger.h"
#include "Enhancements/randomizer/randomizer.h"
#include <soh/Enhancements/randomizer/randomizer_item_tracker.h> #include <soh/Enhancements/randomizer/randomizer_item_tracker.h>
#include "Enhancements/n64_weird_frame_data.inc" #include "Enhancements/n64_weird_frame_data.inc"
#include "soh/frame_interpolation.h" #include "soh/frame_interpolation.h"
@ -40,6 +39,7 @@
#include "macros.h" #include "macros.h"
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
#include "Hooks.h" #include "Hooks.h"
#include <soh/Enhancements/custom-message/CustomMessageManager.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <SDL_scancode.h> #include <SDL_scancode.h>
@ -52,10 +52,13 @@
#endif #endif
#include <Audio.h> #include <Audio.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include <functions.h>
#include <soh/Enhancements/item-tables/ItemTableManager.h> #include <soh/Enhancements/item-tables/ItemTableManager.h>
OTRGlobals* OTRGlobals::Instance; OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance; SaveManager* SaveManager::Instance;
CustomMessageManager* CustomMessageManager::Instance;
ItemTableManager* ItemTableManager::Instance; ItemTableManager* ItemTableManager::Instance;
OTRGlobals::OTRGlobals() { OTRGlobals::OTRGlobals() {
@ -308,6 +311,7 @@ extern "C" void InitOTR() {
#endif #endif
OTRGlobals::Instance = new OTRGlobals(); OTRGlobals::Instance = new OTRGlobals();
SaveManager::Instance = new SaveManager(); SaveManager::Instance = new SaveManager();
CustomMessageManager::Instance = new CustomMessageManager();
ItemTableManager::Instance = new ItemTableManager(); ItemTableManager::Instance = new ItemTableManager();
auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version"); auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version");
@ -1570,99 +1574,39 @@ extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorI
return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams);
} }
extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBufferSize) { extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) {
std::string scrubText("");
int language = CVar_GetS32("gLanguages", 0);
int price = 0; int price = 0;
switch (scrubTextId) { switch (scrubTextId) {
case 0x10A2: case TEXT_SCRUB_POH:
price = 10; price = 10;
break; break;
case 0x10DC: case TEXT_SCRUB_STICK_UPGRADE:
case 0x10DD: case TEXT_SCRUB_NUT_UPGRADE:
price = 40; price = 40;
break; break;
} }
switch (language) { return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price);
case 0: default:
scrubText += 0x12; // add the sound
scrubText += 0x38; // sound id
scrubText += 0x82; // sound id
scrubText += "All right! You win! In return for";
scrubText += 0x01; // newline
scrubText += "sparing me, I will sell you a";
scrubText += 0x01; // newline
scrubText += 0x05; // change the color
scrubText += 0x42; // green
scrubText += "mysterious item";
scrubText += 0x05; // change the color
scrubText += 0x40; // white
scrubText += "!";
scrubText += 0x01; // newline
scrubText += 0x05; // change the color
scrubText += 0x41; // red
scrubText += std::to_string(price);
scrubText += price > 1 ? " Rupees" : " Rupee";
scrubText += 0x05; // change the color
scrubText += 0x40; // white
scrubText += " it is!";
scrubText += 0x07; // go to a new message
scrubText += 0x10; // message id
scrubText += 0xA3; // message id
break;
case 2:
scrubText += 0x12; // add the sound
scrubText += 0x38; // sound id
scrubText += 0x82; // sound id
scrubText += "J'abandonne! Tu veux bien m'acheter";
scrubText += 0x01; // newline
scrubText += "un ";
scrubText += 0x05; // change the color
scrubText += 0x42; // green
scrubText += "objet myst\x96rieux";
//scrubText += ";
scrubText += 0x05; // change the color
scrubText += 0x40; // white
scrubText += "?";
scrubText += 0x01; // newline
scrubText += "\x84";
scrubText += "a fera ";
scrubText += 0x05; // change the color
scrubText += 0x41; // red
scrubText += std::to_string(price) + " Rubis";
scrubText += 0x05; // change the color
scrubText += 0x40; // white
scrubText += "!";
scrubText += 0x07; // go to a new message
scrubText += 0x10; // message id
scrubText += 0xA3; // message id
break;
}
return CopyStringToCharBuffer(scrubText, buffer, maxBufferSize);
} }
extern "C" int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize) { extern "C" CustomMessageEntry Randomizer_GetAltarMessage() {
const std::string& altarText = (LINK_IS_ADULT) ? OTRGlobals::Instance->gRandomizer->GetAdultAltarText() return (LINK_IS_ADULT)
: OTRGlobals::Instance->gRandomizer->GetChildAltarText(); ? CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_ADULT)
return CopyStringToCharBuffer(altarText, buffer, maxBufferSize); : CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_CHILD);
} }
extern "C" int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize) { extern "C" CustomMessageEntry Randomizer_GetGanonText() {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonText(); return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF_NOHINT);
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
} }
extern "C" int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize) { extern "C" CustomMessageEntry Randomizer_GetGanonHintText() {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonHintText(); return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF);
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
} }
extern "C" int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) { extern "C" CustomMessageEntry Randomizer_GetHintFromCheck(RandomizerCheck check) {
// we don't want to make a copy of the std::string returned from GetHintFromCheck // we don't want to make a copy of the std::string returned from GetHintFromCheck
// so we're just going to let RVO take care of it // so we're just going to let RVO take care of it
const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check); const CustomMessageEntry hintText = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, check);
return CopyStringToCharBuffer(hintText, buffer, maxBufferSize); return hintText;
} }
extern "C" GetItemEntry ItemTable_Retrieve(int16_t getItemID) { extern "C" GetItemEntry ItemTable_Retrieve(int16_t getItemID) {
@ -1729,3 +1673,89 @@ extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomize
extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) { extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) {
return gSaveContext.n64ddFlag && Randomizer_GetItemIdFromKnownCheck(randomizerCheck, ogId) == GI_ICE_TRAP; return gSaveContext.n64ddFlag && Randomizer_GetItemIdFromKnownCheck(randomizerCheck, ogId) == GI_ICE_TRAP;
} }
extern "C" CustomMessageEntry Randomizer_GetCustomGetItemMessage(GetItemID giid, char* buffer, const int maxBufferSize) {
const CustomMessageEntry getItemText = CustomMessageManager::Instance->RetrieveMessage(Randomizer::getItemMessageTableID, giid);
return getItemText;
}
extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
MessageContext* msgCtx = &globalCtx->msgCtx;
uint16_t textId = msgCtx->textId;
Font* font = &msgCtx->font;
char* buffer = font->msgBuf;
const int maxBufferSize = sizeof(font->msgBuf);
CustomMessageEntry messageEntry;
if (gSaveContext.n64ddFlag) {
if (textId == TEXT_RANDOMIZER_CUSTOM_ITEM) {
messageEntry =
Randomizer_GetCustomGetItemMessage((GetItemID)GET_PLAYER(globalCtx)->getItemId, buffer, maxBufferSize);
} else if (textId == TEXT_RANDOMIZER_GOSSIP_STONE_HINTS && 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) ||
(Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
s16 actorParams = msgCtx->talkActor->params;
// if we're in a generic grotto
if (globalCtx->sceneNum == 62 && actorParams == 14360) {
// look for the chest in the actorlist to determine
// which grotto we're in
int numOfActorLists =
sizeof(globalCtx->actorCtx.actorLists) / sizeof(globalCtx->actorCtx.actorLists[0]);
for (int i = 0; i < numOfActorLists; i++) {
if (globalCtx->actorCtx.actorLists[i].length) {
if (globalCtx->actorCtx.actorLists[i].head->id == 10) {
// set the params for the hint check to be negative chest params
actorParams = 0 - globalCtx->actorCtx.actorLists[i].head->params;
}
}
}
}
RandomizerCheck hintCheck =
Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams);
messageEntry = Randomizer_GetHintFromCheck(hintCheck);
} else if (textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT) {
// rando hints at altar
messageEntry = Randomizer_GetAltarMessage();
} else if (textId == TEXT_GANONDORF) {
if (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT) {
messageEntry = Randomizer_GetGanonText();
} else {
messageEntry = Randomizer_GetGanonHintText();
}
} else if (textId == TEXT_SCRUB_POH || textId == TEXT_SCRUB_STICK_UPGRADE || textId == TEXT_SCRUB_NUT_UPGRADE) {
messageEntry = Randomizer_GetScrubMessage(textId);
}
}
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {
if (CVar_GetS32("gInjectSkulltulaCount", 0) != 0) {
if (CVar_GetS32("gSkulltulaFreeze", 0) != 0) {
textId = TEXT_GS_NO_FREEZE;
} else {
textId = TEXT_GS_FREEZE;
}
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId);
}
}
if (messageEntry.textBoxType != -1) {
font->charTexBuf[0] = (messageEntry.textBoxType << 4) | messageEntry.textBoxPos;
switch (gSaveContext.language) {
case LANGUAGE_FRA:
return msgCtx->msgLength = font->msgLength =
CopyStringToCharBuffer(messageEntry.french, buffer, maxBufferSize);
case LANGUAGE_GER:
return msgCtx->msgLength = font->msgLength =
CopyStringToCharBuffer(messageEntry.german, buffer, maxBufferSize);
case LANGUAGE_ENG:
default:
return msgCtx->msgLength = font->msgLength =
CopyStringToCharBuffer(messageEntry.english, buffer, maxBufferSize);
}
}
return false;
}

View File

@ -11,6 +11,8 @@
#include "Enhancements/savestates.h" #include "Enhancements/savestates.h"
#include "Enhancements/randomizer/randomizer.h" #include "Enhancements/randomizer/randomizer.h"
const std::string customMessageTableID = "BaseGameOverrides";
class OTRGlobals class OTRGlobals
{ {
public: public:
@ -94,10 +96,6 @@ Sprite* GetSeedTexture(uint8_t index);
void Randomizer_LoadSettings(const char* spoilerFileName); void Randomizer_LoadSettings(const char* spoilerFileName);
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); 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_LoadHintLocations(const char* spoilerFileName);
void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
s16 Randomizer_GetItemModelFromId(s16 itemId); s16 Randomizer_GetItemModelFromId(s16 itemId);
@ -108,6 +106,7 @@ GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actor
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor);
bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId);
int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx);
GetItemEntry ItemTable_Retrieve(int16_t getItemID); GetItemEntry ItemTable_Retrieve(int16_t getItemID);
#endif #endif

View File

@ -1,11 +1,13 @@
#include "OTRGlobals.h" #include "OTRGlobals.h"
#include "ResourceMgr.h" #include "ResourceMgr.h"
#include "Scene.h" #include "Scene.h"
#include "message_data_static.h"
#include "Utils/StringHelper.h" #include "Utils/StringHelper.h"
#include "global.h" #include "global.h"
#include "vt.h" #include "vt.h"
#include <Text.h> #include <Text.h>
#include <message_data_static.h>
#include <soh/Enhancements/custom-message/CustomMessageManager.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sNesMessageEntryTablePtr;
extern "C" MessageTableEntry* sGerMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr;
@ -92,4 +94,22 @@ extern "C" void OTRMessage_Init()
sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str();
sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size();
} }
}
CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID);
CustomMessageManager::Instance->CreateGetItemMessage(
customMessageTableID, (GetItemID)TEXT_GS_NO_FREEZE, ITEM_SKULL_TOKEN,
{
TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM,
"You got a %rGold Skulltula Token%w!&You've collected %r\x19%w tokens&in total!\x0E\x3C",
"Du erhälst ein %rGoldene&Skulltula-Symbol%w! Du hast&insgesamt %r\x19%w symbol gesammelt!\x0E\x3C",
"Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!\x0E\x3C"
}
);
CustomMessageManager::Instance->CreateGetItemMessage(
customMessageTableID, (GetItemID)TEXT_GS_FREEZE, ITEM_SKULL_TOKEN,
{
TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM,
"You got a %rGold Skulltula Token%w!&You've collected %r\x19%w tokens&in total!",
"Du erhälst ein %rGoldene&Skulltula-Symbol%w! Du hast&insgesamt %r\x19%w symbol gesammelt!",
"Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!" });
}

View File

@ -3957,7 +3957,7 @@ void Actor_DrawDoorLock(GlobalContext* globalCtx, s32 frame, s32 type) {
f32 chainsTranslateX; f32 chainsTranslateX;
f32 chainsTranslateY; f32 chainsTranslateY;
f32 rotZStep; f32 rotZStep;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
entry = &sDoorLocksInfo[type]; entry = &sDoorLocksInfo[type];

View File

@ -492,9 +492,10 @@ void Cutscene_Command_Terminator(GlobalContext* globalCtx, CutsceneContext* csCt
s32 temp = 0; s32 temp = 0;
// Automatically skip certain cutscenes when in rando // Automatically skip certain cutscenes when in rando
// cmd->base == 33: Zelda escaping with impa cutscene
// cmd->base == 8: Traveling back/forward in time cutscene // cmd->base == 8: Traveling back/forward in time cutscene
bool randoCsSkip = (gSaveContext.n64ddFlag && (cmd->base == 33 || cmd->base == 8)); // cmd->base == 24: Dropping a fish for Jabu Jabu
// cmd->base == 33: Zelda escaping with impa cutscene
bool randoCsSkip = (gSaveContext.n64ddFlag && (cmd->base == 8 || cmd->base == 24 || cmd->base == 33));
bool debugCsSkip = (CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_START) && bool debugCsSkip = (CHECK_BTN_ALL(globalCtx->state.input[0].press.button, BTN_START) &&
(gSaveContext.fileNum != 0xFEDC) && CVar_GetS32("gDebugEnabled", 0)); (gSaveContext.fileNum != 0xFEDC) && CVar_GetS32("gDebugEnabled", 0));
@ -2090,6 +2091,8 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) {
osSyncPrintf("\ngame_info.mode=[%d] restart_flag", ((void)0, gSaveContext.respawnFlag)); osSyncPrintf("\ngame_info.mode=[%d] restart_flag", ((void)0, gSaveContext.respawnFlag));
if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) { if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) {
const bool bShouldTowerRandoSkip =
(gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE));
if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC)) { if ((gSaveContext.entranceIndex == 0x01E1) && !Flags_GetEventChkInf(0xAC)) {
if (!gSaveContext.n64ddFlag) { if (!gSaveContext.n64ddFlag) {
Flags_SetEventChkInf(0xAC); Flags_SetEventChkInf(0xAC);
@ -2118,14 +2121,15 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) {
gSaveContext.entranceIndex = 0x0053; gSaveContext.entranceIndex = 0x0053;
gSaveContext.cutsceneIndex = 0xFFF8; gSaveContext.cutsceneIndex = 0xFFF8;
} }
} else if (!Flags_GetEventChkInf(0xC7) && } else if ((!Flags_GetEventChkInf(0xC7) &&
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO)) { gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO) ||
(bShouldTowerRandoSkip &&
gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_FINAL)) {
Flags_SetEventChkInf(0xC7); Flags_SetEventChkInf(0xC7);
gSaveContext.entranceIndex = 0x0517; gSaveContext.entranceIndex = 0x0517;
// If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall // If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall
// and exit. // and exit.
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) { if (bShouldTowerRandoSkip) {
return; return;
} }
gSaveContext.cutsceneIndex = 0xFFF0; gSaveContext.cutsceneIndex = 0xFFF0;

View File

@ -1459,7 +1459,7 @@ void Environment_DrawLensFlare(GlobalContext* globalCtx, EnvironmentContext* env
LENS_FLARE_RING, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_RING, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1,
LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1,
}; };
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);
@ -1642,7 +1642,7 @@ void Environment_DrawRain(GlobalContext* globalCtx, View* view, GraphicsContext*
Vec3f unused = { 0.0f, 0.0f, 0.0f }; Vec3f unused = { 0.0f, 0.0f, 0.0f };
Vec3f windDirection = { 0.0f, 0.0f, 0.0f }; Vec3f windDirection = { 0.0f, 0.0f, 0.0f };
Player* player = GET_PLAYER(globalCtx); Player* player = GET_PLAYER(globalCtx);
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
if (!(globalCtx->cameraPtrs[0]->unk_14C & 0x100) && (globalCtx->envCtx.unk_EE[2] == 0)) { if (!(globalCtx->cameraPtrs[0]->unk_14C & 0x100) && (globalCtx->envCtx.unk_EE[2] == 0)) {
@ -1925,7 +1925,7 @@ void Environment_DrawLightning(GlobalContext* globalCtx, s32 unused) {
s32 pad[2]; s32 pad[2];
Vec3f unused1 = { 0.0f, 0.0f, 0.0f }; Vec3f unused1 = { 0.0f, 0.0f, 0.0f };
Vec3f unused2 = { 0.0f, 0.0f, 0.0f }; Vec3f unused2 = { 0.0f, 0.0f, 0.0f };
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -413,7 +413,7 @@ void HealthMeter_Draw(GlobalContext* globalCtx) {
s32 curCombineModeSet = 0; s32 curCombineModeSet = 0;
u8* curBgImgLoaded = NULL; u8* curBgImgLoaded = NULL;
s32 ddHeartCountMinusOne = gSaveContext.inventory.defenseHearts - 1; s32 ddHeartCountMinusOne = gSaveContext.inventory.defenseHearts - 1;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);

View File

@ -1663,7 +1663,9 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
gSaveContext.eventInf[0] = gSaveContext.eventInf[1] = gSaveContext.eventInf[2] = gSaveContext.eventInf[3] = 0; gSaveContext.eventInf[0] = gSaveContext.eventInf[1] = gSaveContext.eventInf[2] = gSaveContext.eventInf[3] = 0;
} }
if (sTextIsCredits) { if (CustomMessage_RetrieveIfExists(globalCtx)) {
osSyncPrintf("Found custom message");
} else if (sTextIsCredits) {
Message_FindCreditsMessage(globalCtx, textId); Message_FindCreditsMessage(globalCtx, textId);
msgCtx->msgLength = font->msgLength; msgCtx->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset; char* src = (uintptr_t)font->msgOffset;
@ -1674,73 +1676,9 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
//font->msgLength, __FILE__, __LINE__); //font->msgLength, __FILE__, __LINE__);
} else { } else {
Message_FindMessage(globalCtx, textId); Message_FindMessage(globalCtx, textId);
// if we're rando'd and talking to a gossip stone msgCtx->msgLength = font->msgLength;
if (gSaveContext.n64ddFlag && char* src = (uintptr_t)font->msgOffset;
textId == 0x2053 && memcpy(font->msgBuf, src, font->msgLength);
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) ||
(Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == 3 &&
CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
s16 actorParams = msgCtx->talkActor->params;
// if we're in a generic grotto
if (globalCtx->sceneNum == 62 && actorParams == 14360) {
// look for the chest in the actorlist to determine
// which grotto we're in
int numOfActorLists = sizeof(globalCtx->actorCtx.actorLists)/sizeof(globalCtx->actorCtx.actorLists[0]);
for(int i = 0; i < numOfActorLists; i++) {
if(globalCtx->actorCtx.actorLists[i].length) {
if(globalCtx->actorCtx.actorLists[i].head->id == 10) {
// set the params for the hint check to be negative chest params
actorParams = 0 - globalCtx->actorCtx.actorLists[i].head->params;
}
}
}
}
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 = Randomizer_CopyHintFromCheck(hintCheck, font->msgBuf, sizeof(font->msgBuf));
} else if (gSaveContext.n64ddFlag && (textId == 0x7040 || textId == 0x7088)) {
// rando hints at altar
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:
strcpy(font->msgBuf, "\x08\x13\x71Vous obtenez un \x05\x41Symbole de\x01Skulltula d'or\x05\x40! "
"Vous avez\x01\collect\x96 "
"\x05\x41\x19\x05\x40 symboles en tout!\x02");
break;
case LANGUAGE_GER:
strcpy(font->msgBuf, "\x08\x13\x71\Du erh\x93lst ein \x05\x41Goldene\x01Skulltula-Symbol\x05\x40\! "
"Du hast\x01insgesamt "
"\x05\x41\x19\x05\x40 symbol gesammelt!\x02");
break;
case LANGUAGE_ENG: default:
strcpy(font->msgBuf,
"\x08\x13\x71You got a \x05\x41Gold Skulltula Token\x05\x40!\x01You've collected "
"\x05\x41\x19\x05\x40 tokens\x01in total!\x02");
break;
}
msgCtx->msgLength = font->msgLength = strlen(font->msgBuf);
} else if (gSaveContext.n64ddFlag && (textId == 0x10A2 || textId == 0x10DC || textId == 0x10DD)) {
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 = Randomizer_CopyGanonText(font->msgBuf, sizeof(font->msgBuf));
} else {
msgCtx->msgLength = font->msgLength = Randomizer_CopyGanonHintText(font->msgBuf, sizeof(font->msgBuf));
}
} else {
msgCtx->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset;
memcpy(font->msgBuf, src, font->msgLength);
}
} }
msgCtx->textBoxProperties = font->charTexBuf[0]; msgCtx->textBoxProperties = font->charTexBuf[0];

View File

@ -279,11 +279,15 @@ void Gameplay_Init(GameState* thisx) {
u8 tempSetupIndex; u8 tempSetupIndex;
s32 pad[2]; s32 pad[2];
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH)) { // Skip Child Stealth when option is enabled, Zelda's Letter isn't obtained and Impa's reward hasn't been received
// eventChkInf[4] & 1 = Got Zelda's Letter
// eventChkInf[5] & 0x200 = Got Impa's reward
// entranceIndex 0x7A, Castle Courtyard - Day from crawlspace
// entranceIndex 0x400, Zelda's Courtyard
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH) &&
!(gSaveContext.eventChkInf[4] & 1) && !(gSaveContext.eventChkInf[5] & 0x200)) {
if (gSaveContext.entranceIndex == 0x7A) { if (gSaveContext.entranceIndex == 0x7A) {
gSaveContext.entranceIndex = 0x400; gSaveContext.entranceIndex = 0x400;
} else if (gSaveContext.entranceIndex == 0x296) {
gSaveContext.entranceIndex = 0x23D;
} }
} }

View File

@ -793,12 +793,12 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.eventChkInf[1] |= (1 << 3); gSaveContext.eventChkInf[1] |= (1 << 3);
gSaveContext.eventChkInf[1] |= (1 << 4); gSaveContext.eventChkInf[1] |= (1 << 4);
// Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM. TODO: Is this flag used for anything else?
gSaveContext.eventChkInf[4] |= 1;
// Got item from impa // Got item from impa
gSaveContext.eventChkInf[5] |= 0x200; gSaveContext.eventChkInf[5] |= 0x200;
// make sure saria is at SFM
gSaveContext.eventChkInf[4] |= (1 << 0);
// set this at the end to ensure we always start with the letter // set this at the end to ensure we always start with the letter
// this is for the off chance we got the weird egg from impa (which should never happen) // this is for the off chance we got the weird egg from impa (which should never happen)
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA; INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;

View File

@ -24,7 +24,7 @@ typedef struct {
/* 0x36 */ f32 pitch; /* 0x36 */ f32 pitch;
/* 0x36 */ f32 yaw; /* 0x36 */ f32 yaw;
/* 0x40 */ f32 roll; /* 0x40 */ f32 roll;
/* 0x44 */ s32 epoch; /* 0x44 */ u32 epoch;
} BgDyYoseizoParticle; // size = 0x48 } BgDyYoseizoParticle; // size = 0x48
typedef struct BgDyYoseizo { typedef struct BgDyYoseizo {

View File

@ -13,7 +13,7 @@ typedef struct {
/* 0x0C */ Vec3f vel; /* 0x0C */ Vec3f vel;
/* 0x18 */ s16 rotVelX; /* 0x18 */ s16 rotVelX;
/* 0x1A */ s16 rotVelY; /* 0x1A */ s16 rotVelY;
/* 0x1C */ s32 epoch; /* 0x1C */ u32 epoch;
} BgJyaMegamiPiece; // size = 0x20 } BgJyaMegamiPiece; // size = 0x20
typedef struct BgJyaMegami { typedef struct BgJyaMegami {

View File

@ -261,7 +261,7 @@ void BgSpot00Hanebasi_DrawTorches(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2; GlobalContext* globalCtx = globalCtx2;
f32 angle; f32 angle;
s32 i; s32 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -17,7 +17,7 @@ typedef struct {
/* 0x26 */ Color_RGB8 color; /* 0x26 */ Color_RGB8 color;
/* 0x2A */ s16 alpha; /* 0x2A */ s16 alpha;
/* 0x2C */ f32 unk_2C; /* 0x2C */ f32 unk_2C;
/* 0x30 */ s32 epoch; /* 0x30 */ u32 epoch;
} BossDodongoEffect; // Size = 0x34 } BossDodongoEffect; // Size = 0x34
typedef struct BossDodongo { typedef struct BossDodongo {

View File

@ -1835,7 +1835,7 @@ void BossFd_DrawBody(GlobalContext* globalCtx, BossFd* this) {
s16 i; s16 i;
f32 temp_float; f32 temp_float;
Mtx* tempMat = Graph_Alloc(globalCtx->state.gfxCtx, 18 * sizeof(Mtx)); Mtx* tempMat = Graph_Alloc(globalCtx->state.gfxCtx, 18 * sizeof(Mtx));
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -87,7 +87,7 @@ typedef struct BossFd2 {
/* 0x1394 */ BossFd2Cam camData; /* 0x1394 */ BossFd2Cam camData;
/* 0x141C */ ColliderJntSph collider; /* 0x141C */ ColliderJntSph collider;
/* 0x143C */ ColliderJntSphElement elements[9]; /* 0x143C */ ColliderJntSphElement elements[9];
/* 0x167C */ s32 epoch; /* 0x167C */ u32 epoch;
} BossFd2; // size = 0x1680 } BossFd2; // size = 0x1680
#endif #endif

View File

@ -3356,7 +3356,7 @@ void BossGanon_DrawShock(BossGanon* this, GlobalContext* globalCtx) {
s32 pad; s32 pad;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);
@ -3463,7 +3463,7 @@ void BossGanon_DrawBigMagicCharge(BossGanon* this, GlobalContext* globalCtx) {
f32 yRot; f32 yRot;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);
@ -4158,7 +4158,7 @@ void BossGanon_LightBall_Draw(Actor* thisx, GlobalContext* globalCtx) {
s16 i; s16 i;
f32 alpha; f32 alpha;
s32 pad; s32 pad;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -2464,7 +2464,7 @@ void func_80904340(BossGanon2* this, GlobalContext* globalCtx) {
f32 angle; f32 angle;
f32 sin; f32 sin;
f32 cos; f32 cos;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -2637,7 +2637,7 @@ void BossGanon2_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dLis
void func_80904D88(BossGanon2* this, GlobalContext* globalCtx) { void func_80904D88(BossGanon2* this, GlobalContext* globalCtx) {
s32 pad; s32 pad;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -2701,7 +2701,7 @@ void func_80904FC8(BossGanon2* this, GlobalContext* globalCtx) {
void func_8090523C(BossGanon2* this, GlobalContext* globalCtx) { void func_8090523C(BossGanon2* this, GlobalContext* globalCtx) {
Player* player; Player* player;
f32 phi_f20; f32 phi_f20;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -2933,7 +2933,7 @@ void func_809060E8(GlobalContext* globalCtx) {
BossGanon2Effect* effect; BossGanon2Effect* effect;
s16 i; s16 i;
BossGanon2Effect* effects; BossGanon2Effect* effects;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
effects = effect = globalCtx->specialEffects; effects = effect = globalCtx->specialEffects;

View File

@ -2443,7 +2443,7 @@ void BossMo_DrawTentacle(BossMo* this, GlobalContext* globalCtx) {
f32 phi_f20; f32 phi_f20;
f32 phi_f22; f32 phi_f22;
Vec3f sp110; Vec3f sp110;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -2706,7 +2706,7 @@ s32 BossSst_OverrideHandTrailDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx**
void BossSst_DrawHand(Actor* thisx, GlobalContext* globalCtx) { void BossSst_DrawHand(Actor* thisx, GlobalContext* globalCtx) {
BossSst* this = (BossSst*)thisx; BossSst* this = (BossSst*)thisx;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -17,7 +17,7 @@ typedef struct {
/* 0x0020 */ s16 move; /* 0x0020 */ s16 move;
/* 0x0022 */ s16 status; /* 0x0022 */ s16 status;
/* 0x0024 */ u8 alpha; /* 0x0024 */ u8 alpha;
/* 0x0028 */ s32 epoch; /* 0x0028 */ u32 epoch;
} BossSstEffect; // size = 0x2C } BossSstEffect; // size = 0x2C
typedef struct { typedef struct {

View File

@ -3329,7 +3329,7 @@ void func_80942180(BossTw* this, GlobalContext* globalCtx) {
void func_809426F0(BossTw* this, GlobalContext* globalCtx) { void func_809426F0(BossTw* this, GlobalContext* globalCtx) {
s32 pad; s32 pad;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -4418,7 +4418,7 @@ void BossTw_BlastDraw(Actor* thisx, GlobalContext* globalCtx2) {
f32 scaleFactor; f32 scaleFactor;
s16 tailIdx; s16 tailIdx;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -4492,7 +4492,7 @@ void BossTw_DrawDeathBall(Actor* thisx, GlobalContext* globalCtx2) {
f32 scaleFactor; f32 scaleFactor;
s16 tailIdx; s16 tailIdx;
s16 i; s16 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -43,7 +43,7 @@ typedef struct {
/* 0x002E */ s16 work[EFF_WORK_MAX]; /* 0x002E */ s16 work[EFF_WORK_MAX];
/* 0x0034 */ f32 workf[EFF_FWORK_MAX]; /* 0x0034 */ f32 workf[EFF_FWORK_MAX];
/* 0x0044 */ Actor* target; /* 0x0044 */ Actor* target;
s32 epoch; u32 epoch;
} BossTwEffect; } BossTwEffect;
typedef enum { typedef enum {

View File

@ -4006,7 +4006,7 @@ void BossVa_DrawDoor(GlobalContext* globalCtx, s16 scale) {
f32 yScale; f32 yScale;
f32 segAngle = 0.0f; f32 segAngle = 0.0f;
s32 i; s32 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -564,7 +564,7 @@ void func_80967FFC(Actor* thisx, GlobalContext* globalCtx) {
Demo6K* this = (Demo6K*)thisx; Demo6K* this = (Demo6K*)thisx;
s32 pad; s32 pad;
u16 timer1 = this->timer1; u16 timer1 = this->timer1;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -695,7 +695,7 @@ void func_809688C4(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2; GlobalContext* globalCtx = globalCtx2;
u32 frames = globalCtx->state.frames; u32 frames = globalCtx->state.frames;
s32 i; s32 i;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
if ((i = (globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->csCtx.npcActions[1] != NULL)) && if ((i = (globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->csCtx.npcActions[1] != NULL)) &&

View File

@ -522,7 +522,7 @@ void DemoKankyo_DrawRain(Actor* thisx, GlobalContext* globalCtx) {
f32 translateY; f32 translateY;
f32 translateZ; f32 translateZ;
s16 j; s16 j;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -663,7 +663,7 @@ void DemoKankyo_DrawClouds(Actor* thisx, GlobalContext* globalCtx) {
f32 dx; f32 dx;
f32 dy; f32 dy;
f32 dz; f32 dz;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -784,7 +784,7 @@ void DemoKankyo_DrawWarpSparkles(Actor* thisx, GlobalContext* globalCtx) {
f32 translateZ; f32 translateZ;
PosRot posRot; PosRot posRot;
u8 linkAge = gSaveContext.linkAge; u8 linkAge = gSaveContext.linkAge;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);
@ -933,7 +933,7 @@ void DemoKankyo_DrawSparkles(Actor* thisx, GlobalContext* globalCtx) {
f32 scale; f32 scale;
s16 i; s16 i;
PosRot posRot; PosRot posRot;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -19,7 +19,7 @@ typedef struct {
/* 0x30 */ char unk_2C[4]; /* 0x30 */ char unk_2C[4];
/* 0x34 */ f32 scale; /* 0x34 */ f32 scale;
/* 0x38 */ char unk_34[8]; /* 0x38 */ char unk_34[8];
/* 0x3C */ s32 epoch; /* 0x3C */ u32 epoch;
} EfcErupcParticles; // size 0x40 } EfcErupcParticles; // size 0x40
#define EFC_ERUPC_NUM_PARTICLES 100 #define EFC_ERUPC_NUM_PARTICLES 100

View File

@ -269,7 +269,7 @@ void EffDust_DrawFunc_8099E4F4(Actor* thisx, GlobalContext* globalCtx2) {
f32* distanceTraveled; f32* distanceTraveled;
s32 i; s32 i;
f32 aux; f32 aux;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);
@ -321,7 +321,7 @@ void EffDust_DrawFunc_8099E784(Actor* thisx, GlobalContext* globalCtx2) {
s32 i; s32 i;
f32 aux; f32 aux;
Player* player = GET_PLAYER(globalCtx); Player* player = GET_PLAYER(globalCtx);
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(gfxCtx); OPEN_DISPS(gfxCtx);

View File

@ -19,7 +19,7 @@ typedef struct EnAnubiceFire {
/* 0x015E */ s16 unk_15E; /* 0x015E */ s16 unk_15E;
/* 0x0178 */ Vec3f unk_160[6]; /* 0x0178 */ Vec3f unk_160[6];
/* 0x01A8 */ ColliderCylinder cylinder; /* 0x01A8 */ ColliderCylinder cylinder;
/* 0x01F4 */ s32 epoch; /* 0x01F4 */ u32 epoch;
} EnAnubiceFire; // size = 0x01F8 } EnAnubiceFire; // size = 0x01F8
#endif #endif

View File

@ -32,7 +32,7 @@ typedef struct EnBa {
/* 0x031C */ s16 unk31C; /* 0x031C */ s16 unk31C;
/* 0x0320 */ ColliderJntSph collider; /* 0x0320 */ ColliderJntSph collider;
/* 0x0340 */ ColliderJntSphElement colliderItems[2]; /* 0x0340 */ ColliderJntSphElement colliderItems[2];
/* 0x03C0 */ s32 epoch; /* 0x03C0 */ u32 epoch;
} EnBa; // size = 0x03C4 } EnBa; // size = 0x03C4
#endif #endif

View File

@ -167,12 +167,12 @@ void EnBoom_Fly(EnBoom* this, GlobalContext* globalCtx) {
// Decrement the return timer and check if it's 0. If it is, check if Link can catch it and handle accordingly. // Decrement the return timer and check if it's 0. If it is, check if Link can catch it and handle accordingly.
// Otherwise handle grabbing and colliding. // Otherwise handle grabbing and colliding.
if (DECR(this->returnTimer) == 0) { if (DECR(this->returnTimer) == 0 || player->boomerangQuickRecall) {
distFromLink = Math_Vec3f_DistXYZ(&this->actor.world.pos, &player->actor.focus.pos); distFromLink = Math_Vec3f_DistXYZ(&this->actor.world.pos, &player->actor.focus.pos);
this->moveTo = &player->actor; this->moveTo = &player->actor;
// If the boomerang is less than 40 units away from Link, he can catch it. // If the boomerang is less than 40 units away from Link, he can catch it.
if (distFromLink < 40.0f) { if (distFromLink < 40.0f || player->boomerangQuickRecall) {
target = this->grabbed; target = this->grabbed;
if (target != NULL) { if (target != NULL) {
Math_Vec3f_Copy(&target->world.pos, &player->actor.world.pos); Math_Vec3f_Copy(&target->world.pos, &player->actor.world.pos);
@ -187,7 +187,8 @@ void EnBoom_Fly(EnBoom* this, GlobalContext* globalCtx) {
} }
} }
// Set player flags and kill the boomerang beacause Link caught it. // Set player flags and kill the boomerang beacause Link caught it.
player->stateFlags1 &= ~0x02000000; player->stateFlags1 &= ~PLAYER_STATE1_25;
player->boomerangQuickRecall = false;
Actor_Kill(&this->actor); Actor_Kill(&this->actor);
} }
} else { } else {

View File

@ -16,7 +16,7 @@ typedef struct EnBx {
/* 0x01B4 */ Vec3s unk_1B4[4]; /* 0x01B4 */ Vec3s unk_1B4[4];
/* 0x01CC */ ColliderCylinder collider; /* 0x01CC */ ColliderCylinder collider;
/* 0x0218 */ ColliderQuad colliderQuad; /* 0x0218 */ ColliderQuad colliderQuad;
/* 0x0298 */ s32 epoch; /* 0x0298 */ u32 epoch;
} EnBx; // size = 0x029C } EnBx; // size = 0x029C
#endif #endif

View File

@ -88,7 +88,7 @@ typedef struct EnClearTagEffect {
/* 0x0058 */ f32 rotationX; /* 0x0058 */ f32 rotationX;
/* 0x005C */ f32 floorHeight; /* 0x005C */ f32 floorHeight;
/* 0x0060 */ Vec3f floorTangent; /* 0x0060 */ Vec3f floorTangent;
/* 0x006C */ s32 epoch; /* 0x006C */ u32 epoch;
} EnClearTagEffect; // size = 0x70 } EnClearTagEffect; // size = 0x70
#define CLEAR_TAG_EFFECT_MAX_COUNT 100 #define CLEAR_TAG_EFFECT_MAX_COUNT 100

View File

@ -14,7 +14,7 @@ typedef struct {
/* 0x0010 */ u8 isAlive; /* 0x0010 */ u8 isAlive;
/* 0x0014 */ Vec3f moveDirection; /* 0x0014 */ Vec3f moveDirection;
/* 0x0020 */ Vec3f rot; /* 0x0020 */ Vec3f rot;
/* 0x002C */ s32 epoch; /* 0x002C */ u32 epoch;
} EnEncount2Particle; // size = 0x30 } EnEncount2Particle; // size = 0x30
typedef struct EnEncount2 { typedef struct EnEncount2 {

View File

@ -25,7 +25,7 @@ typedef struct {
/* 0x0014 */ Vec3f pos; /* 0x0014 */ Vec3f pos;
/* 0x0020 */ Vec3f velocity; /* 0x0020 */ Vec3f velocity;
/* 0x002C */ Vec3f accel; /* 0x002C */ Vec3f accel;
s32 epoch; u32 epoch;
} EnFdEffect; // size = 0x38 } EnFdEffect; // size = 0x38
typedef struct EnFd { typedef struct EnFd {

View File

@ -19,7 +19,7 @@ typedef struct {
/* 0x0014 */ Vec3f pos; /* 0x0014 */ Vec3f pos;
/* 0x0020 */ Vec3f velocity; /* 0x0020 */ Vec3f velocity;
/* 0x002C */ Vec3f accel; /* 0x002C */ Vec3f accel;
s32 epoch; u32 epoch;
} EnFwEffect; } EnFwEffect;
typedef struct EnFw { typedef struct EnFw {

View File

@ -21,7 +21,7 @@ typedef struct {
/* 0x0030 */ f32 xyScale; // /* 0x0030 */ f32 xyScale; //
/* 0x0034 */ f32 xyScaleTarget; /* 0x0034 */ f32 xyScaleTarget;
/* 0x0038 */ u8 isTimerMod8; // conditional, used to run CollisionCheck_SetAT /* 0x0038 */ u8 isTimerMod8; // conditional, used to run CollisionCheck_SetAT
s32 epoch; u32 epoch;
} EnFzEffectSsIceSmoke; // size = 0x3C } EnFzEffectSsIceSmoke; // size = 0x3C
typedef struct EnFz { typedef struct EnFz {

View File

@ -32,7 +32,7 @@ typedef struct {
/* 0x12 */ u8 flag; /* 0x12 */ u8 flag;
/* 0x14 */ Vec3f velocity; /* 0x14 */ Vec3f velocity;
/* 0x20 */ Vec3f rot; /* 0x20 */ Vec3f rot;
s32 epoch; u32 epoch;
} EnGSwitchEffect; // size = 0x2C } EnGSwitchEffect; // size = 0x2C
typedef struct EnGSwitch { typedef struct EnGSwitch {

View File

@ -27,7 +27,7 @@ typedef struct {
/* 0x20 */ f32 unk_20; /* 0x20 */ f32 unk_20;
/* 0x24 */ f32 unk_24; /* 0x24 */ f32 unk_24;
/* 0x28 */ f32 unk_28; /* 0x28 */ f32 unk_28;
s32 epoch; u32 epoch;
} EnGbCagedSoul; // size = 0x2C } EnGbCagedSoul; // size = 0x2C
typedef struct EnGb { typedef struct EnGb {

View File

@ -34,7 +34,7 @@ typedef struct {
/* 0x0014 */ Vec3f pos; /* 0x0014 */ Vec3f pos;
/* 0x0020 */ Vec3f velocity; /* 0x0020 */ Vec3f velocity;
/* 0x002C */ Vec3f accel; /* 0x002C */ Vec3f accel;
s32 epoch; u32 epoch;
} EnGoEffect; // size = 0x38 } EnGoEffect; // size = 0x38
typedef struct EnGo { typedef struct EnGo {

View File

@ -112,14 +112,23 @@ void EnHeishi1_Init(Actor* thisx, GlobalContext* globalCtx) {
} }
} }
// eventChkInf[4] & 1 = Got Zelda's Letter
// eventChkInf[5] & 0x200 = Got item from impa
// eventChkInf[8] & 1 = Ocarina thrown in moat
bool metZelda = (gSaveContext.eventChkInf[4] & 1) && (gSaveContext.eventChkInf[5] & 0x200);
if (this->type != 5) { if (this->type != 5) {
if (((gSaveContext.dayTime < 0xB888) || IS_DAY) && (gSaveContext.n64ddFlag || !(gSaveContext.eventChkInf[8] & 1))) { if ((gSaveContext.dayTime < 0xB888 || IS_DAY) &&
((!gSaveContext.n64ddFlag && !(gSaveContext.eventChkInf[8] & 1)) ||
(gSaveContext.n64ddFlag && !metZelda))) {
this->actionFunc = EnHeishi1_SetupWalk; this->actionFunc = EnHeishi1_SetupWalk;
} else { } else {
Actor_Kill(&this->actor); Actor_Kill(&this->actor);
} }
} else { } else {
if ((gSaveContext.dayTime >= 0xB889) || !IS_DAY || (!gSaveContext.n64ddFlag && (gSaveContext.eventChkInf[8] & 1))) { if ((gSaveContext.dayTime >= 0xB889) || !IS_DAY ||
(!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[8] & 1) ||
(gSaveContext.n64ddFlag && metZelda)) {
this->actionFunc = EnHeishi1_SetupWaitNight; this->actionFunc = EnHeishi1_SetupWaitNight;
} else { } else {
Actor_Kill(&this->actor); Actor_Kill(&this->actor);

View File

@ -18,7 +18,7 @@ typedef struct {
/* 0x002C */ f32 scale; /* 0x002C */ f32 scale;
/* 0x0030 */ f32 unk_30; /* 0x0030 */ f32 unk_30;
/* 0x0034 */ u8 timer; /* 0x0034 */ u8 timer;
s32 epoch; u32 epoch;
} EnNiwFeather; // size = 0x0038 } EnNiwFeather; // size = 0x0038
typedef struct EnNiw { typedef struct EnNiw {

View File

@ -23,7 +23,7 @@ typedef struct EnNwcChick {
/* 0x36 */ u16 height; /* 0x36 */ u16 height;
/* 0x38 */ CollisionPoly* floorPoly; /* 0x38 */ CollisionPoly* floorPoly;
/* 0x44 */ char unk_3C[0x20]; /* 0x44 */ char unk_3C[0x20];
s32 epoch; u32 epoch;
} EnNwcChick; // size = 0x5C } EnNwcChick; // size = 0x5C
typedef struct EnNwc { typedef struct EnNwc {

View File

@ -30,7 +30,7 @@ typedef struct EnNy {
/* 0x01F0 */ f32 unk_1F0; /* 0x01F0 */ f32 unk_1F0;
/* 0x01F4 */ f32 unk_1F4; /* 0x01F4 */ f32 unk_1F4;
/* 0x01F8 */ Vec3f unk_1F8[16]; /* 0x01F8 */ Vec3f unk_1F8[16];
s32 epoch; u32 epoch;
} EnNy; // size = 0x02B8 } EnNy; // size = 0x02B8
#endif #endif

View File

@ -29,7 +29,7 @@ typedef struct EnPoSisters {
/* 0x029C */ LightInfo lightInfo; /* 0x029C */ LightInfo lightInfo;
/* 0x02AC */ ColliderCylinder collider; /* 0x02AC */ ColliderCylinder collider;
/* 0x02F8 */ MtxF unk_2F8; /* 0x02F8 */ MtxF unk_2F8;
s32 epoch; u32 epoch;
} EnPoSisters; // size = 0x0338 } EnPoSisters; // size = 0x0338
#endif #endif

View File

@ -760,6 +760,14 @@ void func_80AEC2C0(EnRu1* this, GlobalContext* globalCtx) {
func_80AEC070(this, globalCtx, something); func_80AEC070(this, globalCtx, something);
} }
// Convenience function used so that Ruto always spawns in Jabu in rando, even after she's been kidnapped
// Equivalent to !(gSaveContext.infTable[20] & 0x20) in vanilla
bool shouldSpawnRuto() {
// gSaveContext.infTable[20] & 0x40 check is to prevent Ruto from spawning during the short period of time when
// she's on the Zora's Sapphire pedestal but hasn't been kidnapped yet (would result in multiple Rutos otherwise)
return !(gSaveContext.infTable[20] & 0x20) || (gSaveContext.n64ddFlag && (gSaveContext.infTable[20] & 0x40));
}
void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) { void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) {
s8 actorRoom; s8 actorRoom;
@ -767,8 +775,7 @@ void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
this->action = 7; this->action = 7;
EnRu1_SetMouthIndex(this, 1); EnRu1_SetMouthIndex(this, 1);
} else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) && } else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) && shouldSpawnRuto()) {
!(gSaveContext.infTable[20] & 0x20)) {
if (!func_80AEB020(this, globalCtx)) { if (!func_80AEB020(this, globalCtx)) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
actorRoom = this->actor.room; actorRoom = this->actor.room;
@ -1172,7 +1179,7 @@ void func_80AED414(EnRu1* this, GlobalContext* globalCtx) {
void func_80AED44C(EnRu1* this, GlobalContext* globalCtx) { void func_80AED44C(EnRu1* this, GlobalContext* globalCtx) {
s8 actorRoom; s8 actorRoom;
if ((gSaveContext.infTable[20] & 2) && !(gSaveContext.infTable[20] & 0x20) && !(gSaveContext.infTable[20] & 1) && if ((gSaveContext.infTable[20] & 2) && shouldSpawnRuto() && !(gSaveContext.infTable[20] & 1) &&
!(gSaveContext.infTable[20] & 0x80)) { !(gSaveContext.infTable[20] & 0x80)) {
if (!func_80AEB020(this, globalCtx)) { if (!func_80AEB020(this, globalCtx)) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
@ -2179,7 +2186,7 @@ void func_80AEFF40(EnRu1* this, GlobalContext* globalCtx) {
void func_80AEFF94(EnRu1* this, GlobalContext* globalCtx) { void func_80AEFF94(EnRu1* this, GlobalContext* globalCtx) {
s8 actorRoom; s8 actorRoom;
if ((gSaveContext.infTable[20] & 2) && (gSaveContext.infTable[20] & 1) && !(gSaveContext.infTable[20] & 0x20) && if ((gSaveContext.infTable[20] & 2) && (gSaveContext.infTable[20] & 1) && shouldSpawnRuto() &&
(!(func_80AEB020(this, globalCtx)))) { (!(func_80AEB020(this, globalCtx)))) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
actorRoom = this->actor.room; actorRoom = this->actor.room;

View File

@ -18,7 +18,7 @@ typedef struct {
/* 0x2C */ f32 unk_2C; /* 0x2C */ f32 unk_2C;
/* 0x30 */ f32 unk_30; /* 0x30 */ f32 unk_30;
/* 0x34 */ u8 unk_34; /* 0x34 */ u8 unk_34;
s32 epoch; u32 epoch;
} EnSyatekiNiw_1; // size = 0x38 } EnSyatekiNiw_1; // size = 0x38
typedef struct EnSyatekiNiw { typedef struct EnSyatekiNiw {

View File

@ -460,10 +460,13 @@ void func_80B14AF4(EnTa* this, GlobalContext* globalCtx) {
void func_80B14B6C(EnTa* this, GlobalContext* globalCtx) { void func_80B14B6C(EnTa* this, GlobalContext* globalCtx) {
if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) { if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) {
OnePointCutscene_Init(globalCtx, 4175, -99, &this->actor, MAIN_CAM); s16 csCamIdx = OnePointCutscene_Init(globalCtx, 4175, -99, &this->actor, MAIN_CAM);
func_80B13AA0(this, func_80B14AF4, func_80B167C0); func_80B13AA0(this, func_80B14AF4, func_80B167C0);
this->unk_2CC = 5; this->unk_2CC = 5;
gSaveContext.eventChkInf[1] |= 0x10; gSaveContext.eventChkInf[1] |= 0x10;
if (gSaveContext.n64ddFlag) {
OnePointCutscene_EndCutscene(globalCtx, csCamIdx);
}
Animation_PlayOnce(&this->skelAnime, &gTalonRunTransitionAnim); Animation_PlayOnce(&this->skelAnime, &gTalonRunTransitionAnim);
this->currentAnimation = &gTalonRunAnim; this->currentAnimation = &gTalonRunAnim;
} }

View File

@ -17,7 +17,7 @@ typedef struct EnTkEff {
/* 0x0014 */ Vec3f pos; /* 0x0014 */ Vec3f pos;
/* 0x0020 */ Vec3f speed; /* 0x0020 */ Vec3f speed;
/* 0x002C */ Vec3f accel; /* 0x002C */ Vec3f accel;
s32 epoch; u32 epoch;
} EnTkEff; // size = 0x0038 } EnTkEff; // size = 0x0038
struct EnTk; struct EnTk;

View File

@ -56,7 +56,7 @@ typedef struct {
/* 0x28 */ f32 scale; /* 0x28 */ f32 scale;
/* 0x2C */ f32 lerpFactor; /* 0x2C */ f32 lerpFactor;
/* 0x30 */ u8 state; /* 0x30 */ u8 state;
s32 epoch; u32 epoch;
} EnViewerFireEffect; // size = 0x34 } EnViewerFireEffect; // size = 0x34
typedef struct EnViewer { typedef struct EnViewer {

View File

@ -90,7 +90,7 @@ typedef struct {
/* 0x32 */ s16 timer; /* 0x32 */ s16 timer;
/* 0x34 */ u8 shouldDraw; /* 0x34 */ u8 shouldDraw;
/* 0x38 */ f32 drawDistance; /* 0x38 */ f32 drawDistance;
s32 epoch; u32 epoch;
} FishingProp; // size = 0x3C } FishingProp; // size = 0x3C
typedef enum { typedef enum {
@ -116,7 +116,7 @@ typedef struct {
/* 0x40 */ s16 unk_40; /* 0x40 */ s16 unk_40;
/* 0x42 */ s16 unk_42; /* 0x42 */ s16 unk_42;
/* 0x44 */ u8 shouldDraw; /* 0x44 */ u8 shouldDraw;
s32 epoch; u32 epoch;
} FishingGroupFish; // size = 0x48 } FishingGroupFish; // size = 0x48
#define LINE_SEG_COUNT 200 #define LINE_SEG_COUNT 200
@ -1766,7 +1766,7 @@ static f32 sSinkingLureSizes[] = {
void Fishing_DrawSinkingLure(GlobalContext* globalCtx) { void Fishing_DrawSinkingLure(GlobalContext* globalCtx) {
s16 i; s16 i;
f32 scale; f32 scale;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx); OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -482,7 +482,7 @@ void MirRay_Draw(Actor* thisx, GlobalContext* globalCtx) {
s32 i; s32 i;
MirRayShieldReflection reflection[6]; MirRayShieldReflection reflection[6];
s32 temp; s32 temp;
static s32 epoch = 0; static u32 epoch = 0;
epoch++; epoch++;
this->reflectIntensity = 0.0f; this->reflectIntensity = 0.0f;

View File

@ -20,6 +20,7 @@
#include "objects/gameplay_keep/gameplay_keep.h" #include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_link_child/object_link_child.h" #include "objects/object_link_child/object_link_child.h"
#include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h"
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
//typedef struct { //typedef struct {
// /* 0x00 */ u8 itemId; // /* 0x00 */ u8 itemId;
@ -146,10 +147,10 @@ s32 func_808353D8(Player* this, GlobalContext* globalCtx);
s32 func_80835588(Player* this, GlobalContext* globalCtx); s32 func_80835588(Player* this, GlobalContext* globalCtx);
s32 func_808356E8(Player* this, GlobalContext* globalCtx); s32 func_808356E8(Player* this, GlobalContext* globalCtx);
s32 func_80835800(Player* this, GlobalContext* globalCtx); s32 func_80835800(Player* this, GlobalContext* globalCtx);
s32 func_80835884(Player* this, GlobalContext* globalCtx); s32 func_80835884(Player* this, GlobalContext* globalCtx); // Start aiming boomerang
s32 func_808358F0(Player* this, GlobalContext* globalCtx); s32 func_808358F0(Player* this, GlobalContext* globalCtx); // Aim boomerang
s32 func_808359FC(Player* this, GlobalContext* globalCtx); s32 func_808359FC(Player* this, GlobalContext* globalCtx); // Throw boomerang
s32 func_80835B60(Player* this, GlobalContext* globalCtx); s32 func_80835B60(Player* this, GlobalContext* globalCtx); // Boomerang active
s32 func_80835C08(Player* this, GlobalContext* globalCtx); s32 func_80835C08(Player* this, GlobalContext* globalCtx);
void func_80835F44(GlobalContext* globalCtx, Player* this, s32 item); void func_80835F44(GlobalContext* globalCtx, Player* this, s32 item);
void func_80839F90(Player* this, GlobalContext* globalCtx); void func_80839F90(Player* this, GlobalContext* globalCtx);
@ -487,8 +488,8 @@ static s32 D_80853604 = 0;
static s32 D_80853608 = 0; static s32 D_80853608 = 0;
static s32 D_8085360C = 0; static s32 D_8085360C = 0;
static s16 D_80853610 = 0; static s16 D_80853610 = 0;
static s32 D_80853614 = 0; static s32 D_80853614 = 0; // Held item button just pressed?
static s32 D_80853618 = 0; static s32 D_80853618 = 0; // Held item button currently down?
static u16 D_8085361C[] = { static u16 D_8085361C[] = {
NA_SE_VO_LI_SWEAT, NA_SE_VO_LI_SWEAT,
@ -653,15 +654,15 @@ static GetItemEntry sGetItemTable[] = {
GET_ITEM(ITEM_DOUBLE_MAGIC, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_DOUBLE_MAGIC, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_DOUBLE_DEFENSE, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xE9, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_DOUBLE_DEFENSE, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xE9, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, 0x44, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, 0x45, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x46, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0x5D, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, 0x7A, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, 0x97, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, 0xF9, 0x80, CHEST_ANIM_LONG), GET_ITEM(ITEM_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG),
GET_ITEM_NONE, GET_ITEM_NONE,
GET_ITEM_NONE, GET_ITEM_NONE,
@ -955,6 +956,7 @@ static s8 sItemActionParams[] = {
static u8 sMaskMemory; static u8 sMaskMemory;
// Used to map action params to update functions
static s32(*D_80853EDC[])(Player* this, GlobalContext* globalCtx) = { static s32(*D_80853EDC[])(Player* this, GlobalContext* globalCtx) = {
func_8083485C, func_8083485C, func_8083485C, func_808349DC, func_808349DC, func_808349DC, func_8083485C, func_8083485C, func_8083485C, func_8083485C, func_808349DC, func_808349DC, func_808349DC, func_8083485C,
func_8083485C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083485C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C,
@ -2734,6 +2736,10 @@ s32 func_80835B60(Player* this, GlobalContext* globalCtx) {
return 1; return 1;
} }
if (D_80853614 && CVar_GetS32("gFastBoomerang", 0)) {
this->boomerangQuickRecall = true;
}
return 0; return 0;
} }

View File

@ -11,7 +11,7 @@ typedef struct {
/* 0x24 */ s16 scale; /* 0x24 */ s16 scale;
/* 0x26 */ s16 scaleStep; /* 0x26 */ s16 scaleStep;
/* 0x28 */ u8 drawMode; /* 0x28 */ u8 drawMode;
/* 0x29 */ s32 epoch; /* 0x29 */ u32 epoch;
} EffectSsBomb2InitParams; // size = 0x30 } EffectSsBomb2InitParams; // size = 0x30
#endif #endif

View File

@ -12,12 +12,12 @@ static s16 sEquipMoveTimer = 10;
bool gSelectingMask; bool gSelectingMask;
static s16 sAmmoVtxOffset[] = { static s16 sAmmoVtxOffset[] = {
0, 2, 4, 6, 99, 99, 8, 99, 99, 10, 99, 99, 99, 99, 99, 99, 12, 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12,
}; };
extern const char* _gAmmoDigit0Tex[]; extern const char* _gAmmoDigit0Tex[];
void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item) { void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) {
s16 ammo; s16 ammo;
s16 i; s16 i;
@ -51,7 +51,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx,
gDPPipeSync(POLY_KAL_DISP++); gDPPipeSync(POLY_KAL_DISP++);
if (i != 0) { if (i != 0) {
gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[item] + 31) * 4], 4, 0); gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[slot] + 31) * 4], 4, 0);
gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[i]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0, gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[i]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
@ -60,7 +60,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx,
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
} }
gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[item] + 32) * 4], 4, 0); gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[(sAmmoVtxOffset[slot] + 32) * 4], 4, 0);
gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[ammo]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0, gDPLoadTextureBlock(POLY_KAL_DISP++, ((u8*)_gAmmoDigit0Tex[ammo]), G_IM_FMT_IA, G_IM_SIZ_8b, 8, 8, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
@ -499,7 +499,7 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) {
for (i = 0; i < 15; i++) { for (i = 0; i < 15; i++) {
if ((gAmmoItems[i] != ITEM_NONE) && (gSaveContext.inventory.items[i] != ITEM_NONE)) { if ((gAmmoItems[i] != ITEM_NONE) && (gSaveContext.inventory.items[i] != ITEM_NONE)) {
KaleidoScope_DrawAmmoCount(pauseCtx, globalCtx->state.gfxCtx, gSaveContext.inventory.items[i]); KaleidoScope_DrawAmmoCount(pauseCtx, globalCtx->state.gfxCtx, gSaveContext.inventory.items[i], i);
} }
} }