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
1. Requires Visual Studio 2022 Community Edition && `python3, cmake, git` (can be installed via chocolatey or manually)
2. Clone the Ship of Harkinian repository
3. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice
Requires:
* At least 8GB of RAM (machines with 4GB have seen complier failures)
* 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_
```powershell
@ -30,8 +48,10 @@ With the cmake build system you have two options for working on the project:
#### Visual Studio
To develop using Visual Studio you only need to use cmake to generate the solution file:
```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
# 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
@ -53,7 +73,7 @@ cd "build/x64"
```
## 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!**
@ -91,7 +111,7 @@ cpack -G External (creates appimage)
```
## 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!**

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
################################################################################
set(CMAKE_CONFIGURATION_TYPES
"Debug"
"Release"
CACHE STRING "" FORCE
)
if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
set(CMAKE_C_FLAGS_DEBUG "-O3 -ffast-math")
set(CMAKE_CXX_FLAGS_DEBUG "-O3 -ffast-math")
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 )
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)
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)
add_custom_target(
ExtractAssets
COMMAND ${CMAKE_COMMAND} -Dprogram=$<TARGET_FILE:ZAPD> -P ${CMAKE_SOURCE_DIR}/CMake/genscript.cmake
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_BINARY_DIR}/soh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
COMMENT "Running asset extraction..."
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")

68
Jenkinsfile vendored
View File

