Merge branch 'develop' into SpammableKaepora

This commit is contained in:
earthcrafterman 2022-05-15 19:31:51 -04:00
commit 35d97bdd6e
140 changed files with 5298 additions and 1180 deletions

View file

@ -2,9 +2,9 @@
## Windows
1. Install [Python](https://www.python.org/ftp/python/3.10.2/python-3.10.2-amd64.exe)
1. Requires [Python](https://www.python.org/downloads/) >= 3.6.
2. Install [Visual Studio 2022 Community Edition](https://visualstudio.microsoft.com/vs/community/)
2b. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`.
3. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`.
4. Clone the Ship of Harkinian repository.
5. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice.
6. Run `OTRExporter/OTRExporter.sln`.
@ -41,9 +41,9 @@ cp /usr/local/lib/libGLEW.a external
cd soh
# Extract the assets/Compile the exporter/Run the exporter
make setup -j$(nproc)
make setup -j$(nproc) OPTFLAGS=-O0 DEBUG=0
# Compile the code
make -j $(nproc)
make -j $(nproc) OPTFLAGS=-O0 DEBUG=0
```
# Compatible Roms
@ -51,3 +51,16 @@ make -j $(nproc)
OOT_PAL_GC checksum 0x09465AC3
OOT_PAL_GC_DBG1 checksum 0x871E1C92 (debug non-master quest)
```
# OTRExporter Usage
The OTRExporter exports an `oot.otr` archive file which Ship of Harkinian requires to play.
Use the `extract_assets.py` script file to run the exporter using any of the following methods:
1) Double click on the script after placing one or more roms in the directory.
2) Drag & Drop a rom onto the script.
3) In a terminal run `python3 extract_assets.py` after placing one or more roms in the directory.
4) In a terminal run `python3 extract_assets.py <path_to_rom>`
If the script finds multiple roms the user is prompted which to use. Selection is done using the number keys and then pressing the carriage return key.

1
Jenkinsfile vendored
View file

