diff --git a/CMakeLists.txt b/CMakeLists.txt index 6045ebc734..6956574919 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ message(STATUS "Dusk version set to ${DUSK_WC_DESCRIBE}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") project(dusk LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING}) if (APPLE) - enable_language(OBJC) + enable_language(OBJC OBJCXX) endif () if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS) # ios.toolchain.cmake hack for SDL @@ -102,12 +102,19 @@ set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE) set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) +target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1) add_subdirectory(libs/freeverb) option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)") option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.") option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON) +if (ANDROID) + set(DUSK_ENABLE_UPDATE_CHECKER_DEFAULT OFF) +else () + set(DUSK_ENABLE_UPDATE_CHECKER_DEFAULT ON) +endif () +option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ${DUSK_ENABLE_UPDATE_CHECKER_DEFAULT}) if(ANDROID) set(DUSK_MOVIE_SUPPORT OFF) @@ -283,9 +290,9 @@ set(DUSK_PRODUCT_NAME "Dusk") set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) -source_group("dusk" FILES ${DUSK_FILES}) +source_group("dusk" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES}) -set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0) +set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1) set(GAME_INCLUDE_DIRS include @@ -313,6 +320,37 @@ if (WIN32) list(APPEND GAME_LIBS Ws2_32) endif () +set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/no_backend.cpp) +if (DUSK_ENABLE_UPDATE_CHECKER) + list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_UPDATE_CHECKER=1) + if (WIN32) + set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/winhttp.cpp) + list(APPEND GAME_LIBS winhttp) + list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_WINHTTP=1) + message(STATUS "dusk: Enabled update checker (WinHTTP)") + elseif (APPLE) + find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED) + set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/url_session.mm) + set_source_files_properties(src/dusk/http/url_session.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + list(APPEND GAME_LIBS ${FOUNDATION_FRAMEWORK}) + list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_URLSESSION=1) + message(STATUS "dusk: Enabled update checker (NSURLSession)") + elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) + find_package(CURL QUIET OPTIONAL_COMPONENTS HTTPS SSL) + if (CURL_FOUND AND CURL_HTTPS_FOUND AND CURL_SSL_FOUND) + set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/curl.cpp) + list(APPEND GAME_LIBS CURL::libcurl) + list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_LIBCURL=1) + message(STATUS "dusk: Enabled update checker (libcurl)") + else () + message(STATUS "dusk: Disabled update checker (libcurl + HTTPS/SSL not found)") + endif () + else () + message(STATUS "dusk: Disabled update checker (unsupported platform)") + endif () +endif () +list(APPEND DUSK_FILES ${DUSK_HTTP_BACKEND_SOURCE}) + if (DUSK_MOVIE_SUPPORT) if (TARGET libjpeg-turbo::turbojpeg-static) list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static) diff --git a/README.md b/README.md index 02b1ded875..5e7412e6aa 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ First, make sure your dump of the game is clean and supported by Dusk. You can d - Extract the .zip file - Launch Dusk -- Press **Select Disc Image**, navigate to your game dump, and select the file -- Press **Start Game** to play! +- Press **Select Disc Image** and provide the path to your supported game dump. +- Press **Play**! # Building @@ -46,3 +46,10 @@ Pull requests are welcomed! Note that we do not accept contributions that are pr # Credits Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors). + +
+
+ + Powered by Aurora + +
diff --git a/assets/aurora-powered.png b/assets/aurora-powered.png new file mode 100644 index 0000000000..35ff017776 Binary files /dev/null and b/assets/aurora-powered.png differ diff --git a/assets/objdiff.png b/assets/objdiff.png deleted file mode 100644 index 94835fa1b3..0000000000 Binary files a/assets/objdiff.png and /dev/null differ diff --git a/assets/org-icon.svg b/assets/org-icon.svg new file mode 100644 index 0000000000..b1e82ead45 --- /dev/null +++ b/assets/org-icon.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/aurora b/extern/aurora index 518747aa86..17be93f0ae 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 518747aa86a50be62ecf92aeb309309b0d58a54a +Subproject commit 17be93f0ae011fc3202e87e3f2efda4aae250fa5 diff --git a/files.cmake b/files.cmake index a463ce5129..53aa7a2636 100644 --- a/files.cmake +++ b/files.cmake @@ -1430,11 +1430,14 @@ set(DUSK_FILES src/dusk/gyro.cpp src/dusk/gamepad_color.cpp src/dusk/autosave.cpp + src/dusk/http/http.hpp src/dusk/io.cpp src/dusk/layout.cpp src/dusk/logging.cpp src/dusk/settings.cpp src/dusk/stubs.cpp + src/dusk/update_check.cpp + src/dusk/update_check.hpp #src/dusk/m_Do_ext_dusk.cpp src/dusk/imgui/ImGuiConfig.hpp src/dusk/imgui/ImGuiConsole.hpp @@ -1447,18 +1450,17 @@ set(DUSK_FILES src/dusk/imgui/ImGuiBloomWindow.hpp src/dusk/imgui/ImGuiMenuTools.cpp src/dusk/imgui/ImGuiMenuTools.hpp - src/dusk/imgui/ImGuiPreLaunchWindow.cpp - src/dusk/imgui/ImGuiPreLaunchWindow.hpp src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp - src/dusk/imgui/ImGuiDebugPad.cpp src/dusk/imgui/ImGuiControllerOverlay.cpp src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiMapLoader.cpp src/dusk/imgui/ImGuiSaveEditor.cpp src/dusk/imgui/ImGuiStateShare.hpp src/dusk/imgui/ImGuiStateShare.cpp + src/dusk/ui/achievements.cpp + src/dusk/ui/achievements.hpp src/dusk/ui/bool_button.cpp src/dusk/ui/bool_button.hpp src/dusk/ui/button.cpp @@ -1469,16 +1471,16 @@ set(DUSK_FILES src/dusk/ui/controller_config.hpp src/dusk/ui/document.cpp src/dusk/ui/document.hpp - src/dusk/ui/achievements.cpp - src/dusk/ui/achievements.hpp - src/dusk/ui/preset.cpp - src/dusk/ui/preset.hpp src/dusk/ui/editor.cpp src/dusk/ui/editor.hpp src/dusk/ui/event.cpp src/dusk/ui/event.hpp + src/dusk/ui/graphics_tuner.cpp + src/dusk/ui/graphics_tuner.hpp src/dusk/ui/input.cpp src/dusk/ui/input.hpp + src/dusk/ui/modal.cpp + src/dusk/ui/modal.hpp src/dusk/ui/nav_types.hpp src/dusk/ui/number_button.cpp src/dusk/ui/number_button.hpp @@ -1486,12 +1488,12 @@ set(DUSK_FILES src/dusk/ui/overlay.hpp src/dusk/ui/pane.cpp src/dusk/ui/pane.hpp - src/dusk/ui/popup.cpp - src/dusk/ui/popup.hpp + src/dusk/ui/menu_bar.cpp + src/dusk/ui/menu_bar.hpp src/dusk/ui/prelaunch.cpp src/dusk/ui/prelaunch.hpp - src/dusk/ui/prelaunch_options.cpp - src/dusk/ui/prelaunch_options.hpp + src/dusk/ui/preset.cpp + src/dusk/ui/preset.hpp src/dusk/ui/select_button.cpp src/dusk/ui/select_button.hpp src/dusk/ui/settings.cpp @@ -1517,3 +1519,10 @@ set(DUSK_FILES src/dusk/discord_presence.cpp src/dusk/version.cpp ) + +set(DUSK_HTTP_BACKEND_FILES + src/dusk/http/no_backend.cpp + src/dusk/http/curl.cpp + src/dusk/http/winhttp.cpp + src/dusk/http/url_session.mm +) diff --git a/include/d/d_menu_fmap2D.h b/include/d/d_menu_fmap2D.h index d0152f0229..7df78bb6d0 100644 --- a/include/d/d_menu_fmap2D.h +++ b/include/d/d_menu_fmap2D.h @@ -169,6 +169,12 @@ public: void mapBlink() {} + #if PLATFORM_WII || TARGET_PC + f32 getMirrorPosX(f32 param_0, f32 param_1) { + return (field_0x11dc * 2.0f - (param_0 + param_1)) - param_1; + } + #endif + // Unknown name struct RegionTexData { /* 0x00 */ float mMinX; diff --git a/include/d/d_menu_map_common.h b/include/d/d_menu_map_common.h index 989aee7d8b..de50d775ca 100644 --- a/include/d/d_menu_map_common.h +++ b/include/d/d_menu_map_common.h @@ -66,6 +66,16 @@ public: _c90 = param_2; } +#if PLATFORM_WII || TARGET_PC + f32 getMirrorCenterPosX(f32 param_0, f32 param_1) { + if (_c90) { + return (mCenterPosX * 2.0f - (param_0 + param_1)) - param_1; + } + + return param_0; + } +#endif + struct Stage_c { // Incomplete class diff --git a/include/dusk/achievements.h b/include/dusk/achievements.h index ca4676ab2d..bf0021c9d7 100644 --- a/include/dusk/achievements.h +++ b/include/dusk/achievements.h @@ -50,8 +50,6 @@ public: bool hasSignal(const char* key) const; std::vector getAchievements() const; - bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); } - std::string consumePendingUnlock(); private: struct Entry { @@ -68,7 +66,6 @@ private: std::unordered_set m_signals; bool m_loaded = false; bool m_dirty = false; - std::queue m_pendingUnlocks; }; } // namespace dusk diff --git a/include/dusk/main.h b/include/dusk/main.h index 065f507d36..d6b9c9927f 100644 --- a/include/dusk/main.h +++ b/include/dusk/main.h @@ -1,6 +1,10 @@ #ifndef DUSK_MAIN_H #define DUSK_MAIN_H +#if defined(__APPLE__) +#include +#endif + #include namespace dusk { @@ -8,7 +12,17 @@ namespace dusk { extern bool IsShuttingDown; extern bool IsGameLaunched; extern bool IsFocusPaused; + extern bool RestartRequested; extern std::filesystem::path ConfigPath; + +#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \ + (defined(TARGET_OS_TV) && TARGET_OS_TV) + inline constexpr bool SupportsProcessRestart = false; +#else + inline constexpr bool SupportsProcessRestart = true; +#endif + + void RequestRestart() noexcept; } #endif // DUSK_MAIN_H diff --git a/include/dusk/map_loader_definitions.h b/include/dusk/map_loader_definitions.h index a0f7150d2d..0ffda772ba 100644 --- a/include/dusk/map_loader_definitions.h +++ b/include/dusk/map_loader_definitions.h @@ -1,5 +1,7 @@ #pragma once +#include + struct RoomEntry { u8 roomNo; std::vector roomPoints = {}; diff --git a/include/dusk/math.h b/include/dusk/math.h index fe27b3046b..04f1087670 100644 --- a/include/dusk/math.h +++ b/include/dusk/math.h @@ -2,9 +2,6 @@ #define _SRC_DUSK_MATH_H_ #include -#include -#include -#include #ifndef M_PI #define M_PI 3.14159265358979323846f @@ -19,139 +16,6 @@ inline float i_cosf(float x) { return cos(x); } inline float i_tanf(float x) { return tan(x); } inline float i_acosf(float x) { return acos(x); } - -// frsqrte matching courtesy of Geotale, with reference to https://achurch.org/cpu-tests/ppc750cl.s - -struct BaseAndDec32 { - uint32_t base; - int32_t dec; -}; - -struct BaseAndDec64 { - uint64_t base; - int64_t dec; -}; - -union c32 { - constexpr c32(const float p) { - f = p; - } - - constexpr c32(const uint32_t p) { - u = p; - } - - uint32_t u; - float f; -}; - -union c64 { - constexpr c64(const double p) { - f = p; - } - - constexpr c64(const uint64_t p) { - u = p; - } - - uint64_t u; - double f; -}; - -static constexpr uint64_t EXPONENT_SHIFT_F64 = 52; -static constexpr uint64_t MANTISSA_MASK_F64 = 0x000fffffffffffffULL; -static constexpr uint64_t EXPONENT_MASK_F64 = 0x7ff0000000000000ULL; -static constexpr uint64_t SIGN_MASK_F64 = 0x8000000000000000ULL; - -static constexpr std::array RSQRTE_TABLE = {{ - {0x69fa000000000ULL, -0x15a0000000LL}, - {0x5f2e000000000ULL, -0x13cc000000LL}, - {0x554a000000000ULL, -0x1234000000LL}, - {0x4c30000000000ULL, -0x10d4000000LL}, - {0x43c8000000000ULL, -0x0f9c000000LL}, - {0x3bfc000000000ULL, -0x0e88000000LL}, - {0x34b8000000000ULL, -0x0d94000000LL}, - {0x2df0000000000ULL, -0x0cb8000000LL}, - {0x2794000000000ULL, -0x0bf0000000LL}, - {0x219c000000000ULL, -0x0b40000000LL}, - {0x1bfc000000000ULL, -0x0aa0000000LL}, - {0x16ae000000000ULL, -0x0a0c000000LL}, - {0x11a8000000000ULL, -0x0984000000LL}, - {0x0ce6000000000ULL, -0x090c000000LL}, - {0x0862000000000ULL, -0x0898000000LL}, - {0x0416000000000ULL, -0x082c000000LL}, - {0xffe8000000000ULL, -0x1e90000000LL}, - {0xf0a4000000000ULL, -0x1c00000000LL}, - {0xe2a8000000000ULL, -0x19c0000000LL}, - {0xd5c8000000000ULL, -0x17c8000000LL}, - {0xc9e4000000000ULL, -0x1610000000LL}, - {0xbedc000000000ULL, -0x1490000000LL}, - {0xb498000000000ULL, -0x1330000000LL}, - {0xab00000000000ULL, -0x11f8000000LL}, - {0xa204000000000ULL, -0x10e8000000LL}, - {0x9994000000000ULL, -0x0fe8000000LL}, - {0x91a0000000000ULL, -0x0f08000000LL}, - {0x8a1c000000000ULL, -0x0e38000000LL}, - {0x8304000000000ULL, -0x0d78000000LL}, - {0x7c48000000000ULL, -0x0cc8000000LL}, - {0x75e4000000000ULL, -0x0c28000000LL}, - {0x6fd0000000000ULL, -0x0b98000000LL}, -}}; - -[[nodiscard]] static inline double frsqrte(const double val) { - c64 bits(val); - - uint64_t mantissa = bits.u & MANTISSA_MASK_F64; - int64_t exponent = bits.u & EXPONENT_MASK_F64; - bool sign = (bits.u & SIGN_MASK_F64) != 0; - - // Handle 0 case - if (mantissa == 0 && exponent == 0) { - return std::copysign(std::numeric_limits::infinity(), bits.f); - } - - // Handle NaN-like - if (exponent == EXPONENT_MASK_F64) { - if (mantissa == 0) { - return sign ? std::numeric_limits::quiet_NaN() : 0.0; - } - - return val; - } - - // Handle negative inputs - if (sign) { - return std::numeric_limits::quiet_NaN(); - } - - if (exponent == 0) { - // Shift so one bit goes to where the exponent would be, - // then clear that bit to mimic a not-subnormal number! - // Aka, if there are 12 leading zeroes, shift left once - uint32_t shift = std::countl_zero(mantissa) - static_cast(63 - EXPONENT_SHIFT_F64); - - mantissa <<= shift; - mantissa &= MANTISSA_MASK_F64; - // The shift is subtracted by 1 because denormals by default - // are offset by 1 (exponent 0 doesn't have implied 1 bit) - exponent -= static_cast(shift - 1) << EXPONENT_SHIFT_F64; - } - - // In reality this doesn't get the full exponent -- Only the least significant bit - // Only that's needed because square roots of higher exponent bits simply multiply the - // result by 2!! - uint32_t key = static_cast((static_cast(exponent) | mantissa) >> 37); - uint64_t new_exp = - (static_cast((0xbfcLL << EXPONENT_SHIFT_F64) - exponent) >> 1) & EXPONENT_MASK_F64; - - // Remove the bits relating to anything higher than the LSB of the exponent - const auto &entry = RSQRTE_TABLE[0x1f & (key >> 11)]; - - // The result is given by an estimate then an adjustment based on the original - // key that was computed - uint64_t new_mantissa = static_cast(entry.base + entry.dec * static_cast(key & 0x7ff)); - - return c64(new_exp | new_mantissa).f; -} +#include #endif // _SRC_DUSK_MATH_H_ diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 7f7aa8cd69..78c5540e58 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -21,6 +21,12 @@ enum class GameLanguage : u8 { Italian = OS_LANGUAGE_ITALIAN, }; +enum class DiscVerificationState : u8 { + Unknown = 0, + Success, + HashMismatch, +}; + namespace config { template <> struct ConfigEnumRange { @@ -33,6 +39,12 @@ struct ConfigEnumRange { static constexpr auto min = GameLanguage::English; static constexpr auto max = GameLanguage::Italian; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = DiscVerificationState::Unknown; + static constexpr auto max = DiscVerificationState::HashMismatch; +}; } // Persistent user settings @@ -45,6 +57,8 @@ struct UserSettings { ConfigVar enableFullscreen; ConfigVar enableVsync; ConfigVar lockAspectRatio; + ConfigVar enableFpsOverlay; + ConfigVar fpsOverlayCorner; } video; struct { @@ -67,7 +81,6 @@ struct UserSettings { // QoL ConfigVar enableQuickTransform; ConfigVar hideTvSettingsScreen; - ConfigVar skipWarningScreen; ConfigVar biggerWallets; ConfigVar noReturnRupees; ConfigVar disableRupeeCutscenes; @@ -86,7 +99,7 @@ struct UserSettings { // Preferences ConfigVar enableMirrorMode; - ConfigVar disableMainHUD; + ConfigVar minimalHUD; ConfigVar pauseOnFocusLost; ConfigVar enableLinkDollRotation; ConfigVar enableAchievementNotifications; @@ -121,6 +134,7 @@ struct UserSettings { ConfigVar invertCameraYAxis; ConfigVar freeCameraSensitivity; ConfigVar debugFlyCam; + ConfigVar debugFlyCamLockEvents; // Cheats ConfigVar infiniteHearts; @@ -147,16 +161,20 @@ struct UserSettings { // Tools ConfigVar speedrunMode; ConfigVar liveSplitEnabled; + ConfigVar recordingMode; } game; struct { ConfigVar isoPath; + ConfigVar isoVerification; ConfigVar graphicsBackend; ConfigVar skipPreLaunchUI; ConfigVar showPipelineCompilation; ConfigVar wasPresetChosen; ConfigVar enableCrashReporting; + ConfigVar checkForUpdates; ConfigVar cardFileType; + ConfigVar enableAdvancedSettings; } backend; }; diff --git a/libs/JSystem/include/JSystem/J3DGraphBase/J3DStruct.h b/libs/JSystem/include/JSystem/J3DGraphBase/J3DStruct.h index b565ad78f8..05663fd84e 100644 --- a/libs/JSystem/include/JSystem/J3DGraphBase/J3DStruct.h +++ b/libs/JSystem/include/JSystem/J3DGraphBase/J3DStruct.h @@ -1,9 +1,9 @@ #ifndef J3DSTRUCT_H #define J3DSTRUCT_H +#include #include #include -#include #include "global.h" #include "JSystem/JMath/JMath.h" @@ -11,7 +11,7 @@ /** * @ingroup jsystem-j3d - * + * */ struct J3DLightInfo { bool operator==(J3DLightInfo& other) const; @@ -28,7 +28,7 @@ struct J3DLightInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTextureSRTInfo { // NOTE: Big endian when loaded from file! @@ -79,7 +79,7 @@ enum J3DTexMtxMode { /** * @ingroup jsystem-j3d - * + * */ struct J3DTexMtxInfo { bool operator==(J3DTexMtxInfo& other) const; @@ -97,7 +97,7 @@ struct J3DTexMtxInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DIndTexMtxInfo { J3DIndTexMtxInfo& operator=(J3DIndTexMtxInfo const&); @@ -107,7 +107,7 @@ struct J3DIndTexMtxInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DFogInfo { bool operator==(J3DFogInfo&) const; @@ -126,7 +126,7 @@ struct J3DFogInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DNBTScaleInfo { bool operator==(const J3DNBTScaleInfo& other) const; @@ -153,7 +153,7 @@ struct J3DIndTexOrderInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTevSwapModeInfo { /* 0x0 */ u8 mRasSel; @@ -164,7 +164,7 @@ struct J3DTevSwapModeInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTevSwapModeTableInfo { /* 0x0 */ u8 field_0x0; @@ -175,7 +175,7 @@ struct J3DTevSwapModeTableInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTevStageInfo { /* 0x0 */ u8 field_0x0; @@ -202,7 +202,7 @@ struct J3DTevStageInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DIndTevStageInfo { /* 0x0 */ u8 mIndStage; @@ -219,7 +219,7 @@ struct J3DIndTevStageInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTexCoordInfo { /* 0x0 */ u8 mTexGenType; @@ -265,7 +265,7 @@ struct J3DBlendInfo { /** * @ingroup jsystem-j3d - * + * */ struct J3DTevOrderInfo { void operator=(const J3DTevOrderInfo& other) { diff --git a/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp b/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp index 32f0e4eed9..c3c72310a0 100644 --- a/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp +++ b/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp @@ -556,8 +556,8 @@ void J3DModelLoader::readVertexData(const J3DVertexBlock& block, J3DVertexData& if (attr == GX_VA_POS) { // can be a little off due to 0x20 alignment, account for that - u32 expect = ((data.mVtxNum * vertStride) + 0x1F) & ~0x1F; - JUT_ASSERT(1234, expect == addrDiff); + // u32 expect = ((data.mVtxNum * vertStride) + 0x1F) & ~0x1F; + // JUT_ASSERT(1234, expect == addrDiff); } else if (attr == GX_VA_NRM) { data.mNrmNum = num; } else if (attr == GX_VA_CLR0) { diff --git a/platforms/freedesktop/1024x1024/apps/dusk.png b/platforms/freedesktop/1024x1024/apps/dusk.png index 862cbed0d8..33eceb7c37 100644 Binary files a/platforms/freedesktop/1024x1024/apps/dusk.png and b/platforms/freedesktop/1024x1024/apps/dusk.png differ diff --git a/platforms/freedesktop/128x128/apps/dusk.png b/platforms/freedesktop/128x128/apps/dusk.png index aaf38689d2..7d73dff804 100644 Binary files a/platforms/freedesktop/128x128/apps/dusk.png and b/platforms/freedesktop/128x128/apps/dusk.png differ diff --git a/platforms/freedesktop/16x16/apps/dusk.png b/platforms/freedesktop/16x16/apps/dusk.png index 21b653c63d..3680f3bf6a 100644 Binary files a/platforms/freedesktop/16x16/apps/dusk.png and b/platforms/freedesktop/16x16/apps/dusk.png differ diff --git a/platforms/freedesktop/256x256/apps/dusk.png b/platforms/freedesktop/256x256/apps/dusk.png index 1f4677878a..4fa9995913 100644 Binary files a/platforms/freedesktop/256x256/apps/dusk.png and b/platforms/freedesktop/256x256/apps/dusk.png differ diff --git a/platforms/freedesktop/32x32/apps/dusk.png b/platforms/freedesktop/32x32/apps/dusk.png index b879a01602..3d966b7cbf 100644 Binary files a/platforms/freedesktop/32x32/apps/dusk.png and b/platforms/freedesktop/32x32/apps/dusk.png differ diff --git a/platforms/freedesktop/48x48/apps/dusk.png b/platforms/freedesktop/48x48/apps/dusk.png index 4f3744ab89..e12bca0df9 100644 Binary files a/platforms/freedesktop/48x48/apps/dusk.png and b/platforms/freedesktop/48x48/apps/dusk.png differ diff --git a/platforms/freedesktop/512x512/apps/dusk.png b/platforms/freedesktop/512x512/apps/dusk.png index 6334f80e81..53afadf4a5 100644 Binary files a/platforms/freedesktop/512x512/apps/dusk.png and b/platforms/freedesktop/512x512/apps/dusk.png differ diff --git a/platforms/freedesktop/64x64/apps/dusk.png b/platforms/freedesktop/64x64/apps/dusk.png index 067a83da90..c0dd5502a5 100644 Binary files a/platforms/freedesktop/64x64/apps/dusk.png and b/platforms/freedesktop/64x64/apps/dusk.png differ diff --git a/platforms/freedesktop/dusk.desktop b/platforms/freedesktop/dusk.desktop index 2e19d7ea26..b052eac6ef 100644 --- a/platforms/freedesktop/dusk.desktop +++ b/platforms/freedesktop/dusk.desktop @@ -6,4 +6,4 @@ Exec=dusk Icon=dusk Terminal=false Type=Application -Categories=Graphics;3DGraphics;Game +Categories=Game; diff --git a/res/org-icon-center.png b/res/org-icon-center.png new file mode 100644 index 0000000000..b3ec7e1f6b Binary files /dev/null and b/res/org-icon-center.png differ diff --git a/res/org-icon-inner.png b/res/org-icon-inner.png new file mode 100644 index 0000000000..4b3c864c74 Binary files /dev/null and b/res/org-icon-inner.png differ diff --git a/res/org-icon-outer.png b/res/org-icon-outer.png new file mode 100644 index 0000000000..6cbcf084d2 Binary files /dev/null and b/res/org-icon-outer.png differ diff --git a/res/org-icon.png b/res/org-icon.png index b7a0614b9b..288dc8768f 100644 Binary files a/res/org-icon.png and b/res/org-icon.png differ diff --git a/res/rml/overlay.rcss b/res/rml/overlay.rcss index e18bb436e5..05c8440b55 100644 --- a/res/rml/overlay.rcss +++ b/res/rml/overlay.rcss @@ -8,140 +8,269 @@ body { height: 100%; margin: 0; padding: 0; - font-family: "Fira Sans Condensed"; - font-size: 24dp; - color: #FFFFFF; - display: flex; - flex-direction: column; - justify-content: flex-end; - align-items: stretch; -} - -.overlay-root { - width: 100%; - min-height: 45%; - display: flex; - flex-direction: column; - justify-content: flex-end; - align-items: stretch; - decorator: vertical-gradient(#00000000 #151610F2); - filter: opacity(0); - transition: filter 0.2s linear-in-out; -} - -.overlay-root[open] { - filter: opacity(1); -} - -.overlay { - width: 100%; - max-width: 1216dp; - margin-left: auto; - margin-right: auto; - display: flex; - flex-direction: column; - gap: 24dp; - padding: 48dp 64dp; -} - -@media (max-height: 800dp) { - .overlay-root { - min-height: 38%; - } - - .overlay { - gap: 16dp; - padding: 32dp 48dp; - } -} - -.header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 24dp; -} - -.carousel-container { - flex: 1 1 auto; - display: flex; - justify-content: flex-end; - min-width: 0; -} - -.description { - font-size: 18dp; - line-height: 22dp; - color: rgba(255, 255, 255, 50%); -} - -.divider { - margin: 1dp 0; - border-top: 1dp rgba(217, 217, 217, 50%); -} - -.footer { - display: flex; - justify-content: space-between; - align-items: center; - gap: 24dp; -} - -footer-button { - display: block; - width: 100%; - max-width: 220dp; - border: 0; - padding: 0; - background-color: transparent; - font-family: "Fira Sans Condensed"; - font-weight: bold; + font-family: "Fira Sans"; + font-weight: normal; font-size: 20dp; - line-height: 24dp; - text-transform: uppercase; - color: #FFFFFF; - opacity: 1; + color: #E0DBC8; + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: stretch; + z-index: 1; + pointer-events: none; +} + +fps, +toast { + position: absolute; + border: 1dp #92875B; + background-color: rgba(21, 22, 16, 80%); +} + +toast { + top: 40dp; + right: 40dp; + display: flex; + flex-flow: column; + border-radius: 14dp; + overflow: hidden; + backdrop-filter: blur(5dp); + box-shadow: 0 0 15dp 3dp; + filter: opacity(0); + transform: scale(0.9); + transform-origin: center; + transition: filter transform 0.2s cubic-in-out; + padding: 18dp 24dp; + gap: 8dp; +} + +toast[open] { + filter: opacity(1); + transform: scale(1); +} + +/*toast:hover { cursor: pointer; + background-color: rgba(61, 59, 36, 80%); } -footer-button.return { - text-align: left; +toast:active { + background-color: rgba(45, 43, 26, 80%); +}*/ + +toast heading { + display: flex; + gap: 18dp; + align-items: center; + font-family: "Fira Sans Condensed"; + font-size: 18dp; + font-weight: bold; + text-transform: uppercase; + color: #92875B; } -footer-button.reset { - text-align: right; +toast heading > span { + flex: 1 0 auto; } -.stepped-carousel { +toast heading > row { + flex: 1 0 auto; display: flex; align-items: center; - justify-content: center; - gap: 16dp; - width: auto; - min-width: 246dp; - padding: 0; - background-color: transparent; - font-family: "Fira Sans Condensed"; - font-weight: bold; + gap: 4dp; } -.stepped-carousel-value { - line-height: 29dp; - min-width: 166dp; +toast message { + display: flex; + flex-flow: column; + gap: 8dp; +} + +toast message row { + display: flex; +} + +toast message row.muted { + opacity: 0.5; +} + +toast progress { + height: 4dp; + position: absolute; + left: 0; + bottom: 0; + width: 100%; +} + +toast progress fill { + background-color: rgba(194, 164, 45, 80%); +} + +toast.achievement { + border: 1dp #C2A42D; +} + +toast.achievement heading { + color: #C2A42D; +} + +toast.controller-warning { + top: auto; + right: auto; + bottom: 40dp; + left: 50%; + width: 440dp; + max-width: 90%; + transform: translateX(-50%) scale(0.9); +} + +toast.controller-warning[open] { + transform: translateX(-50%) scale(1); +} + +toast.controller-warning heading { + color: #C2A42D; +} + +toast.menu-notification { + top: 40dp; + right: auto; + bottom: auto; + left: 50%; + max-width: 90%; + transform: translateX(-50%) scale(0.9); +} + +toast.menu-notification[open] { + transform: translateX(-50%) scale(1); +} + +toast.menu-notification message { + align-items: center; text-align: center; - white-space: nowrap; - opacity: 0.9; } -.stepped-carousel-arrow { - width: 24dp; - height: 24dp; - min-width: 24dp; - padding: 0; - border: 0; - background-color: transparent; - opacity: 1; - cursor: pointer; +toast.menu-notification message row { + align-items: center; + gap: 6dp; +} + +icon { font-family: "Material Symbols Rounded"; font-weight: normal; + display: inline-block; + vertical-align: middle; +} + +icon.arrow-forward { + width: 24dp; + height: 24dp; + font-size: 24dp; + decorator: text("" center center); +} + +icon.trophy { + width: 24dp; + height: 24dp; + font-size: 24dp; + decorator: text("" center center); +} + +icon.controller { + width: 24dp; + height: 24dp; + font-size: 24dp; + decorator: text("" center center); +} + +icon.warning { + width: 24dp; + height: 24dp; + font-size: 24dp; + decorator: text("" center center); +} + +fps { + display: none; + z-index: 99; + font-size: 18dp; + font-weight: bold; + padding: 9dp 12dp; + border-radius: 7dp; + pointer-events: none; + white-space: nowrap; +} + +fps[open] { + display: block; +} + +fps[corner=tl] { + top: 12dp; + left: 12dp; +} + +fps[corner=tr] { + top: 12dp; + right: 12dp; +} + +fps[corner=bl] { + bottom: 12dp; + left: 12dp; +} + +fps[corner=br] { + bottom: 12dp; + right: 12dp; +} + +logo { + position: absolute; + width: 100dp; + height: 100dp; + bottom: 40dp; + left: 40dp; + opacity: 0; + transition: opacity 0.5s linear-in-out; +} + +logo[open] { + opacity: 0.65; +} + +logo img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + filter: drop-shadow(#0008 0 0 14dp); + transform-origin: center; +} + +logo img.inner { + animation: 24s linear-in-out infinite logo-inner-spin; +} + +logo img.outer { + animation: 8s linear-in-out infinite logo-outer-spin; +} + +@keyframes logo-inner-spin { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +} + +@keyframes logo-outer-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } diff --git a/res/rml/prelaunch.rcss b/res/rml/prelaunch.rcss index 9556e74ef2..9b83db4660 100644 --- a/res/rml/prelaunch.rcss +++ b/res/rml/prelaunch.rcss @@ -9,17 +9,44 @@ body { font-weight: normal; font-size: 20dp; color: #FFFFFF; - background-color: #000000; - decorator: image(../prelaunch-bg.png cover left center); filter: opacity(0); transition: filter 1s 0.2s linear-in-out; z-index: -1; } +.gradient { + position: absolute; + width: 100%; + height: 100%; + /* The color gradient from the Figma bands really badly. A fully black gradient does as well, but not as badly. */ + decorator: horizontal-gradient(#000000FF #00000000); +} + +body.mirrored .gradient { + decorator: horizontal-gradient(#00000000 #000000FF); +} + +.background { + position: absolute; + width: 100%; + height: 100%; + decorator: image(../prelaunch-bg.png cover left center); + opacity: 0; + transition: opacity 1s linear-in-out; +} + body[open] { filter: opacity(1); } +body[open] .background { + opacity: 1; +} + +body.disc-ready .background { + opacity: 0; +} + content { display: block; width: 100%; @@ -35,6 +62,7 @@ content[open] { menu { position: absolute; left: 96dp; + right: auto; top: 50%; transform: translateY(-50%); /* Scale based on a reference screen width, 428/1216 */ @@ -47,6 +75,11 @@ menu { gap: 48dp; } +body.mirrored menu { + left: auto; + right: 96dp; +} + hero { display: flex; flex-direction: column; @@ -55,6 +88,10 @@ hero { gap: 8dp; } +body.mirrored hero { + align-items: flex-end; +} + hero img { width: 100%; } @@ -79,6 +116,7 @@ hero img { display: flex; flex-direction: column; gap: 12dp; + align-items: flex-start; } #menu-list button { @@ -86,6 +124,7 @@ hero img { height: 54dp; padding: 8dp 16dp; border-radius: 8dp; + text-align: left; text-transform: uppercase; font-family: "Fira Sans Condensed"; font-size: 32dp; @@ -95,8 +134,14 @@ hero img { decorator: horizontal-gradient(#00000000 #00000000); } +#menu-list button:disabled { + opacity: 0.75; + cursor: default; + decorator: horizontal-gradient(#00000000 #00000000); +} + #menu-list button.anim-done { - transition: decorator color 0.1s linear-in-out; + transition: decorator color opacity 0.1s linear-in-out; } #menu-list button:hover, @@ -105,25 +150,56 @@ hero img { decorator: horizontal-gradient(#FEE685FF #FEE68500); } +body.mirrored #menu-list { + align-items: flex-end; +} + +body.mirrored #menu-list button { + text-align: right; +} + +body.mirrored #menu-list button:hover, +body.mirrored #menu-list button:focus-visible { + decorator: horizontal-gradient(#FEE68500 #FEE685FF); +} + disc-info { position: absolute; left: 96dp; + right: auto; bottom: 72dp; display: flex; flex-direction: column; gap: 12dp; font-size: 24dp; + font-effect: glow(0dp 4dp 0dp 4dp black); + text-align: left; +} + +body.mirrored disc-info { + left: auto; + right: 96dp; + text-align: right; } version-info { position: absolute; right: 96dp; + left: auto; bottom: 72dp; display: flex; flex-direction: column; gap: 12dp; text-align: right; font-size: 24dp; + font-effect: glow(0dp 4dp 0dp 4dp black); + text-align: right; +} + +body.mirrored version-info { + right: auto; + left: 96dp; + text-align: left; } #disc-status { @@ -140,8 +216,24 @@ version-info { color: #FFC9C9; } +#disc-status[status=verifying] { + color: #FFFFFF; +} + +#disc-status[status=mismatch] { + color: #FFD6A7; +} + +#disc-status[status=unknown] { + color: rgba(224, 219, 200, 65%); +} + +#disc-status[status=pending] { + color: #FEE685; +} + #disc-status icon { - display: block; + display: none; width: 24dp; height: 24dp; font-family: "Material Symbols Rounded"; @@ -149,6 +241,10 @@ version-info { font-size: 24dp; } +#disc-status[status] icon { + display: block; +} + #disc-status[status=good] icon { decorator: text("" center center); } @@ -157,24 +253,81 @@ version-info { decorator: text("" center center); } +#disc-status[status=verifying] icon { + decorator: text("" center center); +} + +#disc-status[status=mismatch] icon { + decorator: text("" center center); +} + +#disc-status[status=unknown] icon { + decorator: text("" center center); +} + +#disc-status[status=pending] icon { + decorator: text("" center center); +} + #disc-version { font-size: 20dp; } -/* TODO: Hidden until an actual update checker is introduced */ .update { display: none; font-size: 16dp; - font-weight: bold; - cursor: pointer; - color: #D8F999; + color: #A6A09B; + align-items: center; + justify-content: flex-end; + gap: 8dp; + font-size: 20dp; } -.detail, -.update span { +.update[state=checking], +.update[state=failed] { + display: block; +} + +.update[state=available] { + display: flex; +} + +#update-download { + display: none; + margin: 0dp; + padding: 0dp; + border-width: 0dp; + background-color: transparent; + color: #D8F999; + cursor: pointer; + text-transform: uppercase; + font-weight: bold; + decorator: horizontal-gradient(#00000000 #00000000); +} + +.update[state=available] #update-download { + display: flex; + align-items: center; + gap: 2dp; +} + +#update-download icon { + display: block; + width: 18dp; + height: 18dp; + font-family: "Material Symbols Rounded"; + font-weight: normal; + decorator: text("" center center); +} + +.detail { color: #A6A09B; } +body.mirrored .update { + justify-content: flex-start; +} + /* Startup animation */ .intro-item { opacity: 0; @@ -210,3 +363,84 @@ body.animate-in .intro-item { .delay-5 { transition: opacity transform 0.3s 0.6s cubic-in-out; } + +/* Mobile layout */ +@media (max-height: 640dp) { + .gradient { + decorator: horizontal-gradient(#00000000 #000000FF); + } + + body.mirrored .gradient { + decorator: horizontal-gradient(#000000FF #00000000); + } + + menu { + left: 20dp; + right: 20dp; + width: auto; + min-width: 0; + max-width: none; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 16dp; + } + + body.mirrored menu { + left: 20dp; + right: 20dp; + flex-direction: row-reverse; + } + + hero { + flex: 1 1 0; + min-width: 0; + max-width: 48%; + + } + + body.mirrored hero { + align-items: flex-end; + } + + hero img { + width: 100%; + } + + #menu-list { + flex: 1 1 0; + min-width: 0; + max-width: 52%; + align-items: flex-end; + } + + #menu-list button { + width: 100%; + max-width: 100%; + text-align: right; + } + + #menu-list button:hover, + #menu-list button:focus-visible { + decorator: horizontal-gradient(#FEE68500 #FEE685FF); + } + + body.mirrored #menu-list { + align-items: flex-start; + } + + body.mirrored #menu-list button { + text-align: left; + } + + body.mirrored #menu-list button:hover, + body.mirrored #menu-list button:focus-visible { + decorator: horizontal-gradient(#FEE685FF #FEE68500); + } + + .eyebrow, + disc-info, + version-info { + display: none; + } +} diff --git a/res/rml/tuner.rcss b/res/rml/tuner.rcss new file mode 100644 index 0000000000..86dd2043f6 --- /dev/null +++ b/res/rml/tuner.rcss @@ -0,0 +1,147 @@ +*, *:before, *:after { + box-sizing: border-box; +} + +body { + overflow: visible; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + font-family: "Fira Sans Condensed"; + font-size: 24dp; + color: #FFFFFF; + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: stretch; +} + +.tuner-root { + width: 100%; + min-height: 45%; + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: stretch; + decorator: vertical-gradient(#00000000 #151610F2); + filter: opacity(0); + transition: filter 0.2s linear-in-out; +} + +.tuner-root[open] { + filter: opacity(1); +} + +.tuner { + width: 100%; + max-width: 1216dp; + margin-left: auto; + margin-right: auto; + display: flex; + flex-direction: column; + gap: 24dp; + padding: 48dp 64dp; +} + +@media (max-height: 800dp) { + .tuner-root { + min-height: 38%; + } + + .tuner { + gap: 16dp; + padding: 32dp 48dp; + } +} + +.header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 24dp; +} + +.carousel-container { + flex: 1 1 auto; + display: flex; + justify-content: flex-end; + min-width: 0; +} + +.description { + font-size: 18dp; + line-height: 22dp; + color: rgba(255, 255, 255, 50%); +} + +.divider { + margin: 1dp 0; + border-top: 1dp rgba(217, 217, 217, 50%); +} + +.footer { + display: flex; + justify-content: space-between; + align-items: center; + gap: 24dp; +} + +footer-button { + display: block; + width: 100%; + max-width: 220dp; + border: 0; + padding: 0; + background-color: transparent; + font-family: "Fira Sans Condensed"; + font-weight: bold; + font-size: 20dp; + line-height: 24dp; + text-transform: uppercase; + color: #FFFFFF; + opacity: 1; + cursor: pointer; +} + +footer-button.return { + text-align: left; +} + +footer-button.reset { + text-align: right; +} + +.stepped-carousel { + display: flex; + align-items: center; + justify-content: center; + gap: 16dp; + width: auto; + min-width: 246dp; + padding: 0; + background-color: transparent; + font-family: "Fira Sans Condensed"; + font-weight: bold; +} + +.stepped-carousel-value { + line-height: 29dp; + min-width: 166dp; + text-align: center; + white-space: nowrap; + opacity: 0.9; +} + +.stepped-carousel-arrow { + width: 24dp; + height: 24dp; + min-width: 24dp; + padding: 0; + border: 0; + background-color: transparent; + opacity: 1; + cursor: pointer; + font-family: "Material Symbols Rounded"; + font-weight: normal; +} diff --git a/res/rml/window.rcss b/res/rml/window.rcss index db3558778a..817f3dc333 100644 --- a/res/rml/window.rcss +++ b/res/rml/window.rcss @@ -39,8 +39,8 @@ window.small { width: auto; } -window.preset { - min-width: 650dp; +window.modal { + max-width: 640dp; } window[open] { @@ -100,6 +100,10 @@ window content pane > * { flex: 0 0 auto; } +window content pane:last-of-type > div { + line-height: 1.625; +} + window content pane > spacer { display: block; /* Completes the 24dp bottom inset after the pane's 8dp gap. */ @@ -194,6 +198,11 @@ button:not(:disabled):active { box-shadow: #C2A42D 0 0 0 2dp; } +button.modal-btn { + flex: 1 1 0; + text-align: center; +} + select-button { display: flex; align-items: center; @@ -254,6 +263,8 @@ select-button input { } icon { + width: 1em; + height: 1em; font-family: "Material Symbols Rounded"; font-weight: normal; display: inline-block; @@ -261,10 +272,23 @@ icon { } icon.warning { - width: 1em; - height: 1em; decorator: text("" center center); - color: #ffcc00; +} + +icon.error { + decorator: text("" center center); +} + +icon.verifying { + decorator: text("" center center); +} + +icon.celebration { + decorator: text("" center center); +} + +icon.question-mark { + decorator: text("" center center); } .achievement-row { @@ -323,7 +347,7 @@ icon.warning { color: rgba(224, 219, 200, 45%); } -progressbar { +progress { display: block; width: 100%; height: 6dp; @@ -332,12 +356,12 @@ progressbar { margin: 6dp 0 2dp 0; } -progressbar.progress-done fill { +progress.progress-done fill { background-color: #44aa22; border-radius: 3dp; } -progressbar.progress-ongoing fill { +progress.progress-ongoing fill { background-color: #2255bb; border-radius: 3dp; } @@ -350,35 +374,13 @@ button.achievement-clear { opacity: 0.45; } -.preset-dialog { - display: flex; - flex-flow: column; - padding: 32dp; - gap: 20dp; - flex: 0 1 auto; -} - -.preset-title { - display: block; - font-family: "Fira Sans Condensed"; - font-weight: bold; - font-size: 30dp; - text-align: center; -} - -.preset-intro { - display: block; - font-size: 18dp; - text-align: center; - color: rgba(224, 219, 200, 65%); -} - .preset-grid { display: flex; flex-direction: row; gap: 20dp; flex: 0 1 auto; align-items: flex-start; + width: 100%; } .preset-col { @@ -388,14 +390,104 @@ button.achievement-clear { flex: 1 1 0; } -button.preset-btn { - font-size: 22dp; - padding: 20dp 16dp; -} - .preset-desc { display: block; font-size: 16dp; - color: rgba(224, 219, 200, 65%); text-align: center; } + +.modal-dialog { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 24dp; + gap: 20dp; + flex: 0 1 auto; + width: 100%; + text-align: left; +} + +window.modal.danger { + border: 2dp #852221; +} + +.modal-header { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + width: 100%; + flex: 0 0 auto; + gap: 16dp; +} + +.modal-header icon { + font-size: 24dp; + color: #92875B; +} + +.modal-title { + display: block; + font-family: "Fira Sans Condensed"; + font-weight: bold; + text-transform: uppercase; + font-size: 18dp; + color: #92875B; + flex: 1 1 auto; +} + +window.modal.danger .modal-title, +window.modal.danger .modal-header icon { + color: #B3261E; +} + +.modal-body { + display: block; + width: 100%; + flex: 0 1 auto; + min-width: 0; + font-size: 20dp; + color: #FFFFFF; + font-weight: normal; +} + +.modal-body span.tip { + font-size: 14dp; + color: #92875B; +} + +.verification-progress { + display: flex; + flex-direction: column; + gap: 10dp; + width: 100%; +} + +.verification-file { + display: block; + font-size: 17dp; + color: #FFFFFF; +} + +progress.verification-progress-bar { + height: 8dp; + margin: 2dp 0 0 0; +} + +.verification-detail { + display: block; + font-size: 14dp; + color: rgba(224, 219, 200, 65%); +} + +.modal-actions { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: stretch; + align-items: stretch; + gap: 12dp; + width: 100%; + flex: 0 0 auto; + padding-top: 4dp; +} diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index d53476aa91..8c1d415ae0 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -44,16 +44,14 @@ void daAlink_c::handleWolfHowl() { bool canHowl = false; if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { - if (!checkForestOldCentury()) { - if (checkMidnaRide()) { - if ((checkWolf() && - (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || - (!checkWolf() && - (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && - (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) - { - canHowl = true; - } + if (checkMidnaRide()) { + if ((checkWolf() && + (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || + (!checkWolf() && + (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && + (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) + { + canHowl = true; } } } @@ -124,16 +122,14 @@ void daAlink_c::handleQuickTransform() { bool canTransform = false; if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { - if (!checkForestOldCentury()) { - if (checkMidnaRide()) { - if ((checkWolf() && - (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || - (!checkWolf() && - (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && - (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) - { - canTransform = true; - } + if (checkMidnaRide()) { + if ((checkWolf() && + (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || + (!checkWolf() && + (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && + (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) + { + canTransform = true; } } } diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index 73049af08b..c960d37a7b 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -17,11 +17,11 @@ enum { HS_MODE_RETURN_e = 6, }; -void daAlink_c::hsChainShape_c::draw() { - if (dusk::getSettings().game.superClawshot) { - return; - } +#if TARGET_PC +static const int HS_CHAIN_MAX_LINKS = 600; +#endif +void daAlink_c::hsChainShape_c::draw() { static const int dummy = 0; daAlink_c* alink = (daAlink_c*)getUserArea(); @@ -165,7 +165,11 @@ void daAlink_c::hsChainShape_c::draw() { } (void)0; - while (maxDistanceF > var_f30) { +#if TARGET_PC + int chainLinks = 0; +#endif + + while (maxDistanceF > var_f30 IF_DUSK(&&chainLinks < HS_CHAIN_MAX_LINKS)) { temp_f27 = var_f28 * cM_fsin(sp34 * var_f30); s16 spC = cM_atan2s(temp_f27 - var_f26, 5.0f); sp64.x = sp6C.x + spC; @@ -187,6 +191,10 @@ void daAlink_c::hsChainShape_c::draw() { var_f26 = temp_f27; var_f30 += fabsf(cM_scos(spC)) * 5.0f; + +#if TARGET_PC + chainLinks++; +#endif } } @@ -202,7 +210,11 @@ void daAlink_c::hsChainShape_c::draw() { sp98 = subChainTopPos; sp6C.set(maxDistance.atan2sY_XZ(), maxDistance.atan2sX_Z(), 0); - while (maxDistanceF > var_f30) { +#if TARGET_PC + int subChainLinks = 0; +#endif + + while (maxDistanceF > var_f30 IF_DUSK(&&subChainLinks < HS_CHAIN_MAX_LINKS)) { mDoMtx_stack_c::copy(j3dSys.getViewMtx()); mDoMtx_stack_c::transM(sp98); mDoMtx_stack_c::ZXYrotM(sp6C); @@ -215,6 +227,9 @@ void daAlink_c::hsChainShape_c::draw() { sp98 += maxDistance * 5.0f; ANGLE_ADD_2(sp6C.z, 0x3000); var_f30 += 5.0f; +#if TARGET_PC + subChainLinks++; +#endif } } } diff --git a/src/d/actor/d_a_alink_swindow.inc b/src/d/actor/d_a_alink_swindow.inc index 4f651e16e2..9016f14205 100644 --- a/src/d/actor/d_a_alink_swindow.inc +++ b/src/d/actor/d_a_alink_swindow.inc @@ -41,7 +41,7 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) { u32 var_r28 = 0x10; u32 size = ROUND(i_size, 16); #if TARGET_PC - size *= 2; + size *= 20; // Increase Link's heap size to prevent mods from crashing with higher-quality models. #endif JKRHeap* parent = mDoExt_getGameHeap(); diff --git a/src/d/actor/d_a_door_boss.cpp b/src/d/actor/d_a_door_boss.cpp index 476a9c8ad6..bf042b3323 100644 --- a/src/d/actor/d_a_door_boss.cpp +++ b/src/d/actor/d_a_door_boss.cpp @@ -254,7 +254,11 @@ BOOL daBdoor_c::checkArea() { if (fabsf(vec.z) > 100.0f) { return false; } +#ifdef TARGET_PC + return (s16)((s32)fabs(current.angle.y - 0x7fff - player->current.angle.y) & 0xffff) <= 0x4000 ? 1 : 0; +#else return (s16)fabs((f64)(current.angle.y - 0x7fff - player->current.angle.y)) <= 0x4000 ? 1 : 0; +#endif } BOOL daBdoor_c::checkFront() { diff --git a/src/d/actor/d_a_door_bossL1.cpp b/src/d/actor/d_a_door_bossL1.cpp index a756cc6fd2..649ebbd5f3 100644 --- a/src/d/actor/d_a_door_bossL1.cpp +++ b/src/d/actor/d_a_door_bossL1.cpp @@ -825,7 +825,11 @@ int daBdoorL1_c::checkArea() { if (fabsf(local_48.z) > 100.0f) { return 0; } +#ifdef TARGET_PC + if ((s16)((s32)fabs(current.angle.y - 0x7fff - player->current.angle.y) & 0xffff) <= 0x4000) { +#else if ((s16)fabs((f64)(current.angle.y - 0x7fff - player->current.angle.y)) <= 0x4000) { +#endif return 1; } else { return 0; diff --git a/src/d/actor/d_a_door_bossL5.cpp b/src/d/actor/d_a_door_bossL5.cpp index d71fddad1f..34dac15fa9 100644 --- a/src/d/actor/d_a_door_bossL5.cpp +++ b/src/d/actor/d_a_door_bossL5.cpp @@ -348,7 +348,11 @@ int daBdoorL5_c::checkArea() { if (fabsf(local_48.z) > 100.0f) { return 0; } +#ifdef TARGET_PC + if ((s16)((s32)fabs(current.angle.y - 0x7fff - player->current.angle.y) & 0xffff) <= 0x4000) { +#else if ((s16)fabs((f64)(current.angle.y - 0x7fff - player->current.angle.y)) <= 0x4000) { +#endif return 1; } else { return 0; diff --git a/src/d/actor/d_a_door_mbossL1.cpp b/src/d/actor/d_a_door_mbossL1.cpp index 1f37fbcc7b..5dfd3bb96c 100644 --- a/src/d/actor/d_a_door_mbossL1.cpp +++ b/src/d/actor/d_a_door_mbossL1.cpp @@ -1317,8 +1317,12 @@ int daMBdoorL1_c::checkArea() { if (fabsf(local_48.z) > 110.0f) { return 0; } - + +#ifdef TARGET_PC + if ((s16)((s32)fabs(angle - 0x7fff - player->current.angle.y) & 0xffff) > 0x4000) { +#else if ((s16)fabs((f64)(angle - 0x7fff - player->current.angle.y)) > 0x4000) { +#endif return 0; } else { return 1; diff --git a/src/d/actor/d_a_e_wb.cpp b/src/d/actor/d_a_e_wb.cpp index 75031c42bb..47004737cb 100644 --- a/src/d/actor/d_a_e_wb.cpp +++ b/src/d/actor/d_a_e_wb.cpp @@ -5852,6 +5852,8 @@ static int daE_WB_Create(fopAc_ac_c* actor) { daE_WB_Execute(i_this); c_start = 0; + // Note: this flag makes king bulblin 1 instant die when set, as it only requires 2 laps + // for insta-kill to trigger. if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[88])) { i_this->lap_num = 1; } diff --git a/src/d/d_attention.cpp b/src/d/d_attention.cpp index efa3bfec26..1bb9e84f70 100644 --- a/src/d/d_attention.cpp +++ b/src/d/d_attention.cpp @@ -12,6 +12,10 @@ #include "SSystem/SComponent/c_counter.h" #include +#if TARGET_PC +#include "dusk/settings.h" +#endif + #define DRAW_TYPE_YELLOW 0 #define DRAW_TYPE_RED 1 @@ -1422,6 +1426,11 @@ int dAttention_c::Run() { } void dAttention_c::Draw() { +#if TARGET_PC +if (dusk::getSettings().game.recordingMode) { + return; +} +#endif if (mAttParam.CheckFlag(dAttParam_c::EFlag_ARROW_OFF)) { draw[0].field_0x173 = 3; draw[1].field_0x173 = 3; diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index e559a56d95..8e13c6271f 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -31,6 +31,7 @@ #if TARGET_PC #include "dusk/frame_interpolation.h" #include "dusk/logging.h" +#include "imgui.h" #endif namespace { @@ -7483,6 +7484,8 @@ static constexpr f32 FLYCAM_SPEED = 0.5f; static constexpr f32 FLYCAM_FAST_SPEED = 4.0f; static constexpr f32 FLYCAM_ROTATION_SPEED = 0.002f; static constexpr f32 FLYCAM_TRIGGER_DEADZONE = 20.0f; +static constexpr s16 FLYCAM_ROLL_SPEED = 256; +static ImVec2 sFlyCamLastMousePos = {-1.f, -1.f}; #if TARGET_PC bool dCamera_c::executeDebugFlyCam() { @@ -7490,6 +7493,7 @@ bool dCamera_c::executeDebugFlyCam() { if (mDebugFlyCam.initialized) { deactivateDebugFlyCam(); } + sFlyCamLastMousePos = {-1.f, -1.f}; return false; } @@ -7519,16 +7523,63 @@ bool dCamera_c::executeDebugFlyCam() { mDebugFlyCam.initialized = true; } - event->mEventStatus = 1; - dComIfGp_getEventManager().setCameraPlay(1); + if (dusk::getSettings().game.debugFlyCamLockEvents) { + event->mEventStatus = 1; + dComIfGp_getEventManager().setCameraPlay(1); + } else { + if (event->mEventStatus != 0) { + event->mEventStatus = 0; + } + dComIfGp_getEventManager().setCameraPlay(0); + } - interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0); - f32 stickY = pad.mMainStickPosY * 72.0f; - f32 stickX = pad.mMainStickPosX * 72.0f; - f32 cStickY = pad.mCStickPosY * 59.0f; - f32 cStickX = pad.mCStickPosX * 59.0f; - f32 trigL = pad.mTriggerLeft * 150.0f; - f32 trigR = pad.mTriggerRight * 150.0f; + f32 stickY = 0.f; + f32 stickX = 0.f; + f32 cStickY = 0.f; + f32 cStickX = 0.f; + f32 trigL = 0.f; + f32 trigR = 0.f; + f32 rollInput = 0.f; + bool fast = false; + + if (dusk::getSettings().game.debugFlyCamLockEvents) { + interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0); + stickY = pad.mMainStickPosY * 72.0f; + stickX = pad.mMainStickPosX * 72.0f; + cStickY = pad.mCStickPosY * 59.0f; + cStickX = pad.mCStickPosX * 59.0f; + trigL = pad.mTriggerLeft * 150.0f; + trigR = pad.mTriggerRight * 150.0f; + fast = mDoCPd_c::getHoldZ(PAD_1); + if (mDoCPd_c::getHoldY(PAD_1)) rollInput -= 1.f; + if (mDoCPd_c::getHoldX(PAD_1)) rollInput += 1.f; + } + + { + ImGuiIO& io = ImGui::GetIO(); + if (!io.WantCaptureKeyboard) { + f32 kbX = 0.0f, kbY = 0.0f; + if (ImGui::IsKeyDown(ImGuiKey_W) || ImGui::IsKeyDown(ImGuiKey_UpArrow)) kbY += 1.f; + if (ImGui::IsKeyDown(ImGuiKey_S) || ImGui::IsKeyDown(ImGuiKey_DownArrow)) kbY -= 1.f; + if (ImGui::IsKeyDown(ImGuiKey_D) || ImGui::IsKeyDown(ImGuiKey_RightArrow)) kbX += 1.f; + if (ImGui::IsKeyDown(ImGuiKey_A) || ImGui::IsKeyDown(ImGuiKey_LeftArrow)) kbX -= 1.f; + f32 len = sqrtf(kbX * kbX + kbY * kbY); + if (len > 1.f) { kbX /= len; kbY /= len; } + stickX += kbX * 72.0f; + stickY += kbY * 72.0f; + if (ImGui::IsKeyDown(ImGuiKey_Space)) trigR += 150.0f; + if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) trigL += 150.0f; + if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) fast = true; + if (ImGui::IsKeyDown(ImGuiKey_Q)) rollInput -= 1.0f; + if (ImGui::IsKeyDown(ImGuiKey_E)) rollInput += 1.0f; + } + bool mouseValid = !io.WantCaptureMouse && io.MousePos.x >= 0.0f && io.MousePos.y >= 0.0f; + if (mouseValid && sFlyCamLastMousePos.x >= 0.0f) { + cStickX -= (io.MousePos.x - sFlyCamLastMousePos.x) * 2.0f; + cStickY -= (io.MousePos.y - sFlyCamLastMousePos.y) * 2.0f; + } + sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f}; + } f32 verticalDisp = 0.0f; if (trigR >= FLYCAM_TRIGGER_DEADZONE) { @@ -7542,7 +7593,7 @@ bool dCamera_c::executeDebugFlyCam() { f32 moveDx = stickY * cosf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) - stickX * sinf(mDebugFlyCam.yaw); f32 moveDz = stickY * sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) + stickX * cosf(mDebugFlyCam.yaw); - f32 speed = mDoCPd_c::getHoldZ(PAD_1) ? FLYCAM_FAST_SPEED : FLYCAM_SPEED; + f32 speed = fast ? FLYCAM_FAST_SPEED : FLYCAM_SPEED; mEye.x += speed * moveDx; mEye.y += speed * moveDy; @@ -7553,6 +7604,7 @@ bool dCamera_c::executeDebugFlyCam() { mCenter.z = mEye.z + sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST; mCenter.y = mEye.y + sinf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST; + mBank = mBank + static_cast(rollInput * FLYCAM_ROLL_SPEED * (fast ? FLYCAM_FAST_SPEED / FLYCAM_SPEED : 1.f)); Reset(mCenter, mEye); f32 yawInput = dusk::getSettings().game.invertCameraXAxis ? cStickX : -cStickX; @@ -7570,7 +7622,7 @@ void dCamera_c::deactivateDebugFlyCam() { Reset(mDebugFlyCam.savedCenter, mDebugFlyCam.savedEye, mDebugFlyCam.savedFovy, mDebugFlyCam.savedBank.Val()); dEvt_control_c* event = dComIfGp_getEvent(); - if (event != nullptr) { + if (event != nullptr && event->mEventStatus != 0) { event->mEventStatus = 0; } dComIfGp_getEventManager().setCameraPlay(0); diff --git a/src/d/d_demo.cpp b/src/d/d_demo.cpp index d6425848d3..2f099f2c2a 100644 --- a/src/d/d_demo.cpp +++ b/src/d/d_demo.cpp @@ -11,6 +11,62 @@ #include "JSystem/JGadget/define.h" #include +#include "dusk/logging.h" + +#if TARGET_PC +#include "dusk/ui/ui.hpp" + +namespace { +static int sJaiSkip = -1; + +static JSUList* get_stream_list() { + return Z2GetSoundMgr()->getStreamMgr()->getStreamList(); +} + +static int get_stream_count(JSUList* list) { + int i = 0; + for (JSULink* l = list != nullptr ? list->getFirst() : nullptr; l != nullptr; + l = l->getNext()) { + i++; + } + return i; +} + +static void pause_stream(int skip_first, bool paused) { + int i = 0; + JSUList* list = get_stream_list(); + for (JSULink* l = list->getFirst(); l != nullptr; l = l->getNext(), ++i) { + if (i >= skip_first) { + l->getObject()->pause(paused); + } + } +} + +static void pause_streams(int skip_first) { + if (!dusk::ui::is_prelaunch_open()) { + return; + } + JSUList* list = get_stream_list(); + if (list == nullptr || get_stream_count(list) <= skip_first) { + return; + } + pause_stream(skip_first, true); + sJaiSkip = skip_first; +} + +static void unpause_streams(bool require_prelaunch_hidden) { + if (sJaiSkip < 0) { + return; + } + if (require_prelaunch_hidden && dusk::ui::is_prelaunch_open()) { + return; + } + pause_stream(sJaiSkip, false); + sJaiSkip = -1; +} +} // namespace +#endif + s16 dDemo_c::m_branchId = -1; namespace { @@ -1006,7 +1062,16 @@ int dDemo_c::start(u8 const* p_data, cXyz* p_translation, f32 rotationY) { m_control->setSuspend(0); } +#if TARGET_PC + const int existing_streams = get_stream_count(get_stream_list()); +#endif + m_control->forward(0); + +#if TARGET_PC + pause_streams(existing_streams); +#endif + m_translation = p_translation; if (m_translation != NULL) { @@ -1034,6 +1099,10 @@ static void dummyString2() { void dDemo_c::end() { JUT_ASSERT(1956, m_system != NULL); +#if TARGET_PC + unpause_streams(false); +#endif + m_control->destroyObject_all(); m_object->remove(); m_data = NULL; @@ -1054,6 +1123,10 @@ void dDemo_c::branch() { int dDemo_c::update() { JUT_ASSERT(2064, m_system != NULL); +#if TARGET_PC + unpause_streams(true); +#endif + if (m_data == NULL) { if (m_branchData == NULL) { return 0; diff --git a/src/d/d_map.cpp b/src/d/d_map.cpp index d4e5a98888..25d792f309 100644 --- a/src/d/d_map.cpp +++ b/src/d/d_map.cpp @@ -1595,7 +1595,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) { calcMapCmPerTexel(field_0x80, &field_0x58); getPack(field_0x80, &mPackX, &mPackZ); - mCenterX += mPackX; + mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX; mCenterZ -= mPackZ; mCenterX += field_0x64; mCenterZ += mPackPlusZ; @@ -1657,7 +1657,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) { calcMapCmPerTexel(field_0x80, &field_0x58); getPack(field_0x80, &mPackX, &mPackZ); - mCenterX += mPackX; + mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX; mCenterZ -= mPackZ; } break; @@ -1737,7 +1737,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) { calcMapCmPerTexel(field_0x80, &field_0x58); getPack(field_0x80, &mPackX, &mPackZ); - mCenterX += mPackX; + mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX; mCenterZ -= mPackZ; field_0x8f = 4; #if DEBUG @@ -1829,7 +1829,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) { sp14 += temp_f31_2 * (spC - sp14); sp10 += temp_f31_2 * (sp8 - sp10); - mCenterX += sp14; + mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -sp14 :) sp14; mCenterZ -= sp10; break; } diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index eca620ef98..f5e447a2aa 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -15,13 +15,47 @@ #include #ifdef TARGET_PC +#include +#include +#include + constexpr u16 kMapResolutionMultiplier = 4; -constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier; +constexpr u16 kMapImageSide = 16 * kMapResolutionMultiplier; +constexpr u32 kMapImageTotalPixels = kMapImageSide * kMapImageSide; + +typedef std::function PaintI8Fn; + +void paint_i8(std::span dst, size_t width, PaintI8Fn paint) { + const auto blocksAcross = width >> 3; + + for (size_t i = 0; i < dst.size(); i++) { + // 8x4 block swizzling for I8 + const auto blockIdx = i >> 5; + const auto localIdx = i & 31; + + const auto blockY = blockIdx / blocksAcross; + const auto blockX = blockIdx % blocksAcross; + + const auto localY = localIdx >> 3; + const auto localX = localIdx & 7; + + const auto x = (blockX << 3) + localX; + const auto y = (blockY << 2) + localY; + + dst[i] = paint(x, y); + } +} #endif void dMpath_n::dTexObjAggregate_c::create() { static int const data[7] = { - 79, 80, 77, 78, 76, 81, 82, + 79, // 0: im_map_icon_square_4i.bti + 80, // 1: im_map_icon_tresurebox_4i.bti + 77, // 2: im_map_icon_enter_4i.bti + 78, // 3: im_map_icon_nijumaru_4i.bti + 76, // 4: im_map_icon_circle_4i.bti + 81, // 5: im_map_icon_try_force_4i.bti + 82, // 6: map_icon_circle16x16_4i.bti }; for (int lp1 = 0; lp1 < 7; lp1++) { @@ -35,45 +69,101 @@ void dMpath_n::dTexObjAggregate_c::create() { } #if TARGET_PC - auto hqCircle = JKR_NEW TGXTexObj(); + static bool hqTexsDrawn = false; - static bool hqCircleDrawn = false; - static u8 hqCircleData[kMapCircleSize * kMapCircleSize]; + static u8 hqCircleData[kMapImageTotalPixels]; + static u8 hqCircleAltData[kMapImageTotalPixels]; + static u8 hqNijumaruData[kMapImageTotalPixels]; + static u8 hqEnterData[kMapImageTotalPixels]; + static u8 hqTryForceData[kMapImageTotalPixels]; - if (!hqCircleDrawn) { - const auto center = kMapCircleSize / 2.0f; - const auto radiusSq = center * center; - const auto blocksAcross = kMapCircleSize >> 3; - const auto totalPixels = sizeof(hqCircleData); + if (!hqTexsDrawn) { + constexpr auto center = kMapImageSide / 2.0f; + constexpr auto radiusSq = center * center; - for (size_t i = 0; i < totalPixels; i++) { - // 8x4 block swizzling for I8 - const auto blockIdx = i >> 5; - const auto localIdx = i & 31; + // 6: map_icon_circle16x16_4i.bti - simple circle + paint_i8(std::span{hqCircleData}, kMapImageSide, [=](auto x, auto y) { + const auto dx = (x + 0.5f) - center; + const auto dy = (y + 0.5f) - center; + return (dx * dx + dy * dy < radiusSq) ? 0x11 : 0; + }); - const auto blockY = blockIdx / blocksAcross; - const auto blockX = blockIdx % blocksAcross; - - const auto localY = localIdx >> 3; - const auto localX = localIdx & 7; - - const auto x = (blockX << 3) + localX; - const auto y = (blockY << 2) + localY; + // 4: im_map_icon_circle_4i.bti - outlined circle + paint_i8(std::span{hqCircleAltData}, kMapImageSide, [=](auto x, auto y) { + constexpr auto innerRadius = kMapImageSide * 3.0f / 8.0f; + constexpr auto innerRadiusSq = innerRadius * innerRadius; const auto dx = (x + 0.5f) - center; const auto dy = (y + 0.5f) - center; + const auto dSq = dx * dx + dy * dy; - // the original texture is in I4 format and uses 1 to indicate if inside the circle - // so we scale to I8 range: 255 / 15 = 17 - hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0; - } - hqCircleDrawn = true; + return dSq < radiusSq ? (dSq < innerRadiusSq ? 0x22 : 0x11) : 0; + }); + + // 3: im_map_icon_nijumaru_4i.bti - concentric rings + paint_i8(std::span{hqNijumaruData}, kMapImageSide, [=](auto x, auto y) { + constexpr u8 nijumaruRings[] = {0x11, 0x22, 0x11, 0x11, 0x22, 0x22}; + + const auto dx = (x + 0.5f) - center; + const auto dy = (y + 0.5f) - center; + const auto dSq = dx * dx + dy * dy; + + if (dSq < radiusSq) { + const auto ringIndex = + static_cast(std::trunc(std::sqrt(dSq) / kMapImageSide * 12)); + return nijumaruRings[ringIndex]; + } + return u8{0}; + }); + + // 2: im_map_icon_enter_4i.bti - outlined octagram + paint_i8(std::span{hqEnterData}, kMapImageSide, [=](auto x, auto y) { + constexpr auto outlineWidth = kMapImageSide / 6.0f; + + const auto adx = std::abs((x + 0.5f) - center); + const auto ady = std::abs((y + 0.5f) - center); + const auto dist = + std::min(adx + ady, std::max(adx, ady) * std::numbers::sqrt2_v) - + kMapImageSide / 2.0f; + + return dist > 0.0f ? 0 : (dist > -outlineWidth ? 0x22 : 0x33); + }); + + // 5: im_map_icon_try_force_4i.bti - outlined circle with triangle + paint_i8(std::span{hqTryForceData}, kMapImageSide, [=](auto x, auto y) { + constexpr auto innerRadiusNorm = 5.0f / 12.0f; + constexpr auto innerRadius = kMapImageSide * innerRadiusNorm; + constexpr auto innerRadiusSq = innerRadius * innerRadius; + constexpr auto triRadius = kMapImageSide * innerRadiusNorm / 2.0f; + + const auto dx = (x + 0.5f) - center; + const auto dy = (y + 0.5f) - center; + const auto dSq = dx * dx + dy * dy; + const auto triSideDist = (std::numbers::sqrt3_v * std::abs(dx) - dy) * 0.5f; + const auto insideTri = std::max(dy, triSideDist) < triRadius; + + return insideTri ? 0x22 : (dSq < radiusSq ? (dSq < innerRadiusSq ? 0x33 : 0x22) : 0); + }); + + hqTexsDrawn = true; } - GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP, - GX_CLAMP, GX_FALSE); - GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); - mp_texObj[6] = hqCircle; + constexpr auto replacements = std::to_array >({ + {2, hqEnterData}, + {3, hqNijumaruData}, + {4, hqCircleAltData}, + {5, hqTryForceData}, + {6, hqCircleData}, + }); + + for (const auto& [idx, data] : replacements) { + JKR_DELETE(mp_texObj[idx]); + const auto texobj = JKR_NEW TGXTexObj(); + GXInitTexObj( + texobj, data, kMapImageSide, kMapImageSide, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE); + GXInitTexObjLOD(texobj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); + mp_texObj[idx] = texobj; + } #endif } diff --git a/src/d/d_menu_dmap.cpp b/src/d/d_menu_dmap.cpp index 8ef7fadd4b..b39c9bb287 100644 --- a/src/d/d_menu_dmap.cpp +++ b/src/d/d_menu_dmap.cpp @@ -942,7 +942,10 @@ void dMenu_DmapBg_c::draw() { f32 local_28c = mpBackTexture->getBounds().i.x; mpBackTexture->setBlackWhite(color_black, color_white); mpBackTexture->draw(local_28c, field_0xd94 + mpBackTexture->getBounds().i.y, mpBackTexture->getWidth(), - mpBackTexture->getHeight(), false, false, false); + mpBackTexture->getHeight(), + IF_DUSK(dusk::getSettings().game.enableMirrorMode ? true :) false, + false, + false); grafContext->scissor(field_0xd94 + mDoGph_gInf_c::getMinXF(), scissor_top, mDoGph_gInf_c::getWidthF(), diff --git a/src/d/d_menu_dmap_map.cpp b/src/d/d_menu_dmap_map.cpp index 9100a7d63a..0bb9717952 100644 --- a/src/d/d_menu_dmap_map.cpp +++ b/src/d/d_menu_dmap_map.cpp @@ -368,7 +368,7 @@ void dMenu_StageMapCtrl_c::initGetTreasureList(u8 param_0, s8 param_1) { } inline static s16 rightModeCnvRot(s16 param_0) { - return param_0; + return IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -param_0 :) param_0; } bool dMenu_StageMapCtrl_c::getTreasureList(f32* o_posX, f32* o_posY, s8* param_2, u8* o_swbit, @@ -405,7 +405,7 @@ bool dMenu_StageMapCtrl_c::getTreasureList(f32* o_posX, f32* o_posY, s8* param_2 } inline static f32 rightModeCnvPos(f32 param_0) { - return param_0; + return IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -param_0 :) param_0; } void dMenu_StageMapCtrl_c::cnvPosTo2Dpos(f32 param_0, f32 param_1, f32* param_2, diff --git a/src/d/d_menu_fmap.cpp b/src/d/d_menu_fmap.cpp index 149e03349d..d2b06e962c 100644 --- a/src/d/d_menu_fmap.cpp +++ b/src/d/d_menu_fmap.cpp @@ -919,9 +919,20 @@ void dMenu_Fmap_c::region_map_proc() { } mpDraw2DBack->regionMapMove(mpStick); int stage_no, room_no; + +#if TARGET_PC + f32 arrow_pos_x = mpDraw2DBack->getArrowPos2DX(); + if (dusk::getSettings().game.enableMirrorMode) { + arrow_pos_x = mpDraw2DBack->getMirrorPosX(arrow_pos_x, 0.0f); + } + + f32 pos_x = arrow_pos_x - mDoGph_gInf_c::getMinXF() - mDoGph_gInf_c::getWidthF() * 0.5f; +#else f32 pos_x = mpDraw2DBack->getArrowPos2DX() - mDoGph_gInf_c::getMinXF() - mDoGph_gInf_c::getWidthF() * 0.5f; +#endif f32 pos_y = mpDraw2DBack->getArrowPos2DY() - mDoGph_gInf_c::getHeightF() * 0.5f; + mpMenuFmapMap->getPointStagePathInnerNo(getNowFmapRegionData(), pos_x, pos_y, mStayStageNo, &stage_no, &room_no); if (mStageCursor != stage_no || mRoomCursor != room_no || mResetAreaName) { @@ -2464,6 +2475,13 @@ void dMenu_Fmap_c::portalWarpMapMove(STControl* i_stick) { f32 arrow_y = mpDraw2DBack->getArrowPos2DY(); u8 uVar6 = 0xff; +#if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + arrow_x = mpDraw2DBack->getMirrorPosX(arrow_x, 0.0f); + } +#endif + + for (int i = 0; i < portal_dat->mCount; i++) { if (portals[i].mRegionNo == mpDraw2DBack->getRegionCursor() + 1 && checkDrawPortalIcon(portals[i].mStageNo, portals[i].mSwitchNo)) diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index ea9912998b..d62f7d1037 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -1043,6 +1043,12 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) { calcAllMapPos2D((mArrowPos3DX + control_xpos) - mStageTransX, (mArrowPos3DZ + control_ypos) - mStageTransZ, &sp14, &sp10); +#if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + sp14 = getMirrorPosX(sp14, 0.0f); + } +#endif + mSelectRegion = 0xff; for (int i = 7; i >= 0; i--) { int val = field_0x1230[i]; @@ -1397,6 +1403,15 @@ void dMenu_Fmap2DBack_c::regionTextureDraw() { if (uVar10 != uVar9) { bool b = 0; f32 v = mTransX + (dVar14 + (mRegionMinMapX[uVar10] + field_0xf0c[uVar10])); + + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + b = true; + v = getMirrorPosX(mTransX + (dVar14 + (mRegionMinMapX[uVar10] + field_0xf0c[uVar10])), + mRegionMapSizeX[uVar10] * mZoom * 0.5f); + } + #endif + mpAreaTex[uVar10]->draw( v, mTransZ + (dVar13 + (mRegionMinMapY[uVar10] + field_0xf2c[uVar10])), mRegionMapSizeX[uVar10] * mZoom, mRegionMapSizeY[uVar10] * mZoom, b, false, @@ -1404,6 +1419,15 @@ void dMenu_Fmap2DBack_c::regionTextureDraw() { } else { bool b = 0; f32 v = mTransX + (dVar14 + (mRegionMinMapX[uVar9] + field_0xf0c[uVar9])); + + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + b = true; + v = getMirrorPosX(mTransX + (dVar14 + (mRegionMinMapX[uVar9] + field_0xf0c[uVar9])), + mRegionMapSizeX[uVar9] * mZoom * 0.5f); + } + #endif + mpAreaTex[uVar9]->draw( v, mTransZ + (dVar13 + (mRegionMinMapY[uVar9] + field_0xf2c[uVar9])), mRegionMapSizeX[uVar9] * mZoom, mRegionMapSizeY[uVar9] * mZoom, b, false, diff --git a/src/d/d_menu_map_common.cpp b/src/d/d_menu_map_common.cpp index e7d0fef7ad..0017975c4e 100644 --- a/src/d/d_menu_map_common.cpp +++ b/src/d/d_menu_map_common.cpp @@ -343,6 +343,11 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = icon_pos_x + i_posX; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(pos_x, 0.0f); + } + #endif mpDrawCursor->setPos(pos_x, icon_pos_y + i_posY); mpDrawCursor->setScale(mIconInfo[info_idx].scale * g_fmapHIO.mMapIconHIO.mPortalCursorScale); mpDrawCursor->draw(); @@ -364,6 +369,12 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = (icon_pos_x + i_posX); + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(pos_x, 0.0f); + } + #endif + mpPortalIcon->setPos(pos_x, icon_pos_y + i_posY); mpPortalIcon->setScale(mIconInfo[info_idx].scale * g_fmapHIO.mMapIconHIO.mPortalIconScale); mpPortalIcon->draw(); @@ -399,6 +410,12 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = i_posX + (icon_pos_x - (icon_size_x / 2)); + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(i_posX + (icon_pos_x - (icon_size_x / 2)), icon_size_x / 2); + } + #endif + mPictures[mIconInfo[info_idx].icon_no]->draw(pos_x, (i_posY + (icon_pos_y - icon_size_y / 2)), icon_size_x, icon_size_y, false, false, false); diff --git a/src/d/d_meter2.cpp b/src/d/d_meter2.cpp index fa6774d0a5..097cde7c37 100644 --- a/src/d/d_meter2.cpp +++ b/src/d/d_meter2.cpp @@ -24,9 +24,10 @@ #include "d/actor/d_a_horse.h" #include +#if TARGET_PC #include "dusk/memory.h" - -#include "dusk/memory.h" +#include "dusk/settings.h" +#endif int dMeter2_c::_create() { stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo(); @@ -317,7 +318,9 @@ int dMeter2_c::_execute() { int dMeter2_c::_draw() { #if TARGET_PC - if (dusk::getSettings().game.disableMainHUD) { + if (dusk::getSettings().game.recordingMode || dusk::getSettings().game.minimalHUD || + dusk::getSettings().game.debugFlyCam) + { return 1; } #endif diff --git a/src/d/d_msg_scrn_arrow.cpp b/src/d/d_msg_scrn_arrow.cpp index 7ee3b0503c..cea0dae145 100644 --- a/src/d/d_msg_scrn_arrow.cpp +++ b/src/d/d_msg_scrn_arrow.cpp @@ -6,6 +6,10 @@ #include "d/d_com_inf_game.h" #include "d/d_pane_class.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnArrow_c::dMsgScrnArrow_c() { mpScreen = JKR_NEW J2DScreen(); JUT_ASSERT(0, mpScreen != NULL); @@ -65,6 +69,11 @@ dMsgScrnArrow_c::~dMsgScrnArrow_c() { } void dMsgScrnArrow_c::draw() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* graf_ctx = dComIfGp_getCurrentGrafPort(); mpScreen->draw(0.0f, 0.0f, graf_ctx); } diff --git a/src/d/d_msg_scrn_base.cpp b/src/d/d_msg_scrn_base.cpp index 84899c2824..fdd9e57f9c 100644 --- a/src/d/d_msg_scrn_base.cpp +++ b/src/d/d_msg_scrn_base.cpp @@ -8,6 +8,10 @@ #include "d/d_pane_class.h" #include +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnBase_c::dMsgScrnBase_c() { init(); } @@ -57,12 +61,22 @@ void dMsgScrnBase_c::init() { } void dMsgScrnBase_c::multiDraw() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif if (field_0x48 != NULL) { dComIfGd_set2DOpa(field_0x48); } } void dMsgScrnBase_c::draw() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort(); ctx->setup2D(); @@ -72,10 +86,20 @@ void dMsgScrnBase_c::draw() { } void dMsgScrnBase_c::drawSelf() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif drawOutFont(0.0f, 0.0f, 1.0f); } void dMsgScrnBase_c::drawOutFont(f32 param_0, f32 param_1, f32 param_2) { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif mpOutFont->draw(NULL, param_0, param_1, param_2); } diff --git a/src/d/d_msg_scrn_boss.cpp b/src/d/d_msg_scrn_boss.cpp index 64141770b3..54938ceb72 100644 --- a/src/d/d_msg_scrn_boss.cpp +++ b/src/d/d_msg_scrn_boss.cpp @@ -6,6 +6,10 @@ #include "d/d_msg_object.h" #include "d/d_pane_class.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnBoss_c::dMsgScrnBoss_c() { static u64 t_tag[7] = { MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'), @@ -91,6 +95,11 @@ void dMsgScrnBoss_c::exec() { } void dMsgScrnBoss_c::drawSelf() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort(); ctx->setup2D(); drawOutFont(0.0f, 0.0f, 1.0f); diff --git a/src/d/d_msg_scrn_kanban.cpp b/src/d/d_msg_scrn_kanban.cpp index a9edbef7df..d6e91b12f6 100644 --- a/src/d/d_msg_scrn_kanban.cpp +++ b/src/d/d_msg_scrn_kanban.cpp @@ -13,6 +13,10 @@ #include "d/d_msg_out_font.h" #include "d/d_pane_class.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnKanban_c::dMsgScrnKanban_c(JKRExpHeap* param_0) { if (param_0 != NULL) { field_0xd4 = param_0; @@ -176,6 +180,11 @@ void dMsgScrnKanban_c::exec() { } void dMsgScrnKanban_c::draw() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort(); grafContext->setup2D(); mpScreen->draw(0.0f, 0.0f, grafContext); diff --git a/src/d/d_msg_scrn_place.cpp b/src/d/d_msg_scrn_place.cpp index b2c28efc95..93c2ec7c20 100644 --- a/src/d/d_msg_scrn_place.cpp +++ b/src/d/d_msg_scrn_place.cpp @@ -12,6 +12,10 @@ #include "d/d_msg_object.h" #include "d/d_pane_class.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnPlace_c::dMsgScrnPlace_c() { static u64 t_tag[7] = { MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'), @@ -127,6 +131,11 @@ void dMsgScrnPlace_c::exec() { } void dMsgScrnPlace_c::drawSelf() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort(); grafContext->setup2D(); drawOutFont(0.0f, 0.0f, 1.0f); diff --git a/src/d/d_msg_scrn_talk.cpp b/src/d/d_msg_scrn_talk.cpp index c9f925e784..ace5abd3bb 100644 --- a/src/d/d_msg_scrn_talk.cpp +++ b/src/d/d_msg_scrn_talk.cpp @@ -20,6 +20,10 @@ #include "JSystem/J2DGraph/J2DScreen.h" #include +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnTalk_c::dMsgScrnTalk_c(u8 param_1, u8 param_2, JKRExpHeap* param_3) { if (param_3 != NULL) { field_0xe4 = param_3; @@ -303,6 +307,11 @@ void dMsgScrnTalk_c::exec() { } void dMsgScrnTalk_c::drawSelf() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* grafContext[1]; grafContext[0] = dComIfGp_getCurrentGrafPort(); grafContext[0]->setup2D(); diff --git a/src/d/d_msg_scrn_tree.cpp b/src/d/d_msg_scrn_tree.cpp index 0dee41ef5a..d17ced9bd8 100644 --- a/src/d/d_msg_scrn_tree.cpp +++ b/src/d/d_msg_scrn_tree.cpp @@ -9,6 +9,10 @@ #include "d/d_msg_out_font.h" #include "d/d_pane_class.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + dMsgScrnTree_c::dMsgScrnTree_c(JUTFont* param_0, JKRExpHeap* param_1) { if (param_1 != NULL) { field_0xd8 = param_1; @@ -187,6 +191,11 @@ void dMsgScrnTree_c::exec() { } void dMsgScrnTree_c::draw() { +#if TARGET_PC + if (dusk::getSettings().game.recordingMode) { + return; + } +#endif J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort(); grafContext->setup2D(); mpScreen->draw(0.0f, 0.0f, grafContext); diff --git a/src/d/d_s_logo.cpp b/src/d/d_s_logo.cpp index 8c4d706b7f..672393b033 100644 --- a/src/d/d_s_logo.cpp +++ b/src/d/d_s_logo.cpp @@ -1120,26 +1120,12 @@ int dScnLogo_c::create() { checkProgSelect(); if (field_0x20a != 0) { mExecCommand = EXEC_PROG_IN; - #if TARGET_PC - mTimer = dusk::getSettings().game.skipWarningScreen ? 1 : 30; - #else mTimer = 30; - #endif field_0x218 = getProgressiveMode(); } else { #if TARGET_PC - if (dusk::getSettings().game.skipWarningScreen) { - mTimer = 0; // Possibly unnecessary but just in case - mExecCommand = EXEC_DVD_WAIT; - } else { - if (mDoRst::getWarningDispFlag()) { - mTimer = 90; - mExecCommand = EXEC_NINTENDO_IN; - } else { - mTimer = 120; - mExecCommand = EXEC_WARNING_IN; - } - } + mTimer = 0; // Possibly unnecessary but just in case + mExecCommand = EXEC_DVD_WAIT; #else if (mDoRst::getWarningDispFlag()) { mTimer = 90; diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index f0e2330a15..f7ebf6a20d 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -40,8 +40,9 @@ #include "JSystem/JKernel/JKRAramArchive.h" #if TARGET_PC +#include "dusk/autosave.h" #include "dusk/memory.h" -#include +#include "dusk/ui/ui.hpp" #endif #if DEBUG @@ -794,7 +795,17 @@ static int dScnPly_Execute(dScnPly_c* i_this) { dJprev_c::get()->update(); #endif +#if TARGET_PC + if (!dusk::ui::is_prelaunch_open()) { + dDemo_c::update(); + } else if (dusk::getSettings().audio.menuSounds) { + s8 reverb = dComIfGp_getReverb(dComIfGp_roomControl_getStayNo()); + f32 fxMix = reverb / 127.0f; + g_mEnvSeMgr.field_0x144.startEnvSeDirLevel(JA_SE_ATM_WIND_1, fxMix, 1.0f); + } +#else dDemo_c::update(); +#endif #if DEBUG dJcame_c::get()->update(); diff --git a/src/dusk/OSReport.cpp b/src/dusk/OSReport.cpp index a54bcf0c78..aee1e17bc6 100644 --- a/src/dusk/OSReport.cpp +++ b/src/dusk/OSReport.cpp @@ -21,16 +21,39 @@ static bool checkEnabled() { return !__OSReport_disable || dusk::OSReportReallyForceEnable; } +#ifndef va_copy +#define va_copy(d, s) ((d) = (s)) +#endif + static std::string FormatToString(const char* msg, va_list list) { - int ret = vsnprintf(nullptr, 0, msg, list); - if (ret <= 0) { - return {}; + size_t size = (strlen(msg) * 2) + 50; + std::string str; + va_list ap; + int attempts = 0; + while (true) { + str.resize(size); + va_copy(ap, list); + int n = vsnprintf(str.data(), size, msg, ap); + va_end(ap); + if (n > -1 && n < size) { + str.resize(n); + break; + } + + ++attempts; + if (attempts >= 3) { + if (n == -1) { + str.clear(); + } + break; + } + if (n > -1) { + size = n + 1; + } else { + size *= 2; + } } - ++ret; - std::unique_ptr buf(new char[ret]); - vsnprintf(buf.get(), ret, msg, list); - buf[ret - 1] = '\0'; - return {buf.get()}; + return str; } void OSReport(const char* fmt, ...) { diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index 26a302678e..a090a40969 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -1,14 +1,15 @@ #include "dusk/achievements.h" -#include "dusk/io.hpp" -#include "dusk/main.h" -#include "d/d_com_inf_game.h" -#include "d/d_meter2_info.h" #include "d/actor/d_a_alink.h" #include "d/actor/d_a_npc4.h" #include "d/actor/d_a_player.h" +#include "d/d_com_inf_game.h" #include "d/d_demo.h" -#include "f_pc/f_pc_name.h" +#include "d/d_meter2_info.h" +#include "dusk/io.hpp" +#include "dusk/main.h" +#include "dusk/ui/ui.hpp" #include "f_op/f_op_actor_mng.h" +#include "f_pc/f_pc_name.h" #include #include @@ -454,12 +455,6 @@ AchievementSystem& AchievementSystem::get() { return instance; } -std::string AchievementSystem::consumePendingUnlock() { - std::string msg = std::move(m_pendingUnlocks.front()); - m_pendingUnlocks.pop(); - return msg; -} - std::vector AchievementSystem::getAchievements() const { std::vector result; result.reserve(m_entries.size()); @@ -559,7 +554,14 @@ void AchievementSystem::processEntry(Entry& e) { if (nowUnlocked) { e.achievement.progress = e.achievement.isCounter ? e.achievement.goal : 1; e.achievement.unlocked = true; - m_pendingUnlocks.push(e.achievement.name); + if (getSettings().game.enableAchievementNotifications) { + ui::push_toast({ + .type = "achievement", + .title = "Achievement Unlocked!", + .content = e.achievement.name, + .duration = std::chrono::seconds(5), + }); + } m_dirty = true; } else if (progressChanged) { m_dirty = true; diff --git a/src/dusk/autosave.cpp b/src/dusk/autosave.cpp index f9b76f4c67..779cb19915 100644 --- a/src/dusk/autosave.cpp +++ b/src/dusk/autosave.cpp @@ -1,4 +1,5 @@ #include "dusk/autosave.h" +#include "dusk/ui/ui.hpp" #include "imgui/ImGuiConsole.hpp" u8 mSaveBuffer[QUEST_LOG_SIZE * 3]; @@ -83,6 +84,9 @@ void waitingForWrite() { } void endAutoSave() { - dusk::g_imguiConsole.AddToast("Saving...", 2.0f); + dusk::ui::push_toast({ + .type = "autosave", + .duration = std::chrono::milliseconds(1500), + }); mAutoSaveProc = 0; } \ No newline at end of file diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 856cdce4a3..f4af7a2961 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -154,6 +154,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; template class ConfigImpl; } diff --git a/src/dusk/http/curl.cpp b/src/dusk/http/curl.cpp new file mode 100644 index 0000000000..5fdaf88a64 --- /dev/null +++ b/src/dusk/http/curl.cpp @@ -0,0 +1,206 @@ +#include "http.hpp" + +#include + +#include +#include +#include +#include + +namespace dusk::http { +namespace { + +struct CurlHeaders { + curl_slist* list = nullptr; + + ~CurlHeaders() { + if (list != nullptr) { + curl_slist_free_all(list); + } + } + + bool append(const std::string& header) { + curl_slist* next = curl_slist_append(list, header.c_str()); + if (next == nullptr) { + return false; + } + list = next; + return true; + } +}; + +struct CurlContext { + Response response; + size_t maxBodyBytes = 0; + bool tooLarge = false; +}; + +void initialize_curl() { + curl_global_init(CURL_GLOBAL_DEFAULT); +} + +std::string trim_header_value(std::string_view value) { + while (!value.empty() && (value.front() == ' ' || value.front() == '\t')) { + value.remove_prefix(1); + } + while (!value.empty() && + (value.back() == '\r' || value.back() == '\n' || value.back() == ' ' || + value.back() == '\t')) { + value.remove_suffix(1); + } + return std::string(value); +} + +size_t write_body(char* ptr, size_t size, size_t nmemb, void* userdata) { + auto* context = static_cast(userdata); + const size_t bytes = size * nmemb; + if (bytes > context->maxBodyBytes || + context->response.body.size() > context->maxBodyBytes - bytes) { + context->tooLarge = true; + return 0; + } + + context->response.body.append(ptr, bytes); + return bytes; +} + +size_t write_header(char* ptr, size_t size, size_t nmemb, void* userdata) { + auto* context = static_cast(userdata); + const std::string_view line(ptr, size * nmemb); + if (line.starts_with("HTTP/")) { + context->response.headers.clear(); + return size * nmemb; + } + + const size_t colon = line.find(':'); + if (colon == std::string_view::npos) { + return size * nmemb; + } + + context->response.headers.push_back({ + .name = std::string(line.substr(0, colon)), + .value = trim_header_value(line.substr(colon + 1)), + }); + return size * nmemb; +} + +Error map_curl_error(CURLcode code, bool tooLarge) { + if (tooLarge) { + return Error::TooLarge; + } + + switch (code) { + case CURLE_OK: + return Error::None; + case CURLE_URL_MALFORMAT: + return Error::InvalidUrl; + case CURLE_UNSUPPORTED_PROTOCOL: + return Error::UnsupportedScheme; + case CURLE_OPERATION_TIMEDOUT: + return Error::Timeout; + default: + return Error::Network; + } +} + +long timeout_ms(std::chrono::milliseconds timeout) { + return std::max(1, timeout.count()); +} + +} // namespace + +bool available() noexcept { + return true; +} + +Backend backend() noexcept { + return Backend::LibCurl; +} + +const char* backend_name() noexcept { + return "libcurl"; +} + +Result get(const Request& request) { + if (request.url.empty()) { + return { + .error = Error::InvalidUrl, + .message = "URL is empty", + }; + } + if (!request.url.starts_with("https://")) { + return { + .error = Error::UnsupportedScheme, + .message = "Only https:// URLs are supported", + }; + } + + static std::once_flag initFlag; + std::call_once(initFlag, initialize_curl); + + CURL* curl = curl_easy_init(); + if (curl == nullptr) { + return { + .error = Error::Network, + .message = "Failed to create libcurl request", + }; + } + + CurlHeaders headers; + for (const Header& header : request.headers) { + if (!headers.append(header.name + ": " + header.value)) { + curl_easy_cleanup(curl); + return { + .error = Error::Network, + .message = "Failed to allocate libcurl headers", + }; + } + } + + CurlContext context{ + .maxBodyBytes = request.maxBodyBytes, + }; + + curl_easy_setopt(curl, CURLOPT_URL, request.url.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers.list); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms(request.timeout)); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout_ms(request.timeout)); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_body); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &context); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_header); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &context); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); +#if CURL_AT_LEAST_VERSION(7, 85, 0) + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https"); +#else + curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS); +#endif + + const CURLcode code = curl_easy_perform(curl); + long statusCode = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); + curl_easy_cleanup(curl); + + context.response.statusCode = static_cast(statusCode); + if (code == CURLE_OK) { + return { + .response = std::move(context.response), + }; + } + + const Error error = map_curl_error(code, context.tooLarge); + return { + .error = error, + .message = error == Error::TooLarge ? "Response body exceeded the configured limit" + : curl_easy_strerror(code), + .response = std::move(context.response), + }; +} + +} // namespace dusk::http diff --git a/src/dusk/http/http.hpp b/src/dusk/http/http.hpp new file mode 100644 index 0000000000..d62b031fbc --- /dev/null +++ b/src/dusk/http/http.hpp @@ -0,0 +1,59 @@ +#ifndef DUSK_HTTP_HTTP_HPP +#define DUSK_HTTP_HTTP_HPP + +#include +#include +#include +#include + +namespace dusk::http { + +enum class Backend { + None, + WinHttp, + UrlSession, + LibCurl, +}; + +enum class Error { + None, + NoBackend, + InvalidUrl, + UnsupportedScheme, + Timeout, + TooLarge, + Network, +}; + +struct Header { + std::string name; + std::string value; +}; + +struct Request { + std::string url; + std::vector
headers; + std::chrono::milliseconds timeout{10000}; + size_t maxBodyBytes = 1024 * 1024; +}; + +struct Response { + int statusCode = 0; + std::vector
headers; + std::string body; +}; + +struct Result { + Error error = Error::None; + std::string message; + Response response; +}; + +bool available() noexcept; +Backend backend() noexcept; +const char* backend_name() noexcept; +Result get(const Request& request); + +} // namespace dusk::http + +#endif // DUSK_HTTP_HTTP_HPP diff --git a/src/dusk/http/no_backend.cpp b/src/dusk/http/no_backend.cpp new file mode 100644 index 0000000000..4b42afb3c7 --- /dev/null +++ b/src/dusk/http/no_backend.cpp @@ -0,0 +1,24 @@ +#include "http.hpp" + +namespace dusk::http { + +bool available() noexcept { + return false; +} + +Backend backend() noexcept { + return Backend::None; +} + +const char* backend_name() noexcept { + return "none"; +} + +Result get(const Request&) { + return { + .error = Error::NoBackend, + .message = "No HTTP backend is available", + }; +} + +} // namespace dusk::http diff --git a/src/dusk/http/url_session.mm b/src/dusk/http/url_session.mm new file mode 100644 index 0000000000..01dd699a9c --- /dev/null +++ b/src/dusk/http/url_session.mm @@ -0,0 +1,238 @@ +#include "http.hpp" + +#import + +#include +#include +#include + +@interface DuskHttpRequestDelegate : NSObject +@property(nonatomic) dispatch_semaphore_t semaphore; +@property(nonatomic) size_t maxBodyBytes; +@property(nonatomic, strong) NSMutableData* data; +@property(nonatomic, strong) NSURLResponse* response; +@property(nonatomic, strong) NSError* error; +@property(nonatomic) BOOL tooLarge; +- (instancetype)initWithMaxBodyBytes:(size_t)maxBodyBytes; +@end + +@implementation DuskHttpRequestDelegate + +- (instancetype)initWithMaxBodyBytes:(size_t)maxBodyBytes { + self = [super init]; + if (self != nil) { + _semaphore = dispatch_semaphore_create(0); + _maxBodyBytes = maxBodyBytes; + _data = [NSMutableData data]; + } + return self; +} + +- (void)URLSession:(NSURLSession*)session + task:(NSURLSessionTask*)task + willPerformHTTPRedirection:(NSHTTPURLResponse*)response + newRequest:(NSURLRequest*)request + completionHandler:(void (^)(NSURLRequest*))completionHandler { + if ([[request.URL.scheme lowercaseString] isEqualToString:@"https"]) { + completionHandler(request); + } else { + completionHandler(nil); + } +} + +- (void)URLSession:(NSURLSession*)session + dataTask:(NSURLSessionDataTask*)dataTask +didReceiveResponse:(NSURLResponse*)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + self.response = response; + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession*)session + dataTask:(NSURLSessionDataTask*)dataTask + didReceiveData:(NSData*)data { + if (data.length > self.maxBodyBytes || + self.data.length > self.maxBodyBytes - data.length) { + self.tooLarge = YES; + [dataTask cancel]; + return; + } + [self.data appendData:data]; +} + +- (void)URLSession:(NSURLSession*)session + task:(NSURLSessionTask*)task + didCompleteWithError:(NSError*)error { + if (error != nil && !self.tooLarge) { + self.error = error; + } + dispatch_semaphore_signal(self.semaphore); +} + +@end + +namespace dusk::http { +namespace { + +NSString* to_nsstring(std::string_view value) { + return [[NSString alloc] initWithBytes:value.data() + length:value.size() + encoding:NSUTF8StringEncoding]; +} + +std::string to_string(NSString* value) { + if (value == nil) { + return {}; + } + + const char* utf8 = [value UTF8String]; + return utf8 == nullptr ? std::string() : std::string(utf8); +} + +Error map_nsurl_error(NSError* error) { + if (error == nil || ![error.domain isEqualToString:NSURLErrorDomain]) { + return Error::Network; + } + + switch (error.code) { + case NSURLErrorTimedOut: + return Error::Timeout; + case NSURLErrorBadURL: + case NSURLErrorUnsupportedURL: + return Error::InvalidUrl; + default: + return Error::Network; + } +} + +dispatch_time_t timeout_deadline(std::chrono::milliseconds timeout) { + const auto milliseconds = std::max(1, timeout.count()); + return dispatch_time(DISPATCH_TIME_NOW, + static_cast(milliseconds) * static_cast(NSEC_PER_MSEC)); +} + +} // namespace + +bool available() noexcept { + return true; +} + +Backend backend() noexcept { + return Backend::UrlSession; +} + +const char* backend_name() noexcept { + return "NSURLSession"; +} + +Result get(const Request& request) { + @autoreleasepool { + if (request.url.empty()) { + return { + .error = Error::InvalidUrl, + .message = "URL is empty", + }; + } + if (!request.url.starts_with("https://")) { + return { + .error = Error::UnsupportedScheme, + .message = "Only https:// URLs are supported", + }; + } + + NSString* urlString = to_nsstring(request.url); + if (urlString == nil) { + return { + .error = Error::InvalidUrl, + .message = "URL is not valid UTF-8", + }; + } + + NSURL* url = [NSURL URLWithString:urlString]; + if (url == nil || ![[url.scheme lowercaseString] isEqualToString:@"https"]) { + return { + .error = Error::InvalidUrl, + .message = "Failed to parse URL", + }; + } + + NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url]; + urlRequest.HTTPMethod = @"GET"; + urlRequest.timeoutInterval = request.timeout.count() / 1000.0; + urlRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + for (const Header& header : request.headers) { + NSString* name = to_nsstring(header.name); + NSString* value = to_nsstring(header.value); + if (name == nil || value == nil) { + return { + .error = Error::InvalidUrl, + .message = "Request header is not valid UTF-8", + }; + } + [urlRequest setValue:value forHTTPHeaderField:name]; + } + + NSURLSessionConfiguration* configuration = + [NSURLSessionConfiguration ephemeralSessionConfiguration]; + configuration.timeoutIntervalForRequest = request.timeout.count() / 1000.0; + configuration.timeoutIntervalForResource = request.timeout.count() / 1000.0; + + DuskHttpRequestDelegate* delegate = + [[DuskHttpRequestDelegate alloc] initWithMaxBodyBytes:request.maxBodyBytes]; + NSURLSession* session = [NSURLSession sessionWithConfiguration:configuration + delegate:delegate + delegateQueue:nil]; + NSURLSessionDataTask* task = [session dataTaskWithRequest:urlRequest]; + [task resume]; + + if (dispatch_semaphore_wait(delegate.semaphore, timeout_deadline(request.timeout)) != 0) { + [task cancel]; + [session invalidateAndCancel]; + return { + .error = Error::Timeout, + .message = "Request timed out", + }; + } + + [session finishTasksAndInvalidate]; + + Response response; + if ([delegate.response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)delegate.response; + response.statusCode = static_cast(httpResponse.statusCode); + NSDictionary* headers = httpResponse.allHeaderFields; + for (id key in headers) { + id value = headers[key]; + response.headers.push_back({ + .name = to_string([key description]), + .value = to_string([value description]), + }); + } + } + if (delegate.data != nil && delegate.data.length > 0) { + response.body.assign(static_cast(delegate.data.bytes), + static_cast(delegate.data.length)); + } + + if (delegate.tooLarge) { + return { + .error = Error::TooLarge, + .message = "Response body exceeded the configured limit", + .response = std::move(response), + }; + } + if (delegate.error != nil) { + return { + .error = map_nsurl_error(delegate.error), + .message = to_string(delegate.error.localizedDescription), + .response = std::move(response), + }; + } + + return { + .response = std::move(response), + }; + } +} + +} // namespace dusk::http diff --git a/src/dusk/http/winhttp.cpp b/src/dusk/http/winhttp.cpp new file mode 100644 index 0000000000..937579f076 --- /dev/null +++ b/src/dusk/http/winhttp.cpp @@ -0,0 +1,320 @@ +#include "http.hpp" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include + +#include +#include +#include +#include +#include + +namespace dusk::http { +namespace { + +struct WinHttpHandle { + HINTERNET handle = nullptr; + + WinHttpHandle() = default; + explicit WinHttpHandle(HINTERNET handle) : handle(handle) {} + WinHttpHandle(const WinHttpHandle&) = delete; + WinHttpHandle& operator=(const WinHttpHandle&) = delete; + + ~WinHttpHandle() { + if (handle != nullptr) { + WinHttpCloseHandle(handle); + } + } + + operator HINTERNET() const { return handle; } +}; + +std::wstring utf8_to_wide(std::string_view value) { + if (value.empty()) { + return {}; + } + + const int required = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, value.data(), static_cast(value.size()), nullptr, 0); + if (required <= 0) { + return {}; + } + + std::wstring result(static_cast(required), L'\0'); + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(), static_cast(value.size()), + result.data(), required); + return result; +} + +std::string wide_to_utf8(std::wstring_view value) { + if (value.empty()) { + return {}; + } + + const int required = WideCharToMultiByte( + CP_UTF8, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); + if (required <= 0) { + return {}; + } + + std::string result(static_cast(required), '\0'); + WideCharToMultiByte(CP_UTF8, 0, value.data(), static_cast(value.size()), result.data(), + required, nullptr, nullptr); + return result; +} + +DWORD timeout_ms(std::chrono::milliseconds timeout) { + const auto count = std::max(1, timeout.count()); + return static_cast( + std::min(count, std::numeric_limits::max())); +} + +Error map_winhttp_error(DWORD error) { + switch (error) { + case ERROR_WINHTTP_TIMEOUT: + return Error::Timeout; + case ERROR_WINHTTP_INVALID_URL: + case ERROR_WINHTTP_UNRECOGNIZED_SCHEME: + return Error::InvalidUrl; + case ERROR_WINHTTP_SECURE_FAILURE: + case ERROR_WINHTTP_CANNOT_CONNECT: + case ERROR_WINHTTP_CONNECTION_ERROR: + default: + return Error::Network; + } +} + +Result fail_from_last_error(const char* message) { + const DWORD error = GetLastError(); + return { + .error = map_winhttp_error(error), + .message = std::string(message) + " (" + std::to_string(error) + ")", + }; +} + +std::string trim_header_value(std::string_view value) { + while (!value.empty() && (value.front() == ' ' || value.front() == '\t')) { + value.remove_prefix(1); + } + while (!value.empty() && (value.back() == '\r' || value.back() == '\n' || value.back() == ' ' || + value.back() == '\t')) + { + value.remove_suffix(1); + } + return std::string(value); +} + +void parse_headers(std::wstring_view rawHeaders, Response& response) { + size_t start = 0; + bool firstLine = true; + while (start < rawHeaders.size()) { + size_t end = rawHeaders.find(L"\r\n", start); + if (end == std::wstring_view::npos) { + end = rawHeaders.size(); + } + + const std::wstring_view line = rawHeaders.substr(start, end - start); + if (!line.empty() && !firstLine) { + const size_t colon = line.find(L':'); + if (colon != std::wstring_view::npos) { + response.headers.push_back({ + .name = wide_to_utf8(line.substr(0, colon)), + .value = trim_header_value(wide_to_utf8(line.substr(colon + 1))), + }); + } + } + firstLine = false; + + if (end == rawHeaders.size()) { + break; + } + start = end + 2; + } +} + +bool read_status(HINTERNET request, Response& response) { + DWORD statusCode = 0; + DWORD statusCodeSize = sizeof(statusCode); + if (!WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) + { + return false; + } + response.statusCode = static_cast(statusCode); + return true; +} + +bool read_headers(HINTERNET request, Response& response) { + DWORD headerBytes = 0; + WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, + WINHTTP_NO_OUTPUT_BUFFER, &headerBytes, WINHTTP_NO_HEADER_INDEX); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return false; + } + + std::wstring rawHeaders(headerBytes / sizeof(wchar_t), L'\0'); + if (!WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, + rawHeaders.data(), &headerBytes, WINHTTP_NO_HEADER_INDEX)) + { + return false; + } + if (!rawHeaders.empty() && rawHeaders.back() == L'\0') { + rawHeaders.pop_back(); + } + parse_headers(rawHeaders, response); + return true; +} + +} // namespace + +bool available() noexcept { + return true; +} + +Backend backend() noexcept { + return Backend::WinHttp; +} + +const char* backend_name() noexcept { + return "WinHTTP"; +} + +Result get(const Request& request) { + if (request.url.empty()) { + return { + .error = Error::InvalidUrl, + .message = "URL is empty", + }; + } + + std::wstring wideUrl = utf8_to_wide(request.url); + if (wideUrl.empty()) { + return { + .error = Error::InvalidUrl, + .message = "URL is not valid UTF-8", + }; + } + + URL_COMPONENTS components{}; + components.dwStructSize = sizeof(components); + components.dwSchemeLength = static_cast(-1); + components.dwHostNameLength = static_cast(-1); + components.dwUrlPathLength = static_cast(-1); + components.dwExtraInfoLength = static_cast(-1); + if (!WinHttpCrackUrl(wideUrl.c_str(), static_cast(wideUrl.size()), 0, &components)) { + return fail_from_last_error("Failed to parse URL"); + } + if (components.nScheme != INTERNET_SCHEME_HTTPS) { + return { + .error = Error::UnsupportedScheme, + .message = "Only https:// URLs are supported", + }; + } + + const std::wstring host(components.lpszHostName, components.dwHostNameLength); + std::wstring path; + if (components.lpszUrlPath != nullptr && components.dwUrlPathLength > 0) { + path.assign(components.lpszUrlPath, components.dwUrlPathLength); + } + if (components.lpszExtraInfo != nullptr && components.dwExtraInfoLength > 0) { + path.append(components.lpszExtraInfo, components.dwExtraInfoLength); + } + if (path.empty()) { + path = L"/"; + } + + WinHttpHandle session(WinHttpOpen(L"Dusk", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0)); + if (session.handle == nullptr) { + return fail_from_last_error("Failed to create WinHTTP session"); + } + + const DWORD timeout = timeout_ms(request.timeout); + WinHttpSetTimeouts(session, timeout, timeout, timeout, timeout); + + WinHttpHandle connection(WinHttpConnect(session, host.c_str(), components.nPort, 0)); + if (connection.handle == nullptr) { + return fail_from_last_error("Failed to connect"); + } + + WinHttpHandle httpRequest(WinHttpOpenRequest(connection, L"GET", path.c_str(), nullptr, + WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE)); + if (httpRequest.handle == nullptr) { + return fail_from_last_error("Failed to create request"); + } + + DWORD redirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP; + WinHttpSetOption( + httpRequest, WINHTTP_OPTION_REDIRECT_POLICY, &redirectPolicy, sizeof(redirectPolicy)); + DWORD maxRedirects = 5; + WinHttpSetOption(httpRequest, WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS, &maxRedirects, + sizeof(maxRedirects)); + + for (const Header& header : request.headers) { + const std::wstring wideHeader = utf8_to_wide(header.name + ": " + header.value); + if (wideHeader.empty()) { + return { + .error = Error::InvalidUrl, + .message = "Request header is not valid UTF-8", + }; + } + if (!WinHttpAddRequestHeaders(httpRequest, wideHeader.c_str(), + static_cast(wideHeader.size()), WINHTTP_ADDREQ_FLAG_ADD)) + { + return fail_from_last_error("Failed to add request header"); + } + } + + if (!WinHttpSendRequest( + httpRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) + { + return fail_from_last_error("Failed to send request"); + } + if (!WinHttpReceiveResponse(httpRequest, nullptr)) { + return fail_from_last_error("Failed to receive response"); + } + + Response response; + if (!read_status(httpRequest, response)) { + return fail_from_last_error("Failed to read response status"); + } + read_headers(httpRequest, response); + + for (;;) { + DWORD availableBytes = 0; + if (!WinHttpQueryDataAvailable(httpRequest, &availableBytes)) { + return fail_from_last_error("Failed to query response body"); + } + if (availableBytes == 0) { + break; + } + if (availableBytes > request.maxBodyBytes || + response.body.size() > request.maxBodyBytes - availableBytes) + { + return { + .error = Error::TooLarge, + .message = "Response body exceeded the configured limit", + .response = std::move(response), + }; + } + + std::vector buffer(availableBytes); + DWORD bytesRead = 0; + if (!WinHttpReadData(httpRequest, buffer.data(), availableBytes, &bytesRead)) { + return fail_from_last_error("Failed to read response body"); + } + response.body.append(buffer.data(), bytesRead); + } + + return { + .response = std::move(response), + }; +} + +} // namespace dusk::http diff --git a/src/dusk/imgui/ImGuiAudio.cpp b/src/dusk/imgui/ImGuiAudio.cpp index 6bddc6f07c..ce9290efa5 100644 --- a/src/dusk/imgui/ImGuiAudio.cpp +++ b/src/dusk/imgui/ImGuiAudio.cpp @@ -282,7 +282,9 @@ static void ShowAllJAISeqs() { } void dusk::ImGuiMenuTools::ShowAudioDebug() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug)) + { return; } @@ -328,7 +330,9 @@ void dusk::ImGuiMenuTools::ShowAudioDebug() { } void dusk::ImGuiMenuTools::ShowSaveEditor() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor)) + { return; } m_saveEditor.draw(m_showSaveEditor); diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index 2a39ef85eb..0d2168924c 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -10,7 +10,9 @@ namespace dusk { void ImGuiMenuTools::ShowCameraOverlay() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay)) + { return; } @@ -61,16 +63,32 @@ namespace dusk { ImGui::SetTooltip("Cannot enable while paused or during an active event."); } else { ImGui::SetTooltip("Detach camera and fly freely.\n" - "Left stick: move, C-stick: look\n" - "L/R triggers: up/down, Z: fast"); + "WASD/Arrows/Left stick: move, Mouse/C-stick: look\n" + "Ctrl/L: down, Space/R: up, Shift/Z: fast\n" + "Q Key/Y: roll left, R Key/X: roll right"); } } if (eventRunning) { ImGui::EndDisabled(); } + if (!getSettings().game.debugFlyCam) { + ImGui::BeginDisabled(); + } + config::ImGuiCheckbox("Lock Events", getSettings().game.debugFlyCamLockEvents); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + if (!getSettings().game.debugFlyCam) { + ImGui::SetTooltip("Enable Fly Mode first."); + } else { + ImGui::SetTooltip("Freeze game events while flying."); + } + } + if (!getSettings().game.debugFlyCam) { + ImGui::EndDisabled(); + } + ShowCornerContextMenu(m_cameraOverlayCorner, 0); ImGui::End(); } -} \ No newline at end of file +} diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 355ef14450..e933e314e4 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -10,11 +10,9 @@ #include "fmt/format.h" #include "ImGuiConsole.hpp" -#include "dusk/ui/preset.hpp" -#include "dusk/ui/ui.hpp" +#include "ImGuiEngine.hpp" #include "JSystem/JUtility/JUTGamePad.h" #include "SDL3/SDL_mouse.h" -#include "dusk/achievements.h" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/config.hpp" #include "dusk/dusk.h" @@ -22,6 +20,7 @@ #include "dusk/livesplit.h" #include "dusk/main.h" #include "dusk/settings.h" +#include "dusk/ui/ui.hpp" #include "f_pc/f_pc_manager.h" #include "f_pc/f_pc_name.h" #include "m_Do/m_Do_controller_pad.h" @@ -254,15 +253,6 @@ namespace dusk { UpdateSettings(); - AchievementSystem::get().tick(); - while (AchievementSystem::get().hasPendingUnlock()) { - if (getSettings().game.enableAchievementNotifications) { - m_menuTools.notifyAchievement(AchievementSystem::get().consumePendingUnlock()); - } else { - AchievementSystem::get().consumePendingUnlock(); - } - } - if (!fpcM_SearchByName(fpcNm_LOGO_SCENE_e) && (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R)) @@ -271,16 +261,19 @@ namespace dusk { } if (ImGui::IsKeyPressed(ImGuiKey_F11)) { - ImGuiMenuGame::ToggleFullscreen(); + getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); + VISetWindowFullscreen(getSettings().video.enableFullscreen); + config::Save(); } - // if (!dusk::IsGameLaunched) { - // m_preLaunchWindow.draw(); - // } - if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) { - m_isHidden = !m_isHidden; + if (getSettings().backend.enableAdvancedSettings) { + m_isHidden = !m_isHidden; + } else { + m_isHidden = true; + } } + bool showMenu = !m_isHidden; // The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg, @@ -290,25 +283,11 @@ namespace dusk { m_menuGame.draw(); m_menuTools.draw(); - const auto fpsLabel = - fmt::format(FMT_STRING("FPS: {:.2f}\n"), ImGui::GetIO().Framerate); - const auto fpsSize = - ImGui::CalcTextSize(fpsLabel.data(), fpsLabel.data() + fpsLabel.size()); - ImGui::SetCursorPosX( - ImMax(ImGui::GetCursorPosX(), ImGui::GetWindowWidth() - - ImGui::GetStyle().DisplaySafeAreaPadding.x - - fpsSize.x - ImGui::GetStyle().ItemSpacing.x)); - ImGuiStringViewText(fpsLabel); - ImGui::EndMainMenuBar(); } ImGui::PopStyleColor(); if (dusk::IsGameLaunched && !m_isLaunchInitialized) { - AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ? - "3-finger tap to toggle menu"s : - "Press F1 to toggle menu"s, - 4.f); m_isLaunchInitialized = true; if (getSettings().game.liveSplitEnabled) { dusk::speedrun::connectLiveSplit(); @@ -317,8 +296,68 @@ namespace dusk { UpdateDragScroll(); - m_menuGame.windowControllerConfig(); - m_menuGame.windowInputViewer(); + // Show message when Aurora backend is Null + if (aurora_get_backend() == BACKEND_NULL) { + auto& io = ImGui::GetIO(); + ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y)); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowBgAlpha(0.65f); + ImGui::Begin("Pre Launch Window", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGui::NewLine(); + if (ImGuiEngine::duskLogo) { + const auto& windowSize = ImGui::GetWindowSize(); + ImGui::NewLine(); + float iconSize = 150.f; + float width = iconSize * 2.5f; + ImGui::SameLine(windowSize.x / 2 - width + (width / 2)); + ImGui::Image(ImGuiEngine::duskLogo, ImVec2{width, iconSize}); + } else { + ImGui::PushFont(ImGuiEngine::fontExtraLarge); + ImGuiTextCenter("Dusk"); + ImGui::PopFont(); + } + ImGui::PushFont(ImGuiEngine::fontLarge); + ImGuiTextCenter("Failed to initialize any graphics backend"); + const auto& style = ImGui::GetStyle(); + const auto retrySize = ImGui::CalcTextSize("Retry (Auto backend)"); + const auto quitSize = ImGui::CalcTextSize("Quit"); + float buttonsWidth = quitSize.x + style.FramePadding.x * 2.0f; + if constexpr (SupportsProcessRestart) { + buttonsWidth += retrySize.x + style.FramePadding.x * 2.0f + style.ItemSpacing.x; + } +#if DUSK_CAN_OPEN_DATA_FOLDER + const auto openSize = ImGui::CalcTextSize("Open Data Folder"); + buttonsWidth += openSize.x + style.FramePadding.x * 2.0f + style.ItemSpacing.x; +#endif + ImGui::NewLine(); + ImGui::SetCursorPosX( + ImMax(style.WindowPadding.x, (ImGui::GetWindowSize().x - buttonsWidth) * 0.5f)); + if constexpr (SupportsProcessRestart) { + if (ImGui::Button("Retry (Auto backend)")) { + getSettings().backend.graphicsBackend.setValue("auto"); + config::Save(); + RestartRequested = true; + IsRunning = false; + } + ImGui::SameLine(); + } +#if DUSK_CAN_OPEN_DATA_FOLDER + if (ImGui::Button("Open Data Folder")) { + OpenDataFolder(); + } + ImGui::SameLine(); +#endif + if (ImGui::Button("Quit")) { + IsRunning = false; + } + ImGui::PopFont(); + ImGui::End(); + } + + m_menuTools.ShowInputViewer(); m_menuGame.drawSpeedrunTimerOverlay(); if (getSettings().game.liveSplitEnabled) { @@ -342,8 +381,6 @@ namespace dusk { m_menuTools.ShowSaveEditor(); m_menuTools.ShowStateShare(); } - m_menuTools.showAchievementNotification(); - DuskDebugPad(); // temporary, remove later // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. ImGuiIO& io = ImGui::GetIO(); diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 1755c02856..6715846e7b 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -2,14 +2,16 @@ #define DUSK_IMGUI_HPP #include +#include #include #include +#include #include #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" -#include "ImGuiPreLaunchWindow.hpp" +#include "dusk/main.h" #include "imgui.h" union SDL_Event; @@ -24,7 +26,7 @@ public: void PreDraw(); void PostDraw(); - static bool CheckMenuViewToggle(ImGuiKey key, bool& active); + static bool CheckMenuViewToggle(ImGuiKey key, bool& active); void AddToast(std::string_view message, float duration = 3.f); private: @@ -45,7 +47,6 @@ private: std::deque m_toasts; ImGuiMenuGame m_menuGame; - ImGuiPreLaunchWindow m_preLaunchWindow; // Keep always last ImGuiMenuTools m_menuTools; @@ -72,6 +73,24 @@ bool ImGuiButtonCenter(std::string_view text); float ImGuiScale(); } // namespace dusk -void DuskDebugPad(); +#if defined(_WIN32) || \ + (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \ + (defined(__linux__) && !defined(__ANDROID__)) +#define DUSK_CAN_OPEN_DATA_FOLDER 1 + +namespace fs = std::filesystem; + +static void OpenDataFolder() { + const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); +#if defined(_WIN32) + const std::string url = std::string("file:///") + path; +#else + const std::string url = std::string("file://") + path; +#endif + (void)SDL_OpenURL(url.c_str()); +} +#else +#define DUSK_CAN_OPEN_DATA_FOLDER 0 +#endif #endif // DUSK_IMGUI_HPP diff --git a/src/dusk/imgui/ImGuiControllerOverlay.cpp b/src/dusk/imgui/ImGuiControllerOverlay.cpp index dd0a15806c..75637e5e61 100644 --- a/src/dusk/imgui/ImGuiControllerOverlay.cpp +++ b/src/dusk/imgui/ImGuiControllerOverlay.cpp @@ -3,12 +3,11 @@ #include "imgui.h" #include #include "ImGuiConsole.hpp" -#include "ImGuiMenuGame.hpp" #include namespace dusk { - void ImGuiMenuGame::windowInputViewer() { + void ImGuiMenuTools::ShowInputViewer() { if (!m_showInputViewer) { return; } diff --git a/src/dusk/imgui/ImGuiDebugPad.cpp b/src/dusk/imgui/ImGuiDebugPad.cpp deleted file mode 100644 index b1591f1968..0000000000 --- a/src/dusk/imgui/ImGuiDebugPad.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "m_Do/m_Do_controller_pad.h" - -#include "imgui.h" -#include "ImGuiConsole.hpp" - -void DuskDebugPad() { - auto& pad = mDoCPd_c::getCpadInfo(PAD_1); - auto KeyFlag = [&](ImGuiKey key, u32 padFlag) { - if (ImGui::IsKeyDown(key)) - pad.mButtonFlags |= padFlag; - if (ImGui::IsKeyPressed(key)) - pad.mPressedButtonFlags |= padFlag; - - }; - - KeyFlag(ImGuiKey_K, PAD_BUTTON_A); - KeyFlag(ImGuiKey_J, PAD_BUTTON_B); - KeyFlag(ImGuiKey_L, PAD_BUTTON_X); - KeyFlag(ImGuiKey_I, PAD_BUTTON_Y); - KeyFlag(ImGuiKey_H, PAD_BUTTON_START); - KeyFlag(ImGuiKey_O, PAD_TRIGGER_Z); - KeyFlag(ImGuiKey_Keypad8, PAD_BUTTON_UP); - KeyFlag(ImGuiKey_Keypad2, PAD_BUTTON_DOWN); - KeyFlag(ImGuiKey_Keypad6, PAD_BUTTON_RIGHT); - KeyFlag(ImGuiKey_Keypad4, PAD_BUTTON_LEFT); - - if (ImGui::IsKeyDown(ImGuiKey_W)) { - pad.mMainStickPosY = 1.0f; - pad.mMainStickValue = 1.0f; - pad.mMainStickAngle = 0x8000; - } - - if (ImGui::IsKeyDown(ImGuiKey_S)) { - pad.mMainStickPosY = -1.0f; - pad.mMainStickValue = 1.0f; - pad.mMainStickAngle = 0; - } - - if (ImGui::IsKeyDown(ImGuiKey_D)) { - pad.mMainStickPosX = 1.0f; - pad.mMainStickValue = 1.0f; - pad.mMainStickAngle = 0x4000; - } - - if (ImGui::IsKeyDown(ImGuiKey_A)) { - pad.mMainStickPosX = -1.0f; - pad.mMainStickValue = 1.0f; - pad.mMainStickAngle = -0x4000; - } - - if (ImGui::IsKeyDown(ImGuiKey_Q)) { - pad.mTriggerLeft = 1.0; - pad.mTrigLockL = 1; - pad.mHoldLockL = 1; - } - if (ImGui::IsKeyDown(ImGuiKey_E)) { - pad.mTriggerRight = 1.0; - pad.mTrigLockR = 1; - pad.mHoldLockR = 1; - } -} diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp index 4b6a7fb531..3e742de853 100644 --- a/src/dusk/imgui/ImGuiEngine.cpp +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -219,7 +219,7 @@ void ImGuiEngine_AddTextures() { ImGuiEngine::orgIcon = AddTexture("org-icon.png"); } if (ImGuiEngine::duskLogo == 0) { - ImGuiEngine::duskLogo = AddTexture("logo.png"); + ImGuiEngine::duskLogo = AddTexture("logo-mascot.png"); } } } // namespace dusk diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index 9928690b9b..5c110821f6 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -4,8 +4,9 @@ #include #include #include -#include #include +#include +#include struct duskImguiEventFlagEntry { uint8_t byteIndex; @@ -842,2282 +843,2408 @@ inline const MultiBitEventFlag duskImguiSwappedU16Events[] = { { 0xfd, "Rupees owed to Trill" }, }; -struct EventAreaFlags -{ - uint8_t byteIndex; - uint8_t bitIndex; - uint16_t flagID; - std::string description; +enum class AreaFlagType { Item, Switch, Tbox }; + +struct AreaFlagInd { + constexpr AreaFlagInd() noexcept = default; + constexpr explicit AreaFlagInd(uint16_t areaFlag) noexcept; + constexpr AreaFlagInd(AreaFlagType _type, int _flag) noexcept : type(_type), flagID(_flag) {} + AreaFlagType type; + int flagID; }; -inline EventAreaFlags eventAreaFlagsAG[] = -{ - { 0x00, 0x80, 0x0080, "Ooccoo Map Flag" }, - { 0x00, 0x40, 0x0040, "fourth small chest epic spinner room" }, - { 0x00, 0x20, 0x0020, "third small chest epic spinner room" }, - { 0x00, 0x10, 0x0010, "first small chest epic spinner room" }, - { 0x00, 0x08, 0x0008, "second small chest epic spinner room" }, - { 0x00, 0x04, 0x0004, "PoH first big chest epic spinner room" }, - { 0x00, 0x02, 0x0002, "small chest first west room" }, - { 0x00, 0x01, 0x0001, "small key big chest elevator room B1" }, - { 0x01, 0x80, 0x0180, "small key big chest first room" }, - { 0x01, 0x20, 0x0120, "small key small chest fouth east room" }, - { 0x01, 0x10, 0x0110, "big key chest" }, - { 0x01, 0x08, 0x0108, "PoH right big chest main room" }, - { 0x01, 0x04, 0x0104, "map left big chest main room" }, - { 0x01, 0x02, 0x0102, "west small chest in second west room" }, - { 0x01, 0x01, 0x0101, "north east small chest in second west room" }, - { 0x02, 0x08, 0x0208, "Spinner big chest" }, - { 0x03, 0x40, 0x0340, "small key small chest first east room B1" }, - { 0x03, 0x20, 0x0320, "small key big chest second east room 2F" }, - { 0x03, 0x10, 0x0310, "compass big chest second east room 2F" }, - { 0x03, 0x08, 0x0308, "big chest first west room" }, - { 0x08, 0x80, 0x0880, "killed second poe (triggers flame getting lit cs)" }, - { 0x08, 0x40, 0x0840, "killed first poe" }, - { 0x08, 0x08, 0x0808, "open gate to spinner in mini-boss room cs" }, - { 0x08, 0x04, 0x0804, "unlock exit in mini-boss room (despawns mini-boss)" }, - { 0x08, 0x01, 0x0801, "unlocked boss door" }, - { 0x09, 0x10, 0x0910, "started pulling chain in second east room 1F (stays set)" }, - { 0x09, 0x04, 0x0904, "stairs to lower east room appeared in main room" }, - { 0x09, 0x02, 0x0902, "risen tracks on pillar before boss" }, - { 0x09, 0x01, 0x0901, "unlocked door in second west room" }, - { 0x0A, 0x10, 0x0A10, "killed second poe (duplicate)" }, - { 0x0A, 0x02, 0x0A02, "Tiny bugs spawn in first room small key area (duplicate)" }, - { 0x0A, 0x01, 0x0A01, "Tiny bugs spawn in first room small key area" }, - { 0x0B, 0x80, 0x0B80, "stairs to lower west room appeared in main room cs" }, - { 0x0B, 0x20, 0x0B20, "turn walls in third room 2B cs" }, - { 0x0B, 0x10, 0x0B10, "turn walls in third room 2B" }, - { 0x0B, 0x08, 0x0B08, "open gates in first room" }, - { 0x0B, 0x04, 0x0B04, "open gates in first room cs" }, - { 0x0B, 0x01, 0x0B01, "Stallord Phase 2" }, - { 0x0C, 0x80, 0x0C80, "killed third poe (triggers flame getting lit cs)" }, - { 0x0C, 0x40, 0x0C40, "Main Hall Dig Spot" }, - { 0x0C, 0x01, 0x0C01, "turned walls in first east room (stays set)" }, - { 0x0D, 0x02, 0x0D02, "turned slab in first east room B1 (stays set)" }, - { 0x0E, 0x10, 0x0E10, "Intro Cutscene" }, - { 0x0F, 0x80, 0x0F80, "unlocked door in second east room 2F" }, - { 0x0F, 0x40, 0x0F40, "open poe door once all poe flames are present (removes poe bodies)" }, - { 0x0F, 0x20, 0x0F20, "poe flame top left present" }, - { 0x0F, 0x10, 0x0F10, "poe flame bottom right present" }, - { 0x0F, 0x08, 0x0F08, "poe flame top right present" }, - { 0x0F, 0x04, 0x0F04, "poe flame bottom left present" }, - { 0x0F, 0x02, 0x0F02, "killed fourth poe (triggers flame getting lit cs)" }, - { 0x0F, 0x01, 0x0F01, "flame from third poe leaving lantern cs" }, - { 0x10, 0x40, 0x1040, "killed third poe (duplicate)" }, - { 0x10, 0x20, 0x1020, "flame from second poe leaving lantern cs" }, - { 0x10, 0x10, 0x1010, "open walls in third east room" }, - { 0x10, 0x08, 0x1008, "unlocked door in elevator room 2B" }, - { 0x10, 0x04, 0x1004, "unlocked door in first room" }, - { 0x10, 0x02, 0x1002, "killed stalfos in second west room" }, - { 0x11, 0x80, 0x1180, "killed gibdo in first east room B1" }, - { 0x11, 0x20, 0x1120, "reach boss door (unset once you enter)" }, - { 0x11, 0x04, 0x1104, "killed third poe (duplicate)" }, - { 0x11, 0x02, 0x1102, "unlock door in second room" }, - { 0x11, 0x01, 0x1101, "lit right torch in second room" }, - { 0x12, 0x80, 0x1280, "lit left torch in second room" }, - { 0x12, 0x40, 0x1240, "close spinner slot for walls in third room 2B" }, - { 0x12, 0x20, 0x1220, "unlocked door in first east room 1F" }, - { 0x12, 0x08, 0x1208, "risen tracks on pillar before boss cs" }, - { 0x12, 0x04, 0x1204, "pushed block in first west room" }, - { 0x12, 0x01, 0x1201, "taken down the cube in the second east room 1F" }, - { 0x13, 0x80, 0x1380, "placed cube at the right spot in the second east room 1F" }, - { 0x13, 0x40, 0x1340, "unlock door in fouth east room" }, - { 0x13, 0x20, 0x1320, "close poe door (unsets after lighting torches)" }, - { 0x13, 0x08, 0x1308, "main room poes taking flames cs" }, - { 0x14, 0x10, 0x1410, "explored first room" }, - { 0x14, 0x08, 0x1408, "open exit door in boss room" }, - { 0x15, 0x80, 0x1580, "Midna Text after defeating boss" }, - { 0x15, 0x08, 0x1508, "killed first stalfos in room before mini-boss" }, - { 0x15, 0x04, 0x1504, "killed second stalfos in room before mini-boss" }, - { 0x15, 0x02, 0x1502, "killed third stalfos in room before mini-boss" }, - { 0x15, 0x01, 0x1501, "extend platform to exit in boss room" }, - { 0x16, 0x80, 0x1680, "open gate to spinner in mini-boss room cs" }, - { 0x16, 0x40, 0x1640, "open gate to spinner in mini-boss room" }, - { 0x16, 0x10, 0x1610, "open wall in third west room cs (unset once you leave)" }, - { 0x16, 0x08, 0x1608, "pulled chain in main room" }, - { 0x16, 0x04, 0x1604, "pulled the chain in first room (triggers cs)" }, - { 0x16, 0x02, 0x1602, "open wall in third west room" }, - { 0x17, 0x40, 0x1740, "killed gibdos in third east room" }, - { 0x17, 0x20, 0x1720, "Ooccoo Rescued" }, - { 0x17, 0x10, 0x1710, "opened gates in room before mini-boss" }, - { 0x17, 0x08, 0x1708, "killed fourth poe (duplicate)" }, - { 0x17, 0x02, 0x1702, "dig spot in third east room" }, - { 0x17, 0x01, 0x1701, "Spinner big chest (set after)" }, +constexpr auto byteIndexToAreaFlagType(uint8_t byteIndex) -> AreaFlagType { + if (byteIndex < 2 * sizeof(u32)) { + return AreaFlagType::Tbox; + } else if (byteIndex < 6 * sizeof(u32)) { + return AreaFlagType::Switch; + } else { + return AreaFlagType::Item; + } +}; + +constexpr auto byteIndexToAreaByteIndex(uint8_t byteIndex) -> uint8_t { + if (byteIndex < 2 * sizeof(u32)) { + return byteIndex; + } else if (byteIndex < 6 * sizeof(u32)) { + return byteIndex - 2 * sizeof(u32); + } else { + return byteIndex - 6 * sizeof(u32); + } +}; + +constexpr auto byteIndexToAreaU32Index(uint8_t byteIndex) -> uint8_t { + return byteIndexToAreaByteIndex(byteIndex) / sizeof(u32); +}; + +constexpr auto eventFlagToAreaFlagFormat(uint16_t eventFlag) -> AreaFlagInd { + constexpr auto makeMask = [](uint8_t size) -> uint16_t { return (1 << size) - 1; }; + constexpr size_t areaIndexSize = 5; + + const auto byteInd = eventFlag >> 8; + const auto eventU32Ind = byteIndexToAreaU32Index(byteInd); + const auto relativeByteInd = byteIndexToAreaByteIndex(byteInd); + // if we're looking at 0x580, that would be byte 5, and check if 0x80 is set on that byte + // the event flags are structured differently than area flags + // B is byte index, b is the flag mask to check + // event flags are BBBBBBBB bbbbbbbb + // for area flags, they check bitIndex, not mask, i is index + // also area uses u32 index, not byte index + // area flags are BBBiiiii + // so we need to convert from bit mask to index + // also our byte index has to become a u32 index + + // dividing byte index by sizeof(u32) gets us the u32 index + // but in big endian, the first byte is the highest order byte of the u32 + // so we skip 24 bytes for the first byte, 16 for the second, etc + // essentially (3 - (x % 4)), reversing the modulus, 0=3, 1=2 + const auto bitsToSkip = 8 * ((sizeof(u32) - 1) - (relativeByteInd % sizeof(u32))); + const int areaFlag = ((eventU32Ind) << areaIndexSize) | + ((std::countr_zero(eventFlag) + bitsToSkip) & makeMask(areaIndexSize)); + + return AreaFlagInd{byteIndexToAreaFlagType(byteInd), areaFlag}; +} + +constexpr AreaFlagInd::AreaFlagInd(uint16_t eventFlag) noexcept { + *this = eventFlagToAreaFlagFormat(eventFlag); +} + +struct AreaFlagMultibit { + constexpr AreaFlagMultibit() noexcept = default; + + constexpr explicit AreaFlagMultibit(uint16_t eventFlagMask) noexcept { + const auto byteIndex = eventFlagMask >> 8; + type = byteIndexToAreaFlagType(byteIndex); + index = byteIndexToAreaU32Index(byteIndex); + mask = (eventFlagMask & 0xff) + << (8 * ((sizeof(u32) - 1) - (byteIndexToAreaByteIndex(byteIndex) % sizeof(u32)))); + shift = std::countr_zero(mask); + } + + constexpr explicit AreaFlagMultibit(uint16_t eventFlagMaskHigh, uint16_t eventFlagMaskLow) { + const uint8_t highByteIndex = eventFlagMaskHigh >> 8; + const uint8_t lowByteIndex = eventFlagMaskLow >> 8; + + assert(byteIndexToAreaU32Index(highByteIndex) == byteIndexToAreaU32Index(lowByteIndex)); + const auto byteIndex = byteIndexToAreaU32Index(highByteIndex); + + assert(highByteIndex + 1 == lowByteIndex); + + const uint8_t eventHighMask = eventFlagMaskHigh & 0xff; + const uint8_t eventLowMask = eventFlagMaskLow & 0xff; + assert(eventHighMask != 0); + assert(eventLowMask != 0); + + assert(eventHighMask & 1); + assert(eventLowMask & 0x80); + + const uint16_t combinedMask = (eventHighMask << 8) | eventLowMask; + + const uint32_t finalMask = + combinedMask << (8 * ((sizeof(u32) - 1) - + (byteIndexToAreaByteIndex(lowByteIndex) % sizeof(u32)))); + + assert(std::has_single_bit( + static_cast(finalMask) + (1 << std::countr_zero(finalMask)))); + + type = byteIndexToAreaFlagType(highByteIndex); + index = byteIndexToAreaU32Index(highByteIndex); + mask = finalMask; + shift = std::countr_zero(finalMask); + } + + constexpr AreaFlagMultibit(AreaFlagType _type, uint32_t _mask, uint8_t _index) noexcept + : type(_type), + mask(_mask), + shift(std::countr_zero(_mask)), + index(_index) {} + + uint32_t mask; + uint8_t index; + uint8_t shift; + AreaFlagType type; +}; + +struct EventAreaFlags { + uint8_t byteIndex; + uint8_t bitIndex; + AreaFlagInd flag; + std::string description; + constexpr uint16_t GetFlagID() const { return (byteIndex << 8) | bitIndex; } +}; + +constexpr AreaFlagInd test{0x0b80}; +static_assert(test.type == AreaFlagType::Switch); +static_assert((test.flagID >> 5) == 0); +static_assert((test.flagID & 0x1f) == 7); + +inline EventAreaFlags eventAreaFlagsAG[] = { + { 0x00, 0x80, AreaFlagInd{0x0080}, "Ooccoo Map Flag" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "fourth small chest epic spinner room" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "third small chest epic spinner room" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "first small chest epic spinner room" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "second small chest epic spinner room" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "PoH first big chest epic spinner room" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "small chest first west room" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "small key big chest elevator room B1" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "small key big chest first room" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "small key small chest fouth east room" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "big key chest" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "PoH right big chest main room" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "map left big chest main room" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "west small chest in second west room" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "north east small chest in second west room" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "Spinner big chest" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "small key small chest first east room B1" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "small key big chest second east room 2F" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "compass big chest second east room 2F" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "big chest first west room" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "killed second poe (triggers flame getting lit cs)" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "killed first poe" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "open gate to spinner in mini-boss room cs" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "unlock exit in mini-boss room (despawns mini-boss)" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "unlocked boss door" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "started pulling chain in second east room 1F (stays set)" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "stairs to lower east room appeared in main room" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "risen tracks on pillar before boss" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "unlocked door in second west room" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "killed second poe (duplicate)" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "Tiny bugs spawn in first room small key area (duplicate)" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "Tiny bugs spawn in first room small key area" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "stairs to lower west room appeared in main room cs" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "turn walls in third room 2B cs" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "turn walls in third room 2B" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "open gates in first room" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "open gates in first room cs" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "Stallord Phase 2" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "killed third poe (triggers flame getting lit cs)" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "Main Hall Dig Spot" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "turned walls in first east room (stays set)" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "turned slab in first east room B1 (stays set)" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "Intro Cutscene" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "unlocked door in second east room 2F" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "open poe door once all poe flames are present (removes poe bodies)" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "poe flame top left present" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "poe flame bottom right present" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "poe flame top right present" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "poe flame bottom left present" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "killed fourth poe (triggers flame getting lit cs)" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "flame from third poe leaving lantern cs" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "killed third poe (duplicate)" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "flame from second poe leaving lantern cs" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "open walls in third east room" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "unlocked door in elevator room 2B" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "unlocked door in first room" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "killed stalfos in second west room" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "killed gibdo in first east room B1" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "reach boss door (unset once you enter)" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "killed third poe (duplicate)" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "unlock door in second room" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "lit right torch in second room" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "lit left torch in second room" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "close spinner slot for walls in third room 2B" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "unlocked door in first east room 1F" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "risen tracks on pillar before boss cs" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "pushed block in first west room" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "taken down the cube in the second east room 1F" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "placed cube at the right spot in the second east room 1F" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "unlock door in fouth east room" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "close poe door (unsets after lighting torches)" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "main room poes taking flames cs" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "explored first room" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "open exit door in boss room" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "Midna Text after defeating boss" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "killed first stalfos in room before mini-boss" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "killed second stalfos in room before mini-boss" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "killed third stalfos in room before mini-boss" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "extend platform to exit in boss room" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "open gate to spinner in mini-boss room cs" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "open gate to spinner in mini-boss room" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "open wall in third west room cs (unset once you leave)" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "pulled chain in main room" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "pulled the chain in first room (triggers cs)" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "open wall in third west room" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "killed gibdos in third east room" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "Ooccoo Rescued" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "opened gates in room before mini-boss" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "killed fourth poe (duplicate)" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "dig spot in third east room" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "Spinner big chest (set after)" }, }; inline EventAreaFlags eventAreaFlagsCastleTown[] = { - { 0x03, 0x02, 0x0302, "small chest on doctor's balcony" }, - { 0x06, 0x10, 0x0610, "tear of light next to Telma's bar" }, - { 0x08, 0x80, 0x0880, "killed poe in Jovani's house (set if you dig into the house)" }, - { 0x08, 0x04, 0x0804, "explored 3nd room Jovani-Sewers " }, - { 0x08, 0x02, 0x0802, "explored 2nd room Jovani-Sewers " }, - { 0x08, 0x01, 0x0801, "?" }, - { 0x09, 0x80, 0x0980, "?" }, - { 0x09, 0x40, 0x0940, "?" }, - { 0x09, 0x20, 0x0920, "?" }, - { 0x09, 0x02, 0x0902, "intro cs twlight" }, - { 0x09, 0x01, 0x0901, "midna text after listening to Telma and Ilia spirits during twilight" }, - { 0x0A, 0x80, 0x0A80, "midna breaking castle barrier cs" }, - { 0x0A, 0x20, 0x0A20, "warp you to Lanayru spring (trigger twilight end)" }, - { 0x0A, 0x10, 0x0A10, "fan girl text next to star tent" }, - { 0x0A, 0x04, 0x0A04, "star tent intro cs" }, - { 0x0A, 0x02, 0x0A02, "invisible wall behind doctor gone" }, - { 0x0A, 0x01, 0x0A01, "?" }, - { 0x0B, 0x80, 0x0B80, "water is back in town (twilight)" }, - { 0x0B, 0x40, 0x0B40, "explored east alley that leads south" }, - { 0x0B, 0x20, 0x0B20, "star tent has double clawshot mini-game" }, - { 0x0B, 0x10, 0x0B10, "explored area with star tent" }, - { 0x0B, 0x08, 0x0B08, "explored alley with entrance to Jovani's house" }, - { 0x0B, 0x04, 0x0B04, "explored alley with entrance to agitha's house" }, - { 0x0B, 0x02, 0x0B02, "explored area with entrance to Telma's bar" }, - { 0x0B, 0x01, 0x0B01, "STAR 1 Completed" }, - { 0x0D, 0x04, 0x0D04, "map marker hero's shade" }, - { 0x0E, 0x10, 0x0E10, "malo mart posters on shop" }, - { 0x0E, 0x08, 0x0E08, "magic armor bought malo mart" }, - { 0x0E, 0x04, 0x0E04, "?" }, - { 0x0E, 0x02, 0x0E02, "enter Telma's bar from top intro cs" }, - { 0x0E, 0x01, 0x0E01, "first right door to castle pushed once (default)" }, - { 0x0F, 0x80, 0x0F80, "first left door to castle pushed once (default)" }, - { 0x0F, 0x40, 0x0F40, "first right door to castle pushed twice" }, - { 0x0F, 0x20, 0x0F20, "first right door to castle half closed" }, - { 0x0F, 0x10, 0x0F10, "first left door to castle closed" }, - { 0x0F, 0x08, 0x0F08, "first left door to castle pushed twice" }, - { 0x0F, 0x04, 0x0F04, "Jovani's house intro cs" }, - { 0x0F, 0x02, 0x0F02, "Jovani text after killing poe" }, - { 0x0F, 0x01, 0x0F01, "open path to sewers (Jovani's house)" }, - { 0x10, 0x80, 0x1080, "?" }, - { 0x16, 0x80, 0x1680, "killed light bug next to Telma's bar" }, - { 0x17, 0x08, 0x1708, "Gengle free (Jovani's house)" }, - { 0x17, 0x04, 0x1704, "Midna opens map to look for the last light bug" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "small chest on doctor's balcony" }, + { 0x06, 0x10, AreaFlagInd{0x0610}, "tear of light next to Telma's bar" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "killed poe in Jovani's house (set if you dig into the house)" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "explored 3nd room Jovani-Sewers " }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "explored 2nd room Jovani-Sewers " }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "?" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "?" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "?" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "?" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "intro cs twlight" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "midna text after listening to Telma and Ilia spirits during twilight" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "midna breaking castle barrier cs" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "warp you to Lanayru spring (trigger twilight end)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "fan girl text next to star tent" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "star tent intro cs" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "invisible wall behind doctor gone" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "?" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "water is back in town (twilight)" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "explored east alley that leads south" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "star tent has double clawshot mini-game" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "explored area with star tent" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "explored alley with entrance to Jovani's house" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "explored alley with entrance to agitha's house" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "explored area with entrance to Telma's bar" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "STAR 1 Completed" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "map marker hero's shade" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "malo mart posters on shop" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "magic armor bought malo mart" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "?" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "enter Telma's bar from top intro cs" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "first right door to castle pushed once (default)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "first left door to castle pushed once (default)" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "first right door to castle pushed twice" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "first right door to castle half closed" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "first left door to castle closed" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "first left door to castle pushed twice" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "Jovani's house intro cs" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "Jovani text after killing poe" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "open path to sewers (Jovani's house)" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "?" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "killed light bug next to Telma's bar" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "Gengle free (Jovani's house)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "Midna opens map to look for the last light bug" }, }; inline EventAreaFlags eventAreaFlagsCitS[] = { - { 0x00, 0x08, 0x0008, "south east underwater big chest outside shop" }, - { 0x00, 0x04, 0x0004, "big chest east wing second room 2F" }, - { 0x00, 0x02, 0x0002, "big chest west wing main room 2F" }, - { 0x00, 0x01, 0x0001, "small chest main room 4F outside" }, - { 0x01, 0x80, 0x0180, "small chest west wing north room 2F" }, - { 0x01, 0x40, 0x0140, "center small chest west wing main room 1F" }, - { 0x01, 0x20, 0x0120, "small chest west wing main room B1" }, - { 0x01, 0x10, 0x0110, "north east small chest west wing main room 1F" }, - { 0x01, 0x08, 0x0108, "small chest east wing second room 1F" }, - { 0x01, 0x04, 0x0104, "small chest east wing second room 2F" }, - { 0x01, 0x02, 0x0102, "big chest ouside north wing" }, - { 0x02, 0x80, 0x0280, "small chest west wing main room 3F" }, - { 0x02, 0x40, 0x0240, "small chest main room 3F inside" }, - { 0x02, 0x20, 0x0220, "big key chest" }, - { 0x02, 0x10, 0x0210, "big chest main room 4F outside" }, - { 0x02, 0x08, 0x0208, "small chest west wing main room 2F" }, - { 0x02, 0x02, 0x0202, "PoH big chest west wing main room 3F" }, - { 0x03, 0x80, 0x0380, "small chest west wing north room 3F" }, - { 0x03, 0x40, 0x0340, "PoH big chest west wing north room 2F" }, - { 0x03, 0x20, 0x0320, "small key big chest west wing main room 1F" }, - { 0x03, 0x10, 0x0310, "compass big chest east wing first room B1" }, - { 0x03, 0x08, 0x0308, "south west underwater big chest outside shop" }, - { 0x03, 0x04, 0x0304, "map big chest east wing fourth room 1F" }, - { 0x03, 0x01, 0x0301, "double clawshot big chest east wing fifth room B3" }, - { 0x08, 0x80, 0x0880, "turn on wind in east wing second room 2F" }, - { 0x08, 0x40, 0x0840, "open gate in east wing second room 2F" }, - { 0x08, 0x20, 0x0820, "explored west wing main room 1F (unset if you enter main room)" }, - { 0x08, 0x10, 0x0810, "explored east wing first room 1F (unset if you enter main room)" }, - { 0x08, 0x04, 0x0804, "killed big baba west wing north room 1F" }, - { 0x08, 0x02, 0x0802, "double clawshot big chest east wing fifth room B3 (set after)" }, - { 0x08, 0x01, 0x0801, "west bridge broken" }, - { 0x09, 0x80, 0x0980, "east wing fifth room B3 intro cs" }, - { 0x09, 0x40, 0x0940, "open gate in east wing third room 2F" }, - { 0x09, 0x20, 0x0920, "spawn baba serpants under east bridge" }, - { 0x09, 0x08, 0x0908, "extended east bridge (spinner slot needs to be closed)" }, - { 0x09, 0x04, 0x0904, "extended west bridge (spinner slot needs to be closed)" }, - { 0x09, 0x02, 0x0902, "small key big chest west wing main room 1F (set after)" }, - { 0x0A, 0x80, 0x0A80, "explored main room 1F" }, - { 0x0A, 0x20, 0x0A20, "turn on wind in east wing third room 2F" }, - { 0x0A, 0x10, 0x0A10, "open door in east wing third room 1F" }, - { 0x0A, 0x04, 0x0A04, "fan on ceiling of main room active" }, - { 0x0A, 0x02, 0x0A02, "open gate in east wing fourth room 1F" }, - { 0x0B, 0x80, 0x0B80, "unlock boss door" }, - { 0x0B, 0x40, 0x0B40, "unlock east bridge door 1F" }, - { 0x0B, 0x08, 0x0B08, "east bridge extended (close east spinner slot)" }, - { 0x0B, 0x04, 0x0B04, "west bridge extended (close west spinner slot)" }, - { 0x0B, 0x02, 0x0B02, "open gate outside shop" }, - { 0x0C, 0x08, 0x0C08, "north wing main room intro cs" }, - { 0x0C, 0x04, 0x0C04, "east wing fourth room 2F intro cs" }, - { 0x0C, 0x02, 0x0C02, "went beyond first gate outside shop intro cs" }, - { 0x0C, 0x01, 0x0C01, "Intro CS" }, - { 0x0D, 0x80, 0x0D80, "killed left dynalfos in east wing third room 1F" }, - { 0x0D, 0x40, 0x0D40, "killed right dynalfos in east wing third room 1F" }, - { 0x0D, 0x20, 0x0D20, "?" }, - { 0x0D, 0x10, 0x0D10, "west bridge destroyed cs (triggered when you have a key)" }, - { 0x0D, 0x08, 0x0D08, "killed helmasaurus in main room 1F" }, - { 0x0D, 0x04, 0x0D04, "west bridge extented cs" }, - { 0x0D, 0x02, 0x0D02, "east bridge extented cs" }, - { 0x0E, 0x01, 0x0E01, "small key big chest west wing main room 1F (set after)" }, - { 0x0F, 0x80, 0x0F80, "exited dungeon with midna warp" }, - { 0x0F, 0x40, 0x0F40, "exited dungeon with midna warp" }, - { 0x0F, 0x20, 0x0F20, "save promt after boss" }, - { 0x0F, 0x10, 0x0F10, "open gate in west wing main room B2" }, - { 0x0F, 0x08, 0x0F08, "killed left aeralfos in north wing main room 1F" }, - { 0x0F, 0x04, 0x0F04, "killed right aeralfos in north wing main room 1F" }, - { 0x0F, 0x02, 0x0F02, "open gate in east wing fifth room B3" }, - { 0x0F, 0x01, 0x0F01, "stop fan in east wing fifth room B3" }, - { 0x10, 0x80, 0x1080, "killed third baba serpant under east bridge" }, - { 0x10, 0x10, 0x1010, "killed third tile worm in east wing second room 1F" }, - { 0x10, 0x08, 0x1008, "killed second tile worm in east wing second room 1F" }, - { 0x10, 0x04, 0x1004, "killed first tile worm in east wing second room 1F" }, - { 0x11, 0x20, 0x1120, "killed poe in main room 4F outside" }, - { 0x11, 0x10, 0x1110, "killed poe in west wing main room 2F" }, - { 0x12, 0x20, 0x1220, "small key big chest west wing main room 1F (set after)" }, - { 0x12, 0x02, 0x1202, "latched on to first pillar in east wing first room B2" }, - { 0x13, 0x40, 0x1340, "open door in east wing fifth room B3" }, - { 0x13, 0x10, 0x1310, "?" }, - { 0x15, 0x10, 0x1510, "activate north path fan " }, - { 0x17, 0x40, 0x1740, "killed east dynalfos in main room 3F outside" }, - { 0x17, 0x20, 0x1720, "killed north dynalfos in main room 3F outside" }, - { 0x17, 0x10, 0x1710, "killed dynalfos in west wing north room 3F" }, - { 0x17, 0x08, 0x1708, "killed first baba serpent in path to east spinner slot" }, - { 0x17, 0x04, 0x1704, "killed second baba serpent in path to east spinner slot" }, - { 0x17, 0x02, 0x1702, "killed first baba serpant under east bridge" }, - { 0x17, 0x01, 0x1701, "killed second baba serpant under east bridge" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "south east underwater big chest outside shop" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "big chest east wing second room 2F" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "big chest west wing main room 2F" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "small chest main room 4F outside" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "small chest west wing north room 2F" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "center small chest west wing main room 1F" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "small chest west wing main room B1" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "north east small chest west wing main room 1F" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "small chest east wing second room 1F" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "small chest east wing second room 2F" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "big chest ouside north wing" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "small chest west wing main room 3F" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "small chest main room 3F inside" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "big key chest" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "big chest main room 4F outside" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "small chest west wing main room 2F" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "PoH big chest west wing main room 3F" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small chest west wing north room 3F" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "PoH big chest west wing north room 2F" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "small key big chest west wing main room 1F" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "compass big chest east wing first room B1" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "south west underwater big chest outside shop" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "map big chest east wing fourth room 1F" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "double clawshot big chest east wing fifth room B3" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "turn on wind in east wing second room 2F" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "open gate in east wing second room 2F" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "explored west wing main room 1F (unset if you enter main room)" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "explored east wing first room 1F (unset if you enter main room)" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "killed big baba west wing north room 1F" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "double clawshot big chest east wing fifth room B3 (set after)" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "west bridge broken" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "east wing fifth room B3 intro cs" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "open gate in east wing third room 2F" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "spawn baba serpants under east bridge" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "extended east bridge (spinner slot needs to be closed)" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "extended west bridge (spinner slot needs to be closed)" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "small key big chest west wing main room 1F (set after)" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "explored main room 1F" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "turn on wind in east wing third room 2F" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "open door in east wing third room 1F" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "fan on ceiling of main room active" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "open gate in east wing fourth room 1F" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "unlock boss door" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "unlock east bridge door 1F" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "east bridge extended (close east spinner slot)" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "west bridge extended (close west spinner slot)" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "open gate outside shop" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "north wing main room intro cs" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "east wing fourth room 2F intro cs" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "went beyond first gate outside shop intro cs" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "Intro CS" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "killed left dynalfos in east wing third room 1F" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "killed right dynalfos in east wing third room 1F" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "?" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "west bridge destroyed cs (triggered when you have a key)" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "killed helmasaurus in main room 1F" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "west bridge extented cs" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "east bridge extented cs" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "small key big chest west wing main room 1F (set after)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "exited dungeon with midna warp" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "exited dungeon with midna warp" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "save promt after boss" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "open gate in west wing main room B2" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "killed left aeralfos in north wing main room 1F" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "killed right aeralfos in north wing main room 1F" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "open gate in east wing fifth room B3" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "stop fan in east wing fifth room B3" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "killed third baba serpant under east bridge" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "killed third tile worm in east wing second room 1F" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "killed second tile worm in east wing second room 1F" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "killed first tile worm in east wing second room 1F" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "killed poe in main room 4F outside" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "killed poe in west wing main room 2F" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "small key big chest west wing main room 1F (set after)" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "latched on to first pillar in east wing first room B2" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "open door in east wing fifth room B3" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "?" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "activate north path fan " }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "killed east dynalfos in main room 3F outside" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "killed north dynalfos in main room 3F outside" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "killed dynalfos in west wing north room 3F" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "killed first baba serpent in path to east spinner slot" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "killed second baba serpent in path to east spinner slot" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "killed first baba serpant under east bridge" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "killed second baba serpant under east bridge" }, }; inline EventAreaFlags eventAreaFlagsCoO[] = { - { 0x03, 0x01, 0x0301, "big chest Lanayru Ice Puzzle" }, - { 0x04, 0x80, 0x0480, "big chest right right right path Eldin Long Cave" }, - { 0x04, 0x40, 0x0440, "big chest right right left right path Eldin Long Cave" }, - { 0x04, 0x20, 0x0420, "small chest left right path Eldin Long Cave" }, - //{ 0x08, 0x80, 0x0880, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x40, 0x0840, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x20, 0x0820, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x10, 0x0810, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x08, 0x0808, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x04, 0x0804, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x02, 0x0802, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x08, 0x01, 0x0801, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x09, 0x80, 0x0980, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x09, 0x40, 0x0940, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x09, 0x20, 0x0920, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x09, 0x10, 0x0910, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, - //{ 0x09, 0x04, 0x0904, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x09, 0x02, 0x0902, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x09, 0x01, 0x0901, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0A, 0x80, 0x0A80, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0A, 0x20, 0x0A20, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0A, 0x10, 0x0A10, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0A, 0x08, 0x0A08, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0A, 0x04, 0x0A04, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0B, 0x08, 0x0B08, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0B, 0x04, 0x0B04, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0B, 0x02, 0x0B02, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, - //{ 0x0B, 0x01, 0x0B01, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, - { 0x0D, 0x10, 0x0D10, "broke right ice blocking first doorway in Lanayru Ice Puzzle" }, - { 0x0D, 0x08, 0x0D08, "broke left ice blocking first doorway in Lanayru Ice Puzzle" }, - { 0x0D, 0x04, 0x0D04, "open fourth gate in Lanayru Ice Puzzle" }, - { 0x0D, 0x02, 0x0D02, "open third gate in Lanayru Ice Puzzle" }, - { 0x0D, 0x01, 0x0D01, "open second gate in Lanayru Ice Puzzle" }, - { 0x0E, 0x80, 0x0E80, "open first gate in Lanayru Ice Puzzle" }, - //{ 0x0E, 0x40, 0x0E40, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x20, 0x0E20, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x10, 0x0E10, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x08, 0x0E08, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x04, 0x0E04, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x02, 0x0E02, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0E, 0x01, 0x0E01, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x80, 0x0F80, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x40, 0x0F40, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x20, 0x0F20, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x10, 0x0F10, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x08, 0x0F08, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x04, 0x0F04, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x02, 0x0F02, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, - //{ 0x0F, 0x01, 0x0F01, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, - { 0x10, 0x80, 0x1080, "spawn big chest right right left right path Eldin Long Cave" }, - { 0x10, 0x40, 0x1040, "lit torch 3 (right right right path) Eldin Long Cave" }, - { 0x13, 0x80, 0x1380, "killed poe on floor 44 in Cave of Ordeals" }, - { 0x13, 0x40, 0x1340, "killed poe on floor 33 in Cave of Ordeals" }, - { 0x13, 0x20, 0x1320, "killed poe on floor 17 in Cave of Ordeals" }, - { 0x13, 0x08, 0x1308, "Cave of Ordeals intro cs" }, - { 0x13, 0x04, 0x1304, "obtained fairy's tears (if unset, you can get it even if you already have some) (also spawns that extra darknut on floor 49)" }, - { 0x13, 0x02, 0x1302, "open floor 1 door in Cave of Ordeals cs" }, - { 0x13, 0x01, 0x1301, "broke ice on floor 21 in Cave of Ordeals" }, - { 0x14, 0x40, 0x1440, "explored section 2 right right left right path Eldin Long Cave" }, - { 0x14, 0x20, 0x1420, "explored section 1 right right left right path Eldin Long Cave" }, - { 0x14, 0x10, 0x1410, "explored section 2 right right left left path Eldin Long Cave" }, - { 0x14, 0x08, 0x1408, "explored section 1 right right left left path Eldin Long Cave" }, - { 0x14, 0x04, 0x1404, "explored section 3 right right left path Eldin Long Cave" }, - { 0x14, 0x02, 0x1402, "explored section 2 right right left path Eldin Long Cave" }, - { 0x14, 0x01, 0x1401, "explored section 1 right right left path Eldin Long Cave" }, - { 0x15, 0x80, 0x1580, "explored section 2 right right right path Eldin Long Cave" }, - { 0x15, 0x40, 0x1540, "explored section 1 right right right path Eldin Long Cave" }, - { 0x15, 0x20, 0x1520, "explored section 3 right right path Eldin Long Cave" }, - { 0x15, 0x10, 0x1510, "explored section 2 right right path Eldin Long Cave" }, - { 0x15, 0x08, 0x1508, "explored section 1 right right path Eldin Long Cave" }, - { 0x15, 0x04, 0x1504, "explored section 1 right left path Eldin Long Cave" }, - { 0x15, 0x02, 0x1502, "explored section 6 right path Eldin Long Cave" }, - { 0x15, 0x01, 0x1501, "explored section 5 right path Eldin Long Cave" }, - { 0x16, 0x80, 0x1680, "explored section 4 right path Eldin Long Cave" }, - { 0x16, 0x40, 0x1640, "explored section 3 right path Eldin Long Cave" }, - { 0x16, 0x20, 0x1620, "explored section 2 right path Eldin Long Cave" }, - { 0x16, 0x10, 0x1610, "explored section 1 right path Eldin Long Cave" }, - { 0x16, 0x08, 0x1608, "explored section 2 left right path Eldin Long Cave" }, - { 0x16, 0x04, 0x1604, "explored section 1 right right path Eldin Long Cave" }, - { 0x16, 0x02, 0x1602, "explored section 2 left left path Eldin Long Cave" }, - { 0x16, 0x01, 0x1601, "explored section 1 right right path Eldin Long Cave" }, - { 0x17, 0x80, 0x1780, "explored section 2 left path Eldin Long Cave" }, - { 0x17, 0x40, 0x1740, "explored section 1 right path Eldin Long Cave" }, - { 0x17, 0x20, 0x1720, "explored section 2 Eldin Long Cave" }, - { 0x17, 0x10, 0x1710, "explored section 1 Eldin Long Cave" }, - { 0x17, 0x08, 0x1708, "lit torch 2 (right path) Eldin Long Cave" }, - { 0x17, 0x04, 0x1704, "lit left torch right right left right path Eldin Long Cave" }, - { 0x17, 0x02, 0x1702, "lit right torch right right left right path Eldin Long Cave" }, - { 0x17, 0x01, 0x1701, "killed poe right right left left path Eldin Long Cave" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "big chest Lanayru Ice Puzzle" }, + { 0x04, 0x80, AreaFlagInd{0x0480}, "big chest right right right path Eldin Long Cave" }, + { 0x04, 0x40, AreaFlagInd{0x0440}, "big chest right right left right path Eldin Long Cave" }, + { 0x04, 0x20, AreaFlagInd{0x0420}, "small chest left right path Eldin Long Cave" }, + //{ 0x08, 0x80, AreaFlagInd{0x0880}, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x40, AreaFlagInd{0x0840}, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x20, AreaFlagInd{0x0820}, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x10, AreaFlagInd{0x0810}, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x08, AreaFlagInd{0x0808}, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x04, AreaFlagInd{0x0804}, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x02, AreaFlagInd{0x0802}, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x01, AreaFlagInd{0x0801}, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x80, AreaFlagInd{0x0980}, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x40, AreaFlagInd{0x0940}, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x20, AreaFlagInd{0x0920}, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x10, AreaFlagInd{0x0910}, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x04, AreaFlagInd{0x0904}, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x09, 0x02, AreaFlagInd{0x0902}, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x09, 0x01, AreaFlagInd{0x0901}, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x80, AreaFlagInd{0x0A80}, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x20, AreaFlagInd{0x0A20}, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x10, AreaFlagInd{0x0A10}, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x08, AreaFlagInd{0x0A08}, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x04, AreaFlagInd{0x0A04}, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x08, AreaFlagInd{0x0B08}, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x04, AreaFlagInd{0x0B04}, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x02, AreaFlagInd{0x0B02}, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x01, AreaFlagInd{0x0B01}, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "broke right ice blocking first doorway in Lanayru Ice Puzzle" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "broke left ice blocking first doorway in Lanayru Ice Puzzle" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "open fourth gate in Lanayru Ice Puzzle" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "open third gate in Lanayru Ice Puzzle" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "open second gate in Lanayru Ice Puzzle" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "open first gate in Lanayru Ice Puzzle" }, + //{ 0x0E, 0x40, AreaFlagInd{0x0E40}, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x20, AreaFlagInd{0x0E20}, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x10, AreaFlagInd{0x0E10}, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x08, AreaFlagInd{0x0E08}, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x04, AreaFlagInd{0x0E04}, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x02, AreaFlagInd{0x0E02}, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x01, AreaFlagInd{0x0E01}, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x80, AreaFlagInd{0x0F80}, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x40, AreaFlagInd{0x0F40}, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x20, AreaFlagInd{0x0F20}, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x10, AreaFlagInd{0x0F10}, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x08, AreaFlagInd{0x0F08}, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x04, AreaFlagInd{0x0F04}, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x02, AreaFlagInd{0x0F02}, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x01, AreaFlagInd{0x0F01}, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "spawn big chest right right left right path Eldin Long Cave" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "lit torch 3 (right right right path) Eldin Long Cave" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "killed poe on floor 44 in Cave of Ordeals" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "killed poe on floor 33 in Cave of Ordeals" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "killed poe on floor 17 in Cave of Ordeals" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "Cave of Ordeals intro cs" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "obtained fairy's tears (if unset, you can get it even if you already have some) (also spawns that extra darknut on floor 49)" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "open floor 1 door in Cave of Ordeals cs" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "broke ice on floor 21 in Cave of Ordeals" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "explored section 2 right right left right path Eldin Long Cave" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "explored section 1 right right left right path Eldin Long Cave" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "explored section 2 right right left left path Eldin Long Cave" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "explored section 1 right right left left path Eldin Long Cave" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "explored section 3 right right left path Eldin Long Cave" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "explored section 2 right right left path Eldin Long Cave" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "explored section 1 right right left path Eldin Long Cave" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "explored section 2 right right right path Eldin Long Cave" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "explored section 1 right right right path Eldin Long Cave" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "explored section 3 right right path Eldin Long Cave" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "explored section 2 right right path Eldin Long Cave" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "explored section 1 right right path Eldin Long Cave" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "explored section 1 right left path Eldin Long Cave" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "explored section 6 right path Eldin Long Cave" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "explored section 5 right path Eldin Long Cave" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "explored section 4 right path Eldin Long Cave" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "explored section 3 right path Eldin Long Cave" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "explored section 2 right path Eldin Long Cave" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "explored section 1 right path Eldin Long Cave" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "explored section 2 left right path Eldin Long Cave" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "explored section 1 right right path Eldin Long Cave" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "explored section 2 left left path Eldin Long Cave" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "explored section 1 right right path Eldin Long Cave" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "explored section 2 left path Eldin Long Cave" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "explored section 1 right path Eldin Long Cave" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "explored section 2 Eldin Long Cave" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "explored section 1 Eldin Long Cave" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "lit torch 2 (right path) Eldin Long Cave" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "lit left torch right right left right path Eldin Long Cave" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "lit right torch right right left right path Eldin Long Cave" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "killed poe right right left left path Eldin Long Cave" }, }; inline EventAreaFlags eventAreaFlagsEldin[] = { - { 0x00, 0x01, 0x0001, "Big chest from torches graveyard" }, - { 0x01, 0x80, 0x0180, "Small chest in the inn" }, - { 0x01, 0x40, 0x0140, "PoH big chest death mountain archer alcove" }, - { 0x01, 0x20, 0x0120, "PoH big chest underwater behind spring" }, - { 0x01, 0x10, 0x0110, "Big chest next to watch tower" }, - { 0x01, 0x04, 0x0104, "?" }, - { 0x01, 0x02, 0x0102, "Big chest watch house" }, - { 0x01, 0x01, 0x0101, "tear of light death mountain hot spring water" }, - { 0x02, 0x80, 0x0280, "tear of light next to howling stone death mountain " }, - { 0x02, 0x40, 0x0240, "tear of light death mountain base" }, - { 0x02, 0x10, 0x0210, "tear of light sancuary basement" }, - { 0x02, 0x08, 0x0208, "tear of light Barnes storage house" }, - { 0x02, 0x04, 0x0204, "tear of light watch tower" }, - { 0x02, 0x02, 0x0202, "tear of light at Malo mart" }, - { 0x02, 0x01, 0x0201, "tear of light inn fire room" }, - { 0x03, 0x80, 0x0380, "tear of light Barnes shop" }, - { 0x03, 0x40, 0x0340, "tear of light graveyard" }, - { 0x03, 0x20, 0x0320, "tear of light Barnes storage house" }, - { 0x03, 0x10, 0x0310, "tear of light Barnes storage house" }, - { 0x03, 0x08, 0x0308, "tear of light sancuary basement" }, - { 0x03, 0x04, 0x0304, "tear of light sancuary basement" }, - { 0x03, 0x02, 0x0302, "tear of light ant house" }, - { 0x03, 0x01, 0x0301, "tear of light inn back room" }, - { 0x08, 0x80, 0x0880, "Kakariko Village Portal" }, - { 0x08, 0x40, 0x0840, "kakariko shadow beasts barrier appears (unset after fight)" }, - { 0x08, 0x20, 0x0820, "DM big rock fell" }, - { 0x08, 0x10, 0x0810, "done midna jumps 4 death mountain (hot spring water)" }, - { 0x08, 0x08, 0x0808, "done midna jumps 3 death mountain (1st floor)" }, - { 0x08, 0x04, 0x0804, "killed death mountain shadow beasts cs (unset later?)" }, - { 0x08, 0x01, 0x0801, "done midna jumps 1 death mountain (entrance)" }, - { 0x09, 0x80, 0x0980, "Malo mart has banners inside" }, - { 0x09, 0x40, 0x0940, "DM proper human intro CS (Map marker GM)" }, - { 0x09, 0x20, 0x0920, "Death Mountain Portal" }, - { 0x09, 0x10, 0x0910, "death mountain dark beasts barrier appears" }, - { 0x09, 0x08, 0x0908, "?" }, - { 0x09, 0x04, 0x0904, "?" }, - { 0x09, 0x02, 0x0902, "killed HV bublins (unset when cats spawn)" }, - { 0x09, 0x01, 0x0901, "killed light bug death mountain hot spring water" }, - { 0x0A, 0x80, 0x0A80, "killed light bug next to howling stone death mountain " }, - { 0x0A, 0x40, 0x0A40, "killed light bug death mountain base" }, - { 0x0A, 0x20, 0x0A20, "trigger twilight end cs (vessel of light filled) (Hot Spring Water Present on map)" }, - { 0x0A, 0x10, 0x0A10, "killed light bug sancuary basement" }, - { 0x0A, 0x04, 0x0A04, "killed light bug watch tower" }, - { 0x0A, 0x02, 0x0A02, "killed light bug malo mart" }, - { 0x0A, 0x01, 0x0A01, "killed light bug inn fire room" }, - { 0x0B, 0x80, 0x0B80, "killed light bug Barnes shop" }, - { 0x0B, 0x40, 0x0B40, "killed light bug graveyard" }, - { 0x0B, 0x08, 0x0B08, "killed light bug sancuary basement" }, - { 0x0B, 0x04, 0x0B04, "killed light bug sancuary basement" }, - { 0x0B, 0x02, 0x0B02, "killed light bug ant house" }, - { 0x0B, 0x01, 0x0B01, "killed light bug inn bedroom" }, - { 0x0C, 0x80, 0x0C80, "saw light bug enter Barnes storage house twilight cs" }, - { 0x0C, 0x40, 0x0C40, "malo mart sells hawkeye (moves potion to the right) (set when starting bow mini-game)" }, - { 0x0C, 0x20, 0x0C20, "malo mart sells arrows" }, - { 0x0C, 0x10, 0x0C10, "broke sanctuary roof patch during twilight (duplicate)" }, - { 0x0C, 0x08, 0x0C08, "box moved ant house (spawns light bug)" }, - { 0x0C, 0x04, 0x0C04, "Unknown crashes if rocks are pushed" }, - { 0x0C, 0x02, 0x0C02, "malo mart hylian shield bought" }, - { 0x0C, 0x01, 0x0C01, "ant house explored" }, - { 0x0D, 0x80, 0x0D80, "entered sanctuary from roof during twilight" }, - { 0x0D, 0x40, 0x0D40, "enter Barnes shop through the window in twilight cs" }, - { 0x0D, 0x20, 0x0D20, "light bug comes out of box in ant house cs" }, - { 0x0D, 0x10, 0x0D10, "spawn PoH cat mini game hidden village" }, - { 0x0D, 0x08, 0x0D08, "malo mart hawkeye sold out (needs to be set for arrows to show up)" }, - { 0x0D, 0x04, 0x0D04, "lit all torches in sanctuary twilight (opens basment)" }, - { 0x0D, 0x02, 0x0D02, "light bug in inn fireplace jumps out cs" }, - { 0x0D, 0x01, 0x0D01, "lit inn fireplace" }, - { 0x0E, 0x80, 0x0E80, "knocked down dresser in Barnes shop twilight cs" }, - { 0x0E, 0x40, 0x0E40, "?" }, - { 0x0E, 0x20, 0x0E20, "? (malo mart explored)" }, - { 0x0E, 0x10, 0x0E10, "lit west torch in sanctuary twilight" }, - { 0x0E, 0x08, 0x0E08, "lit north east torch in sanctuary twilight" }, - { 0x0E, 0x04, 0x0E04, "lit east torch in sanctuary twilight" }, - { 0x0E, 0x02, 0x0E02, "lit north west torch in sanctuary twilight" }, - { 0x0F, 0x80, 0x0F80, "broke ant house roof patch (duplicate)" }, - { 0x0F, 0x40, 0x0F40, "moved death mountain rock to exit" }, - { 0x0F, 0x20, 0x0F20, "Eldin spirit talks to Link after getting kakariko Portal cs" }, - { 0x0F, 0x10, 0x0F10, "broke ant house roof patch" }, - { 0x0F, 0x08, 0x0F08, "broke window of Barnes shop twilight" }, - { 0x0F, 0x04, 0x0F04, "broke sanctuary roof patch during twilight" }, - { 0x0F, 0x02, 0x0F02, "Renado talks to Link after trying to go up death mountain trail" }, - { 0x0F, 0x01, 0x0F01, "killed kakariko shadow beasts cs" }, - { 0x10, 0x80, 0x1080, "Killed poe watch tower" }, - { 0x10, 0x40, 0x1040, "Killed poe Barnes storage house" }, - { 0x10, 0x20, 0x1020, "blown up rock underwater to lake hylia from graveward" }, - { 0x10, 0x10, 0x1010, "Graveyard intro cs" }, - { 0x10, 0x08, 0x1008, "explored zora tombstone area" }, - { 0x10, 0x04, 0x1004, "broke floor patch in graveyard during twilight" }, - { 0x10, 0x02, 0x1002, "Killed poe death mountain" }, - { 0x10, 0x01, 0x1001, "Killed poe graveyard center" }, - { 0x11, 0x80, 0x1180, "Killed poe graveyard tombstone" }, - { 0x11, 0x40, 0x1140, "gorons in kakariko hot spring water gone" }, - { 0x11, 0x20, 0x1120, "Map Marker Sanctuary" }, - { 0x11, 0x08, 0x1108, "Midna text after DM big rock fell" }, - { 0x11, 0x04, 0x1104, "done midna jumps 2 death mountain (base floor)" }, - { 0x11, 0x02, 0x1102, "death mountain proper intro cs twilight" }, - { 0x11, 0x01, 0x1101, "moved death mountain rock to hot spring water" }, - { 0x12, 0x80, 0x1280, "sanctuary basement canon room explored" }, - { 0x12, 0x40, 0x1240, "done Midna jumps in sanctuary basement" }, - { 0x12, 0x20, 0x1220, "Midna text before Midna jumps in sanctuary basement" }, - { 0x12, 0x10, 0x1210, "sanctuary twilight cs" }, - { 0x12, 0x08, 0x1208, "killed right shadow bulblin inside inn twilight" }, - { 0x12, 0x04, 0x1204, "killed left shadow bulblin inside inn twilight" }, - { 0x12, 0x02, 0x1202, "killed top shadow bulblin inside inn twilight" }, - { 0x12, 0x01, 0x1201, "enter central room of inn during twilight cs" }, - { 0x13, 0x80, 0x1380, "sanctuary basement hallway to canon explored" }, - { 0x13, 0x40, 0x1340, "Malo mart shield on counter (requires reload)" }, - { 0x13, 0x20, 0x1320, "Kakariko intro cs" }, - { 0x13, 0x10, 0x1310, "blown up rocks on kakariko cliff PoH" }, - { 0x13, 0x08, 0x1308, "Blown up rock to secret passage to back of spring (updates map)" }, - { 0x13, 0x04, 0x1304, "Barnes storage house not blown up (unset once you enter) (twilight)" }, - { 0x13, 0x02, 0x1302, "Barnes storage house blew up cs (also changes map)" }, - { 0x13, 0x01, 0x1301, "Killed poe hidden village" }, - { 0x14, 0x80, 0x1480, "Midna text after sanctuary twilight cs" }, - { 0x14, 0x20, 0x1420, "light bug comes out of dresser in Barnes shop twilight" }, - { 0x14, 0x10, 0x1410, "GM save prompt" }, - { 0x14, 0x08, 0x1408, "Barnes sells Bombs" }, - { 0x14, 0x04, 0x1404, "midna text after shad leaves canon room" }, - { 0x14, 0x02, 0x1402, "Hero's shade map marker" }, - { 0x14, 0x01, 0x1401, "done midna jumps to top of sanctuary (also unlocks it)" }, - { 0x15, 0x80, 0x1580, "blown up rock underwater behind spring" }, - { 0x15, 0x40, 0x1540, "malo mart sells red potion on right slot" }, - { 0x15, 0x20, 0x1520, "beat bow mini-game" }, - { 0x15, 0x10, 0x1510, "malo mart sells red potion on left slot (default)" }, - { 0x15, 0x08, 0x1508, "explored bedroom in the inn" }, - { 0x15, 0x04, 0x1504, "explored central room in the inn" }, - { 0x15, 0x02, 0x1502, "blown up right rock underwater zora tombstone area" }, - { 0x15, 0x01, 0x1501, "midna text after charging dominion rod" }, - { 0x16, 0x80, 0x1680, "Goron lets you enter elevator in sumo hall" }, - { 0x16, 0x40, 0x1640, "Midna text after blowing up Barnes storage house" }, - { 0x16, 0x20, 0x1620, "hit third target in bow mini-game" }, - { 0x16, 0x10, 0x1610, "saved Colin cs (malo mart now open)" }, - { 0x16, 0x04, 0x1604, "Midna text after meeting the kids after twilight" }, - { 0x16, 0x02, 0x1602, "Started Rutela escort" }, - { 0x16, 0x01, 0x1601, "hit second target in bow mini-game" }, - { 0x17, 0x80, 0x1780, "hit first target in bow mini-game" }, - { 0x17, 0x40, 0x1740, "rock to zora tombstone gone + Barnes sells water bombs" }, - { 0x17, 0x20, 0x1720, "Followed Rutela to graveyard" }, - { 0x17, 0x10, 0x1710, "death mountain path intro cs twilight" }, - { 0x17, 0x08, 0x1708, "owl statue possessed cs (sanctuary basement)" }, - { 0x17, 0x04, 0x1704, "done midna jumps ant house (also unlocks it)" }, - { 0x17, 0x02, 0x1702, "Impaz in her house (hidden village)" }, - { 0x17, 0x01, 0x1701, "can't transform in hidden village (if bit 2 is set you can)" }, - { 0x1A, 0x40, 0x1A40, "picked up rupees from right rock underwater zora tombstone area" }, - { 0x1A, 0x20, 0x1A20, "picked up rupees from rock underwater behind spring" }, - { 0x1A, 0x10, 0x1A10, "Free standing PoH kakariko cliff" }, - { 0x1A, 0x08, 0x1A08, "Free standing PoH cat mini game hidden village" }, - { 0x1A, 0x04, 0x1A04, "picked up silver rupee from bell above sanctuary" }, - { 0x1A, 0x02, 0x1A02, "picked up yellow rupee in box secret passage to spring" }, - { 0x1A, 0x01, 0x1A01, "picked up blue rupee in box secret passage to spring" }, - { 0x1B, 0x80, 0x1B80, "picked up yellow rupee in box next to kakariko hot spring water" }, - { 0x1B, 0x40, 0x1B40, "picked up yellow rupee behind dresser inn bedroom" }, - { 0x1B, 0x20, 0x1B20, "picked up red rupee in box on platform above ant house" }, - { 0x1B, 0x10, 0x1B10, "picked up blue rupee behind dresser inn 2nd floor" }, - { 0x1B, 0x08, 0x1B08, "picked up yellow rupee 1 on leadge of top of death montain" }, - { 0x1B, 0x04, 0x1B04, "picked up yellow rupee 2 on leadge of top of death montain" }, - { 0x1B, 0x02, 0x1B02, "picked up yellow rupee 3 on leadge of top of death montain" }, - { 0x1B, 0x01, 0x1B01, "picked up rupee in death montain in rock below pipe (need BaC and rang)" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "Big chest from torches graveyard" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "Small chest in the inn" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "PoH big chest death mountain archer alcove" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "PoH big chest underwater behind spring" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "Big chest next to watch tower" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "?" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "Big chest watch house" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "tear of light death mountain hot spring water" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "tear of light next to howling stone death mountain " }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "tear of light death mountain base" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "tear of light sancuary basement" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "tear of light Barnes storage house" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "tear of light watch tower" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "tear of light at Malo mart" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "tear of light inn fire room" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "tear of light Barnes shop" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "tear of light graveyard" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "tear of light Barnes storage house" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "tear of light Barnes storage house" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "tear of light sancuary basement" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "tear of light sancuary basement" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "tear of light ant house" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "tear of light inn back room" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "Kakariko Village Portal" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "kakariko shadow beasts barrier appears (unset after fight)" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "DM big rock fell" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "done midna jumps 4 death mountain (hot spring water)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "done midna jumps 3 death mountain (1st floor)" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "killed death mountain shadow beasts cs (unset later?)" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "done midna jumps 1 death mountain (entrance)" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "Malo mart has banners inside" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "DM proper human intro CS (Map marker GM)" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Death Mountain Portal" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "death mountain dark beasts barrier appears" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "?" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "?" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "killed HV bublins (unset when cats spawn)" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "killed light bug death mountain hot spring water" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "killed light bug next to howling stone death mountain " }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "killed light bug death mountain base" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "trigger twilight end cs (vessel of light filled) (Hot Spring Water Present on map)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "killed light bug sancuary basement" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "killed light bug watch tower" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "killed light bug malo mart" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "killed light bug inn fire room" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "killed light bug Barnes shop" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "killed light bug graveyard" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "killed light bug sancuary basement" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "killed light bug sancuary basement" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "killed light bug ant house" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "killed light bug inn bedroom" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "saw light bug enter Barnes storage house twilight cs" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "malo mart sells hawkeye (moves potion to the right) (set when starting bow mini-game)" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "malo mart sells arrows" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "broke sanctuary roof patch during twilight (duplicate)" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "box moved ant house (spawns light bug)" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "Unknown crashes if rocks are pushed" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "malo mart hylian shield bought" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "ant house explored" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "entered sanctuary from roof during twilight" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "enter Barnes shop through the window in twilight cs" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "light bug comes out of box in ant house cs" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "spawn PoH cat mini game hidden village" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "malo mart hawkeye sold out (needs to be set for arrows to show up)" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "lit all torches in sanctuary twilight (opens basment)" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "light bug in inn fireplace jumps out cs" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "lit inn fireplace" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "knocked down dresser in Barnes shop twilight cs" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "?" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "? (malo mart explored)" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "lit west torch in sanctuary twilight" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "lit north east torch in sanctuary twilight" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "lit east torch in sanctuary twilight" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "lit north west torch in sanctuary twilight" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "broke ant house roof patch (duplicate)" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "moved death mountain rock to exit" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "Eldin spirit talks to Link after getting kakariko Portal cs" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "broke ant house roof patch" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "broke window of Barnes shop twilight" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "broke sanctuary roof patch during twilight" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "Renado talks to Link after trying to go up death mountain trail" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "killed kakariko shadow beasts cs" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "Killed poe watch tower" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "Killed poe Barnes storage house" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "blown up rock underwater to lake hylia from graveward" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "Graveyard intro cs" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "explored zora tombstone area" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "broke floor patch in graveyard during twilight" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "Killed poe death mountain" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "Killed poe graveyard center" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "Killed poe graveyard tombstone" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "gorons in kakariko hot spring water gone" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "Map Marker Sanctuary" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "Midna text after DM big rock fell" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "done midna jumps 2 death mountain (base floor)" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "death mountain proper intro cs twilight" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "moved death mountain rock to hot spring water" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "sanctuary basement canon room explored" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "done Midna jumps in sanctuary basement" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "Midna text before Midna jumps in sanctuary basement" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "sanctuary twilight cs" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "killed right shadow bulblin inside inn twilight" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "killed left shadow bulblin inside inn twilight" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "killed top shadow bulblin inside inn twilight" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "enter central room of inn during twilight cs" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "sanctuary basement hallway to canon explored" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "Malo mart shield on counter (requires reload)" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "Kakariko intro cs" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "blown up rocks on kakariko cliff PoH" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "Blown up rock to secret passage to back of spring (updates map)" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "Barnes storage house not blown up (unset once you enter) (twilight)" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "Barnes storage house blew up cs (also changes map)" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "Killed poe hidden village" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "Midna text after sanctuary twilight cs" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "light bug comes out of dresser in Barnes shop twilight" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "GM save prompt" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "Barnes sells Bombs" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "midna text after shad leaves canon room" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "Hero's shade map marker" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "done midna jumps to top of sanctuary (also unlocks it)" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "blown up rock underwater behind spring" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "malo mart sells red potion on right slot" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "beat bow mini-game" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "malo mart sells red potion on left slot (default)" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "explored bedroom in the inn" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "explored central room in the inn" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "blown up right rock underwater zora tombstone area" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "midna text after charging dominion rod" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "Goron lets you enter elevator in sumo hall" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "Midna text after blowing up Barnes storage house" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "hit third target in bow mini-game" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "saved Colin cs (malo mart now open)" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "Midna text after meeting the kids after twilight" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "Started Rutela escort" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "hit second target in bow mini-game" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "hit first target in bow mini-game" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "rock to zora tombstone gone + Barnes sells water bombs" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "Followed Rutela to graveyard" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "death mountain path intro cs twilight" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "owl statue possessed cs (sanctuary basement)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "done midna jumps ant house (also unlocks it)" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "Impaz in her house (hidden village)" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "can't transform in hidden village (if bit 2 is set you can)" }, + { 0x1A, 0x40, AreaFlagInd{0x1A40}, "picked up rupees from right rock underwater zora tombstone area" }, + { 0x1A, 0x20, AreaFlagInd{0x1A20}, "picked up rupees from rock underwater behind spring" }, + { 0x1A, 0x10, AreaFlagInd{0x1A10}, "Free standing PoH kakariko cliff" }, + { 0x1A, 0x08, AreaFlagInd{0x1A08}, "Free standing PoH cat mini game hidden village" }, + { 0x1A, 0x04, AreaFlagInd{0x1A04}, "picked up silver rupee from bell above sanctuary" }, + { 0x1A, 0x02, AreaFlagInd{0x1A02}, "picked up yellow rupee in box secret passage to spring" }, + { 0x1A, 0x01, AreaFlagInd{0x1A01}, "picked up blue rupee in box secret passage to spring" }, + { 0x1B, 0x80, AreaFlagInd{0x1B80}, "picked up yellow rupee in box next to kakariko hot spring water" }, + { 0x1B, 0x40, AreaFlagInd{0x1B40}, "picked up yellow rupee behind dresser inn bedroom" }, + { 0x1B, 0x20, AreaFlagInd{0x1B20}, "picked up red rupee in box on platform above ant house" }, + { 0x1B, 0x10, AreaFlagInd{0x1B10}, "picked up blue rupee behind dresser inn 2nd floor" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "picked up yellow rupee 1 on leadge of top of death montain" }, + { 0x1B, 0x04, AreaFlagInd{0x1B04}, "picked up yellow rupee 2 on leadge of top of death montain" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "picked up yellow rupee 3 on leadge of top of death montain" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up rupee in death montain in rock below pipe (need BaC and rang)" }, }; inline EventAreaFlags eventAreaFlagsFaron[] = { - { 0x00, 0x80, 0x0080, "small chest in lantern cave" }, - { 0x00, 0x40, 0x0040, "HP Chest Coro-Mist shortcut" }, - { 0x00, 0x20, 0x0020, "big chest mist area" }, - { 0x00, 0x10, 0x0010, "small chest mist area trunk" }, - { 0x00, 0x08, 0x0008, "small chest mist area next to key cave" }, - { 0x00, 0x04, 0x0004, "PoH chest key cave" }, - { 0x00, 0x01, 0x0001, "Small key cave key chest" }, - { 0x01, 0x80, 0x0180, "Dig Tear #1" }, - { 0x01, 0x20, 0x0120, "Final Tear #1" }, - { 0x01, 0x10, 0x0110, "Final Tear #2" }, - { 0x01, 0x04, 0x0104, "Wall Tear #1 (Mist Area)" }, - { 0x01, 0x02, 0x0102, "Wall Tear #2 (Mist Area)" }, - { 0x02, 0x40, 0x0240, "Tree Tear #1" }, - { 0x02, 0x20, 0x0220, "Tree Tear #2" }, - { 0x02, 0x10, 0x0210, "Tree Tear #3" }, - { 0x02, 0x08, 0x0208, "Gate Tear #1" }, - { 0x02, 0x02, 0x0202, "Coro Tear #1 (inside)" }, - { 0x02, 0x01, 0x0201, "Dig Tear #2" }, - { 0x03, 0x40, 0x0340, "Tear #2" }, - { 0x03, 0x20, 0x0320, "Gate Tear #2" }, - { 0x03, 0x10, 0x0310, "Coro Tear #2 (inside)" }, - { 0x03, 0x02, 0x0302, "Tear #1" }, - { 0x03, 0x01, 0x0301, "Coro Tear (outisde)" }, - { 0x04, 0x80, 0x0480, "Yellow Rupee Chest (N-Faron)" }, - { 0x08, 0x80, 0x0880, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, - { 0x08, 0x40, 0x0840, "explored section with south entrance of mist area (gets unset)" }, - { 0x08, 0x10, 0x0810, "went up east section of mist area after midna jump 1 twilight" }, - { 0x08, 0x08, 0x0808, "S Faron warp twilight fences fall cs" }, - { 0x08, 0x04, 0x0804, "Sky character under owl statue" }, - { 0x08, 0x02, 0x0802, "midna jump 1 mist area (duplicate)" }, - { 0x08, 0x01, 0x0801, "unlock midna jump 1 mist area" }, - { 0x09, 0x80, 0x0980, "Coro spirits talk after killing light bugs in his house" }, - { 0x09, 0x40, 0x0940, "midna jump to Coro's house" }, - { 0x09, 0x20, 0x0920, "Map marker owl statue" }, - { 0x09, 0x10, 0x0910, "opened mist area gate to N faron" }, - { 0x09, 0x08, 0x0908, "lit torch 2 in lantern cave" }, - { 0x09, 0x04, 0x0904, "Talked to Midna next to the deku babas before Coro" }, - { 0x09, 0x02, 0x0902, "Rescued Monkey from Puppets" }, - { 0x09, 0x01, 0x0901, "dug behind Coro gate in twilight" }, - { 0x0A, 0x80, 0x0A80, "took Midna back s warp fight" }, - { 0x0A, 0x40, 0x0A40, "S warp shadow beast revive cs" }, - { 0x0A, 0x20, 0x0A20, "trigger twilight end cs (vessel of light filled)" }, - { 0x0A, 0x10, 0x0A10, "unlocked Coro gate" }, - { 0x0A, 0x08, 0x0A08, "Explored path to sacred grove" }, - { 0x0A, 0x04, 0x0A04, "burned cobweb in front of forest temple" }, - { 0x0A, 0x02, 0x0A02, "see spirit in front of FT twilight cs" }, - { 0x0A, 0x01, 0x0A01, "enter twilight cs" }, - { 0x0B, 0x40, 0x0B40, "talked to the light spirit in twilight" }, - { 0x0B, 0x20, 0x0B20, "saw light bugs dig underground mist area exit twilight" }, - { 0x0B, 0x10, 0x0B10, "Blown up rock next to Coro" }, - { 0x0B, 0x08, 0x0B08, "n warp fight fences appear cs" }, - { 0x0B, 0x04, 0x0B04, "North Faron Portal" }, - { 0x0B, 0x02, 0x0B02, "FT save prompt" }, - { 0x0C, 0x80, 0x0C80, "got lantern back after monkey follow" }, - { 0x0C, 0x40, 0x0C40, "saw light bugs move inside Coro's house cs" }, - { 0x0C, 0x20, 0x0C20, "in monkey follow (gets unset afterwards)" }, - { 0x0C, 0x10, 0x0C10, "Trill lets you shop" }, - { 0x0C, 0x04, 0x0C04, "killed left bokoblin before Trill after twilight" }, - { 0x0C, 0x02, 0x0C02, "killed right bokoblin before Trill after twilight" }, - { 0x0C, 0x01, 0x0C01, "explored section 6 in lantern cave" }, - { 0x0D, 0x80, 0x0D80, "explored section 5 in lantern cave" }, - { 0x0D, 0x40, 0x0D40, "explored section 4 in lantern cave" }, - { 0x0D, 0x20, 0x0D20, "explored section 3 in lantern cave" }, - { 0x0D, 0x10, 0x0D10, "explored section 2 in lantern cave" }, - { 0x0D, 0x08, 0x0D08, "explored section 1 in lantern cave" }, - { 0x0D, 0x04, 0x0D04, "got Coro key from Coro" }, - { 0x0D, 0x02, 0x0D02, "?" }, - { 0x0D, 0x01, 0x0D01, "killed right bokoblin next to Talo's cage" }, - { 0x0E, 0x80, 0x0E80, "killed left bokoblin next to Talo's cage" }, - { 0x0E, 0x40, 0x0E40, "broke Talo's cage" }, - { 0x0E, 0x20, 0x0E20, "killed both bokoblins next to Talo's cage" }, - { 0x0E, 0x08, 0x0E08, "enter Faron intro cs" }, - { 0x0E, 0x04, 0x0E04, "lit Coro's soup" }, - { 0x0E, 0x02, 0x0E02, "saved Talo cs" }, - { 0x0E, 0x01, 0x0E01, "see light spirit from far away in twilight cs" }, - { 0x0F, 0x80, 0x0F80, "enter mist area twilight cs" }, - { 0x0F, 0x40, 0x0F40, "found Talo's stick (child chase)" }, - { 0x0F, 0x20, 0x0F20, "explored top of east slope mist area twilight" }, - { 0x0F, 0x10, 0x0F10, "talked to Coro spirit before killing bugs" }, - { 0x0F, 0x08, 0x0F08, "entered mist area as human" }, - { 0x0F, 0x04, 0x0F04, "Talked to midna before talking to Coro spirit" }, - { 0x0F, 0x02, 0x0F02, "explored section with north exit of mist area (gets unset)" }, - { 0x0F, 0x01, 0x0F01, "saw light bugs on trunk mist area (gets unset)" }, - { 0x10, 0x80, 0x1080, "Map marker Rusl" }, - { 0x10, 0x40, 0x1040, "lit torch 1 in lantern cave" }, - { 0x10, 0x20, 0x1020, "Killed poe mist area" }, - { 0x10, 0x10, 0x1010, "spawn PoH chest key cave" }, - { 0x10, 0x08, 0x1008, "lit right torch in key cave" }, - { 0x10, 0x04, 0x1004, "lit left torch in key cave" }, - { 0x10, 0x02, 0x1002, "explored section 15 in lantern cave" }, - { 0x10, 0x01, 0x1001, "add mist area mist to mini-map" }, - { 0x11, 0x80, 0x1180, "explored section 14 in lantern cave" }, - { 0x11, 0x40, 0x1140, "explored section 13 in lantern cave" }, - { 0x11, 0x20, 0x1120, "explored section 12 in lantern cave" }, - { 0x11, 0x10, 0x1110, "explored section 11 in lantern cave" }, - { 0x11, 0x08, 0x1108, "explored section 10 in lantern cave" }, - { 0x11, 0x04, 0x1104, "explored section 9 in lantern cave" }, - { 0x11, 0x02, 0x1102, "explored section 3 of branching path in lantern cave" }, - { 0x11, 0x01, 0x1101, "explored section 8 in lantern cave" }, - { 0x12, 0x80, 0x1280, "explored section 7 in lantern cave" }, - { 0x12, 0x20, 0x1220, "Midna text before jumping to Lost Woods" }, - { 0x12, 0x10, 0x1210, "killed light bug outside Coro's house (duplicate)" }, - { 0x12, 0x08, 0x1208, "saw light bug run behind Coro gate" }, - { 0x12, 0x04, 0x1204, "Midna text warp to N faron for bridge" }, - { 0x12, 0x02, 0x1202, "saw first 2 light bugs run away from you" }, - { 0x12, 0x01, 0x1201, "S warp shadow beasts are spawned" }, - { 0x13, 0x80, 0x1380, "South Faron Portal" }, - { 0x13, 0x40, 0x1340, "explored section 2 of branching path in lantern cave" }, - { 0x13, 0x20, 0x1320, "killed right bokoblin in front of FT after twilight" }, - { 0x13, 0x10, 0x1310, "killed left bokoblin in front of FT after twilight" }, - { 0x13, 0x08, 0x1308, "explored section 1 of branching path in lantern cave" }, - { 0x13, 0x01, 0x1301, "S warp shadow beasts killed" }, - { 0x14, 0x80, 0x1480, "lit torch 4 in lantern cave" }, - { 0x14, 0x40, 0x1440, "killed light bug mist area north exit" }, - { 0x14, 0x20, 0x1420, "did midna jump 2 mist area" }, - { 0x14, 0x10, 0x1410, "killed light bug mist area north exit" }, - { 0x14, 0x08, 0x1408, "explored section 4 of branching path in lantern cave" }, - { 0x14, 0x04, 0x1404, "killed light bug in front of Forest Temple" }, - { 0x14, 0x02, 0x1402, "killed light bug in front of Forest Temple" }, - { 0x14, 0x01, 0x1401, "killed both light bugs in front of FT cs (map marker FT)" }, - { 0x15, 0x80, 0x1580, "killed light bug mist area south entrance" }, - { 0x15, 0x40, 0x1540, "killed light bug mist area south entrance" }, - { 0x15, 0x20, 0x1520, "did midna jump 5 mist area" }, - { 0x15, 0x10, 0x1510, "did midna jump 3 mist area" }, - { 0x15, 0x08, 0x1508, "killed light bug mist area trunk" }, - { 0x15, 0x04, 0x1504, "killed light bug mist area trunk" }, - { 0x15, 0x02, 0x1502, "killed light bug mist area trunk" }, - { 0x15, 0x01, 0x1501, "killed light bug between latern cave and gate" }, - { 0x16, 0x80, 0x1680, "map marker Talo (only during child save)" }, - { 0x16, 0x40, 0x1640, "killed light bug outside Coro's house" }, - { 0x16, 0x20, 0x1620, "Map marker key cave (only during child save)" }, - { 0x16, 0x10, 0x1610, "remove map marker key cave" }, - { 0x16, 0x08, 0x1608, "did midna jump 4 mist area" }, - { 0x16, 0x04, 0x1604, "killed light bug hallway to Coro (closer to spring)" }, - { 0x16, 0x02, 0x1602, "killed light bug between latern cave and gate" }, - { 0x16, 0x01, 0x1601, "killed both light bugs in Coro's house cs" }, - { 0x17, 0x80, 0x1780, "killed light bug inside Coro's house" }, - { 0x17, 0x40, 0x1740, "killed light bug inside Coro's house" }, - { 0x17, 0x20, 0x1720, "killed light bug hallway to Coro (closer to Coro)" }, - { 0x17, 0x10, 0x1710, "did midna jump 6 mist area" }, - { 0x17, 0x08, 0x1708, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, - { 0x17, 0x04, 0x1704, "lit torch 3 in lantern cave" }, - { 0x17, 0x02, 0x1702, "burned cobweb 2 in lantern cave" }, - { 0x17, 0x01, 0x1701, "burned cobweb 1 in lantern cave" }, - { 0x1B, 0x01, 0x1B01, "picked up rupees from rock next to Coro" }, + { 0x00, 0x80, AreaFlagInd{0x0080}, "small chest in lantern cave" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "HP Chest Coro-Mist shortcut" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "big chest mist area" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "small chest mist area trunk" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "small chest mist area next to key cave" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "PoH chest key cave" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "Small key cave key chest" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "Dig Tear #1" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "Final Tear #1" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "Final Tear #2" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "Wall Tear #1 (Mist Area)" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "Wall Tear #2 (Mist Area)" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "Tree Tear #1" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "Tree Tear #2" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "Tree Tear #3" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "Gate Tear #1" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "Coro Tear #1 (inside)" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "Dig Tear #2" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "Tear #2" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "Gate Tear #2" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "Coro Tear #2 (inside)" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "Tear #1" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "Coro Tear (outisde)" }, + { 0x04, 0x80, AreaFlagInd{0x0480}, "Yellow Rupee Chest (N-Faron)" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "explored section with south entrance of mist area (gets unset)" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "went up east section of mist area after midna jump 1 twilight" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "S Faron warp twilight fences fall cs" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "Sky character under owl statue" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "midna jump 1 mist area (duplicate)" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "unlock midna jump 1 mist area" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "Coro spirits talk after killing light bugs in his house" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "midna jump to Coro's house" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Map marker owl statue" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "opened mist area gate to N faron" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "lit torch 2 in lantern cave" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "Talked to Midna next to the deku babas before Coro" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "Rescued Monkey from Puppets" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "dug behind Coro gate in twilight" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "took Midna back s warp fight" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "S warp shadow beast revive cs" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "trigger twilight end cs (vessel of light filled)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "unlocked Coro gate" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "Explored path to sacred grove" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "burned cobweb in front of forest temple" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "see spirit in front of FT twilight cs" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "enter twilight cs" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "talked to the light spirit in twilight" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "saw light bugs dig underground mist area exit twilight" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "Blown up rock next to Coro" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "n warp fight fences appear cs" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "North Faron Portal" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "FT save prompt" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "got lantern back after monkey follow" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "saw light bugs move inside Coro's house cs" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "in monkey follow (gets unset afterwards)" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "Trill lets you shop" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "killed left bokoblin before Trill after twilight" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "killed right bokoblin before Trill after twilight" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "explored section 6 in lantern cave" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "explored section 5 in lantern cave" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "explored section 4 in lantern cave" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "explored section 3 in lantern cave" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "explored section 2 in lantern cave" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "explored section 1 in lantern cave" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "got Coro key from Coro" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "?" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "killed right bokoblin next to Talo's cage" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "killed left bokoblin next to Talo's cage" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "broke Talo's cage" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "killed both bokoblins next to Talo's cage" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "enter Faron intro cs" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "lit Coro's soup" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "saved Talo cs" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "see light spirit from far away in twilight cs" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "enter mist area twilight cs" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "found Talo's stick (child chase)" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "explored top of east slope mist area twilight" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "talked to Coro spirit before killing bugs" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "entered mist area as human" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "Talked to midna before talking to Coro spirit" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "explored section with north exit of mist area (gets unset)" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "saw light bugs on trunk mist area (gets unset)" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "Map marker Rusl" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "lit torch 1 in lantern cave" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "Killed poe mist area" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "spawn PoH chest key cave" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "lit right torch in key cave" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "lit left torch in key cave" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "explored section 15 in lantern cave" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "add mist area mist to mini-map" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "explored section 14 in lantern cave" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "explored section 13 in lantern cave" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "explored section 12 in lantern cave" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "explored section 11 in lantern cave" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "explored section 10 in lantern cave" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "explored section 9 in lantern cave" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "explored section 3 of branching path in lantern cave" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "explored section 8 in lantern cave" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "explored section 7 in lantern cave" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "Midna text before jumping to Lost Woods" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "killed light bug outside Coro's house (duplicate)" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "saw light bug run behind Coro gate" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "Midna text warp to N faron for bridge" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "saw first 2 light bugs run away from you" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "S warp shadow beasts are spawned" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "South Faron Portal" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "explored section 2 of branching path in lantern cave" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "killed right bokoblin in front of FT after twilight" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "killed left bokoblin in front of FT after twilight" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "explored section 1 of branching path in lantern cave" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "S warp shadow beasts killed" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "lit torch 4 in lantern cave" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "killed light bug mist area north exit" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "did midna jump 2 mist area" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "killed light bug mist area north exit" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "explored section 4 of branching path in lantern cave" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "killed light bug in front of Forest Temple" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "killed light bug in front of Forest Temple" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "killed both light bugs in front of FT cs (map marker FT)" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "killed light bug mist area south entrance" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "killed light bug mist area south entrance" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "did midna jump 5 mist area" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "did midna jump 3 mist area" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "killed light bug mist area trunk" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "killed light bug mist area trunk" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "killed light bug mist area trunk" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "killed light bug between latern cave and gate" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "map marker Talo (only during child save)" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "killed light bug outside Coro's house" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "Map marker key cave (only during child save)" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "remove map marker key cave" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "did midna jump 4 mist area" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "killed light bug hallway to Coro (closer to spring)" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "killed light bug between latern cave and gate" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "killed both light bugs in Coro's house cs" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "killed light bug inside Coro's house" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "killed light bug inside Coro's house" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "killed light bug hallway to Coro (closer to Coro)" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "did midna jump 6 mist area" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "lit torch 3 in lantern cave" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "burned cobweb 2 in lantern cave" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "burned cobweb 1 in lantern cave" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up rupees from rock next to Coro" }, }; inline EventAreaFlags eventAreaFlagsFishingPond[] = { - { 0x1B, 0x01, 0x1B01, "free standing PoH" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "free standing PoH" }, }; inline EventAreaFlags eventAreaFlagsFT[] = { - { 0x00, 0x80, 0x0080, "PoH big chest behind Deku Like" }, - { 0x00, 0x04, 0x0004, "big chest underwater Tiny Cave" }, - { 0x00, 0x02, 0x0002, "small key big chest on pillar tile worm room" }, - { 0x00, 0x01, 0x0001, "Small Chest tile worm room" }, - { 0x01, 0x10, 0x0110, "big chest compass main room" }, - { 0x01, 0x08, 0x0108, "PoH big chest behind stairs tile worm room" }, - { 0x01, 0x02, 0x0102, "saved monkey in front of big pit" }, - { 0x02, 0x80, 0x0280, "saved monkey in boomerang bombling room" }, - { 0x02, 0x20, 0x0220, "saved monkey in tile worm room" }, - { 0x02, 0x10, 0x0210, "saved monkey in big baba room" }, - { 0x02, 0x08, 0x0208, "saved 2nd monkey" }, - { 0x02, 0x04, 0x0204, "first Monkey saved" }, - { 0x02, 0x02, 0x0202, "Small Chest 2nd Monkey room" }, - { 0x03, 0x80, 0x0380, "small chest first room" }, - { 0x03, 0x40, 0x0340, "Big Baba key acquired" }, - { 0x03, 0x10, 0x0310, "small key big chest in single wind bridge room" }, - { 0x03, 0x04, 0x0304, "small key big chest in boomerang bombling room" }, - { 0x03, 0x02, 0x0302, "Big Chest in broken stairs room" }, - { 0x06, 0x01, 0x0601, "Ooccoo map marker" }, - { 0x07, 0x80, 0x0780, "big chest with map main room" }, - { 0x07, 0x40, 0x0740, "Big Key Chest" }, - { 0x07, 0x20, 0x0720, "small chest behind bombable wall main room" }, - { 0x07, 0x04, 0x0704, "Outside Monkey saved" }, - { 0x07, 0x02, 0x0702, "saved monkey in spider cave room" }, - { 0x08, 0x40, 0x0840, "Midna Boomerang text seen" }, - { 0x08, 0x20, 0x0820, "midna text after bridge before Ook broken" }, - { 0x08, 0x08, 0x0808, "Big Baba killed cutscene (still spawned)" }, - { 0x08, 0x02, 0x0802, "hit totem of 2nd monkey once cs" }, - { 0x08, 0x01, 0x0801, "Midna first monkey text end" }, - { 0x09, 0x80, 0x0980, "Boss Door opened" }, - { 0x09, 0x40, 0x0940, "bridge before Ook broken" }, - { 0x09, 0x20, 0x0920, "burned cob web big key room" }, - { 0x09, 0x10, 0x0910, "bridge 2nd monkey room broken" }, - { 0x09, 0x02, 0x0902, "Compass Chest knocked down" }, - { 0x0A, 0x80, 0x0A80, "Monkey freed in spider room" }, - { 0x0A, 0x08, 0x0A08, "unlocked door to 2nd monkey room" }, - { 0x0A, 0x04, 0x0A04, "broke cage of 2nd monkey cs" }, - { 0x0A, 0x02, 0x0A02, "bokoblins see you in single wind bridge room cs" }, - { 0x0A, 0x01, 0x0A01, "turned wind bridge in single wind bridge room cs" }, - { 0x0B, 0x80, 0x0B80, "Unlock Windbridge East Door" }, - { 0x0B, 0x10, 0x0B10, "Girl Monkey helps Link" }, - { 0x0C, 0x40, 0x0C40, "opened cage of monkey in big baba room" }, - { 0x0C, 0x20, 0x0C20, "killed higher bokoblin in room before boss" }, - { 0x0C, 0x10, 0x0C10, "killed lower bokoblin in room before boss" }, - { 0x0C, 0x02, 0x0C02, "blown up rock to Ooccoo" }, - { 0x0D, 0x80, 0x0D80, "blown up rock blocking tile worm room" }, - { 0x0D, 0x40, 0x0D40, "blown up main room bombable wall" }, - //{ 0x0D, 0x20, 0x0D20, "small key big chest tile worm room position" }, - //{ 0x0D, 0x10, 0x0D10, "small key big chest tile worm room position" }, - //{ 0x0D, 0x08, 0x0D08, "small key big chest tile worm room position" }, - //{ 0x0D, 0x04, 0x0D04, "small key big chest tile worm room position" }, - { 0x0D, 0x02, 0x0D02, "Staircase rises main room" }, - { 0x0E, 0x20, 0x0E20, "tile worm room intro cs" }, - { 0x0E, 0x08, 0x0E08, "opened cage of monkey in tile worm room" }, - { 0x0E, 0x04, 0x0E04, "gate to big key opened" }, - { 0x0E, 0x02, 0x0E02, "2nd Monkey room intro cs" }, - { 0x0F, 0x80, 0x0F80, "lit bottom right torch main room" }, - { 0x0F, 0x40, 0x0F40, "lit bottom left torch main room" }, - { 0x0F, 0x20, 0x0F20, "lit upper right torch main room" }, - { 0x0F, 0x10, 0x0F10, "lit upper left torch main room" }, - { 0x0F, 0x08, 0x0F08, "big baba room intro cs" }, - { 0x0F, 0x04, 0x0F04, "enter room before boss Midna text" }, - { 0x0F, 0x02, 0x0F02, "Midna text after saveing a monkey after Ook" }, - { 0x0F, 0x01, 0x0F01, "Small Bridge breaks scene seen" }, - { 0x10, 0x10, 0x1010, "enter southwest door outside intro cs" }, - { 0x10, 0x04, 0x1004, "Midna text after compass" }, - { 0x10, 0x02, 0x1002, "boomerang obtained" }, - { 0x10, 0x01, 0x1001, "burned west cob web main room" }, - { 0x11, 0x08, 0x1108, "5th monkey added to room before boss" }, - { 0x11, 0x04, 0x1104, "4 Monkeys in main room cutscene" }, - { 0x11, 0x02, 0x1102, "turned wind bridge in single wind bridge room" }, - { 0x11, 0x01, 0x1101, "Monkeys regroup in Main Room" }, - { 0x12, 0x80, 0x1280, "4 Monkeys gather in Main Room" }, - { 0x12, 0x40, 0x1240, "blown up 1st rock in boomeang bombling room" }, - { 0x12, 0x10, 0x1210, "Ooccoo Freed" }, - { 0x12, 0x01, 0x1201, "2nd Monkey Bokoblins Killed" }, - { 0x13, 0x80, 0x1380, "Midna first Monkey text prompt (makes vines climbable)" }, - { 0x13, 0x40, 0x1340, "killed big baba cs" }, - { 0x13, 0x08, 0x1308, "?" }, - { 0x13, 0x04, 0x1304, "?" }, - { 0x13, 0x02, 0x1302, "Diababa killed" }, - { 0x13, 0x01, 0x1301, "Diababa Phase 2 (unset post kill)" }, - { 0x14, 0x20, 0x1420, "broke bridge over water that leads to big key" }, - { 0x14, 0x04, 0x1404, "monkeys form a rope in room before boss cs" }, - { 0x14, 0x02, 0x1402, "monkeys start to form a rope in room before boss" }, - { 0x15, 0x80, 0x1580, "All Monkeys form rope" }, - { 0x15, 0x40, 0x1540, "Ook exit door opened" }, - { 0x15, 0x20, 0x1520, "opened gate to monkey in broken stairs room" }, - { 0x15, 0x08, 0x1508, "blown up 2nd rock in boomerang bombling room" }, - { 0x15, 0x02, 0x1502, "saved 5th monkey cs" }, - { 0x15, 0x01, 0x1501, "killed bokoblin next to first monkey" }, - { 0x16, 0x20, 0x1620, "see locked monkey post Ook" }, - { 0x16, 0x10, 0x1610, "Ook defeated" }, - { 0x16, 0x08, 0x1608, "monkeys form a rope in room before boss cs" }, - { 0x16, 0x04, 0x1604, "Staircase rising cutscene for 4th Monkey" }, - { 0x16, 0x02, 0x1602, "Intro Cutscene" }, - { 0x16, 0x01, 0x1601, "2nd Monkey Pillar scene" }, - { 0x17, 0x80, 0x1780, "enter room before boss intro cs" }, - { 0x17, 0x40, 0x1740, "turned mill for the first time in Ook room cs" }, - { 0x17, 0x20, 0x1720, "big chest compass main room (set after)" }, - { 0x17, 0x01, 0x1701, "hit totem of 2nd monkey once" }, - { 0x1B, 0x10, 0x1B10, "picked up red rupee from deku like in spider room" }, + { 0x00, 0x80, AreaFlagInd{0x0080}, "PoH big chest behind Deku Like" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "big chest underwater Tiny Cave" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "small key big chest on pillar tile worm room" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "Small Chest tile worm room" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "big chest compass main room" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "PoH big chest behind stairs tile worm room" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "saved monkey in front of big pit" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "saved monkey in boomerang bombling room" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "saved monkey in tile worm room" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "saved monkey in big baba room" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "saved 2nd monkey" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "first Monkey saved" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "Small Chest 2nd Monkey room" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small chest first room" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "Big Baba key acquired" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "small key big chest in single wind bridge room" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "small key big chest in boomerang bombling room" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "Big Chest in broken stairs room" }, + { 0x06, 0x01, AreaFlagInd{0x0601}, "Ooccoo map marker" }, + { 0x07, 0x80, AreaFlagInd{0x0780}, "big chest with map main room" }, + { 0x07, 0x40, AreaFlagInd{0x0740}, "Big Key Chest" }, + { 0x07, 0x20, AreaFlagInd{0x0720}, "small chest behind bombable wall main room" }, + { 0x07, 0x04, AreaFlagInd{0x0704}, "Outside Monkey saved" }, + { 0x07, 0x02, AreaFlagInd{0x0702}, "saved monkey in spider cave room" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "Midna Boomerang text seen" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "midna text after bridge before Ook broken" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "Big Baba killed cutscene (still spawned)" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "hit totem of 2nd monkey once cs" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "Midna first monkey text end" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "Boss Door opened" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "bridge before Ook broken" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "burned cob web big key room" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "bridge 2nd monkey room broken" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "Compass Chest knocked down" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "Monkey freed in spider room" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "unlocked door to 2nd monkey room" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "broke cage of 2nd monkey cs" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "bokoblins see you in single wind bridge room cs" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "turned wind bridge in single wind bridge room cs" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "Unlock Windbridge East Door" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "Girl Monkey helps Link" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "opened cage of monkey in big baba room" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "killed higher bokoblin in room before boss" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "killed lower bokoblin in room before boss" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "blown up rock to Ooccoo" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "blown up rock blocking tile worm room" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "blown up main room bombable wall" }, + //{ 0x0D, 0x20, AreaFlagInd{0x0D20}, "small key big chest tile worm room position" }, + //{ 0x0D, 0x10, AreaFlagInd{0x0D10}, "small key big chest tile worm room position" }, + //{ 0x0D, 0x08, AreaFlagInd{0x0D08}, "small key big chest tile worm room position" }, + //{ 0x0D, 0x04, AreaFlagInd{0x0D04}, "small key big chest tile worm room position" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "Staircase rises main room" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "tile worm room intro cs" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "opened cage of monkey in tile worm room" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "gate to big key opened" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "2nd Monkey room intro cs" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "lit bottom right torch main room" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "lit bottom left torch main room" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "lit upper right torch main room" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "lit upper left torch main room" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "big baba room intro cs" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "enter room before boss Midna text" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "Midna text after saveing a monkey after Ook" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "Small Bridge breaks scene seen" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "enter southwest door outside intro cs" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "Midna text after compass" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "boomerang obtained" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "burned west cob web main room" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "5th monkey added to room before boss" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "4 Monkeys in main room cutscene" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "turned wind bridge in single wind bridge room" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "Monkeys regroup in Main Room" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "4 Monkeys gather in Main Room" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "blown up 1st rock in boomeang bombling room" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "Ooccoo Freed" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "2nd Monkey Bokoblins Killed" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "Midna first Monkey text prompt (makes vines climbable)" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "killed big baba cs" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "?" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "?" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "Diababa killed" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "Diababa Phase 2 (unset post kill)" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "broke bridge over water that leads to big key" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "monkeys form a rope in room before boss cs" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "monkeys start to form a rope in room before boss" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "All Monkeys form rope" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "Ook exit door opened" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "opened gate to monkey in broken stairs room" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "blown up 2nd rock in boomerang bombling room" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "saved 5th monkey cs" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "killed bokoblin next to first monkey" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "see locked monkey post Ook" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "Ook defeated" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "monkeys form a rope in room before boss cs" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "Staircase rising cutscene for 4th Monkey" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "Intro Cutscene" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "2nd Monkey Pillar scene" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "enter room before boss intro cs" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "turned mill for the first time in Ook room cs" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "big chest compass main room (set after)" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "hit totem of 2nd monkey once" }, + { 0x1B, 0x10, AreaFlagInd{0x1B10}, "picked up red rupee from deku like in spider room" }, }; inline EventAreaFlags eventAreaFlagsGerudoDesert[] = { - { 0x02, 0x80, 0x0280, "big chest next to Arbiter's Grounds" }, - { 0x02, 0x20, 0x0220, "small chest next to camp entrance" }, - { 0x02, 0x08, 0x0208, "small chest on pillar weat of entrance to desert" }, - { 0x02, 0x04, 0x0204, "small chest under tower of left bulblin outside camp" }, - { 0x02, 0x02, 0x0202, "small chest under tower of right bulblin outside camp" }, - { 0x02, 0x01, 0x0201, "small chest next to fire outside camp" }, - { 0x03, 0x80, 0x0380, "small chest island north of cave of ordeals" }, - { 0x03, 0x40, 0x0340, "small chest east canyon" }, - { 0x03, 0x20, 0x0320, "small chest next to pillar in the middle of the messa" }, - { 0x03, 0x08, 0x0308, "small chest behind 2 breakable walls (the west one)" }, - { 0x03, 0x04, 0x0304, "small chest behind 2 breakable walls (the east one)" }, - { 0x03, 0x02, 0x0302, "big chest owl statue" }, - { 0x03, 0x01, 0x0301, "big chest in south secret path" }, - { 0x04, 0x80, 0x0480, "both small chests and key in camp (each one sets it)" }, - { 0x08, 0x80, 0x0880, "?" }, - { 0x08, 0x40, 0x0840, "?" }, - { 0x08, 0x20, 0x0820, "explored island north of cave of ordeals" }, - { 0x08, 0x10, 0x0810, "explored part 9 of bulblin camp (KB battle area)" }, - { 0x08, 0x08, 0x0808, "explored part 8 of bulblin camp" }, - { 0x08, 0x04, 0x0804, "explored part 7 of bulblin camp" }, - { 0x08, 0x02, 0x0802, "explored part 6 of bulblin camp" }, - { 0x08, 0x01, 0x0801, "explored part 5 of bulblin camp" }, - { 0x09, 0x80, 0x0980, "Desert Intro CS (PoT)" }, - { 0x09, 0x20, 0x0920, "Gerudo Messa Portal" }, - { 0x09, 0x08, 0x0908, "explored part 2 of bulblin camp" }, - { 0x09, 0x04, 0x0904, "explored part 4 of bulblin camp" }, - { 0x09, 0x02, 0x0902, "explored part 3 of bulblin camp" }, - { 0x09, 0x01, 0x0901, "?" }, - { 0x0A, 0x40, 0x0A40, "explored south secret path to big chest" }, - { 0x0A, 0x10, 0x0A10, "Mirror chamber intro cs" }, - { 0x0A, 0x04, 0x0A04, "save prompt after beating Arbiter's Grounds" }, - { 0x0A, 0x02, 0x0A02, "killed archer bulblin on bore outside camp" }, - { 0x0A, 0x01, 0x0A01, "killed rider bulblin on bore outside camp" }, - { 0x0B, 0x80, 0x0B80, "killed lone bulblin on bore outside camp" }, - { 0x0B, 0x40, 0x0B40, "killed bulblin on left tower outside camp" }, - { 0x0B, 0x20, 0x0B20, "killed bulblin on right tower outside camp" }, - { 0x0B, 0x10, 0x0B10, "watched outside AG cutscene after bublin camp" }, - { 0x0B, 0x04, 0x0B04, "destroyed fire outside camp" }, - { 0x0B, 0x02, 0x0B02, "destroyed bore meat in camp" }, - { 0x0D, 0x08, 0x0D08, "killed poe next to entrance to camp" }, - { 0x0D, 0x04, 0x0D04, "Hero's Shade map marker" }, - { 0x0D, 0x02, 0x0D02, "spawn big chest next to Arbiter's Grounds" }, - { 0x0D, 0x01, 0x0D01, "lit right torch for big chest next to Arbiter's Grounds entrance" }, - { 0x0E, 0x80, 0x0E80, "lit left torch for big chest next to Arbiter's Grounds entrance" }, - { 0x0E, 0x20, 0x0E20, "explored area with Arbiter's Gounds entrance" }, - { 0x0E, 0x02, 0x0E02, "mirror light stairs appear" }, - { 0x0E, 0x01, 0x0E01, "Mirror Chamber Portal" }, - { 0x0F, 0x04, 0x0F04, "sky character under owl statue" }, - { 0x0F, 0x02, 0x0F02, "map marker owl statue" }, - { 0x0F, 0x01, 0x0F01, "Mirror Raised Cutscene Flag (Places Boar at desert entrance)" }, - { 0x10, 0x40, 0x1040, "broke left wall that prevents access to east small chest (set once pieces despawn)" }, - { 0x10, 0x20, 0x1020, "killed poe next to cave of ordeals" }, - { 0x10, 0x10, 0x1010, "killed poe south of desert entrance" }, - { 0x10, 0x08, 0x1008, "killed poe on elevated platform with grotto (messa)" }, - { 0x10, 0x04, 0x1004, "killed poe next to Arbiter's Grounds entrance" }, - { 0x10, 0x02, 0x1002, "destroyed tower of right bulbin outside camp" }, - { 0x10, 0x01, 0x1001, "destroyed tower of left bulbin outside camp" }, - { 0x11, 0x20, 0x1120, "broke first right wall to camp (set once pieces despawn)" }, - { 0x11, 0x10, 0x1110, "broke first middle wall to camp (set once pieces despawn)" }, - { 0x11, 0x08, 0x1108, "broke first left wall to camp (set once pieces despawn)" }, - { 0x11, 0x04, 0x1104, "broke second right wall to camp (set once pieces despawn)" }, - { 0x11, 0x02, 0x1102, "broke second left wall to camp (set once pieces despawn)" }, - { 0x12, 0x10, 0x1210, "explored elavated section with poe over grotto" }, - { 0x13, 0x40, 0x1340, "Desert Intro CS" }, - { 0x14, 0x80, 0x1480, "started climbing stairs to mirror chamber" }, - { 0x14, 0x40, 0x1440, "exit Arbiters Grounds to go to mirror chamber" }, - { 0x14, 0x02, 0x1402, "map marker palace of twilight (explored mirror chamber)" }, - { 0x14, 0x01, 0x1401, "killed poe in bulblin camp" }, - { 0x17, 0x08, 0x1708, "broke right wall that prevents access to east small chest (set once pieces despawn)" }, - { 0x17, 0x04, 0x1704, "broke left wall that prevents access to west small chest (set once pieces despawn)" }, - { 0x17, 0x02, 0x1702, "broke right wall that prevents access to west small chest (set once pieces despawn)" }, - { 0x18, 0x80, 0x1880, "free standing PoH bore meat bulblin camp" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "big chest next to Arbiter's Grounds" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "small chest next to camp entrance" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "small chest on pillar weat of entrance to desert" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "small chest under tower of left bulblin outside camp" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "small chest under tower of right bulblin outside camp" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "small chest next to fire outside camp" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small chest island north of cave of ordeals" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "small chest east canyon" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "small chest next to pillar in the middle of the messa" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "small chest behind 2 breakable walls (the west one)" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "small chest behind 2 breakable walls (the east one)" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "big chest owl statue" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "big chest in south secret path" }, + { 0x04, 0x80, AreaFlagInd{0x0480}, "both small chests and key in camp (each one sets it)" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "?" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "?" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "explored island north of cave of ordeals" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "explored part 9 of bulblin camp (KB battle area)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "explored part 8 of bulblin camp" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "explored part 7 of bulblin camp" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "explored part 6 of bulblin camp" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "explored part 5 of bulblin camp" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "Desert Intro CS (PoT)" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Gerudo Messa Portal" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "explored part 2 of bulblin camp" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "explored part 4 of bulblin camp" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "explored part 3 of bulblin camp" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "?" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "explored south secret path to big chest" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "Mirror chamber intro cs" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "save prompt after beating Arbiter's Grounds" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "killed archer bulblin on bore outside camp" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "killed rider bulblin on bore outside camp" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "killed lone bulblin on bore outside camp" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "killed bulblin on left tower outside camp" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "killed bulblin on right tower outside camp" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "watched outside AG cutscene after bublin camp" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "destroyed fire outside camp" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "destroyed bore meat in camp" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "killed poe next to entrance to camp" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "Hero's Shade map marker" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "spawn big chest next to Arbiter's Grounds" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "lit right torch for big chest next to Arbiter's Grounds entrance" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "lit left torch for big chest next to Arbiter's Grounds entrance" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "explored area with Arbiter's Gounds entrance" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "mirror light stairs appear" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "Mirror Chamber Portal" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "sky character under owl statue" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "map marker owl statue" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "Mirror Raised Cutscene Flag (Places Boar at desert entrance)" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "broke left wall that prevents access to east small chest (set once pieces despawn)" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "killed poe next to cave of ordeals" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "killed poe south of desert entrance" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "killed poe on elevated platform with grotto (messa)" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "killed poe next to Arbiter's Grounds entrance" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "destroyed tower of right bulbin outside camp" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "destroyed tower of left bulbin outside camp" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "broke first right wall to camp (set once pieces despawn)" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "broke first middle wall to camp (set once pieces despawn)" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "broke first left wall to camp (set once pieces despawn)" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "broke second right wall to camp (set once pieces despawn)" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "broke second left wall to camp (set once pieces despawn)" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "explored elavated section with poe over grotto" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "Desert Intro CS" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "started climbing stairs to mirror chamber" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "exit Arbiters Grounds to go to mirror chamber" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "map marker palace of twilight (explored mirror chamber)" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "killed poe in bulblin camp" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "broke right wall that prevents access to east small chest (set once pieces despawn)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "broke left wall that prevents access to west small chest (set once pieces despawn)" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "broke right wall that prevents access to west small chest (set once pieces despawn)" }, + { 0x18, 0x80, AreaFlagInd{0x1880}, "free standing PoH bore meat bulblin camp" }, }; inline EventAreaFlags eventAreaFlagsGM[] = { - { 0x00, 0x40, 0x0040, "big chest main room top floor" }, - { 0x00, 0x10, 0x0010, "small chest next to switch in toadpoli room" }, - { 0x00, 0x08, 0x0008, "small chest first room" }, - { 0x00, 0x04, 0x0004, "big chest elder 3 room" }, - { 0x00, 0x02, 0x0002, "small chest elder 2 room" }, - { 0x00, 0x01, 0x0001, "small chest elder 1 room" }, - { 0x01, 0x40, 0x0140, "Ooccoo Map Flag" }, - { 0x01, 0x20, 0x0120, "big chest underwater outside room" }, - { 0x01, 0x10, 0x0110, "PoH big chest room 3" }, - { 0x01, 0x02, 0x0102, "map big chest elder 1 room" }, - { 0x01, 0x01, 0x0101, "small key underwater big chest toadpoli room" }, - { 0x02, 0x80, 0x0280, "small key small chest outside room" }, - { 0x02, 0x40, 0x0240, "big chest outside room clawshot" }, - { 0x02, 0x20, 0x0220, "small chest room leading to elder 2" }, - { 0x02, 0x10, 0x0210, "compass big chest" }, - { 0x02, 0x08, 0x0208, "small key big chest main room bottom floor" }, - { 0x02, 0x02, 0x0202, "PoH big chest toadpoli room (the one after the gate)" }, - { 0x03, 0x40, 0x0340, "big chest bow" }, - { 0x08, 0x10, 0x0810, "cut rope of door outside room cs" }, - { 0x08, 0x08, 0x0808, "pressed second button main room floor 2 cs" }, - { 0x08, 0x04, 0x0804, "pressed third button in first room cs" }, - { 0x08, 0x02, 0x0802, "pressed second button in first room cs" }, - { 0x08, 0x01, 0x0801, "cut rope of door in toadpoli room cs" }, - { 0x09, 0x80, 0x0980, "unlocked boss door" }, - { 0x09, 0x20, 0x0920, "pressed first button main room floor 2 cs" }, - { 0x09, 0x10, 0x0910, "killed beamos outside room" }, - { 0x0A, 0x40, 0x0A40, "unlock mini-boss doors" }, - { 0x0A, 0x08, 0x0A08, "pressed button outside room" }, - { 0x0A, 0x04, 0x0A04, "cut rope of door in room before boss" }, - { 0x0A, 0x02, 0x0A02, "cut rope of door in toadpoli room" }, - { 0x0A, 0x01, 0x0A01, "cut rope of door in bow room" }, - { 0x0B, 0x20, 0x0B20, "cut rope of door at top floor of main room" }, - { 0x0B, 0x10, 0x0B10, "pressed first button main room floor 2" }, - { 0x0B, 0x08, 0x0B08, "reach west locked door in main room bottom floor" }, - { 0x0B, 0x04, 0x0B04, "lowered platform to open gate in first room (read only)" }, - { 0x0C, 0x80, 0x0C80, "unlocked north door in toadpoli room" }, - { 0x0C, 0x40, 0x0C40, "pressed second button main room floor 2" }, - { 0x0C, 0x20, 0x0C20, "unlock west locked door in main room bottom floor" }, - { 0x0C, 0x08, 0x0C08, "killed right beamos in toadpoli room" }, - { 0x0C, 0x04, 0x0C04, "killed left beamos in toadpoli room" }, - { 0x0D, 0x80, 0x0D80, "pressed button outside room cs" }, - { 0x0D, 0x40, 0x0D40, "pressed button at top floor of main room" }, - { 0x0D, 0x08, 0x0D08, "unlocked east door outside room" }, - { 0x0D, 0x01, 0x0D01, "broke underwater wood barrier outside room" }, - { 0x0E, 0x80, 0x0E80, "replace tektites with toadpolis in toadpoli room (set after obtaining bow)" }, - { 0x0E, 0x20, 0x0E20, "main room intro cs" }, - { 0x0E, 0x10, 0x0E10, "main room intro cs" }, - { 0x0E, 0x08, 0x0E08, "broke second wood barrier in outside room" }, - { 0x0E, 0x04, 0x0E04, "broke first wood barrier in outside room" }, - { 0x0E, 0x02, 0x0E02, "Oocco Freed" }, - { 0x0E, 0x01, 0x0E01, "elder 2 lets you climb ladder in his room" }, - { 0x0F, 0x80, 0x0F80, "elder 1 lets you climb ladder in his room" }, - { 0x0F, 0x40, 0x0F40, "pulled beamos outside room" }, - { 0x0F, 0x20, 0x0F20, "outside room intro cs" }, - { 0x0F, 0x10, 0x0F10, "outside room getting shot at after mini-boss cs" }, - { 0x0F, 0x08, 0x0F08, "outside room getting shot at after mini-boss cs" }, - { 0x0F, 0x04, 0x0F04, "outside room intro cs" }, - { 0x10, 0x80, 0x1080, "room after bow intro cs" }, - { 0x10, 0x40, 0x1040, "pulled beamos outside room cs" }, - { 0x10, 0x20, 0x1020, "activate first force field in toadpoli room" }, - { 0x10, 0x10, 0x1010, "pressed first button in toadpoli room cs" }, - { 0x10, 0x08, 0x1008, "open gate in toadpoli room cs" }, - { 0x10, 0x04, 0x1004, "pressed second button in toadpoli room cs" }, - { 0x10, 0x02, 0x1002, "activate second force field in toadpoli room" }, - { 0x10, 0x01, 0x1001, "room before elder 1 intro cs" }, - { 0x11, 0x80, 0x1180, "room before elder 1 intro cs" }, - { 0x11, 0x20, 0x1120, "intro cs" }, - { 0x11, 0x10, 0x1110, "pressed first button in first room cs" }, - { 0x11, 0x08, 0x1108, "open gate in first room cs" }, - { 0x11, 0x04, 0x1104, "pressed button in room after bow" }, - { 0x11, 0x02, 0x1102, "hit switch in room after bow" }, - { 0x11, 0x01, 0x1101, "press button room 3" }, - { 0x12, 0x80, 0x1280, "killed south-east beamos bow room" }, - { 0x12, 0x40, 0x1240, "killed south-west beamos bow room" }, - { 0x12, 0x20, 0x1220, "killed west beamos bow room" }, - { 0x12, 0x10, 0x1210, "killed north-east beamos bow room" }, - { 0x12, 0x08, 0x1208, "killed north-west beamos bow room" }, - { 0x12, 0x04, 0x1204, "killed east beamos bow room" }, - { 0x12, 0x02, 0x1202, "killed south beamos bow room" }, - { 0x12, 0x01, 0x1201, "pulled south-east beamos bow room" }, - { 0x13, 0x80, 0x1380, "pulled south-west beamos bow room" }, - { 0x13, 0x40, 0x1340, "pulled west beamos bow room" }, - { 0x13, 0x08, 0x1308, "pulled east beamos bow room" }, - { 0x13, 0x04, 0x1304, "pulled south beamos bow room" }, - { 0x13, 0x02, 0x1302, "pressed first button in toadpoli room" }, - { 0x13, 0x01, 0x1301, "pressed second button in toadpoli room" }, - { 0x15, 0x01, 0x1501, "reached area past pullable wall in room 3 (first in path to elder 1)" }, - { 0x16, 0x10, 0x1610, "reached bottom of water in room before elder 1" }, - { 0x16, 0x08, 0x1608, "reached area past pullable wall in room 3 (first in path to elder 1)" }, - { 0x16, 0x04, 0x1604, "knocked down fence in room after bow" }, - { 0x16, 0x02, 0x1602, "pullable wall in room 3 closed itself" }, - { 0x17, 0x80, 0x1780, "outside room killed leader bulblin archer" }, - { 0x17, 0x20, 0x1720, "cut rope of door outside room" }, - { 0x17, 0x10, 0x1710, "pressed unerwater button in room before elder" }, - { 0x17, 0x08, 0x1708, "main room floor 2 intro cs" }, - { 0x17, 0x04, 0x1704, "main room floor 2 intro cs" }, - { 0x17, 0x02, 0x1702, "hit switch in room after bow cs" }, - { 0x17, 0x01, 0x1701, "room after bow intro cs" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "big chest main room top floor" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "small chest next to switch in toadpoli room" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "small chest first room" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "big chest elder 3 room" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "small chest elder 2 room" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "small chest elder 1 room" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "Ooccoo Map Flag" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "big chest underwater outside room" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "PoH big chest room 3" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "map big chest elder 1 room" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "small key underwater big chest toadpoli room" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "small key small chest outside room" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "big chest outside room clawshot" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "small chest room leading to elder 2" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "compass big chest" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "small key big chest main room bottom floor" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "PoH big chest toadpoli room (the one after the gate)" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "big chest bow" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "cut rope of door outside room cs" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "pressed second button main room floor 2 cs" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "pressed third button in first room cs" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "pressed second button in first room cs" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "cut rope of door in toadpoli room cs" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "unlocked boss door" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "pressed first button main room floor 2 cs" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "killed beamos outside room" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "unlock mini-boss doors" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "pressed button outside room" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "cut rope of door in room before boss" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "cut rope of door in toadpoli room" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "cut rope of door in bow room" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "cut rope of door at top floor of main room" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "pressed first button main room floor 2" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "reach west locked door in main room bottom floor" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "lowered platform to open gate in first room (read only)" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "unlocked north door in toadpoli room" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "pressed second button main room floor 2" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "unlock west locked door in main room bottom floor" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "killed right beamos in toadpoli room" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "killed left beamos in toadpoli room" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "pressed button outside room cs" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "pressed button at top floor of main room" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "unlocked east door outside room" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "broke underwater wood barrier outside room" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "replace tektites with toadpolis in toadpoli room (set after obtaining bow)" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "main room intro cs" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "main room intro cs" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "broke second wood barrier in outside room" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "broke first wood barrier in outside room" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "Oocco Freed" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "elder 2 lets you climb ladder in his room" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "elder 1 lets you climb ladder in his room" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "pulled beamos outside room" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "outside room intro cs" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "outside room getting shot at after mini-boss cs" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "outside room getting shot at after mini-boss cs" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "outside room intro cs" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "room after bow intro cs" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "pulled beamos outside room cs" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "activate first force field in toadpoli room" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "pressed first button in toadpoli room cs" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "open gate in toadpoli room cs" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "pressed second button in toadpoli room cs" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "activate second force field in toadpoli room" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "room before elder 1 intro cs" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "room before elder 1 intro cs" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "intro cs" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "pressed first button in first room cs" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "open gate in first room cs" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "pressed button in room after bow" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "hit switch in room after bow" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "press button room 3" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "killed south-east beamos bow room" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "killed south-west beamos bow room" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "killed west beamos bow room" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "killed north-east beamos bow room" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "killed north-west beamos bow room" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "killed east beamos bow room" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "killed south beamos bow room" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "pulled south-east beamos bow room" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "pulled south-west beamos bow room" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "pulled west beamos bow room" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "pulled east beamos bow room" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "pulled south beamos bow room" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "pressed first button in toadpoli room" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "pressed second button in toadpoli room" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "reached area past pullable wall in room 3 (first in path to elder 1)" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "reached bottom of water in room before elder 1" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "reached area past pullable wall in room 3 (first in path to elder 1)" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "knocked down fence in room after bow" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "pullable wall in room 3 closed itself" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "outside room killed leader bulblin archer" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "cut rope of door outside room" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "pressed unerwater button in room before elder" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "main room floor 2 intro cs" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "main room floor 2 intro cs" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "hit switch in room after bow cs" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "room after bow intro cs" }, }; inline EventAreaFlags eventAreaFlagsGrotto[] = { - { 0x01, 0x20, 0x0120, "big chest grotto 5-4" }, - { 0x01, 0x08, 0x0108, "big chest grotto 4-3" }, - { 0x01, 0x04, 0x0104, "left small chest grotto 2-0" }, - { 0x01, 0x02, 0x0102, "right small chest grotto 2-0" }, - { 0x01, 0x01, 0x0101, "small chest grotto 5-3" }, - { 0x02, 0x80, 0x0280, "big chest grotto 4-2" }, - { 0x02, 0x40, 0x0240, "big chest grotto 3-0" }, - { 0x02, 0x20, 0x0220, "south small chest grotto 2-1" }, - { 0x02, 0x10, 0x0210, "east small chest grotto 2-1" }, - { 0x02, 0x08, 0x0208, "north small chest grotto 2-1" }, - { 0x02, 0x04, 0x0204, "small chest grotto 1-1" }, - { 0x02, 0x01, 0x0201, "big chest grotto 4-1" }, - { 0x03, 0x80, 0x0380, "big chest grotto 1-2" }, - { 0x03, 0x40, 0x0340, "big chest grotto 1-1" }, - { 0x03, 0x20, 0x0320, "big chest grotto 5-2" }, - { 0x03, 0x10, 0x0310, "big chest grotto 4-0" }, - { 0x03, 0x08, 0x0308, "big chest grotto 2-2" }, - { 0x03, 0x04, 0x0304, "big chest grotto 2-0" }, - { 0x03, 0x02, 0x0302, "big chest grotto 5-0" }, - { 0x03, 0x01, 0x0301, "big chest grotto 1-0" }, - { 0x08, 0x80, 0x0880, "lit right torch grotto 1-1" }, - { 0x08, 0x40, 0x0840, "lit left torch grotto 1-1" }, - { 0x08, 0x20, 0x0820, "killed red chu-chu grotto 3-3" }, - { 0x08, 0x10, 0x0810, "killed chu-chu grotto 3-2" }, - { 0x08, 0x08, 0x0808, "killed blue chu-chu grotto 3-1" }, - { 0x08, 0x04, 0x0804, "killed chu-chu grotto 2-0" }, - { 0x08, 0x02, 0x0802, "killed chu-chu grotto 1-2" }, - { 0x08, 0x01, 0x0801, "killed right freezard grotto 4-2" }, - { 0x09, 0x80, 0x0980, "broke ice wall 1 grotto 4-2" }, - { 0x09, 0x40, 0x0940, "killed chu-chu grotto 1-1" }, - { 0x09, 0x20, 0x0920, "killed all enemies grotto 5-4 (spawm chest)" }, - { 0x09, 0x10, 0x0910, "killed left freezard grotto 4-2" }, - { 0x09, 0x08, 0x0908, "killed blue chu-chu grotto 3-3" }, - { 0x09, 0x04, 0x0904, "broke ice wall 2 grotto 4-2" }, - { 0x09, 0x02, 0x0902, "broke ice wall 4 grotto 4-2" }, - { 0x09, 0x01, 0x0901, "killed poe in the back entrance grotto 3-0" }, - { 0x0A, 0x80, 0x0A80, "killed poe next to entrance grotto 3-0" }, - { 0x0A, 0x40, 0x0A40, "broke ice wall 3 grotto 4-2" }, - { 0x0A, 0x20, 0x0A20, "broke ice wall 6 grotto 4-2" }, - { 0x0A, 0x10, 0x0A10, "broke ice wall 5 grotto 4-2" }, - { 0x0A, 0x08, 0x0A08, "killed middle poe grotto 1-3" }, - { 0x0A, 0x04, 0x0A04, "killed right poe grotto 1-3" }, - { 0x0A, 0x02, 0x0A02, "spawn big chest grotto 1-1" }, - { 0x0A, 0x01, 0x0A01, "killed all enemies grotto 4-1 (spawm chest)" }, - { 0x0B, 0x80, 0x0B80, "killed middle freezard grotto 4-2" }, - { 0x0B, 0x40, 0x0B40, "blown up rocks in grotto 3-2" }, - { 0x0B, 0x20, 0x0B20, "killed all enemies grotto 5-2 (spawm chest)" }, - { 0x0B, 0x10, 0x0B10, "killed all enemies grotto 4-0 (spawm chest)" }, - { 0x0B, 0x08, 0x0B08, "killed all enemies grotto 2-2 (spawm chest)" }, - { 0x0B, 0x04, 0x0B04, "killed all enemies grotto 2-0 (spawm chest)" }, - { 0x0B, 0x02, 0x0B02, "killed all enemies grotto 5-0 (spawm chest)" }, - { 0x0B, 0x01, 0x0B01, "killed all enemies grotto 1-0 (spawm chest)" }, - { 0x0E, 0x10, 0x0E10, "spawn big chest grotto 4-3" }, - { 0x0E, 0x08, 0x0E08, "lit torch 3 grotto 4-3" }, - { 0x0E, 0x04, 0x0E04, "lit torch 2 grotto 4-3" }, - { 0x0E, 0x02, 0x0E02, "lit torch 1 grotto 4-3" }, - { 0x0E, 0x01, 0x0E01, "spawn big chest grotto 3-0" }, - { 0x0F, 0x80, 0x0F80, "lit right torch grotto 3-0" }, - { 0x0F, 0x40, 0x0F40, "lit middle torch grotto 3-0" }, - { 0x0F, 0x20, 0x0F20, "lit left torch grotto 3-0" }, - { 0x0F, 0x10, 0x0F10, "spawn big chest grotto 1-2" }, - { 0x0F, 0x08, 0x0F08, "lit middle torch grotto 1-2" }, - { 0x0F, 0x04, 0x0F04, "lit right torch grotto 1-2" }, - { 0x0F, 0x02, 0x0F02, "lit left torch grotto 1-2" }, - { 0x1A, 0x02, 0x1A02, "picked up yellow rupee from pot grotto 1-2" }, - { 0x1A, 0x01, 0x1A01, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x80, 0x1B80, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x40, 0x1B40, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x20, 0x1B20, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x10, 0x1B10, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x08, 0x1B08, "picked up blue rupee from pot grotto 1-2" }, - { 0x1B, 0x04, 0x1B04, "picked up yellow rupee from pot grotto 1-2" }, - { 0x1B, 0x02, 0x1B02, "picked up red rupee from pot grotto 1-2" }, - { 0x1B, 0x01, 0x1B01, "picked up red rupee from pot grotto 1-2" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "big chest grotto 5-4" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "big chest grotto 4-3" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "left small chest grotto 2-0" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "right small chest grotto 2-0" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "small chest grotto 5-3" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "big chest grotto 4-2" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "big chest grotto 3-0" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "south small chest grotto 2-1" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "east small chest grotto 2-1" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "north small chest grotto 2-1" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "small chest grotto 1-1" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "big chest grotto 4-1" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "big chest grotto 1-2" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "big chest grotto 1-1" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "big chest grotto 5-2" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "big chest grotto 4-0" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "big chest grotto 2-2" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "big chest grotto 2-0" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "big chest grotto 5-0" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "big chest grotto 1-0" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "lit right torch grotto 1-1" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "lit left torch grotto 1-1" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "killed red chu-chu grotto 3-3" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "killed chu-chu grotto 3-2" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "killed blue chu-chu grotto 3-1" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "killed chu-chu grotto 2-0" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "killed chu-chu grotto 1-2" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "killed right freezard grotto 4-2" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "broke ice wall 1 grotto 4-2" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "killed chu-chu grotto 1-1" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "killed all enemies grotto 5-4 (spawm chest)" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "killed left freezard grotto 4-2" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "killed blue chu-chu grotto 3-3" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "broke ice wall 2 grotto 4-2" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "broke ice wall 4 grotto 4-2" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "killed poe in the back entrance grotto 3-0" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "killed poe next to entrance grotto 3-0" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "broke ice wall 3 grotto 4-2" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "broke ice wall 6 grotto 4-2" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "broke ice wall 5 grotto 4-2" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "killed middle poe grotto 1-3" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "killed right poe grotto 1-3" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "spawn big chest grotto 1-1" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "killed all enemies grotto 4-1 (spawm chest)" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "killed middle freezard grotto 4-2" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "blown up rocks in grotto 3-2" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "killed all enemies grotto 5-2 (spawm chest)" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "killed all enemies grotto 4-0 (spawm chest)" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "killed all enemies grotto 2-2 (spawm chest)" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "killed all enemies grotto 2-0 (spawm chest)" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "killed all enemies grotto 5-0 (spawm chest)" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "killed all enemies grotto 1-0 (spawm chest)" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "spawn big chest grotto 4-3" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "lit torch 3 grotto 4-3" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "lit torch 2 grotto 4-3" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "lit torch 1 grotto 4-3" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "spawn big chest grotto 3-0" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "lit right torch grotto 3-0" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "lit middle torch grotto 3-0" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "lit left torch grotto 3-0" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "spawn big chest grotto 1-2" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "lit middle torch grotto 1-2" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "lit right torch grotto 1-2" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "lit left torch grotto 1-2" }, + { 0x1A, 0x02, AreaFlagInd{0x1A02}, "picked up yellow rupee from pot grotto 1-2" }, + { 0x1A, 0x01, AreaFlagInd{0x1A01}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x80, AreaFlagInd{0x1B80}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x40, AreaFlagInd{0x1B40}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x20, AreaFlagInd{0x1B20}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x10, AreaFlagInd{0x1B10}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x04, AreaFlagInd{0x1B04}, "picked up yellow rupee from pot grotto 1-2" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "picked up red rupee from pot grotto 1-2" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up red rupee from pot grotto 1-2" }, }; inline EventAreaFlags eventAreaFlagsHC[] = { - { 0x00, 0x40, 0x0040, "big chest behind first gate in graveyard" }, - { 0x00, 0x20, 0x0020, "second small chest treasure room" }, - { 0x00, 0x10, 0x0010, "eighth small chest treasure room" }, - { 0x00, 0x08, 0x0008, "seventh small chest treasure room" }, - { 0x00, 0x04, 0x0004, "sixth small chest treasure room" }, - { 0x00, 0x02, 0x0002, "big chest north room 2F" }, - { 0x01, 0x80, 0x0180, "fourth small chest treasure room" }, - { 0x01, 0x40, 0x0140, "fifth small chest treasure room" }, - { 0x01, 0x20, 0x0120, "third small chest treasure room" }, - { 0x01, 0x08, 0x0108, "fifth big chest treasure room" }, - { 0x01, 0x04, 0x0104, "fourth big chest treasure room" }, - { 0x01, 0x02, 0x0102, "third big chest treasure room" }, - { 0x01, 0x01, 0x0101, "second big chest treasure room" }, - { 0x02, 0x80, 0x0280, "first big chest treasure room" }, - { 0x02, 0x20, 0x0220, "north west big chest center room 2F" }, - { 0x02, 0x08, 0x0208, "small chest east garden" }, - { 0x02, 0x02, 0x0202, "north small chest west garden" }, - { 0x02, 0x01, 0x0201, "compass north east big chest center room 2F" }, - { 0x03, 0x80, 0x0380, "small key big chest behind third gate in graveyard" }, - { 0x03, 0x20, 0x0320, "center small chest west garden" }, - { 0x03, 0x10, 0x0310, "map big chest east garden" }, - { 0x03, 0x08, 0x0308, "king bulblin small key" }, - { 0x03, 0x04, 0x0304, "south west big chest center room 2F" }, - { 0x03, 0x02, 0x0302, "small key big chest outside 2F" }, - { 0x03, 0x01, 0x0301, "big key chest" }, - { 0x07, 0x08, 0x0708, "first small chest treasure room" }, - { 0x07, 0x04, 0x0704, "east small chest behind first gate in graveyard" }, - { 0x07, 0x02, 0x0702, "west small chest behind first gate in graveyard" }, - { 0x08, 0x10, 0x0810, "killed darknut in north room 2F (spawn big chest)" }, - { 0x08, 0x08, 0x0808, "reach end of specter maze 3F" }, - { 0x08, 0x04, 0x0804, "darknut 4F intro cs part 2" }, - { 0x08, 0x02, 0x0802, "darknut 4F intro cs part 1" }, - { 0x08, 0x01, 0x0801, "cut painting in north east room 2F cs" }, - { 0x09, 0x80, 0x0980, "cut painting in north east room 2F cs" }, - { 0x09, 0x40, 0x0940, "killed all enemies in center room 1F cs 1/2" }, - { 0x09, 0x20, 0x0920, "spawn north east big chest center room 2F" }, - { 0x09, 0x10, 0x0910, "killed lizalfos garding big key chest" }, - { 0x09, 0x08, 0x0908, "open third gate in graveyard cs" }, - { 0x09, 0x04, 0x0904, "blown up rock in graveyard" }, - { 0x09, 0x02, 0x0902, "lit torch behind first gate in graveyard (stops rain)" }, - { 0x09, 0x01, 0x0901, "graveyard intro cs" }, - { 0x0A, 0x80, 0x0A80, "open second gate in graveyard cs" }, - { 0x0A, 0x40, 0x0A40, "open first gate in graveyard cs" }, - { 0x0A, 0x20, 0x0A20, "open third gate in graveyard" }, - { 0x0A, 0x10, 0x0A10, "open first gate in graveyard" }, - { 0x0A, 0x04, 0x0A04, "open second gate in graveyard" }, - { 0x0B, 0x01, 0x0B01, "defeated dark beast Ganon" }, - { 0x0C, 0x40, 0x0C40, "cut first left painting in north west room 2F" }, - { 0x0C, 0x20, 0x0C20, "cut second left painting in north west room 2F" }, - { 0x0C, 0x10, 0x0C10, "cut third left painting in north west room 2F" }, - { 0x0C, 0x02, 0x0C02, "killed all enemies in center room 1F" }, - { 0x0D, 0x80, 0x0D80, "despawn yellow magic walls in center room 1F" }, - { 0x0D, 0x40, 0x0D40, "spawn yellow magic walls in center room 1F" }, - { 0x0D, 0x20, 0x0D20, "outside 4F intro cs" }, - { 0x0D, 0x10, 0x0D10, "outside 4F intro cs" }, - { 0x0D, 0x08, 0x0D08, "killed all east bokoblins in south garden" }, - { 0x0D, 0x04, 0x0D04, "killed all west bokoblins in south garden" }, - { 0x0D, 0x01, 0x0D01, "east room 2F intro cs" }, - { 0x0E, 0x80, 0x0E80, "east room 2F intro cs" }, - { 0x0E, 0x10, 0x0E10, "killed right lezalfos in north west room 2F" }, - { 0x0E, 0x08, 0x0E08, "killed left lezalfos in north west room 2F" }, - { 0x0E, 0x01, 0x0E01, "midna text at the end of east garden (talk about wall)" }, - { 0x0F, 0x80, 0x0F80, "explored graveyard" }, - { 0x10, 0x80, 0x1080, "killed both lizalfos in 4F (removes yellow magic barrior)" }, - { 0x10, 0x40, 0x1040, "killed both lizalfos in 3F (removes yellow magic barrior)" }, - { 0x10, 0x20, 0x1020, "south garden intro cs" }, - { 0x10, 0x02, 0x1002, "Midna text prompt after king bulblin" }, - { 0x10, 0x01, 0x1001, "killed all bokoblins in west garden" }, - { 0x11, 0x80, 0x1180, "prevent all torches form extinguishing north east room 2F" }, - { 0x11, 0x40, 0x1140, "unlock door in north east room 2F cs" }, - { 0x11, 0x10, 0x1110, "open second gate in west garden" }, - { 0x11, 0x08, 0x1108, "east garden intro cs" }, - { 0x11, 0x04, 0x1104, "east garden intro cs" }, - { 0x11, 0x02, 0x1102, "open gate in east garden" }, - { 0x11, 0x01, 0x1101, "open gate in east garden cs" }, - { 0x12, 0x80, 0x1280, "unlock door in north east room 2F" }, - { 0x12, 0x40, 0x1240, "lit all torches correctly in north east room 2F" }, - { 0x12, 0x20, 0x1220, "lit all torches correctly in north east room 2F cs" }, - { 0x12, 0x10, 0x1210, "unlock door outside 3F" }, - { 0x12, 0x08, 0x1208, "open gate to big key chest" }, - { 0x12, 0x04, 0x1204, "killed arealfos outside 2F" }, - { 0x12, 0x01, 0x1201, "killed all enemies in center room 1F cs 1/2" }, - { 0x13, 0x40, 0x1340, "Double Darknut room intro cs" }, - { 0x13, 0x08, 0x1308, "spawn north west big chest center room 2F" }, - { 0x13, 0x04, 0x1304, "west room 2F intro cs" }, - { 0x13, 0x02, 0x1302, "cut right painting in north west room 2F" }, - { 0x14, 0x40, 0x1440, "unlock boss door" }, - { 0x14, 0x10, 0x1410, "unlock door in south garden" }, - { 0x14, 0x08, 0x1408, "midna text seen after small key in graveyard" }, - { 0x14, 0x04, 0x1404, "midna text promt after small key in graveyard" }, - { 0x14, 0x02, 0x1402, "Midna text seen after king bulblin" }, - { 0x14, 0x01, 0x1401, "north west room 2F intro cs" }, - { 0x15, 0x40, 0x1540, "cut painting in north east room 2F" }, - { 0x15, 0x08, 0x1508, "second gate in west garden stops moving" }, - { 0x15, 0x04, 0x1504, "open second gate in west garden cs" }, - { 0x15, 0x01, 0x1501, "killed dynalfos in east room 2F (unlocks doors)" }, - { 0x16, 0x80, 0x1680, "unlock treasure room door 4F" }, - { 0x16, 0x04, 0x1604, "killed darknuts in west room 2F (unlocks doors)" }, - { 0x16, 0x02, 0x1602, "reach big chest in north room 2F" }, - { 0x16, 0x01, 0x1601, "lit south east torch north room 2F for the first time cs" }, - { 0x17, 0x80, 0x1780, "lit north east torch north room 2F for the first time cs" }, - { 0x17, 0x10, 0x1710, "unlock door in north west room 2F" }, - { 0x17, 0x01, 0x1701, "killed darknut 4F (removes yellow magic barrier)" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "big chest behind first gate in graveyard" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "second small chest treasure room" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "eighth small chest treasure room" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "seventh small chest treasure room" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "sixth small chest treasure room" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "big chest north room 2F" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "fourth small chest treasure room" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "fifth small chest treasure room" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "third small chest treasure room" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "fifth big chest treasure room" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "fourth big chest treasure room" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "third big chest treasure room" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "second big chest treasure room" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "first big chest treasure room" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "north west big chest center room 2F" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "small chest east garden" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "north small chest west garden" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "compass north east big chest center room 2F" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small key big chest behind third gate in graveyard" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "center small chest west garden" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "map big chest east garden" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "king bulblin small key" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "south west big chest center room 2F" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "small key big chest outside 2F" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "big key chest" }, + { 0x07, 0x08, AreaFlagInd{0x0708}, "first small chest treasure room" }, + { 0x07, 0x04, AreaFlagInd{0x0704}, "east small chest behind first gate in graveyard" }, + { 0x07, 0x02, AreaFlagInd{0x0702}, "west small chest behind first gate in graveyard" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "killed darknut in north room 2F (spawn big chest)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "reach end of specter maze 3F" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "darknut 4F intro cs part 2" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "darknut 4F intro cs part 1" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "cut painting in north east room 2F cs" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "cut painting in north east room 2F cs" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "killed all enemies in center room 1F cs 1/2" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "spawn north east big chest center room 2F" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "killed lizalfos garding big key chest" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "open third gate in graveyard cs" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "blown up rock in graveyard" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "lit torch behind first gate in graveyard (stops rain)" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "graveyard intro cs" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "open second gate in graveyard cs" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "open first gate in graveyard cs" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "open third gate in graveyard" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "open first gate in graveyard" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "open second gate in graveyard" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "defeated dark beast Ganon" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "cut first left painting in north west room 2F" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "cut second left painting in north west room 2F" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "cut third left painting in north west room 2F" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "killed all enemies in center room 1F" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "despawn yellow magic walls in center room 1F" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "spawn yellow magic walls in center room 1F" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "outside 4F intro cs" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "outside 4F intro cs" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "killed all east bokoblins in south garden" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "killed all west bokoblins in south garden" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "east room 2F intro cs" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "east room 2F intro cs" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "killed right lezalfos in north west room 2F" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "killed left lezalfos in north west room 2F" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "midna text at the end of east garden (talk about wall)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "explored graveyard" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "killed both lizalfos in 4F (removes yellow magic barrior)" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "killed both lizalfos in 3F (removes yellow magic barrior)" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "south garden intro cs" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "Midna text prompt after king bulblin" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "killed all bokoblins in west garden" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "prevent all torches form extinguishing north east room 2F" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "unlock door in north east room 2F cs" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "open second gate in west garden" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "east garden intro cs" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "east garden intro cs" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "open gate in east garden" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "open gate in east garden cs" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "unlock door in north east room 2F" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "lit all torches correctly in north east room 2F" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "lit all torches correctly in north east room 2F cs" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "unlock door outside 3F" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "open gate to big key chest" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "killed arealfos outside 2F" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "killed all enemies in center room 1F cs 1/2" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "Double Darknut room intro cs" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "spawn north west big chest center room 2F" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "west room 2F intro cs" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "cut right painting in north west room 2F" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "unlock boss door" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "unlock door in south garden" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "midna text seen after small key in graveyard" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "midna text promt after small key in graveyard" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "Midna text seen after king bulblin" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "north west room 2F intro cs" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "cut painting in north east room 2F" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "second gate in west garden stops moving" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "open second gate in west garden cs" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "killed dynalfos in east room 2F (unlocks doors)" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "unlock treasure room door 4F" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "killed darknuts in west room 2F (unlocks doors)" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "reach big chest in north room 2F" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "lit south east torch north room 2F for the first time cs" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "lit north east torch north room 2F for the first time cs" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "unlock door in north west room 2F" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "killed darknut 4F (removes yellow magic barrier)" }, }; inline EventAreaFlags eventAreaFlagsHyruleField[] = { - { 0x02, 0x80, 0x0280, "Big chest owl statue hylia bridge" }, - { 0x02, 0x40, 0x0240, "Big chest spinner south of castle town" }, - { 0x02, 0x20, 0x0220, "Big chest double clawshot south of castle town" }, - { 0x02, 0x10, 0x0210, "Big chest tight rope south of castle town" }, - { 0x02, 0x08, 0x0208, "Big chest owl statue next to castle town" }, - { 0x02, 0x04, 0x0204, "Big chest on hylia bridge" }, - { 0x02, 0x02, 0x0202, "Big chest next to poe past hylia bridge" }, - { 0x02, 0x01, 0x0201, "Big chest spinner tracks (Lanayru)" }, - { 0x03, 0x80, 0x0380, "Big chest underwater Lanayru field" }, - { 0x03, 0x40, 0x0340, "Big chest under bridge faron field" }, - { 0x03, 0x20, 0x0320, "PoH big chest double clawshot Eldin gorge" }, - { 0x03, 0x10, 0x0310, "Big chest Eldin gorge owl statue" }, - { 0x03, 0x08, 0x0308, "PoH big chest owl statue Eldin bridge" }, - { 0x03, 0x04, 0x0304, "PoH big chest leage Eldin field after kakariko" }, - { 0x03, 0x02, 0x0302, "Map marker Telma carrage past hylia bridge" }, - { 0x03, 0x01, 0x0301, "Map marker Telma carrage west of castle town" }, - { 0x08, 0x80, 0x0880, "Lanayru field intro cs twilight" }, - { 0x08, 0x20, 0x0820, "blown up rock blocking Eldin long cave" }, - { 0x08, 0x10, 0x0810, "Hidden village path open" }, - { 0x08, 0x08, 0x0808, "East Castle Town Bridge Flag" }, - { 0x08, 0x04, 0x0804, "blown up rocks blocking path to zora's domain" }, - { 0x08, 0x01, 0x0801, "Midna pulls up the map to show you can warp" }, - { 0x09, 0x80, 0x0980, "midna text Eldin gorge bridge gone" }, - { 0x09, 0x40, 0x0940, "exit flight by foul after lanayru twilight cleared" }, - { 0x09, 0x20, 0x0920, "Kakariko Gorge Portal" }, - { 0x09, 0x10, 0x0910, "spawn barriers Eldin gorge dark beasts (unset once killed)" }, - { 0x09, 0x08, 0x0908, "bridge of Eldin placed (cs)" }, - { 0x09, 0x04, 0x0904, "Eldin bridge getting stolen cs trigger" }, - { 0x09, 0x02, 0x0902, "blown up rocks past Eldin bridge that lead to Lanayru" }, - { 0x09, 0x01, 0x0901, "see gorge gate cs" }, - { 0x0A, 0x80, 0x0A80, "blown up rocks to spinner tracks (Lanayru field side)" }, - { 0x0A, 0x40, 0x0A40, "blown up rocks to spinner tracks (hylia bridge side)" }, - { 0x0A, 0x20, 0x0A20, "entered Lanayru twilight cs" }, - { 0x0A, 0x10, 0x0A10, "entered Eldin twilight cs" }, - { 0x0A, 0x08, 0x0A08, "killed left shadow bulblin behind gorge gate twilight" }, - { 0x0A, 0x04, 0x0A04, "killed right shadow bulblin behind gorge gate twilight" }, - { 0x0A, 0x02, 0x0A02, "jumped over gorge fence after obtaining Epona" }, - { 0x0B, 0x80, 0x0B80, "Lanayru Main Feild has water on map" }, - { 0x0B, 0x40, 0x0B40, "seeing Lanayru twilight from up close cs" }, - { 0x0B, 0x20, 0x0B20, "seeing Eldin twilight from up close cs" }, - { 0x0B, 0x10, 0x0B10, "spawn dark beasts castle town portal (stays set)" }, - { 0x0B, 0x08, 0x0B08, "Castle Town Portal" }, - { 0x0B, 0x04, 0x0B04, "?" }, - { 0x0B, 0x01, 0x0B01, "blown up rocks from Eldin gorge to Eldin field" }, - { 0x0C, 0x80, 0x0C80, "blown up second rock to poe past hylia bridge" }, - { 0x0C, 0x20, 0x0C20, "Epona is accessible to Link (without calling her) (after lanayru twilight)" }, - { 0x0C, 0x08, 0x0C08, "killed poe past hylia bridge" }, - { 0x0C, 0x04, 0x0C04, "killed poe Eldin gorge" }, - { 0x0C, 0x02, 0x0C02, "killed poe faron field" }, - { 0x0D, 0x80, 0x0D80, "Midna text after warping gorge bridge back" }, - { 0x0D, 0x40, 0x0D40, "?" }, - { 0x0D, 0x10, 0x0D10, "spinner path next to hidden village explored" }, - { 0x0D, 0x08, 0x0D08, "killed poe Lanayru field" }, - { 0x0D, 0x02, 0x0D02, "enter field west of castle town from the east" }, - { 0x0D, 0x01, 0x0D01, "killed poe south of castle town" }, - { 0x0E, 0x80, 0x0E80, "bridge of Hylia intro cs twilight" }, - { 0x0E, 0x40, 0x0E40, "blown up rock blocking ice cave Lanayru field" }, - { 0x0E, 0x20, 0x0E20, "faron field intro cs" }, - { 0x0E, 0x10, 0x0E10, "blown up rock on leadge Eldin field after kakariko" }, - { 0x0E, 0x08, 0x0E08, "blown up first rock to poe past hylia bridge" }, - { 0x0E, 0x04, 0x0E04, "Hero's shade map marker (south castle town)" }, - { 0x0E, 0x02, 0x0E02, "Hero's shade map marker (west castle town)" }, - { 0x0E, 0x01, 0x0E01, "enter bridge east of castle town" }, - { 0x0F, 0x80, 0x0F80, "enter field south of castle town" }, - { 0x0F, 0x40, 0x0F40, "enter field west of castle town from the north" }, - { 0x0F, 0x20, 0x0F20, "?" }, - { 0x0F, 0x10, 0x0F10, "open path from faron field to south of castle town" }, - { 0x0F, 0x08, 0x0F08, "Midna text after Lanayru field twilight cs" }, - { 0x0F, 0x04, 0x0F04, "blown up rocks Eldin field after kakariko" }, - { 0x0F, 0x02, 0x0F02, "Eldin gorge bridge placed cs" }, - { 0x0F, 0x01, 0x0F01, "see Ilia's bag from far away" }, - { 0x10, 0x01, 0x1001, "Zora rivver boat path on map (Eldin)" }, - { 0x11, 0x80, 0x1180, "Sky letter next to castle town" }, - { 0x11, 0x40, 0x1140, "Map marker owl stature next to castle town" }, - { 0x11, 0x20, 0x1120, "Sky letter hylia bridge" }, - { 0x11, 0x10, 0x1110, "Map marker owl stature Hylia bridge" }, - { 0x11, 0x08, 0x1108, "Sky letter Eldin bridge" }, - { 0x11, 0x04, 0x1104, "Map marker owl stature Eldin bridge" }, - { 0x11, 0x02, 0x1102, "Sky letter Eldin gorge" }, - { 0x11, 0x01, 0x1101, "Map marker owl stature Eldin gorge" }, - { 0x12, 0x10, 0x1210, "blown up northern rock in field west of castle town" }, - { 0x12, 0x08, 0x1208, "blown up most northern rock in field west of castle town" }, - { 0x12, 0x04, 0x1204, "blown up rock south of castle town" }, - { 0x12, 0x02, 0x1202, "killed poe next to owl statue next to castle town" }, - { 0x13, 0x80, 0x1380, "killed poe east of castle town" }, - { 0x13, 0x10, 0x1310, "?" }, - { 0x13, 0x08, 0x1308, "?" }, - { 0x13, 0x04, 0x1304, "Epona isn't accessible to Link (without calling her) (after lanayru twilight)" }, - { 0x13, 0x02, 0x1302, "?" }, - { 0x13, 0x01, 0x1301, "Map marker hidden village" }, - { 0x14, 0x80, 0x1480, "blown up southern rock underwater Lanayru field" }, - { 0x14, 0x40, 0x1440, "blown up northern rock underwater Lanayru field" }, - { 0x14, 0x20, 0x1420, "blown up eastern rock Lanayru field " }, - { 0x14, 0x10, 0x1410, "blown up rock next to hylia bridge owl statue" }, - { 0x14, 0x08, 0x1408, "blown up rock closest to faron after hylia bridge" }, - { 0x14, 0x04, 0x1404, "blown up rock next to free standing PoH Elding gorge" }, - { 0x14, 0x01, 0x1401, "blown up rock next to Eldin gorge owl statue" }, - { 0x15, 0x80, 0x1580, "blown up rock past Eldin bridge" }, - { 0x16, 0x20, 0x1620, "Midna text after getting Ilia's scent" }, - { 0x16, 0x10, 0x1610, "Midna text after entering Lanayru twilight" }, - { 0x16, 0x08, 0x1608, "Midna text when seeing Lanayru twilight from far away" }, - { 0x16, 0x04, 0x1604, "Midna text after getting Youth's scent" }, - { 0x16, 0x02, 0x1602, "Midna text after entering Eldin twilight" }, - { 0x16, 0x01, 0x1601, "Midna text when seeing Eldin twilight from far away" }, - { 0x17, 0x80, 0x1780, "got Ilia's scent cs" }, - { 0x17, 0x40, 0x1740, "got youth's scent cs" }, - { 0x17, 0x20, 0x1720, "Epona can't cross Eldin bridge (set when stolen, unset when fixed)" }, - { 0x17, 0x10, 0x1710, "see broken wooden sword from far away cs" }, - { 0x17, 0x08, 0x1708, "Bridge of Eldin Portal" }, - { 0x1A, 0x80, 0x1A80, "picked up rupees from rock past Eldin bridge" }, - { 0x1A, 0x40, 0x1A40, "picked up rupees from rock next to free standing PoH Elding gorge" }, - { 0x1A, 0x20, 0x1A20, "picked up rupees from rock next to Eldin gorge owl statue" }, - { 0x1A, 0x10, 0x1A10, "picked up rupees from rock closest to faron after hylia bridge" }, - { 0x1A, 0x08, 0x1A08, "picked up rupees from rock next to hylia bridge owl statue" }, - { 0x1A, 0x04, 0x1A04, "picked up rupees from rocks to spinner tracks (hylia bridge side)" }, - { 0x1A, 0x02, 0x1A02, "picked up rupees from rocks to spinner tracks (Lanayru field side)" }, - { 0x1A, 0x01, 0x1A01, "picked up rupees from eastern rock Lanayru field " }, - { 0x1B, 0x80, 0x1B80, "picked up rupees from northern rock underwater Lanayru field" }, - { 0x1B, 0x40, 0x1B40, "picked up rupees from southern rock underwater Lanayru field" }, - { 0x1B, 0x20, 0x1B20, "picked up rupees from northern rock in field west of castle town" }, - { 0x1B, 0x10, 0x1B10, "picked up rupees from most northern rock in field west of castle town" }, - { 0x1B, 0x08, 0x1B08, "picked up rupees from rock south of castle town" }, - { 0x1B, 0x04, 0x1B04, "free standing PoH Elding gorge" }, - { 0x1B, 0x02, 0x1B02, "free standing PoH faron field" }, - { 0x1B, 0x01, 0x1B01, "free standing PoH goron Eldin field" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "Big chest owl statue hylia bridge" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "Big chest spinner south of castle town" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "Big chest double clawshot south of castle town" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "Big chest tight rope south of castle town" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "Big chest owl statue next to castle town" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "Big chest on hylia bridge" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "Big chest next to poe past hylia bridge" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "Big chest spinner tracks (Lanayru)" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "Big chest underwater Lanayru field" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "Big chest under bridge faron field" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "PoH big chest double clawshot Eldin gorge" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "Big chest Eldin gorge owl statue" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "PoH big chest owl statue Eldin bridge" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "PoH big chest leage Eldin field after kakariko" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "Map marker Telma carrage past hylia bridge" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "Map marker Telma carrage west of castle town" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "Lanayru field intro cs twilight" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "blown up rock blocking Eldin long cave" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "Hidden village path open" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "East Castle Town Bridge Flag" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "blown up rocks blocking path to zora's domain" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "Midna pulls up the map to show you can warp" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "midna text Eldin gorge bridge gone" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "exit flight by foul after lanayru twilight cleared" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Kakariko Gorge Portal" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "spawn barriers Eldin gorge dark beasts (unset once killed)" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "bridge of Eldin placed (cs)" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "Eldin bridge getting stolen cs trigger" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "blown up rocks past Eldin bridge that lead to Lanayru" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "see gorge gate cs" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "blown up rocks to spinner tracks (Lanayru field side)" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "blown up rocks to spinner tracks (hylia bridge side)" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "entered Lanayru twilight cs" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "entered Eldin twilight cs" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "killed left shadow bulblin behind gorge gate twilight" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "killed right shadow bulblin behind gorge gate twilight" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "jumped over gorge fence after obtaining Epona" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "Lanayru Main Feild has water on map" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "seeing Lanayru twilight from up close cs" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "seeing Eldin twilight from up close cs" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "spawn dark beasts castle town portal (stays set)" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "Castle Town Portal" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "?" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "blown up rocks from Eldin gorge to Eldin field" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "blown up second rock to poe past hylia bridge" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "Epona is accessible to Link (without calling her) (after lanayru twilight)" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "killed poe past hylia bridge" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "killed poe Eldin gorge" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "killed poe faron field" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "Midna text after warping gorge bridge back" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "?" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "spinner path next to hidden village explored" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "killed poe Lanayru field" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "enter field west of castle town from the east" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "killed poe south of castle town" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "bridge of Hylia intro cs twilight" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "blown up rock blocking ice cave Lanayru field" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "faron field intro cs" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "blown up rock on leadge Eldin field after kakariko" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "blown up first rock to poe past hylia bridge" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "Hero's shade map marker (south castle town)" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "Hero's shade map marker (west castle town)" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "enter bridge east of castle town" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "enter field south of castle town" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "enter field west of castle town from the north" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "?" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "open path from faron field to south of castle town" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "Midna text after Lanayru field twilight cs" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "blown up rocks Eldin field after kakariko" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "Eldin gorge bridge placed cs" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "see Ilia's bag from far away" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "Zora rivver boat path on map (Eldin)" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "Sky letter next to castle town" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "Map marker owl stature next to castle town" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "Sky letter hylia bridge" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "Map marker owl stature Hylia bridge" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "Sky letter Eldin bridge" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "Map marker owl stature Eldin bridge" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "Sky letter Eldin gorge" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "Map marker owl stature Eldin gorge" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "blown up northern rock in field west of castle town" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "blown up most northern rock in field west of castle town" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "blown up rock south of castle town" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "killed poe next to owl statue next to castle town" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "killed poe east of castle town" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "?" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "?" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "Epona isn't accessible to Link (without calling her) (after lanayru twilight)" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "?" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "Map marker hidden village" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "blown up southern rock underwater Lanayru field" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "blown up northern rock underwater Lanayru field" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "blown up eastern rock Lanayru field " }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "blown up rock next to hylia bridge owl statue" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "blown up rock closest to faron after hylia bridge" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "blown up rock next to free standing PoH Elding gorge" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "blown up rock next to Eldin gorge owl statue" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "blown up rock past Eldin bridge" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "Midna text after getting Ilia's scent" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "Midna text after entering Lanayru twilight" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "Midna text when seeing Lanayru twilight from far away" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "Midna text after getting Youth's scent" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "Midna text after entering Eldin twilight" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "Midna text when seeing Eldin twilight from far away" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "got Ilia's scent cs" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "got youth's scent cs" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "Epona can't cross Eldin bridge (set when stolen, unset when fixed)" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "see broken wooden sword from far away cs" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "Bridge of Eldin Portal" }, + { 0x1A, 0x80, AreaFlagInd{0x1A80}, "picked up rupees from rock past Eldin bridge" }, + { 0x1A, 0x40, AreaFlagInd{0x1A40}, "picked up rupees from rock next to free standing PoH Elding gorge" }, + { 0x1A, 0x20, AreaFlagInd{0x1A20}, "picked up rupees from rock next to Eldin gorge owl statue" }, + { 0x1A, 0x10, AreaFlagInd{0x1A10}, "picked up rupees from rock closest to faron after hylia bridge" }, + { 0x1A, 0x08, AreaFlagInd{0x1A08}, "picked up rupees from rock next to hylia bridge owl statue" }, + { 0x1A, 0x04, AreaFlagInd{0x1A04}, "picked up rupees from rocks to spinner tracks (hylia bridge side)" }, + { 0x1A, 0x02, AreaFlagInd{0x1A02}, "picked up rupees from rocks to spinner tracks (Lanayru field side)" }, + { 0x1A, 0x01, AreaFlagInd{0x1A01}, "picked up rupees from eastern rock Lanayru field " }, + { 0x1B, 0x80, AreaFlagInd{0x1B80}, "picked up rupees from northern rock underwater Lanayru field" }, + { 0x1B, 0x40, AreaFlagInd{0x1B40}, "picked up rupees from southern rock underwater Lanayru field" }, + { 0x1B, 0x20, AreaFlagInd{0x1B20}, "picked up rupees from northern rock in field west of castle town" }, + { 0x1B, 0x10, AreaFlagInd{0x1B10}, "picked up rupees from most northern rock in field west of castle town" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "picked up rupees from rock south of castle town" }, + { 0x1B, 0x04, AreaFlagInd{0x1B04}, "free standing PoH Elding gorge" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "free standing PoH faron field" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "free standing PoH goron Eldin field" }, }; inline EventAreaFlags eventAreaFlagsLanayru[] = { - { 0x00, 0x40, 0x0040, "small chest next to mother and child iles zora's domain" }, - { 0x00, 0x20, 0x0020, "big chest fountain back room" }, - { 0x00, 0x10, 0x0010, "left small chest fountain back room" }, - { 0x00, 0x08, 0x0008, "right small chest fountain back room" }, - { 0x00, 0x04, 0x0004, "small chest midna jumps zora's domain" }, - { 0x01, 0x10, 0x0110, "west big chest zora's domain throne room" }, - { 0x01, 0x08, 0x0108, "east big chest zora's domain throne room" }, - { 0x02, 0x10, 0x0210, "small chest large underwater pillar in fountain" }, - { 0x02, 0x04, 0x0204, "small chest small underwater pillar in fountain" }, - { 0x02, 0x01, 0x0201, "small chest floor 3 flight by foul" }, - { 0x03, 0x80, 0x0380, "small chest floor 2 flight by foul" }, - { 0x03, 0x40, 0x0340, "big chest right pillar in front of fountain Lake Hylia" }, - { 0x03, 0x20, 0x0320, "big chest underwater next to Lake Hylia warp" }, - { 0x03, 0x10, 0x0310, "east big chest fountain" }, - { 0x03, 0x08, 0x0308, "west big chest fountain" }, - { 0x03, 0x04, 0x0304, "big chest floor 4 flight by foul" }, - { 0x03, 0x02, 0x0302, "small chest left pillar in front of fountain Lae Hylia" }, - { 0x03, 0x01, 0x0301, "big chest floor 5 flight by foul" }, - { 0x04, 0x40, 0x0440, "tear of light throne room zora's domain" }, - { 0x04, 0x20, 0x0420, "first tear of light flying" }, - { 0x04, 0x10, 0x0410, "tear of light midna jumps zora's domain" }, - { 0x04, 0x08, 0x0408, "tear of light on top of water zora's domain" }, - { 0x04, 0x04, 0x0404, "third tear of light flying" }, - { 0x04, 0x02, 0x0402, "fourth tear of light flying" }, - { 0x05, 0x80, 0x0580, "tear of light next to Iza's shop" }, - { 0x05, 0x40, 0x0540, "second tear of light flying" }, - { 0x05, 0x20, 0x0520, "final tear of light" }, - { 0x05, 0x04, 0x0504, "tear of light behind of Fyer's canon" }, - { 0x05, 0x02, 0x0502, "tear of light island east of Lake Hylia" }, - { 0x05, 0x01, 0x0501, "tear of light southmost island Lake Hylia" }, - { 0x06, 0x80, 0x0680, "tear of light next to fountain Lake Hylia" }, - { 0x06, 0x40, 0x0640, "tear of light on top of water zora's domain" }, - { 0x06, 0x20, 0x0620, "tear of light next to mother and child iles zora's domain" }, - { 0x08, 0x80, 0x0880, "see frozen zora spirits in domain twilight" }, - { 0x08, 0x40, 0x0840, "Lake hylia intro cs twilight" }, - { 0x08, 0x20, 0x0820, "blown up underwater rock in center of fountain" }, - { 0x08, 0x10, 0x0810, "the two zoras in upper zora river went down stream (twilight)" }, - { 0x08, 0x08, 0x0808, "saw light bug come out next to Iza spirit cs" }, - { 0x08, 0x02, 0x0802, "blown up rock to Lake hylia long cave" }, - { 0x08, 0x01, 0x0801, "spawned UZR portal fight barriers" }, - { 0x09, 0x80, 0x0980, "opened Upper Zora's River Portal cs" }, - { 0x09, 0x40, 0x0940, "talked to Iza before UZR portal" }, - { 0x09, 0x20, 0x0920, "Upper Zora's River Portal" }, - { 0x09, 0x10, 0x0910, "spawn big chest fountain back room" }, - { 0x09, 0x08, 0x0908, "lit left torch fountain back room" }, - { 0x09, 0x04, 0x0904, "lit right torch fountain back room" }, - { 0x09, 0x02, 0x0902, "seeing Twilight Bloat with sense cs" }, - { 0x09, 0x01, 0x0901, "Twilight Bloat comes out of water cs" }, - { 0x0A, 0x80, 0x0A80, "seeing Twilit Bloat move from far away cs" }, - { 0x0A, 0x40, 0x0A40, "Save Prompt after Lakebed (if disabled, triggers MDH after Lakebed)" }, - { 0x0A, 0x20, 0x0A20, "twilight end cs trigger (also map marker Lakebed Temple)" }, - { 0x0A, 0x10, 0x0A10, "obtained vessel of light (unset after twilight)" }, - { 0x0A, 0x08, 0x0A08, "spawn dark beasts Lake Hylia (unset once killed)" }, - { 0x0A, 0x04, 0x0A04, "Lake Hylia Portal" }, - { 0x0A, 0x02, 0x0A02, "Zora's river intro cs during twilight (flying with bird)" }, - { 0x0A, 0x01, 0x0A01, "midna text promt saying you can call down Kargarok to fly" }, - { 0x0B, 0x80, 0x0B80, "Rutella cs in domain twilight" }, - { 0x0B, 0x40, 0x0B40, "Zora river boat path on map" }, - { 0x0B, 0x20, 0x0B20, "entered Twilight Bloat arena (unset once killed)" }, - { 0x0B, 0x10, 0x0B10, "explored entrance to snowpeak" }, - { 0x0B, 0x08, 0x0B08, "got PoH flight by foul" }, - { 0x0B, 0x04, 0x0B04, "Zora's Domain Portal" }, - { 0x0B, 0x02, 0x0B02, "spawn barriers Zora's domain dark beasts fight" }, - { 0x0B, 0x01, 0x0B01, "Zora's domain intro cs twilight (frozen)" }, - { 0x0C, 0x08, 0x0C08, "blown up south underwater rock zora's domain " }, - { 0x0C, 0x04, 0x0C04, "blown up north underwater rock zora's domain" }, - { 0x0C, 0x02, 0x0C02, "blown up underwater rock in back of fountain" }, - { 0x0C, 0x01, 0x0C01, "Midna text after landing in Lake hylia twilight" }, - { 0x0D, 0x80, 0x0D80, "Iza text after Upper Zora's River Portal" }, - { 0x0D, 0x40, 0x0D40, "can now exit from the sides of zora's domain inside (set during domain outside cs after melting it)" }, - { 0x0D, 0x20, 0x0D20, "Midna text after domain outside cs after melting it" }, - { 0x0D, 0x10, 0x0D10, "domain outside cs after melting it" }, - { 0x0D, 0x08, 0x0D08, "map marker Auru" }, - { 0x0D, 0x04, 0x0D04, "Upper zora's river intro cs during twilight" }, - { 0x0D, 0x02, 0x0D02, "Midna text after leaving lake hylia after Lanayru twilight" }, - { 0x0D, 0x01, 0x0D01, "Zora's domain waterfall is going fast (during twilight only) (unset when you come back to Lake hylia)" }, - { 0x0E, 0x80, 0x0E80, "blown up rock blocking lakebed entrance cs" }, - { 0x0E, 0x40, 0x0E40, "opened stream next to lakebed entance" }, - { 0x0E, 0x20, 0x0E20, "Midna text after arriving at upper zora's river twilight" }, - { 0x0E, 0x10, 0x0E10, "melted zora's domain (Lake Hylia water on map (top part))" }, - { 0x0E, 0x08, 0x0E08, "twilight end cs watched" }, - { 0x0E, 0x04, 0x0E04, "map marker Snowpeak" }, - { 0x0E, 0x01, 0x0E01, "Midna text after coming back to lake after filling it (twilight)" }, - { 0x0F, 0x80, 0x0F80, "blown up rock blocking lakebed entrance" }, - { 0x0F, 0x40, 0x0F40, "went down the fast water in zora's domain (void out) (unset after twilight)" }, - { 0x0F, 0x20, 0x0F20, "Lake hylia filled twilight intro cs (domain water level normal)" }, - { 0x0F, 0x10, 0x0F10, "blown up first rock to throne room zora's domain" }, - { 0x0F, 0x08, 0x0F08, "Midna text prompt to tell you to look under the ice in zora's domain twilight" }, - { 0x0F, 0x04, 0x0F04, "Midna text before midna jumps fozen zora's domain twilight" }, - { 0x0F, 0x02, 0x0F02, "Midna text before midna jumps melted zora's domain twilight" }, - { 0x0F, 0x01, 0x0F01, "Midna text after melting domain (water everywhere on map)" }, - { 0x10, 0x80, 0x1080, "blown up underwater rock zora river town path" }, - { 0x10, 0x40, 0x1040, "spawn west big chest zora's domain throne room" }, - { 0x10, 0x20, 0x1020, "spawn east big chest zora's domain throne room" }, - { 0x10, 0x10, 0x1010, "lit east torch zora's domain throne room" }, - { 0x10, 0x08, 0x1008, "extingushed north torch zora's domain throne room" }, - { 0x10, 0x04, 0x1004, "lit west torch zora's domain throne room" }, - { 0x10, 0x02, 0x1002, "blown up west underwater rock Lakebed area" }, - { 0x10, 0x01, 0x1001, "blown up south underwater rock Lakebed area" }, - { 0x11, 0x80, 0x1180, "saw the two zora spirits from far away in upper zora river cs (twilight)" }, - { 0x11, 0x40, 0x1140, "saw light bug moving after exiting lanayru spring" }, - { 0x11, 0x20, 0x1120, "went down zora's river with bird during twilight" }, - { 0x11, 0x10, 0x1110, "blown up underwater rock zora river lake path" }, - { 0x11, 0x08, 0x1108, "midna text after seeing the frozen zoras in domain twilight" }, - { 0x11, 0x02, 0x1102, "paid Fyer to launch you to the flight by foul platform (unset once you enter the canon)" }, - { 0x11, 0x01, 0x1101, "blown up north underwater rock throne room zora's domain" }, - { 0x12, 0x80, 0x1280, "Lanayru spring map marker" }, - { 0x12, 0x40, 0x1240, "Midna Text after frozen zora's domain twilight intro cs" }, - { 0x12, 0x20, 0x1220, "killed poe underneath flight by foul" }, - { 0x12, 0x10, 0x1210, "killed poe next to watch tower to desert" }, - { 0x12, 0x08, 0x1208, "killed poe east of lake Hylia" }, - { 0x12, 0x04, 0x1204, "killed poe next to mother and chile iles Zora's Domain" }, - { 0x12, 0x02, 0x1202, "killed poe midna jumps Zora's Domain" }, - { 0x12, 0x01, 0x1201, "killed poe in Upper Zora's River" }, - { 0x13, 0x80, 0x1380, "killed poe on flight by foul prizes" }, - { 0x13, 0x40, 0x1340, "killed poe next to fountain Lake Hylia" }, - { 0x13, 0x20, 0x1320, "blew up rock in Iza's house" }, - { 0x13, 0x10, 0x1310, "Iza text after blowing the rocks inside her house" }, - { 0x13, 0x01, 0x1301, "blew up rock in Iza's house cs" }, - { 0x14, 0x40, 0x1440, "killed light bug throne room zora's domain" }, - { 0x14, 0x20, 0x1420, "killed first light bug flying" }, - { 0x14, 0x10, 0x1410, "killed light bug midna jumps zora's domain" }, - { 0x14, 0x08, 0x1408, "killed light bug on top of water zora's domain" }, - { 0x14, 0x04, 0x1404, "killed third light bug flying" }, - { 0x14, 0x02, 0x1402, "killed fourth light bug flying" }, - { 0x14, 0x01, 0x1401, "killed light bug behind of Fyer's canon" }, - { 0x15, 0x80, 0x1580, "killed light bug next to Iza's shop" }, - { 0x15, 0x40, 0x1540, "killed second light bug flying" }, - { 0x15, 0x20, 0x1520, "killed final light bug (Twilight Bloat)" }, - { 0x15, 0x10, 0x1510, "killed light bug island east of Lake Hylia" }, - { 0x15, 0x02, 0x1502, "killed light bug next to mother and child iles zora's domain" }, - { 0x15, 0x01, 0x1501, "?" }, - { 0x16, 0x80, 0x1680, "Watched CS of Ooccoo running to Sky Cannon" }, - { 0x16, 0x40, 0x1640, "killed light bug on top of water zora's domain" }, - { 0x16, 0x20, 0x1620, "killed light bug southmost island Lake Hylia" }, - { 0x16, 0x10, 0x1610, "killed light bug next to fountain Lake Hylia" }, - { 0x16, 0x02, 0x1602, "talked to light spirit during twilight" }, - { 0x16, 0x01, 0x1601, "went up zora's river after melting domain in twilight" }, - { 0x17, 0x80, 0x1780, "blown up rock zora river on land" }, - { 0x17, 0x40, 0x1740, "went up zora's river after melting domain in twilight (also set when failing to do so)" }, - { 0x17, 0x20, 0x1720, "blown up second rock to throne room zora's domain" }, - { 0x17, 0x10, 0x1710, "?" }, - { 0x17, 0x02, 0x1702, "Midna text after Zora's domain portal" }, - { 0x17, 0x01, 0x1701, "blown up underwater rock zora river middle" }, - { 0x18, 0x08, 0x1808, "picked up rupees from south underwater rock Lakebed area" }, - { 0x18, 0x04, 0x1804, "picked up rupees from west underwater rock Lakebed area" }, - { 0x18, 0x02, 0x1802, "picked up green rupees domain midna jumps twilight" }, - { 0x18, 0x01, 0x1801, "picked up fourth green rupee domain midna jumps twilight" }, - { 0x19, 0x80, 0x1980, "picked up third blue rupee midna jumps zora's domain" }, - { 0x19, 0x40, 0x1940, "picked up second blue rupee midna jumps zora's domain" }, - { 0x19, 0x20, 0x1920, "picked up first blue rupee midna jumps zora's domain" }, - { 0x19, 0x10, 0x1910, "picked up rupees from rock zora river on land" }, - { 0x19, 0x08, 0x1908, "picked up rupees from underwater rock zora river lake path" }, - { 0x19, 0x04, 0x1904, "picked up rupees from underwater rock zora river town path" }, - { 0x19, 0x02, 0x1902, "picked up rupees from underwater rock zora river middle" }, - { 0x19, 0x01, 0x1901, "picked up rupees from underwater rock back fountain" }, - { 0x1A, 0x80, 0x1A80, "picked up rupees from underwater rock center fountain" }, - { 0x1A, 0x40, 0x1A40, "picked up rupees from south underwater rock zora's domain " }, - { 0x1A, 0x20, 0x1A20, "picked up rupees from north underwater rock zora's domain" }, - { 0x1A, 0x10, 0x1A10, "picked up rupees from first rock to throne room zora's domain" }, - { 0x1A, 0x08, 0x1A08, "picked up rupees from second rock to throne room zora's domain" }, - { 0x1A, 0x04, 0x1A04, "picked up east blue rupees behind underwater bridge throne room zora's domain" }, - { 0x1A, 0x02, 0x1A02, "picked up west blue rupees behind underwater bridge throne room zora's domain" }, - { 0x1A, 0x01, 0x1A01, "picked up south yellow rupee unerwater throne room zora's domain" }, - { 0x1B, 0x80, 0x1B80, "picked up north yellow rupee unerwater throne room zora's domain" }, - { 0x1B, 0x40, 0x1B40, "picked up east yellow rupee unerwater throne room zora's domain" }, - { 0x1B, 0x20, 0x1B20, "picked up yellow rupee above north underwater rock throne room zora's domain" }, - { 0x1B, 0x10, 0x1B10, "picked up first yellow rupee midna jumps zora's domain" }, - { 0x1B, 0x08, 0x1B08, "picked up second yellow rupee midna jumps zora's domain" }, - { 0x1B, 0x02, 0x1B02, "picked up yellow rupee from broken pillar lakebed area" }, - { 0x1B, 0x01, 0x1B01, "picked up yellow rupee from broken pillar lakebed area" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "small chest next to mother and child iles zora's domain" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "big chest fountain back room" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "left small chest fountain back room" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "right small chest fountain back room" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "small chest midna jumps zora's domain" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "west big chest zora's domain throne room" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "east big chest zora's domain throne room" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "small chest large underwater pillar in fountain" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "small chest small underwater pillar in fountain" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "small chest floor 3 flight by foul" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small chest floor 2 flight by foul" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "big chest right pillar in front of fountain Lake Hylia" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "big chest underwater next to Lake Hylia warp" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "east big chest fountain" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "west big chest fountain" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "big chest floor 4 flight by foul" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "small chest left pillar in front of fountain Lae Hylia" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "big chest floor 5 flight by foul" }, + { 0x04, 0x40, AreaFlagInd{0x0440}, "tear of light throne room zora's domain" }, + { 0x04, 0x20, AreaFlagInd{0x0420}, "first tear of light flying" }, + { 0x04, 0x10, AreaFlagInd{0x0410}, "tear of light midna jumps zora's domain" }, + { 0x04, 0x08, AreaFlagInd{0x0408}, "tear of light on top of water zora's domain" }, + { 0x04, 0x04, AreaFlagInd{0x0404}, "third tear of light flying" }, + { 0x04, 0x02, AreaFlagInd{0x0402}, "fourth tear of light flying" }, + { 0x05, 0x80, AreaFlagInd{0x0580}, "tear of light next to Iza's shop" }, + { 0x05, 0x40, AreaFlagInd{0x0540}, "second tear of light flying" }, + { 0x05, 0x20, AreaFlagInd{0x0520}, "final tear of light" }, + { 0x05, 0x04, AreaFlagInd{0x0504}, "tear of light behind of Fyer's canon" }, + { 0x05, 0x02, AreaFlagInd{0x0502}, "tear of light island east of Lake Hylia" }, + { 0x05, 0x01, AreaFlagInd{0x0501}, "tear of light southmost island Lake Hylia" }, + { 0x06, 0x80, AreaFlagInd{0x0680}, "tear of light next to fountain Lake Hylia" }, + { 0x06, 0x40, AreaFlagInd{0x0640}, "tear of light on top of water zora's domain" }, + { 0x06, 0x20, AreaFlagInd{0x0620}, "tear of light next to mother and child iles zora's domain" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "see frozen zora spirits in domain twilight" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "Lake hylia intro cs twilight" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "blown up underwater rock in center of fountain" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "the two zoras in upper zora river went down stream (twilight)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "saw light bug come out next to Iza spirit cs" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "blown up rock to Lake hylia long cave" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "spawned UZR portal fight barriers" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "opened Upper Zora's River Portal cs" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "talked to Iza before UZR portal" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Upper Zora's River Portal" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "spawn big chest fountain back room" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "lit left torch fountain back room" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "lit right torch fountain back room" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "seeing Twilight Bloat with sense cs" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "Twilight Bloat comes out of water cs" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "seeing Twilit Bloat move from far away cs" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "Save Prompt after Lakebed (if disabled, triggers MDH after Lakebed)" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "twilight end cs trigger (also map marker Lakebed Temple)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "obtained vessel of light (unset after twilight)" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "spawn dark beasts Lake Hylia (unset once killed)" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "Lake Hylia Portal" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "Zora's river intro cs during twilight (flying with bird)" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "midna text promt saying you can call down Kargarok to fly" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "Rutella cs in domain twilight" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "Zora river boat path on map" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "entered Twilight Bloat arena (unset once killed)" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "explored entrance to snowpeak" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "got PoH flight by foul" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "Zora's Domain Portal" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "spawn barriers Zora's domain dark beasts fight" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "Zora's domain intro cs twilight (frozen)" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "blown up south underwater rock zora's domain " }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "blown up north underwater rock zora's domain" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "blown up underwater rock in back of fountain" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "Midna text after landing in Lake hylia twilight" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "Iza text after Upper Zora's River Portal" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "can now exit from the sides of zora's domain inside (set during domain outside cs after melting it)" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "Midna text after domain outside cs after melting it" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "domain outside cs after melting it" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "map marker Auru" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "Upper zora's river intro cs during twilight" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "Midna text after leaving lake hylia after Lanayru twilight" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "Zora's domain waterfall is going fast (during twilight only) (unset when you come back to Lake hylia)" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "blown up rock blocking lakebed entrance cs" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "opened stream next to lakebed entance" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "Midna text after arriving at upper zora's river twilight" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "melted zora's domain (Lake Hylia water on map (top part))" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "twilight end cs watched" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "map marker Snowpeak" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "Midna text after coming back to lake after filling it (twilight)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "blown up rock blocking lakebed entrance" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "went down the fast water in zora's domain (void out) (unset after twilight)" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "Lake hylia filled twilight intro cs (domain water level normal)" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "blown up first rock to throne room zora's domain" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "Midna text prompt to tell you to look under the ice in zora's domain twilight" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "Midna text before midna jumps fozen zora's domain twilight" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "Midna text before midna jumps melted zora's domain twilight" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "Midna text after melting domain (water everywhere on map)" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "blown up underwater rock zora river town path" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "spawn west big chest zora's domain throne room" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "spawn east big chest zora's domain throne room" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "lit east torch zora's domain throne room" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "extingushed north torch zora's domain throne room" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "lit west torch zora's domain throne room" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "blown up west underwater rock Lakebed area" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "blown up south underwater rock Lakebed area" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "saw the two zora spirits from far away in upper zora river cs (twilight)" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "saw light bug moving after exiting lanayru spring" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "went down zora's river with bird during twilight" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "blown up underwater rock zora river lake path" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "midna text after seeing the frozen zoras in domain twilight" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "paid Fyer to launch you to the flight by foul platform (unset once you enter the canon)" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "blown up north underwater rock throne room zora's domain" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "Lanayru spring map marker" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "Midna Text after frozen zora's domain twilight intro cs" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "killed poe underneath flight by foul" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "killed poe next to watch tower to desert" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "killed poe east of lake Hylia" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "killed poe next to mother and chile iles Zora's Domain" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "killed poe midna jumps Zora's Domain" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "killed poe in Upper Zora's River" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "killed poe on flight by foul prizes" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "killed poe next to fountain Lake Hylia" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "blew up rock in Iza's house" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "Iza text after blowing the rocks inside her house" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "blew up rock in Iza's house cs" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "killed light bug throne room zora's domain" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "killed first light bug flying" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "killed light bug midna jumps zora's domain" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "killed light bug on top of water zora's domain" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "killed third light bug flying" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "killed fourth light bug flying" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "killed light bug behind of Fyer's canon" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "killed light bug next to Iza's shop" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "killed second light bug flying" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "killed final light bug (Twilight Bloat)" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "killed light bug island east of Lake Hylia" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "killed light bug next to mother and child iles zora's domain" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "?" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "Watched CS of Ooccoo running to Sky Cannon" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "killed light bug on top of water zora's domain" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "killed light bug southmost island Lake Hylia" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "killed light bug next to fountain Lake Hylia" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "talked to light spirit during twilight" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "went up zora's river after melting domain in twilight" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "blown up rock zora river on land" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "went up zora's river after melting domain in twilight (also set when failing to do so)" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "blown up second rock to throne room zora's domain" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "?" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "Midna text after Zora's domain portal" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "blown up underwater rock zora river middle" }, + { 0x18, 0x08, AreaFlagInd{0x1808}, "picked up rupees from south underwater rock Lakebed area" }, + { 0x18, 0x04, AreaFlagInd{0x1804}, "picked up rupees from west underwater rock Lakebed area" }, + { 0x18, 0x02, AreaFlagInd{0x1802}, "picked up green rupees domain midna jumps twilight" }, + { 0x18, 0x01, AreaFlagInd{0x1801}, "picked up fourth green rupee domain midna jumps twilight" }, + { 0x19, 0x80, AreaFlagInd{0x1980}, "picked up third blue rupee midna jumps zora's domain" }, + { 0x19, 0x40, AreaFlagInd{0x1940}, "picked up second blue rupee midna jumps zora's domain" }, + { 0x19, 0x20, AreaFlagInd{0x1920}, "picked up first blue rupee midna jumps zora's domain" }, + { 0x19, 0x10, AreaFlagInd{0x1910}, "picked up rupees from rock zora river on land" }, + { 0x19, 0x08, AreaFlagInd{0x1908}, "picked up rupees from underwater rock zora river lake path" }, + { 0x19, 0x04, AreaFlagInd{0x1904}, "picked up rupees from underwater rock zora river town path" }, + { 0x19, 0x02, AreaFlagInd{0x1902}, "picked up rupees from underwater rock zora river middle" }, + { 0x19, 0x01, AreaFlagInd{0x1901}, "picked up rupees from underwater rock back fountain" }, + { 0x1A, 0x80, AreaFlagInd{0x1A80}, "picked up rupees from underwater rock center fountain" }, + { 0x1A, 0x40, AreaFlagInd{0x1A40}, "picked up rupees from south underwater rock zora's domain " }, + { 0x1A, 0x20, AreaFlagInd{0x1A20}, "picked up rupees from north underwater rock zora's domain" }, + { 0x1A, 0x10, AreaFlagInd{0x1A10}, "picked up rupees from first rock to throne room zora's domain" }, + { 0x1A, 0x08, AreaFlagInd{0x1A08}, "picked up rupees from second rock to throne room zora's domain" }, + { 0x1A, 0x04, AreaFlagInd{0x1A04}, "picked up east blue rupees behind underwater bridge throne room zora's domain" }, + { 0x1A, 0x02, AreaFlagInd{0x1A02}, "picked up west blue rupees behind underwater bridge throne room zora's domain" }, + { 0x1A, 0x01, AreaFlagInd{0x1A01}, "picked up south yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x80, AreaFlagInd{0x1B80}, "picked up north yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x40, AreaFlagInd{0x1B40}, "picked up east yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x20, AreaFlagInd{0x1B20}, "picked up yellow rupee above north underwater rock throne room zora's domain" }, + { 0x1B, 0x10, AreaFlagInd{0x1B10}, "picked up first yellow rupee midna jumps zora's domain" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "picked up second yellow rupee midna jumps zora's domain" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "picked up yellow rupee from broken pillar lakebed area" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up yellow rupee from broken pillar lakebed area" }, }; inline EventAreaFlags eventAreaFlagsLBT[] = { - { 0x00, 0x40, 0x0040, "small chest first west room 1F" }, - { 0x00, 0x20, 0x0020, "south small chest first room" }, - { 0x00, 0x10, 0x0010, "west small chest first room" }, - { 0x00, 0x08, 0x0008, "small chest second east room 4F" }, - { 0x00, 0x02, 0x0002, "underwater big chest in first west room 2F" }, - { 0x00, 0x01, 0x0001, "small chest first east room 2F" }, - { 0x01, 0x40, 0x0140, "Ooccoo Map Flag" }, - { 0x01, 0x20, 0x0120, "small chest second west room 4F" }, - { 0x01, 0x10, 0x0110, "compass big chest second west room 4F" }, - { 0x01, 0x08, 0x0108, "center small chest first west room 2F" }, - { 0x01, 0x04, 0x0104, "small chest in room before big key" }, - { 0x01, 0x02, 0x0102, "map big chest main room 1F" }, - { 0x01, 0x01, 0x0101, "big chest under boss door main room B1" }, - { 0x02, 0x80, 0x0280, "south underwater big chest in room before mini-boss" }, - { 0x02, 0x40, 0x0240, "north underwater big chest in room before mini-boss" }, - { 0x02, 0x20, 0x0220, "north west big chest first west room 2F" }, - { 0x02, 0x10, 0x0210, "big key chest" }, - { 0x02, 0x08, 0x0208, "big chest second east room 4F" }, - { 0x02, 0x04, 0x0204, "small key big chest first east room 2F" }, - { 0x02, 0x01, 0x0201, "PoH big chest behind gate in first east room 1F" }, - { 0x03, 0x80, 0x0380, "south small chest in first west room 2F" }, - { 0x03, 0x40, 0x0340, "small key big chest first east room 1F" }, - { 0x03, 0x20, 0x0320, "PoH big chest main room 2F" }, - { 0x03, 0x08, 0x0308, "small chest second room" }, - { 0x03, 0x04, 0x0304, "small key big chest room before mini-boss" }, - { 0x03, 0x02, 0x0302, "small chest main room 1F" }, - { 0x03, 0x01, 0x0301, "clawshot big chest mini-boss room" }, - { 0x08, 0x80, 0x0880, "raised water in first east room 1F" }, - { 0x08, 0x40, 0x0840, "water flowing into first east room 1F cs" }, - { 0x08, 0x20, 0x0820, "?" }, - { 0x08, 0x02, 0x0802, "Midna Stalactite text second room" }, - { 0x09, 0x80, 0x0980, "water flowing into first east room 1F" }, - { 0x09, 0x20, 0x0920, "west water flowing into stairs in main room" }, - { 0x09, 0x10, 0x0910, "east water flowing into stairs in main room" }, - { 0x09, 0x08, 0x0908, "water flowing into east wing 1F" }, - { 0x09, 0x04, 0x0904, "water flowing into west wing 1F" }, - { 0x09, 0x02, 0x0902, "water in main room raised twice" }, - { 0x09, 0x01, 0x0901, "water in main room raised once" }, - { 0x0A, 0x80, 0x0A80, "west water not flowing into stairs in main room" }, - { 0x0A, 0x40, 0x0A40, "east water not flowing into stairs in main room" }, - { 0x0A, 0x20, 0x0A20, "west water is flowing into main room" }, - { 0x0A, 0x10, 0x0A10, "staircase top is west main room" }, - { 0x0A, 0x08, 0x0A08, "staircase top is east main room" }, - { 0x0A, 0x04, 0x0A04, "east water is flowing into main room" }, - { 0x0A, 0x02, 0x0A02, "let water flow out of room west wing 2F" }, - { 0x0A, 0x01, 0x0A01, "let water flow out of room east wing 2F" }, - { 0x0B, 0x10, 0x0B10, "spawn clawshot big chest" }, - { 0x0B, 0x08, 0x0B08, "set staircase top is east main room" }, - { 0x0B, 0x04, 0x0B04, "set staircase top is north main room" }, - { 0x0B, 0x02, 0x0B02, "set staircase top is west main room" }, - { 0x0B, 0x01, 0x0B01, "set staircase top is south main room (default)" }, - { 0x0D, 0x40, 0x0D40, "PoH big chest behind gate in first east room 1F (set after)" }, - { 0x0D, 0x20, 0x0D20, "horizontal wheel is turning in first east room" }, - { 0x0D, 0x10, 0x0D10, "unlock east door main room 2F" }, - { 0x0D, 0x08, 0x0D08, "vertical wheel is turning in first east room 2F" }, - { 0x0D, 0x04, 0x0D04, "small key big chest first east room 1F (set after)" }, - { 0x0D, 0x02, 0x0D02, "east wing water switch 4F" }, - { 0x0D, 0x01, 0x0D01, "west wing water switch 4F" }, - { 0x0E, 0x04, 0x0E04, "opened north gate first east room 2F" }, - { 0x0E, 0x01, 0x0E01, "opened gate in first room" }, - { 0x0F, 0x80, 0x0F80, "blown up second rock in room before big key" }, - { 0x0F, 0x40, 0x0F40, "blown up first rock in room before big key" }, - { 0x0F, 0x10, 0x0F10, "unlocked door in second east room 2F" }, - { 0x0F, 0x08, 0x0F08, "unlocked door in room before mini-boss" }, - { 0x0F, 0x02, 0x0F02, "horizontal wheel is turning in first east room cs" }, - { 0x0F, 0x01, 0x0F01, "horizontal wheels turning in first west room" }, - { 0x10, 0x80, 0x1080, "killed lizalfos in south hallway to main room 2F" }, - { 0x10, 0x40, 0x1040, "killed lizalfos behind gate in first east room 1F " }, - { 0x10, 0x04, 0x1004, "blown up rock in room before mini-boss" }, - { 0x11, 0x80, 0x1180, "Ooccoo Freed" }, - { 0x11, 0x20, 0x1120, "unlocked boss door" }, - { 0x11, 0x10, 0x1110, "a stalactite fell in second room (other than the first one)" }, - { 0x11, 0x04, 0x1104, "stalactite fell in first west room 2F" }, - { 0x11, 0x02, 0x1102, "stalactite falls by itself in second room" }, - { 0x11, 0x01, 0x1101, "left stalactite fell in first east room 2F" }, - { 0x12, 0x80, 0x1280, "right stalactite fell in first east room 2F" }, - { 0x12, 0x40, 0x1240, "blown up rock in first east room 2F" }, - { 0x12, 0x20, 0x1220, "south stalactite fell in first east room 1F" }, - { 0x12, 0x10, 0x1210, "north stalactite fell in first east room 1F" }, - { 0x12, 0x08, 0x1208, "south-east stalactite fell second room" }, - { 0x12, 0x04, 0x1204, "north east stalactite fell in second room" }, - { 0x12, 0x02, 0x1202, "south Stalactite fell second room" }, - { 0x12, 0x01, 0x1201, "north west stalactite fell in second room" }, - { 0x13, 0x80, 0x1380, "south west stalactile fell in second room" }, - { 0x13, 0x20, 0x1320, "killed first shell blade in room before big key" }, - { 0x13, 0x10, 0x1310, "killed second shell blade in room before big key" }, - { 0x13, 0x04, 0x1304, "opened north gate in first west room 2F" }, - { 0x13, 0x02, 0x1302, "opened south gate in first west room 2F" }, - { 0x13, 0x01, 0x1301, "opened gates in mini-boss room" }, - { 0x14, 0x10, 0x1410, "explore main room" }, - { 0x14, 0x04, 0x1404, "main room intro cs" }, - { 0x14, 0x02, 0x1402, "south Hallway to Main room intro cs" }, - { 0x14, 0x01, 0x1401, "first room intro cs" }, - { 0x15, 0x20, 0x1520, "move staircase main room cs" }, - { 0x15, 0x08, 0x1508, "west water flowing into staircase main room cs" }, - { 0x15, 0x04, 0x1504, "east water flowing into staircase main room cs" }, - { 0x15, 0x02, 0x1502, "water in main room raised rwice cs" }, - { 0x15, 0x01, 0x1501, "west water is flowing into main room cs" }, - { 0x16, 0x80, 0x1680, "water in main room raised once cs" }, - { 0x16, 0x40, 0x1640, "east water is flowing into main room cs" }, - { 0x16, 0x20, 0x1620, "big key chest (set after)" }, - { 0x16, 0x10, 0x1610, "compass big chest second west room 4F (set after)" }, - { 0x16, 0x08, 0x1608, "bubble worm cs second east room 2F" }, - { 0x16, 0x01, 0x1601, "enter/exit mini-boss room from 1F door (spawns enemies in room before)" }, - { 0x17, 0x04, 0x1704, "killed right lizalfos in first west room 2F" }, - { 0x17, 0x02, 0x1702, "killed left lizalfos in first west room 2F" }, - { 0x17, 0x01, 0x1701, "killed lizalfos in first east room 2F" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "small chest first west room 1F" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "south small chest first room" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "west small chest first room" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "small chest second east room 4F" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "underwater big chest in first west room 2F" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "small chest first east room 2F" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "Ooccoo Map Flag" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "small chest second west room 4F" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "compass big chest second west room 4F" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "center small chest first west room 2F" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "small chest in room before big key" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "map big chest main room 1F" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "big chest under boss door main room B1" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "south underwater big chest in room before mini-boss" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "north underwater big chest in room before mini-boss" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "north west big chest first west room 2F" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "big key chest" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "big chest second east room 4F" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "small key big chest first east room 2F" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "PoH big chest behind gate in first east room 1F" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "south small chest in first west room 2F" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "small key big chest first east room 1F" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "PoH big chest main room 2F" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "small chest second room" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "small key big chest room before mini-boss" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "small chest main room 1F" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "clawshot big chest mini-boss room" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "raised water in first east room 1F" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "water flowing into first east room 1F cs" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "?" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "Midna Stalactite text second room" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "water flowing into first east room 1F" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "west water flowing into stairs in main room" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "east water flowing into stairs in main room" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "water flowing into east wing 1F" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "water flowing into west wing 1F" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "water in main room raised twice" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "water in main room raised once" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "west water not flowing into stairs in main room" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "east water not flowing into stairs in main room" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "west water is flowing into main room" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "staircase top is west main room" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "staircase top is east main room" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "east water is flowing into main room" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "let water flow out of room west wing 2F" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "let water flow out of room east wing 2F" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "spawn clawshot big chest" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "set staircase top is east main room" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "set staircase top is north main room" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "set staircase top is west main room" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "set staircase top is south main room (default)" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "PoH big chest behind gate in first east room 1F (set after)" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "horizontal wheel is turning in first east room" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "unlock east door main room 2F" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "vertical wheel is turning in first east room 2F" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "small key big chest first east room 1F (set after)" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "east wing water switch 4F" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "west wing water switch 4F" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "opened north gate first east room 2F" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "opened gate in first room" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "blown up second rock in room before big key" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "blown up first rock in room before big key" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "unlocked door in second east room 2F" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "unlocked door in room before mini-boss" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "horizontal wheel is turning in first east room cs" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "horizontal wheels turning in first west room" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "killed lizalfos in south hallway to main room 2F" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "killed lizalfos behind gate in first east room 1F " }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "blown up rock in room before mini-boss" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "Ooccoo Freed" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "unlocked boss door" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "a stalactite fell in second room (other than the first one)" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "stalactite fell in first west room 2F" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "stalactite falls by itself in second room" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "left stalactite fell in first east room 2F" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "right stalactite fell in first east room 2F" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "blown up rock in first east room 2F" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "south stalactite fell in first east room 1F" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "north stalactite fell in first east room 1F" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "south-east stalactite fell second room" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "north east stalactite fell in second room" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "south Stalactite fell second room" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "north west stalactite fell in second room" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "south west stalactile fell in second room" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "killed first shell blade in room before big key" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "killed second shell blade in room before big key" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "opened north gate in first west room 2F" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "opened south gate in first west room 2F" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "opened gates in mini-boss room" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "explore main room" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "main room intro cs" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "south Hallway to Main room intro cs" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "first room intro cs" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "move staircase main room cs" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "west water flowing into staircase main room cs" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "east water flowing into staircase main room cs" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "water in main room raised rwice cs" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "west water is flowing into main room cs" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "water in main room raised once cs" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "east water is flowing into main room cs" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "big key chest (set after)" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "compass big chest second west room 4F (set after)" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "bubble worm cs second east room 2F" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "enter/exit mini-boss room from 1F door (spawns enemies in room before)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "killed right lizalfos in first west room 2F" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "killed left lizalfos in first west room 2F" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "killed lizalfos in first east room 2F" }, }; inline EventAreaFlags eventAreaFlagsLHLC[] = { - { 0x02, 0x40, 0x0240, "big chest room 5 lake hylia long cave" }, - { 0x02, 0x20, 0x0220, "east big chest room 10 Lake Hylia Long Cave" }, - { 0x02, 0x10, 0x0210, "north small chest room 9 Lake Hylia Long Cave" }, - { 0x02, 0x08, 0x0208, "east small chest room 8 Lake Hylia Long Cave" }, - { 0x02, 0x04, 0x0204, "north small chest room 6 Lake hylia Long Cave" }, - { 0x02, 0x02, 0x0202, "south small chest room 7 Lake Hylia Long Cave" }, - { 0x02, 0x01, 0x0201, "north small chest room 5 Lake hylia Long Cave" }, - { 0x03, 0x80, 0x0380, "north small chest room 4 Lake Hylia Long Cave" }, - { 0x03, 0x40, 0x0340, "west small chest room 2 Lake hylia Long Cave" }, - { 0x03, 0x20, 0x0320, "west big chest room 7 Lake Hylia Long Cave" }, - { 0x03, 0x10, 0x0310, "north big chest room 8 Lake Hylia Long Cave" }, - { 0x03, 0x08, 0x0308, "big chest room 11 lake hylia long cave" }, - { 0x03, 0x04, 0x0304, "north small chest room 1 Lake hylia Long Cave" }, - { 0x03, 0x02, 0x0302, "west small chest room 1 Lake hylia Long Cave" }, - { 0x03, 0x01, 0x0301, "east small chest room 3 Lake Hylia Long Cave" }, - { 0x04, 0x80, 0x0480, "small chest Goron Stock Cave" }, - { 0x04, 0x40, 0x0440, "big chest in front of exit Goron Stock Cave" }, - { 0x04, 0x20, 0x0420, "big chest spawned form torches Goron Stock Cave" }, - { 0x08, 0x80, 0x0880, "explored section 18 Lake hylia Long Cave" }, - { 0x08, 0x40, 0x0840, "explored section 15 Lake hylia Long Cave" }, - { 0x08, 0x20, 0x0820, "explored section 12 Lake hylia Long Cave" }, - { 0x08, 0x10, 0x0810, "explored section 11 Lake hylia Long Cave" }, - { 0x08, 0x08, 0x0808, "explored section 9 Lake hylia Long Cave" }, - { 0x08, 0x04, 0x0804, "explored section 6 Lake hylia Long Cave" }, - { 0x08, 0x02, 0x0802, "explored section 4 Lake hylia Long Cave" }, - { 0x08, 0x01, 0x0801, "explored section 27 (room 11) Lake hylia Long Cave" }, - { 0x09, 0x80, 0x0980, "explored section 24 (room 10) Lake hylia Long Cave" }, - { 0x09, 0x40, 0x0940, "explored section 23 (room 9) Lake hylia Long Cave" }, - { 0x09, 0x20, 0x0920, "explored section 22 Lake hylia Long Cave" }, - { 0x09, 0x10, 0x0910, "explored east area room 8 Lake hylia Long Cave" }, - { 0x09, 0x08, 0x0908, "explored north area room 8 Lake hylia Long Cave" }, - { 0x09, 0x04, 0x0904, "explored section 21 (room 8) Lake hylia Long Cave" }, - { 0x09, 0x02, 0x0902, "explored section 17 Lake hylia Long Cave" }, - { 0x09, 0x01, 0x0901, "explored south area room 7 Lake hylia Long Cave" }, - { 0x0A, 0x80, 0x0A80, "explored west area room 7 Lake hylia Long Cave" }, - { 0x0A, 0x40, 0x0A40, "explored section 16 (room 7) Lake hylia Long Cave" }, - { 0x0A, 0x20, 0x0A20, "explored section 14 Lake hylia Long Cave" }, - { 0x0A, 0x10, 0x0A10, "explored north area room 6 Lake hylia Long Cave" }, - { 0x0A, 0x08, 0x0A08, "explored section 13 (room 6) Lake hylia Long Cave" }, - { 0x0A, 0x04, 0x0A04, "explored section 10 (room 5) Lake hylia Long Cave" }, - { 0x0A, 0x02, 0x0A02, "explored section 8 Lake hylia Long Cave" }, - { 0x0A, 0x01, 0x0A01, "explored north area room 4 Lake hylia Long Cave" }, - { 0x0B, 0x80, 0x0B80, "explored section 7 (room 4) Lake hylia Long Cave" }, - { 0x0B, 0x40, 0x0B40, "explored section 5 (room 3) Lake hylia Long Cave" }, - { 0x0B, 0x20, 0x0B20, "explored section 3 (room 2) Lake hylia Long Cave" }, - { 0x0B, 0x10, 0x0B10, "explored section 2 Lake hylia Long Cave" }, - { 0x0B, 0x08, 0x0B08, "explored north area room 1 Lake hylia Long Cave" }, - { 0x0B, 0x04, 0x0B04, "explored west area room 1 Lake hylia Long Cave" }, - { 0x0B, 0x02, 0x0B02, "explored section 1 (room 1) Lake hylia Long Cave" }, - { 0x0C, 0x80, 0x0C80, "blown up north rock room 7 Lake hylia long cave" }, - { 0x0C, 0x10, 0x0C10, "blown up north rock room 3 Lake hylia long cave" }, - { 0x0C, 0x04, 0x0C04, "blown up north rock room 4 Lake hylia long cave" }, - { 0x0C, 0x01, 0x0C01, "blown up south rock room 8 Lake hylia long cave" }, - { 0x0D, 0x40, 0x0D40, "blown up east rock room 6 Lake Hylia Long Cave" }, - { 0x0D, 0x20, 0x0D20, "blown up west rock room 6 Lake Hylia Long Cave" }, - { 0x0D, 0x04, 0x0D04, "blown up north rock room 5 Lake Hylia Long Cave" }, - { 0x0D, 0x02, 0x0D02, "blown up north rock room 9 Lake Hylia Long Cave" }, - { 0x0D, 0x01, 0x0D01, "blown up east rock room 3 Lake hylia long cave" }, - { 0x0E, 0x80, 0x0E80, "lit right torch room 5 lake hylia long cave" }, - { 0x0E, 0x40, 0x0E40, "lit left torch room 5 lake hylia long cave" }, - { 0x0E, 0x20, 0x0E20, "spawn big chest room 11 lake hylia long cave" }, - { 0x0E, 0x10, 0x0E10, "lit right torch room 11 Lake Hylia Long Cave" }, - { 0x0E, 0x08, 0x0E08, "lit left torch room 11 Lake Hylia Long Cave" }, - { 0x0E, 0x04, 0x0E04, "explored south area room 11 Lake hylia Long Cave" }, - { 0x0E, 0x02, 0x0E02, "explored east area room 10 Lake hylia Long Cave" }, - { 0x0E, 0x01, 0x0E01, "explored north area room 9 Lake hylia Long Cave" }, - { 0x0F, 0x80, 0x0F80, "explored east area room 6 Lake hylia Long Cave" }, - { 0x0F, 0x40, 0x0F40, "explored north area room 5 Lake hylia Long Cave" }, - { 0x0F, 0x20, 0x0F20, "explored east area room 3 Lake hylia Long Cave" }, - { 0x0F, 0x10, 0x0F10, "explored west area room 2 Lake hylia Long Cave" }, - { 0x0F, 0x08, 0x0F08, "explored section 25 Lake hylia Long Cave" }, - { 0x0F, 0x04, 0x0F04, "explored section 26 Lake hylia Long Cave" }, - { 0x0F, 0x02, 0x0F02, "explored section 20 Lake hylia Long Cave" }, - { 0x0F, 0x01, 0x0F01, "explored section 19 Lake hylia Long Cave" }, - { 0x10, 0x80, 0x1080, "killed poe in room 11 Lake Hylia Long Cave" }, - { 0x10, 0x40, 0x1040, "killed poe in room 3 Lake Hylia Long Cave" }, - { 0x10, 0x20, 0x1020, "killed poe in room 8 Lake Hylia Long Cave" }, - { 0x10, 0x04, 0x1004, "lit torch 9 (room 7) Lake hylia Long Cave" }, - { 0x10, 0x01, 0x1001, "lit torch 5 (room 4) Lake hylia Long Cave" }, - { 0x11, 0x40, 0x1140, "lit torch 3 (room 2) Lake hylia Long Cave" }, - { 0x11, 0x20, 0x1120, "lit torch 2 (room 1) Lake hylia Long Cave" }, - { 0x11, 0x08, 0x1108, "lit torch 12 (room 10) Lake hylia Long Cave" }, - { 0x11, 0x04, 0x1104, "lit torch 10 (room 8) Lake hylia Long Cave" }, - { 0x11, 0x02, 0x1102, "spawn big chest room 5 lake hylia long cave" }, - { 0x11, 0x01, 0x1101, "lit torch 4 (room 3) Lake hylia Long Cave" }, - { 0x12, 0x80, 0x1280, "blown up east rock room 9 Lake hylia long cave" }, - { 0x12, 0x40, 0x1240, "blown up west rock room 2 Lake hylia Long Cave" }, - { 0x12, 0x20, 0x1220, "blown up east rock room 2 Lake hylia Long Cave" }, - { 0x12, 0x10, 0x1210, "blown up north rock room 6 Lake hylia Long Cave" }, - { 0x12, 0x08, 0x1208, "blown up west rock room 5 Lake hylia Long Cave" }, - { 0x12, 0x04, 0x1204, "blown up east rock room 8 Lake Hylia Long Cave" }, - { 0x12, 0x02, 0x1202, "blown up east rock room 10 Lake Hylia Long Cave" }, - { 0x12, 0x01, 0x1201, "blown up north rock room 8 Lake hylia Long Cave" }, - { 0x13, 0x80, 0x1380, "blown up west rock room 7 Lake hylia Long Cave" }, - { 0x13, 0x40, 0x1340, "blown up south rock room 7 Lake hylia Long Cave" }, - { 0x13, 0x20, 0x1320, "blown up south rock room 10 Lake hylia Long Cave" }, - { 0x13, 0x10, 0x1310, "blown up west rock room 4 Lake hylia Long Cave" }, - { 0x13, 0x08, 0x1308, "blown up west rock room 1 Lake hylia Long Cave" }, - { 0x13, 0x04, 0x1304, "blown up north rock room 1 Lake hylia Long Cave" }, - { 0x13, 0x02, 0x1302, "blown up east rock room 1 Lake hylia Long Cave" }, - { 0x14, 0x80, 0x1480, "spawn big chest bottom floor Goron Stock Cave" }, - { 0x14, 0x40, 0x1440, "lit right torch bottom floor Goron Stock Cave" }, - { 0x14, 0x20, 0x1420, "lit left torch bottom floor Goron Stock Cave" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "big chest room 5 lake hylia long cave" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "east big chest room 10 Lake Hylia Long Cave" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "north small chest room 9 Lake Hylia Long Cave" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "east small chest room 8 Lake Hylia Long Cave" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "north small chest room 6 Lake hylia Long Cave" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "south small chest room 7 Lake Hylia Long Cave" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "north small chest room 5 Lake hylia Long Cave" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "north small chest room 4 Lake Hylia Long Cave" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "west small chest room 2 Lake hylia Long Cave" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "west big chest room 7 Lake Hylia Long Cave" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "north big chest room 8 Lake Hylia Long Cave" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "big chest room 11 lake hylia long cave" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "north small chest room 1 Lake hylia Long Cave" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "west small chest room 1 Lake hylia Long Cave" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "east small chest room 3 Lake Hylia Long Cave" }, + { 0x04, 0x80, AreaFlagInd{0x0480}, "small chest Goron Stock Cave" }, + { 0x04, 0x40, AreaFlagInd{0x0440}, "big chest in front of exit Goron Stock Cave" }, + { 0x04, 0x20, AreaFlagInd{0x0420}, "big chest spawned form torches Goron Stock Cave" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "explored section 18 Lake hylia Long Cave" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "explored section 15 Lake hylia Long Cave" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "explored section 12 Lake hylia Long Cave" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "explored section 11 Lake hylia Long Cave" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "explored section 9 Lake hylia Long Cave" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "explored section 6 Lake hylia Long Cave" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "explored section 4 Lake hylia Long Cave" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "explored section 27 (room 11) Lake hylia Long Cave" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "explored section 24 (room 10) Lake hylia Long Cave" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "explored section 23 (room 9) Lake hylia Long Cave" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "explored section 22 Lake hylia Long Cave" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "explored east area room 8 Lake hylia Long Cave" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "explored north area room 8 Lake hylia Long Cave" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "explored section 21 (room 8) Lake hylia Long Cave" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "explored section 17 Lake hylia Long Cave" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "explored south area room 7 Lake hylia Long Cave" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "explored west area room 7 Lake hylia Long Cave" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "explored section 16 (room 7) Lake hylia Long Cave" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "explored section 14 Lake hylia Long Cave" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "explored north area room 6 Lake hylia Long Cave" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "explored section 13 (room 6) Lake hylia Long Cave" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "explored section 10 (room 5) Lake hylia Long Cave" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "explored section 8 Lake hylia Long Cave" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "explored north area room 4 Lake hylia Long Cave" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "explored section 7 (room 4) Lake hylia Long Cave" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "explored section 5 (room 3) Lake hylia Long Cave" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "explored section 3 (room 2) Lake hylia Long Cave" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "explored section 2 Lake hylia Long Cave" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "explored north area room 1 Lake hylia Long Cave" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "explored west area room 1 Lake hylia Long Cave" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "explored section 1 (room 1) Lake hylia Long Cave" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "blown up north rock room 7 Lake hylia long cave" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "blown up north rock room 3 Lake hylia long cave" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "blown up north rock room 4 Lake hylia long cave" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "blown up south rock room 8 Lake hylia long cave" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "blown up east rock room 6 Lake Hylia Long Cave" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "blown up west rock room 6 Lake Hylia Long Cave" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "blown up north rock room 5 Lake Hylia Long Cave" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "blown up north rock room 9 Lake Hylia Long Cave" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "blown up east rock room 3 Lake hylia long cave" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "lit right torch room 5 lake hylia long cave" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "lit left torch room 5 lake hylia long cave" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "spawn big chest room 11 lake hylia long cave" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "lit right torch room 11 Lake Hylia Long Cave" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "lit left torch room 11 Lake Hylia Long Cave" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "explored south area room 11 Lake hylia Long Cave" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "explored east area room 10 Lake hylia Long Cave" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "explored north area room 9 Lake hylia Long Cave" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "explored east area room 6 Lake hylia Long Cave" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "explored north area room 5 Lake hylia Long Cave" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "explored east area room 3 Lake hylia Long Cave" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "explored west area room 2 Lake hylia Long Cave" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "explored section 25 Lake hylia Long Cave" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "explored section 26 Lake hylia Long Cave" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "explored section 20 Lake hylia Long Cave" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "explored section 19 Lake hylia Long Cave" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "killed poe in room 11 Lake Hylia Long Cave" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "killed poe in room 3 Lake Hylia Long Cave" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "killed poe in room 8 Lake Hylia Long Cave" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "lit torch 9 (room 7) Lake hylia Long Cave" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "lit torch 5 (room 4) Lake hylia Long Cave" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "lit torch 3 (room 2) Lake hylia Long Cave" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "lit torch 2 (room 1) Lake hylia Long Cave" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "lit torch 12 (room 10) Lake hylia Long Cave" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "lit torch 10 (room 8) Lake hylia Long Cave" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "spawn big chest room 5 lake hylia long cave" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "lit torch 4 (room 3) Lake hylia Long Cave" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "blown up east rock room 9 Lake hylia long cave" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "blown up west rock room 2 Lake hylia Long Cave" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "blown up east rock room 2 Lake hylia Long Cave" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "blown up north rock room 6 Lake hylia Long Cave" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "blown up west rock room 5 Lake hylia Long Cave" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "blown up east rock room 8 Lake Hylia Long Cave" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "blown up east rock room 10 Lake Hylia Long Cave" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "blown up north rock room 8 Lake hylia Long Cave" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "blown up west rock room 7 Lake hylia Long Cave" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "blown up south rock room 7 Lake hylia Long Cave" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "blown up south rock room 10 Lake hylia Long Cave" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "blown up west rock room 4 Lake hylia Long Cave" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "blown up west rock room 1 Lake hylia Long Cave" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "blown up north rock room 1 Lake hylia Long Cave" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "blown up east rock room 1 Lake hylia Long Cave" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "spawn big chest bottom floor Goron Stock Cave" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "lit right torch bottom floor Goron Stock Cave" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "lit left torch bottom floor Goron Stock Cave" }, }; inline EventAreaFlags eventAreaFlagsOrdon[] = { - { 0x03, 0x10, 0x0310, "wooden sword big chest" }, - { 0x03, 0x04, 0x0304, "iron boots big chest" }, - { 0x03, 0x02, 0x0302, "Big chest link's basement" }, - { 0x08, 0x80, 0x0880, "despawn Bo and Jaggle after scaring them away (wolf night)" }, - { 0x08, 0x40, 0x0840, "scare away Bo and Jaggle after hearing them (wolf night)" }, - { 0x08, 0x20, 0x0820, "started sword training" }, - { 0x08, 0x10, 0x0810, "obtained wooden sword" }, - { 0x08, 0x08, 0x0808, "midna text after getting ordon shield (spawns sword)" }, - { 0x08, 0x04, 0x0804, "got ordon shield (will despawn it if set)" }, - { 0x08, 0x02, 0x0802, "midna text after getting ordon sword" }, - { 0x08, 0x01, 0x0801, "got ordon sword" }, - { 0x09, 0x80, 0x0980, "exit shield house as wolf cs" }, - { 0x09, 0x40, 0x0940, "Goats 2" }, - { 0x09, 0x20, 0x0920, "day 3 intro cs (spawn in ranch)" }, - { 0x09, 0x08, 0x0908, "knocked down bee's nest day 2 cs" }, - { 0x09, 0x04, 0x0904, "? (wolf in village night)" }, - { 0x09, 0x02, 0x0902, "Ranch first time CS" }, - { 0x0A, 0x80, 0x0A80, "Rusl moving during wolf night" }, - { 0x0A, 0x40, 0x0A40, "killed spider on top of Link's house" }, - { 0x0A, 0x20, 0x0A20, "spawn 2 spiders around Link,s house (day 2) (set after buying slingshot)" }, - { 0x0A, 0x10, 0x0A10, "Ilia spring CS watched" }, - { 0x0A, 0x08, 0x0A08, "Ilia spring CS started" }, - { 0x0A, 0x04, 0x0A04, "Ordon Village first time CS" }, - { 0x0A, 0x02, 0x0A02, "Ilia spring CS Trigger" }, - { 0x0A, 0x01, 0x0A01, "killed spider on ladder to link's house" }, - { 0x0B, 0x80, 0x0B80, "Epona being in spring" }, - { 0x0B, 0x20, 0x0B20, "finished slingshot training" }, - { 0x0B, 0x10, 0x0B10, "Entered spring Area first time" }, - { 0x0B, 0x08, 0x0B08, "Intro CS watched" }, - { 0x0B, 0x02, 0x0B02, "finished sword training" }, - { 0x0C, 0x80, 0x0C80, "killed bulblin ordon woods" }, - { 0x0C, 0x40, 0x0C40, "killed second bulblin Link's house" }, - { 0x0C, 0x20, 0x0C20, "killed first bulblin Link's house" }, - { 0x0C, 0x10, 0x0C10, "spawn wooden sword big chest" }, - { 0x0C, 0x08, 0x0C08, "Day 2 intro CS" }, - { 0x0C, 0x04, 0x0C04, "talked to owl as wolf for the first time" }, - { 0x0C, 0x02, 0x0C02, "Goats 1" }, - { 0x0C, 0x01, 0x0C01, "set after getting ordon shield" }, - { 0x0D, 0x80, 0x0D80, "approach faron twilight to enter it with midna cs" }, - { 0x0D, 0x20, 0x0D20, "spawn shadow beast" }, - { 0x0D, 0x10, 0x0D10, "Ordon Spring Portal" }, - { 0x0D, 0x08, 0x0D08, "hear Bo and Jaggle talk about shield from far away (wolf night)" }, - { 0x0D, 0x02, 0x0D02, "entered shield house as wolf cs" }, - { 0x0D, 0x01, 0x0D01, "ordon shield fell down cs" }, - { 0x0E, 0x80, 0x0E80, "midna text leaving spring" }, - { 0x0E, 0x20, 0x0E20, "started midna jump to ordon shield inside house" }, - { 0x0E, 0x08, 0x0E08, "Hanch started attacking (unlocks midna jump to top of shop)" }, - { 0x0E, 0x04, 0x0E04, "midna cs after hearing Bo and Jaggle talk about shield" }, - { 0x0E, 0x02, 0x0E02, "day 3 Fado intro text" }, - { 0x0F, 0x80, 0x0F80, "Allows Link to stop goat in Village" }, - { 0x0F, 0x20, 0x0F20, "started midna jumps to top of shop" }, - { 0x0F, 0x08, 0x0F08, "midna text before doing jumps to top of shop" }, - { 0x0F, 0x04, 0x0F04, "Rusl talking to his wife cs (wolf night)" }, - { 0x0F, 0x02, 0x0F02, "unlock midna jumps to shield house" }, - { 0x0F, 0x01, 0x0F01, "scared Hanch" }, - { 0x12, 0x02, 0x1202, "torch next to Hanch is lit (wolf night)" }, - { 0x12, 0x01, 0x1201, "? (wolf in village night)" }, - { 0x13, 0x80, 0x1380, "iron boots big chest (duplicate)" }, - { 0x13, 0x40, 0x1340, "spawn iron boots chest in Bo's house" }, - { 0x13, 0x20, 0x1320, "brigthen up area under Hanch after getting spoted" }, - { 0x13, 0x10, 0x1310, "set after midna text after getting ordon shield" }, - { 0x13, 0x08, 0x1308, "Hanch spoted you cs (wolf night)" }, - { 0x13, 0x04, 0x1304, "randomly set during wolf night (often during Hanch part)" }, - { 0x13, 0x02, 0x1302, "Hero's shade map marker" }, - { 0x13, 0x01, 0x1301, "Ordon day 1 (save promt)" }, - { 0x14, 0x80, 0x1480, "set after midna text after getting ordon sword" }, - { 0x14, 0x01, 0x1401, "Jump to eagle grass next to Jaggle day 2 (removes Jaggle text)" }, - { 0x15, 0x10, 0x1510, "did midna jumps to top of shop" }, - { 0x16, 0x01, 0x1601, "King Bulblin cs" }, - { 0x17, 0x80, 0x1780, "enter village as wolf intro cs" }, - { 0x17, 0x20, 0x1720, "explored area with link's house (wolf)" }, - { 0x19, 0x80, 0x1980, "picked up yellow rupee on top of Hanch's house" }, - { 0x19, 0x40, 0x1940, "picked up green rupee in grass in front of Bo's house" }, - { 0x19, 0x20, 0x1920, "picked up green rupees in pond next to Rusl's house (day 2)" }, - { 0x19, 0x10, 0x1910, "picked up purple rupee behind Jaggle's house" }, - { 0x19, 0x01, 0x1901, "picked up green rupee in the back of the grass to the right of Link's house" }, - { 0x1A, 0x80, 0x1A80, "picked up green rupee in grass right of gate to village " }, - { 0x1A, 0x40, 0x1A40, "picked up green rupee next to rock in the grass to the right of Link's house" }, - { 0x1A, 0x20, 0x1A20, "picked up green rupee in grass to the right of Link's house" }, - { 0x1A, 0x10, 0x1A10, "picked up first green rupee in crawl space" }, - { 0x1A, 0x08, 0x1A08, "picked up yellow rupee on top of Bo's house" }, - { 0x1A, 0x02, 0x1A02, "picked up blue rupee on top of Hanch's house" }, - { 0x1A, 0x01, 0x1A01, "Picked up Orange Rupee by Rusl's house" }, - { 0x1B, 0x80, 0x1B80, "picked up green rupees on top of Hanch's house (day 2)" }, - { 0x1B, 0x40, 0x1B40, "picked up green rupees on top of Bo's house (day 2)" }, - { 0x1B, 0x08, 0x1B08, "Picked up Ordon Sword" }, - { 0x1B, 0x04, 0x1B04, "picked up green rupee under bridge (day 2)" }, - { 0x1B, 0x02, 0x1B02, "picked up yellow rupees on top of Rusl's house" }, - { 0x1B, 0x01, 0x1B01, "picked up yellow rupee on cliff next to Bo's house" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "wooden sword big chest" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "iron boots big chest" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "Big chest link's basement" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "despawn Bo and Jaggle after scaring them away (wolf night)" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "scare away Bo and Jaggle after hearing them (wolf night)" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "started sword training" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "obtained wooden sword" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "midna text after getting ordon shield (spawns sword)" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "got ordon shield (will despawn it if set)" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "midna text after getting ordon sword" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "got ordon sword" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "exit shield house as wolf cs" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "Goats 2" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "day 3 intro cs (spawn in ranch)" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "knocked down bee's nest day 2 cs" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "? (wolf in village night)" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "Ranch first time CS" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "Rusl moving during wolf night" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "killed spider on top of Link's house" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "spawn 2 spiders around Link,s house (day 2) (set after buying slingshot)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "Ilia spring CS watched" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "Ilia spring CS started" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "Ordon Village first time CS" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "Ilia spring CS Trigger" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "killed spider on ladder to link's house" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "Epona being in spring" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "finished slingshot training" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "Entered spring Area first time" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "Intro CS watched" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "finished sword training" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "killed bulblin ordon woods" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "killed second bulblin Link's house" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "killed first bulblin Link's house" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "spawn wooden sword big chest" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "Day 2 intro CS" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "talked to owl as wolf for the first time" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "Goats 1" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "set after getting ordon shield" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "approach faron twilight to enter it with midna cs" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "spawn shadow beast" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "Ordon Spring Portal" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "hear Bo and Jaggle talk about shield from far away (wolf night)" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "entered shield house as wolf cs" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "ordon shield fell down cs" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "midna text leaving spring" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "started midna jump to ordon shield inside house" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "Hanch started attacking (unlocks midna jump to top of shop)" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "midna cs after hearing Bo and Jaggle talk about shield" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "day 3 Fado intro text" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "Allows Link to stop goat in Village" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "started midna jumps to top of shop" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "midna text before doing jumps to top of shop" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "Rusl talking to his wife cs (wolf night)" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "unlock midna jumps to shield house" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "scared Hanch" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "torch next to Hanch is lit (wolf night)" }, + { 0x12, 0x01, AreaFlagInd{0x1201}, "? (wolf in village night)" }, + { 0x13, 0x80, AreaFlagInd{0x1380}, "iron boots big chest (duplicate)" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "spawn iron boots chest in Bo's house" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "brigthen up area under Hanch after getting spoted" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "set after midna text after getting ordon shield" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "Hanch spoted you cs (wolf night)" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "randomly set during wolf night (often during Hanch part)" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "Hero's shade map marker" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "Ordon day 1 (save promt)" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "set after midna text after getting ordon sword" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "Jump to eagle grass next to Jaggle day 2 (removes Jaggle text)" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "did midna jumps to top of shop" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "King Bulblin cs" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "enter village as wolf intro cs" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "explored area with link's house (wolf)" }, + { 0x19, 0x80, AreaFlagInd{0x1980}, "picked up yellow rupee on top of Hanch's house" }, + { 0x19, 0x40, AreaFlagInd{0x1940}, "picked up green rupee in grass in front of Bo's house" }, + { 0x19, 0x20, AreaFlagInd{0x1920}, "picked up green rupees in pond next to Rusl's house (day 2)" }, + { 0x19, 0x10, AreaFlagInd{0x1910}, "picked up purple rupee behind Jaggle's house" }, + { 0x19, 0x01, AreaFlagInd{0x1901}, "picked up green rupee in the back of the grass to the right of Link's house" }, + { 0x1A, 0x80, AreaFlagInd{0x1A80}, "picked up green rupee in grass right of gate to village " }, + { 0x1A, 0x40, AreaFlagInd{0x1A40}, "picked up green rupee next to rock in the grass to the right of Link's house" }, + { 0x1A, 0x20, AreaFlagInd{0x1A20}, "picked up green rupee in grass to the right of Link's house" }, + { 0x1A, 0x10, AreaFlagInd{0x1A10}, "picked up first green rupee in crawl space" }, + { 0x1A, 0x08, AreaFlagInd{0x1A08}, "picked up yellow rupee on top of Bo's house" }, + { 0x1A, 0x02, AreaFlagInd{0x1A02}, "picked up blue rupee on top of Hanch's house" }, + { 0x1A, 0x01, AreaFlagInd{0x1A01}, "Picked up Orange Rupee by Rusl's house" }, + { 0x1B, 0x80, AreaFlagInd{0x1B80}, "picked up green rupees on top of Hanch's house (day 2)" }, + { 0x1B, 0x40, AreaFlagInd{0x1B40}, "picked up green rupees on top of Bo's house (day 2)" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "Picked up Ordon Sword" }, + { 0x1B, 0x04, AreaFlagInd{0x1B04}, "picked up green rupee under bridge (day 2)" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "picked up yellow rupees on top of Rusl's house" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up yellow rupee on cliff next to Bo's house" }, }; inline EventAreaFlags eventAreaFlagsPoT[] = { - { 0x00, 0x40, 0x0040, "PoH hidden big chest west room 1" }, - { 0x00, 0x20, 0x0020, "north west small chest east room 2" }, - { 0x00, 0x10, 0x0010, "north east small chest east room 2" }, - { 0x00, 0x08, 0x0008, "west small chest east room 1" }, - { 0x00, 0x04, 0x0004, "small key big chest north room 3" }, - { 0x00, 0x02, 0x0002, "south higher big chest west room 2" }, - { 0x00, 0x01, 0x0001, "small key big chest north room 2" }, - { 0x01, 0x80, 0x0180, "big key chest" }, - { 0x01, 0x40, 0x0140, "small key big chest north room 1" }, - { 0x02, 0x08, 0x0208, "placed west sol" }, - { 0x02, 0x04, 0x0204, "placed east sol" }, - { 0x03, 0x80, 0x0380, "small key east big chest east room 2" }, - { 0x03, 0x40, 0x0340, "small key north east big chest east room 1" }, - { 0x03, 0x20, 0x0320, "small key north big chest west room 2" }, - { 0x03, 0x10, 0x0310, "small key big chest west room 1" }, - { 0x03, 0x08, 0x0308, "compass lower south big chest west room 2" }, - { 0x03, 0x01, 0x0301, "PoH east big chest east room 1" }, - { 0x07, 0x10, 0x0710, "north west small chest east room 1" }, - { 0x07, 0x02, 0x0702, "map west big chest east room 2" }, - { 0x08, 0x10, 0x0810, "spawn south fence in east room 3" }, - { 0x08, 0x08, 0x0808, "spawn north fence in east room 3" }, - { 0x08, 0x04, 0x0804, "spawn south fence in west room 3" }, - { 0x08, 0x02, 0x0802, "spawn north fence in west room 3" }, - { 0x09, 0x80, 0x0980, "spawn in main room from midna warp" }, - { 0x09, 0x40, 0x0940, "save prompt after boss" }, - { 0x09, 0x20, 0x0920, "killed east phantom Zant (unlocks door)" }, - { 0x09, 0x10, 0x0910, "killed west phantom Zant (unlocks door)" }, - { 0x09, 0x04, 0x0904, "Phantom Zant 1 CS" }, - { 0x09, 0x02, 0x0902, "?" }, - { 0x09, 0x01, 0x0901, "?" }, - { 0x0A, 0x40, 0x0A40, "killed all Zant heads in east room 2 (spawn big chest)" }, - { 0x0A, 0x20, 0x0A20, "killed Zant head in east room 1 (spawn chest)" }, - { 0x0A, 0x10, 0x0A10, "killed Zant head in west room 2 (spawn 2 big chests)" }, - { 0x0A, 0x08, 0x0A08, "killed Zant head in west room 1 (spawn chest)" }, - { 0x0A, 0x02, 0x0A02, "unlock boss door" }, - { 0x0A, 0x01, 0x0A01, "unlock door in north room 3" }, - { 0x0B, 0x80, 0x0B80, "unlock door in east room 2" }, - { 0x0B, 0x40, 0x0B40, "unlock door in west room 2" }, - { 0x0B, 0x02, 0x0B02, "intro cs" }, - { 0x0B, 0x01, 0x0B01, "?" }, - { 0x0C, 0x80, 0x0C80, "get light master sword cs" }, - { 0x0C, 0x40, 0x0C40, "? (main room)" }, - { 0x0C, 0x20, 0x0C20, "? (main room)" }, - { 0x0C, 0x10, 0x0C10, "Watched CS of platform to east wing being activated" }, - { 0x0C, 0x08, 0x0C08, "Platform to east wing is active" }, - { 0x0C, 0x04, 0x0C04, "Midna text when west sol is placed" }, - { 0x0C, 0x02, 0x0C02, "Midna text when west hand steals sol" }, - { 0x0D, 0x80, 0x0D80, "killed south west Zant head in east room 2" }, - { 0x0D, 0x40, 0x0D40, "killed south east Zant head in east room 2" }, - { 0x0D, 0x20, 0x0D20, "killed center Zant head in east room 2" }, - { 0x0D, 0x10, 0x0D10, "killed first Zant head in east room 2" }, - { 0x0D, 0x08, 0x0D08, "unlock door in north room 2" }, - { 0x0D, 0x04, 0x0D04, "killed dark beasts in north room 3" }, - { 0x0D, 0x02, 0x0D02, "crossed black fog waterfall main room" }, - { 0x0D, 0x01, 0x0D01, "midna text black fog west room 1" }, - { 0x0E, 0x80, 0x0E80, "Midna text finding west sol" }, - { 0x0E, 0x40, 0x0E40, "midna text black fog waterfall main room" }, - { 0x0E, 0x20, 0x0E20, "midna text when seeing a civilian seen" }, - { 0x0E, 0x10, 0x0E10, "midna text after warping back to main room after boss" }, - { 0x0E, 0x02, 0x0E02, "killed second Zant head in north room 3 (spawn big chest)" }, - { 0x0E, 0x01, 0x0E01, "killed first Zant head in north room 3 (spawn head 2)" }, - { 0x0F, 0x80, 0x0F80, "midna text promt when seeing a civilian" }, - { 0x0F, 0x40, 0x0F40, "midna text after light master sword" }, - { 0x0F, 0x20, 0x0F20, "unlock door in north room 1" }, - { 0x0F, 0x10, 0x0F10, "unlock door in east room 1" }, - { 0x0F, 0x08, 0x0F08, "unlock door in west room 1" }, - { 0x10, 0x80, 0x1080, "killed south Zant head in north room 1 (wave 1)" }, - { 0x10, 0x40, 0x1040, "killed center Zant head in north room 1 (wave 1)" }, - { 0x10, 0x20, 0x1020, "killed north west Zant head in north room 1 (wave 1)" }, - { 0x10, 0x10, 0x1010, "killed north east Zant head in north room 1 (wave 1)" }, - { 0x10, 0x08, 0x1008, "?" }, - { 0x10, 0x04, 0x1004, "?" }, - { 0x10, 0x01, 0x1001, "? (main room)" }, - { 0x11, 0x80, 0x1180, "Heal Twili citizen outside west wing" }, - { 0x11, 0x40, 0x1140, "? (main room)" }, - { 0x11, 0x20, 0x1120, "Heal Twili near PoT entrance" }, - { 0x11, 0x10, 0x1110, "Heal Twili citizen outside east wing" }, - { 0x11, 0x08, 0x1108, "Heal Twili citizen next to west sol" }, - { 0x11, 0x04, 0x1104, "Heal Twili citizen next to east sol" }, - { 0x11, 0x02, 0x1102, "Heal Twili citizen north of Light Sword" }, - { 0x11, 0x01, 0x1101, "Heal Twili citizen near fog waterfall" }, - { 0x12, 0x08, 0x1208, "Opened Big Key Chest (causes fence to fall in room before Zant)" }, - { 0x12, 0x04, 0x1204, "Midna text after re-entering west wing after sol stolen" }, - { 0x12, 0x02, 0x1202, "remove fog in north room 4" }, - { 0x13, 0x40, 0x1340, "remove fog and spawn stairs in north room 1" }, - { 0x13, 0x20, 0x1320, "placed east sol in north room 1" }, - { 0x13, 0x10, 0x1310, "placed west sol in north room 1" }, - { 0x13, 0x02, 0x1302, "midna intro text" }, - { 0x15, 0x40, 0x1540, "killed all wave 4 Zant heads in north room 2 (spawn big chest)" }, - { 0x15, 0x20, 0x1520, "killed east Zant head north room 2 (wave 4)" }, - { 0x15, 0x10, 0x1510, "killed west Zant head north room 2 (wave 4)" }, - { 0x15, 0x08, 0x1508, "killed Zant head wave 3 in north room 2 (spawn wave 4)" }, - { 0x15, 0x04, 0x1504, "killed all wave 2 Zant heads in north room 2 (spawn wave 3)" }, - { 0x15, 0x02, 0x1502, "killed west Zant head north room 2 (wave 2)" }, - { 0x15, 0x01, 0x1501, "killed east Zant head north room 2 (wave 2)" }, - { 0x16, 0x80, 0x1680, "killed middle Zant head north room 2 (wave 2)" }, - { 0x16, 0x40, 0x1640, "killed first Zant head north room 2 (spawn wave 2)" }, - { 0x16, 0x10, 0x1610, "Watched east wing second room stairs CS" }, - { 0x16, 0x01, 0x1601, "?" }, - { 0x17, 0x80, 0x1780, "?" }, - { 0x17, 0x40, 0x1740, "killed dark beasts in east room 2" }, - { 0x17, 0x20, 0x1720, "spawn fog in east room 3" }, - { 0x17, 0x10, 0x1710, "spawn fog in west room 3" }, - { 0x17, 0x08, 0x1708, "killed all wave 2 Zant heads in north room 1 (spawn big chest)" }, - { 0x17, 0x04, 0x1704, "killed north west Zant head north room 1 (wave 2)" }, - { 0x17, 0x02, 0x1702, "killed north east Zant head north room 1 (wave 2)" }, - { 0x17, 0x01, 0x1701, "killed all wave 1 Zant heads in north room 1 (spawn wave 2)" }, - { 0x1B, 0x01, 0x1B01, "heart container" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "PoH hidden big chest west room 1" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "north west small chest east room 2" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "north east small chest east room 2" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "west small chest east room 1" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "small key big chest north room 3" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "south higher big chest west room 2" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "small key big chest north room 2" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "big key chest" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "small key big chest north room 1" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "placed west sol" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "placed east sol" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small key east big chest east room 2" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "small key north east big chest east room 1" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "small key north big chest west room 2" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "small key big chest west room 1" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "compass lower south big chest west room 2" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "PoH east big chest east room 1" }, + { 0x07, 0x10, AreaFlagInd{0x0710}, "north west small chest east room 1" }, + { 0x07, 0x02, AreaFlagInd{0x0702}, "map west big chest east room 2" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "spawn south fence in east room 3" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "spawn north fence in east room 3" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "spawn south fence in west room 3" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "spawn north fence in west room 3" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "spawn in main room from midna warp" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "save prompt after boss" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "killed east phantom Zant (unlocks door)" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "killed west phantom Zant (unlocks door)" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "Phantom Zant 1 CS" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "?" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "?" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "killed all Zant heads in east room 2 (spawn big chest)" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "killed Zant head in east room 1 (spawn chest)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "killed Zant head in west room 2 (spawn 2 big chests)" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "killed Zant head in west room 1 (spawn chest)" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "unlock boss door" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "unlock door in north room 3" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "unlock door in east room 2" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "unlock door in west room 2" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "intro cs" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "?" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "get light master sword cs" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "? (main room)" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "? (main room)" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "Watched CS of platform to east wing being activated" }, + { 0x0C, 0x08, AreaFlagInd{0x0C08}, "Platform to east wing is active" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "Midna text when west sol is placed" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "Midna text when west hand steals sol" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "killed south west Zant head in east room 2" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "killed south east Zant head in east room 2" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "killed center Zant head in east room 2" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "killed first Zant head in east room 2" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "unlock door in north room 2" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "killed dark beasts in north room 3" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "crossed black fog waterfall main room" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "midna text black fog west room 1" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "Midna text finding west sol" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "midna text black fog waterfall main room" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "midna text when seeing a civilian seen" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "midna text after warping back to main room after boss" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "killed second Zant head in north room 3 (spawn big chest)" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "killed first Zant head in north room 3 (spawn head 2)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "midna text promt when seeing a civilian" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "midna text after light master sword" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "unlock door in north room 1" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "unlock door in east room 1" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "unlock door in west room 1" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "killed south Zant head in north room 1 (wave 1)" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "killed center Zant head in north room 1 (wave 1)" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "killed north west Zant head in north room 1 (wave 1)" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "killed north east Zant head in north room 1 (wave 1)" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "?" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "?" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "? (main room)" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "Heal Twili citizen outside west wing" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "? (main room)" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "Heal Twili near PoT entrance" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "Heal Twili citizen outside east wing" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "Heal Twili citizen next to west sol" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "Heal Twili citizen next to east sol" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "Heal Twili citizen north of Light Sword" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "Heal Twili citizen near fog waterfall" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "Opened Big Key Chest (causes fence to fall in room before Zant)" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "Midna text after re-entering west wing after sol stolen" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "remove fog in north room 4" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "remove fog and spawn stairs in north room 1" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "placed east sol in north room 1" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "placed west sol in north room 1" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "midna intro text" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "killed all wave 4 Zant heads in north room 2 (spawn big chest)" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "killed east Zant head north room 2 (wave 4)" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "killed west Zant head north room 2 (wave 4)" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "killed Zant head wave 3 in north room 2 (spawn wave 4)" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "killed all wave 2 Zant heads in north room 2 (spawn wave 3)" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "killed west Zant head north room 2 (wave 2)" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "killed east Zant head north room 2 (wave 2)" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "killed middle Zant head north room 2 (wave 2)" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "killed first Zant head north room 2 (spawn wave 2)" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "Watched east wing second room stairs CS" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "?" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "?" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "killed dark beasts in east room 2" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "spawn fog in east room 3" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "spawn fog in west room 3" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "killed all wave 2 Zant heads in north room 1 (spawn big chest)" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "killed north west Zant head north room 1 (wave 2)" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "killed north east Zant head north room 1 (wave 2)" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "killed all wave 1 Zant heads in north room 1 (spawn wave 2)" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "heart container" }, }; inline EventAreaFlags eventAreaFlagsSacredGrove[] = { - { 0x03, 0x08, 0x0308, "Big chest lost woods 2 torches" }, - { 0x03, 0x04, 0x0304, "Big chest spinner in skull kid wolf battle area" }, - { 0x03, 0x02, 0x0302, "PoH big chest temple of time (past)" }, - { 0x08, 0x80, 0x0880, "lit left torch chest lost woods" }, - { 0x08, 0x40, 0x0840, "killed poe temple of time (past)" }, - { 0x08, 0x20, 0x0820, "midna text after pushing block human" }, - { 0x08, 0x10, 0x0810, "cs after pushing block human" }, - { 0x08, 0x08, 0x0808, "intro cs lost woods" }, - { 0x08, 0x02, 0x0802, "?" }, - { 0x08, 0x01, 0x0801, "?" }, - { 0x09, 0x80, 0x0980, "explored section after window before dungeon (includes map marker for dungeon)" }, - { 0x09, 0x40, 0x0940, "stairs to temple of time area near (dungeon)" }, - { 0x09, 0x20, 0x0920, "strike MS into pedestal in past" }, - { 0x09, 0x10, 0x0910, "window and stairs to dungeon work properly" }, - { 0x09, 0x02, 0x0902, "killed poe lost woods water" }, - { 0x09, 0x01, 0x0901, "killed poe in skull kid wolf battle area" }, - { 0x0A, 0x80, 0x0A80, "killed poe in master sword area (present)" }, - { 0x0A, 0x10, 0x0A10, "skull kid wolf battle area explored" }, - { 0x0B, 0x80, 0x0B80, "temple of time (present) main room explored" }, - { 0x0B, 0x40, 0x0B40, "temple of time (past) main room explored" }, - { 0x0B, 0x20, 0x0B20, "blown up rock in skull kid wolf battle area" }, - { 0x0B, 0x10, 0x0B10, "block pushed human" }, - { 0x0B, 0x04, 0x0B04, "Master Sword Puzzle Complete" }, - { 0x0B, 0x02, 0x0B02, "Master sword area explored" }, - { 0x0B, 0x01, 0x0B01, "Temple of time (present) human entrence explored" }, - { 0x0F, 0x02, 0x0F02, "spawn big chest lost woods 2 torches" }, - { 0x0F, 0x01, 0x0F01, "lit right torch chest lost woods" }, - { 0x16, 0x20, 0x1620, "Master Sword Pulled (does not despawn)" }, - { 0x16, 0x10, 0x1610, "Blocks entrance to Woods (auto-set upon re-entering Grove before Skull Kid 2" }, - { 0x16, 0x08, 0x1608, "Lost woods skull kid human chase (unset once done)" }, - { 0x16, 0x02, 0x1602, "skull kid human defeated" }, - { 0x16, 0x01, 0x1601, "lost woods turns to day after skull kid fight human" }, - { 0x17, 0x80, 0x1780, "Skull Kid Appears (set automatically)" }, - { 0x17, 0x40, 0x1740, "Transition to day after Skull Kid" }, - { 0x17, 0x20, 0x1720, "dark beasts spawned" }, - { 0x17, 0x10, 0x1710, "Sacred Grove Portal (removes statue blocking door of time (to past)" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "Big chest lost woods 2 torches" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "Big chest spinner in skull kid wolf battle area" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "PoH big chest temple of time (past)" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "lit left torch chest lost woods" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "killed poe temple of time (past)" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "midna text after pushing block human" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "cs after pushing block human" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "intro cs lost woods" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "?" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "?" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "explored section after window before dungeon (includes map marker for dungeon)" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "stairs to temple of time area near (dungeon)" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "strike MS into pedestal in past" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "window and stairs to dungeon work properly" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "killed poe lost woods water" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "killed poe in skull kid wolf battle area" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "killed poe in master sword area (present)" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "skull kid wolf battle area explored" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "temple of time (present) main room explored" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "temple of time (past) main room explored" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "blown up rock in skull kid wolf battle area" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "block pushed human" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "Master Sword Puzzle Complete" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "Master sword area explored" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "Temple of time (present) human entrence explored" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "spawn big chest lost woods 2 torches" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "lit right torch chest lost woods" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "Master Sword Pulled (does not despawn)" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "Blocks entrance to Woods (auto-set upon re-entering Grove before Skull Kid 2" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "Lost woods skull kid human chase (unset once done)" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "skull kid human defeated" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "lost woods turns to day after skull kid fight human" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "Skull Kid Appears (set automatically)" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "Transition to day after Skull Kid" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "dark beasts spawned" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "Sacred Grove Portal (removes statue blocking door of time (to past)" }, }; inline EventAreaFlags eventAreaFlagsSewer[] = { - { 0x00, 0x80, 0x0080, "0" }, - { 0x00, 0x40, 0x0040, "1" }, - { 0x00, 0x20, 0x0020, "2" }, - { 0x00, 0x10, 0x0010, "3" }, - { 0x00, 0x08, 0x0008, "4" }, - { 0x00, 0x04, 0x0004, "5" }, - { 0x00, 0x02, 0x0002, "6" }, - { 0x00, 0x01, 0x0001, "7" }, - { 0x01, 0x80, 0x0180, "8" }, - { 0x01, 0x40, 0x0140, "9" }, - { 0x01, 0x20, 0x0120, "10" }, - { 0x01, 0x10, 0x0110, "11" }, - { 0x01, 0x08, 0x0108, "12" }, - { 0x01, 0x04, 0x0104, "13" }, - { 0x01, 0x02, 0x0102, "14" }, - { 0x01, 0x01, 0x0101, "15" }, - { 0x02, 0x80, 0x0280, "16" }, - { 0x02, 0x40, 0x0240, "17" }, - { 0x02, 0x20, 0x0220, "18" }, - { 0x02, 0x10, 0x0210, "19" }, - { 0x02, 0x08, 0x0208, "20" }, - { 0x08, 0x80, 0x0880, "twilight final cs" }, - { 0x08, 0x40, 0x0840, "Zelda cs twilight" }, - { 0x08, 0x20, 0x0820, "midna text after first gate sewers (how to fight)" }, - { 0x08, 0x10, 0x0810, "midna text after exiting to rooftops (twilight)" }, - { 0x08, 0x08, 0x0808, "wake up in jail cs" }, - { 0x08, 0x04, 0x0804, "midna promt to use sense to see gard (entrance to sewers)" }, - { 0x08, 0x02, 0x0802, "pushed box outside (MDH)" }, - { 0x08, 0x01, 0x0801, "pulled lever of first water gate in sewers" }, - { 0x09, 0x80, 0x0980, "dug up blue rupee after crawl space (sewers) (twilight)" }, - { 0x09, 0x40, 0x0940, "second water gate in sewers cs (unset afterwards)" }, - { 0x09, 0x20, 0x0920, "first water gate in sewers cs (unset afterwards)" }, - { 0x09, 0x10, 0x0910, "midna cs after diging out of jail" }, - { 0x09, 0x08, 0x0908, "midna intro cs" }, - { 0x09, 0x04, 0x0904, "waited long enough in jail" }, - { 0x09, 0x02, 0x0902, "broke fragile floor first jump of stairway (unlocks first midna jump)" }, - { 0x09, 0x01, 0x0901, "started midna jumps 3 stairway" }, - { 0x0A, 0x80, 0x0A80, "started midna jumps 2 stairway" }, - { 0x0A, 0x40, 0x0A40, "zelda tower intro cs" }, - { 0x0A, 0x20, 0x0A20, "midna went to the other side of the fence in sewers" }, - { 0x0A, 0x10, 0x0A10, "started midna jumps on rooftops" }, - { 0x0A, 0x08, 0x0A08, "started midna jumps 4 stairway (top to door)" }, - { 0x0A, 0x04, 0x0A04, "broke box inside Link's cell" }, - { 0x0A, 0x02, 0x0A02, "did midna jumps 1 stairway (broke small platform)" }, - { 0x0A, 0x01, 0x0A01, "outside top door intro cs" }, - { 0x0B, 0x80, 0x0B80, "broke fire in Zelda's room" }, - { 0x0B, 0x40, 0x0B40, "midna rejoinded link after crawl space" }, - { 0x0B, 0x20, 0x0B20, "went to the other side of the fence in sewers cs" }, - { 0x0B, 0x10, 0x0B10, "top of stairway intro cs" }, - { 0x0B, 0x08, 0x0B08, "stairway intro cs" }, - { 0x0B, 0x04, 0x0B04, "read midna promt to open door" }, - { 0x0B, 0x02, 0x0B02, "opened door in cell next to Link's" }, - { 0x0B, 0x01, 0x0B01, "dug out of Link's cell" }, - { 0x0D, 0x80, 0x0D80, "killed first bulblin outside (MDH)" }, - { 0x0D, 0x20, 0x0D20, "killed second bulblin outside (MDH)" }, - { 0x0D, 0x04, 0x0D04, "killed bulblin at top of stairway (on the patform) (MDH)" }, - { 0x0E, 0x80, 0x0E80, "killed fourth bulblin in stairway (MDH)" }, - { 0x0E, 0x20, 0x0E20, "killed third bulblin in stairway (MDH)" }, - { 0x0E, 0x04, 0x0E04, "killed second bulblin in stairway (MDH)" }, - { 0x0E, 0x02, 0x0E02, "killed first bulblin in stairway (MDH)" }, - { 0x0F, 0x20, 0x0F20, "talked to midna after using sense on first rooftop gard" }, - { 0x0F, 0x10, 0x0F10, "midna text when approching first rooftop gard" }, - { 0x0F, 0x08, 0x0F08, "listened to first gard in sewers" }, - { 0x0F, 0x04, 0x0F04, "saw first rooftop gard with sense" }, - { 0x0F, 0x02, 0x0F02, "saw first gard in sewers" }, - { 0x0F, 0x01, 0x0F01, "midna cs after diging out of jail" }, - { 0x1B, 0x08, 0x1B08, "picked up green rupee in box in secret passge next to fence (sewers) (twilight)" }, - { 0x1B, 0x04, 0x1B04, "picked up blue rupee in box in left secret way (sewers) (twilight)" }, - { 0x1B, 0x02, 0x1B02, "picked up purple rupee in boxes (first windy bridge) (MDH)" }, - { 0x1B, 0x01, 0x1B01, "picked up yellow rupee in Zelda's fire" }, + { 0x00, 0x80, AreaFlagInd{0x0080}, "0" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "1" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "2" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "3" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "4" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "5" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "6" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "7" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "8" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "9" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "10" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "11" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "12" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "13" }, + { 0x01, 0x02, AreaFlagInd{0x0102}, "14" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "15" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "16" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "17" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "18" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "19" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "20" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "twilight final cs" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "Zelda cs twilight" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "midna text after first gate sewers (how to fight)" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "midna text after exiting to rooftops (twilight)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "wake up in jail cs" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "midna promt to use sense to see gard (entrance to sewers)" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "pushed box outside (MDH)" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "pulled lever of first water gate in sewers" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "dug up blue rupee after crawl space (sewers) (twilight)" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "second water gate in sewers cs (unset afterwards)" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "first water gate in sewers cs (unset afterwards)" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "midna cs after diging out of jail" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "midna intro cs" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "waited long enough in jail" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "broke fragile floor first jump of stairway (unlocks first midna jump)" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "started midna jumps 3 stairway" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "started midna jumps 2 stairway" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "zelda tower intro cs" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "midna went to the other side of the fence in sewers" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "started midna jumps on rooftops" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "started midna jumps 4 stairway (top to door)" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "broke box inside Link's cell" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "did midna jumps 1 stairway (broke small platform)" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "outside top door intro cs" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "broke fire in Zelda's room" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "midna rejoinded link after crawl space" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "went to the other side of the fence in sewers cs" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "top of stairway intro cs" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "stairway intro cs" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "read midna promt to open door" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "opened door in cell next to Link's" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "dug out of Link's cell" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "killed first bulblin outside (MDH)" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "killed second bulblin outside (MDH)" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "killed bulblin at top of stairway (on the patform) (MDH)" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "killed fourth bulblin in stairway (MDH)" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "killed third bulblin in stairway (MDH)" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "killed second bulblin in stairway (MDH)" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "killed first bulblin in stairway (MDH)" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "talked to midna after using sense on first rooftop gard" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "midna text when approching first rooftop gard" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "listened to first gard in sewers" }, + { 0x0F, 0x04, AreaFlagInd{0x0F04}, "saw first rooftop gard with sense" }, + { 0x0F, 0x02, AreaFlagInd{0x0F02}, "saw first gard in sewers" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "midna cs after diging out of jail" }, + { 0x1B, 0x08, AreaFlagInd{0x1B08}, "picked up green rupee in box in secret passge next to fence (sewers) (twilight)" }, + { 0x1B, 0x04, AreaFlagInd{0x1B04}, "picked up blue rupee in box in left secret way (sewers) (twilight)" }, + { 0x1B, 0x02, AreaFlagInd{0x1B02}, "picked up purple rupee in boxes (first windy bridge) (MDH)" }, + { 0x1B, 0x01, AreaFlagInd{0x1B01}, "picked up yellow rupee in Zelda's fire" }, }; inline EventAreaFlags eventAreaFlagsSnowpeak[] = { - { 0x03, 0x01, 0x0301, "Big chest transition cave" }, - { 0x08, 0x40, 0x0840, "montain top explored" }, - { 0x08, 0x20, 0x0820, "Map marker Ashei" }, - { 0x08, 0x04, 0x0804, "montain top cs (pan towards tree)" }, - { 0x08, 0x02, 0x0802, "Post SPR Save Prompt" }, - { 0x09, 0x80, 0x0980, "?" }, - { 0x09, 0x40, 0x0940, "?" }, - { 0x09, 0x20, 0x0920, "Snowpeak top portal" }, - { 0x0B, 0x08, 0x0B08, "explored second section up montain" }, - { 0x0B, 0x04, 0x0B04, "explored first section up montain" }, - { 0x0B, 0x02, 0x0B02, "Midna text in front of SPR" }, - { 0x0B, 0x01, 0x0B01, "intro cs" }, - { 0x0D, 0x10, 0x0D10, "spawn big chest transition cave" }, - { 0x0D, 0x08, 0x0D08, "lit left torch transition cave" }, - { 0x0D, 0x04, 0x0D04, "lit right torch transition cave" }, - { 0x0F, 0x08, 0x0F08, "snow fell down next to howling stone" }, - { 0x14, 0x80, 0x1480, "killed poe transition cave" }, - { 0x14, 0x40, 0x1440, "killed poe next to snowpeak ruins" }, - { 0x14, 0x20, 0x1420, "killed first poe up the montain" }, - { 0x14, 0x10, 0x1410, "killed second poe next to lone tree on cliff" }, - { 0x14, 0x08, 0x1408, "killed third poe near 2 trees before howling stone" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "Big chest transition cave" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "montain top explored" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "Map marker Ashei" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "montain top cs (pan towards tree)" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "Post SPR Save Prompt" }, + { 0x09, 0x80, AreaFlagInd{0x0980}, "?" }, + { 0x09, 0x40, AreaFlagInd{0x0940}, "?" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "Snowpeak top portal" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "explored second section up montain" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "explored first section up montain" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "Midna text in front of SPR" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "intro cs" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "spawn big chest transition cave" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "lit left torch transition cave" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "lit right torch transition cave" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "snow fell down next to howling stone" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "killed poe transition cave" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "killed poe next to snowpeak ruins" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "killed first poe up the montain" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "killed second poe next to lone tree on cliff" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "killed third poe near 2 trees before howling stone" }, }; inline EventAreaFlags eventAreaFlagsSPR[] = { - { 0x00, 0x02, 0x0002, "PoH big chest under broken ceiling" }, - { 0x01, 0x80, 0x0180, "left small chest behind armor in first room" }, - { 0x01, 0x40, 0x0140, "right small chest behind armor in first room" }, - { 0x01, 0x20, 0x0120, "PoH big chest in first room 2F" }, - { 0x01, 0x10, 0x0110, "west small chest behind ice in north west room" }, - { 0x01, 0x08, 0x0108, "east small chest behind ice in north west room" }, - { 0x01, 0x04, 0x0104, "small key small chest pumpkin room" }, - { 0x01, 0x01, 0x0101, "Ooccoo" }, - { 0x02, 0x80, 0x0280, "south east small chest in courtyard" }, - { 0x02, 0x40, 0x0240, "small key buried east small chest in courtyard" }, - { 0x02, 0x20, 0x0220, "small key buried west small chest in courtyard" }, - { 0x02, 0x08, 0x0208, "big key chest" }, - { 0x02, 0x04, 0x0204, "pumpkin big chest" }, - { 0x03, 0x80, 0x0380, "small key big chest in compass room 2F" }, - { 0x03, 0x40, 0x0340, "cheese big chest" }, - { 0x03, 0x08, 0x0308, "south small chest behind ice in courtyard" }, - { 0x03, 0x04, 0x0304, "compass big chest" }, - { 0x03, 0x02, 0x0302, "small chest compass room 1F" }, - //{ 0x08, 0x80, 0x0880, "position of second block in ice puzzle room" }, - //{ 0x08, 0x40, 0x0840, "position of second block in ice puzzle room" }, - //{ 0x08, 0x20, 0x0820, "position of second block in ice puzzle room" }, - //{ 0x08, 0x10, 0x0810, "position of second block in ice puzzle room" }, - //{ 0x08, 0x08, 0x0808, "position of second block in ice puzzle room" }, - //{ 0x08, 0x04, 0x0804, "position of third block in ice puzzle room (frozen one)" }, - //{ 0x08, 0x02, 0x0802, "position of third block in ice puzzle room (frozen one)" }, - //{ 0x08, 0x01, 0x0801, "position of third block in ice puzzle room (frozen one)" }, - //{ 0x09, 0x80, 0x0980, "position of third block in ice puzzle room (frozen one)" }, - //{ 0x09, 0x40, 0x0940, "position of third block in ice puzzle room (frozen one)" }, - { 0x09, 0x20, 0x0920, "killed poe in armor in first room" }, - { 0x09, 0x08, 0x0908, "unlock west living room door" }, - { 0x09, 0x04, 0x0904, "unlock north living room door" }, - { 0x09, 0x02, 0x0902, "lowered ball transport (west hallway-freezard)" }, - { 0x09, 0x01, 0x0901, "lowered ball transport (courtyard 2F)" }, - { 0x0A, 0x80, 0x0A80, "dug first time west buried small chest in courtyard" }, - { 0x0A, 0x40, 0x0A40, "lowered ball transport (west hallway-courtyard)" }, - { 0x0A, 0x20, 0x0A20, "dug second time west buried small chest in courtyard" }, - { 0x0A, 0x10, 0x0A10, "talked to Yeta for the first time (gives map)" }, - { 0x0A, 0x04, 0x0A04, "destroyed ice in courtyard 2F" }, - { 0x0A, 0x02, 0x0A02, "Yeta enters bedroom cs (in courtyard)" }, - { 0x0A, 0x01, 0x0A01, "unlock bedroom door" }, - { 0x0B, 0x80, 0x0B80, "enter courtyard" }, - { 0x0B, 0x20, 0x0B20, "compass big chest (set after)" }, - { 0x0B, 0x10, 0x0B10, "broke ice in pumpkin room 2F" }, - { 0x0B, 0x08, 0x0B08, "dug up east small chest in courtyard" }, - { 0x0B, 0x04, 0x0B04, "open west door 2F in ice puzzle room" }, - { 0x0B, 0x02, 0x0B02, "open west door 1F in ice puzzle room" }, - { 0x0C, 0x80, 0x0C80, "destroyed first left armor in first room" }, - { 0x0C, 0x40, 0x0C40, "destroyed second left armor in first room" }, - { 0x0C, 0x20, 0x0C20, "destroyed third left armor in first room" }, - //{ 0x0C, 0x08, 0x0C08, "canon in north west room orientation" }, - //{ 0x0C, 0x04, 0x0C04, "canon in north west room orientation" }, - { 0x0C, 0x02, 0x0C02, "killed freezard in courtyard 1F" }, - { 0x0C, 0x01, 0x0C01, "explored compass room" }, - { 0x0D, 0x80, 0x0D80, "killed first freezard in cage" }, - { 0x0D, 0x40, 0x0D40, "killed freezard in courtyard 2F" }, - { 0x0D, 0x20, 0x0D20, "killed west freezard in room above livng room (2F)" }, - { 0x0D, 0x10, 0x0D10, "killed north freezard in room above livng room (2F)" }, - { 0x0D, 0x08, 0x0D08, "broke ice in first room 2F" }, - { 0x0D, 0x04, 0x0D04, "destroyed ice on block in ice puzzle room" }, - { 0x0D, 0x01, 0x0D01, "unlock door in south east room 2F" }, - { 0x0E, 0x80, 0x0E80, "unlocked door to first room in freezard cage room" }, - { 0x0E, 0x20, 0x0E20, "unlock doors in room before pumpkin" }, - { 0x0E, 0x10, 0x0E10, "unlock door in east outside hallway" }, - { 0x0E, 0x08, 0x0E08, "unlock west door in courtyard" }, - { 0x0E, 0x04, 0x0E04, "explored courtyard 1F" }, - { 0x0E, 0x02, 0x0E02, "explored room above ice puzzle (2F)" }, - { 0x0E, 0x01, 0x0E01, "explored room above pumpkin (2F)" }, - { 0x0F, 0x80, 0x0F80, "puched left block in room above living room (2F)" }, - { 0x0F, 0x40, 0x0F40, "puched right block in room above living room (2F)" }, - { 0x0F, 0x20, 0x0F20, "2nd floor block pushed down in ice puzzle room" }, - //{ 0x0F, 0x10, 0x0F10, "position of first block in ice puzzle room" }, - //{ 0x0F, 0x08, 0x0F08, "position of first block in ice puzzle room" }, - //{ 0x0F, 0x04, 0x0F04, "position of first block in ice puzzle room" }, - //{ 0x0F, 0x02, 0x0F02, "position of first block in ice puzzle room" }, - //{ 0x0F, 0x01, 0x0F01, "position of first block in ice puzzle room" }, - { 0x10, 0x80, 0x1080, "Picked up B&C" }, - { 0x10, 0x40, 0x1040, "?" }, - { 0x10, 0x20, 0x1020, "Yeta lets you open door to kitchen" }, - { 0x10, 0x10, 0x1010, "north west room 1F intro cs" }, - { 0x10, 0x08, 0x1008, "Midna big key text prompt" }, - { 0x10, 0x02, 0x1002, "pumpkin room ambush cs trigger" }, - //{ 0x10, 0x01, 0x1001, "courtyard 2F canon orientation" }, - //{ 0x11, 0x80, 0x1180, "courtyard 2F canon orientation" }, - //{ 0x11, 0x40, 0x1140, "courtyard 1F canon orientation" }, - //{ 0x11, 0x20, 0x1120, "courtyard 1F canon orientation" }, - { 0x11, 0x02, 0x1102, "unlock mini-boss doors" }, - { 0x11, 0x01, 0x1101, "pushed block in west outside hallway" }, - { 0x12, 0x40, 0x1240, "unlock doors in pumpkin room" }, - { 0x12, 0x20, 0x1220, "explored path to bedroom 2F & 3F" }, - { 0x12, 0x10, 0x1210, "killed second freezard in cage" }, - { 0x12, 0x08, 0x1208, "explored west outside hallway 2F (canon)" }, - { 0x12, 0x04, 0x1204, "unlock door to big key in big key room" }, - //{ 0x12, 0x02, 0x1202, "freezard cage canon orientation" }, - //{ 0x12, 0x01, 0x1201, "freezard cage canon orientation" }, - { 0x13, 0x40, 0x1340, "killed chilfos in pumpkin room (unlock south door)" }, - { 0x13, 0x20, 0x1320, "?" }, - { 0x13, 0x10, 0x1310, "killed chilfos in big key room" }, - { 0x13, 0x08, 0x1308, "broke center ice in Ice puzzle room" }, - { 0x13, 0x04, 0x1304, "broke first right armor in first room" }, - { 0x13, 0x02, 0x1302, "broke second right armor in first room (spawns poe)" }, - { 0x13, 0x01, 0x1301, "broke third right armor in first room" }, - { 0x14, 0x80, 0x1480, "killed poe in south east room 2F" }, - { 0x14, 0x40, 0x1440, "Midna big key text seen" }, - { 0x14, 0x10, 0x1410, "explored east outside hallway 2F " }, - { 0x14, 0x08, 0x1408, "explored west outside hallway 1F (canonballs)" }, - { 0x14, 0x04, 0x1404, "explored room above living room (2F)" }, - { 0x14, 0x02, 0x1402, "explored freezard in cages room 2F" }, - { 0x14, 0x01, 0x1401, "Intro Cutscene" }, - { 0x15, 0x80, 0x1580, "unlock west door in pumpkin room" }, - { 0x15, 0x40, 0x1540, "destroyed first right armor in cheese room" }, - { 0x15, 0x20, 0x1520, "freezard in cage cs" }, - { 0x15, 0x08, 0x1508, "courtyard intro cs" }, - { 0x15, 0x04, 0x1504, "killed poe in center of first room" }, - { 0x15, 0x02, 0x1502, "pumpkin room intro cs" }, - { 0x15, 0x01, 0x1501, "?" }, - { 0x16, 0x80, 0x1680, "?" }, - { 0x16, 0x40, 0x1640, "Yeta points to kitchen cs" }, - { 0x16, 0x20, 0x1620, "Midna Cheese text prompt" }, - { 0x16, 0x10, 0x1610, "Midna Cheese text seen" }, - { 0x16, 0x08, 0x1608, "Midna pumpkin text seen" }, - { 0x16, 0x04, 0x1604, "Darkhammer (unsets after defeat)" }, - { 0x16, 0x02, 0x1602, "Midna pumpkin text prompt" }, - { 0x16, 0x01, 0x1601, "unlock exit door in big key room" }, - { 0x17, 0x80, 0x1780, "map marker bedroom key" }, - { 0x17, 0x40, 0x1740, "map marker ordon cheese" }, - { 0x17, 0x20, 0x1720, "map marker ordon pumpkin" }, - { 0x17, 0x10, 0x1710, "Blizzeta Cutscene" }, - { 0x17, 0x08, 0x1708, "broke first ice south door in north west room 1F" }, - { 0x17, 0x04, 0x1704, "broke second ice south door in north west room 1F" }, - { 0x17, 0x02, 0x1702, "broke third ice south door in north west room 1F" }, - { 0x17, 0x01, 0x1701, "broke ice wall in compass room 2F" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "PoH big chest under broken ceiling" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "left small chest behind armor in first room" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "right small chest behind armor in first room" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "PoH big chest in first room 2F" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "west small chest behind ice in north west room" }, + { 0x01, 0x08, AreaFlagInd{0x0108}, "east small chest behind ice in north west room" }, + { 0x01, 0x04, AreaFlagInd{0x0104}, "small key small chest pumpkin room" }, + { 0x01, 0x01, AreaFlagInd{0x0101}, "Ooccoo" }, + { 0x02, 0x80, AreaFlagInd{0x0280}, "south east small chest in courtyard" }, + { 0x02, 0x40, AreaFlagInd{0x0240}, "small key buried east small chest in courtyard" }, + { 0x02, 0x20, AreaFlagInd{0x0220}, "small key buried west small chest in courtyard" }, + { 0x02, 0x08, AreaFlagInd{0x0208}, "big key chest" }, + { 0x02, 0x04, AreaFlagInd{0x0204}, "pumpkin big chest" }, + { 0x03, 0x80, AreaFlagInd{0x0380}, "small key big chest in compass room 2F" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "cheese big chest" }, + { 0x03, 0x08, AreaFlagInd{0x0308}, "south small chest behind ice in courtyard" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "compass big chest" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "small chest compass room 1F" }, + //{ 0x08, 0x80, AreaFlagInd{0x0880}, "position of second block in ice puzzle room" }, + //{ 0x08, 0x40, AreaFlagInd{0x0840}, "position of second block in ice puzzle room" }, + //{ 0x08, 0x20, AreaFlagInd{0x0820}, "position of second block in ice puzzle room" }, + //{ 0x08, 0x10, AreaFlagInd{0x0810}, "position of second block in ice puzzle room" }, + //{ 0x08, 0x08, AreaFlagInd{0x0808}, "position of second block in ice puzzle room" }, + //{ 0x08, 0x04, AreaFlagInd{0x0804}, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x08, 0x02, AreaFlagInd{0x0802}, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x08, 0x01, AreaFlagInd{0x0801}, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x09, 0x80, AreaFlagInd{0x0980}, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x09, 0x40, AreaFlagInd{0x0940}, "position of third block in ice puzzle room (frozen one)" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "killed poe in armor in first room" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "unlock west living room door" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "unlock north living room door" }, + { 0x09, 0x02, AreaFlagInd{0x0902}, "lowered ball transport (west hallway-freezard)" }, + { 0x09, 0x01, AreaFlagInd{0x0901}, "lowered ball transport (courtyard 2F)" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "dug first time west buried small chest in courtyard" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "lowered ball transport (west hallway-courtyard)" }, + { 0x0A, 0x20, AreaFlagInd{0x0A20}, "dug second time west buried small chest in courtyard" }, + { 0x0A, 0x10, AreaFlagInd{0x0A10}, "talked to Yeta for the first time (gives map)" }, + { 0x0A, 0x04, AreaFlagInd{0x0A04}, "destroyed ice in courtyard 2F" }, + { 0x0A, 0x02, AreaFlagInd{0x0A02}, "Yeta enters bedroom cs (in courtyard)" }, + { 0x0A, 0x01, AreaFlagInd{0x0A01}, "unlock bedroom door" }, + { 0x0B, 0x80, AreaFlagInd{0x0B80}, "enter courtyard" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "compass big chest (set after)" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "broke ice in pumpkin room 2F" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "dug up east small chest in courtyard" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "open west door 2F in ice puzzle room" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "open west door 1F in ice puzzle room" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "destroyed first left armor in first room" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "destroyed second left armor in first room" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "destroyed third left armor in first room" }, + //{ 0x0C, 0x08, AreaFlagInd{0x0C08}, "canon in north west room orientation" }, + //{ 0x0C, 0x04, AreaFlagInd{0x0C04}, "canon in north west room orientation" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "killed freezard in courtyard 1F" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "explored compass room" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "killed first freezard in cage" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "killed freezard in courtyard 2F" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "killed west freezard in room above livng room (2F)" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "killed north freezard in room above livng room (2F)" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "broke ice in first room 2F" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "destroyed ice on block in ice puzzle room" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "unlock door in south east room 2F" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "unlocked door to first room in freezard cage room" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "unlock doors in room before pumpkin" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "unlock door in east outside hallway" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "unlock west door in courtyard" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "explored courtyard 1F" }, + { 0x0E, 0x02, AreaFlagInd{0x0E02}, "explored room above ice puzzle (2F)" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "explored room above pumpkin (2F)" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "puched left block in room above living room (2F)" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "puched right block in room above living room (2F)" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "2nd floor block pushed down in ice puzzle room" }, + //{ 0x0F, 0x10, AreaFlagInd{0x0F10}, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x08, AreaFlagInd{0x0F08}, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x04, AreaFlagInd{0x0F04}, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x02, AreaFlagInd{0x0F02}, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x01, AreaFlagInd{0x0F01}, "position of first block in ice puzzle room" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "Picked up B&C" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "?" }, + { 0x10, 0x20, AreaFlagInd{0x1020}, "Yeta lets you open door to kitchen" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "north west room 1F intro cs" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "Midna big key text prompt" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "pumpkin room ambush cs trigger" }, + //{ 0x10, 0x01, AreaFlagInd{0x1001}, "courtyard 2F canon orientation" }, + //{ 0x11, 0x80, AreaFlagInd{0x1180}, "courtyard 2F canon orientation" }, + //{ 0x11, 0x40, AreaFlagInd{0x1140}, "courtyard 1F canon orientation" }, + //{ 0x11, 0x20, AreaFlagInd{0x1120}, "courtyard 1F canon orientation" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "unlock mini-boss doors" }, + { 0x11, 0x01, AreaFlagInd{0x1101}, "pushed block in west outside hallway" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "unlock doors in pumpkin room" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "explored path to bedroom 2F & 3F" }, + { 0x12, 0x10, AreaFlagInd{0x1210}, "killed second freezard in cage" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "explored west outside hallway 2F (canon)" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "unlock door to big key in big key room" }, + //{ 0x12, 0x02, AreaFlagInd{0x1202}, "freezard cage canon orientation" }, + //{ 0x12, 0x01, AreaFlagInd{0x1201}, "freezard cage canon orientation" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "killed chilfos in pumpkin room (unlock south door)" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "?" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "killed chilfos in big key room" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "broke center ice in Ice puzzle room" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "broke first right armor in first room" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "broke second right armor in first room (spawns poe)" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "broke third right armor in first room" }, + { 0x14, 0x80, AreaFlagInd{0x1480}, "killed poe in south east room 2F" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "Midna big key text seen" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "explored east outside hallway 2F " }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "explored west outside hallway 1F (canonballs)" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "explored room above living room (2F)" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "explored freezard in cages room 2F" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "Intro Cutscene" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "unlock west door in pumpkin room" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "destroyed first right armor in cheese room" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "freezard in cage cs" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "courtyard intro cs" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "killed poe in center of first room" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "pumpkin room intro cs" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "?" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "?" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "Yeta points to kitchen cs" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "Midna Cheese text prompt" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "Midna Cheese text seen" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "Midna pumpkin text seen" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "Darkhammer (unsets after defeat)" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "Midna pumpkin text prompt" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "unlock exit door in big key room" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "map marker bedroom key" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "map marker ordon cheese" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "map marker ordon pumpkin" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "Blizzeta Cutscene" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "broke first ice south door in north west room 1F" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "broke second ice south door in north west room 1F" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "broke third ice south door in north west room 1F" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "broke ice wall in compass room 2F" }, }; inline EventAreaFlags eventAreaFlagsToT[] = { - { 0x00, 0x80, 0x0080, "map marker statue in room 2" }, - { 0x00, 0x40, 0x0040, "map marker statue will spawn in room 2" }, - { 0x00, 0x20, 0x0020, "map marker statue in room 3" }, - { 0x00, 0x10, 0x0010, "map marker statue will spawn in room 3" }, - { 0x00, 0x08, 0x0008, "map marker statue in room 4" }, - { 0x00, 0x04, 0x0004, "map marker statue will spawn in room 4" }, - { 0x00, 0x02, 0x0002, "map marker statue in room 5" }, - { 0x00, 0x01, 0x0001, "map marker statue will spawn in room 5" }, - { 0x01, 0x80, 0x0180, "map marker statue in room 6" }, - { 0x01, 0x40, 0x0140, "map marker statue will spawn in room 6" }, - { 0x01, 0x20, 0x0120, "map marker statue in room 7" }, - { 0x01, 0x10, 0x0110, "map marker statue will spawn in room 7" }, - { 0x02, 0x10, 0x0210, "PoH big chest room 4" }, - { 0x02, 0x02, 0x0202, "small key big chest room 6 7F" }, - { 0x02, 0x01, 0x0201, "big key chest" }, - { 0x03, 0x40, 0x0340, "compass big chest room 4" }, - { 0x03, 0x20, 0x0320, "PoH big chest south room 5F" }, - { 0x03, 0x10, 0x0310, "small key big chest south room 5F" }, - { 0x03, 0x04, 0x0304, "small chest room 2 2F" }, - { 0x03, 0x02, 0x0302, "map big chest room 2 3F" }, - { 0x03, 0x01, 0x0301, "dominion rod big chest" }, - { 0x04, 0x80, 0x0480, "Ooccoo" }, - { 0x05, 0x01, 0x0501, "small chest big key room" }, - { 0x06, 0x80, 0x0680, "small chest room 5 7F" }, - { 0x06, 0x40, 0x0640, "south small chest south room 5F" }, - { 0x06, 0x20, 0x0620, "small chest room 2 3F" }, - { 0x06, 0x10, 0x0610, "big chest room 5 6F" }, - { 0x06, 0x08, 0x0608, "big chest room 6 8F" }, - { 0x06, 0x02, 0x0602, "small key big chest room 1" }, - { 0x07, 0x02, 0x0702, "map marker statue in room 1" }, - { 0x07, 0x01, 0x0701, "map marker statue will spawn in room 1" }, - { 0x08, 0x80, 0x0880, "Midna text asking to look at missing statue room 1" }, - { 0x08, 0x40, 0x0840, "Midna text after looking at missing statue room 1" }, - { 0x08, 0x20, 0x0820, "unlock door in room 6 8F" }, - { 0x08, 0x10, 0x0810, "unlock door in room 3 5F (spawn baby and young gohmas in south room 5F)" }, - { 0x08, 0x08, 0x0808, "unlock door in room 1" }, - { 0x08, 0x04, 0x0804, "dominion rod big chest (set after)" }, - { 0x08, 0x02, 0x0802, "killed poe in room 3 3F" }, - { 0x08, 0x01, 0x0801, "killed poe in room 5 7F" }, - { 0x09, 0x20, 0x0920, "intro cs" }, - { 0x09, 0x10, 0x0910, "scale intro cs room 5 6F" }, - { 0x09, 0x08, 0x0908, "change balance of scale for the first time cs" }, - { 0x09, 0x04, 0x0904, "change balance of scale for the first time" }, - { 0x0A, 0x80, 0x0A80, "entered room 7" }, - { 0x0A, 0x40, 0x0A40, "spawn west big chest in south room 5F" }, - { 0x0A, 0x08, 0x0A08, "statue getting possessed for the first time cs" }, - { 0x0B, 0x40, 0x0B40, "deactivate statue slot in room 1 (opens door and deactivates statue)" }, - { 0x0B, 0x20, 0x0B20, "deactivate bell in room 2 (required to spawn in room 1)" }, - { 0x0B, 0x10, 0x0B10, "deactivate bell in room 3 (required to spawn in room 2)" }, - { 0x0B, 0x08, 0x0B08, "deactivate bell in room 4 (required to spawn in room 3)" }, - { 0x0B, 0x04, 0x0B04, "deactivate bell in room 5 (required to spawn in room 4)" }, - { 0x0B, 0x02, 0x0B02, "deactivate bell in room 6 (required to spawn in room 5)" }, - { 0x0B, 0x01, 0x0B01, "deactivate bell in room 7 (required to spawn in room 6)" }, - { 0x0C, 0x80, 0x0C80, "unlock door in south room 5F" }, - { 0x0C, 0x40, 0x0C40, "killed armos in room 2 3F (spawn big chest)" }, - { 0x0C, 0x20, 0x0C20, "killed armos in big key room (unlocks door)" }, - { 0x0C, 0x10, 0x0C10, "lit both torches in room 1 (unset if you leave) (spawn big chest)" }, - { 0x0C, 0x04, 0x0C04, "broke gate in room 2 3F" }, - { 0x0C, 0x02, 0x0C02, "broke fouth gate in room 2 2F" }, - { 0x0C, 0x01, 0x0C01, "broke first gate in room 2 2F" }, - { 0x0D, 0x80, 0x0D80, "broke third gate in room 2 2F" }, - { 0x0D, 0x40, 0x0D40, "broke second gate in room 2 2F" }, - { 0x0D, 0x20, 0x0D20, "broke second sliding door in room 4 4F" }, - { 0x0D, 0x10, 0x0D10, "broke third sliding door in room 4 5F" }, - { 0x0D, 0x08, 0x0D08, "broke second sliding door in room 4 5F" }, - { 0x0D, 0x04, 0x0D04, "broke first sliding door in room 4 5F" }, - { 0x0D, 0x02, 0x0D02, "broke first sliding door in room 4 4F" }, - { 0x0D, 0x01, 0x0D01, "broke first beamos in room before boss" }, - { 0x0E, 0x80, 0x0E80, "broke left beamos in room before boss" }, - { 0x0E, 0x40, 0x0E40, "broke right beamos in room before boss" }, - { 0x0E, 0x20, 0x0E20, "broke beamos in room 6 7F" }, - { 0x0E, 0x10, 0x0E10, "broke first beamos in room 4 4F" }, - { 0x0E, 0x08, 0x0E08, "broke second beamos in room 4 4F" }, - { 0x0E, 0x04, 0x0E04, "broke beamos in room 3 3F" }, - { 0x0E, 0x01, 0x0E01, "broke gate to bell in room 3 3F" }, - { 0x0F, 0x80, 0x0F80, "broke gate to poe in room 3 3F" }, - { 0x0F, 0x40, 0x0F40, "broke gate in room 6 8F" }, - { 0x0F, 0x20, 0x0F20, "open door to poe in room 3 3F" }, - { 0x0F, 0x10, 0x0F10, "spawn baby gohmas in beamos room 3 3F" }, - { 0x0F, 0x08, 0x0F08, "broke gate in room 6 8F cs" }, - { 0x0F, 0x01, 0x0F01, "unlock boss door" }, - { 0x10, 0x80, 0x1080, "open big door in room 1 cs part 2" }, - { 0x10, 0x40, 0x1040, "open big door in room 1 cs part 1" }, - { 0x10, 0x10, 0x1010, "killed a baby gohma in room 6 8F" }, - { 0x10, 0x08, 0x1008, "killed a baby gohma in room 6 8F" }, - { 0x10, 0x04, 0x1004, "killed a baby gohma in room 6 8F" }, - { 0x10, 0x02, 0x1002, "killed a baby gohma in room 6 8F" }, - { 0x10, 0x01, 0x1001, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x80, 0x1180, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x40, 0x1140, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x20, 0x1120, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x10, 0x1110, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x08, 0x1108, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x04, 0x1104, "killed a baby gohma in room 6 8F" }, - { 0x11, 0x02, 0x1102, "killed a baby gohma in room 6 8F" }, - { 0x12, 0x80, 0x1280, "pressed button in room 1 (or 6 8F) for the first time cs" }, - { 0x12, 0x40, 0x1240, "pressed button in room 6 7F for the first time cs" }, - { 0x12, 0x20, 0x1220, "killed both armos in room 6 8F (opens gate)" }, - { 0x12, 0x08, 0x1208, "pressed buttons in room 3 5F for the first time cs" }, - { 0x12, 0x04, 0x1204, "pressed buttons in room 2 3F for the first time cs" }, - { 0x12, 0x02, 0x1202, "pressed button in room 2 2F for the first time cs" }, - { 0x13, 0x40, 0x1340, "open gate to dominion rod in room 7" }, - { 0x13, 0x20, 0x1320, "statue spawning out of bell in room 1 cs trigger" }, - { 0x13, 0x10, 0x1310, "statue spawning out of bell in room 1 cs" }, - { 0x13, 0x08, 0x1308, "killed all baby gohmas in room 6 8F (spawn big chest)" }, - { 0x13, 0x04, 0x1304, "killed all enemies in room 5 6F (spawn big chest)" }, - { 0x13, 0x02, 0x1302, "killed west armos in south room 5F" }, - { 0x13, 0x01, 0x1301, "killed east armos in south room 5F" }, - { 0x14, 0x40, 0x1440, "unlock door in room 7" }, - { 0x14, 0x20, 0x1420, "statue getting in bell in room 7 cs first part" }, - { 0x14, 0x10, 0x1410, "statue getting in bell in room 7 cs second part" }, - { 0x14, 0x08, 0x1408, "statue getting in bell in room 7 cs trigger" }, - { 0x14, 0x04, 0x1404, "open gate to dominion rod in room 7 cs" }, - { 0x14, 0x02, 0x1402, "statue spawn out of bell in room 6" }, - { 0x14, 0x01, 0x1401, "statue spawning out of bell in room 6 cs trigger" }, - { 0x15, 0x80, 0x1580, "statue spawning out of bell in room 6 cs part 1" }, - { 0x15, 0x40, 0x1540, "statue getting in bell in room 6 cs trigger" }, - { 0x15, 0x20, 0x1520, "statue getting in bell in room 6 cs" }, - { 0x15, 0x10, 0x1510, "statue spawning out of bell in room 5 cs trigger" }, - { 0x15, 0x08, 0x1508, "statue spawning out of bell in room 5 cs" }, - { 0x15, 0x04, 0x1504, "statue getting in bell in room 5 cs trigger" }, - { 0x15, 0x02, 0x1502, "statue getting in bell in room 5 cs" }, - { 0x15, 0x01, 0x1501, "statue spawning out of bell in room 4 cs trigger" }, - { 0x16, 0x80, 0x1680, "statue spawning out of bell in room 4 cs" }, - { 0x16, 0x40, 0x1640, "statue getting in bell in room 4 cs trigger" }, - { 0x16, 0x20, 0x1620, "statue getting in bell in room 4 cs" }, - { 0x16, 0x10, 0x1610, "statue spawning out of bell in room 3 cs trigger" }, - { 0x16, 0x08, 0x1608, "statue spawning out of bell in room 3 cs" }, - { 0x16, 0x04, 0x1604, "statue getting in bell in room 3 cs trigger" }, - { 0x16, 0x02, 0x1602, "statue getting in bell in room 3 cs" }, - { 0x16, 0x01, 0x1601, "statue spawning out of bell in room 2 cs trigger" }, - { 0x17, 0x80, 0x1780, "statue spawning out of bell in room 2 cs" }, - { 0x17, 0x40, 0x1740, "statue getting in bell in room 2 cs trigger" }, - { 0x17, 0x20, 0x1720, "statue getting in bell in room 2 cs" }, - { 0x17, 0x10, 0x1710, "deactivate spawning bell in room 7" }, - { 0x17, 0x08, 0x1708, "big door in room 1 opens" }, - { 0x17, 0x04, 0x1704, "open big door in room 1 cs part 2 trigger" }, - { 0x17, 0x02, 0x1702, "open big door in room 1 cs part 1 trigger" }, - { 0x17, 0x01, 0x1701, "statue placed in slot in room 1" }, + { 0x00, 0x80, AreaFlagInd{0x0080}, "map marker statue in room 2" }, + { 0x00, 0x40, AreaFlagInd{0x0040}, "map marker statue will spawn in room 2" }, + { 0x00, 0x20, AreaFlagInd{0x0020}, "map marker statue in room 3" }, + { 0x00, 0x10, AreaFlagInd{0x0010}, "map marker statue will spawn in room 3" }, + { 0x00, 0x08, AreaFlagInd{0x0008}, "map marker statue in room 4" }, + { 0x00, 0x04, AreaFlagInd{0x0004}, "map marker statue will spawn in room 4" }, + { 0x00, 0x02, AreaFlagInd{0x0002}, "map marker statue in room 5" }, + { 0x00, 0x01, AreaFlagInd{0x0001}, "map marker statue will spawn in room 5" }, + { 0x01, 0x80, AreaFlagInd{0x0180}, "map marker statue in room 6" }, + { 0x01, 0x40, AreaFlagInd{0x0140}, "map marker statue will spawn in room 6" }, + { 0x01, 0x20, AreaFlagInd{0x0120}, "map marker statue in room 7" }, + { 0x01, 0x10, AreaFlagInd{0x0110}, "map marker statue will spawn in room 7" }, + { 0x02, 0x10, AreaFlagInd{0x0210}, "PoH big chest room 4" }, + { 0x02, 0x02, AreaFlagInd{0x0202}, "small key big chest room 6 7F" }, + { 0x02, 0x01, AreaFlagInd{0x0201}, "big key chest" }, + { 0x03, 0x40, AreaFlagInd{0x0340}, "compass big chest room 4" }, + { 0x03, 0x20, AreaFlagInd{0x0320}, "PoH big chest south room 5F" }, + { 0x03, 0x10, AreaFlagInd{0x0310}, "small key big chest south room 5F" }, + { 0x03, 0x04, AreaFlagInd{0x0304}, "small chest room 2 2F" }, + { 0x03, 0x02, AreaFlagInd{0x0302}, "map big chest room 2 3F" }, + { 0x03, 0x01, AreaFlagInd{0x0301}, "dominion rod big chest" }, + { 0x04, 0x80, AreaFlagInd{0x0480}, "Ooccoo" }, + { 0x05, 0x01, AreaFlagInd{0x0501}, "small chest big key room" }, + { 0x06, 0x80, AreaFlagInd{0x0680}, "small chest room 5 7F" }, + { 0x06, 0x40, AreaFlagInd{0x0640}, "south small chest south room 5F" }, + { 0x06, 0x20, AreaFlagInd{0x0620}, "small chest room 2 3F" }, + { 0x06, 0x10, AreaFlagInd{0x0610}, "big chest room 5 6F" }, + { 0x06, 0x08, AreaFlagInd{0x0608}, "big chest room 6 8F" }, + { 0x06, 0x02, AreaFlagInd{0x0602}, "small key big chest room 1" }, + { 0x07, 0x02, AreaFlagInd{0x0702}, "map marker statue in room 1" }, + { 0x07, 0x01, AreaFlagInd{0x0701}, "map marker statue will spawn in room 1" }, + { 0x08, 0x80, AreaFlagInd{0x0880}, "Midna text asking to look at missing statue room 1" }, + { 0x08, 0x40, AreaFlagInd{0x0840}, "Midna text after looking at missing statue room 1" }, + { 0x08, 0x20, AreaFlagInd{0x0820}, "unlock door in room 6 8F" }, + { 0x08, 0x10, AreaFlagInd{0x0810}, "unlock door in room 3 5F (spawn baby and young gohmas in south room 5F)" }, + { 0x08, 0x08, AreaFlagInd{0x0808}, "unlock door in room 1" }, + { 0x08, 0x04, AreaFlagInd{0x0804}, "dominion rod big chest (set after)" }, + { 0x08, 0x02, AreaFlagInd{0x0802}, "killed poe in room 3 3F" }, + { 0x08, 0x01, AreaFlagInd{0x0801}, "killed poe in room 5 7F" }, + { 0x09, 0x20, AreaFlagInd{0x0920}, "intro cs" }, + { 0x09, 0x10, AreaFlagInd{0x0910}, "scale intro cs room 5 6F" }, + { 0x09, 0x08, AreaFlagInd{0x0908}, "change balance of scale for the first time cs" }, + { 0x09, 0x04, AreaFlagInd{0x0904}, "change balance of scale for the first time" }, + { 0x0A, 0x80, AreaFlagInd{0x0A80}, "entered room 7" }, + { 0x0A, 0x40, AreaFlagInd{0x0A40}, "spawn west big chest in south room 5F" }, + { 0x0A, 0x08, AreaFlagInd{0x0A08}, "statue getting possessed for the first time cs" }, + { 0x0B, 0x40, AreaFlagInd{0x0B40}, "deactivate statue slot in room 1 (opens door and deactivates statue)" }, + { 0x0B, 0x20, AreaFlagInd{0x0B20}, "deactivate bell in room 2 (required to spawn in room 1)" }, + { 0x0B, 0x10, AreaFlagInd{0x0B10}, "deactivate bell in room 3 (required to spawn in room 2)" }, + { 0x0B, 0x08, AreaFlagInd{0x0B08}, "deactivate bell in room 4 (required to spawn in room 3)" }, + { 0x0B, 0x04, AreaFlagInd{0x0B04}, "deactivate bell in room 5 (required to spawn in room 4)" }, + { 0x0B, 0x02, AreaFlagInd{0x0B02}, "deactivate bell in room 6 (required to spawn in room 5)" }, + { 0x0B, 0x01, AreaFlagInd{0x0B01}, "deactivate bell in room 7 (required to spawn in room 6)" }, + { 0x0C, 0x80, AreaFlagInd{0x0C80}, "unlock door in south room 5F" }, + { 0x0C, 0x40, AreaFlagInd{0x0C40}, "killed armos in room 2 3F (spawn big chest)" }, + { 0x0C, 0x20, AreaFlagInd{0x0C20}, "killed armos in big key room (unlocks door)" }, + { 0x0C, 0x10, AreaFlagInd{0x0C10}, "lit both torches in room 1 (unset if you leave) (spawn big chest)" }, + { 0x0C, 0x04, AreaFlagInd{0x0C04}, "broke gate in room 2 3F" }, + { 0x0C, 0x02, AreaFlagInd{0x0C02}, "broke fouth gate in room 2 2F" }, + { 0x0C, 0x01, AreaFlagInd{0x0C01}, "broke first gate in room 2 2F" }, + { 0x0D, 0x80, AreaFlagInd{0x0D80}, "broke third gate in room 2 2F" }, + { 0x0D, 0x40, AreaFlagInd{0x0D40}, "broke second gate in room 2 2F" }, + { 0x0D, 0x20, AreaFlagInd{0x0D20}, "broke second sliding door in room 4 4F" }, + { 0x0D, 0x10, AreaFlagInd{0x0D10}, "broke third sliding door in room 4 5F" }, + { 0x0D, 0x08, AreaFlagInd{0x0D08}, "broke second sliding door in room 4 5F" }, + { 0x0D, 0x04, AreaFlagInd{0x0D04}, "broke first sliding door in room 4 5F" }, + { 0x0D, 0x02, AreaFlagInd{0x0D02}, "broke first sliding door in room 4 4F" }, + { 0x0D, 0x01, AreaFlagInd{0x0D01}, "broke first beamos in room before boss" }, + { 0x0E, 0x80, AreaFlagInd{0x0E80}, "broke left beamos in room before boss" }, + { 0x0E, 0x40, AreaFlagInd{0x0E40}, "broke right beamos in room before boss" }, + { 0x0E, 0x20, AreaFlagInd{0x0E20}, "broke beamos in room 6 7F" }, + { 0x0E, 0x10, AreaFlagInd{0x0E10}, "broke first beamos in room 4 4F" }, + { 0x0E, 0x08, AreaFlagInd{0x0E08}, "broke second beamos in room 4 4F" }, + { 0x0E, 0x04, AreaFlagInd{0x0E04}, "broke beamos in room 3 3F" }, + { 0x0E, 0x01, AreaFlagInd{0x0E01}, "broke gate to bell in room 3 3F" }, + { 0x0F, 0x80, AreaFlagInd{0x0F80}, "broke gate to poe in room 3 3F" }, + { 0x0F, 0x40, AreaFlagInd{0x0F40}, "broke gate in room 6 8F" }, + { 0x0F, 0x20, AreaFlagInd{0x0F20}, "open door to poe in room 3 3F" }, + { 0x0F, 0x10, AreaFlagInd{0x0F10}, "spawn baby gohmas in beamos room 3 3F" }, + { 0x0F, 0x08, AreaFlagInd{0x0F08}, "broke gate in room 6 8F cs" }, + { 0x0F, 0x01, AreaFlagInd{0x0F01}, "unlock boss door" }, + { 0x10, 0x80, AreaFlagInd{0x1080}, "open big door in room 1 cs part 2" }, + { 0x10, 0x40, AreaFlagInd{0x1040}, "open big door in room 1 cs part 1" }, + { 0x10, 0x10, AreaFlagInd{0x1010}, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x08, AreaFlagInd{0x1008}, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x04, AreaFlagInd{0x1004}, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x02, AreaFlagInd{0x1002}, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x01, AreaFlagInd{0x1001}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x80, AreaFlagInd{0x1180}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x40, AreaFlagInd{0x1140}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x20, AreaFlagInd{0x1120}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x10, AreaFlagInd{0x1110}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x08, AreaFlagInd{0x1108}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x04, AreaFlagInd{0x1104}, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x02, AreaFlagInd{0x1102}, "killed a baby gohma in room 6 8F" }, + { 0x12, 0x80, AreaFlagInd{0x1280}, "pressed button in room 1 (or 6 8F) for the first time cs" }, + { 0x12, 0x40, AreaFlagInd{0x1240}, "pressed button in room 6 7F for the first time cs" }, + { 0x12, 0x20, AreaFlagInd{0x1220}, "killed both armos in room 6 8F (opens gate)" }, + { 0x12, 0x08, AreaFlagInd{0x1208}, "pressed buttons in room 3 5F for the first time cs" }, + { 0x12, 0x04, AreaFlagInd{0x1204}, "pressed buttons in room 2 3F for the first time cs" }, + { 0x12, 0x02, AreaFlagInd{0x1202}, "pressed button in room 2 2F for the first time cs" }, + { 0x13, 0x40, AreaFlagInd{0x1340}, "open gate to dominion rod in room 7" }, + { 0x13, 0x20, AreaFlagInd{0x1320}, "statue spawning out of bell in room 1 cs trigger" }, + { 0x13, 0x10, AreaFlagInd{0x1310}, "statue spawning out of bell in room 1 cs" }, + { 0x13, 0x08, AreaFlagInd{0x1308}, "killed all baby gohmas in room 6 8F (spawn big chest)" }, + { 0x13, 0x04, AreaFlagInd{0x1304}, "killed all enemies in room 5 6F (spawn big chest)" }, + { 0x13, 0x02, AreaFlagInd{0x1302}, "killed west armos in south room 5F" }, + { 0x13, 0x01, AreaFlagInd{0x1301}, "killed east armos in south room 5F" }, + { 0x14, 0x40, AreaFlagInd{0x1440}, "unlock door in room 7" }, + { 0x14, 0x20, AreaFlagInd{0x1420}, "statue getting in bell in room 7 cs first part" }, + { 0x14, 0x10, AreaFlagInd{0x1410}, "statue getting in bell in room 7 cs second part" }, + { 0x14, 0x08, AreaFlagInd{0x1408}, "statue getting in bell in room 7 cs trigger" }, + { 0x14, 0x04, AreaFlagInd{0x1404}, "open gate to dominion rod in room 7 cs" }, + { 0x14, 0x02, AreaFlagInd{0x1402}, "statue spawn out of bell in room 6" }, + { 0x14, 0x01, AreaFlagInd{0x1401}, "statue spawning out of bell in room 6 cs trigger" }, + { 0x15, 0x80, AreaFlagInd{0x1580}, "statue spawning out of bell in room 6 cs part 1" }, + { 0x15, 0x40, AreaFlagInd{0x1540}, "statue getting in bell in room 6 cs trigger" }, + { 0x15, 0x20, AreaFlagInd{0x1520}, "statue getting in bell in room 6 cs" }, + { 0x15, 0x10, AreaFlagInd{0x1510}, "statue spawning out of bell in room 5 cs trigger" }, + { 0x15, 0x08, AreaFlagInd{0x1508}, "statue spawning out of bell in room 5 cs" }, + { 0x15, 0x04, AreaFlagInd{0x1504}, "statue getting in bell in room 5 cs trigger" }, + { 0x15, 0x02, AreaFlagInd{0x1502}, "statue getting in bell in room 5 cs" }, + { 0x15, 0x01, AreaFlagInd{0x1501}, "statue spawning out of bell in room 4 cs trigger" }, + { 0x16, 0x80, AreaFlagInd{0x1680}, "statue spawning out of bell in room 4 cs" }, + { 0x16, 0x40, AreaFlagInd{0x1640}, "statue getting in bell in room 4 cs trigger" }, + { 0x16, 0x20, AreaFlagInd{0x1620}, "statue getting in bell in room 4 cs" }, + { 0x16, 0x10, AreaFlagInd{0x1610}, "statue spawning out of bell in room 3 cs trigger" }, + { 0x16, 0x08, AreaFlagInd{0x1608}, "statue spawning out of bell in room 3 cs" }, + { 0x16, 0x04, AreaFlagInd{0x1604}, "statue getting in bell in room 3 cs trigger" }, + { 0x16, 0x02, AreaFlagInd{0x1602}, "statue getting in bell in room 3 cs" }, + { 0x16, 0x01, AreaFlagInd{0x1601}, "statue spawning out of bell in room 2 cs trigger" }, + { 0x17, 0x80, AreaFlagInd{0x1780}, "statue spawning out of bell in room 2 cs" }, + { 0x17, 0x40, AreaFlagInd{0x1740}, "statue getting in bell in room 2 cs trigger" }, + { 0x17, 0x20, AreaFlagInd{0x1720}, "statue getting in bell in room 2 cs" }, + { 0x17, 0x10, AreaFlagInd{0x1710}, "deactivate spawning bell in room 7" }, + { 0x17, 0x08, AreaFlagInd{0x1708}, "big door in room 1 opens" }, + { 0x17, 0x04, AreaFlagInd{0x1704}, "open big door in room 1 cs part 2 trigger" }, + { 0x17, 0x02, AreaFlagInd{0x1702}, "open big door in room 1 cs part 1 trigger" }, + { 0x17, 0x01, AreaFlagInd{0x1701}, "statue placed in slot in room 1" }, }; struct MultiByteAreaFlag { // flags treated as bool, shift left after checking bool const char* name; - uint16_t highOrderflag; - uint16_t lowOrderflag; + AreaFlagMultibit flag; std::map enumValues; }; + constexpr uint16_t AREA_FLAG_NONE = 0; inline MultiByteAreaFlag ForestTempleMultiByteFlags[] = { { "Worm Room position", - 0x0D3C, AREA_FLAG_NONE, + AreaFlagMultibit{0x0D3C}, { { 0x0, "On Totem", }, { 0x8, "North", }, @@ -3178,7 +3305,7 @@ inline const std::map _SPRIceBlockPuzzleLocations = inline MultiByteAreaFlag SPRMultiByteFlags[] = { { "Courtyard First Floor Cannon", - 0x1160, AREA_FLAG_NONE, + AreaFlagMultibit{0x1160}, { { 1, "North" }, { 0, "South" }, @@ -3188,7 +3315,7 @@ inline MultiByteAreaFlag SPRMultiByteFlags[] = { }, { "Courtyard Second Floor Cannon", - 0x1001, 0x1180, + AreaFlagMultibit{0x1001, 0x1180}, { { 3, "North East" }, { 0, "South East" }, @@ -3198,7 +3325,7 @@ inline MultiByteAreaFlag SPRMultiByteFlags[] = { }, { "Freezard Cage Room Cannon", - 0x1203, AREA_FLAG_NONE, + AreaFlagMultibit{0x1203}, { { 0, "North" }, { 2, "East" }, @@ -3208,7 +3335,7 @@ inline MultiByteAreaFlag SPRMultiByteFlags[] = { }, { "North West Room Cannon", - 0x0C0C, AREA_FLAG_NONE, + AreaFlagMultibit{0x0C0C}, { { 3, "North" }, { 0, "East" }, @@ -3218,17 +3345,17 @@ inline MultiByteAreaFlag SPRMultiByteFlags[] = { }, { "Ice Block 1 Location", - 0x0F1F, AREA_FLAG_NONE, + AreaFlagMultibit{0x0F1F}, _SPRIceBlockPuzzleLocations }, { "Ice Block 2 Location", - 0x08F8, AREA_FLAG_NONE, + AreaFlagMultibit{0x08F8}, _SPRIceBlockPuzzleLocations }, { "Ice Block 3 Location", - 0x0807, 0x09C0, + AreaFlagMultibit{0x0807, 0x09C0}, _SPRIceBlockPuzzleLocations } }; @@ -3314,47 +3441,47 @@ inline const std::map _CoOBlockPuzzle3Locations = { inline MultiByteAreaFlag CoOMultiByteFlags[] = { { "Puzzle 1 Block 1 Location", - 0x0907, 0x0A80, + AreaFlagMultibit{0x0907, 0x0A80}, _CoOBlockPuzzle1Locations }, { "Puzzle 1 Block 2 Location", - 0x0A3C, AREA_FLAG_NONE, + AreaFlagMultibit{0x0A3C}, _CoOBlockPuzzle1Locations }, { "Puzzle 1 Block 3 Location", - 0x0B0F, AREA_FLAG_NONE, + AreaFlagMultibit{0x0B0F}, _CoOBlockPuzzle1Locations }, { "Puzzle 2 Block 1 Location", - 0x08F0, AREA_FLAG_NONE, + AreaFlagMultibit{0x08F0}, _CoOBlockPuzzle2Locations }, { "Puzzle 2 Block 2 Location", - 0x080F, AREA_FLAG_NONE, + AreaFlagMultibit{0x080F}, _CoOBlockPuzzle2Locations }, { "Puzzle 2 Block 3 Location", - 0x09F0, AREA_FLAG_NONE, + AreaFlagMultibit{0x09F0}, _CoOBlockPuzzle2Locations }, { "Puzzle 3 Block 1 Location", - 0x0E7C, AREA_FLAG_NONE, + AreaFlagMultibit{0x0E7C}, _CoOBlockPuzzle3Locations }, { "Puzzle 3 Block 2 Location", - 0x0E03, 0x0FE0, + AreaFlagMultibit{0x0E03, 0x0FE0}, _CoOBlockPuzzle3Locations }, { "Puzzle 3 Block 3 Location", - 0x0F1F, AREA_FLAG_NONE, + AreaFlagMultibit{0x0F1F}, _CoOBlockPuzzle3Locations } }; @@ -3393,4 +3520,4 @@ inline std::map imguiAreaFlagLookup = { 0x1B, AreaFlagIter{ eventAreaFlagsGrotto, {} } }, }; -#endif // !DUSK_IMGUI_EVENTFLAGS_HPP \ No newline at end of file +#endif // !DUSK_IMGUI_EVENTFLAGS_HPP diff --git a/src/dusk/imgui/ImGuiHeapOverlay.cpp b/src/dusk/imgui/ImGuiHeapOverlay.cpp index a63ce4cfbe..33209ab0d4 100644 --- a/src/dusk/imgui/ImGuiHeapOverlay.cpp +++ b/src/dusk/imgui/ImGuiHeapOverlay.cpp @@ -22,7 +22,9 @@ namespace dusk { void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open); void ImGuiMenuTools::ShowHeapOverlay() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay)) + { return; } diff --git a/src/dusk/imgui/ImGuiMapLoader.cpp b/src/dusk/imgui/ImGuiMapLoader.cpp index 63f4befb44..cd6f292152 100644 --- a/src/dusk/imgui/ImGuiMapLoader.cpp +++ b/src/dusk/imgui/ImGuiMapLoader.cpp @@ -9,7 +9,9 @@ namespace dusk { void ImGuiMenuTools::ShowMapLoader() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader)) + { return; } diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 616e0ddbac..79c032ee35 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -1,573 +1,16 @@ #include "fmt/format.h" #include "imgui.h" -#include "ImGuiEngine.hpp" #include "ImGuiConsole.hpp" #include "ImGuiConfig.hpp" #include "dusk/main.h" -#include "dusk/hotkeys.h" #include "m_Do/m_Do_main.h" -#include - namespace dusk { - void ImGuiMenuGame::ToggleFullscreen() { - getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); - VISetWindowFullscreen(getSettings().video.enableFullscreen); - config::Save(); - } - ImGuiMenuGame::ImGuiMenuGame() {} - void ImGuiMenuGame::draw() { - if (ImGui::BeginMenu("Settings")) { - // TODO: Remove this once Controller Config exists in RmlUi - if (ImGui::Button("Configure Controller")){ - m_showControllerConfig = !m_showControllerConfig; - } - - ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); - - ImGui::EndMenu(); - } - } - - static void drawVirtualStick(const char* id, const ImVec2& stick) { - float scale = ImGuiScale(); - ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10)); - - ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale), 0, ImGuiWindowFlags_NoBackground); - ImDrawList* dl = ImGui::GetWindowDrawList(); - ImVec2 p = ImGui::GetCursorScreenPos(); - - float radius = 30.0f * scale; - ImVec2 pos = ImVec2(p.x + radius, p.y + radius); - - constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255); - constexpr ImU32 white = IM_COL32(255, 255, 255, 255); - constexpr ImU32 red = IM_COL32(230, 0, 0, 255); - - dl->AddCircleFilled(pos, radius, stickGray, 8); - dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red); - ImGui::EndChild(); - } - - struct SpecificButtonName { - SDL_GamepadType Type; - const char* Name; - }; - - struct ButtonNames { - SDL_GamepadButton Button; - std::vector Names; - }; - -// clang-format off - static const std::vector GamepadButtonNames = { - { SDL_GAMEPAD_BUTTON_LEFT_STICK, { - {SDL_GAMEPAD_TYPE_PS3, "L3"}, - {SDL_GAMEPAD_TYPE_PS4, "L3"}, - {SDL_GAMEPAD_TYPE_PS5, "L3"}, - {SDL_GAMEPAD_TYPE_XBOX360, "Left Stick"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "Left Stick"}, - {SDL_GAMEPAD_TYPE_GAMECUBE, "Control Stick"}, - }}, - { SDL_GAMEPAD_BUTTON_RIGHT_STICK, { - {SDL_GAMEPAD_TYPE_PS3, "R3"}, - {SDL_GAMEPAD_TYPE_PS4, "R3"}, - {SDL_GAMEPAD_TYPE_PS5, "R3"}, - {SDL_GAMEPAD_TYPE_XBOX360, "Right Stick"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "Right Stick"}, - {SDL_GAMEPAD_TYPE_GAMECUBE, "C Stick"}, - }}, - { SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, { - {SDL_GAMEPAD_TYPE_PS3, "L1"}, - {SDL_GAMEPAD_TYPE_PS4, "L1"}, - {SDL_GAMEPAD_TYPE_PS5, "L1"}, - {SDL_GAMEPAD_TYPE_XBOX360, "LB"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "LB"}, - }}, - { SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, { - {SDL_GAMEPAD_TYPE_PS3, "R1"}, - {SDL_GAMEPAD_TYPE_PS4, "R1"}, - {SDL_GAMEPAD_TYPE_PS5, "R1"}, - {SDL_GAMEPAD_TYPE_XBOX360, "RB"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "RB"}, - {SDL_GAMEPAD_TYPE_GAMECUBE, "Z"}, - }}, - { SDL_GAMEPAD_BUTTON_BACK, { - {SDL_GAMEPAD_TYPE_PS3, "Select"}, - {SDL_GAMEPAD_TYPE_PS4, "Share"}, - {SDL_GAMEPAD_TYPE_PS5, "Create"}, - {SDL_GAMEPAD_TYPE_XBOX360, "Back"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "View"}, - }}, - { SDL_GAMEPAD_BUTTON_START, { - {SDL_GAMEPAD_TYPE_PS3, "Start"}, - {SDL_GAMEPAD_TYPE_PS4, "Options"}, - {SDL_GAMEPAD_TYPE_PS5, "Options"}, - {SDL_GAMEPAD_TYPE_XBOX360, "Start"}, - {SDL_GAMEPAD_TYPE_XBOXONE, "Menu"}, - {SDL_GAMEPAD_TYPE_GAMECUBE, "Start/Pause"}, - }}, - }; -// clang-format on - - static const char* GetNameForGamepadButton(SDL_Gamepad* gamepad, u32 buttonUntyped) { - if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) { - return "Not bound"; - } - - auto button = static_cast(buttonUntyped); - auto label = SDL_GetGamepadButtonLabel(gamepad, button); - - switch (label) { - case SDL_GAMEPAD_BUTTON_LABEL_A: - return "A"; - case SDL_GAMEPAD_BUTTON_LABEL_B: - return "B"; - case SDL_GAMEPAD_BUTTON_LABEL_X: - return "X"; - case SDL_GAMEPAD_BUTTON_LABEL_Y: - return "Y"; - case SDL_GAMEPAD_BUTTON_LABEL_CROSS: - return "Cross"; - case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: - return "Circle"; - case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: - return "Triangle"; - case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: - return "Square"; - default:; // Fall through - } - - auto padType = SDL_GetGamepadType(gamepad); - for (const auto& buttonNames : GamepadButtonNames) { - if (buttonNames.Button != button) { - continue; - } - - for (const auto& name : buttonNames.Names) { - if (name.Type == padType) { - return name.Name; - } - } - } - - switch (button) { - case SDL_GAMEPAD_BUTTON_DPAD_LEFT: - return "D-pad left"; - case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: - return "D-pad right"; - case SDL_GAMEPAD_BUTTON_DPAD_UP: - return "D-pad up"; - case SDL_GAMEPAD_BUTTON_DPAD_DOWN: - return "D-pad down"; - default: - return PADGetNativeButtonName(buttonUntyped); - } - } - - void ImGuiMenuGame::windowControllerConfig() { - if (!m_showControllerConfig) { - return; - } - - // if pending for a button mapping, check to set new input - if (m_controllerConfig.m_pendingButtonMapping != nullptr) { - s32 nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort); - if (nativeButton != -1) { - m_controllerConfig.m_pendingButtonMapping->nativeButton = nativeButton; - m_controllerConfig.m_pendingButtonMapping = nullptr; - m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); - PADSerializeMappings(); - } - } - - // if pending for an axis mapping, check to set new input - if (m_controllerConfig.m_pendingAxisMapping != nullptr) { - auto nativeAxis = PADGetNativeAxisPulled(m_controllerConfig.m_pendingPort); - if (nativeAxis.nativeAxis != -1) { - m_controllerConfig.m_pendingAxisMapping->nativeAxis = nativeAxis; - m_controllerConfig.m_pendingAxisMapping->nativeButton = -1; - m_controllerConfig.m_pendingAxisMapping = nullptr; - m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); - PADSerializeMappings(); - } else { - auto nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort); - if (nativeButton != -1) { - m_controllerConfig.m_pendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; - m_controllerConfig.m_pendingAxisMapping->nativeButton = nativeButton; - m_controllerConfig.m_pendingAxisMapping = nullptr; - m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); - PADSerializeMappings(); - } - } - } - - float scale = ImGuiScale(); - ImGuiWindowFlags windowFlags = - ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_AlwaysAutoResize; - - // ImGui::SetNextWindowBgAlpha(0.65f); - - if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) { - ImGui::End(); - return; - } - - // port tabs - ImGui::BeginTabBar("##ControllerTabs"); - for (int i = PAD_1; i <= PAD_4; i++) { - if (ImGui::BeginTabItem(fmt::format("Port {}", i + 1).c_str())) { - m_controllerConfig.m_selectedPort = i; - ImGui::EndTabItem(); - } - } - ImGui::EndTabBar(); - - // if tab is changed while waiting for input, cancel pending - if ((m_controllerConfig.m_pendingButtonMapping != nullptr || - m_controllerConfig.m_pendingAxisMapping != nullptr) && - m_controllerConfig.m_pendingPort != m_controllerConfig.m_selectedPort) - { - m_controllerConfig.m_pendingButtonMapping = nullptr; - m_controllerConfig.m_pendingAxisMapping = nullptr; - m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); - } - - // get a list of all available controller's names - std::vector controllerList; - controllerList.push_back("None"); - for (int i = 0; i < PADCount(); i++) { - // attach index to name for unique name - controllerList.push_back(fmt::format("{}-{}", PADGetNameForControllerIndex(i), i)); - } - - // get current controller name - const char* tmpName = PADGetName(m_controllerConfig.m_selectedPort); - std::string currentName = "None"; - if (tmpName != nullptr) { - currentName = fmt::format("{}-{}", tmpName, PADGetIndexForPort(m_controllerConfig.m_selectedPort)); - } - - // controller selection combo box - bool changedController = false; - int changedControllerIndex = 0; - ImGui::SetNextItemWidth(400.0f * scale); - if (ImGui::BeginCombo("##ControllerDeviceList", currentName.c_str())) { - for (int i = 0; const auto& name : controllerList) { - if (ImGui::Selectable(name.c_str(), currentName == name)) { - changedControllerIndex = i; - changedController = true; - } - i++; - } - ImGui::EndCombo(); - } - - // handle controller change - if (changedController) { - if (changedControllerIndex > 0) { - PADSetPortForIndex(changedControllerIndex - 1, m_controllerConfig.m_selectedPort); - } - else if (changedControllerIndex == 0) { - // if "None" selected - PADClearPort(m_controllerConfig.m_selectedPort); - } - PADSerializeMappings(); - } - - // restore defaults button - ImGui::SameLine(); - if (ImGui::Button("Default")) { - PADRestoreDefaultMapping(m_controllerConfig.m_selectedPort); - PADSerializeMappings(); - } - - // buttons panel - const float uiButtonSize = 40 * scale; - ImVec2 btnSize(110.0f * scale, 30.0f * scale); - - ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale)); - - SDL_Gamepad* gamepad = PADGetSDLGamepadForIndex(PADGetIndexForPort(m_controllerConfig.m_selectedPort)); - u32 buttonCount; - PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount); - if (btnMappingList != nullptr) { - for (int i = 0; i < buttonCount; i++) { - const char* btnName = PADGetButtonName(btnMappingList[i].padButton); - ImVec2 len = ImGui::CalcTextSize(btnName); - ImVec2 pos = ImGui::GetCursorPos(); - - ImGui::SetCursorPosY(pos.y + len.y / 4); - ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize)); - ImGui::Text("%s", btnName); - ImGui::SameLine(); - - ImGui::SetCursorPosY(pos.y); - - std::string dispName; - if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingButtonMapping == &btnMappingList[i]) { - dispName = fmt::format("Press a Key...##{}", btnName); - } else { - const char* nativeName = GetNameForGamepadButton(gamepad, btnMappingList[i].nativeButton); - if (nativeName == nullptr) { - nativeName = "[unbound]"; - } - dispName = fmt::format("{0}##-{1}", nativeName, i); - } - bool pressed = ImGui::Button(dispName.c_str(), - btnSize); - - if (pressed) { - m_controllerConfig.m_isReading = true; - m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; - m_controllerConfig.m_pendingButtonMapping = &btnMappingList[i]; - PADBlockInput(true); - } - } - } - - ImGuiEndGroupPanel(); - ImGui::SameLine(); - - uint32_t axisCount; - PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount); - - ImGuiBeginGroupPanel("Analog Triggers", ImVec2(150 * scale, 20 * scale)); - - PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R}; - if (axisMappingList != nullptr) { - for (PADAxis trigger : triggers) { - const char* axisName = PADGetAxisName(axisMappingList[trigger].padAxis); - ImVec2 len = ImGui::CalcTextSize(axisName); - ImVec2 pos = ImGui::GetCursorPos(); - - ImGui::SetCursorPosY(pos.y + len.y / 4); - ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize)); - ImGui::Text("%s", axisName); - ImGui::SameLine(); - - ImGui::SetCursorPosY(pos.y); - - std::string dispName; - if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[trigger]) { - dispName = fmt::format("Press a Key...##{}", axisName); - } else { - dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger); - } - bool pressed = ImGui::Button(dispName.c_str(), - btnSize); - - if (pressed) { - m_controllerConfig.m_isReading = true; - m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; - m_controllerConfig.m_pendingAxisMapping = &axisMappingList[trigger]; - PADBlockInput(true); - } - } - } - - int port = m_controllerConfig.m_selectedPort; - PADDeadZones* deadZones = PADGetDeadZones(port); - - if (deadZones != nullptr) { - ImGui::Text("L Threshold"); - ImGui::SameLine(); - { - float tmp = static_cast(deadZones->leftTriggerActivationZone * 100.f) / 32767.f; - if (ImGui::DragFloat("##LThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) { - deadZones->leftTriggerActivationZone = static_cast((tmp / 100.f) * 32767); - PADSerializeMappings(); - } - } - } - - if (deadZones != nullptr) { - ImGui::Text("R Threshold"); - ImGui::SameLine(); - { - float tmp = static_cast(deadZones->rightTriggerActivationZone * 100.f) / 32767.f; - if (ImGui::DragFloat("##RThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) { - deadZones->rightTriggerActivationZone = static_cast((tmp / 100.f) * 32767); - PADSerializeMappings(); - } - } - } - - ImGuiEndGroupPanel(); - ImGui::SameLine(); - - // main stick panel - ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale)); - - drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) }); - - if (axisMappingList != nullptr) { - const PADAxis lStickAxes[] = {PAD_AXIS_LEFT_Y_POS, PAD_AXIS_LEFT_Y_NEG, PAD_AXIS_LEFT_X_NEG, PAD_AXIS_LEFT_X_POS}; - for (auto axis : lStickAxes) { - const char* label = PADGetAxisDirectionLabel(axis); - ImVec2 len = ImGui::CalcTextSize(label); - ImVec2 pos = ImGui::GetCursorPos(); - - ImGui::SetCursorPosY(pos.y + len.y / 4); - ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize)); - ImGui::Text("%s", label); - ImGui::SameLine(); - - ImGui::SetCursorPosY(pos.y); - - std::string dispName; - if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) { - dispName = fmt::format("Press a Key...##{}", label); - } else { - if (axisMappingList[axis].nativeAxis.nativeAxis != -1) { - const char* signStr; - if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) { - signStr = ""; - } else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) { - signStr = "+"; - } else { - signStr = "-"; - } - dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis); - } else { - assert(axisMappingList[axis].nativeButton != -1); - dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis); - } - } - bool pressed = ImGui::Button(dispName.c_str(), btnSize); - - if (pressed) { - m_controllerConfig.m_isReading = true; - m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; - m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis]; - PADBlockInput(true); - } - } - } - - if (deadZones != nullptr) { - ImGui::Text("Dead Zone"); - { - float tmp = static_cast(deadZones->stickDeadZone * 100.f) / 32767.f; - if (ImGui::DragFloat("##mainDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) { - deadZones->stickDeadZone = static_cast((tmp / 100.f) * 32767); - PADSerializeMappings(); - } - } - } - - ImGuiEndGroupPanel(); - ImGui::SameLine(); - - // sub stick panel - ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale)); - - drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) }); - - if (axisMappingList != nullptr) { - const PADAxis rStickAxes[] = {PAD_AXIS_RIGHT_Y_POS, PAD_AXIS_RIGHT_Y_NEG, PAD_AXIS_RIGHT_X_NEG, PAD_AXIS_RIGHT_X_POS}; - for (auto axis : rStickAxes) { - const char* label = PADGetAxisDirectionLabel(axisMappingList[axis].padAxis); - ImVec2 len = ImGui::CalcTextSize(label); - ImVec2 pos = ImGui::GetCursorPos(); - - ImGui::SetCursorPosY(pos.y + len.y / 4); - ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize)); - ImGui::Text("%s", label); - ImGui::SameLine(); - - ImGui::SetCursorPosY(pos.y); - - std::string dispName; - if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) { - dispName = fmt::format("Press a Key...##sub{}", label); - } else { - if (axisMappingList[axis].nativeAxis.nativeAxis != -1) { - const char* signStr; - if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) { - signStr = ""; - } else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) { - signStr = "+"; - } else { - signStr = "-"; - } - dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis); - } else { - assert(axisMappingList[axis].nativeButton != -1); - dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis); - } - } - bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), btnSize); - - if (pressed) { - m_controllerConfig.m_isReading = true; - m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; - m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis]; - PADBlockInput(true); - } - } - } - - if (deadZones != nullptr) { - ImGui::Text("Dead Zone"); - { - float tmp = static_cast(deadZones->substickDeadZone * 100.f) / 32767.f; - if (ImGui::DragFloat("##subDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) { - deadZones->substickDeadZone = static_cast((tmp / 100.f) * 32767); - PADSerializeMappings(); - } - } - } - - ImGuiEndGroupPanel(); - ImGui::SameLine(); - - // Options panel - ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1)); - - if (deadZones != nullptr) { - if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) { - PADSerializeMappings(); - } - if (ImGui::Checkbox("Emulate Triggers", &deadZones->emulateTriggers)) { - PADSerializeMappings(); - } - } - - if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) { - ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1)); - u16 low; - u16 high; - (void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high); - float fLow = (static_cast(low) / 32767.f) * 100.f; - bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%"); - float fHigh = (static_cast(high) / 32767.f) * 100.f; - changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%"); - if (changed) { - PADSetRumbleIntensity(m_controllerConfig.m_selectedPort, - static_cast((fLow / 100) * 32767), - static_cast((fHigh / 100) * 32767)); - PADSerializeMappings(); - } - if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) { - PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD); - m_controllerConfig.m_isRumbling ^= 1; - } - ImGuiEndGroupPanel(); - } - ImGuiEndGroupPanel(); - - ImGui::End(); - } + void ImGuiMenuGame::draw() {} static std::string GetFormattedTime(OSTime ticks) { OSCalendarTime time; @@ -602,6 +45,7 @@ namespace dusk { getSettings().game.enableTurboKeybind.setValue(false); getSettings().game.debugFlyCam.setValue(false); + getSettings().game.autoSave.setValue(false); } SpeedrunInfo m_speedrunInfo; diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index b5ecfa37c0..225a505438 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -46,31 +46,11 @@ namespace dusk { ImGuiMenuGame(); void draw(); - void windowInputViewer(); - void windowControllerConfig(); void drawSpeedrunTimerOverlay(); - static void ToggleFullscreen(); - static void resetForSpeedrunMode(); private: - struct { - int m_selectedPort = 0; - bool m_isReading = false; - PADButtonMapping* m_pendingButtonMapping = nullptr; - PADAxisMapping* m_pendingAxisMapping = nullptr; - int m_pendingPort = -1; - bool m_isRumbling = false; - } m_controllerConfig; - - bool m_showControllerConfig = false; - - bool m_showInputViewer = false; - bool m_showInputViewerGyro = false; - int m_inputOverlayCorner = 3; - std::string m_controllerName; - bool m_showTimerWindow = false; }; } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 714add87c4..306298c28d 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -23,24 +23,6 @@ #include #endif -#if defined(_WIN32) || (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || (defined(__linux__) && !defined(__ANDROID__)) -#define DUSK_CAN_OPEN_DATA_FOLDER 1 - -namespace fs = std::filesystem; - -static void OpenDataFolder() { - const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); -#if defined(_WIN32) - const std::string url = std::string("file:///") + path; -#else - const std::string url = std::string("file://") + path; -#endif - (void)SDL_OpenURL(url.c_str()); -} -#else -#define DUSK_CAN_OPEN_DATA_FOLDER 0 -#endif - namespace aurora::gx { extern bool enableLodBias; } @@ -66,6 +48,8 @@ namespace dusk { ImGui::EndDisabled(); } + ImGui::Separator(); + ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); #if DUSK_CAN_OPEN_DATA_FOLDER ImGui::Separator(); @@ -137,7 +121,9 @@ namespace dusk { } void ImGuiMenuTools::ShowDebugOverlay() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay)) + { return; } @@ -201,7 +187,9 @@ namespace dusk { } void ImGuiMenuTools::ShowPlayerInfo() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo)) + { return; } @@ -267,66 +255,4 @@ namespace dusk { ImGui::End(); ImGui::PopFont(); } - - void ImGuiMenuTools::notifyAchievement(std::string name) { - if (m_notifyTimer <= 0.f) { - m_notifyName = std::move(name); - m_notifyTimer = NOTIFY_DURATION; - } else { - m_notifyQueue.push(std::move(name)); - } - } - - void ImGuiMenuTools::showAchievementNotification() { - if (!getSettings().game.enableAchievementNotifications.getValue()) { - return; - } - if (m_notifyTimer <= 0.f) { - if (m_notifyQueue.empty()) { - return; - } - m_notifyName = std::move(m_notifyQueue.front()); - m_notifyQueue.pop(); - m_notifyTimer = NOTIFY_DURATION; - } - - m_notifyTimer -= ImGui::GetIO().DeltaTime; - - const float alpha = std::min({ - m_notifyTimer / NOTIFY_FADE_TIME, - (NOTIFY_DURATION - m_notifyTimer) / NOTIFY_FADE_TIME, - 1.0f - }); - - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - const float padding = 12.0f; - ImGui::SetNextWindowPos( - ImVec2(viewport->WorkPos.x + viewport->WorkSize.x - padding, viewport->WorkPos.y + padding), - ImGuiCond_Always, ImVec2(1.0f, 0.0f) - ); - - ImGui::SetNextWindowBgAlpha(alpha * 0.92f); - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.06f, 0.01f, alpha * 0.92f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 0.8f, 0.1f, alpha)); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, alpha)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 2.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(14.0f, 10.0f)); - - constexpr ImGuiWindowFlags flags = - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | - ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | - ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs; - - if (ImGui::Begin("##achievement_notify", nullptr, flags)) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.82f, 0.1f, alpha)); - ImGui::TextUnformatted("Achievement Unlocked!"); - ImGui::PopStyleColor(); - ImGui::Spacing(); - ImGui::TextUnformatted(m_notifyName.c_str()); - } - ImGui::End(); - - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(3); - } } diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index 7ae0e5bec6..6b925b7bf3 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -27,8 +27,7 @@ namespace dusk { void ShowAudioDebug(); void ShowSaveEditor(); void ShowStateShare(); - void notifyAchievement(std::string name); - void showAchievementNotification(); + void ShowInputViewer(); private: bool m_showDebugOverlay = false; @@ -69,11 +68,10 @@ namespace dusk { bool m_showStateShare = false; ImGuiStateShare m_stateShare; - std::string m_notifyName; - float m_notifyTimer = 0.f; - std::queue m_notifyQueue; - static constexpr float NOTIFY_DURATION = 4.0f; - static constexpr float NOTIFY_FADE_TIME = 0.5f; + bool m_showInputViewer = false; + bool m_showInputViewerGyro = false; + int m_inputOverlayCorner = 3; + std::string m_controllerName; }; } diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp deleted file mode 100644 index a0006f0ad3..0000000000 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include "imgui.h" - -#include "ImGuiConfig.hpp" -#include "ImGuiEngine.hpp" -#include "ImGuiPreLaunchWindow.hpp" - -#include "../file_select.hpp" -#include "../iso_validate.hpp" -#include "ImGuiConsole.hpp" -#include "dusk/main.h" -#include "dusk/settings.h" - -#include -#include - -#include "aurora/lib/internal.hpp" -#include "aurora/lib/window.hpp" - -namespace dusk { - -typedef void (ImGuiPreLaunchWindow::*drawFunc)(); - -drawFunc drawTable[2] = {&ImGuiPreLaunchWindow::drawMainMenu, &ImGuiPreLaunchWindow::drawOptions}; - -static constexpr std::array skLanguageNames = { - "English", "German", "French", "Spanish", "Italian" -}; - -static constexpr std::array skGameDiscFileFilters{{ - {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, - {"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; - } -} - -static std::string_view card_type_name(CARDFileType type) { - switch (type) { - case CARD_GCIFOLDER: - return "GCI Folder"sv; - case CARD_RAWIMAGE: - return "Card Image"sv; - default: - return ""sv; - } -} - -void fileDialogCallback(void* userdata, const char* path, const char* error) { - auto* self = static_cast(userdata); - if (error != nullptr) { - self->m_selectedIsoPath.clear(); - self->m_errorString = fmt::format("File dialog error: {}", error); - return; - } - - if (path == nullptr) { - self->m_selectedIsoPath.clear(); - return; - } - - self->m_selectedIsoPath = path; - self->m_isPal = iso::isPal(path); - getSettings().backend.isoPath.setValue(self->m_selectedIsoPath); - config::Save(); -} - -ImGuiPreLaunchWindow::ImGuiPreLaunchWindow() = default; - -bool ImGuiPreLaunchWindow::isSelectedPathValid() const { -#if TARGET_ANDROID - return !m_selectedIsoPath.empty(); // unsure why SDL_GetPathInfo doesnt work here -#else - return !m_selectedIsoPath.empty() && SDL_GetPathInfo(m_selectedIsoPath.c_str(), nullptr); -#endif -} - -void ImGuiPreLaunchWindow::draw() { - if (m_IsFirstDraw) { - m_selectedIsoPath = getSettings().backend.isoPath; - m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str()); - m_initialGraphicsBackend = getSettings().backend.graphicsBackend; - m_IsFirstDraw = false; - } - - if (isSelectedPathValid() && getSettings().backend.skipPreLaunchUI) { - dusk::IsGameLaunched = true; - return; - } - - auto& io = ImGui::GetIO(); - - ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y)); - ImGui::SetNextWindowPos(ImVec2(0, 0)); - ImGui::SetNextWindowBgAlpha(0.65f); - - ImGui::Begin("Pre Launch Window", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | - ImGuiWindowFlags_NoBringToFrontOnFocus); - - const auto& windowSize = ImGui::GetWindowSize(); - - for (int i = 0; i < 5; i++) - ImGui::NewLine(); - - float iconSize = 150.f; - ImGui::SameLine(windowSize.x / 2 - iconSize + (iconSize / 2)); - if (ImGuiEngine::orgIcon != 0) { - ImGui::Image(ImGuiEngine::orgIcon, ImVec2{iconSize, iconSize}); - } - ImGuiTextCenter("Twilit Realm presents"); - if (ImGuiEngine::duskLogo) { - ImGui::NewLine(); - float width = iconSize * 2.5f; - ImGui::SameLine(windowSize.x / 2 - width + (width / 2)); - ImGui::Image(ImGuiEngine::duskLogo, ImVec2{width, iconSize}); - } else { - ImGui::PushFont(ImGuiEngine::fontExtraLarge); - ImGuiTextCenter("Dusk"); - ImGui::PopFont(); - } - - (this->*drawTable[m_CurMenu])(); - - ImGui::End(); -} - -void ImGuiPreLaunchWindow::drawMainMenu() { - const auto& windowSize = ImGui::GetWindowSize(); - ImGui::SetCursorPosY(windowSize.y - 200); - - ImGui::PushFont(ImGuiEngine::fontLarge); - - if (!isSelectedPathValid()) { - if (!m_errorString.empty()) { - ImGuiTextCenter(m_errorString); - } - - if (ImGuiButtonCenter("Select disc image...")) { - ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(), - skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr, - false); - } - } else { - if (ImGuiButtonCenter("Start game")) { - dusk::IsGameLaunched = true; - } - } - - if (ImGuiButtonCenter("Options")) { - m_CurMenu = 1; - } - - ImGui::PopFont(); -} - -void ImGuiPreLaunchWindow::drawOptions() { - const auto& windowSize = ImGui::GetWindowSize(); - - ImGui::NewLine(); - - ImGui::PushFont(ImGuiEngine::fontLarge); - ImGuiTextCenter("Options"); - ImGui::Separator(); - ImGui::PopFont(); - - auto cursorY = ImGui::GetCursorPosY(); - float endCursorY = windowSize.y - 100; - - float childWidth = windowSize.x - 400; - - ImGui::SetCursorPosX(windowSize.x / 2 - (childWidth / 2)); - 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(m_selectedIsoPath == "" ? "Set" : "Change")) { - ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(), - skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr, - false); - } - - if (m_isPal) { - auto selectedLanguage = getSettings().game.language.getValue(); - if (ImGui::BeginCombo("Language", skLanguageNames[static_cast(selectedLanguage)])) { - for (u8 i = 0; i < skLanguageNames.size(); ++i) { - if (ImGui::Selectable(skLanguageNames[i])) { - getSettings().game.language.setValue(static_cast(i)); - config::Save(); - } - } - - ImGui::EndCombo(); - } - } - - AuroraBackend configuredBackend = BACKEND_AUTO; - const std::string& configuredBackendId = getSettings().backend.graphicsBackend; - if (!try_parse_backend(configuredBackendId, configuredBackend)) { - configuredBackend = BACKEND_AUTO; - } - - if (ImGui::BeginCombo("Graphics Backend", backend_name(configuredBackend).data())) { - if (ImGui::Selectable("Auto", configuredBackend == BACKEND_AUTO)) { - getSettings().backend.graphicsBackend.setValue("auto"); - config::Save(); - } - - size_t backendCount = 0; - const AuroraBackend* availableBackends = aurora_get_available_backends(&backendCount); - for (size_t i = 0; i < backendCount; ++i) { - const AuroraBackend backend = availableBackends[i]; - const bool isSelected = configuredBackend == backend; - if (ImGui::Selectable(backend_name(backend).data(), isSelected)) { - getSettings().backend.graphicsBackend.setValue( - std::string(backend_id(backend))); - config::Save(); - } - if (isSelected) { - ImGui::SetItemDefaultFocus(); - } - } - - ImGui::EndCombo(); - } - if (configuredBackendId != m_initialGraphicsBackend) { - ImGui::TextDisabled("Restart Required"); - } - auto curFileType = (CARDFileType)getSettings().backend.cardFileType.getValue(); - - if (ImGui::BeginCombo("Save File Type", card_type_name(curFileType).data())) { - - if (ImGui::Selectable("GCI Folder", curFileType == CARD_GCIFOLDER)) { - getSettings().backend.cardFileType.setValue(CARD_GCIFOLDER); - config::Save(); - } - - if (ImGui::Selectable("Card Image", curFileType == CARD_RAWIMAGE)) { - getSettings().backend.cardFileType.setValue(CARD_RAWIMAGE); - config::Save(); - } - - ImGui::EndCombo(); - } - - ImGui::EndChild(); - } - - ImGui::SetCursorPosY(endCursorY); - ImGui::NewLine(); - - ImGui::Separator(); - - ImGui::PushFont(ImGuiEngine::fontLarge); - if (ImGuiButtonCenter("Back")) { - m_CurMenu = 0; - } - ImGui::PopFont(); -} - -} // namespace dusk diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.hpp b/src/dusk/imgui/ImGuiPreLaunchWindow.hpp deleted file mode 100644 index 6cb078a228..0000000000 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -namespace dusk { -class ImGuiPreLaunchWindow { -private: - int m_CurMenu = 0; - bool m_IsFirstDraw = true; - std::string m_initialGraphicsBackend; - - bool isSelectedPathValid() const; - -public: - ImGuiPreLaunchWindow(); - void draw(); - - void drawMainMenu(); - void drawOptions(); - - std::string m_selectedIsoPath; - std::string m_errorString; - bool m_isPal = false; -}; -} // namespace dusk diff --git a/src/dusk/imgui/ImGuiProcessOverlay.cpp b/src/dusk/imgui/ImGuiProcessOverlay.cpp index ed71e6c485..806a9ea0f6 100644 --- a/src/dusk/imgui/ImGuiProcessOverlay.cpp +++ b/src/dusk/imgui/ImGuiProcessOverlay.cpp @@ -126,7 +126,9 @@ namespace dusk { } void ImGuiMenuTools::ShowProcessManager() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement)) + { return; } diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index c31d4e6899..641bcffe7a 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -13,7 +13,6 @@ #include "d/actor/d_a_player.h" #include -#include namespace dusk { enum ItemType { @@ -1355,38 +1354,30 @@ namespace dusk { // genCommonAreaFlags(membit); } - template - concept FlagIter = requires(T t) { - ++t; - --t; - t + 1; - t < t; - { t->flagID } -> std::convertible_to; - }; - - template - concept FlagTester = requires(T t, u16 flagID) { - { t(flagID) } -> std::convertible_to; - }; - - static void sortByFlags(FlagIter auto begin, FlagIter auto end, FlagTester auto&& flagTester) { + template + requires requires(FlagIter a, FlagTester tester) { + --a; ++a; a < a; *a; + a + 1; + { tester(*a) } -> std::convertible_to; + } + static void sortByFlags(FlagIter begin, FlagIter end, FlagTester&& flagTester) { if (begin == end) return; - FlagIter auto fullEnd = end; + auto fullEnd = end; // We want to find the location of where we can swap our `On` flags to. // We're gonna put the `Off` bits first, and the `On` bits last. 0 < 1 // We can achieve this by skipping all the `On` bits at the end. // backtrack until we find a bit that is off - while (begin < --end && flagTester(end->flagID)) { + while (begin < --end && flagTester(*end)) { // move the end pointer back while we find on bits } // end should now be pointing to a bit that is off while (begin < end) { // if there's a flag that's on - if (flagTester(begin->flagID)) { + if (flagTester(*begin)) { // move it to the end std::rotate(begin, begin + 1, fullEnd); // move back the end of where we're checking @@ -1402,122 +1393,82 @@ namespace dusk { static void genAreaFlagTable(uint8_t areaIndex, dSv_memBit_c& membit) { - constexpr auto makeMask = [](uint8_t size) -> uint16_t { return (1 << size) - 1; }; - constexpr auto getByteIndexFromFlag = [](uint16_t f) -> uint8_t { return f >> 8; }; - constexpr auto getBitMaskFromFlag = [](uint16_t f) -> uint8_t { return f & 0xff; }; - constexpr auto getValueSize = [getBitMaskFromFlag](uint16_t f) -> uint8_t { - return std::popcount(getBitMaskFromFlag(f)); - }; - - constexpr auto makeEventFlag = [](uint8_t byteIndex, uint8_t bitIndices) -> uint16_t { - return (byteIndex << 8) | bitIndices; - }; - - const auto eventFlagToAreaFlag = [&](uint16_t areaFlag) -> int { - auto byteInd = getByteIndexFromFlag(areaFlag); - constexpr size_t areaIndexSize = 5; - // if we're looking at 0x580, that would be byte 5, and check if 0x80 is set on that byte - // the event flags are structured differently than area flags - // B is byte index, b is the flag mask to check - // event flags are BBBBBBBB bbbbbbbb - // for area flags, they check bitIndex, not mask, i is index - // also area uses u32 index, not byte index - // area flags are BBBiiiii - // so we need to convert from bit mask to index - // also our byte index has to become a u32 index - - // dividing byte index by sizeof(u32) gets us the u32 index - // but in big endian, the first byte is the highest order byte of the u32 - // so we skip 24 bytes for the first byte, 16 for the second, etc - // essentially (3 - (x % 4)), reversing the modulus, 0=3, 1=2 - auto bitsToSkip = 8 * ((sizeof(u32) - 1) - (byteInd % sizeof(u32))); - return ((byteInd / sizeof(u32)) << areaIndexSize) | ((std::countr_zero(areaFlag) + bitsToSkip) & makeMask(areaIndexSize)); - }; - - constexpr uint8_t validTbox = sizeof(membit.mTbox); - constexpr uint8_t validSwitch = validTbox + sizeof(membit.mSwitch); - constexpr uint8_t validItem = validSwitch + sizeof(membit.mItem); - constexpr uint16_t tboxConvert = 0; - constexpr uint16_t switchConvert = sizeof(membit.mTbox) << 8; - constexpr uint16_t itemConvert = switchConvert + (sizeof(membit.mItem) << 8); - - const auto LoadFlag = [&](uint16_t flag) -> bool { - const auto byteIndex = getByteIndexFromFlag(flag); - - if (byteIndex < validTbox) { - return membit.isTbox(eventFlagToAreaFlag(flag - tboxConvert)); - } else if (byteIndex < validSwitch) { - return membit.isSwitch(eventFlagToAreaFlag(flag - switchConvert)); - } else if (byteIndex < validItem) { - return membit.isItem(eventFlagToAreaFlag(flag - itemConvert)); + const auto LoadFlag = [&](const EventAreaFlags& flag) -> bool { + switch (flag.flag.type) { + case AreaFlagType::Item: { + return membit.isItem(flag.flag.flagID); + } break; + case AreaFlagType::Switch: { + return membit.isSwitch(flag.flag.flagID); + } break; + case AreaFlagType::Tbox: { + return membit.isTbox(flag.flag.flagID); + } break; } return false; }; - const auto SetFlag = [&](uint16_t flag, bool set) -> void { - const auto byteIndex = getByteIndexFromFlag(flag); + const auto SetFlag = [&](const AreaFlagInd& flag, bool set) -> void { if (set) { - if (byteIndex < validTbox) { - membit.onTbox(eventFlagToAreaFlag(flag - tboxConvert)); - } else if (byteIndex < validSwitch) { - membit.onSwitch(eventFlagToAreaFlag(flag - switchConvert)); - } else if (byteIndex < validItem) { - membit.onItem(eventFlagToAreaFlag(flag - itemConvert)); + switch (flag.type) { + case AreaFlagType::Item: { + membit.onItem(flag.flagID); + } break; + case AreaFlagType::Switch: { + membit.onSwitch(flag.flagID); + } break; + case AreaFlagType::Tbox: { + membit.onTbox(flag.flagID); + } break; } } else { - if (byteIndex < validTbox) { - membit.offTbox(eventFlagToAreaFlag(flag - tboxConvert)); - } else if (byteIndex < validSwitch) { - membit.offSwitch(eventFlagToAreaFlag(flag - switchConvert)); - } else if (byteIndex < validItem) { - membit.offItem(eventFlagToAreaFlag(flag - itemConvert)); + switch (flag.type) { + case AreaFlagType::Item: { + membit.offItem(flag.flagID); + } break; + case AreaFlagType::Switch: { + membit.offSwitch(flag.flagID); + } break; + case AreaFlagType::Tbox: { + membit.offTbox(flag.flagID); + } break; } } }; - const auto LoadMultiByteFlag = [&](uint16_t flag) -> uint8_t { - const auto bitInds = getBitMaskFromFlag(flag); - const auto byteIndex = getByteIndexFromFlag(flag); - - const uint16_t startingMask = std::bit_floor(bitInds); - uint8_t val = 0; - for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0; - bitIndexMask >>= 1) - { - val <<= 1; - if (LoadFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask))) { - val |= 1; - } + const auto LoadMultiByteFlag = [&](const AreaFlagMultibit& flag) -> uint8_t { + BE(u32)* areaFlags = nullptr; + switch (flag.type) { + case AreaFlagType::Item: { + areaFlags = membit.mItem; + } break; + case AreaFlagType::Switch: { + areaFlags = membit.mSwitch; + } break; + case AreaFlagType::Tbox: { + areaFlags = membit.mTbox; + } break; } - return val; + assert(areaFlags != nullptr); + return (areaFlags[flag.index] & flag.mask) >> flag.shift; }; - const auto SetMultiByteFlag = [&](uint16_t flag, uint8_t val) -> void { - const auto bitInds = getBitMaskFromFlag(flag); - const auto byteIndex = getByteIndexFromFlag(flag); - - const uint16_t startingMask = std::bit_floor(bitInds); - uint16_t valueMask = 1 << (getValueSize(flag) - 1); - - for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0; - bitIndexMask >>= 1, valueMask >>= 1) - { - SetFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask), (val & valueMask) != 0); + const auto SetMultiByteFlag = [&](const AreaFlagMultibit& flag, uint8_t val) -> void { + BE(u32)* areaFlags = nullptr; + switch (flag.type) { + case AreaFlagType::Item: { + areaFlags = membit.mItem; + } break; + case AreaFlagType::Switch: { + areaFlags = membit.mSwitch; + } break; + case AreaFlagType::Tbox: { + areaFlags = membit.mTbox; + } break; } - }; - const auto LoadSpreadMultiByte = [&](uint16_t high, uint16_t low) -> uint8_t { - if (low == AREA_FLAG_NONE) - return LoadMultiByteFlag(high); - return (LoadMultiByteFlag(high) << getValueSize(low)) | LoadMultiByteFlag(low); - }; - - const auto SetSpreadMultiByte = [&](uint16_t high, uint16_t low, uint8_t value) -> void { - if (low == AREA_FLAG_NONE) - return SetMultiByteFlag(high, value); - const auto lowerSize = getValueSize(low); - SetMultiByteFlag(high, value >> lowerSize); - SetMultiByteFlag(low, value & makeMask(lowerSize)); + areaFlags[flag.index] &= ~flag.mask; + areaFlags[flag.index] |= (val << flag.shift) & flag.mask; }; auto iter = imguiAreaFlagLookup.find(areaIndex); @@ -1569,7 +1520,7 @@ namespace dusk { case COLUMN_DESC: return l.description < r.description; case COLUMN_BIT: - return l.flagID < r.flagID; + return l.GetFlagID() < r.GetFlagID(); } return false; }; @@ -1598,9 +1549,9 @@ namespace dusk { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool flag = LoadFlag(e.flagID); - if (ImGui::Checkbox(fmt::format("##_unused_area_flag_{}", e.flagID).c_str(), &flag)) { - SetFlag(e.flagID, flag); + bool flag = LoadFlag(e); + if (ImGui::Checkbox(fmt::format("##_unused_area_flag_{}", e.flag.flagID).c_str(), &flag)) { + SetFlag(e.flag, flag); } ImGui::TableNextColumn(); @@ -1612,7 +1563,7 @@ namespace dusk { } for (const auto& multiByteFlag : areaFlags.multibyteFlags) { - auto flagValue = LoadSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag); + auto flagValue = LoadMultiByteFlag(multiByteFlag.flag); const char* currentVal = "UNKNOWN"; @@ -1624,7 +1575,7 @@ namespace dusk { if (ImGui::BeginCombo(multiByteFlag.name, currentVal)) { for (const auto& [val, name] : multiByteFlag.enumValues) { if (ImGui::Selectable(name)) { - SetSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag, val); + SetMultiByteFlag(multiByteFlag.flag, val); } } ImGui::EndCombo(); @@ -1757,7 +1708,9 @@ namespace dusk { // if we're sorting by flags, do special sort, regular sort is bad for sorting bools // it can swap values that are the same, and that causes constant reordering if (column == COLUMN_FLAG) { - const auto testEventFunc = [&event](u16 flag) -> bool { return event.isEventBit(flag); }; + const auto testEventFunc = [&event](const duskImguiEventFlagEntry& flag) -> bool { + return event.isEventBit(flag.flagID); + }; if (direction == ImGuiSortDirection_Ascending) { sortByFlags(std::begin(duskImguiEventFlags), diff --git a/src/dusk/imgui/ImGuiStateShare.cpp b/src/dusk/imgui/ImGuiStateShare.cpp index adbe5b6c67..a0bd450984 100644 --- a/src/dusk/imgui/ImGuiStateShare.cpp +++ b/src/dusk/imgui/ImGuiStateShare.cpp @@ -417,7 +417,9 @@ void ImGuiStateShare::draw(bool& open) { } void ImGuiMenuTools::ShowStateShare() { - if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare)) { + if (!getSettings().backend.enableAdvancedSettings || + !ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare)) + { return; } m_stateShare.draw(m_showStateShare); diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index a4e64c5b70..4d9c48d826 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -1,49 +1,99 @@ #include "iso_validate.hpp" +#include #include -#include +#include -#include "SDL3/SDL_iostream.h" +#include +#include +#include +#include + +namespace { + +constexpr uint8_t hex_nibble_to_u8(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + throw std::invalid_argument("invalid hex character"); +} + +constexpr uint64_t parse_u64_hex(std::string_view s) { + if (s.size() != 16) + throw std::invalid_argument("expected 16 hex chars for uint64"); + + uint64_t value = 0; + for (char c : s) { + value = (value << 4) | hex_nibble_to_u8(c); + } + return value; +} + +constexpr XXH128_hash_t parse_xxh128(std::string_view hex) { + if (hex.size() != 32) + throw std::invalid_argument("expected 32 hex chars for XXH128"); + + return XXH128_hash_t{ + .low64 = parse_u64_hex(hex.substr(16, 16)), + .high64 = parse_u64_hex(hex.substr(0, 16)), + }; +} + +} // namespace 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 +enum class Platform : u8 { + GameCube, + Wii, }; -constexpr const char* PAL_GAME_IDS[] = { - "GZ2P01", // GCN PAL - "RZDP01", // Wii PAL +enum class Region : u8 { + NorthAmerica, + Europe, + Japan, + Korea, }; -constexpr const char* SUPPORTED_TP_GAME_IDS[] = { - "GZ2E01", // GCN USA - "GZ2P01", // GCN PAL +struct KnownDisc { + std::string_view id; + Platform platform; + Region region; + bool supported = false; + XXH128_hash_t hash{}; + + constexpr KnownDisc(std::string_view id, Platform platform, Region region) + : id(id), platform(platform), region(region) {} + constexpr KnownDisc( + std::string_view id, Platform platform, Region region, const std::string_view hash) + : id(id), platform(platform), region(region), supported(true), hash(parse_xxh128(hash)) {} }; -template -constexpr bool matches(const char (&id)[6], const char* const (&valid)[N]) { - for (auto elem : valid) { - if (strncmp(id, elem, 6) == 0) { - return true; - } +constexpr auto KNOWN_DISCS = std::to_array({ + {"GZ2E01", Platform::GameCube, Region::NorthAmerica, "14e886f08e548a000afde98a3195e788"}, + {"GZ2J01", Platform::GameCube, Region::Japan}, + {"GZ2P01", Platform::GameCube, Region::Europe, "9ef597588b0035ca9e91b333fa9a8a7e"}, + {"RZDE01", Platform::Wii, Region::NorthAmerica}, + {"RZDJ01", Platform::Wii, Region::Japan}, + {"RZDK01", Platform::Wii, Region::Korea}, + {"RZDP01", Platform::Wii, Region::Europe}, +}); + +constexpr const KnownDisc* find_disc(std::string_view id) { + for (const auto& disc : KNOWN_DISCS) { + if (disc.id == id) + return &disc; } - - return false; + return nullptr; } struct NodHandleWrapper { NodHandle* handle; - NodHandleWrapper() : handle(nullptr) { - } - + NodHandleWrapper() : handle(nullptr) {} ~NodHandleWrapper() { if (handle != nullptr) { nod_free(handle); @@ -52,7 +102,7 @@ struct NodHandleWrapper { } }; -static ValidationError convertNodError(NodResult result) { +static ValidationError convert_nod_error(NodResult result) { switch (result) { case NOD_RESULT_ERR_IO: return ValidationError::IOError; @@ -67,96 +117,135 @@ s64 StreamReadAt(void* user_data, u64 offset, void* out, size_t len) { if (len == 0) { return 0; } - - auto io = static_cast(user_data); - - auto ret = SDL_SeekIO(io, static_cast(offset), SDL_IO_SEEK_SET); + auto* io = static_cast(user_data); + const auto ret = SDL_SeekIO(io, static_cast(offset), SDL_IO_SEEK_SET); if (ret < 0) { return -1; } - - auto read = SDL_ReadIO(io, out, len); + const 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(read); } s64 StreamLength(void* user_data) { - auto io = static_cast(user_data); - return SDL_GetIOSize(io); + return SDL_GetIOSize(static_cast(user_data)); } void StreamClose(void* user_data) { - auto io = static_cast(user_data); - SDL_CloseIO(io); + SDL_CloseIO(static_cast(user_data)); } -ValidationError validate(const char* path) { - NodHandleWrapper disc; +ValidationError verify_disc(NodHandle* disc, VerificationStatus& status) { + std::unique_ptr hashState( + XXH3_createState(), XXH3_freeState); + if (!hashState) { + return ValidationError::Unknown; + } + XXH3_128bits_reset(hashState.get()); + while (true) { + if (status.shouldCancel.load(std::memory_order_relaxed)) { + return ValidationError::Canceled; + } + + size_t bytesAvail; + const auto buf = nod_buf_read(disc, &bytesAvail); + if (!bytesAvail) + break; + + XXH3_128bits_update(hashState.get(), buf, bytesAvail); + + status.bytesRead.fetch_add(bytesAvail, std::memory_order_relaxed); + nod_buf_consume(disc, bytesAvail); + } + + const auto hash = XXH3_128bits_digest(hashState.get()); + if (!XXH128_isEqual(hash, status.knownDisc->hash)) { + return ValidationError::HashMismatch; + } + return ValidationError::Success; +} + +ValidationError validate(const char* path, VerificationStatus& status, DiscInfo& info) { const auto sdlStream = SDL_IOFromFile(path, "rb"); if (sdlStream == nullptr) { return ValidationError::IOError; } - 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; -} -bool isPal(const char* path) { NodHandleWrapper disc; - - const auto sdlStream = SDL_IOFromFile(path, "rb"); - if (sdlStream == nullptr) { - return false; - } - 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 convert_nod_error(result); + } - if (nod_disc_open_stream(&nod_stream, nullptr, &disc.handle) != NOD_RESULT_OK || disc.handle == nullptr) { - return false; + status.bytesTotal.store(nod_disc_size(disc.handle), std::memory_order_relaxed); + + NodDiscHeader header{}; + result = nod_disc_header(disc.handle, &header); + if (result != NOD_RESULT_OK) { + return convert_nod_error(result); + } + + const auto knownDisc = find_disc(std::string_view(header.game_id, 6)); + if (!knownDisc) { + return ValidationError::WrongGame; + } + status.knownDisc = knownDisc; + info.isPal = knownDisc->region == Region::Europe; + if (!knownDisc->supported) { + return ValidationError::WrongVersion; + } + return verify_disc(disc.handle, status); +} + +ValidationError inspect(const char* path, DiscInfo& info) { + const auto sdlStream = SDL_IOFromFile(path, "rb"); + if (sdlStream == nullptr) { + return ValidationError::IOError; + } + + NodHandleWrapper disc; + 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 convert_nod_error(result); } NodDiscHeader header{}; - if (nod_disc_header(disc.handle, &header) != NOD_RESULT_OK) { - return false; + result = nod_disc_header(disc.handle, &header); + if (result != NOD_RESULT_OK) { + return convert_nod_error(result); } - return matches(header.game_id, PAL_GAME_IDS); + const auto knownDisc = find_disc(std::string_view(header.game_id, 6)); + if (!knownDisc) { + return ValidationError::WrongGame; + } + info.isPal = knownDisc->region == Region::Europe; + if (!knownDisc->supported) { + return ValidationError::WrongVersion; + } + return ValidationError::Success; } -} // namespace dusk::iso \ No newline at end of file + +bool isPal(const char* path) { + DiscInfo info{}; + return inspect(path, info) == ValidationError::Success && info.isPal; +} +} // namespace dusk::iso diff --git a/src/dusk/iso_validate.hpp b/src/dusk/iso_validate.hpp index d961f052cd..c737a017d9 100644 --- a/src/dusk/iso_validate.hpp +++ b/src/dusk/iso_validate.hpp @@ -1,19 +1,37 @@ #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 - }; +#include - ValidationError validate(const char* path); - bool isPal(const char* path); -} +namespace dusk::iso { +struct KnownDisc; + +enum class ValidationError : u8 { + Unknown = 0, + IOError, + InvalidImage, + WrongGame, + WrongVersion, + Canceled, + HashMismatch, + Success +}; + +struct VerificationStatus { + std::atomic_size_t bytesRead = 0; + std::atomic_size_t bytesTotal = 0; + const KnownDisc* knownDisc = nullptr; + std::atomic_bool shouldCancel = false; +}; + +struct DiscInfo { + bool isPal = false; +}; + +ValidationError inspect(const char* path, DiscInfo& info); +ValidationError validate(const char* path, VerificationStatus& status, DiscInfo& info); +bool isPal(const char* path); + +} // namespace dusk::iso #endif // DUSK_ISO_VALIDATE_HPP diff --git a/src/dusk/main.cpp b/src/dusk/main.cpp index 22cd5a9fc6..e1b2fd0b6e 100644 --- a/src/dusk/main.cpp +++ b/src/dusk/main.cpp @@ -5,17 +5,110 @@ #endif #include +#include "dusk/main.h" +#include +#include +#include #include #include +#include +#include #include #include #include +#if !defined(_WIN32) +#include +#if defined(__APPLE__) +#include +#endif +#endif + int game_main(int argc, char* argv[]); namespace { +bool RestartProcess(int argc, char* argv[]) { +#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \ + (defined(TARGET_OS_TV) && TARGET_OS_TV) + (void)argc; + (void)argv; + return false; +#elif _WIN32 + std::wstring commandLine = GetCommandLineW(); + STARTUPINFOW startupInfo{}; + startupInfo.cb = sizeof(startupInfo); + PROCESS_INFORMATION processInfo{}; + if (!CreateProcessW(nullptr, commandLine.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, + &startupInfo, &processInfo)) + { + fprintf(stderr, "Failed to restart Dusk: CreateProcessW error %lu\n", GetLastError()); + return false; + } + + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); + return true; +#else + std::filesystem::path executablePath; + +#if defined(__APPLE__) + uint32_t pathSize = 0; + _NSGetExecutablePath(nullptr, &pathSize); + if (pathSize > 0) { + std::string path(pathSize, '\0'); + if (_NSGetExecutablePath(path.data(), &pathSize) == 0) { + path.resize(std::strlen(path.c_str())); + std::error_code ec; + executablePath = std::filesystem::weakly_canonical(path, ec); + if (ec) { + executablePath = path; + } + } + } +#elif defined(__linux__) + std::array path{}; + const ssize_t len = readlink("/proc/self/exe", path.data(), path.size() - 1); + if (len > 0) { + path[static_cast(len)] = '\0'; + executablePath = path.data(); + } +#endif + + if (executablePath.empty() && argc > 0 && argv[0] != nullptr && argv[0][0] != '\0') { + std::error_code ec; + executablePath = std::filesystem::absolute(argv[0], ec); + if (ec) { + executablePath = argv[0]; + } + } + + if (executablePath.empty()) { + fprintf(stderr, "Failed to restart Dusk: unable to resolve executable path\n"); + return false; + } + + std::vector args; + args.reserve(static_cast(std::max(argc, 1))); + args.push_back(executablePath.string()); + for (int i = 1; i < argc; ++i) { + args.emplace_back(argv[i] != nullptr ? argv[i] : ""); + } + + std::vector execArgv; + execArgv.reserve(args.size() + 1); + for (auto& arg : args) { + execArgv.push_back(arg.data()); + } + execArgv.push_back(nullptr); + + execv(executablePath.c_str(), execArgv.data()); + fprintf(stderr, "Failed to restart Dusk: execv failed: %s\n", std::strerror(errno)); + return false; +#endif +} + #if _WIN32 bool ShouldShowWindowsConsole(int argc, char* argv[]) { if (const auto* env = std::getenv("DUSK_CONSOLE")) { @@ -53,19 +146,25 @@ void WindowsSetupConsole(bool showConsole) { SetConsoleOutputCP(CP_UTF8); if (const HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); - stdoutHandle != INVALID_HANDLE_VALUE && stdoutHandle != nullptr) { + stdoutHandle != INVALID_HANDLE_VALUE && stdoutHandle != nullptr) + { DWORD consoleMode = 0; if (GetConsoleMode(stdoutHandle, &consoleMode)) { SetConsoleMode(stdoutHandle, - consoleMode | ENABLE_PROCESSED_OUTPUT - | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + consoleMode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } } } int DuskMain(int argc, char* argv[]) { WindowsSetupConsole(ShouldShowWindowsConsole(argc, argv)); - return game_main(argc, argv); + const int result = game_main(argc, argv); + if constexpr (dusk::SupportsProcessRestart) { + if (dusk::RestartRequested) { + return RestartProcess(argc, argv) ? 0 : result; + } + } + return result; } std::vector WideArgsToUtf8(int argc, wchar_t** argv) { @@ -81,8 +180,8 @@ std::vector WideArgsToUtf8(int argc, wchar_t** argv) { } std::vector utf8Buffer(static_cast(requiredSize)); - WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, utf8Buffer.data(), requiredSize, nullptr, - nullptr); + WideCharToMultiByte( + CP_UTF8, 0, argv[i], -1, utf8Buffer.data(), requiredSize, nullptr, nullptr); utf8Args.emplace_back(utf8Buffer.data()); } @@ -109,7 +208,11 @@ int RunWindowsGuiEntryPoint() { } #else int DuskMain(int argc, char* argv[]) { - return game_main(argc, argv); + const int result = game_main(argc, argv); + if (dusk::RestartRequested && RestartProcess(argc, argv)) { + return 0; + } + return result; } #endif diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 9114bfbee3..aa31540898 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -8,6 +8,8 @@ UserSettings g_userSettings = { .enableFullscreen {"video.enableFullscreen", false}, .enableVsync {"video.enableVsync", true}, .lockAspectRatio {"video.lockAspectRatio", false}, + .enableFpsOverlay {"game.enableFpsOverlay", false}, + .fpsOverlayCorner {"game.fpsOverlayCorner", 0}, }, .audio = { @@ -27,7 +29,6 @@ UserSettings g_userSettings = { // Quality of Life .enableQuickTransform {"game.enableQuickTransform", false}, .hideTvSettingsScreen {"game.hideTvSettingsScreen", true}, - .skipWarningScreen {"game.skipWarningScreen", true}, .biggerWallets {"game.biggerWallets", false}, .noReturnRupees {"game.noReturnRupees", false}, .disableRupeeCutscenes {"game.disableRupeeCutscenes", false}, @@ -46,9 +47,9 @@ UserSettings g_userSettings = { // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, - .disableMainHUD {"game.disableMainHUD", false}, + .minimalHUD {"game.minimalHUD", false}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, - .enableLinkDollRotation = {"game.enableLinkDollRotation", false}, + .enableLinkDollRotation {"game.enableLinkDollRotation", false}, .enableAchievementNotifications {"game.enableAchievementNotifications", true}, // Graphics @@ -80,18 +81,19 @@ UserSettings g_userSettings = { .invertCameraYAxis {"game.invertCameraYAxis", false}, .freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f}, .debugFlyCam {"game.debugFlyCam", false}, + .debugFlyCamLockEvents {"game.debugFlyCamLockEvents", true}, // Cheats .infiniteHearts {"game.infiniteHearts", false}, - .infiniteArrows{"game.infiniteArrows", false}, - .infiniteBombs{"game.infiniteBombs", false}, - .infiniteOil{"game.infiniteOil", false}, - .infiniteOxygen{"game.infiniteOxygen", false}, - .infiniteRupees{"game.infiniteRupees", false}, + .infiniteArrows {"game.infiniteArrows", false}, + .infiniteBombs {"game.infiniteBombs", false}, + .infiniteOil {"game.infiniteOil", false}, + .infiniteOxygen {"game.infiniteOxygen", false}, + .infiniteRupees {"game.infiniteRupees", false}, .enableIndefiniteItemDrops {"game.enableIndefiniteItemDrops", false}, - .moonJump{"game.moonJump", false}, - .superClawshot{"game.superClawshot", false}, - .alwaysGreatspin{"game.alwaysGreatspin", false}, + .moonJump {"game.moonJump", false}, + .superClawshot {"game.superClawshot", false}, + .alwaysGreatspin {"game.alwaysGreatspin", false}, .enableFastIronBoots {"game.enableFastIronBoots", false}, .canTransformAnywhere {"game.canTransformAnywhere", false}, .fastSpinner {"game.fastSpinner", false}, @@ -105,17 +107,21 @@ UserSettings g_userSettings = { // Tools .speedrunMode {"game.speedrunMode", false}, - .liveSplitEnabled {"game.liveSplitEnabled", false} + .liveSplitEnabled {"game.liveSplitEnabled", false}, + .recordingMode {"game.recordingMode", false} }, .backend = { .isoPath {"backend.isoPath", ""}, + .isoVerification {"backend.isoVerification", DiscVerificationState::Unknown}, .graphicsBackend {"backend.graphicsBackend", "auto"}, .skipPreLaunchUI {"backend.skipPreLaunchUI", false}, .showPipelineCompilation {"backend.showPipelineCompilation", false}, .wasPresetChosen {"backend.wasPresetChosen", false}, .enableCrashReporting {"backend.enableCrashReporting", true}, - .cardFileType {"backend.cardFileType", static_cast(CARD_GCIFOLDER)} + .checkForUpdates {"backend.checkForUpdates", true}, + .cardFileType {"backend.cardFileType", static_cast(CARD_GCIFOLDER)}, + .enableAdvancedSettings {"backend.enableAdvancedSettings", false}, } }; @@ -128,6 +134,8 @@ void registerSettings() { Register(g_userSettings.video.enableFullscreen); Register(g_userSettings.video.enableVsync); Register(g_userSettings.video.lockAspectRatio); + Register(g_userSettings.video.enableFpsOverlay); + Register(g_userSettings.video.fpsOverlayCorner); // Audio Register(g_userSettings.audio.masterVolume); @@ -143,7 +151,6 @@ void registerSettings() { Register(g_userSettings.game.language); Register(g_userSettings.game.enableQuickTransform); Register(g_userSettings.game.hideTvSettingsScreen); - Register(g_userSettings.game.skipWarningScreen); Register(g_userSettings.game.biggerWallets); Register(g_userSettings.game.noReturnRupees); Register(g_userSettings.game.disableRupeeCutscenes); @@ -162,7 +169,7 @@ void registerSettings() { Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.invertCameraYAxis); Register(g_userSettings.game.freeCameraSensitivity); - Register(g_userSettings.game.disableMainHUD); + Register(g_userSettings.game.minimalHUD); Register(g_userSettings.game.pauseOnFocusLost); Register(g_userSettings.game.bloomMode); Register(g_userSettings.game.bloomMultiplier); @@ -183,6 +190,7 @@ void registerSettings() { Register(g_userSettings.game.enableTurboKeybind); Register(g_userSettings.game.speedrunMode); Register(g_userSettings.game.liveSplitEnabled); + Register(g_userSettings.game.recordingMode); Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.infiniteHearts); Register(g_userSettings.game.infiniteArrows); @@ -206,14 +214,18 @@ void registerSettings() { Register(g_userSettings.game.gyroInvertYaw); Register(g_userSettings.game.freeCamera); Register(g_userSettings.game.debugFlyCam); + Register(g_userSettings.game.debugFlyCamLockEvents); Register(g_userSettings.backend.isoPath); + Register(g_userSettings.backend.isoVerification); Register(g_userSettings.backend.graphicsBackend); Register(g_userSettings.backend.skipPreLaunchUI); Register(g_userSettings.backend.showPipelineCompilation); Register(g_userSettings.backend.wasPresetChosen); Register(g_userSettings.backend.enableCrashReporting); + Register(g_userSettings.backend.checkForUpdates); Register(g_userSettings.backend.cardFileType); + Register(g_userSettings.backend.enableAdvancedSettings); } // Transient settings diff --git a/src/dusk/ui/achievements.cpp b/src/dusk/ui/achievements.cpp index 93993bb380..725d662ec1 100644 --- a/src/dusk/ui/achievements.cpp +++ b/src/dusk/ui/achievements.cpp @@ -41,7 +41,7 @@ Rml::String build_achievement_info_rml(const Achievement& a) { if (a.isCounter) { float fraction = a.goal > 0 ? float(a.progress) / float(a.goal) : 1.0f; s += fmt::format( - R"()" + R"()" R"({} / {})", fraction, a.unlocked ? "progress-done" : "progress-ongoing", @@ -65,7 +65,7 @@ public: btn.on_nav_command([this, key = std::string(a.key)](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { if (mConfirming) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); + mDoAud_seStartMenu(kSoundClick); AchievementSystem::get().clearOne(key.c_str()); resetConfirm(); } else { @@ -158,7 +158,7 @@ AchievementsWindow::AchievementsWindow() { clearAllBtn.on_nav_command([clearAllPtr, confirmingAll](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { if (*confirmingAll) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); + mDoAud_seStartMenu(kSoundClick); AchievementSystem::get().clearAll(); *confirmingAll = false; clearAllPtr->set_text("Clear All Achievements"); diff --git a/src/dusk/ui/bool_button.cpp b/src/dusk/ui/bool_button.cpp index ca4d3f96d8..2ed088542a 100644 --- a/src/dusk/ui/bool_button.cpp +++ b/src/dusk/ui/bool_button.cpp @@ -36,7 +36,7 @@ bool BoolButton::handle_nav_command(NavCommand cmd) { if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || cmd == NavCommand::Right) { const bool newValue = !mGetValue(); mSetValue(newValue); - mDoAud_seStartMenu(newValue ? Z2SE_SY_CURSOR_OK : Z2SE_SY_CURSOR_CANCEL); + mDoAud_seStartMenu(newValue ? kSoundItemEnable : kSoundItemDisable); return true; } return false; diff --git a/src/dusk/ui/button.cpp b/src/dusk/ui/button.cpp index ac27b03d5a..fb11571af4 100644 --- a/src/dusk/ui/button.cpp +++ b/src/dusk/ui/button.cpp @@ -37,7 +37,6 @@ Button& Button::on_pressed(ButtonCallback callback) { // TODO: convert this to a FluentComponent method? on_nav_command([callback = std::move(callback)](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); callback(); return true; } diff --git a/src/dusk/ui/component.cpp b/src/dusk/ui/component.cpp index 466420eb1e..748df848be 100644 --- a/src/dusk/ui/component.cpp +++ b/src/dusk/ui/component.cpp @@ -59,16 +59,6 @@ void Component::set_disabled(bool value) { } } -Rml::Element* Component::append(Rml::Element* parent, const Rml::String& tag) { - if (parent == nullptr) { - return nullptr; - } - auto* doc = parent->GetOwnerDocument(); - if (doc == nullptr) { - return nullptr; - } - return parent->AppendChild(doc->CreateElement(tag)); -} void Component::listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback, bool capture) { if (element == nullptr) { diff --git a/src/dusk/ui/component.hpp b/src/dusk/ui/component.hpp index 0c49ce3254..e0a602e7fd 100644 --- a/src/dusk/ui/component.hpp +++ b/src/dusk/ui/component.hpp @@ -47,7 +47,6 @@ public: Rml::Element* root() const { return mRoot; } protected: - static Rml::Element* append(Rml::Element* parent, const Rml::String& tag); void clear_children(); Rml::Element* mRoot = nullptr; diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp index 9a3238725e..52c6f6c702 100644 --- a/src/dusk/ui/controller_config.cpp +++ b/src/dusk/ui/controller_config.cpp @@ -3,10 +3,11 @@ #include "bool_button.hpp" #include "button.hpp" #include "pane.hpp" -#include "select_button.hpp" +#include "number_button.hpp" #include #include +#include #include #include @@ -17,9 +18,17 @@ namespace dusk::ui { namespace { +bool keyboard_active(int port) { + u32 count = 0; + return PADGetKeyButtonBindings(static_cast(port), &count) != nullptr; +} + Rml::String current_controller_name(int port) { const char* name = PADGetName(port); - return name == nullptr ? "None" : name; + if (name != nullptr) { + return name; + } + return keyboard_active(port) ? "Keyboard" : "None"; } Rml::String controller_index_name(u32 index) { @@ -202,6 +211,86 @@ bool keyboard_escape_pressed() { return keys != nullptr && SDL_SCANCODE_ESCAPE < keyCount && keys[SDL_SCANCODE_ESCAPE]; } +Rml::String keyboard_key_name(s32 scancode) { + if (scancode == PAD_KEY_INVALID) { + return "Not bound"; + } + switch (scancode) { + case PAD_KEY_MOUSE_LEFT: + return "Mouse Left"; + case PAD_KEY_MOUSE_MIDDLE: + return "Mouse Middle"; + case PAD_KEY_MOUSE_RIGHT: + return "Mouse Right"; + case PAD_KEY_MOUSE_X1: + return "Mouse X1"; + case PAD_KEY_MOUSE_X2: + return "Mouse X2"; + default: + break; + } + if (scancode < 0) { + return "Unknown"; + } + const char* name = SDL_GetScancodeName(static_cast(scancode)); + if (name == nullptr || name[0] == '\0') { + return "Unknown"; + } + return name; +} + +bool keyboard_neutral() { + int keyCount = 0; + const bool* keys = SDL_GetKeyboardState(&keyCount); + if (keys != nullptr) { + for (int i = 0; i < keyCount; ++i) { + if (keys[i]) { + return false; + } + } + } + float x, y; + if (SDL_GetMouseState(&x, &y) != 0) { + return false; + } + return true; +} + +s32 keyboard_key_pressed() { + int keyCount = 0; + const bool* keys = SDL_GetKeyboardState(&keyCount); + if (keys != nullptr) { + for (int i = 1; i < keyCount; ++i) { + if (i == SDL_SCANCODE_ESCAPE) { + continue; + } + if (keys[i]) { + return static_cast(i); + } + } + } + float x, y; + const auto mouseButtons = SDL_GetMouseState(&x, &y); + for (int btn = 1; btn <= 5; ++btn) { + if (mouseButtons & (1u << (btn - 1))) { + return -(btn + 1); // maps to PAD_KEY_MOUSE_LEFT (-2), etc. + } + } + return PAD_KEY_INVALID; +} + +u16 percent_to_raw(int percent) { + return static_cast((static_cast(percent) / 100.f) * 32767.f); +} + +int deadzone_raw_to_percent(u16 raw) { + return static_cast((static_cast(raw) * 100.f) / 32767.f + 0.5f); +} + +int rumble_raw_to_percent(u16 raw) { + return static_cast((static_cast(raw) / 32767.f) * 100.f + 0.5f); +} + } // namespace ControllerConfigWindow::ControllerConfigWindow() { @@ -231,6 +320,7 @@ ControllerConfigWindow::ControllerConfigWindow() { } void ControllerConfigWindow::hide(bool close) { + stop_rumble_test(); cancel_pending_binding(); Window::hide(close); } @@ -241,16 +331,18 @@ void ControllerConfigWindow::update() { } void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) { + stop_rumble_test(); auto& leftPane = add_child(content, Pane::Type::Controlled); auto& rightPane = add_child(content, Pane::Type::Uncontrolled); mRightPane = &rightPane; mActivePort = port; auto addPageButton = [this, &leftPane, &rightPane, port]( - Page page, Rml::String key, auto getValue) { + Page page, Rml::String key, auto getValue, auto isDisabled) { leftPane.register_control(leftPane.add_select_button({ .key = std::move(key), .getValue = std::move(getValue), + .isDisabled = std::move(isDisabled), }), rightPane, [this, port, page](Pane& pane) { mPage = page; @@ -258,10 +350,11 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) { }); }; - addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }); - addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }); - addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }); - addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }); + addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }, [] { return false; }); + addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }, [] { return false; }); + addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }, [] { return false; }); + addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }, [] { return false; }); + addPageButton(Page::Rumble, "Rumble", [] { return Rml::String(">"); }, [port] { return !PADSupportsRumbleIntensity(static_cast(port)); }); leftPane.add_section("Options"); leftPane.register_control(leftPane.add_child(BoolButton::Props{ @@ -311,22 +404,38 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { switch (page) { case Page::Controller: { + pane.add_button( + { + .text = "None", + .isSelected = + [port] { return PADGetIndexForPort(port) < 0 && !keyboard_active(port); }, + }) + .on_pressed([this, port] { + mDoAud_seStartMenu(kSoundItemChange); + cancel_pending_binding(); + PADClearPort(port); + PADSetKeyboardActive(static_cast(port), FALSE); + PADSerializeMappings(); + }); + + pane.add_button({ + .text = "Keyboard", + .isSelected = [port] { return keyboard_active(port); }, + }) + .on_pressed([this, port] { + mDoAud_seStartMenu(kSoundItemChange); + cancel_pending_binding(); + PADClearPort(port); + PADSetKeyboardActive(static_cast(port), TRUE); + PADSerializeMappings(); + }); + const u32 controllerCount = PADCount(); if (controllerCount == 0) { pane.add_text("No controllers detected"); break; } - pane.add_button({ - .text = "None", - .isSelected = [port] { return PADGetIndexForPort(port) < 0; }, - }) - .on_pressed([this, port] { - cancel_pending_binding(); - PADClearPort(port); - PADSerializeMappings(); - }); - for (u32 i = 0; i < controllerCount; ++i) { pane.add_button( { @@ -335,7 +444,9 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { [port, i] { return PADGetIndexForPort(port) == static_cast(i); }, }) .on_pressed([this, port, i] { + mDoAud_seStartMenu(kSoundItemChange); cancel_pending_binding(); + PADSetKeyboardActive(static_cast(port), FALSE); PADSetPortForIndex(i, port); PADSerializeMappings(); }); @@ -343,6 +454,54 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { break; } case Page::Buttons: { + if (keyboard_active(port)) { + auto addKeyButton = [&](PADButton button) { + pane.add_select_button( + { + .key = PADGetButtonName(button), + .getValue = + [this, port, button] { + if (mPendingKeyButton == static_cast(button)) { + return pending_key_label(); + } + u32 count = 0; + PADKeyButtonBinding* bindings = + PADGetKeyButtonBindings(static_cast(port), &count); + if (bindings == nullptr) { + return Rml::String("Not bound"); + } + for (u32 i = 0; i < PAD_BUTTON_COUNT; ++i) { + if (bindings[i].padButton == button) { + return keyboard_key_name(bindings[i].scancode); + } + } + return Rml::String("Not bound"); + }, + }) + .on_pressed([this, port, button] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingKeyButton = static_cast(button); + }); + }; + + pane.add_section("Buttons"); + addKeyButton(PAD_BUTTON_A); + addKeyButton(PAD_BUTTON_B); + addKeyButton(PAD_BUTTON_X); + addKeyButton(PAD_BUTTON_Y); + addKeyButton(PAD_BUTTON_START); + addKeyButton(PAD_TRIGGER_Z); + + pane.add_section("D-Pad"); + addKeyButton(PAD_BUTTON_UP); + addKeyButton(PAD_BUTTON_DOWN); + addKeyButton(PAD_BUTTON_LEFT); + addKeyButton(PAD_BUTTON_RIGHT); + break; + } + u32 buttonCount = 0; PADButtonMapping* mappings = PADGetButtonMappings(port, &buttonCount); if (mappings == nullptr) { @@ -405,6 +564,79 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { break; } case Page::Triggers: { + if (keyboard_active(port)) { + auto addKeyButton = [&](PADButton button) { + pane.add_select_button( + { + .key = PADGetButtonName(button), + .getValue = + [this, port, button] { + if (mPendingKeyButton == static_cast(button)) { + return pending_key_label(); + } + u32 count = 0; + PADKeyButtonBinding* bindings = + PADGetKeyButtonBindings(static_cast(port), &count); + if (bindings == nullptr) { + return Rml::String("Not bound"); + } + for (u32 i = 0; i < PAD_BUTTON_COUNT; ++i) { + if (bindings[i].padButton == button) { + return keyboard_key_name(bindings[i].scancode); + } + } + return Rml::String("Not bound"); + }, + }) + .on_pressed([this, port, button] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingKeyButton = static_cast(button); + }); + }; + + auto addKeyAxis = [&](PADAxis axis) { + pane.add_select_button( + { + .key = PADGetAxisName(axis), + .getValue = + [this, port, axis] { + if (mPendingKeyAxis == static_cast(axis)) { + return pending_key_label(); + } + u32 count = 0; + PADKeyAxisBinding* bindings = + PADGetKeyAxisBindings(static_cast(port), &count); + if (bindings == nullptr) { + return Rml::String("Not bound"); + } + for (u32 i = 0; i < PAD_AXIS_COUNT; ++i) { + if (bindings[i].padAxis == axis) { + return keyboard_key_name(bindings[i].scancode); + } + } + return Rml::String("Not bound"); + }, + }) + .on_pressed([this, port, axis] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingKeyAxis = static_cast(axis); + }); + }; + + pane.add_section("Analog"); + addKeyAxis(PAD_AXIS_TRIGGER_L); + addKeyAxis(PAD_AXIS_TRIGGER_R); + + pane.add_section("Digital"); + addKeyButton(PAD_TRIGGER_L); + addKeyButton(PAD_TRIGGER_R); + break; + } + u32 axisCount = 0; PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount); u32 buttonCount = 0; @@ -468,9 +700,87 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { }); } } + + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + pane.add_section("Emulated Trigger Thresholds"); + pane.add_child(NumberButton::Props{ + .key = "L Threshold", + .getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->leftTriggerActivationZone); }, + .setValue = + [deadZones](int value) { + deadZones->leftTriggerActivationZone = percent_to_raw(value); + PADSerializeMappings(); + }, + .isDisabled = [deadZones] { return !deadZones->emulateTriggers; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + pane.add_child(NumberButton::Props{ + .key = "R Threshold", + .getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->rightTriggerActivationZone); }, + .setValue = + [deadZones](int value) { + deadZones->rightTriggerActivationZone = percent_to_raw(value); + PADSerializeMappings(); + }, + .isDisabled = [deadZones] { return !deadZones->emulateTriggers; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + } break; } case Page::Sticks: { + if (keyboard_active(port)) { + auto addKeyAxis = [&](PADAxis axis) { + pane.add_select_button( + { + .key = PADGetAxisDirectionLabel(axis), + .getValue = + [this, port, axis] { + if (mPendingKeyAxis == static_cast(axis)) { + return pending_key_label(); + } + u32 count = 0; + PADKeyAxisBinding* bindings = + PADGetKeyAxisBindings(static_cast(port), &count); + if (bindings == nullptr) { + return Rml::String("Not bound"); + } + for (u32 i = 0; i < PAD_AXIS_COUNT; ++i) { + if (bindings[i].padAxis == axis) { + return keyboard_key_name(bindings[i].scancode); + } + } + return Rml::String("Not bound"); + }, + }) + .on_pressed([this, port, axis] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingKeyAxis = static_cast(axis); + }); + }; + + pane.add_section("Control Stick"); + addKeyAxis(PAD_AXIS_LEFT_Y_POS); + addKeyAxis(PAD_AXIS_LEFT_Y_NEG); + addKeyAxis(PAD_AXIS_LEFT_X_NEG); + addKeyAxis(PAD_AXIS_LEFT_X_POS); + + pane.add_section("C Stick"); + addKeyAxis(PAD_AXIS_RIGHT_Y_POS); + addKeyAxis(PAD_AXIS_RIGHT_Y_NEG); + addKeyAxis(PAD_AXIS_RIGHT_X_NEG); + addKeyAxis(PAD_AXIS_RIGHT_X_POS); + break; + } + u32 axisCount = 0; PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount); if (axes == nullptr) { @@ -507,12 +817,121 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { addAxis(PAD_AXIS_LEFT_Y_NEG); addAxis(PAD_AXIS_LEFT_X_NEG); addAxis(PAD_AXIS_LEFT_X_POS); + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + pane.add_child(NumberButton::Props{ + .key = "Deadzone", + .getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->stickDeadZone); }, + .setValue = + [deadZones](int value) { + deadZones->stickDeadZone = percent_to_raw(value); + PADSerializeMappings(); + }, + .isDisabled = [deadZones] { return !deadZones->useDeadzones; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + } pane.add_section("C Stick"); addAxis(PAD_AXIS_RIGHT_Y_POS); addAxis(PAD_AXIS_RIGHT_Y_NEG); addAxis(PAD_AXIS_RIGHT_X_NEG); addAxis(PAD_AXIS_RIGHT_X_POS); + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + pane.add_child(NumberButton::Props{ + .key = "Deadzone", + .getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->substickDeadZone); }, + .setValue = + [deadZones](int value) { + deadZones->substickDeadZone = percent_to_raw(value); + PADSerializeMappings(); + }, + .isDisabled = [deadZones] { return !deadZones->useDeadzones; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + } + + break; + } + case Page::Rumble: { + auto& rumbleTest = pane.add_select_button({ + .key = "Test Rumble", + .getValue = + [this, port] { + return (mRumbleTestActive && mRumbleTestPort == port) ? Rml::String("Stop") + : Rml::String("Start"); + }, + }); + rumbleTest.on_pressed([this, port] { + if (!PADSupportsRumbleIntensity(static_cast(port))) { + return; + } + mDoAud_seStartMenu(kSoundItemChange); + if (mRumbleTestActive && mRumbleTestPort == port) { + PADControlMotor(port, PAD_MOTOR_STOP_HARD); + mRumbleTestActive = false; + mRumbleTestPort = -1; + } else { + if (mRumbleTestActive) { + PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD); + } + PADControlMotor(port, PAD_MOTOR_RUMBLE); + mRumbleTestActive = true; + mRumbleTestPort = port; + } + }); + pane.add_child(NumberButton::Props{ + .key = "Low Rumble Frequency", + .getValue = + [port] { + u16 low = 0; + u16 high = 0; + PADGetRumbleIntensity(static_cast(port), &low, &high); + return rumble_raw_to_percent(low); + }, + .setValue = + [port](int value) { + u16 low = 0; + u16 high = 0; + PADGetRumbleIntensity(static_cast(port), &low, &high); + PADSetRumbleIntensity(static_cast(port), percent_to_raw(value), high); + PADSerializeMappings(); + }, + .isDisabled = [this] { return mRumbleTestActive; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + pane.add_child(NumberButton::Props{ + .key = "High Rumble Frequency", + .getValue = + [port] { + u16 low = 0; + u16 high = 0; + PADGetRumbleIntensity(static_cast(port), &low, &high); + return rumble_raw_to_percent(high); + }, + .setValue = + [port](int value) { + u16 low = 0; + u16 high = 0; + PADGetRumbleIntensity(static_cast(port), &low, &high); + PADSetRumbleIntensity(static_cast(port), low, percent_to_raw(value)); + PADSerializeMappings(); + }, + .isDisabled = [this] { return mRumbleTestActive; }, + .min = 0, + .max = 100, + .step = 1, + .suffix = "%", + }); + pane.add_text("Configure your desired rumble intensities, then run a test to check how they feel."); break; } } @@ -547,6 +966,21 @@ void ControllerConfigWindow::poll_pending_binding() { return; } + if (mPendingKeyButton >= 0 || mPendingKeyAxis >= 0) { + const s32 scancode = keyboard_key_pressed(); + if (scancode != PAD_KEY_INVALID) { + if (mPendingKeyButton >= 0) { + PADSetKeyButtonBinding(static_cast(mPendingPort), + {scancode, static_cast(mPendingKeyButton)}); + } else { + PADSetKeyAxisBinding(static_cast(mPendingPort), + {scancode, static_cast(mPendingKeyAxis), 0}); + } + finish_pending_key_binding(); + } + return; + } + if (mPendingButtonMapping != nullptr) { const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort); if (nativeButton != -1) { @@ -588,26 +1022,40 @@ void ControllerConfigWindow::finish_pending_binding(int completedPort) { } void ControllerConfigWindow::unmap_pending_binding() { - if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr) { + if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr && + mPendingKeyButton < 0 && mPendingKeyAxis < 0) + { return; } const int completedPort = mPendingPort; if (mPendingButtonMapping != nullptr) { mPendingButtonMapping->nativeButton = PAD_NATIVE_BUTTON_INVALID; - } - if (mPendingAxisMapping != nullptr) { + finish_pending_binding(completedPort); + } else if (mPendingAxisMapping != nullptr) { mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; mPendingAxisMapping->nativeButton = -1; + finish_pending_binding(completedPort); + } else if (mPendingKeyButton >= 0) { + PADSetKeyButtonBinding(static_cast(completedPort), + {PAD_KEY_INVALID, static_cast(mPendingKeyButton)}); + finish_pending_key_binding(); + } else if (mPendingKeyAxis >= 0) { + PADSetKeyAxisBinding(static_cast(completedPort), + {PAD_KEY_INVALID, static_cast(mPendingKeyAxis), 0}); + finish_pending_key_binding(); } - finish_pending_binding(completedPort); } bool ControllerConfigWindow::capture_active() const { - return mPendingButtonMapping != nullptr || mPendingAxisMapping != nullptr; + return mPendingButtonMapping != nullptr || mPendingAxisMapping != nullptr || + mPendingKeyButton >= 0 || mPendingKeyAxis >= 0; } bool ControllerConfigWindow::pending_input_neutral() const { + if (mPendingKeyButton >= 0 || mPendingKeyAxis >= 0) { + return keyboard_neutral(); + } return input_neutral(mPendingPort); } @@ -621,16 +1069,41 @@ Rml::String ControllerConfigWindow::pending_axis_label() const { void ControllerConfigWindow::cancel_pending_binding() { if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr && - !mSuppressNavigationUntilNeutral) + !mSuppressNavigationUntilNeutral && mPendingKeyButton < 0 && mPendingKeyAxis < 0) { return; } mPendingButtonMapping = nullptr; mPendingAxisMapping = nullptr; + mPendingKeyButton = -1; + mPendingKeyAxis = -1; mPendingPort = -1; mPendingBindingArmed = false; mSuppressNavigationUntilNeutral = false; mSuppressNavigationPort = -1; } +void ControllerConfigWindow::finish_pending_key_binding() { + mPendingKeyButton = -1; + mPendingKeyAxis = -1; + mPendingPort = -1; + mPendingBindingArmed = false; + PADSerializeMappings(); +} + +Rml::String ControllerConfigWindow::pending_key_label() const { + return mPendingBindingArmed ? "Press a key or mouse button..." : "Waiting..."; +} + +void ControllerConfigWindow::stop_rumble_test() { + if (!mRumbleTestActive) { + return; + } + if (mRumbleTestPort >= PAD_CHAN0 && mRumbleTestPort < PAD_CHANMAX) { + PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD); + } + mRumbleTestActive = false; + mRumbleTestPort = -1; +} + } // namespace dusk::ui diff --git a/src/dusk/ui/controller_config.hpp b/src/dusk/ui/controller_config.hpp index 4bcf41ae8d..0fa096c7d1 100644 --- a/src/dusk/ui/controller_config.hpp +++ b/src/dusk/ui/controller_config.hpp @@ -19,6 +19,7 @@ private: Buttons, Triggers, Sticks, + Rumble, }; void build_port_tab(Rml::Element* content, int port); @@ -32,6 +33,9 @@ private: Rml::String pending_button_label() const; Rml::String pending_axis_label() const; void cancel_pending_binding(); + void finish_pending_key_binding(); + Rml::String pending_key_label() const; + void stop_rumble_test(); Page mPage = Page::Controller; Pane* mRightPane = nullptr; @@ -42,6 +46,10 @@ private: int mSuppressNavigationPort = -1; PADButtonMapping* mPendingButtonMapping = nullptr; PADAxisMapping* mPendingAxisMapping = nullptr; + int mPendingKeyButton = -1; + int mPendingKeyAxis = -1; + bool mRumbleTestActive = false; + int mRumbleTestPort = -1; }; } // namespace dusk::ui diff --git a/src/dusk/ui/document.cpp b/src/dusk/ui/document.cpp index 9d581d21ca..a7bcc3f9ed 100644 --- a/src/dusk/ui/document.cpp +++ b/src/dusk/ui/document.cpp @@ -44,15 +44,8 @@ Document::Document(const Rml::String& source) : mDocument(load_document(source)) if (cmd == NavCommand::None) { return; } - auto* prevFocused = mDocument->GetFocusLeafNode(); if (handle_nav_command(event, cmd)) { event.StopPropagation(); - return; - } - if ((cmd == NavCommand::Up || cmd == NavCommand::Down) && - mDocument->GetFocusLeafNode() != prevFocused) - { - mDoAud_seStartMenu(Z2SE_SY_NAME_CURSOR); } }); } @@ -113,7 +106,7 @@ bool Document::visible() const { bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (cmd == NavCommand::Menu) { - mDoAud_seStartMenu(visible() ? Z2SE_SY_MENU_OUT : Z2SE_SY_MENU_IN); + mDoAud_seStartMenu(visible() ? kSoundMenuClose : kSoundMenuOpen); toggle(); return true; } diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index 1ba44f0a27..09216a3b8a 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -185,7 +185,10 @@ void populate_stage_picker(Pane& pane, std::function getStageFile return getStageFile() == stageFile; }, }) - .on_pressed([setStageFile, stageFile = map.mapFile] { setStageFile(stageFile); }); + .on_pressed([setStageFile, stageFile = map.mapFile] { + mDoAud_seStartMenu(kSoundItemChange); + setStageFile(stageFile); + }); } } } @@ -265,8 +268,8 @@ std::map itemMap = { {dItemNo_DUNGEON_BACK_e, {"Ooccoo Jr.", ITEMTYPE_EQUIP_e}}, {dItemNo_SWORD_e, {"Ordon Sword"}}, {dItemNo_MASTER_SWORD_e, {"Master Sword"}}, - {dItemNo_WOOD_SHIELD_e, {"Wooden Shield"}}, - {dItemNo_SHIELD_e, {"Ordon Shield"}}, + {dItemNo_WOOD_SHIELD_e, {"Ordon Shield"}}, + {dItemNo_SHIELD_e, {"Wooden Shield"}}, {dItemNo_HYLIA_SHIELD_e, {"Hylian Shield"}}, {dItemNo_TKS_LETTER_e, {"Ooccoo's Note", ITEMTYPE_EQUIP_e}}, {dItemNo_WEAR_CASUAL_e, {"Ordon Clothes"}}, @@ -741,11 +744,13 @@ void populate_toggle_group(Pane& pane, const std::vector& entries) pane.clear(); pane.add_section("Actions"); pane.add_button("Select All").on_pressed([entries] { + mDoAud_seStartMenu(kSoundItemChange); for (const auto& entry : entries) { entry.setSelected(true); } }); pane.add_button("Select None").on_pressed([entries] { + mDoAud_seStartMenu(kSoundItemChange); for (const auto& entry : entries) { entry.setSelected(false); } @@ -758,6 +763,7 @@ void populate_toggle_group(Pane& pane, const std::vector& entries) .isSelected = entry.isSelected, }) .on_pressed([isSelected = entry.isSelected, setSelected = entry.setSelected] { + mDoAud_seStartMenu(kSoundItemChange); setSelected(!isSelected()); }); } @@ -878,7 +884,10 @@ void populate_item_slot_picker(Pane& pane, int slot) { pane.clear(); pane.add_section("Actions"); pane.add_button(fmt::format("Default ({})", get_item_name(get_slot_default(slot)))) - .on_pressed([slot] { dComIfGs_setItem(slot, get_slot_default(slot)); }); + .on_pressed([slot] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, get_slot_default(slot)); + }); pane.add_section("Items"); pane.add_button( @@ -886,7 +895,10 @@ void populate_item_slot_picker(Pane& pane, int slot) { .text = "None", .isSelected = [slot] { return get_player_item()->mItems[slot] == dItemNo_NONE_e; }, }) - .on_pressed([slot] { dComIfGs_setItem(slot, dItemNo_NONE_e); }); + .on_pressed([slot] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, dItemNo_NONE_e); + }); for (const auto& [itemId, item] : itemMap) { if (item.m_type != ITEMTYPE_EQUIP_e) { continue; @@ -896,15 +908,24 @@ void populate_item_slot_picker(Pane& pane, int slot) { .text = item.m_name, .isSelected = [slot, itemId] { return get_player_item()->mItems[slot] == itemId; }, }) - .on_pressed([slot, itemId] { dComIfGs_setItem(slot, static_cast(itemId)); }); + .on_pressed([slot, itemId] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, static_cast(itemId)); + }); } } void populate_item_flag_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); - pane.add_button("Select All").on_pressed([] { set_all_item_first_bits(true); }); - pane.add_button("Clear None").on_pressed([] { set_all_item_first_bits(false); }); + pane.add_button("Select All").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + set_all_item_first_bits(true); + }); + pane.add_button("Clear None").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + set_all_item_first_bits(false); + }); pane.add_section("Items"); for (const auto& [itemId, item] : itemMap) { @@ -916,7 +937,10 @@ void populate_item_flag_picker(Pane& pane) { .text = item.m_name, .isSelected = [itemId] { return dComIfGs_isItemFirstBit(static_cast(itemId)); }, }) - .on_pressed([itemId] { toggle_item_first_bit(static_cast(itemId)); }); + .on_pressed([itemId] { + mDoAud_seStartMenu(kSoundItemChange); + toggle_item_first_bit(static_cast(itemId)); + }); } } @@ -927,13 +951,19 @@ void populate_select_item_picker(Pane& pane, u8& selectItemData) { .text = "None", .isSelected = [&selectItemData] { return selectItemData == dItemNo_NONE_e; }, }) - .on_pressed([&selectItemData] { selectItemData = dItemNo_NONE_e; }); + .on_pressed([&selectItemData] { + mDoAud_seStartMenu(kSoundItemChange); + selectItemData = dItemNo_NONE_e; + }); for (int i = 0; i < 24; i++) { pane.add_button({ .text = item_label_for_slot(i), .isSelected = [i, &selectItemData] { return selectItemData == i; }, }) - .on_pressed([i, &selectItemData] { selectItemData = i; }); + .on_pressed([i, &selectItemData] { + mDoAud_seStartMenu(kSoundItemChange); + selectItemData = i; + }); } } @@ -946,6 +976,7 @@ void populate_select_clothes_picker(Pane& pane) { .isSelected = [id] { return get_player_status()->mSelectEquip[0] == id; }, }) .on_pressed([id] { + mDoAud_seStartMenu(kSoundItemChange); dMeter2Info_setCloth(id, false); daPy_getPlayerActorClass()->setClothesChange(0); }); @@ -964,7 +995,10 @@ void populate_select_equip_picker(Pane& pane, u8& equip, const std::arraygetWalletSize() == i; }, }) - .on_pressed([i] { get_player_status()->setWalletSize(i); }); + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_status()->setWalletSize(i); + }); } } @@ -1002,7 +1039,10 @@ void populate_form_picker(Pane& pane) { .text = formNames[i], .isSelected = [i] { return get_player_status()->getTransformStatus() == i; }, }) - .on_pressed([i] { get_player_status()->setTransformStatus(i); }); + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_status()->setTransformStatus(i); + }); } } @@ -1013,7 +1053,10 @@ void add_toggle_button(Pane& pane, ToggleEntry entry) { .text = entry.text, .isSelected = isSelected, }) - .on_pressed([isSelected, setSelected] { setSelected(!isSelected()); }); + .on_pressed([isSelected, setSelected] { + mDoAud_seStartMenu(kSoundItemChange); + setSelected(!isSelected()); + }); } template @@ -1126,8 +1169,14 @@ void populate_collect_clothes_picker(Pane& pane) { void populate_poe_souls_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); - pane.add_button("All 60").on_pressed([] { dComIfGs_setPohSpiritNum(60); }); - pane.add_button("Clear").on_pressed([] { dComIfGs_setPohSpiritNum(0); }); + pane.add_button("All 60").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setPohSpiritNum(60); + }); + pane.add_button("Clear").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setPohSpiritNum(0); + }); pane.add_section("Value"); pane.add_child(NumberButton::Props{ @@ -1143,10 +1192,12 @@ void populate_max_life_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); pane.add_button("3 Hearts").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); dComIfGs_setMaxLife(15); dComIfGs_setLife(12); }); pane.add_button("20 Hearts").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); dComIfGs_setMaxLife(100); dComIfGs_setLife(80); }); @@ -1257,7 +1308,10 @@ void populate_target_type_picker(Pane& pane) { .text = targetTypeNames[type], .isSelected = [type] { return get_player_config()->getAttentionType() == type; }, }) - .on_pressed([type] { get_player_config()->setAttentionType(type); }); + .on_pressed([type] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_config()->setAttentionType(type); + }); } } @@ -1269,7 +1323,10 @@ void populate_sound_mode_picker(Pane& pane) { .text = soundModeNames[mode], .isSelected = [mode] { return get_player_config()->getSound() == mode; }, }) - .on_pressed([mode] { get_player_config()->setSound(mode); }); + .on_pressed([mode] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_config()->setSound(mode); + }); } } @@ -1594,6 +1651,7 @@ EditorWindow::EditorWindow() { leftPane.add_section("Item Wheel"); leftPane.register_control(leftPane.add_button("Default All").on_pressed([&rightPane] { + mDoAud_seStartMenu(kSoundItemChange); for (int slot = 0; slot < 24; ++slot) { dComIfGs_setItem(slot, get_slot_default(slot)); } @@ -1601,6 +1659,7 @@ EditorWindow::EditorWindow() { }), rightPane, {}); leftPane.register_control(leftPane.add_button("Clear All").on_pressed([&rightPane] { + mDoAud_seStartMenu(kSoundItemChange); for (int slot = 0; slot < 24; ++slot) { dComIfGs_setItem(slot, dItemNo_NONE_e); } diff --git a/src/dusk/ui/graphics_tuner.cpp b/src/dusk/ui/graphics_tuner.cpp new file mode 100644 index 0000000000..8a11528914 --- /dev/null +++ b/src/dusk/ui/graphics_tuner.cpp @@ -0,0 +1,291 @@ +#include "graphics_tuner.hpp" + +#include "Z2AudioLib/Z2SeMgr.h" +#include "m_Do/m_Do_audio.h" + +#include +#include +#include + +#include "dusk/config.hpp" +#include "dusk/settings.h" + +#include +#include + +namespace dusk::ui { +namespace { + +const Rml::String kDocumentSource = R"RML( + + + + + +
+
+
+
+ +
+
+
+ +
+
+ +
+)RML"; + +int get_value(GraphicsOption option) { + switch (option) { + case GraphicsOption::InternalResolution: + return getSettings().game.internalResolutionScale.getValue(); + case GraphicsOption::ShadowResolution: + return getSettings().game.shadowResolutionMultiplier.getValue(); + case GraphicsOption::BloomMode: + return static_cast(getSettings().game.bloomMode.getValue()); + case GraphicsOption::BloomMultiplier: + return std::clamp( + static_cast(getSettings().game.bloomMultiplier.getValue() * 100.0f + 0.5f), 0, + 100); + } + return 0; +} + +void set_value(GraphicsOption option, int value) { + switch (option) { + case GraphicsOption::InternalResolution: + getSettings().game.internalResolutionScale.setValue(value); + VISetFrameBufferScale(static_cast(value)); + break; + case GraphicsOption::ShadowResolution: + getSettings().game.shadowResolutionMultiplier.setValue(value); + break; + case GraphicsOption::BloomMode: + getSettings().game.bloomMode.setValue(static_cast(std::clamp( + value, static_cast(BloomMode::Off), static_cast(BloomMode::Dusk)))); + break; + case GraphicsOption::BloomMultiplier: + getSettings().game.bloomMultiplier.setValue(std::clamp(value, 0, 100) / 100.0f); + break; + } + config::Save(); +} + +Rml::Element* create_stepped_carousel_root(Rml::Element* parent) { + auto* doc = parent->GetOwnerDocument(); + auto root = doc->CreateElement("div"); + root->SetClass("stepped-carousel", true); + root->SetAttribute("tabindex", "0"); + return parent->AppendChild(std::move(root)); +} + +Rml::Element* create_stepped_carousel_arrow( + Rml::Element* parent, const Rml::String& className, const Rml::String& label) { + auto* doc = parent->GetOwnerDocument(); + auto button = doc->CreateElement("button"); + button->SetClass("stepped-carousel-arrow", true); + button->SetClass(className, true); + button->SetInnerRML(label); + return parent->AppendChild(std::move(button)); +} + +void update_carousel_arrow_color(Rml::Element* arrow, bool dim) { + const Rml::Colourb& color = Rml::Colourb(255, 255, 255, dim ? 128 : 255); + arrow->SetProperty(Rml::PropertyId::Color, Rml::Property(color, Rml::Unit::COLOUR)); +} + +} // namespace + +SteppedCarousel::SteppedCarousel(Rml::Element* parent, Props props) + : Component(create_stepped_carousel_root(parent)), mProps(std::move(props)) { + mPrevElem = create_stepped_carousel_arrow(mRoot, "prev", ""); + mValueElem = append(mRoot, "div"); + mValueElem->SetClass("stepped-carousel-value", true); + mNextElem = create_stepped_carousel_arrow(mRoot, "next", ""); + + listen(mPrevElem, Rml::EventId::Click, + [this](Rml::Event&) { handle_nav_command(NavCommand::Left); }); + listen(mNextElem, Rml::EventId::Click, + [this](Rml::Event&) { handle_nav_command(NavCommand::Right); }); + listen(mRoot, Rml::EventId::Keydown, [this](Rml::Event& event) { + const auto cmd = map_nav_event(event); + if (cmd != NavCommand::None && handle_nav_command(cmd)) { + event.StopPropagation(); + } + }); +} + +bool SteppedCarousel::focus() { + return Component::focus(); +} + +void SteppedCarousel::update() { + if (mValueElem == nullptr) { + return; + } + const int value = std::clamp(mProps.getValue ? mProps.getValue() : 0, mProps.min, mProps.max); + if (mProps.formatValue) { + mValueElem->SetInnerRML(mProps.formatValue(value)); + } else { + mValueElem->SetInnerRML(std::to_string(value)); + } + + update_carousel_arrow_color(mPrevElem, value == mProps.min); + update_carousel_arrow_color(mNextElem, value == mProps.max); +} + +bool SteppedCarousel::handle_nav_command(NavCommand cmd) { + if (cmd == NavCommand::Left) { + const int value = mProps.getValue ? mProps.getValue() : 0; + apply(std::clamp(value - mProps.step, mProps.min, mProps.max)); + return true; + } + if (cmd == NavCommand::Right) { + const int value = mProps.getValue ? mProps.getValue() : 0; + apply(std::clamp(value + mProps.step, mProps.min, mProps.max)); + return true; + } + return false; +} + +void SteppedCarousel::apply(int value) { + const int nextValue = std::clamp(value, mProps.min, mProps.max); + const int currentValue = + std::clamp(mProps.getValue ? mProps.getValue() : 0, mProps.min, mProps.max); + if (nextValue == currentValue) { + return; + } + mDoAud_seStartMenu(kSoundItemChange); + if (mProps.onChange) { + mProps.onChange(nextValue); + } +} + +Rml::String format_graphics_setting_value(GraphicsOption option, int value) { + switch (option) { + case GraphicsOption::InternalResolution: { + u32 width = 0; + u32 height = 0; + AuroraGetRenderSize(&width, &height); + if (value <= 0) { + return fmt::format("Auto ({}×{})", width, height); + } else { + return fmt::format("{}× ({}×{})", value, width, height); + } + } + case GraphicsOption::ShadowResolution: + return fmt::format("{}×", value); + case GraphicsOption::BloomMode: + switch (static_cast(value)) { + case BloomMode::Off: + return "Off"; + case BloomMode::Classic: + return "Classic"; + case BloomMode::Dusk: + return "Dusk"; + } + break; + case GraphicsOption::BloomMultiplier: + return fmt::format("{}%", value); + } + return ""; +} + +GraphicsTuner::GraphicsTuner(GraphicsTunerProps props) + : Document(kDocumentSource), mOption(props.option), mValueMin(props.valueMin), + mValueMax(props.valueMax), mDefaultValue(props.defaultValue) { + if (mDocument == nullptr) { + return; + } + + if (auto* title = mDocument->GetElementById("title")) { + title->SetInnerRML(escape(props.title)); + } + if (auto* description = mDocument->GetElementById("description")) { + description->SetInnerRML(escape(props.helpText)); + } + if (auto* carouselParent = mDocument->GetElementById("carousel-container")) { + add_component(carouselParent, + SteppedCarousel::Props{ + .min = mValueMin, + .max = mValueMax, + .step = 1, + .getValue = [this] { return get_value(mOption); }, + .onChange = [this](int value) { set_value(mOption, value); }, + .formatValue = + [this](int value) { return format_graphics_setting_value(mOption, value); }, + }); + } + + if (auto* footer = mDocument->GetElementById("footer")) { + auto& returnButton = add_component + @@ -49,33 +75,549 @@ constexpr std::array kDiscFileFilters{{ {"All Files", "*"}, }}; -void file_dialog_callback(void*, const char* path, const char* error) { - auto& state = prelaunch_state(); - if (error != nullptr) { +struct DiscVerificationResult { + std::string path; + iso::DiscInfo info; + iso::ValidationError validation = iso::ValidationError::Unknown; +}; + +struct DiscVerificationTask { + explicit DiscVerificationTask(std::string discPath) : path(std::move(discPath)) { + worker = std::thread([this] { + try { + validation = iso::validate(path.c_str(), status, info); + } catch (const std::exception& e) { + PrelaunchLog.error( + "Disc verification failed with exception for '{}': {}", path, e.what()); + validation = iso::ValidationError::Unknown; + } catch (...) { + PrelaunchLog.error( + "Disc verification failed with unknown exception for '{}'", path); + validation = iso::ValidationError::Unknown; + } + done.store(true, std::memory_order_release); + }); + } + + ~DiscVerificationTask() { + status.shouldCancel.store(true, std::memory_order_relaxed); + join(); + } + + void join() { + if (worker.joinable()) { + worker.join(); + } + } + + [[nodiscard]] bool finished() const { return done.load(std::memory_order_acquire); } + + std::string path; + iso::DiscInfo info; + iso::VerificationStatus status; + iso::ValidationError validation = iso::ValidationError::Unknown; + std::atomic_bool done = false; + std::thread worker; +}; + +std::unique_ptr sDiscVerificationTask; +bool sDiscVerificationModalPushed = false; + +struct UpdateCheckTask { + UpdateCheckTask() { + worker = std::thread([this] { + try { + result = update_check::check_latest_github_release("TwilitRealm", "dusk"); + } catch (const std::exception& e) { + result = { + .status = update_check::Status::Failed, + .message = fmt::format("Update check failed with exception: {}", e.what()), + }; + } catch (...) { + result = { + .status = update_check::Status::Failed, + .message = "Update check failed with an unknown exception", + }; + } + done.store(true, std::memory_order_release); + }); + } + + ~UpdateCheckTask() { join(); } + + void join() { + if (worker.joinable()) { + worker.join(); + } + } + + [[nodiscard]] bool finished() const { return done.load(std::memory_order_acquire); } + + update_check::Result result; + std::atomic_bool done = false; + std::thread worker; +}; + +std::unique_ptr sUpdateCheckTask; +std::optional sUpdateCheckResult; + +bool verification_state_allows_launch(iso::ValidationError validation) noexcept { + return validation == iso::ValidationError::Unknown || + validation == iso::ValidationError::Success || + validation == iso::ValidationError::HashMismatch; +} + +iso::ValidationError verification_from_config(DiscVerificationState value) noexcept { + switch (value) { + case DiscVerificationState::Success: + return iso::ValidationError::Success; + case DiscVerificationState::HashMismatch: + return iso::ValidationError::HashMismatch; + default: + return iso::ValidationError::Unknown; + } +} + +DiscVerificationState verification_to_config(iso::ValidationError validation) { + switch (validation) { + case iso::ValidationError::Success: + return DiscVerificationState::Success; + case iso::ValidationError::HashMismatch: + return DiscVerificationState::HashMismatch; + default: + return DiscVerificationState::Unknown; + } +} + +std::string format_bytes(std::size_t bytes) { + constexpr double KiB = 1024.0; + constexpr double MiB = KiB * 1024.0; + constexpr double GiB = MiB * 1024.0; + if (bytes >= static_cast(GiB)) { + return fmt::format("{:.2f} GiB", static_cast(bytes) / GiB); + } + if (bytes >= static_cast(MiB)) { + return fmt::format("{:.0f} MiB", static_cast(bytes) / MiB); + } + if (bytes >= static_cast(KiB)) { + return fmt::format("{:.0f} KiB", static_cast(bytes) / KiB); + } + return fmt::format("{} B", bytes); +} + +void begin_disc_verification(std::string path) noexcept { + if (path.empty()) { return; } - if (path == nullptr) { + if (sDiscVerificationTask != nullptr) { + sDiscVerificationTask->status.shouldCancel.store(true, std::memory_order_relaxed); + sDiscVerificationTask.reset(); + } + sDiscVerificationTask = std::make_unique(std::move(path)); + sDiscVerificationModalPushed = false; +} + +std::optional take_finished_disc_verification() { + if (sDiscVerificationTask == nullptr || !sDiscVerificationTask->finished()) { + return std::nullopt; + } + DiscVerificationResult result{ + .path = sDiscVerificationTask->path, + .info = sDiscVerificationTask->info, + .validation = sDiscVerificationTask->validation, + }; + sDiscVerificationTask->join(); + sDiscVerificationTask.reset(); + sDiscVerificationModalPushed = false; + return result; +} + +void begin_update_check() { + if (!getSettings().backend.checkForUpdates.getValue()) { + return; + } + if (sUpdateCheckTask != nullptr || sUpdateCheckResult.has_value()) { + return; + } + sUpdateCheckTask = std::make_unique(); +} + +std::optional take_finished_update_check() { + if (sUpdateCheckTask == nullptr || !sUpdateCheckTask->finished()) { + return std::nullopt; + } + + sUpdateCheckTask->join(); + auto result = std::move(sUpdateCheckTask->result); + sUpdateCheckTask.reset(); + return result; +} + +std::string update_release_label(const update_check::Release& release) { + std::string_view tagName = release.tagName; + if (!tagName.empty() && tagName.front() == 'v') { + tagName.remove_prefix(1); + } + return std::string(tagName); +} + +void open_update_release() { + if (!sUpdateCheckResult.has_value() || + sUpdateCheckResult->status != update_check::Status::UpdateAvailable) + { return; } - state.selectedIsoPath = path; - state.errorString.clear(); - refresh_path_state(); - getSettings().backend.isoPath.setValue(state.selectedIsoPath); + const std::string url = sUpdateCheckResult->latest.htmlUrl; + if (url.empty()) { + PrelaunchLog.warn("Update is available, but the release did not include a download URL"); + return; + } + if (!SDL_OpenURL(url.c_str())) { + PrelaunchLog.warn("Failed to open update URL '{}': {}", url, SDL_GetError()); + } +} + +std::string get_error_msg(iso::ValidationError error) { + switch (error) { + default: + return "The selected disc image could not be validated."; + case iso::ValidationError::IOError: + return "Unable to read the selected file."; + case iso::ValidationError::InvalidImage: + return "The selected file is not a valid disc image."; + case iso::ValidationError::WrongGame: + return "The selected game is not supported by Dusk."; + case iso::ValidationError::WrongVersion: + return "Dusk currently supports GameCube USA and PAL disc images only."; + case iso::ValidationError::Canceled: + return "Disc verification was canceled. Dusk cannot guarantee the selected disc image " + "is compatible."; + case iso::ValidationError::HashMismatch: + return "The selected disc image did not pass hash verification. It may be corrupt or " + "modified."; + case iso::ValidationError::Success: + return "The selected disc image is valid."; + } +} + +void persist_disc_choice(const std::string& path, iso::ValidationError validation) { + getSettings().backend.isoPath.setValue(path); + getSettings().backend.isoVerification.setValue(verification_to_config(validation)); config::Save(); } -} // namespace +void apply_valid_disc_result( + const std::string& path, const iso::DiscInfo& info, iso::ValidationError validation) { + auto& state = prelaunch_state(); + state.configuredDiscPath = path; + state.configuredDiscCanLaunch = true; + state.configuredDiscInfo = info; + state.configuredDiscValidation = validation; + if (state.activeDiscPath.empty() || path == state.activeDiscPath) { + state.activeDiscPath = path; + state.activeDiscInfo = info; + } + persist_disc_choice(path, validation); +} + +void apply_disc_verification_result(const DiscVerificationResult& result) { + auto& state = prelaunch_state(); + + if (result.validation == iso::ValidationError::HashMismatch || + result.validation == iso::ValidationError::Canceled) + { + state.pendingDiscPath = result.path; + state.pendingDiscInfo = result.info; + state.pendingDiscValidation = result.validation; + state.errorString = escape(get_error_msg(result.validation)); + return; + } + + if (result.validation == iso::ValidationError::Success) { + apply_valid_disc_result(result.path, result.info, result.validation); + state.errorString.clear(); + state.pendingDiscPath.clear(); + state.pendingDiscInfo = {}; + state.pendingDiscValidation = iso::ValidationError::Unknown; + return; + } + + state.pendingDiscPath.clear(); + state.pendingDiscInfo = {}; + state.pendingDiscValidation = iso::ValidationError::Unknown; + state.errorString = escape(get_error_msg(result.validation)); +} + +class DiscVerificationModal : public WindowSmall { +public: + DiscVerificationModal() : WindowSmall("modal", "modal-dialog") { + auto* header = append(mDialog, "div"); + header->SetClass("modal-header", true); + + auto* title = append(header, "div"); + title->SetClass("modal-title", true); + title->SetInnerRML("Verifying disc image"); + + auto* icon = append(header, "icon"); + icon->SetClass("verifying", true); + + auto* body = append(mDialog, "div"); + body->SetClass("modal-body", true); + + auto* content = append(body, "div"); + content->SetClass("verification-progress", true); + + mFileName = append(content, "div"); + mFileName->SetClass("verification-file", true); + + mProgress = append(content, "progress"); + mProgress->SetClass("progress-ongoing", true); + mProgress->SetClass("verification-progress-bar", true); + mProgress->SetAttribute("value", 0.f); + + mDetail = append(content, "div"); + mDetail->SetClass("verification-detail", true); + + auto* actions = append(mDialog, "div"); + actions->SetClass("modal-actions", true); + mCancelButton = std::make_unique