mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-22 15:02:54 -04:00
Merge branch 'main' of https://github.com/TwilitRealm/dusk into randomizer
This commit is contained in:
Vendored
+1
-1
Submodule extern/aurora updated: 4dd23c74d8...4d7ff2ac11
@@ -1376,6 +1376,7 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiSaveEditor.cpp
|
||||
src/dusk/imgui/ImGuiStateShare.hpp
|
||||
src/dusk/imgui/ImGuiStateShare.cpp
|
||||
src/dusk/iso_validate.cpp
|
||||
src/dusk/offset_ptr.cpp
|
||||
src/dusk/OSContext.cpp
|
||||
src/dusk/OSThread.cpp
|
||||
|
||||
@@ -363,6 +363,18 @@ int daMyna_c::destroy() {
|
||||
mpMorf->stopZelAnime();
|
||||
}
|
||||
|
||||
#ifdef TARGET_PC
|
||||
// !@bug d_a_myna.rel unload used to zero these file-statics; with static linking they dangle across scenes.
|
||||
daMyna_LightActor = NULL;
|
||||
daMyna_evtTagActor0 = NULL;
|
||||
daMyna_evtTagActor1 = NULL;
|
||||
daMyna_actor_count = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
daMyna_targetActor[i] = NULL;
|
||||
daMyna_subActor[i] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
l_HOSTIO.removeHIO();
|
||||
#endif
|
||||
|
||||
@@ -40,9 +40,15 @@ namespace dusk {
|
||||
|
||||
void ImGuiTextCenter(std::string_view text) {
|
||||
ImGui::NewLine();
|
||||
float fontSize = ImGui::CalcTextSize(text.data(), text.data() + text.size()).x;
|
||||
float fontSize = ImGui::CalcTextSize(
|
||||
text.data(),
|
||||
text.data() + text.size(),
|
||||
false,
|
||||
ImGui::GetWindowSize().x).x;
|
||||
ImGui::SameLine(ImGui::GetWindowSize().x / 2 - fontSize + fontSize / 2);
|
||||
ImGui::PushTextWrapPos(ImGui::GetWindowSize().x);
|
||||
ImGuiStringViewText(text);
|
||||
ImGui::PopTextWrapPos();
|
||||
}
|
||||
|
||||
bool ImGuiButtonCenter(std::string_view text) {
|
||||
|
||||
@@ -9,107 +9,117 @@ namespace dusk {
|
||||
|
||||
void ImGuiMenuEnhancements::draw() {
|
||||
if (ImGui::BeginMenu("Enhancements")) {
|
||||
if (ImGui::BeginMenu("Quality of Life")) {
|
||||
config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform);
|
||||
if (ImGui::BeginMenu("Gameplay")) {
|
||||
ImGui::SeparatorText("Preferences");
|
||||
|
||||
config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Allows you to quickly transform between forms\n"
|
||||
"without having to talk to Midna.");
|
||||
ImGui::SetTooltip("Mirrors the world horizontally, matching the Wii version of the game.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong);
|
||||
config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day.");
|
||||
ImGui::SetTooltip("Disables the main HUD of the game.\n"
|
||||
"Useful for recording or a more immersive experience!");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Difficulty");
|
||||
|
||||
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
|
||||
|
||||
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Any hit will instantly kill you.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hearts will never drop from enemies,\n"
|
||||
"pots and various other places.");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Quality of Life");
|
||||
|
||||
config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Wallet sizes are like in the HD version. (500, 1000, 2000)");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the delay when writing to the Memory Card.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Prevents Link from playing a struggle animation\n"
|
||||
"when grabbing ledges or climbing on vines.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears);
|
||||
config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
|
||||
ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Hide TV Settings Screen", getSettings().game.hideTvSettingsScreen);
|
||||
config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hides the TV calibration screen shown when loading a save.");
|
||||
ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Skip Warning Screen", getSettings().game.skipWarningScreen);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skips the warning screen shown when loading the game.");
|
||||
ImGui::SetTooltip("Skip the warning screen shown when starting the game.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves);
|
||||
config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the delay when writing to the Memory Card.");
|
||||
ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Preferences")) {
|
||||
config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode);
|
||||
config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Mirrors the world, matching the Wii version of the game.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
|
||||
|
||||
config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Disables the main HUD of the game.\n"
|
||||
"Useful for recording or a more immersive experience!");
|
||||
ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Improves the shadow resolution, making them higher quality.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Unlock Framerate", getSettings().game.enableFrameInterpolation);
|
||||
const bool frameInterpolationHovered = ImGui::IsItemHovered();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f));
|
||||
ImGui::TextUnformatted("[EXPERIMENTAL]");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (frameInterpolationHovered || ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, animation glitches, or instability may occur.");
|
||||
}
|
||||
|
||||
config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Improves the shadow resolution, making them higher quality.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -128,6 +138,10 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Input")) {
|
||||
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
|
||||
|
||||
ImGui::SeparatorText("Gyro");
|
||||
|
||||
config::ImGuiCheckbox("Gyro Aim", getSettings().game.enableGyroAim);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Enables the gyroscope on supported controllers while aiming the\n"
|
||||
@@ -139,9 +153,18 @@ namespace dusk {
|
||||
config::ImGuiCheckbox("Invert Gyro Pitch", getSettings().game.gyroAimInvertPitch);
|
||||
config::ImGuiCheckbox("Invert Gyro Yaw", getSettings().game.gyroAimInvertYaw);
|
||||
|
||||
ImGui::SeparatorText("Tools");
|
||||
|
||||
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::BeginMenu("Cheats")) {
|
||||
config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots);
|
||||
|
||||
@@ -163,23 +186,6 @@ namespace dusk {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Difficulty")) {
|
||||
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
|
||||
|
||||
config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hearts will never drop from enemies,\n"
|
||||
"pots and various other places.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Any hit will instantly kill you.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Technical")) {
|
||||
config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
@@ -190,15 +196,6 @@ namespace dusk {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Tools")) {
|
||||
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "../iso_validate.hpp"
|
||||
|
||||
#include <SDL3/SDL_dialog.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
@@ -26,15 +27,42 @@ static constexpr std::array<SDL_DialogFileFilter, 2> skGameDiscFileFilters{{
|
||||
{"All Files", "*"},
|
||||
}};
|
||||
|
||||
static std::string ShowIsoInvalidError(const iso::ValidationError code) {
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
switch (code) {
|
||||
case iso::ValidationError::IOError:
|
||||
return "Unknown IO error occurred"s;
|
||||
case iso::ValidationError::InvalidImage:
|
||||
return "Unable to interpret selected file as a disc image"s;
|
||||
case iso::ValidationError::WrongGame:
|
||||
return "Selected disc image is for a different game"s;
|
||||
case iso::ValidationError::WrongVersion:
|
||||
return "Selected disc image is for an unsupported version of the game. Only North American GameCube (NTSC/GZ2E01) is supported at this time."s;
|
||||
case iso::ValidationError::ExecutableMismatch:
|
||||
return "Selected disc image contains modified executable files."s;
|
||||
default:
|
||||
return "Unknown error"s;
|
||||
}
|
||||
}
|
||||
|
||||
void fileDialogCallback(void* userdata, const char* const* filelist, [[maybe_unused]] int filter) {
|
||||
auto* self = static_cast<ImGuiPreLaunchWindow*>(userdata);
|
||||
self->m_errorString.clear();
|
||||
if (filelist != nullptr) {
|
||||
if (filelist[0] == nullptr) {
|
||||
// Cancelled
|
||||
self->m_selectedIsoPath.clear();
|
||||
} else {
|
||||
self->m_selectedIsoPath = filelist[0];
|
||||
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
|
||||
const auto path = filelist[0];
|
||||
const auto ret = iso::validate(path);
|
||||
if (ret != iso::ValidationError::Success) {
|
||||
self->m_selectedIsoPath.clear();
|
||||
self->m_errorString = std::move(ShowIsoInvalidError(ret));
|
||||
return;
|
||||
}
|
||||
self->m_selectedIsoPath = path;
|
||||
getSettings().backend.isoPath.setValue(path);
|
||||
config::Save();
|
||||
}
|
||||
} else {
|
||||
@@ -111,6 +139,10 @@ void ImGuiPreLaunchWindow::drawMainMenu() {
|
||||
ImGui::PushFont(ImGuiEngine::fontLarge);
|
||||
|
||||
if (!isSelectedPathValid()) {
|
||||
if (!m_errorString.empty()) {
|
||||
ImGuiTextCenter(m_errorString);
|
||||
}
|
||||
|
||||
if (ImGuiButtonCenter("Select disc image...")) {
|
||||
SDL_ShowOpenFileDialog(&fileDialogCallback, this, aurora::window::get_sdl_window(),
|
||||
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()),
|
||||
@@ -148,6 +180,10 @@ void ImGuiPreLaunchWindow::drawOptions() {
|
||||
if (ImGui::BeginChild("OptionsChild", ImVec2(childWidth, endCursorY - cursorY),
|
||||
ImGuiChildFlags_None, ImGuiWindowFlags_NoBackground))
|
||||
{
|
||||
if (!m_errorString.empty()) {
|
||||
ImGuiTextCenter(m_errorString);
|
||||
}
|
||||
|
||||
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set")) {
|
||||
|
||||
@@ -445,7 +445,7 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Minigame")) {
|
||||
//DrawFlagsTab();
|
||||
drawMinigameTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
@@ -829,8 +829,8 @@ namespace dusk {
|
||||
|
||||
ImGuiBeginGroupPanel("Items", { 200, 100 });
|
||||
for (int slot = 0; slot < 24; slot++) {
|
||||
ImGui::Text("Slot %02d: ", slot);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Slot %02d (%s): ", slot, itemMap.find(getSlotDefault(slot))->second.m_name.c_str());
|
||||
ImGui::SameLine(240.0f);
|
||||
if (ImGui::BeginCombo(fmt::format("##ItemComboBox{}", slot).c_str(), itemMap.find(item.mItems[slot])->second.m_name.c_str())) {
|
||||
if (ImGui::Selectable("None")) {
|
||||
dComIfGs_setItem(slot, dItemNo_NONE_e);
|
||||
@@ -856,7 +856,27 @@ namespace dusk {
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
dSv_player_item_record_c& itemRecord = dComIfGs_getSaveData()->getPlayer().getItemRecord();
|
||||
dSv_player_item_max_c& itemMax = dComIfGs_getSaveData()->getPlayer().getItemMax();
|
||||
|
||||
ImGuiBeginGroupPanel("Item Max Capacities", { 200, 100 });
|
||||
ImGui::InputScalar("Arrows Max", ImGuiDataType_U8, &itemMax.mItemMax[0]);
|
||||
ImGui::InputScalar("Normal Bombs Max", ImGuiDataType_U8, &itemMax.mItemMax[1]);
|
||||
ImGui::InputScalar("Water Bombs Max", ImGuiDataType_U8, &itemMax.mItemMax[2]);
|
||||
ImGui::InputScalar("Bomblings Max", ImGuiDataType_U8, &itemMax.mItemMax[3]);
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImGuiBeginGroupPanel("Item Amounts", { 200, 100 });
|
||||
ImGui::InputScalar("Arrows Amount", ImGuiDataType_U8, &itemRecord.mArrowNum);
|
||||
ImGui::InputScalar("Slingshot Amount", ImGuiDataType_U8, &itemRecord.mPachinkoNum);
|
||||
ImGui::InputScalar("Bomb Bag 1 Amount", ImGuiDataType_U8, &itemRecord.mBombNum[0]);
|
||||
ImGui::InputScalar("Bomb Bag 2 Amount", ImGuiDataType_U8, &itemRecord.mBombNum[1]);
|
||||
ImGui::InputScalar("Bomb Bag 3 Amount", ImGuiDataType_U8, &itemRecord.mBombNum[2]);
|
||||
ImGui::InputScalar("Bottle 1 Amount", ImGuiDataType_U8, &itemRecord.mBottleNum[0]);
|
||||
ImGui::InputScalar("Bottle 2 Amount", ImGuiDataType_U8, &itemRecord.mBottleNum[1]);
|
||||
ImGui::InputScalar("Bottle 3 Amount", ImGuiDataType_U8, &itemRecord.mBottleNum[2]);
|
||||
ImGui::InputScalar("Bottle 4 Amount", ImGuiDataType_U8, &itemRecord.mBottleNum[3]);
|
||||
ImGuiEndGroupPanel();
|
||||
}
|
||||
|
||||
static inline void setItemFirstBit(u8 itemNo, bool owned) {
|
||||
@@ -902,27 +922,42 @@ namespace dusk {
|
||||
void ImGuiSaveEditor::drawCollectionTab() {
|
||||
if (ImGui::TreeNode("Equipment")) {
|
||||
if (ImGui::TreeNode("Swords")) {
|
||||
static u8 sword_list[] = {
|
||||
dItemNo_SWORD_e,
|
||||
dItemNo_MASTER_SWORD_e,
|
||||
dItemNo_WOOD_STICK_e,
|
||||
dItemNo_LIGHT_SWORD_e,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bool got = dComIfGs_isCollectSword((u8)i) != 0;
|
||||
bool got = dComIfGs_isItemFirstBit(sword_list[i]) != 0;
|
||||
if (ImGui::Checkbox(fmt::format("{0}##sword_{1}", sSwordNames[i], i).c_str(), &got)) {
|
||||
if (got) dComIfGs_setCollectSword((u8)i);
|
||||
else dComIfGs_offCollectSword((u8)i);
|
||||
if (got) dComIfGs_onItemFirstBit(sword_list[i]);
|
||||
else dComIfGs_offItemFirstBit(sword_list[i]);
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Shields")) {
|
||||
static u8 shield_list[] = {
|
||||
dItemNo_SHIELD_e,
|
||||
dItemNo_WOOD_SHIELD_e,
|
||||
dItemNo_HYLIA_SHIELD_e,
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
bool got = dComIfGs_isCollectShield((u8)i) != 0;
|
||||
bool got = dComIfGs_isItemFirstBit(shield_list[i]) != 0;
|
||||
if (ImGui::Checkbox(fmt::format("{0}##shield_{1}", sShieldNames[i], i).c_str(), &got)) {
|
||||
if (got) dComIfGs_setCollectShield((u8)i);
|
||||
else dComIfGs_offCollectShield((u8)i);
|
||||
if (got) dComIfGs_onItemFirstBit(shield_list[i]);
|
||||
else dComIfGs_offItemFirstBit(shield_list[i]);
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
// TODO: the game checks if you're in ranch clothes, and if so won't display any other tunics in the menu
|
||||
// find a way to deal with this later
|
||||
if (ImGui::TreeNode("Tunics")) {
|
||||
bool ordonClothes = dComIfGs_isItemFirstBit(dItemNo_WEAR_CASUAL_e) != 0;
|
||||
if (ImGui::Checkbox("Ordon Clothes##tunic_ordon", &ordonClothes)) {
|
||||
@@ -1235,7 +1270,7 @@ namespace dusk {
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImVec2 cursor = ImGui::GetCursorPos();
|
||||
ImVec2 start_cursor = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -1245,13 +1280,17 @@ namespace dusk {
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImGui::SetCursorPos(cursor);
|
||||
ImVec2 cursor = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPos(start_cursor);
|
||||
|
||||
ImGuiBeginGroupPanel("Item", { 100, 100 });
|
||||
for (int j = 0; j < 1; j++) {
|
||||
drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]);
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImGui::SetCursorPos({ start_cursor.x, cursor.y });
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawFlagsTab() {
|
||||
@@ -1328,7 +1367,7 @@ namespace dusk {
|
||||
dSv_event_c& event = dComIfGs_getSaveData()->mEvent;
|
||||
for (int e = 0; e < 255; e++) {
|
||||
ImGui::Text("%03d ", e);
|
||||
ImGui::SameLine();
|
||||
ImGui::SameLine(80.0f);
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
bool flag = event.mEvent[e] & (1 << i);
|
||||
if (ImGui::Checkbox(fmt::format("##event{0}{1}", e, i).c_str(), &flag)) {
|
||||
@@ -1345,10 +1384,25 @@ namespace dusk {
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawMinigameTab() {
|
||||
dSv_MiniGame_c& minigame = dComIfGs_getSaveData()->getMiniGame();
|
||||
InputScalarBE("STAR Game Time (Milliseconds)", ImGuiDataType_U32, &minigame.mHookGameTime);
|
||||
InputScalarBE("Snowboard Race Time (Milliseconds)", ImGuiDataType_U32, &minigame.mRaceGameTime);
|
||||
InputScalarBE("Fruit-Pop-Flight Score", ImGuiDataType_U32, &minigame.mBalloonScore);
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawConfigTab() {
|
||||
dSv_player_config_c& config = dComIfGs_getSaveData()->getPlayer().getConfig();
|
||||
ImGui::Checkbox("Enable Vibration", (bool*)&config.mVibration);
|
||||
if (ImGui::BeginCombo("Target Type", "Hold")) {
|
||||
|
||||
static const char* kTargetTypeNames[] = {"Hold", "Switch"};
|
||||
if (ImGui::BeginCombo("Target Type", kTargetTypeNames[config.mAttentionType])) {
|
||||
if (ImGui::Selectable("Hold")) {
|
||||
config.mAttentionType = 0;
|
||||
}
|
||||
if (ImGui::Selectable("Switch")) {
|
||||
config.mAttentionType = 1;
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace dusk {
|
||||
void drawInventoryTab();
|
||||
void drawCollectionTab();
|
||||
void drawFlagsTab();
|
||||
void drawMinigameTab();
|
||||
void drawConfigTab();
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "iso_validate.hpp"
|
||||
|
||||
#include <nod.h>
|
||||
#include <span>
|
||||
|
||||
#include "SDL3/SDL_iostream.h"
|
||||
|
||||
namespace dusk::iso {
|
||||
|
||||
constexpr const char* TP_GAME_IDS[] = {
|
||||
"GZ2E01", // GCN USA
|
||||
"GZ2P01", // GCN PAL
|
||||
"GZ2J01", // GCN JPN
|
||||
"RZDE01", // Wii USA
|
||||
"RZDP01", // Wii PAL
|
||||
"RZDJ01", // Wii JPN
|
||||
"RZDK01", // Wii KOR
|
||||
};
|
||||
|
||||
constexpr const char* SUPPORTED_TP_GAME_IDS[] = {
|
||||
"GZ2E01", // GCN USA
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
constexpr bool matches(const char (&id)[6], const char* const (&valid)[N]) {
|
||||
for (auto elem : valid) {
|
||||
if (strncmp(id, elem, 6) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct NodHandleWrapper {
|
||||
NodHandle* handle;
|
||||
|
||||
NodHandleWrapper() : handle(nullptr) {
|
||||
}
|
||||
|
||||
~NodHandleWrapper() {
|
||||
if (handle != nullptr) {
|
||||
nod_free(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ValidationError convertNodError(NodResult result) {
|
||||
switch (result) {
|
||||
case NOD_RESULT_ERR_IO:
|
||||
return ValidationError::IOError;
|
||||
case NOD_RESULT_ERR_FORMAT:
|
||||
return ValidationError::InvalidImage;
|
||||
default:
|
||||
return ValidationError::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
s64 StreamReadAt(void* user_data, u64 offset, void* out, size_t len) {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto io = static_cast<SDL_IOStream*>(user_data);
|
||||
|
||||
auto ret = SDL_SeekIO(io, static_cast<s64>(offset), SDL_IO_SEEK_SET);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto read = SDL_ReadIO(io, out, len);
|
||||
if (read == 0) {
|
||||
if (SDL_GetIOStatus(io) == SDL_IO_STATUS_EOF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<s64>(read);
|
||||
}
|
||||
|
||||
s64 StreamLength(void* user_data) {
|
||||
auto io = static_cast<SDL_IOStream*>(user_data);
|
||||
return SDL_GetIOSize(io);
|
||||
}
|
||||
|
||||
void StreamClose(void* user_data) {
|
||||
auto io = static_cast<SDL_IOStream*>(user_data);
|
||||
SDL_CloseIO(io);
|
||||
}
|
||||
|
||||
ValidationError validate(const char* path) {
|
||||
NodHandleWrapper disc;
|
||||
|
||||
const auto sdlStream = SDL_IOFromFile(path, "rb");
|
||||
const NodDiscStream nod_stream {
|
||||
.user_data = sdlStream,
|
||||
.read_at = StreamReadAt,
|
||||
.stream_len = StreamLength,
|
||||
.close = StreamClose,
|
||||
};
|
||||
|
||||
auto result = nod_disc_open_stream(&nod_stream, nullptr, &disc.handle);
|
||||
if (disc.handle == nullptr || result != NOD_RESULT_OK) {
|
||||
return convertNodError(result);
|
||||
}
|
||||
|
||||
NodDiscHeader header{};
|
||||
result = nod_disc_header(disc.handle, &header);
|
||||
if (result != NOD_RESULT_OK) {
|
||||
return convertNodError(result);
|
||||
}
|
||||
|
||||
if (!matches(header.game_id, TP_GAME_IDS)) {
|
||||
return ValidationError::WrongGame;
|
||||
}
|
||||
|
||||
if (!matches(header.game_id, SUPPORTED_TP_GAME_IDS)) {
|
||||
return ValidationError::WrongVersion;
|
||||
}
|
||||
|
||||
return ValidationError::Success;
|
||||
}
|
||||
} // namespace dusk::iso
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef DUSK_ISO_VALIDATE_HPP
|
||||
#define DUSK_ISO_VALIDATE_HPP
|
||||
|
||||
namespace dusk::iso {
|
||||
enum class ValidationError : u8 {
|
||||
Success = 0,
|
||||
IOError,
|
||||
InvalidImage,
|
||||
WrongGame,
|
||||
WrongVersion,
|
||||
ExecutableMismatch,
|
||||
Unknown
|
||||
};
|
||||
|
||||
ValidationError validate(const char* path);
|
||||
}
|
||||
|
||||
#endif // DUSK_ISO_VALIDATE_HPP
|
||||
@@ -2383,8 +2383,8 @@ void mDoExt_3DlineMat0_c::draw() {
|
||||
int var_r26 = (field_0x14 << 1) & 0xFFFF;
|
||||
|
||||
for (int i = 0; i < field_0x10; i++) {
|
||||
GXSETARRAY(GX_VA_POS, field_0x18->field_0x8[field_0x16], sizeof(cXyz) * var_r26, sizeof(cXyz), true);
|
||||
GXSETARRAY(GX_VA_NRM, field_0x18->field_0x10[field_0x16], 3 * var_r26, 3, true);
|
||||
GXSETARRAY(GX_VA_POS, var_r28->field_0x8[field_0x16], sizeof(cXyz) * var_r26, sizeof(cXyz), true);
|
||||
GXSETARRAY(GX_VA_NRM, var_r28->field_0x10[field_0x16], 3 * var_r26, 3, true);
|
||||
|
||||
GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, var_r26);
|
||||
for (u16 j = 0; j < (u16)var_r26; j++) {
|
||||
|
||||
Reference in New Issue
Block a user