@ -3,7 +3,6 @@ pipeline {
options {
timestamps()
timeout(time: 30, unit: 'MINUTES')
skipDefaultCheckout(true)
}

View file

@ -188,7 +188,7 @@ void OTRGame::draw() {
sohFolder = path;
}
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nMaster Quest or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nGameCube PAL or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FILE);
if (path != NULLSTR) {
const std::string patched_n64 = std::string(patched_rom);

View file

@ -6,7 +6,7 @@ The Ship does not include assets and as such requires a prior copy of the game t
## Quick Start
1) Download The Ship of Harkinian from Discord.
1) Download The Ship of Harkinian from [Discord](https://discord.com/invite/BtBmd55HVH).
2) Requires a supported copy of the game (See supported games below).
3) Use the OTRGui to generate an `oot.otr` archive file.
4) Launch `soh.exe`
@ -18,9 +18,9 @@ Build team: `zelda@srd022j`
Build date: `03-02-21 00:49:18` (year-month-day)
sha1: cee6bc3c2a634b41728f2af8da54d9bf8cc14099
```
Ocarina of Time Pal Gamecube
Ocarina of Time PAL GameCube
```
sha1: d0c95b2cb3c6682a171db267932af7af8cf5fa82
sha1: 0227d7c0074f2d0ac935631990da8ec5914597b4
```
Congratulations, you are now sailing with the Ship of Harkinian! Have fun!
@ -64,42 +64,51 @@ Refer to the [building instructions](BUILDING.md) to compile SoH.
- Affirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe
- Affirm that `zapd.exe` exists in the `/assets/extractor` folder
## Nightly Builds
Nightly builds of Ship of Harkinian are available at [https://builds.shipofharkinian.com/job/SoH_Multibranch/job/develop]
## The Harbour Masters Are...
Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer
Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer
Louist103 | Developer - Save System Programmer and General Programmer
Emil | Developer - Fast3D Programmer
m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer
MelonSpeedruns | Developer - General Programmer
Rozlette | Developer - General Programmer
JoshDuMan | Developer - General Programmer
KiritoDev/Lywx | Developer - General Programmer
Theo3 | Developer - General Programmer
Random06457 | Developer - Linux Build
Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer
Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer
Louist103 | Developer - Save System Programmer and General Programmer
Emil | Developer - Fast3D Programmer
m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer
MelonSpeedruns | Developer - General Programmer
Rozlette | Developer - General Programmer
JoshDuMan | Developer - General Programmer
KiritoDev/Lywx | Developer - General Programmer
Theo3 | Developer - General Programmer
Random06457 | Developer - Linux Build
## Special Thanks
Decomp & ZAPD | Made this project even possible in the first place!
MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation.
Rrrrry123 | Speedbunner, encouragement, and community moderation
Fierce deity | Encouragement and community moderation
mzxrules | For his contributions to decomp
zel. | For his contributions to decomp
Aloxado | Developer - General Programmer
MegaMech | Developer - General Programmer
Revo | Tester - GCC support and General Testing
zfg | Tester - General Testing
Horseless Headman | Tester - General Testing
Steven Pritchett | Tester - General Testing
Trenton May | Tester - General Testing
Zeldaboy14 | Tester - General Testing, encouragement, and community moderation
Koby Howell | Tester - General Testing
Logg | Tester - General Testing
Taylor Daley | Graphic Design
Can't Sleep | Graphic Design
MicTheMicrophone | Voice actor for the King
Amphibibro | Voice actor for Link
Lemons
Decomp & ZAPD | Made this project even possible in the first place!
MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation.
Rrrrry123 | Speedbunner, encouragement, and community moderation
Fierce deity | Encouragement and community moderation
mzxrules | For his contributions to decomp
zel. | For his contributions to decomp
Aloxado | Developer - General Programmer
MegaMech | Developer - General Programmer
Revo | Tester - GCC support and General Testing
zfg | Tester - General Testing
Horseless Headman | Tester - General Testing
Steven Pritchett | Tester - General Testing
Trenton May | Tester - General Testing
Zeldaboy14 | Tester - General Testing, encouragement, and community moderation
Koby Howell | Tester - General Testing
Logg | Tester - General Testing
Taylor Daley | Graphic Design
Can't Sleep | Graphic Design
## Video Credits
Kenix | Producer / Writer
rainbow_fash | Executive Producer
TheLegendOfXela | Editor
MicTheMicrophone | Gwonam / The King
Amphibibro | Link
AceHeart | Zelda
###### Lemons

View file

@ -54,11 +54,16 @@ namespace Ship {
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath, bool includeParent, std::shared_ptr<File> FileToLoad) {
HANDLE fileHandle = NULL;
if (FileToLoad == nullptr) {
FileToLoad = std::make_shared<File>();
FileToLoad->path = filePath;
}
if (!SFileOpenFileEx(mainMPQ, filePath.c_str(), 0, &fileHandle)) {
SPDLOG_ERROR("({}) Failed to open file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
FileToLoad->bHasLoadError = true;
return nullptr;
return FileToLoad;
}
DWORD dwFileSize = SFileGetFileSize(fileHandle, 0);
@ -72,18 +77,13 @@ namespace Ship {
}
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
FileToLoad->bHasLoadError = true;
return nullptr;
return FileToLoad;
}
if (!SFileCloseFile(fileHandle)) {
SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
}
if (FileToLoad == nullptr) {
FileToLoad = std::make_shared<File>();
FileToLoad->path = filePath;
}
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
FileToLoad->parent = includeParent ? shared_from_this() : nullptr;
FileToLoad->buffer = fileData;
@ -97,6 +97,11 @@ namespace Ship {
HANDLE fileHandle = NULL;
HANDLE mpqHandle = NULL;
if (FileToLoad == nullptr) {
FileToLoad = std::make_shared<File>();
FileToLoad->path = filePath;
}
for(auto [path, handle] : mpqHandles) {
if (SFileOpenFileEx(mpqHandle, filePath.c_str(), 0, &fileHandle)) {
std::unique_lock Lock(FileToLoad->FileLoadMutex);
@ -121,18 +126,13 @@ namespace Ship {
}
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
FileToLoad->bHasLoadError = true;
return nullptr;
return FileToLoad;
}
if (!SFileCloseFile(fileHandle)) {
SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
}
if (FileToLoad == nullptr) {
FileToLoad = std::make_shared<File>();
FileToLoad->path = filePath;
}
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
FileToLoad->parent = includeParent ? shared_from_this() : nullptr;
FileToLoad->buffer = fileData;
@ -204,7 +204,7 @@ namespace Ship {
return true;
}
std::vector<SFILE_FIND_DATA> Archive::ListFiles(const std::string& searchMask) {
std::vector<SFILE_FIND_DATA> Archive::ListFiles(const std::string& searchMask) const {
auto fileList = std::vector<SFILE_FIND_DATA>();
SFILE_FIND_DATA findContext;
HANDLE hFind;
@ -248,7 +248,7 @@ namespace Ship {
return fileList;
}
bool Archive::HasFile(const std::string& filename) {
bool Archive::HasFile(const std::string& filename) const {
bool result = false;
auto start = std::chrono::steady_clock::now();
@ -267,8 +267,9 @@ namespace Ship {
return result;
}
std::string Archive::HashToString(uint64_t hash) {
return hashes[hash];
const std::string* Archive::HashToString(uint64_t hash) const {
auto it = hashes.find(hash);
return it != hashes.end() ? &it->second : nullptr;
}
bool Archive::Load(bool enableWriting, bool genCRCMap) {

View file

@ -34,9 +34,9 @@ namespace Ship
bool AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize);
bool RemoveFile(const std::string& path);
bool RenameFile(const std::string& oldPath, const std::string& newPath);
std::vector<SFILE_FIND_DATA> ListFiles(const std::string& searchMask);
bool HasFile(const std::string& searchMask);
std::string HashToString(uint64_t hash);
std::vector<SFILE_FIND_DATA> ListFiles(const std::string& searchMask) const;
bool HasFile(const std::string& searchMask) const;
const std::string* HashToString(uint64_t hash) const;
protected:
bool Load(bool enableWriting, bool genCRCMap);
bool Unload();

View file

@ -72,7 +72,7 @@ namespace Ship {
(*this)["WINDOW"]["FULLSCREEN WIDTH"] = std::to_string(1920);
(*this)["WINDOW"]["FULLSCREEN HEIGHT"] = std::to_string(1080);
(*this)["WINDOW"]["FULLSCREEN"] = std::to_string(false);
(*this)["WINDOW"]["GFX BACKEND"] = "sdl";
(*this)["WINDOW"]["GFX BACKEND"] = "";
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CLEFT)] = std::to_string(0x14B);

View file

@ -1,3 +1,6 @@
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
#pragma once
#include <string>
@ -35,3 +38,5 @@ namespace Ship {
mINI::INIFile File;
};
}
#endif

View file

@ -1,23 +1,22 @@
#include "Cvar.h"
#include <map>
#include <string>
#include <functional>
#include <memory>
#include <utility>
#include <PR/ultra64/gbi.h>
std::map<std::string, CVar*> cvars;
CVar* CVar_GetVar(const char* name) {
std::string key(name);
return cvars.contains(key) ? cvars[key] : nullptr;
}
std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
extern "C" CVar* CVar_Get(const char* name) {
return CVar_GetVar(name);
auto it = cvars.find(name);
return (it != cvars.end()) ? it->second.get() : nullptr;
}
extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar != nullptr) {
if (cvar) {
if (cvar->type == CVAR_TYPE_S32)
return cvar->value.valueS32;
}
@ -28,7 +27,7 @@ extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) {
extern "C" float CVar_GetFloat(const char* name, float defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar != nullptr) {
if (cvar) {
if (cvar->type == CVAR_TYPE_FLOAT)
return cvar->value.valueFloat;
}
@ -36,10 +35,10 @@ extern "C" float CVar_GetFloat(const char* name, float defaultValue) {
return defaultValue;
}
extern "C" char* CVar_GetString(const char* name, char* defaultValue) {
extern "C" const char* CVar_GetString(const char* name, const char* defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar != nullptr) {
if (cvar) {
if (cvar->type == CVAR_TYPE_STRING)
return cvar->value.valueStr;
}
@ -48,53 +47,43 @@ extern "C" char* CVar_GetString(const char* name, char* defaultValue) {
}
extern "C" void CVar_SetS32(const char* name, s32 value) {
CVar* cvar = CVar_Get(name);
auto& cvar = cvars[name];
if (!cvar) {
cvar = new CVar;
cvars[std::string(name)] = cvar;
cvar = std::make_unique<CVar>();
}
cvar->type = CVAR_TYPE_S32;
cvar->value.valueS32 = value;
}
void CVar_SetFloat(const char* name, float value) {
CVar* cvar = CVar_Get(name);
auto& cvar = cvars[name];
if (!cvar) {
cvar = new CVar;
cvars[std::string(name)] = cvar;
cvar = std::make_unique<CVar>();
}
cvar->type = CVAR_TYPE_FLOAT;
cvar->value.valueFloat = value;
}
void CVar_SetString(const char* name, char* value) {
CVar* cvar = CVar_Get(name);
void CVar_SetString(const char* name, const char* value) {
auto& cvar = cvars[name];
if (!cvar) {
cvar = new CVar;
cvars[std::string(name)] = cvar;
cvar = std::make_unique<CVar>();
}
cvar->type = CVAR_TYPE_STRING;
cvar->value.valueStr = value;
}
extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar == nullptr)
if (!CVar_Get(name))
CVar_SetS32(name, defaultValue);
}
extern "C" void CVar_RegisterFloat(const char* name, float defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar == nullptr)
if (!CVar_Get(name))
CVar_SetFloat(name, defaultValue);
}
extern "C" void CVar_RegisterString(const char* name, char* defaultValue) {
CVar* cvar = CVar_Get(name);
if (cvar == nullptr)
extern "C" void CVar_RegisterString(const char* name, const char* defaultValue) {
if (!CVar_Get(name))
CVar_SetString(name, defaultValue);
}

View file

@ -6,13 +6,13 @@
typedef enum CVarType { CVAR_TYPE_S32, CVAR_TYPE_FLOAT, CVAR_TYPE_STRING } CVarType;
typedef struct CVar {
char* name;
const char* name;
CVarType type;
union {
s32 valueS32;
float valueFloat;
char* valueStr;
const char* valueStr;
} value;
} CVar;
@ -22,16 +22,15 @@ extern "C"
#endif
//#include <ultra64.h>
CVar* CVar_Get(const char* name);
s32 CVar_GetS32(const char* name, s32 defaultValue);
float CVar_GetFloat(const char* name, float defaultValue);
char* CVar_GetString(const char* name, char* defaultValue);
const char* CVar_GetString(const char* name, const char* defaultValue);
void CVar_SetS32(const char* name, s32 value);
void CVar_RegisterS32(const char* name, s32 defaultValue);
void CVar_RegisterFloat(const char* name, float defaultValue);
void CVar_RegisterString(const char* name, char* defaultValue);
void CVar_RegisterString(const char* name, const char* defaultValue);
#ifdef __cplusplus
};
@ -40,10 +39,11 @@ void CVar_RegisterString(const char* name, char* defaultValue);
#ifdef __cplusplus
#include <map>
#include <string>
#include <functional>
#include <memory>
extern std::map<std::string, CVar*> cvars;
CVar* CVar_GetVar(const char* name);
extern std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
void CVar_SetFloat(const char* name, float value);
void CVar_SetString(const char* name, char* value);
void CVar_SetString(const char* name, const char* value);
#endif
#endif

View file

@ -0,0 +1,225 @@
#include "GameOverlay.h"
#include "Cvar.h"
#include "File.h"
#include "Archive.h"
#include "ResourceMgr.h"
#include "SohConsole.h"
#include "SohImGuiImpl.h"
#include "TextureMod.h"
#include "Lib/ImGui/imgui_internal.h"
#include "Utils/StringHelper.h"
void Ship::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();
std::shared_ptr<File> font = std::make_shared<File>();
base->LoadFile(path, false, font);
if (font->bIsLoaded) {
char* font_data = new char[font->dwBufferSize];
memcpy(font_data, font->buffer.get(), font->dwBufferSize);
Fonts[name] = io.Fonts->AddFontFromMemoryTTF(font_data, font->dwBufferSize, fontSize);
}
}
void Ship::GameOverlay::TextDraw(float x, float y, bool shadow, ImVec4 color, const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::PushFont(Fonts[this->CurrentFont]);
if (shadow) {
ImGui::SetCursorPos(ImVec2(x + 1, y + 1));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.0f, .0f, .0f, color.w));
ImGui::Text(buf, args);
}
ImGui::PopStyleColor();
ImGui::SetCursorPos(ImVec2(x, y));
ImGui::Text(buf, args);
ImGui::PopFont();
ImGui::PopStyleColor();
}
void Ship::GameOverlay::TextDrawNotification(float duration, bool shadow, const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
this->RegisteredOverlays[StringHelper::Sprintf("NotificationID:%d%d", rand(), this->RegisteredOverlays.size())] = new Overlay({ OverlayType::NOTIFICATION, ImStrdup(buf), duration, duration });
NeedsCleanup = true;
}
void Ship::GameOverlay::CleanupNotifications() {
if(!NeedsCleanup) return;
for (auto it = this->RegisteredOverlays.begin(); it != this->RegisteredOverlays.end(); ) {
if (it->second->type == OverlayType::NOTIFICATION && it->second->duration <= 0.0f) {
it = this->RegisteredOverlays.erase(it);
} else {
++it;
}
}
NeedsCleanup = false;
}
float Ship::GameOverlay::GetScreenWidth() {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
return viewport->Size.x;
}
float Ship::GameOverlay::GetScreenHeight() {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
return viewport->Size.y;
}
float Ship::GameOverlay::GetStringWidth(const char* text) {
return CalculateTextSize(text).x;
}
ImVec2 Ship::GameOverlay::CalculateTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) {
ImGuiContext& g = *GImGui;
const char* text_display_end;
if (hide_text_after_double_hash)
text_display_end = ImGui::FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
else
text_display_end = text_end;
GameOverlay* overlay = SohImGui::overlay;
ImFont* font = overlay->CurrentFont == "Default" ? g.Font : overlay->Fonts[overlay->CurrentFont];
const float font_size = font->FontSize;
if (text == text_display_end)
return ImVec2(0.0f, font_size);
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
// Round
// FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
// FIXME: Investigate using ceilf or e.g.
// - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
// - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
text_size.x = IM_FLOOR(text_size.x + 0.99999f);
return text_size;
}
void Ship::GameOverlay::Init() {
this->LoadFont("Press Start 2P", "assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf", 12.0f);
this->LoadFont("Fipps", "assets/ship_of_harkinian/fonts/Fipps-Regular.otf", 32.0f);
const std::string DefaultFont = this->Fonts.begin()->first;
if(!this->Fonts.empty()) {
const std::string font = CVar_GetString("gOverlayFont", ImStrdup(DefaultFont.c_str()));
for (auto& [name, _] : this->Fonts) {
if (font.starts_with(name)) {
this->CurrentFont = name;
break;
}
this->CurrentFont = DefaultFont;
}
}
SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" };
}
void Ship::GameOverlay::DrawSettings() {
ImGui::Text("Overlays Text Font");
if (ImGui::BeginCombo("##TextFont", this->CurrentFont.c_str())) {
for (auto& [name, font] : this->Fonts) {
if (ImGui::Selectable(name.c_str(), name == this->CurrentFont)) {
this->CurrentFont = name;
CVar_SetString("gOverlayFont", ImStrdup(name.c_str()));
SohImGui::needs_save = true;
}
}
ImGui::EndCombo();
}
}
void Ship::GameOverlay::Draw() {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always);
ImGui::SetNextWindowSize(viewport->Size, ImGuiCond_Always);
ImGui::Begin("SoHOverlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs);
this->CleanupNotifications();
float textY = 50;
float notY = 0;
for (auto &[key, overlay] : this->RegisteredOverlays) {
if (overlay->type == OverlayType::TEXT) {
const char* text = ImStrdup(overlay->value);
const CVar* var = CVar_Get(text);
ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
switch (var->type) {
case CVAR_TYPE_FLOAT:
this->TextDraw(30, textY, true, color, "%s %.2f", text, var->value.valueFloat);
break;
case CVAR_TYPE_S32:
this->TextDraw(30, textY, true, color, "%s %d", text, var->value.valueS32);
break;
case CVAR_TYPE_STRING:
this->TextDraw(30, textY, true, color, "%s %s", text, var->value.valueStr);
break;
}
free((void*) text);
textY += 30;
}
if (overlay->type == OverlayType::NOTIFICATION && overlay->duration > 0) {
const char* text = overlay->value;
const float duration = overlay->duration / overlay->fadeTime;
const ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, duration);
const float textWidth = this->GetStringWidth(overlay->value);
this->TextDraw(GetScreenWidth() - textWidth - 40, GetScreenHeight() - 40 - notY, true, color, text);
notY += 30;
overlay->duration -= .05f;
}
}
ImGui::End();
}
bool Ship::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

@ -0,0 +1,42 @@
#pragma once
#include <string>
#include <vector>
#include "Lib/ImGui/imgui.h"
#include <map>
#include <unordered_map>
enum class OverlayType {
TEXT, IMAGE, NOTIFICATION
};
struct Overlay {
OverlayType type;
const char* value;
float fadeTime;
float duration;
};
namespace Ship {
class GameOverlay {
public:
std::unordered_map<std::string, Overlay*> RegisteredOverlays;
std::unordered_map<std::string, ImFont*> Fonts;
std::string CurrentFont = "Default";
void Init();
void Draw();
void DrawSettings();
static float GetScreenWidth();
static float GetScreenHeight();
static float GetStringWidth(const char* text);
static ImVec2 CalculateTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
void TextDraw(float x, float y, bool shadow, ImVec4 color, const char* text, ...);
void TextDrawNotification(float duration, bool shadow, const char* fmt, ...);
private:
bool NeedsCleanup = false;
void CleanupNotifications();
void LoadFont(const std::string& name, const std::string& path, float fontSize);
};
static bool OverlayCommand(const std::vector<std::string>& args);
}

View file

@ -1,3 +1,6 @@
#ifndef GAME_VERSION_H
#define GAME_VERSION_H
#pragma once
#define OOT_NTSC_10 0xEC7011B7
@ -17,4 +20,6 @@
#define OOT_PAL_GC_MQ_DBG 0x917D18F6
#define OOT_IQUE_TW 0x3D81FB3E
#define OOT_IQUE_CN 0xB1E1E07B
#define OOT_UNKNOWN 0xFFFFFFFF
#define OOT_UNKNOWN 0xFFFFFFFF
#endif

View file

@ -1,3 +1,6 @@
#ifndef GLOBAL_CTX_2
#define GLOBAL_CTX_2
#pragma once
#ifdef __cplusplus
@ -38,4 +41,6 @@ namespace Ship {
std::string PatchesPath;
};
}
#endif
#endif
#endif

View file

@ -1027,7 +1027,7 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
gfx_d3d11_get_framebuffer_texture_id,
gfx_d3d11_select_texture_fb,
gfx_d3d11_delete_texture,
gfx_d3d11_set_texture_filter,
gfx_d3d11_set_texture_filter,
gfx_d3d11_get_texture_filter
};

View file

@ -31,10 +31,12 @@
#include "../StrHash64.h"
#include "../../SohImGuiImpl.h"
#include "../../Environment.h"
#include "../../GameVersions.h"
#include "../../ResourceMgr.h"
// OTRTODO: fix header files for these
extern "C" {
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc);
const char* ResourceMgr_GetNameByCRC(uint64_t crc);
int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc);
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
@ -86,7 +88,7 @@ struct LoadedVertex {
static struct {
TextureCacheMap map;
list<TextureCacheMap::iterator> lru;
list<TextureCacheMapIter> lru;
vector<uint32_t> free_texture_ids;
} gfx_texture_cache;
@ -132,14 +134,14 @@ static struct RDP {
const uint8_t *addr;
uint8_t siz;
uint32_t width;
char* otr_path;
const char* otr_path;
} texture_to_load;
struct {
const uint8_t *addr;
uint32_t size_bytes;
uint32_t full_image_line_size_bytes;
uint32_t line_size_bytes;
char* otr_path;
const char* otr_path;
} loaded_texture[2];
struct {
uint8_t fmt;
@ -188,8 +190,12 @@ static int game_framebuffer_msaa_resolved;
uint32_t gfx_msaa_level = 1;
static bool has_drawn_imgui_menu;
static bool dropped_frame;
static const std::unordered_map<Mtx *, MtxF> *current_mtx_replacements;
static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx
static size_t buf_vbo_len;
static size_t buf_vbo_num_tris;
@ -521,18 +527,18 @@ static bool gfx_texture_cache_lookup(int i, int tile) {
key = { orig_addr, { }, fmt, siz, palette_index };
}
auto it = gfx_texture_cache.map.find(key);
TextureCacheMap::iterator it = gfx_texture_cache.map.find(key);
if (it != gfx_texture_cache.map.end()) {
gfx_rapi->select_texture(i, it->second.texture_id);
*n = &*it;
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, *(list<TextureCacheMap::iterator>::iterator*)&it->second.lru_location); // move to back
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, it->second.lru_location); // move to back
return true;
}
if (gfx_texture_cache.map.size() >= TEXTURE_CACHE_MAX_SIZE) {
// Remove the texture that was least recently used
it = gfx_texture_cache.lru.front();
it = gfx_texture_cache.lru.front().it;
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
gfx_texture_cache.map.erase(it);
gfx_texture_cache.lru.pop_front();
@ -549,7 +555,7 @@ static bool gfx_texture_cache_lookup(int i, int tile) {
it = gfx_texture_cache.map.insert(make_pair(key, TextureCacheValue())).first;
TextureCacheNode* node = &*it;
node->second.texture_id = texture_id;
*(list<TextureCacheMap::iterator>::iterator*)&node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), it);
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
gfx_rapi->select_texture(i, texture_id);
gfx_rapi->set_sampler_parameters(i, false, 0, 0);
@ -565,7 +571,7 @@ static void gfx_texture_cache_delete(const uint8_t* orig_addr)
bool again = false;
for (auto it = gfx_texture_cache.map.begin(bucket); it != gfx_texture_cache.map.end(bucket); ++it) {
if (it->first.texture_addr == orig_addr) {
gfx_texture_cache.lru.erase(*(list<TextureCacheMap::iterator>::iterator*)&it->second.lru_location);
gfx_texture_cache.lru.erase(it->second.lru_location);
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
gfx_texture_cache.map.erase(it->first);
again = true;
@ -914,20 +920,31 @@ static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4
static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) {
float matrix[4][4];
#ifndef GBI_FLOATS
// Original GBI where fixed point matrices are used
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j += 2) {
int32_t int_part = addr[i * 2 + j / 2];
uint32_t frac_part = addr[8 + i * 2 + j / 2];
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
if (auto it = current_mtx_replacements->find((Mtx *)addr); it != current_mtx_replacements->end()) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
float v = it->second.mf[i][j];
int as_int = (int)(v * 65536.0f);
matrix[i][j] = as_int * (1.0f / 65536.0f);
}
}
} else {
#ifndef GBI_FLOATS
// Original GBI where fixed point matrices are used
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j += 2) {
int32_t int_part = addr[i * 2 + j / 2];
uint32_t frac_part = addr[8 + i * 2 + j / 2];
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
}
}
}
#else
// For a modified GBI where fixed point values are replaced with floats
memcpy(matrix, addr, sizeof(matrix));
// For a modified GBI where fixed point values are replaced with floats
memcpy(matrix, addr, sizeof(matrix));
#endif
}
if (parameters & G_MTX_PROJECTION) {
if (parameters & G_MTX_LOAD) {
@ -1619,11 +1636,11 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32
rdp.viewport_or_scissor_changed = true;
}
static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr, char* otr_path) {
static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr, const char* otr_path) {
rdp.texture_to_load.addr = (const uint8_t*)addr;
rdp.texture_to_load.siz = size;
rdp.texture_to_load.width = width;
if ( otr_path != nullptr && !strncmp(otr_path, "__OTR__", 7)) otr_path = otr_path + 7;
if (otr_path != nullptr && !strncmp(otr_path, "__OTR__", 7)) otr_path = otr_path + 7;
rdp.texture_to_load.otr_path = otr_path;
}
@ -2097,7 +2114,7 @@ static void gfx_run_dl(Gfx* cmd) {
//puts("dl");
int dummy = 0;
char dlName[128];
char fileName[128];
const char* fileName;
Gfx* dListStart = cmd;
uint64_t ourHash = -1;
@ -2151,8 +2168,16 @@ static void gfx_run_dl(Gfx* cmd) {
uintptr_t mtxAddr = cmd->words.w1;
// OTRTODO: Temp way of dealing with gMtxClear. Need something more elegant in the future...
if (mtxAddr == SEG_ADDR(0, 0x12DB20) || mtxAddr == SEG_ADDR(0, 0x12DB40))
mtxAddr = clearMtx;
uint32_t gameVersion = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->GetGameVersion();
if (gameVersion == OOT_PAL_GC) {
if (mtxAddr == SEG_ADDR(0, 0x0FBC20)) {
mtxAddr = clearMtx;
}
} else {
if (mtxAddr == SEG_ADDR(0, 0x12DB20) || mtxAddr == SEG_ADDR(0, 0x12DB40)) {
mtxAddr = clearMtx;
}
}
#ifdef F3DEX_GBI_2
gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t *) seg_addr(mtxAddr));
@ -2412,7 +2437,7 @@ static void gfx_run_dl(Gfx* cmd) {
uintptr_t addr = cmd->words.w1;
cmd++;
uint64_t hash = ((uint64_t)cmd->words.w0 << 32) + (uint64_t)cmd->words.w1;
ResourceMgr_GetNameByCRC(hash, fileName);
fileName = ResourceMgr_GetNameByCRC(hash);
#if _DEBUG && 0
char* tex = ResourceMgr_LoadTexByCRC(hash);
ResourceMgr_GetNameByCRC(hash, fileName);
@ -2698,6 +2723,7 @@ void gfx_start_frame(void) {
gfx_wapi->handle_events();
gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height);
SohImGui::DrawMainMenuAndCalculateGameSize();
has_drawn_imgui_menu = true;
if (gfx_current_dimensions.height == 0) {
// Avoid division by zero
gfx_current_dimensions.height = 1;
@ -2736,7 +2762,7 @@ void gfx_start_frame(void) {
fbActive = 0;
}
void gfx_run(Gfx *commands) {
void gfx_run(Gfx *commands, const std::unordered_map<Mtx *, MtxF>& mtx_replacements) {
gfx_sp_reset();
//puts("New frame");
@ -2745,12 +2771,21 @@ void gfx_run(Gfx *commands) {
if (!gfx_wapi->start_frame()) {
dropped_frame = true;
SohImGui::DrawFramebufferAndGameInput();
SohImGui::CancelFrame();
if (has_drawn_imgui_menu) {
SohImGui::DrawFramebufferAndGameInput();
SohImGui::CancelFrame();
has_drawn_imgui_menu = false;
}
return;
}
dropped_frame = false;
if (!has_drawn_imgui_menu) {
SohImGui::DrawMainMenuAndCalculateGameSize();
}
current_mtx_replacements = &mtx_replacements;
double t0 = gfx_wapi->get_time();
gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, 1, false, true, true, !game_renders_to_framebuffer);
gfx_rapi->start_frame();
@ -2782,6 +2817,7 @@ void gfx_run(Gfx *commands) {
//printf("Process %f %f\n", t1, t1 - t0);
gfx_rapi->end_frame();
gfx_wapi->swap_buffers_begin();
has_drawn_imgui_menu = false;
}
void gfx_end_frame(void) {

View file

@ -6,6 +6,8 @@
#include <unordered_map>
#include <list>
#include "U64/PR/ultra64/types.h"
struct GfxRenderingAPI;
struct GfxWindowManagerAPI;
@ -44,34 +46,31 @@ struct TextureCacheValue {
uint8_t cms, cmt;
bool linear_filter;
// Old versions of libstdc++ fail to compile this
#ifdef _MSC_VER
std::list<TextureCacheMap::iterator>::iterator lru_location;
#else
std::list<int>::iterator lru_location;
#endif
std::list<struct TextureCacheMapIter>::iterator lru_location;
};
struct TextureCacheMapIter {
TextureCacheMap::iterator it;
};
#ifdef __cplusplus
extern "C" {
#endif
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
extern struct XYWidthHeight gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
extern uint32_t gfx_msaa_level;
}
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
void gfx_run(Gfx* commands);
void gfx_run(Gfx* commands, const std::unordered_map<Mtx*, MtxF>& mtx_replacements);
void gfx_end_frame(void);
void gfx_set_framedivisor(int);
void gfx_texture_cache_clear();
int gfx_create_framebuffer(uint32_t width, uint32_t height);
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height);
void gfx_get_pixel_depth_prepare(float x, float y);
uint16_t gfx_get_pixel_depth(float x, float y);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -40,8 +40,11 @@ namespace Ship
for (size_t i = 0; i < patches.size(); i++)
{
std::string hashStr = resMgr->HashToString(patches[i].crc);
auto resShared = resMgr->GetCachedFile(hashStr);
const std::string* hashStr = resMgr->HashToString(patches[i].crc);
if (hashStr == nullptr)
continue;
auto resShared = resMgr->GetCachedFile(hashStr->c_str());
if (resShared != nullptr)
{
auto res = (Ship::DisplayList*)resShared.get();

View file

@ -215,7 +215,7 @@ namespace Ship {
return ToLoad;
}
std::shared_ptr<Ship::Resource> ResourceMgr::GetCachedFile(std::string FilePath) {
std::shared_ptr<Ship::Resource> ResourceMgr::GetCachedFile(const char* FilePath) const {
auto resCacheFind = ResourceCache.find(FilePath);
if (resCacheFind != ResourceCache.end() &&
@ -227,8 +227,13 @@ namespace Ship {
return nullptr;
}
std::shared_ptr<Resource> ResourceMgr::LoadResource(std::string FilePath) {
auto Promise = LoadResourceAsync(FilePath);
std::shared_ptr<Resource> ResourceMgr::LoadResource(const char* FilePath) {
auto Res = LoadResourceAsync(FilePath);
if (std::holds_alternative<std::shared_ptr<Resource>>(Res))
return std::get<std::shared_ptr<Resource>>(Res);
auto& Promise = std::get<std::shared_ptr<ResourcePromise>>(Res);
if (!Promise->bHasResourceLoaded)
{
@ -241,21 +246,18 @@ namespace Ship {
return Promise->resource;
}
std::shared_ptr<ResourcePromise> ResourceMgr::LoadResourceAsync(std::string FilePath) {
StringHelper::ReplaceOriginal(FilePath, "\\", "/");
if (StringHelper::StartsWith(FilePath, "__OTR__"))
FilePath = StringHelper::Split(FilePath, "__OTR__")[1];
std::shared_ptr<ResourcePromise> Promise = std::make_shared<ResourcePromise>();
std::variant<std::shared_ptr<Resource>, std::shared_ptr<ResourcePromise>> ResourceMgr::LoadResourceAsync(const char* FilePath) {
if (FilePath[0] == '_' && FilePath[1] == '_' && FilePath[2] == 'O' && FilePath[3] == 'T' && FilePath[4] == 'R' && FilePath[5] == '_' && FilePath[6] == '_')
FilePath += 7;
const std::lock_guard<std::mutex> ResLock(ResourceLoadMutex);
auto resCacheFind = ResourceCache.find(FilePath);
if (resCacheFind == ResourceCache.end() || resCacheFind->second->isDirty/* || !FileData->bIsLoaded*/) {
if (resCacheFind == ResourceCache.end()) {
SPDLOG_TRACE("Cache miss on Resource load: {}", FilePath.c_str());
SPDLOG_TRACE("Cache miss on Resource load: {}", FilePath);
}
std::shared_ptr<ResourcePromise> Promise = std::make_shared<ResourcePromise>();
std::shared_ptr<File> FileData = LoadFile(FilePath);
Promise->file = FileData;
@ -269,12 +271,13 @@ namespace Ship {
ResourceLoadQueue.push(Promise);
ResourceLoadNotifier.notify_all();
}
} else {
Promise->bHasResourceLoaded = true;
Promise->resource = resCacheFind->second;
}
return Promise;
return Promise;
}
else
{
return resCacheFind->second;
}
}
std::shared_ptr<std::vector<std::shared_ptr<ResourcePromise>>> ResourceMgr::CacheDirectoryAsync(std::string SearchMask) {
@ -282,10 +285,15 @@ namespace Ship {
auto fileList = OTR->ListFiles(SearchMask);
for (DWORD i = 0; i < fileList.size(); i++) {
auto file = LoadResourceAsync(fileList.operator[](i).cFileName);
if (file != nullptr) {
loadedList->push_back(file);
auto resource = LoadResourceAsync(fileList.operator[](i).cFileName);
if (std::holds_alternative<std::shared_ptr<Resource>>(resource))
{
auto promise = std::make_shared<ResourcePromise>();
promise->bHasResourceLoaded = true;
promise->resource = std::get<std::shared_ptr<Resource>>(resource);
resource = promise;
}
loadedList->push_back(std::get<std::shared_ptr<ResourcePromise>>(resource));
}
return loadedList;
@ -335,7 +343,7 @@ namespace Ship {
ResourceCache.clear();
}
std::string ResourceMgr::HashToString(uint64_t Hash) {
const std::string* ResourceMgr::HashToString(uint64_t Hash) const {
return OTR->HashToString(Hash);
}
}

View file

@ -4,6 +4,7 @@
#include <string>
#include <thread>
#include <queue>
#include <variant>
#include "Resource.h"
#include "GlobalCtx2.h"
@ -25,7 +26,7 @@ namespace Ship
std::shared_ptr<Archive> GetArchive() { return OTR; }
std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
std::string HashToString(uint64_t Hash);
const std::string* HashToString(uint64_t Hash) const;
void InvalidateResourceCache();
@ -33,9 +34,10 @@ namespace Ship
void SetGameVersion(uint32_t newGameVersion);
std::shared_ptr<File> LoadFileAsync(std::string FilePath);
std::shared_ptr<File> LoadFile(std::string FilePath);
std::shared_ptr<Ship::Resource> GetCachedFile(std::string FilePath);
std::shared_ptr<Resource> LoadResource(std::string FilePath);
std::shared_ptr<ResourcePromise> LoadResourceAsync(std::string FilePath);
std::shared_ptr<Ship::Resource> GetCachedFile(const char* FilePath) const;
std::shared_ptr<Resource> LoadResource(const char* FilePath);
std::shared_ptr<Resource> LoadResource(const std::string& FilePath) { return LoadResource(FilePath.c_str()); }
std::variant<std::shared_ptr<Resource>, std::shared_ptr<ResourcePromise>> LoadResourceAsync(const char* FilePath);
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> CacheDirectory(std::string SearchMask);
std::shared_ptr<std::vector<std::shared_ptr<ResourcePromise>>> CacheDirectoryAsync(std::string SearchMask);
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> DirtyDirectory(std::string SearchMask);
@ -50,7 +52,7 @@ namespace Ship
std::weak_ptr<GlobalCtx2> Context;
volatile bool bIsRunning;
std::map<std::string, std::shared_ptr<File>> FileCache;
std::map<std::string, std::shared_ptr<Resource>> ResourceCache;
std::map<std::string, std::shared_ptr<Resource>, std::less<>> ResourceCache;
std::queue<std::shared_ptr<File>> FileLoadQueue;
std::queue<std::shared_ptr<ResourcePromise>> ResourceLoadQueue;
std::shared_ptr<Archive> OTR;

View file

@ -92,7 +92,7 @@ void Console::Update() {
}
for (auto [key, var] : BindingToggle) {
if (ImGui::IsKeyPressed(key)) {
CVar* cvar = CVar_GetVar(var.c_str());
CVar* cvar = CVar_Get(var.c_str());
Dispatch("set " + var + " " + std::to_string(cvar == nullptr ? 0 : !static_cast<bool>(cvar->value.valueS32)));
}
}
@ -106,7 +106,7 @@ void Console::Draw() {
if (!this->opened) return;
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
ImGui::Begin("Console", nullptr);
ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoFocusOnAppearing);
const ImVec2 pos = ImGui::GetWindowPos();
const ImVec2 size = ImGui::GetWindowSize();

View file

@ -18,6 +18,7 @@
#include "TextureMod.h"
#include "Window.h"
#include "Cvar.h"
#include "GameOverlay.h"
#include "Texture.h"
#include "../Fast3D/gfx_pc.h"
#include "Lib/stb/stb_image.h"
@ -59,8 +60,10 @@ namespace SohImGui {
WindowImpl impl;
ImGuiIO* io;
Console* console = new Console;
GameOverlay* overlay = new GameOverlay;
bool p_open = false;
bool needs_save = false;
std::vector<const char*> CustomTexts;
int SelectedLanguage = CVar_GetS32("gLanguages", 0); //Default Language to 0=English 1=German 2=French
float kokiri_col[3] = { 0.118f, 0.41f, 0.106f };
float goron_col[3] = { 0.392f, 0.078f, 0.0f };
@ -254,7 +257,7 @@ namespace SohImGui {
void LoadTexture(const std::string& name, const std::string& path) {
GfxRenderingAPI* api = gfx_get_current_rendering_api();
const auto res = GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(normalize(path));
const auto res = GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(path);
const auto asset = new GameAsset{ api->new_texture() };
uint8_t* img_data = stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(res->buffer.get()), res->dwBufferSize, &asset->width, &asset->height, nullptr, 4);
@ -274,7 +277,7 @@ namespace SohImGui {
void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint) {
GfxRenderingAPI* api = gfx_get_current_rendering_api();
const auto res = static_cast<Ship::Texture*>(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(normalize(path)).get());
const auto res = static_cast<Ship::Texture*>(GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(path).get());
std::vector<uint8_t> texBuffer;
texBuffer.reserve(res->width * res->height * 4);
@ -323,10 +326,13 @@ namespace SohImGui {
ImGui::SetCurrentContext(ctx);
io = &ImGui::GetIO();
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io->Fonts->AddFontDefault();
if (UseViewports()) {
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
console->Init();
overlay->Init();
ImGuiWMInit();
ImGuiBackendInit();
@ -357,7 +363,7 @@ namespace SohImGui {
ModInternal::registerHookListener({ CONTROLLER_READ, [](const HookEvent ev) {
pads = static_cast<OSContPad*>(ev->baseArgs["cont_pad"]);
}});
} });
Game::InitSettings();
}
@ -396,7 +402,7 @@ namespace SohImGui {
EnhancementRadioButton("French", "gLanguages", 2);
*/
int val = CVar_GetS32(cvarName.c_str(), 0);
if (ImGui::RadioButton(text.c_str(), id==val)) {
if (ImGui::RadioButton(text.c_str(), id == val)) {
CVar_SetS32(cvarName.c_str(), (int)id);
needs_save = true;
}
@ -411,6 +417,15 @@ namespace SohImGui {
}
}
void EnhancementButton(std::string text, std::string cvarName)
{
bool val = (bool)CVar_GetS32(cvarName.c_str(), 0);
if (ImGui::Button(text.c_str())) {
CVar_SetS32(cvarName.c_str(), !val);
needs_save = true;
}
}
void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format)
{
int val = CVar_GetS32(cvarName.c_str(), 0);
@ -490,6 +505,11 @@ namespace SohImGui {
}
}
void Tooltip(std::string text) {
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", text.c_str());
}
void DrawMainMenuAndCalculateGameSize() {
console->Update();
ImGuiBackendNewFrame();
@ -588,15 +608,17 @@ namespace SohImGui {
}
EnhancementCheckbox("Show Inputs", "gInputEnabled");
Tooltip("Shows currently pressed inputs on the bottom right of the screen");
EnhancementCheckbox("Rumble Enabled", "gRumbleEnabled");
EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false);
Tooltip("Sets the on screen size of the displayed inputs from Show Inputs");
ImGui::Separator();
EnhancementCheckbox("Dpad Support on Pause and File Select", "gDpadPauseName");
EnhancementCheckbox("DPad Support in Ocarina and Text Choice", "gDpadOcarinaText");
EnhancementCheckbox("DPad Support for Browsing Shop Items", "gDpadShop");
EnhancementCheckbox("D-pad Support on Pause and File Select", "gDpadPauseName");
EnhancementCheckbox("D-pad Support in Ocarina and Text Choice", "gDpadOcarinaText");
EnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop");
ImGui::EndMenu();
}
@ -604,8 +626,10 @@ namespace SohImGui {
if (ImGui::BeginMenu("Graphics"))
{
EnhancementSliderInt("Internal Resolution: %dx", "##IMul", "gInternalResolution", 1, 8, "");
Tooltip("Increases the render resolution of the game, up to 8x your output resolution,\nas a more intensive but effective form of anti-aliasing");
gfx_current_dimensions.internal_mul = CVar_GetS32("gInternalResolution", 1);
EnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "");
Tooltip("Activates anti-aliasing when above 1, up to 8x for 8 samples for every pixel");
gfx_msaa_level = CVar_GetS32("gMSAAValue", 1);
EXPERIMENTAL();
@ -617,13 +641,14 @@ namespace SohImGui {
INFO("New Filter: %s", filters[fId]);
gapi->set_texture_filter((FilteringMode)fId);
CVar_SetS32("gTextureFilter", (int) fId);
CVar_SetS32("gTextureFilter", (int)fId);
needs_save = true;
}
}
ImGui::EndCombo();
}
overlay->DrawSettings();
ImGui::EndMenu();
}
@ -636,35 +661,59 @@ namespace SohImGui {
if (ImGui::BeginMenu("Enhancements"))
{
ImGui::Text("Gameplay");
ImGui::Separator();
if (ImGui::BeginMenu("Gameplay"))
{
EnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "");
EnhancementSliderInt("King Zora Speed: %dx", "##WEEPSPEED", "gMweepSpeed", 1, 5, "");
EnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "");
EnhancementSliderInt("King Zora Speed: %dx", "##WEEPSPEED", "gMweepSpeed", 1, 5, "");
EnhancementCheckbox("Skip Text", "gSkipText");
Tooltip("Holding down B skips text");
EnhancementCheckbox("Mute Low HP Alarm", "gLowHpAlarm");
Tooltip("Disable the low HP beeping sound");
EnhancementCheckbox("Minimal UI", "gMinimalUI");
Tooltip("Hides most of the UI when not needed");
EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony");
Tooltip("Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble");
EnhancementCheckbox("Faster Block Push", "gFasterBlockPush");
EnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots");
Tooltip("Allows equiping the tunic and boots to c-buttons");
EnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood");
Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask");
EnhancementCheckbox("Skip Text", "gSkipText");
EnhancementCheckbox("Minimal UI", "gMinimalUI");
EnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood");
EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony");
ImGui::EndMenu();
}
ImGui::Text("Graphics");
ImGui::Separator();
if (ImGui::BeginMenu("Graphics"))
{
EnhancementCheckbox("N64 Mode", "gN64Mode");
Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution");
EnhancementCheckbox("Animated Link in Pause Menu", "gPauseLiveLink");
EnhancementCheckbox("Enable 3D Dropped items", "gNewDrops");
EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon");
Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have");
EnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon");
Tooltip("Always shows dungeon entrance icons on the minimap");
EnhancementCheckbox("N64 Mode", "gN64Mode");
ImGui::EndMenu();
}
EnhancementCheckbox("Animated Link in Pause Menu", "gPauseLiveLink");
EnhancementCheckbox("Enable 3D Dropped items", "gNewDrops");
EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon");
EnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon");
if (ImGui::BeginMenu("Fixes"))
{
EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR");
Tooltip("Makes the L and R buttons in the pause menu the same color");
EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon");
Tooltip("Show dungeon entrances icon only when it should be");
EnhancementCheckbox("Fix Two Handed idle animations", "gTwoHandedIdle");
Tooltip("Makes two handed idle animation play, a seemingly finished animation that was disabled on accident in the original game");
ImGui::Text("Fixes");
ImGui::Separator();
EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR");
EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon");
ImGui::EndMenu();
}
EXPERIMENTAL();
EnhancementCheckbox("60FPS Interpolation", "g60FPS");
EnhancementCheckbox("Disable LOD", "gDisableLOD");
Tooltip("Turns off the level of detail setting, making models always use their higher poly variants");
ImGui::EndMenu();
}
@ -706,22 +755,33 @@ namespace SohImGui {
}
EnhancementCheckbox("No Clip", "gNoClip");
Tooltip("Allows you to walk through walls");
EnhancementCheckbox("Climb Everything", "gClimbEverything");
Tooltip("Makes every surface in the game climbable");
EnhancementCheckbox("Moon Jump on L", "gMoonJumpOnL");
Tooltip("Holding L makes you float into the air");
EnhancementCheckbox("Super Tunic", "gSuperTunic");
Tooltip("Makes every tunic have the effects of every other tunic");
EnhancementCheckbox("Easy ISG", "gEzISG");
Tooltip("Automatically activates the Infinite Sword glitch, making you constantly swing your sword");
EnhancementCheckbox("Unrestricted Items", "gNoRestrictItems");
Tooltip("Allows you to use any item at any location");
EnhancementCheckbox("Freeze Time", "gFreezeTime");
Tooltip("Freezes the time of day");
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Developer Tools"))
{
EnhancementCheckbox("Stats", "gStatsEnabled");
EnhancementCheckbox("Console", "gConsoleEnabled");
console->opened = CVar_GetS32("gConsoleEnabled", 0);
EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled");
Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right,\nand open the debug menu with L on the pause screen");
ImGui::Separator();
EnhancementCheckbox("Stats", "gStatsEnabled");
Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on");
EnhancementCheckbox("Console", "gConsoleEnabled");
Tooltip("Enables the console window, allowing you to input commands, type help for some examples");
console->opened = CVar_GetS32("gConsoleEnabled", 0);
ImGui::EndMenu();
}
@ -730,7 +790,7 @@ namespace SohImGui {
if (ImGui::BeginMenu(category.first.c_str())) {
for (const std::string& name : category.second) {
std::string varName(name);
varName.erase(std::ranges::remove_if(varName, isspace).begin(), varName.end());
varName.erase(std::ranges::remove_if(varName, isspace).begin(), varName.end());
std::string toggleName = "g" + varName + "Enabled";
EnhancementCheckbox(name, toggleName);
@ -738,6 +798,7 @@ namespace SohImGui {
}
ImGui::EndMenu();
}
}
ImGui::EndMenuBar();
@ -748,7 +809,7 @@ namespace SohImGui {
if (CVar_GetS32("gStatsEnabled", 0)) {
const float framerate = ImGui::GetIO().Framerate;
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Debug Stats", nullptr, ImGuiWindowFlags_None);
ImGui::Begin("Debug Stats", nullptr, ImGuiWindowFlags_NoFocusOnAppearing);
#ifdef _WIN32
ImGui::Text("Platform: Windows");
@ -800,6 +861,8 @@ namespace SohImGui {
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
}
overlay->Draw();
}
void DrawFramebufferAndGameInput() {
@ -912,13 +975,12 @@ namespace SohImGui {
ImTextureID GetTextureByID(int id) {
#ifdef ENABLE_DX11
if (impl.backend == Backend::DX11)
{
ImTextureID gfx_d3d11_get_texture_by_id(int id);
return gfx_d3d11_get_texture_by_id(id);
}
#else
return reinterpret_cast<ImTextureID>(id);
if (impl.backend == Backend::DX11)
{
ImTextureID gfx_d3d11_get_texture_by_id(int id);
return gfx_d3d11_get_texture_by_id(id);
}
#endif
return reinterpret_cast<ImTextureID>(id);
}
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "GameOverlay.h"
#include "Lib/ImGui/imgui.h"
#include "SohConsole.h"
@ -58,6 +59,8 @@ namespace SohImGui {
} CustomWindow;
extern Console* console;
extern Ship::GameOverlay* overlay;
extern bool needs_save;
void Init(WindowImpl window_impl);
void Update(EventImpl event);

View file

@ -43,7 +43,7 @@ namespace Ship {
if (raw_path == nullptr) return;
const auto api = BIND_PTR("gfx_api", GfxRenderingAPI*);
const auto path = normalize(raw_path) + ".png";
const auto path = std::string(raw_path) + ".png";
const auto node = BIND_PTR("node", TextureCacheNode**);
const auto fmt = BIND_VAR("fmt", uint32_t*);
const auto siz = BIND_VAR("siz", uint32_t*);

View file

@ -36,15 +36,6 @@ namespace Ship {
void Hook_InvalidateTexture(HookEvent event);
};
inline std::string normalize(std::string path) {
#ifdef _WIN32
std::ranges::replace(path, '/', '\\');
#else
std::replace(path.begin(), path.end(), '\\', '/');
#endif
return path;
}
inline void GrayOutTexture(uint8_t* data, int width, int height) {
for (int x = 0; x < width * height * 4; x += 4) {

View file

@ -24,6 +24,7 @@
#include <chrono>
#include "SohHooks.h"
#include "SohConsole.h"
#include <iostream>
extern "C" {
@ -118,17 +119,16 @@ extern "C" {
ModInternal::callBindHook(0);
}
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc) {
std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
strcpy(alloc, hashStr.c_str());
return (char*)hashStr.c_str();
const char* ResourceMgr_GetNameByCRC(uint64_t crc) {
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
return hashStr != nullptr ? hashStr->c_str() : nullptr;
}
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc) {
std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
if (hashStr != "") {
auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr));
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
//if (res != nullptr)
return (Vtx*)res->vertices.data();
@ -141,10 +141,10 @@ extern "C" {
}
int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc) {
std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
if (hashStr != "") {
auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr));
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (int32_t*)res->mtx.data();
} else {
return nullptr;
@ -152,10 +152,10 @@ extern "C" {
}
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc) {
std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
if (hashStr != "") {
auto res = std::static_pointer_cast<Ship::DisplayList>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr));
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::DisplayList>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (Gfx*)&res->instructions[0];
} else {
return nullptr;
@ -163,14 +163,14 @@ extern "C" {
}
char* ResourceMgr_LoadTexByCRC(uint64_t crc) {
const std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(crc);
if (!hashStr.empty()) {
const auto res = static_cast<Ship::Texture*>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr).get());
if (hashStr != nullptr) {
const auto res = static_cast<Ship::Texture*>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()).get());
ModInternal::bindHook(LOAD_TEXTURE);
ModInternal::initBindHook(2,
HookParameter({.name = "path", .parameter = (void*)hashStr.c_str() }),
HookParameter({.name = "path", .parameter = (void*)hashStr->c_str() }),
HookParameter({.name = "texture", .parameter = static_cast<void*>(&res->imageData) })
);
ModInternal::callBindHook(0);
@ -183,11 +183,11 @@ extern "C" {
void ResourceMgr_RegisterResourcePatch(uint64_t hash, uint32_t instrIndex, uintptr_t origData)
{
std::string hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(hash);
const std::string* hashStr = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->HashToString(hash);
if (hashStr != "")
if (hashStr != nullptr)
{
auto res = (Ship::Texture*)Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr).get();
auto res = (Ship::Texture*)Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()).get();
Ship::Patch patch;
patch.crc = hash;
@ -281,8 +281,12 @@ namespace Ship {
gfx_start_frame();
}
void Window::RunCommands(Gfx* Commands) {
gfx_run(Commands);
void Window::RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) {
for (const auto& m : mtx_replacements) {
gfx_run(Commands, m);
gfx_end_frame();
}
gfx_run(Commands, {});
gfx_end_frame();
}
@ -328,6 +332,8 @@ namespace Ship {
GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen();
}
// OTRTODO: Rig with Kirito's console?
//if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) {
// ToggleConsole();

View file

@ -19,7 +19,7 @@ namespace Ship {
void MainLoop(void (*MainFunction)(void));
void Init();
void StartFrame();
void RunCommands(Gfx* Commands);
void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements);
void SetFrameDivisor(int divisor);
void GetPixelDepthPrepare(float x, float y);
uint16_t GetPixelDepth(float x, float y);

View file

@ -256,6 +256,7 @@
<ClCompile Include="Blob.cpp" />
<ClCompile Include="Cvar.cpp" />
<ClCompile Include="Environment.cpp" />
<ClCompile Include="GameOverlay.cpp" />
<ClCompile Include="GameSettings.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" />
@ -343,6 +344,7 @@
<ClInclude Include="Blob.h" />
<ClInclude Include="Cvar.h" />
<ClInclude Include="Environment.h" />
<ClInclude Include="GameOverlay.h" />
<ClInclude Include="GameSettings.h" />
<ClInclude Include="GameVersions.h" />
<ClInclude Include="Lib\ImGui\backends\imgui_impl_dx11.h" />

View file

@ -88,6 +88,9 @@
<Filter Include="Source Files\Logging">
<UniqueIdentifier>{bd6557f1-9480-413b-b0cd-843f8efc1939}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\CustomImpl\Overlay">
<UniqueIdentifier>{3285ab8a-06d8-4dac-9af9-efb2a9723ab1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Factories\MaterialFactory.cpp">
@ -339,6 +342,9 @@
<ClCompile Include="GameSettings.cpp">
<Filter>Source Files\CustomImpl</Filter>
</ClCompile>
<ClCompile Include="GameOverlay.cpp">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@ -629,5 +635,8 @@
<ClInclude Include="GameVersions.h">
<Filter>Source Files\Resources</Filter>
</ClInclude>
<ClInclude Include="GameOverlay.h">
<Filter>Source Files\CustomImpl\Overlay</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -1,72 +1,72 @@
<Root>
<File Name="map_48x85_static" Segment="12">
<Texture Name="gDekuTreePauseScreenMapFloor3LeftTex" OutName="deku_tree_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor3RightTex" OutName="deku_tree_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor2LeftTex" OutName="deku_tree_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor2RightTex" OutName="deku_tree_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor1LeftTex" OutName="deku_tree_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor1RightTex" OutName="deku_tree_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement1LeftTex" OutName="deku_tree_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement1RightTex" OutName="deku_tree_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement2LeftTex" OutName="deku_tree_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement2RightTex" OutName="deku_tree_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2RightTex" OutName="dodongos_cavern_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1RightTex" OutName="dodongos_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapFloor1LeftTex" OutName="jabu_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapFloor1RightTex" OutName="jabu_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapBasement1LeftTex" OutName="jabu_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapBasement1RightTex" OutName="jabu_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor2LeftTex" OutName="forest_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor2RightTex" OutName="forest_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor1LeftTex" OutName="forest_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor1RightTex" OutName="forest_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement1LeftTex" OutName="forest_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement1RightTex" OutName="forest_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement2LeftTex" OutName="forest_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement2RightTex" OutName="forest_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor5LeftTex" OutName="fire_temple_pause_screen_map_floor_5_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor5RightTex" OutName="fire_temple_pause_screen_map_floor_5_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor4LeftTex" OutName="fire_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor4RightTex" OutName="fire_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor3LeftTex" OutName="fire_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor3RightTex" OutName="fire_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor2LeftTex" OutName="fire_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor2RightTex" OutName="fire_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor1LeftTex" OutName="fire_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor1RightTex" OutName="fire_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3LeftTex" OutName="water_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3RightTex" OutName="water_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2LeftTex" OutName="water_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2RightTex" OutName="water_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1LeftTex" OutName="water_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1RightTex" OutName="water_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1LeftTex" OutName="water_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1RightTex" OutName="water_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4LeftTex" OutName="spirit_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4RightTex" OutName="spirit_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3LeftTex" OutName="spirit_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3RightTex" OutName="spirit_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2LeftTex" OutName="spirit_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2RightTex" OutName="spirit_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1LeftTex" OutName="spirit_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1RightTex" OutName="spirit_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1LeftTex" OutName="shadow_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1RightTex" OutName="shadow_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2LeftTex" OutName="shadow_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2RightTex" OutName="shadow_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3LeftTex" OutName="shadow_temple_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3RightTex" OutName="shadow_temple_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4LeftTex" OutName="shadow_temple_pause_screen_map_basement_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4RightTex" OutName="shadow_temple_pause_screen_map_basement_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gIceCavernPauseScreenMapFloor1LeftTex" OutName="ice_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gIceCavernPauseScreenMapFloor1RightTex" OutName="ice_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor3LeftTex" OutName="deku_tree_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x0"/>
<Texture Name="gDekuTreePauseScreenMapFloor3RightTex" OutName="deku_tree_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x07F8"/>
<Texture Name="gDekuTreePauseScreenMapFloor2LeftTex" OutName="deku_tree_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x0FF0"/>
<Texture Name="gDekuTreePauseScreenMapFloor2RightTex" OutName="deku_tree_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x17E8"/>
<Texture Name="gDekuTreePauseScreenMapFloor1LeftTex" OutName="deku_tree_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x1FE0"/>
<Texture Name="gDekuTreePauseScreenMapFloor1RightTex" OutName="deku_tree_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x27D8"/>
<Texture Name="gDekuTreePauseScreenMapBasement1LeftTex" OutName="deku_tree_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x2FD0"/>
<Texture Name="gDekuTreePauseScreenMapBasement1RightTex" OutName="deku_tree_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x37C8"/>
<Texture Name="gDekuTreePauseScreenMapBasement2LeftTex" OutName="deku_tree_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x3FC0"/>
<Texture Name="gDekuTreePauseScreenMapBasement2RightTex" OutName="deku_tree_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x47B8"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x4FB0"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2RightTex" OutName="dodongos_cavern_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x57A8"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x5FA0"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1RightTex" OutName="dodongos_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x6798"/>
<Texture Name="gJabuPauseScreenMapFloor1LeftTex" OutName="jabu_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x6F90"/>
<Texture Name="gJabuPauseScreenMapFloor1RightTex" OutName="jabu_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x7788"/>
<Texture Name="gJabuPauseScreenMapBasement1LeftTex" OutName="jabu_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x7F80"/>
<Texture Name="gJabuPauseScreenMapBasement1RightTex" OutName="jabu_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x8778"/>
<Texture Name="gForestTemplePauseScreenMapFloor2LeftTex" OutName="forest_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x8F70"/>
<Texture Name="gForestTemplePauseScreenMapFloor2RightTex" OutName="forest_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x9768"/>
<Texture Name="gForestTemplePauseScreenMapFloor1LeftTex" OutName="forest_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x9F60"/>
<Texture Name="gForestTemplePauseScreenMapFloor1RightTex" OutName="forest_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0xA758"/>
<Texture Name="gForestTemplePauseScreenMapBasement1LeftTex" OutName="forest_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0xAF50"/>
<Texture Name="gForestTemplePauseScreenMapBasement1RightTex" OutName="forest_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0xB748"/>
<Texture Name="gForestTemplePauseScreenMapBasement2LeftTex" OutName="forest_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0xBF40"/>
<Texture Name="gForestTemplePauseScreenMapBasement2RightTex" OutName="forest_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0xC738"/>
<Texture Name="gFireTemplePauseScreenMapFloor5LeftTex" OutName="fire_temple_pause_screen_map_floor_5_left" Format="ci4" Width="48" Height="85" Offset="0xCF30"/>
<Texture Name="gFireTemplePauseScreenMapFloor5RightTex" OutName="fire_temple_pause_screen_map_floor_5_right" Format="ci4" Width="48" Height="85" Offset="0xD728"/>
<Texture Name="gFireTemplePauseScreenMapFloor4LeftTex" OutName="fire_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85" Offset="0xDF20"/>
<Texture Name="gFireTemplePauseScreenMapFloor4RightTex" OutName="fire_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85" Offset="0xE718"/>
<Texture Name="gFireTemplePauseScreenMapFloor3LeftTex" OutName="fire_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0xEF10"/>
<Texture Name="gFireTemplePauseScreenMapFloor3RightTex" OutName="fire_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0xF708"/>
<Texture Name="gFireTemplePauseScreenMapFloor2LeftTex" OutName="fire_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0xFF00"/>
<Texture Name="gFireTemplePauseScreenMapFloor2RightTex" OutName="fire_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x106F8"/>
<Texture Name="gFireTemplePauseScreenMapFloor1LeftTex" OutName="fire_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x10EF0"/>
<Texture Name="gFireTemplePauseScreenMapFloor1RightTex" OutName="fire_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x116E8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3LeftTex" OutName="water_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x11EE0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3RightTex" OutName="water_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x126D8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2LeftTex" OutName="water_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x12ED0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2RightTex" OutName="water_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x136C8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1LeftTex" OutName="water_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x13EC0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1RightTex" OutName="water_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x146B8"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1LeftTex" OutName="water_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x14EB0"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1RightTex" OutName="water_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x156A8"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4LeftTex" OutName="spirit_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85" Offset="0x15EA0"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4RightTex" OutName="spirit_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85" Offset="0x16698"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3LeftTex" OutName="spirit_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x16E90"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3RightTex" OutName="spirit_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x17688"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2LeftTex" OutName="spirit_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x17E80"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2RightTex" OutName="spirit_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x18678"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1LeftTex" OutName="spirit_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x18E70"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1RightTex" OutName="spirit_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x19668"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1LeftTex" OutName="shadow_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x19E60"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1RightTex" OutName="shadow_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x1A658"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2LeftTex" OutName="shadow_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x1AE50"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2RightTex" OutName="shadow_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x1B648"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3LeftTex" OutName="shadow_temple_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85" Offset="0x1BE40"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3RightTex" OutName="shadow_temple_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85" Offset="0x1C638"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4LeftTex" OutName="shadow_temple_pause_screen_map_basement_4_left" Format="ci4" Width="48" Height="85" Offset="0x1CE30"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4RightTex" OutName="shadow_temple_pause_screen_map_basement_4_right" Format="ci4" Width="48" Height="85" Offset="0x1D628"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x1DE20"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x1E618"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x1EE10"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x1F608"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85" Offset="0x1FE00"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85" Offset="0x205F8"/>
<Texture Name="gIceCavernPauseScreenMapFloor1LeftTex" OutName="ice_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x20DF0"/>
<Texture Name="gIceCavernPauseScreenMapFloor1RightTex" OutName="ice_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x215E8"/>
</File>
</Root>

View file

@ -1,72 +1,72 @@
<Root>
<File Name="map_48x85_static" Segment="12">
<Texture Name="gDekuTreePauseScreenMapFloor3LeftTex" OutName="deku_tree_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor3RightTex" OutName="deku_tree_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor2LeftTex" OutName="deku_tree_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor2RightTex" OutName="deku_tree_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor1LeftTex" OutName="deku_tree_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor1RightTex" OutName="deku_tree_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement1LeftTex" OutName="deku_tree_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement1RightTex" OutName="deku_tree_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement2LeftTex" OutName="deku_tree_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapBasement2RightTex" OutName="deku_tree_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2RightTex" OutName="dodongos_cavern_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1RightTex" OutName="dodongos_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapFloor1LeftTex" OutName="jabu_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapFloor1RightTex" OutName="jabu_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapBasement1LeftTex" OutName="jabu_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gJabuPauseScreenMapBasement1RightTex" OutName="jabu_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor2LeftTex" OutName="forest_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor2RightTex" OutName="forest_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor1LeftTex" OutName="forest_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapFloor1RightTex" OutName="forest_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement1LeftTex" OutName="forest_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement1RightTex" OutName="forest_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement2LeftTex" OutName="forest_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gForestTemplePauseScreenMapBasement2RightTex" OutName="forest_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor5LeftTex" OutName="fire_temple_pause_screen_map_floor_5_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor5RightTex" OutName="fire_temple_pause_screen_map_floor_5_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor4LeftTex" OutName="fire_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor4RightTex" OutName="fire_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor3LeftTex" OutName="fire_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor3RightTex" OutName="fire_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor2LeftTex" OutName="fire_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor2RightTex" OutName="fire_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor1LeftTex" OutName="fire_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gFireTemplePauseScreenMapFloor1RightTex" OutName="fire_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3LeftTex" OutName="water_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3RightTex" OutName="water_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2LeftTex" OutName="water_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2RightTex" OutName="water_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1LeftTex" OutName="water_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1RightTex" OutName="water_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1LeftTex" OutName="water_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1RightTex" OutName="water_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4LeftTex" OutName="spirit_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4RightTex" OutName="spirit_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3LeftTex" OutName="spirit_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3RightTex" OutName="spirit_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2LeftTex" OutName="spirit_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2RightTex" OutName="spirit_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1LeftTex" OutName="spirit_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1RightTex" OutName="spirit_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1LeftTex" OutName="shadow_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1RightTex" OutName="shadow_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2LeftTex" OutName="shadow_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2RightTex" OutName="shadow_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3LeftTex" OutName="shadow_temple_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3RightTex" OutName="shadow_temple_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4LeftTex" OutName="shadow_temple_pause_screen_map_basement_4_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4RightTex" OutName="shadow_temple_pause_screen_map_basement_4_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gIceCavernPauseScreenMapFloor1LeftTex" OutName="ice_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85"/>
<Texture Name="gIceCavernPauseScreenMapFloor1RightTex" OutName="ice_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85"/>
<Texture Name="gDekuTreePauseScreenMapFloor3LeftTex" OutName="deku_tree_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x0"/>
<Texture Name="gDekuTreePauseScreenMapFloor3RightTex" OutName="deku_tree_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x07F8"/>
<Texture Name="gDekuTreePauseScreenMapFloor2LeftTex" OutName="deku_tree_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x0FF0"/>
<Texture Name="gDekuTreePauseScreenMapFloor2RightTex" OutName="deku_tree_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x17E8"/>
<Texture Name="gDekuTreePauseScreenMapFloor1LeftTex" OutName="deku_tree_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x1FE0"/>
<Texture Name="gDekuTreePauseScreenMapFloor1RightTex" OutName="deku_tree_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x27D8"/>
<Texture Name="gDekuTreePauseScreenMapBasement1LeftTex" OutName="deku_tree_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x2FD0"/>
<Texture Name="gDekuTreePauseScreenMapBasement1RightTex" OutName="deku_tree_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x37C8"/>
<Texture Name="gDekuTreePauseScreenMapBasement2LeftTex" OutName="deku_tree_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x3FC0"/>
<Texture Name="gDekuTreePauseScreenMapBasement2RightTex" OutName="deku_tree_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x47B8"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x4FB0"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor2RightTex" OutName="dodongos_cavern_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x57A8"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1LeftTex" OutName="dodongos_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x5FA0"/>
<Texture Name="gDodongosCavernPauseScreenMapFloor1RightTex" OutName="dodongos_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x6798"/>
<Texture Name="gJabuPauseScreenMapFloor1LeftTex" OutName="jabu_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x6F90"/>
<Texture Name="gJabuPauseScreenMapFloor1RightTex" OutName="jabu_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x7788"/>
<Texture Name="gJabuPauseScreenMapBasement1LeftTex" OutName="jabu_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x7F80"/>
<Texture Name="gJabuPauseScreenMapBasement1RightTex" OutName="jabu_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x8778"/>
<Texture Name="gForestTemplePauseScreenMapFloor2LeftTex" OutName="forest_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x8F70"/>
<Texture Name="gForestTemplePauseScreenMapFloor2RightTex" OutName="forest_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x9768"/>
<Texture Name="gForestTemplePauseScreenMapFloor1LeftTex" OutName="forest_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x9F60"/>
<Texture Name="gForestTemplePauseScreenMapFloor1RightTex" OutName="forest_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0xA758"/>
<Texture Name="gForestTemplePauseScreenMapBasement1LeftTex" OutName="forest_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0xAF50"/>
<Texture Name="gForestTemplePauseScreenMapBasement1RightTex" OutName="forest_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0xB748"/>
<Texture Name="gForestTemplePauseScreenMapBasement2LeftTex" OutName="forest_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0xBF40"/>
<Texture Name="gForestTemplePauseScreenMapBasement2RightTex" OutName="forest_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0xC738"/>
<Texture Name="gFireTemplePauseScreenMapFloor5LeftTex" OutName="fire_temple_pause_screen_map_floor_5_left" Format="ci4" Width="48" Height="85" Offset="0xCF30"/>
<Texture Name="gFireTemplePauseScreenMapFloor5RightTex" OutName="fire_temple_pause_screen_map_floor_5_right" Format="ci4" Width="48" Height="85" Offset="0xD728"/>
<Texture Name="gFireTemplePauseScreenMapFloor4LeftTex" OutName="fire_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85" Offset="0xDF20"/>
<Texture Name="gFireTemplePauseScreenMapFloor4RightTex" OutName="fire_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85" Offset="0xE718"/>
<Texture Name="gFireTemplePauseScreenMapFloor3LeftTex" OutName="fire_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0xEF10"/>
<Texture Name="gFireTemplePauseScreenMapFloor3RightTex" OutName="fire_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0xF708"/>
<Texture Name="gFireTemplePauseScreenMapFloor2LeftTex" OutName="fire_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0xFF00"/>
<Texture Name="gFireTemplePauseScreenMapFloor2RightTex" OutName="fire_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x106F8"/>
<Texture Name="gFireTemplePauseScreenMapFloor1LeftTex" OutName="fire_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x10EF0"/>
<Texture Name="gFireTemplePauseScreenMapFloor1RightTex" OutName="fire_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x116E8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3LeftTex" OutName="water_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x11EE0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor3RightTex" OutName="water_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x126D8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2LeftTex" OutName="water_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x12ED0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor2RightTex" OutName="water_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x136C8"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1LeftTex" OutName="water_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x13EC0"/>
<Texture Name="gWaterTemplePauseScreenMapFloor1RightTex" OutName="water_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x146B8"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1LeftTex" OutName="water_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x14EB0"/>
<Texture Name="gWaterTemplePauseScreenMapBasement1RightTex" OutName="water_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x156A8"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4LeftTex" OutName="spirit_temple_pause_screen_map_floor_4_left" Format="ci4" Width="48" Height="85" Offset="0x15EA0"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor4RightTex" OutName="spirit_temple_pause_screen_map_floor_4_right" Format="ci4" Width="48" Height="85" Offset="0x16698"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3LeftTex" OutName="spirit_temple_pause_screen_map_floor_3_left" Format="ci4" Width="48" Height="85" Offset="0x16E90"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor3RightTex" OutName="spirit_temple_pause_screen_map_floor_3_right" Format="ci4" Width="48" Height="85" Offset="0x17688"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2LeftTex" OutName="spirit_temple_pause_screen_map_floor_2_left" Format="ci4" Width="48" Height="85" Offset="0x17E80"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor2RightTex" OutName="spirit_temple_pause_screen_map_floor_2_right" Format="ci4" Width="48" Height="85" Offset="0x18678"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1LeftTex" OutName="spirit_temple_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x18E70"/>
<Texture Name="gSpiritTemplePauseScreenMapFloor1RightTex" OutName="spirit_temple_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x19668"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1LeftTex" OutName="shadow_temple_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x19E60"/>
<Texture Name="gShadowTemplePauseScreenMapBasement1RightTex" OutName="shadow_temple_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x1A658"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2LeftTex" OutName="shadow_temple_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x1AE50"/>
<Texture Name="gShadowTemplePauseScreenMapBasement2RightTex" OutName="shadow_temple_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x1B648"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3LeftTex" OutName="shadow_temple_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85" Offset="0x1BE40"/>
<Texture Name="gShadowTemplePauseScreenMapBasement3RightTex" OutName="shadow_temple_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85" Offset="0x1C638"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4LeftTex" OutName="shadow_temple_pause_screen_map_basement_4_left" Format="ci4" Width="48" Height="85" Offset="0x1CE30"/>
<Texture Name="gShadowTemplePauseScreenMapBasement4RightTex" OutName="shadow_temple_pause_screen_map_basement_4_right" Format="ci4" Width="48" Height="85" Offset="0x1D628"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_left" Format="ci4" Width="48" Height="85" Offset="0x1DE20"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement1RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_1_right" Format="ci4" Width="48" Height="85" Offset="0x1E618"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_left" Format="ci4" Width="48" Height="85" Offset="0x1EE10"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement2RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_2_right" Format="ci4" Width="48" Height="85" Offset="0x1F608"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3LeftTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_left" Format="ci4" Width="48" Height="85" Offset="0x1FE00"/>
<Texture Name="gBottomOfTheWellPauseScreenMapBasement3RightTex" OutName="bottom_of_the_well_pause_screen_map_basement_3_right" Format="ci4" Width="48" Height="85" Offset="0x205F8"/>
<Texture Name="gIceCavernPauseScreenMapFloor1LeftTex" OutName="ice_cavern_pause_screen_map_floor_1_left" Format="ci4" Width="48" Height="85" Offset="0x20DF0"/>
<Texture Name="gIceCavernPauseScreenMapFloor1RightTex" OutName="ice_cavern_pause_screen_map_floor_1_right" Format="ci4" Width="48" Height="85" Offset="0x215E8"/>
</File>
</Root>
</Root>

View file

@ -29,6 +29,7 @@ void gDPSetTextureImage(Gfx* pkt, u32 f, u32 s, u32 w, uintptr_t i);
void gSPDisplayList(Gfx* pkt, Gfx* dl);
void gSPDisplayListOffset(Gfx* pkt, Gfx* dl, int offset);
void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0);
void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr);
void cleararena(void);
void bootproc(void);
@ -2404,7 +2405,9 @@ void Heaps_Alloc(void);
void Heaps_Free(void);
#ifdef __cplusplus
#undef this
};
#undef this
#endif
#endif

View file

@ -1,7 +1,12 @@
#ifndef STDDEF_H
#define STDDEF_H
#ifndef __cplusplus
#define NULL ((void*)0)
#else
#define NULL nullptr
#endif
#if 0
#define size_t unsigned long
#define ssize_t long

View file

@ -138,6 +138,8 @@ extern GraphicsContext* __gfxCtx;
#ifndef NDEBUG
#define OPEN_DISPS(gfxCtx, file, line) \
{ \
void FrameInterpolation_RecordOpenChild(const void* a, int b); \
FrameInterpolation_RecordOpenChild(file, line); \
GraphicsContext* __gfxCtx; \
Gfx* dispRefs[4]; \
__gfxCtx = gfxCtx; \
@ -146,6 +148,8 @@ extern GraphicsContext* __gfxCtx;
#else
#define OPEN_DISPS(gfxCtx, file, line) \
{ \
void FrameInterpolation_RecordOpenChild(const void* a, int b); \
FrameInterpolation_RecordOpenChild(file, line); \
GraphicsContext* __gfxCtx; \
__gfxCtx = gfxCtx; \
(void)__gfxCtx;
@ -153,11 +157,15 @@ extern GraphicsContext* __gfxCtx;
#ifndef NDEBUG
#define CLOSE_DISPS(gfxCtx, file, line) \
{void FrameInterpolation_RecordCloseChild(void); \
FrameInterpolation_RecordCloseChild();} \
Graph_CloseDisps(dispRefs, gfxCtx, file, line); \
} \
(void)0
#else
#define CLOSE_DISPS(gfxCtx, file, line) \
{void FrameInterpolation_RecordCloseChild(void); \
FrameInterpolation_RecordCloseChild();} \
(void)0; \
} \
(void)0

View file

@ -30,6 +30,9 @@
#include "ichain.h"
#include "regs.h"
#define AUDIO_HEAP_SIZE 0x38000
#define SYSTEM_HEAP_SIZE (1024 * 1024 * 4)
#ifdef __cplusplus
namespace Ship
{

View file

@ -225,6 +225,7 @@ typedef struct EffectSs {
/* 0x5C */ s16 life; // -1 means this entry is free
/* 0x5E */ u8 priority; // Lower value means higher priority
/* 0x5F */ u8 type;
u32 epoch;
} EffectSs; // size = 0x60
typedef struct {

View file

@ -78,6 +78,12 @@ typedef enum {
/* 0x15 */ SLOT_BOTTLE_4,
/* 0x16 */ SLOT_TRADE_ADULT,
/* 0x17 */ SLOT_TRADE_CHILD,
/* 0x18 */ SLOT_TUNIC_KOKIRI,
/* 0x19 */ SLOT_TUNIC_GORON,
/* 0x1A */ SLOT_TUNIC_ZORA,
/* 0x1B */ SLOT_BOOTS_KOKIRI,
/* 0x1C */ SLOT_BOOTS_IRON,
/* 0x1D */ SLOT_BOOTS_HOVER,
/* 0xFF */ SLOT_NONE = 0xFF
} InventorySlot;

View file

@ -128,7 +128,16 @@ typedef enum {
/* 0x40 */ PLAYER_AP_MASK_GERUDO,
/* 0x41 */ PLAYER_AP_MASK_TRUTH,
/* 0x42 */ PLAYER_AP_LENS,
/* 0x43 */ PLAYER_AP_MAX
/* 0x43 */ PLAYER_AP_SHIELD_DEKU,
/* 0x44 */ PLAYER_AP_SHIELD_HYLIAN,
/* 0x45 */ PLAYER_AP_SHIELD_MIRROR,
/* 0x46 */ PLAYER_AP_TUNIC_KOKIRI,
/* 0x47 */ PLAYER_AP_TUNIC_GORON,
/* 0x48 */ PLAYER_AP_TUNIC_ZORA,
/* 0x49 */ PLAYER_AP_BOOTS_KOKIRI,
/* 0x4A */ PLAYER_AP_BOOTS_IRON,
/* 0x4B */ PLAYER_AP_BOOTS_HOVER,
/* 0x4C */ PLAYER_AP_MAX
} PlayerActionParam;
typedef enum {

View file

@ -173,6 +173,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="soh\frame_interpolation.cpp" />
<ClCompile Include="soh\Enhancements\bootcommands.c" />
<ClCompile Include="soh\Enhancements\debugconsole.cpp" />
<ClCompile Include="soh\Enhancements\debugger\colViewer.cpp" />
@ -180,6 +181,7 @@
<ClCompile Include="soh\Enhancements\debugger\debugSaveEditor.cpp" />
<ClCompile Include="soh\Enhancements\debugger\ImGuiHelpers.cpp" />
<ClCompile Include="soh\Enhancements\gameconsole.c" />
<ClCompile Include="soh\Enhancements\savestates.cpp" />
<ClCompile Include="soh\GbiWrap.cpp" />
<ClCompile Include="soh\gu_pc.c" />
<ClCompile Include="soh\OTRGlobals.cpp" />
@ -328,7 +330,6 @@
<ClCompile Include="src\code\z_msgevent.c" />
<ClCompile Include="src\code\z_olib.c" />
<ClCompile Include="src\code\z_onepointdemo.c" />
<ClCompile Include="src\code\z_onepointdemo_data.c" />
<ClCompile Include="src\code\z_parameter.c" />
<ClCompile Include="src\code\z_path.c" />
<ClCompile Include="src\code\z_play.c" />
@ -878,6 +879,7 @@
<ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="soh\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" />
<ClInclude Include="include\bgm.h" />
<ClInclude Include="include\color.h" />
@ -926,10 +928,12 @@
<ClInclude Include="soh\Enhancements\cvar.h" />
<ClInclude Include="soh\Enhancements\debugconsole.h" />
<ClInclude Include="soh\Enhancements\debugger\colViewer.h" />
<ClInclude Include="soh\Enhancements\savestates.h" />
<ClInclude Include="soh\Enhancements\debugger\debugger.h" />
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h" />
<ClInclude Include="soh\gameconsole.h" />
<ClInclude Include="soh\OTRAudio.h" />
<ClInclude Include="soh\OTRGlobals.h" />
<ClInclude Include="soh\util.h" />
<ClInclude Include="src\overlays\actors\ovl_Arms_Hook\z_arms_hook.h" />
@ -1409,4 +1413,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -630,9 +630,6 @@
<ClCompile Include="src\code\z_onepointdemo.c">
<Filter>Source Files\src\code</Filter>
</ClCompile>
<ClCompile Include="src\code\z_onepointdemo_data.c">
<Filter>Source Files\src\code</Filter>
</ClCompile>
<ClCompile Include="src\code\z_parameter.c">
<Filter>Source Files\src\code</Filter>
</ClCompile>
@ -2189,6 +2186,14 @@
</ClCompile>
<ClCompile Include="soh\Enhancements\debugger\ImGuiHelpers.cpp">
<Filter>Source Files\soh\Enhancements\debugger</Filter>
<ClCompile Include="soh\frame_interpolation.cpp">
<Filter>Source Files\soh</Filter>
</ClCompile>
<ClCompile Include="src\code\z_cheap_proc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\savestates.cpp">
<Filter>Source Files\soh\Enhancements</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -3745,6 +3750,14 @@
</ClInclude>
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h">
<Filter>Header Files\soh\Enhancements\debugger</Filter>
<ClInclude Include="soh\frame_interpolation.h">
<Filter>Header Files\soh</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\savestates.h">
<Filter>Source Files\soh\Enhancements</Filter>
</ClInclude>
<ClInclude Include="soh\OTRAudio.h">
<Filter>Source Files\soh</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>

View file

@ -27,6 +27,7 @@ void BootCommands_Init()
CVar_RegisterS32("gMinimalUI", 0);
CVar_RegisterS32("gRumbleEnabled", 0);
CVar_RegisterS32("gUniformLR", 1);
CVar_RegisterS32("gTwoHandedIdle", 0);
CVar_RegisterS32("gNewDrops", 0);
CVar_RegisterS32("gVisualAgony", 0);
CVar_RegisterS32("gLanguages", 0); //0 = English / 1 = German / 2 = French

View file

@ -1,12 +1,22 @@
#ifdef _MSC_VER
#define NOGDI
#endif
#include "debugconsole.h"
#include "../libultraship/SohImGuiImpl.h"
#include "savestates.h"
#include <vector>
#include <string>
#include "soh/OTRGlobals.h"
#define Path _Path
#define PATH_HACK
#include <Utils/StringHelper.h>
#include <Utils/File.h>
#include "Lib/ImGui/imgui_internal.h"
#undef PATH_HACK
#undef Path
@ -301,6 +311,66 @@ static bool EntranceHandler(const std::vector<std::string>& args) {
gSaveContext.nextTransition = 11;
}
static bool SaveStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[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\"");
return CMD_FAILED;
}
}
static bool LoadStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", slot);
return CMD_SUCCESS;
case SaveStateReturn::FAIL_INVALID_SLOT:
ERROR("[SOH] Invalid State Slot Number (%u)", slot);
return CMD_FAILED;
case SaveStateReturn::FAIL_STATE_EMPTY:
ERROR("[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\"");
return CMD_FAILED;
}
}
static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
int slot;
try {
slot = std::stoi(args[1], nullptr, 10);
} catch (std::invalid_argument const& ex) {
ERROR("[SOH] SaveState slot value must be a number.");
return CMD_FAILED;
}
if (slot < 0) {
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
return CMD_FAILED;
}
OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot);
INFO("[SOH] Slot %u selected", OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot());
return CMD_SUCCESS;
}
#define VARTYPE_INTEGER 0
#define VARTYPE_FLOAT 1
#define VARTYPE_STRING 2
@ -334,7 +404,7 @@ static bool SetCVarHandler(const std::vector<std::string>& args) {
int vType = CheckVarType(args[2]);
if (vType == VARTYPE_STRING)
CVar_SetString(args[1].c_str(), (char*)args[2].c_str());
CVar_SetString(args[1].c_str(), args[2].c_str());
else if (vType == VARTYPE_FLOAT)
CVar_SetFloat(args[1].c_str(), std::stof(args[2]));
else
@ -351,7 +421,7 @@ static bool GetCVarHandler(const std::vector<std::string>& args) {
if (args.size() < 2)
return CMD_FAILED;
CVar* cvar = CVar_GetVar(args[1].c_str());
CVar* cvar = CVar_Get(args[1].c_str());
if (cvar != nullptr)
{
@ -414,6 +484,13 @@ void DebugConsole_Init(void) {
{ { "slot", ArgumentType::NUMBER }, { "item id", ArgumentType::NUMBER } } });
CMD_REGISTER("entrance",
{ EntranceHandler, "Sends player to the entered entrance (hex)", { { "entrance", ArgumentType::NUMBER } } });
CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." });
CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." });
CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", {
{ "Slot number", ArgumentType::NUMBER, }
} });
DebugConsole_LoadCVars();
}
template <typename Numeric> bool is_number(const std::string& s) {
@ -431,7 +508,9 @@ void DebugConsole_LoadCVars()
if (line.empty()) continue;
if (cfg.size() < 2) continue;
if (cfg[1].find("\"") != std::string::npos) {
CVar_SetString(cfg[0].c_str(), const_cast<char*>(cfg[1].c_str()));
std::string value(cfg[1]);
value.erase(std::ranges::remove(value, '\"').begin(), value.end());
CVar_SetString(cfg[0].c_str(), ImStrdup(value.c_str()));
}
if (is_number<float>(cfg[1])) {
CVar_SetFloat(cfg[0].c_str(), std::stof(cfg[1]));

View file

@ -1,6 +1,7 @@
#include "colViewer.h"
#include "../libultraship/SohImGuiImpl.h"
#include "ImGuiHelpers.h"
#include "../../frame_interpolation.h"
#include <vector>
#include <string>
@ -97,7 +98,7 @@ void DrawColViewerWindow(bool& open) {
}
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Collision Viewer", &open)) {
if (!ImGui::Begin("Collision Viewer", &open, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}

View file

@ -251,15 +251,31 @@ void DrawGroupWithBorder(T&& drawFunc) {
ImGui::EndGroup();
}
char z2ASCII(int code) {
int ret;
if (code < 10) { //Digits
ret = code + 0x30;
} else if (code >= 10 && code < 36) { //Uppercase letters
ret = code + 0x37;
} else if (code >= 36 && code < 62) { //Lowercase letters
ret = code + 0x3D;
} else if (code == 62) { //Space
ret = code - 0x1E;
} else if (code == 63 || code == 64) { // _ and .
ret = code - 0x12;
} else {
ret = code;
}
return char(ret);
}
void DrawInfoTab() {
// TODO This is the bare minimum to get the player name showing
// There will need to be more effort to get it robust and editable
// TODO Needs a better method for name changing but for now this will work.
std::string name;
ImU16 one = 1;
for (int i = 0; i < 8; i++) {
char letter = gSaveContext.playerName[i] + 0x3D;
if (letter == '{') {
letter = '\0';
}
char letter = z2ASCII(gSaveContext.playerName[i]);
name += letter;
}
name += '\0';
@ -268,6 +284,14 @@ void DrawInfoTab() {
ImGui::Text("Name: %s", name.c_str());
InsertHelpHoverText("Player Name");
std::string nameID;
for (int i = 0; i < 8; i++) {
nameID = z2ASCII(i);
if (i % 4 != 0) {
ImGui::SameLine();
}
ImGui::InputScalar(nameID.c_str(), ImGuiDataType_U8, &gSaveContext.playerName[i], &one, NULL);
}
// Use an intermediary to keep the health from updating (and potentially killing the player)
// until it is done being edited
@ -377,21 +401,101 @@ void DrawInfoTab() {
ImGui::InputScalar("Bgs Day Count", ImGuiDataType_S32, &gSaveContext.bgsDayCount);
InsertHelpHoverText("Total number of days elapsed since giving Biggoron the claim check");
// TODO Changing Link's age is more involved than just setting gSaveContext.linkAge
// It might not fit here and instead should be only changable when changing scenes
/*
if (ImGui::BeginCombo("Link Age", LINK_IS_ADULT ? "Adult" : "Child")) {
if (ImGui::Selectable("Adult")) {
gSaveContext.linkAge = 0;
ImGui::InputScalar("Entrance Index", ImGuiDataType_S32, &gSaveContext.entranceIndex);
InsertHelpHoverText("From which entrance did Link arrive?");
ImGui::InputScalar("Cutscene Index", ImGuiDataType_S32, &gSaveContext.cutsceneIndex);
InsertHelpHoverText("Which cutscene is this?");
ImGui::InputScalar("Navi Timer", ImGuiDataType_U16, &gSaveContext.naviTimer);
InsertHelpHoverText("Navi wants to talk at 600 units, decides not to at 3000.");
ImGui::InputScalar("Timer 1 State", ImGuiDataType_S16, &gSaveContext.timer1State);
InsertHelpHoverText("Heat timer, race timer, etc. Has white font");
ImGui::InputScalar("Timer 1 Value", ImGuiDataType_S16, &gSaveContext.timer1Value, &one, NULL);
InsertHelpHoverText("Time, in seconds");
ImGui::InputScalar("Timer 2 State", ImGuiDataType_S16, &gSaveContext.timer2State);
InsertHelpHoverText("Trade timer, Ganon collapse timer, etc. Has yellow font");
ImGui::InputScalar("Timer 2 Value", ImGuiDataType_S16, &gSaveContext.timer2Value, &one, NULL);
InsertHelpHoverText("Time, in seconds");
const char* audioName;
switch (gSaveContext.audioSetting) {
case 0:
audioName = "Stereo";
break;
case 1:
audioName = "Mono";
break;
case 2:
audioName = "Headset";
break;
case 3:
audioName = "Surround";
break;
default:
audioName = "?";
}
if (ImGui::BeginCombo("Audio", audioName)) {
if (ImGui::Selectable("Stereo")) {
gSaveContext.audioSetting = 0;
}
if (ImGui::Selectable("Child")) {
gSaveContext.linkAge = 1;
if (ImGui::Selectable("Mono")) {
gSaveContext.audioSetting = 1;
}
if (ImGui::Selectable("Headset")) {
gSaveContext.audioSetting = 2;
}
if (ImGui::Selectable("Surround")) {
gSaveContext.audioSetting = 3;
}
ImGui::EndCombo();
}
*/
InsertHelpHoverText("Sound setting");
bool n64DDFlag = gSaveContext.n64ddFlag != 0;
if (ImGui::Checkbox("64 DD file?", &n64DDFlag)) {
gSaveContext.n64ddFlag = n64DDFlag;
}
InsertHelpHoverText("WARNING! If you save, your file may be locked! Use caution!");
if (ImGui::BeginCombo("Z Target Mode", gSaveContext.zTargetSetting ? "Hold" : "Switch")) {
if (ImGui::Selectable("Switch")) {
gSaveContext.zTargetSetting = 0;
}
if (ImGui::Selectable("Hold")) {
gSaveContext.zTargetSetting = 1;
}
ImGui::EndCombo();
}
InsertHelpHoverText("Z-Targeting behavior");
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
static std::array<const char*, 7> minigameHS = { "Horseback Archery",
"Big Poe Points",
"Fishing",
"Malon's Obstacle Course",
"Running Man Race",
"?",
"Dampe's Race" };
if (ImGui::TreeNode("Minigames")) {
for (int i = 0; i < 7; i++) {
if (i == 5) { //HS_UNK_05 is unused
continue;
}
std::string minigameLbl = minigameHS[i];
ImGui::InputScalar(minigameLbl.c_str(), ImGuiDataType_S32, &gSaveContext.highScores[i], &one, NULL);
}
ImGui::TreePop();
}
ImGui::PopItemWidth();
}
@ -505,7 +609,7 @@ void DrawInventoryTab() {
}
// Draw a flag bitfield as an grid of checkboxes
void DrawFlagArray(const std::string& name, uint32_t& flags) {
void DrawFlagArray32(const std::string& name, uint32_t& flags) {
ImGui::PushID(name.c_str());
for (int32_t flagIndex = 0; flagIndex < 32; flagIndex++) {
if ((flagIndex % 8) != 0) {
@ -526,6 +630,25 @@ void DrawFlagArray(const std::string& name, uint32_t& flags) {
ImGui::PopID();
}
void DrawFlagArray16(const std::string& name, uint16_t& flags) {
ImGui::PushID(name.c_str());
for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) {
ImGui::SameLine();
ImGui::PushID(flagIndex);
uint32_t bitMask = 1 << flagIndex;
bool flag = (flags & bitMask) != 0;
if (ImGui::Checkbox("##check", &flag)) {
if (flag) {
flags |= bitMask;
} else {
flags &= ~bitMask;
}
}
ImGui::PopID();
}
ImGui::PopID();
}
void DrawFlagsTab() {
if (ImGui::TreeNode("Current Scene")) {
if (gGlobalCtx != nullptr) {
@ -534,7 +657,7 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Switch");
InsertHelpHoverText("Permanently-saved switch flags");
DrawFlagArray("Switch", act->flags.swch);
DrawFlagArray32("Switch", act->flags.swch);
});
ImGui::SameLine();
@ -542,13 +665,13 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Temp Switch");
InsertHelpHoverText("Temporary switch flags. Unset on scene transitions");
DrawFlagArray("Temp Switch", act->flags.tempSwch);
DrawFlagArray32("Temp Switch", act->flags.tempSwch);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Clear");
InsertHelpHoverText("Permanently-saved room-clear flags");
DrawFlagArray("Clear", act->flags.clear);
DrawFlagArray32("Clear", act->flags.clear);
});
ImGui::SameLine();
@ -556,13 +679,13 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Temp Clear");
InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions");
DrawFlagArray("Temp Clear", act->flags.tempClear);
DrawFlagArray32("Temp Clear", act->flags.tempClear);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Collect");
InsertHelpHoverText("Permanently-saved collect flags");
DrawFlagArray("Collect", act->flags.collect);
DrawFlagArray32("Collect", act->flags.collect);
});
ImGui::SameLine();
@ -570,13 +693,13 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Temp Collect");
InsertHelpHoverText("Temporary collect flags. Unset on scene transitions");
DrawFlagArray("Temp Collect", act->flags.tempCollect);
DrawFlagArray32("Temp Collect", act->flags.tempCollect);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Chest");
InsertHelpHoverText("Permanently-saved chest flags");
DrawFlagArray("Chest", act->flags.chest);
DrawFlagArray32("Chest", act->flags.chest);
});
ImGui::SameLine();
@ -633,7 +756,7 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Switch");
InsertHelpHoverText("Switch flags");
DrawFlagArray("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch);
DrawFlagArray32("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch);
});
ImGui::SameLine();
@ -641,13 +764,13 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Clear");
InsertHelpHoverText("Room-clear flags");
DrawFlagArray("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear);
DrawFlagArray32("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Collect");
InsertHelpHoverText("Collect flags");
DrawFlagArray("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect);
DrawFlagArray32("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect);
});
ImGui::SameLine();
@ -655,13 +778,13 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Chest");
InsertHelpHoverText("Chest flags");
DrawFlagArray("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest);
DrawFlagArray32("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Rooms");
InsertHelpHoverText("Flags for visted rooms");
DrawFlagArray("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms);
DrawFlagArray32("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms);
});
ImGui::SameLine();
@ -669,7 +792,7 @@ void DrawFlagsTab() {
DrawGroupWithBorder([&]() {
ImGui::Text("Floors");
InsertHelpHoverText("Flags for visted floors");
DrawFlagArray("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors);
DrawFlagArray32("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors);
});
ImGui::TreePop();
@ -730,6 +853,124 @@ void DrawFlagsTab() {
gSaveContext.inventory.gsTokens = gsCount;
}
});
if (ImGui::TreeNode("Event Check Inf Flags")) {
DrawGroupWithBorder([&]() {
ImGui::Text("0");
InsertHelpHoverText("Mostly Kokiri Forest related");
DrawFlagArray16("eci0", gSaveContext.eventChkInf[0]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("1");
InsertHelpHoverText("Mostly Lon Lon Ranch related");
DrawFlagArray16("eci1", gSaveContext.eventChkInf[1]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("2");
InsertHelpHoverText("Dodongo Related?");
DrawFlagArray16("eci2", gSaveContext.eventChkInf[2]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("3");
InsertHelpHoverText("Mostly Zora related");
DrawFlagArray16("eci3", gSaveContext.eventChkInf[3]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("4");
InsertHelpHoverText("Random");
DrawFlagArray16("eci4", gSaveContext.eventChkInf[4]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("5");
InsertHelpHoverText("Mostly song learning related");
DrawFlagArray16("eci5", gSaveContext.eventChkInf[5]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("6");
InsertHelpHoverText("Random");
DrawFlagArray16("eci6", gSaveContext.eventChkInf[6]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("7");
InsertHelpHoverText("Boss Battle related");
DrawFlagArray16("eci7", gSaveContext.eventChkInf[7]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("8");
InsertHelpHoverText("Mask related?");
DrawFlagArray16("eci8", gSaveContext.eventChkInf[8]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("9");
InsertHelpHoverText("Mostly carpenter related");
DrawFlagArray16("eci9", gSaveContext.eventChkInf[9]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("A");
InsertHelpHoverText("First-time overworld entrance cs related");
DrawFlagArray16("eci1", gSaveContext.eventChkInf[10]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("B");
InsertHelpHoverText("First-time dungeon entrance cs/trial cs related");
DrawFlagArray16("eci11", gSaveContext.eventChkInf[11]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("C");
InsertHelpHoverText("Random");
DrawFlagArray16("eci12", gSaveContext.eventChkInf[12]);
});
DrawGroupWithBorder([&]() {
ImGui::Text("D");
InsertHelpHoverText("Frog songs/GS rewards");
DrawFlagArray16("eci13", gSaveContext.eventChkInf[13]);
});
ImGui::TreePop();
}
if (ImGui::TreeNode("Inf Table Flags")) {
for (int i = 0; i < 30; i++) {
std::string it_id = "it" + std::to_string(i);
DrawGroupWithBorder([&]() {
ImGui::Text("%2d", i);
DrawFlagArray16(it_id, gSaveContext.infTable[i]);
});
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Item Get Inf Flags")) {
for (int i = 0; i < 4; i++) {
std::string igi_id = "igi" + std::to_string(i);
DrawGroupWithBorder([&]() {
ImGui::Text("%d", i);
DrawFlagArray16(igi_id, gSaveContext.itemGetInf[i]);
});
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Event Inf Flags")) {
for (int i = 0; i < 4; i++) {
std::string ei_id = "ei" + std::to_string(i);
DrawGroupWithBorder([&]() {
ImGui::Text("%d", i);
DrawFlagArray16(ei_id, gSaveContext.eventInf[i]);
});
}
ImGui::TreePop();
}
}
// Draws a combo that lets you choose and upgrade value from a drop-down of text values
@ -1057,13 +1298,249 @@ void DrawQuestStatusTab() {
ImGui::PopItemWidth();
}
void DrawPlayerTab() {
if (gGlobalCtx != nullptr) {
Player* player = GET_PLAYER(gGlobalCtx);
const char* curSword;
const char* curShield;
const char* curTunic;
const char* curBoots;
switch (player->currentSwordItem) {
case ITEM_SWORD_KOKIRI:
curSword = "Kokiri Sword";
break;
case ITEM_SWORD_MASTER:
curSword = "Master Sword";
break;
case ITEM_SWORD_BGS:
curSword = "Biggoron's Sword";
break;
case ITEM_NONE:
curSword = "None";
break;
default:
curSword = "None";
break;
}
switch (player->currentShield) {
case PLAYER_SHIELD_NONE:
curShield = "None";
break;
case PLAYER_SHIELD_DEKU:
curShield = "Deku Shield";
break;
case PLAYER_SHIELD_HYLIAN:
curShield = "Hylian Shield";
break;
case PLAYER_SHIELD_MIRROR:
curShield = "Mirror Shield";
break;
default:
break;
}
switch (player->currentTunic) {
case PLAYER_TUNIC_KOKIRI:
curTunic = "Kokiri Tunic";
break;
case PLAYER_TUNIC_GORON:
curTunic = "Goron Tunic";
break;
case PLAYER_TUNIC_ZORA:
curTunic = "Zora Tunic";
break;
default:
break;
}
switch (player->currentBoots) {
case PLAYER_BOOTS_KOKIRI:
curBoots = "Kokiri Boots";
break;
case PLAYER_BOOTS_IRON:
curBoots = "Iron Boots";
break;
case PLAYER_BOOTS_HOVER:
curBoots = "Hover Boots";
break;
default:
break;
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
DrawGroupWithBorder([&]() {
ImGui::Text("Link's Position");
ImGui::InputScalar("X Pos", ImGuiDataType_Float, &player->actor.world.pos.x);
ImGui::SameLine();
ImGui::InputScalar("Y Pos", ImGuiDataType_Float, &player->actor.world.pos.y);
ImGui::SameLine();
ImGui::InputScalar("Z Pos", ImGuiDataType_Float, &player->actor.world.pos.z);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Link's Rotation");
InsertHelpHoverText("For Link's rotation in relation to the world");
ImGui::InputScalar("X Rot", ImGuiDataType_S16, &player->actor.world.rot.x);
ImGui::SameLine();
ImGui::InputScalar("Y Rot", ImGuiDataType_S16, &player->actor.world.rot.y);
ImGui::SameLine();
ImGui::InputScalar("Z Rot", ImGuiDataType_S16, &player->actor.world.rot.z);
});
DrawGroupWithBorder([&]() {
ImGui::Text("Link's Model Rotation");
InsertHelpHoverText("For Link's actual model");
ImGui::InputScalar("X ModRot", ImGuiDataType_S16, &player->actor.shape.rot.x);
ImGui::SameLine();
ImGui::InputScalar("Y ModRot", ImGuiDataType_S16, &player->actor.shape.rot.y);
ImGui::SameLine();
ImGui::InputScalar("Z ModRot", ImGuiDataType_S16, &player->actor.shape.rot.z);
});
ImGui::InputScalar("Linear Velocity", ImGuiDataType_Float, &player->linearVelocity);
InsertHelpHoverText("Link's speed along the XZ plane");
ImGui::InputScalar("Y Velocity", ImGuiDataType_Float, &player->actor.velocity.y);
InsertHelpHoverText("Link's speed along the Y plane. Caps at -20");
ImGui::InputScalar("Wall Height", ImGuiDataType_Float, &player->wallHeight);
InsertHelpHoverText("\"height used to determine whether link can climb or grab a ledge at the top\"");
ImGui::InputScalar("Invincibility Timer", ImGuiDataType_S8, &player->invincibilityTimer);
InsertHelpHoverText("Can't take damage while this is nonzero");
ImGui::InputScalar("Gravity", ImGuiDataType_Float, &player->actor.gravity);
InsertHelpHoverText("Rate at which Link falls. Default -4.0f");
if (ImGui::BeginCombo("Link Age on Load", gGlobalCtx->linkAgeOnLoad == 0 ? "Adult" : "Child")) {
if (ImGui::Selectable("Adult")) {
gGlobalCtx->linkAgeOnLoad = 0;
}
if (ImGui::Selectable("Child")) {
gGlobalCtx->linkAgeOnLoad = 1;
}
ImGui::EndCombo();
}
InsertHelpHoverText("This will change Link's age when you load a map");
ImGui::Separator();
ImGui::Text("Link's Current Equipment");
ImGui::PushItemWidth(ImGui::GetFontSize() * 15);
if (ImGui::BeginCombo("Sword", curSword)) {
if (ImGui::Selectable("None")) {
player->currentSwordItem = ITEM_NONE;
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_NONE);
}
if (ImGui::Selectable("Kokiri Sword")) {
player->currentSwordItem = ITEM_SWORD_KOKIRI;
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_KOKIRI;
Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_KOKIRI);
}
if (ImGui::Selectable("Master Sword")) {
player->currentSwordItem = ITEM_SWORD_MASTER;
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_MASTER);
}
if (ImGui::Selectable("Biggoron's Sword")) {
if (gSaveContext.bgsFlag) {
if (gSaveContext.swordHealth < 8) {
gSaveContext.swordHealth = 8;
}
player->currentSwordItem = ITEM_SWORD_BGS;
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_BGS;
} else {
if (gSaveContext.swordHealth < 8) {
gSaveContext.swordHealth = 8;
}
player->currentSwordItem = ITEM_SWORD_BGS;
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_KNIFE;
}
Inventory_ChangeEquipment(EQUIP_SWORD, PLAYER_SWORD_BGS);
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("Shield", curShield)) {
if (ImGui::Selectable("None")) {
player->currentShield = PLAYER_SHIELD_NONE;
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_NONE);
}
if (ImGui::Selectable("Deku Shield")) {
player->currentShield = PLAYER_SHIELD_DEKU;
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_DEKU);
}
if (ImGui::Selectable("Hylian Shield")) {
player->currentShield = PLAYER_SHIELD_HYLIAN;
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_HYLIAN);
}
if (ImGui::Selectable("Mirror Shield")) {
player->currentShield = PLAYER_SHIELD_MIRROR;
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_MIRROR);
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("Tunic", curTunic)) {
if (ImGui::Selectable("Kokiri Tunic")) {
player->currentTunic = PLAYER_TUNIC_KOKIRI;
Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_KOKIRI + 1);
}
if (ImGui::Selectable("Goron Tunic")) {
player->currentTunic = PLAYER_TUNIC_GORON;
Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_GORON + 1);
}
if (ImGui::Selectable("Zora Tunic")) {
player->currentTunic = PLAYER_TUNIC_ZORA;
Inventory_ChangeEquipment(EQUIP_TUNIC, PLAYER_TUNIC_ZORA + 1);
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("Boots", curBoots)) {
if (ImGui::Selectable("Kokiri Boots")) {
player->currentBoots = PLAYER_BOOTS_KOKIRI;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_KOKIRI + 1);
}
if (ImGui::Selectable("Iron Boots")) {
player->currentBoots = PLAYER_BOOTS_IRON;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_IRON + 1);
}
if (ImGui::Selectable("Hover Boots")) {
player->currentBoots = PLAYER_BOOTS_HOVER;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_HOVER + 1);
}
ImGui::EndCombo();
}
ImU16 one = 1;
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
DrawGroupWithBorder([&]() {
ImGui::Text("Current C Equips");
ImGui::InputScalar("C Left", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[1], &one, NULL);
ImGui::SameLine();
ImGui::InputScalar("C Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[2], &one, NULL);
ImGui::SameLine();
ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL);
});
} else {
ImGui::Text("Global Context needed for player info!");
}
}
void DrawSaveEditor(bool& open) {
if (!open) {
return;
}
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Save Editor", &open)) {
if (!ImGui::Begin("Save Editor", &open, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}
@ -1094,6 +1571,11 @@ void DrawSaveEditor(bool& open) {
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Player")) {
DrawPlayerTab();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}

View file

@ -0,0 +1,957 @@
#include "savestates.h"
#include "GameVersions.h"
#include <cstdio> // std::sprintf
#include "spdlog/spdlog.h"
#include <soh/OTRGlobals.h>
#include <soh/OTRAudio.h>
#include <SohImGuiImpl.h>
#include "z64.h"
#include "z64save.h"
#include <variables.h>
#include <functions.h>
#include "z64map_mark.h"
#include "../../src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h"
#include "../../src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h"
#include "../../src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h"
#include "../../src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h"
#include "../../src/overlays/actors/ovl_En_Fr/z_en_fr.h"
extern "C" GlobalContext* gGlobalCtx;
// FROM z_lights.c
// I didn't feel like moving it into a header file.
#define LIGHTS_BUFFER_SIZE 32
typedef struct {
/* 0x000 */ s32 numOccupied;
/* 0x004 */ s32 searchIndex;
/* 0x008 */ LightNode buf[LIGHTS_BUFFER_SIZE];
} LightsBuffer; // size = 0x188
#include "savestates_extern.inc"
typedef struct SaveStateInfo {
unsigned char sysHeapCopy[SYSTEM_HEAP_SIZE];
unsigned char audioHeapCopy[AUDIO_HEAP_SIZE];
SaveContext saveContextCopy;
GameInfo gameInfoCopy;
LightsBuffer lightBufferCopy;
AudioContext audioContextCopy;
MtxF mtxStackCopy[20]; // always 20 matricies
MtxF currentMtxCopy;
uint32_t rngSeed;
int16_t blueWarpTimerCopy; /* From door_warp_1 */
SeqScriptState seqScriptStateCopy[4];// Unrelocated
unk_D_8016E750 unk_D_8016E750Copy[4];
ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
uint8_t gSoundBankMutedCopy[7];
u8 D_801333F0_copy;
u8 gAudioSfxSwapOff_copy;
uint16_t gAudioSfxSwapSource_copy[10];
uint16_t gAudioSfxSwapTarget_copy[10];
uint8_t gAudioSfxSwapMode_copy[10];
void (*D_801755D0_copy)(void);
MapMarkData** sLoadedMarkDataTableCopy;
//Static Data
//Camera data
int32_t sInitRegs_copy;
int32_t gDbgCamEnabled_copy;
int32_t sDbgModeIdx_copy;
int16_t sNextUID_copy;
int32_t sCameraInterfaceFlags_copy;
int32_t sCameraInterfaceAlpha_copy;
int32_t sCameraShrinkWindowVal_copy;
int32_t D_8011D3AC_copy;
int32_t sDemo5PrevAction12Frame_copy;
int32_t sDemo5PrevSfxFrame_copy;
int32_t D_8011D3F0_copy;
OnePointCsFull D_8011D6AC_copy[3];
OnePointCsFull D_8011D724_copy[3];
OnePointCsFull D_8011D79C_copy[3];
OnePointCsFull D_8011D83C_copy[2];
OnePointCsFull D_8011D88C_copy[2];
OnePointCsFull D_8011D8DC_copy[3];
OnePointCsFull D_8011D954_copy[4];
OnePointCsFull D_8011D9F4_copy[3];
int16_t D_8011DB08_copy;
int16_t D_8011DB0C_copy;
int32_t sOOBTimer_copy;
f32 D_8015CE50_copy;
f32 D_8015CE54_copy;
CamColChk D_8015CE58_copy;
//Gameover
uint16_t gGameOverTimer_copy;
//One point demo
uint32_t sPrevFrameCs1100_copy;
CutsceneCameraPoint D_8012013C_copy[14];
CutsceneCameraPoint D_8012021C_copy[14];
CutsceneCameraPoint D_801204D4_copy[14];
CutsceneCameraPoint D_801205B4_copy[14];
OnePointCsFull D_801208EC_copy[3];
OnePointCsFull D_80120964_copy[2];
OnePointCsFull D_801209B4_copy[4];
OnePointCsFull D_80120ACC_copy[5];
OnePointCsFull D_80120B94_copy[11];
OnePointCsFull D_80120D4C_copy[7];
OnePointCsFull D_80120FA4_copy[6];
OnePointCsFull D_80121184_copy[2];
OnePointCsFull D_801211D4_copy[2];
OnePointCsFull D_8012133C_copy[3];
OnePointCsFull D_801213B4_copy[5];
OnePointCsFull D_8012151C_copy[2];
OnePointCsFull D_8012156C_copy[2];
OnePointCsFull D_801215BC_copy[1];
OnePointCsFull D_80121C24_copy[7];
OnePointCsFull D_80121D3C_copy[3];
OnePointCsFull D_80121F1C_copy[4];
OnePointCsFull D_80121FBC_copy[4];
OnePointCsFull D_801220D4_copy[5];
OnePointCsFull D_80122714_copy[4];
OnePointCsFull D_80122CB4_copy[2];
OnePointCsFull D_80122D04_copy[2];
OnePointCsFull D_80122E44_copy[2][7];
OnePointCsFull D_8012313C_copy[3];
OnePointCsFull D_801231B4_copy[4];
OnePointCsFull D_80123254_copy[2];
OnePointCsFull D_801232A4_copy[1];
OnePointCsFull D_80123894_copy[3];
OnePointCsFull D_8012390C_copy[2];
OnePointCsFull D_8012395C_copy[3];
OnePointCsFull D_801239D4_copy[3];
uint16_t gTimeIncrement_copy;
//Overlay static data
// z_bg_ddan_kd
Vec3f sBgDdanKdVelocity_copy;
Vec3f sBgDdanKdAccel_copy;
// z_bg_dodoago
s16 sBgDodoagoFirstExplosiveFlag_copy;
u8 sBgDodoagoDisableBombCatcher_copy;
s32 sBgDodoagoTimer_copy;
// z_bg_haka_trap
uint32_t D_80880F30_copy;
uint32_t D_80881014_copy;
// z_bg_hidan_rock
float D_8088BFC0_copy;
// z_bg_menkuri_eye
int32_t D_8089C1A0_copy;
// z_bg_mori_hineri
int16_t sBgMoriHineriNextCamIdx_copy;
// z_bg_po_event
uint8_t sBgPoEventBlocksAtRest_copy;
uint8_t sBgPoEventPuzzleState_copy;
float sBgPoEventblockPushDist_copy;
// z_bg_relay_objects
uint32_t D_808A9508_copy;
// z_bg_spot18_basket
int16_t D_808B85D0_copy;
// z_boss_ganon
uint32_t sBossGanonSeed1_copy;
uint32_t sBossGanonSeed2_copy;
uint32_t sBossGanonSeed3_copy;
void* sBossGanonGanondorf_copy;
void* sBossGanonZelda_copy;
void* sBossGanonCape_copy;
GanondorfEffect sBossGanonEffectBuf_copy[200];
// z_boss_ganon
uint32_t sBossGanonSeed1;
uint32_t sBossGanonSeed2;
uint32_t sBossGanonSeed3;
void* sBossGanonGanondorf;
void* sBossGanonZelda;
void* sBossGanonCape;
GanondorfEffect sBossGanonEffectBuf[200];
// z_boss_ganon2
Vec3f D_8090EB20_copy;
int8_t D_80910638_copy;
void* sBossGanon2Zelda_copy;
void* D_8090EB30_copy;
int32_t sBossGanon2Seed1_copy;
int32_t sBossGanon2Seed2_copy;
int32_t sBossGanon2Seed3_copy;
Vec3f D_809105D8_copy[4];
Vec3f D_80910608_copy[4];
BossGanon2Effect sBossGanon2Particles_copy[100];
// z_boss_tw
uint8_t sTwInitalized_copy;
BossTwEffect sTwEffects_copy[150];
// z_demo_6k
Vec3f sDemo6kVelocity_copy;
// z_demo_du
int32_t D_8096CE94_copy;
// z_demo_kekkai
Vec3f demoKekkaiVel_copy;
// z_en_bw
int32_t sSlugGroup_copy;
// z_en_clear_tag
uint8_t sClearTagIsEffectInitialized_copy;
EnClearTagEffect sClearTagEffects_copy[CLEAR_TAG_EFFECT_MAX_COUNT];
// z_en_fr
EnFrPointers sEnFrPointers_copy;
// z_en_goma
uint8_t sSpawnNum_copy;
// z_en_insect
float D_80A7DEB0_copy;
int16_t D_80A7DEB4_copy;
int16_t D_80A7DEB8_copy;
// z_en_ishi
int16_t sRockRotSpeedX_copy;
int16_t sRockRotSpeedY_copy;
// z_en_niw
int16_t D_80AB85E0_copy;
uint8_t sLowerRiverSpawned_copy;
uint8_t sUpperRiverSpawned_copy;
// z_en_po_field
int32_t sEnPoFieldNumSpawned_copy;
Vec3s sEnPoFieldSpawnPositions_copy[10];
u8 sEnPoFieldSpawnSwitchFlags_copy[10];
// z_en_takara_man
uint8_t sTakaraIsInitialized_copy;
// z_en_xc
int32_t D_80B41D90_copy;
int32_t sEnXcFlameSpawned_copy;
int32_t D_80B41DA8_copy;
int32_t D_80B41DAC_copy;
// z_en_zf
int16_t D_80B4A1B0_copy;
int16_t D_80B4A1B4_copy;
int32_t D_80B5A468_copy;
int32_t D_80B5A494_copy;
int32_t D_80B5A4BC_copy;
uint8_t sKankyoIsSpawned_copy;
int16_t sTrailingFairies_copy;
//Misc static data
// z_map_exp
s16 sPlayerInitialPosX_copy;
s16 sPlayerInitialPosZ_copy;
s16 sPlayerInitialDirection_copy;
// code_800E(something. fill me in later)
u8 sOcarinaInpEnabled_copy;
s8 D_80130F10_copy;
u8 sCurOcarinaBtnVal_copy;
u8 sPrevOcarinaNoteVal_copy;
u8 sCurOcarinaBtnIdx_copy;
u8 sLearnSongLastBtn_copy;
f32 D_80130F24_copy;
f32 D_80130F28_copy;
s8 D_80130F2C_copy;
s8 D_80130F30_copy;
s8 D_80130F34_copy;
u8 sDisplayedNoteValue_copy;
u8 sPlaybackState_copy;
u32 D_80130F3C_copy;
u32 sNotePlaybackTimer_copy;
u16 sPlaybackNotePos_copy;
u16 sStaffPlaybackPos_copy;
u32 sCurOcarinaBtnPress_copy;
u32 D_8016BA10_copy;
u32 sPrevOcarinaBtnPress_copy;
s32 D_8016BA18_copy;
s32 D_8016BA1C_copy;
u8 sCurOcarinaSong_copy[8];
u8 sOcarinaSongAppendPos_copy;
u8 sOcarinaHasStartedSong_copy;
u8 sOcarinaSongNoteStartIdx_copy;
u8 sOcarinaSongCnt_copy;
u16 sOcarinaAvailSongs_copy;
u8 sStaffPlayingPos_copy;
u16 sLearnSongPos_copy[0x10];
u16 D_8016BA50_copy[0x10];
u16 D_8016BA70_copy[0x10];
u8 sLearnSongExpectedNote_copy[0x10];
OcarinaNote D_8016BAA0_copy;
u8 sAudioHasMalonBgm_copy;
f32 sAudioMalonBgmDist_copy;
// Message_PAL
s16 sOcarinaNoteBufPos_copy;
s16 sOcarinaNoteBufLen_copy;
u8 sOcarinaNoteBuf_copy[12];
u8 D_8014B2F4_copy;
u8 sTextboxSkipped_copy;
u16 sNextTextId_copy;
s16 sLastPlayedSong_copy;
s16 sHasSunsSong_copy;
s16 sMessageHasSetSfx_copy;
u16 sOcarinaSongBitFlags_copy;
} SaveStateInfo;
class SaveState {
friend class SaveStateMgr;
public:
SaveState(std::shared_ptr<SaveStateMgr> mgr, unsigned int slot);
private:
unsigned int slot;
std::shared_ptr<SaveStateMgr> saveStateMgr;
std::shared_ptr<SaveStateInfo> info;
void Save(void);
void Load(void);
void BackupSeqScriptState(void);
void LoadSeqScriptState(void);
void BackupCameraData(void);
void LoadCameraData(void);
void SaveOnePointDemoData(void);
void LoadOnePointDemoData(void);
void SaveOverlayStaticData(void);
void LoadOverlayStaticData(void);
void SaveMiscCodeData(void);
void LoadMiscCodeData(void);
SaveStateInfo* GetSaveStateInfo(void);
};
SaveStateMgr::SaveStateMgr() {
this->SetCurrentSlot(0);
}
SaveStateMgr::~SaveStateMgr() {
this->states.clear();
}
SaveState::SaveState(std::shared_ptr<SaveStateMgr> mgr, unsigned int slot) : saveStateMgr(mgr), slot(slot), info(nullptr) {
this->info = std::make_shared<SaveStateInfo>();
}
void SaveState::BackupSeqScriptState(void) {
for (unsigned int i = 0; i < 4; i++) {
info->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value;
info->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0];
info->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1];
info->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2];
info->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3];
info->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth;
info->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[0] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[1] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[2] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[3] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap);
}
}
void SaveState::LoadSeqScriptState(void) {
for (unsigned int i = 0; i < 4; i++) {
gAudioContext.seqPlayers[i].scriptState.value = info->seqScriptStateCopy[i].value;
gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = info->seqScriptStateCopy[i].remLoopIters[0];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = info->seqScriptStateCopy[i].remLoopIters[1];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = info->seqScriptStateCopy[i].remLoopIters[2];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = info->seqScriptStateCopy[i].remLoopIters[3];
gAudioContext.seqPlayers[i].scriptState.depth = info->seqScriptStateCopy[i].depth;
gAudioContext.seqPlayers[i].scriptState.pc =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[0] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[1] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[2] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[3] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap);
}
}
void SaveState::BackupCameraData(void) {
info->sInitRegs_copy = sInitRegs;
info->gDbgCamEnabled_copy = gDbgCamEnabled;
info->sNextUID_copy = sNextUID;
info->sCameraInterfaceFlags_copy = sCameraInterfaceFlags;
info->sCameraInterfaceAlpha_copy = sCameraInterfaceAlpha;
info->sCameraShrinkWindowVal_copy = sCameraShrinkWindowVal;
info->D_8011D3AC_copy = D_8011D3AC;
info->sDemo5PrevAction12Frame_copy = sDemo5PrevAction12Frame;
info->sDemo5PrevSfxFrame_copy = sDemo5PrevSfxFrame;
info->D_8011D3F0_copy = D_8011D3F0;
memcpy(info->D_8011D6AC_copy, D_8011D6AC, sizeof(info->D_8011D6AC_copy));
memcpy(info->D_8011D724_copy, D_8011D724, sizeof(info->D_8011D724_copy));
memcpy(info->D_8011D79C_copy, D_8011D79C, sizeof(info->D_8011D79C_copy));
memcpy(info->D_8011D83C_copy, D_8011D83C, sizeof(info->D_8011D83C_copy));
memcpy(info->D_8011D88C_copy, D_8011D88C, sizeof(info->D_8011D88C_copy));
memcpy(info->D_8011D8DC_copy, D_8011D8DC, sizeof(info->D_8011D8DC_copy));
memcpy(info->D_8011D954_copy, D_8011D954, sizeof(info->D_8011D954_copy));
memcpy(info->D_8011D9F4_copy, D_8011D9F4, sizeof(info->D_8011D9F4_copy));
info->D_8011DB08_copy = D_8011DB08;
info->D_8011DB0C_copy = D_8011DB0C;
info->sOOBTimer_copy = sOOBTimer;
info->D_8015CE50_copy = D_8015CE50;
info->D_8015CE54_copy = D_8015CE54;
memcpy(&info->D_8015CE58_copy, &D_8015CE58, sizeof(info->D_8015CE58_copy));
}
void SaveState::LoadCameraData(void) {
sInitRegs = info->sInitRegs_copy;
gDbgCamEnabled = info->gDbgCamEnabled_copy;
sDbgModeIdx = info->sDbgModeIdx_copy;
sNextUID = info->sNextUID_copy;
sCameraInterfaceAlpha = info->sCameraInterfaceAlpha_copy;
sCameraInterfaceFlags = info->sCameraInterfaceFlags_copy;
sCameraShrinkWindowVal = info->sCameraShrinkWindowVal_copy;
D_8011D3AC = info->D_8011D3AC_copy;
sDemo5PrevAction12Frame = info->sDemo5PrevAction12Frame_copy;
sDemo5PrevSfxFrame = info->sDemo5PrevSfxFrame_copy;
D_8011D3F0 = info->D_8011D3F0_copy;
memcpy(D_8011D6AC, info->D_8011D6AC_copy, sizeof(info->D_8011D6AC_copy));
memcpy(D_8011D724, info->D_8011D724_copy, sizeof(info->D_8011D724_copy));
memcpy(D_8011D79C, info->D_8011D79C_copy, sizeof(info->D_8011D79C_copy));
memcpy(D_8011D83C, info->D_8011D83C_copy, sizeof(info->D_8011D83C_copy));
memcpy(D_8011D88C, info->D_8011D88C_copy, sizeof(info->D_8011D88C_copy));
memcpy(D_8011D8DC, info->D_8011D8DC_copy, sizeof(info->D_8011D8DC_copy));
memcpy(D_8011D954, info->D_8011D954_copy, sizeof(info->D_8011D954_copy));
memcpy(D_8011D9F4, info->D_8011D9F4_copy, sizeof(info->D_8011D9F4_copy));
D_8011DB08 = info->D_8011DB08_copy;
D_8011DB0C = info->D_8011DB0C_copy;
sOOBTimer = info->sOOBTimer_copy;
D_8015CE50 = info->D_8015CE50_copy;
D_8015CE54 = info->D_8015CE54_copy;
memcpy(&D_8015CE58, &info->D_8015CE58_copy, sizeof(info->D_8015CE58_copy));
}
void SaveState::SaveOnePointDemoData(void) {
info->sPrevFrameCs1100_copy = sPrevFrameCs1100;
memcpy(info->D_8012013C_copy, D_8012013C, sizeof(info->D_8012013C_copy));
memcpy(info->D_8012021C_copy, D_8012021C, sizeof(info->D_8012021C_copy));
memcpy(info->D_801204D4_copy, D_801204D4, sizeof(info->D_801204D4_copy));
memcpy(info->D_801205B4_copy, D_801205B4, sizeof(info->D_801205B4_copy));
memcpy(info->D_801208EC_copy, D_801208EC, sizeof(info->D_801208EC_copy));
memcpy(info->D_80120964_copy, D_80120964, sizeof(info->D_80120964_copy));
memcpy(info->D_801209B4_copy, D_801209B4, sizeof(info->D_801209B4_copy));
memcpy(info->D_80120ACC_copy, D_80120ACC, sizeof(info->D_80120ACC_copy));
memcpy(info->D_80120B94_copy, D_80120B94, sizeof(info->D_80120B94_copy));
memcpy(info->D_80120D4C_copy, D_80120D4C, sizeof(info->D_80120D4C_copy));
memcpy(info->D_80120FA4_copy, D_80120FA4, sizeof(info->D_80120FA4_copy));
memcpy(info->D_80121184_copy, D_80121184, sizeof(info->D_80121184_copy));
memcpy(info->D_801211D4_copy, D_801211D4, sizeof(info->D_801211D4_copy));
memcpy(info->D_8012133C_copy, D_8012133C, sizeof(info->D_8012133C_copy));
memcpy(info->D_801213B4_copy, D_801213B4, sizeof(info->D_801213B4_copy));
memcpy(info->D_8012151C_copy, D_8012151C, sizeof(info->D_8012151C_copy));
memcpy(info->D_8012156C_copy, D_8012156C, sizeof(info->D_8012156C_copy));
memcpy(info->D_801215BC_copy, D_801215BC, sizeof(info->D_801215BC_copy));
memcpy(info->D_80121C24_copy, D_80121C24, sizeof(info->D_80121C24_copy));
memcpy(info->D_80121D3C_copy, D_80121D3C, sizeof(info->D_80121D3C_copy));
memcpy(info->D_80121F1C_copy, D_80121F1C, sizeof(info->D_80121F1C_copy));
memcpy(info->D_80121FBC_copy, D_80121FBC, sizeof(info->D_80121FBC_copy));
memcpy(info->D_801220D4_copy, D_801220D4, sizeof(info->D_801220D4_copy));
memcpy(info->D_80122714_copy, D_80122714, sizeof(info->D_80122714_copy));
memcpy(info->D_80122CB4_copy, D_80122CB4, sizeof(info->D_80122CB4_copy));
memcpy(info->D_80122D04_copy, D_80122D04, sizeof(info->D_80122D04_copy));
memcpy(info->D_80122E44_copy, D_80122E44, sizeof(info->D_80122E44_copy));
memcpy(info->D_8012313C_copy, D_8012313C, sizeof(info->D_8012313C_copy));
memcpy(info->D_801231B4_copy, D_801231B4, sizeof(info->D_801231B4_copy));
memcpy(info->D_80123254_copy, D_80123254, sizeof(info->D_80123254_copy));
memcpy(info->D_801232A4_copy, D_801232A4, sizeof(info->D_801232A4_copy));
memcpy(info->D_80123894_copy, D_80123894, sizeof(info->D_80123894_copy));
memcpy(info->D_8012390C_copy, D_8012390C, sizeof(info->D_8012390C_copy));
memcpy(info->D_8012395C_copy, D_8012395C, sizeof(info->D_8012395C_copy));
memcpy(info->D_801239D4_copy, D_801239D4, sizeof(info->D_801239D4_copy));
}
void SaveState::LoadOnePointDemoData(void) {
sPrevFrameCs1100 = info->sPrevFrameCs1100_copy;
memcpy(D_8012013C, info->D_8012013C_copy, sizeof(info->D_8012013C_copy));
memcpy(D_8012021C, info->D_8012021C_copy, sizeof(info->D_8012021C_copy));
memcpy(D_801204D4, info->D_801204D4_copy, sizeof(info->D_801204D4_copy));
memcpy(D_801205B4, info->D_801205B4_copy, sizeof(info->D_801205B4_copy));
memcpy(D_801208EC, info->D_801208EC_copy, sizeof(info->D_801208EC_copy));
memcpy(D_80120964, info->D_80120964_copy, sizeof(info->D_80120964_copy));
memcpy(D_801209B4, info->D_801209B4_copy, sizeof(info->D_801209B4_copy));
memcpy(D_80120ACC, info->D_80120ACC_copy, sizeof(info->D_80120ACC_copy));
memcpy(D_80120B94, info->D_80120B94_copy, sizeof(info->D_80120B94_copy));
memcpy(D_80120D4C, info->D_80120D4C_copy, sizeof(info->D_80120D4C_copy));
memcpy(D_80120FA4, info->D_80120FA4_copy, sizeof(info->D_80120FA4_copy));
memcpy(D_80121184, info->D_80121184_copy, sizeof(info->D_80121184_copy));
memcpy(D_801211D4, info->D_801211D4_copy, sizeof(info->D_801211D4_copy));
memcpy(D_8012133C, info->D_8012133C_copy, sizeof(info->D_8012133C_copy));
memcpy(D_801213B4, info->D_801213B4_copy, sizeof(info->D_801213B4_copy));
memcpy(D_8012151C, info->D_8012151C_copy, sizeof(info->D_8012151C_copy));
memcpy(D_8012156C, info->D_8012156C_copy, sizeof(info->D_8012156C_copy));
memcpy(D_801215BC, info->D_801215BC_copy, sizeof(info->D_801215BC_copy));
memcpy(D_80121C24, info->D_80121C24_copy, sizeof(info->D_80121C24_copy));
memcpy(D_80121D3C, info->D_80121D3C_copy, sizeof(info->D_80121D3C_copy));
memcpy(D_80121F1C, info->D_80121F1C_copy, sizeof(info->D_80121F1C_copy));
memcpy(D_80121FBC, info->D_80121FBC_copy, sizeof(info->D_80121FBC_copy));
memcpy(D_801220D4, info->D_801220D4_copy, sizeof(info->D_801220D4_copy));
memcpy(D_80122714, info->D_80122714_copy, sizeof(info->D_80122714_copy));
memcpy(D_80122CB4, info->D_80122CB4_copy, sizeof(info->D_80122CB4_copy));
memcpy(D_80122D04, info->D_80122D04_copy, sizeof(info->D_80122D04_copy));
memcpy(D_80122E44, info->D_80122E44_copy, sizeof(info->D_80122E44_copy));
memcpy(D_8012313C, info->D_8012313C_copy, sizeof(info->D_8012313C_copy));
memcpy(D_801231B4, info->D_801231B4_copy, sizeof(info->D_801231B4_copy));
memcpy(D_80123254, info->D_80123254_copy, sizeof(info->D_80123254_copy));
memcpy(D_801232A4, info->D_801232A4_copy, sizeof(info->D_801232A4_copy));
memcpy(D_80123894, info->D_80123894_copy, sizeof(info->D_80123894_copy));
memcpy(D_8012390C, info->D_8012390C_copy, sizeof(info->D_8012390C_copy));
memcpy(D_8012395C, info->D_8012395C_copy, sizeof(info->D_8012395C_copy));
memcpy(D_801239D4, info->D_801239D4_copy, sizeof(info->D_801239D4_copy));
}
void SaveState::SaveOverlayStaticData(void) {
info->sBgDdanKdVelocity_copy = sBgDdanKdVelocity;
info->sBgDdanKdAccel_copy = sBgDdanKdAccel;
info->sBgDodoagoFirstExplosiveFlag_copy = sBgDodoagoFirstExplosiveFlag;
info->sBgDodoagoDisableBombCatcher_copy = sBgDodoagoDisableBombCatcher;
info->sBgDodoagoTimer_copy = sBgDodoagoTimer;
info->D_80880F30_copy = D_80880F30;
info->D_80881014_copy = D_80881014;
info->D_8088BFC0_copy = D_8088BFC0;
info->sBgMoriHineriNextCamIdx_copy = sBgMoriHineriNextCamIdx;
info->sBgPoEventBlocksAtRest_copy = sBgPoEventBlocksAtRest;
info->sBgPoEventPuzzleState_copy = sBgPoEventPuzzleState;
info->sBgPoEventblockPushDist_copy = sBgPoEventblockPushDist;
info->D_808A9508_copy = D_808A9508;
info->D_808B85D0_copy = D_808B85D0;
info->sBossGanonSeed1_copy = sBossGanonSeed1;
info->sBossGanonSeed2_copy = sBossGanonSeed2;
info->sBossGanonSeed3_copy = sBossGanonSeed3;
info->sBossGanonGanondorf_copy = sBossGanonGanondorf;
info->sBossGanonZelda_copy = sBossGanonZelda;
info->sBossGanonCape_copy = sBossGanonCape;
memcpy(info->sBossGanonEffectBuf_copy, sBossGanonEffectBuf, sizeof(info->sBossGanonEffectBuf_copy));
info->D_8090EB20_copy = D_8090EB20;
info->D_80910638_copy = D_80910638;
info->sBossGanon2Zelda_copy = sBossGanon2Zelda;
info->D_8090EB30_copy = D_8090EB30;
info->sBossGanon2Seed1_copy = sBossGanon2Seed1;
info->sBossGanon2Seed2_copy = sBossGanon2Seed2;
info->sBossGanon2Seed3_copy = sBossGanon2Seed3;
memcpy(info->D_809105D8_copy, D_809105D8, sizeof(D_809105D8));
memcpy(info->D_80910608_copy, D_80910608, sizeof(D_80910608));
memcpy(info->sBossGanon2Particles_copy, sBossGanon2Particles, sizeof(sBossGanon2Particles));
info->sTwInitalized_copy = sTwInitalized;
memcpy(info->sTwEffects_copy, sTwEffects, sizeof(sTwEffects));
info->sDemo6kVelocity_copy = sDemo6kVelocity;
info->D_8096CE94_copy = D_8096CE94;
info->demoKekkaiVel_copy = demoKekkaiVel;
info->sSlugGroup_copy = sSlugGroup;
info->sClearTagIsEffectInitialized_copy = sClearTagIsEffectsInitialized;
memcpy(info->sClearTagEffects_copy, sClearTagEffects, sizeof(sClearTagEffects));
memcpy(&info->sEnFrPointers_copy, &sEnFrPointers, sizeof(info->sEnFrPointers_copy));
info->sSpawnNum_copy = sSpawnNum;
info->D_80A7DEB0_copy = D_80A7DEB0;
info->D_80A7DEB4_copy = D_80A7DEB4;
info->D_80A7DEB8_copy = D_80A7DEB8;
info->sRockRotSpeedX_copy = sRockRotSpeedX;
info->sRockRotSpeedY_copy = sRockRotSpeedY;
info->D_80AB85E0_copy = D_80AB85E0;
info->sLowerRiverSpawned_copy = sLowerRiverSpawned;
info->sUpperRiverSpawned_copy = sUpperRiverSpawned;
info->sEnPoFieldNumSpawned_copy = sEnPoFieldNumSpawned;
memcpy(info->sEnPoFieldSpawnPositions_copy, sEnPoFieldSpawnPositions, sizeof(info->sEnPoFieldSpawnPositions_copy));
memcpy(info->sEnPoFieldSpawnSwitchFlags_copy, sEnPoFieldSpawnSwitchFlags, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy));
info->sTakaraIsInitialized_copy = sTakaraIsInitialized;
info->D_80B41D90_copy = D_80B41D90;
info->sEnXcFlameSpawned_copy = sEnXcFlameSpawned;
info->D_80B41DA8_copy = D_80B41DA8;
info->D_80B41DAC_copy = D_80B41DAC;
info->D_80B4A1B0_copy = D_80B4A1B0;
info->D_80B4A1B4_copy = D_80B4A1B4;
info->D_80B5A468_copy = D_80B5A468;
info->D_80B5A494_copy = D_80B5A494;
info->D_80B5A4BC_copy = D_80B5A4BC;
info->sKankyoIsSpawned_copy = sKankyoIsSpawned;
info->sTrailingFairies_copy = sTrailingFairies;
}
void SaveState::LoadOverlayStaticData(void) {
sBgDdanKdVelocity = info->sBgDdanKdVelocity_copy;
sBgDdanKdAccel = info->sBgDdanKdAccel_copy;
sBgDodoagoFirstExplosiveFlag = info->sBgDodoagoFirstExplosiveFlag_copy;
sBgDodoagoDisableBombCatcher = info->sBgDodoagoDisableBombCatcher_copy;
sBgDodoagoTimer = info->sBgDodoagoTimer_copy;
D_80880F30 = info->D_80880F30_copy;
D_80881014 = info->D_80881014_copy;
D_8088BFC0 = info->D_8088BFC0_copy;
sBgMoriHineriNextCamIdx = info->sBgMoriHineriNextCamIdx_copy;
sBgPoEventBlocksAtRest = info->sBgPoEventBlocksAtRest_copy;
sBgPoEventPuzzleState = info->sBgPoEventPuzzleState_copy;
sBgPoEventblockPushDist = info->sBgPoEventblockPushDist_copy;
D_808A9508 = info->D_808A9508_copy;
D_808B85D0 = info->D_808B85D0_copy;
sBossGanonSeed1 = info->sBossGanonSeed1_copy;
sBossGanonSeed2 = info->sBossGanonSeed2_copy;
sBossGanonSeed3 = info->sBossGanonSeed3_copy;
sBossGanonGanondorf = info->sBossGanonGanondorf_copy;
sBossGanonZelda = info->sBossGanonZelda_copy;
sBossGanonCape = info->sBossGanonCape_copy;
memcpy(sBossGanonEffectBuf, info->sBossGanonEffectBuf_copy, sizeof(info->sBossGanonEffectBuf_copy));
D_8090EB20 = info->D_8090EB20_copy;
D_80910638 = info->D_80910638_copy;
sBossGanon2Zelda = info->sBossGanon2Zelda_copy;
D_8090EB30 = info->D_8090EB30_copy;
sBossGanon2Seed1 = info->sBossGanon2Seed1_copy;
sBossGanon2Seed2 = info->sBossGanon2Seed2_copy;
sBossGanon2Seed3 = info->sBossGanon2Seed3_copy;
memcpy(D_809105D8, info->D_809105D8_copy, sizeof(D_809105D8));
memcpy(D_80910608, info->D_80910608_copy, sizeof(D_80910608));
memcpy(sBossGanon2Particles, info->sBossGanon2Particles_copy, sizeof(sBossGanon2Particles));
sTwInitalized = info->sTwInitalized_copy;
memcpy(sTwEffects, info->sTwEffects_copy, sizeof(sTwEffects));
sDemo6kVelocity = info->sDemo6kVelocity_copy;
D_8096CE94 = info->D_8096CE94_copy;
demoKekkaiVel = info->demoKekkaiVel_copy;
sSlugGroup = info->sSlugGroup_copy;
sClearTagIsEffectsInitialized = info->sClearTagIsEffectInitialized_copy;
memcpy(sClearTagEffects, info->sClearTagEffects_copy, sizeof(sClearTagEffects));
D_80A7DEB0 = info->D_80A7DEB0_copy;
D_80A7DEB4 = info->D_80A7DEB4_copy;
D_80A7DEB8 = info->D_80A7DEB8_copy;
sRockRotSpeedX = info->sRockRotSpeedX_copy;
sRockRotSpeedY = info->sRockRotSpeedY_copy;
D_80AB85E0 = info->D_80AB85E0_copy;
sLowerRiverSpawned = info->sLowerRiverSpawned_copy;
sUpperRiverSpawned = info->sUpperRiverSpawned_copy;
sEnPoFieldNumSpawned = info->sEnPoFieldNumSpawned_copy;
memcpy(sEnPoFieldSpawnPositions, info->sEnPoFieldSpawnPositions_copy, sizeof(info->sEnPoFieldSpawnPositions_copy));
memcpy(sEnPoFieldSpawnSwitchFlags, info->sEnPoFieldSpawnSwitchFlags_copy, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy));
sTakaraIsInitialized = info->sTakaraIsInitialized_copy;
D_80B41D90 = info->D_80B41D90_copy;
sEnXcFlameSpawned = info->sEnXcFlameSpawned_copy;
D_80B41DA8 = info->D_80B41DA8_copy;
D_80B41DAC = info->D_80B41DAC_copy;
D_80B4A1B0 = info->D_80B4A1B0_copy;
D_80B4A1B4 = info->D_80B4A1B4_copy;
D_80B5A468 = info->D_80B5A468_copy;
D_80B5A494 = info->D_80B5A494_copy;
D_80B5A4BC = info->D_80B5A4BC_copy;
sKankyoIsSpawned = info->sKankyoIsSpawned_copy;
sTrailingFairies = info->sTrailingFairies_copy;
}
void SaveState::SaveMiscCodeData(void) {
info->gGameOverTimer_copy = gGameOverTimer;
info->gTimeIncrement_copy = gTimeIncrement;
info->sLoadedMarkDataTableCopy = sLoadedMarkDataTable;
info->sPlayerInitialPosX_copy = sPlayerInitialPosX;
info->sPlayerInitialPosZ_copy = sPlayerInitialPosZ;
info->sPlayerInitialDirection_copy = sPlayerInitialDirection;
info->sOcarinaInpEnabled_copy = sOcarinaInpEnabled;
info->D_80130F10_copy = D_80130F10;
info->sCurOcarinaBtnVal_copy = sCurOcarinaBtnVal;
info->sPrevOcarinaNoteVal_copy = sPrevOcarinaNoteVal;
info->sCurOcarinaBtnIdx_copy = sCurOcarinaBtnIdx;
info->sLearnSongLastBtn_copy = sLearnSongLastBtn;
info->D_80130F24_copy = D_80130F24;
info->D_80130F28_copy = D_80130F28;
info->D_80130F2C_copy = D_80130F2C;
info->D_80130F30_copy = D_80130F30;
info->D_80130F34_copy = D_80130F34;
info->sPlaybackState_copy = sPlaybackState;
info->D_80130F3C_copy = D_80130F3C;
info->sNotePlaybackTimer_copy = sNotePlaybackTimer;
info->sPlaybackNotePos_copy = sPlaybackNotePos;
info->sStaffPlaybackPos_copy = sStaffPlaybackPos;
info->sCurOcarinaBtnPress_copy = sCurOcarinaBtnPress;
info->D_8016BA10_copy = D_8016BA10;
info->sPrevOcarinaBtnPress_copy = sPrevOcarinaBtnPress;
info->D_8016BA18_copy = D_8016BA18;
info->D_8016BA1C_copy = D_8016BA1C;
memcpy(info->sCurOcarinaSong_copy, sCurOcarinaSong, sizeof(sCurOcarinaSong));
info->sOcarinaSongAppendPos_copy = sOcarinaSongAppendPos;
info->sOcarinaHasStartedSong_copy = sOcarinaHasStartedSong;
info->sOcarinaSongNoteStartIdx_copy = sOcarinaSongNoteStartIdx;
info->sOcarinaSongCnt_copy = sOcarinaSongCnt;
info->sOcarinaAvailSongs_copy = sOcarinaAvailSongs;
info->sStaffPlayingPos_copy = sStaffPlayingPos;
memcpy(info->sLearnSongPos_copy, sLearnSongPos, sizeof(sLearnSongPos));
memcpy(info->D_8016BA50_copy, D_8016BA50, sizeof(D_8016BA50));
memcpy(info->D_8016BA70_copy, D_8016BA70, sizeof(D_8016BA70));
memcpy(info->sLearnSongExpectedNote_copy, sLearnSongExpectedNote, sizeof(sLearnSongExpectedNote));
memcpy(&info->D_8016BAA0_copy, &D_8016BAA0, sizeof(D_8016BAA0));
info->sAudioHasMalonBgm_copy = sAudioHasMalonBgm;
info->sAudioMalonBgmDist_copy = sAudioMalonBgmDist;
info->sDisplayedNoteValue_copy = sDisplayedNoteValue;
info->sOcarinaNoteBufPos_copy = sOcarinaNoteBufPos;
info->sOcarinaNoteBufLen_copy = sOcarinaNoteBufLen;
memcpy(info->sOcarinaNoteBuf_copy, sOcarinaNoteBuf, sizeof(sOcarinaNoteBuf));
info->D_8014B2F4_copy = D_8014B2F4;
info->sTextboxSkipped_copy = sTextboxSkipped;
info->sNextTextId_copy = sNextTextId;
info->sLastPlayedSong_copy = sLastPlayedSong;
info->sHasSunsSong_copy = sHasSunsSong;
info->sMessageHasSetSfx_copy = sMessageHasSetSfx;
info->sOcarinaSongBitFlags_copy = sOcarinaSongBitFlags;
}
void SaveState::LoadMiscCodeData(void) {
gGameOverTimer = info->gGameOverTimer_copy;
gTimeIncrement = info->gTimeIncrement_copy;
sLoadedMarkDataTable = info->sLoadedMarkDataTableCopy;
sPlayerInitialPosX = info->sPlayerInitialPosX_copy;
sPlayerInitialPosZ = info->sPlayerInitialPosZ_copy;
sPlayerInitialDirection = info->sPlayerInitialDirection_copy;
sOcarinaInpEnabled = info->sOcarinaInpEnabled_copy;
D_80130F10 = info->D_80130F10_copy;
sCurOcarinaBtnVal = info->sCurOcarinaBtnVal_copy;
sPrevOcarinaNoteVal = info->sPrevOcarinaNoteVal_copy;
sCurOcarinaBtnIdx = info->sCurOcarinaBtnIdx_copy;
sLearnSongLastBtn = info->sLearnSongLastBtn_copy;
D_80130F24 = info->D_80130F24_copy;
D_80130F28 = info->D_80130F28_copy;
D_80130F2C = info->D_80130F2C_copy;
D_80130F30 = info->D_80130F30_copy;
D_80130F34 = info->D_80130F34_copy;
sPlaybackState = info->sPlaybackState_copy;
D_80130F3C = info->D_80130F3C_copy;
sNotePlaybackTimer = info->sNotePlaybackTimer_copy;
sPlaybackNotePos = info->sPlaybackNotePos_copy;
sStaffPlaybackPos = info->sStaffPlaybackPos_copy;
sCurOcarinaBtnPress = info->sCurOcarinaBtnPress_copy;
D_8016BA10 = info->D_8016BA10_copy;
sPrevOcarinaBtnPress = info->sPrevOcarinaBtnPress_copy;
D_8016BA18 = info->D_8016BA18_copy;
D_8016BA1C = info->D_8016BA1C_copy;
memcpy(sCurOcarinaSong, info->sCurOcarinaSong_copy, sizeof(sCurOcarinaSong));
sOcarinaSongAppendPos = info->sOcarinaSongAppendPos_copy;
sOcarinaHasStartedSong = info->sOcarinaHasStartedSong_copy;
sOcarinaSongNoteStartIdx = info->sOcarinaSongNoteStartIdx_copy;
sOcarinaSongCnt = info->sOcarinaSongCnt_copy;
sOcarinaAvailSongs = info->sOcarinaAvailSongs_copy;
sStaffPlayingPos = info->sStaffPlayingPos_copy;
memcpy(info->sLearnSongPos_copy, info->sLearnSongPos_copy, sizeof(sLearnSongPos));
memcpy(info->D_8016BA50_copy, info->D_8016BA50_copy, sizeof(D_8016BA50));
memcpy(info->D_8016BA70_copy, info->D_8016BA70_copy, sizeof(D_8016BA70));
memcpy(info->sLearnSongExpectedNote_copy, info->sLearnSongExpectedNote_copy, sizeof(sLearnSongExpectedNote));
memcpy(&D_8016BAA0, &info->D_8016BAA0_copy, sizeof(D_8016BAA0));
sAudioHasMalonBgm = info->sAudioHasMalonBgm_copy;
sAudioMalonBgmDist = info->sAudioMalonBgmDist_copy;
sDisplayedNoteValue = info->sDisplayedNoteValue_copy;
sOcarinaNoteBufPos = info->sOcarinaNoteBufPos_copy;
sOcarinaNoteBufLen = info->sOcarinaNoteBufLen_copy;
memcpy(sOcarinaNoteBuf, info->sOcarinaNoteBuf_copy, sizeof(sOcarinaNoteBuf));
D_8014B2F4 = info->D_8014B2F4_copy;
sTextboxSkipped = info->sTextboxSkipped_copy;
sNextTextId = info->sNextTextId_copy;
sLastPlayedSong = info->sLastPlayedSong_copy;
sHasSunsSong = info->sHasSunsSong_copy;
sMessageHasSetSfx = info->sMessageHasSetSfx_copy;
sOcarinaSongBitFlags = info->sOcarinaSongBitFlags_copy;
}
extern "C" void ProcessSaveStateRequests(void) {
OTRGlobals::Instance->gSaveStateMgr->ProcessSaveStateRequests();
}
void SaveStateMgr::SetCurrentSlot(unsigned int slot) {
SohImGui::overlay->TextDrawNotification(1.0f, true, "slot %u set", slot);
this->currentSlot = slot;
}
unsigned int SaveStateMgr::GetCurrentSlot(void) {
return this->currentSlot;
}
void SaveStateMgr::ProcessSaveStateRequests(void) {
while (!this->requests.empty()) {
const auto& request = this->requests.front();
switch (request.type) {
case RequestType::SAVE:
if (!this->states.contains(request.slot)) {
this->states[request.slot] = std::make_shared<SaveState>(OTRGlobals::Instance->gSaveStateMgr, request.slot);
}
this->states[request.slot]->Save();
SohImGui::overlay->TextDrawNotification(1.0f, true, "saved state %u", request.slot);
break;
case RequestType::LOAD:
if (this->states.contains(request.slot)) {
this->states[request.slot]->Load();
SohImGui::overlay->TextDrawNotification(1.0f, true, "loaded state %u", request.slot);
} else {
SPDLOG_ERROR("Invalid SaveState slot: {}", request.type);
}
break;
[[unlikely]] default:
SPDLOG_ERROR("Invalid SaveState request type: {}", request.type);
break;
}
this->requests.pop();
}
}
SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) {
if (gGlobalCtx == nullptr) {
SPDLOG_ERROR("[SOH] Can not save or load a state outside of \"GamePlay\"");
SohImGui::overlay->TextDrawNotification(1.0f, true, "states not available here", request.slot);
return SaveStateReturn::FAIL_WRONG_GAMESTATE;
}
switch (request.type) {
case RequestType::SAVE:
requests.push(request);
break;
case RequestType::LOAD:
if (states.contains(request.slot)) {
requests.push(request);
} else {
SPDLOG_ERROR("Invalid SaveState slot: {}", request.type);
SohImGui::overlay->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot);
return SaveStateReturn::FAIL_INVALID_SLOT;
}
break;
[[unlikely]] default:
SPDLOG_ERROR("Invalid SaveState request type: {}", request.type);
return SaveStateReturn::FAIL_BAD_REQUEST;
break;
}
}
void SaveState::Save(void) {
std::unique_lock<std::mutex> Lock(audio.mutex);
memcpy(&info->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */);
memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext));
memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy));
BackupSeqScriptState();
memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
memcpy(&info->gSoundBankMutedCopy, gSoundBankMuted, sizeof(info->gSoundBankMutedCopy));
info->D_801333F0_copy = D_801333F0;
info->gAudioSfxSwapOff_copy = gAudioSfxSwapOff;
memcpy(&info->gAudioSfxSwapSource_copy, gAudioSfxSwapSource,
sizeof(info->gAudioSfxSwapSource_copy));
memcpy(&info->gAudioSfxSwapTarget_copy, gAudioSfxSwapTarget,
sizeof(info->gAudioSfxSwapTarget_copy));
memcpy(&info->gAudioSfxSwapMode_copy, gAudioSfxSwapMode,
sizeof(info->gAudioSfxSwapMode_copy));
info->D_801755D0_copy = D_801755D0;
memcpy(&info->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
memcpy(&info->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
memcpy(&info->lightBufferCopy, &sLightsBuffer, sizeof(sLightsBuffer));
memcpy(&info->mtxStackCopy, &sMatrixStack, sizeof(MtxF) * 20);
memcpy(&info->currentMtxCopy, &sCurrentMatrix, sizeof(MtxF));
//Various static data
info->blueWarpTimerCopy = sWarpTimerTarget;
BackupCameraData();
SaveOnePointDemoData();
SaveOverlayStaticData();
SaveMiscCodeData();
}
void SaveState::Load(void) {
std::unique_lock<std::mutex> Lock(audio.mutex);
memcpy(gSystemHeap, &info->sysHeapCopy, SYSTEM_HEAP_SIZE);
memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE);
memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext));
memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy));
LoadSeqScriptState();
memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext));
memcpy(gGameInfo, &info->gameInfoCopy, sizeof(*gGameInfo));
memcpy(&sLightsBuffer, &info->lightBufferCopy, sizeof(sLightsBuffer));
memcpy(&sMatrixStack, &info->mtxStackCopy, sizeof(MtxF) * 20);
memcpy(&sCurrentMatrix, &info->currentMtxCopy, sizeof(MtxF));
sWarpTimerTarget = info->blueWarpTimerCopy;
memcpy(gActiveSounds, info->gActiveSoundsCopy, sizeof(gActiveSounds));
memcpy(gSoundBankMuted, &info->gSoundBankMutedCopy, sizeof(info->gSoundBankMutedCopy));
D_801333F0 = info->D_801333F0_copy;
gAudioSfxSwapOff = info->gAudioSfxSwapOff_copy;
memcpy(gAudioSfxSwapSource, &info->gAudioSfxSwapSource_copy,
sizeof(info->gAudioSfxSwapSource_copy));
memcpy(gAudioSfxSwapTarget, &info->gAudioSfxSwapTarget_copy,
sizeof(info->gAudioSfxSwapTarget_copy));
memcpy(gAudioSfxSwapMode, &info->gAudioSfxSwapMode_copy,
sizeof(info->gAudioSfxSwapMode_copy));
//Various static data
D_801755D0 = info->D_801755D0_copy;
LoadCameraData();
LoadOnePointDemoData();
LoadOverlayStaticData();
LoadMiscCodeData();
}

View file

@ -0,0 +1,62 @@
#ifndef SAVE_STATES_H
#define SAVE_STATES_H
#include <cstdint>
#include <queue>
#include <unordered_map>
#include <memory>
#include <mutex>
enum class SaveStateReturn {
SUCCESS,
FAIL_INVALID_SLOT,
FAIL_NO_MEMORY,
FAIL_STATE_EMPTY,
FAIL_WRONG_GAMESTATE,
FAIL_BAD_REQUEST,
};
typedef struct SaveStateHeader {
uint32_t stateMagic;
uint32_t stateVersion;
//uint32_t gameVersion;
} SaveStateHeader;
enum class RequestType {
SAVE,
LOAD,
};
typedef struct SaveStateRequest {
unsigned int slot;
RequestType type;
} SaveStateRequest;
class SaveState;
class SaveStateMgr {
friend class SaveState;
private:
unsigned int currentSlot;
std::unordered_map<unsigned int, std::shared_ptr<SaveState>> states;
std::queue <SaveStateRequest> requests;
std::mutex mutex;
public:
SaveStateReturn AddRequest(const SaveStateRequest request);
SaveStateMgr();
~SaveStateMgr();
void SetCurrentSlot(unsigned int slot);
unsigned int GetCurrentSlot(void);
SaveStateMgr& operator=(const SaveStateMgr& rhs) = delete;
SaveStateMgr(const SaveStateMgr& rhs) = delete;
void ProcessSaveStateRequests(void);
};
extern std::shared_ptr<SaveStateMgr> gSaveStateMgr;
#endif

View file

@ -0,0 +1,257 @@
extern "C" MtxF* sMatrixStack;
extern "C" MtxF* sCurrentMatrix;
extern "C" LightsBuffer sLightsBuffer;
extern "C" s16 sWarpTimerTarget;
extern "C" MapMarkData** sLoadedMarkDataTable;
//Camera static data
extern "C" int32_t sInitRegs;
extern "C" int32_t gDbgCamEnabled;
extern "C" int32_t sDbgModeIdx;
extern "C" int16_t sNextUID;
extern "C" int32_t sCameraInterfaceFlags;
extern "C" int32_t sCameraInterfaceAlpha;
extern "C" int32_t sCameraShrinkWindowVal;
extern "C" int32_t D_8011D3AC;
extern "C" int32_t sDemo5PrevAction12Frame;
extern "C" int32_t sDemo5PrevSfxFrame;
extern "C" int32_t D_8011D3F0;
extern "C" OnePointCsFull D_8011D6AC[];
extern "C" OnePointCsFull D_8011D724[];
extern "C" OnePointCsFull D_8011D79C[];
extern "C" OnePointCsFull D_8011D83C[];
extern "C" OnePointCsFull D_8011D88C[];
extern "C" OnePointCsFull D_8011D8DC[];
extern "C" OnePointCsFull D_8011D954[];
extern "C" OnePointCsFull D_8011D9F4[];
extern "C" int16_t D_8011DB08;
extern "C" int16_t D_8011DB0C;
extern "C" int32_t sOOBTimer;
extern "C" f32 D_8015CE50;
extern "C" f32 D_8015CE54;
extern "C" CamColChk D_8015CE58;
//Gameover
extern "C" uint16_t gGameOverTimer;
//One Point Demo
extern "C" uint32_t sPrevFrameCs1100;
extern "C" CutsceneCameraPoint D_8012013C[14];
extern "C" CutsceneCameraPoint D_8012021C[14];
extern "C" CutsceneCameraPoint D_801204D4[14];
extern "C" CutsceneCameraPoint D_801205B4[14];
extern "C" OnePointCsFull D_801208EC[3];
extern "C" OnePointCsFull D_80120964[2];
extern "C" OnePointCsFull D_801209B4[4];
extern "C" OnePointCsFull D_80120ACC[5];
extern "C" OnePointCsFull D_80120B94[11];
extern "C" OnePointCsFull D_80120D4C[7];
extern "C" OnePointCsFull D_80120FA4[6];
extern "C" OnePointCsFull D_80121184[2];
extern "C" OnePointCsFull D_801211D4[2];
extern "C" OnePointCsFull D_8012133C[3];
extern "C" OnePointCsFull D_801213B4[5];
extern "C" OnePointCsFull D_8012151C[2];
extern "C" OnePointCsFull D_8012156C[2];
extern "C" OnePointCsFull D_801215BC[1];
extern "C" OnePointCsFull D_80121C24[7];
extern "C" OnePointCsFull D_80121D3C[3];
extern "C" OnePointCsFull D_80121F1C[4];
extern "C" OnePointCsFull D_80121FBC[4];
extern "C" OnePointCsFull D_801220D4[5];
extern "C" OnePointCsFull D_80122714[4];
extern "C" OnePointCsFull D_80122CB4[2];
extern "C" OnePointCsFull D_80122D04[2];
extern "C" OnePointCsFull D_80122E44[2][7];
extern "C" OnePointCsFull D_8012313C[3];
extern "C" OnePointCsFull D_801231B4[4];
extern "C" OnePointCsFull D_80123254[2];
extern "C" OnePointCsFull D_801232A4[1];
extern "C" OnePointCsFull D_80123894[3];
extern "C" OnePointCsFull D_8012390C[2];
extern "C" OnePointCsFull D_8012395C[3];
extern "C" OnePointCsFull D_801239D4[3];
// z_bg_ddan_kd
extern "C" Vec3f sBgDdanKdVelocity;
extern "C" Vec3f sBgDdanKdAccel;
// z_bg_dodoago
extern "C" s16 sBgDodoagoFirstExplosiveFlag;
extern "C" u8 sBgDodoagoDisableBombCatcher;
extern "C" s32 sBgDodoagoTimer;
// z_bg_haka_trap
extern "C" uint32_t D_80880F30;
extern "C" uint32_t D_80881014;
// z_bg_hidan_rock
extern "C" float D_8088BFC0;
// z_bg_menkuri_eye
extern "C" int32_t D_8089C1A0;
// z_bg_mori_hineri
extern "C" int16_t sBgMoriHineriNextCamIdx;
// z_bg_po_event
extern "C" uint8_t sBgPoEventBlocksAtRest;
extern "C" uint8_t sBgPoEventPuzzleState;
extern "C" float sBgPoEventblockPushDist;
// z_bg_relay_objects
extern "C" uint32_t D_808A9508;
// z_bg_spot18_basket
extern "C" int16_t D_808B85D0;
// z_boss_ganon
extern "C" uint32_t sBossGanonSeed1;
extern "C" uint32_t sBossGanonSeed2;
extern "C" uint32_t sBossGanonSeed3;
extern "C" void* sBossGanonGanondorf;
extern "C" void* sBossGanonZelda;
extern "C" void* sBossGanonCape;
extern "C" GanondorfEffect sBossGanonEffectBuf[200];
// z_boss_ganon2
extern "C" Vec3f D_8090EB20;
extern "C" int8_t D_80910638;
extern "C" void* sBossGanon2Zelda;
extern "C" void* D_8090EB30;
extern "C" int32_t sBossGanon2Seed1;
extern "C" int32_t sBossGanon2Seed2;
extern "C" int32_t sBossGanon2Seed3;
extern "C" Vec3f D_809105D8[4];
extern "C" Vec3f D_80910608[4];
extern "C" BossGanon2Effect sBossGanon2Particles[100];
// z_boss_tw
extern "C" uint8_t sTwInitalized;
extern "C" BossTwEffect sTwEffects[150];
// z_demo_6k
extern "C" Vec3f sDemo6kVelocity;
// z_demo_du
extern "C" int32_t D_8096CE94;
// z_demo_kekkai
extern "C" Vec3f demoKekkaiVel;
// z_en_bw
extern "C" int32_t sSlugGroup;
// z_en_clear_tag
extern "C" uint8_t sClearTagIsEffectsInitialized;
extern "C" EnClearTagEffect sClearTagEffects[CLEAR_TAG_EFFECT_MAX_COUNT];
// z_en_fr
extern "C" EnFrPointers sEnFrPointers;
// z_en_goma
extern "C" uint8_t sSpawnNum;
// z_en_in
extern "C" int32_t D_80A7B998;
// z_en_insect
extern "C" float D_80A7DEB0;
extern "C" int16_t D_80A7DEB4;
extern "C" int16_t D_80A7DEB8;
// z_en_ishi
extern "C" int16_t sRockRotSpeedX;
extern "C" int16_t sRockRotSpeedY;
// z_en_niw
extern "C" int16_t D_80AB85E0;
extern "C" uint8_t sLowerRiverSpawned;
extern "C" uint8_t sUpperRiverSpawned;
// z_en_po_field
extern "C" int32_t sEnPoFieldNumSpawned;
extern "C" Vec3s sEnPoFieldSpawnPositions[10];
extern "C" u8 sEnPoFieldSpawnSwitchFlags[10];
// z_en_takara_man
extern "C" uint8_t sTakaraIsInitialized;
// z_en_xc
extern "C" int32_t D_80B41D90;
extern "C" int32_t sEnXcFlameSpawned;
extern "C" int32_t D_80B41DA8;
extern "C" int32_t D_80B41DAC;
// z_en_zf
extern "C" int16_t D_80B4A1B0;
extern "C" int16_t D_80B4A1B4;
extern "C" int32_t D_80B5A468;
extern "C" int32_t D_80B5A494;
extern "C" int32_t D_80B5A4BC;
extern "C" uint8_t sKankyoIsSpawned;
extern "C" int16_t sTrailingFairies;
extern "C" uint16_t gTimeIncrement;
extern "C" s16 sPlayerInitialPosX;
extern "C" s16 sPlayerInitialPosZ;
extern "C" s16 sPlayerInitialDirection;
// code_800EC960
// Related to ocarina
extern "C" u8 sOcarinaInpEnabled;
extern "C" s8 D_80130F10;
extern "C" u8 sCurOcarinaBtnVal;
extern "C" u8 sPrevOcarinaNoteVal;
extern "C" u8 sCurOcarinaBtnIdx;
extern "C" u8 sLearnSongLastBtn;
extern "C" f32 D_80130F24;
extern "C" f32 D_80130F28;
extern "C" s8 D_80130F2C;
extern "C" s8 D_80130F30;
extern "C" s8 D_80130F34;
extern "C" u8 sPlaybackState;
extern "C" u32 D_80130F3C;
extern "C" u32 sNotePlaybackTimer;
extern "C" u16 sPlaybackNotePos;
extern "C" u16 sStaffPlaybackPos;
//IDK what this is but it looks important
extern "C" u32 sCurOcarinaBtnPress;
extern "C" u32 D_8016BA10;
extern "C" u32 sPrevOcarinaBtnPress;
extern "C" s32 D_8016BA18;
extern "C" s32 D_8016BA1C;
extern "C" u8 sCurOcarinaSong[8];
extern "C" u8 sOcarinaSongAppendPos;
extern "C" u8 sOcarinaHasStartedSong;
extern "C" u8 sOcarinaSongNoteStartIdx;
extern "C" u8 sOcarinaSongCnt;
extern "C" u16 sOcarinaAvailSongs;
extern "C" u8 sStaffPlayingPos;
extern "C" u16 sLearnSongPos[0x10];
extern "C" u16 D_8016BA50[0x10];
extern "C" u16 D_8016BA70[0x10];
extern "C" u8 sLearnSongExpectedNote[0x10];
extern "C" OcarinaNote D_8016BAA0;
extern "C" u8 sAudioHasMalonBgm;
extern "C" f32 sAudioMalonBgmDist;
extern "C" u8 sDisplayedNoteValue;
// z_message_PAL
extern "C" s16 sOcarinaNoteBufPos;
extern "C" s16 sOcarinaNoteBufLen;
extern "C" u8 sOcarinaNoteBuf[12];
extern "C" u8 D_8014B2F4;
extern "C" u8 sTextboxSkipped;
extern "C" u16 sNextTextId;
extern "C" s16 sLastPlayedSong;
extern "C" s16 sHasSunsSong;
extern "C" s16 sMessageHasSetSfx;
extern "C" u16 sOcarinaSongBitFlags;

8
soh/soh/OTRAudio.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
static struct {
std::condition_variable cv_to_thread, cv_from_thread;
std::mutex mutex;
bool initialized;
bool processing;
} audio;

View file

@ -1,4 +1,5 @@
#include "OTRGlobals.h"
#include "OTRAudio.h"
#include <iostream>
#include <locale>
#include <codecvt>
@ -28,22 +29,20 @@
#include "AudioPlayer.h"
#include "Enhancements/debugconsole.h"
#include "Enhancements/debugger/debugger.h"
#include "soh/frame_interpolation.h"
#include "Utils/BitConverter.h"
#include "variables.h"
#include "macros.h"
#include <Utils/StringHelper.h>
#include <SDL2/SDL_scancode.h>
OTRGlobals* OTRGlobals::Instance;
static struct {
std::condition_variable cv_to_thread, cv_from_thread;
std::mutex mutex;
bool initialized;
bool processing;
} audio;
OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
gSaveStateMgr = std::make_shared<SaveStateMgr>();
context->GetWindow()->Init();
}
@ -114,12 +113,69 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
}
extern "C" void Graph_StartFrame() {
// Why -1?
int32_t dwScancode = OTRGlobals::Instance->context->GetWindow()->lastScancode;
OTRGlobals::Instance->context->GetWindow()->lastScancode = -1;
switch (dwScancode - 1) {
case SDL_SCANCODE_F5: {
const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn stateReturn =
OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
switch (stateReturn) {
case SaveStateReturn::SUCCESS:
SPDLOG_INFO("[SOH] Saved state to slot {}", slot);
break;
case SaveStateReturn::FAIL_WRONG_GAMESTATE:
SPDLOG_ERROR("[SOH] Can not save a state outside of \"GamePlay\"");
break;
[[unlikely]] default:
break;
}
break;
}
case SDL_SCANCODE_F6: {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
slot++;
if (slot > 5) {
slot = 0;
}
OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot);
SPDLOG_INFO("Set SaveState slot to {}.", slot);
break;
}
case SDL_SCANCODE_F7: {
const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn stateReturn =
OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
switch (stateReturn) {
case SaveStateReturn::SUCCESS:
SPDLOG_INFO("[SOH] Loaded state from slot {}", slot);
break;
case SaveStateReturn::FAIL_INVALID_SLOT:
SPDLOG_ERROR("[SOH] Invalid State Slot Number {}", slot);
break;
case SaveStateReturn::FAIL_STATE_EMPTY:
SPDLOG_ERROR("[SOH] State Slot {} is empty", slot);
break;
case SaveStateReturn::FAIL_WRONG_GAMESTATE:
SPDLOG_ERROR("[SOH] Can not load a state outside of \"GamePlay\"");
break;
[[unlikely]] default:
break;
}
break;
}
}
OTRGlobals::Instance->context->GetWindow()->StartFrame();
}
// C->C++ Bridge
extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(R_UPDATE_RATE);
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(CVar_GetS32("g60FPS", 0) == 0 ? R_UPDATE_RATE : 1);
if (!audio.initialized) {
audio.initialized = true;
@ -131,6 +187,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
audio.cv_to_thread.wait(Lock);
}
}
std::unique_lock<std::mutex> Lock(audio.mutex);
//AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
@ -156,10 +213,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
{
std::unique_lock<std::mutex> Lock(audio.mutex);
audio.processing = false;
}
audio.processing = false;
audio.cv_from_thread.notify_one();
}
}).detach();
@ -171,7 +225,15 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
}
audio.cv_to_thread.notify_one();
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands);
std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
if (CVar_GetS32("g60FPS", 0) != 0) {
int to = R_UPDATE_RATE;
for (int i = 1; i < to; i++) {
mtx_replacements.push_back(FrameInterpolation_Interpolate(i / (float)to));
}
}
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands, mtx_replacements);
{
std::unique_lock<std::mutex> Lock(audio.mutex);

View file

@ -1,17 +1,22 @@
#ifndef OTR_GLOBALS_H
#define OTR_GLOBALS_H
#pragma once
#include "GlobalCtx2.h"
#ifdef __cplusplus
#include "Enhancements/savestates.h"
class OTRGlobals
{
public:
static OTRGlobals* Instance;
static OTRGlobals* Instance;
std::shared_ptr<Ship::GlobalCtx2> context;
std::shared_ptr<Ship::GlobalCtx2> context;
std::shared_ptr<SaveStateMgr> gSaveStateMgr;
OTRGlobals();
~OTRGlobals();
OTRGlobals();
~OTRGlobals();
private:
@ -68,3 +73,5 @@ void AudioPlayer_Play(const uint8_t* buf, uint32_t len);
void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples);
int Controller_ShouldRumble(size_t i);
#endif
#endif

View file

@ -0,0 +1,732 @@
#include "Cvar.h"
#include <vector>
#include <map>
#include <unordered_map>
#include <math.h>
#include "frame_interpolation.h"
/*
Frame interpolation.
The idea of this code is to interpolate all matrices.
The code contains two approaches. The first is to interpolate
all inputs in transformations, such as angles, scale and distances,
and then perform the same transformations with the interpolated values.
After evaluation for some reason some animations such rolling look strange.
The second approach is to simply interpolate the final matrices. This will
more or less simply interpolate the world coordinates for movements.
This will however make rotations ~180 degrees get the "paper effect".
The mitigation is to identify this case for actors and interpolate the
matrix but in model coordinates instead, by "removing" the rotation-
translation before interpolating, create a rotation matrix with the
interpolated angle which is then applied to the matrix.
Currently the code contains both methods but only the second one is currently
used.
Both approaches build a tree of instructions, containing matrices
at leaves. Every node is built from OPEN_DISPS/CLOSE_DISPS and manually
inserted FrameInterpolation_OpenChild/FrameInterpolation_Close child calls.
These nodes contain information that should suffice to identify the matrix,
so we can find it in an adjacent frame.
We can interpolate an arbitrary amount of frames between two original frames,
given a specific interpolation factor (0=old frame, 0.5=average of frames,
1.0=new frame).
*/
extern "C" {
void Matrix_Init(struct GameState* gameState);
void Matrix_Push(void);
void Matrix_Pop(void);
void Matrix_Get(MtxF* dest);
void Matrix_Put(MtxF* src);
void Matrix_Mult(MtxF* mf, u8 mode);
void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode);
void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode);
void Matrix_RotateX(f32 x, u8 mode);
void Matrix_RotateY(f32 y, u8 mode);
void Matrix_RotateZ(f32 z, u8 mode);
void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode);
void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation);
void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot);
Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest);
Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line);
Mtx* Matrix_NewMtx(struct GraphicsContext* gfxCtx, char* file, s32 line);
Mtx* Matrix_MtxFToNewMtx(MtxF* src, struct GraphicsContext* gfxCtx);
void Matrix_MultVec3f(Vec3f* src, Vec3f* dest);
void Matrix_MtxFCopy(MtxF* dest, MtxF* src);
void Matrix_MtxToMtxF(Mtx* src, MtxF* dest);
void Matrix_MultVec3fExt(Vec3f* src, Vec3f* dest, MtxF* mf);
void Matrix_Transpose(MtxF* mf);
void Matrix_ReplaceRotation(MtxF* mf);
void Matrix_MtxFToYXZRotS(MtxF* mf, Vec3s* rotDest, s32 flag);
void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag);
void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode);
MtxF* Matrix_CheckFloats(MtxF* mf, char* file, s32 line);
void Matrix_SetTranslateScaleMtx2(Mtx* mtx, f32 scaleX, f32 scaleY, f32 scaleZ, f32 translateX, f32 translateY,
f32 translateZ);
MtxF* Matrix_GetCurrent(void);
void SkinMatrix_MtxFMtxFMult(MtxF* mfA, MtxF* mfB, MtxF* dest);
}
static bool invert_matrix(const float m[16], float invOut[16]);
using namespace std;
namespace {
enum class Op {
OpenChild,
CloseChild,
MatrixPush,
MatrixPop,
MatrixPut,
MatrixMult,
MatrixTranslate,
MatrixScale,
MatrixRotate1Coord,
MatrixRotateZYX,
MatrixTranslateRotateZYX,
MatrixSetTranslateRotateYXZ,
MatrixMtxFToMtx,
MatrixToMtx,
MatrixReplaceRotation,
MatrixRotateAxis,
SkinMatrixMtxFToMtx
};
typedef pair<const void*, int> label;
union Data {
Data() {
}
struct {
MtxF src;
} matrix_put;
struct {
MtxF mf;
u8 mode;
} matrix_mult;
struct {
f32 x, y, z;
u8 mode;
} matrix_translate, matrix_scale;
struct {
u32 coord;
f32 value;
u8 mode;
} matrix_rotate_1_coord;
struct {
s16 x, y, z;
u8 mode;
} matrix_rotate_zyx;
struct {
Vec3f translation;
Vec3s rotation;
} matrix_translate_rotate_zyx;
struct {
f32 translateX, translateY, translateZ;
Vec3s rot;
//MtxF mtx;
bool has_mtx;
} matrix_set_translate_rotate_yxz;
struct {
MtxF src;
Mtx* dest;
} matrix_mtxf_to_mtx;
struct {
Mtx* dest;
MtxF src;
bool has_adjusted;
} matrix_to_mtx;
struct {
MtxF mf;
} matrix_replace_rotation;
struct {
f32 angle;
Vec3f axis;
u8 mode;
} matrix_rotate_axis;
struct {
label key;
size_t idx;
} open_child;
};
struct Path {
map<label, vector<Path>> children;
map<Op, vector<Data>> ops;
vector<pair<Op, size_t>> items;
};
struct Recording {
Path root_path;
};
bool is_recording;
vector<Path*> current_path;
uint32_t camera_epoch;
uint32_t previous_camera_epoch;
Recording current_recording;
Recording previous_recording;
bool next_is_actor_pos_rot_matrix;
bool has_inv_actor_mtx;
MtxF inv_actor_mtx;
size_t inv_actor_mtx_path_index;
Data& append(Op op) {
auto& m = current_path.back()->ops[op];
current_path.back()->items.emplace_back(op, m.size());
return m.emplace_back();
}
struct InterpolateCtx {
float step;
float w;
unordered_map<Mtx*, MtxF> mtx_replacements;
MtxF tmp_mtxf, tmp_mtxf2;
Vec3f tmp_vec3f;
Vec3s tmp_vec3s;
MtxF actor_mtx;
MtxF* new_replacement(Mtx* addr) {
return &mtx_replacements[addr];
}
void interpolate_mtxf(MtxF* res, MtxF* o, MtxF* n) {
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
res->mf[i][j] = w * o->mf[i][j] + step * n->mf[i][j];
}
}
}
float lerp(f32 o, f32 n) {
return w * o + step * n;
}
void lerp_vec3f(Vec3f* res, Vec3f* o, Vec3f* n) {
res->x = lerp(o->x, n->x);
res->y = lerp(o->y, n->y);
res->z = lerp(o->z, n->z);
}
float interpolate_angle(f32 o, f32 n) {
if (o == n)
return n;
o = fmodf(o, 2 * M_PI);
if (o < 0.0f) {
o += 2 * M_PI;
}
n = fmodf(n, 2 * M_PI);
if (n < 0.0f) {
n += 2 * M_PI;
}
if (fabsf(o - n) > M_PI) {
if (o < n) {
o += 2 * M_PI;
} else {
n += 2 * M_PI;
}
}
if (fabsf(o - n) > M_PI / 2) {
//return n;
}
return lerp(o, n);
}
s16 interpolate_angle(s16 os, s16 ns) {
if (os == ns)
return ns;
int o = (u16)os;
int n = (u16)ns;
u16 res;
int diff = o - n;
if (-0x8000 <= diff && diff <= 0x8000) {
if (diff < -0x4000 || diff > 0x4000) {
return ns;
}
res = (u16)(w * o + step * n);
} else {
if (o < n) {
o += 0x10000;
} else {
n += 0x10000;
}
diff = o - n;
if (diff < -0x4000 || diff > 0x4000) {
return ns;
}
res = (u16)(w * o + step * n);
}
if (os / 327 == ns / 327 && (s16)res / 327 != os / 327) {
int bp = 0;
}
return res;
}
void interpolate_angles(Vec3s* res, Vec3s* o, Vec3s* n) {
res->x = interpolate_angle(o->x, n->x);
res->y = interpolate_angle(o->y, n->y);
res->z = interpolate_angle(o->z, n->z);
}
void interpolate_branch(Path* old_path, Path *new_path) {
for (auto& item : new_path->items) {
Data& new_op = new_path->ops[item.first][item.second];
if (item.first == Op::OpenChild) {
if (auto it = old_path->children.find(new_op.open_child.key);
it != old_path->children.end() && new_op.open_child.idx < it->second.size()) {
interpolate_branch(&it->second[new_op.open_child.idx],
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]);
} else {
interpolate_branch(
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx],
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]);
}
continue;
}
if (auto it = old_path->ops.find(item.first); it != old_path->ops.end()) {
if (item.second < it->second.size()) {
Data& old_op = it->second[item.second];
switch (item.first) {
case Op::OpenChild:
break;
case Op::CloseChild:
break;
case Op::MatrixPush:
Matrix_Push();
break;
case Op::MatrixPop:
Matrix_Pop();
break;
case Op::MatrixPut:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_put.src, &new_op.matrix_put.src);
Matrix_Put(&tmp_mtxf);
break;
case Op::MatrixMult:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_mult.mf, &new_op.matrix_mult.mf);
Matrix_Mult(&tmp_mtxf, new_op.matrix_mult.mode);
break;
case Op::MatrixTranslate:
Matrix_Translate(lerp(old_op.matrix_translate.x, new_op.matrix_translate.x),
lerp(old_op.matrix_translate.y, new_op.matrix_translate.y),
lerp(old_op.matrix_translate.z, new_op.matrix_translate.z),
new_op.matrix_translate.mode);
break;
case Op::MatrixScale:
Matrix_Scale(lerp(old_op.matrix_scale.x, new_op.matrix_scale.x),
lerp(old_op.matrix_scale.y, new_op.matrix_scale.y),
lerp(old_op.matrix_scale.z, new_op.matrix_scale.z),
new_op.matrix_scale.mode);
break;
case Op::MatrixRotate1Coord: {
float v = interpolate_angle(old_op.matrix_rotate_1_coord.value, new_op.matrix_rotate_1_coord.value);
u8 mode = new_op.matrix_rotate_1_coord.mode;
switch (new_op.matrix_rotate_1_coord.coord) {
case 0:
Matrix_RotateX(v, mode);
break;
case 1:
Matrix_RotateY(v, mode);
break;
case 2:
Matrix_RotateZ(v, mode);
break;
}
break;
}
case Op::MatrixRotateZYX:
Matrix_RotateZYX(interpolate_angle(old_op.matrix_rotate_zyx.x, new_op.matrix_rotate_zyx.x),
interpolate_angle(old_op.matrix_rotate_zyx.y, new_op.matrix_rotate_zyx.y),
interpolate_angle(old_op.matrix_rotate_zyx.z, new_op.matrix_rotate_zyx.z),
new_op.matrix_rotate_zyx.mode);
break;
case Op::MatrixTranslateRotateZYX:
lerp_vec3f(&tmp_vec3f, &old_op.matrix_translate_rotate_zyx.translation, &new_op.matrix_translate_rotate_zyx.translation);
interpolate_angles(&tmp_vec3s, &old_op.matrix_translate_rotate_zyx.rotation, &new_op.matrix_translate_rotate_zyx.rotation);
Matrix_TranslateRotateZYX(&tmp_vec3f, &tmp_vec3s);
break;
case Op::MatrixSetTranslateRotateYXZ:
interpolate_angles(&tmp_vec3s, &old_op.matrix_set_translate_rotate_yxz.rot,
&new_op.matrix_set_translate_rotate_yxz.rot);
Matrix_SetTranslateRotateYXZ(lerp(old_op.matrix_set_translate_rotate_yxz.translateX,
new_op.matrix_set_translate_rotate_yxz.translateX),
lerp(old_op.matrix_set_translate_rotate_yxz.translateY,
new_op.matrix_set_translate_rotate_yxz.translateY),
lerp(old_op.matrix_set_translate_rotate_yxz.translateZ,
new_op.matrix_set_translate_rotate_yxz.translateZ),
&tmp_vec3s);
if (new_op.matrix_set_translate_rotate_yxz.has_mtx && old_op.matrix_set_translate_rotate_yxz.has_mtx) {
actor_mtx = *Matrix_GetCurrent();
}
break;
case Op::MatrixMtxFToMtx:
interpolate_mtxf(new_replacement(new_op.matrix_mtxf_to_mtx.dest),
&old_op.matrix_mtxf_to_mtx.src, &new_op.matrix_mtxf_to_mtx.src);
break;
case Op::MatrixToMtx: {
//*new_replacement(new_op.matrix_to_mtx.dest) = *Matrix_GetCurrent();
if (old_op.matrix_to_mtx.has_adjusted && new_op.matrix_to_mtx.has_adjusted) {
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src);
SkinMatrix_MtxFMtxFMult(&actor_mtx, &tmp_mtxf, new_replacement(new_op.matrix_to_mtx.dest));
} else {
interpolate_mtxf(new_replacement(new_op.matrix_to_mtx.dest),
&old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src);
}
break;
}
case Op::MatrixReplaceRotation:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_replace_rotation.mf, &new_op.matrix_replace_rotation.mf);
Matrix_ReplaceRotation(&tmp_mtxf);
break;
case Op::MatrixRotateAxis:
lerp_vec3f(&tmp_vec3f, &old_op.matrix_rotate_axis.axis, &new_op.matrix_rotate_axis.axis);
Matrix_RotateAxis(interpolate_angle(old_op.matrix_rotate_axis.angle, new_op.matrix_rotate_axis.angle),
&tmp_vec3f, new_op.matrix_rotate_axis.mode);
break;
case Op::SkinMatrixMtxFToMtx:
break;
}
}
}
}
}
};
} // anonymous namespace
unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step) {
InterpolateCtx ctx;
ctx.step = step;
ctx.w = 1.0f - step;
ctx.interpolate_branch(&previous_recording.root_path, &current_recording.root_path);
return ctx.mtx_replacements;
}
void FrameInterpolation_StartRecord(void) {
previous_recording = move(current_recording);
current_recording = {};
current_path.clear();
current_path.push_back(&current_recording.root_path);
if (CVar_GetS32("g60FPS", 0) != 0) {
is_recording = true;
}
}
void FrameInterpolation_StopRecord(void) {
previous_camera_epoch = camera_epoch;
is_recording = false;
}
void FrameInterpolation_RecordOpenChild(const void* a, int b) {
if (!is_recording)
return;
label key = { a, b };
auto& m = current_path.back()->children[key];
append(Op::OpenChild).open_child = { key, m.size() };
current_path.push_back(&m.emplace_back());
}
void FrameInterpolation_RecordCloseChild(void) {
if (!is_recording)
return;
//append(Op::CloseChild);
if (has_inv_actor_mtx && current_path.size() == inv_actor_mtx_path_index) {
has_inv_actor_mtx = false;
}
current_path.pop_back();
}
void FrameInterpolation_DontInterpolateCamera(void) {
camera_epoch = previous_camera_epoch + 1;
}
int FrameInterpolation_GetCameraEpoch(void) {
return (int)camera_epoch;
}
void FrameInterpolation_RecordActorPosRotMatrix(void) {
if (!is_recording)
return;
next_is_actor_pos_rot_matrix = true;
}
void FrameInterpolation_RecordMatrixPush(void) {
if (!is_recording)
return;
append(Op::MatrixPush);
}
void FrameInterpolation_RecordMatrixPop(void) {
if (!is_recording)
return;
append(Op::MatrixPop);
}
void FrameInterpolation_RecordMatrixPut(MtxF* src) {
if (!is_recording)
return;
append(Op::MatrixPut).matrix_put = { *src };
}
void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixMult).matrix_mult = { *mf, mode };
}
void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixTranslate).matrix_translate = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixScale).matrix_scale = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotate1Coord).matrix_rotate_1_coord = { coord, value, mode };
}
void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotateZYX).matrix_rotate_zyx = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation) {
if (!is_recording)
return;
append(Op::MatrixTranslateRotateZYX).matrix_translate_rotate_zyx = { *translation, *rotation };
}
void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot) {
if (!is_recording)
return;
auto& d = append(Op::MatrixSetTranslateRotateYXZ).matrix_set_translate_rotate_yxz = { translateX, translateY, translateZ,
*rot };
if (next_is_actor_pos_rot_matrix) {
d.has_mtx = true;
//d.mtx = *Matrix_GetCurrent();
invert_matrix((const float *)Matrix_GetCurrent()->mf, (float *)inv_actor_mtx.mf);
next_is_actor_pos_rot_matrix = false;
has_inv_actor_mtx = true;
inv_actor_mtx_path_index = current_path.size();
}
}
void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest) {
if (!is_recording)
return;
append(Op::MatrixMtxFToMtx).matrix_mtxf_to_mtx = { *src, dest };
}
void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line) {
if (!is_recording)
return;
auto& d = append(Op::MatrixToMtx).matrix_to_mtx = { dest };
if (has_inv_actor_mtx) {
d.has_adjusted = true;
SkinMatrix_MtxFMtxFMult(&inv_actor_mtx, Matrix_GetCurrent(), &d.src);
} else {
d.src = *Matrix_GetCurrent();
}
}
void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf) {
if (!is_recording)
return;
append(Op::MatrixReplaceRotation).matrix_replace_rotation = { *mf };
}
void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotateAxis).matrix_rotate_axis = { angle, *axis, mode };
}
void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest) {
if (!is_recording)
return;
FrameInterpolation_RecordMatrixMtxFToMtx(src, dest);
}
// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
static bool invert_matrix(const float m[16], float invOut[16]) {
float inv[16], det;
int i;
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) {
return false;
}
det = 1.0 / det;
for (i = 0; i < 16; i++) {
invOut[i] = inv[i] * det;
}
return true;
}

View file

@ -0,0 +1,61 @@
#pragma once
#include "include/z64math.h"
#ifdef __cplusplus
#include <unordered_map>
std::unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step);
extern "C" {
#endif
void FrameInterpolation_StartRecord(void);
void FrameInterpolation_StopRecord(void);
void FrameInterpolation_RecordOpenChild(const void* a, int b);
void FrameInterpolation_RecordCloseChild(void);
void FrameInterpolation_DontInterpolateCamera(void);
int FrameInterpolation_GetCameraEpoch(void);
void FrameInterpolation_RecordActorPosRotMatrix(void);
void FrameInterpolation_RecordMatrixPush(void);
void FrameInterpolation_RecordMatrixPop(void);
void FrameInterpolation_RecordMatrixPut(MtxF* src);
void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode);
void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode);
void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode);
void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode);
void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode);
void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation);
void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot);
void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest);
void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line);
void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf);
void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode);
void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest);
#ifdef __cplusplus
}
#endif

View file

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

View file

@ -6,9 +6,6 @@
#include <unistd.h>
#endif
#define AUDIO_HEAP_SIZE 0x38000
#define SYSTEM_HEAP_SIZE (1024 * 1024 * 128)
u8* gAudioHeap;
u8* gSystemHeap;

View file

@ -431,6 +431,8 @@ static struct RunFrameContext {
extern AudioMgr gAudioMgr;
extern void ProcessSaveStateRequests(void);
static void RunFrame()
{
u32 size;
@ -476,7 +478,10 @@ static void RunFrame()
Graph_StartFrame();
PadMgr_ThreadEntry(&gPadMgr);
// TODO: Workaround for rumble being too long. Implement os thread functions.
for (int i = 0; i < 3; i++) {
PadMgr_ThreadEntry(&gPadMgr);
}
Graph_Update(&runFrameContext.gfxCtx, runFrameContext.gameState);
ticksB = GetPerfCounter();
@ -487,6 +492,7 @@ static void RunFrame()
//uint64_t diff = (ticksB - ticksA) / (freq / 1000);
//printf("Frame simulated in %ims\n", diff);
runFrameContext.state = 1;
ProcessSaveStateRequests();
return;
nextFrame:;
}

View file

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
// clang-format off
Mtx gMtxClear = {
65536, 0, 1, 0,
@ -25,11 +27,13 @@ void Matrix_Init(GameState* gameState) {
}
void Matrix_Push(void) {
FrameInterpolation_RecordMatrixPush();
Matrix_MtxFCopy(sCurrentMatrix + 1, sCurrentMatrix);
sCurrentMatrix++;
}
void Matrix_Pop(void) {
FrameInterpolation_RecordMatrixPop();
sCurrentMatrix--;
ASSERT(sCurrentMatrix >= sMatrixStack, "Matrix_now >= Matrix_stack", "../sys_matrix.c", 176);
}
@ -39,6 +43,7 @@ void Matrix_Get(MtxF* dest) {
}
void Matrix_Put(MtxF* src) {
FrameInterpolation_RecordMatrixPut(src);
Matrix_MtxFCopy(sCurrentMatrix, src);
}
@ -47,6 +52,7 @@ MtxF* Matrix_GetCurrent(void) {
}
void Matrix_Mult(MtxF* mf, u8 mode) {
FrameInterpolation_RecordMatrixMult(mf, mode);
MtxF* cmf = Matrix_GetCurrent();
if (mode == MTXMODE_APPLY) {
@ -57,6 +63,7 @@ void Matrix_Mult(MtxF* mf, u8 mode) {
}
void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) {
FrameInterpolation_RecordMatrixTranslate(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
f32 tx;
f32 ty;
@ -80,6 +87,7 @@ void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) {
}
void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) {
FrameInterpolation_RecordMatrixScale(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
if (mode == MTXMODE_APPLY) {
@ -101,6 +109,7 @@ void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) {
}
void Matrix_RotateX(f32 x, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(0, x, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -165,6 +174,7 @@ void Matrix_RotateX(f32 x, u8 mode) {
}
void Matrix_RotateY(f32 y, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(1, y, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -229,6 +239,7 @@ void Matrix_RotateY(f32 y, u8 mode) {
}
void Matrix_RotateZ(f32 z, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(2, z, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -299,6 +310,7 @@ void Matrix_RotateZ(f32 z, u8 mode) {
* Original Name: Matrix_RotateXYZ, changed to reflect rotation order.
*/
void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) {
FrameInterpolation_RecordMatrixRotateZYX(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
f32 temp1;
f32 temp2;
@ -389,6 +401,7 @@ void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) {
* transformed according to whatever the matrix was previously.
*/
void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation) {
FrameInterpolation_RecordMatrixTranslateRotateZYX(translation, rotation);
MtxF* cmf = sCurrentMatrix;
f32 sin = Math_SinS(rotation->z);
f32 cos = Math_CosS(rotation->z);
@ -530,15 +543,20 @@ void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ
} else {
cmf->yx = 0.0f;
}
FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(translateX, translateY, translateZ, rot);
}
Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest) {
FrameInterpolation_RecordMatrixMtxFToMtx(src, dest);
guMtxF2L(src, dest);
return dest;
}
Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line) {
return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
FrameInterpolation_RecordMatrixToMtx(dest, file, line);
guMtxF2L(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
return dest;
//return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
}
Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx, char* file, s32 line) {
@ -627,6 +645,7 @@ void Matrix_Transpose(MtxF* mf) {
* seen as replacing the R rotation with `mf`, hence the function name.
*/
void Matrix_ReplaceRotation(MtxF* mf) {
FrameInterpolation_RecordMatrixReplaceRotation(mf);
MtxF* cmf = sCurrentMatrix;
f32 acc;
f32 temp;
@ -779,6 +798,7 @@ void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag) {
* NB: `axis` is assumed to be a unit vector.
*/
void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode) {
FrameInterpolation_RecordMatrixRotateAxis(angle, axis, mode);
MtxF* cmf;
f32 sin;
f32 cos;

View file

@ -6,6 +6,7 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
#include "objects/object_bdoor/object_bdoor.h"
#include "soh/frame_interpolation.h"
#if defined(_MSC_VER) || defined(__GNUC__)
#include <string.h>
@ -410,6 +411,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
f32 var2;
s32 i;
FrameInterpolation_RecordOpenChild(actor, 0);
player = GET_PLAYER(globalCtx);
spCE = 0xFF;
@ -486,10 +488,12 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
}
}
}
FrameInterpolation_RecordCloseChild();
}
actor = targetCtx->unk_94;
if ((actor != NULL) && !(actor->flags & ACTOR_FLAG_27)) {
FrameInterpolation_RecordOpenChild(actor, 1);
NaviColor* naviColor = &sNaviColorList[actor->category];
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x7);
@ -503,6 +507,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_actor.c", 2153),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_XLU_DISP++, gZTargetArrowDL);
FrameInterpolation_RecordCloseChild();
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 2158);
@ -2490,6 +2495,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
Fault_AddClient(&faultClient, Actor_FaultPrint, actor, "Actor_draw");
FrameInterpolation_RecordOpenChild(actor, 0);
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6035);
lights = LightContext_NewLights(&globalCtx->lightCtx, globalCtx->state.gfxCtx);
@ -2497,6 +2503,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
Lights_BindAll(lights, globalCtx->lightCtx.listHead, (actor->flags & ACTOR_FLAG_22) ? NULL : &actor->world.pos);
Lights_Draw(lights, globalCtx->state.gfxCtx);
FrameInterpolation_RecordActorPosRotMatrix();
if (actor->flags & ACTOR_FLAG_12) {
Matrix_SetTranslateRotateYXZ(
actor->world.pos.x + globalCtx->mainCamera.skyboxOffset.x,
@ -2546,6 +2553,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6119);
FrameInterpolation_RecordCloseChild();
Fault_RemoveClient(&faultClient);
}

View file

@ -6,6 +6,8 @@
#include "overlays/actors/ovl_En_Horse/z_en_horse.h"
#include "soh/frame_interpolation.h"
s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags);
s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags);
s32 Camera_QRegInit(void);
@ -565,10 +567,10 @@ s16 Camera_XZAngle(Vec3f* to, Vec3f* from) {
return DEGF_TO_BINANG(RADF_TO_DEGF(Math_FAtan2F(from->x - to->x, from->z - to->z)));
}
f32 D_8015CE50;
f32 D_8015CE54;
CamColChk D_8015CE58;
s16 func_80044ADC(Camera* camera, s16 yaw, s16 arg2) {
static f32 D_8015CE50;
static f32 D_8015CE54;
static CamColChk D_8015CE58;
Vec3f playerPos;
Vec3f rotatedPos;
Vec3f floorNorm;
@ -6675,6 +6677,7 @@ s32 Camera_Special9(Camera* camera) {
case 1:
spec9->doorParams.timer1--;
if (spec9->doorParams.timer1 <= 0) {
FrameInterpolation_DontInterpolateCamera();
camera->animState++;
if (params->interfaceFlags & 1) {
camPosData = Camera_GetCamBGData(camera);
@ -7221,9 +7224,9 @@ s32 Camera_DbgChangeMode(Camera* camera) {
return true;
}
s16 D_8011DB08 = 0x3F0;
s16 D_8011DB0C = 0x156;
void func_80058E8C(Camera* camera) {
static s16 D_8011DB08 = 0x3F0;
static s16 D_8011DB0C = 0x156;
s32 pad3;
f32 sp60;
s32 pad;
@ -7299,8 +7302,8 @@ void func_80058E8C(Camera* camera) {
}
}
s32 sOOBTimer = 0;
Vec3s Camera_Update(Camera* camera) {
static s32 sOOBTimer = 0;
Vec3f viewAt;
Vec3f viewEye;
Vec3f viewUp;
@ -7968,6 +7971,8 @@ s32 Camera_SetCSParams(Camera* camera, CutsceneCameraPoint* atPoints, CutsceneCa
camera->speedRatio = 0.0f;
}
FrameInterpolation_DontInterpolateCamera();
return 1;
}

View file

@ -1,6 +1,8 @@
#include "global.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
void EffectBlure_AddVertex(EffectBlure* this, Vec3f* p1, Vec3f* p2) {
EffectBlureElement* elem;
s32 numElements;
@ -946,6 +948,7 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) {
s32 j;
s32 phi_t2;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_blure.c", 1596);
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -1059,4 +1062,5 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) {
}
CLOSE_DISPS(gfxCtx, "../z_eff_blure.c", 1823);
FrameInterpolation_RecordCloseChild();
}

View file

@ -2,6 +2,8 @@
#include "vt.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
static Vtx sVertices[5] = {
VTX(-32, -32, 0, 0, 1024, 0xFF, 0xFF, 0xFF, 0xFF),
VTX(32, 32, 0, 1024, 0, 0xFF, 0xFF, 0xFF, 0xFF),
@ -154,6 +156,7 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) {
Color_RGBA8 primColor;
Color_RGBA8 envColor;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_shield_particle.c", 272);
if (this != NULL) {
@ -213,4 +216,5 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) {
}
CLOSE_DISPS(gfxCtx, "../z_eff_shield_particle.c", 359);
FrameInterpolation_RecordCloseChild();
}

View file

@ -1,6 +1,8 @@
#include "global.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
// original name: "spark"
void EffectSpark_Init(void* thisx, void* initParamsx) {
EffectSpark* this = (EffectSpark*)thisx;
@ -152,6 +154,7 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) {
u8 sp1C4;
f32 ratio;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_spark.c", 293);
if (this != NULL) {
@ -274,4 +277,5 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) {
end:
CLOSE_DISPS(gfxCtx, "../z_eff_spark.c", 498);
FrameInterpolation_RecordCloseChild();
}

View file

@ -1,6 +1,8 @@
#include "global.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
EffectSsInfo sEffectSsInfo = { 0 }; // "EffectSS2Info"
void EffectSs_InitInfo(GlobalContext* globalCtx, s32 tableSize) {
@ -233,6 +235,7 @@ void EffectSs_Spawn(GlobalContext* globalCtx, s32 type, s32 priority, void* init
sEffectSsInfo.table[index].type = type;
sEffectSsInfo.table[index].priority = priority;
sEffectSsInfo.table[index].epoch++;
if (initInfo->init(globalCtx, index, &sEffectSsInfo.table[index], initParams) == 0) {
osSyncPrintf(VT_FGCOL(GREEN));
@ -284,7 +287,9 @@ void EffectSs_Draw(GlobalContext* globalCtx, s32 index) {
EffectSs* effectSs = &sEffectSsInfo.table[index];
if (effectSs->draw != NULL) {
FrameInterpolation_RecordOpenChild(effectSs, effectSs->epoch);
effectSs->draw(globalCtx, index, effectSs);
FrameInterpolation_RecordCloseChild();
}
}

View file

@ -498,8 +498,8 @@ void HealthMeter_HandleCriticalAlarm(GlobalContext* globalCtx) {
if (interfaceCtx->unk_22A <= 0) {
interfaceCtx->unk_22A = 0;
interfaceCtx->unk_22C = 0;
if (!Player_InCsMode(globalCtx) && (globalCtx->pauseCtx.state == 0) &&
(globalCtx->pauseCtx.debugState == 0) && HealthMeter_IsCritical() && !Gameplay_InCsMode(globalCtx)) {
if (CVar_GetS32("gLowHpAlarm", 0) == 0 && !Player_InCsMode(globalCtx) && (globalCtx->pauseCtx.state == 0) &&
(globalCtx->pauseCtx.debugState == 0) && HealthMeter_IsCritical() && !Gameplay_InCsMode(globalCtx)) {
func_80078884(NA_SE_SY_HITPOINT_ALARM);
}
}

View file

@ -4,6 +4,8 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define LIGHTS_BUFFER_SIZE 32
//#define LIGHTS_BUFFER_SIZE 1024 // Kill me
@ -434,12 +436,14 @@ void Lights_DrawGlow(GlobalContext* globalCtx) {
if ((info->type == LIGHT_POINT_GLOW) && (params->drawGlow)) {
scale = SQ(params->radius) * 0.0000026f;
FrameInterpolation_RecordOpenChild(node, 0);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, params->color[0], params->color[1], params->color[2], 50);
Matrix_Translate(params->x, params->y, params->z, MTXMODE_NEW);
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_lights.c", 918),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gGlowCircleDL);
FrameInterpolation_RecordCloseChild();
}
node = node->next;

View file

@ -52,7 +52,7 @@ static MapMarkDataOverlay sMapMarkDataOvl = {
gMapMarkDataTable,
};
static MapMarkData** sLoadedMarkDataTable;
MapMarkData** sLoadedMarkDataTable;
void MapMark_Init(GlobalContext* globalCtx) {
MapMarkDataOverlay* overlay = &sMapMarkDataOvl;

View file

@ -4,9 +4,9 @@
static s16 sDisableAttention = false;
static s16 sUnused = -1;
static s32 sPrevFrameCs1100 = -4096;
s32 sPrevFrameCs1100 = -4096;
#include "z_onepointdemo_data.c"
#include "z_onepointdemo_data.inc"
void OnePointCutscene_AddVecSphToVec3f(Vec3f* dst, Vec3f* src, VecSph* vecSph) {
Vec3f out;

View file

@ -1,6 +1,6 @@
#include "global.h"
static CutsceneCameraPoint D_8012013C[14] = {
CutsceneCameraPoint D_8012013C[14] = {
{ CS_CMD_CONTINUE, 25, 40, 70.79991f, { -1814, 533, -1297 } },
{ CS_CMD_CONTINUE, 20, 40, 70.99991f, { -1805, 434, -1293 } },
{ CS_CMD_CONTINUE, 10, 30, 60.0f, { -1794, 323, -1280 } },
@ -16,7 +16,7 @@ static CutsceneCameraPoint D_8012013C[14] = {
{ CS_CMD_STOP, 0, 50, 60.0f, { -1974, 12, -1179 } },
{ CS_CMD_STOP, 0, 30, 60.0f, { -1974, 12, -1179 } },
};
static CutsceneCameraPoint D_8012021C[14] = {
CutsceneCameraPoint D_8012021C[14] = {
{ CS_CMD_CONTINUE, 0, 0, 60.0f, { -1751, 604, -1233 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1752, 516, -1233 } },
{ CS_CMD_CONTINUE, 0, 0, 60.0f, { -1751, 417, -1233 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1767, 306, -1219 } },
{ CS_CMD_CONTINUE, 0, 0, 60.0f, { -1776, 257, -1205 } }, { CS_CMD_CONTINUE, 0, 0, 60.0f, { -1881, 147, -1149 } },
@ -54,7 +54,7 @@ static CutsceneCameraPoint D_80120434[10] = {
{ CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, -119 } }, { CS_CMD_STOP, 0, 0, 60.0f, { 0, 62, -119 } },
};
static CutsceneCameraPoint D_801204D4[14] = {
CutsceneCameraPoint D_801204D4[14] = {
{ CS_CMD_CONTINUE, -15, 40, 80.600006f, { -60, 332, 183 } },
{ CS_CMD_CONTINUE, -22, 30, 80.600006f, { -60, 332, 183 } },
{ CS_CMD_CONTINUE, -20, 38, 80.600006f, { -118, 344, 41 } },
@ -70,7 +70,7 @@ static CutsceneCameraPoint D_801204D4[14] = {
{ CS_CMD_STOP, 6, 30, 85.199936f, { 25, 127, -950 } },
{ CS_CMD_STOP, 0, 30, 85.199936f, { 25, 127, -950 } },
};
static CutsceneCameraPoint D_801205B4[14] = {
CutsceneCameraPoint D_801205B4[14] = {
{ CS_CMD_CONTINUE, 0, 0, 60.0f, { -225, 785, -242 } },
{ CS_CMD_CONTINUE, -21, 0, 80.600006f, { -245, 784, -242 } },
{ CS_CMD_CONTINUE, -21, 0, 80.600006f, { -288, 485, -379 } },
@ -118,18 +118,18 @@ static s16 D_801208E0 = 12;
static s16 D_801208E4 = 90;
static s16 D_801208E8 = 8;
static OnePointCsFull D_801208EC[3] = {
OnePointCsFull D_801208EC[3] = {
{ 0x0F, 0x08, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x81, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80120964[2] = {
OnePointCsFull D_80120964[2] = {
{ 0x8F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x81, 0xFF, 0xA121, 1, 0, 75.0f, 0.6f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
};
static OnePointCsFull D_801209B4[4] = {
OnePointCsFull D_801209B4[4] = {
{ 0x8F, 0x08, 0x0101, 1, 0, 60.0f, 0.9f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x84, 0x01, 0x0100, 29, 0, 45.0f, 0.1f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
{ 0x83, 0xFF, 0x0000, 10, 0, 60.0f, 0.2f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
@ -142,7 +142,7 @@ static OnePointCsFull D_80120A54[3] = {
{ 0x8B, 0xFF, 0x0022, 5000, 0, 75.0f, 0.005f, { 0.0f, 0.0f, -10.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80120ACC[5] = {
OnePointCsFull D_80120ACC[5] = {
{ 0x8F, 0xFF, 0x0442, 10, 0, 40.0f, 1.0f, { -10.0f, 45.0f, 20.0f }, { 20.0f, 30.0f, 160.0f } },
{ 0x95, 0xFF, 0x0000, 1, 0, 40.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
{ 0x8F, 0x01, 0x0442, 10, 0, 40.0f, 1.0f, { -10.0f, 45.0f, 20.0f }, { 20.0f, 30.0f, 160.0f } },
@ -150,7 +150,7 @@ static OnePointCsFull D_80120ACC[5] = {
{ 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80120B94[11] = {
OnePointCsFull D_80120B94[11] = {
{ 0x8F, 0x01, 0x2142, 1, 0, 40.0f, 1.0f, { 20.0f, 40.0f, 20.0f }, { -20.0f, 0.0f, -30.0f } },
{ 0x84, 0xFF, 0x0404, 19, 5, 70.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } },
{ 0x84, 0xFF, 0x0404, 20, 0, 60.0f, 0.01f, { 0.0f, 20.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } },
@ -164,7 +164,7 @@ static OnePointCsFull D_80120B94[11] = {
{ 0x98, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80120D4C[7] = {
OnePointCsFull D_80120D4C[7] = {
{ 0x8F, 0x01, 0x2142, 1, 0, 40.0f, 1.0f, { 20.0f, 40.0f, 20.0f }, { -20.0f, 0.0f, -30.0f } },
{ 0x84, 0xFF, 0x0404, 19, 5, 70.0f, 0.01f, { 0.0f, 30.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } },
{ 0x84, 0xFF, 0x0404, 20, 0, 60.0f, 0.01f, { 0.0f, 20.0f, 20.0f }, { 120.0f, 60.0f, 120.0f } },
@ -185,7 +185,7 @@ static OnePointCsFull D_80120E64[8] = {
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80120FA4[6] = {
OnePointCsFull D_80120FA4[6] = {
{ 0x8F, 0x01, 0x2143, 30, 0, 70.0f, 0.4f, { 0.0f, 40.0f, 50.0f }, { 30.0f, 10.0f, -50.0f } },
{ 0x95, 0xFF, 0x0000, 1, 0, 50.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
{ 0x8F, 0xFF, 0x2222, 10, 0, 42.0f, 1.0f, { 0.0f, 40.0f, 0.0f }, { 0.0f, 85.0f, 45.0f } },
@ -206,12 +206,12 @@ static OnePointCsFull D_8012110C[3] = {
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80121184[2] = {
OnePointCsFull D_80121184[2] = {
{ 0x83, 0x01, 0x0101, 40, 0, -1.0f, 0.1f, { 0.0f, 10.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_801211D4[2] = {
OnePointCsFull D_801211D4[2] = {
{ 0x8F, 0x08, 0x0101, 50, 0, 60.0f, 1.0f, { 0.0f, 10.0f, 0.0f }, { -10.0f, 85.0f, 0.0f } },
{ 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
@ -229,13 +229,13 @@ static OnePointCsFull D_80121314[1] = {
{ 0x8F, 0x08, 0x4141, 1000, 0, 75.0f, 0.6f, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 100.0f } },
};
static OnePointCsFull D_8012133C[3] = {
OnePointCsFull D_8012133C[3] = {
{ 0x8F, 0x01, 0x0141, 40, 0, 75.0f, 1.0f, { 0.0f, 60.0f, 0.0f }, { 0.0f, 0.0f, 100.0f } },
{ 0x83, 0xFF, 0x2121, 20, 0, 60.0f, 0.2f, { 0.0f, -10.0f, -10.0f }, { 0.0f, 10.0f, -100.0f } },
{ 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_801213B4[5] = {
OnePointCsFull D_801213B4[5] = {
{ 0x8F, 0x08, 0xC2C2, 40, 0, 70.0f, 1.0f, { 80.0f, 0.0f, 20.0f }, { 20.0f, 0.0f, 80.0f } },
{ 0x8B, 0x01, 0xC2C2, 120, 0, 70.0f, 0.1f, { 80.0f, 0.0f, 20.0f }, { 20.0f, 0.0f, 80.0f } },
{ 0x8F, 0x53, 0xC2C2, 30, 0, 50.0f, 1.0f, { 60.0f, 0.0f, 20.0f }, { 60.0f, 0.0f, 60.0f } },
@ -250,17 +250,17 @@ static OnePointCsFull D_8012147C[4] = {
{ 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_8012151C[2] = {
OnePointCsFull D_8012151C[2] = {
{ 0x0F, 0x01, 0x0101, 29, 0, 60.0f, 1.0f, { -700.0f, 875.0f, -100.0f }, { -550.0f, 920.0f, -150.0f } },
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_8012156C[2] = {
OnePointCsFull D_8012156C[2] = {
{ 0x8F, 0x4D, 0x4242, 1, 0, 65.0f, 1.0f, { 60.0f, 30.0f, 0.0f }, { 50.0f, 20.0f, 150.0f } },
{ 0x81, 0xFF, 0x4242, -1, 0, 65.0f, 1.0f, { -50.0f, 60.0f, 0.0f }, { -60.0f, 40.0f, 150.0f } },
};
static OnePointCsFull D_801215BC[1] = {
OnePointCsFull D_801215BC[1] = {
{ 0x0F, 0xFF, 0x0101, 5, 0, 65.0f, 1.0f, { -1185.0f, 655.0f, 1185.0f }, { -1255.0f, 735.0f, 1255.0f } },
};
@ -331,7 +331,7 @@ static OnePointCsFull D_80121A44[12] = {
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80121C24[7] = {
OnePointCsFull D_80121C24[7] = {
{ 0x0F, 0x05, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x03, 0xFF, 0x0101, 89, 0, 50.0f, 0.4f, { 125.0f, 320.0f, -1500.0f }, { 125.0f, 500.0f, -1150.0f } },
{ 0x0F, 0x08, 0x0101, 40, 4, 55.0f, 1.0f, { 0.0f, 375.0f, -1440.0f }, { 5.0f, 365.0f, -1315.0f } },
@ -341,7 +341,7 @@ static OnePointCsFull D_80121C24[7] = {
{ 0x11, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80121D3C[3] = {
OnePointCsFull D_80121D3C[3] = {
{ 0x0F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 1023.0f, 738.0f, -2628.0f }, { 993.0f, 770.0f, -2740.0f } },
{ 0x02, 0xFF, 0x0101, 4, 0, 50.0f, 1.0f, { 1255.0f, 350.0f, -1870.0f }, { 1240.0f, 575.0f, -2100.0f } },
{ 0x0F, 0xFF, 0x0000, -1, 0, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
@ -359,14 +359,14 @@ static OnePointCsFull D_80121DB4[9] = {
{ 0x12, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80121F1C[4] = {
OnePointCsFull D_80121F1C[4] = {
{ 0x0F, 0x08, 0x0101, 10, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x01, 0xFF, 0x2121, 10, 0, 50.0f, 0.5f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
{ 0x01, 0x02, 0x2121, 23, 0, 50.0f, 0.5f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 150.0f } },
{ 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80121FBC[4] = {
OnePointCsFull D_80121FBC[4] = {
{ 0x0F, 0xFF, 0x0101, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x01, 0xFF, 0x0101, 10, 0, 30.0f, 1.0f, { -2130.0f, 2885.0f, -1055.0f }, { -2085.0f, 2875.0f, -1145.0f } },
{ 0x0F, 0xFF, 0x0000, 30, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
@ -379,7 +379,7 @@ static OnePointCsFull D_8012205C[3] = {
{ 0x01, 0x01, 0x21A1, 10, 0, 60.0f, 1.0f, { 0.0f, -10.0f, 0.0f }, { 0.0f, 10.0f, -200.0f } },
};
static OnePointCsFull D_801220D4[5] = {
OnePointCsFull D_801220D4[5] = {
{ 0x0F, 0x01, 0x0101, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x01, 0xFF, 0x4141, 10, 5, 55.0f, 0.75f, { 400.0f, -50.0f, 800.0f }, { 600.0f, -60.0f, 800.0f } },
{ 0x01, 0xFF, 0x4141, 15, 10, 40.0f, 0.75f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 200.0f } },
@ -443,7 +443,7 @@ static OnePointCsFull D_8012269C[3] = {
{ 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80122714[4] = {
OnePointCsFull D_80122714[4] = {
{ 0x0F, 0xFF, 0x0101, 20, 0, 45.0f, 1.0f, { -915.0f, -2185.0f, 6335.0f }, { -915.0f, -2290.0f, 6165.0f } },
{ 0x02, 0xFF, 0x0101, -1, 0, 80.0f, 0.8f, { -920.0f, -2270.0f, 6140.0f }, { -920.0f, -2280.0f, 6070.0f } },
{ 0x02, 0xFF, 0x0101, 20, 0, 80.0f, 0.9f, { -920.0f, -2300.0f, 6140.0f }, { -920.0f, -2300.0f, 6070.0f } },
@ -512,12 +512,12 @@ static OnePointCsFull D_80122C8C[1] = {
{ 0x0F, 0xFF, 0x0101, 999, 5, 60.0f, 1.0f, { -70.0f, 140.0f, 25.0f }, { 10.0f, 180.0f, 195.0f } },
};
static OnePointCsFull D_80122CB4[2] = {
OnePointCsFull D_80122CB4[2] = {
{ 0x0F, 0xFF, 0x4242, 5, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 1000.0f }, { 0.0f, 0.0f, 1100.0f } },
{ 0x02, 0xFF, 0x4242, -1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, -100.0f }, { 0.0f, 0.0f, 0.0f } },
};
static OnePointCsFull D_80122D04[2] = {
OnePointCsFull D_80122D04[2] = {
{ 0x0F, 0xFF, 0x4242, 10, 0, 60.0f, 1.0f, { 0.0f, 0.0f, -100.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x02, 0xFF, 0x4242, -1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 1000.0f }, { 0.0f, 0.0f, 1100.0f } },
};
@ -534,7 +534,7 @@ static OnePointCsFull D_80122DCC[3] = {
{ 0x11, 0xFF, 0x0000, 1, -1, -1.0f, -1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80122E44[2][7] = {
OnePointCsFull D_80122E44[2][7] = {
{
{ 0x83, 0xFF, 0x2222, 10, 5, 90.0f, 0.2f, { 50.0f, 100.0f, 140.0f }, { -30.0f, 10.0f, -20.0f } },
{ 0x8F, 0xFF, 0x0000, 20, 0, 90.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
@ -563,25 +563,25 @@ static OnePointCsFull D_80123074[5] = {
{ 0x92, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_8012313C[3] = {
OnePointCsFull D_8012313C[3] = {
{ 0x8F, 0xFF, 0xA2A2, 20, 8, 70.0f, 1.0f, { 65.0f, -150.0f, 50.0f }, { 30.0f, 10.0f, 90.0f } },
{ 0x81, 0xFF, 0xA2A2, 100, 0, 60.0f, 1.0f, { 70.0f, -160.0f, 50.0f }, { 25.0f, 180.0f, 180.0f } },
{ 0x92, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_801231B4[4] = {
OnePointCsFull D_801231B4[4] = {
{ 0x8F, 0xC5, 0x4343, 1, 0, 50.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 5.0f, -1.0f } },
{ 0x81, 0xC5, 0x4343, 48, 0, 50.0f, 0.75f, { 0.0f, 80.0f, 0.0f }, { 0.0f, 15.0f, -1.0f } },
{ 0x8F, 0xC5, 0x4343, 1, 5, 45.0f, 1.0f, { 0.0f, 0.0f, 30.0f }, { 30.0f, 120.0f, 60.0f } },
{ 0x81, 0xC5, 0x4343, -1, 0, -1.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80123254[2] = {
OnePointCsFull D_80123254[2] = {
{ 0x0F, 0xFF, 0x0101, 1, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x03, 0xC5, 0x0101, 49, 0, 50.0f, 0.05f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
};
static OnePointCsFull D_801232A4[1] = {
OnePointCsFull D_801232A4[1] = {
{ 0x0F, 0x45, 0x0101, 9999, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
};
@ -646,24 +646,24 @@ static OnePointCsFull D_801237CC[5] = {
{ 0x0F, 0xFF, 0x0000, 100, -45, 75.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },
};
static OnePointCsFull D_80123894[3] = {
OnePointCsFull D_80123894[3] = {
{ 0x0F, 0xFF, 0x0101, 60, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x0F, 0xFF, 0x4242, 30, 0, 50.0f, 1.0f, { 0.0f, 28.0f, 0.0f }, { 0.0f, 20.0f, 40.0f } },
{ 0x0D, 0xFF, 0x0000, 120, 0, 180.0f, 0.4f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 2.0f, 40.0f } },
};
static OnePointCsFull D_8012390C[2] = {
OnePointCsFull D_8012390C[2] = {
{ 0x0F, 0xFF, 0x0101, 30, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x0F, 0xFF, 0x4242, 180, 0, 60.0f, 1.0f, { 0.0f, 78.0f, 0.0f }, { 0.0f, 78.0f, 200.0f } },
};
static OnePointCsFull D_8012395C[3] = {
OnePointCsFull D_8012395C[3] = {
{ 0x0F, 0xFF, 0x0101, 60, 0, 60.0f, 1.0f, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x0F, 0xFF, 0x4242, 30, 0, 50.0f, 1.0f, { 0.0f, 28.0f, 0.0f }, { 0.0f, 20.0f, -45.0f } },
{ 0x0D, 0xFF, 0x0000, 120, 0, 180.0f, 0.4f, { 0.0f, -5.0f, 0.0f }, { 0.0f, 2.0f, 45.0f } },
};
static OnePointCsFull D_801239D4[3] = {
OnePointCsFull D_801239D4[3] = {
{ 0x0F, 0xFF, 0x4242, 5, 0, 60.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 40.0f, -120.0f } },
{ 0x09, 0xFF, 0x4242, 0, 0, 60.0f, 1.0f, { 0.0f, 20.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
{ 0x12, 0xFF, 0x0000, 1, 0, 60.0f, 1.0f, { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f, -1.0f } },

View file

@ -753,7 +753,15 @@ void func_80083108(GlobalContext* globalCtx) {
gSaveContext.buttonStatus[0] = BTN_DISABLED;
for (i = 1; i < 4; i++) {
if (func_8008F2F8(globalCtx) == 2) {
if ((gSaveContext.equips.buttonItems[i] >= ITEM_SHIELD_DEKU) &&
(gSaveContext.equips.buttonItems[i] <= ITEM_BOOTS_HOVER)) {
// Equipment on c-buttons is always enabled
if (gSaveContext.buttonStatus[i] == BTN_DISABLED) {
sp28 = 1;
}
gSaveContext.buttonStatus[i] = BTN_ENABLED;
} else if (func_8008F2F8(globalCtx) == 2) {
if ((gSaveContext.equips.buttonItems[i] != ITEM_HOOKSHOT) &&
(gSaveContext.equips.buttonItems[i] != ITEM_LONGSHOT)) {
if (gSaveContext.buttonStatus[i] == BTN_ENABLED) {

View file

@ -5,6 +5,8 @@
#include "soh/Enhancements/gameconsole.h"
#include "soh/frame_interpolation.h"
void* D_8012D1F0 = NULL;
//UNK_TYPE D_8012D1F4 = 0; // unused
Input* D_8012D1F8 = NULL;
@ -421,7 +423,7 @@ void Gameplay_Update(GlobalContext* globalCtx) {
input = globalCtx->state.input;
if ((SREG(1) < 0) || (DREG(0) != 0)) {
if ((SREG(1) < 0) || (DREG(0) != 0)) {
SREG(1) = 0;
ZeldaArena_Display();
}
@ -1379,7 +1381,9 @@ void Gameplay_Main(GameState* thisx) {
LOG_NUM("1", 1, "../z_play.c", 4583);
}
FrameInterpolation_StartRecord();
Gameplay_Draw(globalCtx);
FrameInterpolation_StopRecord();
if (1 && HREG(63)) {
LOG_NUM("1", 1, "../z_play.c", 4587);

View file

@ -29,7 +29,8 @@ s16 sBootData[PLAYER_BOOTS_MAX][17] = {
// Used to map action params to model groups
u8 sActionModelGroups[] = {
3, 15, 10, 2, 2, 5, 10, 11, 6, 6, 6, 6, 6, 6, 6, 6, 9, 9, 7, 7, 8, 3, 3, 6, 3, 3, 3, 3, 12, 13, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
14, 14, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3
};
TextTriggerEntry sTextTriggers[] = {
@ -743,26 +744,24 @@ void func_8008F470(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable,
#else
gSPSegment(POLY_OPA_DISP++, 0x09, SEGMENTED_TO_VIRTUAL(sMouthTextures[eyeIndex]));
#endif
Color_RGB8 sTemp;
color = &sTemp;
if (tunic == PLAYER_TUNIC_KOKIRI) {
Color_RGB8 sTemp = { CVar_GetS32("gTunic_Kokiri_Red", sTunicColors[PLAYER_TUNIC_KOKIRI].r),
CVar_GetS32("gTunic_Kokiri_Green", sTunicColors[PLAYER_TUNIC_KOKIRI].g),
CVar_GetS32("gTunic_Kokiri_Blue", sTunicColors[PLAYER_TUNIC_KOKIRI].b) };
color = &sTemp;
color->r = CVar_GetS32("gTunic_Kokiri_Red", sTunicColors[PLAYER_TUNIC_KOKIRI].r);
color->g = CVar_GetS32("gTunic_Kokiri_Green", sTunicColors[PLAYER_TUNIC_KOKIRI].g);
color->b = CVar_GetS32("gTunic_Kokiri_Blue", sTunicColors[PLAYER_TUNIC_KOKIRI].b);
} else if (tunic == PLAYER_TUNIC_GORON) {
Color_RGB8 sTemp = { CVar_GetS32("gTunic_Goron_Red", sTunicColors[PLAYER_TUNIC_GORON].r),
CVar_GetS32("gTunic_Goron_Green", sTunicColors[PLAYER_TUNIC_GORON].g),
CVar_GetS32("gTunic_Goron_Blue", sTunicColors[PLAYER_TUNIC_GORON].b) };
color = &sTemp;
color->r = CVar_GetS32("gTunic_Goron_Red", sTunicColors[PLAYER_TUNIC_GORON].r);
color->g = CVar_GetS32("gTunic_Goron_Green", sTunicColors[PLAYER_TUNIC_GORON].g);
color->b = CVar_GetS32("gTunic_Goron_Blue", sTunicColors[PLAYER_TUNIC_GORON].b);
} else if (tunic == PLAYER_TUNIC_ZORA) {
Color_RGB8 sTemp = { CVar_GetS32("gTunic_Zora_Red", sTunicColors[PLAYER_TUNIC_ZORA].r),
CVar_GetS32("gTunic_Zora_Green", sTunicColors[PLAYER_TUNIC_ZORA].g),
CVar_GetS32("gTunic_Zora_Blue", sTunicColors[PLAYER_TUNIC_ZORA].b) };
color = &sTemp;
color->r = CVar_GetS32("gTunic_Zora_Red", sTunicColors[PLAYER_TUNIC_ZORA].r);
color->g = CVar_GetS32("gTunic_Zora_Green", sTunicColors[PLAYER_TUNIC_ZORA].g);
color->b = CVar_GetS32("gTunic_Zora_Blue", sTunicColors[PLAYER_TUNIC_ZORA].b);
} else {
Color_RGB8 sTemp = { CVar_GetS32("gTunic_Kokiri_Red", sTunicColors[PLAYER_TUNIC_KOKIRI].r),
CVar_GetS32("gTunic_Kokiri_Green", sTunicColors[PLAYER_TUNIC_KOKIRI].g),
CVar_GetS32("gTunic_Kokiri_Blue", sTunicColors[PLAYER_TUNIC_KOKIRI].b) };
color = &sTemp;
color->r = CVar_GetS32("gTunic_Kokiri_Red", sTunicColors[PLAYER_TUNIC_KOKIRI].r);
color->g = CVar_GetS32("gTunic_Kokiri_Green", sTunicColors[PLAYER_TUNIC_KOKIRI].g);
color->b = CVar_GetS32("gTunic_Kokiri_Blue", sTunicColors[PLAYER_TUNIC_KOKIRI].b);
}
gDPSetEnvColor(POLY_OPA_DISP++, color->r, color->g, color->b, 0);

View file

@ -1,6 +1,8 @@
#include "global.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
// clang-format off
MtxF sMtxFClear = {
1.0f, 0.0f, 0.0f, 0.0f,
@ -523,6 +525,7 @@ void SkinMatrix_Vec3sToVec3f(Vec3s* src, Vec3f* dest) {
}
void SkinMatrix_MtxFToMtx(MtxF* src, Mtx* dest) {
FrameInterpolation_RecordSkinMatrixMtxFToMtx(src, dest);
guMtxF2L(src, dest);
}

View file

@ -2,6 +2,9 @@
#include "vt.h"
#include <string.h>
#include <math.h>
#include "soh/frame_interpolation.h"
vu32 D_8012ABF0 = true;
@ -277,6 +280,10 @@ void func_800AAA50(View* view, s32 arg1) {
}
}
static float sqr(float a) {
return a * a;
}
s32 func_800AAA9C(View* view) {
f32 aspect;
s32 width;
@ -307,6 +314,85 @@ s32 func_800AAA9C(View* view) {
height = view->viewport.bottomY - view->viewport.topY;
aspect = (f32)width / (f32)height;
viewing = Graph_Alloc(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667);
view->viewingPtr = viewing;
if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) {
view->eye.x += 1.0f;
view->eye.y += 1.0f;
view->eye.z += 1.0f;
}
func_800ABE74(view->eye.x, view->eye.y, view->eye.z);
MtxF viewingF;
guLookAtF(viewingF.mf, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x,
view->up.y, view->up.z);
// Some heuristics to identify instant camera movements and skip interpolation in that case
static View old_view;
float dirx = view->eye.x - view->lookAt.x;
float diry = view->eye.y - view->lookAt.y;
float dirz = view->eye.z - view->lookAt.z;
float dir_dist = sqrtf(sqr(dirx) + sqr(diry) + sqr(dirz));
dirx /= dir_dist;
diry /= dir_dist;
dirz /= dir_dist;
float odirx = old_view.eye.x - old_view.lookAt.x;
float odiry = old_view.eye.y - old_view.lookAt.y;
float odirz = old_view.eye.z - old_view.lookAt.z;
float odir_dist = sqrtf(sqr(odirx) + sqr(odiry) + sqr(odirz));
odirx /= odir_dist;
odiry /= odir_dist;
odirz /= odir_dist;
float eye_dist = sqrtf(sqr(view->eye.x - old_view.eye.x) + sqr(view->eye.y - old_view.eye.y) + sqr(view->eye.z - old_view.eye.z));
float look_dist = sqrtf(sqr(view->lookAt.x - old_view.lookAt.x) + sqr(view->lookAt.y - old_view.lookAt.y) + sqr(view->lookAt.z - old_view.lookAt.z));
float up_dist = sqrtf(sqr(view->up.x - old_view.up.x) + sqr(view->up.y - old_view.up.y) + sqr(view->up.z - old_view.up.z));
float d_dist = sqrtf(sqr(dirx - odirx) + sqr(diry - odiry) + sqr(dirz - odirz));
bool dont_interpolate = false;
if (up_dist < 0.01 && d_dist < 0.01) {
if (eye_dist + look_dist > 300) {
dont_interpolate = true;
}
} else {
if (eye_dist >= 400) {
dont_interpolate = true;
}
if (look_dist >= 100) {
dont_interpolate = true;
}
if (up_dist >= 1.50f) {
dont_interpolate = true;
}
if (d_dist >= 1.414f && look_dist >= 15) {
dont_interpolate = true;
}
if (d_dist >= 1.414f && up_dist >= 0.31f && look_dist >= 1 && eye_dist >= 300) {
dont_interpolate = true;
}
if (d_dist >= 0.5f && up_dist >= 0.31f && look_dist >= 3 && eye_dist >= 170) {
dont_interpolate = true;
}
if (look_dist >= 52 && eye_dist >= 52) {
dont_interpolate = true;
}
if (look_dist >= 30 && eye_dist >= 90) {
dont_interpolate = true;
}
}
if (dont_interpolate) {
FrameInterpolation_DontInterpolateCamera();
}
FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch());
if (HREG(80) == 11) {
if (HREG(94) != 11) {
HREG(94) = 11;
@ -347,22 +433,17 @@ s32 func_800AAA9C(View* view) {
gSPPerspNormalize(POLY_KAL_DISP++, view->normal);
gSPMatrix(POLY_KAL_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
viewing = Graph_Alloc(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667);
view->viewingPtr = viewing;
if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) {
view->eye.x += 1.0f;
view->eye.y += 1.0f;
view->eye.z += 1.0f;
}
func_800ABE74(view->eye.x, view->eye.y, view->eye.z);
guLookAt(viewing, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x,
view->up.y, view->up.z);
Matrix_MtxFToMtx(viewingF.mf, viewing);
view->viewing = *viewing;
/*if (eye_dist > 1 || look_dist > 1 || abs(up_dist) > 0.1 || abs(d_dist) > 0.1)
printf("%d %f %f %f, %f %f %f, %f %f %f, %f %f %f %f %d\n", (int)view->fovy, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z,
view->up.x, view->up.y, view->up.z, eye_dist, look_dist, up_dist, d_dist, dont_interpolate);*/
old_view = *view;
if (QREG(88) & 2) {
s32 i;
MtxF mf;
@ -374,10 +455,10 @@ s32 func_800AAA9C(View* view) {
}
osSyncPrintf("\n");
}
gSPMatrix(POLY_OPA_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_KAL_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
CLOSE_DISPS(gfxCtx, "../z_view.c", 711);

View file

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
Mtx* sSkyboxDrawMatrix;
Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) {
@ -13,6 +15,7 @@ Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) {
void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z) {
OPEN_DISPS(gfxCtx, "../z_vr_box_draw.c", 52);
FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch());
func_800945A0(gfxCtx);
@ -85,7 +88,7 @@ void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyb
gDPPipeSync(POLY_OPA_DISP++);
//gsSPShaderTest2(POLY_OPA_DISP++);
FrameInterpolation_RecordCloseChild();
CLOSE_DISPS(gfxCtx, "../z_vr_box_draw.c", 125);
}

View file

@ -62,5 +62,6 @@ void guLookAt(Mtx* m, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f
guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp);
guMtxF2L((MtxF*)mf, m);
//guMtxF2L((MtxF*)mf, m);
Matrix_MtxFToMtx((MtxF*)mf, m);
}

View file

@ -37,6 +37,6 @@ void guPerspective(Mtx* m, u16* perspNorm, f32 fovy, f32 aspect, f32 near, f32 f
f32 mf[4][4];
guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale);
guMtxF2L((MtxF*)mf, m);
//guMtxF2L((MtxF*)mf, m);
Matrix_MtxFToMtx((MtxF*)mf, m);
}

View file

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
void guOrthoF(f32 mf[4][4], f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far, f32 scale) {
s32 i, j;
@ -25,5 +27,8 @@ void guOrtho(Mtx* mtx, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 f
guOrthoF(mf, left, right, bottom, top, near, far, scale);
guMtxF2L((MtxF*)mf, mtx);
//guMtxF2L((MtxF*)mf, mtx);
FrameInterpolation_RecordOpenChild("ortho", 0);
Matrix_MtxFToMtx((MtxF*)mf, mtx);
FrameInterpolation_RecordCloseChild();
}

View file

@ -121,8 +121,8 @@ void BgDdanKd_CheckForExplosions(BgDdanKd* this, GlobalContext* globalCtx) {
}
}
static Vec3f velocity = { 0.0f, 5.0f, 0.0f };
static Vec3f accel = { 0.0f, -0.45f, 0.0f };
Vec3f sBgDdanKdVelocity = { 0.0f, 5.0f, 0.0f };
Vec3f sBgDdanKdAccel = { 0.0f, -0.45f, 0.0f };
void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) {
Vec3f pos1;
@ -158,11 +158,11 @@ void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) {
func_80033480(globalCtx, &pos1, 20.0f, 1, effectStrength * 135.0f, 60, 1);
func_80033480(globalCtx, &pos2, 20.0f, 1, effectStrength * 135.0f, 60, 1);
velocity.x = Rand_CenteredFloat(3.0f);
velocity.z = Rand_CenteredFloat(3.0f);
sBgDdanKdVelocity.x = Rand_CenteredFloat(3.0f);
sBgDdanKdVelocity.z = Rand_CenteredFloat(3.0f);
func_8003555C(globalCtx, &pos1, &velocity, &accel);
func_8003555C(globalCtx, &pos2, &velocity, &accel);
func_8003555C(globalCtx, &pos1, &sBgDdanKdVelocity, &sBgDdanKdAccel);
func_8003555C(globalCtx, &pos2, &sBgDdanKdVelocity, &sBgDdanKdAccel);
pos1 = this->dyna.actor.world.pos;
pos1.z += 560.0f + Rand_ZeroOne() * 5.0f;
@ -170,7 +170,7 @@ void BgDdanKd_LowerStairs(BgDdanKd* this, GlobalContext* globalCtx) {
pos1.y = Rand_ZeroOne() * 3.0f + (this->dyna.actor.floorHeight + 20.0f);
func_80033480(globalCtx, &pos1, 20.0f, 1, effectStrength * 135.0f, 60, 1);
func_8003555C(globalCtx, &pos1, &velocity, &accel);
func_8003555C(globalCtx, &pos1, &sBgDdanKdVelocity, &sBgDdanKdAccel);
}
Camera_AddQuake(&globalCtx->mainCamera, 0, effectStrength * 0.6f, 3);
Audio_PlaySoundGeneral(NA_SE_EV_PILLAR_SINK - SFX_FLAG, &this->dyna.actor.projectedPos, 4, &D_801333E0,
@ -192,11 +192,11 @@ void BgDdanKd_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
void BgDdanKd_Reset(void) {
velocity.x = 0.0f;
velocity.y = 5.0f;
velocity.z = 0.0f;
sBgDdanKdVelocity.x = 0.0f;
sBgDdanKdVelocity.y = 5.0f;
sBgDdanKdVelocity.z = 0.0f;
accel.x = 0.0f;
accel.y = -0.45f;
accel.z = 0.0f;
sBgDdanKdAccel.x = 0.0f;
sBgDdanKdAccel.y = -0.45f;
sBgDdanKdAccel.z = 0.0f;
}

View file

@ -74,13 +74,13 @@ static ColliderCylinderInit sColCylinderInitLeftRight = {
{ 50, 60, 280, { 0, 0, 0 } },
};
static s16 sFirstExplosiveFlag = false;
s16 sBgDodoagoFirstExplosiveFlag = false;
static u8 sDisableBombCatcher;
u8 sBgDodoagoDisableBombCatcher;
static u8 sUnused[90]; // unknown length
//static u8 sUnused[90]; // unknown length
static s32 sTimer;
s32 sBgDodoagoTimer;
void BgDodoago_SetupAction(BgDodoago* this, BgDodoagoActionFunc actionFunc) {
this->actionFunc = actionFunc;
@ -135,7 +135,7 @@ void BgDodoago_Init(Actor* thisx, GlobalContext* globalCtx) {
Collider_SetCylinder(globalCtx, &this->colliderRight, &this->dyna.actor, &sColCylinderInitLeftRight);
BgDodoago_SetupAction(this, BgDodoago_WaitExplosives);
sDisableBombCatcher = false;
sBgDodoagoDisableBombCatcher = false;
}
void BgDodoago_Destroy(Actor* thisx, GlobalContext* globalCtx) {
@ -170,16 +170,16 @@ void BgDodoago_WaitExplosives(BgDodoago* this, GlobalContext* globalCtx) {
} else {
OnePointCutscene_Init(globalCtx, 3065, 20, &this->dyna.actor, MAIN_CAM);
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
sTimer += 30;
sBgDodoagoTimer += 30;
return;
}
// the flag is never set back to false, so this only runs once
if (!sFirstExplosiveFlag) {
if (!sBgDodoagoFirstExplosiveFlag) {
// this disables the bomb catcher (see BgDodoago_Update) for a few seconds
this->dyna.actor.parent = explosive;
sFirstExplosiveFlag = true;
sTimer = 50;
sBgDodoagoFirstExplosiveFlag = true;
sBgDodoagoTimer = 50;
}
} else if (Flags_GetEventChkInf(0xB0)) {
Collider_UpdateCylinder(&this->dyna.actor, &this->colliderMain);
@ -219,11 +219,11 @@ void BgDodoago_OpenJaw(BgDodoago* this, GlobalContext* globalCtx) {
}
if (globalCtx->roomCtx.unk_74[BGDODOAGO_EYE_LEFT] != 255 || globalCtx->roomCtx.unk_74[BGDODOAGO_EYE_RIGHT] != 255) {
sTimer--;
sBgDodoagoTimer--;
return;
}
if (sTimer == 108) {
if (sBgDodoagoTimer == 108) {
for (i = ARRAY_COUNT(dustOffsets) - 1; i >= 0; i--) {
pos.x = dustOffsets[i].x + this->dyna.actor.world.pos.x;
pos.y = dustOffsets[i].y + this->dyna.actor.world.pos.y;
@ -290,16 +290,16 @@ void BgDodoago_Update(Actor* thisx, GlobalContext* globalCtx) {
this->dyna.actor.parent = &bomb->actor;
bomb->timer = 50;
bomb->actor.speedXZ = 0.0f;
sTimer = 0;
sBgDodoagoTimer = 0;
}
}
} else {
sTimer++;
sBgDodoagoTimer++;
Flags_GetSwitch(globalCtx, this->dyna.actor.params & 0x3F);
if (!sDisableBombCatcher && sTimer > 140) {
if (!sBgDodoagoDisableBombCatcher && sBgDodoagoTimer > 140) {
if (Flags_GetSwitch(globalCtx, this->dyna.actor.params & 0x3F)) {
// this prevents clearing the actor's parent pointer, effectively disabling the bomb catcher
sDisableBombCatcher++;
sBgDodoagoDisableBombCatcher++;
} else {
this->dyna.actor.parent = NULL;
}
@ -322,7 +322,7 @@ void BgDodoago_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
void BgDodoago_Reset(void) {
sFirstExplosiveFlag = false;
sDisableBombCatcher = 0;
sTimer = 0;
sBgDodoagoFirstExplosiveFlag = false;
sBgDodoagoDisableBombCatcher = 0;
sBgDodoagoTimer = 0;
}

View file

@ -8,6 +8,8 @@
#include "overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
@ -283,6 +285,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
platform = (BgGanonOtyuka*)actor;
if (platform->dyna.actor.projectedPos.z > spBC) {
FrameInterpolation_RecordOpenChild(platform, 0);
if (camera->eye.y > platform->dyna.actor.world.pos.y) {
phi_s2 = sPlatformTopDL;
} else {
@ -309,7 +312,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
for (i = 0; i < ARRAY_COUNT(sSides); i++) {
if (platform->visibleSides & sSides[i]) {
if ((platform->visibleSides & sSides[i]) || 1) { // || 1 for frame interpolation
Matrix_Push();
Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY);
Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY);
@ -320,6 +323,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Pop();
}
}
FrameInterpolation_RecordCloseChild();
}
}
@ -333,6 +337,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
platform = (BgGanonOtyuka*)actor;
if ((platform->dyna.actor.projectedPos.z > -30.0f) && (platform->flashState != FLASH_NONE)) {
FrameInterpolation_RecordOpenChild(platform, 0);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, platform->flashTimer * 4, 0, 32, 64, 1,
platform->flashTimer * 4, 0, 32, 64));
@ -344,7 +349,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Translate(platform->dyna.actor.world.pos.x, 0.0f, platform->dyna.actor.world.pos.z, MTXMODE_NEW);
for (i = 0; i < ARRAY_COUNT(sSides); i++) {
if (platform->unwalledSides & sSides[i]) {
if ((platform->unwalledSides & sSides[i]) || 1) { // || 1 for frame interpolation
Matrix_Push();
Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY);
Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY);
@ -356,6 +361,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Pop();
}
}
FrameInterpolation_RecordCloseChild();
}
}

View file

@ -47,7 +47,7 @@ void BgHakaGate_SkullOfTruth(BgHakaGate* this, GlobalContext* globalCtx);
void BgHakaGate_FalseSkull(BgHakaGate* this, GlobalContext* globalCtx);
static s16 sSkullOfTruthRotY = 0x100;
static u8 sPuzzleState = 1;
static u8 sBgPoEventPuzzleState = 1;
static f32 sStatueDistToPlayer = 0;
static s16 sStatueRotY;
@ -82,7 +82,7 @@ void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx) {
if (sSkullOfTruthRotY != 0x100) {
this->actionFunc = BgHakaGate_FalseSkull;
} else if (ABS(thisx->shape.rot.y) < 0x4000) {
if ((Rand_ZeroOne() * 3.0f) < sPuzzleState) {
if ((Rand_ZeroOne() * 3.0f) < sBgPoEventPuzzleState) {
this->vIsSkullOfTruth = true;
sSkullOfTruthRotY = thisx->shape.rot.y + 0x8000;
if (Flags_GetSwitch(globalCtx, this->switchFlag)) {
@ -91,7 +91,7 @@ void BgHakaGate_Init(Actor* thisx, GlobalContext* globalCtx) {
this->actionFunc = BgHakaGate_SkullOfTruth;
}
} else {
sPuzzleState++;
sBgPoEventPuzzleState++;
this->actionFunc = BgHakaGate_FalseSkull;
}
} else {
@ -141,7 +141,7 @@ void BgHakaGate_Destroy(Actor* thisx, GlobalContext* globalCtx) {
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
if (this->dyna.actor.params == BGHAKAGATE_STATUE) {
sSkullOfTruthRotY = 0x100;
sPuzzleState = 1;
sBgPoEventPuzzleState = 1;
}
}
@ -178,7 +178,7 @@ void BgHakaGate_StatueIdle(BgHakaGate* this, GlobalContext* globalCtx) {
}
}
} else {
if (sPuzzleState == SKULL_OF_TRUTH_FOUND) {
if (sBgPoEventPuzzleState == SKULL_OF_TRUTH_FOUND) {
this->actionFunc = BgHakaGate_StatueInactive;
} else {
this->vTimer = 0;
@ -192,7 +192,12 @@ void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx) {
s16 turnAngle;
this->vTurnRateDeg10++;
this->vTurnRateDeg10 = CLAMP_MAX(this->vTurnRateDeg10, 5);
if (CVar_GetS32("gFasterBlockPush", 0) != 0) {
this->vTurnRateDeg10 = 10;
CLAMP_MAX(this->vTurnRateDeg10, 5);
} else {
this->vTurnRateDeg10 = CLAMP_MAX(this->vTurnRateDeg10, 5);
}
turnFinished = Math_StepToS(&this->vTurnAngleDeg10, 600, this->vTurnRateDeg10);
turnAngle = this->vTurnAngleDeg10 * this->vTurnDirection;
this->dyna.actor.shape.rot.y = (this->vRotYDeg10 + turnAngle) * 0.1f * (0x10000 / 360.0f);
@ -212,7 +217,7 @@ void BgHakaGate_StatueTurn(BgHakaGate* this, GlobalContext* globalCtx) {
this->vRotYDeg10 = (this->vRotYDeg10 + turnAngle) % 3600;
this->vTurnRateDeg10 = 0;
this->vTurnAngleDeg10 = 0;
this->vTimer = 5;
this->vTimer = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 2 : 5;
this->actionFunc = BgHakaGate_StatueIdle;
this->dyna.unk_150 = 0.0f;
}
@ -238,7 +243,7 @@ void BgHakaGate_FloorClosed(BgHakaGate* this, GlobalContext* globalCtx) {
sStatueDistToPlayer = 0.0f;
if (ABS(yawDiff) < 0x80) {
Flags_SetSwitch(globalCtx, this->switchFlag);
sPuzzleState = SKULL_OF_TRUTH_FOUND;
sBgPoEventPuzzleState = SKULL_OF_TRUTH_FOUND;
this->actionFunc = BgHakaGate_DoNothing;
} else {
func_80078884(NA_SE_SY_ERROR);

View file

@ -28,7 +28,7 @@ void func_80880AE8(BgHakaTrap* this, GlobalContext* globalCtx);
void func_80880C0C(BgHakaTrap* this, GlobalContext* globalCtx);
void func_80880D68(BgHakaTrap* this);
static UNK_TYPE D_80880F30 = 0;
UNK_TYPE D_80880F30 = 0;
const ActorInit Bg_Haka_Trap_InitVars = {
ACTOR_BG_HAKA_TRAP,
@ -107,7 +107,7 @@ static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP),
};
static UNK_TYPE D_80881014 = 0;
UNK_TYPE D_80881014 = 0;
void BgHakaTrap_Init(Actor* thisx, GlobalContext* globalCtx) {
BgHakaTrap* this = (BgHakaTrap*)thisx;
s32 pad;

View file

@ -120,7 +120,7 @@ void func_8088B24C(BgHidanRock* this) {
this->actionFunc = func_8088B990;
}
static f32 D_8088BFC0 = 0.0f;
f32 D_8088BFC0 = 0.0f;
void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) {
f32 sp2C;
s32 temp_v1;
@ -137,7 +137,7 @@ void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) {
}
}
this->dyna.actor.speedXZ += 0.05f;
this->dyna.actor.speedXZ += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.05f;
this->dyna.actor.speedXZ = CLAMP_MAX(this->dyna.actor.speedXZ, 2.0f);
if (D_8088BFC0 > 0.0f) {
@ -156,7 +156,7 @@ void func_8088B268(BgHidanRock* this, GlobalContext* globalCtx) {
this->dyna.actor.home.pos.z = this->dyna.actor.world.pos.z;
D_8088BFC0 = 0.0f;
this->dyna.actor.speedXZ = 0.0f;
this->timer = 5;
this->timer = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 2 : 5;
}
func_8002F974(&this->dyna.actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG);

View file

@ -240,7 +240,8 @@ void BgHidanRsekizou_Draw(Actor* thisx, GlobalContext* globalCtx) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x14);
if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0) {
// Strange original code. Add || 1 for frame interpolation to get correct.
if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0 || 1) {
for (i = 3; i >= 0; i--) {
POLY_XLU_DISP = BgHidanRsekizou_DrawFireball(globalCtx, this, i, &mf, 0, POLY_XLU_DISP);
}

View file

@ -23,7 +23,7 @@ void BgJya1flift_SetupDoNothing(BgJya1flift* this);
void BgJya1flift_ResetMoveDelay(BgJya1flift* this);
void BgJya1flift_DelayMove(BgJya1flift* this, GlobalContext* globalCtx);
static u8 sIsSpawned = false;
static u8 sKankyoIsSpawned = false;
const ActorInit Bg_Jya_1flift_InitVars = {
ACTOR_BG_JYA_1FLIFT,
@ -94,9 +94,9 @@ void BgJya1flift_InitCollision(Actor* thisx, GlobalContext* globalCtx) {
void BgJya1flift_Init(Actor* thisx, GlobalContext* globalCtx) {
BgJya1flift* this = (BgJya1flift*)thisx;
// "1 F lift"
osSyncPrintf("(1Fリフト)(flag %d)(room %d)\n", sIsSpawned, globalCtx->roomCtx.curRoom.num);
osSyncPrintf("(1Fリフト)(flag %d)(room %d)\n", sKankyoIsSpawned, globalCtx->roomCtx.curRoom.num);
this->hasInitialized = false;
if (sIsSpawned) {
if (sKankyoIsSpawned) {
Actor_Kill(thisx);
return;
}
@ -109,7 +109,7 @@ void BgJya1flift_Init(Actor* thisx, GlobalContext* globalCtx) {
BgJya1flift_SetupWaitForSwitch(this);
}
thisx->room = -1;
sIsSpawned = true;
sKankyoIsSpawned = true;
this->hasInitialized = true;
}
@ -117,7 +117,7 @@ void BgJya1flift_Destroy(Actor* thisx, GlobalContext* globalCtx) {
BgJya1flift* this = (BgJya1flift*)thisx;
if (this->hasInitialized) {
sIsSpawned = false;
sKankyoIsSpawned = false;
Collider_DestroyCylinder(globalCtx, &this->collider);
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
}

View file

@ -14,7 +14,7 @@ void BgJyaBigmirror_Destroy(Actor* thisx, GlobalContext* globalCtx);
void BgJyaBigmirror_Update(Actor* thisx, GlobalContext* globalCtx);
void BgJyaBigmirror_Draw(Actor* thisx, GlobalContext* globalCtx);
static u8 sIsSpawned = false;
static u8 sKankyoIsSpawned = false;
const ActorInit Bg_Jya_Bigmirror_InitVars = {
ACTOR_BG_JYA_BIGMIRROR,
@ -176,7 +176,7 @@ void BgJyaBigmirror_HandleMirRay(Actor* thisx, GlobalContext* globalCtx) {
void BgJyaBigmirror_Init(Actor* thisx, GlobalContext* globalCtx) {
BgJyaBigmirror* this = (BgJyaBigmirror*)thisx;
if (sIsSpawned) {
if (sKankyoIsSpawned) {
Actor_Kill(&this->actor);
return;
}
@ -185,7 +185,7 @@ void BgJyaBigmirror_Init(Actor* thisx, GlobalContext* globalCtx) {
this->cobraInfo[0].rotY = sCobraSpawnData[0].initRotY;
this->cobraInfo[1].rotY = sCobraSpawnData[1].initRotY;
this->actor.room = -1;
sIsSpawned = true;
sKankyoIsSpawned = true;
this->spawned = true;
this->mirRayObjIndex = -1;
@ -197,7 +197,7 @@ void BgJyaBigmirror_Destroy(Actor* thisx, GlobalContext* globalCtx) {
BgJyaBigmirror* this = (BgJyaBigmirror*)thisx;
if (this->spawned) {
sIsSpawned = false;
sKankyoIsSpawned = false;
}
}

View file

@ -444,7 +444,7 @@ void func_80896950(BgJyaCobra* this, GlobalContext* globalCtx) {
if (this->dyna.unk_150 > 0.001f) {
this->unk_168++;
if (this->unk_168 >= 15) {
if (this->unk_168 >= CVar_GetS32("gFasterBlockPush", 0) != 0 ? 5 : 15) {
func_808969F8(this, globalCtx);
}
} else {
@ -484,9 +484,11 @@ void func_808969F8(BgJyaCobra* this, GlobalContext* globalCtx) {
void func_80896ABC(BgJyaCobra* this, GlobalContext* globalCtx) {
s16 temp_v0;
Player* player = GET_PLAYER(globalCtx);
if (CVar_GetS32("gFasterBlockPush", 0) != 0)
this->unk_16E = 150.0f;
temp_v0 = (s16)((this->unk_16C * 0x2000) + this->dyna.actor.home.rot.y) - this->dyna.actor.world.rot.y;
if (ABS(temp_v0) < 7424) {
if (ABS(temp_v0) < CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3712 : 7424) {
Math_StepToS(&this->unk_16E, 106, 4);
} else {
Math_StepToS(&this->unk_16E, 21, 10);

View file

@ -20,7 +20,7 @@ void BgJyaLift_DelayMove(BgJyaLift* this, GlobalContext* globalCtx);
void BgJyaLift_SetupMove(BgJyaLift* this);
void BgJyaLift_Move(BgJyaLift* this, GlobalContext* globalCtx);
static s16 sIsSpawned = false;
static s16 sKankyoIsSpawned = false;
const ActorInit Bg_Jya_Lift_InitVars = {
ACTOR_BG_JYA_LIFT,
@ -55,7 +55,7 @@ void BgJyaLift_Init(Actor* thisx, GlobalContext* globalCtx) {
BgJyaLift* this = (BgJyaLift*)thisx;
this->isSpawned = false;
if (sIsSpawned) {
if (sKankyoIsSpawned) {
Actor_Kill(thisx);
return;
}
@ -70,7 +70,7 @@ void BgJyaLift_Init(Actor* thisx, GlobalContext* globalCtx) {
BgJyaLift_SetInitPosY(this);
}
thisx->room = -1;
sIsSpawned = true;
sKankyoIsSpawned = true;
this->isSpawned = true;
}
@ -81,7 +81,7 @@ void BgJyaLift_Destroy(Actor* thisx, GlobalContext* globalCtx) {
// "Goddess Lift DT"
osSyncPrintf("女神リフト DT\n");
sIsSpawned = false;
sKankyoIsSpawned = false;
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
}
}

View file

@ -28,7 +28,7 @@ const ActorInit Bg_Menkuri_Eye_InitVars = {
(ActorResetFunc)BgMenkuriEye_Reset,
};
static s32 D_8089C1A0;
s32 D_8089C1A0;
static ColliderJntSphElementInit sJntSphElementsInit[1] = {
{

View file

@ -17,7 +17,7 @@ void func_808A2008(BgMoriElevator* this, GlobalContext* globalCtx);
void BgMoriElevator_MoveIntoGround(BgMoriElevator* this, GlobalContext* globalCtx);
void BgMoriElevator_MoveAboveGround(BgMoriElevator* this, GlobalContext* globalCtx);
static s16 sIsSpawned = false;
static s16 sKankyoIsSpawned = false;
const ActorInit Bg_Mori_Elevator_InitVars = {
ACTOR_BG_MORI_ELEVATOR,
@ -87,18 +87,18 @@ void BgMoriElevator_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
CollisionHeader* colHeader = NULL;
this->unk_172 = sIsSpawned;
this->unk_172 = sKankyoIsSpawned;
this->moriTexObjIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_MORI_TEX);
if (this->moriTexObjIndex < 0) {
Actor_Kill(thisx);
// "Forest Temple obj elevator Bank Danger!"
osSyncPrintf("Error : 森の神殿 obj elevator バンク危険!(%s %d)\n", "../z_bg_mori_elevator.c", 277);
} else {
switch (sIsSpawned) {
switch (sKankyoIsSpawned) {
case false:
// "Forest Temple elevator CT"
osSyncPrintf("森の神殿 elevator CT\n");
sIsSpawned = true;
sKankyoIsSpawned = true;
this->dyna.actor.room = -1;
Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
DynaPolyActor_Init(&this->dyna, DPM_PLAYER);
@ -120,7 +120,7 @@ void BgMoriElevator_Destroy(Actor* thisx, GlobalContext* globalCtx) {
// "Forest Temple elevator DT"
osSyncPrintf("森の神殿 elevator DT\n");
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
sIsSpawned = false;
sKankyoIsSpawned = false;
}
}

View file

@ -28,7 +28,7 @@ void BgMoriHineri_SpawnBossKeyChest(BgMoriHineri* this, GlobalContext* globalCtx
void BgMoriHineri_DoNothing(BgMoriHineri* this, GlobalContext* globalCtx);
void func_808A3D58(BgMoriHineri* this, GlobalContext* globalCtx);
static s16 sNextCamIdx = SUBCAM_NONE;
s16 sBgMoriHineriNextCamIdx = SUBCAM_NONE;
const ActorInit Bg_Mori_Hineri_InitVars = {
ACTOR_BG_MORI_HINERI,
@ -194,28 +194,28 @@ void func_808A3D58(BgMoriHineri* this, GlobalContext* globalCtx) {
OnePointCutscene_EndCutscene(globalCtx, mainCamChildIdx);
}
OnePointCutscene_Init(globalCtx, 3260, 40, &this->dyna.actor, MAIN_CAM);
sNextCamIdx = OnePointCutscene_Init(globalCtx, 3261, 40, &this->dyna.actor, MAIN_CAM);
sBgMoriHineriNextCamIdx = OnePointCutscene_Init(globalCtx, 3261, 40, &this->dyna.actor, MAIN_CAM);
}
}
void func_808A3E54(BgMoriHineri* this, GlobalContext* globalCtx) {
s8 objBankIndex;
if (globalCtx->activeCamera == sNextCamIdx) {
if (sNextCamIdx != MAIN_CAM) {
if (globalCtx->activeCamera == sBgMoriHineriNextCamIdx) {
if (sBgMoriHineriNextCamIdx != MAIN_CAM) {
objBankIndex = this->dyna.actor.objBankIndex;
this->dyna.actor.objBankIndex = this->moriHineriObjIdx;
this->moriHineriObjIdx = objBankIndex;
this->dyna.actor.params ^= 1;
sNextCamIdx = MAIN_CAM;
sBgMoriHineriNextCamIdx = MAIN_CAM;
func_80078884(NA_SE_SY_TRE_BOX_APPEAR);
} else {
this->dyna.actor.draw = NULL;
this->actionFunc = func_808A3D58;
sNextCamIdx = SUBCAM_NONE;
sBgMoriHineriNextCamIdx = SUBCAM_NONE;
}
}
if ((sNextCamIdx >= SUBCAM_FIRST) &&
if ((sBgMoriHineriNextCamIdx >= SUBCAM_FIRST) &&
((GET_ACTIVE_CAM(globalCtx)->eye.z - this->dyna.actor.world.pos.z) < 1100.0f)) {
func_8002F948(&this->dyna.actor, NA_SE_EV_FLOOR_ROLLING - SFX_FLAG);
}
@ -283,5 +283,5 @@ void BgMoriHineri_DrawHallAndRoom(Actor* thisx, GlobalContext* globalCtx) {
}
void BgMoriHineri_Reset() {
sNextCamIdx = SUBCAM_NONE;
sBgMoriHineriNextCamIdx = SUBCAM_NONE;
}

View file

@ -19,7 +19,7 @@ void BgMoriIdomizu_WaitForMoriTex(BgMoriIdomizu* this, GlobalContext* globalCtx)
void BgMoriIdomizu_SetupMain(BgMoriIdomizu* this);
void BgMoriIdomizu_Main(BgMoriIdomizu* this, GlobalContext* globalCtx);
static s16 sIsSpawned = false;
static s16 sKankyoIsSpawned = false;
const ActorInit Bg_Mori_Idomizu_InitVars = {
ACTOR_BG_MORI_IDOMIZU,
@ -50,7 +50,7 @@ void BgMoriIdomizu_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
BgMoriIdomizu* this = (BgMoriIdomizu*)thisx;
if (sIsSpawned) {
if (sKankyoIsSpawned) {
Actor_Kill(&this->actor);
return;
}
@ -76,7 +76,7 @@ void BgMoriIdomizu_Init(Actor* thisx, GlobalContext* globalCtx) {
return;
}
BgMoriIdomizu_SetupWaitForMoriTex(this);
sIsSpawned = true;
sKankyoIsSpawned = true;
this->isLoaded = true;
this->actor.room = -1;
// "Forest Temple well water"
@ -88,7 +88,7 @@ void BgMoriIdomizu_Destroy(Actor* thisx, GlobalContext* globalCtx) {
BgMoriIdomizu* this = (BgMoriIdomizu*)thisx;
if (this->isLoaded) {
sIsSpawned = false;
sKankyoIsSpawned = false;
}
}

View file

@ -94,7 +94,7 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, GlobalContext* globalCtx) {
if (this->dyna.unk_150 > 0.001f) {
this->timer++;
if ((this->timer > 28) && !Player_InCsMode(globalCtx)) {
if ((this->timer > CVar_GetS32("gFasterBlockPush", 0) != 0 ? 14 : 28) && !Player_InCsMode(globalCtx)) {
BgMoriKaitenkabe_SetupRotate(this);
func_8002DF54(globalCtx, &this->dyna.actor, 8);
Math_Vec3f_Copy(&this->lockedPlayerPos, &player->actor.world.pos);
@ -118,7 +118,7 @@ void BgMoriKaitenkabe_Wait(BgMoriKaitenkabe* this, GlobalContext* globalCtx) {
void BgMoriKaitenkabe_SetupRotate(BgMoriKaitenkabe* this) {
this->actionFunc = BgMoriKaitenkabe_Rotate;
this->rotSpeed = 0.0f;
this->rotSpeed = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.0f;
this->rotYdeg = 0.0f;
}

View file

@ -80,11 +80,11 @@ static ColliderTrisInit sTrisInit = {
sTrisElementsInit,
};
static u8 sBlocksAtRest = 0;
u8 sBgPoEventBlocksAtRest = 0;
static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f };
static u8 sPuzzleState;
u8 sBgPoEventPuzzleState;
void BgPoEvent_InitPaintings(BgPoEvent* this, GlobalContext* globalCtx) {
static s16 paintingPosX[] = { -1302, -866, 1421, 985 };
@ -142,10 +142,10 @@ void BgPoEvent_InitPaintings(BgPoEvent* this, GlobalContext* globalCtx) {
}
this->timer = 0;
if (this->type == 4) {
sPuzzleState = 0;
sBgPoEventPuzzleState = 0;
this->actionFunc = BgPoEvent_AmyWait;
} else {
sPuzzleState = (s32)(Rand_ZeroOne() * 3.0f) % 3;
sBgPoEventPuzzleState = (s32)(Rand_ZeroOne() * 3.0f) % 3;
this->actionFunc = BgPoEvent_PaintingEmpty;
}
}
@ -236,7 +236,7 @@ void BgPoEvent_Destroy(Actor* thisx, GlobalContext* globalCtx) {
void BgPoEvent_BlockWait(BgPoEvent* this, GlobalContext* globalCtx) {
this->dyna.actor.world.pos.y = 833.0f;
if (sPuzzleState == 0x3F) {
if (sBgPoEventPuzzleState == 0x3F) {
if (this->type == 1) {
OnePointCutscene_Init(globalCtx, 3150, 65, NULL, MAIN_CAM);
}
@ -244,14 +244,14 @@ void BgPoEvent_BlockWait(BgPoEvent* this, GlobalContext* globalCtx) {
this->actionFunc = BgPoEvent_BlockShake;
} else if (this->dyna.actor.xzDistToPlayer > 50.0f) {
if (this->type != 1) {
sPuzzleState |= (1 << this->index);
sBgPoEventPuzzleState |= (1 << this->index);
} else {
sPuzzleState |= 0x10;
sBgPoEventPuzzleState |= 0x10;
}
} else if (this->type != 1) {
sPuzzleState &= ~(1 << this->index);
sBgPoEventPuzzleState &= ~(1 << this->index);
} else {
sPuzzleState &= ~0x10;
sBgPoEventPuzzleState &= ~0x10;
}
}
@ -265,7 +265,7 @@ void BgPoEvent_BlockShake(BgPoEvent* this, GlobalContext* globalCtx) {
}
if (this->timer == 0) {
this->dyna.actor.world.pos.x = this->dyna.actor.home.pos.x;
sPuzzleState = 0;
sBgPoEventPuzzleState = 0;
this->timer = 60;
this->actionFunc = BgPoEvent_BlockFall;
}
@ -299,9 +299,9 @@ void BgPoEvent_CheckBlock(BgPoEvent* this) {
}
}
if ((phi_v1 == phi_a1) && ((phi_t0 - phi_a3) == 60)) {
sPuzzleState |= (1 << this->index);
sBgPoEventPuzzleState |= (1 << this->index);
} else {
sPuzzleState &= ~(1 << this->index);
sBgPoEventPuzzleState &= ~(1 << this->index);
}
}
@ -312,7 +312,7 @@ void BgPoEvent_BlockFall(BgPoEvent* this, GlobalContext* globalCtx) {
if (Math_StepToF(&this->dyna.actor.world.pos.y, 433.0f, this->dyna.actor.velocity.y)) {
this->dyna.actor.flags &= ~ACTOR_FLAG_5;
this->dyna.actor.velocity.y = 0.0f;
sBlocksAtRest++;
sBgPoEventBlocksAtRest++;
if (this->type != 1) {
BgPoEvent_CheckBlock(this);
} else {
@ -334,7 +334,7 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
Actor* amy;
if (sPuzzleState == 0xF) {
if (sBgPoEventPuzzleState == 0xF) {
this->actionFunc = BgPoEvent_BlockSolved;
if ((this->type == 0) && (this->index == 0)) {
amy =
@ -348,23 +348,23 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) {
gSaveContext.timer1State = 0xA;
}
} else {
if ((gSaveContext.timer1Value == 0) && (sBlocksAtRest == 5)) {
if ((gSaveContext.timer1Value == 0) && (sBgPoEventBlocksAtRest == 5)) {
player->stateFlags2 &= ~0x10;
sPuzzleState = 0x10;
sBlocksAtRest = 0;
sBgPoEventPuzzleState = 0x10;
sBgPoEventBlocksAtRest = 0;
}
if ((sPuzzleState == 0x40) || ((sPuzzleState == 0x10) && !Player_InCsMode(globalCtx))) {
if ((sBgPoEventPuzzleState == 0x40) || ((sBgPoEventPuzzleState == 0x10) && !Player_InCsMode(globalCtx))) {
this->dyna.actor.world.rot.z = this->dyna.actor.shape.rot.z;
this->actionFunc = BgPoEvent_BlockReset;
if (sPuzzleState == 0x10) {
sPuzzleState = 0x40;
if (sBgPoEventPuzzleState == 0x10) {
sBgPoEventPuzzleState = 0x40;
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_BLOCK_RISING);
func_8002DF54(globalCtx, &player->actor, 8);
}
} else if (this->dyna.unk_150 != 0.0f) {
if (this->direction == 0) {
if (func_800435D8(globalCtx, &this->dyna, 0x1E, 0x32, -0x14) != 0) {
sBlocksAtRest--;
sBgPoEventBlocksAtRest--;
this->direction = (this->dyna.unk_150 >= 0.0f) ? 1.0f : -1.0f;
this->actionFunc = BgPoEvent_BlockPush;
} else {
@ -382,16 +382,16 @@ void BgPoEvent_BlockIdle(BgPoEvent* this, GlobalContext* globalCtx) {
}
}
static f32 blockPushDist = 0.0f;
f32 sBgPoEventblockPushDist = 0.0f;
void BgPoEvent_BlockPush(BgPoEvent* this, GlobalContext* globalCtx) {
f32 displacement;
s32 blockStop;
Player* player = GET_PLAYER(globalCtx);
this->dyna.actor.speedXZ += 0.1f;
this->dyna.actor.speedXZ += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 0.5f : 0.1f;
this->dyna.actor.speedXZ = CLAMP_MAX(this->dyna.actor.speedXZ, 2.0f);
blockStop = Math_StepToF(&blockPushDist, 20.0f, this->dyna.actor.speedXZ);
displacement = this->direction * blockPushDist;
blockStop = Math_StepToF(&sBgPoEventblockPushDist, 20.0f, this->dyna.actor.speedXZ);
displacement = this->direction * sBgPoEventblockPushDist;
this->dyna.actor.world.pos.x = (Math_SinS(this->dyna.unk_158) * displacement) + this->dyna.actor.home.pos.x;
this->dyna.actor.world.pos.z = (Math_CosS(this->dyna.unk_158) * displacement) + this->dyna.actor.home.pos.z;
if (blockStop) {
@ -402,10 +402,10 @@ void BgPoEvent_BlockPush(BgPoEvent* this, GlobalContext* globalCtx) {
this->dyna.unk_150 = 0.0f;
this->dyna.actor.home.pos.x = this->dyna.actor.world.pos.x;
this->dyna.actor.home.pos.z = this->dyna.actor.world.pos.z;
blockPushDist = 0.0f;
sBgPoEventblockPushDist = 0.0f;
this->dyna.actor.speedXZ = 0.0f;
this->direction = 5;
sBlocksAtRest++;
this->direction = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3 : 5;
sBgPoEventBlocksAtRest++;
this->actionFunc = BgPoEvent_BlockIdle;
if (this->type == 1) {
return;
@ -428,7 +428,7 @@ void BgPoEvent_BlockReset(BgPoEvent* this, GlobalContext* globalCtx) {
this->index = (this->index + 1) % 4;
this->actionFunc = BgPoEvent_BlockFall;
sPuzzleState = 0;
sBgPoEventPuzzleState = 0;
if (this->type == 1) {
this->timer += 10;
this->timer = CLAMP_MAX(this->timer, 120);
@ -443,14 +443,14 @@ void BgPoEvent_BlockSolved(BgPoEvent* this, GlobalContext* globalCtx) {
player->stateFlags2 &= ~0x10;
}
if (Math_StepToF(&this->dyna.actor.world.pos.y, 369.0f, 2.0f)) {
sPuzzleState = 0x20;
sBgPoEventPuzzleState = 0x20;
Actor_Kill(&this->dyna.actor);
}
}
void BgPoEvent_AmyWait(BgPoEvent* this, GlobalContext* globalCtx) {
if (this->collider.base.acFlags & AC_HIT) {
sPuzzleState |= 0x20;
sBgPoEventPuzzleState |= 0x20;
this->timer = 5;
Actor_SetColorFilter(&this->dyna.actor, 0x4000, 0xFF, 0, 5);
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EN_PO_LAUGH2);
@ -461,12 +461,12 @@ void BgPoEvent_AmyWait(BgPoEvent* this, GlobalContext* globalCtx) {
void BgPoEvent_AmyPuzzle(BgPoEvent* this, GlobalContext* globalCtx) {
Vec3f pos;
if (sPuzzleState == 0xF) {
if (sBgPoEventPuzzleState == 0xF) {
pos.x = this->dyna.actor.world.pos.x - 5.0f;
pos.y = Rand_CenteredFloat(120.0f) + this->dyna.actor.world.pos.y;
pos.z = Rand_CenteredFloat(120.0f) + this->dyna.actor.world.pos.z;
EffectSsDeadDb_Spawn(globalCtx, &pos, &sZeroVec, &sZeroVec, 170, 0, 200, 255, 100, 170, 0, 255, 0, 1, 9, true);
} else if (sPuzzleState == 0x20) {
} else if (sBgPoEventPuzzleState == 0x20) {
Actor_Kill(&this->dyna.actor);
} else {
DECR(this->timer);
@ -476,14 +476,14 @@ void BgPoEvent_AmyPuzzle(BgPoEvent* this, GlobalContext* globalCtx) {
s32 BgPoEvent_NextPainting(BgPoEvent* this) {
if ((this->dyna.actor.parent != NULL) && (this->dyna.actor.child != NULL)) {
if (Rand_ZeroOne() < 0.5f) {
sPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index;
sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index;
} else {
sPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index;
sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index;
}
} else if (this->dyna.actor.parent != NULL) {
sPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index;
sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.parent)->index;
} else if (this->dyna.actor.child != NULL) {
sPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index;
sBgPoEventPuzzleState = ((BgPoEvent*)this->dyna.actor.child)->index;
} else {
return false;
}
@ -491,7 +491,7 @@ s32 BgPoEvent_NextPainting(BgPoEvent* this) {
}
void BgPoEvent_PaintingEmpty(BgPoEvent* this, GlobalContext* globalCtx) {
if (sPuzzleState == this->index) {
if (sBgPoEventPuzzleState == this->index) {
this->timer = 255;
this->actionFunc = BgPoEvent_PaintingAppear;
}
@ -636,7 +636,7 @@ void BgPoEvent_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
void BgPoEvent_Reset(void) {
sBlocksAtRest = 0;
sPuzzleState = 0;
blockPushDist = 0.0f;
sBgPoEventBlocksAtRest = 0;
sBgPoEventPuzzleState = 0;
sBgPoEventblockPushDist = 0.0f;
}

View file

@ -45,7 +45,7 @@ static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP),
};
static u32 D_808A9508 = 0;
u32 D_808A9508 = 0;
void BgRelayObjects_Init(Actor* thisx, GlobalContext* globalCtx) {
BgRelayObjects* this = (BgRelayObjects*)thisx;
s32 pad;

View file

@ -260,7 +260,7 @@ void func_808B4194(BgSpot15Rrbox* this, GlobalContext* globalCtx) {
s32 approxFResult;
Actor* actor = &this->dyna.actor;
this->unk_174 += 0.5f;
this->unk_174 += CVar_GetS32("gFasterBlockPush", 0) != 0 ? 1.0f : 0.5f;
this->unk_174 = CLAMP_MAX(this->unk_174, 2.0f);
@ -294,7 +294,7 @@ void func_808B4194(BgSpot15Rrbox* this, GlobalContext* globalCtx) {
this->dyna.unk_150 = 0.0f;
this->unk_178 = 0.0f;
this->unk_174 = 0.0f;
this->unk_168 = 10;
this->unk_168 = CVar_GetS32("gFasterBlockPush", 0) != 0 ? 3 : 10;
func_808B4084(this, globalCtx);
}
Audio_PlayActorSound2(actor, NA_SE_EV_ROCK_SLIDE - SFX_FLAG);

View file

@ -84,7 +84,7 @@ void func_808B7710(Actor* thisx, GlobalContext* globalCtx) {
this->dyna.actor.colChkInfo.mass = MASS_IMMOVABLE;
}
static s16 D_808B85D0 = 0;
s16 D_808B85D0 = 0;
void func_808B7770(BgSpot18Basket* this, GlobalContext* globalCtx, f32 arg2) {
Vec3f acceleration;
Vec3f velocity;

View file

@ -12,6 +12,8 @@
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
@ -78,6 +80,7 @@ void BossFd_SpawnEmber(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, V
effect->scale = scale / 1000.0f;
effect->alpha = 255;
effect->timer1 = (s16)Rand_ZeroFloat(10.0f);
effect->epoch++;
break;
}
}
@ -95,6 +98,7 @@ void BossFd_SpawnDebris(BossFdEffect* effect, Vec3f* position, Vec3f* velocity,
effect->scale = scale / 1000.0f;
effect->vFdFxRotX = Rand_ZeroFloat(100.0f);
effect->vFdFxRotY = Rand_ZeroFloat(100.0f);
effect->epoch++;
break;
}
}
@ -111,6 +115,7 @@ void BossFd_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Ve
effect->accel = *acceleration;
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->epoch++;
break;
}
}
@ -136,6 +141,7 @@ void BossFd_SpawnFireBreath(BossFdEffect* effect, Vec3f* position, Vec3f* veloci
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->kbAngle = kbAngle;
effect->epoch++;
break;
}
}
@ -1522,6 +1528,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_EMBER) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberMaterialDL);
@ -1536,6 +1543,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4046),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1543,6 +1551,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_DEBRIS) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisMaterialDL);
@ -1557,6 +1566,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4068),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1564,6 +1574,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_DUST) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL);
@ -1580,6 +1591,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2]));
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1587,6 +1599,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_FIRE_BREATH) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL);
@ -1603,6 +1616,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2]));
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1610,6 +1624,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_SKULL_PIECE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceMaterialDL);
@ -1624,6 +1639,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4192),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceModelDL);
FrameInterpolation_RecordCloseChild();
}
}

View file

@ -49,6 +49,7 @@ typedef struct {
/* 0x30 */ f32 scale;
/* 0x34 */ f32 bFdFxFloat1;
/* 0x38 */ f32 bFdFxFloat2;
u32 epoch;
} BossFdEffect; // size = 0x3C
#define BOSSFD_EFFECT_COUNT 180

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