@ -8,12 +8,35 @@ pipeline {
}
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') {
parallel {
stage ('Build Windows') {
options {
timeout(time: 20)
}
environment {
PLATFORM='x64'
PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe'
@ -34,12 +57,9 @@ pipeline {
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
bat """
xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\"
unstash 'assets'
bat """
"${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
cd ".\\build\\${env.PLATFORM}"
"${env.CPACK}" -G ZIP
@ -47,8 +67,8 @@ pipeline {
move "_packages\\*.zip" "soh.zip"
"""
archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true
}
archiveArtifacts artifacts: 'soh.zip', followSymlinks: false, onlyIfSuccessful: true
}
post {
always {
@ -57,9 +77,6 @@ pipeline {
}
}
stage ('Build Linux') {
options {
timeout(time: 20)
}
agent {
label "SoH-Linux-Builders"
}
@ -72,9 +89,9 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
unstash 'assets'
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
if docker ps -aq --filter "name=sohcont" | grep -q .; then docker rm -f sohcont; fi
docker build . -t soh
docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash
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
}
post {
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
}
}
@ -108,11 +126,9 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
unstash 'assets'
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 --build build-cmake --target ExtractAssets --
cmake --build build-cmake --config Release --
(cd build-cmake && cpack)
@ -131,9 +147,6 @@ pipeline {
}
}
stage ('Build Switch') {
options {
timeout(time: 20)
}
agent {
label "SoH-Linux-Builders"
}
@ -146,12 +159,12 @@ pipeline {
userRemoteConfigs: scm.userRemoteConfigs
])
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh '''
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
unstash 'assets'
sh '''
if docker ps -aq --filter "name=sohswitchcont" | grep -q .; then docker rm -f sohswitchcont; fi
docker build . -t sohswitch
docker run --name sohcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash
docker exec sohcont scripts/switch/build.sh
docker run --name sohswitchcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash
docker exec sohswitchcont scripts/switch/build.sh
mv build-switch/soh/*.nro soh.nro
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
}
post {
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
}
}

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());
if (nameSet && nameSet->find(name) == nameSet->end()) {
str += StringHelper::Sprintf(R"(
#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
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
)", name.c_str(), name.c_str(), name.c_str(), name.c_str());
if (nameSet) {
nameSet->insert(name);
}

View File

@ -1,39 +1,35 @@
#include "Console.h"
#include <iostream>
#include <sstream>
#include "Cvar.h"
#include "GlobalCtx2.h"
#include "ImGuiImpl.h"
#include "Lib/ImGui/imgui.h"
#include "Utils/StringHelper.h"
#include "Lib/ImGui/imgui_internal.h"
#include "Utils.h"
namespace Ship {
std::map<ImGuiKey, std::string> Bindings;
std::map<ImGuiKey, std::string> BindingToggle;
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;
}
static bool HelpCommand(const std::vector<std::string>&) {
INFO("SoH Commands:");
for (const auto& cmd : SohImGui::console->Commands) {
INFO("%s", (" - " + cmd.first).c_str());
bool Console::HelpCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
Console->SendInfoMessage("SoH Commands:");
for (const auto& cmd : Console->Commands) {
Console->SendInfoMessage(" - " + cmd.first);
}
return CMD_SUCCESS;
}
static bool ClearCommand(const std::vector<std::string>&) {
SohImGui::console->Log[SohImGui::console->selected_channel].clear();
bool Console::ClearCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
Console->ClearLogs(Console->GetCurrentChannel());
return CMD_SUCCESS;
}
std::string toLowerCase(std::string in) {
std::string cpy(in);
std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower);
return cpy;
}
static bool BindCommand(const std::vector<std::string>& args) {
bool Console::BindCommand(std::shared_ptr<Console> Console, const std::vector<std::string>& args) {
if (args.size() > 2) {
const ImGuiIO* io = &ImGui::GetIO();;
for (size_t k = 0; k < std::size(io->KeysData); k++) {
@ -44,8 +40,8 @@ namespace Ship {
const char* const delim = " ";
std::ostringstream imploded;
std::copy(args.begin() + 2, args.end(), std::ostream_iterator<std::string>(imploded, delim));
Bindings[k] = imploded.str();
INFO("Binding '%s' to %s", args[1].c_str(), Bindings[k].c_str());
Console->Bindings[k] = imploded.str();
Console->SendInfoMessage("Binding '%s' to %s", args[1].c_str(), Console->Bindings[k].c_str());
break;
}
}
@ -53,15 +49,15 @@ namespace Ship {
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) {
const ImGuiIO* io = &ImGui::GetIO();;
for (size_t k = 0; k < std::size(io->KeysData); k++) {
std::string key(ImGui::GetKeyName(k));
if (toLowerCase(args[1]) == toLowerCase(key)) {
BindingToggle[k] = args[2];
INFO("Binding toggle '%s' to %s", args[1].c_str(), BindingToggle[k].c_str());
Console->BindingToggle[k] = args[2];
Console->SendInfoMessage("Binding toggle '%s' to %s", args[1].c_str(), Console->BindingToggle[k].c_str());
break;
}
}
@ -69,22 +65,15 @@ namespace Ship {
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() {
this->InputBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->InputBuffer, "");
this->FilterBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->FilterBuffer, "");
this->Commands["help"] = { HelpCommand, "Shows all the commands" };
this->Commands["clear"] = { ClearCommand, "Clear the console history" };
this->Commands["bind"] = { BindCommand, "Binds key to commands" };
this->Commands["bind-toggle"] = { BindToggleCommand, "Bind key as a bool toggle" };
this->inputBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->inputBuffer, "");
this->filterBuffer = new char[MAX_BUFFER_SIZE];
strcpy(this->filterBuffer, "");
AddCommand("help", { HelpCommand, "Shows all the commands" });
AddCommand("clear", { ClearCommand, "Clear the console history" });
AddCommand("bind", { BindCommand, "Binds key to commands" });
AddCommand("bind-toggle", { BindToggleCommand, "Bind key as a bool toggle" });
}
void Console::Update() {
@ -100,17 +89,21 @@ namespace Ship {
}
void Console::Draw() {
if (!this->opened) {
CVar_SetS32("gConsoleEnabled", 0);
return;
}
bool input_focus = false;
if (!this->opened) return;
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 size = ImGui::GetWindowSize();
// SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole);
// 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::SetNextWindowPos(ImVec2(pos.x + 8, pos.y + size.y - 1));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3));
@ -125,16 +118,16 @@ namespace Ship {
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
if (ImGui::Selectable(preview.c_str())) {
memset(this->InputBuffer, 0, MAX_BUFFER_SIZE);
memcpy(this->InputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size());
this->OpenAutocomplete = false;
memset(this->inputBuffer, 0, MAX_BUFFER_SIZE);
memcpy(this->inputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size());
this->openAutocomplete = false;
input_focus = true;
}
}
ImGui::EndTable();
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
this->OpenAutocomplete = false;
this->openAutocomplete = false;
}
ImGui::PopStyleColor();
ImGui::EndChild();
@ -144,7 +137,7 @@ namespace Ship {
if (ImGui::BeginPopupContextWindow("Context Menu")) {
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;
}
ImGui::EndPopup();
@ -154,34 +147,44 @@ namespace Ship {
}
// Renders top bar filters
if (ImGui::Button("Clear")) this->Log[this->selected_channel].clear();
ImGui::SameLine();
ImGui::SetNextItemWidth(150);
if (ImGui::BeginCombo("##channel", this->selected_channel.c_str())) {
for (const auto& channel : log_channels) {
const bool is_selected = (channel == std::string(this->selected_channel));
if (ImGui::Selectable(channel.c_str(), is_selected))
this->selected_channel = channel;
if (is_selected) ImGui::SetItemDefaultFocus();
if (ImGui::Button("Clear")) this->Log[this->currentChannel].clear();
if (CVar_GetS32("gSinkEnabled", 0)) {
ImGui::SameLine();
ImGui::SetNextItemWidth(150);
if (ImGui::BeginCombo("##channel", this->currentChannel.c_str())) {
for (const auto& channel : LogChannels) {
const bool is_selected = (channel == std::string(this->currentChannel));
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::SetNextItemWidth(150);
if (ImGui::BeginCombo("##level", this->level_filter.c_str())) {
for (const auto& filter : priority_filters) {
const bool is_selected = (filter == std::string(this->level_filter));
if (ImGui::Selectable(filter.c_str(), is_selected))
{
this->level_filter = filter;
if (is_selected) ImGui::SetItemDefaultFocus();
if (this->currentChannel != "Console") {
if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->levelFilter).data())) {
for (const auto& priority_filter : PriorityFilters) {
const bool is_selected = priority_filter == this->levelFilter;
if (ImGui::Selectable(spdlog::level::to_string_view(priority_filter).data(), is_selected))
{
this->levelFilter = priority_filter;
if (is_selected) ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::EndCombo();
} else {
this->levelFilter = spdlog::level::trace;
}
ImGui::SameLine();
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();
// Renders console history
@ -195,16 +198,16 @@ namespace Ship {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
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++) {
ConsoleLine line = channel[i];
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);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
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::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected)
this->selectedEntries.push_back(i);
@ -222,60 +225,64 @@ namespace Ship {
ImGui::SetScrollHereY(1.0f);
ImGui::EndChild();
// Renders input textfield
constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit |
ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
ImGui::PushItemWidth(-53);
if (ImGui::InputTextWithHint("##CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) {
input_focus = true;
if (this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ')
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();
if (this->currentChannel == "Console") {
// Renders input textfield
constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit |
ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
ImGui::PushItemWidth(-53);
if (ImGui::InputTextWithHint("##CMDInput", ">", this->inputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) {
input_focus = true;
if (this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ')
this->Dispatch(std::string(this->inputBuffer));
memset(this->inputBuffer, 0, MAX_BUFFER_SIZE);
}
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50);
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);
}
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::SetItemDefaultFocus();
if (input_focus) ImGui::SetKeyboardFocusHere(-1);
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50);
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();
}
void Console::Dispatch(const std::string& line) {
this->CMDHint = NULLSTR;
this->cmdHint = NULLSTR;
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, " ");
if (this->Commands.contains(cmd_args[0])) {
const CommandEntry entry = this->Commands[cmd_args[0]];
if (!entry.handler(cmd_args) && !entry.arguments.empty())
this->Log[this->selected_channel].push_back({ "[SOH] Usage: " + cmd_args[0] + " " + BuildUsage(entry), ERROR_LVL });
if (!entry.handler(shared_from_this(), cmd_args) && !entry.arguments.empty()) {
SendErrorMessage("[SOH] Usage: " + cmd_args[0] + " " + BuildUsage(entry));
}
return;
}
this->Log[this->selected_channel].push_back({ "[SOH] Command not found", ERROR_LVL });
SendErrorMessage("[SOH] Command not found");
}
int Console::CallbackStub(ImGuiInputTextCallbackData* data) {
const auto instance = static_cast<Console*>(data->UserData);
const bool empty_history = instance->History.empty();
const int history_index = instance->HistoryIndex;
const int history_index = instance->historyIndex;
std::string history;
switch (data->EventKey) {
@ -283,51 +290,103 @@ namespace Ship {
instance->Autocomplete.clear();
for (auto& [cmd, entry] : instance->Commands)
if (cmd.find(std::string(data->Buf)) != std::string::npos) instance->Autocomplete.push_back(cmd);
instance->OpenAutocomplete = !instance->Autocomplete.empty();
instance->CMDHint = NULLSTR;
instance->openAutocomplete = !instance->Autocomplete.empty();
instance->cmdHint = NULLSTR;
break;
case ImGuiKey_UpArrow:
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->InsertChars(0, instance->History[instance->HistoryIndex].c_str());
instance->CMDHint = NULLSTR;
data->InsertChars(0, instance->History[instance->historyIndex].c_str());
instance->cmdHint = NULLSTR;
break;
case ImGuiKey_DownArrow:
if (empty_history) break;
if (history_index > -1) instance->HistoryIndex -= 1;
if (history_index > -1) instance->historyIndex -= 1;
data->DeleteChars(0, data->BufTextLen);
if (history_index >= 0)
data->InsertChars(0, instance->History[history_index].c_str());
instance->CMDHint = NULLSTR;
instance->cmdHint = NULLSTR;
break;
case ImGuiKey_Escape:
instance->HistoryIndex = -1;
instance->historyIndex = -1;
data->DeleteChars(0, data->BufTextLen);
instance->OpenAutocomplete = false;
instance->CMDHint = NULLSTR;
instance->openAutocomplete = false;
instance->cmdHint = NULLSTR;
break;
default:
instance->OpenAutocomplete = false;
instance->openAutocomplete = false;
for (auto& [cmd, entry] : instance->Commands) {
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) {
instance->CMDHint = cmd + " " + BuildUsage(entry);
instance->cmdHint = cmd + " " + BuildUsage(entry);
break;
}
instance->CMDHint = NULLSTR;
instance->cmdHint = NULLSTR;
}
}
return 0;
}
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);
void Console::Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, va_list args) {
char buf[2048];
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
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 "Lib/ImGui/imgui.h"
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include "spdlog/spdlog.h"
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_FAILED false
#define MAX_BUFFER_SIZE 255
#define NULLSTR "None"
typedef std::function<bool(std::vector<std::string> args)> CommandHandler;
enum Priority {
INFO_LVL,
LOG_LVL,
WARNING_LVL,
ERROR_LVL
};
class Console;
typedef std::function<bool(std::shared_ptr<Console> Console, std::vector<std::string> args)> CommandHandler;
enum class ArgumentType {
TEXT, NUMBER, PLAYER_POS, PLAYER_ROT
@ -44,40 +37,68 @@ namespace Ship {
struct ConsoleLine {
std::string text;
Priority priority = Priority::INFO_LVL;
std::string channel = "Main";
spdlog::level::level_enum priority = spdlog::level::info;
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 historyIndex = -1;
std::vector<int> selectedEntries;
std::string filter;
std::string level_filter = NULLSTR;
std::vector<std::string> log_channels = { "Main", "SoH Logging" };
std::vector<std::string> priority_filters = { "None", "Info", "Log", "Warning", "Error" };
std::vector<ImVec4> priority_colors = {
ImVec4(1.0f, 1.0f, 1.0f, 1.0f),
ImVec4(0.2f, 1.0f, 0.2f, 1.0f),
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::string currentChannel = "Console";
bool openAutocomplete = false;
char* inputBuffer = nullptr;
char* filterBuffer = nullptr;
std::string cmdHint = NULLSTR;
spdlog::level::level_enum levelFilter = spdlog::level::trace;
std::vector<std::string> History;
std::string CMDHint = NULLSTR;
char* FilterBuffer = nullptr;
char* InputBuffer = nullptr;
bool OpenAutocomplete = false;
int HistoryIndex = -1;
std::string selected_channel = "Main";
bool opened = false;
std::vector<std::string> Autocomplete;
std::map<ImGuiKey, std::string> Bindings;
std::map<ImGuiKey, std::string> BindingToggle;
std::map<std::string, CommandEntry> Commands;
std::map<std::string, std::vector<ConsoleLine>> Log;
const std::vector<std::string> LogChannels = { "Console", "Logs" };
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 Update();
void Draw();
void Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4);
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 "SDLController.h"
#include <Utils/StringHelper.h>
#include "Cvar.h"
namespace Ship {
uint8_t* controllerBits;
@ -51,18 +52,31 @@ namespace Ship {
*controllerBits |= (backend->Connected()) << slot;
}
void ControlDeck::WriteToPad(OSContPad* pad) const {
for (size_t i = 0; i < virtualDevices.size(); i++) {
const std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
if (backend->GetGuid() == "Auto") {
for (const auto& device : physicalDevices) {
device->Read(&pad[i], i);
}
continue;
}
backend->Read(&pad[i], i);
}
}
void ControlDeck::WriteToPad(OSContPad* pad) const {
#ifdef __SWITCH__
bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0);
#else
bool shouldBlockGameInput = CVar_GetS32("gOpenMenuBar", 0) && CVar_GetS32("gControlNav", 0);
#endif
for (size_t i = 0; i < virtualDevices.size(); 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__)

View File

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

View File

@ -4,12 +4,45 @@
#include "File.h"
#include "Archive.h"
#include "ResourceMgr.h"
#include "Console.h"
#include "ImGuiImpl.h"
#include "Lib/ImGui/imgui_internal.h"
#include "Utils/StringHelper.h"
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) {
ImGuiIO& io = ImGui::GetIO();
std::shared_ptr<Archive> base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive();
@ -123,7 +156,8 @@ namespace Ship {
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() {
@ -196,39 +230,4 @@ namespace Ship {
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 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
spdlog::init_thread_pool(8192, 1);
auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>();
auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
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);
#endif
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
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);
GetLogger()->set_level(spdlog::level::trace);
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;
} CustomWindow;
extern Ship::Console* console;
extern std::shared_ptr<Ship::Console> console;
extern Ship::InputEditor* controller;
extern Ship::GameOverlay* overlay;
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 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 DrawFramebufferAndGameInput(void);
@ -106,6 +112,12 @@ namespace SohImGui {
void EndGroupPanel(float minHeight = 0.0f);
std::string BreakTooltip(const char* 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__
// For Switch we need to set the window width before creating the window
Ship::Switch::GetDisplaySize(&window_width, &window_height);
width = window_width;
height = window_height;
#endif
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__
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);

View File

@ -31,47 +31,24 @@ public:
{}
protected:
void sink_it_(const details::log_msg &msg) override
{
const Ship::Priority priority = convert_to_soh(msg.level);
void sink_it_(const details::log_msg &msg) override {
memory_buf_t formatted;
if (use_raw_msg_)
{
if (use_raw_msg_) {
details::fmt_helper::append_string_view(msg.payload, formatted);
}
else
{
else {
base_sink<Mutex>::formatter_->format(msg, formatted);
}
formatted.push_back('\0');
const char *msg_output = formatted.data();
if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened)
SohImGui::console->Append("SoH Logging", priority, "%s", msg_output);
const char* msg_output = formatted.data();
if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->IsOpened()) {
SohImGui::console->Append("Logs", msg.level, "%s", msg_output);
}
}
void flush_() override {}
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_;
bool use_raw_msg_;

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#include "Utils.h"
#include <cstring>
#include <algorithm>
#ifdef _MSC_VER
#define strdup _strdup
@ -58,4 +59,10 @@ namespace Ship {
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::string toLowerCase(std::string in);
}

View File

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

View File

@ -1,7 +1,6 @@
#!/bin/bash
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 --
(cd build-cmake && cpack -G External)

View File

@ -1,7 +1,4 @@
#!/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 --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})
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
"soh/Enhancements/item-tables/ItemTableManager.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})
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
"src/boot/assert.c"
"src/boot/boot_main.c"
@ -1550,6 +1550,7 @@ set(ALL_FILES
${Header_Files__soh__Enhancements__randomizer}
${Header_Files__soh__Enhancements__randomizer__3drando}
${Header_Files__soh__Enhancements__item_tables}
${Header_Files__soh__Enhancements__custom_message}
${Source_Files__soh}
${Source_Files__soh__Enhancements}
${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__location_access}
${Source_Files__soh__Enhancements__item_tables}
${Source_Files__soh__Enhancements__custom_message}
${Source_Files__src__boot}
${Source_Files__src__buffers}
${Source_Files__src__code}
@ -1822,7 +1824,6 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>
-pthread
-O3 -ffast-math
)
target_link_options(${PROJECT_NAME} PRIVATE

View File

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

View File

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

View File

@ -1124,7 +1124,7 @@ void DrawCosmeticsEditor(bool& open) {
return;
}
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Cosmetics Editor", &open, ImGuiWindowFlags_NoFocusOnAppearing)) {
if (!ImGui::Begin("Cosmetics Editor", &open)) {
ImGui::End();
return;
}
@ -1162,7 +1162,7 @@ void InitCosmeticsEditor() {
//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
//ImGui::SetNextItemWidth(0.0f);
SohImGui::AddWindow("Cosmetics", "Rainbowfunction", LoadRainbowColor, true, true);
SohImGui::AddWindow("Enhancements", "Rainbowfunction", LoadRainbowColor, true, true);
//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 "../libultraship/ImGuiImpl.h"
#include "savestates.h"
#include "Console.h"
#include <vector>
#include <string>
@ -32,14 +33,14 @@ extern GlobalContext* gGlobalCtx;
#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)) {
ERROR("Not enough arguments passed to actorspawn");
SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn");
return CMD_FAILED;
}
if (gGlobalCtx == nullptr) {
ERROR("GlobalCtx == nullptr");
SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
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,
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_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;
INFO("[SOH] You've met with a terrible fate, haven't you?");
SohImGui::console->SendInfoMessage("[SOH] You've met with a terrible fate, haven't you?");
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -100,23 +100,23 @@ static bool SetPlayerHealthHandler(const std::vector<std::string>& args) {
try {
health = std::stoi(args[1]);
} 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;
}
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;
}
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;
}
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.seqId = 0xFF;
gSaveContext.gameMode = 0;
@ -124,7 +124,7 @@ static bool LoadSceneHandler(const std::vector<std::string>&) {
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)
return CMD_FAILED;
@ -133,31 +133,32 @@ static bool RuppeHandler(const std::vector<std::string>& args) {
rupeeAmount = std::stoi(args[1]);
}
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;
}
if (rupeeAmount < 0) {
ERROR("[SOH] Rupee count must be positive");
SohImGui::console->SendErrorMessage("[SOH] Rupee count must be positive");
return CMD_FAILED;
}
gSaveContext.rupees = rupeeAmount;
INFO("Set rupee count to %u", rupeeAmount);
SohImGui::console->SendInfoMessage("Set rupee count to %u", rupeeAmount);
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) {
ERROR("GlobalCtx == nullptr");
SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
return CMD_FAILED;
}
Player* player = GET_PLAYER(gGlobalCtx);
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);
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.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);
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) {
ERROR("GlobalCtx == nullptr");
SohImGui::console->SendErrorMessage("GlobalCtx == nullptr");
return CMD_FAILED;
}
@ -194,9 +196,9 @@ const static std::map<std::string, uint16_t> ammoItems{
{ "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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -205,19 +207,19 @@ static bool AmmoHandler(const std::vector<std::string>& args) {
try {
count = std::stoi(args[2]);
} 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;
}
if (count < 0) {
ERROR("Ammo count must be positive");
SohImGui::console->SendErrorMessage("Ammo count must be positive");
return CMD_FAILED;
}
const auto& it = ammoItems.find(args[1]);
if (it == ammoItems.end()) {
ERROR("Invalid item passed");
SohImGui::console->SendErrorMessage("Invalid item passed");
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 },
};
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -247,19 +249,19 @@ static bool BottleHandler(const std::vector<std::string>& args) {
try {
slot = std::stoi(args[2]);
} 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;
}
if ((slot < 1) || (slot > 4)) {
ERROR("Invalid slot passed");
SohImGui::console->SendErrorMessage("Invalid slot passed");
return CMD_FAILED;
}
const auto& it = bottleItems.find(args[1]);
if (it == bottleItems.end()) {
ERROR("Invalid item passed");
SohImGui::console->SendErrorMessage("Invalid item passed");
return CMD_FAILED;
}
@ -269,9 +271,9 @@ static bool BottleHandler(const std::vector<std::string>& args) {
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -279,9 +281,9 @@ static bool BHandler(const std::vector<std::string>& args) {
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -290,9 +292,9 @@ static bool ItemHandler(const std::vector<std::string>& args) {
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
@ -301,55 +303,54 @@ static bool EntranceHandler(const std::vector<std::string>& args) {
try {
entrance = std::stoi(args[1], nullptr, 16);
} 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;
}
gGlobalCtx->nextEntranceIndex = entrance;
gGlobalCtx->nextEntranceIndex = entrance;
gGlobalCtx->sceneLoadFlag = 0x14;
gGlobalCtx->fadeTransition = 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();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", slot);
SohImGui::console->SendInfoMessage("[SOH] Saved state to slot %u", slot);
return CMD_SUCCESS;
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;
}
}
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();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", slot);
SohImGui::console->SendInfoMessage("[SOH] Loaded state from slot (%u)", slot);
return CMD_SUCCESS;
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;
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;
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;
}
}
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) {
ERROR("[SOH] Unexpected arguments passed");
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
int slot;
@ -357,17 +358,18 @@ static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
try {
slot = std::stoi(args[1], nullptr, 10);
} 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;
}
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;
}
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;
}
@ -402,7 +404,7 @@ static int CheckVarType(const std::string& input)
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)
return CMD_FAILED;
@ -427,12 +429,12 @@ static bool SetCVarHandler(const std::vector<std::string>& args) {
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;
}
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)
return CMD_FAILED;
@ -441,17 +443,17 @@ static bool GetCVarHandler(const std::vector<std::string>& args) {
if (cvar != nullptr)
{
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)
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)
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)
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
{
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
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";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
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
static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
auto message = "Attempting to connect " + entrance->GetName() + " to " + targetEntrance->to_string() + "\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
entrance->Connect(targetEntrance->Disconnect());
entrance->SetReplacement(targetEntrance->GetReplacement());
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) {
if (entrance == nullptr) {
SPDLOG_INFO("Entrance is nullptr in EntranceUnreachableAs()");
SPDLOG_DEBUG("Entrance is nullptr in EntranceUnreachableAs()");
return true;
}
@ -247,7 +247,7 @@ static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector<E
}
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
EntranceType type = EntranceType::None;
@ -285,11 +285,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
if (ElementInContainer(replacementName, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) {
auto message = replacementName + " is replaced by an entrance with a potential child access\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
return false;
} else if (ElementInContainer(replacementName, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) {
auto message = replacementName + " is replaced by an entrance with a potential adult access\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
return false;
}
}
@ -299,11 +299,11 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
if (ElementInContainer(name, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) {
auto message = name + " is potentially accessible as child\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
return false;
} else if (ElementInContainer(name, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) {
auto message = name + " is potentially accessible as adult\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
return false;
}
}
@ -317,7 +317,7 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
auto impasHouseBackHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE_BACK);
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";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
return false;
}
}
@ -328,23 +328,23 @@ static bool ValidateWorld(Entrance* entrancePlaced) {
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
if (!AreaTable(KOKIRI_FOREST)->HasAccess() && !AreaTable(KAKARIKO_VILLAGE)->HasAccess()) {
SPDLOG_INFO("Invalid starting area\n");
SPDLOG_DEBUG("Invalid starting area\n");
return false;
}
// 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)) {
SPDLOG_INFO("Time passing is not guaranteed as both ages\n");
SPDLOG_DEBUG("Time passing is not guaranteed as both ages\n");
return false;
}
// 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
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;
} 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;
}
}
@ -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
if (checkPoeCollectorAccess) {
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;
}
}
SPDLOG_INFO("All Locations NOT REACHABLE\n");
SPDLOG_DEBUG("All Locations NOT REACHABLE\n");
return false;
}
return true;
@ -476,7 +476,7 @@ static void ShuffleEntrancePool(std::vector<Entrance*>& entrancePool, std::vecto
}
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;
}
}
@ -840,7 +840,7 @@ void CreateEntranceOverrides() {
if (noRandomEntrances) {
return;
}
SPDLOG_INFO("\nCREATING ENTRANCE OVERRIDES\n");
SPDLOG_DEBUG("\nCREATING ENTRANCE OVERRIDES\n");
auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false);
for (Entrance* entrance : allShuffleableEntrances) {
@ -851,7 +851,7 @@ void CreateEntranceOverrides() {
}
auto message = "Setting " + entrance->to_string() + "\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
int16_t originalIndex = entrance->GetIndex();
int16_t destinationIndex = entrance->GetReverse()->GetIndex();
@ -868,9 +868,9 @@ void CreateEntranceOverrides() {
});
message = "\tOriginal: " + std::to_string(originalIndex) + "\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
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()) {
allLocationsReachable = false;
auto message = "Location " + Location(loc)->GetName() + " not reachable\n";
SPDLOG_INFO(message);
SPDLOG_DEBUG(message);
#ifndef ENABLE_DEBUG
break;
#endif
@ -567,17 +567,17 @@ static void AssumedFill(const std::vector<uint32_t>& items, const std::vector<ui
if (items.size() > allowedLocations.size()) {
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) {
SPDLOG_INFO("\t");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\t");
SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_DEBUG("\n");
}
SPDLOG_INFO("\nAllowed Locations:\n");
SPDLOG_DEBUG("\nAllowed Locations:\n");
for (const uint32_t loc : allowedLocations) {
SPDLOG_INFO("\t");
SPDLOG_INFO(Location(loc)->GetName());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\t");
SPDLOG_DEBUG(Location(loc)->GetName());
SPDLOG_DEBUG("\n");
}
placementFailure = true;
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
if (accessibleLocations.empty()) {
SPDLOG_INFO("\nCANNOT PLACE ");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO(". TRYING AGAIN...\n");
SPDLOG_DEBUG("\nCANNOT PLACE ");
SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_DEBUG(". TRYING AGAIN...\n");
#ifdef ENABLE_DEBUG
Areas::DumpWorldGraph(ItemTable(item).GetName().GetEnglish());
@ -666,7 +666,7 @@ static void AssumedFill(const std::vector<uint32_t>& items, const std::vector<ui
LogicReset();
GetAccessibleLocations(allLocations, SearchMode::CheckBeatable);
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");
FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true);
return;
@ -1062,7 +1062,7 @@ int Fill() {
}
//Unsuccessful placement
if(retries < 4) {
SPDLOG_INFO("\nGOT STUCK. RETRYING...\n");
SPDLOG_DEBUG("\nGOT STUCK. RETRYING...\n");
Areas::ResetAllLocations();
LogicReset();
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) {
//return if there aren't any hintable locations or gossip stones available
if (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n");
SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return;
}
uint32_t hintedLocation = RandomElement(possibleHintLocations);
const std::vector<uint32_t> accessibleGossipStones = GetAccessibleGossipStones(hintedLocation);
SPDLOG_INFO("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tLocation: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tItem: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_DEBUG("\n");
if (accessibleGossipStones.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n");
SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return;
}
@ -235,9 +235,9 @@ static void CreateLocationHint(const std::vector<uint32_t>& possibleHintLocation
Text prefix = Hint(PREFIX).GetText();
Text finalHint = prefix + locationHintText + " #"+itemHintText+"#.";
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(finalHint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalHint.english);
SPDLOG_DEBUG("\n\n");
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 (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n");
SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return;
}
uint32_t hintedLocation = RandomElement(possibleHintLocations);
SPDLOG_INFO("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tLocation: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tItem: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_DEBUG("\n");
// get an accessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n");
SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return;
}
Location(hintedLocation)->SetAsHinted();
@ -293,9 +293,9 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
locationText = GetHintRegion(parentRegion)->GetHint().GetText();
}
Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText();
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(finalWothHint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalWothHint.english);
SPDLOG_DEBUG("\n\n");
AddHint(finalWothHint, gossipStone, { QM_LBLUE });
}
@ -312,18 +312,18 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
uint32_t hintedLocation = RandomElement(barrenLocations, true);
SPDLOG_INFO("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tLocation: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tItem: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_DEBUG("\n");
// get an accessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n");
SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return;
}
Location(hintedLocation)->SetAsHinted();
@ -341,9 +341,9 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
}
Text finalBarrenHint =
Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText();
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(finalBarrenHint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalBarrenHint.english);
SPDLOG_DEBUG("\n\n");
AddHint(finalBarrenHint, gossipStone, { QM_PINK });
// 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 (possibleHintLocations.empty()) {
SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n");
SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n");
return;
}
uint32_t hintedLocation = RandomElement(possibleHintLocations);
SPDLOG_INFO("\tLocation: ");
SPDLOG_INFO(Location(hintedLocation)->GetName());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tLocation: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetName());
SPDLOG_DEBUG("\n");
SPDLOG_INFO("\tItem: ");
SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tItem: ");
SPDLOG_DEBUG(Location(hintedLocation)->GetPlacedItemName().GetEnglish());
SPDLOG_DEBUG("\n");
//get an acessible gossip stone
const std::vector<uint32_t> gossipStoneLocations = GetAccessibleGossipStones(hintedLocation);
if (gossipStoneLocations.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n");
SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return;
}
Location(hintedLocation)->SetAsHinted();
@ -387,16 +387,16 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
Text locationText = AreaTable(parentRegion)->GetHint().GetText();
Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#.";
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(finalHint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalHint.english);
SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
} else {
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#.";
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(finalHint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalHint.english);
SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN});
}
}
@ -411,15 +411,15 @@ static void CreateJunkHint() {
LogicReset();
const std::vector<uint32_t> gossipStones = GetAccessibleLocations(gossipStoneLocations);
if (gossipStones.empty()) {
SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n");
SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n");
return;
}
uint32_t gossipStone = RandomElement(gossipStones);
Text hint = junkHint.GetText();
SPDLOG_INFO("\tMessage: ");
SPDLOG_INFO(hint.english);
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(hint.english);
SPDLOG_DEBUG("\n\n");
AddHint(hint, gossipStone, {QM_PINK});
}
@ -711,7 +711,7 @@ void CreateAllHints() {
CreateGanonText();
CreateAltarText();
SPDLOG_INFO("\nNOW CREATING HINTS\n");
SPDLOG_DEBUG("\nNOW CREATING HINTS\n");
const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()];
uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit;
@ -768,9 +768,9 @@ void CreateAllHints() {
barrenDungeons.push_back(barrenRegion);
}
}
SPDLOG_INFO("\nBarren Dungeons:\n");
SPDLOG_DEBUG("\nBarren Dungeons:\n");
for (std::string barrenDungeon : barrenDungeons) {
SPDLOG_INFO(barrenDungeon + "\n");
SPDLOG_DEBUG(barrenDungeon + "\n");
}
//Get list of all woth dungeons
@ -783,9 +783,9 @@ void CreateAllHints() {
wothDungeons.push_back(wothRegion);
}
}
SPDLOG_INFO("\nWoth Dungeons:\n");
SPDLOG_DEBUG("\nWoth Dungeons:\n");
for (std::string wothDungeon : wothDungeons) {
SPDLOG_INFO(wothDungeon + "\n");
SPDLOG_DEBUG(wothDungeon + "\n");
}
//Set DungeonInfo array for each dungeon
@ -827,9 +827,9 @@ void CreateAllHints() {
//get a random hint type from the remaining hints
HintType type = RandomElement(remainingHintTypes, true);
SPDLOG_INFO("Attempting to make hint of type: ");
SPDLOG_INFO(hintTypeNames[static_cast<int>(type)]);
SPDLOG_INFO("\n");
SPDLOG_DEBUG("Attempting to make hint of type: ");
SPDLOG_DEBUG(hintTypeNames[static_cast<int>(type)]);
SPDLOG_DEBUG("\n");
//create the appropriate hint for the type
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*/) {
auto loc = Location(locKey);
SPDLOG_INFO("\n");
SPDLOG_INFO(ItemTable(item).GetName().GetEnglish());
SPDLOG_INFO(" placed at ");
SPDLOG_INFO(loc->GetName());
SPDLOG_INFO("\n\n");
SPDLOG_DEBUG("\n");
SPDLOG_DEBUG(ItemTable(item).GetName().GetEnglish());
SPDLOG_DEBUG(" placed at ");
SPDLOG_DEBUG(loc->GetName());
SPDLOG_DEBUG("\n\n");
if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
ItemTable(item).ApplyEffect();
@ -1551,7 +1551,7 @@ void AddExcludedOptions() {
}
void CreateItemOverrides() {
SPDLOG_INFO("NOW CREATING OVERRIDES\n\n");
SPDLOG_DEBUG("NOW CREATING OVERRIDES\n\n");
for (uint32_t locKey : allLocations) {
auto loc = Location(locKey);
ItemOverride_Value val = ItemTable(loc->GetPlaceduint32_t()).Value();
@ -1563,18 +1563,18 @@ void CreateItemOverrides() {
.key = loc->Key(),
.value = val,
});
SPDLOG_INFO("\tScene: ");
SPDLOG_INFO(std::to_string(loc->Key().scene));
SPDLOG_INFO("\tType: ");
SPDLOG_INFO(std::to_string(loc->Key().type));
SPDLOG_INFO("\tFlag: ");
SPDLOG_INFO(std::to_string(loc->Key().flag));
SPDLOG_INFO("\t");
SPDLOG_INFO(loc->GetName());
SPDLOG_INFO(": ");
SPDLOG_INFO(loc->GetPlacedItemName().GetEnglish());
SPDLOG_INFO("\n");
SPDLOG_DEBUG("\tScene: ");
SPDLOG_DEBUG(std::to_string(loc->Key().scene));
SPDLOG_DEBUG("\tType: ");
SPDLOG_DEBUG(std::to_string(loc->Key().type));
SPDLOG_DEBUG("\tFlag: ");
SPDLOG_DEBUG(std::to_string(loc->Key().flag));
SPDLOG_DEBUG("\t");
SPDLOG_DEBUG(loc->GetName());
SPDLOG_DEBUG(": ");
SPDLOG_DEBUG(loc->GetPlacedItemName().GetEnglish());
SPDLOG_DEBUG("\n");
}
SPDLOG_INFO("Overrides Created: ");
SPDLOG_INFO(std::to_string(overrides.size()));
SPDLOG_DEBUG("Overrides Created: ");
SPDLOG_DEBUG(std::to_string(overrides.size()));
}

View File

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

View File

@ -26,13 +26,13 @@ Menu* currentMenu;
} // namespace
void PrintTopScreen() {
SPDLOG_INFO("\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_INFO("\x1b[4;10HA/B/D-pad: Navigate Menu\n");
SPDLOG_INFO(" Select: Exit to Homebrew Menu\n");
SPDLOG_INFO(" Y: New Random Seed\n");
SPDLOG_INFO(" X: Input Custom Seed\n");
SPDLOG_INFO("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str());
SPDLOG_DEBUG("\x1b[2;11H%sOcarina of Time 3D Randomizer%s", CYAN, RESET);
SPDLOG_DEBUG("\x1b[3;18H%s%s-%s%s", CYAN, RANDOMIZER_VERSION, COMMIT_NUMBER, RESET);
SPDLOG_DEBUG("\x1b[4;10HA/B/D-pad: Navigate Menu\n");
SPDLOG_DEBUG(" Select: Exit to Homebrew Menu\n");
SPDLOG_DEBUG(" Y: New Random Seed\n");
SPDLOG_DEBUG(" X: Input Custom Seed\n");
SPDLOG_DEBUG("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str());
}
void MenuInit() {
@ -526,7 +526,7 @@ std::string GenerateRandomizer(std::unordered_map<RandomizerSettingKey, uint8_t>
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 "
"successful.");
SPDLOG_INFO("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n");
SPDLOG_DEBUG("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n");
return "";
} else {
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 <soh/Enhancements/debugger/ImGuiHelpers.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>
using json = nlohmann::json;
using namespace std::literals::string_literals;
std::unordered_map<uint8_t, Sprite> gSeedTextures;
u8 generated;
const std::string Randomizer::getItemMessageTableID = "Randomizer";
const std::string Randomizer::hintMessageTableID = "RandomizerHints";
const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs";
Randomizer::Randomizer() {
Sprite bowSprite = { dgFairyBowIconTex, 32, 32, G_IM_FMT_RGBA, G_IM_SIZ_32b, 0 };
gSeedTextures[0] = bowSprite;
@ -1477,6 +1484,26 @@ void Randomizer::LoadHintLocations(const char* 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->adultAltarText = gSaveContext.adultAltarText;
this->ganonHintText = gSaveContext.ganonHintText;
@ -1485,6 +1512,8 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
for (auto hintLocation : gSaveContext.hintLocations) {
if(hintLocation.check == RC_LINKS_POCKET) break;
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 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 = {
{"À", 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();
}
}
CustomMessageManager::Instance->FormatCustomMessage(formattedHintMessage);
// add icons to altar text
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;
}
std::string Randomizer::GetHintFromCheck(RandomizerCheck check) {
return this->hintLocations[check];
}
u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) {
return this->randoSettings[randoSettingKey];
}
@ -3301,7 +3277,10 @@ void GenerateRandomizerImgui() {
cvarSettings[RSK_CUCCO_COUNT] = CVar_GetS32("gRandomizeCuccosToReturn", 7);
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_TOWER_ESCAPE] = CVar_GetS32("gRandomizeSkipTowerEscape", 0);
@ -4777,6 +4756,60 @@ void DrawRandoEditor(bool& open) {
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() {
GetItemEntry getItemTable[] = {
@ -4910,6 +4943,7 @@ void InitRandoItemTable() {
void InitRando() {
SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor);
Randomizer::CreateCustomMessages();
InitRandoItemTable();
}

View File

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

View File

@ -32,7 +32,6 @@
#include "Enhancements/cosmetics/CosmeticsEditor.h"
#include "Enhancements/debugconsole.h"
#include "Enhancements/debugger/debugger.h"
#include "Enhancements/randomizer/randomizer.h"
#include <soh/Enhancements/randomizer/randomizer_item_tracker.h>
#include "Enhancements/n64_weird_frame_data.inc"
#include "soh/frame_interpolation.h"
@ -40,6 +39,7 @@
#include "macros.h"
#include <Utils/StringHelper.h>
#include "Hooks.h"
#include <soh/Enhancements/custom-message/CustomMessageManager.h>
#ifdef __APPLE__
#include <SDL_scancode.h>
@ -52,10 +52,13 @@
#endif
#include <Audio.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include <functions.h>
#include <soh/Enhancements/item-tables/ItemTableManager.h>
OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance;
CustomMessageManager* CustomMessageManager::Instance;
ItemTableManager* ItemTableManager::Instance;
OTRGlobals::OTRGlobals() {
@ -308,6 +311,7 @@ extern "C" void InitOTR() {
#endif
OTRGlobals::Instance = new OTRGlobals();
SaveManager::Instance = new SaveManager();
CustomMessageManager::Instance = new CustomMessageManager();
ItemTableManager::Instance = new ItemTableManager();
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);
}
extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBufferSize) {
std::string scrubText("");
int language = CVar_GetS32("gLanguages", 0);
extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) {
int price = 0;
switch (scrubTextId) {
case 0x10A2:
case TEXT_SCRUB_POH:
price = 10;
break;
case 0x10DC:
case 0x10DD:
case TEXT_SCRUB_STICK_UPGRADE:
case TEXT_SCRUB_NUT_UPGRADE:
price = 40;
break;
}
switch (language) {
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);
return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price);
}
extern "C" int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize) {
const std::string& altarText = (LINK_IS_ADULT) ? OTRGlobals::Instance->gRandomizer->GetAdultAltarText()
: OTRGlobals::Instance->gRandomizer->GetChildAltarText();
return CopyStringToCharBuffer(altarText, buffer, maxBufferSize);
extern "C" CustomMessageEntry Randomizer_GetAltarMessage() {
return (LINK_IS_ADULT)
? CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_ADULT)
: CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_ALTAR_CHILD);
}
extern "C" int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize) {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonText();
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
extern "C" CustomMessageEntry Randomizer_GetGanonText() {
return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF_NOHINT);
}
extern "C" int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize) {
const std::string& ganonText = OTRGlobals::Instance->gRandomizer->GetGanonHintText();
return CopyStringToCharBuffer(ganonText, buffer, maxBufferSize);
extern "C" CustomMessageEntry Randomizer_GetGanonHintText() {
return CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF);
}
extern "C" int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) {
// we don't want to make a copy of the std::string returned from GetHintFromCheck
extern "C" CustomMessageEntry Randomizer_GetHintFromCheck(RandomizerCheck check) {
// we don't want to make a copy of the std::string returned from GetHintFromCheck
// so we're just going to let RVO take care of it
const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check);
return CopyStringToCharBuffer(hintText, buffer, maxBufferSize);
const CustomMessageEntry hintText = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, check);
return hintText;
}
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) {
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/randomizer/randomizer.h"
const std::string customMessageTableID = "BaseGameOverrides";
class OTRGlobals
{
public:
@ -94,10 +96,6 @@ Sprite* GetSeedTexture(uint8_t index);
void Randomizer_LoadSettings(const char* spoilerFileName);
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
int Randomizer_CopyAltarMessage(char* buffer, const int maxBufferSize);
int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize);
int Randomizer_CopyGanonText(char* buffer, const int maxBufferSize);
int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSize);
void Randomizer_LoadHintLocations(const char* spoilerFileName);
void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
s16 Randomizer_GetItemModelFromId(s16 itemId);
@ -108,6 +106,7 @@ GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actor
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor);
bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId);
int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx);
GetItemEntry ItemTable_Retrieve(int16_t getItemID);
#endif

View File

@ -1,11 +1,13 @@
#include "OTRGlobals.h"
#include "ResourceMgr.h"
#include "Scene.h"
#include "message_data_static.h"
#include "Utils/StringHelper.h"
#include "global.h"
#include "vt.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* sGerMessageEntryTablePtr;
@ -92,4 +94,22 @@ extern "C" void OTRMessage_Init()
sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str();
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 chainsTranslateY;
f32 rotZStep;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
entry = &sDoorLocksInfo[type];

View File

@ -492,9 +492,10 @@ void Cutscene_Command_Terminator(GlobalContext* globalCtx, CutsceneContext* csCt
s32 temp = 0;
// Automatically skip certain cutscenes when in rando
// cmd->base == 33: Zelda escaping with impa 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) &&
(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));
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.n64ddFlag) {
Flags_SetEventChkInf(0xAC);
@ -2118,14 +2121,15 @@ void Cutscene_HandleConditionalTriggers(GlobalContext* globalCtx) {
gSaveContext.entranceIndex = 0x0053;
gSaveContext.cutsceneIndex = 0xFFF8;
}
} else if (!Flags_GetEventChkInf(0xC7) &&
(gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO)) {
} else if ((!Flags_GetEventChkInf(0xC7) &&
gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_DEMO) ||
(bShouldTowerRandoSkip &&
gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_FINAL)) {
Flags_SetEventChkInf(0xC7);
gSaveContext.entranceIndex = 0x0517;
// If we are rando and tower escape skip is on, then set the flag to say we saw the towers fall
// and exit.
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SKIP_TOWER_ESCAPE)) {
if (bShouldTowerRandoSkip) {
return;
}
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_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1, LENS_FLARE_CIRCLE1,
};
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(gfxCtx);
@ -1642,7 +1642,7 @@ void Environment_DrawRain(GlobalContext* globalCtx, View* view, GraphicsContext*
Vec3f unused = { 0.0f, 0.0f, 0.0f };
Vec3f windDirection = { 0.0f, 0.0f, 0.0f };
Player* player = GET_PLAYER(globalCtx);
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
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];
Vec3f unused1 = { 0.0f, 0.0f, 0.0f };
Vec3f unused2 = { 0.0f, 0.0f, 0.0f };
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);

View File

@ -413,7 +413,7 @@ void HealthMeter_Draw(GlobalContext* globalCtx) {
s32 curCombineModeSet = 0;
u8* curBgImgLoaded = NULL;
s32 ddHeartCountMinusOne = gSaveContext.inventory.defenseHearts - 1;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
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;
}
if (sTextIsCredits) {
if (CustomMessage_RetrieveIfExists(globalCtx)) {
osSyncPrintf("Found custom message");
} else if (sTextIsCredits) {
Message_FindCreditsMessage(globalCtx, textId);
msgCtx->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset;
@ -1674,73 +1676,9 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) {
//font->msgLength, __FILE__, __LINE__);
} else {
Message_FindMessage(globalCtx, textId);
// if we're rando'd and talking to a gossip stone
if (gSaveContext.n64ddFlag &&
textId == 0x2053 &&
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->msgLength = font->msgLength;
char* src = (uintptr_t)font->msgOffset;
memcpy(font->msgBuf, src, font->msgLength);
}
msgCtx->textBoxProperties = font->charTexBuf[0];

View File

@ -279,11 +279,15 @@ void Gameplay_Init(GameState* thisx) {
u8 tempSetupIndex;
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) {
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 << 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
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
// 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -564,7 +564,7 @@ void func_80967FFC(Actor* thisx, GlobalContext* globalCtx) {
Demo6K* this = (Demo6K*)thisx;
s32 pad;
u16 timer1 = this->timer1;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
@ -695,7 +695,7 @@ void func_809688C4(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
u32 frames = globalCtx->state.frames;
s32 i;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
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 translateZ;
s16 j;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
@ -663,7 +663,7 @@ void DemoKankyo_DrawClouds(Actor* thisx, GlobalContext* globalCtx) {
f32 dx;
f32 dy;
f32 dz;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
@ -784,7 +784,7 @@ void DemoKankyo_DrawWarpSparkles(Actor* thisx, GlobalContext* globalCtx) {
f32 translateZ;
PosRot posRot;
u8 linkAge = gSaveContext.linkAge;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);
@ -933,7 +933,7 @@ void DemoKankyo_DrawSparkles(Actor* thisx, GlobalContext* globalCtx) {
f32 scale;
s16 i;
PosRot posRot;
static s32 epoch = 0;
static u32 epoch = 0;
epoch++;
OPEN_DISPS(globalCtx->state.gfxCtx);

View File

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

View File

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

View File

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

View File

@ -32,7 +32,7 @@ typedef struct EnBa {
/* 0x031C */ s16 unk31C;
/* 0x0320 */ ColliderJntSph collider;
/* 0x0340 */ ColliderJntSphElement colliderItems[2];
/* 0x03C0 */ s32 epoch;
/* 0x03C0 */ u32 epoch;
} EnBa; // size = 0x03C4
#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.
// 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);
this->moveTo = &player->actor;
// 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;
if (target != NULL) {
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.
player->stateFlags1 &= ~0x02000000;
player->stateFlags1 &= ~PLAYER_STATE1_25;
player->boomerangQuickRecall = false;
Actor_Kill(&this->actor);
}
} else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@ typedef struct {
/* 0x0014 */ Vec3f pos;
/* 0x0020 */ Vec3f velocity;
/* 0x002C */ Vec3f accel;
s32 epoch;
u32 epoch;
} EnGoEffect; // size = 0x38
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 (((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;
} else {
Actor_Kill(&this->actor);
}
} 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;
} else {
Actor_Kill(&this->actor);

View File

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

View File

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

View File

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

View File

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

View File

@ -760,6 +760,14 @@ void func_80AEC2C0(EnRu1* this, GlobalContext* globalCtx) {
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) {
s8 actorRoom;
@ -767,8 +775,7 @@ void func_80AEC320(EnRu1* this, GlobalContext* globalCtx) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
this->action = 7;
EnRu1_SetMouthIndex(this, 1);
} else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) &&
!(gSaveContext.infTable[20] & 0x20)) {
} else if ((gSaveContext.infTable[20] & 0x80) && !(gSaveContext.infTable[20] & 1) && shouldSpawnRuto()) {
if (!func_80AEB020(this, globalCtx)) {
func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
actorRoom = this->actor.room;
@ -1172,7 +1179,7 @@ void func_80AED414(EnRu1* this, GlobalContext* globalCtx) {
void func_80AED44C(EnRu1* this, GlobalContext* globalCtx) {
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)) {
if (!func_80AEB020(this, globalCtx)) {
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) {
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_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0);
actorRoom = this->actor.room;

View File

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

View File

@ -460,10 +460,13 @@ void func_80B14AF4(EnTa* this, GlobalContext* globalCtx) {
void func_80B14B6C(EnTa* this, GlobalContext* globalCtx) {
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);
this->unk_2CC = 5;
gSaveContext.eventChkInf[1] |= 0x10;
if (gSaveContext.n64ddFlag) {
OnePointCutscene_EndCutscene(globalCtx, csCamIdx);
}
Animation_PlayOnce(&this->skelAnime, &gTalonRunTransitionAnim);
this->currentAnimation = &gTalonRunAnim;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_link_child/object_link_child.h"
#include "textures/icon_item_24_static/icon_item_24_static.h"
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
//typedef struct {
// /* 0x00 */ u8 itemId;
@ -146,10 +147,10 @@ s32 func_808353D8(Player* this, GlobalContext* globalCtx);
s32 func_80835588(Player* this, GlobalContext* globalCtx);
s32 func_808356E8(Player* this, GlobalContext* globalCtx);
s32 func_80835800(Player* this, GlobalContext* globalCtx);
s32 func_80835884(Player* this, GlobalContext* globalCtx);
s32 func_808358F0(Player* this, GlobalContext* globalCtx);
s32 func_808359FC(Player* this, GlobalContext* globalCtx);
s32 func_80835B60(Player* this, GlobalContext* globalCtx);
s32 func_80835884(Player* this, GlobalContext* globalCtx); // Start aiming boomerang
s32 func_808358F0(Player* this, GlobalContext* globalCtx); // Aim boomerang
s32 func_808359FC(Player* this, GlobalContext* globalCtx); // Throw boomerang
s32 func_80835B60(Player* this, GlobalContext* globalCtx); // Boomerang active
s32 func_80835C08(Player* this, GlobalContext* globalCtx);
void func_80835F44(GlobalContext* globalCtx, Player* this, s32 item);
void func_80839F90(Player* this, GlobalContext* globalCtx);
@ -487,8 +488,8 @@ static s32 D_80853604 = 0;
static s32 D_80853608 = 0;
static s32 D_8085360C = 0;
static s16 D_80853610 = 0;
static s32 D_80853614 = 0;
static s32 D_80853618 = 0;
static s32 D_80853614 = 0; // Held item button just pressed?
static s32 D_80853618 = 0; // Held item button currently down?
static u16 D_8085361C[] = {
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_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_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, 0x44, 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_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x46, 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_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0x5D, 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_POE, OBJECT_GI_GHOST, GID_POE, 0x97, 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_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, TEXT_RANDOMIZER_CUSTOM_ITEM, 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, TEXT_RANDOMIZER_CUSTOM_ITEM, 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, TEXT_RANDOMIZER_CUSTOM_ITEM, 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, TEXT_RANDOMIZER_CUSTOM_ITEM, 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,
@ -955,6 +956,7 @@ static s8 sItemActionParams[] = {
static u8 sMaskMemory;
// Used to map action params to update functions
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_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C, func_8083501C,
@ -2734,6 +2736,10 @@ s32 func_80835B60(Player* this, GlobalContext* globalCtx) {
return 1;
}
if (D_80853614 && CVar_GetS32("gFastBoomerang", 0)) {
this->boomerangQuickRecall = true;
}
return 0;
}

View File

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

View File

@ -12,12 +12,12 @@ static s16 sEquipMoveTimer = 10;
bool gSelectingMask;
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[];
void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item) {
void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) {
s16 ammo;
s16 i;
@ -51,7 +51,7 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx,
gDPPipeSync(POLY_KAL_DISP++);
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,
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);
}
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,
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++) {
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);
}
}