Merge Upstream

This commit is contained in:
Waterdish
2024-11-10 17:45:18 -08:00
266 changed files with 11675 additions and 3378 deletions
+4 -2
View File
@@ -192,15 +192,17 @@ jobs:
key: ${{ runner.os }}-14-macports-${{ hashFiles('.github/workflows/macports-deps.txt') }}
restore-keys: |
${{ runner.os }}-14-macports-
# Updated PATH applies to the next step and onwards
- name: Install MacPorts (if necessary)
run: |
if [ command -v port &>/dev/null ]; then
if command -v /opt/local/bin/port 2>&1 >/dev/null; then
echo "MacPorts already installed"
else
echo "Installing MacPorts"
wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-14-Sonoma.pkg
sudo installer -pkg ./MacPorts-2.9.3-14-Sonoma.pkg -target /
fi
echo "/opt/local/bin:/opt/local/sbin" >> $GITHUB_PATH
echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH"
- name: Install dependencies
run: |
brew uninstall --ignore-dependencies libpng
+6 -5
View File
@@ -12,7 +12,7 @@ jobs:
if: ${{ github.event.workflow_run.event == 'pull_request' }}
steps:
- id: 'pr-number'
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
result-encoding: string
script: |
@@ -20,8 +20,9 @@ jobs:
const pullHeadSHA = '${{github.event.workflow_run.head_sha}}';
const pullUserId = ${{github.event.sender.id}};
const prNumber = await (async () => {
const pulls = await github.rest.pulls.list({owner, repo});
for await (const {data} of github.paginate.iterator(pulls)) {
for await (const { data } of github.paginate.iterator(
github.rest.pulls.list, { owner, repo }
)) {
for (const pull of data) {
if (pull.head.sha === pullHeadSHA && pull.user.id === pullUserId) {
return pull.number;
@@ -36,7 +37,7 @@ jobs:
return prNumber;
- id: 'artifacts-text'
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
result-encoding: string
script: |
@@ -54,7 +55,7 @@ jobs:
return acc;
}, '### Build Artifacts');
- id: 'add-to-pr'
uses: garrettjoecox/pr-section@3.1.0
uses: garrettjoecox/pr-section@4.0.0
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pr-number: ${{ steps.pr-number.outputs.result }}
+3 -3
View File
@@ -5,10 +5,10 @@ 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")
project(2s2h VERSION 1.0.2 LANGUAGES C CXX)
project(2s2h VERSION 1.1.0 LANGUAGES C CXX)
include(CMake/2ship-cvars.cmake)
include(CMake/lus-cvars.cmake)
set(PROJECT_BUILD_NAME "Rika Charlie" CACHE STRING "" FORCE)
set(PROJECT_BUILD_NAME "Satoko Alfa" CACHE STRING "" FORCE)
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT 2ship)
@@ -32,7 +32,7 @@ endif()
set(GFX_DEBUG_DISASSEMBLER ON)
# Tell LUS we're using F3DEX_GBI_2 (in a way that doesn't break libgfxd)
set(USE_F3DEX2 ON)
set(GBI_UCODE F3DEX_GBI_2)
################################################################################
# Set target arch type if empty. Visual studio solution generator provides it.
+239
View File
@@ -0,0 +1,239 @@
# Building 2 Ship 2 Harkinian
## Windows
Requires:
* At least 8GB of RAM (machines with 4GB have seen complier failures)
* Visual Studio 2022 Community Edition with the C++ feature set
* One of the Windows SDKs that comes with Visual Studio, for example the current Windows 10 version 10.0.19041.0
* The `MSVC v143 - VS 2022 C++ build tools` component of Visual Studio
* Python 3 (can be installed manually or as part of Visual Studio)
* Git (can be installed manually or as part of Visual Studio)
* Cmake (can be installed via chocolatey or manually)
During installation, check the "Desktop development with C++" feature set:
![image](https://user-images.githubusercontent.com/30329717/183511274-d11aceea-7900-46ec-acb6-3f2cc110021a.png)
Doing so should also check one of the Windows SDKs by default. Then, in the installation details in the right-hand column, make sure you also check the v143 toolset. This is often done by default.
It is recommended that you install Python and Git standalone, the install process in VS Installer has given some issues in the past.
1. Clone the 2 Ship 2 Harkinian repository
_Note: Be sure to either clone with the ``--recursive`` flag or do ``git submodule update --init`` after cloning to pull in the libultraship submodule!_
2. After setup and initial build, use the built-in O2R extraction to make your mm.o2r file.
_Note: Instructions assume using powershell_
```powershell
# Navigate to the 2ship2harkinian repo within powershell. ie: cd "C:\yourpath\2ship2harkinian"
cd 2ship2harkinian
# Setup cmake project
# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging
& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64
# Generate 2ship.o2r
& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target Generate2ShipOtr
# Compile project
# Add `--config Release` if you're packaging
& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64
# Now you can run the executable in .\build\x64 or run in Visual Studio
```
### Developing 2S2H
With the cmake build system you have two options for working on the project:
#### Visual Studio
To develop using Visual Studio you only need to use cmake to generate the solution file:
```powershell
# Generates 2s2h.sln at `build/x64` for Visual Studio 2022
& 'C:\Program Files\CMake\bin\cmake' -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64
```
#### Visual Studio Code or another editor
To develop using Visual Studio Code or another editor you only need to open the repository in it.
To build you'll need to follow the instructions from the building section.
_Note: If you're using Visual Studio Code, the [cpack plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._
_Experimental: You can also use another build system entirely rather than MSVC like [Ninja](https://ninja-build.org/) for possibly better performance._
### Generating the distributable
After compiling the project you can generate the distributable by running:
```powershell
# Go to build folder
cd "build/x64"
# Generate
& 'C:\Program Files\CMake\bin\cpack.exe' -G ZIP
```
### Additional CMake Targets
#### Clean
```powershell
# If you need to clean the project you can run
C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target clean
```
#### Regenerate Asset Headers
```powershell
# If you need to regenerate the asset headers to check them into source
C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target ExtractAssetHeaders
```
## Linux
### Install dependencies
#### Debian/Ubuntu
```sh
# using gcc
apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
# or using clang
apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
```
#### Arch
```sh
# using gcc
pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost
# or using clang
pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost
```
#### Fedora
```sh
# using gcc
dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel
# or using clang
dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel
```
#### openSUSE
```sh
# using gcc
zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel
# or using clang
zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel
```
### Build
_Note: If you're using Visual Studio Code, the [CMake Tools plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._
```bash
# Clone the repo and enter the directory
git clone https://github.com/HarbourMasters/2ship2harkinian.git
cd 2ship2harkinian
# Clone the submodules
git submodule update --init
# Generate Ninja project
# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging
# Add `-DPython3_EXECUTABLE=$(which python3)` if you are using non-standard Python installations such as PyEnv
cmake -H. -Bbuild-cmake -GNinja
# Generate 2ship.o2r
cmake --build build-cmake --target Generate2ShipOtr
# Compile the project
# Add `--config Release` if you're packaging
cmake --build build-cmake
# Now you can run the executable in ./build-cmake/mm/2s2h.elf
# To develop the project open the repository in VSCode (or your preferred editor)
```
### Generate a distributable
After compiling the project you can generate a distributable by running of the following:
```bash
# Go to build folder
cd build-cmake
# Generate
cpack -G DEB
cpack -G ZIP
cpack -G External (creates appimage)
```
### Additional CMake Targets
#### Clean
```bash
# If you need to clean the project you can run
cmake --build build-cmake --target clean
```
#### Regenerate Asset Headers
```bash
# If you need to regenerate the asset headers to check them into source
cmake --build build-cmake --target ExtractAssetHeaders
```
## macOS
Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake, nlohmann-json, libzip` (can be installed via homebrew, macports, etc)
**Important: For maximum performance make sure you have ninja build tools installed!**
_Note: If you're using Visual Studio Code, the [cpack plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) makes it very easy to just press run and debug._
```bash
# Clone the repo
git clone https://github.com/HarbourMasters/2ship2harkinian.git
cd 2ship2harkinian
# Clone the submodule libultraship
git submodule update --init
# Generate Ninja project
# Add `-DCMAKE_BUILD_TYPE:STRING=Release` if you're packaging
cmake -H. -Bbuild-cmake -GNinja
# Generate 2ship.o2r
cmake --build build-cmake --target Generate2ShipOtr
# Compile the project
# Add `--config Release` if you're packaging
cmake --build build-cmake
# Now you can run the executable file:
./build-cmake/mm/2s2h-macos
# To develop the project open the repository in VSCode (or your preferred editor)
```
### Generating a distributable
After compiling the project you can generate a distributable by running of the following:
```bash
# Go to build folder
cd build-cmake
# Generate
cpack
```
### Additional CMake Targets
#### Clean
```bash
# If you need to clean the project you can run
cmake --build build-cmake --target clean
```
#### Regenerate Asset Headers
```bash
# If you need to regenerate the asset headers to check them into source
cmake --build build-cmake --target ExtractAssetHeaders
```
# Compatible Roms
See [`supportedHashes.json`](supportedHashes.json)
## 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 `mm/`.
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 separately 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.
+1 -1
View File
@@ -7,4 +7,4 @@
"name": "NTSC-U GC",
"sha1": "9743aa026e9269b339eb0e3044cd5830a440c1fd"
}
]
]
+42 -14
View File
@@ -8,6 +8,7 @@
#include <Fast3D/gfx_pc.h>
#include "UIWidgets.hpp"
#include "HudEditor.h"
#include "Notification.h"
#ifdef __APPLE__
#include "graphic/Fast3D/gfx_metal.h"
@@ -20,6 +21,9 @@
#include "include/global.h"
#include "include/z64audio.h"
#include "Enhancements/Trackers/ItemTracker.h"
#include "Enhancements/Trackers/ItemTrackerSettings.h"
namespace BenGui {
// MARK: - Delegates
@@ -27,7 +31,6 @@ std::shared_ptr<BenMenuBar> mBenMenuBar;
std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
std::shared_ptr<Ship::GuiWindow> mStatsWindow;
std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow;
std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
@@ -35,6 +38,11 @@ std::shared_ptr<HudEditorWindow> mHudEditorWindow;
std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
std::shared_ptr<CollisionViewerWindow> mCollisionViewerWindow;
std::shared_ptr<EventLogWindow> mEventLogWindow;
std::shared_ptr<BenMenu> mBenMenu;
std::shared_ptr<BenInputEditorWindow> mBenInputEditorWindow;
std::shared_ptr<Notification::Window> mNotificationWindow;
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
void SetupGuiElements() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
@@ -47,7 +55,7 @@ void SetupGuiElements() {
mBenMenuBar = std::make_shared<BenMenuBar>(CVAR_MENU_BAR_OPEN, CVarGetInteger(CVAR_MENU_BAR_OPEN, 0));
gui->SetMenuBar(std::reinterpret_pointer_cast<Ship::GuiMenuBar>(mBenMenuBar));
if (gui->GetMenuBar() && !gui->GetMenuBar()->IsVisible()) {
if (!gui->GetMenuBar() && !CVarGetInteger("gSettings.DisableMenuShortcutNotify", 0)) {
#if defined(__SWITCH__) || defined(__WIIU__) || defined(__ANDROID__)
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press - to access enhancements menu");
#else
@@ -55,6 +63,9 @@ void SetupGuiElements() {
#endif
}
mBenMenu = std::make_shared<BenMenu>("gWindows.Menu", "Settings Menu");
gui->SetMenu(mBenMenu);
mStatsWindow = gui->GetGuiWindow("Stats");
if (mStatsWindow == nullptr) {
SPDLOG_ERROR("Could not find stats window");
@@ -65,43 +76,60 @@ void SetupGuiElements() {
SPDLOG_ERROR("Could not find console window");
}
mInputEditorWindow = gui->GetGuiWindow("Input Editor");
if (mInputEditorWindow == nullptr) {
SPDLOG_ERROR("Could not find input editor window");
}
mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow");
if (mGfxDebuggerWindow == nullptr) {
SPDLOG_ERROR("Could not find input GfxDebuggerWindow");
}
mSaveEditorWindow = std::make_shared<SaveEditorWindow>("gWindows.SaveEditor", "Save Editor");
mBenInputEditorWindow = std::make_shared<BenInputEditorWindow>("gWindows.BenInputEditor", "2S2H Input Editor");
gui->AddGuiWindow(mBenInputEditorWindow);
mSaveEditorWindow = std::make_shared<SaveEditorWindow>("gWindows.SaveEditor", "Save Editor", ImVec2(480, 600));
gui->AddGuiWindow(mSaveEditorWindow);
mHudEditorWindow = std::make_shared<HudEditorWindow>("gWindows.HudEditor", "Hud Editor");
mHudEditorWindow = std::make_shared<HudEditorWindow>("gWindows.HudEditor", "HUD Editor", ImVec2(480, 600));
gui->AddGuiWindow(mHudEditorWindow);
mActorViewerWindow = std::make_shared<ActorViewerWindow>("gWindows.ActorViewer", "Actor Viewer");
mActorViewerWindow = std::make_shared<ActorViewerWindow>("gWindows.ActorViewer", "Actor Viewer", ImVec2(520, 600));
gui->AddGuiWindow(mActorViewerWindow);
mCollisionViewerWindow = std::make_shared<CollisionViewerWindow>("gWindows.CollisionViewer", "Collision Viewer");
mCollisionViewerWindow =
std::make_shared<CollisionViewerWindow>("gWindows.CollisionViewer", "Collision Viewer", ImVec2(390, 475));
gui->AddGuiWindow(mCollisionViewerWindow);
mEventLogWindow = std::make_shared<EventLogWindow>("gWindows.EventLog", "Event Log");
mEventLogWindow = std::make_shared<EventLogWindow>("gWindows.EventLog", "Event Log", ImVec2(520, 600));
gui->AddGuiWindow(mEventLogWindow);
mItemTrackerWindow = std::make_shared<ItemTrackerWindow>("gWindows.ItemTracker", "Item Tracker");
gui->AddGuiWindow(mItemTrackerWindow);
mItemTrackerSettingsWindow = std::make_shared<ItemTrackerSettingsWindow>("gWindows.ItemTrackerSettings",
"Item Tracker Settings", ImVec2(800, 400));
gui->AddGuiWindow(mItemTrackerSettingsWindow);
gui->SetPadBtnTogglesMenu();
mNotificationWindow = std::make_shared<Notification::Window>("gWindows.Notifications", "Notifications Window");
gui->AddGuiWindow(mNotificationWindow);
mNotificationWindow->Show();
}
void Destroy() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
gui->RemoveAllGuiWindows();
mBenMenuBar = nullptr;
mBenMenu = nullptr;
mStatsWindow = nullptr;
mConsoleWindow = nullptr;
mInputEditorWindow = nullptr;
mBenInputEditorWindow = nullptr;
mGfxDebuggerWindow = nullptr;
mCollisionViewerWindow = nullptr;
mEventLogWindow = nullptr;
mNotificationWindow = nullptr;
mSaveEditorWindow = nullptr;
mHudEditorWindow = nullptr;
mActorViewerWindow = nullptr;
mItemTrackerWindow = nullptr;
mItemTrackerSettingsWindow = nullptr;
}
} // namespace BenGui
+2
View File
@@ -7,6 +7,8 @@
#include "DeveloperTools/ActorViewer.h"
#include "DeveloperTools/CollisionViewer.h"
#include "DeveloperTools/EventLog.h"
#include "BenInputEditorWindow.h"
#include "Menu.h"
namespace BenGui {
void SetupHooks();
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
#pragma once
#include "stdint.h"
#include "window/gui/GuiWindow.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui.h>
#include <unordered_map>
#include <string>
#include <vector>
#include <set>
#include "controller/controldevice/controller/Controller.h"
class BenInputEditorWindow : public Ship::GuiWindow {
public:
using Ship::GuiWindow::GuiWindow;
~BenInputEditorWindow();
void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading);
void DrawInputChip(const char* buttonName, ImVec4 color);
void DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone = 0, bool gyro = false);
void DrawControllerSchema();
bool TestingRumble();
void DrawFullContents();
void DrawPortTabContents(uint8_t portIndex);
protected:
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
private:
void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, Ship::Direction direction,
ImVec4 color);
void DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask, ImVec4 color);
void DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id);
void DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask);
void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction,
std::string id);
void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction);
void DrawStickSection(uint8_t port, uint8_t stick, int32_t id, ImVec4 color);
void DrawRumbleSection(uint8_t port);
void DrawRemoveRumbleMappingButton(uint8_t port, std::string id);
void DrawAddRumbleMappingButton(uint8_t port);
void DrawLEDSection(uint8_t port);
void DrawRemoveLEDMappingButton(uint8_t port, std::string id);
void DrawAddLEDMappingButton(uint8_t port);
void DrawGyroSection(uint8_t port);
void DrawRemoveGyroMappingButton(uint8_t port, std::string id);
void DrawAddGyroMappingButton(uint8_t port);
int32_t mGameInputBlockTimer;
int32_t mMappingInputBlockTimer;
int32_t mRumbleTimer;
std::shared_ptr<Ship::ControllerRumbleMapping> mRumbleMappingToTest;
// mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... }
std::unordered_map<uint8_t, std::unordered_map<CONTROLLERBUTTONS_T, std::vector<std::string>>> mBitmaskToMappingIds;
// mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... }
std::unordered_map<uint8_t,
std::unordered_map<uint8_t, std::unordered_map<Ship::Direction, std::vector<std::string>>>>
mStickDirectionToMappingIds;
void UpdateBitmaskToMappingIds(uint8_t port);
void UpdateStickDirectionToMappingIds(uint8_t port);
void GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor);
void DrawPortTab(uint8_t portIndex);
std::set<CONTROLLERBUTTONS_T> mButtonsBitmasks;
std::set<CONTROLLERBUTTONS_T> mDpadBitmasks;
void DrawButtonDeviceIcons(uint8_t portIndex, std::set<CONTROLLERBUTTONS_T> bitmasks);
void DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick);
void DrawRumbleDeviceIcons(uint8_t portIndex);
void DrawGyroDeviceIcons(uint8_t portIndex);
void DrawLEDDeviceIcons(uint8_t portIndex);
bool mInputEditorPopupOpen;
void DrawSetDefaultsButton(uint8_t portIndex);
void DrawClearAllButton(uint8_t portIndex);
std::map<Ship::ShipDeviceIndex, bool> mDeviceIndexVisiblity;
void DrawDeviceVisibilityButtons();
};
+270 -24
View File
@@ -8,12 +8,13 @@
#include <unordered_map>
#include <string>
#include "2s2h/Enhancements/Enhancements.h"
#include "2s2h/Enhancements/Graphics/MotionBlur.h"
#include "2s2h/Enhancements/Graphics/PlayAsKafei.h"
#include "2s2h/Enhancements/GfxPatcher/AuthenticGfxPatches.h"
#include "2s2h/DeveloperTools/DeveloperTools.h"
#include "2s2h/DeveloperTools/WarpPoint.h"
#include "HudEditor.h"
#include "2s2h/Enhancements/Trackers/ItemTracker.h"
#include "2s2h/Enhancements/Trackers/ItemTrackerSettings.h"
extern "C" {
#include "z64.h"
#include "functions.h"
@@ -38,14 +39,14 @@ static const std::unordered_map<Ship::AudioBackend, const char*> audioBackendsMa
};
static std::unordered_map<Ship::WindowBackend, const char*> windowBackendsMap = {
{ Ship::WindowBackend::DX11, "DirectX" },
{ Ship::WindowBackend::SDL_OPENGL, "OpenGL" },
{ Ship::WindowBackend::SDL_METAL, "Metal" },
{ Ship::WindowBackend::GX2, "GX2" }
{ Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" },
{ Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL" },
{ Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" },
};
static const std::unordered_map<int32_t, const char*> clockTypeOptions = {
{ CLOCK_TYPE_ORIGINAL, "Original" },
{ CLOCK_TYPE_3DS, "MM3D style" },
{ CLOCK_TYPE_TEXT_BASED, "Text only" },
};
@@ -55,6 +56,18 @@ static const std::unordered_map<int32_t, const char*> alwaysWinDoggyraceOptions
{ ALWAYS_WIN_DOGGY_RACE_ALWAYS, "Always" },
};
static const std::unordered_map<int32_t, const char*> cremiaRewardOptions = {
{ CREMIA_REWARD_RANDOM, "Vanilla" },
{ CREMIA_REWARD_ALWAYS_HUG, "Hug" },
{ CREMIA_REWARD_ALWAYS_RUPEE, "Rupee" },
};
static const std::unordered_map<int32_t, const char*> timeStopOptions = {
{ TIME_STOP_OFF, "Off" },
{ TIME_STOP_TEMPLES, "Temples" },
{ TIME_STOP_TEMPLES_DUNGEONS, "Temples + Mini Dungeons" },
};
namespace BenGui {
std::shared_ptr<std::vector<Ship::WindowBackend>> availableWindowBackends;
std::unordered_map<Ship::WindowBackend, const char*> availableWindowBackendsMap;
@@ -63,7 +76,7 @@ Ship::WindowBackend configWindowBackend;
void UpdateWindowBackendObjects() {
Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend();
int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
if (configWindowBackendId != -1 && configWindowBackendId < static_cast<int>(Ship::WindowBackend::BACKEND_COUNT)) {
if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) {
configWindowBackend = static_cast<Ship::WindowBackend>(configWindowBackendId);
} else {
configWindowBackend = runningWindowBackend;
@@ -147,7 +160,7 @@ void DrawBenMenu() {
}
}
extern std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
extern std::shared_ptr<BenInputEditorWindow> mBenInputEditorWindow;
void DrawSettingsMenu() {
if (UIWidgets::BeginMenu("Settings")) {
@@ -214,19 +227,21 @@ void DrawSettingsMenu() {
{ // FPS Slider
constexpr unsigned int minFps = 20;
static unsigned int maxFps;
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) {
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() ==
Ship::WindowBackend::FAST3D_DXGI_DX11) {
maxFps = 360;
} else {
maxFps = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
}
unsigned int currentFps =
std::max(std::min(OTRGlobals::Instance->GetInterpolationFPS(), maxFps), minFps);
bool matchingRefreshRate =
CVarGetInteger("gMatchRefreshRate", 0) &&
Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() != Ship::WindowBackend::DX11;
bool matchingRefreshRate = CVarGetInteger("gMatchRefreshRate", 0) &&
Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() !=
Ship::WindowBackend::FAST3D_DXGI_DX11;
UIWidgets::CVarSliderInt((currentFps == 20) ? "FPS: Original (20)" : "FPS: %d", "gInterpolationFPS",
minFps, maxFps, 20, { .disabled = matchingRefreshRate });
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) {
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() ==
Ship::WindowBackend::FAST3D_DXGI_DX11) {
UIWidgets::Tooltip(
"Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is "
"purely visual and does not impact game logic, execution of glitches etc.\n\n A higher target "
@@ -238,7 +253,8 @@ void DrawSettingsMenu() {
}
} // END FPS Slider
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) {
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() ==
Ship::WindowBackend::FAST3D_DXGI_DX11) {
// UIWidgets::Spacer(0);
if (ImGui::Button("Match Refresh Rate")) {
int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
@@ -252,7 +268,8 @@ void DrawSettingsMenu() {
}
UIWidgets::Tooltip("Matches interpolation value to the current game's window refresh rate");
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::DX11) {
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() ==
Ship::WindowBackend::FAST3D_DXGI_DX11) {
UIWidgets::CVarSliderInt(CVarGetInteger("gExtraLatencyThreshold", 80) == 0 ? "Jitter fix: Off"
: "Jitter fix: >= %d FPS",
"gExtraLatencyThreshold", 0, 360, 80);
@@ -302,8 +319,8 @@ void DrawSettingsMenu() {
// #region 2S2H [Todo] None of this works yet
/*
if (UIWidgets::BeginMenu("Controller")) { */
if (mInputEditorWindow) {
UIWidgets::WindowButton("Controller Mapping", "gWindows.InputEditor", mInputEditorWindow);
if (mBenInputEditorWindow) {
UIWidgets::WindowButton("Controller Mapping", "gWindows.InputEditor", mBenInputEditorWindow);
}
/*
#ifndef __SWITCH__
@@ -334,10 +351,11 @@ void DrawSettingsMenu() {
}
extern std::shared_ptr<HudEditorWindow> mHudEditorWindow;
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
extern std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
void DrawEnhancementsMenu() {
if (UIWidgets::BeginMenu("Enhancements")) {
if (UIWidgets::BeginMenu("Camera")) {
ImGui::SeparatorText("Fixes");
UIWidgets::CVarCheckbox(
@@ -345,6 +363,50 @@ void DrawEnhancementsMenu() {
{ .tooltip =
"Fixes the camera snap that occurs when you are moving and press the targetting button." });
ImGui::SeparatorText("First Person");
UIWidgets::CVarCheckbox("Disable Auto-Centering",
"gEnhancements.Camera.FirstPerson.DisableFirstPersonAutoCenterView");
UIWidgets::CVarCheckbox("Invert X Axis", "gEnhancements.Camera.FirstPerson.InvertX");
UIWidgets::CVarCheckbox("Invert Y Axis", "gEnhancements.Camera.FirstPerson.InvertY",
{ .defaultValue = true });
UIWidgets::CVarSliderFloat("X Axis Sensitivity: %.0f%%", "gEnhancements.Camera.FirstPerson.SensitivityX",
0.1f, 2.0f, 1.0f, { .isPercentage = true });
UIWidgets::CVarSliderFloat("Y Axis Sensitivity: %.0f%%", "gEnhancements.Camera.FirstPerson.SensitivityY",
0.1f, 2.0f, 1.0f, { .isPercentage = true });
UIWidgets::CVarCheckbox(
"Gyro Aiming", "gEnhancements.Camera.FirstPerson.GyroEnabled",
{ .tooltip = "Enables gyro aiming in first person mode. Requires a controller with gyro support, and "
"for it to be mapped in the Controller Mapping menu" });
if (CVarGetInteger("gEnhancements.Camera.FirstPerson.GyroEnabled", 0)) {
UIWidgets::CVarCheckbox("Invert Gyro X Axis", "gEnhancements.Camera.FirstPerson.GyroInvertX");
UIWidgets::CVarCheckbox("Invert Gyro Y Axis", "gEnhancements.Camera.FirstPerson.GyroInvertY");
UIWidgets::CVarSliderFloat("Gyro X Axis Sensitivity: %.0f%%",
"gEnhancements.Camera.FirstPerson.GyroSensitivityX", 0.1f, 2.0f, 1.0f,
{ .isPercentage = true });
UIWidgets::CVarSliderFloat("Gyro Y Axis Sensitivity: %.0f%%",
"gEnhancements.Camera.FirstPerson.GyroSensitivityY", 0.1f, 2.0f, 1.0f,
{ .isPercentage = true });
}
UIWidgets::CVarCheckbox(
"Right Stick Aiming", "gEnhancements.Camera.FirstPerson.RightStickEnabled",
{ .tooltip = "Enables right stick aiming in first person mode. Requires the controller right stick to "
"be mapped in the Controller Mapping menu" });
if (CVarGetInteger("gEnhancements.Camera.FirstPerson.RightStickEnabled", 0)) {
UIWidgets::CVarCheckbox("Move with left stick while in first person",
"gEnhancements.Camera.FirstPerson.MoveInFirstPerson");
UIWidgets::CVarCheckbox("Invert Right Stick X Axis",
"gEnhancements.Camera.FirstPerson.RightStickInvertX");
UIWidgets::CVarCheckbox("Invert Right Stick Y Axis",
"gEnhancements.Camera.FirstPerson.RightStickInvertY", { .defaultValue = true });
UIWidgets::CVarSliderFloat("Right Stick X Axis Sensitivity: %.0f%%",
"gEnhancements.Camera.FirstPerson.RightStickSensitivityX", 0.1f, 2.0f, 1.0f,
{ .isPercentage = true });
UIWidgets::CVarSliderFloat("Right Stick Y Axis Sensitivity: %.0f%%",
"gEnhancements.Camera.FirstPerson.RightStickSensitivityY", 0.1f, 2.0f, 1.0f,
{ .isPercentage = true });
}
ImGui::SeparatorText("Free Look");
if (UIWidgets::CVarCheckbox(
"Free Look", "gEnhancements.Camera.FreeLook.Enable",
@@ -419,6 +481,12 @@ void DrawEnhancementsMenu() {
{
.tooltip = "When starting a game you will be taken straight to South Clock Town as Deku Link.",
});
if (CVarGetInteger("gEnhancements.Cutscenes.SkipIntroSequence", 0)) {
UIWidgets::CVarCheckbox(
"Skip First Cycle", "gEnhancements.Cutscenes.SkipFirstCycle",
{ .tooltip = "When starting a game you will be taken straight to South Clock Town as Human Link "
"with Deku Mask, Ocarina, Song of Time, and Song of Healing." });
}
UIWidgets::CVarCheckbox(
"Skip Story Cutscenes", "gEnhancements.Cutscenes.SkipStoryCutscenes",
{
@@ -468,6 +536,17 @@ void DrawEnhancementsMenu() {
{ .tooltip = "Playing the Song Of Time will not reset the Sword back to Kokiri Sword." });
UIWidgets::CVarCheckbox("Do not reset Rupees", "gEnhancements.Cycle.DoNotResetRupees",
{ .tooltip = "Playing the Song Of Time will not reset the your rupees." });
UIWidgets::CVarCheckbox(
"Do not reset Time Speed", "gEnhancements.Cycle.DoNotResetTimeSpeed",
{ .tooltip =
"Playing the Song Of Time will not reset the current time speed set by Inverted Song of Time." });
if (UIWidgets::CVarCheckbox(
"Keep Express Mail", "gEnhancements.Cycle.KeepExpressMail",
{ .tooltip = "Allows the player to keep the Express Mail in their inventory after delivering it "
"the first time, so that both deliveries can be done within one cycle" })) {
RegisterKeepExpressMail();
}
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 0, 255));
ImGui::SeparatorText("Unstable");
@@ -480,7 +559,11 @@ void DrawEnhancementsMenu() {
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Dialogues")) {
if (UIWidgets::BeginMenu("Dialogue")) {
UIWidgets::CVarCheckbox(
"Fast Bank Selection", "gEnhancements.Dialogue.FastBankSelection",
{ .tooltip = "Pressing the Z or R buttons while the Deposit/Withdrawl Rupees dialogue is open will set "
"the Rupees to Links current Rupees or 0 respectively." });
UIWidgets::CVarCheckbox(
"Fast Text", "gEnhancements.Dialogue.FastText",
{ .tooltip = "Speeds up text rendering, and enables holding of B progress to next message" });
@@ -495,15 +578,49 @@ void DrawEnhancementsMenu() {
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Equipment")) {
UIWidgets::CVarCheckbox("Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed",
{ .tooltip = "Removes the animation for equipping Magic Arrows." });
UIWidgets::CVarCheckbox(
"Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall",
{ .tooltip =
"Pressing B will instantly recall the fin boomerang back to Zora Link after they are thrown." });
UIWidgets::CVarCheckbox(
"Two-Handed Sword Spin Attack", "gEnhancements.Equipment.TwoHandedSwordSpinAttack",
{ .tooltip = "Enables magic spin attacks for the Fierce Deity Sword and Great Fairy's Sword." });
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Fixes")) {
UIWidgets::CVarCheckbox("Fix Ammo Count Color", "gFixes.FixAmmoCountEnvColor",
{ .tooltip = "Fixes a missing gDPSetEnvColor, which causes the ammo count to be "
"the wrong color prior to obtaining magic or other conditions." });
UIWidgets::CVarCheckbox("Fix Fierce Deity Z-Target movement",
"gEnhancements.Fixes.FierceDeityZTargetMovement",
{ .tooltip = "Fixes Fierce Deity movement being choppy when Z-targeting" });
UIWidgets::CVarCheckbox("Fix Hess and Weirdshot Crash", "gEnhancements.Fixes.HessCrash",
{ .tooltip = "Fixes a crash that can occur when performing a HESS or Weirdshot.",
.defaultValue = true });
UIWidgets::CVarCheckbox("Fix Text Control Characters", "gEnhancements.Fixes.ControlCharacters",
{ .tooltip = "Fixes certain control characters not functioning properly "
"depending on their position within the text." });
UIWidgets::CVarCheckbox("Fix Ikana Great Fairy Fountain Color", "gFixes.FixIkanaGreatFairyFountainColor",
{ .tooltip = "Fixes a bug that results in the Ikana Great Fairy fountain looking "
"green instead of yellow, this was fixed in the EU version" });
if (UIWidgets::CVarCheckbox(
"Fix Texture overflow OOB", "gEnhancements.Fixes.FixTexturesOOB",
{ .tooltip = "Fixes textures that normally overflow to be patched with the correct size or format",
.defaultValue = true })) {
GfxPatcher_ApplyOverflowTexturePatches();
}
ImGui::EndMenu();
}
@@ -511,6 +628,12 @@ void DrawEnhancementsMenu() {
ImGui::SeparatorText("Clock");
UIWidgets::CVarCombobox("Clock Type", "gEnhancements.Graphics.ClockType", clockTypeOptions);
UIWidgets::CVarCheckbox("24 Hours Clock", "gEnhancements.Graphics.24HoursClock");
ImGui::SeparatorText("Mods");
UIWidgets::CVarCheckbox("Use Alternate Assets", "gEnhancements.Mods.AlternateAssets",
{ .tooltip = "Toggle between standard assets and alternate assets. Usually mods "
"will indicate if this setting has to be used or not." });
MotionBlur_RenderMenuOptions();
ImGui::SeparatorText("Other");
UIWidgets::CVarCheckbox("Authentic logo", "gEnhancements.Graphics.AuthenticLogo",
@@ -518,15 +641,60 @@ void DrawEnhancementsMenu() {
"model and texture on the boot logo start screen" });
UIWidgets::CVarCheckbox("Bow Reticle", "gEnhancements.Graphics.BowReticle",
{ .tooltip = "Gives the bow a reticle when you draw an arrow" });
if (UIWidgets::CVarCheckbox("3D Item Drops", "gEnhancements.Graphics.3DItemDrops",
{ .tooltip = "Makes item drops 3D" })) {
Register3DItemDrops();
}
UIWidgets::CVarCheckbox(
"Disable Black Bar Letterboxes", "gEnhancements.Graphics.DisableBlackBars",
{ .tooltip = "Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be "
"minor visual glitches that were covered up by the black bars\nPlease disable this "
"setting before reporting a bug" });
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 0, 255));
ImGui::SeparatorText("Unstable");
ImGui::PopStyleColor();
UIWidgets::CVarCheckbox(
"Disable Scene Geometry Distance Check", "gEnhancements.Graphics.DisableSceneGeometryDistanceCheck",
{ .tooltip =
"Disables the distance check for scene geometry, allowing it to be drawn no matter how far "
"away it is from the player. This may have unintended side effects." });
UIWidgets::CVarCheckbox("Widescreen Actor Culling",
"gEnhancements.Graphics.ActorCullingAccountsForWidescreen",
{ .tooltip = "Adjusts the culling planes to account for widescreen resolutions. "
"This may have unintended side effects." });
if (UIWidgets::CVarSliderInt(
"Increase Actor Draw Distance: %dx", "gEnhancements.Graphics.IncreaseActorDrawDistance", 1, 5, 1,
{ .tooltip =
"Increase the range in which Actors are drawn. This may have unintended side effects." })) {
CVarSetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance",
MIN(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1),
CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1)));
}
if (UIWidgets::CVarSliderInt(
"Increase Actor Update Distance: %dx", "gEnhancements.Graphics.IncreaseActorUpdateDistance", 1, 5,
1,
{ .tooltip =
"Increase the range in which Actors are updated. This may have unintended side effects." })) {
CVarSetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance",
MAX(CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1),
CVarGetInteger("gEnhancements.Graphics.IncreaseActorUpdateDistance", 1)));
}
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Masks")) {
UIWidgets::CVarCheckbox("Blast Mask has Powder Keg Force", "gEnhancements.Masks.BlastMaskKeg");
UIWidgets::CVarCheckbox("Fast Transformation", "gEnhancements.Masks.FastTransformation");
UIWidgets::CVarCheckbox("Fierce Deity's Mask Anywhere", "gEnhancements.Masks.FierceDeitysAnywhere",
{ .tooltip = "Allow using Fierce Deity's mask outside of boss rooms." });
UIWidgets::CVarCheckbox("No Blast Mask Cooldown", "gEnhancements.Masks.NoBlastMaskCooldown", {});
if (UIWidgets::CVarCheckbox("Persistent Bunny Hood", "gEnhancements.Masks.PersistentBunnyHood.Enabled",
{ .tooltip = "Permanantly toggle a speed boost from the bunny hood by pressing "
"'A' on it in the mask menu." })) {
UpdatePersistentMasksState();
}
ImGui::EndMenu();
}
@@ -534,6 +702,15 @@ void DrawEnhancementsMenu() {
if (UIWidgets::BeginMenu("Minigames")) {
UIWidgets::CVarCombobox("Always Win Doggy Race", "gEnhancements.Minigames.AlwaysWinDoggyRace",
alwaysWinDoggyraceOptions);
UIWidgets::CVarCombobox(
"Milk Run Reward Options", "gEnhancements.Minigames.CremiaHugs", cremiaRewardOptions,
{ .tooltip = "Choose what reward you get for winning the Milk Run minigame after the first time. \n"
"-Vanilla: Reward is Random\n"
"-Hug: Get the hugging cutscene\n"
"-Rupee: Get the rupee reward",
.defaultIndex = CREMIA_REWARD_RANDOM });
UIWidgets::CVarSliderInt("Swordsman School Winning Score: %d",
"gEnhancements.Minigames.SwordsmanSchoolScore", 1, 30, 30);
ImGui::EndMenu();
}
@@ -541,12 +718,33 @@ void DrawEnhancementsMenu() {
if (UIWidgets::BeginMenu("Modes")) {
UIWidgets::CVarCheckbox("Play As Kafei", "gModes.PlayAsKafei",
{ .tooltip = "Requires scene reload to take effect." });
if (UIWidgets::CVarCheckbox("Time Moves When You Move", "gModes.TimeMovesWhenYouMove")) {
RegisterTimeMovesWhenYouMove();
}
if (UIWidgets::CVarCheckbox("Mirrored World", "gModes.MirroredWorld.Mode")) {
if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) {
CVarSetInteger("gModes.MirroredWorld.State", 1);
} else {
CVarClear("gModes.MirroredWorld.State");
}
}
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Player Movement")) {
UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.PlayerMovement.ClimbSpeed", 1, 5, 1,
{ .tooltip = "Increases the speed at which Link climbs vines and ladders." });
if (UIWidgets::BeginMenu("Player")) {
UIWidgets::CVarSliderInt("Climb speed", "gEnhancements.Player.ClimbSpeed", 1, 5, 1,
{ .tooltip = "Increases the speed at which Link climbs vines and ladders." });
if (UIWidgets::CVarCheckbox("Fast Deku Flower Launch", "gEnhancements.Player.FastFlowerLaunch",
{ .tooltip =
"Speeds up the time it takes to be able to get maximum height from "
"launching out of a deku flower" })) {
RegisterFastFlowerLaunch();
}
UIWidgets::CVarCheckbox("Instant Putaway", "gEnhancements.Player.InstantPutaway",
{ .tooltip = "Allows Link to instantly puts away held item without waiting." });
UIWidgets::CVarCheckbox("Fierce Deity Putaway", "gEnhancements.Player.FierceDeityPutaway",
{ .tooltip = "Allows Fierce Deity Link to put away his sword." });
ImGui::EndMenu();
}
@@ -563,6 +761,14 @@ void DrawEnhancementsMenu() {
UIWidgets::CVarCheckbox("Tatl ISG", "gEnhancements.Restorations.TatlISG",
{ .tooltip = "Restores Navi ISG from OOT, but now with Tatl." });
if (UIWidgets::CVarCheckbox(
"Woodfall Mountain Appearance", "gEnhancements.Restorations.WoodfallMountainAppearance",
{ .tooltip = "Restores the appearance of Woodfall mountain to not look poisoned "
"when viewed from Termina Field after clearing Woodfall Temple\n\n"
"Requires a scene reload to take effect" })) {
RegisterWoodfallMountainAppearance();
}
ImGui::EndMenu();
}
@@ -576,15 +782,40 @@ void DrawEnhancementsMenu() {
{ .tooltip = "Enables using the Dpad for Ocarina playback." });
UIWidgets::CVarCheckbox("Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput",
{ .tooltip = "Prevent dropping inputs when playing the ocarina quickly" });
UIWidgets::CVarCheckbox("Skip Scarecrow Song", "gEnhancements.Playback.SkipScarecrowSong",
{ .tooltip = "Pierre appears when the Ocarina is pulled out." });
UIWidgets::CVarCheckbox("Pause Owl Warp", "gEnhancements.Songs.PauseOwlWarp",
{ .tooltip = "Allows the player to use the pause menu map to owl warp instead of "
"having to play the Song of Soaring." });
UIWidgets::CVarSliderInt("Zora Eggs For Bossa Nova", "gEnhancements.Songs.ZoraEggCount", 1, 7, 7,
{ .tooltip = "The number of eggs required to unlock new wave bossa nova." });
ImGui::EndMenu();
}
if (UIWidgets::BeginMenu("Difficulty Options")) {
if (UIWidgets::CVarCheckbox("Disable Takkuri Steal", "gEnhancements.Cheats.DisableTakkuriSteal",
{ .tooltip = "Prevents the Takkuri from stealing key items like bottles and "
"swords. It may still steal other items." })) {
RegisterDisableTakkuriSteal();
}
ImGui::EndMenu();
}
if (mHudEditorWindow) {
UIWidgets::WindowButton("Hud Editor", "gWindows.HudEditor", mHudEditorWindow,
{ .tooltip = "Enables the Hud Editor window, allowing you to edit your hud" });
}
if (mItemTrackerWindow) {
UIWidgets::WindowButton("Item Tracker", "gWindows.ItemTracker", mItemTrackerWindow);
}
if (mItemTrackerSettingsWindow) {
UIWidgets::WindowButton("Item Tracker Settings", "gWindows.ItemTrackerSettings",
mItemTrackerSettingsWindow);
}
ImGui::EndMenu();
}
}
@@ -595,13 +826,28 @@ void DrawCheatsMenu() {
UIWidgets::CVarCheckbox("Infinite Magic", "gCheats.InfiniteMagic");
UIWidgets::CVarCheckbox("Infinite Rupees", "gCheats.InfiniteRupees");
UIWidgets::CVarCheckbox("Infinite Consumables", "gCheats.InfiniteConsumables");
if (UIWidgets::CVarCheckbox(
"Longer Deku Flower Glide", "gCheats.LongerFlowerGlide",
{ .tooltip = "Allows Deku Link to glide longer, no longer dropping after a certain distance" })) {
RegisterLongerFlowerGlide();
}
UIWidgets::CVarCheckbox("No Clip", "gCheats.NoClip");
UIWidgets::CVarCheckbox("Unbreakable Razor Sword", "gCheats.UnbreakableRazorSword");
UIWidgets::CVarCheckbox("Unrestricted Items", "gCheats.UnrestrictedItems");
if (UIWidgets::CVarCheckbox("Moon Jump on L", "gCheats.MoonJumpOnL",
{ .tooltip = "Holding L makes you float into the air" })) {
RegisterMoonJumpOnL();
}
UIWidgets::CVarCheckbox("No Clip", "gCheats.NoClip");
UIWidgets::CVarCheckbox("Elegy of Emptiness Anywhere", "gCheats.ElegyAnywhere",
{ .tooltip = "Allows Elegy of Emptiness outside of Ikana" });
UIWidgets::CVarCombobox(
"Stop Time in Dungeons", "gCheats.TempleTimeStop", timeStopOptions,
{ .tooltip = "Stops time from advancing in selected areas. Requires a room change to update.\n\n"
"- Off: Vanilla behaviour.\n"
"- Temples: Stops time in Woodfall, Snowhead, Great Bay, and Stone Tower Temples.\n"
"- Temples + Mini Dungeons: In addition to the above temples, stops time in both Spider "
"Houses, Pirate's Fortress, Beneath the Well, Ancient Castle of Ikana, and Secret Shrine.",
.defaultIndex = TIME_STOP_OFF });
ImGui::EndMenu();
}
+1
View File
@@ -7,6 +7,7 @@
#include "DeveloperTools/ActorViewer.h"
#include "DeveloperTools/CollisionViewer.h"
#include "DeveloperTools/EventLog.h"
#include "BenInputEditorWindow.h"
namespace BenGui {
class BenMenuBar : public Ship::GuiMenuBar {
+6 -9
View File
@@ -17,6 +17,7 @@ HudEditorElement hudEditorElements[HUD_EDITOR_ELEMENT_MAX] = {
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_D_PAD, "D-Pad", "DPad", 271, 55, 255, 255, 255, 255),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_MINIMAP, "Minimap", "Minimap", 295, 220, 0, 255, 255, 160),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_START, "Start Button", "Start", 136, 17, 255, 130, 60, 255),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_CARROT, "Horse Carrots", "Carrots", 160, 64, 236, 92, 41, 255),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_CLOCK, "Three Day Clock", "Clock", 160, 206, 255, 255, 255, 255),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_HEARTS, "Hearts", "Hearts", 30, 26, 255, 70, 50, 255),
HUD_EDITOR_ELEMENT(HUD_EDITOR_ELEMENT_MAGIC_METER, "Magic", "Magic", 18, 34, 0, 200, 0, 255),
@@ -166,12 +167,6 @@ enum Presets {
};
void HudEditorWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(480, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Hud Editor", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}
static HudEditor::Presets preset = HudEditor::Presets::VANILLA;
if (UIWidgets::Combobox("Preset", &preset, presetNames)) {
for (int i = HUD_EDITOR_ELEMENT_B; i < HUD_EDITOR_ELEMENT_MAX; i++) {
@@ -206,6 +201,8 @@ void HudEditorWindow::DrawElement() {
HUD_EDITOR_ELEMENT_MODE_MOVABLE_RIGHT);
CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_START].modeCvar,
HUD_EDITOR_ELEMENT_MODE_MOVABLE_RIGHT);
CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_CARROT].modeCvar,
HUD_EDITOR_ELEMENT_MODE_MOVABLE_43);
CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_CLOCK].modeCvar,
HUD_EDITOR_ELEMENT_MODE_MOVABLE_43);
CVarSetInteger(hudEditorElements[HUD_EDITOR_ELEMENT_HEARTS].modeCvar,
@@ -249,7 +246,9 @@ void HudEditorWindow::DrawElement() {
}
if (CVarGetInteger(hudEditorElements[i].modeCvar, HUD_EDITOR_ELEMENT_MODE_VANILLA) >=
HUD_EDITOR_ELEMENT_MODE_MOVABLE_43) {
if (ImGui::BeginTable("##table", 3, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoBordersInBody)) {
if (ImGui::BeginTable("##table", 3,
ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoBordersInBody |
ImGuiTableFlags_SizingStretchSame)) {
ImGui::TableNextColumn();
UIWidgets::CVarSliderInt("X", hudEditorElements[i].xCvar, -10, 330, hudEditorElements[i].defaultX,
{
@@ -276,6 +275,4 @@ void HudEditorWindow::DrawElement() {
}
ImGui::PopID();
}
ImGui::End();
}
+1
View File
@@ -32,6 +32,7 @@ typedef enum {
HUD_EDITOR_ELEMENT_D_PAD,
HUD_EDITOR_ELEMENT_MINIMAP,
HUD_EDITOR_ELEMENT_START,
HUD_EDITOR_ELEMENT_CARROT,
HUD_EDITOR_ELEMENT_CLOCK,
HUD_EDITOR_ELEMENT_HEARTS,
HUD_EDITOR_ELEMENT_MAGIC_METER,
+468
View File
@@ -0,0 +1,468 @@
#include "Menu.h"
#include "BenPort.h"
#include "BenGui.hpp"
#include "UIWidgets.hpp"
#include "graphic/Fast3D/gfx_rendering_api.h"
#include "2s2h/Enhancements/Enhancements.h"
#include "2s2h/DeveloperTools/DeveloperTools.h"
#include "window/gui/GuiMenuBar.h"
#include "window/gui/GuiElement.h"
#include "DeveloperTools/SaveEditor.h"
#include "DeveloperTools/ActorViewer.h"
#include "DeveloperTools/CollisionViewer.h"
#include "DeveloperTools/EventLog.h"
#include "HudEditor.h"
#include "SearchableMenuItems.h"
extern "C" {
#include "z64.h"
#include "functions.h"
extern PlayState* gPlayState;
}
std::vector<ImVec2> windowTypeSizes = { {} };
namespace BenGui {
extern std::shared_ptr<HudEditorWindow> mHudEditorWindow;
extern std::shared_ptr<Ship::GuiWindow> mStatsWindow;
extern std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
extern std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow;
extern std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
extern std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
extern std::shared_ptr<CollisionViewerWindow> mCollisionViewerWindow;
extern std::shared_ptr<EventLogWindow> mEventLogWindow;
extern std::shared_ptr<BenInputEditorWindow> mBenInputEditorWindow;
extern std::shared_ptr<std::vector<Ship::WindowBackend>> availableWindowBackends;
extern std::unordered_map<Ship::WindowBackend, const char*> availableWindowBackendsMap;
extern Ship::WindowBackend configWindowBackend;
extern void UpdateWindowBackendObjects();
// BENTODO: Not implemented yet
// UIWidgets::CVarCheckbox("Widescreen Actor Culling",
// "gEnhancements.Graphics.ActorCullingAccountsForWidescreen",
// { .tooltip = "Adjusts the culling planes to account for widescreen resolutions. "
// "This may have unintended side effects." });
// if (gPlayState != NULL) {
// ImGui::Separator();
// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_ENABLE);
// if (gPlayState->frameAdvCtx.enabled) {
// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_SINGLE);
// SearchMenuGetItem(MENU_ITEM_FRAME_ADVANCE_HOLD);
// if (ImGui::IsItemActive()) {
// CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1);
// }
// }
// }
// ImGui::PushStyleColor(ImGuiCol_Button, menuTheme[menuThemeIndex]);
// RenderWarpPointSection();
// ImGui::PopStyleColor(1);
//}
BenMenu::BenMenu(const std::string& consoleVariable, const std::string& name) : GuiWindow(consoleVariable, name) {
}
void BenMenu::InitElement() {
popped = CVarGetInteger("gSettings.Menu.Popout", 0);
poppedSize.x = CVarGetInteger("gSettings.Menu.PoppedWidth", 1280);
poppedSize.y = CVarGetInteger("gSettings.Menu.PoppedHeight", 800);
poppedPos.x = CVarGetInteger("gSettings.Menu.PoppedPos.x", 0);
poppedPos.y = CVarGetInteger("gSettings.Menu.PoppedPos.y", 0);
AddSettings();
AddEnhancements();
AddDevTools();
menuEntries = { { "Settings", settingsSidebar, "gSettings.Menu.SettingsSidebarIndex" },
{ "Enhancements", enhancementsSidebar, "gSettings.Menu.EnhancementsSidebarIndex" },
{ "Developer Tools", devToolsSidebar, "gSettings.Menu.DevToolsSidebarIndex" } };
UpdateWindowBackendObjects();
}
void BenMenu::UpdateElement() {
}
bool ModernMenuSidebarEntry(std::string label) {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pos = window->DC.CursorPos;
const ImGuiID sidebarId = window->GetID(std::string(label + "##Sidebar").c_str());
ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
pos.y += style.FramePadding.y;
pos.x = window->WorkRect.GetCenter().x - labelSize.x / 2;
ImRect bb = { pos - style.FramePadding, pos + labelSize + style.FramePadding };
ImGui::ItemSize(bb, style.FramePadding.y);
ImGui::ItemAdd(bb, sidebarId);
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, sidebarId, &hovered, &held);
if (pressed) {
ImGui::MarkItemEdited(sidebarId);
}
window->DrawList->AddRectFilled(pos - style.FramePadding, pos + labelSize + style.FramePadding,
ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive
: hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button),
3.0f);
UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
return pressed;
}
bool ModernMenuHeaderEntry(std::string label) {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pos = window->DC.CursorPos;
const ImGuiID headerId = window->GetID(std::string(label + "##Header").c_str());
ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
ImRect bb = { pos, pos + labelSize + style.FramePadding * 2 };
ImGui::ItemSize(bb, style.FramePadding.y);
ImGui::ItemAdd(bb, headerId);
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, headerId, &hovered, &held);
window->DrawList->AddRectFilled(bb.Min, bb.Max,
ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive
: hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button),
3.0f);
pos += style.FramePadding;
UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
return pressed;
}
void BenMenu::Draw() {
if (!IsVisible()) {
return;
}
DrawElement();
// Sync up the IsVisible flag if it was changed by ImGui
SyncVisibilityConsoleVariable();
}
void BenMenu::DrawElement() {
for (auto& [reason, info] : disabledMap) {
info.active = info.evaluation(info);
}
menuThemeIndex = static_cast<ColorOption>(CVarGetInteger("gSettings.MenuTheme", 3));
windowHeight = ImGui::GetMainViewport()->WorkSize.y;
windowWidth = ImGui::GetMainViewport()->WorkSize.x;
auto windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
bool popout = CVarGetInteger("gSettings.Menu.Popout", 0) && allowPopout;
if (popout) {
windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDocking;
}
if (popout != popped) {
if (popout) {
windowHeight = poppedSize.y;
windowWidth = poppedSize.x;
ImGui::SetNextWindowSize({ static_cast<float>(windowWidth), static_cast<float>(windowHeight) },
ImGuiCond_Always);
ImGui::SetNextWindowPos(poppedPos, ImGuiCond_Always);
} else if (popped) {
CVarSetFloat("gSettings.Menu.PoppedWidth", poppedSize.x);
CVarSetFloat("gSettings.Menu.PoppedHeight", poppedSize.y);
CVarSave();
}
}
popped = popout;
auto windowCond = ImGuiCond_Always;
if (!popout) {
ImGui::SetNextWindowSize({ static_cast<float>(windowWidth), static_cast<float>(windowHeight) }, windowCond);
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), windowCond, { 0.5f, 0.5f });
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
}
if (!ImGui::Begin("Main Menu", NULL, windowFlags | ImGuiWindowFlags_NoBringToFrontOnFocus)) {
if (!popout) {
ImGui::PopStyleVar();
}
ImGui::End();
return;
}
if (popped != popout) {
if (!popout) {
ImGui::PopStyleVar();
}
CVarSetInteger("gSettings.Menu.Popout", popped);
CVarSetFloat("gSettings.Menu.PoppedWidth", poppedSize.x);
CVarSetFloat("gSettings.Menu.PoppedHeight", poppedSize.y);
CVarSetFloat("gSettings.Menu.PoppedPos.x", poppedSize.x);
CVarSetFloat("gSettings.Menu.PoppedPos.y", poppedSize.y);
CVarSave();
ImGui::End();
return;
}
ImGui::PushFont(OTRGlobals::Instance->fontStandardLargest);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
windowHeight = window->WorkRect.GetHeight();
windowWidth = window->WorkRect.GetWidth();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
auto sectionCount = menuEntries.size();
const char* headerCvar = "gSettings.Menu.SelectedHeader";
uint8_t headerIndex = CVarGetInteger(headerCvar, 0);
ImVec2 pos = window->DC.CursorPos;
float centerX = pos.x + windowWidth / 2 - (style.ItemSpacing.x * (sectionCount + 1));
std::vector<ImVec2> headerSizes;
float headerWidth = 200.0f + style.ItemSpacing.x;
for (int i = 0; i < sectionCount; i++) {
ImVec2 size = ImGui::CalcTextSize(menuEntries.at(i).label.c_str());
headerSizes.push_back(size);
headerWidth += size.x + style.FramePadding.x * 2;
if (i + 1 < sectionCount) {
headerWidth += style.ItemSpacing.x;
}
}
ImVec2 menuSize = { std::fminf(1280, windowWidth), std::fminf(800, windowHeight) };
pos += window->WorkRect.GetSize() / 2 - menuSize / 2;
ImGui::SetNextWindowPos(pos);
ImGui::BeginChild("Menu Block", menuSize,
ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar);
std::vector<SidebarEntry> sidebar;
float headerHeight = headerSizes.at(0).y + style.FramePadding.y * 2;
ImVec2 buttonSize = ImGui::CalcTextSize(ICON_FA_TIMES_CIRCLE) + style.FramePadding * 2;
bool scrollbar = false;
if (headerWidth > menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3) {
headerHeight += style.ScrollbarSize;
scrollbar = true;
}
if (UIWidgets::Button(ICON_FA_TIMES_CIRCLE, { .size = UIWidgets::Sizes::Inline, .tooltip = "Close Menu (Esc)" })) {
ToggleVisibility();
}
ImGui::SameLine();
ImGui::SetNextWindowSizeConstraints({ 0, headerHeight }, { headerWidth, headerHeight });
ImVec2 headerSelSize = { menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3, headerHeight };
if (scrollbar) {
headerSelSize.y += style.ScrollbarSize;
}
bool autoFocus = CVarGetInteger("gSettings.SearchAutofocus", 0);
bool headerSearch = !CVarGetInteger("gSettings.SidebarSearch", 0);
ImGui::BeginChild("Header Selection", headerSelSize,
ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_HorizontalScrollbar);
for (int i = 0; i < sectionCount; i++) {
auto entry = menuEntries.at(i);
uint8_t nextIndex = i;
UIWidgets::PushStyleButton(menuTheme[menuThemeIndex]);
if (headerIndex != i) {
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
}
if (ModernMenuHeaderEntry(entry.label)) {
if (autoFocus) {
menuSearch.Clear();
}
CVarSetInteger(headerCvar, i);
CVarSave();
nextIndex = i;
}
if (headerIndex != i) {
ImGui::PopStyleColor();
}
UIWidgets::PopStyleButton();
if (headerIndex == i) {
sidebar = entry.sidebarEntries;
}
if (i + 1 < sectionCount) {
ImGui::SameLine();
}
if (nextIndex != i) {
headerIndex = nextIndex;
}
}
std::string menuSearchText = "";
if (headerSearch) {
ImGui::SameLine();
if (autoFocus && ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() &&
!ImGui::IsMouseClicked(0)) {
ImGui::SetKeyboardFocusHere(0);
}
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0, 0, 0, 0 });
menuSearch.Draw("##search", 200.0f);
menuSearchText = menuSearch.InputBuf;
menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), menuSearchText.end());
if (menuSearchText.length() < 1) {
ImGui::SameLine(headerWidth - 200.0f + style.ItemSpacing.x);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Search...");
}
ImGui::PopStyleColor();
}
ImGui::EndChild();
ImGui::SameLine(menuSize.x - (buttonSize.x * 2) - style.ItemSpacing.x);
if (UIWidgets::Button(ICON_FA_UNDO, { .color = UIWidgets::Colors::Red,
.size = UIWidgets::Sizes::Inline,
.tooltip = "Reset"
#ifdef __APPLE__
" (Command-R)"
#elif !defined(__SWITCH__) && !defined(__WIIU__)
" (Ctrl+R)"
#else
""
#endif
})) {
std::reinterpret_pointer_cast<Ship::ConsoleWindow>(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))
->Dispatch("reset");
}
ImGui::SameLine();
if (UIWidgets::Button(
ICON_FA_POWER_OFF,
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline, .tooltip = "Quit 2S2H" })) {
if (!popped) {
ToggleVisibility();
}
Ship::Context::GetInstance()->GetWindow()->Close();
}
ImGui::PopStyleVar();
pos.y += headerHeight + style.ItemSpacing.y;
pos.x = centerX - menuSize.x / 2 + (style.ItemSpacing.x * (sectionCount + 1));
window->DrawList->AddRectFilled(pos, pos + ImVec2{ menuSize.x, 4 }, ImGui::GetColorU32({ 255, 255, 255, 255 }),
true, style.WindowRounding);
pos.y += style.ItemSpacing.y;
float sectionHeight = menuSize.y - headerHeight - 4 - style.ItemSpacing.y * 2;
float columnHeight = sectionHeight - style.ItemSpacing.y * 4;
ImGui::SetNextWindowPos(pos + style.ItemSpacing * 2);
float sidebarWidth = 200 - style.ItemSpacing.x;
const char* sidebarCvar = menuEntries.at(headerIndex).sidebarCvar;
uint8_t sectionIndex = CVarGetInteger(sidebarCvar, 0);
if (sectionIndex > sidebar.size() - 1)
sectionIndex = sidebar.size() - 1;
if (sectionIndex < 0)
sectionIndex = 0;
float sectionCenterX = pos.x + (sidebarWidth / 2);
float topY = pos.y;
ImGui::SetNextWindowSizeConstraints({ sidebarWidth, 0 }, { sidebarWidth, columnHeight });
ImGui::BeginChild((menuEntries.at(headerIndex).label + " Section").c_str(), { sidebarWidth, columnHeight * 3 },
ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoTitleBar);
for (size_t i = 0; i < sidebar.size(); i++) {
auto sidebarEntry = sidebar.at(i);
uint8_t nextIndex = i;
UIWidgets::PushStyleButton(menuTheme[menuThemeIndex]);
if (sectionIndex != i) {
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
}
if (ModernMenuSidebarEntry(sidebarEntry.label)) {
if (autoFocus) {
menuSearch.Clear();
}
CVarSetInteger(sidebarCvar, i);
CVarSave();
nextIndex = i;
}
if (sectionIndex != i) {
ImGui::PopStyleColor();
}
UIWidgets::PopStyleButton();
if (nextIndex != i) {
sectionIndex = i;
}
}
ImGui::EndChild();
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
pos = ImVec2{ sectionCenterX + (sidebarWidth / 2), topY } + style.ItemSpacing * 2;
window->DrawList->AddRectFilled(pos, pos + ImVec2{ 4, sectionHeight - style.FramePadding.y * 2 },
ImGui::GetColorU32({ 255, 255, 255, 255 }), true, style.WindowRounding);
pos.x += 4 + style.ItemSpacing.x;
ImGui::SetNextWindowPos(pos + style.ItemSpacing);
float sectionWidth = menuSize.x - sidebarWidth - 4 - style.ItemSpacing.x * 4;
std::string sectionMenuId = sidebar.at(sectionIndex).label + " Settings";
int columns = sidebar.at(sectionIndex).columnCount;
size_t columnFuncs = sidebar.at(sectionIndex).columnWidgets.size();
if (windowWidth < 800) {
columns = 1;
}
float columnWidth = (sectionWidth - style.ItemSpacing.x * columns) / columns;
bool useColumns = columns > 1;
if (!useColumns || (headerSearch && menuSearchText.length() > 0)) {
ImGui::SameLine();
ImGui::SetNextWindowSizeConstraints({ sectionWidth, 0 }, { sectionWidth, columnHeight });
ImGui::BeginChild(sectionMenuId.c_str(), { sectionWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY,
ImGuiWindowFlags_NoTitleBar);
}
if (headerSearch && menuSearchText.length() > 0) {
ImGui::BeginChild("Search Results");
int searchCount = 0;
for (auto& [menuLabel, menuSidebar, cvar] : menuEntries) {
for (auto& sidebar : menuSidebar) {
for (auto& widgets : sidebar.columnWidgets) {
int column = 1;
for (auto& info : widgets) {
if (info.widgetType == WIDGET_SEPARATOR || info.widgetType == WIDGET_SEPARATOR_TEXT ||
info.isHidden) {
continue;
}
std::string widgetStr = std::string(info.widgetName) + std::string(info.widgetTooltip);
std::transform(menuSearchText.begin(), menuSearchText.end(), menuSearchText.begin(), ::tolower);
std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower);
widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end());
if (widgetStr.find(menuSearchText) != std::string::npos) {
SearchMenuGetItem(info);
searchCount++;
ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::Colors::Gray);
std::string origin = fmt::format(" ({} -> {}, Clmn {})", menuLabel, sidebar.label, column);
ImGui::Text("%s", origin.c_str());
ImGui::PopStyleColor();
}
}
column++;
}
}
}
if (searchCount == 0) {
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("No results found").x) / 2);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "No results found");
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("Clear Search").x) / 2 - 10.0f);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
if (UIWidgets::Button("Clear Search", { .size = UIWidgets::Sizes::Inline })) {
menuSearch.Clear();
}
}
ImGui::EndChild();
} else {
for (int i = 0; i < columnFuncs; i++) {
std::string sectionId = fmt::format("{} Column {}", sectionMenuId, i);
if (useColumns) {
ImGui::SetNextWindowSizeConstraints({ columnWidth, 0 }, { columnWidth, columnHeight });
ImGui::BeginChild(sectionId.c_str(), { columnWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY,
ImGuiWindowFlags_NoTitleBar);
}
for (auto& entry : sidebar.at(sectionIndex).columnWidgets.at(i)) {
SearchMenuGetItem(entry);
}
if (useColumns) {
ImGui::EndChild();
}
if (i < columns - 1) {
ImGui::SameLine();
}
}
}
if (!useColumns || menuSearchText.length() > 0) {
ImGui::EndChild();
}
ImGui::PopFont();
ImGui::PopFont();
if (!popout) {
ImGui::PopStyleVar();
}
ImGui::EndChild();
if (popout) {
poppedSize = ImGui::GetWindowSize();
poppedPos = ImGui::GetWindowPos();
}
ImGui::End();
}
} // namespace BenGui
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <libultraship/libultraship.h>
#include "UIWidgets.hpp"
namespace BenGui {
class BenMenu : public Ship::GuiWindow {
public:
using Ship::GuiWindow::GuiWindow;
BenMenu(const std::string& consoleVariable, const std::string& name);
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
void Draw() override;
protected:
ImVec2 mOriginalSize;
std::string mName;
uint32_t mWindowFlags;
private:
bool allowPopout = true; // PortNote: should be set to false on small screen ports
bool popped;
ImVec2 poppedSize;
ImVec2 poppedPos;
float windowHeight;
float windowWidth;
};
} // namespace BenGui
+140
View File
@@ -0,0 +1,140 @@
#include "Notification.h"
#include <libultraship/libultraship.h>
extern "C" {
#include "functions.h"
#include "macros.h"
#include "variables.h"
}
namespace Notification {
static uint32_t nextId = 0;
static std::vector<Options> notifications = {};
void Window::Draw() {
auto vp = ImGui::GetMainViewport();
const float margin = 30.0f;
const float padding = 10.0f;
int position = CVarGetInteger("gNotifications.Position", 3);
// Top Left
ImVec2 basePosition;
switch (position) {
case 0: // Top Left
basePosition = ImVec2(vp->Pos.x + margin, vp->Pos.y + margin);
break;
case 1: // Top Right
basePosition = ImVec2(vp->Pos.x + vp->Size.x - margin, vp->Pos.y + margin);
break;
case 2: // Bottom Left
basePosition = ImVec2(vp->Pos.x + margin, vp->Pos.y + vp->Size.y - margin);
break;
case 3: // Bottom Right
basePosition = ImVec2(vp->Pos.x + vp->Size.x - margin, vp->Pos.y + vp->Size.y - margin);
break;
case 4: // Hidden
return;
}
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, CVarGetFloat("gNotifications.BgOpacity", 0.5f)));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f * CVarGetFloat("gNotifications.Size", 1.8f), 6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f * CVarGetFloat("gNotifications.Size", 1.8f), 8.0f));
for (int index = 0; index < notifications.size(); ++index) {
auto& notification = notifications[index];
int inverseIndex = -ABS(index - (notifications.size() - 1));
ImGui::SetNextWindowViewport(vp->ID);
if (notification.remainingTime < 4.0f) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, (notification.remainingTime - 1) / 3.0f);
} else {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.0f);
}
ImGui::Begin(("notification#" + std::to_string(notification.id)).c_str(), nullptr,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoScrollbar);
ImGui::SetWindowFontScale(CVarGetFloat("gNotifications.Size", 1.8f));
ImVec2 notificationPos;
switch (position) {
case 0: // Top Left
notificationPos =
ImVec2(basePosition.x, basePosition.y + ((ImGui::GetWindowSize().y + padding) * inverseIndex));
break;
case 1: // Top Right
notificationPos = ImVec2(basePosition.x - ImGui::GetWindowSize().x,
basePosition.y + ((ImGui::GetWindowSize().y + padding) * inverseIndex));
break;
case 2: // Bottom Left
notificationPos = ImVec2(basePosition.x,
basePosition.y - ((ImGui::GetWindowSize().y + padding) * (inverseIndex + 1)));
break;
case 3: // Bottom Right
notificationPos = ImVec2(basePosition.x - ImGui::GetWindowSize().x,
basePosition.y - ((ImGui::GetWindowSize().y + padding) * (inverseIndex + 1)));
break;
}
ImGui::SetWindowPos(notificationPos);
ImGui::AlignTextToFramePadding();
if (notification.itemIcon != nullptr) {
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(notification.itemIcon),
ImVec2(22 * CVarGetFloat("gNotifications.Size", 1.8f), 22 * CVarGetFloat("gNotifications.Size", 1.8f)));
ImGui::SameLine();
}
if (!notification.prefix.empty()) {
ImGui::TextColored(notification.prefixColor, "%s", notification.prefix.c_str());
ImGui::SameLine();
}
ImGui::TextColored(notification.messageColor, "%s", notification.message.c_str());
if (!notification.suffix.empty()) {
ImGui::SameLine();
ImGui::TextColored(notification.suffixColor, "%s", notification.suffix.c_str());
}
ImGui::End();
ImGui::PopStyleVar();
}
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(2);
}
void Window::UpdateElement() {
for (int index = 0; index < notifications.size(); ++index) {
auto& notification = notifications[index];
// decrement remainingTime
notification.remainingTime -= ImGui::GetIO().DeltaTime;
// remove notification if it has expired
if (notification.remainingTime <= 0) {
notifications.erase(notifications.begin() + index);
--index;
}
}
}
void Emit(Options notification) {
notification.id = nextId++;
if (notification.remainingTime == 0.0f) {
notification.remainingTime = CVarGetFloat("gNotifications.Duration", 10.0f);
}
notifications.push_back(notification);
AudioSfx_PlaySfx(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
}
} // namespace Notification
+37
View File
@@ -0,0 +1,37 @@
#ifndef NOTIFICATION_H
#define NOTIFICATION_H
#ifdef __cplusplus
#include <string>
#include <libultraship/libultraship.h>
namespace Notification {
struct Options {
uint32_t id = 0;
const char* itemIcon = nullptr;
std::string prefix = "";
ImVec4 prefixColor = ImVec4(0.5f, 0.5f, 1.0f, 1.0f);
std::string message = "";
ImVec4 messageColor = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
std::string suffix = "";
ImVec4 suffixColor = ImVec4(1.0f, 0.5f, 0.5f, 1.0f);
float remainingTime = 0.0f; // Seconds
};
class Window : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void InitElement() override{};
void DrawElement() override{};
void Draw() override;
void UpdateElement() override;
};
void Emit(Options notification);
} // namespace Notification
#endif // __cplusplus
#endif // NOTIFICATION_H
File diff suppressed because it is too large Load Diff

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