Merge remote-tracking branch 'origin/main' into feature/autosave

# Conflicts:
#	src/dusk/imgui/ImGuiConsole.cpp
This commit is contained in:
MelonSpeedruns
2026-04-17 12:10:24 -04:00
34 changed files with 1934 additions and 199 deletions
+29 -24
View File
@@ -67,6 +67,7 @@ jobs:
run: ci/build-appimage.sh
- name: Upload artifacts
if: startsWith(github.event.ref, 'refs/tags/v')
uses: actions/upload-artifact@v7
with:
name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}}
@@ -76,24 +77,27 @@ jobs:
build-apple:
name: Build Apple (${{matrix.name}})
if: 'false' # TODO enable when CI is free
runs-on: macos-latest
runs-on: [self-hosted, macOS]
strategy:
fail-fast: false
matrix:
include:
- name: AppleClang macOS universal
- name: AppleClang macOS arm64
platform: macos
preset: x-macos-ci
artifact_name: macos-appleclang-universal
- name: AppleClang iOS arm64
platform: ios
preset: x-ios-ci
artifact_name: ios-appleclang-arm64
- name: AppleClang tvOS arm64
platform: tvos
preset: x-tvos-ci
artifact_name: tvos-appleclang-arm64
preset: x-macos-ci-arm64
artifact_name: macos-appleclang-arm64
# - name: AppleClang macOS x86_64
# platform: macos
# preset: x-macos-ci-x86_64
# artifact_name: macos-appleclang-x86_64
# - name: AppleClang iOS arm64
# platform: ios
# preset: x-ios-ci
# artifact_name: ios-appleclang-arm64
# - name: AppleClang tvOS arm64
# platform: tvos
# preset: x-tvos-ci
# artifact_name: tvos-appleclang-arm64
steps:
- uses: actions/checkout@v6
@@ -101,22 +105,15 @@ jobs:
fetch-depth: 0
submodules: recursive
- name: Update Homebrew
if: matrix.platform == 'tvos'
run: |
brew update
brew upgrade --formula
- name: Install dependencies
if: 'false'
run: brew install cmake ninja
- name: Install markupsafe
if: matrix.platform == 'tvos'
run: pip3 install --break-system-packages markupsafe
- name: Install Rust iOS target
if: matrix.platform == 'ios'
run: rustup target add aarch64-apple-ios
run: |
rustup toolchain install stable
rustup target add aarch64-apple-ios
- name: Install Rust tvOS target
if: matrix.platform == 'tvos'
@@ -124,6 +121,12 @@ jobs:
rustup toolchain install nightly
rustup target add --toolchain nightly aarch64-apple-tvos
- name: Install Rust x86_64 macOS target
if: endsWith(matrix.preset, 'x86_64')
run: |
rustup toolchain install stable
rustup target add x86_64-apple-darwin
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
@@ -134,6 +137,7 @@ jobs:
run: cmake --build --preset ${{matrix.preset}}
- name: Upload artifacts
if: startsWith(github.event.ref, 'refs/tags/v')
uses: actions/upload-artifact@v7
with:
name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}}
@@ -199,6 +203,7 @@ jobs:
run: cmake --build --preset x-windows-ci-${{matrix.preset}}
- name: Upload artifacts
if: startsWith(github.event.ref, 'refs/tags/v')
uses: actions/upload-artifact@v7
with:
name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}}
+102 -68
View File
@@ -68,6 +68,9 @@ endif()
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)
endif ()
if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
# ios.toolchain.cmake hack for SDL
set(TVOS ON)
@@ -125,19 +128,37 @@ if (DUSK_MOVIE_SUPPORT)
else ()
set(_jpeg_lib ${_jpeg_install_dir}/lib/libturbojpeg.a)
endif ()
set(_jpeg_cmake_args
-DCMAKE_INSTALL_PREFIX=${_jpeg_install_dir}
-DENABLE_SHARED=OFF
-DWITH_TURBOJPEG=ON
-DWITH_JAVA=OFF
)
if (CMAKE_TOOLCHAIN_FILE)
get_filename_component(_jpeg_toolchain_file "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
list(APPEND _jpeg_cmake_args -DCMAKE_TOOLCHAIN_FILE=${_jpeg_toolchain_file})
endif ()
set(_jpeg_passthrough_vars
CMAKE_BUILD_TYPE
CMAKE_C_COMPILER
CMAKE_C_COMPILER_LAUNCHER
CMAKE_MAKE_PROGRAM
CMAKE_MSVC_RUNTIME_LIBRARY
CMAKE_OSX_ARCHITECTURES
DEPLOYMENT_TARGET
ENABLE_ARC
ENABLE_BITCODE
PLATFORM
)
foreach(_var IN LISTS _jpeg_passthrough_vars)
if (DEFINED ${_var})
list(APPEND _jpeg_cmake_args -D${_var}=${${_var}})
endif ()
endforeach ()
ExternalProject_Add(libjpeg-turbo-ext
URL https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/3.1.0.tar.gz
URL_HASH SHA256=35fec2e1ddfb05ecf6d93e50bc57c1e54bc81c16d611ddf6eff73fff266d8285
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX=${_jpeg_install_dir}
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}
-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}
-DENABLE_SHARED=OFF
-DWITH_TURBOJPEG=ON
-DWITH_JAVA=OFF
CMAKE_ARGS ${_jpeg_cmake_args}
BUILD_BYPRODUCTS ${_jpeg_lib}
)
file(MAKE_DIRECTORY ${_jpeg_install_dir}/include)
@@ -249,7 +270,7 @@ include(files.cmake)
# TODO: version handling for res includes
set(DUSK_BUNDLE_NAME Dusk)
set(DUSK_BUNDLE_IDENTIFIER dev.decomp.dusk)
set(DUSK_BUNDLE_IDENTIFIER dev.twilitrealm.dusk)
set(DUSK_COMPANY_NAME "Twilit Realm")
set(DUSK_FILE_DESCRIPTION "Dusk")
set(DUSK_PRODUCT_NAME "Dusk")
@@ -277,7 +298,7 @@ set(GAME_INCLUDE_DIRS
${CMAKE_BINARY_DIR})
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient)
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt)
list(APPEND GAME_LIBS libzstd_static)
@@ -362,12 +383,14 @@ if (ANDROID)
target_link_options(dusk PRIVATE "-Wl,-u,SDL_main")
endif ()
add_custom_command(TARGET dusk POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/res"
"$<TARGET_FILE_DIR:dusk>/res"
COMMENT "Copying resources"
)
if (NOT APPLE)
add_custom_command(TARGET dusk POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/res"
"$<TARGET_FILE_DIR:dusk>/res"
COMMENT "Copying resources"
)
endif ()
if (WIN32)
set(DUSK_WINDOWS_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/windows)
@@ -401,44 +424,49 @@ endif ()
if (APPLE)
if (IOS)
set(DUSK_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios)
set(DUSK_INFO_PLIST ${DUSK_RESOURCE_DIR}/Info.plist.in)
file(GLOB_RECURSE DUSK_RESOURCE_FILES "${DUSK_RESOURCE_DIR}/Base.lproj/*")
endif ()
if (IOS OR TVOS)
target_sources(dusk PRIVATE ${DUSK_RESOURCE_FILES})
foreach (FILE ${DUSK_RESOURCE_FILES})
file(RELATIVE_PATH NEW_FILE "${DUSK_RESOURCE_DIR}" ${FILE})
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
endforeach ()
set_target_properties(
dusk PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME}
MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER}
MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING}
OUTPUT_NAME dusk
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES"
)
if (CMAKE_GENERATOR STREQUAL "Xcode")
set_target_properties(dusk PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${DUSK_INFO_PLIST})
elseif (DEFINED DUSK_INFO_PLIST)
set(MACOSX_BUNDLE_EXECUTABLE_NAME dusk)
set(MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER})
set(MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME})
set(MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING})
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING})
set(DUSK_GENERATED_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/dusk.Info.plist)
configure_file(${DUSK_INFO_PLIST} ${DUSK_GENERATED_INFO_PLIST})
add_custom_command(
TARGET dusk POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DUSK_GENERATED_INFO_PLIST} $<TARGET_FILE_DIR:dusk>/Info.plist
VERBATIM
)
endif ()
elseif (TVOS)
set(DUSK_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/tvos)
else ()
set(DUSK_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/macos)
endif ()
set(DUSK_INFO_PLIST ${DUSK_RESOURCE_DIR}/Info.plist.in)
file(GLOB_RECURSE DUSK_RESOURCE_FILES
"${DUSK_RESOURCE_DIR}/Assets.car"
"${DUSK_RESOURCE_DIR}/Base.lproj/*"
"${DUSK_RESOURCE_DIR}/Dusk.icns")
file(GLOB_RECURSE DUSK_APP_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/res/*")
target_sources(dusk PRIVATE ${DUSK_RESOURCE_FILES})
target_sources(dusk PRIVATE ${DUSK_APP_RESOURCE_FILES})
foreach (FILE ${DUSK_RESOURCE_FILES})
file(RELATIVE_PATH NEW_FILE "${DUSK_RESOURCE_DIR}" ${FILE})
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
endforeach ()
foreach (FILE ${DUSK_APP_RESOURCE_FILES})
file(RELATIVE_PATH NEW_FILE "${CMAKE_CURRENT_SOURCE_DIR}" ${FILE})
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
endforeach ()
set_target_properties(
dusk PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME}
MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER}
MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING}
MACOSX_BUNDLE_INFO_PLIST ${DUSK_INFO_PLIST}
OUTPUT_NAME Dusk
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES"
)
endif ()
if (IOS)
find_library(UIKIT_FRAMEWORK UIKit REQUIRED)
find_library(UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK UniformTypeIdentifiers REQUIRED)
target_sources(dusk PRIVATE src/dusk/ios/FileSelectDialog.m)
set_source_files_properties(src/dusk/ios/FileSelectDialog.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(dusk PRIVATE ${UIKIT_FRAMEWORK} ${UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK})
endif ()
include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake)
@@ -487,7 +515,9 @@ if (TARGET crashpad_handler)
endif ()
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX})
aurora_install_runtime_dlls(dusk ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
if (NOT APPLE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
endif ()
if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
set(DEBUG_FILES_LIST "")
foreach (target IN LISTS BINARY_TARGETS EXTRA_TARGETS)
@@ -509,18 +539,22 @@ if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
endif ()
list(APPEND DEBUG_FILES_LIST "${output_name}")
endforeach ()
if (WIN32)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".pdb")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND 7z a -t7z \"${CMAKE_INSTALL_PREFIX}/debug.7z\" ${DEBUG_FILES})")
elseif (APPLE)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".dSYM")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND tar acfv \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})")
elseif (UNIX)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".dbg")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND tar -I \"xz -9 -T0\" -cvf \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})")
# This is a terrible hack to only run this on CI
# until I turn this into a script or something
if(DEFINED ENV{GITHUB_ENV})
if (WIN32)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".pdb")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND 7z a -t7z \"${CMAKE_INSTALL_PREFIX}/debug.7z\" ${DEBUG_FILES})")
elseif (APPLE)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".dSYM")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND tar acfv \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})")
elseif (UNIX)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".dbg")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
install(CODE "execute_process(WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\" COMMAND tar -I \"xz -9 -T0\" -cvf \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})")
endif ()
endif ()
endif ()
foreach (target IN LISTS BINARY_TARGETS)
+61 -11
View File
@@ -380,7 +380,40 @@
"inherits": [
"macos-default-relwithdebinfo",
"ci"
]
],
"cacheVariables": {
"AURORA_DAWN_PROVIDER": "vendor",
"AURORA_NOD_PROVIDER": "vendor",
"CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": {
"type": "BOOL",
"value": true
},
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew",
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
}
},
{
"name": "x-macos-ci-arm64",
"inherits": [
"x-macos-ci"
],
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "x-macos-ci-x86_64",
"inherits": [
"x-macos-ci"
],
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "x86_64",
"Rust_CARGO_TARGET": "x86_64-apple-darwin"
}
},
{
"name": "x-ios-ci",
@@ -389,7 +422,11 @@
],
"cacheVariables": {
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
}
},
{
@@ -399,7 +436,11 @@
],
"cacheVariables": {
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
}
},
{
@@ -556,10 +597,19 @@
]
},
{
"name": "x-macos-ci",
"configurePreset": "x-macos-ci",
"description": "(Internal) macOS CI",
"displayName": "(Internal) macOS CI",
"name": "x-macos-ci-arm64",
"configurePreset": "x-macos-ci-arm64",
"description": "(Internal) macOS CI arm64",
"displayName": "(Internal) macOS CI arm64",
"targets": [
"install"
]
},
{
"name": "x-macos-ci-x86_64",
"configurePreset": "x-macos-ci-x86_64",
"description": "(Internal) macOS CI x86_64",
"displayName": "(Internal) macOS CI x86_64",
"targets": [
"install"
]
@@ -567,8 +617,8 @@
{
"name": "x-ios-ci",
"configurePreset": "x-ios-ci",
"description": "(Internal) iOS CI",
"displayName": "(Internal) iOS CI",
"description": "(Internal) iOS CI arm64",
"displayName": "(Internal) iOS CI arm64",
"targets": [
"install"
]
@@ -576,8 +626,8 @@
{
"name": "x-tvos-ci",
"configurePreset": "x-tvos-ci",
"description": "(Internal) tvOS CI",
"displayName": "(Internal) tvOS CI",
"description": "(Internal) tvOS CI arm64",
"displayName": "(Internal) tvOS CI arm64",
"targets": [
"install"
]
+1 -1
+2
View File
@@ -1342,6 +1342,8 @@ set(DUSK_FILES
src/dusk/endian.cpp
src/dusk/extras.c
src/dusk/extras.cpp
src/dusk/file_select.cpp
src/dusk/file_select.hpp
src/dusk/frame_interpolation.cpp
src/dusk/globals.cpp
src/dusk/gyro.cpp
+18 -2
View File
@@ -125,8 +125,15 @@ public:
#if TARGET_PC
static f32 hudAspectScaleDown;
static f32 hudAspectScaleUp;
static f32 ScaleHUDXLeft(f32 baseX) { return getMinXF() + baseX; }
static f32 ScaleHUDXRight(f32 baseX) { return -getMinXF() + baseX; }
static void updateSafeAreaBounds();
static f32 getSafeMinXF() { return m_safeMinXF; }
static f32 getSafeMinYF() { return m_safeMinYF; }
static f32 getSafeWidthF() { return m_safeWidthF; }
static f32 getSafeHeightF() { return m_safeHeightF; }
static f32 getSafeMaxXF() { return m_safeMaxXF; }
static f32 getSafeMaxYF() { return m_safeMaxYF; }
static f32 ScaleHUDXLeft(f32 baseX) { return getSafeMinXF() + baseX; }
static f32 ScaleHUDXRight(f32 baseX) { return getSafeMaxXF() - FB_WIDTH_BASE + baseX; }
#endif
static void setBlureMtx(const Mtx m) {
@@ -369,6 +376,15 @@ public:
static int m_height;
static f32 m_heightF;
static f32 m_widthF;
#if TARGET_PC
static f32 m_safeMinXF;
static f32 m_safeMinYF;
static f32 m_safeMaxXF;
static f32 m_safeMaxYF;
static f32 m_safeWidthF;
static f32 m_safeHeightF;
#endif
#endif
};
@@ -314,10 +314,17 @@ void JStudio_JStage::TAdaptor_actor::getJSG_SRT_(JStudio::TControl const* pContr
}
void JStudio_JStage::TAdaptor_actor::TVVOutput_ANIMATION_FRAME_::operator()(
f32 param_1, JStudio::TAdaptor* adaptor) const {
f32 param_1, JStudio::TAdaptor* adaptor) const {
#if TARGET_PC
TAdaptor_actor* actor_adaptor = static_cast<TAdaptor_actor*>(adaptor);
JStage::TActor* actor = actor_adaptor->get_pJSG_();
// field_0x8 is always hardcoded to either 305 or 309
u32 idx = (field_0x8 == 305) ? actor_adaptor->field_0x130 : actor_adaptor->field_0x134;
#else
JStage::TActor* actor = static_cast<TAdaptor_actor*>(adaptor)->get_pJSG_();
// not sure what this bit is
u32 idx = *(u32*)(((uintptr_t)adaptor - 1) + field_0x8);
#endif
u8 idx_lowBytes = idx;
u8 idx_highBytes = idx >> 8;
@@ -15,7 +15,7 @@
android:allowBackup="true"
android:hardwareAccelerated="true"
android:appCategory="game"
android:icon="@android:drawable/sym_def_app_icon"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar"
android:enableOnBackInvokedCallback="false">
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -1
View File
@@ -13,7 +13,9 @@
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>mainicon.icns</string>
<string>Dusk</string>
<key>CFBundleIconName</key>
<string>Dusk</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleName</key>
+6
View File
@@ -4258,6 +4258,12 @@ int daAlink_c::createHeap() {
return 0;
}
#if TARGET_PC
// lets try to zero-initialize the arrays instead of having garbage values
std::memset(sp1C, 0, sizeof(J3DTransformInfo) * sp38);
std::memset(sp30, 0, sizeof(Quaternion) * sp38);
#endif
field_0x2060 = JKR_NEW mDoExt_MtxCalcOldFrame(sp1C, sp30);
if (field_0x2060 == NULL) {
return 0;
+119 -1
View File
@@ -12,6 +12,7 @@
#if TARGET_PC
#include "dusk/dvd_asset.hpp"
#include "dusk/frame_interpolation.h"
static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; }
static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; }
static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; }
@@ -267,6 +268,37 @@ static void* tex_d[2] = {
static char lbl_277_bss_0;
#if TARGET_PC
static void mant_build_anchor_frame(const cXyz& anchor_a, const cXyz& anchor_b, Mtx out) {
cXyz axis_x = anchor_b - anchor_a;
if (!axis_x.normalizeRS()) {
axis_x = cXyz::BaseX;
}
cXyz helper = fabsf(axis_x.y) > 0.95f ? cXyz::BaseZ : cXyz::BaseY;
cXyz axis_z = axis_x.getCrossProduct(helper);
if (!axis_z.normalizeRS()) {
axis_z = cXyz::BaseZ;
}
cXyz axis_y = axis_z.getCrossProduct(axis_x);
if (!axis_y.normalizeRS()) {
axis_y = cXyz::BaseY;
}
const cXyz center = anchor_a + ((anchor_b - anchor_a) * 0.5f);
const cXyz col[3] = { axis_x, axis_y, axis_z };
const f32 t[3] = { center.x, center.y, center.z };
for (int r = 0; r < 3; ++r) {
out[r][0] = (&col[0].x)[r];
out[r][1] = (&col[1].x)[r];
out[r][2] = (&col[2].x)[r];
out[r][3] = t[r];
}
}
#endif
void daMant_packet_c::draw() {
#if TARGET_PC
void* image = l_Egnd_mantTEX;
@@ -290,8 +322,72 @@ void daMant_packet_c::draw() {
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_F32, 0);
#if TARGET_PC
cXyz* draw_pos = &this->mNrm[0][0];
{
const u8 curr_buffer = this->field_0x74;
const cXyz* curr_pos = &this->mPos[curr_buffer][0];
const MtxP curr_frame = curr_buffer == 0 ? this->mMtx : this->mMtx2;
Mtx curr_frame_inverse;
MTXInverse(curr_frame, curr_frame_inverse);
const u8 prev_buffer = curr_buffer ^ 1;
const cXyz* prev_pos = &this->mPos[prev_buffer][0];
Mtx prev_frame_inverse;
MTXInverse(prev_buffer == 0 ? this->mMtx : this->mMtx2, prev_frame_inverse);
Mtx presented_frame;
MTXCopy(curr_frame, presented_frame);
mant_class* mant_p = reinterpret_cast<mant_class*>(reinterpret_cast<u8*>(this) - offsetof(mant_class, field_0x0570));
if (mant_p != NULL) {
b_gnd_class* parent = (b_gnd_class*)fopAcM_SearchByID(mant_p->parentActorID);
if (parent != NULL && parent->mpModelMorf != NULL) {
J3DModel* model = parent->mpModelMorf->getModel();
if (model != NULL) {
MtxP src34 = model->getAnmMtx(34);
MtxP src25 = model->getAnmMtx(25);
Mtx joint_34_scratch;
Mtx joint_25_scratch;
MtxP joint_34 = dusk::frame_interp::lookup_replacement(src34, joint_34_scratch) ? joint_34_scratch : src34;
MtxP joint_25 = dusk::frame_interp::lookup_replacement(src25, joint_25_scratch) ? joint_25_scratch : src25;
cXyz presented_anchor_a;
cXyz presented_anchor_b;
cXyz local_offset;
MTXCopy(joint_34, *calc_mtx);
local_offset.set(10.0f, 5.0f, -17.0f);
MtxPosition(&local_offset, &presented_anchor_a);
MTXCopy(joint_25, *calc_mtx);
local_offset.set(10.0f, 5.0f, 17.0f);
MtxPosition(&local_offset, &presented_anchor_b);
mant_build_anchor_frame(presented_anchor_a, presented_anchor_b, presented_frame);
}
}
}
const f32 step = dusk::frame_interp::get_interpolation_step();
for (int i = 0; i < 169; ++i) {
cXyz curr_local;
MTXMultVec(curr_frame_inverse, &curr_pos[i], &curr_local);
cXyz prev_local;
MTXMultVec(prev_frame_inverse, &prev_pos[i], &prev_local);
cXyz local = prev_local + ((curr_local - prev_local) * step);
MTXMultVec(presented_frame, &local, &draw_pos[i]);
}
}
GXSETARRAY(GX_VA_POS, draw_pos, sizeof(mNrm[0]), 12, true);
GXSETARRAY(GX_VA_NRM, &l_normal, sizeof(l_normal), 12, false);
#else
GXSETARRAY(GX_VA_POS, this->getPos(), sizeof(mPos[0]), 12, true);
GXSETARRAY(GX_VA_NRM, this->getNrm(), sizeof(mNrm[0]), 12, true);
#endif
GXSETARRAY(GX_VA_TEX0, &l_texCoord, sizeof(l_texCoord), 8, false); // TODO: set to true when converted to float literals
GXSetZCompLoc(0);
@@ -329,9 +425,14 @@ void daMant_packet_c::draw() {
GXSetCullMode(GX_CULL_BACK);
GXLoadPosMtxImm(this->mMtx, GX_PNMTX0);
Mtx MStack_54;
#if TARGET_PC
GXLoadPosMtxImm(j3dSys.getViewMtx(), GX_PNMTX0);
cMtx_inverseTranspose(j3dSys.getViewMtx(), MStack_54);
#else
GXLoadPosMtxImm(this->mMtx, GX_PNMTX0);
cMtx_inverseTranspose(this->mMtx, MStack_54);
#endif
GXLoadNrmMtxImm(MStack_54, GX_PNMTX0);
GXCallDisplayList(l_Egnd_mantDL, 0x3e0);
@@ -347,8 +448,13 @@ void daMant_packet_c::draw() {
GXSetTevKColor(GX_KCOLOR0, COMPOUND_LITERAL(GXColor){0, 0, 0, 0});
GXSetCullMode(GX_CULL_FRONT);
#if TARGET_PC
GXLoadPosMtxImm(j3dSys.getViewMtx(), GX_PNMTX0);
cMtx_inverseTranspose(j3dSys.getViewMtx(), MStack_54);
#else
GXLoadPosMtxImm(this->mMtx2, GX_PNMTX0);
cMtx_inverseTranspose(this->mMtx2, MStack_54);
#endif
GXLoadNrmMtxImm(MStack_54, GX_PNMTX0);
GXCallDisplayList(l_Egnd_mantDL, 0x3e0);
@@ -360,11 +466,13 @@ void daMant_packet_c::draw() {
static int daMant_Draw(mant_class* i_this) {
g_env_light.settingTevStruct(0, &i_this->current.pos, &i_this->tevStr);
#if !TARGET_PC
MtxTrans(0.0f, 0.0f, 0.0f, 0.0f);
cMtx_concat(j3dSys.getViewMtx(), *calc_mtx, i_this->field_0x0570.getMtx());
cMtx_concat(j3dSys.getViewMtx(), *calc_mtx, i_this->field_0x0570.getMtx2());
#endif
i_this->field_0x0570.setTevStr(&i_this->tevStr);
@@ -635,8 +743,13 @@ static void mant_v_calc(mant_class* i_this) {
}
static void mant_move(mant_class* i_this) {
#if TARGET_PC
u8 uVar1 = i_this->field_0x0570.field_0x74 ^ 1;
cXyz* pcVar5 = &i_this->field_0x0570.mPos[uVar1][0];
#else
u8 uVar1 = i_this->field_0x0570.field_0x74;
cXyz* pcVar5 = i_this->field_0x0570.getPos();
#endif
mant_v_calc(i_this);
for (int i = 0; i < 13; i++) {
for (int j = 0; j < 13; j++) {
@@ -644,7 +757,12 @@ static void mant_move(mant_class* i_this) {
}
}
#if TARGET_PC
mant_build_anchor_frame(i_this->field_0x3928[0], i_this->field_0x3928[1], uVar1 == 0 ? i_this->field_0x0570.mMtx : i_this->field_0x0570.mMtx2);
i_this->field_0x0570.field_0x74 = uVar1;
#else
DCStoreRangeNoSync(i_this->field_0x0570.getPos(), 0x7ec);
#endif
}
static int mant_cut_type;
+1 -1
View File
@@ -147,7 +147,7 @@ void dBrightCheck_c::modeMove() {
void dBrightCheck_c::brightCheckWide() {
// Main Canvas
mBrightCheck.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mBrightCheck.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
mBrightCheck.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
// Right Square
mBrightCheck.Scr->search(MULTI_CHAR('fuchi_1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+9 -4
View File
@@ -3776,7 +3776,7 @@ bool dFile_select_c::yesnoWakuAlpahAnm(u8 param_1) {
#if TARGET_PC
void dFile_select_c::fileSelectWide() {
mYnSel.ScrYn->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mYnSel.ScrYn->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
mYnSel.ScrYn->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
mYnSel.ScrYn->search(MULTI_CHAR('w_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mYnSel.ScrYn->search(MULTI_CHAR('f_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
@@ -3784,7 +3784,7 @@ void dFile_select_c::fileSelectWide() {
mYnSel.ScrYn->search(MULTI_CHAR('f_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
m3mSel.Scr3m->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
m3mSel.Scr3m->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
m3mSel.Scr3m->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
m3mSel.Scr3m->search(MULTI_CHAR('w_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
m3mSel.Scr3m->search(MULTI_CHAR('f_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
@@ -3794,7 +3794,7 @@ void dFile_select_c::fileSelectWide() {
m3mSel.Scr3m->search(MULTI_CHAR('f_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
fileSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
fileSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
fileSel.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
fileSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
fileSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
@@ -5584,7 +5584,13 @@ void dFile_select3D_c::createMirrorModel() {
void dFile_select3D_c::toItem3Dpos(f32 param_0, f32 param_1, f32 param_2, cXyz* param_3) {
Mtx adStack_98;
Mtx auStack_c8;
#if TARGET_PC
param_0 =
(2.0f * ((param_0 - mDoGph_gInf_c::getSafeMinXF()) / mDoGph_gInf_c::getSafeWidthF()) -
1.0f);
#else
param_0 = (2.0f * ((param_0 - mDoGph_gInf_c::getMinXF()) / mDoGph_gInf_c::getWidthF()) - 1.0f);
#endif
param_1 = (2.0f * ((param_1 - -100.0f) / FB_HEIGHT_BASE) - 1.0f);
calcViewMtx(adStack_98);
cMtx_inverse(adStack_98, auStack_c8);
@@ -5601,4 +5607,3 @@ void dFile_select3D_c::calcViewMtx(Mtx param_0) {
cXyz pos2(0.0f, 1.0f, 0.0f);
cMtx_lookAt(param_0, &pos1, &cXyz::Zero, &pos2, 0);
}
+8 -2
View File
@@ -99,7 +99,7 @@ dMenu_Collect2D_c::~dMenu_Collect2D_c() {
void dMenu_Collect2D_c::menuCollectWide() {
// Main Canvas
mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mpScreen->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
mpScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
// Pieces of Heart
mpScreen->search(MULTI_CHAR('heart_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
@@ -182,7 +182,7 @@ void dMenu_Collect2D_c::_create() {
}
#if TARGET_PC
mpScreenIcon->translate(-mDoGph_gInf_c::getMinXF(), 0.0f);
mpScreenIcon->translate(-mDoGph_gInf_c::getSafeMinXF(), 0.0f);
#endif
dPaneClass_showNullPane(mpScreenIcon);
@@ -2706,8 +2706,14 @@ void dMenu_Collect3D_c::setupItem3D(Mtx param_0) {
void dMenu_Collect3D_c::toItem3Dpos(f32 param_0, f32 param_1, f32 param_2, cXyz* param_3) {
Mtx adStack_98;
Mtx auStack_c8;
#if TARGET_PC
param_0 =
(2.0f * ((param_0 - mDoGph_gInf_c::getSafeMinXF()) / mDoGph_gInf_c::getSafeWidthF()) -
1.0f);
#else
param_0 =
(2.0f * ((param_0 - mDoGph_gInf_c::getMinXF()) / mDoGph_gInf_c::getWidthF()) - 1.0f);
#endif
param_1 = (2.0f * ((param_1 - -100.0f) / FB_HEIGHT_BASE) - 1.0f);
calcViewMtx(adStack_98);
MTXInverse(adStack_98, auStack_c8);
+1 -1
View File
@@ -2779,7 +2779,7 @@ void dMenu_save_c::_draw() {
#if TARGET_PC
void dMenu_save_c::menuSaveWide() {
mSaveSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mSaveSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f);
mSaveSel.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
mSaveSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mSaveSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+91
View File
@@ -0,0 +1,91 @@
#include "file_select.hpp"
#include <memory>
#include <SDL3/SDL_dialog.h>
#include <SDL3/SDL_error.h>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST
#define USE_IOS_DIALOG 1
#include "ios/FileSelectDialog.h"
#else
#define USE_IOS_DIALOG 0
#endif
namespace dusk {
namespace {
#if USE_IOS_DIALOG
struct IOSDialogCallbackState {
FileCallback callback;
void* userdata;
};
void onIOSDialogFinished(void* userdata, const char* path, const char* error) {
std::unique_ptr<IOSDialogCallbackState> state(static_cast<IOSDialogCallbackState*>(userdata));
if (error != nullptr) {
state->callback(state->userdata, nullptr, error);
return;
}
if (path == nullptr) {
state->callback(state->userdata, nullptr, nullptr);
return;
}
state->callback(state->userdata, path, nullptr);
}
#else
struct SDLDialogCallbackState {
FileCallback callback;
void* userdata;
};
void onSDLDialogFinished(void* userdata, const char* const* filelist, [[maybe_unused]] int filter) {
std::unique_ptr<SDLDialogCallbackState> state(static_cast<SDLDialogCallbackState*>(userdata));
if (filelist == nullptr) {
state->callback(state->userdata, nullptr, SDL_GetError());
return;
}
if (filelist[0] == nullptr) {
state->callback(state->userdata, nullptr, nullptr);
return;
}
state->callback(state->userdata, filelist[0], nullptr);
}
#endif
} // namespace
void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window,
const SDL_DialogFileFilter* filters, int nfilters, const char* default_location,
bool allow_many) {
if (callback == nullptr) {
return;
}
#if USE_IOS_DIALOG
auto state = std::make_unique<IOSDialogCallbackState>();
state->callback = callback;
state->userdata = userdata;
Dusk_iOS_ShowFileSelect(&onIOSDialogFinished, state.release(), window, filters, nfilters,
default_location, allow_many);
#else
auto state = std::make_unique<SDLDialogCallbackState>();
state->callback = callback;
state->userdata = userdata;
SDL_ShowOpenFileDialog(&onSDLDialogFinished, state.release(), window, filters, nfilters,
default_location, allow_many);
#endif
}
} // namespace dusk
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <SDL3/SDL_dialog.h>
struct SDL_Window;
namespace dusk {
using FileCallback = void (*)(void* userdata, const char* path, const char* error);
void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window,
const SDL_DialogFileFilter* filters, int nfilters, const char* default_location,
bool allow_many);
} // namespace dusk
+151 -21
View File
@@ -3,23 +3,24 @@
#include <numeric>
#include <string_view>
#include <chrono>
#include <thread>
#include "fmt/format.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui.h"
#include <imgui_internal.h>
#include "fmt/format.h"
#include "ImGuiConsole.hpp"
#include "JSystem/JUtility/JUTGamePad.h"
#include "SDL3/SDL_events.h"
#include "SDL3/SDL_mouse.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_main.h"
#include "aurora/lib/window.hpp"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/config.hpp"
#include "dusk/dusk.h"
#include "dusk/main.h"
#include "dusk/settings.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/dusk.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_main.h"
#include "tracy/Tracy.hpp"
#if _WIN32
@@ -30,6 +31,30 @@
using namespace std::string_literals;
using namespace std::string_view_literals;
namespace {
ImVec2 TouchEventToScreenPos(const SDL_TouchFingerEvent& touch) {
const AuroraWindowSize size = aurora::window::get_window_size();
return ImVec2{
touch.x * static_cast<float>(size.width),
touch.y * static_cast<float>(size.height),
};
}
ImGuiWindow* FindDragScrollWindow(ImGuiWindow* window) {
while (window != nullptr) {
const bool canScrollX = window->ScrollMax.x > 0.0f;
const bool canScrollY = window->ScrollMax.y > 0.0f;
const bool canScrollWithMouse = (window->Flags & (ImGuiWindowFlags_NoScrollWithMouse |
ImGuiWindowFlags_NoMouseInputs)) == 0;
if ((canScrollX || canScrollY) && canScrollWithMouse) {
return window;
}
window = window->ParentWindow;
}
return nullptr;
}
} // namespace
namespace dusk {
float ImGuiScale() { return 1.0f; }
@@ -208,6 +233,51 @@ namespace dusk {
ImGuiConsole::ImGuiConsole() {}
void ImGuiConsole::HandleSDLEvent(const SDL_Event& event) {
if (!IsGameLaunched) {
return;
}
switch (event.type) {
case SDL_EVENT_FINGER_DOWN:
if (!m_touchTapActive) {
m_touchTapActive = true;
m_touchTapMoved = false;
m_touchTapFingerId = event.tfinger.fingerID;
m_touchTapStartPos = TouchEventToScreenPos(event.tfinger);
}
break;
case SDL_EVENT_FINGER_MOTION:
if (m_touchTapActive && m_touchTapFingerId == event.tfinger.fingerID) {
const auto currentPos = TouchEventToScreenPos(event.tfinger);
const auto delta = currentPos - m_touchTapStartPos;
if (ImLengthSqr(delta) > 144.0f) {
m_touchTapMoved = true;
}
}
break;
case SDL_EVENT_FINGER_UP:
if (m_touchTapActive && m_touchTapFingerId == event.tfinger.fingerID) {
const bool shouldToggle =
!m_touchTapMoved && (m_isHidden || !ImGui::GetIO().WantCaptureMouse);
m_touchTapActive = false;
m_touchTapMoved = false;
if (shouldToggle) {
m_isHidden = !m_isHidden;
getSettings().backend.duskMenuOpen.setValue(!m_isHidden);
Save();
}
}
break;
case SDL_EVENT_FINGER_CANCELED:
m_touchTapActive = false;
m_touchTapMoved = false;
break;
default:
break;
}
}
void ImGuiConsole::UpdateSettings() {
getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab);
@@ -237,26 +307,31 @@ namespace dusk {
if (!dusk::IsGameLaunched) {
m_preLaunchWindow.draw();
}
m_isHidden = getSettings().backend.duskMenuOpen;
CheckMenuViewToggle(ImGuiKey_F1, m_isHidden);
m_isHidden = !getSettings().backend.duskMenuOpen;
bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden);
if (dusk::IsGameLaunched) {
if (getSettings().backend.duskMenuOpen != m_isHidden) {
m_isHidden = !getSettings().backend.duskMenuOpen;
getSettings().backend.duskMenuOpen.setValue(m_isHidden);
config::Save();
const bool menuOpen = !m_isHidden;
if (getSettings().backend.duskMenuOpen != menuOpen) {
getSettings().backend.duskMenuOpen.setValue(menuOpen);
Save();
}
}
if ((!dusk::IsGameLaunched || getSettings().backend.duskMenuOpen) && ImGui::BeginMainMenuBar()) {
if (showMenu && ImGui::BeginMainMenuBar()) {
m_menuGame.draw();
m_menuEnhancements.draw();
m_menuTools.draw();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 100.0f * ImGuiScale());
ImGuiIO& io = ImGui::GetIO();
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.2f}\n"), io.Framerate));
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();
}
@@ -267,10 +342,15 @@ namespace dusk {
}
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
ShowToast("Press F1 to toggle menu", 2.5f);
ShowToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
"Tap to toggle menu" :
"Press F1 to toggle menu",
2.5f);
m_isLaunchInitialized = true;
}
UpdateDragScroll();
m_menuGame.windowControllerConfig();
m_menuGame.windowInputViewer();
if (dusk::IsGameLaunched) {
@@ -289,8 +369,7 @@ namespace dusk {
DuskDebugPad(); // temporary, remove later
// Only show cursor when menu or any windows are open
if ((!dusk::IsGameLaunched || getSettings().backend.duskMenuOpen) || ImGui::GetIO().MetricsRenderWindows > 0)
{
if (showMenu || ImGui::GetIO().MetricsRenderWindows > 0) {
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange;
// Imgui will re-show cursor.
} else {
@@ -306,6 +385,57 @@ namespace dusk {
ShowPipelineProgress();
}
void ImGuiConsole::UpdateDragScroll() {
ImGuiContext& g = *ImGui::GetCurrentContext();
ImGuiIO& io = ImGui::GetIO();
if (io.MouseSource != ImGuiMouseSource_TouchScreen) {
m_dragScrollWindow = nullptr;
return;
}
if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
m_dragScrollWindow = nullptr;
return;
}
if (io.WantTextInput || (g.ActiveId != 0 && g.InputTextState.ID == g.ActiveId)) {
m_dragScrollWindow = nullptr;
return;
}
if (!ImGui::IsMouseDragging(ImGuiMouseButton_Left, io.MouseDragThreshold)) {
return;
}
if (m_dragScrollWindow == nullptr) {
ImGuiWindow* hoveredWindow = nullptr;
ImGuiWindow* hoveredWindowUnderMovingWindow = nullptr;
ImGui::FindHoveredWindowEx(io.MousePos, false, &hoveredWindow,
&hoveredWindowUnderMovingWindow);
m_dragScrollWindow = FindDragScrollWindow(hoveredWindow);
m_dragScrollLastMousePos = io.MousePos;
}
if (m_dragScrollWindow == nullptr) {
return;
}
const auto mouseDelta = io.MousePos - m_dragScrollLastMousePos;
m_dragScrollLastMousePos = io.MousePos;
if (mouseDelta.x != 0.0f && m_dragScrollWindow->ScrollMax.x > 0.0f) {
ImGui::SetScrollX(m_dragScrollWindow,
ImClamp(m_dragScrollWindow->Scroll.x - mouseDelta.x, 0.0f,
m_dragScrollWindow->ScrollMax.x));
}
if (mouseDelta.y != 0.0f && m_dragScrollWindow->ScrollMax.y > 0.0f) {
ImGui::SetScrollY(m_dragScrollWindow,
ImClamp(m_dragScrollWindow->Scroll.y - mouseDelta.y, 0.0f,
m_dragScrollWindow->ScrollMax.y));
}
}
bool ImGuiConsole::CheckMenuViewToggle(ImGuiKey key, bool& active) {
if (ImGui::IsKeyPressed(key)) {
active = !active;
+14 -1
View File
@@ -1,11 +1,13 @@
#ifndef DUSK_IMGUI_HPP
#define DUSK_IMGUI_HPP
#include <aurora/aurora.h>
#include <deque>
#include <string>
#include <string_view>
#include <aurora/aurora.h>
#include <SDL3/SDL_touch.h>
#include "ImGuiFirstRunPreset.hpp"
#include "ImGuiMenuEnhancements.hpp"
#include "ImGuiMenuGame.hpp"
@@ -13,10 +15,14 @@
#include "ImGuiPreLaunchWindow.hpp"
#include "imgui.h"
union SDL_Event;
struct ImGuiWindow;
namespace dusk {
class ImGuiConsole {
public:
ImGuiConsole();
void HandleSDLEvent(const SDL_Event& event);
void UpdateSettings();
void PreDraw();
void PostDraw();
@@ -36,6 +42,12 @@ private:
bool m_isHidden = true;
bool m_isLaunchInitialized = false;
bool m_touchTapActive = false;
bool m_touchTapMoved = false;
SDL_FingerID m_touchTapFingerId = 0;
ImVec2 m_touchTapStartPos = {};
ImGuiWindow* m_dragScrollWindow = nullptr;
ImVec2 m_dragScrollLastMousePos = {};
std::deque<Toast> m_toasts;
ImGuiFirstRunPreset m_firstRunPreset;
@@ -48,6 +60,7 @@ private:
void ShowToasts();
void ShowPipelineProgress();
void UpdateDragScroll();
};
extern ImGuiConsole g_imguiConsole;
+18
View File
@@ -3,12 +3,14 @@
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#include <aurora/imgui.h>
#include <cmath>
#include <cstring>
#include <fmt/format.h>
#include <string>
#include "aurora/lib/window.hpp"
#include "dusk/logging.h"
#ifdef IMGUI_ENABLE_FREETYPE
@@ -37,6 +39,20 @@ ImTextureID AddTexture(const char* assetName) {
}
return aurora_imgui_add_texture(image.width, image.height, image.data.get());
}
ImVec2 GetDisplaySafeAreaPadding() {
SDL_Window* window = aurora::window::get_sdl_window();
if (window == nullptr) {
return ImVec2(0.0f, 0.0f);
}
SDL_Rect safeRect{};
if (!SDL_GetWindowSafeArea(window, &safeRect)) {
return ImVec2(0.0f, 0.0f);
}
return ImVec2(static_cast<float>(safeRect.x), static_cast<float>(safeRect.y));
}
} // namespace
ImFont* ImGuiEngine::fontNormal;
@@ -75,6 +91,7 @@ void ImGuiEngine_Initialize(float scale) {
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
io.FontGlobalScale = scale > 0.0f ? 1.0f / scale : 1.0f;
io.ConfigWindowsMoveFromTitleBarOnly = IsMobile;
ImGuiEngine::fontNormal =
CreateFont(std::floor(18.f * scale), GetAssetPath("Inter-Regular.ttf"), "Inter Regular");
@@ -104,6 +121,7 @@ void ImGuiEngine_Initialize(float scale) {
style.PopupRounding = 7.0;
style.TabBorderSize = 1.f;
style.TabRounding = 3.f;
style.DisplaySafeAreaPadding = GetDisplaySafeAreaPadding();
auto* colors = style.Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
+6
View File
@@ -25,4 +25,10 @@ struct Image {
uint32_t height;
};
Image GetImage(const std::string& path);
#if (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || defined(__ANDROID__)
inline constexpr bool IsMobile = true;
#else
inline constexpr bool IsMobile = false;
#endif
} // namespace dusk
+842
View File
@@ -0,0 +1,842 @@
#ifndef DUSK_IMGUI_EVENTFLAGS_HPP
#define DUSK_IMGUI_EVENTFLAGS_HPP
#include <string>
#include <utility>
struct duskImguiEventFlagEntry {
uint8_t byteIndex;
uint8_t bitIndex;
uint16_t flagID;
std::string flagName;
std::string description;
std::string location;
};
inline duskImguiEventFlagEntry duskImguiEventFlags[] = {
{ 0x00, 0x80, 0x0080, "TEST_001", "Kakariko bridge portal warp hint", "Faron Woods" },
{ 0x00, 0x40, 0x0040, "TEST_002", "Big magma stone portal warp hint", "Death Mountain" },
{ 0x00, 0x20, 0x0020, "TEST_003", "Handed over tomato puree", "LV5 Dungeon" },
{ 0x00, 0x10, 0x0010, "TEST_004", "Handed over secret ingredient", "LV5 Dungeon" },
{ 0x00, 0x08, 0x0008, "F_0001", "Spoke to Renado after Colin returns", "Kakariko Village" },
{ 0x00, 0x04, 0x0004, "F_0002", "Lost wrestling match to elder goron for first time", "Death Mountain (room)" },
{ 0x00, 0x02, 0x0002, "F_0003", "Handed over tomato puree and left room", "LV5 Dungeon" },
{ 0x00, 0x01, 0x0001, "F_0004", "Handed over secret ingredient and left room", "LV5 Dungeon" },
{ 0x01, 0x80, 0x0180, "F_0005", "Gathered 14 Tears of Light in area 4", "Misc." },
{ 0x01, 0x40, 0x0140, "F_0006", "First conversation with Yeto in kitchen", "LV5 Dungeon" },
{ 0x01, 0x20, 0x0120, "F_0007", "Spoke to Yeta while holding cheese", "LV5 Dungeon" },
{ 0x01, 0x10, 0x0110, "F_0008", "First conversation with Fado at the farm on 1st day", "Ordon Village" },
{ 0x01, 0x08, 0x0108, "F_0009", "Approach secret entrance with Colin", "Ordon Woods" },
{ 0x01, 0x04, 0x0104, "F_0010", "First convo with Colin blocking path (forced)", "Ordon Village" },
{ 0x01, 0x02, 0x0102, "F_0011", "Fence jumping complete", "Ranch" },
{ 0x01, 0x01, 0x0101, "F_0012", "Get metal sword!", "Ordon Village" },
{ 0x02, 0x80, 0x0280, "F_0013", "2nd day - First time rampaging goat escapes", "Ordon Village" },
{ 0x02, 0x40, 0x0240, "F_0014", "sword tutorial ends", "Ordon Village" },
{ 0x02, 0x20, 0x0220, "F_0015", "Slingshot tutorial ends", "Ordon Village" },
{ 0x02, 0x10, 0x0210, "F_0016", "On 3rd day, start following Colin who is blocking path", "Ordon Village" },
{ 0x02, 0x08, 0x0208, "F_0017", "Spoke to beth right after sword tutorial", "Ordon Village" },
{ 0x02, 0x04, 0x0204, "F_0018", "Asked by Fado to jump fence", "Ranch" },
{ 0x02, 0x02, 0x0202, "F_0019", "Spoke with Ilia (Colin is there too) at the spring", "Ordon Woods" },
{ 0x02, 0x01, 0x0201, "F_0020", "First convo with Sera while shop is closed", "Ordon Village" },
{ 0x03, 0x80, 0x0380, "D_0001", "Stopped by squirrel in front of house at night", "Ordon Village" },
{ 0x03, 0x40, 0x0340, "F_0021", "2nd day: spoke with Pergie", "Ordon Village" },
{ 0x03, 0x20, 0x0320, "F_0022", "Start fence-jump on 1st day", "Ranch" },
{ 0x03, 0x10, 0x0310, "F_0023", "Called by Jaggle from below hill", "Ordon Village" },
{ 0x03, 0x08, 0x0308, "F_0024", "Spoke with Talo/Malo/Beth (before obtaining slingshot)", "Ordon Village" },
{ 0x03, 0x04, 0x0304, "F_0025", "Pass Uli's pick-up tutorial", "Ordon Village" },
{ 0x03, 0x02, 0x0302, "F_0026", "gave wooden sword to talo on 3rd day", "Ordon Village" },
{ 0x03, 0x01, 0x0301, "F_0027", "Uli tutorial ends (same whether pass or fail)", "Ordon Village" },
{ 0x04, 0x80, 0x0480, "F_0028", "spoke to yeta while holding pumpkin", "LV5 Dungeon" },
{ 0x04, 0x40, 0x0440, "F_0029", "2nd day - refused sword tutorial", "Ordon Village" },
{ 0x04, 0x20, 0x0420, "F_0030", "before sword tutorial - first conversation with Beth", "Ordon Village" },
{ 0x04, 0x10, 0x0410, "F_0031", "2nd day - Spoke to Uli bfore finding basket", "Ordon Village" },
{ 0x04, 0x08, 0x0408, "F_0032", "3rd day - First convo with fado (before forced goat chase)", "Ranch" },
{ 0x04, 0x04, 0x0404, "F_0033", "First day - spoke with Uli", "Ordon Village" },
{ 0x04, 0x02, 0x0402, "M_006", "3rd day - finished chasing goats, speak to Fado in free state", "Ranch" },
{ 0x04, 0x01, 0x0401, "M_007", "first conversation with Shad in basement (about the words of opening)", "Kakariko Village" },
{ 0x05, 0x80, 0x0580, "M_008", "cutscene - attacked by monsters at Ordon spring", "Kawagoe Cutscene" },
{ 0x05, 0x40, 0x0540, "M_009", "[cutscene: 6B] Prison escape - Midna rides on back", "Kawagoe Cutscene" },
{ 0x05, 0x20, 0x0520, "M_010", "[cutscene: 6A] Midna appears in the prison", "Kawagoe Cutscene" },
{ 0x05, 0x10, 0x0510, "M_011", "Midna removes wolf's chains in prison", "Inside Hyrule Castle" },
{ 0x05, 0x08, 0x0508, "M_012", "[cutscene: 7] Meet Princess Zelda at castle", "Kawagoe Cutscene" },
{ 0x05, 0x04, 0x0504, "M_013", "First heard about Twilight gate from Midna", "Misc." },
{ 0x05, 0x02, 0x0502, "M_014", "[cutscene: 8] First warped from castle by Midna", "Kawagoe Cutscene" },
{ 0x05, 0x01, 0x0501, "M_015", "Can use Midna's B charge attack", "Faron Woods" },
{ 0x06, 0x80, 0x0680, "M_016", "[cutscene: 9] Ordon village spirit appears", "Kawagoe Cutscene" },
{ 0x06, 0x40, 0x0640, "M_017", "[cutscene: 10] Dark Hyrule Forest - Midna again", "Kawagoe Cutscene" },
{ 0x06, 0x20, 0x0620, "M_018", "Brought Kakariko bridge back to original location", "main event" },
{ 0x06, 0x10, 0x0610, "M_019", "[cutscene: 11] forest spirit revived - Hero's birth", "Kawagoe Cutscene" },
{ 0x06, 0x08, 0x0608, "M_020", "[cutscene: ] Colin kidnapped : ON once watched", "Kawagoe Cutscene" },
{ 0x06, 0x04, 0x0604, "M_021", "First portal warp", "main event" },
{ 0x06, 0x02, 0x0602, "M_022", "LV1 dungeon clear (Midna creates warp hole)", "LV1 Dungeon" },
{ 0x06, 0x01, 0x0601, "M_023", "Epona rescued flag", "main event" },
{ 0x07, 0x80, 0x0780, "M_024", "[cutscene: 16] take back Colin", "Kawagoe Cutscene" },
{ 0x07, 0x40, 0x0740, "M_025", "First wresting match against fat (elder) goron", "Death Mountain (room)" },
{ 0x07, 0x20, 0x0720, "M_026", "Reunion with Bo (Watched cutscene before wrestle match)", "Ordon Village" },
{ 0x07, 0x10, 0x0710, "M_027", "[cutscene: 13] kids in the church (beast eyes)", "Kawagoe Cutscene" },
{ 0x07, 0x08, 0x0708, "M_028", "[cutscene: 14] restore mountain spirit - Reuinion with Colin et al.", "Kawagoe Cutscene" },
{ 0x07, 0x04, 0x0704, "M_029", "Win wrestle match against Gor Coron", "Death Mountain (room)" },
{ 0x07, 0x02, 0x0702, "M_030", "First conversation with Gor Coron", "Death Mountain (room)" },
{ 0x07, 0x01, 0x0701, "M_031", "LV2 dungeon clear", "LV2 Dungeon" },
{ 0x08, 0x80, 0x0880, "M_032", "Melted Zora river ice with magma rock", "main event" },
{ 0x08, 0x40, 0x0840, "M_033", "Start carriage guarding game", "main event" },
{ 0x08, 0x20, 0x0820, "M_034", "[cutscene: 19] Reunion with Ilia LV3", "Kawagoe Cutscene" },
{ 0x08, 0x10, 0x0810, "M_035", "[cutscene: 35] after carriage guarding event", "Kawagoe Cutscene" },
{ 0x08, 0x08, 0x0808, "M_036", "Begin carriage guarding (after joust revenge)", "main event" },
{ 0x08, 0x04, 0x0804, "M_037", "Got Zora armor from Zora queen", "Kakariko Village" },
{ 0x08, 0x02, 0x0802, "M_038", "[bow and arrow game] listen to hawkeye hint", "Kakariko Village" },
{ 0x08, 0x01, 0x0801, "M_039", "[Bow and arrow game] First time talking to Talo", "Kakariko Village" },
{ 0x09, 0x80, 0x0980, "M_040", "[bow and arrow game] Spoke to Talo after completing", "Kakariko Village" },
{ 0x09, 0x40, 0x0940, "M_041", "[Bow and Arrow game] First attempt", "Kakariko Village" },
{ 0x09, 0x20, 0x0920, "M_042", "[Bow and Arrow game] clear", "Kakariko Village" },
{ 0x09, 0x10, 0x0910, "M_043", "[Bow and Arrow game] Complete using Hawkeye", "Kakariko Village" },
{ 0x09, 0x08, 0x0908, "M_044", "[Barnes Bomb Shop] Bought premium pack", "Kakariko Village" },
{ 0x09, 0x04, 0x0904, "M_045", "LV3 Dungeon clear", "LV3 Dungeon" },
{ 0x09, 0x02, 0x0902, "M_046", "[Iza river descent] Get advice about boulder blocking river", "Zora's River" },
{ 0x09, 0x01, 0x0901, "M_047", "Iza Twilight - Talked after defeating shadow bugs", "Zora's River" },
{ 0x0A, 0x80, 0x0A80, "M_048", "Ran away while clearing rubble at hut", "Zora's River" },
{ 0x0A, 0x40, 0x0A40, "M_049", "Threw first rolling goron at death mountain", "Death Mountain" },
{ 0x0A, 0x20, 0x0A20, "M_050", "Joust bridge disappears", "main event" },
{ 0x0A, 0x10, 0x0A10, "M_051", "Shadow Kargorok (?) (Large) event complete (Horse grass appears in various places)", "main event" },
{ 0x0A, 0x08, 0x0A08, "M_052", "Horseback battle clear", "main event" },
{ 0x0A, 0x04, 0x0A04, "M_053", "Horseback battle cutscene", "main event" },
{ 0x0A, 0x02, 0x0A02, "M_054", "Joust / one-on-one battle cutscene", "main event" },
{ 0x0A, 0x01, 0x0A01, "M_055", "Did damage at least once during joust/one-on-one battle", "main event" },
{ 0x0B, 0x80, 0x0B80, "M_056", "Ignored Iza's concerns", "Ring field" },
{ 0x0B, 0x40, 0x0B40, "M_057", "View boar cutscene after defeating King Bulblin", "Desert" },
{ 0x0B, 0x20, 0x0B20, "M_058", "First time meeting Yeta (forced converation)", "LV5 Dungeon" },
{ 0x0B, 0x10, 0x0B10, "M_059", "received map from Yeta", "LV5 Dungeon" },
{ 0x0B, 0x08, 0x0B08, "M_060", "[Iza river descent] ", "Zora's River" },
{ 0x0B, 0x04, 0x0B04, "M_061", "[Iza river descent] Got explanation for clearing rubble 1 time", "Zora's River" },
{ 0x0B, 0x02, 0x0B02, "M_062", "[Iza] Says thanks after night stalker battle", "Zora's River" },
{ 0x0B, 0x01, 0x0B01, "M_063", "[Iza river descent] Finish job (First time descending river)", "Zora's River" },
{ 0x0C, 0x80, 0x0C80, "M_064", "Water returns to Hylia Lake (spoke with Queen Rutela)", "Zora's Domain" },
{ 0x0C, 0x40, 0x0C40, "M_065", "Spoke with Faron spirit after clearing LV1 dungeon", "Faron Woods" },
//{ 0x0C, 0x20, 0x0C20, "M_066", "N/A", "N/A" },
{ 0x0C, 0x10, 0x0C10, "M_067", "Midna riding / not riding (ON == riding)", "main event" },
{ 0x0C, 0x08, 0x0C08, "M_068", "when OFF, wolf carries sword and shield on back", "main event" },
{ 0x0C, 0x04, 0x0C04, "M_069", "First conversation with child goron shop clerk", "Kakariko Village" },
{ 0x0C, 0x02, 0x0C02, "M_070", "[cutscene: 18] Lanayru spirit restored", "Kawagoe Cutscene" },
{ 0x0C, 0x01, 0x0C01, "M_071", "[cutscene: 20] Zant appears (during Midna's desperate hour)", "Kawagoe Cutscene" },
{ 0x0D, 0x80, 0x0D80, "M_072", "Get wooden shield", "Ordon Village" },
{ 0x0D, 0x40, 0x0D40, "M_073", "Spoke with Renado after guarding carriage [0030]", "Kakariko Village" },
{ 0x0D, 0x20, 0x0D20, "M_074", "Spoke with Renado after guarding carriage [0031]", "Kakariko Village" },
{ 0x0D, 0x10, 0x0D10, "M_075", "Forced conversation with Yeta after getting bedroom key", "LV5 Dungeon" },
{ 0x0D, 0x08, 0x0D08, "M_076", "First conversation with Castle Town Malo Mart shop clerk", "Misc." },
{ 0x0D, 0x04, 0x0D04, "M_077", "Get shadow crystal (can now transform)", "main event" },
{ 0x0D, 0x02, 0x0D02, "M_078", "Spoke with frog A", "Ordon Village" },
{ 0x0D, 0x01, 0x0D01, "M_079", "Ordon village night: Heard Z Jump dialogie in Pergie's house", "Ordon Village" },
{ 0x0E, 0x80, 0x0E80, "M_080", "Spoke with brown cucco", "Ordon Village" },
{ 0x0E, 0x40, 0x0E40, "M_081", "First conversation with Goron that shoots you up (shared with everyone)", "Death Mountain" },
{ 0x0E, 0x20, 0x0E20, "M_082", "Spoke with spring Goron A", "Death Mountain" },
{ 0x0E, 0x10, 0x0E10, "M_083", "Heard Fyer's talk after water restored", "Lake Hylia" },
{ 0x0E, 0x08, 0x0E08, "M_084", "Complete sequence of shopping at Malo Mart first time", "Kakariko Village" },
{ 0x0E, 0x04, 0x0E04, "M_085", "Midna dialogue right before Boss Bug's Tear of Light appears", "Twilight Ring field" },
{ 0x0E, 0x02, 0x0E02, "M_086", "Show Boss Bug's Tear of Light on the map", "Twilight Ring field" },
{ 0x0E, 0x01, 0x0E01, "M_087", "Ilia memory event start", "Ring field" },
{ 0x0F, 0x80, 0x0F80, "M_088", "Get Renado's Letter", "Kakariko Village" },
{ 0x0F, 0x40, 0x0F40, "M_089", "First time entering doctor's office (forced conversation)", "Castle Town" },
{ 0x0F, 0x20, 0x0F20, "M_090", "Spoke to town doctor before showing receipt", "Castle Town" },
{ 0x0F, 0x10, 0x0F10, "M_091", "Buy out fundraiser amount (Malo becomes nice)", "Kakariko Village" },
{ 0x0F, 0x08, 0x0F08, "M_092", "Warped Eldin Bridge", "Ring field" },
{ 0x0F, 0x04, 0x0F04, "M_093", "First conversation with Fyer after desert's debut", "Lake Hylia" },
{ 0x0F, 0x02, 0x0F02, "M_094", "First time visiting Rizu's hut after completing river job (forced conversation)", "Zora's River" },
{ 0x0F, 0x01, 0x0F01, "M_095", "First time meeting Coro (obtain lantern)", "Faron Woods" },
{ 0x10, 0x80, 0x1080, "M_096", "3rd day: spoke with Pergie", "Ordon Village" },
{ 0x10, 0x40, 0x1040, "F_0034", "first conversation wtih Rusl", "Ordon Village" },
{ 0x10, 0x20, 0x1020, "F_0035", "F0003: Spoke to Colin while he is stopping hors (doesn't have fishing rod)", "Ordon Village" },
{ 0x10, 0x10, 0x1010, "M_001", "Opening cutscene", "Kawagoe Cutscene" },
{ 0x10, 0x08, 0x1008, "M_003", "F0003: Spoke to Colin while he is stopping hors (has fishing rod)", "Ordon Village" },
{ 0x10, 0x04, 0x1004, "F_0036", "Spoke to Jaggle using L-focus before climbing vines?", "Ordon Village" },
{ 0x10, 0x02, 0x1002, "F_0037", "Jaggle - Spoke on the hill?", "Ordon Village" },
{ 0x10, 0x01, 0x1001, "F_0038", "Opening (2nd day) cat returns home", "Ordon Village" },
{ 0x11, 0x80, 0x1180, "F_0039", "Warned by Hanch after climbing vines on 2nd day", "Ordon Village" },
{ 0x11, 0x40, 0x1140, "F_0040", "2nd day: Spoke to Jaggle after blowing on whistle", "Ordon Village" },
{ 0x11, 0x20, 0x1120, "F_0041", "Opening 2nd day - After this is turned ON Hanch is attacked by bees", "Ordon Village" },
{ 0x11, 0x10, 0x1110, "F_0042", "Spoke with Yeta right after arriving at bedroom", "LV5 Dungeon" },
{ 0x11, 0x08, 0x1108, "F_0043", "First visit after fundrasing funds drop to 200", "Kakariko Village" },
{ 0x11, 0x04, 0x1104, "F_0044", "Accepted sword tutorial first time", "Ordon Village" },
{ 0x11, 0x02, 0x1102, "F_0045", "Opening 3rd day - spoke with Uli", "Ordon Village" },
{ 0x11, 0x01, 0x1101, "F_0046", "Spoke with Sera after saving(lt;) failing(gt;) cat", "Ordon Village" },
{ 0x12, 0x80, 0x1280, "F_0047", "First visit after Ordon Village shop opens", "Ordon Village" },
{ 0x12, 0x40, 0x1240, "F_0048", "Uli's pick-up tutorial <fail>", "Ordon Village" },
{ 0x12, 0x20, 0x1220, "F_0049", "Uli's pick up tutorial <fail to throw>", "Ordon Village" },
{ 0x12, 0x10, 0x1210, "F_0050", "Saw cutscene for getting iron boots", "Ordon Village" },
{ 0x12, 0x08, 0x1208, "F_0051", "Spoke to Sera in the shop after saving cat", "Ordon Village" },
{ 0x12, 0x04, 0x1204, "F_0052", "Had 2nd conversaton with Sera before saving cat", "Ordon Village" },
{ 0x12, 0x02, 0x1202, "F_0053", "Saw night stalker appearance cutscene", "Faron Woods" },
{ 0x12, 0x01, 0x1201, "F_0054", "Lost wrestling match with elder goron while wearing iron boots", "Death Mountain" },
{ 0x13, 0x80, 0x1380, "F_0055", "Received Vessel of Light from Faron spirit", "Faron Woods" },
{ 0x13, 0x40, 0x1340, "F_0056", "Lost to elder goron 2+ times", "Death Mountain" },
{ 0x13, 0x20, 0x1320, "F_0057", "[cutscene: 17] Part with the children", "Kawagoe Cutscene" },
{ 0x13, 0x10, 0x1310, "F_0058", "Listened to voices on other side of door in Telma's shop", "Castle Town" },
{ 0x13, 0x08, 0x1308, "F_0059", "Conversation after getting spirit and tears of light (darkness cleared) <- probably unused ...", "+ Scary flag" },
{ 0x13, 0x04, 0x1304, "F_0060", "First conversation with Hozu in the World of Light", "Zora's River" },
{ 0x13, 0x02, 0x1302, "F_0061", "Heard spring goron and shopkeeper rumers after winning wrestling match against elder goron", "Death Mountain" },
{ 0x13, 0x01, 0x1301, "F_0062", "Abandoned taking Fyer's cannon after paying", "Lake Hylia" },
{ 0x14, 0x80, 0x1480, "F_0063", "Used Fyer's cannon for first time", "Lake Hylia" },
{ 0x14, 0x40, 0x1440, "F_0064", "first convo with yeta after obtaining tomato puree", "LV5 Dungeon" },
{ 0x14, 0x20, 0x1420, "F_0065", "Yeta adds last symbol onto map", "LV5 Dungeon" },
{ 0x14, 0x10, 0x1410, "F_0066", "First saw Goron cutscene on mountain path", "Death Mountain" },
{ 0x14, 0x08, 0x1408, "F_0067", "Recieved milk jar (1/2) from Sera", "Ordon Village" },
//{ 0x14, 0x04, 0x1404, "F_0068", "N/A", "N/A" },
{ 0x14, 0x02, 0x1402, "F_0069", "F0048: Thanked by Colen for clearing path", "Ordon Village" },
{ 0x14, 0x01, 0x1401, "F_0070", "Colin went deep into the woods", "Ordon Woods" },
{ 0x15, 0x80, 0x1580, "M_002", "[cutscene: 2] Met with Ilia (brings horse to spring)", "Kawagoe Cutscene" },
{ 0x15, 0x40, 0x1540, "F_0071", "Cannot warp to Lanayru", "Twilight Ring field" },
{ 0x15, 0x20, 0x1520, "F_0072", "Knocked down large beehive with hawk", "Ordon Village" },
{ 0x15, 0x10, 0x1510, "F_0073", "Attacked after charging at large beehive", "Ordon Village" },
{ 0x15, 0x08, 0x1508, "F_0074", "Hanch attacked by bees", "Ordon Village" },
{ 0x15, 0x04, 0x1504, "F_0075", "Angered Jaggle by destroying pumpkin", "Ordon Village" },
{ 0x15, 0x02, 0x1502, "F_0076", "Spoke to Hanch in lake", "Ordon Village" },
{ 0x15, 0x01, 0x1501, "F_0077", "First converstaion with Agetha inside", "Castle Town" },
{ 0x16, 0x80, 0x1680, "F_0078", "Hanch returned to land after jumping into lake", "Ordon Village" },
{ 0x16, 0x40, 0x1640, "F_0079", "2nd Day - successful knocked down rampaging mountain goat", "Ordon Village" },
{ 0x16, 0x20, 0x1620, "F_0080", "Completed all of mountain goat rampage event", "Ordon Village" },
{ 0x16, 0x10, 0x1610, "F_0081", "20 mountain goats rampaged", "Ordon Village" },
{ 0x16, 0x08, 0x1608, "F_0082", "Completed coversation with Bo after 20th mountain goat's rampage", "Ordon Village" },
{ 0x16, 0x04, 0x1604, "F_0083", "Deliver letter from Agetha", "Letter" },
{ 0x16, 0x02, 0x1602, "F_0084", "Opening days 2&3: knocked down a beehive with slingshot", "Ordon Village" },
{ 0x16, 0x01, 0x1601, "F_0085", "Rusl appears at woods entrance", "Ordon Village" },
{ 0x17, 0x80, 0x1780, "F_0086", "Spoke with Hanch after knocking down beehive with hawk", "Ordon Village" },
{ 0x17, 0x40, 0x1740, "F_0087", "Left search area after first conversation with Pergie", "Ordon Village" },
{ 0x17, 0x20, 0x1720, "F_0088", "Spoke to Beth after quitting sword tutorial", "Ordon Village" },
{ 0x17, 0x10, 0x1710, "F_0089", "Talked to village chief for first time", "Ordon Village" },
{ 0x17, 0x08, 0x1708, "F_0090", "F:1126 - South - Spoke with Agetha's stalker (before talking with Agetha inside)", "Castle Town" },
{ 0x17, 0x04, 0x1704, "F_0091", "F:1126 - South - Spoke with Agetha's stalker (after talking with Agetha inside)", "Ordon Village" },
{ 0x17, 0x02, 0x1702, "F_0092", "F:1127 - South - Spoke with the Hyrule soldier guide", "Castle Town" },
{ 0x17, 0x01, 0x1701, "F_0093", "F:1128 - South - Spoke with female clerk at vegetable stand", "Castle Town" },
{ 0x18, 0x80, 0x1880, "F_0094", "Talo went after the monkey", "Ordon Village" },
{ 0x18, 0x40, 0x1840, "F_0095", "Spoke to Fado before mountain goat rampage", "Ranch" },
{ 0x18, 0x20, 0x1820, "F_0096", "Have spoken to Bo with 1 health", "Ordon Village" },
{ 0x18, 0x10, 0x1810, "F_0097", "First conversation with dog eavesdrop hint", "Ordon Village" },
{ 0x18, 0x08, 0x1808, "F_0202", "Rusl / Wolf fails to get sword", "Ordon Village" },
{ 0x18, 0x04, 0x1804, "F_0203", "First tried to steal from unnmaned shop (Havent checked donation box)", "Shop" },
{ 0x18, 0x02, 0x1802, "F_0204", "Talked to Midna from across the bars in the sewer", "Inside Hyrule Castle" },
{ 0x18, 0x01, 0x1801, "F_0205", "Heard Rusl and Uli talking in Ordon village at night", "Ordon Village" },
{ 0x19, 0x80, 0x1980, "F_0206", "Barrier of darkness tag: tried to enter without getting sword and shield", "Ordon Woods" },
{ 0x19, 0x40, 0x1940, "F_0207", "Viewed Hanch, the Hawker cutscene", "Ordon Village" },
{ 0x19, 0x20, 0x1920, "F_0208", "Hanch leapt after being startled by wolf", "Ordon Village" },
{ 0x19, 0x10, 0x1910, "F_0209", "Escape after failing to eavesdrop to Bo and Jaggle", "Ordon Village" },
{ 0x19, 0x08, 0x1908, "F_0210", "F0004: Try to get on horse when Colin is stopping horse", "Ordon Village" },
{ 0x19, 0x04, 0x1904, "F_0211", "Successfully eavesdrop on Bo and Jaggle", "Ordon Village" },
{ 0x19, 0x02, 0x1902, "F_0212", "Conversation wtih Colin in front of Ordon springs gate", "Ordon Woods" },
{ 0x19, 0x01, 0x1901, "F_0213", "Called by spirit after NS fight at Kakariko entrance", "Kakariko Village" },
{ 0x1A, 0x80, 0x1A80, "F_0214", " First heard Midna's hint about Z", "Inside Hyrule Castle" },
{ 0x1A, 0x40, 0x1A40, "F_0215", "Spoke with cat on roof", "Ordon Village" },
{ 0x1A, 0x20, 0x1A20, "F_0216", "Spoke with Ordon village cucco B (white)", "Ordon Village" },
{ 0x1A, 0x10, 0x1A10, "F_0217", "First conversation after speaking with Coro again after clearing up twilight", "Faron Woods" },
{ 0x1A, 0x08, 0x1A08, "F_0218", "Bought jar of oil from Coro", "Faron Woods" },
{ 0x1A, 0x04, 0x1A04, "F_0219", "Heard Agetha say \"but you have some\"", "Castle Town" },
{ 0x1A, 0x02, 0x1A02, "F_0220", "First time - Talked to one of the Hyrule soldiers underneath castle in Twilight", "Inside Hyrule Castle" },
{ 0x1A, 0x01, 0x1A01, "F_0221", "Received vessel of light from spirit", "Kakariko Village" },
{ 0x1B, 0x80, 0x1B80, "F_0222", "Finished Coro ignite event", "Faron Woods" },
{ 0x1B, 0x40, 0x1B40, "F_0223", "Listened to Coro's dialogue before defeating shadow bugs", "Farron Woods inside woodcutter's shop" },
{ 0x1B, 0x20, 0x1B20, "F_0224", "Flag for lantern guide monkey cutscene", "Faron Woods" },
{ 0x1B, 0x10, 0x1B10, "F_0225", "Lanter guide monkey doesn't come out a second time", "Faron Woods" },
{ 0x1B, 0x08, 0x1B08, "F_0226", "Get lantern back from monkey", "Faron Woods" },
{ 0x1B, 0x04, 0x1B04, "F_0227", "Try to leave mist woods after lantern taken", "Faron Woods" },
{ 0x1B, 0x02, 0x1B02, "F_0228", "Listened to goron's complaint at the entrance to twilight mountain path", "Death Mountain" },
{ 0x1B, 0x01, 0x1B01, "F_0229", "Try to leave the mist woods area without lantern (after returning monkey)", "Faron Woods" },
{ 0x1C, 0x80, 0x1C80, "F_0230", "Twilight - listened to goron B's complaints", "Death Mountain" },
{ 0x1C, 0x40, 0x1C40, "F_0231", "Did first wrestle match with Bo", "Ordon Village" },
{ 0x1C, 0x20, 0x1C20, "F_0232", "get iron boots from Bo", "Ordon Village" },
{ 0x1C, 0x10, 0x1C10, "F_0233", "Win practice battle with Bo (before getting boots)", "Ordon Village" },
{ 0x1C, 0x08, 0x1C08, "F_234", "Attacked by Trill", "Faron Woods" },
{ 0x1C, 0x04, 0x1C04, "F_0235", "Giant game clear", "Sacred Grove" },
{ 0x1C, 0x02, 0x1C02, "F_0236", "Make Midna angry after doing wrong destination for Kakariko bridge warp", "Misc." },
{ 0x1C, 0x01, 0x1C01, "F_0237", "Entered Malo Mart (chatted with Malo)", "Kakariko Village" },
{ 0x1D, 0x80, 0x1D80, "F_0238", "Destroyed all puppets (monkey girl event before sacred grove)", "Faron Woods" },
{ 0x1D, 0x40, 0x1D40, "T_0239", "Spoke with Fyer (start dark carge)", "Lake Hylia" },
{ 0x1D, 0x20, 0x1D20, "F_0240", "Speak with Barnes while heas making bombs", "Kakariko Village" },
{ 0x1D, 0x10, 0x1D10, "F_0241", "First conversation with Barnes after bomb shop open", "Kakariko Village" },
{ 0x1D, 0x08, 0x1D08, "F_0242", "Spoke with the dazed chief goron after Fyrus battle", "LV2 Dungeon" },
{ 0x1D, 0x04, 0x1D04, "F_0243", "Speak with Luda wiping Colin's sweat", "Kakariko Village" },
{ 0x1D, 0x02, 0x1D02, "F_0244", "Speak to Talo while COlin is wiping sweat", "Kakariko Village" },
{ 0x1D, 0x01, 0x1D01, "MAP_VISIBLE", "Area map show/hide", "2D Map" },
{ 0x1E, 0x80, 0x1E80, "F_0246", "Malo Mart fundraiser (and carying spring water) start", "Kakariko Village" },
{ 0x1E, 0x40, 0x1E40, "F_0247", "First conversation with Malo (shopping complete) after helping Malo Mart fundraiser", "Kakariko Village" },
{ 0x1E, 0x20, 0x1E20, "F_0248", "Speak with Coro after clearing Forest Temple", "Faron Woods" },
{ 0x1E, 0x10, 0x1E10, "F_0249", "Try to leave after paying for Flight by Fowl (first time only)", "Lake Hylia" },
{ 0x1E, 0x08, 0x1E08, "F_0250", "[cutscene: 21] reunion with Zelda / Midna revived (Ganon wall appears)", "Kawagoe Cutscene" },
{ 0x1E, 0x04, 0x1E04, "F_0251", "Speak again with Sera before finding kids (forced conversation)", "Ordon Village" },
{ 0x1E, 0x02, 0x1E02, "F_0252", "Spoke to Sera while kids are missing (dealing with shop)", "Ordon Village" },
{ 0x1E, 0x01, 0x1E01, "F_0253", "Stuck to magnet lift at least once", "For E3 2006" },
{ 0x1F, 0x80, 0x1F80, "F_0254", "Hit boss's weak spot at least once", "For E3 2006" },
{ 0x1F, 0x40, 0x1F40, "F_0255", "Boss exhausted (grabbing chains) only on during state (normally off)", "For E3 2006" },
{ 0x1F, 0x20, 0x1F20, "F_0256", "Knocked down boss at leased once", "For E3 2006" },
{ 0x1F, 0x10, 0x1F10, "F_0257", "Only ON when boss is in hollow state (normally off, changes in real time)", "For E3 2006" },
{ 0x1F, 0x08, 0x1F08, "F_0258", "Heard hint right above heavy switch", "For E3 2006" },
{ 0x1F, 0x04, 0x1F04, "F_0259", "Heard first forced dialogue from Midna", "For E3 2006" },
{ 0x1F, 0x02, 0x1F02, "F_0260", "First time speaking to Resistance Rusl", "Castle Town" },
{ 0x1F, 0x01, 0x1F01, "F_0261", "First conversation with Resistance Auru (made fun of)", "Castle Town" },
{ 0x20, 0x80, 0x2080, "F_0262", "First conversation with Resistance Shad (made fun of)", "Castle Town" },
{ 0x20, 0x40, 0x2040, "F_0263", "First conversation with Resistance Ashei (3) (made fun of)", "Castle Town" },
{ 0x20, 0x20, 0x2020, "F_0264", "get master sword", "Kawagoe Cutscene" },
{ 0x20, 0x10, 0x2010, "F_0265", "LV4 dungeon clear", "LV4 Dungeon," },
{ 0x20, 0x08, 0x2008, "F_0266", "LV5 dungeon clear", "LV5 Dungeon" },
{ 0x20, 0x04, 0x2004, "F_0267", "LV6 dungeon clear", "LV6 Dungeon" },
{ 0x20, 0x02, 0x2002, "F_0268", "LV7 dungeon clear", "LV7 dungeon" },
{ 0x20, 0x01, 0x2001, "F_0269", "First conversation with Telma after getting master sword", "Castle Town" },
{ 0x21, 0x80, 0x2180, "F_0270", "Gave Renado's letter to Telma", "Castle Town" },
{ 0x21, 0x40, 0x2140, "F_0271", "Talked with Telma again after the other conversation after getting master sword", "Castle Town" },
{ 0x21, 0x20, 0x2120, "F_0272", "Saw Auru's location on map", "Castle Town" },
{ 0x21, 0x10, 0x2110, "F_0273", "Saw Ashei's location on map", "Castle Town" },
{ 0x21, 0x08, 0x2108, "F_0274", "Saw Rusl's location on map", "Castle Town" },
{ 0x21, 0x04, 0x2104, "F_0275", "Saw Shad's location on map", "Castle Town" },
{ 0x21, 0x02, 0x2102, "F_0276", "Heard conversation with Louise about stolen wood carving", "Castle Town" },
{ 0x21, 0x01, 0x2101, "F_0277", "Hear conversation between Telma and Ilia in Telma's shop (Twilight)", "Castle Town" },
{ 0x22, 0x80, 0x2280, "F_0278", "Received pendant from Impaz", "Hidden Village" },
{ 0x22, 0x40, 0x2240, "F_0279", "Saw cutscene about scent of kids from wooden sword", "Ring field" },
{ 0x22, 0x20, 0x2220, "F_0280", "Saw cutscene about Ilia's scent from pouch", "Ring field" },
{ 0x22, 0x10, 0x2210, "F_0281", "Malo Mart opens in Castle Town", "Shop" },
{ 0x22, 0x08, 0x2208, "F_282", "First conversation with Yeto at peak after LV5 dungeon clear", "Snowpeak mountain" },
{ 0x22, 0x04, 0x2204, "F_283", "Get wood carving", "Ring field" },
{ 0x22, 0x02, 0x2202, "F_284", "Already have a score recorded for Plumm's game", "Lake Hylia" },
{ 0x22, 0x01, 0x2201, "F_285", "First conversation with Plumm as wolf", "Lake Hylia" },
{ 0x23, 0x80, 0x2380, "F_286", "Cleared Plumm's attraction (get heart piece)", "Lake Hylia" },
{ 0x23, 0x40, 0x2340, "F_287", "Handed wood carving to Ilia", "Kakariko Village" },
{ 0x23, 0x20, 0x2320, "F_288", "[cutscene: ] Ilia gets her memories back", "Kawagoe Cutscene" },
{ 0x23, 0x10, 0x2310, "F_289", "Heard conversation about entering double clawshot game LV1", "Castle Town" },
{ 0x23, 0x08, 0x2308, "F_290", "Double clawshot game LV1 cleared", "Castle Town" },
{ 0x23, 0x04, 0x2304, "M_097", "Can use magic", "main event" },
{ 0x23, 0x02, 0x2302, "F_0292", "Star Game 2 first experience", "Castle Town" },
{ 0x23, 0x01, 0x2301, "F_0293", "Star Game 2 cleared", "Castle Town" },
{ 0x24, 0x80, 0x2480, "F_0294", "Shaman - Prayers reached the heavens (heart piece obtained complete)", "Castle Town" },
{ 0x24, 0x40, 0x2440, "F_0295", "Watched meeting Louise event when sneaking into Telma's shop (wolf)", "Castle Town" },
{ 0x24, 0x20, 0x2420, "F_0296", "Spoke with Louise after kicked being kicked out of Telma's shop", "Castle Town" },
{ 0x24, 0x10, 0x2410, "F_0297", "First spoke with Chudley store clerk", "Castle Town" },
{ 0x24, 0x08, 0x2408, "F_0298", "Spoke with Auru after completing LV4 dungeon", "Castle Town" },
{ 0x24, 0x04, 0x2404, "F_0299", "Spoke with Shad at Telma's shop after getting master sword", "Castle Town" },
{ 0x24, 0x02, 0x2402, "F_0300", "Heard about Sky People from Shad at Telma's shop", "Castle Town" },
{ 0x24, 0x01, 0x2401, "F_0301", "Spoke with Shad after LV7 dungeon clear", "Castle Town" },
{ 0x25, 0x80, 0x2580, "F_0302", "Saw cutscene of Shad casting spells underneat Kakariko Village", "Kakariko Village" },
{ 0x25, 0x40, 0x2540, "F_0303", "Saw Shad's spell 2", "Kakariko Village" },
{ 0x25, 0x20, 0x2520, "F_0304", "Spoke with Auru at Hylia Lake", "Lake Hylia" },
{ 0x25, 0x10, 0x2510, "F_0305", "Heard about Fyer from Auru (desert cannon ON)", "Lake Hylia" },
{ 0x25, 0x08, 0x2508, "F_0306", "Used Fyer's cannon to go to desert", "Desert" },
{ 0x25, 0x04, 0x2504, "F_0307", "Spoke with Yeto at top of mountain as wolf", "Snowpeak mountain" },
{ 0x25, 0x02, 0x2502, "F_0308", "Watched first meeting event with Yeto at top of mountain (human)", "Snowpeak mountain" },
{ 0x25, 0x01, 0x2501, "F_0309", "First conversation with Agetha inside (gives golden bug capture quest)", "Castle Town" },
{ 0x26, 0x80, 0x2680, "F_0310", "Hand Auru's note to Fyer", "Lake Hylia" },
{ 0x26, 0x40, 0x2640, "F_0311", "LV8 Dungeon use 1", "LV8 Dungeon" },
{ 0x26, 0x20, 0x2620, "F_0312", "LV8 Dungeon use 2", "LV8 Dungeon" },
{ 0x26, 0x10, 0x2610, "F_0313", "LV8 Dungeon use 3", "LV8 Dungeon" },
{ 0x26, 0x08, 0x2608, "F_0314", "LV8 Dungeon use 4", "LV8 Dungeon" },
{ 0x26, 0x04, 0x2604, "F_0315", "LV8 Dungeon use 5", "LV8 Dungeon" },
{ 0x26, 0x02, 0x2602, "F_0316", "LV8 Dungeon use 6", "LV8 Dungeon" },
{ 0x26, 0x01, 0x2601, "F_0317", "LV8 Dungeon use 7", "LV8 Dungeon" },
{ 0x27, 0x80, 0x2780, "F_0318", "LV8 Dungeon use 8", "LV8 Dungeon" },
{ 0x27, 0x40, 0x2740, "F_0319", "LV8 Dungeon use 9", "LV8 Dungeon" },
{ 0x27, 0x20, 0x2720, "F_0320", "LV8 Dungeon use 10", "LV8 Dungeon" },
{ 0x27, 0x10, 0x2710, "F_0321", "Showed reciept to town doctor", "Castle Town" },
{ 0x27, 0x08, 0x2708, "F_0322", "Flow 0010 Spoke with Zora in Zora armor", "Zora's Domain" },
{ 0x27, 0x04, 0x2704, "F_0323", "Flow 0020 Spoke with Zora", "Zora's Domain" },
{ 0x27, 0x02, 0x2702, "F_0324", "Flow 0023 Speak with Zora before blowing up magma rock", "Zora's Domain" },
{ 0x27, 0x01, 0x2701, "F_0325", "Flow 0023 Speak with Zora after blowing up magma rock", "Zora's Domain" },
{ 0x28, 0x80, 0x2880, "F_0326", "LV8 mini-boss defeated flag", "LV8 Dungeon" },
{ 0x28, 0x40, 0x2840, "F_0327", "First time warped by Ooccoo Sr.", "Misc." },
{ 0x28, 0x20, 0x2820, "F_0328", "Talk again with Jaggle after finding kids", "Ordon Village" },
{ 0x28, 0x10, 0x2810, "F_0329", "Jaggle brings up shield", "Ordon Village" },
{ 0x28, 0x08, 0x2808, "F_0330", "Meet again with Uli for the first time (first forced conversation)", "Ordon Village" },
{ 0x28, 0x04, 0x2804, "F_0331", "Meet again and talk with Uli after finding kids (1st time)", "Ordon Village" },
{ 0x28, 0x02, 0x2802, "F_0332", "Meet again and talk with Uli after finding kids (2nd time)", "Ordon Village" },
{ 0x28, 0x01, 0x2801, "F_0333", "Uli brings up the sword", "Ordon Village" },
{ 0x29, 0x80, 0x2980, "F_0334", "Spoke with Ashei at Telma's shop after getting master sword", "Castle Town" },
{ 0x29, 0x40, 0x2940, "F_0335", "Obtained scribble from Ashei at mountain pass", "Snowpeak mountain" },
{ 0x29, 0x20, 0x2920, "F_0336", "Blew up molten rock bomb ", "Zora's Domain" },
{ 0x29, 0x10, 0x2910, "F_0337", "Listened to old ladies A/B conversation (wolf / Ralis hint FLOW104)", "Castle Town" },
{ 0x29, 0x08, 0x2908, "F_0338", "Obtained 1 secret techinques - Shield attack", "Secret techniques" },
{ 0x29, 0x04, 0x2904, "F_0339", "Obtained 2 secret techinques", "Secret techniques" },
{ 0x29, 0x02, 0x2902, "F_0340", "Obtained 3 secret techinques", "Secret techniques" },
{ 0x29, 0x01, 0x2901, "F_0341", "Obtained 4 secret techinques", "Secret techniques" },
{ 0x2A, 0x80, 0x2A80, "F_0342", "Obtained 5 secret techinques", "Secret techniques" },
{ 0x2A, 0x40, 0x2A40, "F_0343", "Obtained 6 secret techinques", "Secret techniques" },
{ 0x2A, 0x20, 0x2A20, "F_0344", "Obtained 7 secret techinques", "Secret techniques" },
{ 0x2A, 0x10, 0x2A10, "F_0345", "Opening 2nd day - lit Coro's pot", "Faron Woods" },
{ 0x2A, 0x08, 0x2A08, "F_0346", "Turned down Auru's request to go to the desert", "Lake Hylia" },
{ 0x2A, 0x04, 0x2A04, "F_0347", "Spoke with Ashei after LV5 dungeon clear ", "Castle Town" },
{ 0x2A, 0x02, 0x2A02, "F_0348", "Spoke with Zora soldier in front of LV3 dungeon (before bombing entrance)", "Lake Hylia" },
{ 0x2A, 0x01, 0x2A01, "F_0349", "Spoke with Zora soldier in front of LV3 dungeon (after bombing entrance)", "Lake Hylia" },
{ 0x2B, 0x80, 0x2B80, "F_0350", "Showed wood carving doll to Renado", "Kakariko Village" },
{ 0x2B, 0x40, 0x2B40, "F_0351", "First meeting with Agether outside (haven't met inside yet) : gives bug even quest", "Ring field" },
{ 0x2B, 0x20, 0x2B20, "F_0352", "Second conversation with Agetha (outside)", "Ring field" },
{ 0x2B, 0x10, 0x2B10, "F_0353", "Conversation with lady complaining about Chudley's shop", "Castle Town" },
{ 0x2B, 0x08, 0x2B08, "F_0354", "[cutscene] Mirror complete", "Kawagoe Cutscene" },
{ 0x2B, 0x04, 0x2B04, "F_0355", "Showed wood carving to village doctor", "Castle Town" },
{ 0x2B, 0x02, 0x2B02, "F_0356", "Spoke with village doctor after Ilia's memories restored", "Castle Town" },
{ 0x2B, 0x01, 0x2B01, "F_0357", "Spoke with Telma's guardian goron after she came back", "Death Mountain" },
{ 0x2C, 0x80, 0x2C80, "F_0358", "Spoke with Telma after Ilia's memories restored", "Castle Town" },
{ 0x2C, 0x40, 0x2C40, "F_0359", "Spoke with Ilia while she's watching over Ralis", "Kakariko Village" },
{ 0x2C, 0x20, 0x2C20, "F_0360", "Conversation with fortune teller as wolf", "Castle Town" },
{ 0x2C, 0x10, 0x2C10, "F_0361", "Spun the spinning pillars", "LV4 Dungeon," },
{ 0x2C, 0x08, 0x2C08, "F_0362", "Properly spoke with Resistance Rusl again (2nd time)", "Castle Town" },
{ 0x2C, 0x04, 0x2C04, "F_0363", "Stole sword from Rusl in Ordon Village at night (wolf)", "Ordon Village" },
{ 0x2C, 0x02, 0x2C02, "F_0364", "Listened to monkey girl's laments (Twilight)", "Faron Woods" },
{ 0x2C, 0x01, 0x2C01, "F_0365", "Spoke with Gor Liggs after LV dungeon clear", "Death Mountain (room)" },
{ 0x2D, 0x80, 0x2D80, "F_0366", "Spoke with Gor Liggs after Ilia's memories restored", "Death Mountain (room)" },
{ 0x2D, 0x40, 0x2D40, "F_0367", "Spoke with goron blocking mountain path after LV2 dungeon clear", "Death Mountain" },
{ 0x2D, 0x20, 0x2D20, "F_0368", "First conversation wtih goron in front of hotel", "Kakariko Village" },
{ 0x2D, 0x10, 0x2D10, "F_0369", "First conversation with goron in front of watch tower", "Kakariko Village" },
{ 0x2D, 0x08, 0x2D08, "F_0370", "First converstaion with Karakiko springs goron (adult)", "Kakariko Village" },
{ 0x2D, 0x04, 0x2D04, "F_0371", "First conversation wtih goron in front of bomb shop (while only selling bombs)", "Kakariko Village" },
{ 0x2D, 0x02, 0x2D02, "F_0372", "Tried to by milk before saving cat", "Ordon Village" },
{ 0x2D, 0x01, 0x2D01, "F_0373", "Coversation with Darbus after Ilia's memories restored", "Death Mountain" },
{ 0x2E, 0x80, 0x2E80, "F_0374", "Conversation with Darbus in wrestling room after LV2 dungeon clear", "Death Mountain" },
{ 0x2E, 0x40, 0x2E40, "F_0375", "First conversation with fundraising goron at Malo Mart", "Kakariko Village" },
{ 0x2E, 0x20, 0x2E20, "F_0376", "Gathered funds for bridge repair! (set by program after raising funds)", "Kakariko Village" },
{ 0x2E, 0x10, 0x2E10, "F_0377", "Goron spring water shop open!", "Castle Town" },
{ 0x2E, 0x08, 0x2E08, "F_0378", "Darbus destroyed hidden village boulder", "Ring field" },
{ 0x2E, 0x04, 0x2E04, "F_0379", "Completed golden bugs", "N/A" },
{ 0x2E, 0x02, 0x2E02, "F_0380", "Complete first meeting with Agetha (Recieved bug collection quest)", "N/A" },
{ 0x2E, 0x01, 0x2E01, "F_0381", "First conversation with parent goron after spring water shop opens", "Castle Town" },
{ 0x2F, 0x80, 0x2F80, "F_0382", "Listened to laments of fallen goron (while bridge broken)", "Castle Town" },
{ 0x2F, 0x40, 0x2F40, "F_0383", "Spoke with child goron after spring water shop opens", "Castle Town" },
{ 0x2F, 0x20, 0x2F20, "F_0384", "Spring water shop - Spoke with child goron while shop closed", "Castle Town" },
{ 0x2F, 0x10, 0x2F10, "F_0385", "First conversation with Barnes after stocking water bombs", "Kakariko Village" },
{ 0x2F, 0x08, 0x2F08, "F_0386", "Conversation with Barnes after he starts selling Bomblings and landmines", "Kakariko Village" },
{ 0x2F, 0x04, 0x2F04, "F_0387", "Learned scent of medicine", "Castle Town" },
{ 0x2F, 0x02, 0x2F02, "F_0388", "Graveyard - Spoke with Ralis after changing scene (before obtaining earrings)", "Kakariko Village" },
{ 0x2F, 0x01, 0x2F01, "F_0389", "First conversation with goron digging hole in south", "Ring field" },
{ 0x30, 0x80, 0x3080, "F_0390", "First conversation after saving Jovani", "Castle Town" },
{ 0x30, 0x40, 0x3040, "F_0391", "Gave spring water to goron south of castle town", "Ring field" },
{ 0x30, 0x20, 0x3020, "F_0392", "spoke with goron digging hole after opening caslt town south road", "Ring field" },
{ 0x30, 0x10, 0x3010, "F_0393", "First conversation at Poe shop (generic Poe appearance)", "Castle Town" },
{ 0x30, 0x08, 0x3008, "F_0394", "Received first key from chibi elder (204)", "LV2 Dungeon" },
{ 0x30, 0x04, 0x3004, "F_0395", "First conversation with Gor Liggs in Kakariko Village", "Kakariko Village" },
{ 0x30, 0x02, 0x3002, "F_0396", "Failed to carry hot spring water (speak with elder to reset)", "Kakariko Village" },
{ 0x30, 0x01, 0x3001, "F_0397", "Gor Liggs conversation sequence B", "Kakariko Village" },
{ 0x31, 0x80, 0x3180, "F_0398", "Gor Liggs conversation sequence C", "Kakariko Village" },
{ 0x31, 0x40, 0x3140, "F_0399", "Conversation with Gor Liggs - hot spring game available", "Kakariko Village" },
{ 0x31, 0x20, 0x3120, "F_0400", "Warped sky cannon to Lake Hylia", "Kakariko Village" },
{ 0x31, 0x10, 0x3110, "F_0401", "Beetle (M)", "Golden bugs" },
{ 0x31, 0x08, 0x3108, "F_0402", "Beetle (F)", "Golden bugs" },
{ 0x31, 0x04, 0x3104, "F_0403", "Butterfly (M)", "Golden bugs" },
{ 0x31, 0x02, 0x3102, "F_0404", "Butterfly (F)", "Golden bugs" },
{ 0x31, 0x01, 0x3101, "F_0405", "Stag beetle (M)", "Golden bugs" },
{ 0x32, 0x80, 0x3280, "F_0406", "Stag beetle (F)", "Golden bugs" },
{ 0x32, 0x40, 0x3240, "F_0407", "Grasshopper (M)", "Golden bugs" },
{ 0x32, 0x20, 0x3220, "F_0408", "Grasshopper (F)", "Golden bugs" },
{ 0x32, 0x10, 0x3210, "F_0409", "Phasmid (M)", "Golden bugs" },
{ 0x32, 0x08, 0x3208, "F_0410", "Phasmid (F)", "Golden bugs" },
{ 0x32, 0x04, 0x3204, "F_0411", "Pill bug (M)", "Golden bugs" },
{ 0x32, 0x02, 0x3202, "F_0412", "Pill bug (F)", "Golden bugs" },
{ 0x32, 0x01, 0x3201, "F_0413", "Mantis (M)", "Golden bugs" },
{ 0x33, 0x80, 0x3380, "F_0414", "Mantis (F)", "Golden bugs" },
{ 0x33, 0x40, 0x3340, "F_0415", "Ladybug (M)", "Golden bugs" },
{ 0x33, 0x20, 0x3320, "F_0416", "Ladybug (F)", "Golden bugs" },
{ 0x33, 0x10, 0x3310, "F_0417", "Snail (M)", "Golden bugs" },
{ 0x33, 0x08, 0x3308, "F_0418", "Snail (F)", "Golden bugs" },
{ 0x33, 0x04, 0x3304, "F_0419", "Dragonfly (M)", "Golden bugs" },
{ 0x33, 0x02, 0x3302, "F_0420", "Dragonfly (F)", "Golden bugs" },
{ 0x33, 0x01, 0x3301, "F_0421", "Ant (M)", "Golden bugs" },
{ 0x34, 0x80, 0x3480, "F_0422", "Ant (F)", "Golden bugs" },
{ 0x34, 0x40, 0x3440, "F_0423", "Dayfly (M)", "Golden bugs" },
{ 0x34, 0x20, 0x3420, "F_0424", "Dayfly (F)", "Golden bugs" },
{ 0x34, 0x10, 0x3410, "F_0425", "[Captured in bottle] Beetle (M)", "Golden bugs" },
{ 0x34, 0x08, 0x3408, "F_0426", "[Captured in bottle] Beetle (F)", "Golden bugs" },
{ 0x34, 0x04, 0x3404, "F_0427", "[Captured in bottle] Butterfly (M)", "Golden bugs" },
{ 0x34, 0x02, 0x3402, "F_0428", "[Captured in bottle] Butterfly (F)", "Golden bugs" },
{ 0x34, 0x01, 0x3401, "F_0429", "[Captured in bottle] Stag beetle (M)", "Golden bugs" },
{ 0x35, 0x80, 0x3580, "F_0430", "[Captured in bottle] Stag beetle (F)", "Golden bugs" },
{ 0x35, 0x40, 0x3540, "F_0431", "[Captured in bottle] Grasshopper (M)", "Golden bugs" },
{ 0x35, 0x20, 0x3520, "F_0432", "[Captured in bottle] Grasshopper (F)", "Golden bugs" },
{ 0x35, 0x10, 0x3510, "F_0433", "[Captured in bottle] Phasmid (M)", "Golden bugs" },
{ 0x35, 0x08, 0x3508, "F_0434", "[Captured in bottle] Phasmid (F)", "Golden bugs" },
{ 0x35, 0x04, 0x3504, "F_0435", "[Captured in bottle] Pill bug (M)", "Golden bugs" },
{ 0x35, 0x02, 0x3502, "F_0436", "[Captured in bottle] Pill bug (F)", "Golden bugs" },
{ 0x35, 0x01, 0x3501, "F_0437", "[Captured in bottle] Mantis (M)", "Golden bugs" },
{ 0x36, 0x80, 0x3680, "F_0438", "[Captured in bottle] Mantis (F)", "Golden bugs" },
{ 0x36, 0x40, 0x3640, "F_0439", "[Captured in bottle] Ladybug (M)", "Golden bugs" },
{ 0x36, 0x20, 0x3620, "F_0440", "[Captured in bottle] Ladybug (F)", "Golden bugs" },
{ 0x36, 0x10, 0x3610, "F_0441", "[Captured in bottle] Snail (M)", "Golden bugs" },
{ 0x36, 0x08, 0x3608, "F_0442", "[Captured in bottle] Snail (F)", "Golden bugs" },
{ 0x36, 0x04, 0x3604, "F_0443", "[Captured in bottle] Dragonfly (M)", "Golden bugs" },
{ 0x36, 0x02, 0x3602, "F_0444", "[Captured in bottle] Dragonfly (F)", "Golden bugs" },
{ 0x36, 0x01, 0x3601, "F_0445", "[Captured in bottle] Ant (M)", "Golden bugs" },
{ 0x37, 0x80, 0x3780, "F_0446", "[Captured in bottle] Ant (F)", "Golden bugs" },
{ 0x37, 0x40, 0x3740, "F_0447", "[Captured in bottle] Dayfly (M)", "Golden bugs" },
{ 0x37, 0x20, 0x3720, "F_0448", "[Captured in bottle] Dayfly (F)", "Golden bugs" },
{ 0x37, 0x10, 0x3710, "F_0449", "Talk with Gor Liggs again - first time after talking iwth Hot spring water parent goron (before fundraising)", "Kakariko Village" },
{ 0x37, 0x08, 0x3708, "F_0450", "Double Clawshot shop final stage first conversation", "Castle Town" },
{ 0x37, 0x04, 0x3704, "F_0453", "Postman first appears", "Ring field" },
{ 0x37, 0x02, 0x3702, "F_0454", "Recieved 3rd key from fundraising elder (206)", "LV2 Dungeon" },
{ 0x37, 0x01, 0x3701, "F_0455", "Recieved 3rd key from fundraising elder (205)", "LV2 Dungeon" },
{ 0x38, 0x80, 0x3880, "F_0456", "First time meeting with Jovani", "Castle Town" },
{ 0x38, 0x40, 0x3840, "F_0457", "Revived cat", "Castle Town" },
{ 0x38, 0x20, 0x3820, "F_0458", "Coversation with Jovani after collecting 60 ghosts", "Castle Town" },
{ 0x38, 0x10, 0x3810, "F_0459", "Coversation with Gengle after collecting 40 ghosts", "Castle Town" },
{ 0x38, 0x08, 0x3808, "F_0460", "Coversation with Gengle after collecting 50 ghosts", "Castle Town" },
{ 0x38, 0x04, 0x3804, "F_0461", "First time entered fishing house", "Fishing" },
{ 0x38, 0x02, 0x3802, "F_0462", "Reserved for fishing", "Fishing" },
{ 0x38, 0x01, 0x3801, "F_0463", "Reserved for fishing", "Fishing" },
{ 0x39, 0x80, 0x3980, "F_0464", "Reserved for fishing", "Fishing" },
{ 0x39, 0x40, 0x3940, "F_0465", "Reserved for fishing", "Fishing" },
{ 0x39, 0x20, 0x3920, "F_0466", "Reserved for fishing", "Fishing" },
//{ 0x39, 0x10, 0x3910, "F_0467", "N/A", "Fishing" },
{ 0x39, 0x08, 0x3908, "F_0468", "Reserved for fishing", "Fishing" },
{ 0x39, 0x04, 0x3904, "F_0469", "Reserved for fishing", "Fishing" },
{ 0x39, 0x02, 0x3902, "F_0470", "Reserved for fishing", "Fishing" },
{ 0x39, 0x01, 0x3901, "F_0471", "Finished 2 wrestling matches against Bo", "Ordon Village" },
{ 0x3A, 0x80, 0x3A80, "F_0472", "Distant howling complete (for secret technique 2)", "Secret techniques" },
{ 0x3A, 0x40, 0x3A40, "F_0473", "Distant howling complete (for secret technique 3)", "Secret techniques" },
{ 0x3A, 0x20, 0x3A20, "F_0474", "Distant howling complete (for secret technique 4)", "Secret techniques" },
{ 0x3A, 0x10, 0x3A10, "F_0475", "Distant howling complete (for secret technique 5)", "Secret techniques" },
{ 0x3A, 0x08, 0x3A08, "F_0476", "Distant howling complete (for secret technique 6)", "Secret techniques" },
{ 0x3A, 0x04, 0x3A04, "F_0477", "Distant howling complete (for secret technique 7)", "Secret techniques" },
{ 0x3A, 0x02, 0x3A02, "F_0478", "Spoke to Ralis who returned to Zora's domain", "Zora's Domain" },
{ 0x3A, 0x01, 0x3A01, "F_0479", "First conversation with Ralis in front of grave", "Kakariko Village" },
{ 0x3B, 0x80, 0x3B80, "F_0480", "Received Coral Earrings from Ralis", "Kakariko Village" },
{ 0x3B, 0x40, 0x3B40, "F_0481", "Beat Yeta at snowboard first time", "Snowpeak mountain" },
{ 0x3B, 0x20, 0x3B20, "F_0482", "After beating Yeto, first conversation with Yeta at peack (challanged to a match)", "N/A" },
{ 0x3B, 0x10, 0x3B10, "F_0483", "First beat Yeta at snowboard (heart piece)", "Snowpeak mountain" },
{ 0x3B, 0x08, 0x3B08, "F_0484", "Completed sky canon repairs!", "Lake Hylia" },
{ 0x3B, 0x04, 0x3B04, "F_0485", "Heard Fyer talk about repairs 1 time", "Lake Hylia" },
{ 0x3B, 0x02, 0x3B02, "F_0486", "Spoke with Luda while Ralis is visiting graveyard", "Kakariko Village" },
{ 0x3B, 0x01, 0x3B01, "F_0487", "Spoke with Luda after Ralis returns home", "Kakariko Village" },
{ 0x3C, 0x80, 0x3C80, "F_0488", "Conversation with goron in front of bomb shop - underwater bomb appears", "Kakariko Village" },
{ 0x3C, 0x40, 0x3C40, "F_0489", "Conversation with goron in front of bomb shop - all bomb types appear", "Kakariko Village" },
{ 0x3C, 0x20, 0x3C20, "F_0490", "Spoke with cucco (thinks Link will eat him)", "Ordon Village" },
{ 0x3C, 0x10, 0x3C10, "F_0491", "Spoke with mini-boss (magnet goron) after LV2 dungeon clear", "LV2 Dungeon" },
{ 0x3C, 0x08, 0x3C08, "F_0492", "Gold wolf disappearance 2", "Secret techniques" },
{ 0x3C, 0x04, 0x3C04, "F_0493", "Gold wolf disappearance 3", "Secret techniques" },
{ 0x3C, 0x02, 0x3C02, "F_0494", "Gold wolf disappearance 4", "Secret techniques" },
{ 0x3C, 0x01, 0x3C01, "F_0495", "Gold wolf disappearance 5", "Secret techniques" },
{ 0x3D, 0x80, 0x3D80, "F_0496", "Gold wolf disappearance 6", "Secret techniques" },
{ 0x3D, 0x40, 0x3D40, "F_0497", "Gold wolf disappearance 7", "Secret techniques" },
{ 0x3D, 0x20, 0x3D20, "F_0498", "Spoke with Beth after Lalis is revived", "Kakariko Village" },
{ 0x3D, 0x10, 0x3D10, "F_0499", "Saved magma goron", "Zora's Domain" },
{ 0x3D, 0x08, 0x3D08, "F_0500", "Met Uli before finding kids (look at sleeping Rusl)", "Ordon Village" },
{ 0x3D, 0x04, 0x3D04, "F_0501", "Cave of Ordeals - B10 first arrival", "sub-dungeon" },
{ 0x3D, 0x02, 0x3D02, "F_0502", "Cave of Ordeals - B20 first arrival", "sub-dungeon" },
{ 0x3D, 0x01, 0x3D01, "F_0503", "Cave of Ordeals - B30 first arrival", "sub-dungeon" },
{ 0x3E, 0x80, 0x3E80, "F_0504", "Cave of Ordeals - B40 first arrival", "sub-dungeon" },
{ 0x3E, 0x40, 0x3E40, "F_0505", "Cave of Ordeals - B50 first arrival (clear)", "sub-dungeon" },
{ 0x3E, 0x20, 0x3E20, "F_0506", "Only met Ooccoo Sr. - not yet son (shared LV1-LV5)", "N/A" },
{ 0x3E, 0x10, 0x3E10, "F_0507", "Also met the son in dungeon with first Ooccoo Sr. meeting - turns 506 OFF (shared LV1-LV5)", "N/A" },
{ 0x3E, 0x08, 0x3E08, "F_0508", "Meb Ooccoo Sr. B - doesnt turn OFF (shared LV1-LV5)", "Ooccoo Sr. stuff" },
{ 0x3E, 0x04, 0x3E04, "F_0509", "Met Ooccoo Sr. second time", "Ooccoo Sr. stuff" },
{ 0x3E, 0x02, 0x3E02, "F_0510", "Watched LV7 dungion start cutscene", "LV7 dungeon" },
{ 0x3E, 0x01, 0x3E01, "F_0513", "Spoke with Colin when neither Ilia nor Ralis are doing well", "Kakariko Village" },
{ 0x3F, 0x80, 0x3F80, "F_0514", "Spoke with Colin after Ralis is revived but before Ilia is revived", "Kakariko Village" },
{ 0x3F, 0x40, 0x3F40, "F_0515", "Spoke with Colin after Ilia and Ralis are revived", "Kakariko Village" },
{ 0x3F, 0x20, 0x3F20, "F_0516", "Told Uli directly about having found kids", "Ordon Village" },
{ 0x3F, 0x10, 0x3F10, "F_0517", "Had normal conversation 1 with Uli after finding kids (before Colin kidnapped)", "Ordon Village" },
{ 0x3F, 0x08, 0x3F08, "F_0518", "Colin kidnapped ~ Heard about giving letter to Colin from sleeping Uli", "Ordon Village" },
{ 0x3F, 0x04, 0x3F04, "F_0519", "Spoke with Juggle after finding children", "Ordon Village" },
{ 0x3F, 0x02, 0x3F02, "F_0520", "Spoke with Sera after finding children", "Ordon Village" },
{ 0x3F, 0x01, 0x3F01, "F_0521", "Spoke with Sera across the counter after finding children (her script is shortened after this)", "Ordon Village" },
{ 0x40, 0x80, 0x4080, "F_0522", "Heard about Sacred Grove from saved monkey girl", "Faron Woods" },
{ 0x40, 0x40, 0x4040, "F_0523", "Spoke with Hanch before finding children", "Ordon Village" },
{ 0x40, 0x20, 0x4020, "F_0524", "Spoke with Hanch after finding children", "Ordon Village" },
{ 0x40, 0x10, 0x4010, "F_0525", "First conversation with underwater Zora bomb seller", "Lake Hylia" },
{ 0x40, 0x08, 0x4008, "F_0526", "[Cutscene: 23] Midna reveals her true form", "Kawagoe Cutscene" },
{ 0x40, 0x04, 0x4004, "F_0527", "Refused Resistance Rusl's request", "Faron Woods" },
{ 0x40, 0x02, 0x4002, "F_0528", "Resistance Rusl summoned golden cucco", "Faron Woods" },
{ 0x40, 0x01, 0x4001, "F_0529", "Spoke with Rusl after clearing LV6 dungion", "Castle Town" },
{ 0x41, 0x80, 0x4180, "F_0530", "Spoke with Pergie after finding children", "Ordon Village" },
{ 0x41, 0x40, 0x4140, "F_0531", "Spoke with Pergie while children are kidnapped", "Ordon Village" },
{ 0x41, 0x20, 0x4120, "F_0532", "Pergie butts in about a shield", "Ordon Village" },
{ 0x41, 0x10, 0x4110, "F_0533", "Spoke with Fado after finding children", "Ordon Village" },
{ 0x41, 0x08, 0x4108, "F_0534", "Spoke with Fado before finding children", "Ordon Village" },
{ 0x41, 0x04, 0x4104, "F_0535", "Spoke with goron in water after recieving reward (bomb bag)", "Zora's Domain" },
{ 0x41, 0x02, 0x4102, "F_0536", "Spoke with goron in water before recieving reward", "Zora's Domain" },
{ 0x41, 0x01, 0x4101, "F_0537", "Had Coro and wolf conversation", "Faron Woods" },
{ 0x42, 0x80, 0x4280, "F_0538", "Spoke with sky person Oocoo Sr. after clearing LV7 dungeon", "LV7 dungeon" },
{ 0x42, 0x40, 0x4240, "F_0539", "Receieved heart piece from Fado for mountain goat chase", "Ordon Village" },
{ 0x42, 0x20, 0x4220, "F_0540", "Heard hint from Midna right after first portal warp", "Faron Woods" },
//{ 0x42, 0x10, 0x4210, "F_0541", "N/A", "N/A" },
{ 0x42, 0x08, 0x4208, "F_0542", "[Cutscene] Ganon wall disappears (Midna goes crazy)", "Kawagoe Cutscene" },
{ 0x42, 0x04, 0x4204, "F_0543", "Met Resistance Rusl again in the woods", "Faron Woods" },
{ 0x42, 0x02, 0x4202, "F_0544", "Watched cutscene of monkey girl running away after being attacked by puppet", "Faron Woods" },
{ 0x42, 0x01, 0x4201, "F_0545", "Watched cutscene of Ooccoo Sr. parting (after LV6)", "Sacred Grove" },
{ 0x43, 0x80, 0x4380, "F_0546", "East - Spoke with soldier in front of east gate about light (while bridge is broken)", "Castle Town" },
{ 0x43, 0x40, 0x4340, "F_0547", "conversation with Jovani after collecting 40 ghosts", "Castle Town" },
{ 0x43, 0x20, 0x4320, "F_0548", "Opening 3rd day - spoke with Jaggle", "Ordon Village" },
{ 0x43, 0x10, 0x4310, "F_0549", "Heard old lady A, B, soldier set (talking about water) (when there's no water)", "Castle Town" },
{ 0x43, 0x08, 0x4308, "F_0550", "Gain ability to use sense", "main event" },
{ 0x43, 0x04, 0x4304, "F_0551", "LV8 Dungeon control use 1", "LV8 Dungeon" },
{ 0x43, 0x02, 0x4302, "F_0552", "LV8 Dungeon control use 2", "LV8 Dungeon" },
{ 0x43, 0x01, 0x4301, "F_0553", "LV8 Dungeon control use 3", "LV8 Dungeon" },
{ 0x44, 0x80, 0x4480, "F_0554", "LV8 Dungeon control use 4", "LV8 Dungeon" },
{ 0x44, 0x40, 0x4440, "F_0555", "LV8 Dungeon control use 5", "LV8 Dungeon" },
{ 0x44, 0x20, 0x4420, "F_0556", "LV8 Dungeon control use 6", "LV8 Dungeon" },
{ 0x44, 0x10, 0x4410, "F_0557", "LV8 Dungeon control use 7", "LV8 Dungeon" },
{ 0x44, 0x08, 0x4408, "F_0558", "LV8 Dungeon control use 8", "LV8 Dungeon" },
{ 0x44, 0x04, 0x4404, "F_0559", "LV8 Dungeon control use 9", "LV8 Dungeon" },
{ 0x44, 0x02, 0x4402, "F_0560", "LV8 Dungeon control use 10", "LV8 Dungeon" },
{ 0x44, 0x01, 0x4401, "F_0561", "LV8 Dungeon control use 11", "LV8 Dungeon" },
{ 0x45, 0x80, 0x4580, "F_0562", "LV8 Dungeon control use 12", "LV8 Dungeon" },
{ 0x45, 0x40, 0x4540, "F_0563", "Brought back Gengle (after getting 50 souls, dealt with by program)", "Misc." },
{ 0x45, 0x20, 0x4520, "F_0564", "Heard story from solder at Telma's shop (during Twilight)", "Castle Town" },
{ 0x45, 0x10, 0x4510, "F_0565", "2nd Day Complete", "N/A" },
{ 0x45, 0x08, 0x4508, "F_0566", "Letter from Ooccoo Sr. came in OK (no son)", "Ooccoo Sr. stuff" },
{ 0x45, 0x04, 0x4504, "F_0567", "Letter from Ooccoo Sr. came in OK (yes son)", "Ooccoo Sr. stuff" },
{ 0x45, 0x02, 0x4502, "F_0568", "Broke Iza's pots (first offence)", "Zora's River" },
{ 0x45, 0x01, 0x4501, "F_0569", "Compensation demands from Iza (resets if paid)", "Zora's River" },
{ 0x46, 0x80, 0x4680, "F_0570", "Cleared LV8 dungeon", "LV8 Dungeon" },
{ 0x46, 0x40, 0x4640, "F_0571", "Refuse Talo's request (for wooden sword) on 3rd day (first time)", "Ordon Village" },
{ 0x46, 0x20, 0x4620, "F_0572", "Refuse Talo's request (for wooden sword) on 3rd day (again)", "Ordon Village" },
{ 0x46, 0x10, 0x4610, "F_0573", "1st Day - Fado moves to the farm (disappears from in front of Link's house)", "Ordon Village" },
{ 0x46, 0x08, 0x4608, "F_0574", "1st Day - Start mountain goat chasing in evening", "Ranch" },
{ 0x46, 0x04, 0x4604, "F_0575", "1st Day - End mountain goat chasing in evening", "Ranch" },
{ 0x46, 0x02, 0x4602, "F_0576", "2nd Day - Spoke with Fado", "Ordon Village" },
{ 0x46, 0x01, 0x4601, "F_0577", "2nd Day - Retrieved basket from monkey (hit hawk)", "Ordon Village" },
{ 0x47, 0x80, 0x4780, "F_0578", "Spoke to Beth on 3rd day", "Ordon Village" },
{ 0x47, 0x40, 0x4740, "F_0579", "Opening (2nd day) First time talking with Hanch before being attacked by bees", "Ordon Village" },
{ 0x47, 0x20, 0x4720, "F_0580", "1st Day - Blew on Epona's reed whistle at Ordon Spring", "Ordon Village" },
{ 0x47, 0x10, 0x4710, "F_0581", "2nd Day - First time calling the hawk using the grass whistle", "Ordon Village" },
{ 0x47, 0x08, 0x4708, "F_0582", "1st Day - spoke to Ilia before blowing the reed whistle", "Ordon Woods" },
{ 0x47, 0x04, 0x4704, "F_0583", "1st day - Spoke to Ilia after blowing the reed whistle", "Ordon Woods" },
{ 0x47, 0x02, 0x4702, "F_0584", "1st Day - spoke to Rusl", "Ordon Village" },
{ 0x47, 0x01, 0x4701, "F_0585", "1st day - Spoke to Bo", "Ordon Village" },
{ 0x48, 0x80, 0x4880, "F_0586", "Spoke to Bo after defeating mountain goat", "Ordon Village" },
{ 0x48, 0x40, 0x4840, "F_0587", "successfully defeated rampaging mountain goat", "Ordon Village" },
{ 0x48, 0x20, 0x4820, "F_0588", "First time letting rampaging mountain goat escape", "Ordon Village" },
{ 0x48, 0x10, 0x4810, "F_0589", "Sera - spoke on first day", "Ordon Village" },
{ 0x48, 0x08, 0x4808, "F_0590", "2nd Day - Spoke to Malo during Talo's disappearance (after getting lantern)", "Ordon Village" },
{ 0x48, 0x04, 0x4804, "F_0591", "2nd Day - Spoke to Malo right after Talo disappears", "Ordon Woods" },
{ 0x48, 0x02, 0x4802, "F_0592", "2nd Day - Spoke with Beth during Talo's disappearance (after getting lantern)", "Ordon Village" },
{ 0x48, 0x01, 0x4801, "F_0593", "2nd Day - Conversation with Beth right after Talo's disappearance", "Ordon Woods" },
{ 0x49, 0x80, 0x4980, "F_0594", "2nd Day - Colin (conversation after receiving lantern from Coro)", "Ordon Village" },
{ 0x49, 0x40, 0x4940, "F_0595", "2nd Day - Conversation with Colin after sword tutorial and after horse rejection", "Ordon Village" },
{ 0x49, 0x20, 0x4920, "F_0596", "2nd Day - Conversation with Colin after sword tutorial, before horse rejection", "Ordon Village" },
{ 0x49, 0x10, 0x4910, "F_0597", "2nd Day - First time speaking with Bo (after successfully defeating mountain goat)", "Ordon Village" },
{ 0x49, 0x08, 0x4908, "F_0598", "2nd Day - First conversation with Bo", "Ordon Village" },
{ 0x49, 0x04, 0x4904, "F_0599", "2nd Day - tried to enter Bo's house", "Ordon Village" },
{ 0x49, 0x02, 0x4902, "F_0600", "Purchase slingshot", "Ordon Village" },
{ 0x49, 0x01, 0x4901, "F_0601", "Spoke to imprisoned Talo", "Faron Woods" },
{ 0x4A, 0x40, 0x4A40, "F_0700", "First day ends", "N/A" },
{ 0x4A, 0x20, 0x4A20, "F_0701", "Talo discovers monkey in Link's house garden", "N/A" },
{ 0x4A, 0x10, 0x4A10, "F_0702", "Confirmed kidnapped Talo", "Ordon Village" },
{ 0x4A, 0x08, 0x4A08, "F_0606", "Giants switched places", "Sacred Grove" },
{ 0x4A, 0x04, 0x4A04, "F_0607", "Quit Slingshot tutorial", "Ordon Village" },
{ 0x4A, 0x02, 0x4A02, "F_0608", "Began Slingshot tutorial", "Ordon Village" },
{ 0x4A, 0x01, 0x4A01, "F_0609", "Slingshot Tutorial - First time hitting scarcrow torso", "Ordon Village" },
{ 0x4B, 0x80, 0x4B80, "F_0610", "Slingshot Tutorial - Hit it without using focus", "Ordon Village" },
{ 0x4B, 0x40, 0x4B40, "F_0611", "Slingshot Tutorial - Hit it using focusing", "Ordon Village" },
{ 0x4B, 0x20, 0x4B20, "F_0612", "Pachinco Tutorial - Spoke before hitting target", "Ordon Village" },
{ 0x4B, 0x10, 0x4B10, "F_0613", "Slingshot Tutorial - Spoke before getting 2 scarecrow heards", "Ordon Village" },
{ 0x4B, 0x08, 0x4B08, "F_0614", "2nd Day - Heard forced conversation immediately after the slignshot tutorial", "Ordon Village" },
{ 0x4B, 0x04, 0x4B04, "F_0615", "Recieved vessel of light from Lanayru spirit", "Lake Hylia" },
{ 0x4B, 0x02, 0x4B02, "F_0616", "3rd Day - Spoke to Talo/Malo after handing over wooden sword (1st time)", "Ordon Village" },
{ 0x4B, 0x01, 0x4B01, "F_0617", "3rd Day - Spoke to Talo/Malo after handing over wooden sword (2nd time)", "Ordon Village" },
{ 0x4C, 0x80, 0x4C80, "F_0618", "Scooped bee larva into bottle on opening 2nd Day ", "Ordon Village" },
{ 0x4C, 0x40, 0x4C40, "F_0619", "Spoke to Zora soldier (near cannon) in Lake Hylia", "Lake Hylia" },
{ 0x4C, 0x20, 0x4C20, "F_0620", "First caught a Reek Fish", "Zora's Domain" },
{ 0x4C, 0x10, 0x4C10, "F_0621", "Spoke to Hanch on 3rd day (knocked down beehive on 2nd day)", "Ordon Village" },
{ 0x4C, 0x08, 0x4C08, "F_0622", "Opening 2nd day: Spoke to Hanch before being attacked by bees", "Ordon Village" },
{ 0x4C, 0x04, 0x4C04, "F_0623", "Opening 3rd day: Spoke to Hanch before being attacked by bees", "Ordon Village" },
{ 0x4C, 0x02, 0x4C02, "F_0624", "3rd day: Warned by Hanch when climbing vines", "Ordon Village" },
{ 0x4C, 0x01, 0x4C01, "F_0625", "Saved Talo and a monkey", "Faron Woods" },
{ 0x4D, 0x80, 0x4D80, "F_0626", "Received a heart piece from Jovani", "Castle Town" },
{ 0x4D, 0x40, 0x4D40, "F_0627", "Spoke with Jovani at the bar", "Castle Town" },
{ 0x4D, 0x20, 0x4D20, "F_0628", "Received 200 Rupees from Gengle", "Castle Town" },
{ 0x4D, 0x10, 0x4D10, "F_0629", "First conversation iwth Gengle after speaking with Jovani at the bar", "Castle Town" },
{ 0x4D, 0x08, 0x4D08, "F_0630", "(Cutscene 4 - ?) Right after Link is captured (wolf)", "Kawagoe Cutscene" },
{ 0x4A, 0x80, 0x4A80, "F_0631", "Heard when zooming in on fish tank (1)", "Fishing Pond (inside)" },
{ 0x4D, 0x04, 0x4D04, "F_0632", "Heard first time zooming in on fish tank (2)", "Fishing Pond (inside)" },
{ 0x4D, 0x02, 0x4D02, "F_0633", "Heard second time zooming in on fish tank (2)", "Fishing Pond (inside)" },
{ 0x4D, 0x01, 0x4D01, "F_0634", "Heard zooming in on lure (no frog)", "Fishing Pond (inside)" },
{ 0x4E, 0x80, 0x4E80, "F_0635", "Heard zooming in on lure (yes frog)", "Fishing Pond (inside)" },
{ 0x4E, 0x40, 0x4E40, "F_0636", "Heard first time zooming in on frog lure", "Fishing Pond (inside)" },
{ 0x4E, 0x20, 0x4E20, "F_0637", "Cleard all of roll goal game (get frog lure)", "Fishing Pond (inside)" },
{ 0x4E, 0x10, 0x4E10, "F_0638", "Heard first time zooming in on canoe", "Fishing Pond (inside)" },
{ 0x4E, 0x08, 0x4E08, "F_0639", "Heard first time zooming in on hat", "Fishing Pond (inside)" },
{ 0x4E, 0x04, 0x4E04, "F_0640", "Heard first time zooming in on pot", "Fishing Pond (inside)" },
{ 0x4E, 0x02, 0x4E02, "F_0641", "Heard First time zooming in on rug", "Fishing Pond (inside)" },
{ 0x4E, 0x01, 0x4E01, "F_0642", "Heard first time zooming in on book", "Fishing Pond (inside)" },
{ 0x4F, 0x80, 0x4F80, "F_0643", "Heard first time zooming in on old man's photo", "Fishing Pond (inside)" },
{ 0x4F, 0x40, 0x4F40, "F_0644", "Heard first time zooming in on Coro's photo", "Fishing Pond (inside)" },
{ 0x4F, 0x20, 0x4F20, "F_0645", "Heard First time zoomin in on Iza's photo", "Fishing Pond (inside)" },
{ 0x4F, 0x10, 0x4F10, "F_0646", "Heard first time zooming in on Hena's photo", "Fishing Pond (inside)" },
{ 0x4F, 0x08, 0x4F08, "F_0647", "Heard second time zooming in on Hena's photo", "Fishing Pond (inside)" },
{ 0x4F, 0x04, 0x4F04, "F_0648", "Heard Hena's photo 1,2 (additional story)", "Fishing Pond (inside)" },
{ 0x4F, 0x02, 0x4F02, "F_0649", "Heard first time zooming in on Link's picture", "Fishing Pond (inside)" },
{ 0x4F, 0x01, 0x4F01, "F_0650", "Heard second time zooming in on Link's picture", "Fishing Pond (inside)" },
{ 0x50, 0x80, 0x5080, "F_0651", "Caught Greengill with bobber first time", "Fishing" },
{ 0x50, 0x40, 0x5040, "F_0652", "Caught Hylian Bass with bobber first time", "Fishing" },
{ 0x50, 0x20, 0x5020, "F_0653", "Caught Hylian Pike with bobber first time", "Fishing" },
{ 0x50, 0x10, 0x5010, "F_0654", "Caught Hylian Loach using bobber first time", "Fishing" },
{ 0x50, 0x08, 0x5008, "F_0655", "Caught an Ordon Catfish using bobber first time", "Fishing" },
{ 0x50, 0x04, 0x5004, "F_0656", "Caught something (any fish) using lure first time", "Fishing" },
{ 0x50, 0x02, 0x5002, "F_0657", "Caught Hylian Loach in front of Hena first time", "Fishing" },
{ 0x50, 0x01, 0x5001, "F_0658", "Recieved large wallet from Agitha", "Castle Town" },
{ 0x51, 0x80, 0x5180, "F_0659", "Hear information about spirit spring in Lake Hylia from Twilight Soldier or map", "Castle Town" },
{ 0x51, 0x40, 0x5140, "F_0660", "Twilight Lake Hylia Listened to Zora soldier A talk", "Lake Hylia" },
{ 0x51, 0x20, 0x5120, "F_0661", "Twilight Lake Hylia Listened to Zora soldier B&C talk", "Lake Hylia" },
{ 0x51, 0x10, 0x5110, "F_0662", "Omit rules after clearing roll goal game once", "Fishing Pond (inside)" },
{ 0x51, 0x08, 0x5108, "F_0663", "Listened to Purdy's unnecessary words", "Fishing Pond (inside)" },
{ 0x51, 0x04, 0x5104, "F_0664", "After clearing roll goal game / first attempt", "Fishing Pond (inside)" },
{ 0x51, 0x02, 0x5102, "F_0665", "First zoom in Roll goal game", "Fishing Pond (inside)" },
{ 0x51, 0x01, 0x5101, "F_0666", "Showed Yeto sketch to Zora soldier next to Snowpeak Mountain", "Zora's Domain" },
{ 0x52, 0x80, 0x5280, "F_0667", "Showed Yeto sketch to average Zora soldier (generic)", "Zora's Domain" },
{ 0x52, 0x40, 0x5240, "F_0668", "Showed Yeto sketch to Zora civilian (generic)", "Zora's Domain" },
{ 0x52, 0x20, 0x5220, "F_0669", "Pulled on Fyrus chains at least once", "LV2 Dungeon" },
{ 0x52, 0x10, 0x5210, "F_0670", "Hitting knocked-down Fyrus", "LV2 Dungeon" },
{ 0x52, 0x08, 0x5208, "F_0671", "Through magnet goron into lava once", "LV2 Dungeon" },
{ 0x52, 0x04, 0x5204, "F_0672", "First time seeing magnet goron tumbling", "LV2 Dungeon" },
{ 0x52, 0x02, 0x5202, "F_0673", "Heard hint about Fyrus's weakness (F0215)", "LV2 Dungeon" },
{ 0x52, 0x01, 0x5201, "F_0674", "Light - Spoke with cafe table: townsperson A1", "Castle Town" },
{ 0x53, 0x80, 0x5380, "F_0675", "Light - cafe counter: Spoke with townsgirl A1 (shop clerk)", "Castle Town" },
{ 0x53, 0x40, 0x5340, "F_0676", "Light - Spoke with Cafe customer: Townsperson F1 (just the man)", "Castle Town" },
{ 0x53, 0x20, 0x5320, "F_0677", "Light - Spoke with Cafe customer B: Townsperson D1 and Man B1", "Castle Town" },
{ 0x53, 0x10, 0x5310, "F_0678", "Spoke with Group A (Town girl C2, Boy B1, Town girl D1) in front of fountain", "Castle Town" },
{ 0x53, 0x08, 0x5308, "F_0679", "Cheated during Roll goal game", "Fishing Pond (inside)" },
{ 0x53, 0x04, 0x5304, "F_0680", "Heard Midna's hint after cutscene of ghost escaping", "LV4 Dungeon," },
{ 0x53, 0x02, 0x5302, "F_0681", "Heard Midna's hint after defeating first ghost", "LV4 Dungeon," },
{ 0x53, 0x01, 0x5301, "F_0682", "First conversation with Oocca Shopkeeper", "LV7 dungeon" },
{ 0x54, 0x80, 0x5480, "F_0683", "Spoke with Group B (Old lady A1, Boy A1, Town girl B1) in central square", "Castle Town" },
{ 0x54, 0x40, 0x5440, "F_0684", "Look at R00 statue using sense", "LV6 Dungeon" },
{ 0x54, 0x20, 0x5420, "F_0685", "(Cutscene 32) Sage appears, get first Mirror of Twilight shard", "Kawagoe Cutscene" },
{ 0x54, 0x10, 0x5410, "F_0686", "Get fused shadow piece (final mask)", "LV8 Dungeon" },
{ 0x54, 0x08, 0x5408, "F_0687", "Spoke with town girl D1 in front of south road hot spring shop (CLOSED)", "Castle Town" },
{ 0x54, 0x04, 0x5404, "F_0688", "Spoke with town girl D1 in front of south road hot spring shop (OPEN)", "Castle Town" },
{ 0x54, 0x02, 0x5402, "F_0689", "South Road - Spoke with meat shop villager man C1", "Castle Town" },
{ 0x54, 0x01, 0x5401, "F_0690", "South Road - Spoke with woman A1 in front of fortune teller's shop", "Castle Town" },
{ 0x55, 0x80, 0x5580, "F_0691", "Spoke with south alley children before guarding carriage", "Castle Town" },
{ 0x55, 0x40, 0x5540, "F_0692", "Spoke with south alley children after guarding carriage", "Castle Town" },
{ 0x55, 0x20, 0x5520, "F_0693", "First conversation with Plumm while human", "Lake Hylia" },
{ 0x55, 0x10, 0x5510, "F_0694", "Conversation with Jovani after collecting 20 ghosts", "Castle Town" },
{ 0x55, 0x08, 0x5508, "F_0695", "First time frog lure slips out", "Fishing" },
{ 0x55, 0x04, 0x5504, "F_0696", "Spoke with inquiring Hyrule guard before saving Jovani", "Castle Town" },
{ 0x55, 0x02, 0x5502, "F_0697", "Spoke with inquiring Hyrule guard after saving Jovani", "N/A" },
{ 0x55, 0x01, 0x5501, "F_0698", "Spoke with woman B1 in front of south vegetable stand (before guarding carriage)", "Castle Town" },
{ 0x56, 0x80, 0x5680, "F_0699", "Spoke with woman B1 in front of south vegetable stand (after guarding carriage)", "Castle Town" },
{ 0x56, 0x40, 0x5640, "F_0700B", "South Vegetable vendor - Spoke with Villager D2 (before guarding carriage)", "Castle Town" },
{ 0x56, 0x20, 0x5620, "F_0701B", "South Vegetable vendor - Spoke with Villager D2 (after guarding carriage)", "N/A" },
{ 0x56, 0x10, 0x5610, "F_0702B", "South Baker - Spoke with Boy A2", "Castle Town" },
{ 0x56, 0x08, 0x5608, "F_0703", "Caught Reek fish for first time while fishing", "Fishing" },
{ 0x56, 0x04, 0x5604, "F_0704", "Listened to Iza in Twilight before domain is thawed", "Zora's River" },
{ 0x56, 0x02, 0x5602, "F_0705", "First conversation with Kaeru (frog) during Midna's desperate hour", "Castle Town" },
{ 0x56, 0x01, 0x5601, "F_0706", "First conversation wtih Torako (cat) during Midna's desperate hour", "Castle Town" },
{ 0x57, 0x80, 0x5780, "F_0707", "Midna's desperate hour, first conversation with Mii (cat)", "Castle Town" },
{ 0x57, 0x40, 0x5740, "F_0708", "First conversaton with doctor after completing spirit", "Castle Town" },
{ 0x57, 0x20, 0x5720, "F_0709", "Midna's desperate hour, first conversation wtih Stephanie (cat)", "Castle Town" },
{ 0x57, 0x10, 0x5710, "F_0715", "Speak with dog to west", "Castle Town" },
{ 0x57, 0x08, 0x5708, "F_0716", "Speak with dog to the east", "Castle Town" },
{ 0x57, 0x04, 0x5704, "F_0717", "Wist - Speak to the dog owner", "Castle Town" },
{ 0x57, 0x02, 0x5702, "F_0718", "South - Spoke to old lady at the vegetable stand (Chudley)", "Castle Town" },
{ 0x57, 0x01, 0x5701, "F_0719", "South - Spoke to old lady at the vegetable stand (Malo Mart)", "Castle Town" },
{ 0x58, 0x80, 0x5880, "F_0720", "South - Spoke to fruit stand vendor (before guarding carriage)", "Castle Town" },
{ 0x58, 0x40, 0x5840, "F_0721", "South - Spoke to fruit stand vendor (after guarding carriage)", "Castle Town" },
{ 0x58, 0x20, 0x5820, "F_0722", "East - Spoke to man at the T-shaped street", "Castle Town" },
{ 0x58, 0x10, 0x5810, "F_0723", "East - Spoke to man in the alley", "Castle Town" },
{ 0x58, 0x08, 0x5808, "F_0724", "East - Spoke to two ladies gossiping", "Castle Town" },
{ 0x58, 0x04, 0x5804, "F_0725", "Speak to Renado who is announcing Shad's visit", "Kakariko Village" },
{ 0x58, 0x02, 0x5802, "F_0726", "Talk to Iza as wolf", "Zora's River" },
{ 0x58, 0x01, 0x5801, "F_0727", "First conversation with shoe-shine boy", "Castle Town" },
{ 0x59, 0x80, 0x5980, "F_0728", "Refused entry into Chudley's shop because of dirty shoes", "Castle Town" },
{ 0x59, 0x40, 0x5940, "F_0729", "Right after postman's \"Hey!\"", "Ring field" },
{ 0x59, 0x20, 0x5920, "F_0730", "Rode Iza's boat for the first time", "Zora's River" },
{ 0x59, 0x10, 0x5910, "F_0732", "Spoke with Cucco (After completing Ilia's memory event)", "Hidden Village" },
{ 0x59, 0x08, 0x5908, "F_0733", "Recieved Heart piece reward from Iza for going down the river", "Zora's River" },
{ 0x59, 0x04, 0x5904, "F_0734", "Spoke with wild duck", "Fishing" },
{ 0x59, 0x02, 0x5902, "F_0735", "Spoke with domestic duck", "Fishing" },
{ 0x59, 0x01, 0x5901, "F_0736", "Heard Midna's hint / monkey hint", "LV1 Dungeon" },
{ 0x5A, 0x80, 0x5A80, "F_0737", "First conversation with Udo (cat) during Midna's desperate hour", "Castle Town" },
{ 0x5A, 0x40, 0x5A40, "F_0738", "South - Spoke with female customer at vegetable stand", "Castle Town" },
{ 0x5A, 0x20, 0x5A20, "F_0739", "South - Spoke with old customer at fruit stand", "Castle Town" },
{ 0x5A, 0x10, 0x5A10, "F_0740", "Spoke with child Goron (selling lantern oil) (before Ganon wall)", "Castle Town" },
{ 0x5A, 0x08, 0x5A08, "F_0741", "Spoke with child Goron (selling lantern oil) (after Ganon wall)", "Castle Town" },
{ 0x5A, 0x04, 0x5A04, "F_0742", "Spoke with child Goron (selling red potion)", "Castle Town" },
{ 0x5A, 0x02, 0x5A02, "F_0743", "Spoke with adult Goron (30 arrows) (before Ganon wall)", "Castle Town" },
{ 0x5A, 0x01, 0x5A01, "F_0744", "Spoke with adult Goron (30 arrows) (after Ganon wall)", "Castle Town" },
{ 0x5B, 0x80, 0x5B80, "F_0745", "Spoke with adult Goron (Hylia shield)", "Castle Town" },
{ 0x5B, 0x40, 0x5B40, "F_0746", "Spoke with Cucco A", "Kakariko Village" },
{ 0x5B, 0x20, 0x5B20, "F_0747", "Spoke with Cucco B", "Kakariko Village" },
{ 0x5B, 0x10, 0x5B10, "F_0748", "First conversation with hint hawk", "Ring field" },
{ 0x5B, 0x08, 0x5B08, "F_0749", "After clearing cat game (Heart piece is buried, whether it is obtained depends on the player)", "Hidden Village" },
{ 0x5B, 0x04, 0x5B04, "F_0750", "First conversation with Captain Cucco after beginning cat game activities", "Hidden Village" },
{ 0x5B, 0x02, 0x5B02, "F_0751", "Heard detailed explaination from Captain Cucco for the first time", "Hidden Village" },
{ 0x5B, 0x01, 0x5B01, "F_0752", "Beat cat game again", "Hidden Village" },
{ 0x5C, 0x80, 0x5C80, "F_0753", "Scooped Coro's bad soup for the first time", "Faron Woods" },
{ 0x5C, 0x40, 0x5C40, "F_0754", "Heard Midna's hint / Monkey hint 2 times (SAVE72=ON)", "LV1 Dungeon" },
{ 0x5C, 0x20, 0x5C20, "F_0755", "Twilight Heard Iza's line right after shadow bug appears", "Zora's River" },
{ 0x5C, 0x10, 0x5C10, "F_0756", "Join with Ooccoo Sr.", "LV7 dungeon" },
{ 0x5C, 0x08, 0x5C08, "F_0757", "Had Trill and wolf conversation", "Faron Woods" },
{ 0x5C, 0x04, 0x5C04, "F_0758", "Stole from unmanned shop (For use in Trill wolf conversation. Resets after speaking)", "Faron Woods" },
{ 0x5C, 0x02, 0x5C02, "F_0759", "Opening (3rd day) first conversation with Sera", "Ordon Village" },
{ 0x5C, 0x01, 0x5C01, "B_BTN_GUIDE", "B-button guide", "Misc." },
{ 0x5D, 0x80, 0x5D80, "J_BTN_GUIDE", "X-button guide", "Misc." },
{ 0x5D, 0x40, 0x5D40, "F_0768", "Heard forced conversation with Midna after Hylia Lake introduction cutscene", "Lake Hylia" },
{ 0x5D, 0x20, 0x5D20, "F_0769", "Forced conversation with Midna right after first arrival at upper Zora's river", "Zora's River" },
{ 0x5D, 0x10, 0x5D10, "F_0770", "Twilight (frozen) Heard forced conversation after first visit cutscene", "Zora's Domain" },
{ 0x5D, 0x08, 0x5D08, "F_0771", "Unmanned Shop : last payment stolen", "Faron Woods" },
{ 0x5D, 0x04, 0x5D04, "F_0772", "Unmanned Shop : last payment too little", "Faron Woods" },
{ 0x5D, 0x02, 0x5D02, "F_0773", "Unmanned Shop : last payment too much", "Faron Woods" },
{ 0x5D, 0x01, 0x5D01, "F_0774", "Listened to Midna's conversation after seeing frozen Zora", "Zora's Domain" },
{ 0x5E, 0x80, 0x5E80, "F_0775", "Heard forced conversation with Midna after first Fyer's cannon", "Lake Hylia" },
{ 0x5E, 0x40, 0x5E40, "F_0776", "Link first turned to wolf due to fog in LV8 dungeon", "LV8 Dungeon" },
{ 0x5E, 0x20, 0x5E20, "F_0777", "Spoke to Epona", "Misc." },
{ 0x5E, 0x10, 0x5E10, "F_0778", "Heard forced conversation with Midna after story about spirits after clearing LV1 dungeon", "Faron Woods" },
{ 0x5E, 0x08, 0x5E08, "F_0779", "Heard one hint from Midna while bridge is burning", "Lake Hylia" },
{ 0x5E, 0x04, 0x5E04, "F_0780", "Heard Ilia talk about the messenger from the sky after her memories are restored", "Kakariko Village" },
{ 0x5E, 0x02, 0x5E02, "F_0781", "Spoke to Ilia in church after clearing LV6", "Kakariko Village" },
{ 0x5E, 0x01, 0x5E01, "F_0782", "Spoke to Renado after LV3 complete, before LV6 complete", "Kakariko Village" },
{ 0x5F, 0x80, 0x5F80, "F_0783", "Showed dominion rod to Impaz", "Hidden Village" },
{ 0x5F, 0x40, 0x5F40, "F_0784", "Had normal conversation with Shad after he returns to church basement", "Kakariko Village" },
{ 0x5F, 0x20, 0x5F20, "F_0785", "Shad leaves after attempting to warp sky cannon", "Kakariko Village" },
{ 0x5F, 0x10, 0x5F10, "F_0786", "Forced conversation with Shad when he sees the sky cannon", "Kakariko Village" },
{ 0x5F, 0x08, 0x5F08, "F_0787", "Stopped by Midna when trying to warp the sky cannon", "Kakariko Village" },
{ 0x5F, 0x04, 0x5F04, "F_0788", "Talked to Zora going up the waterfall", "Zora's River" },
{ 0x5F, 0x02, 0x5F02, "F_0789", "Grabbed sweet apple 1 time", "Castle Town" },
{ 0x5F, 0x01, 0x5F01, "F_0790", "Sera faces the cat (outside conversation area when 520 is ON)", "Ordon Village" },
{ 0x60, 0x80, 0x6080, "F_0791", "Sky character 1", "Sky character" },
{ 0x60, 0x40, 0x6040, "F_0792", "Sky character 2", "Sky character" },
{ 0x60, 0x20, 0x6020, "F_0793", "Sky character 3", "Sky character" },
{ 0x60, 0x10, 0x6010, "F_0794", "Sky character 4", "Sky character" },
{ 0x60, 0x08, 0x6008, "F_0795", "Sky character 5", "Sky character" },
{ 0x60, 0x04, 0x6004, "F_0796", "Sky character 6", "Sky character" },
{ 0x60, 0x02, 0x6002, "F_0797", "Have selected \"Take Cannon / Repair\" at Fyer's cannon (when there's no other business)", "Lake Hylia" },
{ 0x60, 0x01, 0x6001, "F_0798", "Heard about Zora from Fyer", "Lake Hylia" },
{ 0x61, 0x80, 0x6180, "F_0799", "Listened to the fallen Goron's complaints (after opening bridge)", "Ring field" },
{ 0x61, 0x40, 0x6140, "F_0800", "After returning to Ordon Woods, until Midna comes out of the shadows (If 800 is ON, Midna can't be called)", "Kawagoe Cutscene" },
{ 0x61, 0x20, 0x6120, "F_0801", "First learned Reek Fish scent", "Zora's Domain" },
{ 0x61, 0x10, 0x6110, "F_0802", "Trill attacks when stealing", "Faron Woods" },
{ 0x61, 0x08, 0x6108, "F_0803", "Talked to Old Lady Impaz after going to Sky", "Hidden Village" },
{ 0x61, 0x04, 0x6104, "F_0804", "Heard Midna's forced conversation immediately after plunge into Eldin Twilight", "Twilight Ring field" },
{ 0x61, 0x02, 0x6102, "F_0805", "Bought Hylian shield from Malo Mart", "Kakariko Village" },
{ 0x61, 0x01, 0x6101, "F_0806", "Talked to Hanch on the first day", "Ordon Village" },
{ 0x62, 0x80, 0x6280, "F_0807", "Talked to Colin on the first day", "Ordon Village" },
{ 0x62, 0x40, 0x6240, "F_0808", "Talked to Beth on the first day", "Ordon Village" },
{ 0x62, 0x20, 0x6220, "F_0809", "3 groupie girls (first conversation where they become Link's groupies)", "Castle Town" },
{ 0x62, 0x10, 0x6210, "F_0810", "Learned ghost's scent", "LV4 Dungeon" },
{ 0x62, 0x08, 0x6208, "F_0811", "Attempted Star Game for the first time", "Castle Town" },
//{ 0x62, 0x04, 0x6204, "F_0812", "N/A", "N/A" },
//{ 0x62, 0x02, 0x6202, "F_0813", "N/A", "N/A" },
//{ 0x62, 0x01, 0x6201, "F_0814", "N/A", "N/A" },
//{ 0x63, 0x80, 0x6380, "F_0815", "N/A", "N/A" },
//{ 0x63, 0x40, 0x6340, "F_0816", "N/A", "N/A" },
//{ 0x63, 0x20, 0x6320, "F_0817", "N/A", "N/A" },
//{ 0x63, 0x10, 0x6310, "F_0818", "N/A", "N/A" },
//{ 0x63, 0x08, 0x6308, "F_0819", "N/A", "N/A" },
//{ 0x63, 0x04, 0x6304, "F_0820", "N/A", "N/A" },
{ 0x63, 0x02, 0x6302, "KORO2_ALLCLEAR", "After all stages (8-8) of roll goal game cleared", "Fishing" },
};
struct MultiBitEventFlag {
uint8_t byteInd;
const char* description;
};
inline const MultiBitEventFlag duskImguiU8Events[] = {
{ 0xf2, "Ordon Catfish size record in Fishing Hole (in cm)" },
{ 0xf3, "Hylian Pike size record in Fishing Hole (in cm)" },
{ 0xf4, "Hylian Loach size record in Fishing Hole (in cm)" },
{ 0xf5, "Hyrule Bass size record in Fishing Hole (in cm)" },
{ 0xf6, "Number of Rollgoal Levels beaten" },
};
inline const MultiBitEventFlag duskImguiU16Events[] = {
{ 0xf7, "Rupees donated to Charlo" },
{ 0xf9, "Rupees donated towards the current Malo Mart donation goal" },
};
inline const MultiBitEventFlag duskImguiSwappedU16Events[] = {
{ 0xfb, "Rupees paid to Trill" },
{ 0xfd, "Rupees owed to Trill" },
};
#endif // !DUSK_IMGUI_EVENTFLAGS_HPP
+12 -9
View File
@@ -1,6 +1,7 @@
#include "fmt/format.h"
#include "imgui.h"
#include "ImGuiEngine.hpp"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiConfig.hpp"
@@ -32,15 +33,17 @@ namespace dusk {
void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Game")) {
if (ImGui::BeginMenu("Graphics")) {
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
ToggleFullscreen();
}
if (!IsMobile) {
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
ToggleFullscreen();
}
if (ImGui::MenuItem("Default Window Size")) {
getSettings().video.enableFullscreen.setValue(false);
VISetWindowFullscreen(false);
VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2);
VICenterWindow();
if (ImGui::MenuItem("Default Window Size")) {
getSettings().video.enableFullscreen.setValue(false);
VISetWindowFullscreen(false);
VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2);
VICenterWindow();
}
}
bool vsync = getSettings().video.enableVsync;
@@ -147,7 +150,7 @@ namespace dusk {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
if (ImGui::MenuItem("Exit")) {
if (!IsMobile && ImGui::MenuItem("Exit")) {
dusk::IsRunning = false;
}
+21 -29
View File
@@ -4,13 +4,13 @@
#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 "../iso_validate.hpp"
#include <SDL3/SDL_dialog.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_filesystem.h>
#include "aurora/lib/internal.hpp"
@@ -46,30 +46,22 @@ static std::string ShowIsoInvalidError(const iso::ValidationError code) {
}
}
void fileDialogCallback(void* userdata, const char* const* filelist, [[maybe_unused]] int filter) {
void fileDialogCallback(void* userdata, const char* path, const char* error) {
auto* self = static_cast<ImGuiPreLaunchWindow*>(userdata);
self->m_errorString.clear();
if (filelist != nullptr) {
if (filelist[0] == nullptr) {
// Cancelled
self->m_selectedIsoPath.clear();
} else {
const auto path = filelist[0];
const auto ret = iso::validate(path);
if (ret != iso::ValidationError::Success) {
self->m_selectedIsoPath.clear();
self->m_errorString = std::move(ShowIsoInvalidError(ret));
return;
}
self->m_selectedIsoPath = path;
getSettings().backend.isoPath.setValue(path);
config::Save();
}
} else {
// Error occurred
if (error != nullptr) {
self->m_selectedIsoPath.clear();
self->m_errorString = fmt::format("File dialog error: {}", SDL_GetError());
self->m_errorString = fmt::format("File dialog error: {}", error);
return;
}
if (path == nullptr) {
self->m_selectedIsoPath.clear();
return;
}
self->m_selectedIsoPath = path;
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
config::Save();
}
ImGuiPreLaunchWindow::ImGuiPreLaunchWindow() = default;
@@ -144,9 +136,9 @@ void ImGuiPreLaunchWindow::drawMainMenu() {
}
if (ImGuiButtonCenter("Select disc image...")) {
SDL_ShowOpenFileDialog(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()),
nullptr, false);
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
false);
}
} else {
if (ImGuiButtonCenter("Start game")) {
@@ -187,9 +179,9 @@ void ImGuiPreLaunchWindow::drawOptions() {
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine();
if (ImGui::Button("Set")) {
SDL_ShowOpenFileDialog(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()),
nullptr, false);
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
false);
}
AuroraBackend configuredBackend = BACKEND_AUTO;
+123 -12
View File
@@ -4,6 +4,7 @@
#include "ImGuiConsole.hpp"
#include "ImGuiSaveEditor.hpp"
#include "ImGuiEventFlags.hpp"
#include "d/d_com_inf_game.h"
#include "d/d_item_data.h"
@@ -1419,20 +1420,130 @@ namespace dusk {
if (ImGui::TreeNode("Event Flags")) {
dSv_event_c& event = dComIfGs_getSaveData()->mEvent;
for (int e = 0; e < 255; e++) {
ImGui::Text("%03d ", e);
ImGui::SameLine(80.0f);
for (int i = 7; i >= 0; i--) {
bool flag = event.mEvent[e] & (1 << i);
if (ImGui::Checkbox(fmt::format("##event{0}{1}", e, i).c_str(), &flag)) {
if (flag)
event.mEvent[e] |= (1 << i);
else
event.mEvent[e] &= ~(1 << i);
static ImGuiTextFilter filter;
filter.Draw(); // Search bar
ImVec2 flagTableSize = {700, 400};
if (ImGui::BeginTable("Events", 4,
ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | ImGuiTableFlags_Sortable,
flagTableSize))
{
ImGui::TableSetupScrollFreeze(0, 1);
constexpr int COLUMN_FLAG = 0, COLUMN_NAME = 1, COLUMN_LOC = 2, COLUMN_DESC = 3;
ImGui::TableSetupColumn("Flag");
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Location");
ImGui::TableSetupColumn("Description");
ImGui::TableHeadersRow();
// if we're sorting by whether the flag is set or not,
// we want to re-sort whenever a flag updates, which means every frame cuz we don't know when it changes.
// otherwise only re-sort when the sort is dirty
if (auto* sort = ImGui::TableGetSortSpecs();
sort != nullptr && sort->SpecsCount > 0 &&
(sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG))
{
auto column = sort->Specs->ColumnIndex;
const auto cmp = [&](const duskImguiEventFlagEntry& l,
const duskImguiEventFlagEntry& r) -> bool {
switch (column) {
case COLUMN_FLAG:
return (bool)event.isEventBit(l.flagID) <
(bool)event.isEventBit(r.flagID);
case COLUMN_NAME:
return l.flagName < r.flagName;
case COLUMN_LOC:
return l.location < r.location;
case COLUMN_DESC:
return l.description < r.description;
}
return false;
};
const auto direction = sort->Specs[0].SortDirection;
if (direction == ImGuiSortDirection_Ascending) {
std::sort(std::begin(duskImguiEventFlags), std::end(duskImguiEventFlags), cmp);
} else {
std::sort(std::rbegin(duskImguiEventFlags), std::rend(duskImguiEventFlags), cmp);
}
ImGui::SameLine();
sort->SpecsDirty = false;
}
ImGui::NewLine();
for (const auto& e : duskImguiEventFlags) {
if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str()))
{
continue;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool flag = event.getEventReg(e.flagID);
if (ImGui::Checkbox(("##" + e.flagName).c_str(), &flag)) {
if (flag) {
event.onEventBit(e.flagID);
} else {
event.offEventBit(e.flagID);
}
}
ImGui::TableNextColumn();
ImGui::Text(e.flagName.c_str());
ImGui::TableNextColumn();
ImGui::Text(e.location.c_str());
ImGui::TableNextColumn();
ImGui::Text(e.description.c_str());
}
ImGui::EndTable();
}
// event values that are stored as u8s in the event flags
for (const auto& e : duskImguiU8Events) {
int v = event.mEvent[e.byteInd];
if (ImGui::InputInt(e.description, &v)) {
v = std::clamp(v, 0, 0xff);
event.mEvent[e.byteInd] = (u8)v;
}
}
// event values that are stored as u16s in the event flags
for (const auto& e : duskImguiU16Events) {
int v = (event.mEvent[e.byteInd] << 8) | event.mEvent[e.byteInd + 1];
if (ImGui::InputInt(e.description, &v)) {
v = std::clamp(v, 0, 0xffff);
event.mEvent[e.byteInd] = (u8)(v >> 8);
event.mEvent[e.byteInd + 1] = (u8)v;
}
}
// event values that are stored as swapped u16s in the event flags
for (const auto& e : duskImguiSwappedU16Events) {
int v = (event.mEvent[e.byteInd + 1] << 8) | event.mEvent[e.byteInd];
if (ImGui::InputInt(e.description, &v)) {
v = std::clamp(v, 0, 0xffff);
event.mEvent[e.byteInd + 1] = (u8)(v >> 8);
event.mEvent[e.byteInd] = (u8)v;
}
}
if (ImGui::TreeNode("Event Matrix")) {
for (int e = 0; e < 255; e++) {
ImGui::Text("%03d ", e);
ImGui::SameLine(80.0f);
for (int i = 7; i >= 0; i--) {
bool flag = event.mEvent[e] & (1 << i);
if (ImGui::Checkbox(fmt::format("##event{0}{1}", e, i).c_str(), &flag)) {
if (flag)
event.mEvent[e] |= (1 << i);
else
event.mEvent[e] &= ~(1 << i);
}
ImGui::SameLine();
}
ImGui::NewLine();
}
ImGui::TreePop();
}
ImGui::TreePop();
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <stdbool.h>
#include <SDL3/SDL_dialog.h>
struct SDL_Window;
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*IOSFileCallback)(void* userdata, const char* path, const char* error);
void Dusk_iOS_ShowFileSelect(IOSFileCallback callback, void* userdata, SDL_Window* window,
const SDL_DialogFileFilter* filters, int nfilters,
const char* default_location, bool allow_many);
#ifdef __cplusplus
}
#endif
+151
View File
@@ -0,0 +1,151 @@
#include "FileSelectDialog.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import <objc/runtime.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_video.h>
static void *g_picker_delegate_key = &g_picker_delegate_key;
static void RunOnMainThread(void (^block)(void))
{
if ([NSThread isMainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
static NSError *MakeError(NSString *message)
{
return [NSError errorWithDomain:@"org.twilitrealm.dusk.file-select"
code:1
userInfo:@{NSLocalizedDescriptionKey: message}];
}
static UIViewController *FindTopViewController(UIViewController *controller)
{
UIViewController *current = controller;
while (current.presentedViewController != nil) {
current = current.presentedViewController;
}
return current;
}
static UIViewController *PresenterFromWindow(SDL_Window *window)
{
if (window == nil) {
return nil;
}
const SDL_PropertiesID props = SDL_GetWindowProperties(window);
if (props == 0) {
return nil;
}
UIWindow *uiwindow = (__bridge UIWindow *)SDL_GetPointerProperty(
props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL);
if (uiwindow == nil || uiwindow.rootViewController == nil) {
return nil;
}
return FindTopViewController(uiwindow.rootViewController);
}
static NSURL *InitialDirectoryURL(const char *default_location)
{
if (default_location == NULL || *default_location == '\0') {
return nil;
}
NSString *path = [NSString stringWithUTF8String:default_location];
NSURL *url = [NSURL fileURLWithPath:path];
if ([path hasSuffix:@"/"]) {
return url;
}
return [url URLByDeletingLastPathComponent];
}
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
@property(nonatomic, assign) IOSFileCallback callback;
@property(nonatomic, assign) void *userdata;
@end
@implementation DocumentPickerDelegate
- (void)finishWithPath:(const char *)path error:(const char *)error {
if (self.callback != NULL) {
self.callback(self.userdata, path, error);
}
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller
didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
{
NSURL *url = urls.firstObject;
if (url == nil) {
[self finishWithPath:NULL error:NULL];
return;
}
[self finishWithPath:url.path.UTF8String error:NULL];
(void)controller;
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
[self finishWithPath:NULL error:NULL];
(void)controller;
}
@end
void Dusk_iOS_ShowFileSelect(IOSFileCallback callback, void *userdata,
SDL_Window *window,
const SDL_DialogFileFilter *filters, int nfilters,
const char *default_location,
bool allow_many)
{
RunOnMainThread(^{
@autoreleasepool {
UIViewController *presenter = PresenterFromWindow(window);
if (presenter == nil) {
callback(userdata, NULL, "Failed to find an iOS view controller for the file picker.");
return;
}
NSLog(@"[ShowFileSelect] presenting picker from %@", NSStringFromClass([presenter class]));
UIDocumentPickerViewController *picker =
[[UIDocumentPickerViewController alloc]
initForOpeningContentTypes:@[ UTTypeItem ]
asCopy:YES];
picker.allowsMultipleSelection = allow_many ? YES : NO;
picker.shouldShowFileExtensions = YES;
NSURL *directory_url = InitialDirectoryURL(default_location);
if (directory_url != nil) {
picker.directoryURL = directory_url;
}
DocumentPickerDelegate *delegate = [DocumentPickerDelegate new];
delegate.callback = callback;
delegate.userdata = userdata;
picker.delegate = delegate;
objc_setAssociatedObject(picker, g_picker_delegate_key, delegate,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[presenter presentViewController:picker animated:YES completion:nil];
(void)filters;
(void)nfilters;
}
});
}
+87 -2
View File
@@ -47,6 +47,8 @@
#endif
#if TARGET_PC
#include <SDL3/SDL_video.h>
#include "aurora/lib/window.hpp"
#include "d/actor/d_a_horse.h"
#include "dusk/dusk.h"
#include "dusk/endian.h"
@@ -636,8 +638,9 @@ void mDoGph_gInf_c::setTvSize() {
m_invScale = 1.0f / m_scale;
#if TARGET_PC
hudAspectScaleDown = 1.3571428f / mDoGph_gInf_c::getAspect();
hudAspectScaleUp = 1.0f / hudAspectScaleDown;
updateSafeAreaBounds();
hudAspectScaleUp = getSafeWidthF() / FB_WIDTH_BASE;
hudAspectScaleDown = FB_WIDTH_BASE / getSafeWidthF();
#endif
}
@@ -765,6 +768,88 @@ void mDoGph_gInf_c::setWideZoomLightProjection(Mtx& m) {
#if TARGET_PC
f32 mDoGph_gInf_c::hudAspectScaleDown = 1.0f;
f32 mDoGph_gInf_c::hudAspectScaleUp = 1.0f;
f32 mDoGph_gInf_c::m_safeMinXF = 0.0f;
f32 mDoGph_gInf_c::m_safeMinYF = 0.0f;
f32 mDoGph_gInf_c::m_safeMaxXF = FB_WIDTH_BASE;
f32 mDoGph_gInf_c::m_safeMaxYF = FB_HEIGHT_BASE;
f32 mDoGph_gInf_c::m_safeWidthF = FB_WIDTH_BASE;
f32 mDoGph_gInf_c::m_safeHeightF = FB_HEIGHT_BASE;
void mDoGph_gInf_c::updateSafeAreaBounds() {
m_safeMinXF = m_minXF;
m_safeMinYF = m_minYF;
m_safeMaxXF = m_maxXF;
m_safeMaxYF = m_maxYF;
m_safeWidthF = m_widthF;
m_safeHeightF = m_heightF;
SDL_Window* window = aurora::window::get_sdl_window();
if (window == NULL) {
return;
}
const AuroraWindowSize windowSize = aurora::window::get_window_size();
const f32 windowWidth = static_cast<f32>(windowSize.width);
const f32 windowHeight = static_cast<f32>(windowSize.height);
if (windowWidth <= 0.0f || windowHeight <= 0.0f) {
return;
}
SDL_Rect safeRect{};
if (!SDL_GetWindowSafeArea(window, &safeRect)) {
return;
}
if (windowSize.native_fb_width == 0 || windowSize.native_fb_height == 0 ||
windowSize.fb_width == 0 || windowSize.fb_height == 0)
{
return;
}
const f32 nativeScaleX = static_cast<f32>(windowSize.native_fb_width) / windowWidth;
const f32 nativeScaleY = static_cast<f32>(windowSize.native_fb_height) / windowHeight;
const f32 safeLeft = static_cast<f32>(safeRect.x) * nativeScaleX;
const f32 safeTop = static_cast<f32>(safeRect.y) * nativeScaleY;
const f32 safeRight = static_cast<f32>(safeRect.x + safeRect.w) * nativeScaleX;
const f32 safeBottom = static_cast<f32>(safeRect.y + safeRect.h) * nativeScaleY;
const f32 viewportLeft =
(static_cast<f32>(windowSize.native_fb_width) - static_cast<f32>(windowSize.fb_width)) *
0.5f;
const f32 viewportTop =
(static_cast<f32>(windowSize.native_fb_height) - static_cast<f32>(windowSize.fb_height)) *
0.5f;
const f32 viewportRight = viewportLeft + static_cast<f32>(windowSize.fb_width);
const f32 viewportBottom = viewportTop + static_cast<f32>(windowSize.fb_height);
const f32 leftInset = std::max(0.0f, safeLeft - viewportLeft) *
(m_widthF / static_cast<f32>(windowSize.fb_width));
const f32 topInset = std::max(0.0f, safeTop - viewportTop) *
(m_heightF / static_cast<f32>(windowSize.fb_height));
const f32 rightInset = std::max(0.0f, viewportRight - safeRight) *
(m_widthF / static_cast<f32>(windowSize.fb_width));
const f32 bottomInset = std::max(0.0f, viewportBottom - safeBottom) *
(m_heightF / static_cast<f32>(windowSize.fb_height));
const f32 safeMinXF = m_minXF + leftInset;
const f32 safeMinYF = m_minYF + topInset;
const f32 safeMaxXF = m_maxXF - rightInset;
const f32 safeMaxYF = m_maxYF - bottomInset;
const f32 safeWidthF = safeMaxXF - safeMinXF;
const f32 safeHeightF = safeMaxYF - safeMinYF;
if (safeWidthF <= 0.0f || safeHeightF <= 0.0f) {
return;
}
m_safeMinXF = safeMinXF;
m_safeMinYF = safeMinYF;
m_safeMaxXF = safeMaxXF;
m_safeMaxYF = safeMaxYF;
m_safeWidthF = safeWidthF;
m_safeHeightF = safeHeightF;
}
void mDoGph_gInf_c::setWindowSize(AuroraWindowSize const& size) {
JUTVideo::getManager()->setWindowSize(size);
+1 -1
View File
@@ -154,7 +154,7 @@ void mDoLib_project(Vec* src, Vec* dst, JGeometry::TBox2<f32> viewport) {
xSize = FB_WIDTH;
} else {
#if TARGET_PC
xOffset = mDoGph_gInf_c::getMinXF();
xOffset = mDoGph_gInf_c::getSafeMinXF();
xSize = viewport.f.x * mDoGph_gInf_c::hudAspectScaleUp;
#else
xOffset = viewport.i.x;
+12 -6
View File
@@ -133,6 +133,9 @@ bool launchUILoop() {
const AuroraEvent* event = aurora_update();
while (event != nullptr && event->type != AURORA_NONE) {
switch (event->type) {
case AURORA_SDL_EVENT:
dusk::g_imguiConsole.HandleSDLEvent(event->sdl);
break;
case AURORA_WINDOW_RESIZED:
preLaunchUIWindowSize = event->windowSize;
break;
@@ -202,9 +205,9 @@ void main01(void) {
if (preLaunchUIWindowSize.width != 0)
mDoGph_gInf_c::setWindowSize(preLaunchUIWindowSize);
constexpr double kSimStepSeconds = 1.0 / 30.0;
constexpr float kSimStepSeconds = 1.0 / 30.0;
auto previous_time = std::chrono::steady_clock::now();
double accumulator = kSimStepSeconds;
float accumulator = kSimStepSeconds;
do {
// 1. Update Window Events
@@ -213,6 +216,9 @@ void main01(void) {
switch (event->type) {
case AURORA_NONE:
goto eventsDone;
case AURORA_SDL_EVENT:
dusk::g_imguiConsole.HandleSDLEvent(event->sdl);
break;
case AURORA_WINDOW_RESIZED:
mDoGph_gInf_c::setWindowSize(event->windowSize);
break;
@@ -229,7 +235,7 @@ void main01(void) {
eventsDone:;
auto current_time = std::chrono::steady_clock::now();
double frame_seconds = std::chrono::duration<double>(current_time - previous_time).count();
float frame_seconds = std::chrono::duration<float>(current_time - previous_time).count();
previous_time = current_time;
accumulator += frame_seconds;
@@ -243,12 +249,12 @@ void main01(void) {
if (dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit) {
dusk::frame_interp::notify_presentation_frame();
while (accumulator >= kSimStepSeconds) {
if (accumulator >= kSimStepSeconds) {
mDoCPd_c::read();
dusk::gyro::read(kSimStepSeconds);
fapGm_Execute();
mDoAud_Execute();
accumulator -= kSimStepSeconds;
accumulator = 0.0f;
}
dusk::frame_interp::interpolate(static_cast<float>(accumulator / kSimStepSeconds));
{
@@ -256,7 +262,7 @@ void main01(void) {
cAPIGph_Painter();
}
} else {
accumulator = 0.0;
accumulator = 0.0f;
// Game Inputs
mDoCPd_c::read();