mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-19 21:03:42 -07:00
Merge branch 'develop' of github.com:Malkierian/Shipwright into lus-bump-mpq
This commit is contained in:
commit
86d7e301de
83 changed files with 10221 additions and 20928 deletions
2
.github/workflows/apt-deps.txt
vendored
2
.github/workflows/apt-deps.txt
vendored
|
@ -1 +1 @@
|
||||||
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libespeak-ng-dev ninja-build
|
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build libogg-dev libopus-dev opus-tools libopusfile-dev libvorbis-dev libespeak-ng-dev
|
2
.github/workflows/macports-deps.txt
vendored
2
.github/workflows/macports-deps.txt
vendored
|
@ -1 +1 @@
|
||||||
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal libzip +universal nlohmann-json +universal tinyxml2 +universal
|
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal libzip +universal nlohmann-json +universal tinyxml2 +universal libogg +universal libopus +universal opusfile +universal libvorbis +universal
|
61
CMake/FindOgg.cmake
Normal file
61
CMake/FindOgg.cmake
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# - Find ogg
|
||||||
|
# Find the native ogg includes and libraries
|
||||||
|
#
|
||||||
|
# OGG_INCLUDE_DIRS - where to find ogg.h, etc.
|
||||||
|
# OGG_LIBRARIES - List of libraries when using ogg.
|
||||||
|
# OGG_FOUND - True if ogg found.
|
||||||
|
|
||||||
|
if (OGG_INCLUDE_DIR)
|
||||||
|
# Already in cache, be silent
|
||||||
|
set(OGG_FIND_QUIETLY TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
find_package (PkgConfig QUIET)
|
||||||
|
pkg_check_modules (PC_OGG QUIET ogg>=1.3.0)
|
||||||
|
|
||||||
|
set (OGG_VERSION ${PC_OGG_VERSION})
|
||||||
|
|
||||||
|
find_path (OGG_INCLUDE_DIR ogg/ogg.h
|
||||||
|
HINTS
|
||||||
|
${PC_OGG_INCLUDEDIR}
|
||||||
|
${PC_OGG_INCLUDE_DIRS}
|
||||||
|
${OGG_ROOT}
|
||||||
|
)
|
||||||
|
# MSVC built ogg may be named ogg_static.
|
||||||
|
# The provided project files name the library with the lib prefix.
|
||||||
|
find_library (OGG_LIBRARY
|
||||||
|
NAMES
|
||||||
|
ogg
|
||||||
|
ogg_static
|
||||||
|
libogg
|
||||||
|
libogg_static
|
||||||
|
HINTS
|
||||||
|
${PC_OGG_LIBDIR}
|
||||||
|
${PC_OGG_LIBRARY_DIRS}
|
||||||
|
${OGG_ROOT}
|
||||||
|
)
|
||||||
|
# Handle the QUIETLY and REQUIRED arguments and set OGG_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE.
|
||||||
|
include (FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args (Ogg
|
||||||
|
REQUIRED_VARS
|
||||||
|
OGG_LIBRARY
|
||||||
|
OGG_INCLUDE_DIR
|
||||||
|
VERSION_VAR
|
||||||
|
OGG_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
if (OGG_FOUND)
|
||||||
|
set (OGG_LIBRARIES ${OGG_LIBRARY})
|
||||||
|
set (OGG_INCLUDE_DIRS ${OGG_INCLUDE_DIR})
|
||||||
|
|
||||||
|
if(NOT TARGET Ogg::ogg)
|
||||||
|
add_library(Ogg::ogg UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(Ogg::ogg PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${OGG_INCLUDE_DIRS}"
|
||||||
|
IMPORTED_LOCATION "${OGG_LIBRARIES}"
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
mark_as_advanced (OGG_INCLUDE_DIR OGG_LIBRARY)
|
44
CMake/FindOpus.cmake
Normal file
44
CMake/FindOpus.cmake
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# - FindOpus.cmake
|
||||||
|
# Find the native opus includes and libraries
|
||||||
|
#
|
||||||
|
# OPUS_INCLUDE_DIRS - where to find opus/opus.h, etc.
|
||||||
|
# OPUS_LIBRARIES - List of libraries when using libopus(file).
|
||||||
|
# OPUS_FOUND - True if libopus found.
|
||||||
|
|
||||||
|
if(OPUS_INCLUDE_DIR AND OPUS_LIBRARY AND OPUSFILE_LIBRARY)
|
||||||
|
# Already in cache, be silent
|
||||||
|
set(OPUS_FIND_QUIETLY TRUE)
|
||||||
|
endif(OPUS_INCLUDE_DIR AND OPUS_LIBRARY AND OPUSFILE_LIBRARY)
|
||||||
|
|
||||||
|
find_path(OPUS_INCLUDE_DIR
|
||||||
|
NAMES opusfile.h
|
||||||
|
PATH_SUFFIXES opus
|
||||||
|
)
|
||||||
|
|
||||||
|
# MSVC built opus may be named opus_static
|
||||||
|
# The provided project files name the library with the lib prefix.
|
||||||
|
find_library(OPUS_LIBRARY
|
||||||
|
NAMES opus opus_static libopus libopus_static
|
||||||
|
)
|
||||||
|
#find_library(OPUSFILE_LIBRARY
|
||||||
|
# NAMES opusfile opusfile_static libopusfile libopusfile_static
|
||||||
|
#)
|
||||||
|
|
||||||
|
# Handle the QUIETLY and REQUIRED arguments and set OPUS_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE.
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(Opus DEFAULT_MSG
|
||||||
|
OPUS_LIBRARY OPUS_INCLUDE_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
if(OPUS_FOUND)
|
||||||
|
set(OPUS_LIBRARIES ${OPUS_LIBRARY})
|
||||||
|
set(OPUS_INCLUDE_DIRS ${OPUS_INCLUDE_DIR})
|
||||||
|
if(NOT TARGET Opus::opus)
|
||||||
|
add_library(Opus::opus UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(Opus::opus PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${OPUS_INCLUDE_DIRS}"
|
||||||
|
IMPORTED_LOCATION "${OPUS_LIBRARIES}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif(OPUS_FOUND)
|
55
CMake/FindOpusFile.cmake
Normal file
55
CMake/FindOpusFile.cmake
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# FindOpusFile.cmake
|
||||||
|
# Locate the libopusfile library and its dependencies (libopus and libogg).
|
||||||
|
# Defines the following variables on success:
|
||||||
|
# OPUSFILE_FOUND - Indicates if opusfile was found
|
||||||
|
# OPUSFILE_INCLUDE_DIR - Directory containing opusfile.h
|
||||||
|
# OPUSFILE_LIBRARY - Path to the opusfile library
|
||||||
|
# OPUSFILE_LIBRARIES - Full list of libraries to link (opusfile, opus, ogg)
|
||||||
|
|
||||||
|
# Search for the OpusFile header
|
||||||
|
find_path(OPUSFILE_INCLUDE_DIR
|
||||||
|
NAMES opusfile.h
|
||||||
|
PATHS /usr/include/opus /usr/local/include/opus /opt/local/include/opus /opt/homebrew/include/opus
|
||||||
|
DOC "Directory where opusfile.h is located"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Search for the OpusFile library
|
||||||
|
find_library(OPUSFILE_LIBRARY
|
||||||
|
NAMES opusfile
|
||||||
|
DOC "Path to the libopusfile library"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Search for the Opus library (dependency of OpusFile)
|
||||||
|
find_library(OPUS_LIBRARY
|
||||||
|
NAMES opus
|
||||||
|
DOC "Path to the libopus library (dependency of libopusfile)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Search for the Ogg library (dependency of OpusFile)
|
||||||
|
find_library(OGG_LIBRARY
|
||||||
|
NAMES ogg
|
||||||
|
DOC "Path to the libogg library (dependency of libopusfile)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if all required components are found
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(OpusFile
|
||||||
|
REQUIRED_VARS OPUSFILE_LIBRARY OPUSFILE_INCLUDE_DIR OPUS_LIBRARY OGG_LIBRARY
|
||||||
|
VERSION_VAR OPUSFILE_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define an imported target if everything is found
|
||||||
|
if (OPUSFILE_FOUND)
|
||||||
|
add_library(Opusfile::Opusfile INTERFACE IMPORTED)
|
||||||
|
|
||||||
|
set_target_properties(Opusfile::Opusfile PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${OPUSFILE_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES "${OPUSFILE_LIBRARY};${OPUS_LIBRARY};${OGG_LIBRARY}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Optionally expose the include and libraries separately
|
||||||
|
set(OPUSFILE_LIBRARIES ${OPUSFILE_LIBRARY} ${OPUS_LIBRARY} ${OGG_LIBRARY})
|
||||||
|
set(OPUSFILE_INCLUDE_DIRS ${OPUSFILE_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
set(OPUSFILE_FOUND FALSE)
|
||||||
|
endif()
|
210
CMake/FindVorbis.cmake
Normal file
210
CMake/FindVorbis.cmake
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindVorbis
|
||||||
|
----------
|
||||||
|
|
||||||
|
Finds the native vorbis, vorbisenc amd vorbisfile includes and libraries.
|
||||||
|
|
||||||
|
Imported Targets
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module provides the following imported targets, if found:
|
||||||
|
|
||||||
|
``Vorbis::vorbis``
|
||||||
|
The Vorbis library
|
||||||
|
``Vorbis::vorbisenc``
|
||||||
|
The VorbisEnc library
|
||||||
|
``Vorbis::vorbisfile``
|
||||||
|
The VorbisFile library
|
||||||
|
|
||||||
|
Result Variables
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This will define the following variables:
|
||||||
|
|
||||||
|
``Vorbis_Vorbis_INCLUDE_DIRS``
|
||||||
|
List of include directories when using vorbis.
|
||||||
|
``Vorbis_Enc_INCLUDE_DIRS``
|
||||||
|
List of include directories when using vorbisenc.
|
||||||
|
``Vorbis_File_INCLUDE_DIRS``
|
||||||
|
List of include directories when using vorbisfile.
|
||||||
|
``Vorbis_Vorbis_LIBRARIES``
|
||||||
|
List of libraries when using vorbis.
|
||||||
|
``Vorbis_Enc_LIBRARIES``
|
||||||
|
List of libraries when using vorbisenc.
|
||||||
|
``Vorbis_File_LIBRARIES``
|
||||||
|
List of libraries when using vorbisfile.
|
||||||
|
``Vorbis_FOUND``
|
||||||
|
True if vorbis and requested components found.
|
||||||
|
``Vorbis_Vorbis_FOUND``
|
||||||
|
True if vorbis found.
|
||||||
|
``Vorbis_Enc_FOUND``
|
||||||
|
True if vorbisenc found.
|
||||||
|
``Vorbis_Enc_FOUND``
|
||||||
|
True if vorbisfile found.
|
||||||
|
|
||||||
|
Cache variables
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The following cache variables may also be set:
|
||||||
|
|
||||||
|
``Vorbis_Vorbis_INCLUDE_DIR``
|
||||||
|
The directory containing ``vorbis/vorbis.h``.
|
||||||
|
``Vorbis_Enc_INCLUDE_DIR``
|
||||||
|
The directory containing ``vorbis/vorbisenc.h``.
|
||||||
|
``Vorbis_File_INCLUDE_DIR``
|
||||||
|
The directory containing ``vorbis/vorbisenc.h``.
|
||||||
|
``Vorbis_Vorbis_LIBRARY``
|
||||||
|
The path to the vorbis library.
|
||||||
|
``Vorbis_Enc_LIBRARY``
|
||||||
|
The path to the vorbisenc library.
|
||||||
|
``Vorbis_File_LIBRARY``
|
||||||
|
The path to the vorbisfile library.
|
||||||
|
|
||||||
|
Hints
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
A user may set ``Vorbis_ROOT`` to a vorbis installation root to tell this module where to look.
|
||||||
|
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
if (Vorbis_Vorbis_INCLUDE_DIR)
|
||||||
|
# Already in cache, be silent
|
||||||
|
set (Vorbis_FIND_QUIETLY TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set (Vorbis_Vorbis_FIND_QUIETLY TRUE)
|
||||||
|
set (Vorbis_Enc_FIND_QUIETLY TRUE)
|
||||||
|
set (Vorbis_File_FIND_QUIETLY TRUE)
|
||||||
|
|
||||||
|
find_package (Ogg QUIET)
|
||||||
|
|
||||||
|
find_package (PkgConfig QUIET)
|
||||||
|
pkg_check_modules (PC_Vorbis_Vorbis QUIET vorbis)
|
||||||
|
pkg_check_modules (PC_Vorbis_Enc QUIET vorbisenc)
|
||||||
|
pkg_check_modules (PC_Vorbis_File QUIET vorbisfile)
|
||||||
|
|
||||||
|
set (Vorbis_VERSION ${PC_Vorbis_Vorbis_VERSION})
|
||||||
|
|
||||||
|
find_path (Vorbis_Vorbis_INCLUDE_DIR vorbis/codec.h
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_Vorbis_INCLUDEDIR}
|
||||||
|
${PC_Vorbis_Vorbis_INCLUDE_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_path (Vorbis_Enc_INCLUDE_DIR vorbis/vorbisenc.h
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_Enc_INCLUDEDIR}
|
||||||
|
${PC_Vorbis_Enc_INCLUDE_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_path (Vorbis_File_INCLUDE_DIR vorbis/vorbisfile.h
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_File_INCLUDEDIR}
|
||||||
|
${PC_Vorbis_File_INCLUDE_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library (Vorbis_Vorbis_LIBRARY
|
||||||
|
NAMES
|
||||||
|
vorbis
|
||||||
|
vorbis_static
|
||||||
|
libvorbis
|
||||||
|
libvorbis_static
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_Vorbis_LIBDIR}
|
||||||
|
${PC_Vorbis_Vorbis_LIBRARY_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library (Vorbis_Enc_LIBRARY
|
||||||
|
NAMES
|
||||||
|
vorbisenc
|
||||||
|
vorbisenc_static
|
||||||
|
libvorbisenc
|
||||||
|
libvorbisenc_static
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_Enc_LIBDIR}
|
||||||
|
${PC_Vorbis_Enc_LIBRARY_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library (Vorbis_File_LIBRARY
|
||||||
|
NAMES
|
||||||
|
vorbisfile
|
||||||
|
vorbisfile_static
|
||||||
|
libvorbisfile
|
||||||
|
libvorbisfile_static
|
||||||
|
HINTS
|
||||||
|
${PC_Vorbis_File_LIBDIR}
|
||||||
|
${PC_Vorbis_File_LIBRARY_DIRS}
|
||||||
|
${Vorbis_ROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
include (FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
if (Vorbis_Vorbis_LIBRARY AND Vorbis_Vorbis_INCLUDE_DIR AND Ogg_FOUND)
|
||||||
|
set (Vorbis_Vorbis_FOUND TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (Vorbis_Enc_LIBRARY AND Vorbis_Enc_INCLUDE_DIR AND Vorbis_Vorbis_FOUND)
|
||||||
|
set (Vorbis_Enc_FOUND TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (Vorbis_Vorbis_FOUND AND Vorbis_File_LIBRARY AND Vorbis_File_INCLUDE_DIR)
|
||||||
|
set (Vorbis_File_FOUND TRUE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
find_package_handle_standard_args (Vorbis
|
||||||
|
REQUIRED_VARS
|
||||||
|
Vorbis_Vorbis_LIBRARY
|
||||||
|
Vorbis_Vorbis_INCLUDE_DIR
|
||||||
|
Ogg_FOUND
|
||||||
|
HANDLE_COMPONENTS
|
||||||
|
VERSION_VAR Vorbis_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
if (Vorbis_Vorbis_FOUND)
|
||||||
|
set (Vorbis_Vorbis_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR})
|
||||||
|
set (Vorbis_Vorbis_LIBRARIES ${VORBIS_LIBRARY} ${OGG_LIBRARIES})
|
||||||
|
if (NOT TARGET Vorbis::vorbis)
|
||||||
|
add_library (Vorbis::vorbis UNKNOWN IMPORTED)
|
||||||
|
set_target_properties (Vorbis::vorbis PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Vorbis_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LOCATION "${Vorbis_Vorbis_LIBRARY}"
|
||||||
|
INTERFACE_LINK_LIBRARIES Ogg::ogg
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (Vorbis_Enc_FOUND)
|
||||||
|
set (Vorbis_Enc_INCLUDE_DIRS ${Vorbis_Enc_INCLUDE_DIR})
|
||||||
|
set (Vorbis_Enc_LIBRARIES ${Vorbis_Enc_LIBRARY} ${Vorbis_Enc_LIBRARIES})
|
||||||
|
if (NOT TARGET Vorbis::vorbisenc)
|
||||||
|
add_library (Vorbis::vorbisenc UNKNOWN IMPORTED)
|
||||||
|
set_target_properties (Vorbis::vorbisenc PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Enc_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LOCATION "${Vorbis_Enc_LIBRARY}"
|
||||||
|
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (Vorbis_File_FOUND)
|
||||||
|
set (Vorbis_File_INCLUDE_DIRS ${Vorbis_File_INCLUDE_DIR})
|
||||||
|
set (Vorbis_File_LIBRARIES ${Vorbis_File_LIBRARY} ${Vorbis_File_LIBRARIES})
|
||||||
|
if (NOT TARGET Vorbis::vorbisfile)
|
||||||
|
add_library (Vorbis::vorbisfile UNKNOWN IMPORTED)
|
||||||
|
set_target_properties (Vorbis::vorbisfile PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_File_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LOCATION "${Vorbis_File_LIBRARY}"
|
||||||
|
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
mark_as_advanced (Vorbis_Vorbis_INCLUDE_DIR Vorbis_Vorbis_LIBRARY)
|
||||||
|
mark_as_advanced (Vorbis_Enc_INCLUDE_DIR Vorbis_Enc_LIBRARY)
|
||||||
|
mark_as_advanced (Vorbis_File_INCLUDE_DIR Vorbis_File_LIBRARY)
|
|
@ -83,8 +83,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
||||||
|
|
||||||
vcpkg_bootstrap()
|
vcpkg_bootstrap()
|
||||||
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog)
|
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile)
|
||||||
|
|
||||||
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
||||||
endif()
|
endif()
|
||||||
|
@ -154,6 +153,7 @@ set(GFX_DEBUG_DISASSEMBLER ON)
|
||||||
|
|
||||||
# Tell LUS we're using F3DEX_GBI_2 (in a way that doesn't break libgfxd)
|
# Tell LUS we're using F3DEX_GBI_2 (in a way that doesn't break libgfxd)
|
||||||
set(GBI_UCODE F3DEX_GBI_2)
|
set(GBI_UCODE F3DEX_GBI_2)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
|
||||||
|
|
||||||
# Enable MPQ and OTR support
|
# Enable MPQ and OTR support
|
||||||
set(INCLUDE_MPQ_SUPPORT ON)
|
set(INCLUDE_MPQ_SUPPORT ON)
|
||||||
|
|
|
@ -283,8 +283,17 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
|
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
|
||||||
endif()
|
endif()
|
||||||
################################################################################
|
################################################################################
|
||||||
# Compile definitions
|
# Find/download Dr Libs (For custom audio)
|
||||||
################################################################################
|
################################################################################
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
dr_libs
|
||||||
|
GIT_REPOSITORY https://github.com/mackron/dr_libs.git
|
||||||
|
GIT_TAG da35f9d6c7374a95353fd1df1d394d44ab66cf01
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(dr_libs)
|
||||||
|
|
||||||
find_package(SDL2)
|
find_package(SDL2)
|
||||||
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
@ -303,6 +312,10 @@ if (ESPEAK)
|
||||||
add_compile_definitions(ESPEAK=1)
|
add_compile_definitions(ESPEAK=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Compile definitions
|
||||||
|
################################################################################
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE assets
|
target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
||||||
|
@ -335,6 +348,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||||
${SDL2-INCLUDE}
|
${SDL2-INCLUDE}
|
||||||
${SDL2-NET-INCLUDE}
|
${SDL2-NET-INCLUDE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/assets/
|
${CMAKE_CURRENT_SOURCE_DIR}/assets/
|
||||||
|
${dr_libs_SOURCE_DIR}
|
||||||
.
|
.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -586,6 +600,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||||
|
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE
|
target_link_options(${PROJECT_NAME} PRIVATE
|
||||||
-pthread
|
-pthread
|
||||||
|
#-fsanitize=address
|
||||||
-Wl,-export-dynamic
|
-Wl,-export-dynamic
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
@ -626,6 +641,15 @@ endif()
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
find_package(glfw3 REQUIRED)
|
find_package(glfw3 REQUIRED)
|
||||||
|
find_package(Ogg CONFIG REQUIRED)
|
||||||
|
link_libraries(Ogg::ogg)
|
||||||
|
|
||||||
|
find_package(Vorbis CONFIG REQUIRED)
|
||||||
|
link_libraries(Vorbis::vorbisfile)
|
||||||
|
find_package(Opus CONFIG REQUIRED)
|
||||||
|
link_libraries(Opus::opus)
|
||||||
|
find_package(OpusFile CONFIG REQUIRED)
|
||||||
|
link_libraries(OpusFile::opusfile CONFIG REQUIRED)
|
||||||
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
|
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
|
||||||
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
||||||
"libultraship;"
|
"libultraship;"
|
||||||
|
@ -639,6 +663,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
"imm32;"
|
"imm32;"
|
||||||
"version;"
|
"version;"
|
||||||
"setupapi"
|
"setupapi"
|
||||||
|
"Ogg::ogg"
|
||||||
|
"Opus::opus"
|
||||||
|
"Vorbis::vorbis"
|
||||||
|
"Vorbis::vorbisenc"
|
||||||
|
"Vorbis::vorbisfile"
|
||||||
|
"OpusFile::opusfile"
|
||||||
)
|
)
|
||||||
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
|
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
|
||||||
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
||||||
|
@ -679,10 +709,21 @@ else()
|
||||||
find_package(SDL2)
|
find_package(SDL2)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
find_package(Ogg REQUIRED)
|
||||||
|
find_package(Vorbis REQUIRED)
|
||||||
|
find_package(Opus REQUIRED)
|
||||||
|
find_package(OpusFile REQUIRED)
|
||||||
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
set(ADDITIONAL_LIBRARY_DEPENDENCIES
|
||||||
"libultraship;"
|
"libultraship;"
|
||||||
"ZAPDLib;"
|
"ZAPDLib;"
|
||||||
SDL2::SDL2
|
SDL2::SDL2
|
||||||
|
"Ogg::ogg"
|
||||||
|
"Vorbis::vorbis"
|
||||||
|
"Vorbis::vorbisenc"
|
||||||
|
"Vorbis::vorbisfile"
|
||||||
|
"Opus::opus"
|
||||||
|
"Opusfile::Opusfile"
|
||||||
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
|
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,10 @@
|
||||||
#ifndef Z64_AUDIO_H
|
#ifndef Z64_AUDIO_H
|
||||||
#define Z64_AUDIO_H
|
#define Z64_AUDIO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <endianness.h>
|
#include <endianness.h>
|
||||||
|
|
||||||
#define MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0))
|
#define MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0))
|
||||||
|
@ -24,8 +28,8 @@
|
||||||
|
|
||||||
//#define MAX_SEQUENCES 0x800
|
//#define MAX_SEQUENCES 0x800
|
||||||
extern size_t sequenceMapSize;
|
extern size_t sequenceMapSize;
|
||||||
|
extern size_t fontMapSize;
|
||||||
extern char* fontMap[256];
|
extern char** fontMap;
|
||||||
|
|
||||||
#define MAX_AUTHENTIC_SEQID 110
|
#define MAX_AUTHENTIC_SEQID 110
|
||||||
|
|
||||||
|
@ -54,7 +58,8 @@ typedef enum {
|
||||||
/* 2 */ CODEC_S16_INMEMORY,
|
/* 2 */ CODEC_S16_INMEMORY,
|
||||||
/* 3 */ CODEC_SMALL_ADPCM,
|
/* 3 */ CODEC_SMALL_ADPCM,
|
||||||
/* 4 */ CODEC_REVERB,
|
/* 4 */ CODEC_REVERB,
|
||||||
/* 5 */ CODEC_S16
|
/* 5 */ CODEC_S16,
|
||||||
|
/* 6 */ CODEC_OPUS,
|
||||||
} SampleCodec;
|
} SampleCodec;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -117,12 +122,13 @@ typedef struct {
|
||||||
/* 0x2 */ s16 arg;
|
/* 0x2 */ s16 arg;
|
||||||
} AdsrEnvelope; // size = 0x4
|
} AdsrEnvelope; // size = 0x4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct AdpcmLoop {
|
||||||
/* 0x00 */ uintptr_t start;
|
/* 0x00 */ u32 start;
|
||||||
/* 0x04 */ uintptr_t end;
|
/* 0x04 */ u32 loopEnd; // numSamples position into the sample where the loop ends
|
||||||
/* 0x08 */ u32 count;
|
/* 0x08 */ u32 count; // The number of times the loop is played before the sound completes. Setting count to -1
|
||||||
/* 0x0C */ char unk_0C[0x4];
|
// indicates that the loop should play indefinitely.
|
||||||
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
|
/* 0x0C */ u32 sampleEnd; // total number of s16-samples in the sample audio clip
|
||||||
|
/* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned
|
||||||
} AdpcmLoop; // size = 0x30 (or 0x10)
|
} AdpcmLoop; // size = 0x30 (or 0x10)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -131,24 +137,23 @@ typedef struct {
|
||||||
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
|
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
|
||||||
} AdpcmBook; // size >= 0x8
|
} AdpcmBook; // size >= 0x8
|
||||||
|
|
||||||
typedef struct
|
typedef struct SoundFontSample {
|
||||||
{
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
/* 0x00 */ u32 codec : 4;
|
///* 0x0 */ u32 unk_0 : 1;
|
||||||
/* 0x00 */ u32 medium : 2;
|
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
|
||||||
/* 0x00 */ u32 unk_bit26 : 1;
|
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
|
||||||
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
|
/* 0x0 */ u32 unk_bit26 : 1;
|
||||||
/* 0x01 */ u32 size : 24;
|
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
|
||||||
|
|
||||||
};
|
};
|
||||||
u32 asU32;
|
u32 asU32;
|
||||||
};
|
};
|
||||||
|
/* 0x1 */ u32 size; // Size of the sample
|
||||||
/* 0x04 */ u8* sampleAddr;
|
u32 fileSize;
|
||||||
/* 0x08 */ AdpcmLoop* loop;
|
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either rom or ram
|
||||||
/* 0x0C */ AdpcmBook* book;
|
/* 0x8 */ AdpcmLoop* loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram
|
||||||
u32 sampleRateMagicValue; // For wav samples only...
|
/* 0xC */ AdpcmBook* book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram
|
||||||
s32 sampleRate; // For wav samples only...
|
|
||||||
} SoundFontSample; // size = 0x10
|
} SoundFontSample; // size = 0x10
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -465,6 +470,8 @@ typedef struct {
|
||||||
/* 0x00F0 */ s16 dummyResampleState[0x10];
|
/* 0x00F0 */ s16 dummyResampleState[0x10];
|
||||||
} NoteSynthesisBuffers; // size = 0x110
|
} NoteSynthesisBuffers; // size = 0x110
|
||||||
|
|
||||||
|
struct OggOpusFile;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ u8 restart;
|
/* 0x00 */ u8 restart;
|
||||||
/* 0x01 */ u8 sampleDmaIndex;
|
/* 0x01 */ u8 sampleDmaIndex;
|
||||||
|
@ -483,6 +490,7 @@ typedef struct {
|
||||||
/* 0x1A */ u8 unk_1A;
|
/* 0x1A */ u8 unk_1A;
|
||||||
/* 0x1C */ u16 unk_1C;
|
/* 0x1C */ u16 unk_1C;
|
||||||
/* 0x1E */ u16 unk_1E;
|
/* 0x1E */ u16 unk_1E;
|
||||||
|
struct OggOpusFile* opusFile; // Only for streamed opus audio
|
||||||
} NoteSynthesisState; // size = 0x20
|
} NoteSynthesisState; // size = 0x20
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -917,7 +925,7 @@ typedef struct {
|
||||||
/* 0x3420 */ AudioPoolSplit3 persistentCommonPoolSplit;
|
/* 0x3420 */ AudioPoolSplit3 persistentCommonPoolSplit;
|
||||||
/* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit;
|
/* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit;
|
||||||
/* 0x3438 */ u8 sampleFontLoadStatus[0x30];
|
/* 0x3438 */ u8 sampleFontLoadStatus[0x30];
|
||||||
/* 0x3468 */ u8 fontLoadStatus[0x30];
|
/* 0x3468 */ u8* fontLoadStatus;
|
||||||
/* 0x3498 */ u8* seqLoadStatus;
|
/* 0x3498 */ u8* seqLoadStatus;
|
||||||
/* 0x3518 */ volatile u8 resetStatus;
|
/* 0x3518 */ volatile u8 resetStatus;
|
||||||
/* 0x3519 */ u8 audioResetSpecIdToLoad;
|
/* 0x3519 */ u8 audioResetSpecIdToLoad;
|
||||||
|
@ -1119,10 +1127,6 @@ typedef struct {
|
||||||
uint8_t fonts[16];
|
uint8_t fonts[16];
|
||||||
} SequenceData;
|
} SequenceData;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Audio_SetGameVolume(int player_id, f32 volume);
|
void Audio_SetGameVolume(int player_id, f32 volume);
|
||||||
float Audio_GetGameVolume(int player_id);
|
float Audio_GetGameVolume(int player_id);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||||
#include "soh/ShipInit.hpp"
|
#include "soh/ShipInit.hpp"
|
||||||
#include "soh/Enhancements/randomizer/context.h"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern PlayState* gPlayState;
|
extern PlayState* gPlayState;
|
||||||
|
|
35
soh/soh/Enhancements/TimeSavers/FasterPauseMenu.cpp
Normal file
35
soh/soh/Enhancements/TimeSavers/FasterPauseMenu.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||||
|
#include "soh/ShipInit.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "variables.h"
|
||||||
|
extern PlayState* gPlayState;
|
||||||
|
extern void func_808237B4(PlayState* play, Input* input);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CVAR_FASTER_PAUSE_MENU_NAME CVAR_ENHANCEMENT("FasterPauseMenu")
|
||||||
|
#define CVAR_FASTER_PAUSE_MENU_VALUE CVarGetInteger(CVAR_FASTER_PAUSE_MENU_NAME, 0)
|
||||||
|
|
||||||
|
void OnKaleidoUpdateFaster() {
|
||||||
|
ZREG(46) = 2; // pauseCtx->eye and pauseCtx->unk_1EA multiply by this for animation. Double the default value.
|
||||||
|
WREG(6) = 4; // Numerous kaleido animations divide by this for movement and alpha. Half the default value.
|
||||||
|
|
||||||
|
// Page turn animation is governed by func_808237B4. Those values don't use registers to modify the speed, so we
|
||||||
|
// just directly call it twice to effectively double the speed.
|
||||||
|
if (gPlayState->pauseCtx.state == 6 && gPlayState->pauseCtx.unk_1E4 == 1) { // In page turning mode
|
||||||
|
func_808237B4(gPlayState, gPlayState->state.input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitFasterPauseMenu() {
|
||||||
|
COND_HOOK(GameInteractor::OnKaleidoUpdate, CVAR_FASTER_PAUSE_MENU_VALUE, OnKaleidoUpdateFaster);
|
||||||
|
|
||||||
|
// Reset register values on close. These values are only used by z_kaleido_scope_PAL.c
|
||||||
|
COND_VB_SHOULD(VB_KALEIDO_UNPAUSE_CLOSE, CVAR_FASTER_PAUSE_MENU_VALUE, {
|
||||||
|
// Default values, as defined in Regs_InitDataImpl
|
||||||
|
ZREG(46) = 1;
|
||||||
|
WREG(6) = 8;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterShipInitFunc initFunc(InitFasterPauseMenu, { CVAR_FASTER_PAUSE_MENU_NAME });
|
|
@ -512,7 +512,7 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
|
||||||
/*french*/ "Selon moi, le #trésor au fond du lac# est #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, le #trésor au fond du lac# est #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
// /*spanish*/ Según dicen, el #tesoro hundido del lago# se trata de #[[1]]#.
|
// /*spanish*/ Según dicen, el #tesoro hundido del lago# se trata de #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_GF_GERUDO_MEMBERSHIP_CARD] = HintText(CustomMessage("They say that #rescuing captured carpenters# is rewarded with #[[1]]#.",
|
hintTextTable[RHT_TH_FREED_CARPENTERS] = HintText(CustomMessage("They say that #rescuing captured carpenters# is rewarded with #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Retten gefangener Zimmerleute# #[[1]]# einbrächte.",
|
/*german*/ "Man erzählt sich, daß das #Retten gefangener Zimmerleute# #[[1]]# einbrächte.",
|
||||||
/*french*/ "Selon moi, #secourir les charpentiers capturés# assure #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, #secourir les charpentiers capturés# assure #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
// /*spanish*/ Según dicen, #rescatar los apresados carpinteros# se premia con #[[1]]#.
|
// /*spanish*/ Según dicen, #rescatar los apresados carpinteros# se premia con #[[1]]#.
|
||||||
|
@ -622,24 +622,24 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
|
||||||
/*french*/ "Selon moi, #recouvert de cendres volcaniques# gît #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, #recouvert de cendres volcaniques# gît #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
// /*spanish*/ Según dicen, bajo la #ceniza volcánica# yace #[[1]]#.
|
// /*spanish*/ Según dicen, bajo la #ceniza volcánica# yace #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_GF_NORTH_F1_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
|
hintTextTable[RHT_TH_1_TORCH_CARPENTER] = HintText(CustomMessage("They say that #defeating the Gerudo in a room with 1 torch# reveals #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
|
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",//TODO_TRANSLATE update to match
|
||||||
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE update to match
|
||||||
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_GF_NORTH_F2_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
|
hintTextTable[RHT_TH_DEAD_END_CARPENTER] = HintText(CustomMessage("They say that #defeating the Gerudo in a Dead End# reveals #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
|
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",//TODO_TRANSLATE update to match
|
||||||
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE update to match
|
||||||
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_GF_SOUTH_F1_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
|
hintTextTable[RHT_TH_DOUBLE_CELL_CARPENTER] = HintText(CustomMessage("They say that #defeating the Gerudo in a large jail# reveals #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
|
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",//TODO_TRANSLATE update to match
|
||||||
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE update to match
|
||||||
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_GF_SOUTH_F2_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
|
hintTextTable[RHT_TH_STEEP_SLOPE_CARPENTER] = HintText(CustomMessage("They say that #defeating the Gerudo between steep slopes# reveals #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
|
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",//TODO_TRANSLATE update to match
|
||||||
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE update to match
|
||||||
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[1]]#.
|
||||||
|
|
||||||
hintTextTable[RHT_HF_GS_NEAR_KAK_GROTTO] = HintText(CustomMessage("They say that a #spider-guarded spider in a hole# hoards #[[1]]#.",
|
hintTextTable[RHT_HF_GS_NEAR_KAK_GROTTO] = HintText(CustomMessage("They say that a #spider-guarded spider in a hole# hoards #[[1]]#.",
|
||||||
|
@ -1496,9 +1496,37 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
|
||||||
/*german*/ "Man erzählt sich, daß ein #Krug im Kokiri-Wald# #[[1]]# enthielte.",
|
/*german*/ "Man erzählt sich, daß ein #Krug im Kokiri-Wald# #[[1]]# enthielte.",
|
||||||
/*french*/ "Selon moi, une #jarre dans la Fôret Kokiri# contient #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, une #jarre dans la Fôret Kokiri# contient #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
|
|
||||||
hintTextTable[RHT_POT_GERUDO_FORTRESS] = HintText(CustomMessage("They say that a #pot in Gerudo Fortress# contains #[[1]]#.",
|
hintTextTable[RHT_TH_BREAK_ROOM_FRONT_POT] = HintText(CustomMessage("They say that the #front pot watched by resting thieves# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
/*german*/ "Man erzählt sich, daß ein #Krug in der Gerudo-Festung# #[[1]]# enthielte.",
|
|
||||||
/*french*/ "Selon moi, une #jarre dans la Forteresse Gerudo# contient #[[1]]#.", {QM_RED, QM_GREEN}));
|
hintTextTable[RHT_TH_BREAK_ROOM_BACK_POT] = HintText(CustomMessage("They say that the #back pot watched by resting thieves# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_KITCHEN_POT_1] = HintText(CustomMessage("They say that a #Hideout's Kitchen pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_KITCHEN_POT_2] = HintText(CustomMessage("They say that a #Hideout's Kitchen pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_1_TORCH_CELL_RIGHT_POT] = HintText(CustomMessage("They say that the #thieve's right pot, watched by a single torch# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_1_TORCH_CELL_MID_POT] = HintText(CustomMessage("They say that the #thieve's middle pot, watched by a single torch# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_1_TORCH_CELL_LEFT_POT] = HintText(CustomMessage("They say that the #thieve's left pot, watched by a single torch# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_STEEP_SLOPE_RIGHT_POT] = HintText(CustomMessage("They say that a #Gerudo pot, on the right of a sloped corner# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_STEEP_SLOPE_LEFT_POT] = HintText(CustomMessage("They say that a #Gerudo pot, on the left of a sloped corner# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_NEAR_DOUBLE_CELL_RIGHT_POT] = HintText(CustomMessage("They say that the #right pot near 2 jail cells# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_NEAR_DOUBLE_CELL_MID_POT] = HintText(CustomMessage("They say that the #mid pot near 2 jail cells# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_NEAR_DOUBLE_CELL_LEFT_POT] = HintText(CustomMessage("They say that the #left pot near 2 jail cells# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_RIGHTMOST_JAILED_POT] = HintText(CustomMessage("They say that the #rightmost jailed pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_RIGHT_MIDDLE_JAILED_POT] = HintText(CustomMessage("They say that the #right middle jailed pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_LEFT_MIDDLE_JAILED_POT] = HintText(CustomMessage("They say that the #left middle jailed pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
|
hintTextTable[RHT_TH_LEFTMOST_JAILED_POT] = HintText(CustomMessage("They say that the #leftmost jailed pot# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
|
||||||
|
|
||||||
hintTextTable[RHT_POT_WASTELAND] = HintText(CustomMessage("They say that a #pot in Haunted Wasteland# contains #[[1]]#.",
|
hintTextTable[RHT_POT_WASTELAND] = HintText(CustomMessage("They say that a #pot in Haunted Wasteland# contains #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß ein #Krug in der Gespensterwüste# #[[1]]# enthielte.",
|
/*german*/ "Man erzählt sich, daß ein #Krug in der Gespensterwüste# #[[1]]# enthielte.",
|
||||||
|
@ -1961,7 +1989,7 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
|
||||||
/*german*/ "Man erzählt sich, daß das #Machen von Regen in den verlorenen Wäldern# #[[1]]# enthülle.",
|
/*german*/ "Man erzählt sich, daß das #Machen von Regen in den verlorenen Wäldern# #[[1]]# enthülle.",
|
||||||
/*french*/ "Selon moi, #jouer une mélodie orageuse dans les Bois Perdus# révèle #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, #jouer une mélodie orageuse dans les Bois Perdus# révèle #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
|
|
||||||
hintTextTable[RHT_GF_KITCHEN_SUN_FAIRY] = HintText(CustomMessage("They say that #calling the sun in a guarded kitchen# exposes #[[1]]#.",
|
hintTextTable[RHT_TH_KITCHEN_SUN_FAIRY] = HintText(CustomMessage("They say that #calling the sun in a guarded kitchen# exposes #[[1]]#.",
|
||||||
/*german*/ "Man erzählt sich, daß das #Anrufen der Sonne in einer bewachten Küche# #[[1]]# freilege.",
|
/*german*/ "Man erzählt sich, daß das #Anrufen der Sonne in einer bewachten Küche# #[[1]]# freilege.",
|
||||||
/*french*/ "Selon moi, #appeler le soleil dans une cuisine gardée# révèle #[[1]]#.", {QM_RED, QM_GREEN}));
|
/*french*/ "Selon moi, #appeler le soleil dans une cuisine gardée# révèle #[[1]]#.", {QM_RED, QM_GREEN}));
|
||||||
|
|
||||||
|
|
|
@ -811,16 +811,16 @@ void GenerateItemPool() {
|
||||||
|
|
||||||
// Gerudo Fortress
|
// Gerudo Fortress
|
||||||
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE)) {
|
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE)) {
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_1_TORCH_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
} else if (ctx->GetOption(RSK_GERUDO_KEYS).IsNot(RO_GERUDO_KEYS_VANILLA)) {
|
} else if (ctx->GetOption(RSK_GERUDO_KEYS).IsNot(RO_GERUDO_KEYS_VANILLA)) {
|
||||||
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
|
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
|
||||||
AddItemToMainPool(RG_GERUDO_FORTRESS_SMALL_KEY);
|
AddItemToMainPool(RG_GERUDO_FORTRESS_SMALL_KEY);
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
} else {
|
} else {
|
||||||
// Only add key ring if 4 Fortress keys necessary
|
// Only add key ring if 4 Fortress keys necessary
|
||||||
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS) && ctx->GetOption(RSK_KEYRINGS)) {
|
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS) && ctx->GetOption(RSK_KEYRINGS)) {
|
||||||
|
@ -843,15 +843,15 @@ void GenerateItemPool() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
|
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
ctx->PlaceItemInLocation(RC_TH_1_TORCH_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
|
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
|
||||||
} else {
|
} else {
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
ctx->PlaceItemInLocation(RC_TH_1_TORCH_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
||||||
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,9 +862,9 @@ void GenerateItemPool() {
|
||||||
ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD);
|
ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD);
|
||||||
} else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
|
} else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
|
||||||
AddItemToPool(PendingJunkPool, RG_GERUDO_MEMBERSHIP_CARD);
|
AddItemToPool(PendingJunkPool, RG_GERUDO_MEMBERSHIP_CARD);
|
||||||
ctx->PlaceItemInLocation(RC_GF_GERUDO_MEMBERSHIP_CARD, RG_ICE_TRAP, false, true);
|
ctx->PlaceItemInLocation(RC_TH_FREED_CARPENTERS, RG_ICE_TRAP, false, true);
|
||||||
} else {
|
} else {
|
||||||
ctx->PlaceItemInLocation(RC_GF_GERUDO_MEMBERSHIP_CARD, RG_GERUDO_MEMBERSHIP_CARD, false, true);
|
ctx->PlaceItemInLocation(RC_TH_FREED_CARPENTERS, RG_GERUDO_MEMBERSHIP_CARD, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys
|
// Keys
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <soh/OTRGlobals.h>
|
#include <soh/OTRGlobals.h>
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "src/overlays/actors/ovl_Obj_Comb/z_obj_comb.h"
|
#include "src/overlays/actors/ovl_Obj_Comb/z_obj_comb.h"
|
||||||
|
@ -10,12 +11,14 @@ extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);
|
||||||
|
|
||||||
void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
|
void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
|
||||||
s16 params = objComb->actor.params & 0x1F;
|
s16 params = objComb->actor.params & 0x1F;
|
||||||
|
const auto beehiveIdentity = ObjectExtension::GetInstance().Get<BeehiveIdentity>(&objComb->actor);
|
||||||
|
|
||||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && beehiveIdentity != nullptr &&
|
||||||
|
!Flags_GetRandomizerInf(beehiveIdentity->randomizerInf)) {
|
||||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &objComb->actor.world.pos, ITEM00_SOH_DUMMY);
|
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &objComb->actor.world.pos, ITEM00_SOH_DUMMY);
|
||||||
item00->randoInf = objComb->beehiveIdentity.randomizerInf;
|
item00->randoInf = beehiveIdentity->randomizerInf;
|
||||||
item00->itemEntry =
|
item00->itemEntry =
|
||||||
OTRGlobals::Instance->gRandomizer->GetItemFromKnownCheck(objComb->beehiveIdentity.randomizerCheck, GI_NONE);
|
OTRGlobals::Instance->gRandomizer->GetItemFromKnownCheck(beehiveIdentity->randomizerCheck, GI_NONE);
|
||||||
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +40,11 @@ void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
|
void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
|
||||||
s32 dmgFlags;
|
|
||||||
|
|
||||||
objComb->unk_1B0 -= 50;
|
objComb->unk_1B0 -= 50;
|
||||||
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && !Flags_GetRandomizerInf(objComb->beehiveIdentity.randomizerInf)) {
|
|
||||||
|
const auto beehiveIdentity = ObjectExtension::GetInstance().Get<BeehiveIdentity>(&objComb->actor);
|
||||||
|
if (RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES) && beehiveIdentity == nullptr &&
|
||||||
|
!Flags_GetRandomizerInf(beehiveIdentity->randomizerInf)) {
|
||||||
if (objComb->unk_1B0 <= -5000) {
|
if (objComb->unk_1B0 <= -5000) {
|
||||||
objComb->unk_1B0 = 1500;
|
objComb->unk_1B0 = 1500;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +54,7 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
|
||||||
|
|
||||||
if ((objComb->collider.base.acFlags & AC_HIT) != 0) {
|
if ((objComb->collider.base.acFlags & AC_HIT) != 0) {
|
||||||
objComb->collider.base.acFlags &= ~AC_HIT;
|
objComb->collider.base.acFlags &= ~AC_HIT;
|
||||||
dmgFlags = objComb->collider.elements[0].info.acHitInfo->toucher.dmgFlags;
|
s32 dmgFlags = objComb->collider.elements[0].info.acHitInfo->toucher.dmgFlags;
|
||||||
if (dmgFlags & 0x4001F866) {
|
if (dmgFlags & 0x4001F866) {
|
||||||
objComb->unk_1B0 = 1500;
|
objComb->unk_1B0 = 1500;
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,8 +74,9 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
|
||||||
void ObjComb_RandomizerInit(void* actor) {
|
void ObjComb_RandomizerInit(void* actor) {
|
||||||
ObjComb* objComb = static_cast<ObjComb*>(actor);
|
ObjComb* objComb = static_cast<ObjComb*>(actor);
|
||||||
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
||||||
objComb->beehiveIdentity = OTRGlobals::Instance->gRandomizer->IdentifyBeehive(
|
auto beehiveIdentity = OTRGlobals::Instance->gRandomizer->IdentifyBeehive(
|
||||||
gPlayState->sceneNum, (s16)objComb->actor.world.pos.x, respawnData);
|
gPlayState->sceneNum, (s16)objComb->actor.world.pos.x, respawnData);
|
||||||
|
ObjectExtension::GetInstance().Set<BeehiveIdentity>(actor, std::move(beehiveIdentity));
|
||||||
objComb->actionFunc = (ObjCombActionFunc)ObjComb_RandomizerWait;
|
objComb->actionFunc = (ObjCombActionFunc)ObjComb_RandomizerWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,4 +137,5 @@ void Rando::StaticData::RegisterBeehiveLocations() {
|
||||||
// clang-format-on
|
// clang-format-on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Register<BeehiveIdentity> RegisterBeehiveIdentity;
|
||||||
static RegisterShipInitFunc registerFunc(Rando::StaticData::RegisterBeehiveLocations);
|
static RegisterShipInitFunc registerFunc(Rando::StaticData::RegisterBeehiveLocations);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#include "ShuffleCrates.h"
|
#include <soh/OTRGlobals.h>
|
||||||
#include "soh_assets.h"
|
#include "soh_assets.h"
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
#include <libultraship/libultra.h>
|
#include <libultraship/libultra.h>
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "soh/ResourceManagerHelpers.h"
|
#include "soh/ResourceManagerHelpers.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
|
@ -31,8 +32,14 @@ extern "C" void ObjKibako2_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<CrateIdentity>(thisx);
|
||||||
|
if (crateIdentity == nullptr) {
|
||||||
|
Gfx_DrawDListOpa(play, (Gfx*)gLargeRandoCrateDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GetItemEntry crateItem =
|
GetItemEntry crateItem =
|
||||||
Rando::Context::GetInstance()->GetFinalGIEntry(crateActor->crateIdentity.randomizerCheck, true, GI_NONE);
|
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
|
||||||
getItemCategory = crateItem.getItemCategory;
|
getItemCategory = crateItem.getItemCategory;
|
||||||
|
|
||||||
// If they have bombchus, don't consider the bombchu item major
|
// If they have bombchus, don't consider the bombchu item major
|
||||||
|
@ -99,8 +106,14 @@ extern "C" void ObjKibako_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetItemEntry smallCrateItem = Rando::Context::GetInstance()->GetFinalGIEntry(
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<SmallCrateIdentity>(thisx);
|
||||||
smallCrateActor->smallCrateIdentity.randomizerCheck, true, GI_NONE);
|
if (crateIdentity == nullptr) {
|
||||||
|
Gfx_DrawDListOpa(play, (Gfx*)gSmallRandoCrateDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetItemEntry smallCrateItem =
|
||||||
|
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
|
||||||
getItemCategory = smallCrateItem.getItemCategory;
|
getItemCategory = smallCrateItem.getItemCategory;
|
||||||
|
|
||||||
// If they have bombchus, don't consider the bombchu item major
|
// If they have bombchus, don't consider the bombchu item major
|
||||||
|
@ -154,15 +167,19 @@ extern "C" void ObjKibako_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play) {
|
uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play) {
|
||||||
RandomizerCheck rc = crateActor->crateIdentity.randomizerCheck;
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<CrateIdentity>(&crateActor->dyna.actor);
|
||||||
|
if (crateIdentity == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomizerCheck rc = crateIdentity->randomizerCheck;
|
||||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||||
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
||||||
|
|
||||||
// Don't pull randomized item if crate isn't randomized or is already checked
|
// Don't pull randomized item if crate isn't randomized or is already checked
|
||||||
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
||||||
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
|
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
|
||||||
Flags_GetRandomizerInf(crateActor->crateIdentity.randomizerInf) ||
|
Flags_GetRandomizerInf(crateIdentity->randomizerInf) || crateIdentity->randomizerCheck == RC_UNKNOWN_CHECK) {
|
||||||
crateActor->crateIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -170,15 +187,19 @@ uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, PlayState* play)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* play) {
|
uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* play) {
|
||||||
RandomizerCheck rc = smallCrateActor->smallCrateIdentity.randomizerCheck;
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<SmallCrateIdentity>(&smallCrateActor->actor);
|
||||||
|
if (crateIdentity == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomizerCheck rc = crateIdentity->randomizerCheck;
|
||||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||||
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
uint8_t crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
|
||||||
|
|
||||||
// Don't pull randomized item if crate isn't randomized or is already checked
|
// Don't pull randomized item if crate isn't randomized or is already checked
|
||||||
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
|
||||||
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
|
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
|
||||||
Flags_GetRandomizerInf(smallCrateActor->smallCrateIdentity.randomizerInf) ||
|
Flags_GetRandomizerInf(crateIdentity->randomizerInf) || crateIdentity->randomizerCheck == RC_UNKNOWN_CHECK) {
|
||||||
smallCrateActor->smallCrateIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -186,10 +207,14 @@ uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* pla
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjKibako2_RandomizerSpawnCollectible(ObjKibako2* crateActor, PlayState* play) {
|
void ObjKibako2_RandomizerSpawnCollectible(ObjKibako2* crateActor, PlayState* play) {
|
||||||
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<CrateIdentity>(&crateActor->dyna.actor);
|
||||||
|
if (crateIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &crateActor->dyna.actor.world.pos, ITEM00_SOH_DUMMY);
|
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &crateActor->dyna.actor.world.pos, ITEM00_SOH_DUMMY);
|
||||||
item00->randoInf = crateActor->crateIdentity.randomizerInf;
|
item00->randoInf = crateIdentity->randomizerInf;
|
||||||
item00->itemEntry =
|
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
|
||||||
Rando::Context::GetInstance()->GetFinalGIEntry(crateActor->crateIdentity.randomizerCheck, true, GI_NONE);
|
|
||||||
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
||||||
item00->actor.velocity.y = 8.0f;
|
item00->actor.velocity.y = 8.0f;
|
||||||
item00->actor.speedXZ = 2.0f;
|
item00->actor.speedXZ = 2.0f;
|
||||||
|
@ -197,10 +222,14 @@ void ObjKibako2_RandomizerSpawnCollectible(ObjKibako2* crateActor, PlayState* pl
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState* play) {
|
void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState* play) {
|
||||||
|
const auto crateIdentity = ObjectExtension::GetInstance().Get<SmallCrateIdentity>(&smallCrateActor->actor);
|
||||||
|
if (crateIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &smallCrateActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &smallCrateActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
||||||
item00->randoInf = smallCrateActor->smallCrateIdentity.randomizerInf;
|
item00->randoInf = crateIdentity->randomizerInf;
|
||||||
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(
|
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
|
||||||
smallCrateActor->smallCrateIdentity.randomizerCheck, true, GI_NONE);
|
|
||||||
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
||||||
item00->actor.velocity.y = 8.0f;
|
item00->actor.velocity.y = 8.0f;
|
||||||
item00->actor.speedXZ = 2.0f;
|
item00->actor.speedXZ = 2.0f;
|
||||||
|
@ -231,8 +260,9 @@ void ObjKibako2_RandomizerInit(void* actorRef) {
|
||||||
|
|
||||||
ObjKibako2* crateActor = static_cast<ObjKibako2*>(actorRef);
|
ObjKibako2* crateActor = static_cast<ObjKibako2*>(actorRef);
|
||||||
|
|
||||||
crateActor->crateIdentity = OTRGlobals::Instance->gRandomizer->IdentifyCrate(
|
auto crateIdentity = OTRGlobals::Instance->gRandomizer->IdentifyCrate(gPlayState->sceneNum, (s16)actor->world.pos.x,
|
||||||
gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z);
|
(s16)actor->world.pos.z);
|
||||||
|
ObjectExtension::GetInstance().Set<CrateIdentity>(actor, std::move(crateIdentity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjKibako_RandomizerInit(void* actorRef) {
|
void ObjKibako_RandomizerInit(void* actorRef) {
|
||||||
|
@ -243,8 +273,9 @@ void ObjKibako_RandomizerInit(void* actorRef) {
|
||||||
|
|
||||||
ObjKibako* smallCrateActor = static_cast<ObjKibako*>(actorRef);
|
ObjKibako* smallCrateActor = static_cast<ObjKibako*>(actorRef);
|
||||||
|
|
||||||
smallCrateActor->smallCrateIdentity = OTRGlobals::Instance->gRandomizer->IdentifySmallCrate(
|
auto crateIdentity = OTRGlobals::Instance->gRandomizer->IdentifySmallCrate(
|
||||||
gPlayState->sceneNum, (s16)actor->home.pos.x, (s16)actor->home.pos.z);
|
gPlayState->sceneNum, (s16)actor->home.pos.x, (s16)actor->home.pos.z);
|
||||||
|
ObjectExtension::GetInstance().Set<SmallCrateIdentity>(actor, std::move(crateIdentity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterShuffleCrates() {
|
void RegisterShuffleCrates() {
|
||||||
|
@ -302,38 +333,38 @@ void Rando::StaticData::RegisterCrateLocations() {
|
||||||
locationTable[RC_GV_FREESTANDING_POH_CRATE] = Location::Crate(RC_GV_FREESTANDING_POH_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-350, 1480), "Freestanding PoH Crate", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_FREESTANDING_POH_CRATE));
|
locationTable[RC_GV_FREESTANDING_POH_CRATE] = Location::Crate(RC_GV_FREESTANDING_POH_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-350, 1480), "Freestanding PoH Crate", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_FREESTANDING_POH_CRATE));
|
||||||
locationTable[RC_GV_NEAR_COW_CRATE] = Location::Crate(RC_GV_NEAR_COW_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-449, 123), "Near Cow Crate", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_NEAR_COW_CRATE));
|
locationTable[RC_GV_NEAR_COW_CRATE] = Location::Crate(RC_GV_NEAR_COW_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-449, 123), "Near Cow Crate", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_NEAR_COW_CRATE));
|
||||||
locationTable[RC_GF_ABOVE_JAIL_CRATE] = Location::Crate(RC_GF_ABOVE_JAIL_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(51, -2997), "Above Jail Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ABOVE_JAIL_CRATE));
|
locationTable[RC_GF_ABOVE_JAIL_CRATE] = Location::Crate(RC_GF_ABOVE_JAIL_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(51, -2997), "Above Jail Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ABOVE_JAIL_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_CENTER_CRATE_1] = Location::Crate(RC_GF_OUTSIDE_CENTER_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1534), "Outside Center Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_CENTER_CRATE_1));
|
locationTable[RC_GF_SOUTHMOST_CENTER_CRATE] = Location::Crate(RC_GF_SOUTHMOST_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1534), "Southmost Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTHMOST_CENTER_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_CENTER_CRATE_2] = Location::Crate(RC_GF_OUTSIDE_CENTER_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1594), "Outside Center Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_CENTER_CRATE_2));
|
locationTable[RC_GF_MID_SOUTH_CENTER_CRATE] = Location::Crate(RC_GF_MID_SOUTH_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(315, -1594), "Middle South Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_MID_SOUTH_CENTER_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_CENTER_CRATE_3] = Location::Crate(RC_GF_OUTSIDE_CENTER_CRATE_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1782), "Outside Center Crate 3", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_CENTER_CRATE_3));
|
locationTable[RC_GF_MID_NORTH_CENTER_CRATE] = Location::Crate(RC_GF_MID_NORTH_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1782), "Middle North Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_MID_NORTH_CENTER_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_CENTER_CRATE_4] = Location::Crate(RC_GF_OUTSIDE_CENTER_CRATE_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1842), "Outside Center Crate 4", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_CENTER_CRATE_4));
|
locationTable[RR_GF_NORTHMOST_CENTER_CRATE] = Location::Crate(RR_GF_NORTHMOST_CENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(310, -1842), "Northmost Center Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTHMOST_CENTER_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_LEFT_CRATE_1] = Location::Crate(RC_GF_OUTSIDE_LEFT_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-60, -2210), "Outside Left Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_LEFT_CRATE_1));
|
locationTable[RC_GF_OUTSKIRTS_NE_CRATE] = Location::Crate(RC_GF_OUTSKIRTS_NE_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-60, -2210), "Outskirts Northeast Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSKIRTS_NE_CRATE));
|
||||||
locationTable[RC_GF_OUTSIDE_LEFT_CRATE_2] = Location::Crate(RC_GF_OUTSIDE_LEFT_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-120, -2210), "Outside Left Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSIDE_LEFT_CRATE_2));
|
locationTable[RC_GF_OUTSKIRTS_NW_CRATE] = Location::Crate(RC_GF_OUTSKIRTS_NW_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(-120, -2210), "Outskirts Northwest Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_OUTSKIRTS_NW_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_2] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -1780), "Archery Range Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_2));
|
locationTable[RC_GF_HBA_RANGE_CRATE_2] = Location::Crate(RC_GF_HBA_RANGE_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -1780), "Horseback Archery Range Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_2));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_3] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2020), "Archery Range Crate 3", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_3));
|
locationTable[RC_GF_HBA_RANGE_CRATE_3] = Location::Crate(RC_GF_HBA_RANGE_CRATE_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2020), "Horseback Archery Range Crate 3", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_3));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_4] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2260), "Archery Range Crate 4", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_4));
|
locationTable[RC_GF_HBA_RANGE_CRATE_4] = Location::Crate(RC_GF_HBA_RANGE_CRATE_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2260), "Horseback Archery Range Crate 4", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_4));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_1] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -1540), "Archery Range Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_1));
|
locationTable[RC_GF_HBA_RANGE_CRATE_1] = Location::Crate(RC_GF_HBA_RANGE_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -1540), "Horseback Archery Range Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_1));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_5] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_5, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2500), "Archery Range Crate 5", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_5));
|
locationTable[RC_GF_HBA_RANGE_CRATE_5] = Location::Crate(RC_GF_HBA_RANGE_CRATE_5, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2500), "Horseback Archery Range Crate 5", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_5));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_6] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_6, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2740), "Archery Range Crate 6", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_6));
|
locationTable[RC_GF_HBA_RANGE_CRATE_6] = Location::Crate(RC_GF_HBA_RANGE_CRATE_6, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2740), "Horseback Archery Range Crate 6", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_6));
|
||||||
locationTable[RC_GF_ARCHERY_RANGE_CRATE_7] = Location::Crate(RC_GF_ARCHERY_RANGE_CRATE_7, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2980), "Archery Range Crate 7", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RANGE_CRATE_7));
|
locationTable[RC_GF_HBA_RANGE_CRATE_7] = Location::Crate(RC_GF_HBA_RANGE_CRATE_7, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(4090, -2980), "Horseback Archery Range Crate 7", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_RANGE_CRATE_7));
|
||||||
locationTable[RC_GF_ARCHERY_START_CRATE_1] = Location::Crate(RC_GF_ARCHERY_START_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3727, -243), "Near Archery Start Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_START_CRATE_1));
|
locationTable[RC_GF_HBA_CANOPY_EAST_CRATE] = Location::Crate(RC_GF_HBA_CANOPY_EAST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3727, -243), "Horseback Archery Canopy East Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_CANOPY_EAST_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_START_CRATE_2] = Location::Crate(RC_GF_ARCHERY_START_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3667, -243), "Near Archery Start Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_START_CRATE_2));
|
locationTable[RC_GF_HBA_CANOPY_WEST_CRATE] = Location::Crate(RC_GF_HBA_CANOPY_WEST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3667, -243), "Horseback Archery Canopy West Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_HBA_CANOPY_WEST_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_LEFT_END_CRATE_1] = Location::Crate(RC_GF_ARCHERY_LEFT_END_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3446, -4875), "Archery Left End Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_1));
|
locationTable[RC_GF_NORTH_TARGET_EAST_CRATE] = Location::Crate(RC_GF_NORTH_TARGET_EAST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3446, -4875), "North Target East Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_TARGET_EAST_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_LEFT_END_CRATE_2] = Location::Crate(RC_GF_ARCHERY_LEFT_END_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3303, -5018), "Archery Left End Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_2));
|
locationTable[RC_GF_NORTH_TARGET_WEST_CRATE] = Location::Crate(RC_GF_NORTH_TARGET_WEST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3303, -5018), "North Target West Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_TARGET_WEST_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_RIGHT_END_CRATE_1] = Location::Crate(RC_GF_ARCHERY_RIGHT_END_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3406, 414), "Archery Right End Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_1));
|
locationTable[RC_GF_SOUTH_TARGET_EAST_CRATE] = Location::Crate(RC_GF_SOUTH_TARGET_EAST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3406, 414), "South Target East Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_TARGET_EAST_CRATE));
|
||||||
locationTable[RC_GF_ARCHERY_RIGHT_END_CRATE_2] = Location::Crate(RC_GF_ARCHERY_RIGHT_END_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3330, 406), "Archery Right End Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_2));
|
locationTable[RC_GF_SOUTH_TARGET_WEST_CRATE] = Location::Crate(RC_GF_SOUTH_TARGET_WEST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3330, 406), "South Target West Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_TARGET_WEST_CRATE));
|
||||||
locationTable[RC_GF_KITCHEN_CRATE_1] = Location::Crate(RC_GF_KITCHEN_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1144, -1251), "Kitchen Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_CRATE_1));
|
locationTable[RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE] = Location::Crate(RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1144, -1251), "Near Kitchen Leftmost Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_KITCHEN_LEFTMOST_CRATE));
|
||||||
locationTable[RC_GF_KITCHEN_CRATE_2] = Location::Crate(RC_GF_KITCHEN_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1144, -1191), "Kitchen Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_CRATE_2));
|
locationTable[RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE] = Location::Crate(RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1144, -1191), "Near Kitchen Middle Left Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_KITCHEN_MID_LEFT_CRATE));
|
||||||
locationTable[RC_GF_KITCHEN_CRATE_3] = Location::Crate(RC_GF_KITCHEN_CRATE_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1256, -847), "Kitchen Crate 3", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_CRATE_3));
|
locationTable[RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE] = Location::Crate(RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1256, -847), "Near Kitchen Middle Right Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_KITCHEN_MID_RIGHT_CRATE));
|
||||||
locationTable[RC_GF_KITCHEN_CRATE_4] = Location::Crate(RC_GF_KITCHEN_CRATE_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1256, -787), "Kitchen Crate 4", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_CRATE_4));
|
locationTable[RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE] = Location::Crate(RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1256, -787), "Near Kitchen Rightmost Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_KITCHEN_RIGHTMOST_CRATE));
|
||||||
locationTable[RC_GF_KITCHEN_CRATE_5] = Location::Crate(RC_GF_KITCHEN_CRATE_5, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1610, -624), "Kitchen Crate 5", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_CRATE_5));
|
locationTable[RC_TH_KITCHEN_CRATE] = Location::Crate(RC_TH_KITCHEN_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1610, -624), "Kitchen Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_KITCHEN_CRATE));
|
||||||
locationTable[RC_GF_BREAK_ROOM_CRATE_1] = Location::Crate(RC_GF_BREAK_ROOM_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1260, -3155), "Break Room Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_CRATE_1));
|
locationTable[RC_TH_BREAK_HALLWAY_OUTER_CRATE] = Location::Crate(RC_TH_BREAK_HALLWAY_OUTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1260, -3155), "Break Hallway Outer Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_HALLWAY_OUTER_CRATE));
|
||||||
locationTable[RC_GF_BREAK_ROOM_CRATE_4] = Location::Crate(RC_GF_BREAK_ROOM_CRATE_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1600, -3550), "Break Room Crate 4", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_CRATE_4));
|
locationTable[RC_TH_BREAK_ROOM_LEFT_CRATE] = Location::Crate(RC_TH_BREAK_ROOM_LEFT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1600, -3550), "Break Room Left Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_ROOM_LEFT_CRATE));
|
||||||
locationTable[RC_GF_BREAK_ROOM_CRATE_2] = Location::Crate(RC_GF_BREAK_ROOM_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1360, -3325), "Break Room Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_CRATE_2));
|
locationTable[RC_TH_BREAK_HALLWAY_INNER_CRATE] = Location::Crate(RC_TH_BREAK_HALLWAY_INNER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1360, -3325), "Break Hallway Inner Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_HALLWAY_INNER_CRATE));
|
||||||
locationTable[RC_GF_BREAK_ROOM_CRATE_3] = Location::Crate(RC_GF_BREAK_ROOM_CRATE_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1600, -3502), "Break Room Crate 3", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_CRATE_3));
|
locationTable[RC_TH_BREAK_ROOM_RIGHT_CRATE] = Location::Crate(RC_TH_BREAK_ROOM_RIGHT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1600, -3502), "Break Room Right Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_ROOM_RIGHT_CRATE));
|
||||||
locationTable[RC_GF_NORTH_F1_CARPENTER_CRATE] = Location::Crate(RC_GF_NORTH_F1_CARPENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-510, -2213), "North F1 Carpenter Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F1_CARPENTER_CRATE));
|
locationTable[RC_TH_1_TORCH_CELL_CRATE] = Location::Crate(RC_TH_1_TORCH_CELL_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-510, -2213), "1 Torch Cell Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_1_TORCH_CELL_CRATE));
|
||||||
locationTable[RC_GF_NORTH_F3_CARPENTER_CRATE] = Location::Crate(RC_GF_NORTH_F3_CARPENTER_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1090, -2210), "North F3 Carpenter Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F3_CARPENTER_CRATE));
|
locationTable[RC_TH_DEAD_END_CELL_CRATE] = Location::Crate(RC_TH_DEAD_END_CELL_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1090, -2210), "Dead End Cell Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_DEAD_END_CELL_CRATE));
|
||||||
locationTable[RC_GF_SOUTH_F2_CARPENTER_CRATE_1] = Location::Crate(RC_GF_SOUTH_F2_CARPENTER_CRATE_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-49, 11), "South F2 Carpenter Crate 1", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_1));
|
locationTable[RC_TH_DOUBLE_CELL_LEFT_CRATE] = Location::Crate(RC_TH_DOUBLE_CELL_LEFT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-49, 11), "Double Cell Left Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_DOUBLE_CELL_LEFT_CRATE));
|
||||||
locationTable[RC_GF_SOUTH_F2_CARPENTER_CRATE_2] = Location::Crate(RC_GF_SOUTH_F2_CARPENTER_CRATE_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(11, 11), "South F2 Carpenter Crate 2", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_2));
|
locationTable[RC_TH_DOUBLE_CELL_RIGHT_CRATE] = Location::Crate(RC_TH_DOUBLE_CELL_RIGHT_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(11, 11), "Double Cell Right Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_DOUBLE_CELL_RIGHT_CRATE));
|
||||||
locationTable[RC_HW_BEFORE_QUICKSAND_CRATE] = Location::Crate(RC_HW_BEFORE_QUICKSAND_CRATE, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3832, 2840), "Before Quicksand Crate", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_BEFORE_QUICKSAND_CRATE));
|
locationTable[RC_HW_BEFORE_QUICKSAND_CRATE] = Location::Crate(RC_HW_BEFORE_QUICKSAND_CRATE, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3832, 2840), "Before Quicksand Crate", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_BEFORE_QUICKSAND_CRATE));
|
||||||
locationTable[RC_HW_AFTER_QUICKSAND_CRATE_1] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_1, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3235, 2313), "After Quicksand Crate 1", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_1));
|
locationTable[RC_HW_AFTER_QUICKSAND_CRATE_1] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_1, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3235, 2313), "After Quicksand Crate 1", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_1));
|
||||||
locationTable[RC_HW_AFTER_QUICKSAND_CRATE_2] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_2, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3125, 2459), "After Quicksand Crate 2", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_2));
|
locationTable[RC_HW_AFTER_QUICKSAND_CRATE_2] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_2, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3125, 2459), "After Quicksand Crate 2", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_2));
|
||||||
|
@ -378,7 +409,7 @@ void Rando::StaticData::RegisterCrateLocations() {
|
||||||
locationTable[RC_GV_CRATE_BRIDGE_2] = Location::NLCrate(RC_GV_CRATE_BRIDGE_2, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -125), "Near Bridge Crate 2", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_2));
|
locationTable[RC_GV_CRATE_BRIDGE_2] = Location::NLCrate(RC_GV_CRATE_BRIDGE_2, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -125), "Near Bridge Crate 2", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_2));
|
||||||
locationTable[RC_GV_CRATE_BRIDGE_3] = Location::NLCrate(RC_GV_CRATE_BRIDGE_3, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -150), "Near Bridge Crate 3", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_3));
|
locationTable[RC_GV_CRATE_BRIDGE_3] = Location::NLCrate(RC_GV_CRATE_BRIDGE_3, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -150), "Near Bridge Crate 3", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_3));
|
||||||
locationTable[RC_GV_CRATE_BRIDGE_4] = Location::NLCrate(RC_GV_CRATE_BRIDGE_4, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -90), "Near Bridge Crate 4", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_4));
|
locationTable[RC_GV_CRATE_BRIDGE_4] = Location::NLCrate(RC_GV_CRATE_BRIDGE_4, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-860, -90), "Near Bridge Crate 4", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_4));
|
||||||
locationTable[RC_GF_ARCHERY_LEFT_END_CHILD_CRATE] = Location::NLCrate(RC_GF_ARCHERY_LEFT_END_CHILD_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3443, -4876), "Archery Left End Child Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ARCHERY_LEFT_END_CHILD_CRATE));
|
locationTable[RC_GF_NORTH_TARGET_CHILD_CRATE] = Location::NLCrate(RC_GF_NORTH_TARGET_CHILD_CRATE, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_GERUDOS_FORTRESS, TWO_ACTOR_PARAMS(3443, -4876), "North Target Child Crate", RHT_CRATE_GERUDOS_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_TARGET_CHILD_CRATE));
|
||||||
|
|
||||||
// MQ Crates
|
// MQ Crates
|
||||||
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
|
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
|
||||||
|
@ -564,5 +595,7 @@ void Rando::StaticData::RegisterCrateLocations() {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Register<CrateIdentity> RegisterCrateIdentity;
|
||||||
|
static ObjectExtension::Register<SmallCrateIdentity> RegisterSmallCrateIdentity;
|
||||||
static RegisterShipInitFunc initFunc(RegisterShuffleCrates, { "IS_RANDO" });
|
static RegisterShipInitFunc initFunc(RegisterShuffleCrates, { "IS_RANDO" });
|
||||||
static RegisterShipInitFunc locFunc(Rando::StaticData::RegisterCrateLocations);
|
static RegisterShipInitFunc locFunc(Rando::StaticData::RegisterCrateLocations);
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#ifndef ShuffleCrates_H
|
|
||||||
#define ShuffleCrates_H
|
|
||||||
|
|
||||||
#include <z64.h>
|
|
||||||
#include <soh/OTRGlobals.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void ObjKibako2_RandomizerInit(void* actorRef);
|
|
||||||
void ObjKibako_RandomizerInit(void* actorRef);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ShuffleCrates_H
|
|
|
@ -1,19 +1,28 @@
|
||||||
|
#include "soh/OTRGlobals.h"
|
||||||
#include "randomizer_grotto.h"
|
#include "randomizer_grotto.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "soh/cvar_prefixes.h"
|
||||||
|
#include "static_data.h"
|
||||||
|
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
#include "src/overlays/actors/ovl_En_Elf/z_en_elf.h"
|
#include "src/overlays/actors/ovl_En_Elf/z_en_elf.h"
|
||||||
#include "src/overlays/actors/ovl_Obj_Bean/z_obj_bean.h"
|
#include "src/overlays/actors/ovl_Obj_Bean/z_obj_bean.h"
|
||||||
#include "src/overlays/actors/ovl_En_Gs/z_en_gs.h"
|
#include "src/overlays/actors/ovl_En_Gs/z_en_gs.h"
|
||||||
#include "src/overlays/actors/ovl_Shot_Sun/z_shot_sun.h"
|
#include "src/overlays/actors/ovl_Shot_Sun/z_shot_sun.h"
|
||||||
#include "soh/OTRGlobals.h"
|
}
|
||||||
#include "soh/cvar_prefixes.h"
|
|
||||||
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
|
||||||
#include "static_data.h"
|
|
||||||
|
|
||||||
#define FAIRY_FLAG_TIMED (1 << 8)
|
#define FAIRY_FLAG_TIMED (1 << 8)
|
||||||
|
|
||||||
void ShuffleFairies_DrawRandomizedItem(EnElf* enElf, PlayState* play) {
|
void ShuffleFairies_DrawRandomizedItem(EnElf* enElf, PlayState* play) {
|
||||||
|
const auto fairyIdentity = ObjectExtension::GetInstance().Get<FairyIdentity>(&enElf->actor);
|
||||||
|
if (fairyIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GetItemEntry randoGetItem =
|
GetItemEntry randoGetItem =
|
||||||
Rando::Context::GetInstance()->GetFinalGIEntry(enElf->sohFairyIdentity.randomizerCheck, true, GI_FAIRY);
|
Rando::Context::GetInstance()->GetFinalGIEntry(fairyIdentity->randomizerCheck, true, GI_FAIRY);
|
||||||
if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) {
|
if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) {
|
||||||
randoGetItem = GET_ITEM_MYSTERY;
|
randoGetItem = GET_ITEM_MYSTERY;
|
||||||
}
|
}
|
||||||
|
@ -33,8 +42,8 @@ bool ShuffleFairies_FairyExists(FairyIdentity fairyIdentity) {
|
||||||
if (actor->id != ACTOR_EN_ELF) {
|
if (actor->id != ACTOR_EN_ELF) {
|
||||||
actor = actor->next;
|
actor = actor->next;
|
||||||
} else {
|
} else {
|
||||||
EnElf* enElf = (EnElf*)(actor);
|
const auto actorFairyIdentity = ObjectExtension::GetInstance().Get<FairyIdentity>(&actor);
|
||||||
if (fairyIdentity.randomizerInf == enElf->sohFairyIdentity.randomizerInf) {
|
if (actorFairyIdentity != nullptr && fairyIdentity.randomizerInf == actorFairyIdentity->randomizerInf) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
actor = actor->next;
|
actor = actor->next;
|
||||||
|
@ -70,10 +79,10 @@ FairyIdentity ShuffleFairies_GetFairyIdentity(int32_t params) {
|
||||||
static bool SpawnFairy(f32 posX, f32 posY, f32 posZ, int32_t params, FairyType fairyType) {
|
static bool SpawnFairy(f32 posX, f32 posY, f32 posZ, int32_t params, FairyType fairyType) {
|
||||||
FairyIdentity fairyIdentity = ShuffleFairies_GetFairyIdentity(params);
|
FairyIdentity fairyIdentity = ShuffleFairies_GetFairyIdentity(params);
|
||||||
if (!Flags_GetRandomizerInf(fairyIdentity.randomizerInf)) {
|
if (!Flags_GetRandomizerInf(fairyIdentity.randomizerInf)) {
|
||||||
EnElf* fairy = (EnElf*)Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_ELF, posX, posY - 30.0f, posZ, 0,
|
Actor* fairy = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_ELF, posX, posY - 30.0f, posZ, 0, 0, 0,
|
||||||
0, 0, fairyType, true);
|
fairyType, true);
|
||||||
fairy->sohFairyIdentity = fairyIdentity;
|
ObjectExtension::GetInstance().Set<FairyIdentity>(fairy, std::move(fairyIdentity));
|
||||||
fairy->actor.draw = (ActorFunc)ShuffleFairies_DrawRandomizedItem;
|
fairy->draw = (ActorFunc)ShuffleFairies_DrawRandomizedItem;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -85,8 +94,14 @@ void RegisterShuffleFairies() {
|
||||||
// Grant item when picking up fairy.
|
// Grant item when picking up fairy.
|
||||||
COND_VB_SHOULD(VB_FAIRY_HEAL, shouldRegister, {
|
COND_VB_SHOULD(VB_FAIRY_HEAL, shouldRegister, {
|
||||||
EnElf* enElf = va_arg(args, EnElf*);
|
EnElf* enElf = va_arg(args, EnElf*);
|
||||||
if (enElf->sohFairyIdentity.randomizerInf && enElf->sohFairyIdentity.randomizerInf != RAND_INF_MAX) {
|
|
||||||
Flags_SetRandomizerInf(enElf->sohFairyIdentity.randomizerInf);
|
const auto fairyIdentity = ObjectExtension::GetInstance().Get<FairyIdentity>(&enElf->actor);
|
||||||
|
if (fairyIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fairyIdentity != nullptr && fairyIdentity->randomizerInf && fairyIdentity->randomizerInf != RAND_INF_MAX) {
|
||||||
|
Flags_SetRandomizerInf(fairyIdentity->randomizerInf);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -375,7 +390,7 @@ void Rando::StaticData::RegisterFairyLocations() {
|
||||||
locationTable[RC_DMT_FLAG_SUN_FAIRY] = Location::Fairy(RC_DMT_FLAG_SUN_FAIRY, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_TRAIL, SCENE_DEATH_MOUNTAIN_TRAIL, TWO_ACTOR_PARAMS(0x1000, 464), "Flag Sun's Song Fairy", RHT_DMT_FLAG_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMT_FLAG_SUN_FAIRY));
|
locationTable[RC_DMT_FLAG_SUN_FAIRY] = Location::Fairy(RC_DMT_FLAG_SUN_FAIRY, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_TRAIL, SCENE_DEATH_MOUNTAIN_TRAIL, TWO_ACTOR_PARAMS(0x1000, 464), "Flag Sun's Song Fairy", RHT_DMT_FLAG_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMT_FLAG_SUN_FAIRY));
|
||||||
locationTable[RC_DMT_COW_GROTTO_STORMS_FAIRY] = Location::Fairy(RC_DMT_COW_GROTTO_STORMS_FAIRY, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_TRAIL, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x1000, -311), "Cow Grotto Song of Storms Fairy", RHT_DMT_COW_GROTTO_STORMS_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMT_COW_GROTTO_STORMS_FAIRY));
|
locationTable[RC_DMT_COW_GROTTO_STORMS_FAIRY] = Location::Fairy(RC_DMT_COW_GROTTO_STORMS_FAIRY, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_TRAIL, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x1000, -311), "Cow Grotto Song of Storms Fairy", RHT_DMT_COW_GROTTO_STORMS_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMT_COW_GROTTO_STORMS_FAIRY));
|
||||||
locationTable[RC_LW_SHORTCUT_STORMS_FAIRY] = Location::Fairy(RC_LW_SHORTCUT_STORMS_FAIRY, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(0x1000, -795), "Shortcuts Song of Storms Fairy", RHT_LW_SHORTCUT_STORMS_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_SHORTCUT_STORMS_FAIRY));
|
locationTable[RC_LW_SHORTCUT_STORMS_FAIRY] = Location::Fairy(RC_LW_SHORTCUT_STORMS_FAIRY, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(0x1000, -795), "Shortcuts Song of Storms Fairy", RHT_LW_SHORTCUT_STORMS_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_SHORTCUT_STORMS_FAIRY));
|
||||||
locationTable[RC_GF_KITCHEN_SUN_FAIRY] = Location::Fairy(RC_GF_KITCHEN_SUN_FAIRY, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(0x1000, -621), "Kitchen Sun's Song Fairy", RHT_GF_KITCHEN_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_SUN_FAIRY));
|
locationTable[RC_TH_KITCHEN_SUN_FAIRY] = Location::Fairy(RC_TH_KITCHEN_SUN_FAIRY, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(0x1000, -621), "Kitchen Sun's Song Fairy", RHT_TH_KITCHEN_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_KITCHEN_SUN_FAIRY));
|
||||||
locationTable[RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY] = Location::Fairy(RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x1000, 741), "Scrub Grotto Sun's Song Fairy", RHT_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY));
|
locationTable[RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY] = Location::Fairy(RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x1000, 741), "Scrub Grotto Sun's Song Fairy", RHT_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY));
|
||||||
locationTable[RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY] = Location::Fairy(RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY, RCQUEST_BOTH, RCAREA_GRAVEYARD, SCENE_ROYAL_FAMILYS_TOMB, TWO_ACTOR_PARAMS(0x1000, 1476), "Royal Family's Tomb Sun's Song Fairy", RHT_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY));
|
locationTable[RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY] = Location::Fairy(RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY, RCQUEST_BOTH, RCAREA_GRAVEYARD, SCENE_ROYAL_FAMILYS_TOMB, TWO_ACTOR_PARAMS(0x1000, 1476), "Royal Family's Tomb Sun's Song Fairy", RHT_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY));
|
||||||
|
|
||||||
|
@ -404,5 +419,6 @@ void Rando::StaticData::RegisterFairyLocations() {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Register<FairyIdentity> RegisterFairyIdentity;
|
||||||
static RegisterShipInitFunc registerShuffleFairies(RegisterShuffleFairies, { "IS_RANDO" });
|
static RegisterShipInitFunc registerShuffleFairies(RegisterShuffleFairies, { "IS_RANDO" });
|
||||||
static RegisterShipInitFunc registerShuffleFairiesLocations(Rando::StaticData::RegisterFairyLocations);
|
static RegisterShipInitFunc registerShuffleFairiesLocations(Rando::StaticData::RegisterFairyLocations);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "ShuffleGrass.h"
|
#include <soh/OTRGlobals.h>
|
||||||
#include "soh_assets.h"
|
#include "soh_assets.h"
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
#include "soh/Enhancements/enhancementTypes.h"
|
#include "soh/Enhancements/enhancementTypes.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -27,18 +28,20 @@ extern "C" void EnKusa_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
static Gfx* dLists[] = { (Gfx*)gRandoBushJunkDL, (Gfx*)gRandoCuttableGrassJunkDL, (Gfx*)gRandoCuttableGrassJunkDL };
|
static Gfx* dLists[] = { (Gfx*)gRandoBushJunkDL, (Gfx*)gRandoCuttableGrassJunkDL, (Gfx*)gRandoCuttableGrassJunkDL };
|
||||||
auto grassActor = ((EnKusa*)thisx);
|
auto grassActor = ((EnKusa*)thisx);
|
||||||
|
|
||||||
|
const auto grassIdentity = ObjectExtension::GetInstance().Get<GrassIdentity>(thisx);
|
||||||
|
|
||||||
OPEN_DISPS(play->state.gfxCtx);
|
OPEN_DISPS(play->state.gfxCtx);
|
||||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||||
|
|
||||||
if (grassActor->grassIdentity.randomizerCheck != RC_MAX &&
|
if (grassIdentity != nullptr && grassIdentity->randomizerCheck != RC_MAX &&
|
||||||
Flags_GetRandomizerInf(grassActor->grassIdentity.randomizerInf) == 0) {
|
Flags_GetRandomizerInf(grassIdentity->randomizerInf) == 0) {
|
||||||
int csmc = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_DISABLED);
|
int csmc = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_DISABLED);
|
||||||
int requiresStoneAgony = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"), 0);
|
int requiresStoneAgony = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"), 0);
|
||||||
|
|
||||||
if ((csmc == CSMC_BOTH || csmc == CSMC_TEXTURE) &&
|
if ((csmc == CSMC_BOTH || csmc == CSMC_TEXTURE) &&
|
||||||
(!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
|
(!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
|
||||||
auto itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(grassActor->grassIdentity.randomizerCheck,
|
auto itemEntry =
|
||||||
true, GI_NONE);
|
Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE);
|
||||||
GetItemCategory getItemCategory = itemEntry.getItemCategory;
|
GetItemCategory getItemCategory = itemEntry.getItemCategory;
|
||||||
|
|
||||||
switch (getItemCategory) {
|
switch (getItemCategory) {
|
||||||
|
@ -88,19 +91,19 @@ extern "C" void EnKusa_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t EnKusa_RandomizerHoldsItem(EnKusa* grassActor, PlayState* play) {
|
uint8_t EnKusa_RandomizerHoldsItem(EnKusa* grassActor, PlayState* play) {
|
||||||
if (grassActor->grassIdentity.randomizerCheck == RC_MAX)
|
const auto grassIdentity = ObjectExtension::GetInstance().Get<GrassIdentity>(&grassActor->actor);
|
||||||
|
|
||||||
|
if (grassIdentity == nullptr || grassIdentity->randomizerCheck == RC_MAX)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RandomizerCheck rc = grassActor->grassIdentity.randomizerCheck;
|
RandomizerCheck rc = grassIdentity->randomizerCheck;
|
||||||
|
|
||||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||||
uint8_t grassSetting = RAND_GET_OPTION(RSK_SHUFFLE_GRASS);
|
uint8_t grassSetting = RAND_GET_OPTION(RSK_SHUFFLE_GRASS);
|
||||||
|
|
||||||
// Don't pull randomized item if grass isn't randomized or is already checked
|
// Don't pull randomized item if grass isn't randomized or is already checked
|
||||||
if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) ||
|
if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) ||
|
||||||
(grassSetting == RO_SHUFFLE_GRASS_DUNGEONS && !isDungeon) ||
|
(grassSetting == RO_SHUFFLE_GRASS_DUNGEONS && !isDungeon) ||
|
||||||
Flags_GetRandomizerInf(grassActor->grassIdentity.randomizerInf) ||
|
Flags_GetRandomizerInf(grassIdentity->randomizerInf) || rc == RC_UNKNOWN_CHECK) {
|
||||||
grassActor->grassIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -108,10 +111,14 @@ uint8_t EnKusa_RandomizerHoldsItem(EnKusa* grassActor, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnKusa_RandomizerSpawnCollectible(EnKusa* grassActor, PlayState* play) {
|
void EnKusa_RandomizerSpawnCollectible(EnKusa* grassActor, PlayState* play) {
|
||||||
|
const auto grassIdentity = ObjectExtension::GetInstance().Get<GrassIdentity>(&grassActor->actor);
|
||||||
|
if (grassIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &grassActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &grassActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
||||||
item00->randoInf = grassActor->grassIdentity.randomizerInf;
|
item00->randoInf = grassIdentity->randomizerInf;
|
||||||
item00->itemEntry =
|
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE);
|
||||||
Rando::Context::GetInstance()->GetFinalGIEntry(grassActor->grassIdentity.randomizerCheck, true, GI_NONE);
|
|
||||||
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
||||||
item00->actor.velocity.y = 8.0f;
|
item00->actor.velocity.y = 8.0f;
|
||||||
item00->actor.speedXZ = 2.0f;
|
item00->actor.speedXZ = 2.0f;
|
||||||
|
@ -127,8 +134,9 @@ void EnKusa_RandomizerInit(void* actorRef) {
|
||||||
EnKusa* grassActor = static_cast<EnKusa*>(actorRef);
|
EnKusa* grassActor = static_cast<EnKusa*>(actorRef);
|
||||||
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1);
|
||||||
|
|
||||||
grassActor->grassIdentity = OTRGlobals::Instance->gRandomizer->IdentifyGrass(
|
auto grassIdentity = OTRGlobals::Instance->gRandomizer->IdentifyGrass(
|
||||||
gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z, respawnData, gPlayState->linkAgeOnLoad);
|
gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z, respawnData, gPlayState->linkAgeOnLoad);
|
||||||
|
ObjectExtension::GetInstance().Set<GrassIdentity>(actor, std::move(grassIdentity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterShuffleGrass() {
|
void RegisterShuffleGrass() {
|
||||||
|
@ -150,8 +158,10 @@ void RegisterShuffleGrass() {
|
||||||
EnKusa* grassActor = va_arg(args, EnKusa*);
|
EnKusa* grassActor = va_arg(args, EnKusa*);
|
||||||
if (EnKusa_RandomizerHoldsItem(grassActor, gPlayState)) {
|
if (EnKusa_RandomizerHoldsItem(grassActor, gPlayState)) {
|
||||||
EnKusa_RandomizerSpawnCollectible(grassActor, gPlayState);
|
EnKusa_RandomizerSpawnCollectible(grassActor, gPlayState);
|
||||||
grassActor->grassIdentity.randomizerCheck = RC_MAX;
|
ObjectExtension::GetInstance().Set<GrassIdentity>(&grassActor->actor, std::move(GrassIdentity{
|
||||||
grassActor->grassIdentity.randomizerInf = RAND_INF_MAX;
|
.randomizerInf = RAND_INF_MAX,
|
||||||
|
.randomizerCheck = RC_MAX,
|
||||||
|
}));
|
||||||
*should = false;
|
*should = false;
|
||||||
} else {
|
} else {
|
||||||
*should = true;
|
*should = true;
|
||||||
|
@ -519,5 +529,6 @@ void Rando::StaticData::RegisterGrassLocations() {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Register<GrassIdentity> RegisterGrassIdentity;
|
||||||
static RegisterShipInitFunc registerShuffleGrass(RegisterShuffleGrass, { "IS_RANDO" });
|
static RegisterShipInitFunc registerShuffleGrass(RegisterShuffleGrass, { "IS_RANDO" });
|
||||||
static RegisterShipInitFunc registerShuffleGrassLocations(Rando::StaticData::RegisterGrassLocations);
|
static RegisterShipInitFunc registerShuffleGrassLocations(Rando::StaticData::RegisterGrassLocations);
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef SHUFFLEGRASS_H
|
|
||||||
#define SHUFFLEGRASS_H
|
|
||||||
|
|
||||||
#include <z64.h>
|
|
||||||
#include <soh/OTRGlobals.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void EnKusa_RandomizerInit(void* actorRef);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // SHUFFLEGRASS_H
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "soh_assets.h"
|
#include "soh_assets.h"
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
|
@ -25,15 +26,19 @@ extern "C" void ObjTsubo_RandomizerDraw(Actor* thisx, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) {
|
uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) {
|
||||||
RandomizerCheck rc = potActor->potIdentity.randomizerCheck;
|
const auto potIdentity = ObjectExtension::GetInstance().Get<PotIdentity>(&potActor->actor);
|
||||||
|
if (potIdentity == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomizerCheck rc = potIdentity->randomizerCheck;
|
||||||
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
|
||||||
uint8_t potSetting = RAND_GET_OPTION(RSK_SHUFFLE_POTS);
|
uint8_t potSetting = RAND_GET_OPTION(RSK_SHUFFLE_POTS);
|
||||||
|
|
||||||
// Don't pull randomized item if pot isn't randomized or is already checked
|
// Don't pull randomized item if pot isn't randomized or is already checked
|
||||||
if (!IS_RANDO || (potSetting == RO_SHUFFLE_POTS_OVERWORLD && isDungeon) ||
|
if (!IS_RANDO || (potSetting == RO_SHUFFLE_POTS_OVERWORLD && isDungeon) ||
|
||||||
(potSetting == RO_SHUFFLE_POTS_DUNGEONS && !isDungeon) ||
|
(potSetting == RO_SHUFFLE_POTS_DUNGEONS && !isDungeon) || Flags_GetRandomizerInf(potIdentity->randomizerInf) ||
|
||||||
Flags_GetRandomizerInf(potActor->potIdentity.randomizerInf) ||
|
potIdentity->randomizerCheck == RC_UNKNOWN_CHECK) {
|
||||||
potActor->potIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -41,10 +46,14 @@ uint8_t ObjTsubo_RandomizerHoldsItem(ObjTsubo* potActor, PlayState* play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjTsubo_RandomizerSpawnCollectible(ObjTsubo* potActor, PlayState* play) {
|
void ObjTsubo_RandomizerSpawnCollectible(ObjTsubo* potActor, PlayState* play) {
|
||||||
|
const auto potIdentity = ObjectExtension::GetInstance().Get<PotIdentity>(&potActor->actor);
|
||||||
|
if (potIdentity == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &potActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
EnItem00* item00 = (EnItem00*)Item_DropCollectible2(play, &potActor->actor.world.pos, ITEM00_SOH_DUMMY);
|
||||||
item00->randoInf = potActor->potIdentity.randomizerInf;
|
item00->randoInf = potIdentity->randomizerInf;
|
||||||
item00->itemEntry =
|
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(potIdentity->randomizerCheck, true, GI_NONE);
|
||||||
Rando::Context::GetInstance()->GetFinalGIEntry(potActor->potIdentity.randomizerCheck, true, GI_NONE);
|
|
||||||
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
|
||||||
item00->actor.velocity.y = 8.0f;
|
item00->actor.velocity.y = 8.0f;
|
||||||
item00->actor.speedXZ = 2.0f;
|
item00->actor.speedXZ = 2.0f;
|
||||||
|
@ -58,8 +67,9 @@ void RegisterShufflePots() {
|
||||||
Actor* actor = static_cast<Actor*>(actorRef);
|
Actor* actor = static_cast<Actor*>(actorRef);
|
||||||
ObjTsubo* potActor = static_cast<ObjTsubo*>(actorRef);
|
ObjTsubo* potActor = static_cast<ObjTsubo*>(actorRef);
|
||||||
|
|
||||||
potActor->potIdentity = OTRGlobals::Instance->gRandomizer->IdentifyPot(
|
auto potIdentity = OTRGlobals::Instance->gRandomizer->IdentifyPot(gPlayState->sceneNum, (s16)actor->world.pos.x,
|
||||||
gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z);
|
(s16)actor->world.pos.z);
|
||||||
|
ObjectExtension::GetInstance().Set<PotIdentity>(actor, std::move(potIdentity));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw custom model for pot to indicate it holding a randomized item.
|
// Draw custom model for pot to indicate it holding a randomized item.
|
||||||
|
@ -104,26 +114,26 @@ void Rando::StaticData::RegisterPotLocations() {
|
||||||
locationTable[RC_KF_TWINS_HOUSE_POT_1] = Location::Pot(RC_KF_TWINS_HOUSE_POT_1, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_TWINS_HOUSE, TWO_ACTOR_PARAMS(33, -55), "Twins House Pot 1", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_TWINS_HOUSE_POT_1));
|
locationTable[RC_KF_TWINS_HOUSE_POT_1] = Location::Pot(RC_KF_TWINS_HOUSE_POT_1, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_TWINS_HOUSE, TWO_ACTOR_PARAMS(33, -55), "Twins House Pot 1", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_TWINS_HOUSE_POT_1));
|
||||||
locationTable[RC_KF_BROTHERS_HOUSE_POT_1] = Location::Pot(RC_KF_BROTHERS_HOUSE_POT_1, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_KNOW_IT_ALL_BROS_HOUSE, TWO_ACTOR_PARAMS(-134, -29), "Brothers House Pot 1", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BROTHERS_HOUSE_POT_1));
|
locationTable[RC_KF_BROTHERS_HOUSE_POT_1] = Location::Pot(RC_KF_BROTHERS_HOUSE_POT_1, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_KNOW_IT_ALL_BROS_HOUSE, TWO_ACTOR_PARAMS(-134, -29), "Brothers House Pot 1", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BROTHERS_HOUSE_POT_1));
|
||||||
locationTable[RC_KF_BROTHERS_HOUSE_POT_2] = Location::Pot(RC_KF_BROTHERS_HOUSE_POT_2, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_KNOW_IT_ALL_BROS_HOUSE, TWO_ACTOR_PARAMS(-68, 114), "Brothers House Pot 2", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BROTHERS_HOUSE_POT_2));
|
locationTable[RC_KF_BROTHERS_HOUSE_POT_2] = Location::Pot(RC_KF_BROTHERS_HOUSE_POT_2, RCQUEST_BOTH, RCAREA_KOKIRI_FOREST, SCENE_KNOW_IT_ALL_BROS_HOUSE, TWO_ACTOR_PARAMS(-68, 114), "Brothers House Pot 2", RHT_POT_KOKIRI_FOREST, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BROTHERS_HOUSE_POT_2));
|
||||||
locationTable[RC_GF_BREAK_ROOM_POT_1] = Location::Pot(RC_GF_BREAK_ROOM_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1438, -3629), "Break Room Pot 1", RHT_POT_GERUDO_FORTRESS, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_POT_1));
|
locationTable[RC_TH_BREAK_ROOM_FRONT_POT] = Location::Pot(RC_TH_BREAK_ROOM_FRONT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1438, -3629), "Break Room Front Pot", RHT_TH_BREAK_ROOM_FRONT_POT, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_ROOM_FRONT_POT));
|
||||||
locationTable[RC_GF_BREAK_ROOM_POT_2] = Location::Pot(RC_GF_BREAK_ROOM_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1403, -3679), "Break Room Pot 2", RHT_POT_GERUDO_FORTRESS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_BREAK_ROOM_POT_2));
|
locationTable[RC_TH_BREAK_ROOM_BACK_POT] = Location::Pot(RC_TH_BREAK_ROOM_BACK_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1403, -3679), "Break Room Back Pot", RHT_TH_BREAK_ROOM_BACK_POT, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_BREAK_ROOM_BACK_POT));
|
||||||
locationTable[RC_GF_KITCHEN_POT_1] = Location::Pot(RC_GF_KITCHEN_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1908, -789), "Kitchen Pot 1", RHT_POT_GERUDO_FORTRESS, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_POT_1));
|
locationTable[RC_TH_KITCHEN_POT_1] = Location::Pot(RC_TH_KITCHEN_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1908, -789), "Kitchen Pot 1", RHT_TH_KITCHEN_POT_1, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_KITCHEN_POT_1));
|
||||||
locationTable[RC_GF_KITCHEN_POT_2] = Location::Pot(RC_GF_KITCHEN_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1951, -850), "Kitchen Pot 2", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_KITCHEN_POT_2));
|
locationTable[RC_TH_KITCHEN_POT_2] = Location::Pot(RC_TH_KITCHEN_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(1951, -850), "Kitchen Pot 2", RHT_TH_KITCHEN_POT_2, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_KITCHEN_POT_2));
|
||||||
locationTable[RC_GF_NORTH_F1_CARPENTER_POT_1] = Location::Pot(RC_GF_NORTH_F1_CARPENTER_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-475, -2622), "North F1 Carpenter Pot 1", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F1_CARPENTER_POT_1));
|
locationTable[RC_TH_1_TORCH_CELL_RIGHT_POT] = Location::Pot(RC_TH_1_TORCH_CELL_RIGHT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-475, -2622), "1 Torch Cell Right Pot", RHT_TH_1_TORCH_CELL_RIGHT_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_1_TORCH_CELL_RIGHT_POT));
|
||||||
locationTable[RC_GF_NORTH_F1_CARPENTER_POT_2] = Location::Pot(RC_GF_NORTH_F1_CARPENTER_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-512, -2621), "North F1 Carpenter Pot 2", RHT_POT_GERUDO_FORTRESS, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F1_CARPENTER_POT_2));
|
locationTable[RC_TH_1_TORCH_CELL_MID_POT] = Location::Pot(RC_TH_1_TORCH_CELL_MID_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-512, -2621), "1 Torch Cell Middle Pot", RHT_TH_1_TORCH_CELL_MID_POT, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_1_TORCH_CELL_MID_POT));
|
||||||
locationTable[RC_GF_NORTH_F1_CARPENTER_POT_3] = Location::Pot(RC_GF_NORTH_F1_CARPENTER_POT_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-511, -2582), "North F1 Carpenter Pot 3", RHT_POT_GERUDO_FORTRESS, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F1_CARPENTER_POT_3));
|
locationTable[RC_TH_1_TORCH_CELL_LEFT_POT] = Location::Pot(RC_TH_1_TORCH_CELL_LEFT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(-511, -2582), "1 Torch Cell Left Pot", RHT_TH_1_TORCH_CELL_LEFT_POT, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_1_TORCH_CELL_LEFT_POT));
|
||||||
locationTable[RC_GF_NORTH_F2_CARPENTER_POT_1] = Location::Pot(RC_GF_NORTH_F2_CARPENTER_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(67, -1975), "North F2 Carpenter Pot 1", RHT_POT_GERUDO_FORTRESS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F2_CARPENTER_POT_1));
|
locationTable[RC_TH_STEEP_SLOPE_RIGHT_POT] = Location::Pot(RC_TH_STEEP_SLOPE_RIGHT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(67, -1975), "Steep Slope Right Pot", RHT_TH_STEEP_SLOPE_RIGHT_POT, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_STEEP_SLOPE_RIGHT_POT));
|
||||||
locationTable[RC_GF_NORTH_F2_CARPENTER_POT_2] = Location::Pot(RC_GF_NORTH_F2_CARPENTER_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(39, -1943), "North F2 Carpenter Pot 2", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_NORTH_F2_CARPENTER_POT_2));
|
locationTable[RC_TH_STEEP_SLOPE_LEFT_POT] = Location::Pot(RC_TH_STEEP_SLOPE_LEFT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(39, -1943), "Steep Slope Left Pot", RHT_TH_STEEP_SLOPE_LEFT_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_STEEP_SLOPE_LEFT_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_POT_1] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(691, 48), "South F1 Carpenter Pot 1", RHT_POT_GERUDO_FORTRESS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_1));
|
locationTable[RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT] = Location::Pot(RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(691, 48), "Double Cell Right Pot", RHT_TH_NEAR_DOUBLE_CELL_RIGHT_POT, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_DOUBLE_CELL_RIGHT_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_POT_2] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(691, 16), "South F1 Carpenter Pot 2", RHT_POT_GERUDO_FORTRESS, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_2));
|
locationTable[RC_TH_NEAR_DOUBLE_CELL_MID_POT] = Location::Pot(RC_TH_NEAR_DOUBLE_CELL_MID_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(691, 16), "Double Cell Middle Pot", RHT_TH_NEAR_DOUBLE_CELL_MID_POT, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_NEAR_DOUBLE_CELL_MID_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_POT_3] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_POT_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(661, 16), "South F1 Carpenter Pot 3", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_3));
|
locationTable[RC_TH_NEAR_DOUBLE_CELL_LEFT_POT] = Location::Pot(RC_TH_NEAR_DOUBLE_CELL_LEFT_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(661, 16), "Double Cell Left Pot", RHT_TH_NEAR_DOUBLE_CELL_LEFT_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_NEAR_DOUBLE_CELL_LEFT_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(26, 524), "South F1 Carpenter Cell Pot 1", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_1));
|
locationTable[RC_TH_RIGHTMOST_JAILED_POT] = Location::Pot(RC_TH_RIGHTMOST_JAILED_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(26, 524), "Rightmost Jailed Pot", RHT_TH_RIGHTMOST_JAILED_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_RIGHTMOST_JAILED_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(61, 549), "South F1 Carpenter Cell Pot 2", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_2));
|
locationTable[RC_TH_RIGHT_MIDDLE_JAILED_POT] = Location::Pot(RC_TH_RIGHT_MIDDLE_JAILED_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(61, 549), "Right Middle Jailed Pot", RHT_TH_LEFT_MIDDLE_JAILED_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_RIGHT_MIDDLE_JAILED_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(215, 549), "South F1 Carpenter Cell Pot 3", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_3));
|
locationTable[RC_TH_LEFT_MIDDLE_JAILED_POT] = Location::Pot(RC_TH_LEFT_MIDDLE_JAILED_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(215, 549), "Left Middle Jailed Pot", RHT_TH_RIGHT_MIDDLE_JAILED_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_LEFT_MIDDLE_JAILED_POT));
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4] = Location::Pot(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(254, 529), "South F1 Carpenter Cell Pot 4", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_4));
|
locationTable[RC_TH_LEFTMOST_JAILED_POT] = Location::Pot(RC_TH_LEFTMOST_JAILED_POT, RCQUEST_BOTH, RCAREA_GERUDO_FORTRESS, SCENE_THIEVES_HIDEOUT, TWO_ACTOR_PARAMS(254, 529), "Leftmost Jailed Pot", RHT_TH_LEFTMOST_JAILED_POT, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_LEFTMOST_JAILED_POT));
|
||||||
locationTable[RC_WASTELAND_NEAR_GS_POT_1] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_1, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(488, -2424), "Near GS Pot 1", RHT_POT_GERUDO_FORTRESS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_1));
|
locationTable[RC_WASTELAND_NEAR_GS_POT_1] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_1, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(488, -2424), "Near GS Pot 1", RHT_POT_WASTELAND, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_1));
|
||||||
locationTable[RC_WASTELAND_NEAR_GS_POT_2] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_2, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(485, -2463), "Near GS Pot 2", RHT_POT_GERUDO_FORTRESS, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_2));
|
locationTable[RC_WASTELAND_NEAR_GS_POT_2] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_2, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(485, -2463), "Near GS Pot 2", RHT_POT_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_2));
|
||||||
locationTable[RC_WASTELAND_NEAR_GS_POT_3] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_3, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(806, -2426), "Near GS Pot 3", RHT_POT_GERUDO_FORTRESS, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_3));
|
locationTable[RC_WASTELAND_NEAR_GS_POT_3] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_3, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(806, -2426), "Near GS Pot 3", RHT_POT_WASTELAND, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_3));
|
||||||
locationTable[RC_WASTELAND_NEAR_GS_POT_4] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_4, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(801, -2460), "Near GS Pot 4", RHT_POT_GERUDO_FORTRESS, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_4));
|
locationTable[RC_WASTELAND_NEAR_GS_POT_4] = Location::Pot(RC_WASTELAND_NEAR_GS_POT_4, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(801, -2460), "Near GS Pot 4", RHT_POT_WASTELAND, RG_RECOVERY_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WASTELAND_NEAR_GS_POT_4));
|
||||||
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_1] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-60, 27), "Guard House Child Pot 1", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_1));
|
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_1] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-60, 27), "Guard House Child Pot 1", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_1));
|
||||||
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_2] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-89, 28), "Guard House Child Pot 2", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_2));
|
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_2] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-89, 28), "Guard House Child Pot 2", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_2));
|
||||||
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_3] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_3, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-110, 6), "Guard House Child Pot 3", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_3));
|
locationTable[RC_MK_GUARD_HOUSE_CHILD_POT_3] = Location::Pot(RC_MK_GUARD_HOUSE_CHILD_POT_3, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-110, 6), "Guard House Child Pot 3", RHT_POT_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CHILD_POT_3));
|
||||||
|
@ -649,5 +659,6 @@ void Rando::StaticData::RegisterPotLocations() {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Register<PotIdentity> RegisterPotIdentity;
|
||||||
static RegisterShipInitFunc registerShufflePots(RegisterShufflePots, { "IS_RANDO" });
|
static RegisterShipInitFunc registerShufflePots(RegisterShufflePots, { "IS_RANDO" });
|
||||||
static RegisterShipInitFunc registerShufflePotLocations(Rando::StaticData::RegisterPotLocations);
|
static RegisterShipInitFunc registerShufflePotLocations(Rando::StaticData::RegisterPotLocations);
|
||||||
|
|
|
@ -276,8 +276,8 @@ void SetAllEntrancesData() {
|
||||||
{ EntranceType::Dungeon, RR_BOTTOM_OF_THE_WELL_ENTRYWAY, RR_KAK_WELL, ENTR_KAKARIKO_VILLAGE_OUTSIDE_BOTTOM_OF_THE_WELL } },
|
{ EntranceType::Dungeon, RR_BOTTOM_OF_THE_WELL_ENTRYWAY, RR_KAK_WELL, ENTR_KAKARIKO_VILLAGE_OUTSIDE_BOTTOM_OF_THE_WELL } },
|
||||||
{ { EntranceType::Dungeon, RR_ZF_LEDGE, RR_ICE_CAVERN_ENTRYWAY, ENTR_ICE_CAVERN_ENTRANCE },
|
{ { EntranceType::Dungeon, RR_ZF_LEDGE, RR_ICE_CAVERN_ENTRYWAY, ENTR_ICE_CAVERN_ENTRANCE },
|
||||||
{ EntranceType::Dungeon, RR_ICE_CAVERN_ENTRYWAY, RR_ZF_LEDGE, ENTR_ZORAS_FOUNTAIN_OUTSIDE_ICE_CAVERN } },
|
{ EntranceType::Dungeon, RR_ICE_CAVERN_ENTRYWAY, RR_ZF_LEDGE, ENTR_ZORAS_FOUNTAIN_OUTSIDE_ICE_CAVERN } },
|
||||||
{ { EntranceType::Dungeon, RR_GERUDO_FORTRESS, RR_GERUDO_TRAINING_GROUND_ENTRYWAY, ENTR_GERUDO_TRAINING_GROUND_ENTRANCE },
|
{ { EntranceType::Dungeon, RR_GF_OUTSIDE_GTG, RR_GERUDO_TRAINING_GROUND_ENTRYWAY, ENTR_GERUDO_TRAINING_GROUND_ENTRANCE },
|
||||||
{ EntranceType::Dungeon, RR_GERUDO_TRAINING_GROUND_ENTRYWAY, RR_GERUDO_FORTRESS, ENTR_GERUDOS_FORTRESS_OUTSIDE_GERUDO_TRAINING_GROUND } },
|
{ EntranceType::Dungeon, RR_GERUDO_TRAINING_GROUND_ENTRYWAY, RR_GF_OUTSIDE_GTG, ENTR_GERUDOS_FORTRESS_OUTSIDE_GERUDO_TRAINING_GROUND } },
|
||||||
{ { EntranceType::GanonDungeon, RR_GANONS_CASTLE_LEDGE, RR_GANONS_CASTLE_ENTRYWAY, ENTR_INSIDE_GANONS_CASTLE_ENTRANCE },
|
{ { EntranceType::GanonDungeon, RR_GANONS_CASTLE_LEDGE, RR_GANONS_CASTLE_ENTRYWAY, ENTR_INSIDE_GANONS_CASTLE_ENTRANCE },
|
||||||
{ EntranceType::GanonDungeon, RR_GANONS_CASTLE_ENTRYWAY, RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE, ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT } },
|
{ EntranceType::GanonDungeon, RR_GANONS_CASTLE_ENTRYWAY, RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE, ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT } },
|
||||||
|
|
||||||
|
@ -429,8 +429,8 @@ void SetAllEntrancesData() {
|
||||||
{ EntranceType::GrottoGrave, RR_KF_STORMS_GROTTO, RR_KOKIRI_FOREST, ENTRANCE_GROTTO_EXIT(GROTTO_KF_STORMS_OFFSET) } },
|
{ EntranceType::GrottoGrave, RR_KF_STORMS_GROTTO, RR_KOKIRI_FOREST, ENTRANCE_GROTTO_EXIT(GROTTO_KF_STORMS_OFFSET) } },
|
||||||
{ { EntranceType::GrottoGrave, RR_ZORAS_DOMAIN_ISLAND, RR_ZD_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_ZD_STORMS_OFFSET) },
|
{ { EntranceType::GrottoGrave, RR_ZORAS_DOMAIN_ISLAND, RR_ZD_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_ZD_STORMS_OFFSET) },
|
||||||
{ EntranceType::GrottoGrave, RR_ZD_STORMS_GROTTO, RR_ZORAS_DOMAIN_ISLAND, ENTRANCE_GROTTO_EXIT(GROTTO_ZD_STORMS_OFFSET) } },
|
{ EntranceType::GrottoGrave, RR_ZD_STORMS_GROTTO, RR_ZORAS_DOMAIN_ISLAND, ENTRANCE_GROTTO_EXIT(GROTTO_ZD_STORMS_OFFSET) } },
|
||||||
{ { EntranceType::GrottoGrave, RR_GERUDO_FORTRESS, RR_GF_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GF_STORMS_OFFSET) },
|
{ { EntranceType::GrottoGrave, RR_GF_NEAR_GROTTO, RR_GF_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GF_STORMS_OFFSET) },
|
||||||
{ EntranceType::GrottoGrave, RR_GF_STORMS_GROTTO, RR_GERUDO_FORTRESS, ENTRANCE_GROTTO_EXIT(GROTTO_GF_STORMS_OFFSET) } },
|
{ EntranceType::GrottoGrave, RR_GF_STORMS_GROTTO, RR_GF_NEAR_GROTTO, ENTRANCE_GROTTO_EXIT(GROTTO_GF_STORMS_OFFSET) } },
|
||||||
{ { EntranceType::GrottoGrave, RR_GV_FORTRESS_SIDE, RR_GV_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GV_STORMS_OFFSET) },
|
{ { EntranceType::GrottoGrave, RR_GV_FORTRESS_SIDE, RR_GV_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GV_STORMS_OFFSET) },
|
||||||
{ EntranceType::GrottoGrave, RR_GV_STORMS_GROTTO, RR_GV_FORTRESS_SIDE, ENTRANCE_GROTTO_EXIT(GROTTO_GV_STORMS_OFFSET) } },
|
{ EntranceType::GrottoGrave, RR_GV_STORMS_GROTTO, RR_GV_FORTRESS_SIDE, ENTRANCE_GROTTO_EXIT(GROTTO_GV_STORMS_OFFSET) } },
|
||||||
{ { EntranceType::GrottoGrave, RR_GV_GROTTO_LEDGE, RR_GV_OCTOROK_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GV_OCTOROK_OFFSET) },
|
{ { EntranceType::GrottoGrave, RR_GV_GROTTO_LEDGE, RR_GV_OCTOROK_GROTTO, ENTRANCE_GROTTO_LOAD(GROTTO_GV_OCTOROK_OFFSET) },
|
||||||
|
@ -474,8 +474,8 @@ void SetAllEntrancesData() {
|
||||||
{ EntranceType::Overworld, RR_LON_LON_RANCH, RR_HYRULE_FIELD, ENTR_HYRULE_FIELD_CENTER_EXIT } },
|
{ EntranceType::Overworld, RR_LON_LON_RANCH, RR_HYRULE_FIELD, ENTR_HYRULE_FIELD_CENTER_EXIT } },
|
||||||
{ { EntranceType::Overworld, RR_LH_FROM_SHORTCUT, RR_ZORAS_DOMAIN, ENTR_ZORAS_DOMAIN_UNDERWATER_SHORTCUT },
|
{ { EntranceType::Overworld, RR_LH_FROM_SHORTCUT, RR_ZORAS_DOMAIN, ENTR_ZORAS_DOMAIN_UNDERWATER_SHORTCUT },
|
||||||
{ EntranceType::Overworld, RR_ZORAS_DOMAIN, RR_LH_FROM_SHORTCUT, ENTR_LAKE_HYLIA_UNDERWATER_SHORTCUT } },
|
{ EntranceType::Overworld, RR_ZORAS_DOMAIN, RR_LH_FROM_SHORTCUT, ENTR_LAKE_HYLIA_UNDERWATER_SHORTCUT } },
|
||||||
{ { EntranceType::Overworld, RR_GV_FORTRESS_SIDE, RR_GERUDO_FORTRESS, ENTR_GERUDOS_FORTRESS_EAST_EXIT },
|
{ { EntranceType::Overworld, RR_GV_FORTRESS_SIDE, RR_GF_OUTSKIRTS, ENTR_GERUDOS_FORTRESS_EAST_EXIT },
|
||||||
{ EntranceType::Overworld, RR_GERUDO_FORTRESS, RR_GV_FORTRESS_SIDE, ENTR_GERUDO_VALLEY_WEST_EXIT } },
|
{ EntranceType::Overworld, RR_GF_OUTSKIRTS, RR_GV_FORTRESS_SIDE, ENTR_GERUDO_VALLEY_WEST_EXIT } },
|
||||||
{ { EntranceType::Overworld, RR_GF_OUTSIDE_GATE, RR_WASTELAND_NEAR_FORTRESS, ENTR_HAUNTED_WASTELAND_EAST_EXIT },
|
{ { EntranceType::Overworld, RR_GF_OUTSIDE_GATE, RR_WASTELAND_NEAR_FORTRESS, ENTR_HAUNTED_WASTELAND_EAST_EXIT },
|
||||||
{ EntranceType::Overworld, RR_WASTELAND_NEAR_FORTRESS, RR_GF_OUTSIDE_GATE, ENTR_GERUDOS_FORTRESS_GATE_EXIT } },
|
{ EntranceType::Overworld, RR_WASTELAND_NEAR_FORTRESS, RR_GF_OUTSIDE_GATE, ENTR_GERUDOS_FORTRESS_GATE_EXIT } },
|
||||||
{ { EntranceType::Overworld, RR_WASTELAND_NEAR_COLOSSUS, RR_DESERT_COLOSSUS, ENTR_DESERT_COLOSSUS_EAST_EXIT },
|
{ { EntranceType::Overworld, RR_WASTELAND_NEAR_COLOSSUS, RR_DESERT_COLOSSUS, ENTR_DESERT_COLOSSUS_EAST_EXIT },
|
||||||
|
|
|
@ -1452,7 +1452,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VB_GIVE_ITEM_GERUDO_MEMBERSHIP_CARD: {
|
case VB_GIVE_ITEM_GERUDO_MEMBERSHIP_CARD: {
|
||||||
Flags_SetRandomizerInf(RAND_INF_GF_ITEM_FROM_LEADER_OF_FORTRESS);
|
Flags_SetRandomizerInf(RAND_INF_TH_ITEM_FROM_LEADER_OF_FORTRESS);
|
||||||
*should = false;
|
*should = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2122,7 +2122,7 @@ void RandomizerOnGameFrameUpdateHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
|
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
|
||||||
gSaveContext.rupees = static_cast<int8_t>(CUR_CAPACITY(UPG_WALLET));
|
gSaveContext.rupees = static_cast<s16>(CUR_CAPACITY(UPG_WALLET));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) {
|
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) {
|
||||||
|
|
|
@ -672,6 +672,11 @@ void RegionTable_Init() {
|
||||||
areaTable[RR_ROOT] = Region("Root", SCENE_ID_MAX, TIME_DOESNT_PASS, {RA_LINKS_POCKET}, {
|
areaTable[RR_ROOT] = Region("Root", SCENE_ID_MAX, TIME_DOESNT_PASS, {RA_LINKS_POCKET}, {
|
||||||
//Events
|
//Events
|
||||||
EventAccess(&logic->KakarikoVillageGateOpen, []{return ctx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN);}),
|
EventAccess(&logic->KakarikoVillageGateOpen, []{return ctx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN);}),
|
||||||
|
EventAccess(&logic->THCouldFree1TorchCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE);}),
|
||||||
|
EventAccess(&logic->THCouldFreeDoubleCellCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}),
|
||||||
|
EventAccess(&logic->TH_CouldFreeDeadEndCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}),
|
||||||
|
EventAccess(&logic->THCouldRescueSlopeCarpenter, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST);}),
|
||||||
|
EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE);}),
|
||||||
}, {
|
}, {
|
||||||
//Locations
|
//Locations
|
||||||
LOCATION(RC_LINKS_POCKET, true),
|
LOCATION(RC_LINKS_POCKET, true),
|
||||||
|
@ -756,6 +761,7 @@ void RegionTable_Init() {
|
||||||
RegionTable_Init_ZorasFountain();
|
RegionTable_Init_ZorasFountain();
|
||||||
RegionTable_Init_GerudoValley();
|
RegionTable_Init_GerudoValley();
|
||||||
RegionTable_Init_GerudoFortress();
|
RegionTable_Init_GerudoFortress();
|
||||||
|
RegionTable_Init_ThievesHideout();
|
||||||
RegionTable_Init_HauntedWasteland();
|
RegionTable_Init_HauntedWasteland();
|
||||||
RegionTable_Init_DesertColossus();
|
RegionTable_Init_DesertColossus();
|
||||||
// Dungeons
|
// Dungeons
|
||||||
|
|
|
@ -389,5 +389,6 @@ void RegionTable_Init_SpiritTemple();
|
||||||
void RegionTable_Init_ShadowTemple();
|
void RegionTable_Init_ShadowTemple();
|
||||||
void RegionTable_Init_BottomOfTheWell();
|
void RegionTable_Init_BottomOfTheWell();
|
||||||
void RegionTable_Init_IceCavern();
|
void RegionTable_Init_IceCavern();
|
||||||
|
void RegionTable_Init_ThievesHideout();
|
||||||
void RegionTable_Init_GerudoTrainingGround();
|
void RegionTable_Init_GerudoTrainingGround();
|
||||||
void RegionTable_Init_GanonsCastle();
|
void RegionTable_Init_GanonsCastle();
|
|
@ -11,7 +11,7 @@ void RegionTable_Init_GerudoTrainingGround() {
|
||||||
//Exits
|
//Exits
|
||||||
Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsVanilla();}),
|
Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsVanilla();}),
|
||||||
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsMQ();}),
|
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsMQ();}),
|
||||||
Entrance(RR_GERUDO_FORTRESS, []{return true;}),
|
Entrance(RR_GF_OUTSIDE_GTG, []{return true;}),
|
||||||
});
|
});
|
||||||
|
|
||||||
#pragma region Vanilla
|
#pragma region Vanilla
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
#include "soh/Enhancements/randomizer/location_access.h"
|
|
||||||
#include "soh/Enhancements/randomizer/entrance.h"
|
|
||||||
|
|
||||||
using namespace Rando;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file should be split into "gerudo_fortress.cpp" (overworld) & "thieves_hideout.cpp" (dungeons)
|
|
||||||
* when the gerudo fortress refactor is done
|
|
||||||
*/
|
|
||||||
|
|
||||||
void RegionTable_Init_GerudoFortress() {
|
|
||||||
// clang-format off
|
|
||||||
areaTable[RR_GERUDO_FORTRESS] = Region("Gerudo Fortress", SCENE_GERUDOS_FORTRESS, {
|
|
||||||
//Events
|
|
||||||
EventAccess(&logic->CarpenterRescue, []{return logic->CanFinishGerudoFortress();}),
|
|
||||||
EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}),
|
|
||||||
EventAccess(&logic->GtG_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET);}),
|
|
||||||
}, {
|
|
||||||
//Locations
|
|
||||||
LOCATION(RC_GF_CHEST, logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || logic->CanUse(RG_LONGSHOT)),
|
|
||||||
LOCATION(RC_GF_HBA_1000_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay),
|
|
||||||
LOCATION(RC_GF_HBA_1500_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay),
|
|
||||||
LOCATION(RC_GF_NORTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
|
||||||
LOCATION(RC_GF_NORTH_F2_CARPENTER, (logic->CanKillEnemy(RE_GERUDO_WARRIOR)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
|
||||||
LOCATION(RC_GF_SOUTH_F2_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
|
||||||
LOCATION(RC_GF_GERUDO_MEMBERSHIP_CARD, logic->CanFinishGerudoFortress()),
|
|
||||||
LOCATION(RC_GF_GS_ARCHERY_RANGE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanGetNightTimeGS()),
|
|
||||||
LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN) || ctx->GetTrickOption(RT_GF_JUMP)) && logic->CanGetNightTimeGS()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_POT_1, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GF_JUMP) && (ctx->GetTrickOption(RT_GF_KITCHEN) || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))) && logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_POT_2, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GF_JUMP) && (ctx->GetTrickOption(RT_GF_KITCHEN) || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))) && logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_POT_1, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_POT_2, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_1, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_2, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_3, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_1, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_2, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_1, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_2, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_3, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, logic->CanBreakPots()),
|
|
||||||
LOCATION(RC_GF_ABOVE_JAIL_CRATE, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || (logic->CanUse(RG_HOOKSHOT) && ctx->GetTrickOption(RT_GF_JUMP))) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_CENTER_CRATE_1, logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_CENTER_CRATE_2, logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_CENTER_CRATE_3, logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_CENTER_CRATE_4, logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_LEFT_CRATE_1, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_OUTSIDE_LEFT_CRATE_2, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_1, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_2, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_3, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_4, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_5, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_6, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RANGE_CRATE_7, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_START_CRATE_1, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_START_CRATE_2, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_LEFT_END_CRATE_1, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_LEFT_END_CRATE_2, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && (logic->IsAdult || (logic->BlastOrSmash() || logic->HookshotOrBoomerang() || logic->CanUse(RG_HOVER_BOOTS)))),
|
|
||||||
LOCATION(RC_GF_ARCHERY_LEFT_END_CHILD_CRATE, logic->IsChild && logic->HasExplosives() && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RIGHT_END_CRATE_1, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_ARCHERY_RIGHT_END_CRATE_2, (logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_CRATE_1, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_CRATE_2, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_CRATE_3, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_CRATE_4, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_KITCHEN_CRATE_5, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_CRATE_1, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GF_JUMP) && (ctx->GetTrickOption(RT_GF_KITCHEN) || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_CRATE_2, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GF_JUMP) && (ctx->GetTrickOption(RT_GF_KITCHEN) || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_CRATE_3, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || ((logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_JUMP)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW)))) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_BREAK_ROOM_CRATE_4, (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || ((logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_JUMP)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW)))) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_NORTH_F1_CARPENTER_CRATE, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_NORTH_F3_CARPENTER_CRATE, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F2_CARPENTER_CRATE_1, logic->CanBreakCrates()),
|
|
||||||
LOCATION(RC_GF_SOUTH_F2_CARPENTER_CRATE_2, logic->CanBreakCrates()),
|
|
||||||
|
|
||||||
|
|
||||||
//RANDOTODO doublecheck when GF isn't a blob
|
|
||||||
LOCATION(RC_GF_KITCHEN_SUN_FAIRY, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_SUNS_SONG)),
|
|
||||||
}, {
|
|
||||||
//Exits
|
|
||||||
Entrance(RR_GV_FORTRESS_SIDE, []{return true;}),
|
|
||||||
Entrance(RR_GF_OUTSIDE_GATE, []{return logic->GF_GateOpen;}),
|
|
||||||
Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return logic->GtG_GateOpen && (logic->IsAdult || ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES));}),
|
|
||||||
Entrance(RR_GF_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}),
|
|
||||||
});
|
|
||||||
|
|
||||||
areaTable[RR_GF_OUTSIDE_GATE] = Region("GF Outside Gate", SCENE_GERUDOS_FORTRESS, {
|
|
||||||
//Events
|
|
||||||
EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) /*|| ShuffleSpecialIndoorEntrances*/);}),
|
|
||||||
}, {}, {
|
|
||||||
//Exits
|
|
||||||
Entrance(RR_GERUDO_FORTRESS, []{return (logic->IsAdult && (logic->CanUse(RG_HOOKSHOT) || !ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES))) || logic->GF_GateOpen;}),
|
|
||||||
Entrance(RR_WASTELAND_NEAR_FORTRESS, []{return true;}),
|
|
||||||
});
|
|
||||||
|
|
||||||
areaTable[RR_GF_STORMS_GROTTO] = Region("GF Storms Grotto", SCENE_GROTTOS, {
|
|
||||||
//Events
|
|
||||||
EventAccess(&logic->FreeFairies, []{return true;}),
|
|
||||||
}, {
|
|
||||||
//Locations
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_1, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_2, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_3, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_4, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_5, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_6, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_7, true),
|
|
||||||
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_8, true),
|
|
||||||
}, {
|
|
||||||
//Exits
|
|
||||||
Entrance(RR_GERUDO_FORTRESS, []{return true;}),
|
|
||||||
});
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
|
@ -0,0 +1,249 @@
|
||||||
|
#include "soh/Enhancements/randomizer/location_access.h"
|
||||||
|
#include "soh/Enhancements/randomizer/entrance.h"
|
||||||
|
|
||||||
|
using namespace Rando;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
void RegionTable_Init_GerudoFortress() {
|
||||||
|
#pragma region Ground
|
||||||
|
|
||||||
|
areaTable[RR_GF_OUTSKIRTS] = Region("Gerudo Fortress Outskirts", SCENE_GERUDOS_FORTRESS, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}), //needs climb
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_OUTSKIRTS_NE_CRATE, (logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD)) && logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_OUTSKIRTS_NW_CRATE, logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD)),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GV_FORTRESS_SIDE, []{return true;}),
|
||||||
|
Entrance(RR_TH_1_TORCH_CELL, []{return true;}),
|
||||||
|
Entrance(RR_GF_OUTSIDE_GATE, []{return logic->GF_GateOpen;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
Entrance(RR_GF_OUTSIDE_GTG, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
//You can talk to the guards to get yourself thrown in jail, so long as you have a hookshot to actually end up there
|
||||||
|
Entrance(RR_GF_JAIL_WINDOW, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_NEAR_GROTTO] = Region("GF Near Grotto", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_SOUTHMOST_CENTER_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_MID_SOUTH_CENTER_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_MID_NORTH_CENTER_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RR_GF_NORTHMOST_CENTER_CRATE, logic->CanBreakCrates()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_1_TORCH_CELL, []{return true;}),
|
||||||
|
Entrance(RR_TH_STEEP_SLOPE_CELL, []{return true;}),
|
||||||
|
Entrance(RR_TH_KITCHEN_CORRIDOR, []{return true;}),
|
||||||
|
//Jail
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_JAIL_WINDOW, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
Entrance(RR_GF_OUTSIDE_GTG, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
Entrance(RR_GF_TOP_OF_UPPER_VINES, []{return logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
Entrance(RR_GF_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_OUTSIDE_GTG] = Region("GF Outside GTG", SCENE_GERUDOS_FORTRESS, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->GtG_GateOpen, []{return (logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET));}),
|
||||||
|
}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return logic->GtG_GateOpen && (logic->IsAdult || ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES));}),
|
||||||
|
//Jail
|
||||||
|
Entrance(RR_GF_JAIL_WINDOW, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
// RANDTODO: Add tricks for getting past the gerudo guarding the hba range
|
||||||
|
Entrance(RR_GF_ABOVE_GTG, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
Entrance(RR_GF_TOP_OF_UPPER_VINES, []{return logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
Entrance(RR_GF_HBA_RANGE, []{return logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Rooftops
|
||||||
|
|
||||||
|
areaTable[RR_GF_ABOVE_GTG] = Region("GF Above GTG", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_DOUBLE_CELL, []{return true;}),
|
||||||
|
Entrance(RR_TH_KITCHEN_CORRIDOR, []{return true;}),
|
||||||
|
//Jail
|
||||||
|
Entrance(RR_GF_JAIL_WINDOW, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
Entrance(RR_GF_OUTSIDE_GTG, []{return logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
// need to explicitly convert it into a bool
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_LOWER_VINES, []{return ctx->GetTrickOption(RT_GF_JUMP).Get() != 0 ;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_BOTTOM_OF_LOWER_VINES] = Region("GF Bottom of Lower Vines", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_STEEP_SLOPE_CELL, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true /* logic->CanClimb() */;}),
|
||||||
|
Entrance(RR_GF_ABOVE_GTG, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_TOP_OF_LOWER_VINES] = Region("GF Top of Lower Vines", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_KITCHEN_TOP, []{return true;}),
|
||||||
|
Entrance(RR_TH_DOUBLE_CELL, []{return true;}),
|
||||||
|
Entrance(RR_GF_ABOVE_GTG, []{return true;}),
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_LOWER_VINES, []{return true;}),
|
||||||
|
// need to explicitly convert it into a bool
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_UPPER_VINES, []{return logic->IsAdult && ctx->GetTrickOption(RT_GF_JUMP).Get();}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_NEAR_GS] = Region("GF Near GS", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOMB_THROW) && logic->CanGetNightTimeGS()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_KITCHEN_TOP, []{return true;}),
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_SLOPED_ROOF, []{return logic->IsAdult;}),
|
||||||
|
Entrance(RR_GF_LONG_ROOF, []{return logic->CanUse(RG_HOVER_BOOTS) /* || bunny hood jump */ || logic->IsAdult && ctx->GetTrickOption(RT_GF_JUMP);}),
|
||||||
|
Entrance(RR_GF_NEAR_CHEST, []{return logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
Entrance(RR_GF_BELOW_GS, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_SLOPED_ROOF] = Region("GF Sloped Roof", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GS, []{return true;}),
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_UPPER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_TOP_OF_UPPER_VINES, []{return logic->IsAdult && ctx->GetTrickOption(RT_GF_JUMP).Get();}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_BOTTOM_OF_UPPER_VINES] = Region("GF Bottom of Upper Vines", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_OUTSIDE_GTG, []{return true;}),
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_SLOPED_ROOF, []{return logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS);}),
|
||||||
|
Entrance(RR_GF_TOP_OF_UPPER_VINES, []{return true /* logic->CanClimb() */;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_TOP_OF_UPPER_VINES] = Region("GF Top of Upper Vines", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
//if RR_GF_SLOPED_ROOF > RR_GF_TOP_OF_UPPER_VINES is ever made part of RT_GF_JUMP, climb is needed to get back up
|
||||||
|
LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH) && logic->CanGetNightTimeGS()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_SLOPED_ROOF, []{return true;}),
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_UPPER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_CHEST, []{return logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_SCARECROW) && logic->CanUse(RG_HOOKSHOT)) || logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_NEAR_CHEST] = Region("GF Near Chest", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_CHEST, true),
|
||||||
|
LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) && logic->CanGetNightTimeGS()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_NEAR_GS, []{return true;}),
|
||||||
|
Entrance(RR_GF_LONG_ROOF, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_LONG_ROOF] = Region("GF Long Roof", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_LOWER_VINES, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GS, []{return (logic->IsAdult && ctx->GetTrickOption(RT_GF_JUMP)) || logic->CanUse(RG_HOVER_BOOTS);}),
|
||||||
|
Entrance(RR_GF_BELOW_GS, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_CHEST, []{return logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
Entrance(RR_GF_BELOW_CHEST, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_BELOW_GS] = Region("GF Below GS", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_LONGSHOT) && logic->CanGetNightTimeGS()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_DEAD_END_CELL, []{return true;}),
|
||||||
|
Entrance(RR_GF_BOTTOM_OF_LOWER_VINES, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_BELOW_CHEST] = Region("GF Below Chest", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_BREAK_ROOM, []{return true;}),
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
areaTable[RR_GF_ABOVE_JAIL] = Region("GF Above Jail", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_ABOVE_JAIL_CRATE, true),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
//you don't take fall damage if you land on the rock with the flag on for some reason
|
||||||
|
//there's a trick to reach RR_GF_LONG_ROOF but that's too intricate for GF_JUMP
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return ctx->GetTrickOption(RT_GF_JUMP).Get() != 0;}),
|
||||||
|
Entrance(RR_GF_NEAR_CHEST, []{return logic->CanUse(RG_LONGSHOT);}),
|
||||||
|
Entrance(RR_GF_BELOW_CHEST, []{return logic->TakeDamage();}),
|
||||||
|
Entrance(RR_GF_JAIL_WINDOW, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_JAIL_WINDOW] = Region("GF Jail Window", SCENE_GERUDOS_FORTRESS, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
//There's a trick where hovers backwalk into backflip gives access to RR_GF_LONG_ROOF from here
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_BELOW_CHEST, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_HBA_RANGE] = Region("GF HBA Range", SCENE_GERUDOS_FORTRESS, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_HBA_1000_POINTS, logic->IsAdult && logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay),
|
||||||
|
LOCATION(RC_GF_HBA_1500_POINTS, logic->IsAdult && logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_GS, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) && logic->CanGetNightTimeGS()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_1, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_2, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_3, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_4, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_5, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_6, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_RANGE_CRATE_7, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_CANOPY_EAST_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_HBA_CANOPY_WEST_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_NORTH_TARGET_EAST_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_NORTH_TARGET_WEST_CRATE, logic->IsAdult || (logic->BlastOrSmash() || logic->HookshotOrBoomerang() || logic->CanUse(RG_HOVER_BOOTS))),
|
||||||
|
//implies logic->CanBreakCrates()
|
||||||
|
LOCATION(RC_GF_NORTH_TARGET_CHILD_CRATE, logic->IsChild && logic->BlastOrSmash()),
|
||||||
|
LOCATION(RC_GF_SOUTH_TARGET_EAST_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_GF_SOUTH_TARGET_WEST_CRATE, logic->CanBreakCrates()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_OUTSIDE_GTG, []{return logic->IsChild || logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_OUTSIDE_GATE] = Region("GF Outside Gate", SCENE_GERUDOS_FORTRESS, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}),
|
||||||
|
}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return logic->GF_GateOpen;}),
|
||||||
|
Entrance(RR_WASTELAND_NEAR_FORTRESS, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_GF_STORMS_GROTTO] = Region("GF Storms Grotto", SCENE_GROTTOS, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->FreeFairies, []{return true;}),
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_1, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_2, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_3, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_4, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_5, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_6, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_7, true),
|
||||||
|
LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_8, true),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// clang-format on
|
|
@ -17,7 +17,7 @@ void RegionTable_Init_GerudoValley() {
|
||||||
Entrance(RR_GV_UPPER_STREAM, []{return logic->IsChild || logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}),
|
Entrance(RR_GV_UPPER_STREAM, []{return logic->IsChild || logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}),
|
||||||
Entrance(RR_GV_CRATE_LEDGE, []{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}),
|
Entrance(RR_GV_CRATE_LEDGE, []{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}),
|
||||||
Entrance(RR_GV_GROTTO_LEDGE, []{return true;}),
|
Entrance(RR_GV_GROTTO_LEDGE, []{return true;}),
|
||||||
Entrance(RR_GV_FORTRESS_SIDE, []{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}),
|
Entrance(RR_GV_FORTRESS_SIDE, []{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->THRescuedAllCarpenters)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}),
|
||||||
Entrance(RR_GV_LOWER_STREAM, []{return logic->IsChild;}), //can use cucco as child
|
Entrance(RR_GV_LOWER_STREAM, []{return logic->IsChild;}), //can use cucco as child
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -78,9 +78,9 @@ void RegionTable_Init_GerudoValley() {
|
||||||
LOCATION(RC_GV_CRATE_BRIDGE_4, logic->IsChild && logic->CanBreakCrates()),
|
LOCATION(RC_GV_CRATE_BRIDGE_4, logic->IsChild && logic->CanBreakCrates()),
|
||||||
}, {
|
}, {
|
||||||
//Exits
|
//Exits
|
||||||
Entrance(RR_GERUDO_FORTRESS, []{return true;}),
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
Entrance(RR_GV_UPPER_STREAM, []{return true;}),
|
Entrance(RR_GV_UPPER_STREAM, []{return true;}),
|
||||||
Entrance(RR_GERUDO_VALLEY, []{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue;}),
|
Entrance(RR_GERUDO_VALLEY, []{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->THRescuedAllCarpenters;}),
|
||||||
Entrance(RR_GV_CARPENTER_TENT, []{return logic->IsAdult;}),
|
Entrance(RR_GV_CARPENTER_TENT, []{return logic->IsAdult;}),
|
||||||
Entrance(RR_GV_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}),
|
Entrance(RR_GV_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}),
|
||||||
Entrance(RR_GV_CRATE_LEDGE, []{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}),
|
Entrance(RR_GV_CRATE_LEDGE, []{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}),
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include "soh/Enhancements/randomizer/location_access.h"
|
||||||
|
#include "soh/Enhancements/randomizer/entrance.h"
|
||||||
|
|
||||||
|
using namespace Rando;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// When Thieve's hideout entrances are shuffled, getting caught by guards should behave like void outs to avoid logic headaches.
|
||||||
|
void RegionTable_Init_ThievesHideout() {
|
||||||
|
areaTable[RR_TH_1_TORCH_CELL] = Region("Thieves Hideout 1 Torch Cell", SCENE_THIEVES_HIDEOUT, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->THCouldFree1TorchCarpenter, []{return logic->CanKillEnemy(RE_GERUDO_WARRIOR);}),
|
||||||
|
EventAccess(&logic->THRescuedAllCarpenters, []{return logic->SmallKeys(RR_GF_OUTSKIRTS, ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL) ? 4 : 1) && logic->THCouldFree1TorchCarpenter && logic->THCouldFreeDoubleCellCarpenter && logic->TH_CouldFreeDeadEndCarpenter && logic->THCouldRescueSlopeCarpenter;}),
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_1_TORCH_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
||||||
|
LOCATION(RC_TH_1_TORCH_CELL_RIGHT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_1_TORCH_CELL_MID_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_1_TORCH_CELL_LEFT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_1_TORCH_CELL_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_FREED_CARPENTERS, logic->THRescuedAllCarpenters),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_DOUBLE_CELL] = Region("Thieves Hideout Double Cell", SCENE_THIEVES_HIDEOUT, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->THCouldFreeDoubleCellCarpenter, []{return logic->CanKillEnemy(RE_GERUDO_WARRIOR);}),
|
||||||
|
EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL) && logic->SmallKeys(RR_GF_OUTSKIRTS, 4) && logic->THCouldFree1TorchCarpenter && logic->THCouldFreeDoubleCellCarpenter && logic->TH_CouldFreeDeadEndCarpenter && logic->THCouldRescueSlopeCarpenter;}),
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_DOUBLE_CELL_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
||||||
|
LOCATION(RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_NEAR_DOUBLE_CELL_MID_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_NEAR_DOUBLE_CELL_LEFT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_RIGHTMOST_JAILED_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_RIGHT_MIDDLE_JAILED_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_LEFT_MIDDLE_JAILED_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_LEFTMOST_JAILED_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_DOUBLE_CELL_LEFT_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_DOUBLE_CELL_RIGHT_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_FREED_CARPENTERS, logic->THRescuedAllCarpenters),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_OUTSKIRTS, []{return true;}),
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_DEAD_END_CELL] = Region("Thieves Hideout Dead End Cell", SCENE_THIEVES_HIDEOUT, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->TH_CouldFreeDeadEndCarpenter, []{return logic->CanKillEnemy(RE_GERUDO_WARRIOR);}),
|
||||||
|
EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL) && logic->SmallKeys(RR_GF_OUTSKIRTS, 4) && logic->THCouldFree1TorchCarpenter && logic->THCouldFreeDoubleCellCarpenter && logic->TH_CouldFreeDeadEndCarpenter && logic->THCouldRescueSlopeCarpenter;}),
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_DEAD_END_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
||||||
|
LOCATION(RC_TH_DEAD_END_CELL_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_FREED_CARPENTERS, logic->THRescuedAllCarpenters),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_BELOW_GS, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_STEEP_SLOPE_CELL] = Region("Thieves Hideout Steep Slope Cell", SCENE_THIEVES_HIDEOUT, {
|
||||||
|
//Events
|
||||||
|
EventAccess(&logic->THCouldRescueSlopeCarpenter, []{return logic->CanKillEnemy(RE_GERUDO_WARRIOR);}),
|
||||||
|
EventAccess(&logic->THRescuedAllCarpenters, []{return ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL) && logic->SmallKeys(RR_GF_OUTSKIRTS, 4) && logic->THCouldFree1TorchCarpenter && logic->THCouldFreeDoubleCellCarpenter && logic->TH_CouldFreeDeadEndCarpenter && logic->THCouldRescueSlopeCarpenter;}),
|
||||||
|
}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_STEEP_SLOPE_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)),
|
||||||
|
LOCATION(RC_TH_STEEP_SLOPE_RIGHT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_STEEP_SLOPE_LEFT_POT, logic->CanBreakPots()),
|
||||||
|
LOCATION(RC_TH_FREED_CARPENTERS, logic->THRescuedAllCarpenters),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_ABOVE_GTG, []{return true;}),
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return true;}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_KITCHEN_CORRIDOR] = Region("Thieves Hideout Kitchen Corridor", SCENE_THIEVES_HIDEOUT, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE, logic->CanBreakCrates()),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
|
||||||
|
Entrance(RR_GF_ABOVE_GTG, []{return true;}),
|
||||||
|
Entrance(RR_TH_KITCHEN_MAIN, []{return logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_KITCHEN_MAIN] = Region("Thieves Hideout Kitchen Bottom", SCENE_THIEVES_HIDEOUT, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_KITCHEN_POT_1, logic->CanBreakPots() && logic->CanPassEnemy(RE_GERUDO_GUARD)),
|
||||||
|
LOCATION(RC_TH_KITCHEN_POT_2, logic->CanBreakPots() && logic->CanPassEnemy(RE_GERUDO_GUARD)),
|
||||||
|
LOCATION(RC_TH_KITCHEN_CRATE, logic->CanBreakCrates() && logic->CanPassEnemy(RE_GERUDO_GUARD)),
|
||||||
|
LOCATION(RC_TH_KITCHEN_SUN_FAIRY, logic->CanPassEnemy(RE_GERUDO_GUARD) && logic->CanUse(RG_SUNS_SONG)),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_KITCHEN_CORRIDOR, []{return logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
Entrance(RR_TH_KITCHEN_TOP, []{return logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_KITCHEN_TOP] = Region("Thieves Hideout Kitchen Top", SCENE_THIEVES_HIDEOUT, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_KITCHEN_POT_1, logic->CanUse(RG_BOOMERANG)),
|
||||||
|
LOCATION(RC_TH_KITCHEN_POT_2, logic->CanUse(RG_BOOMERANG)),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_KITCHEN_MAIN, []{return true;}),
|
||||||
|
//hookshot to cross using the rafters is implied in logic->CanPassEnemy(RE_GERUDO_GUARD)
|
||||||
|
Entrance(RR_GF_NEAR_GS, []{return logic->CanPassEnemy(RE_GERUDO_GUARD) || logic->CanUse(RG_HOVER_BOOTS);}),
|
||||||
|
Entrance(RR_GF_TOP_OF_LOWER_VINES, []{return logic->CanPassEnemy(RE_GERUDO_GUARD) || logic->CanUse(RG_HOVER_BOOTS);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_BREAK_ROOM] = Region("Thieves Hideout Break Room", SCENE_THIEVES_HIDEOUT, {}, {
|
||||||
|
//Locations
|
||||||
|
LOCATION(RC_TH_BREAK_ROOM_FRONT_POT, (logic->CanPassEnemy(RE_BREAK_ROOM_GUARD) && logic->CanBreakPots()) ||
|
||||||
|
(logic->CanPassEnemy(RE_GERUDO_GUARD) && logic->CanUse(RG_BOOMERANG))),
|
||||||
|
LOCATION(RC_TH_BREAK_ROOM_BACK_POT, (logic->CanPassEnemy(RE_BREAK_ROOM_GUARD) && logic->CanBreakPots()) ||
|
||||||
|
(logic->CanPassEnemy(RE_GERUDO_GUARD) && logic->CanUse(RG_BOOMERANG))),
|
||||||
|
LOCATION(RC_TH_BREAK_HALLWAY_OUTER_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_BREAK_HALLWAY_INNER_CRATE, logic->CanBreakCrates()),
|
||||||
|
LOCATION(RC_TH_BREAK_ROOM_RIGHT_CRATE, (logic->CanPassEnemy(RE_BREAK_ROOM_GUARD) && logic->CanBreakCrates()) ||
|
||||||
|
(logic->CanPassEnemy(RE_GERUDO_GUARD) && logic->HasExplosives() && logic->CanUse(RG_BOOMERANG))),
|
||||||
|
LOCATION(RC_TH_BREAK_ROOM_LEFT_CRATE, (logic->CanPassEnemy(RE_BREAK_ROOM_GUARD) && logic->CanBreakCrates()) ||
|
||||||
|
(logic->CanPassEnemy(RE_GERUDO_GUARD) && logic->HasExplosives() && logic->CanUse(RG_BOOMERANG))),
|
||||||
|
}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_GF_BELOW_CHEST, []{return logic->CanPassEnemy(RE_GERUDO_GUARD);}),
|
||||||
|
//Implies logic->CanPassEnemy(RE_GERUDO_GUARD)
|
||||||
|
Entrance(RR_TH_BREAK_ROOM_CORRIDOR, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
});
|
||||||
|
|
||||||
|
areaTable[RR_TH_BREAK_ROOM_CORRIDOR] = Region("Thieves Hideout Break Room", SCENE_THIEVES_HIDEOUT, {}, {}, {
|
||||||
|
//Exits
|
||||||
|
Entrance(RR_TH_BREAK_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}),
|
||||||
|
Entrance(RR_GF_ABOVE_JAIL, []{return true;}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// clang-format on
|
|
@ -173,12 +173,12 @@ void Rando::StaticData::InitLocationTable() {
|
||||||
locationTable[RC_GF_CHEST] = Location::Chest(RC_GF_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_GERUDOS_FORTRESS, 1984, 0x00, "Chest", RHT_GF_CHEST, RG_PIECE_OF_HEART, true);
|
locationTable[RC_GF_CHEST] = Location::Chest(RC_GF_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_GERUDOS_FORTRESS, 1984, 0x00, "Chest", RHT_GF_CHEST, RG_PIECE_OF_HEART, true);
|
||||||
locationTable[RC_GF_HBA_1000_POINTS] = Location::Base(RC_GF_HBA_1000_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, "HBA 1000 Points", RHT_GF_HBA_1000_POINTS, RG_PIECE_OF_HEART, SpoilerCollectionCheck::InfTable(INFTABLE_190), true);
|
locationTable[RC_GF_HBA_1000_POINTS] = Location::Base(RC_GF_HBA_1000_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, "HBA 1000 Points", RHT_GF_HBA_1000_POINTS, RG_PIECE_OF_HEART, SpoilerCollectionCheck::InfTable(INFTABLE_190), true);
|
||||||
locationTable[RC_GF_HBA_1500_POINTS] = Location::Base(RC_GF_HBA_1500_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, "HBA 1500 Points", RHT_GF_HBA_1500_POINTS, RG_PROGRESSIVE_BOW, SpoilerCollectionCheck::ItemGetInf(15), true);
|
locationTable[RC_GF_HBA_1500_POINTS] = Location::Base(RC_GF_HBA_1500_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, "HBA 1500 Points", RHT_GF_HBA_1500_POINTS, RG_PROGRESSIVE_BOW, SpoilerCollectionCheck::ItemGetInf(15), true);
|
||||||
// RandoTodo: Do we replace these with the RC_HIDEOUT keys or keep these?
|
// Thieves Hideout
|
||||||
locationTable[RC_GF_GERUDO_MEMBERSHIP_CARD] = Location::Base(RC_GF_GERUDO_MEMBERSHIP_CARD, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_THIEVES_HIDEOUT, 0x00, "Gerudo Membership Card", RHT_GF_GERUDO_MEMBERSHIP_CARD, RG_GERUDO_MEMBERSHIP_CARD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GF_ITEM_FROM_LEADER_OF_FORTRESS), true);
|
locationTable[RC_TH_FREED_CARPENTERS] = Location::Base(RC_TH_FREED_CARPENTERS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_THIEVES_HIDEOUT, 0x00, "Freed All Carpenters", RHT_TH_FREED_CARPENTERS, RG_GERUDO_MEMBERSHIP_CARD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_TH_ITEM_FROM_LEADER_OF_FORTRESS), true);
|
||||||
locationTable[RC_GF_NORTH_F1_CARPENTER] = Location::Collectable(RC_GF_NORTH_F1_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3089, 0x0C, "North F1 Carpenter", RHT_GF_NORTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
locationTable[RC_TH_1_TORCH_CARPENTER] = Location::Collectable(RC_TH_1_TORCH_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3089, 0x0C, "1 Torch Carpenter", RHT_TH_1_TORCH_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
||||||
locationTable[RC_GF_NORTH_F2_CARPENTER] = Location::Collectable(RC_GF_NORTH_F2_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 2577, 0x0A, "North F2 Carpenter", RHT_GF_NORTH_F2_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
locationTable[RC_TH_DEAD_END_CARPENTER] = Location::Collectable(RC_TH_DEAD_END_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 2577, 0x0A, "Dead End Carpenter", RHT_TH_DEAD_END_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
||||||
locationTable[RC_GF_SOUTH_F1_CARPENTER] = Location::Collectable(RC_GF_SOUTH_F1_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3601, 0x0E, "South F1 Carpenter", RHT_GF_SOUTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
locationTable[RC_TH_DOUBLE_CELL_CARPENTER] = Location::Collectable(RC_TH_DOUBLE_CELL_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3601, 0x0E, "Double Cell Carpenter", RHT_TH_DOUBLE_CELL_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
||||||
locationTable[RC_GF_SOUTH_F2_CARPENTER] = Location::Collectable(RC_GF_SOUTH_F2_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3857, 0x0F, "South F2 Carpenter", RHT_GF_SOUTH_F2_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
locationTable[RC_TH_STEEP_SLOPE_CARPENTER] = Location::Collectable(RC_TH_STEEP_SLOPE_CARPENTER, RCQUEST_BOTH, RCTYPE_GF_KEY, ACTOR_EN_ITEM00, SCENE_THIEVES_HIDEOUT, 3857, 0x0F, "Steep Slope Carpenter", RHT_TH_STEEP_SLOPE_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, true);
|
||||||
// Haunted Wasteland
|
// Haunted Wasteland
|
||||||
locationTable[RC_WASTELAND_CHEST] = Location::Chest(RC_WASTELAND_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_WASTELAND, ACTOR_EN_BOX, SCENE_HAUNTED_WASTELAND, -30048, 0x00, "Chest", RHT_WASTELAND_CHEST, RG_PURPLE_RUPEE);
|
locationTable[RC_WASTELAND_CHEST] = Location::Chest(RC_WASTELAND_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_WASTELAND, ACTOR_EN_BOX, SCENE_HAUNTED_WASTELAND, -30048, 0x00, "Chest", RHT_WASTELAND_CHEST, RG_PURPLE_RUPEE);
|
||||||
locationTable[RC_WASTELAND_BOMBCHU_SALESMAN] = Location::Base(RC_WASTELAND_BOMBCHU_SALESMAN, RCQUEST_BOTH, RCTYPE_MERCHANT, RCAREA_WASTELAND, ACTOR_ID_MAX, SCENE_HAUNTED_WASTELAND, 0x00, "Carpet Salesman", RHT_WASTELAND_BOMBCHU_SALESMAN, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN), false, 200);
|
locationTable[RC_WASTELAND_BOMBCHU_SALESMAN] = Location::Base(RC_WASTELAND_BOMBCHU_SALESMAN, RCQUEST_BOTH, RCTYPE_MERCHANT, RCAREA_WASTELAND, ACTOR_ID_MAX, SCENE_HAUNTED_WASTELAND, 0x00, "Carpet Salesman", RHT_WASTELAND_BOMBCHU_SALESMAN, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN), false, 200);
|
||||||
|
@ -748,7 +748,7 @@ void Rando::StaticData::InitLocationTable() {
|
||||||
locationTable[RC_GV_GS_PILLAR] = Location::GSToken(RC_GV_GS_PILLAR, RCQUEST_BOTH, SCENE_GERUDO_VALLEY, 21252, 0x04, "GS Pillar", RHT_GV_GS_PILLAR, 0x13);
|
locationTable[RC_GV_GS_PILLAR] = Location::GSToken(RC_GV_GS_PILLAR, RCQUEST_BOTH, SCENE_GERUDO_VALLEY, 21252, 0x04, "GS Pillar", RHT_GV_GS_PILLAR, 0x13);
|
||||||
locationTable[RC_GV_GS_BEHIND_TENT] = Location::GSToken(RC_GV_GS_BEHIND_TENT, RCQUEST_BOTH, SCENE_GERUDO_VALLEY, 21256, 0x08, "GS Behind Tent", RHT_GV_GS_BEHIND_TENT, 0x13);
|
locationTable[RC_GV_GS_BEHIND_TENT] = Location::GSToken(RC_GV_GS_BEHIND_TENT, RCQUEST_BOTH, SCENE_GERUDO_VALLEY, 21256, 0x08, "GS Behind Tent", RHT_GV_GS_BEHIND_TENT, 0x13);
|
||||||
// Gerudo Fortress
|
// Gerudo Fortress
|
||||||
locationTable[RC_GF_GS_ARCHERY_RANGE] = Location::GSToken(RC_GF_GS_ARCHERY_RANGE, RCQUEST_BOTH, SCENE_GERUDOS_FORTRESS, 21505, 0x01, "GS Archery Range", RHT_GF_GS_ARCHERY_RANGE, 0x14);
|
locationTable[RC_GF_HBA_RANGE_GS] = Location::GSToken(RC_GF_HBA_RANGE_GS, RCQUEST_BOTH, SCENE_GERUDOS_FORTRESS, 21505, 0x01, "GS Archery Range", RHT_GF_GS_ARCHERY_RANGE, 0x14);
|
||||||
locationTable[RC_GF_GS_TOP_FLOOR] = Location::GSToken(RC_GF_GS_TOP_FLOOR, RCQUEST_BOTH, SCENE_GERUDOS_FORTRESS, 21506, 0x02, "GS Top Floor", RHT_GF_GS_TOP_FLOOR, 0x14);
|
locationTable[RC_GF_GS_TOP_FLOOR] = Location::GSToken(RC_GF_GS_TOP_FLOOR, RCQUEST_BOTH, SCENE_GERUDOS_FORTRESS, 21506, 0x02, "GS Top Floor", RHT_GF_GS_TOP_FLOOR, 0x14);
|
||||||
// Wasteland & Desert Colossus
|
// Wasteland & Desert Colossus
|
||||||
locationTable[RC_WASTELAND_GS] = Location::GSToken(RC_WASTELAND_GS, RCQUEST_BOTH, SCENE_HAUNTED_WASTELAND, 13570, 0x02, "GS", RHT_WASTELAND_GS, 0x15);
|
locationTable[RC_WASTELAND_GS] = Location::GSToken(RC_WASTELAND_GS, RCQUEST_BOTH, SCENE_HAUNTED_WASTELAND, 13570, 0x02, "GS", RHT_WASTELAND_GS, 0x15);
|
||||||
|
|
|
@ -487,6 +487,9 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
bool inWater) {
|
bool inWater) {
|
||||||
bool killed = false;
|
bool killed = false;
|
||||||
switch (enemy) {
|
switch (enemy) {
|
||||||
|
case RE_GERUDO_GUARD:
|
||||||
|
case RE_BREAK_ROOM_GUARD:
|
||||||
|
return false;
|
||||||
case RE_GOLD_SKULLTULA:
|
case RE_GOLD_SKULLTULA:
|
||||||
switch (distance) {
|
switch (distance) {
|
||||||
case ED_CLOSE:
|
case ED_CLOSE:
|
||||||
|
@ -835,6 +838,11 @@ bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
case RE_PURPLE_LEEVER:
|
case RE_PURPLE_LEEVER:
|
||||||
case RE_OCTOROK:
|
case RE_OCTOROK:
|
||||||
return true;
|
return true;
|
||||||
|
case RE_GERUDO_GUARD:
|
||||||
|
return ctx->GetTrickOption(RT_PASS_GUARDS_WITH_NOTHING) || HasItem(RG_GERUDO_MEMBERSHIP_CARD) ||
|
||||||
|
CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT);
|
||||||
|
case RE_BREAK_ROOM_GUARD:
|
||||||
|
return HasItem(RG_GERUDO_MEMBERSHIP_CARD) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT);
|
||||||
case RE_BIG_SKULLTULA:
|
case RE_BIG_SKULLTULA:
|
||||||
// hammer jumpslash can pass, but only on flat land where you can kill with hammer swing
|
// hammer jumpslash can pass, but only on flat land where you can kill with hammer swing
|
||||||
return CanUse(RG_NUTS) || CanUse(RG_BOOMERANG);
|
return CanUse(RG_NUTS) || CanUse(RG_BOOMERANG);
|
||||||
|
@ -843,6 +851,7 @@ bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
|
||||||
case RE_GIBDO:
|
case RE_GIBDO:
|
||||||
case RE_REDEAD:
|
case RE_REDEAD:
|
||||||
// we need a way to check if suns won't force a reload
|
// we need a way to check if suns won't force a reload
|
||||||
|
// RANDOTODO: check if stealthing past these guys works everywhere
|
||||||
return CanUse(RG_HOOKSHOT) || CanUse(RG_SUNS_SONG);
|
return CanUse(RG_HOOKSHOT) || CanUse(RG_SUNS_SONG);
|
||||||
case RE_IRON_KNUCKLE:
|
case RE_IRON_KNUCKLE:
|
||||||
case RE_BIG_OCTO:
|
case RE_BIG_OCTO:
|
||||||
|
@ -1308,16 +1317,6 @@ bool Logic::TradeQuestStep(RandomizerGet rg) {
|
||||||
return hasState;
|
return hasState;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logic::CanFinishGerudoFortress() {
|
|
||||||
return (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL) && SmallKeys(RR_GERUDO_FORTRESS, 4) &&
|
|
||||||
CanKillEnemy(RE_GERUDO_WARRIOR) &&
|
|
||||||
(HasItem(RG_GERUDO_MEMBERSHIP_CARD) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) ||
|
|
||||||
CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))) ||
|
|
||||||
(ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST) && SmallKeys(RR_GERUDO_FORTRESS, 1) &&
|
|
||||||
CanKillEnemy(RE_GERUDO_WARRIOR)) ||
|
|
||||||
ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Logic::CanStandingShield() {
|
bool Logic::CanStandingShield() {
|
||||||
return CanUse(RG_MIRROR_SHIELD) || (IsAdult && HasItem(RG_HYLIAN_SHIELD)) || CanUse(RG_DEKU_SHIELD);
|
return CanUse(RG_MIRROR_SHIELD) || (IsAdult && HasItem(RG_HYLIAN_SHIELD)) || CanUse(RG_DEKU_SHIELD);
|
||||||
}
|
}
|
||||||
|
@ -1440,7 +1439,7 @@ bool Logic::SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless
|
||||||
}*/
|
}*/
|
||||||
return GetSmallKeyCount(SCENE_TREASURE_BOX_SHOP) >= requiredAmountGlitchless;
|
return GetSmallKeyCount(SCENE_TREASURE_BOX_SHOP) >= requiredAmountGlitchless;
|
||||||
|
|
||||||
case RR_GERUDO_FORTRESS:
|
case RR_GF_OUTSKIRTS:
|
||||||
return GetSmallKeyCount(SCENE_THIEVES_HIDEOUT) >= requiredAmountGlitchless;
|
return GetSmallKeyCount(SCENE_THIEVES_HIDEOUT) >= requiredAmountGlitchless;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2470,7 +2469,10 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
ShowedMidoSwordAndShield = false;
|
ShowedMidoSwordAndShield = false;
|
||||||
CarpenterRescue = false;
|
THCouldFree1TorchCarpenter = false;
|
||||||
|
THCouldFreeDoubleCellCarpenter = false;
|
||||||
|
TH_CouldFreeDeadEndCarpenter = false;
|
||||||
|
THCouldRescueSlopeCarpenter = false;
|
||||||
GF_GateOpen = false;
|
GF_GateOpen = false;
|
||||||
GtG_GateOpen = false;
|
GtG_GateOpen = false;
|
||||||
DampesWindmillAccess = false;
|
DampesWindmillAccess = false;
|
||||||
|
|
|
@ -110,7 +110,11 @@ class Logic {
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
bool ShowedMidoSwordAndShield = false;
|
bool ShowedMidoSwordAndShield = false;
|
||||||
bool CarpenterRescue = false;
|
bool THCouldFree1TorchCarpenter = false;
|
||||||
|
bool THCouldFreeDoubleCellCarpenter = false;
|
||||||
|
bool TH_CouldFreeDeadEndCarpenter = false;
|
||||||
|
bool THCouldRescueSlopeCarpenter = false;
|
||||||
|
bool THRescuedAllCarpenters = false;
|
||||||
bool GF_GateOpen = false;
|
bool GF_GateOpen = false;
|
||||||
bool GtG_GateOpen = false;
|
bool GtG_GateOpen = false;
|
||||||
bool DampesWindmillAccess = false;
|
bool DampesWindmillAccess = false;
|
||||||
|
@ -246,7 +250,6 @@ class Logic {
|
||||||
bool HasFireSource();
|
bool HasFireSource();
|
||||||
bool HasFireSourceWithTorch();
|
bool HasFireSourceWithTorch();
|
||||||
bool TradeQuestStep(RandomizerGet rg);
|
bool TradeQuestStep(RandomizerGet rg);
|
||||||
bool CanFinishGerudoFortress();
|
|
||||||
bool CanStandingShield();
|
bool CanStandingShield();
|
||||||
bool CanShield();
|
bool CanShield();
|
||||||
bool CanUseProjectile();
|
bool CanUseProjectile();
|
||||||
|
|
|
@ -1706,22 +1706,22 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
|
||||||
{ RC_KF_TWINS_HOUSE_POT_2, RAND_INF_KF_TWINS_HOUSE_POT_2 },
|
{ RC_KF_TWINS_HOUSE_POT_2, RAND_INF_KF_TWINS_HOUSE_POT_2 },
|
||||||
{ RC_KF_BROTHERS_HOUSE_POT_1, RAND_INF_KF_BROTHERS_HOUSE_POT_1 },
|
{ RC_KF_BROTHERS_HOUSE_POT_1, RAND_INF_KF_BROTHERS_HOUSE_POT_1 },
|
||||||
{ RC_KF_BROTHERS_HOUSE_POT_2, RAND_INF_KF_BROTHERS_HOUSE_POT_2 },
|
{ RC_KF_BROTHERS_HOUSE_POT_2, RAND_INF_KF_BROTHERS_HOUSE_POT_2 },
|
||||||
{ RC_GF_BREAK_ROOM_POT_1, RAND_INF_GF_BREAK_ROOM_POT_1 },
|
{ RC_TH_BREAK_ROOM_FRONT_POT, RAND_INF_TH_BREAK_ROOM_FRONT_POT },
|
||||||
{ RC_GF_BREAK_ROOM_POT_2, RAND_INF_GF_BREAK_ROOM_POT_2 },
|
{ RC_TH_BREAK_ROOM_BACK_POT, RAND_INF_TH_BREAK_ROOM_BACK_POT },
|
||||||
{ RC_GF_KITCHEN_POT_1, RAND_INF_GF_KITCHEN_POT_1 },
|
{ RC_TH_KITCHEN_POT_1, RAND_INF_TH_KITCHEN_POT_1 },
|
||||||
{ RC_GF_KITCHEN_POT_2, RAND_INF_GF_KITCHEN_POT_2 },
|
{ RC_TH_KITCHEN_POT_2, RAND_INF_TH_KITCHEN_POT_2 },
|
||||||
{ RC_GF_NORTH_F1_CARPENTER_POT_1, RAND_INF_GF_NORTH_F1_CARPENTER_POT_1 },
|
{ RC_TH_1_TORCH_CELL_RIGHT_POT, RAND_INF_TH_1_TORCH_CELL_RIGHT_POT },
|
||||||
{ RC_GF_NORTH_F1_CARPENTER_POT_2, RAND_INF_GF_NORTH_F1_CARPENTER_POT_2 },
|
{ RC_TH_1_TORCH_CELL_MID_POT, RAND_INF_TH_1_TORCH_CELL_MID_POT },
|
||||||
{ RC_GF_NORTH_F1_CARPENTER_POT_3, RAND_INF_GF_NORTH_F1_CARPENTER_POT_3 },
|
{ RC_TH_1_TORCH_CELL_LEFT_POT, RAND_INF_TH_1_TORCH_CELL_LEFT_POT },
|
||||||
{ RC_GF_NORTH_F2_CARPENTER_POT_1, RAND_INF_GF_NORTH_F2_CARPENTER_POT_1 },
|
{ RC_TH_STEEP_SLOPE_RIGHT_POT, RAND_INF_TH_STEEP_SLOPE_RIGHT_POT },
|
||||||
{ RC_GF_NORTH_F2_CARPENTER_POT_2, RAND_INF_GF_NORTH_F2_CARPENTER_POT_2 },
|
{ RC_TH_STEEP_SLOPE_LEFT_POT, RAND_INF_TH_STEEP_SLOPE_LEFT_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_POT_1, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_1 },
|
{ RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT, RAND_INF_TH_NEAR_DOUBLE_CELL_RIGHT_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_POT_2, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_2 },
|
{ RC_TH_NEAR_DOUBLE_CELL_MID_POT, RAND_INF_TH_NEAR_DOUBLE_CELL_MID_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_POT_3, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_3 },
|
{ RC_TH_NEAR_DOUBLE_CELL_LEFT_POT, RAND_INF_NEAR_DOUBLE_CELL_LEFT_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_1 },
|
{ RC_TH_RIGHTMOST_JAILED_POT, RAND_INF_TH_RIGHTMOST_JAILED_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_2 },
|
{ RC_TH_RIGHT_MIDDLE_JAILED_POT, RAND_INF_TH_RIGHT_MIDDLE_JAILED_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_3 },
|
{ RC_TH_LEFT_MIDDLE_JAILED_POT, RAND_INF_TH_LEFT_MIDDLE_JAILED_POT },
|
||||||
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_4 },
|
{ RC_TH_LEFTMOST_JAILED_POT, RAND_INF_TH_LEFTMOST_JAILED_POT },
|
||||||
{ RC_WASTELAND_NEAR_GS_POT_1, RAND_INF_WASTELAND_NEAR_GS_POT_1 },
|
{ RC_WASTELAND_NEAR_GS_POT_1, RAND_INF_WASTELAND_NEAR_GS_POT_1 },
|
||||||
{ RC_WASTELAND_NEAR_GS_POT_2, RAND_INF_WASTELAND_NEAR_GS_POT_2 },
|
{ RC_WASTELAND_NEAR_GS_POT_2, RAND_INF_WASTELAND_NEAR_GS_POT_2 },
|
||||||
{ RC_WASTELAND_NEAR_GS_POT_3, RAND_INF_WASTELAND_NEAR_GS_POT_3 },
|
{ RC_WASTELAND_NEAR_GS_POT_3, RAND_INF_WASTELAND_NEAR_GS_POT_3 },
|
||||||
|
@ -2272,136 +2272,136 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
|
||||||
RAND_INF_GF_ABOVE_JAIL_CRATE,
|
RAND_INF_GF_ABOVE_JAIL_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_1,
|
RC_GF_SOUTHMOST_CENTER_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_CENTER_CRATE_1,
|
RAND_INF_GF_SOUTHMOST_CENTER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_2,
|
RC_GF_MID_SOUTH_CENTER_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_CENTER_CRATE_2,
|
RAND_INF_GF_MID_SOUTH_CENTER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_3,
|
RC_GF_MID_NORTH_CENTER_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_CENTER_CRATE_3,
|
RAND_INF_GF_MID_NORTH_CENTER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_4,
|
RR_GF_NORTHMOST_CENTER_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_CENTER_CRATE_4,
|
RAND_INF_GF_NORTHMOST_CENTER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_LEFT_CRATE_1,
|
RC_GF_OUTSKIRTS_NE_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_LEFT_CRATE_1,
|
RAND_INF_GF_OUTSKIRTS_NE_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_OUTSIDE_LEFT_CRATE_2,
|
RC_GF_OUTSKIRTS_NW_CRATE,
|
||||||
RAND_INF_GF_OUTSIDE_LEFT_CRATE_2,
|
RAND_INF_GF_OUTSKIRTS_NW_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_1,
|
RC_GF_HBA_RANGE_CRATE_1,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_1,
|
RAND_INF_GF_HBA_RANGE_CRATE_1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_2,
|
RC_GF_HBA_RANGE_CRATE_2,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_2,
|
RAND_INF_GF_HBA_RANGE_CRATE_2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_3,
|
RC_GF_HBA_RANGE_CRATE_3,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_3,
|
RAND_INF_GF_HBA_RANGE_CRATE_3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_4,
|
RC_GF_HBA_RANGE_CRATE_4,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_4,
|
RAND_INF_GF_HBA_RANGE_CRATE_4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_5,
|
RC_GF_HBA_RANGE_CRATE_5,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_5,
|
RAND_INF_GF_HBA_RANGE_CRATE_5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_6,
|
RC_GF_HBA_RANGE_CRATE_6,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_6,
|
RAND_INF_GF_HBA_RANGE_CRATE_6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_7,
|
RC_GF_HBA_RANGE_CRATE_7,
|
||||||
RAND_INF_GF_ARCHERY_RANGE_CRATE_7,
|
RAND_INF_GF_HBA_RANGE_CRATE_7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_START_CRATE_1,
|
RC_GF_HBA_CANOPY_EAST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_START_CRATE_1,
|
RAND_INF_GF_HBA_CANOPY_EAST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_START_CRATE_2,
|
RC_GF_HBA_CANOPY_WEST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_START_CRATE_2,
|
RAND_INF_GF_HBA_CANOPY_WEST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_LEFT_END_CRATE_1,
|
RC_GF_NORTH_TARGET_EAST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_LEFT_END_CRATE_1,
|
RAND_INF_GF_NORTH_TARGET_EAST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_LEFT_END_CRATE_2,
|
RC_GF_NORTH_TARGET_WEST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_LEFT_END_CRATE_2,
|
RAND_INF_GF_NORTH_TARGET_WEST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_LEFT_END_CHILD_CRATE,
|
RC_GF_NORTH_TARGET_CHILD_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_LEFT_END_CHILD_CRATE,
|
RAND_INF_GF_NORTH_TARGET_CHILD_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RIGHT_END_CRATE_1,
|
RC_GF_SOUTH_TARGET_EAST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_1,
|
RAND_INF_GF_SOUTH_TARGET_EAST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_ARCHERY_RIGHT_END_CRATE_2,
|
RC_GF_SOUTH_TARGET_WEST_CRATE,
|
||||||
RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_2,
|
RAND_INF_GF_SOUTH_TARGET_WEST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_KITCHEN_CRATE_1,
|
RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
|
||||||
RAND_INF_GF_KITCHEN_CRATE_1,
|
RAND_INF_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_KITCHEN_CRATE_2,
|
RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
|
||||||
RAND_INF_GF_KITCHEN_CRATE_2,
|
RAND_INF_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_KITCHEN_CRATE_3,
|
RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
|
||||||
RAND_INF_GF_KITCHEN_CRATE_3,
|
RAND_INF_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_KITCHEN_CRATE_4,
|
RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
|
||||||
RAND_INF_GF_KITCHEN_CRATE_4,
|
RAND_INF_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_KITCHEN_CRATE_5,
|
RC_TH_KITCHEN_CRATE,
|
||||||
RAND_INF_GF_KITCHEN_CRATE_5,
|
RAND_INF_TH_KITCHEN_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_BREAK_ROOM_CRATE_1,
|
RC_TH_BREAK_HALLWAY_OUTER_CRATE,
|
||||||
RAND_INF_GF_BREAK_ROOM_CRATE_1,
|
RAND_INF_TH_BREAK_HALLWAY_OUTER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_BREAK_ROOM_CRATE_2,
|
RC_TH_BREAK_HALLWAY_INNER_CRATE,
|
||||||
RAND_INF_GF_BREAK_ROOM_CRATE_2,
|
RAND_INF_TH_BREAK_HALLWAY_INNER_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_BREAK_ROOM_CRATE_3,
|
RC_TH_BREAK_ROOM_RIGHT_CRATE,
|
||||||
RAND_INF_GF_BREAK_ROOM_CRATE_3,
|
RAND_INF_TH_BREAK_ROOM_RIGHT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_BREAK_ROOM_CRATE_4,
|
RC_TH_BREAK_ROOM_LEFT_CRATE,
|
||||||
RAND_INF_GF_BREAK_ROOM_CRATE_4,
|
RAND_INF_TH_BREAK_ROOM_LEFT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_NORTH_F1_CARPENTER_CRATE,
|
RC_TH_1_TORCH_CELL_CRATE,
|
||||||
RAND_INF_GF_NORTH_F1_CARPENTER_CRATE,
|
RAND_INF_TH_1_TORCH_CELL_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_NORTH_F3_CARPENTER_CRATE,
|
RC_TH_DEAD_END_CELL_CRATE,
|
||||||
RAND_INF_GF_NORTH_F3_CARPENTER_CRATE,
|
RAND_INF_TH_DEAD_END_CELL_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_SOUTH_F2_CARPENTER_CRATE_1,
|
RC_TH_DOUBLE_CELL_LEFT_CRATE,
|
||||||
RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_1,
|
RAND_INF_TH_DOUBLE_CELL_LEFT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_GF_SOUTH_F2_CARPENTER_CRATE_2,
|
RC_TH_DOUBLE_CELL_RIGHT_CRATE,
|
||||||
RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_2,
|
RAND_INF_TH_DOUBLE_CELL_RIGHT_CRATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RC_HW_BEFORE_QUICKSAND_CRATE,
|
RC_HW_BEFORE_QUICKSAND_CRATE,
|
||||||
|
|
|
@ -418,9 +418,34 @@ typedef enum {
|
||||||
RR_GV_FORTRESS_SIDE,
|
RR_GV_FORTRESS_SIDE,
|
||||||
RR_GV_CARPENTER_TENT,
|
RR_GV_CARPENTER_TENT,
|
||||||
RR_GV_STORMS_GROTTO,
|
RR_GV_STORMS_GROTTO,
|
||||||
RR_GERUDO_FORTRESS,
|
RR_GF_OUTSKIRTS,
|
||||||
|
RR_GF_NEAR_GROTTO,
|
||||||
|
RR_GF_OUTSIDE_GTG,
|
||||||
|
RR_GF_ABOVE_GTG,
|
||||||
|
RR_GF_BOTTOM_OF_LOWER_VINES,
|
||||||
|
RR_GF_TOP_OF_LOWER_VINES,
|
||||||
|
RR_GF_NEAR_GS,
|
||||||
|
RR_GF_SLOPED_ROOF,
|
||||||
|
RR_GF_BOTTOM_OF_UPPER_VINES,
|
||||||
|
RR_GF_TOP_OF_UPPER_VINES,
|
||||||
|
RR_GF_NEAR_CHEST,
|
||||||
|
RR_GF_LONG_ROOF,
|
||||||
|
RR_GF_BELOW_GS,
|
||||||
|
RR_GF_BELOW_CHEST,
|
||||||
|
RR_GF_HBA_RANGE,
|
||||||
|
RR_GF_ABOVE_JAIL,
|
||||||
|
RR_GF_JAIL_WINDOW,
|
||||||
RR_GF_OUTSIDE_GATE,
|
RR_GF_OUTSIDE_GATE,
|
||||||
RR_GF_STORMS_GROTTO,
|
RR_GF_STORMS_GROTTO,
|
||||||
|
RR_TH_1_TORCH_CELL,
|
||||||
|
RR_TH_DOUBLE_CELL,
|
||||||
|
RR_TH_DEAD_END_CELL,
|
||||||
|
RR_TH_STEEP_SLOPE_CELL,
|
||||||
|
RR_TH_KITCHEN_CORRIDOR,
|
||||||
|
RR_TH_KITCHEN_MAIN,
|
||||||
|
RR_TH_KITCHEN_TOP,
|
||||||
|
RR_TH_BREAK_ROOM,
|
||||||
|
RR_TH_BREAK_ROOM_CORRIDOR,
|
||||||
RR_WASTELAND_NEAR_FORTRESS,
|
RR_WASTELAND_NEAR_FORTRESS,
|
||||||
RR_HAUNTED_WASTELAND,
|
RR_HAUNTED_WASTELAND,
|
||||||
RR_WASTELAND_NEAR_COLOSSUS,
|
RR_WASTELAND_NEAR_COLOSSUS,
|
||||||
|
@ -1393,13 +1418,13 @@ typedef enum {
|
||||||
RC_GF_CHEST,
|
RC_GF_CHEST,
|
||||||
RC_GF_HBA_1000_POINTS,
|
RC_GF_HBA_1000_POINTS,
|
||||||
RC_GF_HBA_1500_POINTS,
|
RC_GF_HBA_1500_POINTS,
|
||||||
RC_GF_GERUDO_MEMBERSHIP_CARD,
|
RC_TH_FREED_CARPENTERS,
|
||||||
RC_GF_NORTH_F1_CARPENTER,
|
RC_TH_1_TORCH_CARPENTER,
|
||||||
RC_GF_NORTH_F2_CARPENTER,
|
RC_TH_DEAD_END_CARPENTER,
|
||||||
RC_GF_SOUTH_F1_CARPENTER,
|
RC_TH_DOUBLE_CELL_CARPENTER,
|
||||||
RC_GF_SOUTH_F2_CARPENTER,
|
RC_TH_STEEP_SLOPE_CARPENTER,
|
||||||
RC_GF_GS_TOP_FLOOR,
|
RC_GF_GS_TOP_FLOOR,
|
||||||
RC_GF_GS_ARCHERY_RANGE,
|
RC_GF_HBA_RANGE_GS,
|
||||||
RC_HIDEOUT_JAIL_GUARD_1_TORCH,
|
RC_HIDEOUT_JAIL_GUARD_1_TORCH,
|
||||||
RC_HIDEOUT_JAIL_GUARD_2_TORCHES,
|
RC_HIDEOUT_JAIL_GUARD_2_TORCHES,
|
||||||
RC_HIDEOUT_JAIL_GUARD_3_TORCHES,
|
RC_HIDEOUT_JAIL_GUARD_3_TORCHES,
|
||||||
|
@ -1817,22 +1842,22 @@ typedef enum {
|
||||||
RC_KF_TWINS_HOUSE_POT_2,
|
RC_KF_TWINS_HOUSE_POT_2,
|
||||||
RC_KF_BROTHERS_HOUSE_POT_1,
|
RC_KF_BROTHERS_HOUSE_POT_1,
|
||||||
RC_KF_BROTHERS_HOUSE_POT_2,
|
RC_KF_BROTHERS_HOUSE_POT_2,
|
||||||
RC_GF_BREAK_ROOM_POT_1,
|
RC_TH_BREAK_ROOM_FRONT_POT,
|
||||||
RC_GF_BREAK_ROOM_POT_2,
|
RC_TH_BREAK_ROOM_BACK_POT,
|
||||||
RC_GF_KITCHEN_POT_1,
|
RC_TH_KITCHEN_POT_1,
|
||||||
RC_GF_KITCHEN_POT_2,
|
RC_TH_KITCHEN_POT_2,
|
||||||
RC_GF_NORTH_F1_CARPENTER_POT_1,
|
RC_TH_1_TORCH_CELL_RIGHT_POT,
|
||||||
RC_GF_NORTH_F1_CARPENTER_POT_2,
|
RC_TH_1_TORCH_CELL_MID_POT,
|
||||||
RC_GF_NORTH_F1_CARPENTER_POT_3,
|
RC_TH_1_TORCH_CELL_LEFT_POT,
|
||||||
RC_GF_NORTH_F2_CARPENTER_POT_1,
|
RC_TH_STEEP_SLOPE_RIGHT_POT,
|
||||||
RC_GF_NORTH_F2_CARPENTER_POT_2,
|
RC_TH_STEEP_SLOPE_LEFT_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_POT_1,
|
RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_POT_2,
|
RC_TH_NEAR_DOUBLE_CELL_MID_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_POT_3,
|
RC_TH_NEAR_DOUBLE_CELL_LEFT_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1,
|
RC_TH_RIGHTMOST_JAILED_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2,
|
RC_TH_RIGHT_MIDDLE_JAILED_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3,
|
RC_TH_LEFT_MIDDLE_JAILED_POT,
|
||||||
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4,
|
RC_TH_LEFTMOST_JAILED_POT,
|
||||||
RC_WASTELAND_NEAR_GS_POT_1,
|
RC_WASTELAND_NEAR_GS_POT_1,
|
||||||
RC_WASTELAND_NEAR_GS_POT_2,
|
RC_WASTELAND_NEAR_GS_POT_2,
|
||||||
RC_WASTELAND_NEAR_GS_POT_3,
|
RC_WASTELAND_NEAR_GS_POT_3,
|
||||||
|
@ -2366,39 +2391,39 @@ typedef enum {
|
||||||
RC_GV_CRATE_BRIDGE_3,
|
RC_GV_CRATE_BRIDGE_3,
|
||||||
RC_GV_CRATE_BRIDGE_4,
|
RC_GV_CRATE_BRIDGE_4,
|
||||||
RC_GF_ABOVE_JAIL_CRATE,
|
RC_GF_ABOVE_JAIL_CRATE,
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_1,
|
RC_GF_SOUTHMOST_CENTER_CRATE,
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_2,
|
RC_GF_MID_SOUTH_CENTER_CRATE,
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_3,
|
RC_GF_MID_NORTH_CENTER_CRATE,
|
||||||
RC_GF_OUTSIDE_CENTER_CRATE_4,
|
RR_GF_NORTHMOST_CENTER_CRATE,
|
||||||
RC_GF_OUTSIDE_LEFT_CRATE_1,
|
RC_GF_OUTSKIRTS_NE_CRATE,
|
||||||
RC_GF_OUTSIDE_LEFT_CRATE_2,
|
RC_GF_OUTSKIRTS_NW_CRATE,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_1,
|
RC_GF_HBA_RANGE_CRATE_1,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_2,
|
RC_GF_HBA_RANGE_CRATE_2,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_3,
|
RC_GF_HBA_RANGE_CRATE_3,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_4,
|
RC_GF_HBA_RANGE_CRATE_4,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_5,
|
RC_GF_HBA_RANGE_CRATE_5,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_6,
|
RC_GF_HBA_RANGE_CRATE_6,
|
||||||
RC_GF_ARCHERY_RANGE_CRATE_7,
|
RC_GF_HBA_RANGE_CRATE_7,
|
||||||
RC_GF_ARCHERY_START_CRATE_1,
|
RC_GF_HBA_CANOPY_EAST_CRATE,
|
||||||
RC_GF_ARCHERY_START_CRATE_2,
|
RC_GF_HBA_CANOPY_WEST_CRATE,
|
||||||
RC_GF_ARCHERY_LEFT_END_CRATE_1,
|
RC_GF_NORTH_TARGET_EAST_CRATE,
|
||||||
RC_GF_ARCHERY_LEFT_END_CRATE_2,
|
RC_GF_NORTH_TARGET_WEST_CRATE,
|
||||||
RC_GF_ARCHERY_LEFT_END_CHILD_CRATE,
|
RC_GF_NORTH_TARGET_CHILD_CRATE,
|
||||||
RC_GF_ARCHERY_RIGHT_END_CRATE_1,
|
RC_GF_SOUTH_TARGET_EAST_CRATE,
|
||||||
RC_GF_ARCHERY_RIGHT_END_CRATE_2,
|
RC_GF_SOUTH_TARGET_WEST_CRATE,
|
||||||
RC_GF_KITCHEN_CRATE_1,
|
RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
|
||||||
RC_GF_KITCHEN_CRATE_2,
|
RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
|
||||||
RC_GF_KITCHEN_CRATE_3,
|
RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
|
||||||
RC_GF_KITCHEN_CRATE_4,
|
RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
|
||||||
RC_GF_KITCHEN_CRATE_5,
|
RC_TH_KITCHEN_CRATE,
|
||||||
RC_GF_BREAK_ROOM_CRATE_1,
|
RC_TH_BREAK_HALLWAY_OUTER_CRATE,
|
||||||
RC_GF_BREAK_ROOM_CRATE_2,
|
RC_TH_BREAK_HALLWAY_INNER_CRATE,
|
||||||
RC_GF_BREAK_ROOM_CRATE_3,
|
RC_TH_BREAK_ROOM_RIGHT_CRATE,
|
||||||
RC_GF_BREAK_ROOM_CRATE_4,
|
RC_TH_BREAK_ROOM_LEFT_CRATE,
|
||||||
RC_GF_NORTH_F1_CARPENTER_CRATE,
|
RC_TH_1_TORCH_CELL_CRATE,
|
||||||
RC_GF_NORTH_F3_CARPENTER_CRATE,
|
RC_TH_DEAD_END_CELL_CRATE,
|
||||||
RC_GF_SOUTH_F2_CARPENTER_CRATE_1,
|
RC_TH_DOUBLE_CELL_LEFT_CRATE,
|
||||||
RC_GF_SOUTH_F2_CARPENTER_CRATE_2,
|
RC_TH_DOUBLE_CELL_RIGHT_CRATE,
|
||||||
RC_HW_BEFORE_QUICKSAND_CRATE,
|
RC_HW_BEFORE_QUICKSAND_CRATE,
|
||||||
RC_HW_AFTER_QUICKSAND_CRATE_1,
|
RC_HW_AFTER_QUICKSAND_CRATE_1,
|
||||||
RC_HW_AFTER_QUICKSAND_CRATE_2,
|
RC_HW_AFTER_QUICKSAND_CRATE_2,
|
||||||
|
@ -3112,7 +3137,7 @@ typedef enum {
|
||||||
RC_DMT_FLAG_SUN_FAIRY,
|
RC_DMT_FLAG_SUN_FAIRY,
|
||||||
RC_DMT_COW_GROTTO_STORMS_FAIRY,
|
RC_DMT_COW_GROTTO_STORMS_FAIRY,
|
||||||
RC_LW_SHORTCUT_STORMS_FAIRY,
|
RC_LW_SHORTCUT_STORMS_FAIRY,
|
||||||
RC_GF_KITCHEN_SUN_FAIRY,
|
RC_TH_KITCHEN_SUN_FAIRY,
|
||||||
RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY,
|
RC_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY,
|
||||||
RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
|
RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
|
||||||
RC_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
|
RC_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
|
||||||
|
@ -3551,7 +3576,7 @@ typedef enum {
|
||||||
RT_LH_LAB_DIVING,
|
RT_LH_LAB_DIVING,
|
||||||
RT_LH_WATER_HOOKSHOT,
|
RT_LH_WATER_HOOKSHOT,
|
||||||
RT_GV_CRATE_HOVERS,
|
RT_GV_CRATE_HOVERS,
|
||||||
RT_GF_KITCHEN,
|
RT_PASS_GUARDS_WITH_NOTHING,
|
||||||
RT_GF_JUMP,
|
RT_GF_JUMP,
|
||||||
RT_GF_WARRIOR_WITH_DIFFICULT_WEAPON,
|
RT_GF_WARRIOR_WITH_DIFFICULT_WEAPON,
|
||||||
RT_HW_BUNNY_CROSSING,
|
RT_HW_BUNNY_CROSSING,
|
||||||
|
@ -4504,11 +4529,11 @@ typedef enum {
|
||||||
RHT_GF_CHEST,
|
RHT_GF_CHEST,
|
||||||
RHT_GF_HBA_1000_POINTS,
|
RHT_GF_HBA_1000_POINTS,
|
||||||
RHT_GF_HBA_1500_POINTS,
|
RHT_GF_HBA_1500_POINTS,
|
||||||
RHT_GF_GERUDO_MEMBERSHIP_CARD,
|
RHT_TH_FREED_CARPENTERS,
|
||||||
RHT_GF_NORTH_F1_CARPENTER,
|
RHT_TH_1_TORCH_CARPENTER,
|
||||||
RHT_GF_NORTH_F2_CARPENTER,
|
RHT_TH_DEAD_END_CARPENTER,
|
||||||
RHT_GF_SOUTH_F1_CARPENTER,
|
RHT_TH_DOUBLE_CELL_CARPENTER,
|
||||||
RHT_GF_SOUTH_F2_CARPENTER,
|
RHT_TH_STEEP_SLOPE_CARPENTER,
|
||||||
RHT_GF_GS_TOP_FLOOR,
|
RHT_GF_GS_TOP_FLOOR,
|
||||||
RHT_GF_GS_ARCHERY_RANGE,
|
RHT_GF_GS_ARCHERY_RANGE,
|
||||||
RHT_HIDEOUT_JAIL_GUARD_1_TORCH,
|
RHT_HIDEOUT_JAIL_GUARD_1_TORCH,
|
||||||
|
@ -5391,7 +5416,22 @@ typedef enum {
|
||||||
RHT_MASK_SHOP_HINT,
|
RHT_MASK_SHOP_HINT,
|
||||||
// Shuffle Pots
|
// Shuffle Pots
|
||||||
RHT_POT_KOKIRI_FOREST,
|
RHT_POT_KOKIRI_FOREST,
|
||||||
RHT_POT_GERUDO_FORTRESS,
|
RHT_TH_BREAK_ROOM_FRONT_POT,
|
||||||
|
RHT_TH_BREAK_ROOM_BACK_POT,
|
||||||
|
RHT_TH_KITCHEN_POT_1,
|
||||||
|
RHT_TH_KITCHEN_POT_2,
|
||||||
|
RHT_TH_1_TORCH_CELL_RIGHT_POT,
|
||||||
|
RHT_TH_1_TORCH_CELL_MID_POT,
|
||||||
|
RHT_TH_1_TORCH_CELL_LEFT_POT,
|
||||||
|
RHT_TH_STEEP_SLOPE_RIGHT_POT,
|
||||||
|
RHT_TH_STEEP_SLOPE_LEFT_POT,
|
||||||
|
RHT_TH_NEAR_DOUBLE_CELL_RIGHT_POT,
|
||||||
|
RHT_TH_NEAR_DOUBLE_CELL_MID_POT,
|
||||||
|
RHT_TH_NEAR_DOUBLE_CELL_LEFT_POT,
|
||||||
|
RHT_TH_RIGHTMOST_JAILED_POT,
|
||||||
|
RHT_TH_RIGHT_MIDDLE_JAILED_POT,
|
||||||
|
RHT_TH_LEFT_MIDDLE_JAILED_POT,
|
||||||
|
RHT_TH_LEFTMOST_JAILED_POT,
|
||||||
RHT_POT_WASTELAND,
|
RHT_POT_WASTELAND,
|
||||||
RHT_POT_MARKET,
|
RHT_POT_MARKET,
|
||||||
RHT_POT_KAKARIKO,
|
RHT_POT_KAKARIKO,
|
||||||
|
@ -5581,7 +5621,7 @@ typedef enum {
|
||||||
RHT_DMT_FLAG_SUN_FAIRY,
|
RHT_DMT_FLAG_SUN_FAIRY,
|
||||||
RHT_DMT_COW_GROTTO_STORMS_FAIRY,
|
RHT_DMT_COW_GROTTO_STORMS_FAIRY,
|
||||||
RHT_LW_SHORTCUT_STORMS_FAIRY,
|
RHT_LW_SHORTCUT_STORMS_FAIRY,
|
||||||
RHT_GF_KITCHEN_SUN_FAIRY,
|
RHT_TH_KITCHEN_SUN_FAIRY,
|
||||||
RHT_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY,
|
RHT_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY,
|
||||||
RHT_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
|
RHT_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
|
||||||
RHT_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
|
RHT_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
|
||||||
|
@ -6454,6 +6494,8 @@ typedef enum {
|
||||||
RE_STINGER,
|
RE_STINGER,
|
||||||
RE_BIG_OCTO,
|
RE_BIG_OCTO,
|
||||||
RE_GERUDO_WARRIOR,
|
RE_GERUDO_WARRIOR,
|
||||||
|
RE_GERUDO_GUARD,
|
||||||
|
RE_BREAK_ROOM_GUARD,
|
||||||
RE_GIBDO,
|
RE_GIBDO,
|
||||||
RE_GOHMA,
|
RE_GOHMA,
|
||||||
RE_KING_DODONGO,
|
RE_KING_DODONGO,
|
||||||
|
|
|
@ -233,20 +233,20 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
|
||||||
(location.GetRandomizerCheck() != RC_KAK_100_GOLD_SKULLTULA_REWARD ||
|
(location.GetRandomizerCheck() != RC_KAK_100_GOLD_SKULLTULA_REWARD ||
|
||||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) !=
|
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) !=
|
||||||
RO_GANON_BOSS_KEY_KAK_TOKENS) && // 100 skull reward ganon boss key
|
RO_GANON_BOSS_KEY_KAK_TOKENS) && // 100 skull reward ganon boss key
|
||||||
(location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD ||
|
(location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_TH_FREED_CARPENTERS ||
|
||||||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
||||||
RO_GF_CARPENTERS_FREE &&
|
RO_GF_CARPENTERS_FREE &&
|
||||||
location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD) ||
|
location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_TH_FREED_CARPENTERS) ||
|
||||||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
||||||
RO_GF_CARPENTERS_FAST &&
|
RO_GF_CARPENTERS_FAST &&
|
||||||
((location.GetRandomizerCheck() == RC_GF_GERUDO_MEMBERSHIP_CARD &&
|
((location.GetRandomizerCheck() == RC_TH_FREED_CARPENTERS &&
|
||||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), RO_GENERIC_NO) == RO_GENERIC_YES) ||
|
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), RO_GENERIC_NO) == RO_GENERIC_YES) ||
|
||||||
(location.GetRandomizerCheck() == RC_GF_NORTH_F1_CARPENTER &&
|
(location.GetRandomizerCheck() == RC_TH_1_TORCH_CARPENTER &&
|
||||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=
|
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=
|
||||||
RO_GERUDO_KEYS_VANILLA))) ||
|
RO_GERUDO_KEYS_VANILLA))) ||
|
||||||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
|
||||||
RO_GF_CARPENTERS_NORMAL &&
|
RO_GF_CARPENTERS_NORMAL &&
|
||||||
((location.GetRandomizerCheck() == RC_GF_GERUDO_MEMBERSHIP_CARD &&
|
((location.GetRandomizerCheck() == RC_TH_FREED_CARPENTERS &&
|
||||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), RO_GENERIC_NO) == RO_GENERIC_YES) ||
|
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), RO_GENERIC_NO) == RO_GENERIC_YES) ||
|
||||||
(location.GetRCType() == RCTYPE_GF_KEY &&
|
(location.GetRCType() == RCTYPE_GF_KEY &&
|
||||||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=
|
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=
|
||||||
|
|
|
@ -759,7 +759,7 @@ void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
|
||||||
if ((flag == EVENTCHKINF_CARPENTERS_FREE(0) || flag == EVENTCHKINF_CARPENTERS_FREE(1) ||
|
if ((flag == EVENTCHKINF_CARPENTERS_FREE(0) || flag == EVENTCHKINF_CARPENTERS_FREE(1) ||
|
||||||
flag == EVENTCHKINF_CARPENTERS_FREE(2) || flag == EVENTCHKINF_CARPENTERS_FREE(3)) &&
|
flag == EVENTCHKINF_CARPENTERS_FREE(2) || flag == EVENTCHKINF_CARPENTERS_FREE(3)) &&
|
||||||
GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) {
|
GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) {
|
||||||
SetCheckCollected(RC_GF_GERUDO_MEMBERSHIP_CARD);
|
SetCheckCollected(RC_TH_FREED_CARPENTERS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF;
|
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF;
|
||||||
|
@ -1589,10 +1589,10 @@ bool IsCheckShuffled(RandomizerCheck rc) {
|
||||||
(loc->GetRCType() != RCTYPE_BOSS_KEY || showBossKeysanity) &&
|
(loc->GetRCType() != RCTYPE_BOSS_KEY || showBossKeysanity) &&
|
||||||
(loc->GetRCType() != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
|
(loc->GetRCType() != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
|
||||||
(rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
|
(rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
|
||||||
(loc->GetRCType() != RCTYPE_GF_KEY && rc != RC_GF_GERUDO_MEMBERSHIP_CARD ||
|
(loc->GetRCType() != RCTYPE_GF_KEY && rc != RC_TH_FREED_CARPENTERS ||
|
||||||
(showGerudoCard && rc == RC_GF_GERUDO_MEMBERSHIP_CARD) ||
|
(showGerudoCard && rc == RC_TH_FREED_CARPENTERS) ||
|
||||||
(fortressNormal && showGerudoFortressKeys && loc->GetRCType() == RCTYPE_GF_KEY) ||
|
(fortressNormal && showGerudoFortressKeys && loc->GetRCType() == RCTYPE_GF_KEY) ||
|
||||||
(fortressFast && showGerudoFortressKeys && rc == RC_GF_NORTH_F1_CARPENTER));
|
(fortressFast && showGerudoFortressKeys && rc == RC_TH_1_TORCH_CARPENTER));
|
||||||
} else if (loc->IsVanillaCompletion()) {
|
} else if (loc->IsVanillaCompletion()) {
|
||||||
return (OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) || rc == RC_GIFT_FROM_RAURU) &&
|
return (OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) || rc == RC_GIFT_FROM_RAURU) &&
|
||||||
rc != RC_LINKS_POCKET;
|
rc != RC_LINKS_POCKET;
|
||||||
|
|
|
@ -203,22 +203,22 @@ DEFINE_RAND_INF(RAND_INF_KF_TWINS_HOUSE_POT_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_KF_TWINS_HOUSE_POT_2)
|
DEFINE_RAND_INF(RAND_INF_KF_TWINS_HOUSE_POT_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_KF_BROTHERS_HOUSE_POT_1)
|
DEFINE_RAND_INF(RAND_INF_KF_BROTHERS_HOUSE_POT_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_KF_BROTHERS_HOUSE_POT_2)
|
DEFINE_RAND_INF(RAND_INF_KF_BROTHERS_HOUSE_POT_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_FRONT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_BACK_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_POT_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_POT_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_RIGHT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_MID_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_3)
|
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_LEFT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F2_CARPENTER_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_STEEP_SLOPE_RIGHT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F2_CARPENTER_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_STEEP_SLOPE_LEFT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_DOUBLE_CELL_RIGHT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_DOUBLE_CELL_MID_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_3)
|
DEFINE_RAND_INF(RAND_INF_NEAR_DOUBLE_CELL_LEFT_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_1)
|
DEFINE_RAND_INF(RAND_INF_TH_RIGHTMOST_JAILED_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_2)
|
DEFINE_RAND_INF(RAND_INF_TH_RIGHT_MIDDLE_JAILED_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_3)
|
DEFINE_RAND_INF(RAND_INF_TH_LEFT_MIDDLE_JAILED_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_4)
|
DEFINE_RAND_INF(RAND_INF_TH_LEFTMOST_JAILED_POT)
|
||||||
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_1)
|
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_2)
|
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_3)
|
DEFINE_RAND_INF(RAND_INF_WASTELAND_NEAR_GS_POT_3)
|
||||||
|
@ -748,39 +748,39 @@ DEFINE_RAND_INF(RAND_INF_GV_CRATE_BRIDGE_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_GV_CRATE_BRIDGE_3)
|
DEFINE_RAND_INF(RAND_INF_GV_CRATE_BRIDGE_3)
|
||||||
DEFINE_RAND_INF(RAND_INF_GV_CRATE_BRIDGE_4)
|
DEFINE_RAND_INF(RAND_INF_GV_CRATE_BRIDGE_4)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ABOVE_JAIL_CRATE)
|
DEFINE_RAND_INF(RAND_INF_GF_ABOVE_JAIL_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_SOUTHMOST_CENTER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_MID_SOUTH_CENTER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_3)
|
DEFINE_RAND_INF(RAND_INF_GF_MID_NORTH_CENTER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_4)
|
DEFINE_RAND_INF(RAND_INF_GF_NORTHMOST_CENTER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_LEFT_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_OUTSKIRTS_NE_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_LEFT_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_OUTSKIRTS_NW_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_2)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_3)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_3)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_4)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_4)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_5)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_5)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_6)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_6)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_7)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_7)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_START_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_CANOPY_EAST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_START_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_HBA_CANOPY_WEST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_EAST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_WEST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CHILD_CRATE)
|
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_CHILD_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_TARGET_EAST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_TARGET_WEST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_LEFTMOST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_MID_LEFT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_3)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_MID_RIGHT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_4)
|
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_RIGHTMOST_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_5)
|
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_HALLWAY_OUTER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_HALLWAY_INNER_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_3)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_RIGHT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_4)
|
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_LEFT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_CRATE)
|
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F3_CARPENTER_CRATE)
|
DEFINE_RAND_INF(RAND_INF_TH_DEAD_END_CELL_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_TH_DOUBLE_CELL_LEFT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_TH_DOUBLE_CELL_RIGHT_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_HW_BEFORE_QUICKSAND_CRATE)
|
DEFINE_RAND_INF(RAND_INF_HW_BEFORE_QUICKSAND_CRATE)
|
||||||
DEFINE_RAND_INF(RAND_INF_HW_AFTER_QUICKSAND_CRATE_1)
|
DEFINE_RAND_INF(RAND_INF_HW_AFTER_QUICKSAND_CRATE_1)
|
||||||
DEFINE_RAND_INF(RAND_INF_HW_AFTER_QUICKSAND_CRATE_2)
|
DEFINE_RAND_INF(RAND_INF_HW_AFTER_QUICKSAND_CRATE_2)
|
||||||
|
@ -1089,7 +1089,7 @@ DEFINE_RAND_INF(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3)
|
||||||
DEFINE_RAND_INF(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4)
|
DEFINE_RAND_INF(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4)
|
||||||
DEFINE_RAND_INF(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5)
|
DEFINE_RAND_INF(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5)
|
||||||
|
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_ITEM_FROM_LEADER_OF_FORTRESS)
|
DEFINE_RAND_INF(RAND_INF_TH_ITEM_FROM_LEADER_OF_FORTRESS)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_GTG_GATE_PERMANENTLY_OPEN)
|
DEFINE_RAND_INF(RAND_INF_GF_GTG_GATE_PERMANENTLY_OPEN)
|
||||||
|
|
||||||
DEFINE_RAND_INF(RAND_INF_ZELDAS_LETTER)
|
DEFINE_RAND_INF(RAND_INF_ZELDAS_LETTER)
|
||||||
|
@ -1504,7 +1504,7 @@ DEFINE_RAND_INF(RAND_INF_DMT_FLAG_SUN_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_DMT_COW_GROTTO_STORMS_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_DMT_COW_GROTTO_STORMS_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_HF_FENCE_GROTTO_STORMS_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_HF_FENCE_GROTTO_STORMS_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_LW_SHORTCUT_STORMS_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_LW_SHORTCUT_STORMS_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_SUN_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_SUN_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_LW_DEKU_SCRUB_GROTTO_SUN_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY)
|
||||||
DEFINE_RAND_INF(RAND_INF_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY)
|
DEFINE_RAND_INF(RAND_INF_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY)
|
||||||
|
|
|
@ -580,13 +580,13 @@ void Settings::CreateOptions() {
|
||||||
"Gerudo Valley Crate PoH as Adult with Hover Boots",
|
"Gerudo Valley Crate PoH as Adult with Hover Boots",
|
||||||
"From the far side of Gerudo Valley, a precise Hover Boots movement and jump-slash recoil can allow "
|
"From the far side of Gerudo Valley, a precise Hover Boots movement and jump-slash recoil can allow "
|
||||||
"adult to reach the ledge with the crate PoH without needing Longshot. You will take fall damage.");
|
"adult to reach the ledge with the crate PoH without needing Longshot. You will take fall damage.");
|
||||||
OPT_TRICK(RT_GF_KITCHEN, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE },
|
OPT_TRICK(RT_PASS_GUARDS_WITH_NOTHING, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE },
|
||||||
"Thieves\' Hideout \"Kitchen\" with No Additional Items",
|
"Sneak Past Moving Gerudo Guards with No Items",
|
||||||
"Allows passing through the kitchen by avoiding being seen by the guards. The logic normally guarantees "
|
"The logic normally guarantees Bow or Hookshot to stun them from a distance,"
|
||||||
"Bow or Hookshot to stun them from a distance, or Hover Boots to cross the room without needing to deal "
|
"but every moving guard can be passed with basic movement and AI manipulation");
|
||||||
"with the guards.");
|
|
||||||
OPT_TRICK(RT_GF_JUMP, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE }, "Gerudo\'s Fortress Ledge Jumps",
|
OPT_TRICK(RT_GF_JUMP, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE }, "Gerudo\'s Fortress Ledge Jumps",
|
||||||
"Adult can jump onto the top roof of the fortress without going through the interior of the hideout.");
|
"It is possible to navigate the rooves of Fortress with unintuative jumps to reach additional areas "
|
||||||
|
"without going inside.");
|
||||||
OPT_TRICK(RT_GF_WARRIOR_WITH_DIFFICULT_WEAPON, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE },
|
OPT_TRICK(RT_GF_WARRIOR_WITH_DIFFICULT_WEAPON, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE },
|
||||||
"Gerudo\'s Fortress Warriors with Difficult Weapons",
|
"Gerudo\'s Fortress Warriors with Difficult Weapons",
|
||||||
"Warriors can be defeated with Slingshot or Bombchus.");
|
"Warriors can be defeated with Slingshot or Bombchus.");
|
||||||
|
|
|
@ -411,12 +411,19 @@ void OTRGlobals::Initialize() {
|
||||||
static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
|
static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
|
||||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSampleV2>(), RESOURCE_FORMAT_BINARY,
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSampleV2>(), RESOURCE_FORMAT_BINARY,
|
||||||
"AudioSample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 2);
|
"AudioSample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 2);
|
||||||
|
|
||||||
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLAudioSampleV0>(), RESOURCE_FORMAT_XML,
|
||||||
|
"Sample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 0);
|
||||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSoundFontV2>(),
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSoundFontV2>(),
|
||||||
RESOURCE_FORMAT_BINARY, "AudioSoundFont",
|
RESOURCE_FORMAT_BINARY, "AudioSoundFont",
|
||||||
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 2);
|
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 2);
|
||||||
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLSoundFontV0>(), RESOURCE_FORMAT_XML,
|
||||||
|
"SoundFont", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 0);
|
||||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSequenceV2>(),
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSequenceV2>(),
|
||||||
RESOURCE_FORMAT_BINARY, "AudioSequence",
|
RESOURCE_FORMAT_BINARY, "AudioSequence",
|
||||||
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 2);
|
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 2);
|
||||||
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLAudioSequenceV0>(), RESOURCE_FORMAT_XML,
|
||||||
|
"Sequence", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 0);
|
||||||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryBackgroundV0>(), RESOURCE_FORMAT_BINARY,
|
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryBackgroundV0>(), RESOURCE_FORMAT_BINARY,
|
||||||
"Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
|
"Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
|
||||||
|
|
||||||
|
@ -602,6 +609,12 @@ extern "C" void OTRAudio_Init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" char** sequenceMap;
|
||||||
|
extern "C" size_t sequenceMapSize;
|
||||||
|
|
||||||
|
extern "C" char** fontMap;
|
||||||
|
extern "C" size_t fontMapSize;
|
||||||
|
|
||||||
extern "C" void OTRAudio_Exit() {
|
extern "C" void OTRAudio_Exit() {
|
||||||
// Tell the audio thread to stop
|
// Tell the audio thread to stop
|
||||||
{
|
{
|
||||||
|
@ -612,6 +625,19 @@ extern "C" void OTRAudio_Exit() {
|
||||||
|
|
||||||
// Wait until the audio thread quit
|
// Wait until the audio thread quit
|
||||||
audio.thread.join();
|
audio.thread.join();
|
||||||
|
#if 0
|
||||||
|
for (size_t i = 0; i < sequenceMapSize; i++) {
|
||||||
|
free(sequenceMap[i]);
|
||||||
|
}
|
||||||
|
free(sequenceMap);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fontMapSize; i++) {
|
||||||
|
free(fontMap[i]);
|
||||||
|
}
|
||||||
|
free(fontMap);
|
||||||
|
free(gAudioContext.seqLoadStatus);
|
||||||
|
free(gAudioContext.fontLoadStatus);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void VanillaItemTable_Init() {
|
extern "C" void VanillaItemTable_Init() {
|
||||||
|
@ -1070,6 +1096,10 @@ void DetectOTRVersion(std::string fileName, bool isMQ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void Messagebox_ShowErrorBox(char* title, char* body) {
|
||||||
|
Extractor::ShowErrorBox(title, body);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& base) {
|
bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& base) {
|
||||||
auto rel = std::filesystem::relative(path, base);
|
auto rel = std::filesystem::relative(path, base);
|
||||||
return !rel.empty() && rel.native()[0] != '.';
|
return !rel.empty() && rel.native()[0] != '.';
|
||||||
|
|
|
@ -171,6 +171,7 @@ void CheckTracker_RecalculateAvailableChecks();
|
||||||
|
|
||||||
GetItemID RetrieveGetItemIDFromItemID(ItemID itemID);
|
GetItemID RetrieveGetItemIDFromItemID(ItemID itemID);
|
||||||
RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID);
|
RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID);
|
||||||
|
void Messagebox_ShowErrorBox(char* title, char* body);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -429,11 +429,16 @@ extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) {
|
||||||
return *sequence;
|
return *sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" SequenceData* ResourceMgr_LoadSeqPtrByName(const char* path) {
|
||||||
|
SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path);
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(const char* path) {
|
extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(const char* path) {
|
||||||
return (SoundFontSample*)ResourceGetDataByName(path);
|
return (SoundFontSample*)ResourceGetDataByName(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) {
|
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFontByName(const char* path) {
|
||||||
return (SoundFont*)ResourceGetDataByName(path);
|
return (SoundFont*)ResourceGetDataByName(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,9 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
|
||||||
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
|
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
|
||||||
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
|
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
|
||||||
Vtx* ResourceMgr_LoadVtxByName(char* path);
|
Vtx* ResourceMgr_LoadVtxByName(char* path);
|
||||||
SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path);
|
SoundFont* ResourceMgr_LoadAudioSoundFontByName(const char* path);
|
||||||
SequenceData ResourceMgr_LoadSeqByName(const char* path);
|
SequenceData ResourceMgr_LoadSeqByName(const char* path);
|
||||||
|
SequenceData* ResourceMgr_LoadSeqPtrByName(const char* path);
|
||||||
SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
|
SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
|
||||||
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
|
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
|
||||||
bool ResourceMgr_IsAltAssetsEnabled();
|
bool ResourceMgr_IsAltAssetsEnabled();
|
||||||
|
|
|
@ -351,6 +351,9 @@ void SohMenu::AddMenuEnhancements() {
|
||||||
AddWidget(path, "King Zora Speed: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
|
AddWidget(path, "King Zora Speed: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
|
||||||
.CVar(CVAR_ENHANCEMENT("MweepSpeed"))
|
.CVar(CVAR_ENHANCEMENT("MweepSpeed"))
|
||||||
.Options(FloatSliderOptions().Min(0.1f).Max(5.0f).DefaultValue(1.0f).Format("%.2fx"));
|
.Options(FloatSliderOptions().Min(0.1f).Max(5.0f).DefaultValue(1.0f).Format("%.2fx"));
|
||||||
|
AddWidget(path, "Faster Pause Menu", WIDGET_CVAR_CHECKBOX)
|
||||||
|
.CVar(CVAR_ENHANCEMENT("FasterPauseMenu"))
|
||||||
|
.Options(CheckboxOptions().Tooltip("Speeds up animation of the pause menu, similar to Majora's Mask"));
|
||||||
|
|
||||||
path.column = SECTION_COLUMN_3;
|
path.column = SECTION_COLUMN_3;
|
||||||
AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT);
|
AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT);
|
||||||
|
|
265
soh/soh/mixer.c
265
soh/soh/mixer.c
|
@ -1,9 +1,11 @@
|
||||||
|
//! This file is always optimized by a rule in the CMakeList. This is done because the SIMD functions are very large
|
||||||
|
//! when unoptimized and clang does not allow optimizing a single function.
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "mixer.h"
|
#include "mixer.h"
|
||||||
|
|
||||||
#ifndef __clang__
|
#ifndef __clang__
|
||||||
#pragma GCC optimize("unroll-loops")
|
#pragma GCC optimize("unroll-loops")
|
||||||
#endif
|
#endif
|
||||||
|
@ -66,6 +68,9 @@ static int16_t resample_table[64][4] = {
|
||||||
{ 0xffdf, 0x0d46, 0x66ad, 0x0c39 }
|
{ 0xffdf, 0x0d46, 0x66ad, 0x0c39 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void aMixImplSSE2(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
|
||||||
|
static void aMixImplNEON(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
|
||||||
|
|
||||||
static inline int16_t clamp16(int32_t v) {
|
static inline int16_t clamp16(int32_t v) {
|
||||||
if (v < -0x8000) {
|
if (v < -0x8000) {
|
||||||
return -0x8000;
|
return -0x8000;
|
||||||
|
@ -99,6 +104,33 @@ void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbyte
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <opus/opus.h>
|
||||||
|
#include <opusfile.h>
|
||||||
|
|
||||||
|
void aOPUSdecImpl(void* source_addr, uint16_t dest_addr, uint16_t nbytes, struct OggOpusFile** decState, int32_t pos,
|
||||||
|
uint32_t size) {
|
||||||
|
int readSamples = 0;
|
||||||
|
if (*decState == NULL) {
|
||||||
|
*decState = op_open_memory(source_addr, size, NULL);
|
||||||
|
}
|
||||||
|
op_pcm_seek(*decState, pos);
|
||||||
|
int ret = op_read(*decState, BUF_S16(dest_addr), nbytes / 2, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
readSamples += ret;
|
||||||
|
while (readSamples < nbytes / 2) {
|
||||||
|
ret = op_read(*decState, BUF_S16(dest_addr + readSamples * 2), (nbytes - readSamples * 2) / 2, NULL);
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
readSamples += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aOPUSFree(struct OggOpusFile* opusFile) {
|
||||||
|
op_free(opusFile);
|
||||||
|
}
|
||||||
|
|
||||||
void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes) {
|
void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes) {
|
||||||
memcpy(dest_addr, BUF_S16(source_addr), ROUND_DOWN_16(nbytes));
|
memcpy(dest_addr, BUF_S16(source_addr), ROUND_DOWN_16(nbytes));
|
||||||
}
|
}
|
||||||
|
@ -296,7 +328,7 @@ void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool
|
||||||
} while (n > 0);
|
} while (n > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
static void aMixImplRef(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||||
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
|
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
|
||||||
int16_t* in = BUF_S16(in_addr);
|
int16_t* in = BUF_S16(in_addr);
|
||||||
int16_t* out = BUF_S16(out_addr);
|
int16_t* out = BUF_S16(out_addr);
|
||||||
|
@ -323,6 +355,16 @@ void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||||
|
#if defined(__SSE2__) || defined(_M_AMD64)
|
||||||
|
aMixImplSSE2(count, gain, in_addr, out_addr);
|
||||||
|
#elif defined(__ARM_NEON)
|
||||||
|
aMixImplNEON(count, gain, in_addr, out_addr);
|
||||||
|
#else
|
||||||
|
aMixImplRef(count, gain, in_addr, out_addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void aS8DecImpl(uint8_t flags, ADPCM_STATE state) {
|
void aS8DecImpl(uint8_t flags, ADPCM_STATE state) {
|
||||||
uint8_t* in = BUF_U8(rspa.in);
|
uint8_t* in = BUF_U8(rspa.in);
|
||||||
int16_t* out = BUF_S16(rspa.out);
|
int16_t* out = BUF_S16(rspa.out);
|
||||||
|
@ -555,3 +597,222 @@ void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_add
|
||||||
nbytes -= 32 * sizeof(int16_t);
|
nbytes -= 32 * sizeof(int16_t);
|
||||||
} while (nbytes > 0);
|
} while (nbytes > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From here on there are SIMD implementations of the various mixer functions.
|
||||||
|
// A note about FORCE_OPTIMIZE...
|
||||||
|
// Compilers don't handle SIMD code well when not optimizing. It is unlikely that this code will need to be debugged
|
||||||
|
// outside of specific audio issues. We can assume it should always be optimized.
|
||||||
|
|
||||||
|
// SIMD operations expect aligned data
|
||||||
|
#include "align_asset_macro.h"
|
||||||
|
|
||||||
|
#if defined(__SSE2__) || defined(_M_AMD64)
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
static const ALIGN_ASSET(16) int16_t x7fff[8] = {
|
||||||
|
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
|
||||||
|
};
|
||||||
|
static const ALIGN_ASSET(16) int32_t x4000[4] = {
|
||||||
|
0x4000,
|
||||||
|
0x4000,
|
||||||
|
0x4000,
|
||||||
|
0x4000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aMixImplSSE2(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||||
|
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
|
||||||
|
int16_t* in = BUF_S16(in_addr);
|
||||||
|
int16_t* out = BUF_S16(out_addr);
|
||||||
|
int i;
|
||||||
|
int32_t sample;
|
||||||
|
if (gain == -0x8000) {
|
||||||
|
while (nbytes > 0) {
|
||||||
|
for (unsigned int i = 0; i < 2; i++) {
|
||||||
|
__m128i outVec = _mm_loadu_si128((__m128i*)out);
|
||||||
|
__m128i inVec = _mm_loadu_si128((__m128i*)in);
|
||||||
|
__m128i subsVec = _mm_subs_epi16(outVec, inVec);
|
||||||
|
_mm_storeu_si128(out, subsVec);
|
||||||
|
nbytes -= 8 * sizeof(int16_t);
|
||||||
|
in += 8;
|
||||||
|
out += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load constants into vectors from aligned memory.
|
||||||
|
__m128i x7fffVec = _mm_load_si128((__m128i*)x7fff);
|
||||||
|
__m128i x4000Vec = _mm_load_si128((__m128i*)x4000);
|
||||||
|
__m128i gainVec = _mm_set1_epi16(gain);
|
||||||
|
while (nbytes > 0) {
|
||||||
|
for (unsigned int i = 0; i < 2; i++) {
|
||||||
|
// Load input and output data into vectors
|
||||||
|
__m128i outVec = _mm_loadu_si128((__m128i*)out);
|
||||||
|
__m128i inVec = _mm_loadu_si128((__m128i*)in);
|
||||||
|
// Multiply `out` by `0x7FFF` producing 32 bit results, and store the upper and lower bits in each vector.
|
||||||
|
// Equivalent to `out[0..8] * 0x7FFF`
|
||||||
|
__m128i outx7fffLoVec = _mm_mullo_epi16(outVec, x7fffVec);
|
||||||
|
__m128i outx7fffHiVec = _mm_mulhi_epi16(outVec, x7fffVec);
|
||||||
|
// Same as above but for in and gain. Equivalent to `in[0..8] * gain`
|
||||||
|
__m128i inxGainLoVec = _mm_mullo_epi16(inVec, gainVec);
|
||||||
|
__m128i inxGainHiVec = _mm_mulhi_epi16(inVec, gainVec);
|
||||||
|
|
||||||
|
// Interleave the lo and hi bits into one 32 bit value for each vector element.
|
||||||
|
// So now we have 4 full elements in each vector instead of 8 half elements.
|
||||||
|
outx7fffLoVec = _mm_unpacklo_epi16(outx7fffLoVec, outx7fffHiVec);
|
||||||
|
outx7fffHiVec = _mm_unpackhi_epi16(outx7fffLoVec, outx7fffHiVec);
|
||||||
|
inxGainLoVec = _mm_unpacklo_epi16(inxGainLoVec, inxGainHiVec);
|
||||||
|
inxGainHiVec = _mm_unpackhi_epi16(inxGainLoVec, inxGainHiVec);
|
||||||
|
|
||||||
|
// Now we have 4 32 bit elements. Continue the calculaton per the reference implementation.
|
||||||
|
// We already did out + 0x7fff and in * gain.
|
||||||
|
// *out * 0x7fff + *in++ * gain is the final result of these two calculations.
|
||||||
|
__m128i addLoVec = _mm_add_epi32(outx7fffLoVec, inxGainLoVec);
|
||||||
|
__m128i addHiVec = _mm_add_epi32(outx7fffHiVec, inxGainHiVec);
|
||||||
|
// Add 0x4000 to each element
|
||||||
|
addLoVec = _mm_add_epi32(addLoVec, x4000Vec);
|
||||||
|
addHiVec = _mm_add_epi32(addHiVec, x4000Vec);
|
||||||
|
// Shift each element over by 15
|
||||||
|
__m128i shiftedLoVec = _mm_srai_epi32(addLoVec, 15);
|
||||||
|
__m128i shiftedHiVec = _mm_srai_epi32(addHiVec, 15);
|
||||||
|
// Convert each 32 bit element to 16 bit with saturation (clamp) and store in `outVec`
|
||||||
|
outVec = _mm_packs_epi32(shiftedLoVec, shiftedHiVec);
|
||||||
|
// Write the final vector back to memory
|
||||||
|
// The final calculation is ((out[0..8] * 0x7fff + in[0..8] * gain) + 0x4000) >> 15;
|
||||||
|
_mm_storeu_si128((__m128i*)out, outVec);
|
||||||
|
|
||||||
|
in += 8;
|
||||||
|
out += 8;
|
||||||
|
nbytes -= 8 * sizeof(int16_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(__ARM_NEON)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
static const int32_t x4000Arr[4] = { 0x4000, 0x4000, 0x4000, 0x4000 };
|
||||||
|
void aMixImplNEON(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||||
|
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
|
||||||
|
int16_t* in = BUF_S16(in_addr);
|
||||||
|
int16_t* out = BUF_S16(out_addr);
|
||||||
|
int i;
|
||||||
|
int32_t sample;
|
||||||
|
|
||||||
|
if (gain == -0x8000) {
|
||||||
|
while (nbytes > 0) {
|
||||||
|
for (unsigned int i = 0; i < 2; i++) {
|
||||||
|
int16x8_t outVec = vld1q_s16(out);
|
||||||
|
int16x8_t inVec = vld1q_s16(in);
|
||||||
|
int16x8_t subVec = vqsubq_s16(outVec, inVec);
|
||||||
|
vst1q_s16(out, subVec);
|
||||||
|
nbytes -= 8 * sizeof(int16_t);
|
||||||
|
out += 8;
|
||||||
|
in += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int16x8_t gainVec = vdupq_n_s16(gain);
|
||||||
|
int32x4_t x4000Vec = vld1q_s32(x4000Arr);
|
||||||
|
while (nbytes > 0) {
|
||||||
|
for (unsigned int i = 0; i < 2; i++) {
|
||||||
|
// for (i = 0; i < 16; i++) {
|
||||||
|
int16x8_t outVec = vld1q_s16(out);
|
||||||
|
int16x8_t inVec = vld1q_s16(in);
|
||||||
|
int16x4_t outLoVec = vget_low_s16(outVec);
|
||||||
|
int16x8_t outLoVec2 = vcombine_s16(outLoVec, outLoVec);
|
||||||
|
int16x4_t inLoVec = vget_low_s16(inVec);
|
||||||
|
int16x8_t inLoVec2 = vcombine_s16(inLoVec, inLoVec);
|
||||||
|
int32x4_t outX7fffHiVec = vmull_high_n_s16(outVec, 0x7FFF);
|
||||||
|
int32x4_t outX7fffLoVec = vmull_high_n_s16(outLoVec2, 0x7FFF);
|
||||||
|
|
||||||
|
int32x4_t inGainLoVec = vmull_high_s16(inLoVec2, gainVec);
|
||||||
|
int32x4_t inGainHiVec = vmull_high_s16(inVec, gainVec);
|
||||||
|
int32x4_t addVecLo = vaddq_s32(outX7fffLoVec, inGainLoVec);
|
||||||
|
int32x4_t addVecHi = vaddq_s32(outX7fffHiVec, inGainHiVec);
|
||||||
|
addVecHi = vaddq_s32(addVecHi, x4000Vec);
|
||||||
|
addVecLo = vaddq_s32(addVecLo, x4000Vec);
|
||||||
|
int32x4_t shiftVecHi = vshrq_n_s32(addVecHi, 15);
|
||||||
|
int32x4_t shiftVecLo = vshrq_n_s32(addVecLo, 15);
|
||||||
|
int16x4_t shiftedNarrowHiVec = vqmovn_s32(shiftVecHi);
|
||||||
|
int16x4_t shiftedNarrowLoVec = vqmovn_s32(shiftVecLo);
|
||||||
|
vst1_s16(out, shiftedNarrowLoVec);
|
||||||
|
out += 4;
|
||||||
|
vst1_s16(out, shiftedNarrowHiVec);
|
||||||
|
// int16x8_t finalVec = vcombine_s16(shiftedNarrowLoVec, shiftedNarrowHiVec);
|
||||||
|
// vst1q_s16(out, finalVec);
|
||||||
|
out += 4;
|
||||||
|
in += 8;
|
||||||
|
|
||||||
|
nbytes -= 8 * sizeof(int16_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static const ALIGN_ASSET(32) int16_t x7fff[16] = { 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,};
|
||||||
|
static const ALIGN_ASSET(32) int32_t x4000[8] = { 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000};
|
||||||
|
|
||||||
|
#pragma GCC target("avx2")
|
||||||
|
// AVX2 version of the SSE2 implementation above. AVX2 wasn't released until 2014 and I don't have a good way of checking for it at compile time.
|
||||||
|
void aMixImpl256(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
|
||||||
|
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
|
||||||
|
int16_t* in = BUF_S16(in_addr);
|
||||||
|
int16_t* out = BUF_S16(out_addr);
|
||||||
|
int i;
|
||||||
|
int32_t sample;
|
||||||
|
if (gain == -0x8000) {
|
||||||
|
while (nbytes > 0) {
|
||||||
|
__m256i outVec =_mm256_loadu_si256((__m256*)out);
|
||||||
|
__m256i inVec =_mm256_loadu_si256((__m256i*)in);
|
||||||
|
__m256i subsVec =_mm256_subs_epi16(outVec, inVec);
|
||||||
|
_mm256_storeu_si256(out, subsVec);
|
||||||
|
in += 16;
|
||||||
|
out += 16;
|
||||||
|
nbytes -= 16 * sizeof(int16_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load constants into vectors from aligned memory.
|
||||||
|
__m256i x7fffVec = _mm256_load_si256((__m256i*)x7fff);
|
||||||
|
__m256i x4000Vec = _mm256_load_si256((__m256i*)x4000);
|
||||||
|
__m256i gainVec = _mm256_set1_epi16(gain);
|
||||||
|
while (nbytes > 0) {
|
||||||
|
// Load input and output data into vectors
|
||||||
|
__m256i outVec = _mm256_loadu_si256((__m256i*)out);
|
||||||
|
__m256i inVec = _mm256_loadu_si256((__m256i*)in);
|
||||||
|
// Multiply `out` by `0x7FFF` producing 32 bit results, and store the upper and lower bits in each vector.
|
||||||
|
// Equivalent to `out[0..16] * 0x7FFF`
|
||||||
|
__m256i outx7fffLoVec = _mm256_mullo_epi16(outVec, x7fffVec);
|
||||||
|
__m256i outx7fffHiVec = _mm256_mulhi_epi16(outVec, x7fffVec);
|
||||||
|
// Same as above but for in and gain. Equivalent to `in[0..16] * gain`
|
||||||
|
__m256i inxGainLoVec = _mm256_mullo_epi16(inVec, gainVec);
|
||||||
|
__m256i inxGainHiVec = _mm256_mulhi_epi16(inVec, gainVec);
|
||||||
|
|
||||||
|
// Interleave the lo and hi bits into one 32 bit value for each vector element.
|
||||||
|
// So now we have 8 full elements in each vector instead of 16 half elements.
|
||||||
|
outx7fffLoVec = _mm256_unpacklo_epi16(outx7fffLoVec, outx7fffHiVec);
|
||||||
|
outx7fffHiVec = _mm256_unpackhi_epi16(outx7fffLoVec, outx7fffHiVec);
|
||||||
|
inxGainLoVec = _mm256_unpacklo_epi16(inxGainLoVec, inxGainHiVec);
|
||||||
|
inxGainHiVec = _mm256_unpackhi_epi16(inxGainLoVec, inxGainHiVec);
|
||||||
|
|
||||||
|
// Now we have 8 32 bit elements. Continue the calculaton per the reference implementation.
|
||||||
|
// We already did out + 0x7fff and in * gain.
|
||||||
|
// *out * 0x7fff + *in++ * gain is the final result of these two calculations.
|
||||||
|
__m256i addLoVec = _mm256_add_epi32(outx7fffLoVec, inxGainLoVec);
|
||||||
|
__m256i addHiVec = _mm256_add_epi32(outx7fffHiVec, inxGainHiVec);
|
||||||
|
// Add 0x4000 to each element
|
||||||
|
addLoVec = _mm256_add_epi32(addLoVec, x4000Vec);
|
||||||
|
addHiVec = _mm256_add_epi32(addHiVec, x4000Vec);
|
||||||
|
// Shift each element over by 15
|
||||||
|
__m256i shiftedLoVec = _mm256_srai_epi32(addLoVec, 15);
|
||||||
|
__m256i shiftedHiVec = _mm256_srai_epi32(addHiVec, 15);
|
||||||
|
// Convert each 32 bit element to 16 bit with saturation (clamp) and store in `outVec`
|
||||||
|
outVec = _mm256_packs_epi32(shiftedLoVec, shiftedHiVec);
|
||||||
|
// Write the final vector back to memory
|
||||||
|
// The final calculation is ((out[0..16] * 0x7fff + in[0..16] * gain) + 0x4000) >> 15;
|
||||||
|
_mm256_storeu_si256((__m256i*)out, outVec);
|
||||||
|
|
||||||
|
in += 16;
|
||||||
|
out += 16;
|
||||||
|
nbytes -= 16 * sizeof(int16_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -57,6 +57,11 @@ void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr);
|
||||||
void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c);
|
void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c);
|
||||||
void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr);
|
void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr);
|
||||||
|
|
||||||
|
struct OggOpusFile;
|
||||||
|
|
||||||
|
void aOPUSdecImpl(void* source_addr, uint16_t dest_addr, uint16_t nbytes, struct OggOpusFile** decState, int32_t pos,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
#define aSegment(pkt, s, b) \
|
#define aSegment(pkt, s, b) \
|
||||||
do { \
|
do { \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -1,6 +1,193 @@
|
||||||
#include "soh/resource/importer/AudioSampleFactory.h"
|
#include "soh/resource/importer/AudioSampleFactory.h"
|
||||||
|
#include "soh/resource/importer/AudioSoundFontFactory.h"
|
||||||
#include "soh/resource/type/AudioSample.h"
|
#include "soh/resource/type/AudioSample.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "z64.h"
|
||||||
|
#include "z64audio.h"
|
||||||
|
#include "Context.h"
|
||||||
|
#include "resource/archive/Archive.h"
|
||||||
|
#include "resource/ResourceManager.h"
|
||||||
|
#define DR_WAV_IMPLEMENTATION
|
||||||
|
#include <dr_wav.h>
|
||||||
|
|
||||||
|
#define DR_MP3_IMPLEMENTATION
|
||||||
|
#include <dr_mp3.h>
|
||||||
|
|
||||||
|
#define DR_FLAC_IMPLEMENTATION
|
||||||
|
#include <dr_flac.h>
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include <vorbis/codec.h>
|
||||||
|
#include "vorbis/vorbisfile.h"
|
||||||
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
struct OggFileData {
|
||||||
|
void* data;
|
||||||
|
size_t pos;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum class OggType {
|
||||||
|
None = -1,
|
||||||
|
Vorbis,
|
||||||
|
Opus,
|
||||||
|
} OggType;
|
||||||
|
|
||||||
|
static size_t VorbisReadCallback(void* out, size_t size, size_t elems, void* src) {
|
||||||
|
OggFileData* data = static_cast<OggFileData*>(src);
|
||||||
|
size_t toRead = size * elems;
|
||||||
|
|
||||||
|
if (toRead > data->size - data->pos) {
|
||||||
|
toRead = data->size - data->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, static_cast<uint8_t*>(data->data) + data->pos, toRead);
|
||||||
|
data->pos += toRead;
|
||||||
|
|
||||||
|
return toRead / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int VorbisSeekCallback(void* src, ogg_int64_t pos, int whence) {
|
||||||
|
OggFileData* data = static_cast<OggFileData*>(src);
|
||||||
|
size_t newPos;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
newPos = pos;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
newPos = data->pos + pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
newPos = data->size + pos;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (newPos > data->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->pos = newPos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int VorbisCloseCallback([[maybe_unused]] void* src) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long VorbisTellCallback(void* src) {
|
||||||
|
OggFileData* data = static_cast<OggFileData*>(src);
|
||||||
|
return data->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ov_callbacks vorbisCallbacks = {
|
||||||
|
VorbisReadCallback,
|
||||||
|
VorbisSeekCallback,
|
||||||
|
VorbisCloseCallback,
|
||||||
|
VorbisTellCallback,
|
||||||
|
};
|
||||||
|
|
||||||
|
static OggType GetOggType(OggFileData* data) {
|
||||||
|
ogg_sync_state oy;
|
||||||
|
ogg_stream_state os;
|
||||||
|
ogg_page og;
|
||||||
|
ogg_packet op;
|
||||||
|
OggType type;
|
||||||
|
// The first page as the header information, containing, among other things, what kind of data this ogg holds.
|
||||||
|
ogg_sync_init(&oy);
|
||||||
|
char* buffer = ogg_sync_buffer(&oy, 4096);
|
||||||
|
VorbisReadCallback(buffer, 4096, 1, data);
|
||||||
|
ogg_sync_wrote(&oy, 4096);
|
||||||
|
|
||||||
|
ogg_sync_pageout(&oy, &og);
|
||||||
|
ogg_stream_init(&os, ogg_page_serialno(&og));
|
||||||
|
ogg_stream_pagein(&os, &og);
|
||||||
|
ogg_stream_packetout(&os, &op);
|
||||||
|
|
||||||
|
// Can't use strmp because op.packet isn't a null terminated string.
|
||||||
|
if (memcmp((char*)op.packet, "\x01vorbis", 7) == 0) {
|
||||||
|
type = OggType::Vorbis;
|
||||||
|
} else if (memcmp((char*)op.packet, "OpusHead", 8) == 0) {
|
||||||
|
type = OggType::Opus;
|
||||||
|
} else {
|
||||||
|
type = OggType::None;
|
||||||
|
}
|
||||||
|
ogg_stream_clear(&os);
|
||||||
|
ogg_sync_clear(&oy);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Mp3DecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile) {
|
||||||
|
drmp3 mp3;
|
||||||
|
drwav_uint64 numFrames;
|
||||||
|
drmp3_bool32 ret =
|
||||||
|
drmp3_init_memory(&mp3, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
|
||||||
|
numFrames = drmp3_get_pcm_frame_count(&mp3);
|
||||||
|
drwav_uint64 channels = mp3.channels;
|
||||||
|
drwav_uint64 sampleRate = mp3.sampleRate;
|
||||||
|
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[numFrames * channels * 2];
|
||||||
|
drmp3_read_pcm_frames_s16(&mp3, numFrames, (int16_t*)audioSample->sample.sampleAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FlacDecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile) {
|
||||||
|
drflac* flac = drflac_open_memory(sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
|
||||||
|
drflac_uint64 numFrames = flac->totalPCMFrameCount;
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[numFrames * flac->channels * 2];
|
||||||
|
drflac_read_pcm_frames_s16(flac, numFrames, (int16_t*)audioSample->sample.sampleAddr);
|
||||||
|
drflac_close(flac);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OggDecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) {
|
||||||
|
OggVorbis_File vf;
|
||||||
|
char dataBuff[4096];
|
||||||
|
long read = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
OggFileData fileData = {
|
||||||
|
.data = sampleFile->Buffer.get()->data(),
|
||||||
|
.pos = 0,
|
||||||
|
.size = sampleFile->Buffer.get()->size(),
|
||||||
|
};
|
||||||
|
switch (GetOggType(&fileData)) {
|
||||||
|
case OggType::Vorbis: {
|
||||||
|
// Getting the type advanced the position. We are going to use a different library to decode the file which
|
||||||
|
// assumes the file starts at 0
|
||||||
|
fileData.pos = 0;
|
||||||
|
int ret = ov_open_callbacks(&fileData, &vf, nullptr, 0, vorbisCallbacks);
|
||||||
|
|
||||||
|
vorbis_info* vi = ov_info(&vf, -1);
|
||||||
|
|
||||||
|
uint64_t numFrames = ov_pcm_total(&vf, -1);
|
||||||
|
uint64_t sampleRate = vi->rate;
|
||||||
|
uint64_t numChannels = vi->channels;
|
||||||
|
int bitStream = 0;
|
||||||
|
size_t toRead = numFrames * numChannels * 2;
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[toRead];
|
||||||
|
do {
|
||||||
|
read = ov_read(&vf, dataBuff, 4096, 0, 2, 1, &bitStream);
|
||||||
|
memcpy(audioSample->sample.sampleAddr + pos, dataBuff, read);
|
||||||
|
pos += read;
|
||||||
|
} while (read != 0);
|
||||||
|
ov_clear(&vf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OggType::Opus: {
|
||||||
|
// OPUS encoded data is decoded by the audio driver.
|
||||||
|
audioSample->sample.codec = CODEC_OPUS;
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[sampleFile->Buffer.get()->size()];
|
||||||
|
memcpy(audioSample->sample.sampleAddr, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OggType::None: {
|
||||||
|
char buff[2048];
|
||||||
|
snprintf(buff, 2048, "Ogg file %s is not Vorbis or OPUS", initData->Path.c_str());
|
||||||
|
throw std::runtime_error(buff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
std::shared_ptr<Ship::IResource>
|
std::shared_ptr<Ship::IResource>
|
||||||
|
@ -16,108 +203,154 @@ ResourceFactoryBinaryAudioSampleV2::ReadResource(std::shared_ptr<Ship::File> fil
|
||||||
audioSample->sample.codec = reader->ReadUByte();
|
audioSample->sample.codec = reader->ReadUByte();
|
||||||
audioSample->sample.medium = reader->ReadUByte();
|
audioSample->sample.medium = reader->ReadUByte();
|
||||||
audioSample->sample.unk_bit26 = reader->ReadUByte();
|
audioSample->sample.unk_bit26 = reader->ReadUByte();
|
||||||
audioSample->sample.unk_bit25 = reader->ReadUByte();
|
audioSample->sample.isRelocated = reader->ReadUByte();
|
||||||
audioSample->sample.size = reader->ReadUInt32();
|
audioSample->sample.size = reader->ReadUInt32();
|
||||||
|
|
||||||
audioSample->audioSampleData.reserve(audioSample->sample.size);
|
audioSample->sample.sampleAddr = new uint8_t[audioSample->sample.size];
|
||||||
for (uint32_t i = 0; i < audioSample->sample.size; i++) {
|
for (uint32_t i = 0; i < audioSample->sample.size; i++) {
|
||||||
audioSample->audioSampleData.push_back(reader->ReadUByte());
|
audioSample->sample.sampleAddr[i] = reader->ReadUByte();
|
||||||
}
|
}
|
||||||
audioSample->sample.sampleAddr = audioSample->audioSampleData.data();
|
|
||||||
|
|
||||||
audioSample->loop.start = reader->ReadUInt32();
|
audioSample->loop.start = reader->ReadUInt32();
|
||||||
audioSample->loop.end = reader->ReadUInt32();
|
audioSample->loop.end = reader->ReadUInt32();
|
||||||
audioSample->loop.count = reader->ReadUInt32();
|
audioSample->loop.count = reader->ReadUInt32();
|
||||||
|
|
||||||
audioSample->loopStateCount = reader->ReadUInt32();
|
// This always seems to be 16. Can it be removed in V3?
|
||||||
|
uint32_t loopStateCount = reader->ReadUInt32();
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
audioSample->loop.state[i] = 0;
|
audioSample->loop.state[i] = 0;
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < audioSample->loopStateCount; i++) {
|
for (uint32_t i = 0; i < loopStateCount; i++) {
|
||||||
audioSample->loop.state[i] = reader->ReadInt16();
|
audioSample->loop.state[i] = reader->ReadInt16();
|
||||||
}
|
}
|
||||||
audioSample->sample.loop = &audioSample->loop;
|
audioSample->sample.loop = &audioSample->loop;
|
||||||
|
|
||||||
audioSample->book.order = reader->ReadInt32();
|
audioSample->book.order = reader->ReadInt32();
|
||||||
audioSample->book.npredictors = reader->ReadInt32();
|
audioSample->book.npredictors = reader->ReadInt32();
|
||||||
audioSample->bookDataCount = reader->ReadUInt32();
|
uint32_t bookDataCount = reader->ReadUInt32();
|
||||||
|
|
||||||
audioSample->bookData.reserve(audioSample->bookDataCount);
|
audioSample->book.book = new int16_t[bookDataCount];
|
||||||
for (uint32_t i = 0; i < audioSample->bookDataCount; i++) {
|
|
||||||
audioSample->bookData.push_back(reader->ReadInt16());
|
for (uint32_t i = 0; i < bookDataCount; i++) {
|
||||||
|
audioSample->book.book[i] = reader->ReadInt16();
|
||||||
}
|
}
|
||||||
audioSample->book.book = audioSample->bookData.data();
|
|
||||||
audioSample->sample.book = &audioSample->book;
|
audioSample->sample.book = &audioSample->book;
|
||||||
|
|
||||||
return audioSample;
|
return audioSample;
|
||||||
}
|
}
|
||||||
} // namespace SOH
|
|
||||||
|
|
||||||
/*
|
std::shared_ptr<Ship::IResource>
|
||||||
in ResourceMgr_LoadAudioSample we used to have
|
ResourceFactoryXMLAudioSampleV0::ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
--------------
|
std::shared_ptr<Ship::ResourceInitData> initData) {
|
||||||
if (cachedCustomSFs.find(path) != cachedCustomSFs.end())
|
if (!FileHasValidFormatAndReader(file, initData)) {
|
||||||
return cachedCustomSFs[path];
|
|
||||||
|
|
||||||
SoundFontSample* cSample = ReadCustomSample(path);
|
|
||||||
|
|
||||||
if (cSample != nullptr)
|
|
||||||
return cSample;
|
|
||||||
--------------
|
|
||||||
before the rest of the standard sample reading, this is the ReadCustomSample code we used to have
|
|
||||||
|
|
||||||
extern "C" SoundFontSample* ReadCustomSample(const char* path) {
|
|
||||||
|
|
||||||
if (!ExtensionCache.contains(path))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ExtensionEntry entry = ExtensionCache[path];
|
|
||||||
|
|
||||||
auto sampleRaw = Ship::Context::GetInstance()->GetResourceManager()->LoadFile(entry.path);
|
|
||||||
uint32_t* strem = (uint32_t*)sampleRaw->Buffer.get();
|
|
||||||
uint8_t* strem2 = (uint8_t*)strem;
|
|
||||||
|
|
||||||
SoundFontSample* sampleC = new SoundFontSample;
|
|
||||||
|
|
||||||
if (entry.ext == "wav") {
|
|
||||||
drwav_uint32 channels;
|
|
||||||
drwav_uint32 sampleRate;
|
|
||||||
drwav_uint64 totalPcm;
|
|
||||||
drmp3_int16* pcmData =
|
|
||||||
drwav_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &channels, &sampleRate, &totalPcm,
|
|
||||||
NULL); sampleC->size = totalPcm; sampleC->sampleAddr = (uint8_t*)pcmData; sampleC->codec = CODEC_S16;
|
|
||||||
|
|
||||||
sampleC->loop = new AdpcmLoop;
|
|
||||||
sampleC->loop->start = 0;
|
|
||||||
sampleC->loop->end = sampleC->size - 1;
|
|
||||||
sampleC->loop->count = 0;
|
|
||||||
sampleC->sampleRateMagicValue = 'RIFF';
|
|
||||||
sampleC->sampleRate = sampleRate;
|
|
||||||
|
|
||||||
cachedCustomSFs[path] = sampleC;
|
|
||||||
return sampleC;
|
|
||||||
} else if (entry.ext == "mp3") {
|
|
||||||
drmp3_config mp3Info;
|
|
||||||
drmp3_uint64 totalPcm;
|
|
||||||
drmp3_int16* pcmData =
|
|
||||||
drmp3_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &mp3Info, &totalPcm, NULL);
|
|
||||||
|
|
||||||
sampleC->size = totalPcm * mp3Info.channels * sizeof(short);
|
|
||||||
sampleC->sampleAddr = (uint8_t*)pcmData;
|
|
||||||
sampleC->codec = CODEC_S16;
|
|
||||||
|
|
||||||
sampleC->loop = new AdpcmLoop;
|
|
||||||
sampleC->loop->start = 0;
|
|
||||||
sampleC->loop->end = sampleC->size;
|
|
||||||
sampleC->loop->count = 0;
|
|
||||||
sampleC->sampleRateMagicValue = 'RIFF';
|
|
||||||
sampleC->sampleRate = mp3Info.sampleRate;
|
|
||||||
|
|
||||||
cachedCustomSFs[path] = sampleC;
|
|
||||||
return sampleC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
auto audioSample = std::make_shared<AudioSample>(initData);
|
||||||
|
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
|
||||||
|
const char* customFormatStr = child->Attribute("CustomFormat");
|
||||||
|
memset(&audioSample->sample, 0, sizeof(audioSample->sample));
|
||||||
|
audioSample->sample.isRelocated = 0;
|
||||||
|
audioSample->sample.codec = CodecStrToInt(child->Attribute("Codec"), initData->Path.c_str());
|
||||||
|
audioSample->sample.medium =
|
||||||
|
ResourceFactoryXMLSoundFontV0::MediumStrToInt(child->Attribute("Medium"), initData->Path.c_str());
|
||||||
|
audioSample->sample.unk_bit26 = child->IntAttribute("bit26");
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* loopRoot = child->FirstChildElement("ADPCMLoop");
|
||||||
|
if (loopRoot != nullptr) {
|
||||||
|
size_t i = 0;
|
||||||
|
audioSample->loop.start = loopRoot->UnsignedAttribute("Start");
|
||||||
|
audioSample->loop.end = loopRoot->UnsignedAttribute("End");
|
||||||
|
audioSample->loop.count = loopRoot->UnsignedAttribute("Count");
|
||||||
|
tinyxml2::XMLElement* predictor = loopRoot->FirstChildElement("Predictor");
|
||||||
|
while (predictor != nullptr) {
|
||||||
|
audioSample->loop.state[i++] = predictor->IntAttribute("State");
|
||||||
|
predictor = predictor->NextSiblingElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* bookRoot = child->FirstChildElement("ADPCMBook");
|
||||||
|
if (bookRoot != nullptr) {
|
||||||
|
size_t i = 0;
|
||||||
|
audioSample->book.npredictors = bookRoot->IntAttribute("Npredictors");
|
||||||
|
audioSample->book.order = bookRoot->IntAttribute("Order");
|
||||||
|
tinyxml2::XMLElement* book = bookRoot->FirstChildElement("Book");
|
||||||
|
size_t numBooks = audioSample->book.npredictors * audioSample->book.order * 8;
|
||||||
|
audioSample->book.book = new int16_t[numBooks];
|
||||||
|
while (book != nullptr) {
|
||||||
|
audioSample->book.book[i++] = book->IntAttribute("Page");
|
||||||
|
book = book->NextSiblingElement();
|
||||||
|
}
|
||||||
|
audioSample->sample.book = &audioSample->book;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioSample->sample.loop = &audioSample->loop;
|
||||||
|
size_t size = child->Int64Attribute("Size");
|
||||||
|
audioSample->sample.size = size;
|
||||||
|
|
||||||
|
const char* path = child->Attribute("Path");
|
||||||
|
|
||||||
|
auto sampleFile = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFile(path);
|
||||||
|
audioSample->sample.fileSize = sampleFile->Buffer.get()->size();
|
||||||
|
if (customFormatStr != nullptr) {
|
||||||
|
// Compressed files can take a really long time to decode (~250ms per).
|
||||||
|
// This worked when we tested it (09/04/2024) (Works on my machine)
|
||||||
|
if (strcmp(customFormatStr, "wav") == 0) {
|
||||||
|
drwav wav;
|
||||||
|
drwav_uint64 numFrames;
|
||||||
|
|
||||||
|
drwav_bool32 ret =
|
||||||
|
drwav_init_memory(&wav, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
|
||||||
|
|
||||||
|
drwav_get_length_in_pcm_frames(&wav, &numFrames);
|
||||||
|
|
||||||
|
audioSample->tuning = (wav.sampleRate * wav.channels) / 32000.0f;
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[numFrames * wav.channels * 2];
|
||||||
|
|
||||||
|
drwav_read_pcm_frames_s16(&wav, numFrames, (int16_t*)audioSample->sample.sampleAddr);
|
||||||
|
return audioSample;
|
||||||
|
} else if (strcmp(customFormatStr, "mp3") == 0) {
|
||||||
|
std::thread fileDecoderThread = std::thread(Mp3DecoderWorker, audioSample, sampleFile);
|
||||||
|
fileDecoderThread.detach();
|
||||||
|
return audioSample;
|
||||||
|
} else if (strcmp(customFormatStr, "ogg") == 0) {
|
||||||
|
std::thread fileDecoderThread = std::thread(OggDecoderWorker, audioSample, sampleFile, initData);
|
||||||
|
fileDecoderThread.detach();
|
||||||
|
return audioSample;
|
||||||
|
} else if (strcmp(customFormatStr, "flac") == 0) {
|
||||||
|
std::thread fileDecoderThread = std::thread(FlacDecoderWorker, audioSample, sampleFile);
|
||||||
|
fileDecoderThread.detach();
|
||||||
|
return audioSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not a normal streamed sample. Fallback to the original ADPCM sample to be decoded by the audio engine.
|
||||||
|
audioSample->sample.sampleAddr = new uint8_t[size];
|
||||||
|
// Can't use memcpy due to endianness issues.
|
||||||
|
for (uint32_t i = 0; i < size; i++) {
|
||||||
|
audioSample->sample.sampleAddr[i] = sampleFile->Buffer.get()->data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return audioSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
uint8_t ResourceFactoryXMLAudioSampleV0::CodecStrToInt(const char* str, const char* file) {
|
||||||
|
if (strcmp("ADPCM", str) == 0) {
|
||||||
|
return CODEC_ADPCM;
|
||||||
|
} else if (strcmp("S8", str) == 0) {
|
||||||
|
return CODEC_S8;
|
||||||
|
} else if (strcmp("S16MEM", str) == 0) {
|
||||||
|
return CODEC_S16_INMEMORY;
|
||||||
|
} else if (strcmp("ADPCMSMALL", str) == 0) {
|
||||||
|
return CODEC_SMALL_ADPCM;
|
||||||
|
} else if (strcmp("REVERB", str) == 0) {
|
||||||
|
return CODEC_REVERB;
|
||||||
|
} else if (strcmp("S16", str) == 0) {
|
||||||
|
return CODEC_S16;
|
||||||
|
} else {
|
||||||
|
char buff[2048];
|
||||||
|
snprintf(buff, 2048, "Invalid codec in %s. Got %s, expected ADPCM, S8, S16MEM, ADPCMSMALL, REVERB, S16.", file,
|
||||||
|
str);
|
||||||
|
throw std::runtime_error(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace SOH
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
#include "ResourceFactoryBinary.h"
|
#include "ResourceFactoryBinary.h"
|
||||||
|
#include "ResourceFactoryXML.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
class ResourceFactoryBinaryAudioSampleV2 final : public Ship::ResourceFactoryBinary {
|
class ResourceFactoryBinaryAudioSampleV2 final : public Ship::ResourceFactoryBinary {
|
||||||
|
@ -9,4 +10,14 @@ class ResourceFactoryBinaryAudioSampleV2 final : public Ship::ResourceFactoryBin
|
||||||
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ResourceFactoryXMLAudioSampleV0 final : public Ship::ResourceFactoryXML {
|
||||||
|
public:
|
||||||
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint8_t CodecStrToInt(const char* str, const char* file);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace SOH
|
} // namespace SOH
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
#include "soh/resource/importer/AudioSequenceFactory.h"
|
#include "soh/resource/importer/AudioSequenceFactory.h"
|
||||||
|
#include "soh/resource/importer/AudioSoundFontFactory.h"
|
||||||
#include "soh/resource/type/AudioSequence.h"
|
#include "soh/resource/type/AudioSequence.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "resource/ResourceManager.h"
|
||||||
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
#include "Context.h"
|
||||||
|
#include "resource/archive/Archive.h"
|
||||||
|
#include "BinaryWriter.h"
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
std::shared_ptr<Ship::IResource>
|
std::shared_ptr<Ship::IResource>
|
||||||
|
@ -13,12 +21,11 @@ ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> f
|
||||||
auto audioSequence = std::make_shared<AudioSequence>(initData);
|
auto audioSequence = std::make_shared<AudioSequence>(initData);
|
||||||
auto reader = std::get<std::shared_ptr<Ship::BinaryReader>>(file->Reader);
|
auto reader = std::get<std::shared_ptr<Ship::BinaryReader>>(file->Reader);
|
||||||
|
|
||||||
audioSequence->sequence.seqDataSize = reader->ReadInt32();
|
audioSequence->sequence.seqDataSize = reader->ReadUInt32();
|
||||||
audioSequence->sequenceData.reserve(audioSequence->sequence.seqDataSize);
|
audioSequence->sequence.seqData = new char[audioSequence->sequence.seqDataSize];
|
||||||
for (int32_t i = 0; i < audioSequence->sequence.seqDataSize; i++) {
|
for (int32_t i = 0; i < audioSequence->sequence.seqDataSize; i++) {
|
||||||
audioSequence->sequenceData.push_back(reader->ReadChar());
|
audioSequence->sequence.seqData[i] = reader->ReadChar();
|
||||||
}
|
}
|
||||||
audioSequence->sequence.seqData = audioSequence->sequenceData.data();
|
|
||||||
|
|
||||||
audioSequence->sequence.seqNumber = reader->ReadUByte();
|
audioSequence->sequence.seqNumber = reader->ReadUByte();
|
||||||
audioSequence->sequence.medium = reader->ReadUByte();
|
audioSequence->sequence.medium = reader->ReadUByte();
|
||||||
|
@ -34,4 +41,355 @@ ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> f
|
||||||
|
|
||||||
return audioSequence;
|
return audioSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> static void WriteInsnOneArg(Ship::BinaryWriter* writer, uint8_t opcode, T arg) {
|
||||||
|
static_assert(std::is_fundamental<T>::value);
|
||||||
|
writer->Write(opcode);
|
||||||
|
writer->Write(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
static void WriteInsnTwoArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2) {
|
||||||
|
static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
|
||||||
|
writer->Write(opcode);
|
||||||
|
writer->Write(arg1);
|
||||||
|
writer->Write(arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3>
|
||||||
|
static void WriteInsnThreeArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2, T3 arg3) {
|
||||||
|
static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
|
||||||
|
writer->Write(opcode);
|
||||||
|
writer->Write(arg1);
|
||||||
|
writer->Write(arg2);
|
||||||
|
writer->Write(arg3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteInsnNoArg(Ship::BinaryWriter* writer, uint8_t opcode) {
|
||||||
|
writer->Write(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteLegato(Ship::BinaryWriter* writer) {
|
||||||
|
WriteInsnNoArg(writer, 0xC4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteNoLegato(Ship::BinaryWriter* writer) {
|
||||||
|
WriteInsnNoArg(writer, 0xC5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteMuteBhv(Ship::BinaryWriter* writer, uint8_t arg) {
|
||||||
|
WriteInsnOneArg(writer, 0xD3, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteMuteScale(Ship::BinaryWriter* writer, uint8_t arg) {
|
||||||
|
WriteInsnOneArg(writer, 0xD5, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteInitchan(Ship::BinaryWriter* writer, uint16_t channels) {
|
||||||
|
WriteInsnOneArg(writer, 0xD7, channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteLdchan(Ship::BinaryWriter* writer, uint8_t channel, uint16_t offset) {
|
||||||
|
WriteInsnOneArg(writer, 0x90 | channel, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteVolSHeader(Ship::BinaryWriter* writer, uint8_t vol) {
|
||||||
|
WriteInsnOneArg(writer, 0xDB, vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteVolCHeader(Ship::BinaryWriter* writer, uint8_t vol) {
|
||||||
|
WriteInsnOneArg(writer, 0xDF, vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteTempo(Ship::BinaryWriter* writer, uint8_t tempo) {
|
||||||
|
WriteInsnOneArg(writer, 0xDD, tempo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteJump(Ship::BinaryWriter* writer, uint16_t offset) {
|
||||||
|
WriteInsnOneArg(writer, 0xFB, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteDisablecan(Ship::BinaryWriter* writer, uint16_t channels) {
|
||||||
|
WriteInsnOneArg(writer, 0xD6, channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteNoshort(Ship::BinaryWriter* writer) {
|
||||||
|
WriteInsnNoArg(writer, 0xC4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteLdlayer(Ship::BinaryWriter* writer, uint8_t layer, uint16_t offset) {
|
||||||
|
WriteInsnOneArg(writer, 0x88 | layer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WritePan(Ship::BinaryWriter* writer, uint8_t pan) {
|
||||||
|
WriteInsnOneArg(writer, 0xDD, pan);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteBend(Ship::BinaryWriter* writer, uint8_t bend) {
|
||||||
|
WriteInsnOneArg(writer, 0xD3, bend);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteInstrument(Ship::BinaryWriter* writer, uint8_t instrument) {
|
||||||
|
WriteInsnOneArg(writer, 0xC1, instrument);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteTranspose(Ship::BinaryWriter* writer, int8_t transpose) {
|
||||||
|
WriteInsnOneArg(writer, 0xC2, transpose);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteDelay(Ship::BinaryWriter* writer, uint16_t delay) {
|
||||||
|
if (delay > 0x7F) {
|
||||||
|
WriteInsnOneArg(writer, 0xFD, static_cast<uint16_t>(delay | 0x8000));
|
||||||
|
} else {
|
||||||
|
WriteInsnOneArg(writer, 0xFD, static_cast<uint8_t>(delay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void WriteLDelay(Ship::BinaryWriter* writer, T delay) {
|
||||||
|
WriteInsnOneArg(writer, 0xC0, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static void WriteNotedv(Ship::BinaryWriter* writer, uint8_t note, T delay, uint8_t velocity) {
|
||||||
|
WriteInsnTwoArg(writer, note, delay, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteNotedvg(Ship::BinaryWriter* writer, uint8_t note, uint16_t delay, uint8_t velocity, uint8_t gateTime) {
|
||||||
|
if (delay > 0x7F) {
|
||||||
|
WriteInsnThreeArg(writer, note, static_cast<uint16_t>(delay | 0x8000), velocity, gateTime);
|
||||||
|
} else {
|
||||||
|
WriteInsnThreeArg(writer, note, static_cast<uint8_t>(delay), velocity, gateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteMonoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
|
||||||
|
uint16_t channelStart;
|
||||||
|
uint16_t channelPlaceholderOff;
|
||||||
|
uint16_t loopPoint;
|
||||||
|
uint16_t layerPlaceholderOff;
|
||||||
|
uint16_t layerStart;
|
||||||
|
if (looped) {
|
||||||
|
delay = 0x7FFF;
|
||||||
|
}
|
||||||
|
// Write seq header
|
||||||
|
|
||||||
|
// These two values are always the same in OOT and MM
|
||||||
|
WriteMuteBhv(writer, 0x20);
|
||||||
|
WriteMuteScale(writer, 0x32);
|
||||||
|
|
||||||
|
// We only have one channel
|
||||||
|
WriteInitchan(writer, 0b11);
|
||||||
|
// Store the current position so we can write the address of the channel when we are ready.
|
||||||
|
channelPlaceholderOff = writer->GetBaseAddress();
|
||||||
|
// Store the current position so we can loop here after the song ends.
|
||||||
|
loopPoint = writer->GetBaseAddress();
|
||||||
|
WriteLdchan(writer, 0, 0); // Fill in the actual address later
|
||||||
|
|
||||||
|
WriteVolSHeader(writer, 127); // Max volume
|
||||||
|
WriteTempo(writer, tempo);
|
||||||
|
|
||||||
|
WriteDelay(writer, delay);
|
||||||
|
if (looped) {
|
||||||
|
WriteJump(writer, loopPoint);
|
||||||
|
}
|
||||||
|
WriteDisablecan(writer, 0b11);
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
// Fill in the ldchan from before
|
||||||
|
channelStart = writer->GetBaseAddress();
|
||||||
|
writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
|
||||||
|
WriteLdchan(writer, 0, channelStart);
|
||||||
|
writer->Seek(channelStart, Ship::SeekOffsetType::Start);
|
||||||
|
|
||||||
|
// Channel header
|
||||||
|
layerPlaceholderOff = writer->GetBaseAddress();
|
||||||
|
WriteNoshort(writer);
|
||||||
|
WriteLdlayer(writer, 0, 0);
|
||||||
|
WritePan(writer, 64);
|
||||||
|
WriteVolCHeader(writer, 127); // Max volume
|
||||||
|
WriteBend(writer, 0);
|
||||||
|
WriteInstrument(writer, 0);
|
||||||
|
WriteDelay(writer, delay);
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
layerStart = writer->GetBaseAddress();
|
||||||
|
writer->Seek(layerPlaceholderOff, Ship::SeekOffsetType::Start);
|
||||||
|
WriteLdlayer(writer, 0, layerStart);
|
||||||
|
writer->Seek(layerStart, Ship::SeekOffsetType::Start);
|
||||||
|
|
||||||
|
// Note layer
|
||||||
|
WriteLegato(writer);
|
||||||
|
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteStereoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
|
||||||
|
uint16_t lChannelStart;
|
||||||
|
uint16_t rChannelStart;
|
||||||
|
uint16_t channelPlaceholderOff;
|
||||||
|
uint16_t loopPoint;
|
||||||
|
uint16_t lLayerPlaceholderOff;
|
||||||
|
uint16_t rLayerPlaceholderOff;
|
||||||
|
uint16_t lLayerOffset;
|
||||||
|
uint16_t rLayerOffset;
|
||||||
|
|
||||||
|
uint16_t layerStart;
|
||||||
|
// Write seq header
|
||||||
|
if (looped) {
|
||||||
|
delay = 0x7FFF;
|
||||||
|
}
|
||||||
|
// These two values are always the same in OOT and MM
|
||||||
|
WriteMuteBhv(writer, 0x20);
|
||||||
|
WriteMuteScale(writer, 0x32);
|
||||||
|
|
||||||
|
// We only have one channel
|
||||||
|
WriteInitchan(writer, 0b11);
|
||||||
|
// Store the current position so we can write the address of the channel when we are ready.
|
||||||
|
channelPlaceholderOff = writer->GetBaseAddress();
|
||||||
|
// Store the current position so we can loop here after the song ends.
|
||||||
|
loopPoint = writer->GetBaseAddress();
|
||||||
|
// Left note channel
|
||||||
|
WriteLdchan(writer, 0, 0); // Fill in the actual address later
|
||||||
|
// Right note channel
|
||||||
|
WriteLdchan(writer, 1, 0); // Fill in the actual address later
|
||||||
|
|
||||||
|
WriteVolSHeader(writer, 127); // Max volume
|
||||||
|
WriteTempo(writer, tempo);
|
||||||
|
|
||||||
|
WriteDelay(writer, delay);
|
||||||
|
if (looped) {
|
||||||
|
WriteJump(writer, loopPoint);
|
||||||
|
}
|
||||||
|
WriteDisablecan(writer, 0b11);
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
lChannelStart = writer->GetBaseAddress();
|
||||||
|
// Left Channel header
|
||||||
|
WriteNoshort(writer);
|
||||||
|
lLayerPlaceholderOff = writer->GetBaseAddress();
|
||||||
|
WriteLdlayer(writer, 0, 0);
|
||||||
|
WritePan(writer, 0);
|
||||||
|
WriteVolCHeader(writer, 127); // Max volume
|
||||||
|
WriteBend(writer, 0);
|
||||||
|
WriteInstrument(writer, 0);
|
||||||
|
WriteDelay(writer, delay);
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
rChannelStart = writer->GetBaseAddress();
|
||||||
|
// Right Channel header
|
||||||
|
WriteNoshort(writer);
|
||||||
|
rLayerPlaceholderOff = writer->GetBaseAddress();
|
||||||
|
WriteLdlayer(writer, 1, 0);
|
||||||
|
WritePan(writer, 127);
|
||||||
|
WriteVolCHeader(writer, 127); // Max volume
|
||||||
|
WriteBend(writer, 0);
|
||||||
|
WriteInstrument(writer, 1);
|
||||||
|
WriteDelay(writer, delay);
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
uint16_t placeHolder = writer->GetBaseAddress();
|
||||||
|
writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
|
||||||
|
WriteLdchan(writer, 0, lChannelStart);
|
||||||
|
WriteLdchan(writer, 1, rChannelStart);
|
||||||
|
writer->Seek(placeHolder, Ship::SeekOffsetType::Start);
|
||||||
|
|
||||||
|
// Left Note layer
|
||||||
|
lLayerOffset = writer->GetBaseAddress();
|
||||||
|
WriteLegato(writer);
|
||||||
|
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
// Right Note layer
|
||||||
|
rLayerOffset = writer->GetBaseAddress();
|
||||||
|
WriteLegato(writer);
|
||||||
|
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
|
||||||
|
writer->Write(static_cast<uint8_t>(0xFF));
|
||||||
|
|
||||||
|
writer->Seek(lLayerPlaceholderOff, Ship::SeekOffsetType::Start);
|
||||||
|
WriteLdlayer(writer, 0, lLayerOffset);
|
||||||
|
writer->Seek(rLayerPlaceholderOff, Ship::SeekOffsetType::Start);
|
||||||
|
WriteLdlayer(writer, 1, rLayerOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Ship::IResource>
|
||||||
|
ResourceFactoryXMLAudioSequenceV0::ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) {
|
||||||
|
if (!FileHasValidFormatAndReader(file, initData)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sequence = std::make_shared<AudioSequence>(initData);
|
||||||
|
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
sequence->sequence.medium =
|
||||||
|
ResourceFactoryXMLSoundFontV0::MediumStrToInt(child->Attribute("Medium"), initData->Path.c_str());
|
||||||
|
sequence->sequence.cachePolicy =
|
||||||
|
ResourceFactoryXMLSoundFontV0::CachePolicyToInt(child->Attribute("CachePolicy"), initData->Path.c_str());
|
||||||
|
sequence->sequence.seqDataSize = child->IntAttribute("Size");
|
||||||
|
sequence->sequence.seqNumber = child->IntAttribute("Index");
|
||||||
|
bool streamed = child->BoolAttribute("Streamed");
|
||||||
|
|
||||||
|
memset(sequence->sequence.fonts, 0, sizeof(sequence->sequence.fonts));
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* fontsElement = child->FirstChildElement();
|
||||||
|
tinyxml2::XMLElement* fontElement = fontsElement->FirstChildElement();
|
||||||
|
while (fontElement != nullptr) {
|
||||||
|
sequence->sequence.fonts[i] = fontElement->IntAttribute("FontIdx");
|
||||||
|
fontElement = fontElement->NextSiblingElement();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
sequence->sequence.numFonts = i;
|
||||||
|
|
||||||
|
const char* path = child->Attribute("Path");
|
||||||
|
std::shared_ptr<Ship::File> seqFile;
|
||||||
|
if (path != nullptr) {
|
||||||
|
seqFile = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!streamed) {
|
||||||
|
sequence->sequence.seqDataSize = seqFile->Buffer.get()->size();
|
||||||
|
sequence->sequence.seqData = new char[seqFile->Buffer.get()->size()];
|
||||||
|
memcpy(sequence->sequence.seqData, seqFile->Buffer.get()->data(), seqFile->Buffer.get()->size());
|
||||||
|
} else {
|
||||||
|
// setting numFonts to -1 tells the game's audio engine the sound font to used is CRC64 encoded in the font
|
||||||
|
// indicies.
|
||||||
|
sequence->sequence.numFonts = -1;
|
||||||
|
if (path != nullptr) {
|
||||||
|
sequence->sequence.seqDataSize = seqFile->Buffer.get()->size();
|
||||||
|
sequence->sequence.seqData = new char[seqFile->Buffer.get()->size()];
|
||||||
|
memcpy(sequence->sequence.seqData, seqFile->Buffer.get()->data(), seqFile->Buffer.get()->size());
|
||||||
|
} else {
|
||||||
|
unsigned int length = child->UnsignedAttribute("Length");
|
||||||
|
bool looped = child->BoolAttribute("Looped", true);
|
||||||
|
bool stereo = child->BoolAttribute("Stereo", false);
|
||||||
|
Ship::BinaryWriter writer = Ship::BinaryWriter();
|
||||||
|
writer.SetEndianness(Ship::Endianness::Big);
|
||||||
|
|
||||||
|
// 1 second worth of ticks can be found by using `ticks = 60 / (bpm * 48)`
|
||||||
|
// Get the number of ticks per second and then divide the length by this number to get the number of ticks
|
||||||
|
// for the song.
|
||||||
|
constexpr uint8_t TEMPO = 1;
|
||||||
|
constexpr float TEMPO_F = TEMPO;
|
||||||
|
// Use floats for this first calculation so we can round up
|
||||||
|
float delayF = length / (60.0f / (TEMPO_F * 48.0f));
|
||||||
|
// Convert to u16. This way this value is encoded changes depending on the value.
|
||||||
|
// It can be at most 0xFFFF so store it in a u16 for now.
|
||||||
|
uint16_t delay;
|
||||||
|
if (delayF >= 65535.0f) {
|
||||||
|
delay = 0x7FFF;
|
||||||
|
} else {
|
||||||
|
delay = delayF;
|
||||||
|
}
|
||||||
|
if (stereo) {
|
||||||
|
WriteStereoSingleSeq(&writer, delay, TEMPO, looped);
|
||||||
|
} else {
|
||||||
|
WriteMonoSingleSeq(&writer, delay, TEMPO, looped);
|
||||||
|
}
|
||||||
|
sequence->sequence.seqDataSize = writer.ToVector().size();
|
||||||
|
sequence->sequence.seqData = new char[sequence->sequence.seqDataSize];
|
||||||
|
memcpy(sequence->sequence.seqData, writer.ToVector().data(), sequence->sequence.seqDataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
} // namespace SOH
|
} // namespace SOH
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
#include "ResourceFactoryBinary.h"
|
#include "ResourceFactoryBinary.h"
|
||||||
|
#include "ResourceFactoryXML.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
class ResourceFactoryBinaryAudioSequenceV2 final : public Ship::ResourceFactoryBinary {
|
class ResourceFactoryBinaryAudioSequenceV2 final : public Ship::ResourceFactoryBinary {
|
||||||
|
@ -9,4 +10,11 @@ class ResourceFactoryBinaryAudioSequenceV2 final : public Ship::ResourceFactoryB
|
||||||
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ResourceFactoryXMLAudioSequenceV0 final : public Ship::ResourceFactoryXML {
|
||||||
|
public:
|
||||||
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace SOH
|
} // namespace SOH
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
#include "soh/resource/importer/AudioSoundFontFactory.h"
|
#include "soh/resource/importer/AudioSoundFontFactory.h"
|
||||||
#include "soh/resource/type/AudioSoundFont.h"
|
#include "soh/resource/type/AudioSoundFont.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include <tinyxml2.h>
|
||||||
#include "libultraship/libultraship.h"
|
#include <z64.h>
|
||||||
|
#include "z64audio.h"
|
||||||
|
#include "Context.h"
|
||||||
|
#include "resource/archive/Archive.h"
|
||||||
|
#include "resource/ResourceManager.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
std::shared_ptr<Ship::IResource>
|
std::shared_ptr<Ship::IResource>
|
||||||
|
@ -35,117 +39,115 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
|
||||||
audioSoundFont->soundFont.numSfx = soundEffectCount;
|
audioSoundFont->soundFont.numSfx = soundEffectCount;
|
||||||
|
|
||||||
// 🥁 DRUMS 🥁
|
// 🥁 DRUMS 🥁
|
||||||
audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
|
// audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
|
||||||
audioSoundFont->drumAddresses.reserve(audioSoundFont->soundFont.numDrums);
|
audioSoundFont->drumAddresses.reserve(audioSoundFont->soundFont.numDrums);
|
||||||
for (uint32_t i = 0; i < audioSoundFont->soundFont.numDrums; i++) {
|
for (uint32_t i = 0; i < audioSoundFont->soundFont.numDrums; i++) {
|
||||||
Drum drum;
|
Drum* drum = new Drum;
|
||||||
drum.releaseRate = reader->ReadUByte();
|
drum->releaseRate = reader->ReadUByte();
|
||||||
drum.pan = reader->ReadUByte();
|
drum->pan = reader->ReadUByte();
|
||||||
drum.loaded = reader->ReadUByte();
|
drum->loaded = reader->ReadUByte();
|
||||||
drum.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
|
drum->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
|
||||||
|
|
||||||
uint32_t envelopeCount = reader->ReadUInt32();
|
uint32_t envelopeCount = reader->ReadUInt32();
|
||||||
audioSoundFont->drumEnvelopeCounts.push_back(envelopeCount);
|
drum->envelope = new AdsrEnvelope[envelopeCount];
|
||||||
std::vector<AdsrEnvelope> drumEnvelopes;
|
for (uint32_t j = 0; j < envelopeCount; j++) {
|
||||||
drumEnvelopes.reserve(audioSoundFont->drumEnvelopeCounts[i]);
|
|
||||||
for (uint32_t j = 0; j < audioSoundFont->drumEnvelopeCounts.back(); j++) {
|
|
||||||
AdsrEnvelope env;
|
|
||||||
|
|
||||||
int16_t delay = reader->ReadInt16();
|
int16_t delay = reader->ReadInt16();
|
||||||
int16_t arg = reader->ReadInt16();
|
int16_t arg = reader->ReadInt16();
|
||||||
|
|
||||||
env.delay = BE16SWAP(delay);
|
drum->envelope[j].delay = BE16SWAP(delay);
|
||||||
env.arg = BE16SWAP(arg);
|
drum->envelope[j].arg = BE16SWAP(arg);
|
||||||
|
|
||||||
drumEnvelopes.push_back(env);
|
|
||||||
}
|
}
|
||||||
audioSoundFont->drumEnvelopeArrays.push_back(drumEnvelopes);
|
|
||||||
drum.envelope = audioSoundFont->drumEnvelopeArrays.back().data();
|
|
||||||
|
|
||||||
bool hasSample = reader->ReadInt8();
|
bool hasSample = reader->ReadInt8();
|
||||||
std::string sampleFileName = reader->ReadString();
|
std::string sampleFileName = reader->ReadString();
|
||||||
drum.sound.tuning = reader->ReadFloat();
|
drum->sound.tuning = reader->ReadFloat();
|
||||||
|
|
||||||
if (sampleFileName.empty()) {
|
if (sampleFileName.empty()) {
|
||||||
drum.sound.sample = nullptr;
|
drum->sound.sample = nullptr;
|
||||||
} else {
|
} else {
|
||||||
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
||||||
drum.sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
drum->sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
audioSoundFont->drums.push_back(drum);
|
// audioSoundFont->drums.push_back(drum);
|
||||||
audioSoundFont->drumAddresses.push_back(&audioSoundFont->drums.back());
|
// BENTODO clean this up in V3.
|
||||||
|
if (drum->sound.sample == nullptr) {
|
||||||
|
delete[] drum->envelope;
|
||||||
|
delete drum;
|
||||||
|
audioSoundFont->drumAddresses.push_back(nullptr);
|
||||||
|
} else {
|
||||||
|
audioSoundFont->drumAddresses.push_back(drum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
audioSoundFont->soundFont.drums = audioSoundFont->drumAddresses.data();
|
audioSoundFont->soundFont.drums = audioSoundFont->drumAddresses.data();
|
||||||
|
|
||||||
// 🎺🎻🎷🎸🎹 INSTRUMENTS 🎹🎸🎷🎻🎺
|
// 🎺🎻🎷🎸🎹 INSTRUMENTS 🎹🎸🎷🎻🎺
|
||||||
audioSoundFont->instruments.reserve(audioSoundFont->soundFont.numInstruments);
|
|
||||||
for (uint32_t i = 0; i < audioSoundFont->soundFont.numInstruments; i++) {
|
for (uint32_t i = 0; i < audioSoundFont->soundFont.numInstruments; i++) {
|
||||||
Instrument instrument;
|
Instrument* instrument = new Instrument;
|
||||||
|
|
||||||
uint8_t isValidEntry = reader->ReadUByte();
|
uint8_t isValidEntry = reader->ReadUByte();
|
||||||
instrument.loaded = reader->ReadUByte();
|
instrument->loaded = reader->ReadUByte();
|
||||||
instrument.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
|
instrument->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
|
||||||
|
|
||||||
instrument.normalRangeLo = reader->ReadUByte();
|
instrument->normalRangeLo = reader->ReadUByte();
|
||||||
instrument.normalRangeHi = reader->ReadUByte();
|
instrument->normalRangeHi = reader->ReadUByte();
|
||||||
instrument.releaseRate = reader->ReadUByte();
|
instrument->releaseRate = reader->ReadUByte();
|
||||||
|
|
||||||
uint32_t envelopeCount = reader->ReadInt32();
|
uint32_t envelopeCount = reader->ReadInt32();
|
||||||
audioSoundFont->instrumentEnvelopeCounts.push_back(envelopeCount);
|
instrument->envelope = new AdsrEnvelope[envelopeCount];
|
||||||
std::vector<AdsrEnvelope> instrumentEnvelopes;
|
|
||||||
for (uint32_t j = 0; j < audioSoundFont->instrumentEnvelopeCounts.back(); j++) {
|
|
||||||
AdsrEnvelope env;
|
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < envelopeCount; j++) {
|
||||||
int16_t delay = reader->ReadInt16();
|
int16_t delay = reader->ReadInt16();
|
||||||
int16_t arg = reader->ReadInt16();
|
int16_t arg = reader->ReadInt16();
|
||||||
|
|
||||||
env.delay = BE16SWAP(delay);
|
instrument->envelope[j].delay = BE16SWAP(delay);
|
||||||
env.arg = BE16SWAP(arg);
|
instrument->envelope[j].arg = BE16SWAP(arg);
|
||||||
|
|
||||||
instrumentEnvelopes.push_back(env);
|
|
||||||
}
|
}
|
||||||
audioSoundFont->instrumentEnvelopeArrays.push_back(instrumentEnvelopes);
|
|
||||||
instrument.envelope = audioSoundFont->instrumentEnvelopeArrays.back().data();
|
|
||||||
|
|
||||||
bool hasLowNoteSoundFontEntry = reader->ReadInt8();
|
bool hasLowNoteSoundFontEntry = reader->ReadInt8();
|
||||||
if (hasLowNoteSoundFontEntry) {
|
if (hasLowNoteSoundFontEntry) {
|
||||||
bool hasSampleRef = reader->ReadInt8();
|
bool hasSampleRef = reader->ReadInt8();
|
||||||
std::string sampleFileName = reader->ReadString();
|
std::string sampleFileName = reader->ReadString();
|
||||||
instrument.lowNotesSound.tuning = reader->ReadFloat();
|
instrument->lowNotesSound.tuning = reader->ReadFloat();
|
||||||
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
||||||
instrument.lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
instrument->lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
} else {
|
} else {
|
||||||
instrument.lowNotesSound.sample = nullptr;
|
instrument->lowNotesSound.sample = nullptr;
|
||||||
instrument.lowNotesSound.tuning = 0;
|
instrument->lowNotesSound.tuning = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasNormalNoteSoundFontEntry = reader->ReadInt8();
|
bool hasNormalNoteSoundFontEntry = reader->ReadInt8();
|
||||||
if (hasNormalNoteSoundFontEntry) {
|
if (hasNormalNoteSoundFontEntry) {
|
||||||
|
// BENTODO remove in V3
|
||||||
bool hasSampleRef = reader->ReadInt8();
|
bool hasSampleRef = reader->ReadInt8();
|
||||||
std::string sampleFileName = reader->ReadString();
|
std::string sampleFileName = reader->ReadString();
|
||||||
instrument.normalNotesSound.tuning = reader->ReadFloat();
|
instrument->normalNotesSound.tuning = reader->ReadFloat();
|
||||||
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
||||||
instrument.normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
instrument->normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
} else {
|
} else {
|
||||||
instrument.normalNotesSound.sample = nullptr;
|
instrument->normalNotesSound.sample = nullptr;
|
||||||
instrument.normalNotesSound.tuning = 0;
|
instrument->normalNotesSound.tuning = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasHighNoteSoundFontEntry = reader->ReadInt8();
|
bool hasHighNoteSoundFontEntry = reader->ReadInt8();
|
||||||
if (hasHighNoteSoundFontEntry) {
|
if (hasHighNoteSoundFontEntry) {
|
||||||
bool hasSampleRef = reader->ReadInt8();
|
bool hasSampleRef = reader->ReadInt8();
|
||||||
std::string sampleFileName = reader->ReadString();
|
std::string sampleFileName = reader->ReadString();
|
||||||
instrument.highNotesSound.tuning = reader->ReadFloat();
|
instrument->highNotesSound.tuning = reader->ReadFloat();
|
||||||
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
|
||||||
instrument.highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
instrument->highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
} else {
|
} else {
|
||||||
instrument.highNotesSound.sample = nullptr;
|
instrument->highNotesSound.sample = nullptr;
|
||||||
instrument.highNotesSound.tuning = 0;
|
instrument->highNotesSound.tuning = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioSoundFont->instruments.push_back(instrument);
|
if (isValidEntry) {
|
||||||
audioSoundFont->instrumentAddresses.push_back(isValidEntry ? &audioSoundFont->instruments.back() : nullptr);
|
audioSoundFont->instrumentAddresses.push_back(instrument);
|
||||||
|
} else {
|
||||||
|
delete[] instrument->envelope;
|
||||||
|
delete instrument;
|
||||||
|
audioSoundFont->instrumentAddresses.push_back(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
audioSoundFont->soundFont.instruments = audioSoundFont->instrumentAddresses.data();
|
audioSoundFont->soundFont.instruments = audioSoundFont->instrumentAddresses.data();
|
||||||
|
|
||||||
|
@ -169,4 +171,302 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
|
||||||
|
|
||||||
return audioSoundFont;
|
return audioSoundFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int8_t ResourceFactoryXMLSoundFontV0::MediumStrToInt(const char* str, const char* file) {
|
||||||
|
if (!strcmp("Ram", str)) {
|
||||||
|
return MEDIUM_RAM;
|
||||||
|
} else if (!strcmp("Unk", str)) {
|
||||||
|
return MEDIUM_UNK;
|
||||||
|
} else if (!strcmp("Cart", str)) {
|
||||||
|
return MEDIUM_CART;
|
||||||
|
} else if (!strcmp("Disk", str)) {
|
||||||
|
return MEDIUM_DISK_DRIVE;
|
||||||
|
// 4 is skipped
|
||||||
|
} else {
|
||||||
|
char buff[2048];
|
||||||
|
snprintf(buff, 2048, "Bad medium value in %s. Got %s, expected Ram, Unk, Cart, or Disk.", file, str);
|
||||||
|
throw std::runtime_error(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ResourceFactoryXMLSoundFontV0::CachePolicyToInt(const char* str, const char* file) {
|
||||||
|
if (!strcmp("Temporary", str)) {
|
||||||
|
return CACHE_TEMPORARY;
|
||||||
|
} else if (!strcmp("Persistent", str)) {
|
||||||
|
return CACHE_PERSISTENT;
|
||||||
|
} else if (!strcmp("Either", str)) {
|
||||||
|
return CACHE_EITHER;
|
||||||
|
} else if (!strcmp("Permanent", str)) {
|
||||||
|
return CACHE_PERMANENT;
|
||||||
|
} else {
|
||||||
|
char buff[2048];
|
||||||
|
snprintf(buff, 2048,
|
||||||
|
"Bad cache policy value in %s. Got %s, expected Temporary, Persistent, Either, or Permanent.", file,
|
||||||
|
str);
|
||||||
|
throw std::runtime_error(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceFactoryXMLSoundFontV0::ParseDrums(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
|
||||||
|
element = element->FirstChildElement();
|
||||||
|
// No drums
|
||||||
|
if (element == nullptr) {
|
||||||
|
soundFont->soundFont.drums = nullptr;
|
||||||
|
soundFont->soundFont.numDrums = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
int patch = element->IntAttribute("Patches", -1);
|
||||||
|
Drum* drum;
|
||||||
|
if (patch != -1) {
|
||||||
|
drum = soundFont->drumAddresses[patch];
|
||||||
|
} else {
|
||||||
|
drum = new Drum;
|
||||||
|
}
|
||||||
|
std::vector<AdsrEnvelope> envelopes;
|
||||||
|
drum->releaseRate = element->IntAttribute("ReleaseRate");
|
||||||
|
drum->pan = element->IntAttribute("Pan");
|
||||||
|
drum->loaded = element->IntAttribute("Loaded");
|
||||||
|
drum->sound.tuning = element->FloatAttribute("Tuning");
|
||||||
|
const char* sampleStr = element->Attribute("SampleRef");
|
||||||
|
|
||||||
|
if (sampleStr != nullptr && sampleStr[0] != 0) {
|
||||||
|
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr);
|
||||||
|
drum->sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
|
} else {
|
||||||
|
drum->sound.sample = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element->FirstChildElement();
|
||||||
|
if (!strcmp(element->Name(), "Envelopes")) {
|
||||||
|
// element = (tinyxml2::XMLElement*)element->FirstChildElement();
|
||||||
|
unsigned int envCount = 0;
|
||||||
|
envelopes = ParseEnvelopes(soundFont, element, &envCount);
|
||||||
|
element = (tinyxml2::XMLElement*)element->Parent();
|
||||||
|
soundFont->drumEnvelopeArrays.push_back(envelopes);
|
||||||
|
// If we are applying a patch the envelopes are already allocated
|
||||||
|
// TODO revert this if we enable editing envelopes in a patch
|
||||||
|
if (patch == -1) {
|
||||||
|
drum->envelope = new AdsrEnvelope[envelopes.size()];
|
||||||
|
}
|
||||||
|
memcpy(drum->envelope, envelopes.data(), envelopes.size() * sizeof(AdsrEnvelope));
|
||||||
|
} else {
|
||||||
|
drum->envelope = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drum->sound.sample == nullptr) {
|
||||||
|
soundFont->drumAddresses.push_back(nullptr);
|
||||||
|
} else {
|
||||||
|
soundFont->drumAddresses.push_back(drum);
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element->NextSiblingElement();
|
||||||
|
} while (element != nullptr);
|
||||||
|
|
||||||
|
soundFont->soundFont.numDrums = soundFont->drumAddresses.size();
|
||||||
|
soundFont->soundFont.drums = soundFont->drumAddresses.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceFactoryXMLSoundFontV0::ParseInstruments(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
|
||||||
|
element = element->FirstChildElement();
|
||||||
|
if (element == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
int patch = element->IntAttribute("Patches", -1);
|
||||||
|
Instrument* instrument;
|
||||||
|
// Same as drums, if applying a patch, don't re-allocate and clear.
|
||||||
|
if (patch != -1) {
|
||||||
|
instrument = soundFont->instrumentAddresses[patch];
|
||||||
|
} else {
|
||||||
|
instrument = new Instrument;
|
||||||
|
memset(instrument, 0, sizeof(Instrument));
|
||||||
|
}
|
||||||
|
unsigned int envCount = 0;
|
||||||
|
std::vector<AdsrEnvelope> envelopes;
|
||||||
|
|
||||||
|
int isValid = element->BoolAttribute("IsValid");
|
||||||
|
instrument->loaded = element->IntAttribute("Loaded");
|
||||||
|
instrument->normalRangeLo = element->IntAttribute("NormalRangeLo");
|
||||||
|
instrument->normalRangeHi = element->IntAttribute("NormalRangeHi");
|
||||||
|
instrument->releaseRate = element->IntAttribute("ReleaseRate");
|
||||||
|
tinyxml2::XMLElement* instrumentElement = element->FirstChildElement();
|
||||||
|
tinyxml2::XMLElement* instrumentElementCopy = instrumentElement;
|
||||||
|
|
||||||
|
if (instrumentElement != nullptr && !strcmp(instrumentElement->Name(), "Envelopes")) {
|
||||||
|
envelopes = ParseEnvelopes(soundFont, instrumentElement, &envCount);
|
||||||
|
if (patch == -1) {
|
||||||
|
instrument->envelope = new AdsrEnvelope[envelopes.size()];
|
||||||
|
}
|
||||||
|
memcpy(instrument->envelope, envelopes.data(), envelopes.size() * sizeof(AdsrEnvelope));
|
||||||
|
instrumentElement = instrumentElement->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instrumentElement != nullptr && !strcmp("LowNotesSound", instrumentElement->Name())) {
|
||||||
|
instrument->lowNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
|
||||||
|
const char* sampleStr = instrumentElement->Attribute("SampleRef");
|
||||||
|
if (sampleStr != nullptr && sampleStr[0] != 0) {
|
||||||
|
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
|
||||||
|
if (res->tuning != -1.0f) {
|
||||||
|
instrument->lowNotesSound.tuning = res->tuning;
|
||||||
|
}
|
||||||
|
instrument->lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
|
}
|
||||||
|
instrumentElement = instrumentElement->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instrumentElement != nullptr && !strcmp("NormalNotesSound", instrumentElement->Name())) {
|
||||||
|
instrument->normalNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
|
||||||
|
const char* sampleStr = instrumentElement->Attribute("SampleRef");
|
||||||
|
if (sampleStr != nullptr && sampleStr[0] != 0) {
|
||||||
|
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
|
||||||
|
if (res->tuning != -1.0f) {
|
||||||
|
instrument->normalNotesSound.tuning = res->tuning;
|
||||||
|
}
|
||||||
|
instrument->normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
|
}
|
||||||
|
instrumentElement = instrumentElement->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instrumentElement != nullptr && !strcmp("HighNotesSound", instrumentElement->Name())) {
|
||||||
|
instrument->highNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
|
||||||
|
const char* sampleStr = instrumentElement->Attribute("SampleRef");
|
||||||
|
if (sampleStr != nullptr && sampleStr[0] != 0) {
|
||||||
|
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
|
||||||
|
if (res->tuning != -1.0f) {
|
||||||
|
instrument->highNotesSound.tuning = res->tuning;
|
||||||
|
}
|
||||||
|
instrument->highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
|
}
|
||||||
|
instrumentElement = instrumentElement->NextSiblingElement();
|
||||||
|
}
|
||||||
|
// Don't add it to the list if applying a patch
|
||||||
|
if (patch == -1) {
|
||||||
|
soundFont->instrumentAddresses.push_back(instrument);
|
||||||
|
}
|
||||||
|
element = instrumentElementCopy;
|
||||||
|
element = (tinyxml2::XMLElement*)element->Parent();
|
||||||
|
element = element->NextSiblingElement();
|
||||||
|
} while (element != nullptr);
|
||||||
|
|
||||||
|
soundFont->soundFont.instruments = soundFont->instrumentAddresses.data();
|
||||||
|
soundFont->soundFont.numInstruments = soundFont->instrumentAddresses.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceFactoryXMLSoundFontV0::ParseSfxTable(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
|
||||||
|
size_t count = element->IntAttribute("Count");
|
||||||
|
|
||||||
|
element = element->FirstChildElement();
|
||||||
|
|
||||||
|
while (element != nullptr) {
|
||||||
|
int patch = element->IntAttribute("Patches", -1);
|
||||||
|
|
||||||
|
SoundFontSound sound = {};
|
||||||
|
|
||||||
|
const char* sampleStr = element->Attribute("SampleRef");
|
||||||
|
// Insert an empty sound effect. The game assumes the empty slots are
|
||||||
|
// filled so we can't just skip them
|
||||||
|
if (sampleStr == nullptr)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
sound.tuning = element->FloatAttribute("Tuning");
|
||||||
|
if (sampleStr[0] != 0) {
|
||||||
|
auto res = static_pointer_cast<SOH::AudioSample>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
|
||||||
|
if (res->tuning != -1.0f) {
|
||||||
|
sound.tuning = res->tuning;
|
||||||
|
}
|
||||||
|
sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
|
||||||
|
}
|
||||||
|
skip:
|
||||||
|
element = element->NextSiblingElement();
|
||||||
|
if (patch != -1) {
|
||||||
|
soundFont->soundEffects[patch] = sound;
|
||||||
|
} else {
|
||||||
|
soundFont->soundEffects.push_back(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
soundFont->soundFont.soundEffects = soundFont->soundEffects.data();
|
||||||
|
soundFont->soundFont.numSfx = soundFont->soundEffects.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AdsrEnvelope> SOH::ResourceFactoryXMLSoundFontV0::ParseEnvelopes(AudioSoundFont* soundFont,
|
||||||
|
tinyxml2::XMLElement* element,
|
||||||
|
unsigned int* count) {
|
||||||
|
std::vector<AdsrEnvelope> envelopes;
|
||||||
|
unsigned int total = 0;
|
||||||
|
element = element->FirstChildElement("Envelope");
|
||||||
|
while (element != nullptr) {
|
||||||
|
AdsrEnvelope env = {
|
||||||
|
.delay = (s16)element->IntAttribute("Delay"),
|
||||||
|
.arg = (s16)element->IntAttribute("Arg"),
|
||||||
|
};
|
||||||
|
env.delay = BSWAP16(env.delay);
|
||||||
|
env.arg = BSWAP16(env.arg);
|
||||||
|
envelopes.emplace_back(env);
|
||||||
|
element = element->NextSiblingElement("Envelope");
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
*count = total;
|
||||||
|
return envelopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Ship::IResource>
|
||||||
|
ResourceFactoryXMLSoundFontV0::ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) {
|
||||||
|
if (!FileHasValidFormatAndReader(file, initData)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
|
||||||
|
const char* patch = child->Attribute("Patches");
|
||||||
|
std::shared_ptr<Ship::IResource> sf;
|
||||||
|
std::shared_ptr<AudioSoundFont> audioSoundFont;
|
||||||
|
// If we are patching an existing SF, load the original, otherwise create and clear a new one.
|
||||||
|
if (patch != nullptr) {
|
||||||
|
std::string origName = "audio/fonts/";
|
||||||
|
origName += patch;
|
||||||
|
audioSoundFont = dynamic_pointer_cast<AudioSoundFont>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(origName));
|
||||||
|
} else {
|
||||||
|
audioSoundFont = std::make_shared<AudioSoundFont>(initData);
|
||||||
|
memset(&audioSoundFont->soundFont, 0, sizeof(audioSoundFont->soundFont));
|
||||||
|
}
|
||||||
|
// Header data
|
||||||
|
audioSoundFont->soundFont.fntIndex = child->IntAttribute("Num", 0);
|
||||||
|
|
||||||
|
const char* mediumStr = child->Attribute("Medium");
|
||||||
|
audioSoundFont->medium = MediumStrToInt(mediumStr, initData->Path.c_str());
|
||||||
|
|
||||||
|
const char* cachePolicyStr = child->Attribute("CachePolicy");
|
||||||
|
audioSoundFont->cachePolicy = CachePolicyToInt(cachePolicyStr, initData->Path.c_str());
|
||||||
|
|
||||||
|
audioSoundFont->data1 = child->IntAttribute("Data1");
|
||||||
|
audioSoundFont->data2 = child->IntAttribute("Data2");
|
||||||
|
audioSoundFont->data3 = child->IntAttribute("Data3");
|
||||||
|
|
||||||
|
audioSoundFont->soundFont.sampleBankId1 = audioSoundFont->data1 >> 8;
|
||||||
|
audioSoundFont->soundFont.sampleBankId2 = audioSoundFont->data1 & 0xFF;
|
||||||
|
|
||||||
|
child = (tinyxml2::XMLElement*)child->FirstChildElement();
|
||||||
|
|
||||||
|
while (child != nullptr) {
|
||||||
|
const char* name = child->Name();
|
||||||
|
|
||||||
|
if (!strcmp(name, "Drums")) {
|
||||||
|
ParseDrums(audioSoundFont.get(), child);
|
||||||
|
} else if (!strcmp(name, "Instruments")) {
|
||||||
|
ParseInstruments(audioSoundFont.get(), child);
|
||||||
|
} else if (!strcmp(name, "SfxTable")) {
|
||||||
|
ParseSfxTable(audioSoundFont.get(), child);
|
||||||
|
}
|
||||||
|
child = child->NextSiblingElement();
|
||||||
|
}
|
||||||
|
return audioSoundFont;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace SOH
|
} // namespace SOH
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
#include "ResourceFactoryBinary.h"
|
#include "ResourceFactoryBinary.h"
|
||||||
|
#include "ResourceFactoryXML.h"
|
||||||
|
#include "soh/resource/type/AudioSoundFont.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
class ResourceFactoryBinaryAudioSoundFontV2 final : public Ship::ResourceFactoryBinary {
|
class ResourceFactoryBinaryAudioSoundFontV2 final : public Ship::ResourceFactoryBinary {
|
||||||
|
@ -9,4 +11,20 @@ class ResourceFactoryBinaryAudioSoundFontV2 final : public Ship::ResourceFactory
|
||||||
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ResourceFactoryXMLSoundFontV0 final : public Ship::ResourceFactoryXML {
|
||||||
|
public:
|
||||||
|
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
|
||||||
|
std::shared_ptr<Ship::ResourceInitData> initData) override;
|
||||||
|
static int8_t MediumStrToInt(const char* str, const char* file);
|
||||||
|
static int8_t CachePolicyToInt(const char* str, const char* file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ParseDrums(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
|
||||||
|
void ParseInstruments(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
|
||||||
|
void ParseSfxTable(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
|
||||||
|
std::vector<AdsrEnvelope> ParseEnvelopes(AudioSoundFont* soundFont, tinyxml2::XMLElement* element,
|
||||||
|
unsigned int* count);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace SOH
|
} // namespace SOH
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
#include "AudioSample.h"
|
#include "AudioSample.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
|
AudioSample::~AudioSample() {
|
||||||
|
if (sample.book != nullptr && sample.book->book != nullptr) {
|
||||||
|
delete[] sample.book->book;
|
||||||
|
}
|
||||||
|
if (sample.sampleAddr != nullptr) {
|
||||||
|
delete[] sample.sampleAddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
Sample* AudioSample::GetPointer() {
|
Sample* AudioSample::GetPointer() {
|
||||||
return &sample;
|
return &sample;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
#include <libultraship/libultra/types.h>
|
#include <libultraship/libultra/types.h>
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ uintptr_t start;
|
/* 0x00 */ u32 start;
|
||||||
/* 0x04 */ uintptr_t end;
|
/* 0x04 */ u32 end;
|
||||||
/* 0x08 */ u32 count;
|
/* 0x08 */ u32 count;
|
||||||
/* 0x0C */ char unk_0C[0x4];
|
/* 0x0C */ char unk_0C[0x4];
|
||||||
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
|
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
|
||||||
|
@ -20,23 +19,25 @@ typedef struct {
|
||||||
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
|
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
|
||||||
} AdpcmBook; // s
|
} AdpcmBook; // s
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Sample {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
/* 0x00 */ u32 codec : 4;
|
///* 0x0 */ u32 unk_0 : 1;
|
||||||
/* 0x00 */ u32 medium : 2;
|
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
|
||||||
/* 0x00 */ u32 unk_bit26 : 1;
|
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
|
||||||
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
|
/* 0x0 */ u32 unk_bit26 : 1;
|
||||||
/* 0x01 */ u32 size : 24;
|
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
|
||||||
};
|
};
|
||||||
u32 asU32;
|
u32 asU32;
|
||||||
};
|
};
|
||||||
|
/* 0x1 */ u32 size; // Size of the sample
|
||||||
/* 0x04 */ u8* sampleAddr;
|
u32 fileSize;
|
||||||
/* 0x08 */ AdpcmLoop* loop;
|
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either
|
||||||
/* 0x0C */ AdpcmBook* book;
|
// rom or ram
|
||||||
u32 sampleRateMagicValue; // For wav samples only...
|
/* 0x8 */ AdpcmLoop*
|
||||||
s32 sampleRate; // For wav samples only...
|
loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram
|
||||||
|
/* 0xC */ AdpcmBook*
|
||||||
|
book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram
|
||||||
} Sample; // size = 0x10
|
} Sample; // size = 0x10
|
||||||
|
|
||||||
class AudioSample : public Ship::Resource<Sample> {
|
class AudioSample : public Ship::Resource<Sample> {
|
||||||
|
@ -45,18 +46,15 @@ class AudioSample : public Ship::Resource<Sample> {
|
||||||
|
|
||||||
AudioSample() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
AudioSample() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
||||||
}
|
}
|
||||||
|
~AudioSample();
|
||||||
|
|
||||||
Sample* GetPointer();
|
Sample* GetPointer();
|
||||||
size_t GetPointerSize();
|
size_t GetPointerSize();
|
||||||
|
|
||||||
Sample sample;
|
Sample sample;
|
||||||
std::vector<uint8_t> audioSampleData;
|
|
||||||
|
|
||||||
AdpcmLoop loop;
|
AdpcmLoop loop;
|
||||||
uint32_t loopStateCount;
|
|
||||||
|
|
||||||
AdpcmBook book;
|
AdpcmBook book;
|
||||||
uint32_t bookDataCount;
|
// Only applies to streamed audio
|
||||||
std::vector<int16_t> bookData;
|
float tuning = -1.0f;
|
||||||
};
|
};
|
||||||
}; // namespace SOH
|
}; // namespace SOH
|
|
@ -9,4 +9,10 @@ Sequence* AudioSequence::GetPointer() {
|
||||||
size_t AudioSequence::GetPointerSize() {
|
size_t AudioSequence::GetPointerSize() {
|
||||||
return sizeof(Sequence);
|
return sizeof(Sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioSequence::~AudioSequence() {
|
||||||
|
delete[] sequence.seqData;
|
||||||
|
sequence.seqData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace SOH
|
} // namespace SOH
|
|
@ -1,19 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
#include <libultraship/libultra/types.h>
|
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* seqData;
|
char* seqData;
|
||||||
int32_t seqDataSize;
|
uint32_t seqDataSize;
|
||||||
uint16_t seqNumber;
|
uint16_t seqNumber;
|
||||||
uint8_t medium;
|
uint8_t medium;
|
||||||
uint8_t cachePolicy;
|
uint8_t cachePolicy;
|
||||||
int32_t numFonts;
|
uint32_t numFonts;
|
||||||
uint8_t fonts[16];
|
uint8_t fonts[16];
|
||||||
} Sequence;
|
} Sequence;
|
||||||
|
|
||||||
|
@ -23,11 +21,11 @@ class AudioSequence : public Ship::Resource<Sequence> {
|
||||||
|
|
||||||
AudioSequence() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
AudioSequence() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
||||||
}
|
}
|
||||||
|
~AudioSequence();
|
||||||
|
|
||||||
Sequence* GetPointer();
|
Sequence* GetPointer();
|
||||||
size_t GetPointerSize();
|
size_t GetPointerSize();
|
||||||
|
|
||||||
Sequence sequence;
|
Sequence sequence;
|
||||||
std::vector<char> sequenceData;
|
|
||||||
};
|
};
|
||||||
}; // namespace SOH
|
}; // namespace SOH
|
|
@ -1,6 +1,23 @@
|
||||||
#include "AudioSoundFont.h"
|
#include "AudioSoundFont.h"
|
||||||
|
|
||||||
namespace SOH {
|
namespace SOH {
|
||||||
|
|
||||||
|
AudioSoundFont::~AudioSoundFont() {
|
||||||
|
for (auto i : instrumentAddresses) {
|
||||||
|
if (i != nullptr) {
|
||||||
|
delete[] i->envelope;
|
||||||
|
delete i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto d : drumAddresses) {
|
||||||
|
if (d != nullptr) {
|
||||||
|
delete[] d->envelope;
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SoundFont* AudioSoundFont::GetPointer() {
|
SoundFont* AudioSoundFont::GetPointer() {
|
||||||
return &soundFont;
|
return &soundFont;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ class AudioSoundFont : public Ship::Resource<SoundFont> {
|
||||||
|
|
||||||
AudioSoundFont() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
AudioSoundFont() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
|
||||||
}
|
}
|
||||||
|
~AudioSoundFont();
|
||||||
|
|
||||||
SoundFont* GetPointer();
|
SoundFont* GetPointer();
|
||||||
size_t GetPointerSize();
|
size_t GetPointerSize();
|
||||||
|
@ -68,15 +69,10 @@ class AudioSoundFont : public Ship::Resource<SoundFont> {
|
||||||
uint16_t data2;
|
uint16_t data2;
|
||||||
uint16_t data3;
|
uint16_t data3;
|
||||||
|
|
||||||
std::vector<Drum> drums;
|
|
||||||
std::vector<Drum*> drumAddresses;
|
std::vector<Drum*> drumAddresses;
|
||||||
std::vector<uint32_t> drumEnvelopeCounts;
|
|
||||||
std::vector<std::vector<AdsrEnvelope>> drumEnvelopeArrays;
|
std::vector<std::vector<AdsrEnvelope>> drumEnvelopeArrays;
|
||||||
|
|
||||||
std::vector<Instrument> instruments;
|
|
||||||
std::vector<Instrument*> instrumentAddresses;
|
std::vector<Instrument*> instrumentAddresses;
|
||||||
std::vector<uint32_t> instrumentEnvelopeCounts;
|
|
||||||
std::vector<std::vector<AdsrEnvelope>> instrumentEnvelopeArrays;
|
|
||||||
|
|
||||||
std::vector<SoundFontSound> soundEffects;
|
std::vector<SoundFontSound> soundEffects;
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ void func_800DDE3C(void) {
|
||||||
void AudioHeap_ResetLoadStatus(void) {
|
void AudioHeap_ResetLoadStatus(void) {
|
||||||
s32 i;
|
s32 i;
|
||||||
|
|
||||||
for (i = 0; i < 0x30; i++) {
|
for (i = 0; i < fontMapSize; i++) {
|
||||||
if (gAudioContext.fontLoadStatus[i] != 5) {
|
if (gAudioContext.fontLoadStatus[i] != 5) {
|
||||||
gAudioContext.fontLoadStatus[i] = 0;
|
gAudioContext.fontLoadStatus[i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -940,7 +940,7 @@ void AudioHeap_Init(void) {
|
||||||
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
|
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
|
||||||
reverb->loop.start = 0;
|
reverb->loop.start = 0;
|
||||||
reverb->loop.count = 1;
|
reverb->loop.count = 1;
|
||||||
reverb->loop.end = reverb->windowSize;
|
reverb->loop.loopEnd = reverb->windowSize;
|
||||||
|
|
||||||
if (reverb->downsampleRate != 1) {
|
if (reverb->downsampleRate != 1) {
|
||||||
reverb->unk_0E = 0x8000 / reverb->downsampleRate;
|
reverb->unk_0E = 0x8000 / reverb->downsampleRate;
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include "soh/Enhancements/audio/AudioCollection.h"
|
#include "soh/Enhancements/audio/AudioCollection.h"
|
||||||
#include "soh/Enhancements/audio/AudioEditor.h"
|
#include "soh/Enhancements/audio/AudioEditor.h"
|
||||||
#include "soh/ResourceManagerHelpers.h"
|
#include "soh/ResourceManagerHelpers.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define strdup _strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status))
|
#define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status))
|
||||||
#define ASYNC_TBLTYPE(v) ((u8)(v >> 16))
|
#define ASYNC_TBLTYPE(v) ((u8)(v >> 16))
|
||||||
|
@ -82,7 +86,8 @@ char** sequenceMap;
|
||||||
size_t sequenceMapSize;
|
size_t sequenceMapSize;
|
||||||
// A map of authentic sequence IDs to their cache policies, for use with sequence swapping.
|
// A map of authentic sequence IDs to their cache policies, for use with sequence swapping.
|
||||||
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
|
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
|
||||||
char* fontMap[256];
|
size_t fontMapSize;
|
||||||
|
char** fontMap;
|
||||||
|
|
||||||
uintptr_t fontStart;
|
uintptr_t fontStart;
|
||||||
uint32_t fontOffsets[8192];
|
uint32_t fontOffsets[8192];
|
||||||
|
@ -419,7 +424,7 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 arg1) {
|
||||||
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
|
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
|
||||||
void* sampleAddr;
|
void* sampleAddr;
|
||||||
|
|
||||||
if (sample->unk_bit25 == 1) {
|
if (sample->isRelocated == 1) {
|
||||||
if (sample->medium != MEDIUM_RAM) {
|
if (sample->medium != MEDIUM_RAM) {
|
||||||
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
|
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
|
||||||
CACHE_PERSISTENT);
|
CACHE_PERSISTENT);
|
||||||
|
@ -701,7 +706,7 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
|
|
||||||
sampleBankId1 = sf->sampleBankId1;
|
sampleBankId1 = sf->sampleBankId1;
|
||||||
sampleBankId2 = sf->sampleBankId2;
|
sampleBankId2 = sf->sampleBankId2;
|
||||||
|
@ -759,7 +764,7 @@ uintptr_t AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
|
||||||
cachePolicy = sData.cachePolicy;
|
cachePolicy = sData.cachePolicy;
|
||||||
romAddr = 0;
|
romAddr = 0;
|
||||||
} else if (tableType == FONT_TABLE) {
|
} else if (tableType == FONT_TABLE) {
|
||||||
fnt = ResourceMgr_LoadAudioSoundFont(fontMap[id]);
|
fnt = ResourceMgr_LoadAudioSoundFontByName(fontMap[id]);
|
||||||
size = sizeof(SoundFont);
|
size = sizeof(SoundFont);
|
||||||
medium = 2;
|
medium = 2;
|
||||||
cachePolicy = 0;
|
cachePolicy = 0;
|
||||||
|
@ -887,6 +892,7 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo) {
|
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo) {
|
||||||
|
return;
|
||||||
uintptr_t reloc;
|
uintptr_t reloc;
|
||||||
uintptr_t reloc2;
|
uintptr_t reloc2;
|
||||||
Instrument* inst;
|
Instrument* inst;
|
||||||
|
@ -898,7 +904,7 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
|
||||||
s32 numInstruments = 0;
|
s32 numInstruments = 0;
|
||||||
s32 numSfx = 0;
|
s32 numSfx = 0;
|
||||||
|
|
||||||
sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
numDrums = sf->numDrums;
|
numDrums = sf->numDrums;
|
||||||
numInstruments = sf->numInstruments;
|
numInstruments = sf->numInstruments;
|
||||||
numSfx = sf->numSfx;
|
numSfx = sf->numSfx;
|
||||||
|
@ -1247,12 +1253,13 @@ int strcmp_sort(const void* str1, const void* str2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_Init(void* heap, size_t heapSize) {
|
void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
char pad[0x48];
|
s32 pad1[9];
|
||||||
s32 numFonts;
|
s32 numFonts;
|
||||||
void* temp_v0_3;
|
s32 pad2[2];
|
||||||
|
u8* audioCtxPtr;
|
||||||
|
void* addr;
|
||||||
s32 i;
|
s32 i;
|
||||||
u64* heapP;
|
s32 j;
|
||||||
s16* u2974p;
|
|
||||||
|
|
||||||
D_801755D0 = NULL;
|
D_801755D0 = NULL;
|
||||||
gAudioContext.resetTimer = 0;
|
gAudioContext.resetTimer = 0;
|
||||||
|
@ -1266,10 +1273,12 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
gAudioContext.unk_2960 = 20.03042f;
|
gAudioContext.unk_2960 = 20.03042f;
|
||||||
gAudioContext.refreshRate = 50;
|
gAudioContext.refreshRate = 50;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OS_TV_MPAL:
|
case OS_TV_MPAL:
|
||||||
gAudioContext.unk_2960 = 16.546f;
|
gAudioContext.unk_2960 = 16.546f;
|
||||||
gAudioContext.refreshRate = 60;
|
gAudioContext.refreshRate = 60;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OS_TV_NTSC:
|
case OS_TV_NTSC:
|
||||||
default:
|
default:
|
||||||
gAudioContext.unk_2960 = 16.713f;
|
gAudioContext.unk_2960 = 16.713f;
|
||||||
|
@ -1278,7 +1287,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
|
|
||||||
Audio_InitMesgQueues();
|
Audio_InitMesgQueues();
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) {
|
||||||
gAudioContext.aiBufLengths[i] = 0xA0;
|
gAudioContext.aiBufLengths[i] = 0xA0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,12 +1298,14 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
gAudioContext.currTask = NULL;
|
gAudioContext.currTask = NULL;
|
||||||
gAudioContext.rspTask[0].task.t.data_size = 0;
|
gAudioContext.rspTask[0].task.t.data_size = 0;
|
||||||
gAudioContext.rspTask[1].task.t.data_size = 0;
|
gAudioContext.rspTask[1].task.t.data_size = 0;
|
||||||
|
|
||||||
osCreateMesgQueue(&gAudioContext.syncDmaQueue, &gAudioContext.syncDmaMesg, 1);
|
osCreateMesgQueue(&gAudioContext.syncDmaQueue, &gAudioContext.syncDmaMesg, 1);
|
||||||
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf, 0x40);
|
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf,
|
||||||
|
ARRAY_COUNT(gAudioContext.currAudioFrameDmaMesgBuf));
|
||||||
osCreateMesgQueue(&gAudioContext.externalLoadQueue, gAudioContext.externalLoadMesgBuf,
|
osCreateMesgQueue(&gAudioContext.externalLoadQueue, gAudioContext.externalLoadMesgBuf,
|
||||||
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
|
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
|
||||||
osCreateMesgQueue(&gAudioContext.preloadSampleQueue, gAudioContext.preloadSampleMesgBuf,
|
osCreateMesgQueue(&gAudioContext.preloadSampleQueue, gAudioContext.preloadSampleMesgBuf,
|
||||||
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
|
ARRAY_COUNT(gAudioContext.preloadSampleMesgBuf));
|
||||||
gAudioContext.curAudioFrameDmaCount = 0;
|
gAudioContext.curAudioFrameDmaCount = 0;
|
||||||
gAudioContext.sampleDmaCount = 0;
|
gAudioContext.sampleDmaCount = 0;
|
||||||
gAudioContext.cartHandle = osCartRomInit();
|
gAudioContext.cartHandle = osCartRomInit();
|
||||||
|
@ -1304,20 +1315,24 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
gAudioContext.audioHeapSize = D_8014A6C4.heapSize;
|
gAudioContext.audioHeapSize = D_8014A6C4.heapSize;
|
||||||
} else {
|
} else {
|
||||||
void** hp = &heap;
|
void** hp = &heap;
|
||||||
|
|
||||||
gAudioContext.audioHeap = *hp;
|
gAudioContext.audioHeap = *hp;
|
||||||
gAudioContext.audioHeapSize = heapSize;
|
gAudioContext.audioHeapSize = heapSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < gAudioContext.audioHeapSize / 8; i++) {
|
for (i = 0; i < ((s32)gAudioContext.audioHeapSize / (s32)sizeof(u64)); i++) {
|
||||||
((u64*)gAudioContext.audioHeap)[i] = 0;
|
((u64*)gAudioContext.audioHeap)[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main Pool Split (split entirety of audio heap into initPool and sessionPool)
|
||||||
AudioHeap_InitMainPools(D_8014A6C4.initPoolSize);
|
AudioHeap_InitMainPools(D_8014A6C4.initPoolSize);
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
// Initialize the audio interface buffers
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBuffers); i++) {
|
||||||
gAudioContext.aiBuffers[i] = AudioHeap_AllocZeroed(&gAudioContext.audioInitPool, AIBUF_LEN * sizeof(s16));
|
gAudioContext.aiBuffers[i] = AudioHeap_AllocZeroed(&gAudioContext.audioInitPool, AIBUF_LEN * sizeof(s16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect audio tables to their tables in memory
|
||||||
// gAudioContext.sequenceTable = (AudioTable*)gSequenceTable;
|
// gAudioContext.sequenceTable = (AudioTable*)gSequenceTable;
|
||||||
// gAudioContext.soundFontTable = (AudioTable*)gSoundFontTable;
|
// gAudioContext.soundFontTable = (AudioTable*)gSoundFontTable;
|
||||||
// gAudioContext.sampleBankTable = (AudioTable*)gSampleBankTable;
|
// gAudioContext.sampleBankTable = (AudioTable*)gSampleBankTable;
|
||||||
|
@ -1325,31 +1340,60 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
// gAudioContext.numSequences = gAudioContext.sequenceTable->numEntries;
|
// gAudioContext.numSequences = gAudioContext.sequenceTable->numEntries;
|
||||||
|
|
||||||
gAudioContext.audioResetSpecIdToLoad = 0;
|
gAudioContext.audioResetSpecIdToLoad = 0;
|
||||||
gAudioContext.resetStatus = 1;
|
gAudioContext.resetStatus = 1; // Set reset to immediately initialize the audio heap
|
||||||
|
|
||||||
AudioHeap_ResetStep();
|
AudioHeap_ResetStep();
|
||||||
|
|
||||||
|
// Initialize audio tables
|
||||||
|
// AudioLoad_InitTable(gAudioContext.sequenceTable, SEGMENT_ROM_START(Audioseq), 0);
|
||||||
|
// AudioLoad_InitTable(gAudioContext.soundFontTable, SEGMENT_ROM_START(Audiobank), 0);
|
||||||
|
// AudioLoad_InitTable(gAudioContext.sampleBankTable, SEGMENT_ROM_START(Audiotable), 0);
|
||||||
|
|
||||||
|
// #region 2S2H [Port] Audio in the archive and custom sequences
|
||||||
|
// Only load the original sequences right now because custom songs may require data from sound fonts and samples
|
||||||
int seqListSize = 0;
|
int seqListSize = 0;
|
||||||
int customSeqListSize = 0;
|
int customSeqListSize = 0;
|
||||||
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
|
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
|
||||||
char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize);
|
char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize);
|
||||||
sequenceMapSize = (size_t)(AudioCollection_SequenceMapSize() + customSeqListSize);
|
sequenceMapSize = (size_t)(seqListSize + customSeqListSize);
|
||||||
sequenceMap = malloc(sequenceMapSize * sizeof(char*));
|
sequenceMap = malloc((sequenceMapSize + 0xF) * sizeof(char*));
|
||||||
gAudioContext.seqLoadStatus = malloc(sequenceMapSize * sizeof(char*));
|
|
||||||
|
|
||||||
|
gAudioContext.seqLoadStatus = malloc(sequenceMapSize);
|
||||||
|
memset(gAudioContext.seqLoadStatus, 5, sequenceMapSize);
|
||||||
for (size_t i = 0; i < seqListSize; i++) {
|
for (size_t i = 0; i < seqListSize; i++) {
|
||||||
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
|
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
|
||||||
|
sequenceMap[sDat.seqNumber] = strdup(seqList[i]);
|
||||||
char* str = malloc(strlen(seqList[i]) + 1);
|
|
||||||
strcpy(str, seqList[i]);
|
|
||||||
|
|
||||||
sequenceMap[sDat.seqNumber] = str;
|
|
||||||
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
|
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(seqList);
|
free(seqList);
|
||||||
|
|
||||||
int startingSeqNum = MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
|
// 2S2H [Streamed Audio] We need to load the custom songs after the fonts because streamed songs will use a hash to
|
||||||
|
// find its soundfont
|
||||||
|
int fntListSize = 0;
|
||||||
|
int customFntListSize = 0;
|
||||||
|
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
|
||||||
|
char** customFntList = ResourceMgr_ListFiles("custom/fonts/*", &customFntListSize);
|
||||||
|
|
||||||
|
gAudioContext.fontLoadStatus = malloc(customFntListSize + fntListSize);
|
||||||
|
fontMap = calloc(customFntListSize + fntListSize, sizeof(char*));
|
||||||
|
fontMapSize = customFntListSize + fntListSize;
|
||||||
|
for (int i = 0; i < fntListSize; i++) {
|
||||||
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fntList[i]);
|
||||||
|
fontMap[sf->fntIndex] = strdup(fntList[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fntList);
|
||||||
|
|
||||||
|
int customFontStart = fntListSize;
|
||||||
|
for (int i = customFontStart; i < customFntListSize + fntListSize; i++) {
|
||||||
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(customFntList[i - customFontStart]);
|
||||||
|
sf->fntIndex = i;
|
||||||
|
fontMap[i] = strdup(customFntList[i - customFontStart]);
|
||||||
|
}
|
||||||
|
free(customFntList);
|
||||||
|
|
||||||
|
// 2S2H Port I think we need to take use seqListSize because entry 0x7A is missing.
|
||||||
|
int startingSeqNum = seqListSize; // MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
|
||||||
qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort);
|
qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort);
|
||||||
|
|
||||||
// Because AudioCollection's sequenceMap actually has more than sequences (including instruments from 130-135 and
|
// Because AudioCollection's sequenceMap actually has more than sequences (including instruments from 130-135 and
|
||||||
|
@ -1361,48 +1405,61 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
|
||||||
|
|
||||||
for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) {
|
for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) {
|
||||||
// ensure that what would be the next sequence number is actually unassigned in AudioCollection
|
// ensure that what would be the next sequence number is actually unassigned in AudioCollection
|
||||||
|
int j = i - startingSeqNum;
|
||||||
|
SequenceData* sDat = ResourceMgr_LoadSeqPtrByName(customSeqList[j]);
|
||||||
|
|
||||||
|
if (sDat->numFonts == -1) {
|
||||||
|
uint64_t crc;
|
||||||
|
|
||||||
|
memcpy(&crc, sDat->fonts, sizeof(uint64_t));
|
||||||
|
const char* res = ResourceGetNameByCrc(crc);
|
||||||
|
if (res == NULL) {
|
||||||
|
// Passing a null buffer and length of 0 to snprintf will return the required numbers of characters the
|
||||||
|
// buffer needs to be.
|
||||||
|
int len =
|
||||||
|
snprintf(NULL, 0, "Could not find sound font for sequence %s. It will not be in the audio editor.",
|
||||||
|
customSeqList[j]);
|
||||||
|
char* error = malloc(len + 1);
|
||||||
|
snprintf(error, len, "Could not find sound font for sequence %s. It will not be in the audio editor.",
|
||||||
|
customSeqList[j]);
|
||||||
|
LUSLOG_ERROR("%s", error);
|
||||||
|
Messagebox_ShowErrorBox("Invalid Sequence", error);
|
||||||
|
free(error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(res);
|
||||||
|
memset(&sDat->fonts[0], 0, sizeof(sDat->fonts));
|
||||||
|
sDat->fonts[0] = sf->fntIndex;
|
||||||
|
sDat->numFonts = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (AudioCollection_HasSequenceNum(seqNum)) {
|
while (AudioCollection_HasSequenceNum(seqNum)) {
|
||||||
seqNum++;
|
seqNum++;
|
||||||
}
|
}
|
||||||
int j = i - startingSeqNum;
|
|
||||||
AudioCollection_AddToCollection(customSeqList[j], seqNum);
|
AudioCollection_AddToCollection(customSeqList[j], seqNum);
|
||||||
SequenceData sDat = ResourceMgr_LoadSeqByName(customSeqList[j]);
|
|
||||||
sDat.seqNumber = seqNum;
|
|
||||||
|
|
||||||
char* str = malloc(strlen(customSeqList[j]) + 1);
|
sDat->seqNumber = seqNum;
|
||||||
strcpy(str, customSeqList[j]);
|
printf("%d\n", seqNum);
|
||||||
|
sequenceMap[sDat->seqNumber] = strdup(customSeqList[j]);
|
||||||
sequenceMap[sDat.seqNumber] = str;
|
|
||||||
seqNum++;
|
seqNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(customSeqList);
|
free(customSeqList);
|
||||||
|
|
||||||
int fntListSize = 0;
|
|
||||||
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
|
|
||||||
|
|
||||||
for (int i = 0; i < fntListSize; i++) {
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fntList[i]);
|
|
||||||
|
|
||||||
char* str = malloc(strlen(fntList[i]) + 1);
|
|
||||||
strcpy(str, fntList[i]);
|
|
||||||
|
|
||||||
fontMap[sf->fntIndex] = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
numFonts = fntListSize;
|
numFonts = fntListSize;
|
||||||
|
|
||||||
free(fntList);
|
// #end region
|
||||||
gAudioContext.soundFonts = AudioHeap_Alloc(&gAudioContext.audioInitPool, numFonts * sizeof(SoundFont));
|
gAudioContext.soundFonts = AudioHeap_Alloc(&gAudioContext.audioInitPool, numFonts * sizeof(SoundFont));
|
||||||
|
|
||||||
if (temp_v0_3 = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), temp_v0_3 == NULL) {
|
if (addr = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), addr == NULL) {
|
||||||
// cast away const from D_8014A6C4
|
// cast away const from D_8014A6C4
|
||||||
// *((u32*)&D_8014A6C4.permanentPoolSize) = 0;
|
*((u32*)&D_8014A6C4.permanentPoolSize) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, temp_v0_3, D_8014A6C4.permanentPoolSize);
|
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, addr, D_8014A6C4.permanentPoolSize);
|
||||||
gAudioContextInitalized = true;
|
gAudioContextInitalized = true;
|
||||||
osSendMesg32(gAudioContext.taskStartQueueP, gAudioContext.totalTaskCnt, OS_MESG_NOBLOCK);
|
osSendMesg(gAudioContext.taskStartQueueP, OS_MESG_32(gAudioContext.totalTaskCnt), OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_InitSlowLoads(void) {
|
void AudioLoad_InitSlowLoads(void) {
|
||||||
|
@ -2059,7 +2116,7 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
|
||||||
|
|
||||||
gAudioContext.numUsedSamples = 0;
|
gAudioContext.numUsedSamples = 0;
|
||||||
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
|
|
||||||
numDrums = sf->numDrums;
|
numDrums = sf->numDrums;
|
||||||
numInstruments = sf->numInstruments;
|
numInstruments = sf->numInstruments;
|
||||||
|
@ -2188,7 +2245,7 @@ void AudioLoad_LoadPermanentSamples(void) {
|
||||||
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioContext.permanentCache[i].id);
|
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioContext.permanentCache[i].id);
|
||||||
// fontId = gAudioContext.permanentCache[i].id;
|
// fontId = gAudioContext.permanentCache[i].id;
|
||||||
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
relocInfo.sampleBankId1 = sf->sampleBankId1;
|
relocInfo.sampleBankId1 = sf->sampleBankId1;
|
||||||
relocInfo.sampleBankId2 = sf->sampleBankId2;
|
relocInfo.sampleBankId2 = sf->sampleBankId2;
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,7 @@ void Audio_NoteInit(Note* note) {
|
||||||
note->noteSubEu = gDefaultNoteSub;
|
note->noteSubEu = gDefaultNoteSub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void aOPUSFree(struct OggOpusFile* opusFile);
|
||||||
void Audio_NoteDisable(Note* note) {
|
void Audio_NoteDisable(Note* note) {
|
||||||
if (note->noteSubEu.bitField0.needsInit == true) {
|
if (note->noteSubEu.bitField0.needsInit == true) {
|
||||||
note->noteSubEu.bitField0.needsInit = false;
|
note->noteSubEu.bitField0.needsInit = false;
|
||||||
|
@ -159,6 +160,10 @@ void Audio_NoteDisable(Note* note) {
|
||||||
note->playbackState.prevParentLayer = NO_LAYER;
|
note->playbackState.prevParentLayer = NO_LAYER;
|
||||||
note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED;
|
note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED;
|
||||||
note->playbackState.adsr.current = 0;
|
note->playbackState.adsr.current = 0;
|
||||||
|
if (note->synthesisState.opusFile != NULL) {
|
||||||
|
aOPUSFree(note->synthesisState.opusFile);
|
||||||
|
note->synthesisState.opusFile = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio_ProcessNotes(void) {
|
void Audio_ProcessNotes(void) {
|
||||||
|
@ -293,13 +298,6 @@ void Audio_ProcessNotes(void) {
|
||||||
|
|
||||||
f32 resampRate = gAudioContext.audioBufferParameters.resampleRate;
|
f32 resampRate = gAudioContext.audioBufferParameters.resampleRate;
|
||||||
|
|
||||||
// CUSTOM SAMPLE CHECK
|
|
||||||
if (!noteSubEu2->bitField1.isSyntheticWave && noteSubEu2->sound.soundFontSound != NULL &&
|
|
||||||
noteSubEu2->sound.soundFontSound->sample != NULL &&
|
|
||||||
noteSubEu2->sound.soundFontSound->sample->sampleRateMagicValue == 'RIFF') {
|
|
||||||
resampRate = CALC_RESAMPLE_FREQ(noteSubEu2->sound.soundFontSound->sample->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
subAttrs.frequency *= resampRate;
|
subAttrs.frequency *= resampRate;
|
||||||
|
|
||||||
subAttrs.velocity *= scale;
|
subAttrs.velocity *= scale;
|
||||||
|
@ -335,7 +333,7 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int instCnt = 0;
|
int instCnt = 0;
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
|
|
||||||
if (instId >= sf->numInstruments)
|
if (instId >= sf->numInstruments)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -362,7 +360,7 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
if (drumId < sf->numDrums) {
|
if (drumId < sf->numDrums) {
|
||||||
drum = sf->drums[drumId];
|
drum = sf->drums[drumId];
|
||||||
}
|
}
|
||||||
|
@ -386,7 +384,7 @@ SoundFontSound* Audio_GetSfx(s32 fontId, s32 sfxId) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
|
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
|
||||||
if (sfxId < sf->numSfx) {
|
if (sfxId < sf->numSfx) {
|
||||||
sfx = &sf->soundEffects[sfxId];
|
sfx = &sf->soundEffects[sfxId];
|
||||||
}
|
}
|
||||||
|
|
|
@ -789,7 +789,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd) {
|
||||||
layer->freqScale *= layer->unk_34;
|
layer->freqScale *= layer->unk_34;
|
||||||
if (layer->delay == 0) {
|
if (layer->delay == 0) {
|
||||||
if (layer->sound != NULL) {
|
if (layer->sound != NULL) {
|
||||||
time = (f32)layer->sound->sample->loop->end;
|
time = (f32)layer->sound->sample->loop->loopEnd;
|
||||||
} else {
|
} else {
|
||||||
time = 0.0f;
|
time = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -761,7 +761,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
audioFontSample = noteSubEu->sound.soundFontSound->sample;
|
audioFontSample = noteSubEu->sound.soundFontSound->sample;
|
||||||
|
|
||||||
loopInfo = audioFontSample->loop;
|
loopInfo = audioFontSample->loop;
|
||||||
loopEndPos = loopInfo->end;
|
loopEndPos = loopInfo->loopEnd;
|
||||||
sampleAddr = audioFontSample->sampleAddr;
|
sampleAddr = audioFontSample->sampleAddr;
|
||||||
resampledTempLen = 0;
|
resampledTempLen = 0;
|
||||||
|
|
||||||
|
@ -853,14 +853,27 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
s5 = samplesLenAdjusted;
|
s5 = samplesLenAdjusted;
|
||||||
goto skip;
|
goto skip;
|
||||||
case CODEC_S16:
|
case CODEC_S16:
|
||||||
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted * 2) + 0x20);
|
case CODEC_OPUS:
|
||||||
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2),
|
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted + 16) * 2);
|
||||||
audioFontSample->sampleAddr + (synthState->samplePosInt * 2));
|
|
||||||
|
|
||||||
flags = A_CONTINUE;
|
flags = A_CONTINUE;
|
||||||
skipBytes = 0;
|
skipBytes = 0;
|
||||||
nSamplesProcessed = samplesLenAdjusted;
|
size_t bytesToRead;
|
||||||
s5 = samplesLenAdjusted;
|
nSamplesProcessed += samplesLenAdjusted;
|
||||||
|
|
||||||
|
if (((synthState->samplePosInt * 2) + (samplesLenAdjusted)*2) < audioFontSample->size) {
|
||||||
|
bytesToRead = (samplesLenAdjusted)*2;
|
||||||
|
} else {
|
||||||
|
bytesToRead = audioFontSample->size - (synthState->samplePosInt * 2);
|
||||||
|
}
|
||||||
|
// 2S2H [Port] [Custom audio] Handle decoding OPUS data
|
||||||
|
if (audioFontSample->codec == CODEC_OPUS) {
|
||||||
|
aOPUSdecImpl(sampleAddr, DMEM_UNCOMPRESSED_NOTE, bytesToRead, &synthState->opusFile,
|
||||||
|
synthState->samplePosInt, audioFontSample->fileSize);
|
||||||
|
} else {
|
||||||
|
aLoadBuffer(cmd++, sampleAddr + (synthState->samplePosInt * 2), DMEM_UNCOMPRESSED_NOTE,
|
||||||
|
bytesToRead);
|
||||||
|
}
|
||||||
|
|
||||||
goto skip;
|
goto skip;
|
||||||
case CODEC_REVERB:
|
case CODEC_REVERB:
|
||||||
break;
|
break;
|
||||||
|
@ -886,6 +899,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
sampleDataStartPad = (uintptr_t)sampleData & 0xF;
|
sampleDataStartPad = (uintptr_t)sampleData & 0xF;
|
||||||
aligned = ALIGN16((nFramesToDecode * frameSize) + 16);
|
aligned = ALIGN16((nFramesToDecode * frameSize) + 16);
|
||||||
addr = DMEM_COMPRESSED_ADPCM_DATA - aligned;
|
addr = DMEM_COMPRESSED_ADPCM_DATA - aligned;
|
||||||
|
|
||||||
aLoadBuffer(cmd++, sampleData - sampleDataStartPad, addr, aligned);
|
aLoadBuffer(cmd++, sampleData - sampleDataStartPad, addr, aligned);
|
||||||
} else {
|
} else {
|
||||||
nSamplesToDecode = 0;
|
nSamplesToDecode = 0;
|
||||||
|
@ -893,7 +907,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (synthState->restart) {
|
if (synthState->restart) {
|
||||||
aSetLoop(cmd++, audioFontSample->loop->state);
|
aSetLoop(cmd++, audioFontSample->loop->predictorState);
|
||||||
flags = A_LOOP;
|
flags = A_LOOP;
|
||||||
synthState->restart = false;
|
synthState->restart = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,7 +792,7 @@ s32 func_800E6590(s32 playerIdx, s32 arg1, s32 arg2) {
|
||||||
if (sound == NULL) {
|
if (sound == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
loopEnd = sound->sample->loop->end;
|
loopEnd = sound->sample->loop->loopEnd;
|
||||||
samplePos = note->synthesisState.samplePosInt;
|
samplePos = note->synthesisState.samplePosInt;
|
||||||
return loopEnd - samplePos;
|
return loopEnd - samplePos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,6 @@ typedef struct EnElf {
|
||||||
/* 0x02C7 */ u8 unk_2C7;
|
/* 0x02C7 */ u8 unk_2C7;
|
||||||
/* 0x02C8 */ EnElfUnkFunc func_2C8;
|
/* 0x02C8 */ EnElfUnkFunc func_2C8;
|
||||||
/* 0x02CC */ EnElfActionFunc actionFunc;
|
/* 0x02CC */ EnElfActionFunc actionFunc;
|
||||||
// #region SOH [Randomizer]
|
|
||||||
/* */ FairyIdentity sohFairyIdentity;
|
|
||||||
// #endregion
|
|
||||||
} EnElf; // size = 0x02D0
|
} EnElf; // size = 0x02D0
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -20,7 +20,6 @@ typedef struct EnKusa {
|
||||||
/* 0x0150 */ ColliderCylinder collider;
|
/* 0x0150 */ ColliderCylinder collider;
|
||||||
/* 0x019C */ s16 timer;
|
/* 0x019C */ s16 timer;
|
||||||
/* 0x019E */ s8 objBankIndex;
|
/* 0x019E */ s8 objBankIndex;
|
||||||
/* */ GrassIdentity grassIdentity;
|
|
||||||
} EnKusa; // size = 0x01A0
|
} EnKusa; // size = 0x01A0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,7 +15,6 @@ typedef struct ObjComb {
|
||||||
/* 0x0170 */ ColliderJntSphElement colliderItems[1];
|
/* 0x0170 */ ColliderJntSphElement colliderItems[1];
|
||||||
/* 0x01B0 */ s16 unk_1B0;
|
/* 0x01B0 */ s16 unk_1B0;
|
||||||
/* 0x01B2 */ s16 unk_1B2;
|
/* 0x01B2 */ s16 unk_1B2;
|
||||||
/* */ BeehiveIdentity beehiveIdentity;
|
|
||||||
} ObjComb; // size = 0x01B4
|
} ObjComb; // size = 0x01B4
|
||||||
|
|
||||||
void ObjComb_Break(ObjComb* objComb, PlayState* play);
|
void ObjComb_Break(ObjComb* objComb, PlayState* play);
|
||||||
|
|
|
@ -12,7 +12,6 @@ typedef struct ObjKibako {
|
||||||
/* 0x0000 */ Actor actor;
|
/* 0x0000 */ Actor actor;
|
||||||
/* 0x014C */ ObjKibakoActionFunc actionFunc;
|
/* 0x014C */ ObjKibakoActionFunc actionFunc;
|
||||||
/* 0x0150 */ ColliderCylinder collider;
|
/* 0x0150 */ ColliderCylinder collider;
|
||||||
/* */ SmallCrateIdentity smallCrateIdentity;
|
|
||||||
} ObjKibako; // size = 0x019C
|
} ObjKibako; // size = 0x019C
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,6 @@ typedef struct ObjKibako2 {
|
||||||
/* 0x0164 */ ColliderCylinder collider;
|
/* 0x0164 */ ColliderCylinder collider;
|
||||||
/* 0x01B0 */ ObjKibako2ActionFunc actionFunc;
|
/* 0x01B0 */ ObjKibako2ActionFunc actionFunc;
|
||||||
/* 0x01B4 */ s16 collectibleFlag;
|
/* 0x01B4 */ s16 collectibleFlag;
|
||||||
/* */ CrateIdentity crateIdentity;
|
|
||||||
} ObjKibako2; // size = 0x01B8
|
} ObjKibako2; // size = 0x01B8
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,6 @@ typedef struct ObjTsubo {
|
||||||
/* 0x014C */ ObjTsuboActionFunc actionFunc;
|
/* 0x014C */ ObjTsuboActionFunc actionFunc;
|
||||||
/* 0x0150 */ ColliderCylinder collider;
|
/* 0x0150 */ ColliderCylinder collider;
|
||||||
/* 0x019C */ s8 objTsuboBankIndex;
|
/* 0x019C */ s8 objTsuboBankIndex;
|
||||||
/* */ PotIdentity potIdentity;
|
|
||||||
} ObjTsubo; // size = 0x01A0
|
} ObjTsubo; // size = 0x01A0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue