mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-05-25 15:35:18 -04:00
Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 242a35c3a0 | |||
| f57cae120d | |||
| 177194ca5a | |||
| 3218b2def2 | |||
| 8a76a3aa83 | |||
| 5771e6cd1f | |||
| e14fcf92d2 | |||
| 612700c2ab | |||
| 4e08eca1b9 | |||
| 44f963e310 | |||
| 544460d909 | |||
| f6c310ae84 | |||
| 9b020c0986 | |||
| 3617b2e5b7 | |||
| 72dcf3466b | |||
| 0aab836d1f | |||
| 9fe7839f9a | |||
| 22efba8cd7 | |||
| 1e2b60c6e0 | |||
| 279553e6b3 | |||
| 0df5060541 | |||
| 47f206825d | |||
| 569013535e | |||
| 589e25948e | |||
| 170a9103f9 | |||
| ec4cee787c | |||
| 7a75fe8411 | |||
| 6d6c1c8c32 | |||
| 21ae445548 | |||
| 5c21bb0b8a | |||
| 6b6cfa5ebe | |||
| 402d7dd3b7 | |||
| 0629140357 | |||
| beb414eb0a | |||
| 2422c94f6b | |||
| e5bc5188e7 | |||
| eb222f3998 | |||
| a1cb921042 | |||
| e79bd2587d | |||
| cb5faa1ac8 | |||
| 37f31116b3 | |||
| 52a976489b | |||
| 643a98244b | |||
| a58705eaf4 | |||
| a9e7faa180 | |||
| 4291ec8252 | |||
| 2a9d93dd65 | |||
| 33539be458 | |||
| 6e417713b9 | |||
| 1b9962dfc2 | |||
| 1b9ab52e35 | |||
| 261db2c3e1 | |||
| 7964bde063 | |||
| 1e178c4497 | |||
| c0ad43e509 | |||
| d6dbaacb03 | |||
| d9662ab63b | |||
| 52b182d4dc | |||
| 12737143c7 | |||
| a335aba987 | |||
| edceb2d460 | |||
| 7c8be2153c | |||
| 32ad0ab4b8 | |||
| a5f7478b99 | |||
| 207d38e476 | |||
| c36e9cc32d | |||
| 745444fa90 | |||
| 750ae907c2 | |||
| 2e4a19c0ee | |||
| f665326a67 | |||
| 418d0f8e6c | |||
| 13b8f26435 | |||
| ba5d5c25d1 | |||
| 6be1f28d7b | |||
| 15a6568607 | |||
| 1fe862515d | |||
| 6eef813e5d | |||
| 76c9895432 | |||
| 048207eb7d | |||
| 170b9c1224 | |||
| 1e7cf8858f | |||
| 4b10a887a6 | |||
| ff3548a1b6 | |||
| fda198db76 | |||
| 7f06087cef | |||
| 6ae28273d1 | |||
| 5b2a50cac2 | |||
| 1e258318a1 | |||
| 156de816fb | |||
| ba13e6b2c4 | |||
| ecb10e6ac2 | |||
| ab104623a7 | |||
| f42f86e3ef | |||
| 85bccab1bb | |||
| 5ce4e75bd2 | |||
| 4d8c70fb1f | |||
| 17b1a8e7fd | |||
| a95b1067b4 | |||
| a6120811d5 |
@@ -12,7 +12,15 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract assets
|
||||
- name: Extract assets (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
cp ../../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
|
||||
cmake --no-warn-unused-cli -S . -B build-cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE:STRING=Release
|
||||
cmake --build build-cmake --target ExtractAssets --config Release
|
||||
7z a assets.zip soh/assets
|
||||
- name: Extract assets (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
cp ../../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
|
||||
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
|
||||
@@ -85,7 +93,17 @@ jobs:
|
||||
readme.txt
|
||||
build-linux:
|
||||
needs: extract-assets
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
gcc: 10
|
||||
archive-suffix: compatibility
|
||||
- os: ubuntu-22.04
|
||||
gcc: 12
|
||||
archive-suffix: performance
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -97,13 +115,13 @@ jobs:
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-ccache
|
||||
key: ${{ matrix.os }}-ccache
|
||||
- name: Install latest SDL
|
||||
run: |
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
wget https://www.libsdl.org/release/SDL2-2.24.1.tar.gz
|
||||
tar -xzf SDL2-2.24.1.tar.gz
|
||||
cd SDL2-2.24.1
|
||||
wget https://www.libsdl.org/release/SDL2-2.26.1.tar.gz
|
||||
tar -xzf SDL2-2.26.1.tar.gz
|
||||
cd SDL2-2.26.1
|
||||
./configure
|
||||
make -j 10
|
||||
sudo make install
|
||||
@@ -135,12 +153,12 @@ jobs:
|
||||
mv README.md readme.txt
|
||||
mv build-cmake/*.appimage soh.appimage
|
||||
env:
|
||||
CC: gcc-10
|
||||
CXX: g++-10
|
||||
CC: gcc-${{ matrix.gcc }}
|
||||
CXX: g++-${{ matrix.gcc }}
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: soh-linux
|
||||
name: soh-linux-${{ matrix.archive-suffix }}
|
||||
path: |
|
||||
soh.appimage
|
||||
readme.txt
|
||||
|
||||
+15
@@ -22,6 +22,9 @@ You can also find the v142 toolset by searching through the individual component
|
||||
While you're there, you can also install Python 3 and Git if needed.
|
||||
|
||||
1. Clone the Ship of Harkinian repository
|
||||
|
||||
_Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule init`` after cloning to pull in the libultraship submodule!_
|
||||
|
||||
2. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice
|
||||
|
||||
_Note: Instructions assume using powershell_
|
||||
@@ -215,3 +218,15 @@ Use the `extract_assets.py` script file to run the exporter using any of the fol
|
||||
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.
|
||||
|
||||
## Getting CI to work on your fork
|
||||
|
||||
The CI works via [Github Actions](https://github.com/features/actions) where we mostly make use of machines hosted by Github; except for the very first step of the CI process called "Extract assets". This steps extracts assets from the game file and generates an "assets" folder in `soh/`.
|
||||
|
||||
To get this step working on your fork, you'll need to add a machine to your own repository as a self-hosted runner via "Settings > Actions > Runners" in your repository settings. Make sure to add the 'asset-builder' tag to your newly added runner to assign it to run this step. To setup your runner as a service read the docs [here](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=linux).
|
||||
|
||||
### Runner on Windows
|
||||
You'll have to enable the ability to run unsigned scripts through PowerShell. To do this, open Powershell as administrator and run `set-executionpolicy remotesigned`. Most dependencies get installed as part of the CI process. You will also need to seperately install 7z and add it to the PATH so `7z` can be run as a command. [Chocolatey](https://chocolatey.org/) or other package managers can be used to install it easily.
|
||||
|
||||
### Runner on UNIX systems
|
||||
If you're on macOS or Linux take a look at `macports-deps.txt` or `apt-deps.txt` to see the dependencies expected to be on your machine.
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||
|
||||
project(Ship LANGUAGES C CXX
|
||||
VERSION 5.1.3)
|
||||
set(PROJECT_BUILD_NAME "BRADLEY DELTA" CACHE STRING "")
|
||||
VERSION 6.0.0)
|
||||
set(PROJECT_BUILD_NAME "GIBBS ALFA" CACHE STRING "")
|
||||
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
||||
|
||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "AnimationExporter.h"
|
||||
#include <Animation.h>
|
||||
#include <resource/type/Animation.h>
|
||||
|
||||
void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZAnimation* anim = (ZAnimation*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::Animation);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_Animation);
|
||||
|
||||
ZNormalAnimation* normalAnim = dynamic_cast<ZNormalAnimation*>(anim);
|
||||
ZCurveAnimation* curveAnim = dynamic_cast<ZCurveAnimation*>(anim);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "AudioExporter.h"
|
||||
#include "Main.h"
|
||||
#include <Animation.h>
|
||||
#include <Utils/MemoryStream.h>
|
||||
#include <Globals.h>
|
||||
#include <Utils/File.h>
|
||||
@@ -30,7 +29,7 @@ void OTRExporter_Audio::WriteSampleEntryReference(ZAudio* audio, SampleEntry* en
|
||||
|
||||
void OTRExporter_Audio::WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer)
|
||||
{
|
||||
WriteHeader(nullptr, "", writer, Ship::ResourceType::AudioSample, Ship::Version::Rachael);
|
||||
WriteHeader(nullptr, "", writer, Ship::ResourceType::SOH_AudioSample, Ship::Version::Rachael);
|
||||
|
||||
writer->Write(entry->codec);
|
||||
writer->Write(entry->medium);
|
||||
@@ -82,7 +81,7 @@ void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
||||
{
|
||||
ZAudio* audio = (ZAudio*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::Audio, Ship::Version::Rachael);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_Audio, Ship::Version::Rachael);
|
||||
|
||||
// Write Samples as individual files
|
||||
for (auto pair : audio->samples)
|
||||
@@ -115,7 +114,7 @@ void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
||||
MemoryStream* fntStream = new MemoryStream();
|
||||
BinaryWriter fntWriter = BinaryWriter(fntStream);
|
||||
|
||||
WriteHeader(nullptr, "", &fntWriter, Ship::ResourceType::AudioSoundFont, Ship::Version::Rachael);
|
||||
WriteHeader(nullptr, "", &fntWriter, Ship::ResourceType::SOH_AudioSoundFont, Ship::Version::Rachael);
|
||||
|
||||
fntWriter.Write((uint32_t)i);
|
||||
fntWriter.Write(audio->soundFontTable[i].medium);
|
||||
@@ -174,7 +173,7 @@ void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
||||
MemoryStream* seqStream = new MemoryStream();
|
||||
BinaryWriter seqWriter = BinaryWriter(seqStream);
|
||||
|
||||
WriteHeader(nullptr, "", &seqWriter, Ship::ResourceType::AudioSequence, Ship::Version::Rachael);
|
||||
WriteHeader(nullptr, "", &seqWriter, Ship::ResourceType::SOH_AudioSequence, Ship::Version::Rachael);
|
||||
|
||||
seqWriter.Write((uint32_t)seq.size());
|
||||
seqWriter.Write(seq.data(), seq.size());
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
void OTRExporter_Background::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZBackground* bg = (ZBackground*)res;
|
||||
|
||||
WriteHeader(bg, outPath, writer, Ship::ResourceType::SOH_Background);
|
||||
|
||||
writer->Write((uint32_t)bg->GetRawDataSize());
|
||||
|
||||
auto data = bg->parent->GetRawData();
|
||||
writer->Write((char*)data.data() + bg->GetRawDataIndex(), bg->GetRawDataSize());
|
||||
|
||||
@@ -158,16 +158,19 @@ endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/ZAPD/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/tinyxml2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/include
|
||||
# TODO: these should no longer be necessary if we were to link against LUS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource/types
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/spdlog/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/graphic/Fast3D/U64
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/Mercury
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/tinyxml2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/StormLib/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/spdlog/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/nlohmann-json/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../soh/soh
|
||||
.
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "CollisionExporter.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
void OTRExporter_Collision::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZCollisionHeader* col = (ZCollisionHeader*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::CollisionHeader);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_CollisionHeader);
|
||||
|
||||
writer->Write(col->absMinX);
|
||||
writer->Write(col->absMinY);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "CutsceneExporter.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZCutscene* cs = (ZCutscene*)res;
|
||||
|
||||
WriteHeader(cs, outPath, writer, Ship::ResourceType::Cutscene);
|
||||
WriteHeader(cs, outPath, writer, Ship::ResourceType::SOH_Cutscene);
|
||||
|
||||
//writer->Write((uint32_t)cs->commands.size() + 2 + 2);
|
||||
writer->Write((uint32_t)0);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <Utils/BitConverter.h>
|
||||
#include "StrHash64/StrHash64.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "PR/ultra64/gbi.h"
|
||||
#include <libultraship/libultra/gbi.h>
|
||||
#include <Globals.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "ZArray.h"
|
||||
//#include "OTRExporter.h"
|
||||
#include <Utils/BinaryWriter.h>
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include "VersionInfo.h"
|
||||
|
||||
class OTRExporter : public ZResourceExporter
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <Archive.h>
|
||||
#include "Main.h"
|
||||
#include "BackgroundExporter.h"
|
||||
#include "TextureExporter.h"
|
||||
#include "RoomExporter.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Archive.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern std::shared_ptr<Ship::Archive> otrArchive;
|
||||
extern std::map<std::string, std::vector<char>> files;
|
||||
|
||||
@@ -5,7 +5,7 @@ void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
||||
{
|
||||
ZPath* path = (ZPath*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::Path);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_Path);
|
||||
|
||||
writer->Write((uint32_t)path->pathways.size());
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "PlayerAnimationExporter.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
void OTRExporter_PlayerAnimationExporter::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZPlayerAnimationData* anim = (ZPlayerAnimationData*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::PlayerAnimation);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_PlayerAnimation);
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <ZRoom/Commands/SetAlternateHeaders.h>
|
||||
#include "CollisionExporter.h"
|
||||
#include "DisplayListExporter.h"
|
||||
#include "Resource.h"
|
||||
#include <libultraship/bridge.h>
|
||||
#include <Globals.h>
|
||||
#include <ZRoom/Commands/SetExitList.h>
|
||||
#include <ZRoom/Commands/SetPathways.h>
|
||||
@@ -39,7 +39,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
||||
{
|
||||
ZRoom* room = (ZRoom*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::Room);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_Room);
|
||||
|
||||
writer->Write((uint32_t)room->commands.size());
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "SkeletonExporter.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <Globals.h>
|
||||
#include "DisplayListExporter.h"
|
||||
|
||||
@@ -7,7 +7,7 @@ void OTRExporter_Skeleton::Save(ZResource* res, const fs::path& outPath, BinaryW
|
||||
{
|
||||
ZSkeleton* skel = (ZSkeleton*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::Skeleton);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_Skeleton);
|
||||
|
||||
writer->Write((uint8_t)skel->type);
|
||||
writer->Write((uint8_t)skel->limbType);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "SkeletonLimbExporter.h"
|
||||
#include "DisplayListExporter.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <Globals.h>
|
||||
|
||||
void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZLimb* limb = (ZLimb*)res;
|
||||
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SkeletonLimb);
|
||||
WriteHeader(res, outPath, writer, Ship::ResourceType::SOH_SkeletonLimb);
|
||||
|
||||
writer->Write((uint8_t)limb->type);
|
||||
writer->Write((uint8_t)limb->skinSegmentType);
|
||||
|
||||
@@ -5,7 +5,7 @@ void OTRExporter_Text::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
||||
{
|
||||
ZText* txt = (ZText*)res;
|
||||
|
||||
WriteHeader(txt, outPath, writer, Ship::ResourceType::Text);
|
||||
WriteHeader(txt, outPath, writer, Ship::ResourceType::SOH_Text);
|
||||
|
||||
writer->Write((uint32_t)txt->messages.size());
|
||||
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
#include "VersionInfo.h"
|
||||
#include <Resource.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
std::map<Ship::ResourceType, uint32_t> resourceVersions;
|
||||
|
||||
void InitVersionInfo()
|
||||
{
|
||||
resourceVersions = std::map<Ship::ResourceType, uint32_t> {
|
||||
{ Ship::ResourceType::Animation, 0 },
|
||||
{ Ship::ResourceType::Model, 0 },
|
||||
{ Ship::ResourceType::SOH_Animation, 0 },
|
||||
{ Ship::ResourceType::Texture, 0 },
|
||||
{ Ship::ResourceType::Material, 0 },
|
||||
{ Ship::ResourceType::PlayerAnimation, 0 },
|
||||
{ Ship::ResourceType::SOH_PlayerAnimation, 0 },
|
||||
{ Ship::ResourceType::DisplayList, 0 },
|
||||
{ Ship::ResourceType::Room, 0 },
|
||||
{ Ship::ResourceType::CollisionHeader, 0 },
|
||||
{ Ship::ResourceType::Skeleton, 0 },
|
||||
{ Ship::ResourceType::SkeletonLimb, 0 },
|
||||
{ Ship::ResourceType::SOH_Room, 0 },
|
||||
{ Ship::ResourceType::SOH_CollisionHeader, 0 },
|
||||
{ Ship::ResourceType::SOH_Skeleton, 0 },
|
||||
{ Ship::ResourceType::SOH_SkeletonLimb, 0 },
|
||||
{ Ship::ResourceType::Matrix, 0 },
|
||||
{ Ship::ResourceType::Path, 0 },
|
||||
{ Ship::ResourceType::SOH_Path, 0 },
|
||||
{ Ship::ResourceType::Vertex, 0 },
|
||||
{ Ship::ResourceType::Cutscene, 0 },
|
||||
{ Ship::ResourceType::SOH_Cutscene, 0 },
|
||||
{ Ship::ResourceType::Array, 0 },
|
||||
{ Ship::ResourceType::Text, 0 },
|
||||
{ Ship::ResourceType::SOH_Text, 0 },
|
||||
{ Ship::ResourceType::Blob, 0 },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "VtxExporter.h"
|
||||
#include "Resource.h"
|
||||
#include <libultraship/bridge.h>
|
||||
#include "VersionInfo.h"
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define Z64CUTSCENE_H
|
||||
|
||||
#if 0
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u16 entrance; // entrance index upon which the cutscene should trigger
|
||||
|
||||
@@ -32,17 +32,16 @@ def main():
|
||||
parser.add_argument("-z", "--zapd", help="Path to ZAPD executable", dest="zapd_exe", type=str)
|
||||
parser.add_argument("rom", help="Path to the rom", type=str, nargs="?")
|
||||
parser.add_argument("--non-interactive", help="Runs the script non-interactively for use in build scripts.", dest="non_interactive", action="store_true")
|
||||
parser.add_argument("-v", "--verbose", help="Display rom's header checksums and their corresponding xml folder", dest="verbose", action="store_true")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
rom_paths = [ args.rom ] if args.rom else rom_chooser.chooseROM(args.non_interactive)
|
||||
for rom_path in rom_paths:
|
||||
rom = Z64Rom(rom_path)
|
||||
|
||||
roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive)
|
||||
for rom in roms:
|
||||
if (os.path.exists("Extract")):
|
||||
shutil.rmtree("Extract")
|
||||
|
||||
BuildOTR("../soh/assets/xml/" + rom.version.xml_ver + "/", rom_path, zapd_exe=args.zapd_exe)
|
||||
BuildOTR("../soh/assets/xml/" + rom.version.xml_ver + "/", rom.file_path, zapd_exe=args.zapd_exe)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -2,12 +2,13 @@ import os, sys, glob
|
||||
|
||||
from rom_info import Z64Rom
|
||||
|
||||
def chooseROM(non_interactive=False):
|
||||
def chooseROM(verbose=False, non_interactive=False):
|
||||
roms = []
|
||||
|
||||
for file in glob.glob("*.z64"):
|
||||
if Z64Rom.isValidRom(file):
|
||||
roms.append(file)
|
||||
rom = Z64Rom(file)
|
||||
if rom.is_valid:
|
||||
roms.append(rom)
|
||||
|
||||
if not (roms):
|
||||
print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr)
|
||||
@@ -21,23 +22,28 @@ def chooseROM(non_interactive=False):
|
||||
foundMq = False
|
||||
foundOot = False
|
||||
for rom in roms:
|
||||
isMq = Z64Rom.isMqRom(rom)
|
||||
if isMq and not foundMq:
|
||||
if rom.isMq and not foundMq:
|
||||
romsToExtract.append(rom)
|
||||
foundMq = True
|
||||
elif not isMq and not foundOot:
|
||||
elif not rom.isMq and not foundOot:
|
||||
romsToExtract.append(rom)
|
||||
foundOot = True
|
||||
return romsToExtract
|
||||
|
||||
print(str(len(roms))+ " roms found, please select one by pressing 1-"+str(len(roms)))
|
||||
print(f"{len(roms)} roms found, please select one by pressing 1-{len(roms)}")
|
||||
print()
|
||||
|
||||
for i in range(len(roms)):
|
||||
print(str(i+1)+ ". " + roms[i])
|
||||
print(f"[{i+1:>2d}] {roms[i].file_path}")
|
||||
if verbose:
|
||||
print(f" Checksum: {roms[i].checksum.value}, Version XML: {roms[i].version.xml_ver}")
|
||||
print()
|
||||
|
||||
while(1):
|
||||
try:
|
||||
selection = int(input())
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
except:
|
||||
print("Bad input. Try again with the number keys.")
|
||||
continue
|
||||
|
||||
@@ -59,7 +59,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
.
|
||||
)
|
||||
|
||||
INSTALL(TARGETS OTRGui DESTINATION . COMPONENT ship)
|
||||
INSTALL(TARGETS OTRGui DESTINATION . COMPONENT ship OPTIONAL)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/assets
|
||||
DESTINATION .
|
||||
COMPONENT ship
|
||||
|
||||
@@ -4,6 +4,10 @@ A PC port of OoT allowing you to enjoy the game with modern controls, widescreen
|
||||
|
||||
The Ship does not include assets and as such requires a prior copy of the game to play.
|
||||
|
||||
## Discord
|
||||
|
||||
Official Discord: https://discord.com/invite/BtBmd55HVH
|
||||
|
||||
## Quick Start (Windows)
|
||||
|
||||
1) Download The Ship of Harkinian from [Discord](https://discord.com/invite/BtBmd55HVH).
|
||||
@@ -128,32 +132,19 @@ Once you have prepared your sequences folder:
|
||||
|
||||
Assuming you have done everything correctly, boot up SoH and open up the SFX Editor (In the Enhancements dropdown). You should now be able to swap out any of the in game sequences/fanfares for the sequences added in your newly generated OTR file. If you have any trouble with this process please reach out in the support section of the Discord
|
||||
|
||||
## Take The Survey
|
||||
Want to use cartridge readers in tandem with the OTRGui?
|
||||
Take [this survey](https://retroarchopenhardware.com/survey.php) to increase chances of this becoming reality.
|
||||
|
||||
## Discord
|
||||
|
||||
Official Discord: https://discord.com/invite/BtBmd55HVH
|
||||
|
||||
## Building The Ship of Harkinian
|
||||
|
||||
Refer to the [building instructions](BUILDING.md) to compile SoH.
|
||||
|
||||
## Getting CI to work on your fork
|
||||
|
||||
The CI works via [Github Actions](https://github.com/features/actions) where we mostly make use of machines hosted by Github; except for the very first step of the CI process called "Extract assets". This steps extracts assets from the game file and generates an "assets" folder in `soh/`.
|
||||
|
||||
To get this step working on your fork, you'll need to add a machine to your own repository as a self-hosted runner via "Settings > Actions > Runners" in your repository settings. If you're on macOS or Linux take a look at `macports-deps.txt` or `apt-deps.txt` to see the dependencies expected to be on your machine. For Windows, deps get installed as part of the CI process. To setup your runner as a service read the docs [here](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service?platform=linux).
|
||||
|
||||
|
||||
## Troubleshooting The Exporter
|
||||
- Confirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe
|
||||
- Confirm that `zapd.exe` exists in the `/assets/extractor` folder
|
||||
|
||||
## Nightly Builds
|
||||
Nightly builds of Ship of Harkinian are available here: [Windows](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-windows.zip), [macOS](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-mac.zip), [Linux](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux.zip), [Switch](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-switch.zip), [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip)
|
||||
Nightly builds of Ship of Harkinian are available here: [Windows](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-windows.zip), [macOS](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-mac.zip), [Linux (compatibility*)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-compatiblity.zip), [Linux (performance*)](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux-performance.zip), [Switch](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-switch.zip), [Wii U](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-wiiu.zip)
|
||||
|
||||
_*compatibility: compatible with most Linux distributions, but may not be as performant as the perf build._\
|
||||
_*performance: requires glibc 2.35 or newer, but will be more performant than the compat build._
|
||||
|
||||
## Take The Survey
|
||||
Want to use cartridge readers in tandem with the OTRGui?
|
||||
Take [this survey](https://retroarchopenhardware.com/survey.php) to increase chances of this becoming reality.
|
||||
|
||||
## The Harbour Masters Are...
|
||||
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/HarbourMasters/ZAPDTR.git
|
||||
branch = master
|
||||
commit = a53a53ea4216b926253dde2c942ae0ca6e2f2ccd
|
||||
parent = f52a2a6406eb1bbd2b631c65923d879a83983ccb
|
||||
commit = e23b125d89bd973998d2eb00896bcbaf1b53a329
|
||||
parent = 17b1a8e7fd5517f9232e531da0fed6ef80a87f04
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
cmdver = 0.4.3
|
||||
|
||||
@@ -336,6 +336,8 @@ find_package(PNG REQUIRED)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/tinyxml2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../ZAPDTR/lib/libgfxd
|
||||
${PNG_PNG_INCLUDE_DIR}/
|
||||
|
||||
@@ -221,7 +221,7 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename)
|
||||
// Check for repeated attributes.
|
||||
if (offsetXml != nullptr)
|
||||
{
|
||||
rawDataIndex = strtol(StringHelper::Split(offsetXml, "0x")[1].c_str(), NULL, 16);
|
||||
rawDataIndex = strtol(StringHelper::Split(std::string(offsetXml), "0x")[1].c_str(), NULL, 16);
|
||||
|
||||
if (offsetSet.find(offsetXml) != offsetSet.end())
|
||||
{
|
||||
@@ -831,7 +831,7 @@ void ZFile::GenerateSourceHeaderFiles()
|
||||
xmlPath = StringHelper::Replace(xmlPath, "\\", "/");
|
||||
auto pathList = StringHelper::Split(xmlPath, "/");
|
||||
std::string outPath = "";
|
||||
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
outPath += pathList[i] + "/";
|
||||
|
||||
@@ -1192,7 +1192,7 @@ std::string ZFile::ProcessTextureIntersections([[maybe_unused]] const std::strin
|
||||
|
||||
if (declarations.find(currentOffset) != declarations.end())
|
||||
declarations.at(currentOffset)->size = currentTex->GetRawDataSize();
|
||||
|
||||
|
||||
currentTex->DeclareVar(GetName(), "");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Declaration.h"
|
||||
#include "Utils/BinaryWriter.h"
|
||||
#include "Utils/Directory.h"
|
||||
#include <Utils/BinaryWriter.h>
|
||||
#include <Utils/Directory.h>
|
||||
#include "tinyxml2.h"
|
||||
|
||||
#define SEGMENT_SCENE 2
|
||||
|
||||
+1
-1
Submodule libultraship updated: df3a6dd292...d3e42d7f4e
+246
-2
@@ -123,7 +123,7 @@ set(Header_Files__include
|
||||
#"include/stdbool_n64.h"
|
||||
#"include/stddef_n64.h"
|
||||
#"include/stdlib_n64.h"
|
||||
"include/ultra64.h"
|
||||
# "include/ultra64.h"
|
||||
"include/unk.h"
|
||||
"include/variables.h"
|
||||
"include/vt.h"
|
||||
@@ -182,6 +182,7 @@ set(Header_Files__soh__Enhancements__sfx_editor
|
||||
source_group("Header Files\\soh\\Enhancements\\sfx-editor" FILES ${Header_Files__soh__Enhancements__sfx_editor})
|
||||
|
||||
set(Header_Files__soh__Enhancements__debugger
|
||||
"soh/Enhancements/debugger/dlViewer.h"
|
||||
"soh/Enhancements/debugger/actorViewer.h"
|
||||
"soh/Enhancements/debugger/colViewer.h"
|
||||
"soh/Enhancements/debugger/debugger.h"
|
||||
@@ -257,6 +258,12 @@ set(Header_Files__soh__Enhancements__item_tables
|
||||
|
||||
source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables})
|
||||
|
||||
set(Header_Files__soh__Enhancements__game_interactor
|
||||
"soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
"soh/Enhancements/game-interactor/GameInteractionEffect.h"
|
||||
)
|
||||
source_group("Header Files\\soh\\Enhancements\\game-interactor" FILES ${Header_Files__soh__Enhancements__game_interactor})
|
||||
|
||||
if (BUILD_CROWD_CONTROL)
|
||||
set(Header_Files__soh__Enhancements__crowd_control
|
||||
"soh/Enhancements/crowd-control/CrowdControl.h"
|
||||
@@ -269,6 +276,8 @@ set(Source_Files__soh
|
||||
"soh/OTRAudio.h"
|
||||
"soh/OTRGlobals.cpp"
|
||||
"soh/OTRGlobals.h"
|
||||
"soh/mixer.c"
|
||||
"soh/mixer.h"
|
||||
"soh/SaveManager.h"
|
||||
"soh/SaveManager.cpp"
|
||||
"soh/frame_interpolation.h"
|
||||
@@ -288,6 +297,194 @@ set(Source_Files__soh
|
||||
)
|
||||
source_group("Source Files\\soh" FILES ${Source_Files__soh})
|
||||
|
||||
set(Header_Files__soh__resourceTypes
|
||||
"soh/resource/type/Animation.h"
|
||||
"soh/resource/type/AudioSample.h"
|
||||
"soh/resource/type/AudioSequence.h"
|
||||
"soh/resource/type/AudioSoundFont.h"
|
||||
"soh/resource/type/CollisionHeader.h"
|
||||
"soh/resource/type/Cutscene.h"
|
||||
"soh/resource/type/Path.h"
|
||||
"soh/resource/type/PlayerAnimation.h"
|
||||
"soh/resource/type/Scene.h"
|
||||
"soh/resource/type/Skeleton.h"
|
||||
"soh/resource/type/SkeletonLimb.h"
|
||||
"soh/resource/type/Text.h"
|
||||
"soh/resource/type/Background.h"
|
||||
)
|
||||
source_group("Header Files\\soh\\resource\\type" FILES ${Header_Files__soh__resourceTypes})
|
||||
|
||||
set(Source_Files__soh__resourceTypes
|
||||
"soh/resource/type/Animation.cpp"
|
||||
"soh/resource/type/AudioSample.cpp"
|
||||
"soh/resource/type/AudioSequence.cpp"
|
||||
"soh/resource/type/AudioSoundFont.cpp"
|
||||
"soh/resource/type/CollisionHeader.cpp"
|
||||
"soh/resource/type/Cutscene.cpp"
|
||||
"soh/resource/type/Path.cpp"
|
||||
"soh/resource/type/PlayerAnimation.cpp"
|
||||
"soh/resource/type/Scene.cpp"
|
||||
"soh/resource/type/Skeleton.cpp"
|
||||
"soh/resource/type/SkeletonLimb.cpp"
|
||||
"soh/resource/type/Text.cpp"
|
||||
"soh/resource/type/Background.cpp"
|
||||
)
|
||||
source_group("Source Files\\soh\\resource\\type" FILES ${Source_Files__soh__resourceTypes})
|
||||
|
||||
set(Header_Files__soh__resourceFactories
|
||||
"soh/resource/importer/AnimationFactory.h"
|
||||
"soh/resource/importer/AudioSampleFactory.h"
|
||||
"soh/resource/importer/AudioSequenceFactory.h"
|
||||
"soh/resource/importer/AudioSoundFontFactory.h"
|
||||
"soh/resource/importer/CollisionHeaderFactory.h"
|
||||
"soh/resource/importer/CutsceneFactory.h"
|
||||
"soh/resource/importer/PathFactory.h"
|
||||
"soh/resource/importer/PlayerAnimationFactory.h"
|
||||
"soh/resource/importer/SceneFactory.h"
|
||||
"soh/resource/importer/SkeletonFactory.h"
|
||||
"soh/resource/importer/SkeletonLimbFactory.h"
|
||||
"soh/resource/importer/TextFactory.h"
|
||||
"soh/resource/importer/BackgroundFactory.h"
|
||||
)
|
||||
source_group("Header Files\\soh\\resource\\importer" FILES ${Header_Files__soh__resourceFactories})
|
||||
|
||||
set(Source_Files__soh__resourceFactories
|
||||
"soh/resource/importer/AnimationFactory.cpp"
|
||||
"soh/resource/importer/AudioSampleFactory.cpp"
|
||||
"soh/resource/importer/AudioSequenceFactory.cpp"
|
||||
"soh/resource/importer/AudioSoundFontFactory.cpp"
|
||||
"soh/resource/importer/CollisionHeaderFactory.cpp"
|
||||
"soh/resource/importer/CutsceneFactory.cpp"
|
||||
"soh/resource/importer/PathFactory.cpp"
|
||||
"soh/resource/importer/PlayerAnimationFactory.cpp"
|
||||
"soh/resource/importer/SceneFactory.cpp"
|
||||
"soh/resource/importer/SkeletonFactory.cpp"
|
||||
"soh/resource/importer/SkeletonLimbFactory.cpp"
|
||||
"soh/resource/importer/TextFactory.cpp"
|
||||
"soh/resource/importer/BackgroundFactory.cpp"
|
||||
)
|
||||
source_group("Source Files\\soh\\resource\\importer" FILES ${Source_Files__soh__resourceFactories})
|
||||
|
||||
set(Header_Files__soh__scenecommandTypes
|
||||
"soh/resource/type/scenecommand/EndMarker.h"
|
||||
"soh/resource/type/scenecommand/RomFile.h"
|
||||
"soh/resource/type/scenecommand/SceneCommand.h"
|
||||
"soh/resource/type/scenecommand/SetActorList.h"
|
||||
"soh/resource/type/scenecommand/SetAlternateHeaders.h"
|
||||
"soh/resource/type/scenecommand/SetCameraSettings.h"
|
||||
"soh/resource/type/scenecommand/SetCollisionHeader.h"
|
||||
"soh/resource/type/scenecommand/SetCsCamera.h"
|
||||
"soh/resource/type/scenecommand/SetCutscenes.h"
|
||||
"soh/resource/type/scenecommand/SetEchoSettings.h"
|
||||
"soh/resource/type/scenecommand/SetEntranceList.h"
|
||||
"soh/resource/type/scenecommand/SetExitList.h"
|
||||
"soh/resource/type/scenecommand/SetLightingSettings.h"
|
||||
"soh/resource/type/scenecommand/SetLightList.h"
|
||||
"soh/resource/type/scenecommand/SetMesh.h"
|
||||
"soh/resource/type/scenecommand/SetObjectList.h"
|
||||
"soh/resource/type/scenecommand/SetPathways.h"
|
||||
"soh/resource/type/scenecommand/SetRoomBehavior.h"
|
||||
"soh/resource/type/scenecommand/SetRoomList.h"
|
||||
"soh/resource/type/scenecommand/SetSkyboxModifier.h"
|
||||
"soh/resource/type/scenecommand/SetSkyboxSettings.h"
|
||||
"soh/resource/type/scenecommand/SetSoundSettings.h"
|
||||
"soh/resource/type/scenecommand/SetSpecialObjects.h"
|
||||
"soh/resource/type/scenecommand/SetStartPositionList.h"
|
||||
"soh/resource/type/scenecommand/SetTimeSettings.h"
|
||||
"soh/resource/type/scenecommand/SetTransitionActorList.h"
|
||||
"soh/resource/type/scenecommand/SetWindSettings.h"
|
||||
)
|
||||
source_group("Header Files\\soh\\resource\\type\\scenecommand" FILES ${Header_Files__soh__scenecommandTypes})
|
||||
|
||||
set(Source_Files__soh__scenecommandTypes
|
||||
"soh/resource/type/scenecommand/EndMarker.cpp"
|
||||
"soh/resource/type/scenecommand/SetActorList.cpp"
|
||||
"soh/resource/type/scenecommand/SetAlternateHeaders.cpp"
|
||||
"soh/resource/type/scenecommand/SetCameraSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetCollisionHeader.cpp"
|
||||
"soh/resource/type/scenecommand/SetCsCamera.cpp"
|
||||
"soh/resource/type/scenecommand/SetCutscenes.cpp"
|
||||
"soh/resource/type/scenecommand/SetEchoSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetEntranceList.cpp"
|
||||
"soh/resource/type/scenecommand/SetExitList.cpp"
|
||||
"soh/resource/type/scenecommand/SetLightingSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetLightList.cpp"
|
||||
"soh/resource/type/scenecommand/SetMesh.cpp"
|
||||
"soh/resource/type/scenecommand/SetObjectList.cpp"
|
||||
"soh/resource/type/scenecommand/SetPathways.cpp"
|
||||
"soh/resource/type/scenecommand/SetRoomBehavior.cpp"
|
||||
"soh/resource/type/scenecommand/SetRoomList.cpp"
|
||||
"soh/resource/type/scenecommand/SetSkyboxModifier.cpp"
|
||||
"soh/resource/type/scenecommand/SetSkyboxSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetSoundSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetSpecialObjects.cpp"
|
||||
"soh/resource/type/scenecommand/SetStartPositionList.cpp"
|
||||
"soh/resource/type/scenecommand/SetTimeSettings.cpp"
|
||||
"soh/resource/type/scenecommand/SetTransitionActorList.cpp"
|
||||
"soh/resource/type/scenecommand/SetWindSettings.cpp"
|
||||
)
|
||||
source_group("Source Files\\soh\\resource\\type\\scenecommand" FILES ${Source_Files__soh__scenecommandTypes})
|
||||
|
||||
set(Header_Files__soh__scenecommandFactories
|
||||
"soh/resource/importer/scenecommand/EndMarkerFactory.h"
|
||||
"soh/resource/importer/scenecommand/SceneCommandFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetActorListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetAlternateHeadersFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetCameraSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetCollisionHeaderFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetCsCameraFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetCutscenesFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetEchoSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetEntranceListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetExitListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetLightingSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetLightListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetMeshFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetObjectListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetPathwaysFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetRoomBehaviorFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetRoomListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetSkyboxModifierFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetSkyboxSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetSoundSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetSpecialObjectsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetStartPositionListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetTimeSettingsFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetTransitionActorListFactory.h"
|
||||
"soh/resource/importer/scenecommand/SetWindSettingsFactory.h"
|
||||
)
|
||||
source_group("Header Files\\soh\\resource\\importer\\scenecommand" FILES ${Header_Files__soh__scenecommandFactories})
|
||||
|
||||
set(Source_Files__soh__scenecommandFactories
|
||||
"soh/resource/importer/scenecommand/EndMarkerFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SceneCommandFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetActorListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetAlternateHeadersFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetCameraSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetCollisionHeaderFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetCsCameraFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetCutscenesFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetEchoSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetEntranceListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetExitListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetLightingSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetLightListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetMeshFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetObjectListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetPathwaysFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetRoomBehaviorFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetRoomListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetSkyboxModifierFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetSkyboxSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetSoundSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetSpecialObjectsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetStartPositionListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetTimeSettingsFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetTransitionActorListFactory.cpp"
|
||||
"soh/resource/importer/scenecommand/SetWindSettingsFactory.cpp"
|
||||
)
|
||||
source_group("Source Files\\soh\\resource\\importer\\scenecommand" FILES ${Source_Files__soh__scenecommandFactories})
|
||||
|
||||
set(Source_Files__soh__Enhancements
|
||||
"soh/Enhancements/bootcommands.c"
|
||||
"soh/Enhancements/debugconsole.cpp"
|
||||
@@ -315,6 +512,7 @@ set(Source_Files__soh__Enhancements__sfx_editor
|
||||
source_group("Source Files\\soh\\Enhancements\\sfx-editor" FILES ${Source_Files__soh__Enhancements__sfx_editor})
|
||||
|
||||
set(Source_Files__soh__Enhancements__debugger
|
||||
"soh/Enhancements/debugger/dlViewer.cpp"
|
||||
"soh/Enhancements/debugger/actorViewer.cpp"
|
||||
"soh/Enhancements/debugger/colViewer.cpp"
|
||||
"soh/Enhancements/debugger/debugger.cpp"
|
||||
@@ -411,6 +609,14 @@ set(Source_Files__soh__Enhancements__item_tables
|
||||
|
||||
source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables})
|
||||
|
||||
set(Source_Files__soh__Enhancements__game_interactor
|
||||
"soh/Enhancements/game-interactor/GameInteractor.cpp"
|
||||
"soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp"
|
||||
"soh/Enhancements/game-interactor/GameInteractor_State.cpp"
|
||||
"soh/Enhancements/game-interactor/GameInteractionEffect.cpp"
|
||||
)
|
||||
source_group("Source Files\\soh\\Enhancements\\game-interactor" FILES ${Source_Files__soh__Enhancements__game_interactor})
|
||||
|
||||
if (BUILD_CROWD_CONTROL)
|
||||
set(Source_Files__soh__Enhancements__crowd_control
|
||||
"soh/Enhancements/crowd-control/CrowdControl.cpp"
|
||||
@@ -1629,6 +1835,7 @@ set(ALL_FILES
|
||||
${Header_Files__soh__Enhancements__randomizer__3drando}
|
||||
${Header_Files__soh__Enhancements__item_tables}
|
||||
${Header_Files__soh__Enhancements__custom_message}
|
||||
${Header_Files__soh__Enhancements__game_interactor}
|
||||
${Header_Files__soh__Enhancements__crowd_control}
|
||||
${Source_Files__soh}
|
||||
${Source_Files__soh__Enhancements}
|
||||
@@ -1642,6 +1849,7 @@ set(ALL_FILES
|
||||
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
|
||||
${Source_Files__soh__Enhancements__item_tables}
|
||||
${Source_Files__soh__Enhancements__custom_message}
|
||||
${Source_Files__soh__Enhancements__game_interactor}
|
||||
${Source_Files__soh__Enhancements__crowd_control}
|
||||
${Source_Files__src__boot}
|
||||
${Source_Files__src__buffers}
|
||||
@@ -1655,6 +1863,14 @@ set(ALL_FILES
|
||||
${Source_Files__src__overlays__gamestates__ovl_title}
|
||||
${Source_Files__src__overlays__misc__ovl_kaleido_scope}
|
||||
${Source_Files__src__overlays__misc__ovl_map_mark_data}
|
||||
${Header_Files__soh__resourceTypes}
|
||||
${Source_Files__soh__resourceTypes}
|
||||
${Header_Files__soh__resourceFactories}
|
||||
${Source_Files__soh__resourceFactories}
|
||||
${Header_Files__soh__scenecommandTypes}
|
||||
${Source_Files__soh__scenecommandTypes}
|
||||
${Source_Files__soh__scenecommandFactories}
|
||||
${Header_Files__soh__scenecommandFactories}
|
||||
)
|
||||
|
||||
################################################################################
|
||||
@@ -1719,6 +1935,32 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
|
||||
endif()
|
||||
################################################################################
|
||||
# Find/download Boost
|
||||
################################################################################
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Boost
|
||||
URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz
|
||||
URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6
|
||||
SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it)
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change
|
||||
)
|
||||
|
||||
set(Boost_NO_BOOST_CMAKE false)
|
||||
set(BOOST_INCLUDEDIR ${FETCHCONTENT_BASE_DIR}/boost-src) # Location where FetchContent stores the source
|
||||
message("Searching for Boost installation")
|
||||
find_package(Boost)
|
||||
|
||||
if (NOT ${Boost_FOUND})
|
||||
message("Boost not found. Downloading now...")
|
||||
FetchContent_MakeAvailable(Boost)
|
||||
message("Boost downloaded to " ${FETCHCONTENT_BASE_DIR}/boost-src)
|
||||
set(BOOST-INCLUDE ${FETCHCONTENT_BASE_DIR}/boost-src)
|
||||
else()
|
||||
message("Boost found in " ${Boost_INCLUDE_DIRS})
|
||||
set(BOOST-INCLUDE ${Boost_INCLUDE_DIRS})
|
||||
endif()
|
||||
################################################################################
|
||||
# Compile definitions
|
||||
################################################################################
|
||||
find_package(SDL2)
|
||||
@@ -1741,7 +1983,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/misc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource/types
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource/type
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/audio
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern/Mercury
|
||||
@@ -1752,8 +1994,10 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic/Fast3D/U64/PR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD/resource/type
|
||||
${SDL2-INCLUDE}
|
||||
${SDL2-NET-INCLUDE}
|
||||
${BOOST-INCLUDE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/assets/
|
||||
.
|
||||
)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// 32 bit implementation based off of Boost hash
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_MIX_32_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_MIX_32_HPP
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<uint32_t Bits> struct hash_mix_impl_32;
|
||||
|
||||
// hash_mix for 32 bit
|
||||
//
|
||||
// We use the "best xmxmx" implementation from
|
||||
// https://github.com/skeeto/hash-prospector/issues/19
|
||||
|
||||
template<> struct hash_mix_impl_32<32>
|
||||
{
|
||||
inline static boost::uint32_t fn( boost::uint32_t x )
|
||||
{
|
||||
boost::uint32_t const m1 = 0x21f0aaad;
|
||||
boost::uint32_t const m2 = 0x735a2d97;
|
||||
|
||||
x ^= x >> 16;
|
||||
x *= m1;
|
||||
x ^= x >> 15;
|
||||
x *= m2;
|
||||
x ^= x >> 15;
|
||||
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
inline uint32_t hash_mix_32( uint32_t v )
|
||||
{
|
||||
return hash_mix_impl_32<32>::fn( v );
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_MIX_32_HPP
|
||||
@@ -0,0 +1,117 @@
|
||||
// 32 bit implementation based off of Boost hash
|
||||
// Only implementing 32 bit version of char based ranges
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
|
||||
|
||||
#include <boost_custom/container_hash/hash_fwd_32.hpp>
|
||||
#include <boost_custom/container_hash/version.hpp>
|
||||
|
||||
#if BOOST_VERSION_HAS_HASH_RANGE
|
||||
#include <boost/container_hash/detail/hash_range.hpp>
|
||||
#else
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <iterator>
|
||||
#endif // #if BOOST_VERSION_HAS_HASH_RANGE
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
#if !BOOST_VERSION_HAS_HASH_RANGE
|
||||
|
||||
template<class T> struct is_char_type: public boost::false_type {};
|
||||
|
||||
#if CHAR_BIT == 8
|
||||
|
||||
template<> struct is_char_type<char>: public boost::true_type {};
|
||||
template<> struct is_char_type<signed char>: public boost::true_type {};
|
||||
template<> struct is_char_type<unsigned char>: public boost::true_type {};
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
template<> struct is_char_type<char8_t>: public boost::true_type {};
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||
template<> struct is_char_type<std::byte>: public boost::true_type {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
||||
|
||||
template<class It>
|
||||
inline typename boost::enable_if_<
|
||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||
is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value,
|
||||
std::size_t>::type
|
||||
hash_range_32( uint32_t seed, It first, It last )
|
||||
{
|
||||
std::size_t n = static_cast<std::size_t>( last - first );
|
||||
|
||||
for( ; n >= 4; first += 4, n -= 4 )
|
||||
{
|
||||
// clang 5+, gcc 5+ figure out this pattern and use a single mov on x86
|
||||
// gcc on s390x and power BE even knows how to use load-reverse
|
||||
|
||||
boost::uint32_t w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[2] ) ) << 16 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[3] ) ) << 24;
|
||||
|
||||
hash_combine_32( seed, w );
|
||||
}
|
||||
|
||||
{
|
||||
// add a trailing suffix byte of 0x01 because otherwise sequences of
|
||||
// trailing zeroes are indistinguishable from end of string
|
||||
|
||||
boost::uint32_t w = 0x01u;
|
||||
|
||||
switch( n )
|
||||
{
|
||||
case 1:
|
||||
|
||||
w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
||||
0x0100u;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
||||
0x010000u;
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
w =
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[0] ) ) |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[1] ) ) << 8 |
|
||||
static_cast<boost::uint32_t>( static_cast<unsigned char>( first[2] ) ) << 16 |
|
||||
0x01000000u;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
hash_combine_32( seed, w );
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
|
||||
@@ -0,0 +1,172 @@
|
||||
// 32 bit implementation based off of Boost hash
|
||||
// Only implementing 32 bit versions integral and string based hashes
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_HASH_32_HPP
|
||||
#define BOOST_FUNCTIONAL_HASH_HASH_32_HPP
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost_custom/container_hash/hash_fwd_32.hpp>
|
||||
#include <boost_custom/container_hash/detail/hash_mix_32.hpp>
|
||||
#include <boost_custom/container_hash/detail/hash_range_32.hpp>
|
||||
#include <boost_custom/container_hash/version.hpp>
|
||||
|
||||
#if !BOOST_VERSION_HAS_HASH_RANGE
|
||||
#include <boost/type_traits/is_unsigned.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(__GNUC__, < 3) \
|
||||
&& !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
|
||||
#define BOOST_HASH_CHAR_TRAITS string_char_traits
|
||||
#else
|
||||
#define BOOST_HASH_CHAR_TRAITS char_traits
|
||||
#endif
|
||||
|
||||
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//
|
||||
// boost::hash_value
|
||||
//
|
||||
|
||||
// integral types
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template<class T,
|
||||
bool bigger_than_size_t = (sizeof(T) > sizeof(uint32_t)),
|
||||
bool is_unsigned = boost::is_unsigned<T>::value,
|
||||
std::size_t size_t_bits = sizeof(uint32_t) * CHAR_BIT,
|
||||
std::size_t type_bits = sizeof(T) * CHAR_BIT>
|
||||
struct hash_integral_impl_32;
|
||||
|
||||
template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl_32<T, false, is_unsigned, size_t_bits, type_bits>
|
||||
{
|
||||
static uint32_t fn( T v )
|
||||
{
|
||||
return static_cast<uint32_t>( v );
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl_32<T, true, false, size_t_bits, type_bits>
|
||||
{
|
||||
static uint32_t fn( T v )
|
||||
{
|
||||
typedef typename boost::make_unsigned<T>::type U;
|
||||
|
||||
if( v >= 0 )
|
||||
{
|
||||
return hash_integral_impl_32<U>::fn( static_cast<U>( v ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ~hash_integral_impl_32<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct hash_integral_impl_32<T, true, true, 32, 64>
|
||||
{
|
||||
static uint32_t fn( T v )
|
||||
{
|
||||
uint32_t seed = 0;
|
||||
|
||||
seed = static_cast<uint32_t>( v >> 32 ) + hash_detail::hash_mix_32( seed );
|
||||
seed = static_cast<uint32_t>( v ) + hash_detail::hash_mix_32( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct hash_integral_impl_32<T, true, true, 32, 128>
|
||||
{
|
||||
static uint32_t fn( T v )
|
||||
{
|
||||
uint32_t seed = 0;
|
||||
|
||||
seed = static_cast<uint32_t>( v >> 96 ) + hash_detail::hash_mix_32( seed );
|
||||
seed = static_cast<uint32_t>( v >> 64 ) + hash_detail::hash_mix_32( seed );
|
||||
seed = static_cast<uint32_t>( v >> 32 ) + hash_detail::hash_mix_32( seed );
|
||||
seed = static_cast<uint32_t>( v ) + hash_detail::hash_mix_32( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
template <typename T>
|
||||
typename boost::enable_if_<boost::is_integral<T>::value, uint32_t>::type
|
||||
hash_value_32( T v )
|
||||
{
|
||||
return hash_detail::hash_integral_impl_32<T>::fn( v );
|
||||
}
|
||||
|
||||
// contiguous ranges (string, vector, array)
|
||||
#if BOOST_VERSION_HAS_HASH_RANGE
|
||||
template <typename T>
|
||||
typename boost::enable_if_<container_hash::is_contiguous_range<T>::value, uint32_t>::type
|
||||
hash_value_32( T const& v )
|
||||
{
|
||||
return boost::hash_range_32( v.data(), v.data() + v.size() );
|
||||
}
|
||||
#else
|
||||
template <class Ch, class A>
|
||||
inline uint32_t hash_value_32(
|
||||
std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const& v)
|
||||
{
|
||||
return boost::hash_range_32( v.data(), v.data() + v.size() );
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost::hash_combine
|
||||
//
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine_32( uint32_t& seed, T const& v )
|
||||
{
|
||||
seed = boost::hash_detail::hash_mix_32( seed + 0x9e3779b9 + boost::hash_32<T>()( v ) );
|
||||
}
|
||||
|
||||
//
|
||||
// boost::hash_range
|
||||
//
|
||||
|
||||
template <class It>
|
||||
inline void hash_range_32( uint32_t& seed, It first, It last )
|
||||
{
|
||||
seed = hash_detail::hash_range_32( seed, first, last );
|
||||
}
|
||||
|
||||
template <class It>
|
||||
inline uint32_t hash_range_32( It first, It last )
|
||||
{
|
||||
uint32_t seed = 0;
|
||||
|
||||
hash_range_32( seed, first, last );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
//
|
||||
// boost::hash
|
||||
//
|
||||
|
||||
template <class T> struct hash_32
|
||||
{
|
||||
typedef T argument_type;
|
||||
typedef uint32_t result_type;
|
||||
|
||||
uint32_t operator()( T const& val ) const
|
||||
{
|
||||
return hash_value_32( val );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#undef BOOST_HASH_CHAR_TRAITS
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_32_HPP
|
||||
@@ -0,0 +1,25 @@
|
||||
// 32 bit implementation based off of Boost hash
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_FWD_32_HPP
|
||||
#define BOOST_FUNCTIONAL_HASH_FWD_32_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
template<class T> struct hash_32;
|
||||
|
||||
template<class T> void hash_combine_32( uint32_t& seed, T const& v );
|
||||
|
||||
template<class It> void hash_range_32( uint32_t&, It, It );
|
||||
template<class It> uint32_t hash_range_32( It, It );
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_32_HPP
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef BOOST_CONTAINER_HASH_VERSION_HPP
|
||||
#define BOOST_CONTAINER_HASH_VERSION_HPP
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#define BOOST_VERSION_HAS_HASH_RANGE ((BOOST_VERSION / 100 % 1000) >= 81)
|
||||
|
||||
#endif // #ifndef BOOST_CONTAINER_HASH_VERSION_HPP
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#ifndef FP_H
|
||||
#define FP_H
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
extern f32 qNaN0x3FFFFF;
|
||||
extern f32 qNaN0x10000;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define FUNCTIONS_H
|
||||
|
||||
#include "z64.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define this thisx
|
||||
@@ -97,8 +98,6 @@ void LogUtils_CheckValidPointer(const char* exp, void* ptr, const char* file, s3
|
||||
void LogUtils_LogThreadId(const char* name, s32 line);
|
||||
void LogUtils_HungupThread(const char* name, s32 line);
|
||||
void LogUtils_ResetHungup(void);
|
||||
s32 vsprintf(char* dst, const char* fmt, va_list args);
|
||||
s32 sprintf(char* dst, const char* fmt, ...);
|
||||
void __osPiCreateAccessQueue(void);
|
||||
void __osPiGetAccess(void);
|
||||
void __osPiRelAccess(void);
|
||||
@@ -532,10 +531,10 @@ void func_8003424C(PlayState* play, Vec3f* arg1);
|
||||
void Actor_SetColorFilter(Actor* actor, s16 colorFlag, s16 colorIntensityMax, s16 xluFlag, s16 duration);
|
||||
Hilite* func_800342EC(Vec3f* object, PlayState* play);
|
||||
Hilite* func_8003435C(Vec3f* object, PlayState* play);
|
||||
s32 func_800343CC(PlayState* play, Actor* actor, s16* arg2, f32 interactRange,
|
||||
u16 (*unkFunc1)(PlayState*, Actor*), s16 (*unkFunc2)(PlayState*, Actor*));
|
||||
s16 func_800347E8(s16 arg0);
|
||||
void func_80034A14(Actor* actor, struct_80034A14_arg1* arg1, s16 arg2, s16 arg3);
|
||||
s32 Npc_UpdateTalking(PlayState* play, Actor* actor, s16* talkState, f32 interactRange,
|
||||
NpcGetTextIdFunc getTextId, NpcUpdateTalkStateFunc updateTalkState);
|
||||
s16 Npc_GetTrackingPresetMaxPlayerYaw(s16 presetIndex);
|
||||
void Npc_TrackPoint(Actor* actor, NpcInteractInfo* interactInfo, s16 presetIndex, s16 trackingMode);
|
||||
void func_80034BA0(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw,
|
||||
PostLimbDraw postLimbDraw, Actor* actor, s16 alpha);
|
||||
void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw,
|
||||
@@ -1080,8 +1079,6 @@ void Interface_SetDoAction(PlayState* play, u16 action);
|
||||
void Interface_SetNaviCall(PlayState* play, u16 naviCallState);
|
||||
void Interface_LoadActionLabelB(PlayState* play, u16 action);
|
||||
s32 Health_ChangeBy(PlayState* play, s16 healthChange);
|
||||
void Health_GiveHearts(s16 hearts);
|
||||
void Health_RemoveHearts(s16 hearts);
|
||||
void Rupees_ChangeBy(s16 rupeeChange);
|
||||
void Inventory_ChangeAmmo(s16 item, s16 ammoChange);
|
||||
void Magic_Fill(PlayState* play);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/Enhancements/gameconsole.h"
|
||||
#include "soh/Enhancements/gameplaystats.h"
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
#define _AudioseqSegmentRomStart "Audioseq"
|
||||
#define _AudiobankSegmentRomStart "Audiobank"
|
||||
@@ -38,4 +38,8 @@
|
||||
#define _z_select_staticSegmentRomStart 0
|
||||
#define _z_select_staticSegmentRomEnd 0
|
||||
|
||||
// TODO: POSIX/BSD Bug, this is a hack to fix the build compilation on any BSD system (Switch, Wii-U, Vita, etc)
|
||||
// <sys/types.h> defines quad as a macro, which conflicts with the quad parameter on z_collision_check.c
|
||||
#undef quad
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef MATH_H
|
||||
#define MATH_H
|
||||
|
||||
#include "ultra64/types.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
#define M_PI 3.14159265358979323846f
|
||||
#define M_SQRT2 1.41421356237309504880f
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef STDLIB_H
|
||||
#define STDLIB_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
@@ -300,9 +300,9 @@ extern GraphicsContext* __gfxCtx;
|
||||
// #endregion
|
||||
|
||||
// #region SOH [Enhancements]
|
||||
#define CHECK_EQUIPMENT_AGE(i, j) (CVar_GetS32("gTimelessEquipment", 0) || (gEquipAgeReqs[i][j] == 9) || (gEquipAgeReqs[i][j] == ((void)0, gSaveContext.linkAge)))
|
||||
#define CHECK_SLOT_AGE(slotIndex) (CVar_GetS32("gTimelessEquipment", 0) || (gSlotAgeReqs[slotIndex] == 9) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge))
|
||||
#define CHECK_ITEM_AGE(itemIndex) (CVar_GetS32("gTimelessEquipment", 0) || (gItemAgeReqs[itemIndex] == 9) || (gItemAgeReqs[itemIndex] == gSaveContext.linkAge))
|
||||
#define CHECK_EQUIPMENT_AGE(i, j) (CVarGetInteger("gTimelessEquipment", 0) || (gEquipAgeReqs[i][j] == 9) || (gEquipAgeReqs[i][j] == ((void)0, gSaveContext.linkAge)))
|
||||
#define CHECK_SLOT_AGE(slotIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gSlotAgeReqs[slotIndex] == 9) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge))
|
||||
#define CHECK_ITEM_AGE(itemIndex) (CVarGetInteger("gTimelessEquipment", 0) || (gItemAgeReqs[itemIndex] == 9) || (gItemAgeReqs[itemIndex] == gSaveContext.linkAge))
|
||||
|
||||
#define DPAD_ITEM(button) ((gSaveContext.buttonStatus[(button) + 5] != BTN_DISABLED) \
|
||||
? gSaveContext.equips.buttonItems[(button) + 4] \
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef ULTRA64_H
|
||||
#define ULTRA64_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "ultra64/types.h"
|
||||
#include "unk.h"
|
||||
|
||||
#include "libc/stdarg.h"
|
||||
#include "libc/stdbool.h"
|
||||
#include "libc/stddef.h"
|
||||
#include "libc/stdlib.h"
|
||||
#include "libc/math.h"
|
||||
|
||||
#include "ultra64/exception.h"
|
||||
#include "ultra64/rcp.h"
|
||||
#include "ultra64/rdp.h"
|
||||
#include "ultra64/rsp.h"
|
||||
#include "ultra64/thread.h"
|
||||
#include "ultra64/convert.h"
|
||||
#include "ultra64/time.h"
|
||||
#include "ultra64/message.h"
|
||||
#include "ultra64/sptask.h"
|
||||
#include "ultra64/gu.h"
|
||||
#include "ultra64/vi.h"
|
||||
#include "ultra64/pi.h"
|
||||
#include "ultra64/controller.h"
|
||||
#include "ultra64/printf.h"
|
||||
#include "ultra64/mbi.h"
|
||||
#include "ultra64/pfs.h"
|
||||
#include "ultra64/motor.h"
|
||||
#include "ultra64/r4300.h"
|
||||
|
||||
#endif
|
||||
@@ -32,4 +32,11 @@
|
||||
#define VT_RST VT_SGR("")
|
||||
#define VT_CLS VT_ED(2)
|
||||
|
||||
#ifdef USE_BELL
|
||||
// ASCII BEL character, plays an alert tone
|
||||
#define BEL '\a'
|
||||
#else
|
||||
#define BEL '\0'
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+44
-48
@@ -1,8 +1,8 @@
|
||||
#ifndef Z64_H
|
||||
#define Z64_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include "ultra64/gs2dex.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include "unk.h" // this used to get pulled in via ultra64.h
|
||||
#include "z64save.h"
|
||||
#include "z64light.h"
|
||||
#include "z64bgcheck.h"
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "alignment.h"
|
||||
#include "sequence.h"
|
||||
#include "sfx.h"
|
||||
#include <color.h>
|
||||
#include <libultraship/color.h>
|
||||
#include "ichain.h"
|
||||
#include "regs.h"
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace Ship
|
||||
class Scene;
|
||||
class DisplayList;
|
||||
};
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#define SCREEN_WIDTH 320
|
||||
@@ -948,14 +949,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* 0x00 */ Gfx* opa;
|
||||
/* 0x04 */ Gfx* xlu;
|
||||
|
||||
#ifdef __cplusplus
|
||||
Ship::DisplayList* opaDL;
|
||||
Ship::DisplayList* xluDL;
|
||||
#else
|
||||
void* opaDL;
|
||||
void* xluDL;
|
||||
#endif
|
||||
} PolygonDlist; // size = 0x8
|
||||
|
||||
|
||||
@@ -1016,14 +1009,6 @@ typedef struct {
|
||||
/* 0x06 */ s16 unk_06;
|
||||
/* 0x08 */ Gfx* opa;
|
||||
/* 0x0C */ Gfx* xlu;
|
||||
|
||||
#ifdef __cplusplus
|
||||
Ship::DisplayList* opaDL;
|
||||
Ship::DisplayList* xluDL;
|
||||
#else
|
||||
void* opaDL;
|
||||
void* xluDL;
|
||||
#endif
|
||||
} PolygonDlist2; // size = 0x8
|
||||
|
||||
typedef struct {
|
||||
@@ -1087,12 +1072,7 @@ typedef struct {
|
||||
/* 0x58 */ OSMesgQueue loadQueue;
|
||||
/* 0x70 */ OSMesg loadMsg;
|
||||
/* 0x74 */ s16 unk_74[2]; // context-specific data used by the current scene draw config
|
||||
|
||||
#ifdef __cplusplus
|
||||
Ship::Scene* roomToLoad;
|
||||
#else
|
||||
void* roomToLoad;
|
||||
#endif
|
||||
} RoomContext; // size = 0x78
|
||||
|
||||
typedef struct {
|
||||
@@ -1235,18 +1215,45 @@ typedef struct {
|
||||
struct SelectContext;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ char* name;
|
||||
/* 0x04 */ void (*loadFunc)(struct SelectContext*, s32);
|
||||
/* 0x08 */ s32 entranceIndex;
|
||||
} SceneSelectEntry; // size = 0xC
|
||||
/* 0x00 */ char* japaneseName;
|
||||
/* 0x04 */ char* englishName;
|
||||
/* 0x08 */ char* germanName;
|
||||
/* 0x0C */ char* frenchName;
|
||||
/* 0x10 */ void (*loadFunc)(struct SelectContext*, s32);
|
||||
/* 0x14 */ s32 entranceIndex;
|
||||
} SceneSelectEntry; // size = 0x18
|
||||
|
||||
typedef struct {
|
||||
/* */ char* name;
|
||||
/* */ char* japaneseAge;
|
||||
/* */ char* englishAge;
|
||||
/* */ char* germanAge;
|
||||
/* */ char* frenchAge;
|
||||
} SceneSelectAgeLabels;
|
||||
|
||||
typedef struct {
|
||||
/* */ char* japaneseMessage;
|
||||
/* */ char* englishMessage;
|
||||
/* */ char* germanMessage;
|
||||
/* */ char* frenchMessage;
|
||||
} SceneSelectLoadingMessages;
|
||||
|
||||
typedef struct {
|
||||
/* */ char* englishAge;
|
||||
/* */ char* germanAge;
|
||||
/* */ char* frenchAge;
|
||||
} BetterSceneSelectAgeLabels;
|
||||
|
||||
typedef struct {
|
||||
/* */ char* englishName;
|
||||
/* */ char* germanName;
|
||||
/* */ char* frenchName;
|
||||
/* */ s32 entranceIndex;
|
||||
} BetterSceneSelectEntrancePair;
|
||||
|
||||
typedef struct {
|
||||
/* */ char* name;
|
||||
/* */ char* englishName;
|
||||
/* */ char* germanName;
|
||||
/* */ char* frenchName;
|
||||
/* */ void (*loadFunc)(struct SelectContext*, s32);
|
||||
/* */ s32 count;
|
||||
/* */ BetterSceneSelectEntrancePair entrancePairs[18];
|
||||
@@ -1310,13 +1317,7 @@ typedef struct PlayState {
|
||||
/* 0x000A4 */ s16 sceneNum;
|
||||
/* 0x000A6 */ u8 sceneConfig;
|
||||
/* 0x000A7 */ char unk_A7[0x9];
|
||||
|
||||
#ifdef __cplusplus
|
||||
Ship::Scene* sceneSegment;
|
||||
#else
|
||||
/* 0x000B0 */ void* sceneSegment;
|
||||
#endif
|
||||
|
||||
/* 0x000B8 */ View view;
|
||||
/* 0x001E0 */ Camera mainCamera;
|
||||
/* 0x0034C */ Camera subCameras[NUM_CAMS - SUBCAM_FIRST];
|
||||
@@ -1532,18 +1533,6 @@ typedef struct {
|
||||
/* 0x08 */ f32 morphFrames;
|
||||
} AnimationMinimalInfo; // size = 0xC
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 unk_00;
|
||||
/* 0x02 */ s16 unk_02;
|
||||
/* 0x04 */ s16 unk_04;
|
||||
/* 0x06 */ s16 unk_06;
|
||||
/* 0x08 */ Vec3s unk_08;
|
||||
/* 0x0E */ Vec3s unk_0E;
|
||||
/* 0x14 */ f32 unk_14;
|
||||
/* 0x18 */ Vec3f unk_18;
|
||||
/* 0x24 */ s16 unk_24;
|
||||
} struct_80034A14_arg1; // size = 0x28
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s8 scene;
|
||||
/* 0x01 */ s8 spawn;
|
||||
@@ -2233,6 +2222,13 @@ typedef struct {
|
||||
const char** palettes;
|
||||
} SkyboxTableEntry;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ PAUSE_ANY_CURSOR_RANDO_ONLY,
|
||||
/* 0x01 */ PAUSE_ANY_CURSOR_ALWAYS_ON,
|
||||
/* 0x02 */ PAUSE_ANY_CURSOR_ALWAYS_OFF,
|
||||
/* 0x03 */ PAUSE_ANY_CURSOR_MAX
|
||||
} PauseCursorAnySlotOptions;
|
||||
|
||||
#define ROM_FILE(name) \
|
||||
{ 0, 0, #name }
|
||||
|
||||
|
||||
+29
-2
@@ -20,8 +20,8 @@ struct Lights;
|
||||
typedef void (*ActorFunc)(struct Actor*, struct PlayState*);
|
||||
typedef void (*ActorResetFunc)(void);
|
||||
typedef void (*ActorShadowFunc)(struct Actor*, struct Lights*, struct PlayState*);
|
||||
typedef u16 (*callback1_800343CC)(struct PlayState*, struct Actor*);
|
||||
typedef s16 (*callback2_800343CC)(struct PlayState*, struct Actor*);
|
||||
typedef u16 (*NpcGetTextIdFunc)(struct PlayState*, struct Actor*);
|
||||
typedef s16 (*NpcUpdateTalkStateFunc)(struct PlayState*, struct Actor*);
|
||||
|
||||
typedef struct {
|
||||
Vec3f pos;
|
||||
@@ -369,4 +369,31 @@ typedef enum {
|
||||
DOORLOCK_NORMAL_SPIRIT
|
||||
} DoorLockType;
|
||||
|
||||
typedef enum {
|
||||
/* 0x0 */ NPC_TALK_STATE_IDLE, // NPC not currently talking to player
|
||||
/* 0x1 */ NPC_TALK_STATE_TALKING, // NPC is currently talking to player
|
||||
/* 0x2 */ NPC_TALK_STATE_ACTION, // An NPC-defined action triggered in the conversation
|
||||
/* 0x3 */ NPC_TALK_STATE_ITEM_GIVEN // NPC finished giving an item and text box is done
|
||||
} NpcTalkState;
|
||||
|
||||
typedef enum {
|
||||
/* 0x0 */ NPC_TRACKING_PLAYER_AUTO_TURN, // Determine tracking mode based on player position, see Npc_UpdateAutoTurn
|
||||
/* 0x1 */ NPC_TRACKING_NONE, // Don't track the target (usually the player)
|
||||
/* 0x2 */ NPC_TRACKING_HEAD_AND_TORSO, // Track target by turning the head and the torso
|
||||
/* 0x3 */ NPC_TRACKING_HEAD, // Track target by turning the head
|
||||
/* 0x4 */ NPC_TRACKING_FULL_BODY // Track target by turning the body, torso and head
|
||||
} NpcTrackingMode;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ s16 talkState;
|
||||
/* 0x02 */ s16 trackingMode;
|
||||
/* 0x04 */ s16 autoTurnTimer;
|
||||
/* 0x06 */ s16 autoTurnState;
|
||||
/* 0x08 */ Vec3s headRot;
|
||||
/* 0x0E */ Vec3s torsoRot;
|
||||
/* 0x14 */ f32 yOffset; // Y position offset to add to actor position when calculating angle to target
|
||||
/* 0x18 */ Vec3f trackPos;
|
||||
/* 0x24 */ char unk_24[0x4];
|
||||
} NpcInteractInfo; // size = 0x28
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64_ANIMATION_H
|
||||
#define Z64_ANIMATION_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include "z64dma.h"
|
||||
#include "z64math.h"
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* 0x00 */ s32 order;
|
||||
/* 0x04 */ s32 npredictors;
|
||||
/* 0x08 */ s16 book[]; // size 8 * order * npredictors. 8-byte aligned
|
||||
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
|
||||
} AdpcmBook; // size >= 0x8
|
||||
|
||||
typedef struct
|
||||
@@ -137,7 +137,7 @@ typedef struct
|
||||
/* 0x00 */ u32 codec : 4;
|
||||
/* 0x00 */ u32 medium : 2;
|
||||
/* 0x00 */ u32 unk_bit26 : 1;
|
||||
/* 0x00 */ u32 unk_bit25 : 1;
|
||||
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
|
||||
/* 0x01 */ u32 size : 24;
|
||||
};
|
||||
u32 asU32;
|
||||
@@ -819,7 +819,7 @@ typedef struct {
|
||||
/* 0x0E */ u8 ttl; // duration after which the DMA can be discarded
|
||||
} SampleDma; // size = 0x10
|
||||
|
||||
#include <ultra64/abi.h>
|
||||
#include <libultraship/libultra/abi.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x0000 */ char unk_0000;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64CAMERA_H
|
||||
#define Z64CAMERA_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include "z64cutscene.h"
|
||||
|
||||
#define CAM_STAT_CUT 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64CUTSCENE_H
|
||||
#define Z64CUTSCENE_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u16 entrance; // entrance index upon which the cutscene should trigger
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64_DMA_H
|
||||
#define Z64_DMA_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ uintptr_t vromAddr; // VROM address (source)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64EFFECT_H
|
||||
#define Z64EFFECT_H
|
||||
|
||||
#include <color.h>
|
||||
#include <libultraship/color.h>
|
||||
|
||||
struct GraphicsContext;
|
||||
struct PlayState;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64ELF_MESSAGE_H
|
||||
#define Z64ELF_MESSAGE_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
// Checks the condition and exits the script if the check passes
|
||||
#define ELF_MSG_TYPE_CHECK 0
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef Z64LIGHT_H
|
||||
#define Z64LIGHT_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include "ultra64/gbi.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include <libultraship/libultra/gbi.h>
|
||||
#include "z64math.h"
|
||||
#include <color.h>
|
||||
#include <libultraship/color.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x0 */ s16 x;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64MAP_MARK_H
|
||||
#define Z64MAP_MARK_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
#define MAP_MARK_NONE -1
|
||||
#define MAP_MARK_CHEST 0
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef Z64MATH_H
|
||||
#define Z64MATH_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include <include/libc/math.h>
|
||||
|
||||
#define VEC_SET(V,X,Y,Z) (V).x=(X);(V).y=(Y);(V).z=(Z)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef Z64SAVE_H
|
||||
#define Z64SAVE_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <libultraship/libultra.h>
|
||||
#include "z64math.h"
|
||||
#include "z64audio.h"
|
||||
#include "soh/Enhancements/randomizer/randomizerTypes.h"
|
||||
@@ -253,6 +253,7 @@ typedef struct {
|
||||
/* */ u8 pendingIceTrapCount;
|
||||
/* */ SohStats sohStats;
|
||||
/* */ u8 temporaryWeapon;
|
||||
/* */ FaroresWindData backupFW;
|
||||
// #endregion
|
||||
// #region SOH [Randomizer]
|
||||
// Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer
|
||||
@@ -264,6 +265,7 @@ typedef struct {
|
||||
/* */ char adultAltarText[750];
|
||||
/* */ char ganonHintText[150];
|
||||
/* */ char ganonText[250];
|
||||
/* */ char dampeText[150];
|
||||
/* */ char warpMinuetText[100];
|
||||
/* */ char warpBoleroText[100];
|
||||
/* */ char warpSerenadeText[100];
|
||||
@@ -344,9 +346,9 @@ typedef enum {
|
||||
|
||||
#define EVENTCHKINF_02 0x02
|
||||
#define EVENTCHKINF_03 0x03
|
||||
#define EVENTCHKINF_04 0x04
|
||||
#define EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD 0x04
|
||||
#define EVENTCHKINF_05 0x05
|
||||
#define EVENTCHKINF_07 0x07
|
||||
#define EVENTCHKINF_OBTAINED_KOKIRI_EMERALD_DEKU_TREE_DEAD 0x07
|
||||
#define EVENTCHKINF_09 0x09
|
||||
#define EVENTCHKINF_0A 0x0A
|
||||
#define EVENTCHKINF_0B 0x0B
|
||||
@@ -389,7 +391,7 @@ typedef enum {
|
||||
#define EVENTCHKINF_40_INDEX 4
|
||||
#define EVENTCHKINF_40_SHIFT 0
|
||||
#define EVENTCHKINF_40_MASK (1 << EVENTCHKINF_40_SHIFT)
|
||||
#define EVENTCHKINF_40 ((EVENTCHKINF_40_INDEX << 4) | EVENTCHKINF_40_SHIFT)
|
||||
#define EVENTCHKINF_OBTAINED_ZELDAS_LETTER ((EVENTCHKINF_40_INDEX << 4) | EVENTCHKINF_40_SHIFT)
|
||||
|
||||
#define EVENTCHKINF_41 0x41
|
||||
#define EVENTCHKINF_42 0x42
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef Z64TRANSITION_H
|
||||
#define Z64TRANSITION_H
|
||||
|
||||
#include "ultra64.h"
|
||||
#include <color.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <libultraship/color.h>
|
||||
|
||||
typedef struct {
|
||||
f32 unk_0;
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
<string>@CMAKE_PROJECT_VERSION@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2022 HarbourMasters.</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
</dict>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <CrashHandler.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -9,4 +9,4 @@ void CrashHandler_PrintSohData(char* buffer, size_t* pos);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
#include "gameconsole.h"
|
||||
#include <macros.h>
|
||||
#include <z64.h>
|
||||
#include <ultra64.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <functions.h>
|
||||
#include <variables.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <z64.h>
|
||||
#include <ultra64/gbi.h>
|
||||
#include <ultra64/gs2dex.h>
|
||||
#include <ultra64/controller.h>
|
||||
|
||||
uint8_t gLoadFileSelect = 0, gSkipLogoTest = 0;
|
||||
|
||||
@@ -22,12 +20,15 @@ static BootCommand sCommands[] = { { "--skiplogo", BootCommands_Command_SkipLogo
|
||||
|
||||
void BootCommands_Init()
|
||||
{
|
||||
CVar_RegisterS32("gDebugEnabled", 0);
|
||||
CVar_RegisterS32("gLanguages", LANGUAGE_ENG);
|
||||
CVar_RegisterS32("gInvertYAxis", 1);
|
||||
CVar_SetS32("gRandoGenerating", 0); // Clear when a crash happened during rando seed generation
|
||||
CVarRegisterInteger("gDebugEnabled", 0);
|
||||
CVarRegisterInteger("gLanguages", LANGUAGE_ENG);
|
||||
CVarRegisterInteger("gDebugWarpScreenTranslation", 1);
|
||||
CVarRegisterInteger("gInvertYAxis", 1);
|
||||
// Clears vars to prevent randomizer menu from being disabled
|
||||
CVarSetInteger("gRandoGenerating", 0); // Clear when a crash happened during rando seed generation
|
||||
CVarSetInteger("gOnFileSelectNameEntry", 0); // Clear when soh is killed on the file name entry page
|
||||
#if defined(__SWITCH__) || defined(__WIIU__)
|
||||
CVar_RegisterS32("gControlNav", 1); // always enable controller nav on switch/wii u
|
||||
CVarRegisterInteger("gControlNav", 1); // always enable controller nav on switch/wii u
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef _BOOTCOMMANDS_H_
|
||||
#define _BOOTCOMMANDS_H_
|
||||
#include <ultra64.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <z64.h>
|
||||
|
||||
typedef s32 (*BootCommandFunc)(char** argv, s32 argc); // Returns the number of arguments it read
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <variables.h>
|
||||
|
||||
#include <ImGui/imgui.h>
|
||||
#include <ImGui/imgui_internal.h>
|
||||
#include <Cvar.h>
|
||||
#include <UltraController.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <libultraship/libultra/controller.h>
|
||||
#include <Utils/StringHelper.h>
|
||||
#include <ImGuiImpl.h>
|
||||
|
||||
@@ -109,7 +110,7 @@ namespace GameControlEditor {
|
||||
// Draw a button mapping setting consisting of a padded label and button dropdown.
|
||||
// excludedButtons indicates which buttons are unavailable to choose from.
|
||||
void DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons) {
|
||||
N64ButtonMask currentButton = CVar_GetS32(mapping.cVarName, mapping.defaultBtn);
|
||||
N64ButtonMask currentButton = CVarGetInteger(mapping.cVarName, mapping.defaultBtn);
|
||||
|
||||
const char* preview;
|
||||
if (buttonNames.contains(currentButton)) {
|
||||
@@ -134,7 +135,7 @@ namespace GameControlEditor {
|
||||
continue;
|
||||
}
|
||||
if (ImGui::Selectable(i->second, i->first == currentButton)) {
|
||||
CVar_SetS32(mapping.cVarName, i->first);
|
||||
CVarSetInteger(mapping.cVarName, i->first);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
@@ -158,11 +159,11 @@ namespace GameControlEditor {
|
||||
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
|
||||
UIWidgets::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls");
|
||||
|
||||
if (CVar_GetS32("gCustomOcarinaControls", 0) == 1) {
|
||||
if (CVarGetInteger("gCustomOcarinaControls", 0) == 1) {
|
||||
if (ImGui::BeginTable("tableCustomMainOcarinaControls", 2, ImGuiTableFlags_SizingStretchProp)) {
|
||||
float labelWidth;
|
||||
N64ButtonMask disableMask = BTN_B;
|
||||
if (CVar_GetS32("gDpadOcarina", 0)) {
|
||||
if (CVarGetInteger("gDpadOcarina", 0)) {
|
||||
disableMask |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
|
||||
}
|
||||
|
||||
@@ -242,11 +243,11 @@ namespace GameControlEditor {
|
||||
UIWidgets::PaddedEnhancementCheckbox("Disable Auto-Centering in First-Person View", "gDisableAutoCenterViewFirstPerson");
|
||||
DrawHelpIcon("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable Custom Aiming/First-Person sensitivity", "gEnableFirstPersonSensitivity", true, false);
|
||||
if (CVar_GetS32("gEnableFirstPersonSensitivity", 0)) {
|
||||
if (CVarGetInteger("gEnableFirstPersonSensitivity", 0)) {
|
||||
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Sensitivity: %d %%", "##FirstPersonSensitivity",
|
||||
"gFirstPersonCameraSensitivity", 0.01f, 5.0f, "", 1.0f, true, true);
|
||||
} else {
|
||||
CVar_SetFloat("gFirstPersonCameraSensitivity", 1.0f);
|
||||
CVarSetFloat("gFirstPersonCameraSensitivity", 1.0f);
|
||||
}
|
||||
SohImGui::EndGroupPanel();
|
||||
|
||||
@@ -296,9 +297,15 @@ namespace GameControlEditor {
|
||||
ImVec2 cursor = ImGui::GetCursorPos();
|
||||
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
|
||||
SohImGui::BeginGroupPanel("Misc Controls", ImGui::GetContentRegionAvail());
|
||||
UIWidgets::PaddedText("Allow the cursor to be on any slot");
|
||||
static const char* cursorOnAnySlot[3] = { "Only in Rando", "Always", "Never" };
|
||||
UIWidgets::EnhancementCombobox("gPauseAnyCursor", cursorOnAnySlot, PAUSE_ANY_CURSOR_MAX, PAUSE_ANY_CURSOR_RANDO_ONLY);
|
||||
DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select "
|
||||
"certain items.");
|
||||
UIWidgets::Spacer(0);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false);
|
||||
DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above");
|
||||
if (CVar_GetS32("gEnableWalkModify", 0)) {
|
||||
if (CVarGetInteger("gEnableWalkModify", 0)) {
|
||||
UIWidgets::Spacer(5);
|
||||
SohImGui::BeginGroupPanel("Walk Modifier", ImGui::GetContentRegionAvail());
|
||||
UIWidgets::PaddedEnhancementCheckbox("Toggle modifier instead of holding", "gWalkSpeedToggle", true, false);
|
||||
@@ -307,8 +314,6 @@ namespace GameControlEditor {
|
||||
SohImGui::EndGroupPanel();
|
||||
}
|
||||
UIWidgets::Spacer(0);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor");
|
||||
DrawHelpIcon("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL");
|
||||
DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up");
|
||||
SohImGui::EndGroupPanel();
|
||||
@@ -317,7 +322,7 @@ namespace GameControlEditor {
|
||||
|
||||
void DrawUI(bool& open) {
|
||||
if (!open) {
|
||||
CVar_SetS32("gGameControlEditorEnabled", false);
|
||||
CVarSetInteger("gGameControlEditorEnabled", false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
#include <ImGuiImpl.h>
|
||||
|
||||
#define PATCH_GFX(path, name, cvar, index, instruction) \
|
||||
if (CVar_GetS32(cvar, 0)) { \
|
||||
if (CVarGetInteger(cvar, 0)) { \
|
||||
ResourceMgr_PatchGfxByName(path, name, index, instruction); \
|
||||
} else { \
|
||||
ResourceMgr_UnpatchGfxByName(path, name); \
|
||||
@@ -25,3 +25,5 @@ static ImGuiTableColumnFlags FlagsCell = ImGuiTableColumnFlags_WidthStretch | Im
|
||||
|
||||
void InitCosmeticsEditor();//Init the menu itself
|
||||
ImVec4 GetRandomValue(int MaximumPossible);
|
||||
void CosmeticsEditor_RandomizeAll();
|
||||
void CosmeticsEditor_ResetAll();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifdef ENABLE_CROWD_CONTROL
|
||||
|
||||
#include "CrowdControl.h"
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <Console.h>
|
||||
#include <ImGuiImpl.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -17,10 +17,6 @@ extern "C" {
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#include "../debugconsole.h"
|
||||
|
||||
#define CMD_EXECUTE SohImGui::GetConsole()->Dispatch
|
||||
|
||||
#define EFFECT_HIGH_GRAVITY "high_gravity"
|
||||
#define EFFECT_LOW_GRAVITY "low_gravity"
|
||||
#define EFFECT_DAMAGE_MULTIPLIER "damage_multiplier"
|
||||
@@ -52,6 +48,7 @@ extern PlayState* gPlayState;
|
||||
#define EFFECT_INCREASE_SPEED "increase_speed"
|
||||
#define EFFECT_DECREASE_SPEED "decrease_speed"
|
||||
#define EFFECT_NO_Z_TARGETING "no_z"
|
||||
#define EFFECT_GIVE_DEKU_SHIELD "give_dekushield"
|
||||
|
||||
#define EFFECT_SPAWN_WALLMASTER "spawn_wallmaster"
|
||||
#define EFFECT_SPAWN_ARWING "spawn_arwing"
|
||||
@@ -66,6 +63,18 @@ extern PlayState* gPlayState;
|
||||
#define EFFECT_SPAWN_LIKE_LIKE "spawn_likelike"
|
||||
#define EFFECT_SPAWN_CUCCO_STORM "cucco_storm"
|
||||
|
||||
#define EFFECT_CAT_UI "ui"
|
||||
#define EFFECT_CAT_GRAVITY "gravity"
|
||||
#define EFFECT_CAT_LINK_SIZE "link_size"
|
||||
#define EFFECT_CAT_PACIFIST "pacifist"
|
||||
#define EFFECT_CAT_NO_Z "no_z"
|
||||
#define EFFECT_CAT_WEATHER "weather"
|
||||
#define EFFECT_CAT_REVERSE_CONTROLS "reverse_controls"
|
||||
#define EFFECT_CAT_BOOTS "boots"
|
||||
#define EFFECT_CAT_SPEED "speed"
|
||||
#define EFFECT_CAT_DAMAGE_TAKEN "damage_taken"
|
||||
#define EFFECT_CAT_SPAWN_ENEMY "spawn_enemy"
|
||||
#define EFFECT_CAT_NONE "none"
|
||||
|
||||
void CrowdControl::Init() {
|
||||
SDLNet_Init();
|
||||
@@ -101,7 +110,7 @@ void CrowdControl::Disable() {
|
||||
|
||||
void CrowdControl::ListenToServer() {
|
||||
while (isEnabled) {
|
||||
while (!connected) {
|
||||
while (!connected && isEnabled) {
|
||||
SPDLOG_TRACE("[CrowdControl] Attempting to make connection to server...");
|
||||
tcpsock = SDLNet_TCP_Open(&ip);
|
||||
|
||||
@@ -112,8 +121,10 @@ void CrowdControl::ListenToServer() {
|
||||
}
|
||||
}
|
||||
|
||||
auto socketSet = SDLNet_AllocSocketSet(1);
|
||||
SDLNet_TCP_AddSocket(socketSet, tcpsock);
|
||||
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
|
||||
if (tcpsock) {
|
||||
SDLNet_TCP_AddSocket(socketSet, tcpsock);
|
||||
}
|
||||
|
||||
// Listen to socket messages
|
||||
while (connected && tcpsock && isEnabled) {
|
||||
@@ -140,34 +151,29 @@ void CrowdControl::ListenToServer() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If effect is a one off run, let's execute
|
||||
// If effect is not a timed effect, execute and return result.
|
||||
if (!incomingEffect->timeRemaining) {
|
||||
EffectResult result =
|
||||
ExecuteEffect(incomingEffect->type.c_str(), incomingEffect->value, false);
|
||||
EffectResult result = CrowdControl::ExecuteEffect(incomingEffect);
|
||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||
} else {
|
||||
// check if a conflicting event is already active
|
||||
// If another timed effect is already active that conflicts with the incoming effect.
|
||||
bool isConflictingEffectActive = false;
|
||||
for (Effect* pack : activeEffects) {
|
||||
if (pack != incomingEffect && pack->category == incomingEffect->category &&
|
||||
pack->id < incomingEffect->id) {
|
||||
for (Effect* effect : activeEffects) {
|
||||
if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) {
|
||||
isConflictingEffectActive = true;
|
||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining,
|
||||
EffectResult::Retry);
|
||||
|
||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if effect can be executed
|
||||
EffectResult result =
|
||||
ExecuteEffect(incomingEffect->type.c_str(), incomingEffect->value, true);
|
||||
if (result == EffectResult::Retry || result == EffectResult::Failure) {
|
||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isConflictingEffectActive) {
|
||||
// Check if effect can be applied, if it can't, let CC know.
|
||||
EffectResult result = CrowdControl::CanApplyEffect(incomingEffect);
|
||||
if (result == EffectResult::Retry || result == EffectResult::Failure) {
|
||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
activeEffectsMutex.lock();
|
||||
activeEffects.push_back(incomingEffect);
|
||||
activeEffectsMutex.unlock();
|
||||
@@ -185,27 +191,31 @@ void CrowdControl::ListenToServer() {
|
||||
|
||||
void CrowdControl::ProcessActiveEffects() {
|
||||
while (isEnabled) {
|
||||
// we only want to send events when status changes, on start we send Success,
|
||||
// if it fails at some point, we send Pause, and when it starts to succeed again we send Success.
|
||||
// We only want to send events when status changes, on start we send Success.
|
||||
// If it fails at some point, we send Pause, and when it starts to succeed again we send Success.
|
||||
// CC uses this to pause the timer on the overlay.
|
||||
activeEffectsMutex.lock();
|
||||
auto it = activeEffects.begin();
|
||||
|
||||
while (it != activeEffects.end()) {
|
||||
Effect *effect = *it;
|
||||
EffectResult result = ExecuteEffect(effect->type.c_str(), effect->value, false);
|
||||
EffectResult result = CrowdControl::ExecuteEffect(effect);
|
||||
|
||||
if (result == EffectResult::Success) {
|
||||
// If time remaining has reached 0, we have finished the effect
|
||||
// If time remaining has reached 0, we have finished the effect.
|
||||
if (effect->timeRemaining <= 0) {
|
||||
it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect),
|
||||
activeEffects.end());
|
||||
RemoveEffect(effect->type.c_str());
|
||||
|
||||
GameInteractor::RemoveEffect(effect->giEffect);
|
||||
delete effect;
|
||||
} else {
|
||||
// If we have a success after previously being paused, fire Resume event
|
||||
// If we have a success after previously being paused, tell CC to resume timer.
|
||||
if (effect->isPaused) {
|
||||
effect->isPaused = false;
|
||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Resumed);
|
||||
// If not paused before, subtract time from the timer and send a Success event if
|
||||
// the result is different from the last time this was ran.
|
||||
// Timed events are put on a thread that runs once per second.
|
||||
} else {
|
||||
effect->timeRemaining -= 1000;
|
||||
if (result != effect->lastExecutionResult) {
|
||||
@@ -213,7 +223,6 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Success);
|
||||
}
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
} else { // Timed effects only do Success or Retry
|
||||
@@ -221,7 +230,6 @@ void CrowdControl::ProcessActiveEffects() {
|
||||
effect->isPaused = true;
|
||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Paused);
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
@@ -258,328 +266,224 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||
effect->lastExecutionResult = EffectResult::Initiate;
|
||||
effect->id = dataReceived["id"];
|
||||
auto parameters = dataReceived["parameters"];
|
||||
if (parameters.size() > 0) {
|
||||
effect->value = dataReceived["parameters"][0];
|
||||
}
|
||||
effect->type = dataReceived["code"].get<std::string>();
|
||||
auto effectName = dataReceived["code"].get<std::string>();
|
||||
|
||||
if (effect->type == EFFECT_HIGH_GRAVITY || effect->type == EFFECT_LOW_GRAVITY) {
|
||||
effect->category = "gravity";
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_DAMAGE_MULTIPLIER || effect->type == EFFECT_DEFENSE_MULTIPLIER) {
|
||||
effect->category = "defense";
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_GIANT_LINK || effect->type == EFFECT_MINISH_LINK ||
|
||||
effect->type == EFFECT_INVISIBLE_LINK || effect->type == EFFECT_PAPER_LINK) {
|
||||
effect->category = "link_size";
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_FREEZE || effect->type == EFFECT_DAMAGE || effect->type == EFFECT_HEAL ||
|
||||
effect->type == EFFECT_KNOCKBACK || effect->type == EFFECT_ELECTROCUTE ||
|
||||
effect->type == EFFECT_BURN || effect->type == EFFECT_KILL) {
|
||||
effect->category = "link_damage";
|
||||
} else if (effect->type == EFFECT_HOVER_BOOTS || effect->type == EFFECT_IRON_BOOTS) {
|
||||
effect->category = "boots";
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_ADD_HEART_CONTAINER || effect->type == EFFECT_REMOVE_HEART_CONTAINER) {
|
||||
effect->category = "heart_container";
|
||||
} else if (effect->type == EFFECT_NO_UI) {
|
||||
effect->category = "ui";
|
||||
if (parameters.size() > 0) {
|
||||
effect->value[0] = dataReceived["parameters"][0];
|
||||
}
|
||||
|
||||
// Assign GameInteractionEffect + values to CC effect.
|
||||
// Categories are mostly used for checking for conflicting timed effects.
|
||||
if (effectName == EFFECT_ADD_HEART_CONTAINER) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->giEffect->parameter = 1;
|
||||
} else if (effectName == EFFECT_REMOVE_HEART_CONTAINER) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||
effect->giEffect->parameter = -1;
|
||||
} else if (effectName == EFFECT_FILL_MAGIC) {
|
||||
effect->giEffect = new GameInteractionEffect::FillMagic();
|
||||
} else if (effectName == EFFECT_EMPTY_MAGIC) {
|
||||
effect->giEffect = new GameInteractionEffect::EmptyMagic();
|
||||
} else if (effectName == EFFECT_ADD_RUPEES) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||
} else if (effectName == EFFECT_REMOVE_RUPEES) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||
effect->paramMultiplier = -1;
|
||||
} else if (effectName == EFFECT_NO_UI) {
|
||||
effect->category = EFFECT_CAT_UI;
|
||||
effect->timeRemaining = 60000;
|
||||
} else if (effect->type == EFFECT_FILL_MAGIC || effect->type == EFFECT_EMPTY_MAGIC) {
|
||||
effect->category = "magic";
|
||||
} else if (effect->type == EFFECT_OHKO) {
|
||||
effect->category = "ohko";
|
||||
effect->giEffect = new GameInteractionEffect::NoUI();
|
||||
} else if (effectName == EFFECT_HIGH_GRAVITY) {
|
||||
effect->category = EFFECT_CAT_GRAVITY;
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_PACIFIST) {
|
||||
effect->category = "pacifist";
|
||||
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
||||
effect->giEffect->parameter = GI_GRAVITY_LEVEL_HEAVY;
|
||||
} else if (effectName == EFFECT_LOW_GRAVITY) {
|
||||
effect->category = EFFECT_CAT_GRAVITY;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
||||
effect->giEffect->parameter = GI_GRAVITY_LEVEL_LIGHT;
|
||||
} else if (effectName == EFFECT_KILL) {
|
||||
effect->giEffect = new GameInteractionEffect::SetPlayerHealth();
|
||||
effect->value[0] = 0;
|
||||
} else if (effectName == EFFECT_FREEZE) {
|
||||
effect->giEffect = new GameInteractionEffect::FreezePlayer();
|
||||
} else if (effectName == EFFECT_BURN) {
|
||||
effect->giEffect = new GameInteractionEffect::BurnPlayer();
|
||||
} else if (effectName == EFFECT_ELECTROCUTE) {
|
||||
effect->giEffect = new GameInteractionEffect::ElectrocutePlayer();
|
||||
} else if (effectName == EFFECT_KNOCKBACK) {
|
||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||
} else if (effectName == EFFECT_HEAL) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||
} else if (effectName == EFFECT_DAMAGE) {
|
||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||
effect->paramMultiplier = -1;
|
||||
} else if (effectName == EFFECT_GIANT_LINK) {
|
||||
effect->category = EFFECT_CAT_LINK_SIZE;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->giEffect->parameter = GI_LINK_SIZE_GIANT;
|
||||
} else if (effectName == EFFECT_MINISH_LINK) {
|
||||
effect->category = EFFECT_CAT_LINK_SIZE;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->giEffect->parameter = GI_LINK_SIZE_MINISH;
|
||||
} else if (effectName == EFFECT_PAPER_LINK) {
|
||||
effect->category = EFFECT_CAT_LINK_SIZE;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||
effect->giEffect->parameter = GI_LINK_SIZE_PAPER;
|
||||
} else if (effectName == EFFECT_INVISIBLE_LINK) {
|
||||
effect->category = EFFECT_CAT_LINK_SIZE;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::InvisibleLink();
|
||||
} else if (effectName == EFFECT_PACIFIST) {
|
||||
effect->category = EFFECT_CAT_PACIFIST;
|
||||
effect->timeRemaining = 15000;
|
||||
} else if (effect->type == EFFECT_RAINSTORM) {
|
||||
effect->category = "weather";
|
||||
effect->giEffect = new GameInteractionEffect::PacifistMode();
|
||||
} else if (effectName == EFFECT_NO_Z_TARGETING) {
|
||||
effect->category = EFFECT_CAT_NO_Z;
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_REVERSE_CONTROLS) {
|
||||
effect->category = "controls";
|
||||
effect->giEffect = new GameInteractionEffect::DisableZTargeting();
|
||||
} else if (effectName == EFFECT_RAINSTORM) {
|
||||
effect->category = EFFECT_CAT_WEATHER;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::WeatherRainstorm();
|
||||
} else if (effectName == EFFECT_REVERSE_CONTROLS) {
|
||||
effect->category = EFFECT_CAT_REVERSE_CONTROLS;
|
||||
effect->timeRemaining = 60000;
|
||||
} else if (effect->type == EFFECT_ADD_RUPEES || effect->type == EFFECT_REMOVE_RUPEES) {
|
||||
effect->category = "rupees";
|
||||
} else if (effect->type == EFFECT_INCREASE_SPEED || effect->type == EFFECT_DECREASE_SPEED) {
|
||||
effect->category = "speed";
|
||||
effect->giEffect = new GameInteractionEffect::ReverseControls();
|
||||
} else if (effectName == EFFECT_IRON_BOOTS) {
|
||||
effect->category = EFFECT_CAT_BOOTS;
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_NO_Z_TARGETING) {
|
||||
effect->category = "no_z";
|
||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||
effect->giEffect->parameter = PLAYER_BOOTS_IRON;
|
||||
} else if (effectName == EFFECT_HOVER_BOOTS) {
|
||||
effect->category = EFFECT_CAT_BOOTS;
|
||||
effect->timeRemaining = 30000;
|
||||
} else if (effect->type == EFFECT_SPAWN_WALLMASTER || effect->type == EFFECT_SPAWN_ARWING ||
|
||||
effect->type == EFFECT_SPAWN_DARK_LINK || effect->type == EFFECT_SPAWN_STALFOS ||
|
||||
effect->type == EFFECT_SPAWN_WOLFOS || effect->type == EFFECT_SPAWN_FREEZARD ||
|
||||
effect->type == EFFECT_SPAWN_KEESE || effect->type == EFFECT_SPAWN_ICE_KEESE ||
|
||||
effect->type == EFFECT_SPAWN_FIRE_KEESE || effect->type == EFFECT_SPAWN_TEKTITE ||
|
||||
effect->type == EFFECT_SPAWN_LIKE_LIKE || effect->type == EFFECT_SPAWN_CUCCO_STORM) {
|
||||
effect->category = "spawn";
|
||||
} else {
|
||||
effect->category = "none";
|
||||
effect->timeRemaining = 0;
|
||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||
effect->giEffect->parameter = PLAYER_BOOTS_HOVER;;
|
||||
} else if (effectName == EFFECT_GIVE_DEKU_SHIELD) {
|
||||
effect->giEffect = new GameInteractionEffect::GiveDekuShield();
|
||||
} else if (effectName == EFFECT_INCREASE_SPEED) {
|
||||
effect->category = EFFECT_CAT_SPEED;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||
effect->giEffect->parameter = 2;
|
||||
} else if (effectName == EFFECT_DECREASE_SPEED) {
|
||||
effect->category = EFFECT_CAT_SPEED;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||
effect->giEffect->parameter = -2;
|
||||
} else if (effectName == EFFECT_OHKO) {
|
||||
effect->category = EFFECT_CAT_DAMAGE_TAKEN;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::OneHitKO();
|
||||
} else if (effectName == EFFECT_DAMAGE_MULTIPLIER) {
|
||||
effect->category = EFFECT_CAT_DAMAGE_TAKEN;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||
effect->paramMultiplier = -1;
|
||||
} else if (effectName == EFFECT_DEFENSE_MULTIPLIER) {
|
||||
effect->category = EFFECT_CAT_DAMAGE_TAKEN;
|
||||
effect->timeRemaining = 30000;
|
||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||
} else if (effectName == EFFECT_SPAWN_CUCCO_STORM) {
|
||||
effect->giEffect = new GameInteractionEffect::SpawnCuccoStorm();
|
||||
} else if (effectName == EFFECT_SPAWN_WALLMASTER) {
|
||||
effect->value[0] = ACTOR_EN_WALLMAS;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_ARWING) {
|
||||
effect->value[0] = ACTOR_EN_CLEAR_TAG;
|
||||
// Parameter for no cutscene Arwing
|
||||
effect->value[1] = 1;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_DARK_LINK) {
|
||||
effect->value[0] = ACTOR_EN_TORCH2;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_STALFOS) {
|
||||
effect->value[0] = ACTOR_EN_TEST;
|
||||
// Parameter for gravity-obeying Stalfos
|
||||
effect->value[1] = 2;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_WOLFOS) {
|
||||
effect->value[0] = ACTOR_EN_WF;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_FREEZARD) {
|
||||
effect->value[0] = ACTOR_EN_FZ;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_KEESE) {
|
||||
effect->value[0] = ACTOR_EN_FIREFLY;
|
||||
// Parameter for normal keese
|
||||
effect->value[1] = 2;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_ICE_KEESE) {
|
||||
effect->value[0] = ACTOR_EN_FIREFLY;
|
||||
// Parameter for ice keese
|
||||
effect->value[1] = 4;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_FIRE_KEESE) {
|
||||
effect->value[0] = ACTOR_EN_FIREFLY;
|
||||
// Parameter for fire keese
|
||||
effect->value[1] = 1;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_TEKTITE) {
|
||||
effect->value[0] = ACTOR_EN_TITE;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
} else if (effectName == EFFECT_SPAWN_LIKE_LIKE) {
|
||||
effect->value[0] = ACTOR_EN_RR;
|
||||
effect->category = EFFECT_CAT_SPAWN_ENEMY;
|
||||
}
|
||||
|
||||
// If no value is specifically set, default to using whatever CC sends us.
|
||||
// Values are used for various things depending on the effect, but they
|
||||
// usually represent the "amount" of an effect. Amount of hearts healed,
|
||||
// strength of knockback, etc.
|
||||
if (effect->giEffect != NULL) {
|
||||
if (!effect->giEffect->parameter && effect->value[0]) {
|
||||
effect->giEffect->parameter = effect->value[0] * effect->paramMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect->category == "") {
|
||||
effect->category = EFFECT_CAT_NONE;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
CrowdControl::EffectResult CrowdControl::ExecuteEffect(std::string effectId, uint32_t value, bool dryRun) {
|
||||
// Don't execute effect and don't advance timer when the player is not in a proper loaded savefile
|
||||
// and when they're busy dying.
|
||||
if (gPlayState == NULL || gPlayState->gameOverCtx.state > 0 || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) {
|
||||
return EffectResult::Retry;
|
||||
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
|
||||
GameInteractionEffectQueryResult giResult;
|
||||
if (effect->category == EFFECT_CAT_SPAWN_ENEMY) {
|
||||
giResult = GameInteractor::RawAction::SpawnEnemyWithOffset(effect->value[0], effect->value[1]);
|
||||
} else {
|
||||
giResult = GameInteractor::ApplyEffect(effect->giEffect);
|
||||
}
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
if (player != NULL) {
|
||||
if (effectId == EFFECT_ADD_HEART_CONTAINER) {
|
||||
if (gSaveContext.healthCapacity >= 0x140) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(EFFECT_ADD_HEART_CONTAINER);
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_REMOVE_HEART_CONTAINER) {
|
||||
if ((gSaveContext.healthCapacity - 0x10) <= 0) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(EFFECT_REMOVE_HEART_CONTAINER);
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_FILL_MAGIC) {
|
||||
if (!gSaveContext.isMagicAcquired) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (gSaveContext.magic >= (gSaveContext.isDoubleMagicAcquired + 1) + 0x30) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(EFFECT_FILL_MAGIC);
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_EMPTY_MAGIC) {
|
||||
if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(EFFECT_EMPTY_MAGIC);
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_ADD_RUPEES) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees {}", value));
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_REMOVE_RUPEES) {
|
||||
if (gSaveContext.rupees - value < 0) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("update_rupees -{}", value));
|
||||
return EffectResult::Success;
|
||||
}
|
||||
}
|
||||
|
||||
if (player != NULL && !Player_InBlockingCsMode(gPlayState, player) && gPlayState->pauseCtx.state == 0
|
||||
&& gPlayState->msgCtx.msgMode == 0) {
|
||||
if (effectId == EFFECT_HIGH_GRAVITY) {
|
||||
if (dryRun == 0) CMD_EXECUTE("gravity 2");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_LOW_GRAVITY) {
|
||||
if (dryRun == 0) CMD_EXECUTE("gravity 0");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_KILL
|
||||
|| effectId == EFFECT_FREEZE
|
||||
|| effectId == EFFECT_BURN
|
||||
|| effectId == EFFECT_ELECTROCUTE
|
||||
|| effectId == EFFECT_SPAWN_CUCCO_STORM
|
||||
) {
|
||||
if (PlayerGrounded(player)) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("{}", effectId));
|
||||
return EffectResult::Success;
|
||||
}
|
||||
return EffectResult::Failure;
|
||||
} else if (effectId == EFFECT_HEAL
|
||||
|| effectId == EFFECT_KNOCKBACK
|
||||
) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value));
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_GIANT_LINK
|
||||
|| effectId == EFFECT_MINISH_LINK
|
||||
|| effectId == EFFECT_NO_UI
|
||||
|| effectId == EFFECT_INVISIBLE_LINK
|
||||
|| effectId == EFFECT_PAPER_LINK
|
||||
|| effectId == EFFECT_NO_Z_TARGETING
|
||||
|| effectId == EFFECT_OHKO
|
||||
|| effectId == EFFECT_PACIFIST
|
||||
|| effectId == EFFECT_RAINSTORM
|
||||
) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("{} 1", effectId));
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_REVERSE_CONTROLS) {
|
||||
if (dryRun == 0) CMD_EXECUTE("reverse_controls 1");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_IRON_BOOTS) {
|
||||
if (dryRun == 0) CMD_EXECUTE("boots iron");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_HOVER_BOOTS) {
|
||||
if (dryRun == 0) CMD_EXECUTE("boots hover");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == "give_dekushield") {
|
||||
if (dryRun == 0) CMD_EXECUTE("givedekushield");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_SPAWN_WALLMASTER
|
||||
|| effectId == EFFECT_SPAWN_ARWING
|
||||
|| effectId == EFFECT_SPAWN_DARK_LINK
|
||||
|| effectId == EFFECT_SPAWN_STALFOS
|
||||
|| effectId == EFFECT_SPAWN_WOLFOS
|
||||
|| effectId == EFFECT_SPAWN_FREEZARD
|
||||
|| effectId == EFFECT_SPAWN_KEESE
|
||||
|| effectId == EFFECT_SPAWN_ICE_KEESE
|
||||
|| effectId == EFFECT_SPAWN_FIRE_KEESE
|
||||
|| effectId == EFFECT_SPAWN_TEKTITE
|
||||
|| effectId == EFFECT_SPAWN_LIKE_LIKE
|
||||
) {
|
||||
if (dryRun == 0) {
|
||||
if (CrowdControl::SpawnEnemy(effectId)) {
|
||||
return EffectResult::Success;
|
||||
} else {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
}
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_INCREASE_SPEED) {
|
||||
if (dryRun == 0) CMD_EXECUTE("speed_modifier 2");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_DECREASE_SPEED) {
|
||||
if (dryRun == 0) CMD_EXECUTE("speed_modifier -2");
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_DAMAGE_MULTIPLIER) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier -{}", value));
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_DEFENSE_MULTIPLIER) {
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("defense_modifier {}", value));
|
||||
return EffectResult::Success;
|
||||
} else if (effectId == EFFECT_DAMAGE) {
|
||||
if ((gSaveContext.health - (16 * value)) <= 0) {
|
||||
return EffectResult::Failure;
|
||||
}
|
||||
|
||||
if (dryRun == 0) CMD_EXECUTE(fmt::format("{} {}", effectId, value));
|
||||
return EffectResult::Success;
|
||||
}
|
||||
}
|
||||
|
||||
return EffectResult::Retry;
|
||||
return TranslateGiEnum(giResult);
|
||||
}
|
||||
|
||||
bool CrowdControl::SpawnEnemy(std::string effectId) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
int enemyId = 0;
|
||||
int enemyParams = 0;
|
||||
float posXOffset = 0;
|
||||
float posYOffset = 0;
|
||||
float posZOffset = 0;
|
||||
|
||||
if (effectId == EFFECT_SPAWN_WALLMASTER) {
|
||||
enemyId = 17;
|
||||
} else if (effectId == EFFECT_SPAWN_ARWING) {
|
||||
// Don't allow Arwings in certain areas because they cause issues.
|
||||
// Locations: King dodongo room, Morpha room, Twinrova room, Ganondorf room, Fishing pond, Ganon's room
|
||||
// TODO: Swap this to disabling the option in CC options menu instead.
|
||||
if (gPlayState->sceneNum == SCENE_DDAN_BOSS || gPlayState->sceneNum == SCENE_MIZUSIN_BS ||
|
||||
gPlayState->sceneNum == SCENE_JYASINBOSS || gPlayState->sceneNum == SCENE_GANON_BOSS ||
|
||||
gPlayState->sceneNum == SCENE_TURIBORI || gPlayState->sceneNum == SCENE_GANON_DEMO) {
|
||||
return 0;
|
||||
}
|
||||
enemyId = 315;
|
||||
enemyParams = 1;
|
||||
posYOffset = 100;
|
||||
} else if (effectId == EFFECT_SPAWN_DARK_LINK) {
|
||||
enemyId = 51;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_STALFOS) {
|
||||
enemyId = 2;
|
||||
enemyParams = 2;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_WOLFOS) {
|
||||
enemyId = 431;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_FREEZARD) {
|
||||
enemyId = 289;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_KEESE) {
|
||||
enemyId = 19;
|
||||
enemyParams = 2;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_ICE_KEESE) {
|
||||
enemyId = 19;
|
||||
enemyParams = 4;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_FIRE_KEESE) {
|
||||
enemyId = 19;
|
||||
enemyParams = 1;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_TEKTITE) {
|
||||
enemyId = 27;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (effectId == EFFECT_SPAWN_LIKE_LIKE) {
|
||||
enemyId = 221;
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
}
|
||||
|
||||
return Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, player->actor.world.pos.x + posXOffset,
|
||||
player->actor.world.pos.y + posYOffset, player->actor.world.pos.z + posZOffset, 0, 0, 0, enemyParams, 0);
|
||||
/// Checks if effect can be applied -- should not be used to check for spawn enemy effects.
|
||||
CrowdControl::EffectResult CrowdControl::CanApplyEffect(Effect* effect) {
|
||||
assert(effect->category != EFFECT_CAT_SPAWN_ENEMY);
|
||||
GameInteractionEffectQueryResult giResult = GameInteractor::CanApplyEffect(effect->giEffect);
|
||||
|
||||
return TranslateGiEnum(giResult);
|
||||
}
|
||||
|
||||
void CrowdControl::RemoveEffect(std::string effectId) {
|
||||
if (gPlayState == NULL) {
|
||||
return;
|
||||
CrowdControl::EffectResult CrowdControl::TranslateGiEnum(GameInteractionEffectQueryResult giResult) {
|
||||
// Translate GameInteractor result into CC's own enums.
|
||||
EffectResult result;
|
||||
if (giResult == GameInteractionEffectQueryResult::Possible) {
|
||||
result = EffectResult::Success;
|
||||
} else if (giResult == GameInteractionEffectQueryResult::TemporarilyNotPossible) {
|
||||
result = EffectResult::Retry;
|
||||
} else {
|
||||
result = EffectResult::Failure;
|
||||
}
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
if (player != NULL) {
|
||||
if (effectId == EFFECT_GIANT_LINK
|
||||
|| effectId == EFFECT_MINISH_LINK
|
||||
|| effectId == EFFECT_NO_UI
|
||||
|| effectId == EFFECT_INVISIBLE_LINK
|
||||
|| effectId == EFFECT_PAPER_LINK
|
||||
|| effectId == EFFECT_NO_Z_TARGETING
|
||||
|| effectId == EFFECT_OHKO
|
||||
|| effectId == EFFECT_PACIFIST
|
||||
|| effectId == EFFECT_RAINSTORM
|
||||
) {
|
||||
CMD_EXECUTE(fmt::format("{} 0", effectId));
|
||||
return;
|
||||
} else if (effectId == EFFECT_IRON_BOOTS || effectId == EFFECT_HOVER_BOOTS) {
|
||||
CMD_EXECUTE("boots kokiri");
|
||||
return;
|
||||
} else if (effectId == EFFECT_HIGH_GRAVITY || effectId == EFFECT_LOW_GRAVITY) {
|
||||
CMD_EXECUTE("gravity 1");
|
||||
return;
|
||||
} else if (effectId == EFFECT_REVERSE_CONTROLS) {
|
||||
CMD_EXECUTE("reverse_controls 0");
|
||||
return;
|
||||
} else if (effectId == EFFECT_INCREASE_SPEED
|
||||
|| effectId == EFFECT_DECREASE_SPEED
|
||||
) {
|
||||
CMD_EXECUTE("speed_modifier 0");
|
||||
return;
|
||||
} else if (effectId == EFFECT_DAMAGE_MULTIPLIER
|
||||
|| effectId == EFFECT_DEFENSE_MULTIPLIER
|
||||
) {
|
||||
CMD_EXECUTE("defense_modifier 0");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
|
||||
#include "../game-interactor/GameInteractor.h"
|
||||
|
||||
class CrowdControl {
|
||||
private:
|
||||
enum EffectResult {
|
||||
@@ -61,10 +63,11 @@ class CrowdControl {
|
||||
|
||||
typedef struct Effect {
|
||||
uint32_t id;
|
||||
std::string type;
|
||||
uint32_t value;
|
||||
uint32_t value[2];
|
||||
std::string category;
|
||||
long timeRemaining;
|
||||
GameInteractionEffectBase *giEffect;
|
||||
int32_t paramMultiplier = 1;
|
||||
|
||||
// Metadata used while executing (only for timed effects)
|
||||
bool isPaused;
|
||||
@@ -88,12 +91,11 @@ class CrowdControl {
|
||||
void ListenToServer();
|
||||
void ProcessActiveEffects();
|
||||
|
||||
void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining,
|
||||
CrowdControl::EffectResult status);
|
||||
void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status);
|
||||
Effect* ParseMessage(char payload[512]);
|
||||
EffectResult ExecuteEffect(std::string effectId, uint32_t value, bool dryRun);
|
||||
void RemoveEffect(std::string effectId);
|
||||
bool SpawnEnemy(std::string effectId);
|
||||
EffectResult ExecuteEffect(Effect* effect);
|
||||
EffectResult CanApplyEffect(Effect *effect);
|
||||
EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult);
|
||||
|
||||
public:
|
||||
static CrowdControl* Instance;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
TEXT_CURSED_SKULLTULA_PEOPLE = 0x22,
|
||||
TEXT_DAMPES_DIARY = 0x5003,
|
||||
TEXT_BUY_BOMBCHU_10_PROMPT = 0x8C,
|
||||
TEXT_BUY_BOMBCHU_10_DESC = 0xBC,
|
||||
TEXT_GS_NO_FREEZE = 0xB4,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,30 +2,4 @@
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#define GRAVITY_LEVEL_NORMAL 1.0f
|
||||
#define GRAVITY_LEVEL_LIGHT 0.0f
|
||||
#define GRAVITY_LEVEL_HEAVY 2.0f
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// bools are exported as uint32_t for compatibility with C code
|
||||
extern uint32_t chaosEffectNoUI;
|
||||
extern uint32_t chaosEffectGiantLink;
|
||||
extern uint32_t chaosEffectMinishLink;
|
||||
extern uint32_t chaosEffectPaperLink;
|
||||
extern uint32_t chaosEffectResetLinkScale;
|
||||
extern uint32_t chaosEffectInvisibleLink;
|
||||
extern uint32_t chaosEffectOneHitKO;
|
||||
extern uint32_t chaosEffectPacifistMode;
|
||||
extern int32_t chaosEffectDefenseModifier;
|
||||
extern uint32_t chaosEffectNoZ;
|
||||
extern uint32_t chaosEffectReverseControls;
|
||||
|
||||
extern uint32_t chaosEffectGravityLevel;
|
||||
extern int32_t chaosEffectSpeedModifier;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void DebugConsole_Init(void);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
@@ -531,7 +531,7 @@ void PopulateActorDropdown(int i, std::vector<Actor*>& data) {
|
||||
|
||||
void DrawActorViewer(bool& open) {
|
||||
if (!open) {
|
||||
CVar_SetS32("gActorViewerEnabled", 0);
|
||||
CVarSetInteger("gActorViewerEnabled", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -541,8 +541,8 @@ void DrawActorViewer(bool& open) {
|
||||
return;
|
||||
}
|
||||
|
||||
static Actor display;
|
||||
static const Actor empty{};
|
||||
static Actor* display;
|
||||
static Actor empty{};
|
||||
static Actor* fetch = NULL;
|
||||
static ActorInfo newActor = {0,0, {0, 0, 0}, {0, 0, 0}};
|
||||
static ActorOverlay* dispOverlay;
|
||||
@@ -558,7 +558,7 @@ void DrawActorViewer(bool& open) {
|
||||
if (gPlayState != nullptr) {
|
||||
needs_reset = lastSceneId != gPlayState->sceneNum;
|
||||
if (needs_reset) {
|
||||
display = empty;
|
||||
display = ∅
|
||||
fetch = nullptr;
|
||||
dispOverlay = nullptr;
|
||||
actor = category = 0;
|
||||
@@ -591,7 +591,7 @@ void DrawActorViewer(bool& open) {
|
||||
|
||||
if (ImGui::Selectable(label.c_str())) {
|
||||
rm = LIST;
|
||||
display = *list[i];
|
||||
display = list[i];
|
||||
actor = i;
|
||||
filler = label;
|
||||
break;
|
||||
@@ -601,50 +601,62 @@ void DrawActorViewer(bool& open) {
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Selected Actor")) {
|
||||
dispOverlay = display.overlayEntry;
|
||||
dispOverlay = display->overlayEntry;
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Name: %s", dispOverlay != nullptr ? dispOverlay->name : "???");
|
||||
ImGui::Text("Description: %s", dispOverlay != nullptr ? GetActorDescription(display.id).c_str() : "???");
|
||||
ImGui::Text("Category: %s", dispOverlay != nullptr ? acMapping[display.category] : "???");
|
||||
ImGui::Text("ID: %d", display.id);
|
||||
ImGui::Text("Parameters: %d", display.params);
|
||||
ImGui::Text("Description: %s", dispOverlay != nullptr ? GetActorDescription(display->id).c_str() : "???");
|
||||
ImGui::Text("Category: %s", dispOverlay != nullptr ? acMapping[display->category] : "???");
|
||||
ImGui::Text("ID: %d", display->id);
|
||||
ImGui::Text("Parameters: %d", display->params);
|
||||
});
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Actor Position");
|
||||
ImGui::InputScalar("x pos", ImGuiDataType_Float, &display.world.pos.x);
|
||||
ImGui::InputScalar("x pos", ImGuiDataType_Float, &display->world.pos.x);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("y pos", ImGuiDataType_Float, &display.world.pos.y);
|
||||
ImGui::InputScalar("y pos", ImGuiDataType_Float, &display->world.pos.y);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("z pos", ImGuiDataType_Float, &display.world.pos.z);
|
||||
ImGui::InputScalar("z pos", ImGuiDataType_Float, &display->world.pos.z);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Actor Rotation");
|
||||
ImGui::InputScalar("x rot", ImGuiDataType_S16, &display.world.rot.x);
|
||||
ImGui::InputScalar("x rot", ImGuiDataType_S16, &display->world.rot.x);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("y rot", ImGuiDataType_S16, &display.world.rot.y);
|
||||
ImGui::InputScalar("y rot", ImGuiDataType_S16, &display->world.rot.y);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("z rot", ImGuiDataType_S16, &display.world.rot.z);
|
||||
ImGui::InputScalar("z rot", ImGuiDataType_S16, &display->world.rot.z);
|
||||
});
|
||||
|
||||
if (display.category == ACTORCAT_BOSS || display.category == ACTORCAT_ENEMY) {
|
||||
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display.colChkInfo.health);
|
||||
if (display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) {
|
||||
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health);
|
||||
UIWidgets::InsertHelpHoverText("Some actors might not use this!");
|
||||
}
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("flags");
|
||||
UIWidgets::DrawFlagArray32("flags", display->flags);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("bgCheckFlags");
|
||||
UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags);
|
||||
});
|
||||
|
||||
if (ImGui::Button("Refresh")) {
|
||||
PopulateActorDropdown(category, list);
|
||||
switch (rm) {
|
||||
case INTERACT:
|
||||
case HELD:
|
||||
case TARGET:
|
||||
display = *fetch;
|
||||
display = fetch;
|
||||
break;
|
||||
case LIST:
|
||||
display = *list[actor];
|
||||
display = list[actor];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -653,7 +665,7 @@ void DrawActorViewer(bool& open) {
|
||||
|
||||
if (ImGui::Button("Go to Actor")) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &display.world.pos);
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
|
||||
Math_Vec3f_Copy(&player->actor.home.pos, &player->actor.world.pos);
|
||||
}
|
||||
|
||||
@@ -661,7 +673,7 @@ void DrawActorViewer(bool& open) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->targetActor;
|
||||
if (fetch != NULL) {
|
||||
display = *fetch;
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = TARGET;
|
||||
@@ -672,7 +684,7 @@ void DrawActorViewer(bool& open) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->heldActor;
|
||||
if (fetch != NULL) {
|
||||
display = *fetch;
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = HELD;
|
||||
@@ -683,7 +695,7 @@ void DrawActorViewer(bool& open) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->interactRangeActor;
|
||||
if (fetch != NULL) {
|
||||
display = *fetch;
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = INTERACT;
|
||||
@@ -739,7 +751,7 @@ void DrawActorViewer(bool& open) {
|
||||
}
|
||||
|
||||
if (ImGui::Button("Spawn as Child")) {
|
||||
Actor* parent = &display;
|
||||
Actor* parent = display;
|
||||
if (parent != NULL) {
|
||||
if (newActor.id >= 0 && newActor.id < ACTOR_ID_MAX &&
|
||||
gActorOverlayTable[newActor.id].initInfo != NULL) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
@@ -53,7 +53,7 @@ static std::vector<Vtx> sphereVtx;
|
||||
// Draws the ImGui window for the collision viewer
|
||||
void DrawColViewerWindow(bool& open) {
|
||||
if (!open) {
|
||||
CVar_SetS32("gCollisionViewerEnabled", 0);
|
||||
CVarSetInteger("gCollisionViewerEnabled", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
|
||||
alpha = 0xFF;
|
||||
}
|
||||
|
||||
if (CVar_GetS32("gColViewerDecal", 0) != 0) {
|
||||
if (CVarGetInteger("gColViewerDecal", 0) != 0) {
|
||||
rm |= ZMODE_DEC;
|
||||
} else if (setting == ColRenderSetting::Transparent) {
|
||||
rm |= ZMODE_XLU;
|
||||
@@ -327,7 +327,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
|
||||
gfx.push_back(gsDPSetCycleType(G_CYC_1CYCLE));
|
||||
gfx.push_back(gsDPSetRenderMode(rm | blc1, rm | blc2));
|
||||
|
||||
if (CVar_GetS32("gColViewerShaded", 0) != 0) {
|
||||
if (CVarGetInteger("gColViewerShaded", 0) != 0) {
|
||||
gfx.push_back(gsDPSetCombineMode(G_CC_MODULATERGB_PRIM_ENVA, G_CC_MODULATERGB_PRIM_ENVA));
|
||||
gfx.push_back(gsSPLoadGeometryMode(G_CULL_BACK | G_ZBUFFER | G_LIGHTING));
|
||||
} else {
|
||||
@@ -340,9 +340,9 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
|
||||
|
||||
// Draws a dynapoly structure (scenes or Bg Actors)
|
||||
void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
|
||||
uint32_t colorR = CVar_GetS32("gColViewerColorNormalR", 255);
|
||||
uint32_t colorG = CVar_GetS32("gColViewerColorNormalG", 255);
|
||||
uint32_t colorB = CVar_GetS32("gColViewerColorNormalB", 255);
|
||||
uint32_t colorR = CVarGetInteger("gColViewerColorNormalR", 255);
|
||||
uint32_t colorG = CVarGetInteger("gColViewerColorNormalG", 255);
|
||||
uint32_t colorB = CVarGetInteger("gColViewerColorNormalB", 255);
|
||||
uint32_t colorA = 255;
|
||||
|
||||
uint32_t lastColorR = colorR;
|
||||
@@ -359,35 +359,35 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
|
||||
CollisionPoly* poly = &col->polyList[i];
|
||||
|
||||
if (SurfaceType_IsHookshotSurface(&gPlayState->colCtx, poly, bgId)) {
|
||||
colorR = CVar_GetS32("gColViewerColorHookshotR", 128);
|
||||
colorG = CVar_GetS32("gColViewerColorHookshotG", 128);
|
||||
colorB = CVar_GetS32("gColViewerColorHookshotB", 255);
|
||||
colorR = CVarGetInteger("gColViewerColorHookshotR", 128);
|
||||
colorG = CVarGetInteger("gColViewerColorHookshotG", 128);
|
||||
colorB = CVarGetInteger("gColViewerColorHookshotB", 255);
|
||||
} else if (func_80041D94(&gPlayState->colCtx, poly, bgId) > 0x01) {
|
||||
colorR = CVar_GetS32("gColViewerColorInteractableR", 192);
|
||||
colorG = CVar_GetS32("gColViewerColorInteractableG", 0);
|
||||
colorB = CVar_GetS32("gColViewerColorInteractableB", 192);
|
||||
colorR = CVarGetInteger("gColViewerColorInteractableR", 192);
|
||||
colorG = CVarGetInteger("gColViewerColorInteractableG", 0);
|
||||
colorB = CVarGetInteger("gColViewerColorInteractableB", 192);
|
||||
} else if (func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x0C) {
|
||||
colorR = CVar_GetS32("gColViewerColorVoidR", 255);
|
||||
colorG = CVar_GetS32("gColViewerColorVoidG", 0);
|
||||
colorB = CVar_GetS32("gColViewerColorVoidB", 0);
|
||||
colorR = CVarGetInteger("gColViewerColorVoidR", 255);
|
||||
colorG = CVarGetInteger("gColViewerColorVoidG", 0);
|
||||
colorB = CVarGetInteger("gColViewerColorVoidB", 0);
|
||||
} else if (SurfaceType_GetSceneExitIndex(&gPlayState->colCtx, poly, bgId) ||
|
||||
func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x05) {
|
||||
colorR = CVar_GetS32("gColViewerColorEntranceR", 0);
|
||||
colorG = CVar_GetS32("gColViewerColorEntranceG", 255);
|
||||
colorB = CVar_GetS32("gColViewerColorEntranceB", 0);
|
||||
colorR = CVarGetInteger("gColViewerColorEntranceR", 0);
|
||||
colorG = CVarGetInteger("gColViewerColorEntranceG", 255);
|
||||
colorB = CVarGetInteger("gColViewerColorEntranceB", 0);
|
||||
} else if (func_80041D4C(&gPlayState->colCtx, poly, bgId) != 0 ||
|
||||
SurfaceType_IsWallDamage(&gPlayState->colCtx, poly, bgId)) {
|
||||
colorR = CVar_GetS32("gColViewerColorSpecialSurfaceR", 192);
|
||||
colorG = CVar_GetS32("gColViewerColorSpecialSurfaceG", 255);
|
||||
colorB = CVar_GetS32("gColViewerColorSpecialSurfaceB", 192);
|
||||
colorR = CVarGetInteger("gColViewerColorSpecialSurfaceR", 192);
|
||||
colorG = CVarGetInteger("gColViewerColorSpecialSurfaceG", 255);
|
||||
colorB = CVarGetInteger("gColViewerColorSpecialSurfaceB", 192);
|
||||
} else if (SurfaceType_GetSlope(&gPlayState->colCtx, poly, bgId) == 0x01) {
|
||||
colorR = CVar_GetS32("gColViewerColorSlopeR", 255);
|
||||
colorG = CVar_GetS32("gColViewerColorSlopeG", 255);
|
||||
colorB = CVar_GetS32("gColViewerColorSlopeB", 128);
|
||||
colorR = CVarGetInteger("gColViewerColorSlopeR", 255);
|
||||
colorG = CVarGetInteger("gColViewerColorSlopeG", 255);
|
||||
colorB = CVarGetInteger("gColViewerColorSlopeB", 128);
|
||||
} else {
|
||||
colorR = CVar_GetS32("gColViewerColorNormalR", 255);
|
||||
colorG = CVar_GetS32("gColViewerColorNormalG", 255);
|
||||
colorB = CVar_GetS32("gColViewerColorNormalB", 255);
|
||||
colorR = CVarGetInteger("gColViewerColorNormalR", 255);
|
||||
colorG = CVarGetInteger("gColViewerColorNormalG", 255);
|
||||
colorB = CVarGetInteger("gColViewerColorNormalB", 255);
|
||||
}
|
||||
|
||||
if (colorR != lastColorR || colorG != lastColorG || colorB != lastColorB) {
|
||||
@@ -435,9 +435,9 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
|
||||
|
||||
// Draws the scene
|
||||
void DrawSceneCollision() {
|
||||
ColRenderSetting showSceneColSetting = (ColRenderSetting)CVar_GetS32("gColViewerScene", 0);
|
||||
ColRenderSetting showSceneColSetting = (ColRenderSetting)CVarGetInteger("gColViewerScene", 0);
|
||||
|
||||
if (showSceneColSetting == ColRenderSetting::Disabled || CVar_GetS32("gColViewerEnabled", 0) == 0) {
|
||||
if (showSceneColSetting == ColRenderSetting::Disabled || CVarGetInteger("gColViewerEnabled", 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -450,8 +450,8 @@ void DrawSceneCollision() {
|
||||
|
||||
// Draws all Bg Actors
|
||||
void DrawBgActorCollision() {
|
||||
ColRenderSetting showBgActorSetting = (ColRenderSetting)CVar_GetS32("gColViewerBgActors", 0);
|
||||
if (showBgActorSetting == ColRenderSetting::Disabled || CVar_GetS32("gColViewerEnabled", 0) == 0) {
|
||||
ColRenderSetting showBgActorSetting = (ColRenderSetting)CVarGetInteger("gColViewerBgActors", 0);
|
||||
if (showBgActorSetting == ColRenderSetting::Disabled || CVarGetInteger("gColViewerEnabled", 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -575,8 +575,8 @@ void DrawColCheckList(std::vector<Gfx>& dl, Collider** objects, int32_t count) {
|
||||
|
||||
// Draws all Col Check objects
|
||||
void DrawColCheckCollision() {
|
||||
ColRenderSetting showColCheckSetting = (ColRenderSetting)CVar_GetS32("gColViewerColCheck", 0);
|
||||
if (showColCheckSetting == ColRenderSetting::Disabled || CVar_GetS32("gColViewerEnabled", 0) == 0) {
|
||||
ColRenderSetting showColCheckSetting = (ColRenderSetting)CVarGetInteger("gColViewerColCheck", 0);
|
||||
if (showColCheckSetting == ColRenderSetting::Disabled || CVarGetInteger("gColViewerEnabled", 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -586,14 +586,14 @@ void DrawColCheckCollision() {
|
||||
|
||||
CollisionCheckContext& col = gPlayState->colChkCtx;
|
||||
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVar_GetS32("gColViewerColorOCR", 255), CVar_GetS32("gColViewerColorOCG", 255),
|
||||
CVar_GetS32("gColViewerColorOCB", 255), 255));
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorOCR", 255), CVarGetInteger("gColViewerColorOCG", 255),
|
||||
CVarGetInteger("gColViewerColorOCB", 255), 255));
|
||||
DrawColCheckList(dl, col.colOC, col.colOCCount);
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVar_GetS32("gColViewerColorACR", 0), CVar_GetS32("gColViewerColorACG", 0),
|
||||
CVar_GetS32("gColViewerColorACB", 255), 255));
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorACR", 0), CVarGetInteger("gColViewerColorACG", 0),
|
||||
CVarGetInteger("gColViewerColorACB", 255), 255));
|
||||
DrawColCheckList(dl, col.colAC, col.colACCount);
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVar_GetS32("gColViewerColorATR", 255), CVar_GetS32("gColViewerColorATG", 0),
|
||||
CVar_GetS32("gColViewerColorATB", 0), 255));
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorATR", 255), CVarGetInteger("gColViewerColorATG", 0),
|
||||
CVarGetInteger("gColViewerColorATB", 0), 255));
|
||||
|
||||
DrawColCheckList(dl, col.colAT, col.colATCount);
|
||||
}
|
||||
@@ -628,8 +628,8 @@ extern "C" f32 zdWaterBoxMinY;
|
||||
|
||||
// Draws all waterboxes
|
||||
void DrawWaterboxList() {
|
||||
ColRenderSetting showWaterboxSetting = (ColRenderSetting)CVar_GetS32("gColViewerWaterbox", 0);
|
||||
if (showWaterboxSetting == ColRenderSetting::Disabled || CVar_GetS32("gColViewerEnabled", 0) == 0) {
|
||||
ColRenderSetting showWaterboxSetting = (ColRenderSetting)CVarGetInteger("gColViewerWaterbox", 0);
|
||||
if (showWaterboxSetting == ColRenderSetting::Disabled || CVarGetInteger("gColViewerEnabled", 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -637,9 +637,9 @@ void DrawWaterboxList() {
|
||||
InitGfx(dl, showWaterboxSetting);
|
||||
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
|
||||
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVar_GetS32("gColViewerColorWaterboxR", 0),
|
||||
CVar_GetS32("gColViewerColorWaterboxG", 0),
|
||||
CVar_GetS32("gColViewerColorWaterboxB", 255), 255));
|
||||
dl.push_back(gsDPSetPrimColor(0, 0, CVarGetInteger("gColViewerColorWaterboxR", 0),
|
||||
CVarGetInteger("gColViewerColorWaterboxG", 0),
|
||||
CVarGetInteger("gColViewerColorWaterboxB", 255), 255));
|
||||
|
||||
CollisionHeader* col = gPlayState->colCtx.colHeader;
|
||||
for (int32_t waterboxIndex = 0; waterboxIndex < col->numWaterBoxes; waterboxIndex++) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
@@ -749,28 +749,7 @@ void DrawInventoryTab() {
|
||||
}
|
||||
|
||||
// Draw a flag bitfield as an grid of checkboxes
|
||||
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) {
|
||||
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 DrawFlagArray16(const FlagTable& flagTable, uint16_t row, uint16_t& flags) {
|
||||
void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& flags) {
|
||||
ImGui::PushID((std::to_string(row) + flagTable.name).c_str());
|
||||
for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) {
|
||||
ImGui::SameLine();
|
||||
@@ -798,6 +777,36 @@ void DrawFlagArray16(const FlagTable& flagTable, uint16_t row, uint16_t& flags)
|
||||
}
|
||||
|
||||
void DrawFlagsTab() {
|
||||
if (ImGui::TreeNode("Player State")) {
|
||||
if (gPlayState != nullptr) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("stateFlags1");
|
||||
UIWidgets::DrawFlagArray32("stateFlags1", player->stateFlags1);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("stateFlags2");
|
||||
UIWidgets::DrawFlagArray32("stateFlags2", player->stateFlags2);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("stateFlags3");
|
||||
UIWidgets::DrawFlagArray8("stateFlags3", player->stateFlags3);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("unk_6AE");
|
||||
UIWidgets::DrawFlagArray16("unk_6AE", player->unk_6AE);
|
||||
});
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Current Scene")) {
|
||||
if (gPlayState != nullptr) {
|
||||
ActorContext* act = &gPlayState->actorCtx;
|
||||
@@ -805,7 +814,15 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Switch");
|
||||
UIWidgets::InsertHelpHoverText("Permanently-saved switch flags");
|
||||
DrawFlagArray32("Switch", act->flags.swch);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Switch")) {
|
||||
act->flags.swch = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Switch")) {
|
||||
act->flags.swch = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Switch", act->flags.swch);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -813,13 +830,29 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Temp Switch");
|
||||
UIWidgets::InsertHelpHoverText("Temporary switch flags. Unset on scene transitions");
|
||||
DrawFlagArray32("Temp Switch", act->flags.tempSwch);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Temp Switch")) {
|
||||
act->flags.tempSwch = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Temp Switch")) {
|
||||
act->flags.tempSwch = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Temp Switch", act->flags.tempSwch);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Clear");
|
||||
UIWidgets::InsertHelpHoverText("Permanently-saved room-clear flags");
|
||||
DrawFlagArray32("Clear", act->flags.clear);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Clear")) {
|
||||
act->flags.clear = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Clear")) {
|
||||
act->flags.clear = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Clear", act->flags.clear);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -827,13 +860,29 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Temp Clear");
|
||||
UIWidgets::InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions");
|
||||
DrawFlagArray32("Temp Clear", act->flags.tempClear);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Temp Clear")) {
|
||||
act->flags.tempClear = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Temp Clear")) {
|
||||
act->flags.tempClear = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Temp Clear", act->flags.tempClear);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Collect");
|
||||
UIWidgets::InsertHelpHoverText("Permanently-saved collect flags");
|
||||
DrawFlagArray32("Collect", act->flags.collect);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Collect")) {
|
||||
act->flags.collect = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Collect")) {
|
||||
act->flags.collect = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Collect", act->flags.collect);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -841,13 +890,29 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Temp Collect");
|
||||
UIWidgets::InsertHelpHoverText("Temporary collect flags. Unset on scene transitions");
|
||||
DrawFlagArray32("Temp Collect", act->flags.tempCollect);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Temp Collect")) {
|
||||
act->flags.tempCollect = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Temp Collect")) {
|
||||
act->flags.tempCollect = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Temp Collect", act->flags.tempCollect);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Chest");
|
||||
UIWidgets::InsertHelpHoverText("Permanently-saved chest flags");
|
||||
DrawFlagArray32("Chest", act->flags.chest);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set All##Chest")) {
|
||||
act->flags.chest = UINT32_MAX;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear All##Chest")) {
|
||||
act->flags.chest = 0;
|
||||
}
|
||||
UIWidgets::DrawFlagArray32("Chest", act->flags.chest);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -913,7 +978,7 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Switch");
|
||||
UIWidgets::InsertHelpHoverText("Switch flags");
|
||||
DrawFlagArray32("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch);
|
||||
UIWidgets::DrawFlagArray32("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -921,13 +986,13 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Clear");
|
||||
UIWidgets::InsertHelpHoverText("Room-clear flags");
|
||||
DrawFlagArray32("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear);
|
||||
UIWidgets::DrawFlagArray32("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Collect");
|
||||
UIWidgets::InsertHelpHoverText("Collect flags");
|
||||
DrawFlagArray32("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect);
|
||||
UIWidgets::DrawFlagArray32("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -935,13 +1000,13 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Chest");
|
||||
UIWidgets::InsertHelpHoverText("Chest flags");
|
||||
DrawFlagArray32("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest);
|
||||
UIWidgets::DrawFlagArray32("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest);
|
||||
});
|
||||
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Rooms");
|
||||
UIWidgets::InsertHelpHoverText("Flags for visted rooms");
|
||||
DrawFlagArray32("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms);
|
||||
UIWidgets::DrawFlagArray32("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -949,7 +1014,7 @@ void DrawFlagsTab() {
|
||||
DrawGroupWithBorder([&]() {
|
||||
ImGui::Text("Floors");
|
||||
UIWidgets::InsertHelpHoverText("Flags for visted floors");
|
||||
DrawFlagArray32("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors);
|
||||
UIWidgets::DrawFlagArray32("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors);
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
@@ -1027,19 +1092,19 @@ void DrawFlagsTab() {
|
||||
ImGui::Text(fmt::format("{:<2x}", j).c_str());
|
||||
switch (flagTable.flagTableType) {
|
||||
case EVENT_CHECK_INF:
|
||||
DrawFlagArray16(flagTable, j, gSaveContext.eventChkInf[j]);
|
||||
DrawFlagTableArray16(flagTable, j, gSaveContext.eventChkInf[j]);
|
||||
break;
|
||||
case ITEM_GET_INF:
|
||||
DrawFlagArray16(flagTable, j, gSaveContext.itemGetInf[j]);
|
||||
DrawFlagTableArray16(flagTable, j, gSaveContext.itemGetInf[j]);
|
||||
break;
|
||||
case INF_TABLE:
|
||||
DrawFlagArray16(flagTable, j, gSaveContext.infTable[j]);
|
||||
DrawFlagTableArray16(flagTable, j, gSaveContext.infTable[j]);
|
||||
break;
|
||||
case EVENT_INF:
|
||||
DrawFlagArray16(flagTable, j, gSaveContext.eventInf[j]);
|
||||
DrawFlagTableArray16(flagTable, j, gSaveContext.eventInf[j]);
|
||||
break;
|
||||
case RANDOMIZER_INF:
|
||||
DrawFlagArray16(flagTable, j, gSaveContext.randomizerInf[j]);
|
||||
DrawFlagTableArray16(flagTable, j, gSaveContext.randomizerInf[j]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -1622,7 +1687,7 @@ void DrawPlayerTab() {
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL);
|
||||
|
||||
if (CVar_GetS32("gDpadEquips", 0)) {
|
||||
if (CVarGetInteger("gDpadEquips", 0)) {
|
||||
ImGui::NewLine();
|
||||
ImGui::Text("Current D-pad Equips");
|
||||
ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working
|
||||
@@ -1663,7 +1728,7 @@ void DrawPlayerTab() {
|
||||
|
||||
void DrawSaveEditor(bool& open) {
|
||||
if (!open) {
|
||||
CVar_SetS32("gSaveEditorEnabled", 0);
|
||||
CVarSetInteger("gSaveEditorEnabled", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const std::vector<FlagTable> flagTables = {
|
||||
{ 0x09, "Used Deku Tree Blue Warp" },
|
||||
{ 0x0A, "Played Saria's Song for Mido as Adult" },
|
||||
{ 0x0C, "Met Deku Tree" },
|
||||
{ 0x0F, "Spoke to Mido about Saria's whereabouts" },
|
||||
{ 0x10, "Spoke to Child Malon at Castle or Market" },
|
||||
{ 0x11, "Spoke to Ingo at Ranch before Talon returns" },
|
||||
{ 0x12, "Obtained Pocket Egg" },
|
||||
@@ -219,7 +220,7 @@ const std::vector<FlagTable> flagTables = {
|
||||
{ 0x24, "Spoke to Kokiri Boy Cutting Grass" },
|
||||
{ 0x26, "Spoke to Kokiri Girl on Shop Awning" },
|
||||
{ 0x28, "Spoke to Kokiri Girl About Training Center" },
|
||||
{ 0x31, "Spoke to Kokiri Boy on Bed in Mido's House" },
|
||||
{ 0x41, "Spoke to Kokiri Boy on Bed in Mido's House" },
|
||||
{ 0x51, "Spoke to Kokiri Girl in Saria's House" },
|
||||
{ 0x59, "Spoke to Know-It-All Bro. About Temple" },
|
||||
{ 0x61, "Spoke to Know-It-All Bro. About Saria" },
|
||||
@@ -495,5 +496,7 @@ const std::vector<FlagTable> flagTables = {
|
||||
{ RAND_INF_ADULT_TRADES_DMT_TRADE_BROKEN_SWORD, "ADULT_TRADES_DMT_TRADE_BROKEN_SWORD" },
|
||||
{ RAND_INF_ADULT_TRADES_LH_TRADE_FROG, "ADULT_TRADES_LH_TRADE_FROG" },
|
||||
{ RAND_INF_ADULT_TRADES_DMT_TRADE_EYEDROPS, "ADULT_TRADES_DMT_TRADE_EYEDROPS" },
|
||||
|
||||
{ RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD, "KAK_100_GOLD_SKULLTULA_REWARD" },
|
||||
} },
|
||||
};
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "debugSaveEditor.h"
|
||||
#include "colViewer.h"
|
||||
#include "actorViewer.h"
|
||||
#include "dlViewer.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -9,6 +10,7 @@ void Debug_Init(void) {
|
||||
InitSaveEditor();
|
||||
InitColViewer();
|
||||
InitActorViewer();
|
||||
InitDLViewer();
|
||||
}
|
||||
|
||||
void Debug_Draw(void) {
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "actorViewer.h"
|
||||
#include "../../util.h"
|
||||
#include "../../UIWidgets.hpp"
|
||||
#include <ImGuiImpl.h>
|
||||
#include "ResourceMgr.h"
|
||||
#include "DisplayList.h"
|
||||
#include "../../OTRGlobals.h"
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#include "z64math.h"
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
extern PlayState* gPlayState;
|
||||
|
||||
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
|
||||
}
|
||||
|
||||
char searchString[64] = "";
|
||||
int displayListsSearchResultsCount;
|
||||
char** displayListsSearchResults;
|
||||
char* activeDisplayList = nullptr;
|
||||
|
||||
std::map<int, std::string> cmdMap = {
|
||||
{ G_SETPRIMCOLOR, "gsDPSetPrimColor" },
|
||||
{ G_SETENVCOLOR, "gsDPSetEnvColor" },
|
||||
{ G_RDPPIPESYNC, "gsDPPipeSync" },
|
||||
{ G_SETGRAYSCALE, "gsSPGrayscale" },
|
||||
{ G_SETINTENSITY, "gsDPSetGrayscaleColor" },
|
||||
{ G_LOADTLUT, "gsDPLoadTLUT" },
|
||||
{ G_ENDDL, "gsSPEndDisplayList" },
|
||||
};
|
||||
|
||||
void DrawDLViewer(bool& open) {
|
||||
if (!open) {
|
||||
CVarSetInteger("gDLViewerEnabled", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Display List Viewer", &open, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) {
|
||||
displayListsSearchResults = ResourceMgr_ListFiles(("*" + std::string(searchString) + "*DL").c_str(), &displayListsSearchResultsCount);
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Active Display List", activeDisplayList)) {
|
||||
for (int i = 0; i < displayListsSearchResultsCount; i++) {
|
||||
if (ImGui::Selectable(displayListsSearchResults[i])) {
|
||||
activeDisplayList = displayListsSearchResults[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (activeDisplayList != nullptr) {
|
||||
auto res = std::static_pointer_cast<Ship::DisplayList>(OTRGlobals::Instance->context->GetResourceManager()->LoadResource(activeDisplayList));
|
||||
for (int i = 0; i < res->Instructions.size(); i++) {
|
||||
std::string id = "##CMD" + std::to_string(i);
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[i];
|
||||
int cmd = gfx->words.w0 >> 24;
|
||||
if (cmdMap.find(cmd) == cmdMap.end()) continue;
|
||||
|
||||
std::string cmdLabel = cmdMap.at(cmd);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushItemWidth(25.0f);
|
||||
ImGui::Text("%d", i);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(150.0f);
|
||||
if (ImGui::BeginCombo(("CMD" + id).c_str(), cmdLabel.c_str())) {
|
||||
if (ImGui::Selectable("gsDPSetPrimColor") && cmd != G_SETPRIMCOLOR) {
|
||||
*gfx = gsDPSetPrimColor(0, 0, 0, 0, 0, 255);
|
||||
}
|
||||
if (ImGui::Selectable("gsDPSetEnvColor")) {
|
||||
*gfx = gsDPSetEnvColor(0, 0, 0, 255);
|
||||
}
|
||||
if (ImGui::Selectable("gsDPPipeSync")) {
|
||||
*gfx = gsDPPipeSync();
|
||||
}
|
||||
if (ImGui::Selectable("gsSPGrayscale")) {
|
||||
*gfx = gsSPGrayscale(true);
|
||||
}
|
||||
if (ImGui::Selectable("gsDPSetGrayscaleColor")) {
|
||||
*gfx = gsDPSetGrayscaleColor(0, 0, 0, 255);
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
if (gfx->words.w0 >> 24 == G_SETPRIMCOLOR || gfx->words.w0 >> 24 == G_SETINTENSITY || gfx->words.w0 >> 24 == G_SETENVCOLOR) {
|
||||
uint8_t r = _SHIFTR(gfx->words.w1, 24, 8);
|
||||
uint8_t g = _SHIFTR(gfx->words.w1, 16, 8);
|
||||
uint8_t b = _SHIFTR(gfx->words.w1, 8, 8);
|
||||
uint8_t a = _SHIFTR(gfx->words.w1, 0, 8);
|
||||
ImGui::PushItemWidth(30.0f);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::InputScalar(("r" + id).c_str(), ImGuiDataType_U8, &r)) {
|
||||
gfx->words.w1 = _SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::InputScalar(("g" + id).c_str(), ImGuiDataType_U8, &g)) {
|
||||
gfx->words.w1 = _SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::InputScalar(("b" + id).c_str(), ImGuiDataType_U8, &b)) {
|
||||
gfx->words.w1 = _SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::InputScalar(("a" + id).c_str(), ImGuiDataType_U8, &a)) {
|
||||
gfx->words.w1 = _SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
if (gfx->words.w0 >> 24 == G_RDPPIPESYNC) {
|
||||
}
|
||||
if (gfx->words.w0 >> 24 == G_SETGRAYSCALE) {
|
||||
bool* state = (bool*)&gfx->words.w1;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox(("state" + id).c_str(), state)) {
|
||||
//
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void InitDLViewer() {
|
||||
SohImGui::AddWindow("Developer Tools", "Display List Viewer", DrawDLViewer);
|
||||
|
||||
displayListsSearchResults = ResourceMgr_ListFiles("*DL", &displayListsSearchResultsCount);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void InitDLViewer();
|
||||
@@ -232,7 +232,7 @@ extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t *actorId, f32 *po
|
||||
}
|
||||
|
||||
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) {
|
||||
if (CVar_GetS32("gSeededRandomizedEnemies", 0) && gSaveContext.n64ddFlag) {
|
||||
if (CVarGetInteger("gSeededRandomizedEnemies", 0) && gSaveContext.n64ddFlag) {
|
||||
uint32_t finalSeed = seed + gSaveContext.seedIcons[0] + gSaveContext.seedIcons[1] + gSaveContext.seedIcons[2] +
|
||||
gSaveContext.seedIcons[3] + gSaveContext.seedIcons[4];
|
||||
Random_Init(finalSeed);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
typedef struct EnemyEntry {
|
||||
int16_t id;
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
GameInteractionEffects is used in conjunction with GameInteractor.
|
||||
|
||||
It's intended to be used in places that want to interact with the game
|
||||
while having checks built-in for if said effect is able to be executed.
|
||||
|
||||
Effects that can last for a certain amount of time (timed effects)
|
||||
have functions to both enable and disable said effect.
|
||||
*/
|
||||
|
||||
#include "GameInteractionEffect.h"
|
||||
#include "GameInteractor.h"
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractionEffectBase::Apply() {
|
||||
GameInteractionEffectQueryResult result = CanBeApplied();
|
||||
if (result != GameInteractionEffectQueryResult::Possible) {
|
||||
return result;
|
||||
}
|
||||
|
||||
_Apply();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// For most effects, CanBeRemoved is the same as CanBeApplied. When its not: please override `CanBeRemoved`.
|
||||
GameInteractionEffectQueryResult GameInteractionEffectBase::CanBeRemoved() {
|
||||
return CanBeApplied();
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractionEffectBase::Remove() {
|
||||
GameInteractionEffectQueryResult result = CanBeRemoved();
|
||||
if (result != GameInteractionEffectQueryResult::Possible) {
|
||||
return result;
|
||||
}
|
||||
|
||||
_Remove();
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace GameInteractionEffect {
|
||||
|
||||
// MARK: - ModifyHeartContainers
|
||||
GameInteractionEffectQueryResult ModifyHeartContainers::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if (
|
||||
(parameter > 0 && (gSaveContext.healthCapacity + (parameter * 0x10) > 0x140)) ||
|
||||
(parameter < 0 && (gSaveContext.healthCapacity + (parameter * 0x10) < 0x10))
|
||||
) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
}
|
||||
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
|
||||
void ModifyHeartContainers::_Apply() {
|
||||
GameInteractor::RawAction::AddOrRemoveHealthContainers(parameter);
|
||||
}
|
||||
|
||||
// MARK: - FillMagic
|
||||
GameInteractionEffectQueryResult FillMagic::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if (!gSaveContext.isMagicAcquired || gSaveContext.magic >= ((gSaveContext.isDoubleMagicAcquired + 1) * 48)) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void FillMagic::_Apply() {
|
||||
GameInteractor::RawAction::AddOrRemoveMagic(96);
|
||||
}
|
||||
|
||||
// MARK: - EmptyMagic
|
||||
GameInteractionEffectQueryResult EmptyMagic::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if (!gSaveContext.isMagicAcquired || gSaveContext.magic <= 0) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void EmptyMagic::_Apply() {
|
||||
GameInteractor::RawAction::AddOrRemoveMagic(-96);
|
||||
}
|
||||
|
||||
// MARK: - ModifyRupees
|
||||
GameInteractionEffectQueryResult ModifyRupees::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if (
|
||||
(parameter < 0 && gSaveContext.rupees <= 0) ||
|
||||
(parameter > 0 && gSaveContext.rupees >= CUR_CAPACITY(UPG_WALLET))
|
||||
) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ModifyRupees::_Apply() {
|
||||
Rupees_ChangeBy(parameter);
|
||||
}
|
||||
|
||||
// MARK: - NoUI
|
||||
GameInteractionEffectQueryResult NoUI::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void NoUI::_Apply() {
|
||||
GameInteractor::State::NoUIActive = 1;
|
||||
}
|
||||
void NoUI::_Remove() {
|
||||
GameInteractor::State::NoUIActive = 0;
|
||||
}
|
||||
|
||||
// MARK: - ModifyGravity
|
||||
GameInteractionEffectQueryResult ModifyGravity::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ModifyGravity::_Apply() {
|
||||
GameInteractor::State::GravityLevel = (GIGravityLevel)parameter;
|
||||
}
|
||||
void ModifyGravity::_Remove() {
|
||||
GameInteractor::State::GravityLevel = GI_GRAVITY_LEVEL_NORMAL;
|
||||
}
|
||||
|
||||
// MARK: - ModifyHealth
|
||||
GameInteractionEffectQueryResult ModifyHealth::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if (
|
||||
(parameter > 0 && gSaveContext.health == gSaveContext.healthCapacity)
|
||||
|| (parameter < 0 && (gSaveContext.health + (16 * parameter) <= 0))
|
||||
) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
}
|
||||
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
void ModifyHealth::_Apply() {
|
||||
GameInteractor::RawAction::HealOrDamagePlayer(parameter);
|
||||
}
|
||||
|
||||
// MARK: - SetPlayerHealth
|
||||
GameInteractionEffectQueryResult SetPlayerHealth::CanBeApplied() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void SetPlayerHealth::_Apply() {
|
||||
GameInteractor::RawAction::SetPlayerHealth(parameter);
|
||||
}
|
||||
|
||||
// MARK: - FreezePlayer
|
||||
GameInteractionEffectQueryResult FreezePlayer::CanBeApplied() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void FreezePlayer::_Apply() {
|
||||
GameInteractor::RawAction::FreezePlayer();
|
||||
}
|
||||
|
||||
// MARK: - BurnPlayer
|
||||
GameInteractionEffectQueryResult BurnPlayer::CanBeApplied() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void BurnPlayer::_Apply() {
|
||||
GameInteractor::RawAction::BurnPlayer();
|
||||
}
|
||||
|
||||
// MARK: - ElectrocutePlayer
|
||||
GameInteractionEffectQueryResult ElectrocutePlayer::CanBeApplied() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused() || !PlayerGrounded(player)) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ElectrocutePlayer::_Apply() {
|
||||
GameInteractor::RawAction::ElectrocutePlayer();
|
||||
}
|
||||
|
||||
// MARK: - KnockbackPlayer
|
||||
GameInteractionEffectQueryResult KnockbackPlayer::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void KnockbackPlayer::_Apply() {
|
||||
GameInteractor::RawAction::KnockbackPlayer(parameter);
|
||||
}
|
||||
|
||||
// MARK: - ModifyLinkSize
|
||||
GameInteractionEffectQueryResult ModifyLinkSize::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ModifyLinkSize::_Apply() {
|
||||
GameInteractor::State::LinkSize = (GILinkSize)parameter;
|
||||
}
|
||||
void ModifyLinkSize::_Remove() {
|
||||
GameInteractor::State::LinkSize = GI_LINK_SIZE_RESET;
|
||||
}
|
||||
|
||||
// MARK: - InvisibleLink
|
||||
GameInteractionEffectQueryResult InvisibleLink::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void InvisibleLink::_Apply() {
|
||||
GameInteractor::RawAction::SetLinkInvisibility(true);
|
||||
}
|
||||
void InvisibleLink::_Remove() {
|
||||
GameInteractor::RawAction::SetLinkInvisibility(false);
|
||||
}
|
||||
|
||||
// MARK: - PacifistMode
|
||||
GameInteractionEffectQueryResult PacifistMode::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void PacifistMode::_Apply() {
|
||||
GameInteractor::State::SetPacifistMode(true);
|
||||
}
|
||||
void PacifistMode::_Remove() {
|
||||
GameInteractor::State::SetPacifistMode(false);
|
||||
}
|
||||
|
||||
// MARK: - DisableZTargeting
|
||||
GameInteractionEffectQueryResult DisableZTargeting::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void DisableZTargeting::_Apply() {
|
||||
GameInteractor::State::DisableZTargetingActive = 1;
|
||||
}
|
||||
void DisableZTargeting::_Remove() {
|
||||
GameInteractor::State::DisableZTargetingActive = 0;
|
||||
}
|
||||
|
||||
// MARK: - WeatherRainstorm
|
||||
GameInteractionEffectQueryResult WeatherRainstorm::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void WeatherRainstorm::_Apply() {
|
||||
GameInteractor::RawAction::SetWeatherStorm(true);
|
||||
}
|
||||
void WeatherRainstorm::_Remove() {
|
||||
GameInteractor::RawAction::SetWeatherStorm(false);
|
||||
}
|
||||
|
||||
// MARK: - ReverseControls
|
||||
GameInteractionEffectQueryResult ReverseControls::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ReverseControls::_Apply() {
|
||||
GameInteractor::State::ReverseControlsActive = 1;
|
||||
}
|
||||
void ReverseControls::_Remove() {
|
||||
GameInteractor::State::ReverseControlsActive = 0;
|
||||
}
|
||||
|
||||
// MARK: - ForceEquipBoots
|
||||
GameInteractionEffectQueryResult ForceEquipBoots::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ForceEquipBoots::_Apply() {
|
||||
GameInteractor::RawAction::ForceEquipBoots(parameter);
|
||||
}
|
||||
void ForceEquipBoots::_Remove() {
|
||||
GameInteractor::RawAction::ForceEquipBoots(PLAYER_BOOTS_KOKIRI);
|
||||
}
|
||||
|
||||
// MARK: - ModifyRunSpeedModifier
|
||||
GameInteractionEffectQueryResult ModifyRunSpeedModifier::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ModifyRunSpeedModifier::_Apply() {
|
||||
GameInteractor::State::RunSpeedModifier = parameter;
|
||||
}
|
||||
void ModifyRunSpeedModifier::_Remove() {
|
||||
GameInteractor::State::RunSpeedModifier = 0;
|
||||
}
|
||||
|
||||
// MARK: - OneHitKO
|
||||
GameInteractionEffectQueryResult OneHitKO::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void OneHitKO::_Apply() {
|
||||
GameInteractor::State::OneHitKOActive = 1;
|
||||
}
|
||||
void OneHitKO::_Remove() {
|
||||
GameInteractor::State::OneHitKOActive = 0;
|
||||
}
|
||||
|
||||
// MARK: - IncreaseDamageTaken
|
||||
GameInteractionEffectQueryResult ModifyDefenseModifier::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void ModifyDefenseModifier::_Apply() {
|
||||
GameInteractor::State::DefenseModifier = parameter;
|
||||
}
|
||||
void ModifyDefenseModifier::_Remove() {
|
||||
GameInteractor::State::DefenseModifier = 0;
|
||||
}
|
||||
|
||||
// MARK: - GiveDekuShield
|
||||
GameInteractionEffectQueryResult GiveDekuShield::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else if ((Item_CheckObtainability(ITEM_SHIELD_DEKU) != ITEM_NONE)) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void GiveDekuShield::_Apply() {
|
||||
GameInteractor::RawAction::GiveDekuShield();
|
||||
}
|
||||
|
||||
// MARK: - SpawnCuccoStorm
|
||||
GameInteractionEffectQueryResult SpawnCuccoStorm::CanBeApplied() {
|
||||
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
} else {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
}
|
||||
void SpawnCuccoStorm::_Apply() {
|
||||
GameInteractor::RawAction::SpawnCuccoStorm();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef GameInteractionEffect_h
|
||||
#define GameInteractionEffect_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
enum GameInteractionEffectQueryResult {
|
||||
Possible = 0x00,
|
||||
TemporarilyNotPossible = 0x01,
|
||||
NotPossible = 0xFF
|
||||
};
|
||||
|
||||
class GameInteractionEffectBase {
|
||||
public:
|
||||
virtual GameInteractionEffectQueryResult CanBeApplied() = 0;
|
||||
virtual GameInteractionEffectQueryResult CanBeRemoved();
|
||||
GameInteractionEffectQueryResult Apply();
|
||||
GameInteractionEffectQueryResult Remove();
|
||||
int32_t parameter;
|
||||
protected:
|
||||
virtual void _Apply() = 0;
|
||||
virtual void _Remove() {};
|
||||
};
|
||||
|
||||
namespace GameInteractionEffect {
|
||||
class ModifyHeartContainers: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class FillMagic: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class EmptyMagic: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ModifyRupees: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class NoUI: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyGravity: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyHealth: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SetPlayerHealth: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class FreezePlayer: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class BurnPlayer: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ElectrocutePlayer: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class KnockbackPlayer: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class ModifyLinkSize: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class InvisibleLink : public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class PacifistMode : public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class DisableZTargeting: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class WeatherRainstorm: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ReverseControls: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ForceEquipBoots: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyRunSpeedModifier: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class OneHitKO : public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class ModifyDefenseModifier: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
void _Remove() override;
|
||||
};
|
||||
|
||||
class GiveDekuShield: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
|
||||
class SpawnCuccoStorm: public GameInteractionEffectBase {
|
||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||
void _Apply() override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif /* GameInteractionEffect_h */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
GameInteractor is meant to be used for interacting with the game (yup...).
|
||||
It exposes functions that directly modify, add or remove game related elements.
|
||||
|
||||
GameInteractionEffects.cpp is used when code that needs these
|
||||
functions also need a check wether a command can be run or not.
|
||||
|
||||
If these checks need to happen wherever GameInteractor functions are needed, the
|
||||
GameInteractor functions can be called directly.
|
||||
*/
|
||||
|
||||
#include "GameInteractor.h"
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include "variables.h"
|
||||
#include "macros.h"
|
||||
#include "functions.h"
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#include "overlays/actors/ovl_En_Niw/z_en_niw.h"
|
||||
|
||||
// MARK: - Effects
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractor::CanApplyEffect(GameInteractionEffectBase* effect) {
|
||||
return effect->CanBeApplied();
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractor::ApplyEffect(GameInteractionEffectBase* effect) {
|
||||
return effect->Apply();
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractor::RemoveEffect(GameInteractionEffectBase* effect) {
|
||||
return effect->Remove();
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
bool GameInteractor::IsSaveLoaded() {
|
||||
Player* player;
|
||||
if (gPlayState != NULL) {
|
||||
player = GET_PLAYER(gPlayState);
|
||||
}
|
||||
return (gPlayState == NULL || player == NULL || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) ? false : true;
|
||||
}
|
||||
|
||||
bool GameInteractor::IsGameplayPaused() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
return (Player_InBlockingCsMode(gPlayState, player) || gPlayState->pauseCtx.state != 0 || gPlayState->msgCtx.msgMode != 0) ? true : false;
|
||||
}
|
||||
|
||||
bool GameInteractor::CanSpawnEnemy() {
|
||||
return GameInteractor::IsSaveLoaded() && !GameInteractor::IsGameplayPaused();
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef GameInteractor_h
|
||||
#define GameInteractor_h
|
||||
|
||||
#include "GameInteractionEffect.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ GI_LINK_SIZE_NORMAL,
|
||||
/* 0x01 */ GI_LINK_SIZE_GIANT,
|
||||
/* 0x02 */ GI_LINK_SIZE_MINISH,
|
||||
/* 0x03 */ GI_LINK_SIZE_PAPER,
|
||||
/* 0x04 */ GI_LINK_SIZE_RESET
|
||||
} GILinkSize;
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ GI_GRAVITY_LEVEL_LIGHT,
|
||||
/* 0x01 */ GI_GRAVITY_LEVEL_NORMAL,
|
||||
/* 0x02 */ GI_GRAVITY_LEVEL_HEAVY,
|
||||
} GIGravityLevel;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
uint8_t GameInteractor_NoUIActive();
|
||||
GILinkSize GameInteractor_GetLinkSize();
|
||||
void GameInteractor_SetLinkSize(GILinkSize size);
|
||||
uint8_t GameInteractor_InvisibleLinkActive();
|
||||
uint8_t GameInteractor_OneHitKOActive();
|
||||
uint8_t GameInteractor_PacifistModeActive();
|
||||
uint8_t GameInteractor_DisableZTargetingActive();
|
||||
uint8_t GameInteractor_ReverseControlsActive();
|
||||
int32_t GameInteractor_DefenseModifier();
|
||||
int32_t GameInteractor_RunSpeedModifier();
|
||||
GIGravityLevel GameInteractor_GravityLevel();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class GameInteractor {
|
||||
public:
|
||||
static GameInteractor* Instance;
|
||||
|
||||
// Gsme State
|
||||
class State {
|
||||
public:
|
||||
static bool NoUIActive;
|
||||
static GILinkSize LinkSize;
|
||||
static bool InvisibleLinkActive;
|
||||
static bool OneHitKOActive;
|
||||
static bool PacifistModeActive;
|
||||
static bool DisableZTargetingActive;
|
||||
static bool ReverseControlsActive;
|
||||
static int32_t DefenseModifier;
|
||||
static int32_t RunSpeedModifier;
|
||||
static GIGravityLevel GravityLevel;
|
||||
|
||||
static void SetPacifistMode(bool active);
|
||||
};
|
||||
|
||||
// Effects
|
||||
static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase* effect);
|
||||
static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase* effect);
|
||||
static GameInteractionEffectQueryResult RemoveEffect(GameInteractionEffectBase* effect);
|
||||
|
||||
// Helpers
|
||||
static bool IsSaveLoaded();
|
||||
static bool IsGameplayPaused();
|
||||
static bool CanSpawnEnemy();
|
||||
|
||||
class RawAction {
|
||||
public:
|
||||
static void AddOrRemoveHealthContainers(int16_t amount);
|
||||
static void AddOrRemoveMagic(int8_t amount);
|
||||
static void HealOrDamagePlayer(int16_t hearts);
|
||||
static void SetPlayerHealth(int16_t hearts);
|
||||
static void SetLinkInvisibility(bool active);
|
||||
static void SetWeatherStorm(bool active);
|
||||
static void ForceEquipBoots(int8_t boots);
|
||||
static void FreezePlayer();
|
||||
static void BurnPlayer();
|
||||
static void ElectrocutePlayer();
|
||||
static void KnockbackPlayer(float strength);
|
||||
static void GiveDekuShield();
|
||||
static void SpawnCuccoStorm();
|
||||
static void ForceInterfaceUpdate();
|
||||
|
||||
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams);
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif /* GameInteractor_h */
|
||||
@@ -0,0 +1,199 @@
|
||||
#include "GameInteractor.h"
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
extern "C" {
|
||||
#include "variables.h"
|
||||
#include "macros.h"
|
||||
#include "functions.h"
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
#include "overlays/actors/ovl_En_Niw/z_en_niw.h"
|
||||
|
||||
void GameInteractor::RawAction::AddOrRemoveHealthContainers(int16_t amount) {
|
||||
gSaveContext.healthCapacity += amount * 0x10;
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::AddOrRemoveMagic(int8_t amount) {
|
||||
// Full single magic = 48
|
||||
// Full double magic = 96
|
||||
int8_t currentMagicCapacity = (gSaveContext.isDoubleMagicAcquired + 1) * 48;
|
||||
|
||||
if (gSaveContext.isMagicAcquired) {
|
||||
gSaveContext.prevMagicState = gSaveContext.magicState;
|
||||
if (amount > 0) {
|
||||
if (gSaveContext.magic + amount > currentMagicCapacity) {
|
||||
gSaveContext.magicFillTarget = currentMagicCapacity;
|
||||
} else {
|
||||
gSaveContext.magicFillTarget = gSaveContext.magic + amount;
|
||||
}
|
||||
gSaveContext.magicState = MAGIC_STATE_FILL;
|
||||
} else if (amount < 0) {
|
||||
if (gSaveContext.magic + amount < 0) {
|
||||
gSaveContext.magic = 0;
|
||||
} else {
|
||||
gSaveContext.magic += amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::HealOrDamagePlayer(int16_t hearts) {
|
||||
if (hearts > 0) {
|
||||
Health_ChangeBy(gPlayState, hearts * 0x10);
|
||||
} else if (hearts < 0) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Health_ChangeBy(gPlayState, hearts * 0x10);
|
||||
func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0);
|
||||
player->invincibilityTimer = 28;
|
||||
}
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::SetPlayerHealth(int16_t hearts) {
|
||||
gSaveContext.health = hearts * 0x10;
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::SetLinkInvisibility(bool active) {
|
||||
GameInteractor::State::InvisibleLinkActive = active;
|
||||
if (!active) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
player->actor.shape.shadowDraw = ActorShadow_DrawFeet;
|
||||
}
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::SetWeatherStorm(bool active) {
|
||||
if (active) {
|
||||
gPlayState->envCtx.unk_F2[0] = 20; // rain intensity target
|
||||
gPlayState->envCtx.gloomySkyMode = 1; // start gloomy sky
|
||||
if ((gWeatherMode != 0) || gPlayState->envCtx.unk_17 != 0) {
|
||||
gPlayState->envCtx.unk_DE = 1;
|
||||
}
|
||||
gPlayState->envCtx.lightningMode = LIGHTNING_MODE_ON;
|
||||
Environment_PlayStormNatureAmbience(gPlayState);
|
||||
} else {
|
||||
gPlayState->envCtx.unk_F2[0] = 0;
|
||||
if (gPlayState->csCtx.state == CS_STATE_IDLE) {
|
||||
Environment_StopStormNatureAmbience(gPlayState);
|
||||
} else if (func_800FA0B4(SEQ_PLAYER_BGM_MAIN) == NA_BGM_NATURE_AMBIENCE) {
|
||||
Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_LIGHTNING, CHANNEL_IO_PORT_1, 0);
|
||||
Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_RAIN, CHANNEL_IO_PORT_1, 0);
|
||||
}
|
||||
osSyncPrintf("\n\n\nE_wether_flg=[%d]", gWeatherMode);
|
||||
osSyncPrintf("\nrain_evt_trg=[%d]\n\n", gPlayState->envCtx.gloomySkyMode);
|
||||
if (gWeatherMode == 0 && (gPlayState->envCtx.gloomySkyMode == 1)) {
|
||||
gPlayState->envCtx.gloomySkyMode = 2; // end gloomy sky
|
||||
} else {
|
||||
gPlayState->envCtx.gloomySkyMode = 0;
|
||||
gPlayState->envCtx.unk_DE = 0;
|
||||
}
|
||||
gPlayState->envCtx.lightningMode = LIGHTNING_MODE_LAST;
|
||||
}
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::ForceEquipBoots(int8_t boots) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
player->currentBoots = boots;
|
||||
Inventory_ChangeEquipment(EQUIP_BOOTS, boots + 1);
|
||||
Player_SetBootData(gPlayState, player);
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::FreezePlayer() {
|
||||
gSaveContext.pendingIceTrapCount++;
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::BurnPlayer() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
for (int i = 0; i < 18; i++) {
|
||||
player->flameTimers[i] = Rand_S16Offset(0, 200);
|
||||
}
|
||||
player->isBurning = true;
|
||||
func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::ElectrocutePlayer() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
func_80837C0C(gPlayState, player, 4, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::KnockbackPlayer(float strength) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
func_8002F71C(gPlayState, &player->actor, strength * 5, player->actor.world.rot.y + 0x8000, strength * 5);
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::GiveDekuShield() {
|
||||
// Give Deku Shield to the player, and automatically equip it when they're child and have no shield currently equiped.
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Item_Give(gPlayState, ITEM_SHIELD_DEKU);
|
||||
if (LINK_IS_CHILD && player->currentShield == PLAYER_SHIELD_NONE) {
|
||||
player->currentShield = PLAYER_SHIELD_DEKU;
|
||||
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_DEKU);
|
||||
}
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::SpawnCuccoStorm() {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
EnNiw* cucco = (EnNiw*)Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_NIW, player->actor.world.pos.x,
|
||||
player->actor.world.pos.y + 2200, player->actor.world.pos.z, 0, 0, 0, 0, 0);
|
||||
cucco->actionFunc = func_80AB70A0_nocutscene;
|
||||
}
|
||||
|
||||
void GameInteractor::RawAction::ForceInterfaceUpdate() {
|
||||
gSaveContext.unk_13E8 = 50;
|
||||
Interface_Update(gPlayState);
|
||||
}
|
||||
|
||||
GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams) {
|
||||
|
||||
if (!GameInteractor::CanSpawnEnemy()) {
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
}
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
float posXOffset = 0;
|
||||
float posYOffset = 0;
|
||||
float posZOffset = 0;
|
||||
|
||||
if (enemyId == ACTOR_EN_WALLMAS) {
|
||||
|
||||
} else if (enemyId == ACTOR_EN_CLEAR_TAG) {
|
||||
// Don't allow Arwings in certain areas because they cause issues.
|
||||
// Locations: King dodongo room, Morpha room, Twinrova room, Ganondorf room, Fishing pond, Ganon's room
|
||||
// TODO: Swap this to disabling the option in CC options menu instead.
|
||||
if (gPlayState->sceneNum == SCENE_DDAN_BOSS || gPlayState->sceneNum == SCENE_MIZUSIN_BS ||
|
||||
gPlayState->sceneNum == SCENE_JYASINBOSS || gPlayState->sceneNum == SCENE_GANON_BOSS ||
|
||||
gPlayState->sceneNum == SCENE_TURIBORI || gPlayState->sceneNum == SCENE_GANON_DEMO) {
|
||||
return GameInteractionEffectQueryResult::NotPossible;
|
||||
}
|
||||
posYOffset = 100;
|
||||
} else if (enemyId == ACTOR_EN_TORCH2) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_TEST) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_WF) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_FZ) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_FIREFLY) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_TITE) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
} else if (enemyId == ACTOR_EN_RR) {
|
||||
posXOffset = 75;
|
||||
posYOffset = 50;
|
||||
}
|
||||
|
||||
if (Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, player->actor.world.pos.x + posXOffset,
|
||||
player->actor.world.pos.y + posYOffset, player->actor.world.pos.z + posZOffset, 0, 0, 0,
|
||||
enemyParams, 0) != NULL) {
|
||||
return GameInteractionEffectQueryResult::Possible;
|
||||
}
|
||||
|
||||
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "GameInteractor.h"
|
||||
|
||||
// MARK: - State Definitions
|
||||
|
||||
bool GameInteractor::State::NoUIActive = 0;
|
||||
GILinkSize GameInteractor::State::LinkSize = GI_LINK_SIZE_NORMAL;
|
||||
bool GameInteractor::State::InvisibleLinkActive = 0;
|
||||
bool GameInteractor::State::OneHitKOActive = 0;
|
||||
bool GameInteractor::State::PacifistModeActive = 0;
|
||||
bool GameInteractor::State::DisableZTargetingActive = 0;
|
||||
bool GameInteractor::State::ReverseControlsActive = 0;
|
||||
int32_t GameInteractor::State::DefenseModifier = 0;
|
||||
int32_t GameInteractor::State::RunSpeedModifier = 0;
|
||||
GIGravityLevel GameInteractor::State::GravityLevel = GI_GRAVITY_LEVEL_NORMAL;
|
||||
|
||||
void GameInteractor::State::SetPacifistMode(bool active) {
|
||||
PacifistModeActive = active;
|
||||
// Force interface update to update the button's transparency.
|
||||
GameInteractor::RawAction::ForceInterfaceUpdate();
|
||||
}
|
||||
|
||||
// MARK: C - Bridge
|
||||
|
||||
// MARK: - GameInteractor::State::NoUIActive
|
||||
uint8_t GameInteractor_NoUIActive() {
|
||||
return GameInteractor::State::NoUIActive;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::LinkSize
|
||||
GILinkSize GameInteractor_GetLinkSize() {
|
||||
return GameInteractor::State::LinkSize;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::LinkSize
|
||||
void GameInteractor_SetLinkSize(GILinkSize size) {
|
||||
GameInteractor::State::LinkSize = size;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::InvisibleLinkActive
|
||||
uint8_t GameInteractor_InvisibleLinkActive() {
|
||||
return GameInteractor::State::InvisibleLinkActive;
|
||||
}
|
||||
|
||||
void GameInteractor_SetInvisibleLinkActive(uint8_t active) {
|
||||
GameInteractor::State::InvisibleLinkActive = active;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::OneHitKOActive
|
||||
uint8_t GameInteractor_OneHitKOActive() {
|
||||
return GameInteractor::State::OneHitKOActive;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::PacifistModeActive
|
||||
uint8_t GameInteractor_PacifistModeActive() {
|
||||
return GameInteractor::State::PacifistModeActive;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::DisableZTargetingActive
|
||||
uint8_t GameInteractor_DisableZTargetingActive() {
|
||||
return GameInteractor::State::DisableZTargetingActive;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::DisableCameraRotationActive
|
||||
uint8_t GameInteractor_ReverseControlsActive() {
|
||||
return GameInteractor::State::ReverseControlsActive;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::DisableCameraRotationActive
|
||||
int32_t GameInteractor_DefenseModifier() {
|
||||
return GameInteractor::State::DefenseModifier;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::DisableCameraRotationActive
|
||||
int32_t GameInteractor_RunSpeedModifier() {
|
||||
return GameInteractor::State::RunSpeedModifier;
|
||||
}
|
||||
|
||||
// MARK: - GameInteractor::State::DisableCameraRotationActive
|
||||
GIGravityLevel GameInteractor_GravityLevel() {
|
||||
return GameInteractor::State::GravityLevel;
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
#include "../OTRGlobals.h"
|
||||
#include <macros.h>
|
||||
#include <z64.h>
|
||||
#include <ultra64.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <functions.h>
|
||||
#include <variables.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <z64.h>
|
||||
#include <ultra64/gbi.h>
|
||||
#include <ultra64/gs2dex.h>
|
||||
#include <ultra64/controller.h>
|
||||
#include <libultraship/libultra/gbi.h>
|
||||
#include <libultraship/libultra/gs2dex.h>
|
||||
#include <libultraship/libultra/controller.h>
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef _GAMECONSOLE_H_
|
||||
#define _GAMECONSOLE_H_
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <libultraship/libultra.h>
|
||||
#include <z64.h>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
|
||||
#define MAX_CVARS 2048
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <Hooks.h>
|
||||
|
||||
extern "C" {
|
||||
@@ -110,7 +110,7 @@ void DisplayStatIfNonZero(const char* text, uint32_t value) {
|
||||
|
||||
void DrawStatsTracker(bool& open) {
|
||||
if (!open) {
|
||||
CVar_SetS32("gGameplayStatsEnabled", 0);
|
||||
CVarSetInteger("gGameplayStatsEnabled", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,9 @@ void DrawStatsTracker(bool& open) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
bool showTimestamps = (CVarGetInteger("gGameplayStatsMode", 0) <= 1);
|
||||
bool showCounts = ( (CVarGetInteger("gGameplayStatsMode", 0) == 0) || (CVarGetInteger("gGameplayStatsMode", 0) == 2) );
|
||||
|
||||
u32 totalTimer = GAMEPLAYSTAT_TOTAL_TIME;
|
||||
u32 enemiesDefeated = 0;
|
||||
@@ -168,172 +171,188 @@ void DrawStatsTracker(bool& open) {
|
||||
ImGui::EndTable();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f });
|
||||
ImGui::BeginTable("gameStatsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV);
|
||||
ImGui::BeginTable("gameStatsTable", (showTimestamps && showCounts) ? 2 : 1, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV);
|
||||
|
||||
ImGui::TableSetupColumn("Timestamps", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
||||
ImGui::TableSetupColumn("Counts", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
||||
if (showTimestamps) {
|
||||
ImGui::TableSetupColumn("Timestamps", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
||||
}
|
||||
if (showCounts) {
|
||||
ImGui::TableSetupColumn("Counts", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
||||
}
|
||||
ImGui::TableHeadersRow();
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Display chronological timestamps of items obtained and bosses defeated
|
||||
for (int i = 0; i < TIMESTAMP_MAX; i++) {
|
||||
// To be shown, the entry must have a non-zero time and a string for its display name
|
||||
if (timestampDisplay[i].time > 0 && strnlen(timestampDisplay[i].name, 21) > 1) {
|
||||
DisplayTimeHHMMSS(timestampDisplay[i].time, timestampDisplay[i].name, timestampDisplay[i].color);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
DisplayStat("Enemies Defeated: ", enemiesDefeated);
|
||||
// Show breakdown of enemies defeated in a tree. Only show counts for enemies if they've been defeated at least once.
|
||||
if (enemiesDefeated > 0) {
|
||||
if (ImGui::TreeNode("Enemy Details...")) {
|
||||
|
||||
DisplayStatIfNonZero("Anubis: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ANUBIS]);
|
||||
DisplayStatIfNonZero("Armos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ARMOS]);
|
||||
DisplayStatIfNonZero("Arwing: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ARWING]);
|
||||
DisplayStatIfNonZero("Bari: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BARI]);
|
||||
DisplayStatIfNonZero("Biri: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BIRI]);
|
||||
DisplayStatIfNonZero("Beamos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BEAMOS]);
|
||||
DisplayStatIfNonZero("Big Octo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BIG_OCTO]);
|
||||
DisplayStatIfNonZero("Bubble (Blue): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]);
|
||||
DisplayStatIfNonZero("Bubble (Green): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]);
|
||||
DisplayStatIfNonZero("Bubble (Red): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]);
|
||||
DisplayStatIfNonZero("Bubble (White): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]);
|
||||
DisplayStatIfNonZero("Business Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUSINESS_SCRUB]);
|
||||
DisplayStatIfNonZero("Dark Link: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DARK_LINK]);
|
||||
DisplayStatIfNonZero("Dead Hand: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEAD_HAND]);
|
||||
DisplayStatIfNonZero("Deku Baba: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]);
|
||||
DisplayStatIfNonZero("Deku Baba (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]);
|
||||
DisplayStatIfNonZero("Deku Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_SCRUB]);
|
||||
DisplayStatIfNonZero("Dinolfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]);
|
||||
DisplayStatIfNonZero("Dodongo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DODONGO]);
|
||||
DisplayStatIfNonZero("Dodongo (Baby): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DODONGO_BABY]);
|
||||
DisplayStatIfNonZero("Door Mimic: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DOOR_TRAP]);
|
||||
DisplayStatIfNonZero("Flare Dancer: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLARE_DANCER]);
|
||||
DisplayStatIfNonZero("Floormaster: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLOORMASTER]/3);
|
||||
DisplayStatIfNonZero("Flying Floor Tile: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLOOR_TILE]);
|
||||
DisplayStatIfNonZero("Flying Pot: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLYING_POT]);
|
||||
DisplayStatIfNonZero("Freezard: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FREEZARD]);
|
||||
DisplayStatIfNonZero("Gerudo Thief: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GERUDO_THIEF]);
|
||||
DisplayStatIfNonZero("Gibdo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GIBDO]);
|
||||
DisplayStatIfNonZero("Gohma Larva: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GOHMA_LARVA]);
|
||||
DisplayStatIfNonZero("Guay: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GUAY]);
|
||||
DisplayStatIfNonZero("Iron Knuckle: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]);
|
||||
DisplayStatIfNonZero("Iron Knuckle (Nab): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]);
|
||||
DisplayStatIfNonZero("Keese: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE]);
|
||||
DisplayStatIfNonZero("Keese (Fire): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]);
|
||||
DisplayStatIfNonZero("Keese (Ice): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]);
|
||||
DisplayStatIfNonZero("Leever: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER]);
|
||||
DisplayStatIfNonZero("Leever (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]);
|
||||
DisplayStatIfNonZero("Like-Like: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIKE_LIKE]);
|
||||
DisplayStatIfNonZero("Lizalfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]);
|
||||
DisplayStatIfNonZero("Mad Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MAD_SCRUB]);
|
||||
DisplayStatIfNonZero("Moblin: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]);
|
||||
DisplayStatIfNonZero("Moblin (Club): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]);
|
||||
DisplayStatIfNonZero("Octorok: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_OCTOROK]);
|
||||
DisplayStatIfNonZero("Parasitic Tentacle: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PARASITIC_TENTACLE]);
|
||||
DisplayStatIfNonZero("Peahat: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]);
|
||||
DisplayStatIfNonZero("Peahat Larva: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]);
|
||||
DisplayStatIfNonZero("Poe: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]);
|
||||
DisplayStatIfNonZero("Poe (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]);
|
||||
DisplayStatIfNonZero("Poe (Composer): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]);
|
||||
DisplayStatIfNonZero("Poe Sisters: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_SISTERS]);
|
||||
DisplayStatIfNonZero("Redead: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_REDEAD]);
|
||||
DisplayStatIfNonZero("Shabom: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SHABOM]);
|
||||
DisplayStatIfNonZero("Shellblade: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SHELLBLADE]);
|
||||
DisplayStatIfNonZero("Skull Kid: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULL_KID]);
|
||||
DisplayStatIfNonZero("Skulltula: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]);
|
||||
DisplayStatIfNonZero("Skulltula (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]);
|
||||
DisplayStatIfNonZero("Skulltula (Gold): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]);
|
||||
DisplayStatIfNonZero("Skullwalltula: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]);
|
||||
DisplayStatIfNonZero("Spike: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SPIKE]);
|
||||
DisplayStatIfNonZero("Stalchild: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STALCHILD]);
|
||||
DisplayStatIfNonZero("Stalfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STALFOS]);
|
||||
DisplayStatIfNonZero("Stinger: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STINGER]);
|
||||
DisplayStatIfNonZero("Tailpasaran: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]);
|
||||
DisplayStatIfNonZero("Tektite (Blue): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]);
|
||||
DisplayStatIfNonZero("Tektite (Red): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]);
|
||||
DisplayStatIfNonZero("Torch Slug: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TORCH_SLUG]);
|
||||
DisplayStatIfNonZero("Wallmaster: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WALLMASTER]);
|
||||
DisplayStatIfNonZero("Withered Deku Baba: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WITHERED_DEKU_BABA]);
|
||||
DisplayStatIfNonZero("Wolfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]);
|
||||
DisplayStatIfNonZero("Wolfos (White): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]);
|
||||
if (showTimestamps) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayStat("Rupees Collected: ", gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED]);
|
||||
UIWidgets::Tooltip("Includes rupees collected with a full wallet.");
|
||||
DisplayStat("Rupees Spent: ", gSaveContext.sohStats.count[COUNT_RUPEES_SPENT]);
|
||||
DisplayStat("Chests Opened: ", gSaveContext.sohStats.count[COUNT_CHESTS_OPENED]);
|
||||
|
||||
DisplayStat("Ammo Used: ", ammoUsed);
|
||||
// Show breakdown of ammo used in a collapsible tree. Only show ammo types if they've been used at least once.
|
||||
if (ammoUsed > 0) {
|
||||
if (ImGui::TreeNode("Ammo Details...")) {
|
||||
|
||||
DisplayStatIfNonZero("Deku Sticks: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK]);
|
||||
DisplayStatIfNonZero("Deku Nuts: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_NUT]);
|
||||
DisplayStatIfNonZero("Deku Seeds: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_SEED]);
|
||||
DisplayStatIfNonZero("Bombs: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMB]);
|
||||
DisplayStatIfNonZero("Bombchus: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMBCHU]);
|
||||
DisplayStatIfNonZero("Arrows: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_ARROW]);
|
||||
DisplayStatIfNonZero("Beans: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BEAN]);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::TreePop();
|
||||
// Display chronological timestamps of items obtained and bosses defeated
|
||||
for (int i = 0; i < TIMESTAMP_MAX; i++) {
|
||||
// To be shown, the entry must have a non-zero time and a string for its display name
|
||||
if (timestampDisplay[i].time > 0 && strnlen(timestampDisplay[i].name, 21) > 1) {
|
||||
DisplayTimeHHMMSS(timestampDisplay[i].time, timestampDisplay[i].name, timestampDisplay[i].color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DisplayStat("Damage Taken: ", gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN]);
|
||||
DisplayStat("Sword Swings: ", gSaveContext.sohStats.count[COUNT_SWORD_SWINGS]);
|
||||
DisplayStat("Steps Taken: ", gSaveContext.sohStats.count[COUNT_STEPS]);
|
||||
// If using MM Bunny Hood enhancement, show how long it's been equipped (not counting pause time)
|
||||
if (CVar_GetS32("gMMBunnyHood", 0) || gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] > 0) {
|
||||
DisplayTimeHHMMSS(gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] / 2, "Bunny Hood Time: ", COLOR_WHITE);
|
||||
}
|
||||
DisplayStat("Rolls: ", gSaveContext.sohStats.count[COUNT_ROLLS]);
|
||||
DisplayStat("Bonks: ", gSaveContext.sohStats.count[COUNT_BONKS]);
|
||||
DisplayStat("Sidehops: ", gSaveContext.sohStats.count[COUNT_SIDEHOPS]);
|
||||
DisplayStat("Backflips: ", gSaveContext.sohStats.count[COUNT_BACKFLIPS]);
|
||||
DisplayStat("Ice Traps: ", gSaveContext.sohStats.count[COUNT_ICE_TRAPS]);
|
||||
DisplayStat("Pauses: ", gSaveContext.sohStats.count[COUNT_PAUSES]);
|
||||
DisplayStat("Pots Smashed: ", gSaveContext.sohStats.count[COUNT_POTS_BROKEN]);
|
||||
DisplayStat("Bushes Cut: ", gSaveContext.sohStats.count[COUNT_BUSHES_CUT]);
|
||||
if (showCounts) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
DisplayStat("Buttons Pressed: ", buttonPresses);
|
||||
// Show breakdown of ammo used in a collapsible tree. Only show ammo types if they've been used at least once.
|
||||
if (buttonPresses > 0) {
|
||||
if (ImGui::TreeNode("Buttons...")) {
|
||||
|
||||
DisplayStatIfNonZero("A: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A]);
|
||||
DisplayStatIfNonZero("B: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_B]);
|
||||
DisplayStatIfNonZero("L: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_L]);
|
||||
DisplayStatIfNonZero("R: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_R]);
|
||||
DisplayStatIfNonZero("Z: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_Z]);
|
||||
DisplayStatIfNonZero("C-Up: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CUP]);
|
||||
DisplayStatIfNonZero("C-Right: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CRIGHT]);
|
||||
DisplayStatIfNonZero("C-Down: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CDOWN]);
|
||||
DisplayStatIfNonZero("C-Left: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CLEFT]);
|
||||
DisplayStatIfNonZero("D-Up: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DUP]);
|
||||
DisplayStatIfNonZero("D-Right: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DRIGHT]);
|
||||
DisplayStatIfNonZero("D-Down: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DDOWN]);
|
||||
DisplayStatIfNonZero("D-Left: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DLEFT]);
|
||||
DisplayStatIfNonZero("Start: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_START]);
|
||||
DisplayStat("Enemies Defeated: ", enemiesDefeated);
|
||||
// Show breakdown of enemies defeated in a tree. Only show counts for enemies if they've been defeated at least once.
|
||||
if (enemiesDefeated > 0) {
|
||||
if (ImGui::TreeNode("Enemy Details...")) {
|
||||
|
||||
DisplayStatIfNonZero("Anubis: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ANUBIS]);
|
||||
DisplayStatIfNonZero("Armos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ARMOS]);
|
||||
DisplayStatIfNonZero("Arwing: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_ARWING]);
|
||||
DisplayStatIfNonZero("Bari: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BARI]);
|
||||
DisplayStatIfNonZero("Biri: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BIRI]);
|
||||
DisplayStatIfNonZero("Beamos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BEAMOS]);
|
||||
DisplayStatIfNonZero("Big Octo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BIG_OCTO]);
|
||||
DisplayStatIfNonZero("Bubble (Blue): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]);
|
||||
DisplayStatIfNonZero("Bubble (Green): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]);
|
||||
DisplayStatIfNonZero("Bubble (Red): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]);
|
||||
DisplayStatIfNonZero("Bubble (White): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]);
|
||||
DisplayStatIfNonZero("Business Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUSINESS_SCRUB]);
|
||||
DisplayStatIfNonZero("Dark Link: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DARK_LINK]);
|
||||
DisplayStatIfNonZero("Dead Hand: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEAD_HAND]);
|
||||
DisplayStatIfNonZero("Deku Baba: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]);
|
||||
DisplayStatIfNonZero("Deku Baba (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]);
|
||||
DisplayStatIfNonZero("Deku Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_SCRUB]);
|
||||
DisplayStatIfNonZero("Dinolfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]);
|
||||
DisplayStatIfNonZero("Dodongo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DODONGO]);
|
||||
DisplayStatIfNonZero("Dodongo (Baby): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DODONGO_BABY]);
|
||||
DisplayStatIfNonZero("Door Mimic: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DOOR_TRAP]);
|
||||
DisplayStatIfNonZero("Flare Dancer: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLARE_DANCER]);
|
||||
DisplayStatIfNonZero("Floormaster: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLOORMASTER]/3);
|
||||
DisplayStatIfNonZero("Flying Floor Tile: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLOOR_TILE]);
|
||||
DisplayStatIfNonZero("Flying Pot: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FLYING_POT]);
|
||||
DisplayStatIfNonZero("Freezard: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_FREEZARD]);
|
||||
DisplayStatIfNonZero("Gerudo Thief: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GERUDO_THIEF]);
|
||||
DisplayStatIfNonZero("Gibdo: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GIBDO]);
|
||||
DisplayStatIfNonZero("Gohma Larva: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GOHMA_LARVA]);
|
||||
DisplayStatIfNonZero("Guay: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GUAY]);
|
||||
DisplayStatIfNonZero("Iron Knuckle: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]);
|
||||
DisplayStatIfNonZero("Iron Knuckle (Nab): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]);
|
||||
DisplayStatIfNonZero("Keese: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE]);
|
||||
DisplayStatIfNonZero("Keese (Fire): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]);
|
||||
DisplayStatIfNonZero("Keese (Ice): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]);
|
||||
DisplayStatIfNonZero("Leever: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER]);
|
||||
DisplayStatIfNonZero("Leever (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]);
|
||||
DisplayStatIfNonZero("Like-Like: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIKE_LIKE]);
|
||||
DisplayStatIfNonZero("Lizalfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]);
|
||||
DisplayStatIfNonZero("Mad Scrub: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MAD_SCRUB]);
|
||||
DisplayStatIfNonZero("Moblin: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]);
|
||||
DisplayStatIfNonZero("Moblin (Club): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]);
|
||||
DisplayStatIfNonZero("Octorok: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_OCTOROK]);
|
||||
DisplayStatIfNonZero("Parasitic Tentacle: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PARASITIC_TENTACLE]);
|
||||
DisplayStatIfNonZero("Peahat: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]);
|
||||
DisplayStatIfNonZero("Peahat Larva: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]);
|
||||
DisplayStatIfNonZero("Poe: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]);
|
||||
DisplayStatIfNonZero("Poe (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]);
|
||||
DisplayStatIfNonZero("Poe (Composer): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]);
|
||||
DisplayStatIfNonZero("Poe Sisters: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_SISTERS]);
|
||||
DisplayStatIfNonZero("Redead: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_REDEAD]);
|
||||
DisplayStatIfNonZero("Shabom: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SHABOM]);
|
||||
DisplayStatIfNonZero("Shellblade: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SHELLBLADE]);
|
||||
DisplayStatIfNonZero("Skull Kid: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULL_KID]);
|
||||
DisplayStatIfNonZero("Skulltula: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]);
|
||||
DisplayStatIfNonZero("Skulltula (Big): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]);
|
||||
DisplayStatIfNonZero("Skulltula (Gold): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]);
|
||||
DisplayStatIfNonZero("Skullwalltula: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]);
|
||||
DisplayStatIfNonZero("Spike: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SPIKE]);
|
||||
DisplayStatIfNonZero("Stalchild: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STALCHILD]);
|
||||
DisplayStatIfNonZero("Stalfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STALFOS]);
|
||||
DisplayStatIfNonZero("Stinger: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_STINGER]);
|
||||
DisplayStatIfNonZero("Tailpasaran: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]);
|
||||
DisplayStatIfNonZero("Tektite (Blue): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]);
|
||||
DisplayStatIfNonZero("Tektite (Red): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]);
|
||||
DisplayStatIfNonZero("Torch Slug: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TORCH_SLUG]);
|
||||
DisplayStatIfNonZero("Wallmaster: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WALLMASTER]);
|
||||
DisplayStatIfNonZero("Withered Deku Baba: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WITHERED_DEKU_BABA]);
|
||||
DisplayStatIfNonZero("Wolfos: ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]);
|
||||
DisplayStatIfNonZero("Wolfos (White): ", gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayStat("Rupees Collected: ", gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED]);
|
||||
UIWidgets::Tooltip("Includes rupees collected with a full wallet.");
|
||||
DisplayStat("Rupees Spent: ", gSaveContext.sohStats.count[COUNT_RUPEES_SPENT]);
|
||||
DisplayStat("Chests Opened: ", gSaveContext.sohStats.count[COUNT_CHESTS_OPENED]);
|
||||
|
||||
DisplayStat("Ammo Used: ", ammoUsed);
|
||||
// Show breakdown of ammo used in a collapsible tree. Only show ammo types if they've been used at least once.
|
||||
if (ammoUsed > 0) {
|
||||
if (ImGui::TreeNode("Ammo Details...")) {
|
||||
|
||||
DisplayStatIfNonZero("Deku Sticks: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK]);
|
||||
DisplayStatIfNonZero("Deku Nuts: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_NUT]);
|
||||
DisplayStatIfNonZero("Deku Seeds: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_SEED]);
|
||||
DisplayStatIfNonZero("Bombs: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMB]);
|
||||
DisplayStatIfNonZero("Bombchus: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMBCHU]);
|
||||
DisplayStatIfNonZero("Arrows: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_ARROW]);
|
||||
DisplayStatIfNonZero("Beans: ", gSaveContext.sohStats.count[COUNT_AMMO_USED_BEAN]);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayStat("Damage Taken: ", gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN]);
|
||||
DisplayStat("Sword Swings: ", gSaveContext.sohStats.count[COUNT_SWORD_SWINGS]);
|
||||
DisplayStat("Steps Taken: ", gSaveContext.sohStats.count[COUNT_STEPS]);
|
||||
// If using MM Bunny Hood enhancement, show how long it's been equipped (not counting pause time)
|
||||
if (CVarGetInteger("gMMBunnyHood", 0) || gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] > 0) {
|
||||
DisplayTimeHHMMSS(gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] / 2, "Bunny Hood Time: ", COLOR_WHITE);
|
||||
}
|
||||
DisplayStat("Rolls: ", gSaveContext.sohStats.count[COUNT_ROLLS]);
|
||||
DisplayStat("Bonks: ", gSaveContext.sohStats.count[COUNT_BONKS]);
|
||||
DisplayStat("Sidehops: ", gSaveContext.sohStats.count[COUNT_SIDEHOPS]);
|
||||
DisplayStat("Backflips: ", gSaveContext.sohStats.count[COUNT_BACKFLIPS]);
|
||||
DisplayStat("Ice Traps: ", gSaveContext.sohStats.count[COUNT_ICE_TRAPS]);
|
||||
DisplayStat("Pauses: ", gSaveContext.sohStats.count[COUNT_PAUSES]);
|
||||
DisplayStat("Pots Smashed: ", gSaveContext.sohStats.count[COUNT_POTS_BROKEN]);
|
||||
DisplayStat("Bushes Cut: ", gSaveContext.sohStats.count[COUNT_BUSHES_CUT]);
|
||||
|
||||
DisplayStat("Buttons Pressed: ", buttonPresses);
|
||||
// Show breakdown of ammo used in a collapsible tree. Only show ammo types if they've been used at least once.
|
||||
if (buttonPresses > 0) {
|
||||
if (ImGui::TreeNode("Buttons...")) {
|
||||
|
||||
DisplayStatIfNonZero("A: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A]);
|
||||
DisplayStatIfNonZero("B: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_B]);
|
||||
DisplayStatIfNonZero("L: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_L]);
|
||||
DisplayStatIfNonZero("R: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_R]);
|
||||
DisplayStatIfNonZero("Z: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_Z]);
|
||||
DisplayStatIfNonZero("C-Up: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CUP]);
|
||||
DisplayStatIfNonZero("C-Right: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CRIGHT]);
|
||||
DisplayStatIfNonZero("C-Down: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CDOWN]);
|
||||
DisplayStatIfNonZero("C-Left: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CLEFT]);
|
||||
DisplayStatIfNonZero("D-Up: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DUP]);
|
||||
DisplayStatIfNonZero("D-Right: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DRIGHT]);
|
||||
DisplayStatIfNonZero("D-Down: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DDOWN]);
|
||||
DisplayStatIfNonZero("D-Left: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DLEFT]);
|
||||
DisplayStatIfNonZero("Start: ", gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_START]);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::EndTable();
|
||||
|
||||
const char* gameplayStatsModeOptions[3] = { "Both", "Timestamps", "Counts"};
|
||||
|
||||
ImGui::Text("Display Mode");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
|
||||
UIWidgets::EnhancementCombobox("gGameplayStatsMode", gameplayStatsModeOptions, 3, 0);
|
||||
|
||||
ImGui::Text("Note: Gameplay stats are saved to the current file and will be\nlost if you quit without saving.");
|
||||
|
||||
ImGui::End();
|
||||
@@ -379,6 +398,22 @@ void SetupDisplayNames() {
|
||||
strcpy(timestampDisplayName[ITEM_SCALE_GOLDEN], "Gold Scale: ");
|
||||
strcpy(timestampDisplayName[ITEM_WALLET_ADULT], "Adult's Wallet: ");
|
||||
strcpy(timestampDisplayName[ITEM_WALLET_GIANT], "Giant's Wallet: ");
|
||||
strcpy(timestampDisplayName[ITEM_WEIRD_EGG], "Weird Egg: ");
|
||||
strcpy(timestampDisplayName[ITEM_GERUDO_CARD], "Gerudo's Card: ");
|
||||
strcpy(timestampDisplayName[ITEM_COJIRO], "Cojiro: ");
|
||||
strcpy(timestampDisplayName[ITEM_POCKET_EGG], "Pocket Egg: ");
|
||||
strcpy(timestampDisplayName[ITEM_MASK_SKULL], "Skull Mask: ");
|
||||
strcpy(timestampDisplayName[ITEM_MASK_SPOOKY], "Spooky Mask: ");
|
||||
strcpy(timestampDisplayName[ITEM_MASK_KEATON], "Keaton Mask: ");
|
||||
strcpy(timestampDisplayName[ITEM_MASK_BUNNY], "Bunny Hood: ");
|
||||
strcpy(timestampDisplayName[ITEM_ODD_MUSHROOM], "Odd Mushroom: ");
|
||||
strcpy(timestampDisplayName[ITEM_ODD_POTION], "Odd Potion: ");
|
||||
strcpy(timestampDisplayName[ITEM_SAW], "Poacher's Saw: ");
|
||||
strcpy(timestampDisplayName[ITEM_SWORD_BROKEN], "Broken Goron Sword: ");
|
||||
strcpy(timestampDisplayName[ITEM_PRESCRIPTION], "Prescription: ");
|
||||
strcpy(timestampDisplayName[ITEM_FROG], "Eyeball Frog: ");
|
||||
strcpy(timestampDisplayName[ITEM_EYEDROPS], "Eye Drops: ");
|
||||
strcpy(timestampDisplayName[ITEM_CLAIM_CHECK], "Claim Check: ");
|
||||
strcpy(timestampDisplayName[ITEM_SONG_MINUET], "Minuet of Forest: ");
|
||||
strcpy(timestampDisplayName[ITEM_SONG_BOLERO], "Bolero of Fire: ");
|
||||
strcpy(timestampDisplayName[ITEM_SONG_SERENADE], "Serenade of Water: ");
|
||||
@@ -466,7 +501,7 @@ void SetupDisplayColors() {
|
||||
}
|
||||
|
||||
void InitStatTracker() {
|
||||
SohImGui::AddWindow("Enhancements", "Gameplay Stats", DrawStatsTracker);
|
||||
SohImGui::AddWindow("Enhancements", "Gameplay Stats", DrawStatsTracker, CVarGetInteger("gGameplayStatsEnabled", 0) == 1);
|
||||
SetupDisplayNames();
|
||||
SetupDisplayColors();
|
||||
}
|
||||
@@ -3,12 +3,12 @@
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <ImGuiImpl.h>
|
||||
#include <Cvar.h>
|
||||
#include <libultraship/bridge.h>
|
||||
#include "soh/UIWidgets.hpp"
|
||||
|
||||
void clearCvars(std::vector<const char*> cvarsToClear) {
|
||||
for(const char* cvar : cvarsToClear) {
|
||||
CVar_Clear(cvar);
|
||||
CVarClear(cvar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ void applyPreset(std::vector<PresetEntry> entries) {
|
||||
for(auto& [cvar, type, value] : entries) {
|
||||
switch (type) {
|
||||
case PRESET_ENTRY_TYPE_S32:
|
||||
CVar_SetS32(cvar, std::get<int32_t>(value));
|
||||
CVarSetInteger(cvar, std::get<int32_t>(value));
|
||||
break;
|
||||
case PRESET_ENTRY_TYPE_FLOAT:
|
||||
CVar_SetFloat(cvar, std::get<float>(value));
|
||||
CVarSetFloat(cvar, std::get<float>(value));
|
||||
break;
|
||||
case PRESET_ENTRY_TYPE_STRING:
|
||||
CVar_SetString(cvar, std::get<const char*>(value));
|
||||
CVarSetString(cvar, std::get<const char*>(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ void applyPreset(std::vector<PresetEntry> entries) {
|
||||
void DrawPresetSelector(PresetType presetTypeId) {
|
||||
const std::string presetTypeCvar = "gPreset" + std::to_string(presetTypeId);
|
||||
const PresetTypeDefinition presetTypeDef = presetTypes.at(presetTypeId);
|
||||
const uint16_t selectedPresetId = CVar_GetS32(presetTypeCvar.c_str(), 0);
|
||||
const uint16_t selectedPresetId = CVarGetInteger(presetTypeCvar.c_str(), 0);
|
||||
const PresetDefinition selectedPresetDef = presetTypeDef.presets.at(selectedPresetId);
|
||||
std::string comboboxTooltip = "";
|
||||
for ( auto iter = presetTypeDef.presets.begin(); iter != presetTypeDef.presets.end(); ++iter ) {
|
||||
@@ -43,7 +43,7 @@ void DrawPresetSelector(PresetType presetTypeId) {
|
||||
if (ImGui::BeginCombo("##PresetsComboBox", selectedPresetDef.label)) {
|
||||
for ( auto iter = presetTypeDef.presets.begin(); iter != presetTypeDef.presets.end(); ++iter ) {
|
||||
if (ImGui::Selectable(iter->second.label, iter->first == selectedPresetId)) {
|
||||
CVar_SetS32(presetTypeCvar.c_str(), iter->first);
|
||||
CVarSetInteger(presetTypeCvar.c_str(), iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +55,8 @@ void DrawPresetSelector(PresetType presetTypeId) {
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f));
|
||||
if (ImGui::Button(("Apply Preset##" + presetTypeCvar).c_str())) {
|
||||
if (selectedPresetId == 0) {
|
||||
clearCvars(presetTypeDef.cvarsToClear);
|
||||
} else {
|
||||
clearCvars(presetTypeDef.cvarsToClear);
|
||||
if (selectedPresetId != 0) {
|
||||
applyPreset(selectedPresetDef.entries);
|
||||
}
|
||||
SohImGui::RequestCvarSaveOnNextTick();
|
||||
|
||||
@@ -86,6 +86,7 @@ const std::vector<const char*> enhancementsCvars = {
|
||||
"gNoHeartDrops",
|
||||
"gBombchuDrops",
|
||||
"gGoronPot",
|
||||
"gFullHealthSpawn",
|
||||
"gDampeWin",
|
||||
"gRedPotionEffect",
|
||||
"gRedPotionHealth",
|
||||
@@ -156,6 +157,7 @@ const std::vector<const char*> enhancementsCvars = {
|
||||
"gHoverFishing",
|
||||
"gN64WeirdFrames",
|
||||
"gBombchusOOB",
|
||||
"gQuickPutaway",
|
||||
"gGsCutscene",
|
||||
"gSkipSaveConfirmation",
|
||||
"gAutosave",
|
||||
@@ -173,16 +175,27 @@ const std::vector<const char*> enhancementsCvars = {
|
||||
"gBombchuBowlingNoBigCucco",
|
||||
"gBombchuBowlingAmmunition",
|
||||
"gCreditsFix",
|
||||
"gSilverRupeeJingleExtend",
|
||||
"gStaticExplosionRadius",
|
||||
"gNoInputForCredits",
|
||||
"gFastFarores",
|
||||
};
|
||||
|
||||
const std::vector<const char*> randomizerCvars = {
|
||||
"gRandomize10GSHint",
|
||||
"gRandomize20GSHint",
|
||||
"gRandomize30GSHint",
|
||||
"gRandomize40GSHint",
|
||||
"gRandomize50GSHint",
|
||||
"gRandomizeAllLocationsReachable",
|
||||
"gRandomizeAltarHint",
|
||||
"gRandomizeBigPoeTargetCount",
|
||||
"gRandomizeBlueFireArrows",
|
||||
"gRandomizeBombchusInLogic",
|
||||
"gRandomizeBossKeysanity",
|
||||
"gRandomizeCompleteMaskQuest",
|
||||
"gRandomizeCuccosToReturn",
|
||||
"gRandomizeDampeHint",
|
||||
"gRandomizeDecoupleEntrances",
|
||||
"gRandomizeDoorOfTime",
|
||||
"gRandomizeDungeonCount",
|
||||
@@ -208,6 +221,7 @@ const std::vector<const char*> randomizerCvars = {
|
||||
"gRandomizeLacsRewardCount",
|
||||
"gRandomizeLacsStoneCount",
|
||||
"gRandomizeLacsTokenCount",
|
||||
"gRandomizeLAHint",
|
||||
"gRandomizeLinksPocket",
|
||||
"gRandomizeLogicRules",
|
||||
"gRandomizeMedallionCount",
|
||||
@@ -220,9 +234,11 @@ const std::vector<const char*> randomizerCvars = {
|
||||
"gRandomizeMqDungeons",
|
||||
"gRandomizeRainbowBridge",
|
||||
"gRandomizeRewardCount",
|
||||
"gRandomizeScrubText",
|
||||
"gRandomizeShopsanity",
|
||||
"gRandomizeShuffleAdultTrade",
|
||||
"gRandomizeShuffleBeans",
|
||||
"gRandomizeShuffleBossEntrances",
|
||||
"gRandomizeShuffleCows",
|
||||
"gRandomizeShuffleDungeonReward",
|
||||
"gRandomizeShuffleDungeonsEntrances",
|
||||
@@ -259,14 +275,27 @@ const std::vector<const char*> randomizerCvars = {
|
||||
"gRandomizeSkipTowerEscape",
|
||||
"gRandomizeStartingAge",
|
||||
"gRandomizeStartingConsumables",
|
||||
"gRandomizeStartingBoleroOfFire",
|
||||
"gRandomizeStartingDekuShield",
|
||||
"gRandomizeStartingEponasSong",
|
||||
"gRandomizeStartingKokiriSword",
|
||||
"gRandomizeStartingMapsCompasses",
|
||||
"gRandomizeStartingMinuetOfForest",
|
||||
"gRandomizeStartingNocturneOfShadow",
|
||||
"gRandomizeStartingOcarina",
|
||||
"gRandomizeStartingPreludeOfLight",
|
||||
"gRandomizeStartingRequiemOfSpirit",
|
||||
"gRandomizeStartingSariasSong",
|
||||
"gRandomizeStartingSerenadeOfWater",
|
||||
"gRandomizeStartingSkulltulaToken",
|
||||
"gRandomizeStartingSongOfStorms",
|
||||
"gRandomizeStartingSongOfTime",
|
||||
"gRandomizeStartingSunsSong",
|
||||
"gRandomizeStartingZeldasLullaby",
|
||||
"gRandomizeStoneCount",
|
||||
"gRandomizeSunlightArrows",
|
||||
"gRandomizeTokenCount",
|
||||
"gRandomizeWarpSongText",
|
||||
"gRandomizeZorasFountain",
|
||||
};
|
||||
|
||||
@@ -320,6 +349,8 @@ const std::vector<PresetEntry> vanillaPlusPresetEntries = {
|
||||
PRESET_ENTRY_S32("gDekuNutUpgradeFix", 1),
|
||||
// Fix Navi text HUD position
|
||||
PRESET_ENTRY_S32("gNaviTextFix", 1),
|
||||
// Extend Silver Rupee Jingle
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
@@ -329,6 +360,8 @@ const std::vector<PresetEntry> vanillaPlusPresetEntries = {
|
||||
PRESET_ENTRY_S32("gN64WeirdFrames", 1),
|
||||
// Bombchus out of bounds
|
||||
PRESET_ENTRY_S32("gBombchusOOB", 1),
|
||||
// Quick Putaway
|
||||
PRESET_ENTRY_S32("gQuickPutaway", 1),
|
||||
// Skip save confirmation
|
||||
PRESET_ENTRY_S32("gSkipSaveConfirmation", 1),
|
||||
};
|
||||
@@ -350,7 +383,7 @@ const std::vector<PresetEntry> enhancedPresetEntries = {
|
||||
// Text Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gTextSpeed", 5),
|
||||
// King Zora Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 2),
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 5),
|
||||
// Faster Block Push (+0 to +5)
|
||||
PRESET_ENTRY_S32("gFasterBlockPush", 5),
|
||||
// Better Owl
|
||||
@@ -383,6 +416,8 @@ const std::vector<PresetEntry> enhancedPresetEntries = {
|
||||
PRESET_ENTRY_S32("gDekuNutUpgradeFix", 1),
|
||||
// Fix Navi text HUD position
|
||||
PRESET_ENTRY_S32("gNaviTextFix", 1),
|
||||
// Extend Silver Rupee Jingle
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
@@ -392,10 +427,10 @@ const std::vector<PresetEntry> enhancedPresetEntries = {
|
||||
PRESET_ENTRY_S32("gN64WeirdFrames", 1),
|
||||
// Bombchus out of bounds
|
||||
PRESET_ENTRY_S32("gBombchusOOB", 1),
|
||||
// Quick Putaway
|
||||
PRESET_ENTRY_S32("gQuickPutaway", 1),
|
||||
// Skip save confirmation
|
||||
PRESET_ENTRY_S32("gSkipSaveConfirmation", 1),
|
||||
// King Zora Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 5),
|
||||
// Biggoron Forge Time (0 to 3)
|
||||
PRESET_ENTRY_S32("gForgeTime", 0),
|
||||
// Vine/Ladder Climb speed (+0 to +12)
|
||||
@@ -467,7 +502,7 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
// Text Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gTextSpeed", 5),
|
||||
// King Zora Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 2),
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 5),
|
||||
// Faster Block Push (+0 to +5)
|
||||
PRESET_ENTRY_S32("gFasterBlockPush", 5),
|
||||
// Better Owl
|
||||
@@ -480,9 +515,6 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
// Inject Item Counts in messages
|
||||
PRESET_ENTRY_S32("gInjectItemCounts", 1),
|
||||
|
||||
// Pause link animation (0 to 16)
|
||||
PRESET_ENTRY_S32("gPauseLiveLink", 1),
|
||||
|
||||
// Dynamic Wallet Icon
|
||||
PRESET_ENTRY_S32("gDynamicWalletIcon", 1),
|
||||
// Always show dungeon entrances
|
||||
@@ -500,6 +532,8 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
PRESET_ENTRY_S32("gDekuNutUpgradeFix", 1),
|
||||
// Fix Navi text HUD position
|
||||
PRESET_ENTRY_S32("gNaviTextFix", 1),
|
||||
// Extend Silver Rupee Jingle
|
||||
PRESET_ENTRY_S32("gSilverRupeeJingleExtend", 1),
|
||||
|
||||
// Red Ganon blood
|
||||
PRESET_ENTRY_S32("gRedGanonBlood", 1),
|
||||
@@ -509,10 +543,10 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
PRESET_ENTRY_S32("gN64WeirdFrames", 1),
|
||||
// Bombchus out of bounds
|
||||
PRESET_ENTRY_S32("gBombchusOOB", 1),
|
||||
// Quick Putaway
|
||||
PRESET_ENTRY_S32("gQuickPutaway", 1),
|
||||
// Skip save confirmation
|
||||
PRESET_ENTRY_S32("gSkipSaveConfirmation", 1),
|
||||
// King Zora Speed (1 to 5)
|
||||
PRESET_ENTRY_S32("gMweepSpeed", 5),
|
||||
// Biggoron Forge Time (0 to 3)
|
||||
PRESET_ENTRY_S32("gForgeTime", 0),
|
||||
// Vine/Ladder Climb speed (+0 to +12)
|
||||
@@ -545,6 +579,8 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
PRESET_ENTRY_S32("gDampeWin", 1),
|
||||
// Skip Magic Arrow Equip Animation
|
||||
PRESET_ENTRY_S32("gSkipArrowAnimation", 1),
|
||||
// Exit Market at Night
|
||||
PRESET_ENTRY_S32("gMarketSneak", 1),
|
||||
|
||||
// Equip arrows on multiple slots
|
||||
PRESET_ENTRY_S32("gSeparateArrows", 1),
|
||||
@@ -565,8 +601,6 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
|
||||
// Autosave
|
||||
PRESET_ENTRY_S32("gAutosave", 1),
|
||||
// Allow the cursor to be on any slot
|
||||
PRESET_ENTRY_S32("gPauseAnyCursor", 1),
|
||||
|
||||
// Customize Fishing Behaviour
|
||||
PRESET_ENTRY_S32("gCustomizeFishing", 1),
|
||||
@@ -592,6 +626,10 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
|
||||
PRESET_ENTRY_S32("gPauseLiveLink", 16),
|
||||
// Frames to wait
|
||||
PRESET_ENTRY_S32("gMinFrameCount", 200),
|
||||
|
||||
PRESET_ENTRY_S32("gNoInputForCredits", 1),
|
||||
|
||||
PRESET_ENTRY_S32("gFastFarores", 1),
|
||||
};
|
||||
|
||||
const std::vector<PresetEntry> s6PresetEntries = {
|
||||
|
||||
@@ -81,12 +81,25 @@ void SetAllEntrancesData(std::vector<EntranceInfoPair>& entranceShuffleTable) {
|
||||
forwardEntrance->SetBlueWarp(forwardEntry.blueWarp);
|
||||
forwardEntrance->SetType(forwardEntry.type);
|
||||
forwardEntrance->SetAsPrimary();
|
||||
|
||||
// When decouple entrances is on, mark it for entrances except boss rooms
|
||||
if (Settings::DecoupleEntrances && forwardEntry.type != EntranceType::ChildBoss &&
|
||||
forwardEntry.type != EntranceType::AdultBoss) {
|
||||
forwardEntrance->SetDecoupled();
|
||||
}
|
||||
|
||||
if (returnEntry.parentRegion != NONE) {
|
||||
Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion);
|
||||
returnEntrance->SetIndex(returnEntry.index);
|
||||
returnEntrance->SetBlueWarp(returnEntry.blueWarp);
|
||||
returnEntrance->SetType(returnEntry.type);
|
||||
forwardEntrance->BindTwoWay(returnEntrance);
|
||||
|
||||
// Mark reverse entrance as decoupled
|
||||
if (Settings::DecoupleEntrances && returnEntry.type != EntranceType::ChildBoss &&
|
||||
returnEntry.type != EntranceType::AdultBoss) {
|
||||
returnEntrance->SetDecoupled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +109,7 @@ static std::vector<Entrance*> AssumeEntrancePool(std::vector<Entrance*>& entranc
|
||||
for (Entrance* entrance : entrancePool) {
|
||||
totalRandomizableEntrances++;
|
||||
Entrance* assumedForward = entrance->AssumeReachable();
|
||||
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable();
|
||||
if (!(Settings::MixedEntrancePools && (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)))) {
|
||||
auto type = entrance->GetType();
|
||||
@@ -218,7 +231,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
|
||||
SPDLOG_DEBUG(message);
|
||||
entrance->Connect(targetEntrance->Disconnect());
|
||||
entrance->SetReplacement(targetEntrance->GetReplacement());
|
||||
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
targetEntrance->GetReplacement()->GetReverse()->Connect(entrance->GetReverse()->GetAssumed()->Disconnect());
|
||||
targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse());
|
||||
}
|
||||
@@ -229,7 +242,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
|
||||
static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) {
|
||||
targetEntrance->Connect(entrance->Disconnect());
|
||||
entrance->SetReplacement(nullptr);
|
||||
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect());
|
||||
targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr);
|
||||
}
|
||||
@@ -247,7 +260,7 @@ static void DeleteTargetEntrance(Entrance* targetEntrance) {
|
||||
|
||||
static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) {
|
||||
DeleteTargetEntrance(targetEntrance);
|
||||
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
|
||||
if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
|
||||
auto replacedReverse = targetEntrance->GetReplacement()->GetReverse();
|
||||
DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed());
|
||||
}
|
||||
@@ -786,9 +799,9 @@ int ShuffleAllEntrances() {
|
||||
{EntranceType::SpecialInterior, KAK_POTION_SHOP_BACK, KAK_BACKYARD, 0x04FF}},
|
||||
|
||||
// Grotto Loads use an entrance index of 0x0700 + their grotto id. The id is used as index for the
|
||||
// grottoLoadTable in src/grotto.c
|
||||
// grottoLoadTable in soh/soh/Enhancements/randomizer/randomizer_grotto.c
|
||||
// Grotto Returns use an entrance index of 0x0800 + their grotto id. The id is used as index for the
|
||||
// grottoReturnTable in src/grotto.c
|
||||
// grottoReturnTable in soh/soh/Enhancements/randomizer/randomizer_grotto.c
|
||||
{{EntranceType::GrottoGrave, DESERT_COLOSSUS, COLOSSUS_GROTTO, 0x0700},
|
||||
{EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}},
|
||||
{{EntranceType::GrottoGrave, LAKE_HYLIA, LH_GROTTO, 0x0701},
|
||||
@@ -933,6 +946,23 @@ int ShuffleAllEntrances() {
|
||||
{{EntranceType::WarpSong, REQUIEM_OF_SPIRIT_WARP, DESERT_COLOSSUS, 0x01F1}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::WarpSong, NOCTURNE_OF_SHADOW_WARP, GRAVEYARD_WARP_PAD_REGION, 0x0568}, NO_RETURN_ENTRANCE},
|
||||
{{EntranceType::WarpSong, PRELUDE_OF_LIGHT_WARP, TEMPLE_OF_TIME, 0x05F4}, NO_RETURN_ENTRANCE},
|
||||
|
||||
{{EntranceType::ChildBoss, DEKU_TREE_BOSS_ENTRYWAY, DEKU_TREE_BOSS_ROOM, 0x040F},
|
||||
{EntranceType::ChildBoss, DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY, 0x0252, 0x0457}},
|
||||
{{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ENTRYWAY, DODONGOS_CAVERN_BOSS_ROOM, 0x040B},
|
||||
{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY, 0x00C5, 0x047A}},
|
||||
{{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ENTRYWAY, JABU_JABUS_BELLY_BOSS_ROOM, 0x0301},
|
||||
{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY, 0x0407, 0x010E}},
|
||||
{{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ENTRYWAY, FOREST_TEMPLE_BOSS_ROOM, 0x000C},
|
||||
{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY, 0x024E, 0x0608}},
|
||||
{{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ENTRYWAY, FIRE_TEMPLE_BOSS_ROOM, 0x0305},
|
||||
{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY, 0x0175, 0x0564}},
|
||||
{{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ENTRYWAY, WATER_TEMPLE_BOSS_ROOM, 0x0417},
|
||||
{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY, 0x0423, 0x060C}},
|
||||
{{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ENTRYWAY, SPIRIT_TEMPLE_BOSS_ROOM, 0x008D},
|
||||
{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY, 0x02F5, 0x0610}},
|
||||
{{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ENTRYWAY, SHADOW_TEMPLE_BOSS_ROOM, 0x0413},
|
||||
{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY, 0x02B2, 0x0580}},
|
||||
};
|
||||
|
||||
std::map<std::string, PriorityEntrance> priorityEntranceTable = {
|
||||
@@ -971,6 +1001,28 @@ int ShuffleAllEntrances() {
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle Bosses
|
||||
if (Settings::ShuffleBossEntrances.IsNot(SHUFFLEBOSSES_OFF)) {
|
||||
if (Settings::ShuffleBossEntrances.Is(SHUFFLEBOSSES_FULL)) {
|
||||
entrancePools[EntranceType::Boss] = GetShuffleableEntrances(EntranceType::ChildBoss);
|
||||
AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::AdultBoss));
|
||||
// If forest is closed, ensure Ghoma is inside the Deku tree
|
||||
// Deku tree being in its vanilla location is handled below
|
||||
if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::Boss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;});
|
||||
}
|
||||
} else {
|
||||
entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss);
|
||||
entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss);
|
||||
// If forest is closed, ensure Ghoma is inside the Deku tree
|
||||
if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) {
|
||||
FilterAndEraseFromPool(entrancePools[EntranceType::ChildBoss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY &&
|
||||
entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Shuffle Dungeon Entrances
|
||||
if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) {
|
||||
entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon);
|
||||
|
||||
@@ -22,6 +22,9 @@ enum class EntranceType {
|
||||
Dungeon,
|
||||
GanonDungeon,
|
||||
DungeonReverse,
|
||||
Boss,
|
||||
ChildBoss,
|
||||
AdultBoss,
|
||||
Interior,
|
||||
InteriorReverse,
|
||||
SpecialInterior,
|
||||
@@ -180,6 +183,14 @@ public:
|
||||
return primary;
|
||||
}
|
||||
|
||||
bool IsDecoupled() const {
|
||||
return decoupled;
|
||||
}
|
||||
|
||||
void SetDecoupled() {
|
||||
decoupled = true;
|
||||
}
|
||||
|
||||
int16_t GetIndex() const {
|
||||
return index;
|
||||
}
|
||||
@@ -269,6 +280,7 @@ private:
|
||||
bool shuffled = false;
|
||||
bool primary = false;
|
||||
bool addedToPool = false;
|
||||
bool decoupled = false;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
|
||||
@@ -148,7 +148,10 @@ static int GetMaxGSCount() {
|
||||
//Get the max amount of GS which could be useful from token reward locations
|
||||
int maxUseful = 0;
|
||||
//If the highest advancement item is a token, we know it is useless since it won't lead to an otherwise useful item
|
||||
if (Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) {
|
||||
if (Location(KAK_100_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_100_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) {
|
||||
maxUseful = 100;
|
||||
}
|
||||
else if (Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) {
|
||||
maxUseful = 50;
|
||||
}
|
||||
else if (Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) {
|
||||
@@ -295,8 +298,8 @@ std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowe
|
||||
if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !noRandomEntrances) {
|
||||
entranceSphere.push_back(&exit);
|
||||
exit.AddToPool();
|
||||
// Don't list a coupled entrance from both directions
|
||||
if (exit.GetReplacement()->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
|
||||
// Don't list a two-way coupled entrance from both directions
|
||||
if (exit.GetReverse() != nullptr && exit.GetReplacement()->GetReverse() != nullptr && !exit.IsDecoupled()) {
|
||||
exit.GetReplacement()->GetReverse()->AddToPool();
|
||||
}
|
||||
}
|
||||
@@ -1074,6 +1077,14 @@ int Fill() {
|
||||
if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) {
|
||||
CreateMerchantsHints();
|
||||
}
|
||||
//Always execute ganon hint generation for the funny line
|
||||
CreateGanonText();
|
||||
if (AltarHintText) {
|
||||
CreateAltarText();
|
||||
}
|
||||
if (DampeHintText) {
|
||||
CreateDampesDiaryText();
|
||||
}
|
||||
if (ShuffleWarpSongs) {
|
||||
CreateWarpSongTexts();
|
||||
}
|
||||
|
||||
@@ -74,6 +74,25 @@ void HintTable_Init() {
|
||||
Text{ "#Malon's obstacle course# leads to", /*french*/ "la #course à obstacle de Malon# amène à",
|
||||
/*spanish*/ "la #carrera de obstáculos de Malon# brinda" });
|
||||
|
||||
hintTable[KAK_100_GOLD_SKULLTULA_REWARD] = HintText::Always(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "#100 bug badges# rewards",
|
||||
/*french*/ "#100 écussons# donnent",
|
||||
/*spanish*/ "#100 medallas de insectos# otorgan" },
|
||||
Text{ "#100 spider souls# yields",
|
||||
/*french*/ "#100 âmes d'arachnide# donnent",
|
||||
/*spanish*/ "#100 almas de araña# otorgan" },
|
||||
Text{ "#100 auriferous arachnids# lead to",
|
||||
/*french*/ "#100 arachnides aurifères# donnent",
|
||||
/*spanish*/ "#100 arácnidos auríferos# otorgan" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "slaying #100 Gold Skulltulas# reveals",
|
||||
/*french*/ "détruire #100 Skulltulas d'or# donne",
|
||||
/*spanish*/ "exterminar #100 skulltulas doradas# revela" });
|
||||
|
||||
/*--------------------------
|
||||
| SOMETIMES HINT TEXT |
|
||||
---------------------------*/
|
||||
@@ -2519,93 +2538,61 @@ void HintTable_Init() {
|
||||
| BOSS HINT TEXT |
|
||||
---------------------------*/
|
||||
|
||||
hintTable[QUEEN_GOHMA] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "An #ancient tree# rewards", /*french*/ "le #vieil arbre# octroie",
|
||||
/*spanish*/ "un #ancestral árbol# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Deku Tree# rewards", /*french*/ "l'#Arbre Mojo# octroie",
|
||||
/*spanish*/ "el #Gran Árbol Deku# premia con" });
|
||||
hintTable[QUEEN_GOHMA] = HintText::Boss({
|
||||
// obscure text
|
||||
Text{"the #Parasitic Armored Arachnid# holds", /*french*/"le #monstre insectoïde géant# possède", /*spanish*/"el #arácnido parasitario acorazado# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Queen Gohma# holds", /*french*/"la #Reine Gohma# possède", /*spanish*/"la #Reina Goma# porta"});
|
||||
|
||||
hintTable[KING_DODONGO] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "An #immense cavern# rewards", /*french*/ "l'#immense caverne# octroie",
|
||||
/*spanish*/ "una #descomunal cueva# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "#Dodongo's Cavern# rewards", /*french*/ "la #Caverne Dodongo# octroie",
|
||||
/*spanish*/ "la #Cueva de los Dodongos# premia con" });
|
||||
hintTable[KING_DODONGO] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Infernal Dinosaur# holds", /*french*/"le #dinosaure infernal# possède", /*spanish*/"el #dinosaurio infernal# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#King Dodongo# holds", /*french*/"le #Roi Dodongo# possède", /*spanish*/"el #Rey Dodongo# porta"});
|
||||
|
||||
hintTable[BARINADE] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "the #belly of a deity# rewards", /*french*/ "le #ventre du gardien# octroie",
|
||||
/*spanish*/ "la #tripa de cierta deidad# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "#Jabu-Jabu's Belly# rewards", /*french*/ "le #Ventre de Jabu-Jabu# octroie",
|
||||
/*spanish*/ "la #tripa de Jabu-Jabu# premia con" });
|
||||
hintTable[BARINADE] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Bio-Electric Anemone# holds", /*french*/"l'#anémone bioélectrique# possède", /*spanish*/"la #anémona bioeléctrica# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Barinade# holds", /*french*/"#Barinade# possède", /*spanish*/"#Barinade# porta"});
|
||||
|
||||
hintTable[PHANTOM_GANON] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "a #deep forest# rewards", /*french*/ "la #profonde forêt# octroie",
|
||||
/*spanish*/ "el #profundo bosque# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Forest Temple# rewards", /*french*/ "le #Temple de la Forêt# octroie",
|
||||
/*spanish*/ "el #Templo del Bosque# premia con" });
|
||||
hintTable[PHANTOM_GANON] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Evil Spirit from Beyond# holds", /*french*/"l'#esprit maléfique de l'au-delà# possède", /*spanish*/"el #espíritu maligno de ultratumba# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Phantom Ganon# holds", /*french*/"#Ganon Spectral# possède", /*spanish*/"#Ganon Fantasma# porta"});
|
||||
|
||||
hintTable[VOLVAGIA] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "a #high mountain# rewards", /*french*/ "la #grande montagne# octroie",
|
||||
/*spanish*/ "una #alta montaña# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Fire Temple# rewards", /*french*/ "le #Temple du Feu# octroie",
|
||||
/*spanish*/ "el #Templo del Fuego# premia con" });
|
||||
hintTable[VOLVAGIA] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Subterranean Lava Dragon# holds", /*french*/"le #dragon des profondeurs# possède", /*spanish*/"el #dragón de lava subterráneo# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Volvagia# holds", /*french*/"#Volvagia# possède", /*spanish*/"#Volvagia# porta"});
|
||||
|
||||
hintTable[MORPHA] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "a #vast lake# rewards", /*french*/ "le #vaste lac# octroie",
|
||||
/*spanish*/ "un #lago inmenso# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Water Temple# rewards", /*french*/ "le #Temple de l'Eau# octroie",
|
||||
/*spanish*/ "el #Templo del Agua# premia con" });
|
||||
hintTable[MORPHA] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Giant Aquatic Amoeba# holds", /*french*/"l'#amibe aquatique géante# possède", /*spanish*/"la #ameba acuática gigante# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Morpha# holds", /*french*/"#Morpha# possède", /*spanish*/"#Morpha# porta"});
|
||||
|
||||
hintTable[BONGO_BONGO] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "the #house of the dead# rewards", /*french*/ "la #maison des morts# octroie",
|
||||
/*spanish*/ "la #casa de la muerte# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Shadow Temple# rewards", /*french*/ "le #Temple de l'Ombre# octroie",
|
||||
/*spanish*/ "el #Templo de las Sombras#" });
|
||||
hintTable[BONGO_BONGO] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Phantom Shadow Beast# holds", /*french*/"le #monstre de l'ombre# possède", /*spanish*/"la #alimaña oscura espectral# porta"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Bongo Bongo# holds", /*french*/"#Bongo Bongo# possède", /*spanish*/"#Bongo Bongo# porta"});
|
||||
|
||||
hintTable[TWINROVA] = HintText::Boss(
|
||||
{
|
||||
// obscure text
|
||||
Text{ "a #goddess of the sand# rewards", /*french*/ "la #déesse des sables# octroie",
|
||||
/*spanish*/ "la #diosa de la arena# premia con" },
|
||||
},
|
||||
{},
|
||||
// clear text
|
||||
Text{ "the #Spirit Temple# rewards", /*french*/ "le #Temple de l'Esprit# octroie",
|
||||
/*spanish*/ "el #Templo del Espíritu# premia con" });
|
||||
hintTable[TWINROVA] = HintText::Boss({
|
||||
//obscure text
|
||||
Text{"the #Sorceress Sisters# hold", /*french*/"#les sorcières jumelles# possède", /*spanish*/"las #hermanas hechiceras# portan"},
|
||||
}, {},
|
||||
//clear text
|
||||
Text{"#Twinrova# holds", /*french*/"#Twinrova# possède", /*spanish*/"#Birova# porta"});
|
||||
//
|
||||
// [LINKS_POCKET_BOSS] = HintText::Boss({
|
||||
// //obscure text
|
||||
@@ -2731,6 +2718,13 @@ void HintTable_Init() {
|
||||
/*spanish*/ "Y el héroe recibirá la llave del #señor del mal# cuando haya completado la #Trifuerza#." },
|
||||
});
|
||||
|
||||
hintTable[GANON_BK_SKULLTULA_HINT] = HintText::GanonsBossKey({
|
||||
// obscure text
|
||||
Text { "And the %revil one%w's key will be&provided by the cursed rich man&once %r100 Gold Skulltula Tokens%w&are retrieved.",
|
||||
/*french*/ "Aussi, la %rclé du Malin%w sera&donnée par l'homme maudit une&fois que %r100 Symboles de&Skulltula d'or%w auront été trouvés.",
|
||||
/*spanish*/ "Y el rico maldito entregará la llave&del #señor de mal# tras obtener&100 símbolos de skulltula dorada#."},
|
||||
});
|
||||
|
||||
/*--------------------------
|
||||
| LACS HINT TEXT |
|
||||
---------------------------*/
|
||||
|
||||
@@ -418,6 +418,10 @@ void HintTable_Init_Exclude_Overworld() {
|
||||
Text{"a #carpet guru# sells", /*french*/"#un marchand du désert# vend", /*spanish*/"el #genio de una alfombra# vende"},
|
||||
});
|
||||
|
||||
hintTable[GC_MEDIGORON] = HintText::Exclude({
|
||||
//obscure text
|
||||
Text{"#Medigoron# sells", /*french*/"#Medigoron# vend", /*spanish*/"#Medigoron# vende"},
|
||||
});
|
||||
|
||||
hintTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = HintText::Exclude({
|
||||
//obscure text
|
||||
|
||||
@@ -116,6 +116,7 @@ Text childAltarText;
|
||||
Text adultAltarText;
|
||||
Text ganonText;
|
||||
Text ganonHintText;
|
||||
Text dampesText;
|
||||
Text warpMinuetText;
|
||||
Text warpBoleroText;
|
||||
Text warpSerenadeText;
|
||||
@@ -139,6 +140,10 @@ Text& GetGanonHintText() {
|
||||
return ganonHintText;
|
||||
}
|
||||
|
||||
Text& GetDampeHintText() {
|
||||
return dampesText;
|
||||
}
|
||||
|
||||
Text& GetWarpMinuetText() {
|
||||
return warpMinuetText;
|
||||
}
|
||||
@@ -312,17 +317,12 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
|
||||
Location(hintedLocation)->SetAsHinted();
|
||||
uint32_t gossipStone = RandomElement(gossipStoneLocations);
|
||||
|
||||
// form hint text
|
||||
Text locationText;
|
||||
if (Location(hintedLocation)->IsDungeon()) {
|
||||
*remainingDungeonWothHints -= 1;
|
||||
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
|
||||
locationText = AreaTable(parentRegion)->GetHint().GetText();
|
||||
|
||||
} else {
|
||||
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
|
||||
locationText = GetHintRegion(parentRegion)->GetHint().GetText();
|
||||
}
|
||||
|
||||
// form hint text
|
||||
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
|
||||
Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText();
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalWothHint.english);
|
||||
@@ -360,16 +360,12 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
|
||||
Location(hintedLocation)->SetAsHinted();
|
||||
uint32_t gossipStone = RandomElement(gossipStoneLocations);
|
||||
|
||||
// form hint text
|
||||
Text locationText;
|
||||
if (Location(hintedLocation)->IsDungeon()) {
|
||||
*remainingDungeonBarrenHints -= 1;
|
||||
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
|
||||
locationText = Hint(AreaTable(parentRegion)->hintKey).GetText();
|
||||
} else {
|
||||
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
|
||||
locationText = Hint(GetHintRegion(parentRegion)->hintKey).GetText();
|
||||
}
|
||||
|
||||
// form hint text
|
||||
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
|
||||
Text finalBarrenHint =
|
||||
Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText();
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
@@ -414,16 +410,15 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
|
||||
|
||||
//form hint text
|
||||
Text itemText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText();
|
||||
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
|
||||
// RANDOTODO: reconsider dungeon vs non-dungeon item location hints when boss shuffle mixed pools happens
|
||||
if (Location(hintedLocation)->IsDungeon()) {
|
||||
uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey();
|
||||
Text locationText = AreaTable(parentRegion)->GetHint().GetText();
|
||||
Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#.";
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalHint.english);
|
||||
SPDLOG_DEBUG("\n\n");
|
||||
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
|
||||
} else {
|
||||
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
|
||||
Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#.";
|
||||
SPDLOG_DEBUG("\tMessage: ");
|
||||
SPDLOG_DEBUG(finalHint.english);
|
||||
@@ -546,7 +541,7 @@ static void CreateTrialHints() {
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateGanonText() {
|
||||
void CreateGanonText() {
|
||||
|
||||
//funny ganon line
|
||||
ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText();
|
||||
@@ -658,6 +653,9 @@ static Text BuildGanonBossKeyText() {
|
||||
} else if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE)) {
|
||||
ganonBossKeyText = Hint(GANON_BK_ANYWHERE_HINT).GetText();
|
||||
|
||||
} else if (GanonsBossKey.Is(GANONSBOSSKEY_FINAL_GS_REWARD)) {
|
||||
ganonBossKeyText = Hint(GANON_BK_SKULLTULA_HINT).GetText();
|
||||
|
||||
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_VANILLA)) {
|
||||
ganonBossKeyText = Hint(LACS_VANILLA_HINT).GetText();
|
||||
|
||||
@@ -680,7 +678,7 @@ static Text BuildGanonBossKeyText() {
|
||||
return Text()+"$b"+ganonBossKeyText+"^";
|
||||
}
|
||||
|
||||
static void CreateAltarText() {
|
||||
void CreateAltarText() {
|
||||
|
||||
//Child Altar Text
|
||||
childAltarText = Hint(SPIRITUAL_STONE_TEXT_START).GetText()+"^"+
|
||||
@@ -737,6 +735,25 @@ void CreateMerchantsHints() {
|
||||
CreateMessageFromTextObject(0x6078, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextTwo, {QM_RED, QM_YELLOW, QM_RED}));
|
||||
}
|
||||
|
||||
void CreateDampesDiaryText() {
|
||||
uint32_t item = PROGRESSIVE_HOOKSHOT;
|
||||
uint32_t location = FilterFromPool(allLocations, [item](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == item;})[0];
|
||||
Text area = GetHintRegion(Location(location)->GetParentRegionKey())->GetHint().GetText();
|
||||
Text temp1 = Text{
|
||||
"Whoever reads this, please enter %g",
|
||||
"Toi qui lit ce journal, rends-toi dans %g",
|
||||
"Wer immer dies liest, der möge folgenden Ort aufsuchen: %g"
|
||||
};
|
||||
|
||||
Text temp2 = {
|
||||
"%w. I will let you have my stretching, shrinking keepsake.^I'm waiting for you.&--Dampé",
|
||||
"%w. Et peut-être auras-tu droit à mon précieux %rtrésor%w.^Je t'attends...&--Igor",
|
||||
"%w. Ihm gebe ich meinen langen, kurzen Schatz.^Ich warte!&Boris"
|
||||
};
|
||||
|
||||
dampesText = temp1 + area + temp2;
|
||||
}
|
||||
|
||||
void CreateWarpSongTexts() {
|
||||
auto warpSongEntrances = GetShuffleableEntrances(EntranceType::WarpSong, false);
|
||||
|
||||
@@ -777,9 +794,6 @@ void CreateWarpSongTexts() {
|
||||
|
||||
void CreateAllHints() {
|
||||
|
||||
CreateGanonText();
|
||||
CreateAltarText();
|
||||
|
||||
SPDLOG_DEBUG("\nNOW CREATING HINTS\n");
|
||||
const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()];
|
||||
|
||||
|
||||
@@ -221,11 +221,15 @@ extern uint32_t GetHintRegionHintKey(const uint32_t area);
|
||||
extern void CreateAllHints();
|
||||
extern void CreateMerchantsHints();
|
||||
extern void CreateWarpSongTexts();
|
||||
extern void CreateDampesDiaryText();
|
||||
extern void CreateGanonText();
|
||||
extern void CreateAltarText();
|
||||
|
||||
Text& GetChildAltarText();
|
||||
Text& GetAdultAltarText();
|
||||
Text& GetGanonText();
|
||||
Text& GetGanonHintText();
|
||||
Text& GetDampeHintText();
|
||||
|
||||
Text& GetWarpMinuetText();
|
||||
Text& GetWarpBoleroText();
|
||||
|
||||
@@ -286,6 +286,11 @@ Item& ItemFromGIID(const int giid) {
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// there are vanilla items that don't exist in the item table we're reading from here
|
||||
// if we made it this far, it means we didn't find an item in the table
|
||||
// if we don't return anything, the game will crash, so, as a workaround, return greg
|
||||
return itemTable[GREEN_RUPEE];
|
||||
}
|
||||
|
||||
//This function should only be used to place items containing hint text
|
||||
|
||||
@@ -116,6 +116,7 @@ void LocationTable_Init() {
|
||||
locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_30_GOLD_SKULLTULA_REWARD, 0x50, 0x46, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_40_GOLD_SKULLTULA_REWARD, 0x50, 0x03, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_50_GOLD_SKULLTULA_REWARD, 0x50, 0x3E, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_100_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_100_GOLD_SKULLTULA_REWARD, 0x50, 0x3E, "Kak 100 Gold Skulltula Reward", KAK_100_GOLD_SKULLTULA_REWARD, HUGE_RUPEE, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDF), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, 0x3E, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_KAK_SHOOTING_GALLERY_REWARD, 0x42, 0x30, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::Chest(0x42, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, 0x20, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO);
|
||||
@@ -1276,6 +1277,7 @@ std::vector<uint32_t> overworldLocations = {
|
||||
KAK_30_GOLD_SKULLTULA_REWARD,
|
||||
KAK_40_GOLD_SKULLTULA_REWARD,
|
||||
KAK_50_GOLD_SKULLTULA_REWARD,
|
||||
KAK_100_GOLD_SKULLTULA_REWARD,
|
||||
KAK_MAN_ON_ROOF,
|
||||
KAK_SHOOTING_GALLERY_REWARD,
|
||||
KAK_TRADE_ODD_MUSHROOM,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user