Merge remote-tracking branch 'origin/develop' into actor-accessibility-experiments

This commit is contained in:
Demur Rumed 2025-06-28 13:47:05 +00:00
commit 8b252a5c85
87 changed files with 10232 additions and 20950 deletions

View file

@ -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

View file

@ -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
View 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
View 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
View 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
View 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)

View file

@ -83,8 +83,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(VCPKG_TARGET_TRIPLET x64-windows-static)
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")
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
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)
set(GBI_UCODE F3DEX_GBI_2)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
################################################################################
# Set CONTROLLERBUTTONS_T

View file

@ -288,8 +288,17 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
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)
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
@ -308,6 +317,10 @@ if (ESPEAK)
add_compile_definitions(ESPEAK=1)
endif()
################################################################################
# Compile definitions
################################################################################
target_include_directories(${PROJECT_NAME} PRIVATE assets
${CMAKE_CURRENT_SOURCE_DIR}/include/
${CMAKE_CURRENT_SOURCE_DIR}/src/
@ -340,6 +353,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
${SDL2-INCLUDE}
${SDL2-NET-INCLUDE}
${CMAKE_CURRENT_SOURCE_DIR}/assets/
${dr_libs_SOURCE_DIR}
.
)
@ -591,6 +605,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_link_options(${PROJECT_NAME} PRIVATE
-pthread
#-fsanitize=address
-Wl,-export-dynamic
)
endif()
@ -631,6 +646,15 @@ endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
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")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
@ -644,6 +668,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"imm32;"
"version;"
"setupapi"
"Ogg::ogg"
"Opus::opus"
"Vorbis::vorbis"
"Vorbis::vorbisenc"
"Vorbis::vorbisfile"
"OpusFile::opusfile"
)
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
@ -684,10 +714,21 @@ else()
find_package(SDL2)
set(THREADS_PREFER_PTHREAD_FLAG ON)
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
"libultraship;"
"ZAPDLib;"
SDL2::SDL2
"Ogg::ogg"
"Vorbis::vorbis"
"Vorbis::vorbisenc"
"Vorbis::vorbisfile"
"Opus::opus"
"Opusfile::Opusfile"
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
${CMAKE_DL_LIBS}
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

View file

@ -1,6 +1,10 @@
#ifndef Z64_AUDIO_H
#define Z64_AUDIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <endianness.h>
#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
extern size_t sequenceMapSize;
extern char* fontMap[256];
extern size_t fontMapSize;
extern char** fontMap;
#define MAX_AUTHENTIC_SEQID 110
@ -54,7 +58,8 @@ typedef enum {
/* 2 */ CODEC_S16_INMEMORY,
/* 3 */ CODEC_SMALL_ADPCM,
/* 4 */ CODEC_REVERB,
/* 5 */ CODEC_S16
/* 5 */ CODEC_S16,
/* 6 */ CODEC_OPUS,
} SampleCodec;
typedef enum {
@ -117,13 +122,14 @@ typedef struct {
/* 0x2 */ s16 arg;
} AdsrEnvelope; // size = 0x4
typedef struct {
/* 0x00 */ uintptr_t start;
/* 0x04 */ uintptr_t end;
/* 0x08 */ u32 count;
/* 0x0C */ char unk_0C[0x4];
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
} AdpcmLoop; // size = 0x30 (or 0x10)
typedef struct AdpcmLoop {
/* 0x00 */ u32 start;
/* 0x04 */ u32 loopEnd; // numSamples position into the sample where the loop ends
/* 0x08 */ u32 count; // The number of times the loop is played before the sound completes. Setting count to -1
// indicates that the loop should play indefinitely.
/* 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)
typedef struct {
/* 0x00 */ s32 order;
@ -131,24 +137,23 @@ typedef struct {
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
} AdpcmBook; // size >= 0x8
typedef struct
{
typedef struct SoundFontSample {
union {
struct {
/* 0x00 */ u32 codec : 4;
/* 0x00 */ u32 medium : 2;
/* 0x00 */ u32 unk_bit26 : 1;
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
/* 0x01 */ u32 size : 24;
///* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
};
u32 asU32;
};
/* 0x04 */ u8* sampleAddr;
/* 0x08 */ AdpcmLoop* loop;
/* 0x0C */ AdpcmBook* book;
u32 sampleRateMagicValue; // For wav samples only...
s32 sampleRate; // For wav samples only...
/* 0x1 */ u32 size; // Size of the sample
u32 fileSize;
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either rom or ram
/* 0x8 */ AdpcmLoop* 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
} SoundFontSample; // size = 0x10
typedef struct {
@ -465,6 +470,8 @@ typedef struct {
/* 0x00F0 */ s16 dummyResampleState[0x10];
} NoteSynthesisBuffers; // size = 0x110
struct OggOpusFile;
typedef struct {
/* 0x00 */ u8 restart;
/* 0x01 */ u8 sampleDmaIndex;
@ -483,6 +490,7 @@ typedef struct {
/* 0x1A */ u8 unk_1A;
/* 0x1C */ u16 unk_1C;
/* 0x1E */ u16 unk_1E;
struct OggOpusFile* opusFile; // Only for streamed opus audio
} NoteSynthesisState; // size = 0x20
typedef struct {
@ -917,7 +925,7 @@ typedef struct {
/* 0x3420 */ AudioPoolSplit3 persistentCommonPoolSplit;
/* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit;
/* 0x3438 */ u8 sampleFontLoadStatus[0x30];
/* 0x3468 */ u8 fontLoadStatus[0x30];
/* 0x3468 */ u8* fontLoadStatus;
/* 0x3498 */ u8* seqLoadStatus;
/* 0x3518 */ volatile u8 resetStatus;
/* 0x3519 */ u8 audioResetSpecIdToLoad;
@ -1119,10 +1127,6 @@ typedef struct {
uint8_t fonts[16];
} SequenceData;
#ifdef __cplusplus
extern "C" {
#endif
void Audio_SetGameVolume(int player_id, f32 volume);
float Audio_GetGameVolume(int player_id);

View file

@ -1,6 +1,5 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
#include "soh/Enhancements/randomizer/context.h"
extern "C" {
extern PlayState* gPlayState;

View file

@ -512,10 +512,10 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
/*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]]#.
hintTextTable[RHT_GF_GERUDO_MEMBERSHIP_CARD] = 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.",
/*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]]#.
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.",
/*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]]#.
hintTextTable[RHT_WASTELAND_BOMBCHU_SALESMAN] = HintText(CustomMessage("They say that a #carpet guru# sells #[[1]]#.",
/*german*/ "Man erzählt sich, daß ein #fliegender Einsiedler# #[[1]]# verkaufe.",
@ -622,25 +622,25 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
/*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]]#.
hintTextTable[RHT_GF_NORTH_F1_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
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.",//TODO_TRANSLATE update to match
/*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]]#.
hintTextTable[RHT_GF_NORTH_F2_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
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.",//TODO_TRANSLATE update to match
/*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]]#.
hintTextTable[RHT_GF_SOUTH_F1_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[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.",//TODO_TRANSLATE update to match
/*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]]#.
hintTextTable[RHT_GF_SOUTH_F2_CARPENTER] = HintText(CustomMessage("They say that #defeating Gerudo guards# reveals #[[1]]#.",
/*german*/ "Man erzählt sich, daß das #Besiegen der Gerudo-Wachen# #[[1]]# enthüllen würde.",
/*french*/ "Selon moi, les #geôliers Gerudo# détiennent #[[1]]#.", {QM_RED, QM_GREEN}));
// /*spanish*/ Según dicen, #derrotar a las guardas Gerudo# revela #[[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.",//TODO_TRANSLATE update to match
/*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]]#.
hintTextTable[RHT_HF_GS_NEAR_KAK_GROTTO] = HintText(CustomMessage("They say that a #spider-guarded spider in a hole# hoards #[[1]]#.",
/*german*/ "Man erzählt sich, daß eine #spinnenbewachte Spinne in einem Erdloch #[[1]]# horte.",
@ -1496,9 +1496,37 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
/*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}));
hintTextTable[RHT_POT_GERUDO_FORTRESS] = HintText(CustomMessage("They say that a #pot in Gerudo Fortress# contains #[[1]]#.",
/*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_FRONT_POT] = HintText(CustomMessage("They say that the #front pot watched by resting thieves# contains #[[1]]#.", {QM_RED, QM_GREEN}));//TODO_TRANSLATE
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]]#.",
/*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.",
/*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.",
/*french*/ "Selon moi, #appeler le soleil dans une cuisine gardée# révèle #[[1]]#.", {QM_RED, QM_GREEN}));

View file

@ -811,16 +811,16 @@ void GenerateItemPool() {
// Gerudo Fortress
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_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_1_TORCH_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_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)) {
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
AddItemToMainPool(RG_GERUDO_FORTRESS_SMALL_KEY);
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
} else {
// Only add key ring if 4 Fortress keys necessary
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS) && ctx->GetOption(RSK_KEYRINGS)) {
@ -843,15 +843,15 @@ void GenerateItemPool() {
}
} else {
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_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_1_TORCH_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
ctx->PlaceItemInLocation(RC_TH_DEAD_END_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
} else {
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_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_GF_SOUTH_F1_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_1_TORCH_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_TH_DOUBLE_CELL_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);
} else if (ctx->GetOption(RSK_SHUFFLE_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 {
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

View file

@ -1,5 +1,6 @@
#include <soh/OTRGlobals.h>
#include "static_data.h"
#include "soh/ObjectExtension/ObjectExtension.h"
extern "C" {
#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) {
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);
item00->randoInf = objComb->beehiveIdentity.randomizerInf;
item00->randoInf = beehiveIdentity->randomizerInf;
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;
return;
}
@ -37,10 +40,11 @@ void ObjComb_RandomizerChooseItemDrop(ObjComb* objComb, PlayState* play) {
}
void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
s32 dmgFlags;
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) {
objComb->unk_1B0 = 1500;
}
@ -50,7 +54,7 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
if ((objComb->collider.base.acFlags & AC_HIT) != 0) {
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) {
objComb->unk_1B0 = 1500;
} else {
@ -70,8 +74,9 @@ void ObjComb_RandomizerWait(ObjComb* objComb, PlayState* play) {
void ObjComb_RandomizerInit(void* actor) {
ObjComb* objComb = static_cast<ObjComb*>(actor);
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);
ObjectExtension::GetInstance().Set<BeehiveIdentity>(actor, std::move(beehiveIdentity));
objComb->actionFunc = (ObjCombActionFunc)ObjComb_RandomizerWait;
}
@ -132,4 +137,5 @@ void Rando::StaticData::RegisterBeehiveLocations() {
// clang-format-on
}
static ObjectExtension::Register<BeehiveIdentity> RegisterBeehiveIdentity;
static RegisterShipInitFunc registerFunc(Rando::StaticData::RegisterBeehiveLocations);

View file

@ -1,9 +1,10 @@
#include "ShuffleCrates.h"
#include <soh/OTRGlobals.h>
#include "soh_assets.h"
#include "static_data.h"
#include <libultraship/libultra.h>
#include "global.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/ObjectExtension/ObjectExtension.h"
extern "C" {
#include "variables.h"
@ -31,8 +32,14 @@ extern "C" void ObjKibako2_RandomizerDraw(Actor* thisx, PlayState* play) {
return;
}
const auto crateIdentity = ObjectExtension::GetInstance().Get<CrateIdentity>(thisx);
if (crateIdentity == nullptr) {
Gfx_DrawDListOpa(play, (Gfx*)gLargeRandoCrateDL);
return;
}
GetItemEntry crateItem =
Rando::Context::GetInstance()->GetFinalGIEntry(crateActor->crateIdentity.randomizerCheck, true, GI_NONE);
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
getItemCategory = crateItem.getItemCategory;
// 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;
}
GetItemEntry smallCrateItem = Rando::Context::GetInstance()->GetFinalGIEntry(
smallCrateActor->smallCrateIdentity.randomizerCheck, true, GI_NONE);
const auto crateIdentity = ObjectExtension::GetInstance().Get<SmallCrateIdentity>(thisx);
if (crateIdentity == nullptr) {
Gfx_DrawDListOpa(play, (Gfx*)gSmallRandoCrateDL);
return;
}
GetItemEntry smallCrateItem =
Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
getItemCategory = smallCrateItem.getItemCategory;
// 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) {
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 crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
// Don't pull randomized item if crate isn't randomized or is already checked
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
Flags_GetRandomizerInf(crateActor->crateIdentity.randomizerInf) ||
crateActor->crateIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
Flags_GetRandomizerInf(crateIdentity->randomizerInf) || crateIdentity->randomizerCheck == RC_UNKNOWN_CHECK) {
return false;
} else {
return true;
@ -170,15 +187,19 @@ uint8_t ObjKibako2_RandomizerHoldsItem(ObjKibako2* crateActor, 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 crateSetting = RAND_GET_OPTION(RSK_SHUFFLE_CRATES);
// Don't pull randomized item if crate isn't randomized or is already checked
if (!IS_RANDO || (crateSetting == RO_SHUFFLE_CRATES_OVERWORLD && isDungeon) ||
(crateSetting == RO_SHUFFLE_CRATES_DUNGEONS && !isDungeon) ||
Flags_GetRandomizerInf(smallCrateActor->smallCrateIdentity.randomizerInf) ||
smallCrateActor->smallCrateIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
Flags_GetRandomizerInf(crateIdentity->randomizerInf) || crateIdentity->randomizerCheck == RC_UNKNOWN_CHECK) {
return false;
} else {
return true;
@ -186,10 +207,14 @@ uint8_t ObjKibako_RandomizerHoldsItem(ObjKibako* smallCrateActor, PlayState* pla
}
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);
item00->randoInf = crateActor->crateIdentity.randomizerInf;
item00->itemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(crateActor->crateIdentity.randomizerCheck, true, GI_NONE);
item00->randoInf = crateIdentity->randomizerInf;
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
@ -197,10 +222,14 @@ void ObjKibako2_RandomizerSpawnCollectible(ObjKibako2* crateActor, PlayState* pl
}
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);
item00->randoInf = smallCrateActor->smallCrateIdentity.randomizerInf;
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(
smallCrateActor->smallCrateIdentity.randomizerCheck, true, GI_NONE);
item00->randoInf = crateIdentity->randomizerInf;
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(crateIdentity->randomizerCheck, true, GI_NONE);
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
@ -231,8 +260,9 @@ void ObjKibako2_RandomizerInit(void* actorRef) {
ObjKibako2* crateActor = static_cast<ObjKibako2*>(actorRef);
crateActor->crateIdentity = OTRGlobals::Instance->gRandomizer->IdentifyCrate(
gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z);
auto crateIdentity = OTRGlobals::Instance->gRandomizer->IdentifyCrate(gPlayState->sceneNum, (s16)actor->world.pos.x,
(s16)actor->world.pos.z);
ObjectExtension::GetInstance().Set<CrateIdentity>(actor, std::move(crateIdentity));
}
void ObjKibako_RandomizerInit(void* actorRef) {
@ -243,8 +273,9 @@ void ObjKibako_RandomizerInit(void* 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);
ObjectExtension::GetInstance().Set<SmallCrateIdentity>(actor, std::move(crateIdentity));
}
void RegisterShuffleCrates() {
@ -298,271 +329,273 @@ void Rando::StaticData::RegisterCrateLocations() {
registered = true;
// clang-format off
// Overworld Crates
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
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_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_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_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_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[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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_3] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_3, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3026, 2631), "After Quicksand Crate 3", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_3));
locationTable[RC_HW_NEAR_COLOSSUS_CRATE] = Location::Crate(RC_HW_NEAR_COLOSSUS_CRATE, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(-1531, -976), "Near Colossus Crate", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_NEAR_COLOSSUS_CRATE));
locationTable[RC_MK_NEAR_BAZAAR_CRATE_1] = Location::Crate(RC_MK_NEAR_BAZAAR_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(490, 338), "Near Bazaar Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_NEAR_BAZAAR_CRATE_1));
locationTable[RC_MK_NEAR_BAZAAR_CRATE_2] = Location::Crate(RC_MK_NEAR_BAZAAR_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(490, 132), "Near Bazaar Crate 2", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_NEAR_BAZAAR_CRATE_2));
locationTable[RC_MK_SHOOTING_GALLERY_CRATE_1] = Location::Crate(RC_MK_SHOOTING_GALLERY_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(-150, -576), "Shooting Gallery Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_SHOOTING_GALLERY_CRATE_1));
locationTable[RC_MK_SHOOTING_GALLERY_CRATE_2] = Location::Crate(RC_MK_SHOOTING_GALLERY_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(-90, -576), "Shooting Gallery Crate 2", RHT_CRATE_MARKET, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_SHOOTING_GALLERY_CRATE_2));
locationTable[RC_MK_LOST_DOG_HOUSE_CRATE] = Location::Crate(RC_MK_LOST_DOG_HOUSE_CRATE, RCQUEST_BOTH, RCAREA_MARKET, SCENE_DOG_LADY_HOUSE, TWO_ACTOR_PARAMS(176, 170), "Lost Dog House Crate", RHT_CRATE_MARKET, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_LOST_DOG_HOUSE_CRATE));
locationTable[RC_MK_GUARD_HOUSE_CRATE_1] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(76, -210), "Guard House Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_1));
locationTable[RC_MK_GUARD_HOUSE_CRATE_2] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(28, -210), "Guard House Crate 2", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_2));
locationTable[RC_MK_GUARD_HOUSE_CRATE_3] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_3, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 120), "Guard House Crate 3", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_3));
locationTable[RC_MK_GUARD_HOUSE_CRATE_4] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_4, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 168), "Guard House Crate 4", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_4));
locationTable[RC_MK_GUARD_HOUSE_CRATE_5] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_5, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 216), "Guard House Crate 5", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_5));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1039, 10), "Near Open Grotto Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1099, 10), "Near Open Grotto Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(506, -358), "Near Open Grotto Adult Crate 3", RHT_CRATE_KAKARIKO_VILLAGE, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(483, -302), "Near Open Grotto Adult Crate 4", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4));
locationTable[RC_KAK_NEAR_POTION_SHOP_ADULT_CRATE] = Location::Crate(RC_KAK_NEAR_POTION_SHOP_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(186, -758), "Near Potion Shop Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_POTION_SHOP_ADULT_CRATE));
locationTable[RC_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE] = Location::Crate(RC_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(185, 776), "Near Shooting Gallery Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(92, 348), "Near Boarding House Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(32, 348), "Near Boarding House Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-389, 1518), "Near Impas House Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-389, 1470), "Near Impas House Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_BAZAAR_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_BAZAAR_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-433, -401), "Near Bazaar Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_BAZAAR_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_BAZAAR_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-489, -424), "Near Bazaar Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_ADULT_CRATE_2));
locationTable[RC_KAK_BEHIND_GS_HOUSE_ADULT_CRATE] = Location::Crate(RC_KAK_BEHIND_GS_HOUSE_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-724, 871), "Behind GS House Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_BEHIND_GS_HOUSE_ADULT_CRATE));
locationTable[RC_KAK_NEAR_GY_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_GY_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1732, 1366), "Near Graveyard Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_GY_CHILD_CRATE));
locationTable[RC_KAK_NEAR_WINDMILL_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_WINDMILL_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1170, 601), "Near Windmill Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_WINDMILL_CHILD_CRATE));
locationTable[RC_KAK_NEAR_FENCE_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_FENCE_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1170, 111), "Near Fence Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_FENCE_CHILD_CRATE));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-60, -46), "Near Boarding House Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE));
locationTable[RC_KAK_NEAR_BAZAAR_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_BAZAAR_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-636, -478), "Near Bazaar Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_CHILD_CRATE));
locationTable[RC_GRAVEYARD_CRATE] = Location::Crate(RC_GRAVEYARD_CRATE, RCQUEST_BOTH, RCAREA_GRAVEYARD, SCENE_GRAVEYARD, TWO_ACTOR_PARAMS(-1050, -350), "Freestanding PoH Crate", RHT_CRATE_GRAVEYARD, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GRAVEYARD_CRATE));
locationTable[RC_GC_MAZE_CRATE] = Location::Crate(RC_GC_MAZE_CRATE, RCQUEST_BOTH, RCAREA_GORON_CITY, SCENE_GORON_CITY, TWO_ACTOR_PARAMS(-1124, -1339), "Maze Crate", RHT_CRATE_GORON_CITY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GC_MAZE_CRATE));
locationTable[RC_DMC_CRATE] = Location::Crate(RC_DMC_CRATE, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_CRATER, SCENE_DEATH_MOUNTAIN_CRATER, TWO_ACTOR_PARAMS(-950, 1892), "Crate", RHT_CRATE_DEATH_MOUNTAIN_CRATER, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMC_CRATE));
locationTable[RC_LLR_NEAR_TREE_CRATE] = Location::Crate(RC_LLR_NEAR_TREE_CRATE, RCQUEST_BOTH, RCAREA_LON_LON_RANCH, SCENE_LON_LON_RANCH, TWO_ACTOR_PARAMS(1160, -2376), "Near Tree Crate", RHT_CRATE_LON_LON_RANCH, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LLR_NEAR_TREE_CRATE));
locationTable[RC_LH_LAB_CRATE] = Location::Crate(RC_LH_LAB_CRATE, RCQUEST_BOTH, RCAREA_LAKE_HYLIA, SCENE_LAKESIDE_LABORATORY, TWO_ACTOR_PARAMS(90, -119), "Lab Crate", RHT_CRATE_LAKESIDE_LABORATORY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LH_LAB_CRATE));
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
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_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_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_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_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[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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_3] = Location::Crate(RC_HW_AFTER_QUICKSAND_CRATE_3, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(3026, 2631), "After Quicksand Crate 3", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_AFTER_QUICKSAND_CRATE_3));
locationTable[RC_HW_NEAR_COLOSSUS_CRATE] = Location::Crate(RC_HW_NEAR_COLOSSUS_CRATE, RCQUEST_BOTH, RCAREA_WASTELAND, SCENE_HAUNTED_WASTELAND, TWO_ACTOR_PARAMS(-1531, -976), "Near Colossus Crate", RHT_CRATE_WASTELAND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_HW_NEAR_COLOSSUS_CRATE));
locationTable[RC_MK_NEAR_BAZAAR_CRATE_1] = Location::Crate(RC_MK_NEAR_BAZAAR_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(490, 338), "Near Bazaar Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_NEAR_BAZAAR_CRATE_1));
locationTable[RC_MK_NEAR_BAZAAR_CRATE_2] = Location::Crate(RC_MK_NEAR_BAZAAR_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(490, 132), "Near Bazaar Crate 2", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_NEAR_BAZAAR_CRATE_2));
locationTable[RC_MK_SHOOTING_GALLERY_CRATE_1] = Location::Crate(RC_MK_SHOOTING_GALLERY_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(-150, -576), "Shooting Gallery Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_SHOOTING_GALLERY_CRATE_1));
locationTable[RC_MK_SHOOTING_GALLERY_CRATE_2] = Location::Crate(RC_MK_SHOOTING_GALLERY_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_DAY, TWO_ACTOR_PARAMS(-90, -576), "Shooting Gallery Crate 2", RHT_CRATE_MARKET, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_SHOOTING_GALLERY_CRATE_2));
locationTable[RC_MK_LOST_DOG_HOUSE_CRATE] = Location::Crate(RC_MK_LOST_DOG_HOUSE_CRATE, RCQUEST_BOTH, RCAREA_MARKET, SCENE_DOG_LADY_HOUSE, TWO_ACTOR_PARAMS(176, 170), "Lost Dog House Crate", RHT_CRATE_MARKET, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_LOST_DOG_HOUSE_CRATE));
locationTable[RC_MK_GUARD_HOUSE_CRATE_1] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_1, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(76, -210), "Guard House Crate 1", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_1));
locationTable[RC_MK_GUARD_HOUSE_CRATE_2] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_2, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(28, -210), "Guard House Crate 2", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_2));
locationTable[RC_MK_GUARD_HOUSE_CRATE_3] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_3, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 120), "Guard House Crate 3", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_3));
locationTable[RC_MK_GUARD_HOUSE_CRATE_4] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_4, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 168), "Guard House Crate 4", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_4));
locationTable[RC_MK_GUARD_HOUSE_CRATE_5] = Location::Crate(RC_MK_GUARD_HOUSE_CRATE_5, RCQUEST_BOTH, RCAREA_MARKET, SCENE_MARKET_GUARD_HOUSE, TWO_ACTOR_PARAMS(-90, 216), "Guard House Crate 5", RHT_CRATE_MARKET, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_GUARD_HOUSE_CRATE_5));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1039, 10), "Near Open Grotto Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1099, 10), "Near Open Grotto Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(506, -358), "Near Open Grotto Adult Crate 3", RHT_CRATE_KAKARIKO_VILLAGE, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_3));
locationTable[RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4] = Location::Crate(RC_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(483, -302), "Near Open Grotto Adult Crate 4", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_OPEN_GROTTO_ADULT_CRATE_4));
locationTable[RC_KAK_NEAR_POTION_SHOP_ADULT_CRATE] = Location::Crate(RC_KAK_NEAR_POTION_SHOP_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(186, -758), "Near Potion Shop Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_POTION_SHOP_ADULT_CRATE));
locationTable[RC_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE] = Location::Crate(RC_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(185, 776), "Near Shooting Gallery Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_SHOOTING_GALLERY_ADULT_CRATE));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(92, 348), "Near Boarding House Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(32, 348), "Near Boarding House Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-389, 1518), "Near Impas House Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-389, 1470), "Near Impas House Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_IMPAS_HOUSE_ADULT_CRATE_2));
locationTable[RC_KAK_NEAR_BAZAAR_ADULT_CRATE_1] = Location::Crate(RC_KAK_NEAR_BAZAAR_ADULT_CRATE_1, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-433, -401), "Near Bazaar Adult Crate 1", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_ADULT_CRATE_1));
locationTable[RC_KAK_NEAR_BAZAAR_ADULT_CRATE_2] = Location::Crate(RC_KAK_NEAR_BAZAAR_ADULT_CRATE_2, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-489, -424), "Near Bazaar Adult Crate 2", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_ADULT_CRATE_2));
locationTable[RC_KAK_BEHIND_GS_HOUSE_ADULT_CRATE] = Location::Crate(RC_KAK_BEHIND_GS_HOUSE_ADULT_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-724, 871), "Behind GS House Adult Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_BEHIND_GS_HOUSE_ADULT_CRATE));
locationTable[RC_KAK_NEAR_GY_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_GY_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1732, 1366), "Near Graveyard Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_GY_CHILD_CRATE));
locationTable[RC_KAK_NEAR_WINDMILL_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_WINDMILL_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1170, 601), "Near Windmill Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_WINDMILL_CHILD_CRATE));
locationTable[RC_KAK_NEAR_FENCE_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_FENCE_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(1170, 111), "Near Fence Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_FENCE_CHILD_CRATE));
locationTable[RC_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-60, -46), "Near Boarding House Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BOARDING_HOUSE_CHILD_CRATE));
locationTable[RC_KAK_NEAR_BAZAAR_CHILD_CRATE] = Location::Crate(RC_KAK_NEAR_BAZAAR_CHILD_CRATE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_KAKARIKO_VILLAGE, TWO_ACTOR_PARAMS(-636, -478), "Near Bazaar Child Crate", RHT_CRATE_KAKARIKO_VILLAGE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_NEAR_BAZAAR_CHILD_CRATE));
locationTable[RC_GRAVEYARD_CRATE] = Location::Crate(RC_GRAVEYARD_CRATE, RCQUEST_BOTH, RCAREA_GRAVEYARD, SCENE_GRAVEYARD, TWO_ACTOR_PARAMS(-1050, -350), "Freestanding PoH Crate", RHT_CRATE_GRAVEYARD, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GRAVEYARD_CRATE));
locationTable[RC_GC_MAZE_CRATE] = Location::Crate(RC_GC_MAZE_CRATE, RCQUEST_BOTH, RCAREA_GORON_CITY, SCENE_GORON_CITY, TWO_ACTOR_PARAMS(-1124, -1339), "Maze Crate", RHT_CRATE_GORON_CITY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GC_MAZE_CRATE));
locationTable[RC_DMC_CRATE] = Location::Crate(RC_DMC_CRATE, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_CRATER, SCENE_DEATH_MOUNTAIN_CRATER, TWO_ACTOR_PARAMS(-950, 1892), "Crate", RHT_CRATE_DEATH_MOUNTAIN_CRATER, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DMC_CRATE));
locationTable[RC_LLR_NEAR_TREE_CRATE] = Location::Crate(RC_LLR_NEAR_TREE_CRATE, RCQUEST_BOTH, RCAREA_LON_LON_RANCH, SCENE_LON_LON_RANCH, TWO_ACTOR_PARAMS(1160, -2376), "Near Tree Crate", RHT_CRATE_LON_LON_RANCH, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LLR_NEAR_TREE_CRATE));
locationTable[RC_LH_LAB_CRATE] = Location::Crate(RC_LH_LAB_CRATE, RCQUEST_BOTH, RCAREA_LAKE_HYLIA, SCENE_LAKESIDE_LABORATORY, TWO_ACTOR_PARAMS(90, -119), "Lab Crate", RHT_CRATE_LAKESIDE_LABORATORY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LH_LAB_CRATE));
// No Logic Crates
locationTable[RC_GV_CRATE_BRIDGE_1] = Location::NLCrate(RC_GV_CRATE_BRIDGE_1, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-764, 148), "Near Bridge Crate 1", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_1));
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_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_GV_CRATE_BRIDGE_1] = Location::NLCrate(RC_GV_CRATE_BRIDGE_1, RCQUEST_BOTH, RCAREA_GERUDO_VALLEY, SCENE_GERUDO_VALLEY, TWO_ACTOR_PARAMS(-764, 148), "Near Bridge Crate 1", RHT_CRATE_GERUDO_VALLEY, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GV_CRATE_BRIDGE_1));
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_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_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
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
locationTable[RC_DEKU_TREE_MQ_LOBBY_CRATE] = Location::Crate(RC_DEKU_TREE_MQ_LOBBY_CRATE, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(279, 333), "MQ Lobby Crate", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_LOBBY_CRATE));
locationTable[RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1] = Location::Crate(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(-805, -62), "MQ Slingshot Room Crate 1", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1));
locationTable[RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2] = Location::Crate(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(-805, -2), "MQ Slingshot Room Crate 2", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1886, -744), "MQ Poe Room Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1826, -744), "MQ Poe Room Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1536, -1391), "MQ Poe Room Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1536, -1451), "MQ Poe Room Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2267, -1824), "MQ Poe Room Crate 5", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2267, -1884), "MQ Poe Room Crate 6", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2232, -1161), "MQ Poe Room Crate 7", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2232, -1221), "MQ Poe Room Crate 8", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1730, -1836), "MQ Staircase Lower Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2190, -1835), "MQ Staircase Lower Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1510, -1837), "MQ Staircase Upper Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1511, -1084), "MQ Staircase Upper Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2410, -1084), "MQ Staircase Upper Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2411, -1836), "MQ Staircase Upper Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(3191, -897), "MQ Two Flames Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2776, -810), "MQ Two Flames Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2055, -1714), "MQ Larvae Room Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2055, -1774), "MQ Larvae Room Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1871, -1976), "MQ Larvae Room Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1811, -1976), "MQ Larvae Room Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1625, -1721), "MQ Larvae Room Crate 5", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1625, -1781), "MQ Larvae Room Crate 6", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1205, 769), "MQ Outside Boss Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1205, 709), "MQ Outside Boss Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1130, -654), "MQ Outside Boss Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1211, -775), "MQ Outside Boss Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1457, -417), "MQ Outside Boss Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1457, -534), "MQ Outside Boss Crate 6", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2249, -56), "MQ Shortcut Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2189, -56), "MQ Shortcut Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2150, 55), "MQ Shortcut Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2135, -62), "MQ Shortcut Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2090, 55), "MQ Shortcut Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2030, 55), "MQ Shortcut Crate 6", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2230, 1147), "MQ Lizalfos Maze Lower Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2230, 1195), "MQ Lizalfos Maze Lower Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2124, 1154), "MQ Lizalfos Maze Lower Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1817, 1330), "MQ Lizalfos Maze Upper Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1710, 1288), "MQ Lizalfos Maze Upper Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1710, 1336), "MQ Lizalfos Maze Upper Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1407, -756), "MQ Lava Torch Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(384, 351), "MQ Lava Torch Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1409, -1176), "MQ Lava Torch Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(999, -402), "MQ Lava Torch Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1210, 163), "MQ Lava Torch Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-150, -336), "MQ Central Pillar Upper Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-210, -336), "MQ Central Pillar Upper Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(299, 485), "MQ Central Pillar Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 486), "MQ Central Pillar Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(222, 204), "MQ Central Pillar Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(455, 425), "MQ Central Pillar Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(455, 365), "MQ Central Pillar Lower Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 426), "MQ Central Pillar Lower Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 366), "MQ Central Pillar Lower Crate 7", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(162, 204), "MQ Central Pillar Lower Crate 8", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(31, 636), "MQ Central Pillar Lower Crate 9", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(151, 636), "MQ Central Pillar Lower Crate 10", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(102, 204), "MQ Central Pillar Lower Crate 11", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(91, 636), "MQ Central Pillar Lower Crate 12", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(25, 522), "MQ Central Pillar Lower Crate 13", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(25, 582), "MQ Central Pillar Lower Crate 14", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(698, 399), "MQ Lizalfos Hallway Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(437, 576), "MQ Lizalfos Hallway Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(270, 504), "MQ Lizalfos Hallway Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(686, 1016), "MQ Lizalfos Hallway Room Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(795, 870), "MQ Lizalfos Hallway Room Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(795, 810), "MQ Lizalfos Hallway Room Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(524, 839), "MQ Lizalfos Hallway Room Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(525, 954), "MQ Lizalfos Hallway Room Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(816, 570), "MQ Lizalfos Hallway Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(816, 510), "MQ Lizalfos Hallway Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -712), "MQ Storage Room A Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -821), "MQ Storage Room A Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -922), "MQ Storage Room A Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1434, -1036), "MQ Storage Room A Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1374, -1036), "MQ Storage Room A Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1265, -1036), "MQ Storage Room A Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1205, -1036), "MQ Storage Room A Crate 7", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-892, -91), "MQ GS Storage Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1149, 173), "MQ GS Storage Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1157, -221), "MQ GS Storage Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-945, -315), "MQ GS Storage Room Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1150, -141), "MQ GS Storage Room Lower Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1103, -315), "MQ GS Storage Room Lower Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-884, 65), "MQ GS Storage Room Upper Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1150, 56), "MQ GS Storage Room Upper Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2196, -1918), "MQ Dragon Room Torches Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2196, -1978), "MQ Dragon Room Torches Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1718, -2006), "MQ Dragon Room Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1778, -2006), "MQ Dragon Room Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1997, -1912), "MQ Dragon Room Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1997, -1972), "MQ Dragon Room Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1092, -1926), "MQ Dragon Room Door Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1153, -1926), "MQ Dragon Room Door Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1257, -1567), "MQ BK Room Upper Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1289, -1205), "MQ BK Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-985, -1333), "MQ BK Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1297, -1300), "MQ BK Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1069, -1402), "MQ BK Room Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-11, -2075), "MQ Whirlpool Front Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-371, -2077), "MQ Whirlpool Front Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-455, -2394), "MQ Whirlpool Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-498, -2661), "MQ Whirlpool Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(11, -2737), "MQ Whirlpool Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-251, -2731), "MQ Whirlpool Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-119, -2481), "MQ Whirlpool Submerged Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(126, -2485), "MQ Whirlpool Submerged Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-7, -3126), "MQ Whirlpool Behind Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-87, -3126), "MQ Whirlpool Behind Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-303, -3126), "MQ Whirlpool Behind Gate Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-390, -3126), "MQ Whirlpool Behind Gate Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-397, -3818), "MQ Dodongo Room Upper Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(30, -3215), "MQ Dodongo Room Hall Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-85, -3460), "MQ Dodongo Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-271, -3826), "MQ Dodongo Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(36, -3700), "MQ Dodongo Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1436, -2766), "MQ Storage Room B Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1125, -2866), "MQ Storage Room B Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1125, -2926), "MQ Storage Room B Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1435, -2935), "MQ Storage Room B Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1436, -2875), "MQ Storage Room B Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-994, 744), "MQ Triple Torch Room Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-991, 976), "MQ Triple Torch Room Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1511, 975), "MQ Triple Torch Room Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 792), "MQ Triple Torch Room Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 975), "MQ Triple Torch Room Submerged Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 744), "MQ Triple Torch Room Submerged Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2183, 977), "MQ Triple Torch Room Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2260, 744), "MQ Triple Torch Room Gate Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2200, 743), "MQ Triple Torch Room Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(510, -1558), "MQ Statue Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(570, -1558), "MQ Statue Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-150, -1138), "MQ Big Mirror Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(270, -1138), "MQ Big Mirror Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-150, -1186), "MQ Big Mirror Crate 3", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(270, -1186), "MQ Big Mirror Crate 4", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4));
locationTable[RC_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE] = Location::Crate(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE, RCQUEST_MQ, RCAREA_GERUDO_TRAINING_GROUND, SCENE_GERUDO_TRAINING_GROUND, TWO_ACTOR_PARAMS(-59, -1598), "MQ Maze Crate", RHT_CRATE_GERUDO_TRAINING_GROUND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE));
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
locationTable[RC_DEKU_TREE_MQ_LOBBY_CRATE] = Location::Crate(RC_DEKU_TREE_MQ_LOBBY_CRATE, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(279, 333), "MQ Lobby Crate", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_LOBBY_CRATE));
locationTable[RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1] = Location::Crate(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(-805, -62), "MQ Slingshot Room Crate 1", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_1));
locationTable[RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2] = Location::Crate(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DEKU_TREE, SCENE_DEKU_TREE, TWO_ACTOR_PARAMS(-805, -2), "MQ Slingshot Room Crate 2", RHT_CRATE_DEKU_TREE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DEKU_TREE_MQ_SLINGSHOT_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1886, -744), "MQ Poe Room Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1826, -744), "MQ Poe Room Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1536, -1391), "MQ Poe Room Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1536, -1451), "MQ Poe Room Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2267, -1824), "MQ Poe Room Crate 5", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_5));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2267, -1884), "MQ Poe Room Crate 6", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_6));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2232, -1161), "MQ Poe Room Crate 7", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_7));
locationTable[RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8] = Location::Crate(RC_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2232, -1221), "MQ Poe Room Crate 8", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_POE_ROOM_CRATE_8));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1730, -1836), "MQ Staircase Lower Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2190, -1835), "MQ Staircase Lower Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_LOWER_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1510, -1837), "MQ Staircase Upper Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-1511, -1084), "MQ Staircase Upper Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2410, -1084), "MQ Staircase Upper Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(-2411, -1836), "MQ Staircase Upper Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_STAIRCASE_UPPER_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(3191, -897), "MQ Two Flames Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2776, -810), "MQ Two Flames Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_TWO_FLAMES_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2055, -1714), "MQ Larvae Room Crate 1", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_1));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(2055, -1774), "MQ Larvae Room Crate 2", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_2));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1871, -1976), "MQ Larvae Room Crate 3", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_3));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1811, -1976), "MQ Larvae Room Crate 4", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_4));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1625, -1721), "MQ Larvae Room Crate 5", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_5));
locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6] = Location::Crate(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6, RCQUEST_MQ, RCAREA_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, TWO_ACTOR_PARAMS(1625, -1781), "MQ Larvae Room Crate 6", RHT_CRATE_DODONGOS_CAVERN, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1205, 769), "MQ Outside Boss Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1205, 709), "MQ Outside Boss Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1130, -654), "MQ Outside Boss Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1211, -775), "MQ Outside Boss Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1457, -417), "MQ Outside Boss Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_5));
locationTable[RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6] = Location::Crate(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-1457, -534), "MQ Outside Boss Crate 6", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2249, -56), "MQ Shortcut Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2189, -56), "MQ Shortcut Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2150, 55), "MQ Shortcut Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2135, -62), "MQ Shortcut Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2090, 55), "MQ Shortcut Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_5));
locationTable[RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6] = Location::Crate(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2030, 55), "MQ Shortcut Crate 6", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_6));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2230, 1147), "MQ Lizalfos Maze Lower Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2230, 1195), "MQ Lizalfos Maze Lower Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(2124, 1154), "MQ Lizalfos Maze Lower Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1817, 1330), "MQ Lizalfos Maze Upper Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1710, 1288), "MQ Lizalfos Maze Upper Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1710, 1336), "MQ Lizalfos Maze Upper Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1407, -756), "MQ Lava Torch Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(384, 351), "MQ Lava Torch Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1409, -1176), "MQ Lava Torch Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(999, -402), "MQ Lava Torch Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5] = Location::Crate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1210, 163), "MQ Lava Torch Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-150, -336), "MQ Central Pillar Upper Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-210, -336), "MQ Central Pillar Upper Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_UPPER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(299, 485), "MQ Central Pillar Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 486), "MQ Central Pillar Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(222, 204), "MQ Central Pillar Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(455, 425), "MQ Central Pillar Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(455, 365), "MQ Central Pillar Lower Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 426), "MQ Central Pillar Lower Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(215, 366), "MQ Central Pillar Lower Crate 7", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_7));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(162, 204), "MQ Central Pillar Lower Crate 8", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_8));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(31, 636), "MQ Central Pillar Lower Crate 9", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_9));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(151, 636), "MQ Central Pillar Lower Crate 10", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_10));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(102, 204), "MQ Central Pillar Lower Crate 11", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_11));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(91, 636), "MQ Central Pillar Lower Crate 12", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_12));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(25, 522), "MQ Central Pillar Lower Crate 13", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_13));
locationTable[RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14] = Location::Crate(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(25, 582), "MQ Central Pillar Lower Crate 14", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_CENTRAL_PILLAR_LOWER_CRATE_14));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(698, 399), "MQ Lizalfos Hallway Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(437, 576), "MQ Lizalfos Hallway Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(270, 504), "MQ Lizalfos Hallway Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(686, 1016), "MQ Lizalfos Hallway Room Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(795, 870), "MQ Lizalfos Hallway Room Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(795, 810), "MQ Lizalfos Hallway Room Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(524, 839), "MQ Lizalfos Hallway Room Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(525, 954), "MQ Lizalfos Hallway Room Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_ROOM_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(816, 570), "MQ Lizalfos Hallway Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(816, 510), "MQ Lizalfos Hallway Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_GATE_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -712), "MQ Storage Room A Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -821), "MQ Storage Room A Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1536, -922), "MQ Storage Room A Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1434, -1036), "MQ Storage Room A Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1374, -1036), "MQ Storage Room A Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1265, -1036), "MQ Storage Room A Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1205, -1036), "MQ Storage Room A Crate 7", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_CRATE_7));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-892, -91), "MQ GS Storage Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1149, 173), "MQ GS Storage Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1157, -221), "MQ GS Storage Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-945, -315), "MQ GS Storage Room Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1150, -141), "MQ GS Storage Room Lower Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1103, -315), "MQ GS Storage Room Lower Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-884, 65), "MQ GS Storage Room Upper Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1150, 56), "MQ GS Storage Room Upper Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2196, -1918), "MQ Dragon Room Torches Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2196, -1978), "MQ Dragon Room Torches Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1718, -2006), "MQ Dragon Room Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1778, -2006), "MQ Dragon Room Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1997, -1912), "MQ Dragon Room Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1997, -1972), "MQ Dragon Room Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1092, -1926), "MQ Dragon Room Door Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1153, -1926), "MQ Dragon Room Door Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1257, -1567), "MQ BK Room Upper Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_UPPER_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1289, -1205), "MQ BK Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-985, -1333), "MQ BK Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1297, -1300), "MQ BK Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1069, -1402), "MQ BK Room Lower Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_BK_ROOM_LOWER_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-11, -2075), "MQ Whirlpool Front Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-371, -2077), "MQ Whirlpool Front Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-455, -2394), "MQ Whirlpool Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-498, -2661), "MQ Whirlpool Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(11, -2737), "MQ Whirlpool Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-251, -2731), "MQ Whirlpool Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-119, -2481), "MQ Whirlpool Submerged Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(126, -2485), "MQ Whirlpool Submerged Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-7, -3126), "MQ Whirlpool Behind Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-87, -3126), "MQ Whirlpool Behind Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-303, -3126), "MQ Whirlpool Behind Gate Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-390, -3126), "MQ Whirlpool Behind Gate Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_WHIRLPOOL_BEHIND_GATE_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-397, -3818), "MQ Dodongo Room Upper Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_UPPER_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(30, -3215), "MQ Dodongo Room Hall Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_HALL_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-85, -3460), "MQ Dodongo Room Lower Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-271, -3826), "MQ Dodongo Room Lower Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(36, -3700), "MQ Dodongo Room Lower Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DODONGO_ROOM_LOWER_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1436, -2766), "MQ Storage Room B Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1125, -2866), "MQ Storage Room B Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1125, -2926), "MQ Storage Room B Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1435, -2935), "MQ Storage Room B Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1436, -2875), "MQ Storage Room B Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_B_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-994, 744), "MQ Triple Torch Room Submerged Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-991, 976), "MQ Triple Torch Room Submerged Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1511, 975), "MQ Triple Torch Room Submerged Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 792), "MQ Triple Torch Room Submerged Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 975), "MQ Triple Torch Room Submerged Crate 5", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1571, 744), "MQ Triple Torch Room Submerged Crate 6", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2183, 977), "MQ Triple Torch Room Gate Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2260, 744), "MQ Triple Torch Room Gate Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2] = Location::Crate(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2200, 743), "MQ Triple Torch Room Gate Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_GATE_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(510, -1558), "MQ Statue Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(570, -1558), "MQ Statue Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-150, -1138), "MQ Big Mirror Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(270, -1138), "MQ Big Mirror Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-150, -1186), "MQ Big Mirror Crate 3", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_3));
locationTable[RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4] = Location::Crate(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(270, -1186), "MQ Big Mirror Crate 4", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CRATE_4));
locationTable[RC_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE] = Location::Crate(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE, RCQUEST_MQ, RCAREA_GERUDO_TRAINING_GROUND, SCENE_GERUDO_TRAINING_GROUND, TWO_ACTOR_PARAMS(-59, -1598), "MQ Maze Crate", RHT_CRATE_GERUDO_TRAINING_GROUND, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_GERUDO_TRAINING_GROUND_MQ_MAZE_CRATE));
// Small Crates
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
locationTable[RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-141, -1945), "Platform Room Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-189, -1925), "Platform Room Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-2030, -1172), "After Hammer Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-2072, -1135), "After Hammer Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-971, -940), "Before Child Climb Small Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_BOMBS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-1151, -939), "Before Child Climb Small Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-512, -4592), "MQ Triple Hallway Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-666, -4671), "MQ Triple Hallway Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1381, -2115), "MQ Jigglies Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1341, -2116), "MQ Jigglies Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(1599, -1322), "MQ Frozen Eye Switch Small Crate 1", RHT_CRATE_FOREST_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2364, -873), "MQ Frozen Eye Switch Small Crate 2", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2312, -874), "MQ Frozen Eye Switch Small Crate 3", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1699, 1290), "MQ Lizalfos Maze Upper Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1699, 1332), "MQ Lizalfos Maze Upper Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(460, 370), "MQ Lava Torch Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1405, -975), "MQ Lava Torch Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(685, 183), "MQ Lava Torch Small Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1210, 163), "MQ Lava Torch Small Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1267, 200), "MQ Lava Torch Small Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1952), "MQ Dragon Room Torches Small Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1911), "MQ Dragon Room Torches Small Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1991), "MQ Dragon Room Torches Small Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1470, -622), "MQ Storage Room A Small Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1341, -621), "MQ Storage Room A Small Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1393, -621), "MQ Storage Room A Small Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1284, -621), "MQ Storage Room A Small Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1166, 97), "MQ GS Storage Room Lower Small Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-992, 382), "MQ GS Storage Room Upper Small Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(365, 52), "MQ Truth Spinner Small Crate 1", RHT_CRATE_SHADOW_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(363, -62), "MQ Truth Spinner Small Crate 2", RHT_CRATE_SHADOW_TEMPLE, RG_BOMBS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(363, -7), "MQ Truth Spinner Small Crate 3", RHT_CRATE_SHADOW_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(366, 114), "MQ Truth Spinner Small Crate 4", RHT_CRATE_SHADOW_TEMPLE, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE] = Location::SmallCrate(RC_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-271, -983), "MQ Statue Small Crate", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE));
locationTable[RC_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE] = Location::SmallCrate(RC_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(1382, 190), "MQ Beamos Small Crate", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE));
// Randomizer Check Randomizer Check Quest Area Scene ID Params Short Name Hint Text Key Vanilla Spoiler Collection Check
locationTable[RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-141, -1945), "Platform Room Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-189, -1925), "Platform Room Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_PLATFORM_ROOM_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-2030, -1172), "After Hammer Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(-2072, -1135), "After Hammer Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_AFTER_HAMMER_SMALL_CRATE_2));
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-971, -940), "Before Child Climb Small Crate 1", RHT_CRATE_SPIRIT_TEMPLE, RG_BOMBS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_1));
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-1151, -939), "Before Child Climb Small Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-512, -4592), "MQ Triple Hallway Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-666, -4671), "MQ Triple Hallway Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1381, -2115), "MQ Jigglies Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1341, -2116), "MQ Jigglies Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(1599, -1322), "MQ Frozen Eye Switch Small Crate 1", RHT_CRATE_FOREST_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2364, -873), "MQ Frozen Eye Switch Small Crate 2", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2312, -874), "MQ Frozen Eye Switch Small Crate 3", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1699, 1290), "MQ Lizalfos Maze Upper Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1699, 1332), "MQ Lizalfos Maze Upper Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(460, 370), "MQ Lava Torch Small Crate 1", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_1));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1405, -975), "MQ Lava Torch Small Crate 2", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_2));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(685, 183), "MQ Lava Torch Small Crate 3", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_3));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1210, 163), "MQ Lava Torch Small Crate 4", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_4));
locationTable[RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5] = Location::SmallCrate(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5, RCQUEST_MQ, RCAREA_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, TWO_ACTOR_PARAMS(1267, 200), "MQ Lava Torch Small Crate 5", RHT_CRATE_FIRE_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FIRE_TEMPLE_MQ_LAVA_TORCH_SMALL_CRATE_5));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1952), "MQ Dragon Room Torches Small Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1911), "MQ Dragon Room Torches Small Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-2210, -1991), "MQ Dragon Room Torches Small Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_DRAGON_ROOM_TORCHES_SMALL_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1470, -622), "MQ Storage Room A Small Crate 1", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_1));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1341, -621), "MQ Storage Room A Small Crate 2", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_2));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1393, -621), "MQ Storage Room A Small Crate 3", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_3));
locationTable[RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(1284, -621), "MQ Storage Room A Small Crate 4", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_STORAGE_ROOM_A_SMALL_CRATE_4));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-1166, 97), "MQ GS Storage Room Lower Small Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_LOWER_SMALL_CRATE));
locationTable[RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE] = Location::SmallCrate(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE, RCQUEST_MQ, RCAREA_WATER_TEMPLE, SCENE_WATER_TEMPLE, TWO_ACTOR_PARAMS(-992, 382), "MQ GS Storage Room Upper Small Crate", RHT_CRATE_WATER_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_UPPER_SMALL_CRATE));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(365, 52), "MQ Truth Spinner Small Crate 1", RHT_CRATE_SHADOW_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_1));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(363, -62), "MQ Truth Spinner Small Crate 2", RHT_CRATE_SHADOW_TEMPLE, RG_BOMBS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_2));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(363, -7), "MQ Truth Spinner Small Crate 3", RHT_CRATE_SHADOW_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_3));
locationTable[RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4] = Location::SmallCrate(RC_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4, RCQUEST_MQ, RCAREA_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE, TWO_ACTOR_PARAMS(366, 114), "MQ Truth Spinner Small Crate 4", RHT_CRATE_SHADOW_TEMPLE, RG_ARROWS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SHADOW_TEMPLE_MQ_TRUTH_SPINNER_SMALL_CRATE_4));
locationTable[RC_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE] = Location::SmallCrate(RC_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-271, -983), "MQ Statue Small Crate", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_STATUE_SMALL_CRATE));
locationTable[RC_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE] = Location::SmallCrate(RC_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE, RCQUEST_MQ, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(1382, 190), "MQ Beamos Small Crate", RHT_CRATE_SPIRIT_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_MQ_BEAMOS_SMALL_CRATE));
// clang-format on
}
static ObjectExtension::Register<CrateIdentity> RegisterCrateIdentity;
static ObjectExtension::Register<SmallCrateIdentity> RegisterSmallCrateIdentity;
static RegisterShipInitFunc initFunc(RegisterShuffleCrates, { "IS_RANDO" });
static RegisterShipInitFunc locFunc(Rando::StaticData::RegisterCrateLocations);

View file

@ -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

View file

@ -1,19 +1,28 @@
#include "soh/OTRGlobals.h"
#include "randomizer_grotto.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_Obj_Bean/z_obj_bean.h"
#include "src/overlays/actors/ovl_En_Gs/z_en_gs.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)
void ShuffleFairies_DrawRandomizedItem(EnElf* enElf, PlayState* play) {
const auto fairyIdentity = ObjectExtension::GetInstance().Get<FairyIdentity>(&enElf->actor);
if (fairyIdentity == nullptr) {
return;
}
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)) {
randoGetItem = GET_ITEM_MYSTERY;
}
@ -33,8 +42,8 @@ bool ShuffleFairies_FairyExists(FairyIdentity fairyIdentity) {
if (actor->id != ACTOR_EN_ELF) {
actor = actor->next;
} else {
EnElf* enElf = (EnElf*)(actor);
if (fairyIdentity.randomizerInf == enElf->sohFairyIdentity.randomizerInf) {
const auto actorFairyIdentity = ObjectExtension::GetInstance().Get<FairyIdentity>(&actor);
if (actorFairyIdentity != nullptr && fairyIdentity.randomizerInf == actorFairyIdentity->randomizerInf) {
return true;
}
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) {
FairyIdentity fairyIdentity = ShuffleFairies_GetFairyIdentity(params);
if (!Flags_GetRandomizerInf(fairyIdentity.randomizerInf)) {
EnElf* fairy = (EnElf*)Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_ELF, posX, posY - 30.0f, posZ, 0,
0, 0, fairyType, true);
fairy->sohFairyIdentity = fairyIdentity;
fairy->actor.draw = (ActorFunc)ShuffleFairies_DrawRandomizedItem;
Actor* fairy = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_ELF, posX, posY - 30.0f, posZ, 0, 0, 0,
fairyType, true);
ObjectExtension::GetInstance().Set<FairyIdentity>(fairy, std::move(fairyIdentity));
fairy->draw = (ActorFunc)ShuffleFairies_DrawRandomizedItem;
return true;
}
return false;
@ -85,8 +94,14 @@ void RegisterShuffleFairies() {
// Grant item when picking up fairy.
COND_VB_SHOULD(VB_FAIRY_HEAL, shouldRegister, {
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_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_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_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
}
static ObjectExtension::Register<FairyIdentity> RegisterFairyIdentity;
static RegisterShipInitFunc registerShuffleFairies(RegisterShuffleFairies, { "IS_RANDO" });
static RegisterShipInitFunc registerShuffleFairiesLocations(Rando::StaticData::RegisterFairyLocations);

View file

@ -1,6 +1,7 @@
#include "ShuffleGrass.h"
#include <soh/OTRGlobals.h>
#include "soh_assets.h"
#include "static_data.h"
#include "soh/ObjectExtension/ObjectExtension.h"
#include "soh/Enhancements/enhancementTypes.h"
extern "C" {
@ -27,18 +28,20 @@ extern "C" void EnKusa_RandomizerDraw(Actor* thisx, PlayState* play) {
static Gfx* dLists[] = { (Gfx*)gRandoBushJunkDL, (Gfx*)gRandoCuttableGrassJunkDL, (Gfx*)gRandoCuttableGrassJunkDL };
auto grassActor = ((EnKusa*)thisx);
const auto grassIdentity = ObjectExtension::GetInstance().Get<GrassIdentity>(thisx);
OPEN_DISPS(play->state.gfxCtx);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
if (grassActor->grassIdentity.randomizerCheck != RC_MAX &&
Flags_GetRandomizerInf(grassActor->grassIdentity.randomizerInf) == 0) {
if (grassIdentity != nullptr && grassIdentity->randomizerCheck != RC_MAX &&
Flags_GetRandomizerInf(grassIdentity->randomizerInf) == 0) {
int csmc = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_DISABLED);
int requiresStoneAgony = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"), 0);
if ((csmc == CSMC_BOTH || csmc == CSMC_TEXTURE) &&
(!requiresStoneAgony || (requiresStoneAgony && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) {
auto itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(grassActor->grassIdentity.randomizerCheck,
true, GI_NONE);
auto itemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE);
GetItemCategory getItemCategory = itemEntry.getItemCategory;
switch (getItemCategory) {
@ -88,19 +91,19 @@ extern "C" void EnKusa_RandomizerDraw(Actor* thisx, 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;
RandomizerCheck rc = grassActor->grassIdentity.randomizerCheck;
RandomizerCheck rc = grassIdentity->randomizerCheck;
uint8_t isDungeon = Rando::StaticData::GetLocation(rc)->IsDungeon();
uint8_t grassSetting = RAND_GET_OPTION(RSK_SHUFFLE_GRASS);
// Don't pull randomized item if grass isn't randomized or is already checked
if (!IS_RANDO || (grassSetting == RO_SHUFFLE_GRASS_OVERWORLD && isDungeon) ||
(grassSetting == RO_SHUFFLE_GRASS_DUNGEONS && !isDungeon) ||
Flags_GetRandomizerInf(grassActor->grassIdentity.randomizerInf) ||
grassActor->grassIdentity.randomizerCheck == RC_UNKNOWN_CHECK) {
Flags_GetRandomizerInf(grassIdentity->randomizerInf) || rc == RC_UNKNOWN_CHECK) {
return false;
} else {
return true;
@ -108,10 +111,14 @@ uint8_t EnKusa_RandomizerHoldsItem(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);
item00->randoInf = grassActor->grassIdentity.randomizerInf;
item00->itemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(grassActor->grassIdentity.randomizerCheck, true, GI_NONE);
item00->randoInf = grassIdentity->randomizerInf;
item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(grassIdentity->randomizerCheck, true, GI_NONE);
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
@ -127,8 +134,9 @@ void EnKusa_RandomizerInit(void* actorRef) {
EnKusa* grassActor = static_cast<EnKusa*>(actorRef);
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);
ObjectExtension::GetInstance().Set<GrassIdentity>(actor, std::move(grassIdentity));
}
void RegisterShuffleGrass() {
@ -150,8 +158,10 @@ void RegisterShuffleGrass() {
EnKusa* grassActor = va_arg(args, EnKusa*);
if (EnKusa_RandomizerHoldsItem(grassActor, gPlayState)) {
EnKusa_RandomizerSpawnCollectible(grassActor, gPlayState);
grassActor->grassIdentity.randomizerCheck = RC_MAX;
grassActor->grassIdentity.randomizerInf = RAND_INF_MAX;
ObjectExtension::GetInstance().Set<GrassIdentity>(&grassActor->actor, std::move(GrassIdentity{
.randomizerInf = RAND_INF_MAX,
.randomizerCheck = RC_MAX,
}));
*should = false;
} else {
*should = true;
@ -519,5 +529,6 @@ void Rando::StaticData::RegisterGrassLocations() {
// clang-format on
}
static ObjectExtension::Register<GrassIdentity> RegisterGrassIdentity;
static RegisterShipInitFunc registerShuffleGrass(RegisterShuffleGrass, { "IS_RANDO" });
static RegisterShipInitFunc registerShuffleGrassLocations(Rando::StaticData::RegisterGrassLocations);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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_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_GERUDO_FORTRESS, 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_GF_OUTSIDE_GTG, RR_GERUDO_TRAINING_GROUND_ENTRYWAY, ENTR_GERUDO_TRAINING_GROUND_ENTRANCE },
{ 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_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_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_GERUDO_FORTRESS, 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_NEAR_GROTTO, RR_GF_STORMS_GROTTO, ENTRANCE_GROTTO_LOAD(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_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) },
@ -474,8 +474,8 @@ void SetAllEntrancesData() {
{ 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_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_GERUDO_FORTRESS, RR_GV_FORTRESS_SIDE, ENTR_GERUDO_VALLEY_WEST_EXIT } },
{ { EntranceType::Overworld, RR_GV_FORTRESS_SIDE, RR_GF_OUTSKIRTS, ENTR_GERUDOS_FORTRESS_EAST_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_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 },

View file

@ -1452,7 +1452,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
break;
}
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;
break;
}
@ -2122,7 +2122,7 @@ void RandomizerOnGameFrameUpdateHandler() {
}
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)) {

View file

@ -671,7 +671,12 @@ void RegionTable_Init() {
// clang-format off
areaTable[RR_ROOT] = Region("Root", SCENE_ID_MAX, TIME_DOESNT_PASS, {RA_LINKS_POCKET}, {
//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
LOCATION(RC_LINKS_POCKET, true),
@ -756,6 +761,7 @@ void RegionTable_Init() {
RegionTable_Init_ZorasFountain();
RegionTable_Init_GerudoValley();
RegionTable_Init_GerudoFortress();
RegionTable_Init_ThievesHideout();
RegionTable_Init_HauntedWasteland();
RegionTable_Init_DesertColossus();
// Dungeons

View file

@ -389,5 +389,6 @@ void RegionTable_Init_SpiritTemple();
void RegionTable_Init_ShadowTemple();
void RegionTable_Init_BottomOfTheWell();
void RegionTable_Init_IceCavern();
void RegionTable_Init_ThievesHideout();
void RegionTable_Init_GerudoTrainingGround();
void RegionTable_Init_GanonsCastle();

View file

@ -25,8 +25,8 @@ void RegionTable_Init_BottomOfTheWell() {
}, {
//Locations
LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw || logic->CanOpenUnderwaterChest()),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw || logic->CanOpenUnderwaterChest()),
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()),
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_2, logic->CanBreakPots()),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT, (logic->CanBreakPots() && logic->LoweredWaterInsideBotw) || logic->CanUse(RG_BOOMERANG)),

View file

@ -117,7 +117,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_STAIRS_LOWER] = Region("Dodongos Cavern Stairs Lower", SCENE_DODONGOS_CAVERN, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}),
Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, []{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}),
Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, []{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRS_WITH_BOW) && logic->CanUse(RG_FAIRY_BOW));}),
Entrance(RR_DODONGOS_CAVERN_COMPASS_ROOM, []{return Here(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}),
});
@ -304,7 +304,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER] = Region("Dodongos Cavern MQ Stairs Lower", SCENE_DODONGOS_CAVERN, {
//Events
//EventAccess(&logic->CanClimbDCStairs, []{return logic->HasExplosives || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}),
//EventAccess(&logic->CanClimbDCStairs, []{return logic->HasExplosives || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRS_WITH_BOW) && logic->CanUse(RG_FAIRY_BOW));}),
}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_1, logic->CanBreakPots()),
@ -317,7 +317,7 @@ void RegionTable_Init_DodongosCavern() {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}),
//This is possible with sticks and shield, igniting a first flower by "touch" then very quickly crouch stabbing in a way that cuts the corner to light the 3rd bomb on the other side, but that's a trick
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->HasExplosives() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));});}),
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->HasExplosives() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRS_WITH_BOW) && logic->CanUse(RG_FAIRY_BOW));});}),
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->CanBreakMudWalls();});}),
});
@ -330,7 +330,7 @@ void RegionTable_Init_DodongosCavern() {
LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS));}),
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return logic->HasExplosives() || (logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS) || ctx->GetTrickOption(RT_DC_MQ_STAIRS_WITH_ONLY_STRENGTH))) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRS_WITH_BOW) && logic->CanUse(RG_FAIRY_BOW));}),
Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return true;}),
});

View file

@ -147,7 +147,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_SEWER] = Region("Forest Temple Sewer", SCENE_FOREST_TEMPLE, {}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_WELL_CHEST, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER)),
LOCATION(RC_FOREST_TEMPLE_WELL_CHEST, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanOpenUnderwaterChest() && logic->WaterTimer() >= 8)),
LOCATION(RC_FOREST_TEMPLE_WELL_WEST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)),
LOCATION(RC_FOREST_TEMPLE_WELL_EAST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)),
}, {
@ -444,7 +444,7 @@ void RegionTable_Init_ForestTemple() {
EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, logic->CanHitEyeTargets()),
LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, logic->CanHitEyeTargets() || (logic->CanOpenUnderwaterChest() && logic->WaterTimer() >= 8)),
LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
//implies logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)
LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, logic->CanHitEyeTargets() || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))),

View file

@ -11,7 +11,7 @@ void RegionTable_Init_GerudoTrainingGround() {
//Exits
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_FORTRESS, []{return true;}),
Entrance(RR_GF_OUTSIDE_GTG, []{return true;}),
});
#pragma region Vanilla
@ -173,7 +173,7 @@ void RegionTable_Init_GerudoTrainingGround() {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE] = Region("Gerudo Training Ground MQ Left Side", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_MQ_WITHOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM] = Region("Gerudo Training Ground MQ Stalfos Room", SCENE_GERUDO_TRAINING_GROUND, {
@ -287,7 +287,7 @@ void RegionTable_Init_GerudoTrainingGround() {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_UNDERWATER] = Region("Gerudo Training Ground MQ Underwater", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
//it is possible to snipe the stingers with bow or sling before dropping in, or just get really lucky, and avoid needing to take damage, but that might be trick worthy
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->TakeDamage()),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->HasItem(RG_BRONZE_SCALE) && logic->TakeDamage()),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return true;}),

View file

@ -351,7 +351,7 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST] = Region("Spirit Temple MQ Statue Room East", SCENE_SPIRIT_TEMPLE, {}, {
//Locations
LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, logic->CanUse(RG_HOOKSHOT) & logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS))),
LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS))),
LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS))),
}, {
//Exits

View file

@ -379,8 +379,7 @@ void RegionTable_Init_WaterTemple() {
}, {
//Locations
LOCATION(RC_WATER_TEMPLE_MQ_MAP_CHEST, logic->MQWaterLevel(WL_HIGH) && logic->HasFireSource() && logic->CanUse(RG_HOOKSHOT)),
//easy to get at WL_HIGH with the hook-the-underwater-chest glitch
LOCATION(RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_HOOKSHOT)),
LOCATION(RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, (logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_HOOKSHOT)) || (logic->MQWaterLevel(WL_HIGH_OR_MID) && logic->CanOpenUnderwaterChest())),
LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_1, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)),
LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_2, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)),
}, {

View file

@ -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
}

View file

@ -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

View file

@ -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_CRATE_LEDGE, []{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}),
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
});
@ -78,9 +78,9 @@ void RegionTable_Init_GerudoValley() {
LOCATION(RC_GV_CRATE_BRIDGE_4, logic->IsChild && logic->CanBreakCrates()),
}, {
//Exits
Entrance(RR_GERUDO_FORTRESS, []{return true;}),
Entrance(RR_GF_OUTSKIRTS, []{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_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}),
Entrance(RR_GV_CRATE_LEDGE, []{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}),

View file

@ -7,7 +7,7 @@ void RegionTable_Init_HyruleField() {
// clang-format off
areaTable[RR_HYRULE_FIELD] = Region("Hyrule Field", SCENE_HYRULE_FIELD, {
//Events
EventAccess(&logic->BigPoeKill, []{return logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_EPONA) && logic->HasBottle();}),
EventAccess(&logic->BigPoeKill, []{return logic->HasBottle() && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_EPONA) || ctx->GetTrickOption(RT_HF_BIG_POE_WITHOUT_EPONA));}),
}, {
//Locations
LOCATION(RC_HF_OCARINA_OF_TIME_ITEM, logic->IsChild && logic->StoneCount() == 3 && logic->HasItem(RG_BRONZE_SCALE)),

View file

@ -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

View file

@ -171,14 +171,14 @@ void Rando::StaticData::InitLocationTable() {
locationTable[RC_GV_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_GV_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xF0), "Deku Scrub Grotto Front", RHT_GV_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT), false, 40);
// Gerudo Fortress
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_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?
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_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_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_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_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_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);
// Thieves Hideout
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_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_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_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_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
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);
@ -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_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
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);
// Wasteland & Desert Colossus
locationTable[RC_WASTELAND_GS] = Location::GSToken(RC_WASTELAND_GS, RCQUEST_BOTH, SCENE_HAUNTED_WASTELAND, 13570, 0x02, "GS", RHT_WASTELAND_GS, 0x15);

View file

@ -441,6 +441,10 @@ bool Logic::CanOpenOverworldDoor(RandomizerGet key) {
return HasItem(key);
}
bool Logic::CanOpenUnderwaterChest() {
return ctx->GetTrickOption(RT_OPEN_UNDERWATER_CHEST) && CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT);
}
uint8_t GetDifficultyValueFromString(Rando::Option& glitchOption) {
return 0;
}
@ -483,6 +487,9 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
bool inWater) {
bool killed = false;
switch (enemy) {
case RE_GERUDO_GUARD:
case RE_BREAK_ROOM_GUARD:
return false;
case RE_GOLD_SKULLTULA:
switch (distance) {
case ED_CLOSE:
@ -732,7 +739,8 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
(CanUse(RG_NUTS) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || HookshotOrBoomerang());
case RE_KING_DODONGO:
return HasBossSoul(RG_KING_DODONGO_SOUL) && CanJumpslash() &&
(CanUse(RG_BOMB_BAG) || HasItem(RG_GORONS_BRACELET));
(CanUse(RG_BOMB_BAG) || HasItem(RG_GORONS_BRACELET) ||
(ctx->GetTrickOption(RT_DC_DODONGO_CHU) && IsAdult && CanUse(RG_BOMBCHU_5)));
case RE_BARINADE:
return HasBossSoul(RG_BARINADE_SOUL) && CanUse(RG_BOOMERANG) && CanJumpslashExceptHammer();
case RE_PHANTOM_GANON:
@ -741,7 +749,10 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
case RE_VOLVAGIA:
return HasBossSoul(RG_VOLVAGIA_SOUL) && CanUse(RG_MEGATON_HAMMER);
case RE_MORPHA:
return HasBossSoul(RG_MORPHA_SOUL) && CanUse(RG_HOOKSHOT) && (CanUseSword() || CanUse(RG_MEGATON_HAMMER));
return HasBossSoul(RG_MORPHA_SOUL) &&
(CanUse(RG_HOOKSHOT) ||
(ctx->GetTrickOption(RT_WATER_MORPHA_WITHOUT_HOOKSHOT) && HasItem(RG_BRONZE_SCALE))) &&
(CanUseSword() || CanUse(RG_MEGATON_HAMMER));
case RE_BONGO_BONGO:
return HasBossSoul(RG_BONGO_BONGO_SOUL) &&
(CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_BONGO)) && CanUseSword() &&
@ -827,6 +838,11 @@ bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
case RE_PURPLE_LEEVER:
case RE_OCTOROK:
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:
// hammer jumpslash can pass, but only on flat land where you can kill with hammer swing
return CanUse(RG_NUTS) || CanUse(RG_BOOMERANG);
@ -835,6 +851,7 @@ bool Logic::CanPassEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
case RE_GIBDO:
case RE_REDEAD:
// 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);
case RE_IRON_KNUCKLE:
case RE_BIG_OCTO:
@ -1300,16 +1317,6 @@ bool Logic::TradeQuestStep(RandomizerGet rg) {
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() {
return CanUse(RG_MIRROR_SHIELD) || (IsAdult && HasItem(RG_HYLIAN_SHIELD)) || CanUse(RG_DEKU_SHIELD);
}
@ -1432,7 +1439,7 @@ bool Logic::SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless
}*/
return GetSmallKeyCount(SCENE_TREASURE_BOX_SHOP) >= requiredAmountGlitchless;
case RR_GERUDO_FORTRESS:
case RR_GF_OUTSKIRTS:
return GetSmallKeyCount(SCENE_THIEVES_HIDEOUT) >= requiredAmountGlitchless;
default:
@ -2462,7 +2469,10 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
// Events
ShowedMidoSwordAndShield = false;
CarpenterRescue = false;
THCouldFree1TorchCarpenter = false;
THCouldFreeDoubleCellCarpenter = false;
TH_CouldFreeDeadEndCarpenter = false;
THCouldRescueSlopeCarpenter = false;
GF_GateOpen = false;
GtG_GateOpen = false;
DampesWindmillAccess = false;
@ -2515,7 +2525,7 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
MQWaterStalfosPit = false;
MQWaterDragonTorches = false;
MQWaterB1Switch = false;
// MQWaterPillarSoTBlock = false;
// MQWaterPillarSoTBlock = false;
MQWaterOpenedPillarB1 = false;
MQSpiritCrawlBoulder = false;
MQSpiritMapRoomEnemies = false;

View file

@ -110,7 +110,11 @@ class Logic {
// Events
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 GtG_GateOpen = false;
bool DampesWindmillAccess = false;
@ -189,6 +193,7 @@ class Logic {
bool CanOpenOverworldDoor(RandomizerGet itemName);
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmount);
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched);
bool CanOpenUnderwaterChest();
bool CanDoGlitch(GlitchType glitch);
bool CanEquipSwap(RandomizerGet itemName);
bool CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance = ED_CLOSE, bool wallOrFloor = true,
@ -245,7 +250,6 @@ class Logic {
bool HasFireSource();
bool HasFireSourceWithTorch();
bool TradeQuestStep(RandomizerGet rg);
bool CanFinishGerudoFortress();
bool CanStandingShield();
bool CanShield();
bool CanUseProjectile();

View file

@ -1706,22 +1706,22 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
{ 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_2, RAND_INF_KF_BROTHERS_HOUSE_POT_2 },
{ RC_GF_BREAK_ROOM_POT_1, RAND_INF_GF_BREAK_ROOM_POT_1 },
{ RC_GF_BREAK_ROOM_POT_2, RAND_INF_GF_BREAK_ROOM_POT_2 },
{ RC_GF_KITCHEN_POT_1, RAND_INF_GF_KITCHEN_POT_1 },
{ RC_GF_KITCHEN_POT_2, RAND_INF_GF_KITCHEN_POT_2 },
{ RC_GF_NORTH_F1_CARPENTER_POT_1, RAND_INF_GF_NORTH_F1_CARPENTER_POT_1 },
{ RC_GF_NORTH_F1_CARPENTER_POT_2, RAND_INF_GF_NORTH_F1_CARPENTER_POT_2 },
{ RC_GF_NORTH_F1_CARPENTER_POT_3, RAND_INF_GF_NORTH_F1_CARPENTER_POT_3 },
{ RC_GF_NORTH_F2_CARPENTER_POT_1, RAND_INF_GF_NORTH_F2_CARPENTER_POT_1 },
{ RC_GF_NORTH_F2_CARPENTER_POT_2, RAND_INF_GF_NORTH_F2_CARPENTER_POT_2 },
{ RC_GF_SOUTH_F1_CARPENTER_POT_1, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_1 },
{ RC_GF_SOUTH_F1_CARPENTER_POT_2, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_2 },
{ RC_GF_SOUTH_F1_CARPENTER_POT_3, RAND_INF_GF_SOUTH_F1_CARPENTER_POT_3 },
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_1 },
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_2 },
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_3 },
{ RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_4 },
{ RC_TH_BREAK_ROOM_FRONT_POT, RAND_INF_TH_BREAK_ROOM_FRONT_POT },
{ RC_TH_BREAK_ROOM_BACK_POT, RAND_INF_TH_BREAK_ROOM_BACK_POT },
{ RC_TH_KITCHEN_POT_1, RAND_INF_TH_KITCHEN_POT_1 },
{ RC_TH_KITCHEN_POT_2, RAND_INF_TH_KITCHEN_POT_2 },
{ RC_TH_1_TORCH_CELL_RIGHT_POT, RAND_INF_TH_1_TORCH_CELL_RIGHT_POT },
{ RC_TH_1_TORCH_CELL_MID_POT, RAND_INF_TH_1_TORCH_CELL_MID_POT },
{ RC_TH_1_TORCH_CELL_LEFT_POT, RAND_INF_TH_1_TORCH_CELL_LEFT_POT },
{ RC_TH_STEEP_SLOPE_RIGHT_POT, RAND_INF_TH_STEEP_SLOPE_RIGHT_POT },
{ RC_TH_STEEP_SLOPE_LEFT_POT, RAND_INF_TH_STEEP_SLOPE_LEFT_POT },
{ RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT, RAND_INF_TH_NEAR_DOUBLE_CELL_RIGHT_POT },
{ RC_TH_NEAR_DOUBLE_CELL_MID_POT, RAND_INF_TH_NEAR_DOUBLE_CELL_MID_POT },
{ RC_TH_NEAR_DOUBLE_CELL_LEFT_POT, RAND_INF_NEAR_DOUBLE_CELL_LEFT_POT },
{ RC_TH_RIGHTMOST_JAILED_POT, RAND_INF_TH_RIGHTMOST_JAILED_POT },
{ RC_TH_RIGHT_MIDDLE_JAILED_POT, RAND_INF_TH_RIGHT_MIDDLE_JAILED_POT },
{ RC_TH_LEFT_MIDDLE_JAILED_POT, RAND_INF_TH_LEFT_MIDDLE_JAILED_POT },
{ 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_2, RAND_INF_WASTELAND_NEAR_GS_POT_2 },
{ 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,
},
{
RC_GF_OUTSIDE_CENTER_CRATE_1,
RAND_INF_GF_OUTSIDE_CENTER_CRATE_1,
RC_GF_SOUTHMOST_CENTER_CRATE,
RAND_INF_GF_SOUTHMOST_CENTER_CRATE,
},
{
RC_GF_OUTSIDE_CENTER_CRATE_2,
RAND_INF_GF_OUTSIDE_CENTER_CRATE_2,
RC_GF_MID_SOUTH_CENTER_CRATE,
RAND_INF_GF_MID_SOUTH_CENTER_CRATE,
},
{
RC_GF_OUTSIDE_CENTER_CRATE_3,
RAND_INF_GF_OUTSIDE_CENTER_CRATE_3,
RC_GF_MID_NORTH_CENTER_CRATE,
RAND_INF_GF_MID_NORTH_CENTER_CRATE,
},
{
RC_GF_OUTSIDE_CENTER_CRATE_4,
RAND_INF_GF_OUTSIDE_CENTER_CRATE_4,
RR_GF_NORTHMOST_CENTER_CRATE,
RAND_INF_GF_NORTHMOST_CENTER_CRATE,
},
{
RC_GF_OUTSIDE_LEFT_CRATE_1,
RAND_INF_GF_OUTSIDE_LEFT_CRATE_1,
RC_GF_OUTSKIRTS_NE_CRATE,
RAND_INF_GF_OUTSKIRTS_NE_CRATE,
},
{
RC_GF_OUTSIDE_LEFT_CRATE_2,
RAND_INF_GF_OUTSIDE_LEFT_CRATE_2,
RC_GF_OUTSKIRTS_NW_CRATE,
RAND_INF_GF_OUTSKIRTS_NW_CRATE,
},
{
RC_GF_ARCHERY_RANGE_CRATE_1,
RAND_INF_GF_ARCHERY_RANGE_CRATE_1,
RC_GF_HBA_RANGE_CRATE_1,
RAND_INF_GF_HBA_RANGE_CRATE_1,
},
{
RC_GF_ARCHERY_RANGE_CRATE_2,
RAND_INF_GF_ARCHERY_RANGE_CRATE_2,
RC_GF_HBA_RANGE_CRATE_2,
RAND_INF_GF_HBA_RANGE_CRATE_2,
},
{
RC_GF_ARCHERY_RANGE_CRATE_3,
RAND_INF_GF_ARCHERY_RANGE_CRATE_3,
RC_GF_HBA_RANGE_CRATE_3,
RAND_INF_GF_HBA_RANGE_CRATE_3,
},
{
RC_GF_ARCHERY_RANGE_CRATE_4,
RAND_INF_GF_ARCHERY_RANGE_CRATE_4,
RC_GF_HBA_RANGE_CRATE_4,
RAND_INF_GF_HBA_RANGE_CRATE_4,
},
{
RC_GF_ARCHERY_RANGE_CRATE_5,
RAND_INF_GF_ARCHERY_RANGE_CRATE_5,
RC_GF_HBA_RANGE_CRATE_5,
RAND_INF_GF_HBA_RANGE_CRATE_5,
},
{
RC_GF_ARCHERY_RANGE_CRATE_6,
RAND_INF_GF_ARCHERY_RANGE_CRATE_6,
RC_GF_HBA_RANGE_CRATE_6,
RAND_INF_GF_HBA_RANGE_CRATE_6,
},
{
RC_GF_ARCHERY_RANGE_CRATE_7,
RAND_INF_GF_ARCHERY_RANGE_CRATE_7,
RC_GF_HBA_RANGE_CRATE_7,
RAND_INF_GF_HBA_RANGE_CRATE_7,
},
{
RC_GF_ARCHERY_START_CRATE_1,
RAND_INF_GF_ARCHERY_START_CRATE_1,
RC_GF_HBA_CANOPY_EAST_CRATE,
RAND_INF_GF_HBA_CANOPY_EAST_CRATE,
},
{
RC_GF_ARCHERY_START_CRATE_2,
RAND_INF_GF_ARCHERY_START_CRATE_2,
RC_GF_HBA_CANOPY_WEST_CRATE,
RAND_INF_GF_HBA_CANOPY_WEST_CRATE,
},
{
RC_GF_ARCHERY_LEFT_END_CRATE_1,
RAND_INF_GF_ARCHERY_LEFT_END_CRATE_1,
RC_GF_NORTH_TARGET_EAST_CRATE,
RAND_INF_GF_NORTH_TARGET_EAST_CRATE,
},
{
RC_GF_ARCHERY_LEFT_END_CRATE_2,
RAND_INF_GF_ARCHERY_LEFT_END_CRATE_2,
RC_GF_NORTH_TARGET_WEST_CRATE,
RAND_INF_GF_NORTH_TARGET_WEST_CRATE,
},
{
RC_GF_ARCHERY_LEFT_END_CHILD_CRATE,
RAND_INF_GF_ARCHERY_LEFT_END_CHILD_CRATE,
RC_GF_NORTH_TARGET_CHILD_CRATE,
RAND_INF_GF_NORTH_TARGET_CHILD_CRATE,
},
{
RC_GF_ARCHERY_RIGHT_END_CRATE_1,
RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_1,
RC_GF_SOUTH_TARGET_EAST_CRATE,
RAND_INF_GF_SOUTH_TARGET_EAST_CRATE,
},
{
RC_GF_ARCHERY_RIGHT_END_CRATE_2,
RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_2,
RC_GF_SOUTH_TARGET_WEST_CRATE,
RAND_INF_GF_SOUTH_TARGET_WEST_CRATE,
},
{
RC_GF_KITCHEN_CRATE_1,
RAND_INF_GF_KITCHEN_CRATE_1,
RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
RAND_INF_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
},
{
RC_GF_KITCHEN_CRATE_2,
RAND_INF_GF_KITCHEN_CRATE_2,
RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
RAND_INF_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
},
{
RC_GF_KITCHEN_CRATE_3,
RAND_INF_GF_KITCHEN_CRATE_3,
RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
RAND_INF_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
},
{
RC_GF_KITCHEN_CRATE_4,
RAND_INF_GF_KITCHEN_CRATE_4,
RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
RAND_INF_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
},
{
RC_GF_KITCHEN_CRATE_5,
RAND_INF_GF_KITCHEN_CRATE_5,
RC_TH_KITCHEN_CRATE,
RAND_INF_TH_KITCHEN_CRATE,
},
{
RC_GF_BREAK_ROOM_CRATE_1,
RAND_INF_GF_BREAK_ROOM_CRATE_1,
RC_TH_BREAK_HALLWAY_OUTER_CRATE,
RAND_INF_TH_BREAK_HALLWAY_OUTER_CRATE,
},
{
RC_GF_BREAK_ROOM_CRATE_2,
RAND_INF_GF_BREAK_ROOM_CRATE_2,
RC_TH_BREAK_HALLWAY_INNER_CRATE,
RAND_INF_TH_BREAK_HALLWAY_INNER_CRATE,
},
{
RC_GF_BREAK_ROOM_CRATE_3,
RAND_INF_GF_BREAK_ROOM_CRATE_3,
RC_TH_BREAK_ROOM_RIGHT_CRATE,
RAND_INF_TH_BREAK_ROOM_RIGHT_CRATE,
},
{
RC_GF_BREAK_ROOM_CRATE_4,
RAND_INF_GF_BREAK_ROOM_CRATE_4,
RC_TH_BREAK_ROOM_LEFT_CRATE,
RAND_INF_TH_BREAK_ROOM_LEFT_CRATE,
},
{
RC_GF_NORTH_F1_CARPENTER_CRATE,
RAND_INF_GF_NORTH_F1_CARPENTER_CRATE,
RC_TH_1_TORCH_CELL_CRATE,
RAND_INF_TH_1_TORCH_CELL_CRATE,
},
{
RC_GF_NORTH_F3_CARPENTER_CRATE,
RAND_INF_GF_NORTH_F3_CARPENTER_CRATE,
RC_TH_DEAD_END_CELL_CRATE,
RAND_INF_TH_DEAD_END_CELL_CRATE,
},
{
RC_GF_SOUTH_F2_CARPENTER_CRATE_1,
RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_1,
RC_TH_DOUBLE_CELL_LEFT_CRATE,
RAND_INF_TH_DOUBLE_CELL_LEFT_CRATE,
},
{
RC_GF_SOUTH_F2_CARPENTER_CRATE_2,
RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_2,
RC_TH_DOUBLE_CELL_RIGHT_CRATE,
RAND_INF_TH_DOUBLE_CELL_RIGHT_CRATE,
},
{
RC_HW_BEFORE_QUICKSAND_CRATE,

View file

@ -418,9 +418,34 @@ typedef enum {
RR_GV_FORTRESS_SIDE,
RR_GV_CARPENTER_TENT,
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_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_HAUNTED_WASTELAND,
RR_WASTELAND_NEAR_COLOSSUS,
@ -1393,13 +1418,13 @@ typedef enum {
RC_GF_CHEST,
RC_GF_HBA_1000_POINTS,
RC_GF_HBA_1500_POINTS,
RC_GF_GERUDO_MEMBERSHIP_CARD,
RC_GF_NORTH_F1_CARPENTER,
RC_GF_NORTH_F2_CARPENTER,
RC_GF_SOUTH_F1_CARPENTER,
RC_GF_SOUTH_F2_CARPENTER,
RC_TH_FREED_CARPENTERS,
RC_TH_1_TORCH_CARPENTER,
RC_TH_DEAD_END_CARPENTER,
RC_TH_DOUBLE_CELL_CARPENTER,
RC_TH_STEEP_SLOPE_CARPENTER,
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_2_TORCHES,
RC_HIDEOUT_JAIL_GUARD_3_TORCHES,
@ -1817,22 +1842,22 @@ typedef enum {
RC_KF_TWINS_HOUSE_POT_2,
RC_KF_BROTHERS_HOUSE_POT_1,
RC_KF_BROTHERS_HOUSE_POT_2,
RC_GF_BREAK_ROOM_POT_1,
RC_GF_BREAK_ROOM_POT_2,
RC_GF_KITCHEN_POT_1,
RC_GF_KITCHEN_POT_2,
RC_GF_NORTH_F1_CARPENTER_POT_1,
RC_GF_NORTH_F1_CARPENTER_POT_2,
RC_GF_NORTH_F1_CARPENTER_POT_3,
RC_GF_NORTH_F2_CARPENTER_POT_1,
RC_GF_NORTH_F2_CARPENTER_POT_2,
RC_GF_SOUTH_F1_CARPENTER_POT_1,
RC_GF_SOUTH_F1_CARPENTER_POT_2,
RC_GF_SOUTH_F1_CARPENTER_POT_3,
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1,
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2,
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3,
RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4,
RC_TH_BREAK_ROOM_FRONT_POT,
RC_TH_BREAK_ROOM_BACK_POT,
RC_TH_KITCHEN_POT_1,
RC_TH_KITCHEN_POT_2,
RC_TH_1_TORCH_CELL_RIGHT_POT,
RC_TH_1_TORCH_CELL_MID_POT,
RC_TH_1_TORCH_CELL_LEFT_POT,
RC_TH_STEEP_SLOPE_RIGHT_POT,
RC_TH_STEEP_SLOPE_LEFT_POT,
RC_TH_NEAR_DOUBLE_CELL_RIGHT_POT,
RC_TH_NEAR_DOUBLE_CELL_MID_POT,
RC_TH_NEAR_DOUBLE_CELL_LEFT_POT,
RC_TH_RIGHTMOST_JAILED_POT,
RC_TH_RIGHT_MIDDLE_JAILED_POT,
RC_TH_LEFT_MIDDLE_JAILED_POT,
RC_TH_LEFTMOST_JAILED_POT,
RC_WASTELAND_NEAR_GS_POT_1,
RC_WASTELAND_NEAR_GS_POT_2,
RC_WASTELAND_NEAR_GS_POT_3,
@ -2366,39 +2391,39 @@ typedef enum {
RC_GV_CRATE_BRIDGE_3,
RC_GV_CRATE_BRIDGE_4,
RC_GF_ABOVE_JAIL_CRATE,
RC_GF_OUTSIDE_CENTER_CRATE_1,
RC_GF_OUTSIDE_CENTER_CRATE_2,
RC_GF_OUTSIDE_CENTER_CRATE_3,
RC_GF_OUTSIDE_CENTER_CRATE_4,
RC_GF_OUTSIDE_LEFT_CRATE_1,
RC_GF_OUTSIDE_LEFT_CRATE_2,
RC_GF_ARCHERY_RANGE_CRATE_1,
RC_GF_ARCHERY_RANGE_CRATE_2,
RC_GF_ARCHERY_RANGE_CRATE_3,
RC_GF_ARCHERY_RANGE_CRATE_4,
RC_GF_ARCHERY_RANGE_CRATE_5,
RC_GF_ARCHERY_RANGE_CRATE_6,
RC_GF_ARCHERY_RANGE_CRATE_7,
RC_GF_ARCHERY_START_CRATE_1,
RC_GF_ARCHERY_START_CRATE_2,
RC_GF_ARCHERY_LEFT_END_CRATE_1,
RC_GF_ARCHERY_LEFT_END_CRATE_2,
RC_GF_ARCHERY_LEFT_END_CHILD_CRATE,
RC_GF_ARCHERY_RIGHT_END_CRATE_1,
RC_GF_ARCHERY_RIGHT_END_CRATE_2,
RC_GF_KITCHEN_CRATE_1,
RC_GF_KITCHEN_CRATE_2,
RC_GF_KITCHEN_CRATE_3,
RC_GF_KITCHEN_CRATE_4,
RC_GF_KITCHEN_CRATE_5,
RC_GF_BREAK_ROOM_CRATE_1,
RC_GF_BREAK_ROOM_CRATE_2,
RC_GF_BREAK_ROOM_CRATE_3,
RC_GF_BREAK_ROOM_CRATE_4,
RC_GF_NORTH_F1_CARPENTER_CRATE,
RC_GF_NORTH_F3_CARPENTER_CRATE,
RC_GF_SOUTH_F2_CARPENTER_CRATE_1,
RC_GF_SOUTH_F2_CARPENTER_CRATE_2,
RC_GF_SOUTHMOST_CENTER_CRATE,
RC_GF_MID_SOUTH_CENTER_CRATE,
RC_GF_MID_NORTH_CENTER_CRATE,
RR_GF_NORTHMOST_CENTER_CRATE,
RC_GF_OUTSKIRTS_NE_CRATE,
RC_GF_OUTSKIRTS_NW_CRATE,
RC_GF_HBA_RANGE_CRATE_1,
RC_GF_HBA_RANGE_CRATE_2,
RC_GF_HBA_RANGE_CRATE_3,
RC_GF_HBA_RANGE_CRATE_4,
RC_GF_HBA_RANGE_CRATE_5,
RC_GF_HBA_RANGE_CRATE_6,
RC_GF_HBA_RANGE_CRATE_7,
RC_GF_HBA_CANOPY_EAST_CRATE,
RC_GF_HBA_CANOPY_WEST_CRATE,
RC_GF_NORTH_TARGET_EAST_CRATE,
RC_GF_NORTH_TARGET_WEST_CRATE,
RC_GF_NORTH_TARGET_CHILD_CRATE,
RC_GF_SOUTH_TARGET_EAST_CRATE,
RC_GF_SOUTH_TARGET_WEST_CRATE,
RC_TH_NEAR_KITCHEN_LEFTMOST_CRATE,
RC_TH_NEAR_KITCHEN_MID_LEFT_CRATE,
RC_TH_NEAR_KITCHEN_MID_RIGHT_CRATE,
RC_TH_NEAR_KITCHEN_RIGHTMOST_CRATE,
RC_TH_KITCHEN_CRATE,
RC_TH_BREAK_HALLWAY_OUTER_CRATE,
RC_TH_BREAK_HALLWAY_INNER_CRATE,
RC_TH_BREAK_ROOM_RIGHT_CRATE,
RC_TH_BREAK_ROOM_LEFT_CRATE,
RC_TH_1_TORCH_CELL_CRATE,
RC_TH_DEAD_END_CELL_CRATE,
RC_TH_DOUBLE_CELL_LEFT_CRATE,
RC_TH_DOUBLE_CELL_RIGHT_CRATE,
RC_HW_BEFORE_QUICKSAND_CRATE,
RC_HW_AFTER_QUICKSAND_CRATE_1,
RC_HW_AFTER_QUICKSAND_CRATE_2,
@ -3112,7 +3137,7 @@ typedef enum {
RC_DMT_FLAG_SUN_FAIRY,
RC_DMT_COW_GROTTO_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_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
RC_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
@ -3506,11 +3531,13 @@ typedef enum {
RT_HOVER_BOOST_SIMPLE,
RT_BOMBCHU_BEEHIVES,
RT_BLUE_FIRE_MUD_WALLS,
RT_OPEN_UNDERWATER_CHEST,
RT_KF_ADULT_GS, // -- location tricks
RT_LW_BRIDGE,
RT_LW_MIDO_BACKFLIP,
RT_LW_GS_BEAN,
RT_HC_STORMS_GS,
RT_HF_BIG_POE_WITHOUT_EPONA,
RT_KAK_MAN_ON_ROOF,
RT_KAK_TOWER_GS,
RT_KAK_ADULT_WINDMILL_POH,
@ -3549,7 +3576,7 @@ typedef enum {
RT_LH_LAB_DIVING,
RT_LH_WATER_HOOKSHOT,
RT_GV_CRATE_HOVERS,
RT_GF_KITCHEN,
RT_PASS_GUARDS_WITH_NOTHING,
RT_GF_JUMP,
RT_GF_WARRIOR_WITH_DIFFICULT_WEAPON,
RT_HW_BUNNY_CROSSING,
@ -3565,14 +3592,16 @@ typedef enum {
RT_DEKU_MQ_LOG,
RT_DC_SCARECROW_GS,
RT_DC_VINES_GS,
RT_DC_STAIRCASE,
RT_DC_STAIRS_WITH_BOW,
RT_DC_SLINGSHOT_SKIP,
RT_DC_SCRUB_ROOM,
RT_DC_JUMP,
RT_DC_HAMMER_FLOOR,
RT_DC_MQ_STAIRS_WITH_ONLY_STRENGTH,
RT_DC_MQ_CHILD_BOMBS,
RT_DC_MQ_CHILD_EYES,
RT_DC_MQ_ADULT_EYES,
RT_DC_DODONGO_CHU,
RT_JABU_ALCOVE_JUMP_DIVE,
RT_JABU_BOSS_HOVER,
RT_JABU_NEAR_BOSS_RANGED,
@ -3628,6 +3657,7 @@ typedef enum {
RT_WATER_CHILD_DRAGON,
RT_WATER_MQ_CENTRAL_PILLAR,
RT_WATER_MQ_LOCKED_GS,
RT_WATER_MORPHA_WITHOUT_HOOKSHOT,
RT_LENS_SHADOW,
RT_LENS_SHADOW_PLATFORM,
RT_LENS_BONGO,
@ -3666,7 +3696,7 @@ typedef enum {
RT_GTG_FAKE_WALL,
RT_LENS_GTG_MQ,
RT_GTG_MQ_WITH_HOOKSHOT,
RT_GTG_MQ_WIHTOUT_HOOKSHOT,
RT_GTG_MQ_WITHOUT_HOOKSHOT,
RT_LENS_GANON,
RT_GANON_SPIRIT_TRIAL_HOOKSHOT,
RT_LENS_GANON_MQ,
@ -4499,11 +4529,11 @@ typedef enum {
RHT_GF_CHEST,
RHT_GF_HBA_1000_POINTS,
RHT_GF_HBA_1500_POINTS,
RHT_GF_GERUDO_MEMBERSHIP_CARD,
RHT_GF_NORTH_F1_CARPENTER,
RHT_GF_NORTH_F2_CARPENTER,
RHT_GF_SOUTH_F1_CARPENTER,
RHT_GF_SOUTH_F2_CARPENTER,
RHT_TH_FREED_CARPENTERS,
RHT_TH_1_TORCH_CARPENTER,
RHT_TH_DEAD_END_CARPENTER,
RHT_TH_DOUBLE_CELL_CARPENTER,
RHT_TH_STEEP_SLOPE_CARPENTER,
RHT_GF_GS_TOP_FLOOR,
RHT_GF_GS_ARCHERY_RANGE,
RHT_HIDEOUT_JAIL_GUARD_1_TORCH,
@ -5386,7 +5416,22 @@ typedef enum {
RHT_MASK_SHOP_HINT,
// Shuffle Pots
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_MARKET,
RHT_POT_KAKARIKO,
@ -5576,7 +5621,7 @@ typedef enum {
RHT_DMT_FLAG_SUN_FAIRY,
RHT_DMT_COW_GROTTO_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_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY,
RHT_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY,
@ -6449,6 +6494,8 @@ typedef enum {
RE_STINGER,
RE_BIG_OCTO,
RE_GERUDO_WARRIOR,
RE_GERUDO_GUARD,
RE_BREAK_ROOM_GUARD,
RE_GIBDO,
RE_GOHMA,
RE_KING_DODONGO,

View file

@ -233,20 +233,20 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
(location.GetRandomizerCheck() != RC_KAK_100_GOLD_SKULLTULA_REWARD ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) !=
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) ==
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) ==
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) ||
(location.GetRandomizerCheck() == RC_GF_NORTH_F1_CARPENTER &&
(location.GetRandomizerCheck() == RC_TH_1_TORCH_CARPENTER &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=
RO_GERUDO_KEYS_VANILLA))) ||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), 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) ||
(location.GetRCType() == RCTYPE_GF_KEY &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) !=

View file

@ -759,7 +759,7 @@ void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
if ((flag == EVENTCHKINF_CARPENTERS_FREE(0) || flag == EVENTCHKINF_CARPENTERS_FREE(1) ||
flag == EVENTCHKINF_CARPENTERS_FREE(2) || flag == EVENTCHKINF_CARPENTERS_FREE(3)) &&
GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) {
SetCheckCollected(RC_GF_GERUDO_MEMBERSHIP_CARD);
SetCheckCollected(RC_TH_FREED_CARPENTERS);
return;
}
checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF;
@ -1589,10 +1589,10 @@ bool IsCheckShuffled(RandomizerCheck rc) {
(loc->GetRCType() != RCTYPE_BOSS_KEY || showBossKeysanity) &&
(loc->GetRCType() != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
(rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
(loc->GetRCType() != RCTYPE_GF_KEY && rc != RC_GF_GERUDO_MEMBERSHIP_CARD ||
(showGerudoCard && rc == RC_GF_GERUDO_MEMBERSHIP_CARD) ||
(loc->GetRCType() != RCTYPE_GF_KEY && rc != RC_TH_FREED_CARPENTERS ||
(showGerudoCard && rc == RC_TH_FREED_CARPENTERS) ||
(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()) {
return (OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) || rc == RC_GIFT_FROM_RAURU) &&
rc != RC_LINKS_POCKET;

View file

@ -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_BROTHERS_HOUSE_POT_1)
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_GF_BREAK_ROOM_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_POT_1)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_1)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_POT_3)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F2_CARPENTER_POT_1)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F2_CARPENTER_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_1)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_POT_3)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_1)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_2)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_3)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F1_CARPENTER_CELL_POT_4)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_FRONT_POT)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_BACK_POT)
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_POT_1)
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_POT_2)
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_RIGHT_POT)
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_MID_POT)
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_LEFT_POT)
DEFINE_RAND_INF(RAND_INF_TH_STEEP_SLOPE_RIGHT_POT)
DEFINE_RAND_INF(RAND_INF_TH_STEEP_SLOPE_LEFT_POT)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_DOUBLE_CELL_RIGHT_POT)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_DOUBLE_CELL_MID_POT)
DEFINE_RAND_INF(RAND_INF_NEAR_DOUBLE_CELL_LEFT_POT)
DEFINE_RAND_INF(RAND_INF_TH_RIGHTMOST_JAILED_POT)
DEFINE_RAND_INF(RAND_INF_TH_RIGHT_MIDDLE_JAILED_POT)
DEFINE_RAND_INF(RAND_INF_TH_LEFT_MIDDLE_JAILED_POT)
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_2)
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_4)
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_OUTSIDE_CENTER_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_3)
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_CENTER_CRATE_4)
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_LEFT_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_OUTSIDE_LEFT_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_3)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_4)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_5)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_6)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RANGE_CRATE_7)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_START_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_START_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_LEFT_END_CHILD_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_ARCHERY_RIGHT_END_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_3)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_4)
DEFINE_RAND_INF(RAND_INF_GF_KITCHEN_CRATE_5)
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_3)
DEFINE_RAND_INF(RAND_INF_GF_BREAK_ROOM_CRATE_4)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F1_CARPENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_F3_CARPENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_F2_CARPENTER_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_SOUTHMOST_CENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_MID_SOUTH_CENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_MID_NORTH_CENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_NORTHMOST_CENTER_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_OUTSKIRTS_NE_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_OUTSKIRTS_NW_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_1)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_2)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_3)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_4)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_5)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_6)
DEFINE_RAND_INF(RAND_INF_GF_HBA_RANGE_CRATE_7)
DEFINE_RAND_INF(RAND_INF_GF_HBA_CANOPY_EAST_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_HBA_CANOPY_WEST_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_EAST_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_WEST_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_NORTH_TARGET_CHILD_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_TARGET_EAST_CRATE)
DEFINE_RAND_INF(RAND_INF_GF_SOUTH_TARGET_WEST_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_LEFTMOST_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_MID_LEFT_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_MID_RIGHT_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_NEAR_KITCHEN_RIGHTMOST_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_KITCHEN_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_HALLWAY_OUTER_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_HALLWAY_INNER_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_RIGHT_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_BREAK_ROOM_LEFT_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_1_TORCH_CELL_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_DEAD_END_CELL_CRATE)
DEFINE_RAND_INF(RAND_INF_TH_DOUBLE_CELL_LEFT_CRATE)
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_AFTER_QUICKSAND_CRATE_1)
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_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_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_HF_FENCE_GROTTO_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_GRAVEYARD_ROYAL_FAMILYS_TOMB_SUN_FAIRY)
DEFINE_RAND_INF(RAND_INF_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY)

View file

@ -403,6 +403,9 @@ void Settings::CreateOptions() {
"apply to MQ Dead Hand bomb flowers.\nUsing blue fire on bombflower to stop rolling goron also requires "
"\"Stop Link the Goron with Din's Fire\".\nUsing blue fire arrows to break floor in King Dodongo's "
"chamber also requires \"Dodongo\'s Cavern Smash the Boss Lobby Floor\".");
OPT_TRICK(RT_OPEN_UNDERWATER_CHEST, RCQUEST_BOTH, RA_NONE, { Tricks::Tag::NOVICE, Tricks::Tag::GLITCH },
"Open Underwater Chests",
"Underwater chests can be opened by wearing iron boots and hookshotting the chest.");
OPT_TRICK(RT_KF_ADULT_GS, RCQUEST_BOTH, RA_KOKIRI_FOREST, { Tricks::Tag::NOVICE },
"Adult Kokiri Forest GS with Hover Boots",
"Can be obtained without Hookshot by using the Hover Boots off of one of the roots.");
@ -423,6 +426,9 @@ void Settings::CreateOptions() {
"Hyrule Castle Storms Grotto GS with Just Boomerang",
"With precise throws, the Boomerang alone can kill the Skulltula and collect the token, without first "
"needing to blow up the wall.");
OPT_TRICK(RT_HF_BIG_POE_WITHOUT_EPONA, RCQUEST_BOTH, RA_HYRULE_FIELD, { Tricks::Tag::NOVICE },
"Big Poe without Epona",
"Big Poes have a chance of appearing without Epona, you can shoot them quickly with only bow.");
OPT_TRICK(RT_KAK_MAN_ON_ROOF, RCQUEST_BOTH, RA_KAKARIKO_VILLAGE, { Tricks::Tag::NOVICE },
"Man on Roof without Hookshot",
"Can be reached by side-hopping off the watchtower as either age, or by jumping onto the potion shop's "
@ -555,7 +561,7 @@ void Settings::CreateOptions() {
"A precise jump slash can kill the Skulltula and recoil back onto the top of the frozen waterfall. To "
"kill it, the logic normally guarantees one of Hookshot, Bow, or Magic.");
OPT_TRICK(RT_ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES, RCQUEST_BOTH, RA_ZORAS_FOUNTAIN, { Tricks::Tag::NOVICE },
"Zora\'s Fountain Great Fairy Without Explosives",
"Zora\'s Fountain Great Fairy without Explosives",
"It's possible to use silver gauntlets to pick up the silver rock and hammer to break the rock below it, "
"allowing you to ledge grab the edge of the hole and get past the breakable wall (hammer can't break the "
"wall itself).");
@ -574,13 +580,13 @@ void Settings::CreateOptions() {
"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 "
"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 },
"Thieves\' Hideout \"Kitchen\" with No Additional Items",
"Allows passing through the kitchen by avoiding being seen by the guards. The logic normally guarantees "
"Bow or Hookshot to stun them from a distance, or Hover Boots to cross the room without needing to deal "
"with the guards.");
OPT_TRICK(RT_PASS_GUARDS_WITH_NOTHING, RCQUEST_BOTH, RA_GERUDO_FORTRESS, { Tricks::Tag::NOVICE },
"Sneak Past Moving Gerudo Guards with No Items",
"The logic normally guarantees Bow or Hookshot to stun them from a distance,"
"but every moving guard can be passed with basic movement and AI manipulation");
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 },
"Gerudo\'s Fortress Warriors with Difficult Weapons",
"Warriors can be defeated with Slingshot or Bombchus.");
@ -640,8 +646,8 @@ void Settings::CreateOptions() {
"Dodongo\'s Cavern Vines GS from Below with Longshot",
"The vines upon which this Skulltula rests are one-sided collision. You can use the Longshot to get it "
"from below, by shooting it through the vines, bypassing the need to lower the staircase.");
OPT_TRICK(RT_DC_STAIRCASE, RCQUEST_VANILLA, RA_DODONGOS_CAVERN, { Tricks::Tag::NOVICE },
"Dodongo\'s Cavern Staircase with Bow",
OPT_TRICK(RT_DC_STAIRS_WITH_BOW, RCQUEST_VANILLA, RA_DODONGOS_CAVERN, { Tricks::Tag::NOVICE },
"Dodongo\'s Cavern Stairs with Bow",
"The Bow can be used to knock down the stairs with two well-timed shots.");
OPT_TRICK(RT_DC_SLINGSHOT_SKIP, RCQUEST_VANILLA, RA_DODONGOS_CAVERN, { Tricks::Tag::EXPERT },
"Dodongo\'s Cavern Child Slingshot Skips",
@ -660,6 +666,12 @@ void Settings::CreateOptions() {
"The bombable floor before King Dodongo can be destroyed with Hammer if hit in the very center. This is "
"only relevant with Shuffle Boss Entrances or if Dodongo's Cavern is MQ and either variant of "
"\"Dodongo's Cavern MQ Light the Eyes with Strength\" is on.");
OPT_TRICK(RT_DC_DODONGO_CHU, RCQUEST_BOTH, RA_DODONGOS_CAVERN, { Tricks::Tag::ADVANCED },
"Dodongo\'s Cavern Dodongo without Bombchus",
"With precise timing you can feed King Dodongo a bombchu during a backflip");
OPT_TRICK(RT_DC_MQ_STAIRS_WITH_ONLY_STRENGTH, RCQUEST_MQ, RA_DODONGOS_CAVERN, { Tricks::Tag::NOVICE },
"Dodongo\'s Cavern MQ Stairs With Only Strength",
"Taking a bomb from the back can be used to lower stairs without using stick to drop bomb from wall.");
OPT_TRICK(RT_DC_MQ_CHILD_BOMBS, RCQUEST_MQ, RA_DODONGOS_CAVERN, { Tricks::Tag::ADVANCED },
"Dodongo\'s Cavern MQ Early Bomb Bag Area as Child",
"With a precise jump slash from above, you can reach the Bomb Bag area as only child without needing a "
@ -938,6 +950,8 @@ void Settings::CreateOptions() {
"Water Temple MQ North Basement GS without Small Key",
"There is an invisible Hookshot target that can be used to get over the gate that blocks you from going to "
"this Skulltula early, skipping a small key as well as needing Hovers or Scarecrow to reach the locked door.");
OPT_TRICK(RT_WATER_MORPHA_WITHOUT_HOOKSHOT, RCQUEST_BOTH, RA_WATER_TEMPLE, { Tricks::Tag::EXTREME },
"Water Temple Morpha without Hookshot", "It is possible to slash at Morpha without hookshot.");
OPT_TRICK(RT_LENS_SHADOW, RCQUEST_VANILLA, RA_SHADOW_TEMPLE, { Tricks::Tag::NOVICE },
"Shadow Temple Stationary Objects without Lens of Truth",
"Removes the requirements for the Lens of Truth in Shadow Temple for most areas in the dungeon except "
@ -1100,7 +1114,7 @@ void Settings::CreateOptions() {
"Gerudo Training Ground MQ Left Side Silver Rupees with Hookshot",
"The highest Silver Rupee can be obtained by hookshooting the target and then immediately jump slashing "
"toward the Rupee.");
OPT_TRICK(RT_GTG_MQ_WIHTOUT_HOOKSHOT, RCQUEST_MQ, RA_GERUDO_TRAINING_GROUND, { Tricks::Tag::INTERMEDIATE },
OPT_TRICK(RT_GTG_MQ_WITHOUT_HOOKSHOT, RCQUEST_MQ, RA_GERUDO_TRAINING_GROUND, { Tricks::Tag::INTERMEDIATE },
"Gerudo Training Ground MQ Left Side Silver Rupees without Hookshot",
"After collecting the rest of the Silver Rupees in the room, you can reach the final Silver Rupee on the "
"ceiling by being pulled up into it after getting grabbed by the Wallmaster. The Wallmaster will not "

View file

@ -420,12 +420,19 @@ void OTRGlobals::Initialize() {
static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSampleV2>(), RESOURCE_FORMAT_BINARY,
"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>(),
RESOURCE_FORMAT_BINARY, "AudioSoundFont",
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>(),
RESOURCE_FORMAT_BINARY, "AudioSequence",
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,
"Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
@ -616,6 +623,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() {
// Tell the audio thread to stop
{
@ -626,6 +639,19 @@ extern "C" void OTRAudio_Exit() {
// Wait until the audio thread quit
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() {
@ -1085,6 +1111,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) {
auto rel = std::filesystem::relative(path, base);
return !rel.empty() && rel.native()[0] != '.';

View file

@ -171,6 +171,7 @@ void CheckTracker_RecalculateAvailableChecks();
GetItemID RetrieveGetItemIDFromItemID(ItemID itemID);
RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID);
void Messagebox_ShowErrorBox(char* title, char* body);
#endif
#ifdef __cplusplus

View file

@ -429,11 +429,16 @@ extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) {
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) {
return (SoundFontSample*)ResourceGetDataByName(path);
}
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) {
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFontByName(const char* path) {
return (SoundFont*)ResourceGetDataByName(path);
}

View file

@ -51,8 +51,9 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
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_LoadSeqPtrByName(const char* path);
SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
bool ResourceMgr_IsAltAssetsEnabled();

View file

@ -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 <stdint.h>
#include <string.h>
#include <stdio.h>
#include "mixer.h"
#ifndef __clang__
#pragma GCC optimize("unroll-loops")
#endif
@ -66,6 +68,9 @@ static int16_t resample_table[64][4] = {
{ 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) {
if (v < -0x8000) {
return -0x8000;
@ -99,6 +104,33 @@ void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbyte
#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) {
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);
}
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));
int16_t* in = BUF_S16(in_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) {
uint8_t* in = BUF_U8(rspa.in);
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);
} 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

View file

@ -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 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) \
do { \
} while (0)

View file

@ -1,6 +1,193 @@
#include "soh/resource/importer/AudioSampleFactory.h"
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSample.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 {
std::shared_ptr<Ship::IResource>
@ -16,108 +203,154 @@ ResourceFactoryBinaryAudioSampleV2::ReadResource(std::shared_ptr<Ship::File> fil
audioSample->sample.codec = reader->ReadUByte();
audioSample->sample.medium = 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->audioSampleData.reserve(audioSample->sample.size);
audioSample->sample.sampleAddr = new uint8_t[audioSample->sample.size];
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.end = 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++) {
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->sample.loop = &audioSample->loop;
audioSample->book.order = reader->ReadInt32();
audioSample->book.npredictors = reader->ReadInt32();
audioSample->bookDataCount = reader->ReadUInt32();
uint32_t bookDataCount = reader->ReadUInt32();
audioSample->bookData.reserve(audioSample->bookDataCount);
for (uint32_t i = 0; i < audioSample->bookDataCount; i++) {
audioSample->bookData.push_back(reader->ReadInt16());
audioSample->book.book = new int16_t[bookDataCount];
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;
return audioSample;
}
} // namespace SOH
/*
in ResourceMgr_LoadAudioSample we used to have
--------------
if (cachedCustomSFs.find(path) != cachedCustomSFs.end())
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))
std::shared_ptr<Ship::IResource>
ResourceFactoryXMLAudioSampleV0::ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (!FileHasValidFormatAndReader(file, initData)) {
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

View file

@ -2,6 +2,7 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
namespace SOH {
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::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

View file

@ -1,6 +1,14 @@
#include "soh/resource/importer/AudioSequenceFactory.h"
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSequence.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 {
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 reader = std::get<std::shared_ptr<Ship::BinaryReader>>(file->Reader);
audioSequence->sequence.seqDataSize = reader->ReadInt32();
audioSequence->sequenceData.reserve(audioSequence->sequence.seqDataSize);
audioSequence->sequence.seqDataSize = reader->ReadUInt32();
audioSequence->sequence.seqData = new char[audioSequence->sequence.seqDataSize];
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.medium = reader->ReadUByte();
@ -34,4 +41,355 @@ ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> f
return audioSequence;
}
} // namespace SOH
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

View file

@ -2,6 +2,7 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
namespace SOH {
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::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

View file

@ -1,7 +1,11 @@
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSoundFont.h"
#include "spdlog/spdlog.h"
#include "libultraship/libultraship.h"
#include <tinyxml2.h>
#include <z64.h>
#include "z64audio.h"
#include "Context.h"
#include "resource/archive/Archive.h"
#include "resource/ResourceManager.h"
namespace SOH {
std::shared_ptr<Ship::IResource>
@ -35,117 +39,115 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
audioSoundFont->soundFont.numSfx = soundEffectCount;
// 🥁 DRUMS 🥁
audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
// audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
audioSoundFont->drumAddresses.reserve(audioSoundFont->soundFont.numDrums);
for (uint32_t i = 0; i < audioSoundFont->soundFont.numDrums; i++) {
Drum drum;
drum.releaseRate = reader->ReadUByte();
drum.pan = reader->ReadUByte();
drum.loaded = reader->ReadUByte();
drum.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
Drum* drum = new Drum;
drum->releaseRate = reader->ReadUByte();
drum->pan = reader->ReadUByte();
drum->loaded = reader->ReadUByte();
drum->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
uint32_t envelopeCount = reader->ReadUInt32();
audioSoundFont->drumEnvelopeCounts.push_back(envelopeCount);
std::vector<AdsrEnvelope> drumEnvelopes;
drumEnvelopes.reserve(audioSoundFont->drumEnvelopeCounts[i]);
for (uint32_t j = 0; j < audioSoundFont->drumEnvelopeCounts.back(); j++) {
AdsrEnvelope env;
drum->envelope = new AdsrEnvelope[envelopeCount];
for (uint32_t j = 0; j < envelopeCount; j++) {
int16_t delay = reader->ReadInt16();
int16_t arg = reader->ReadInt16();
env.delay = BE16SWAP(delay);
env.arg = BE16SWAP(arg);
drumEnvelopes.push_back(env);
drum->envelope[j].delay = BE16SWAP(delay);
drum->envelope[j].arg = BE16SWAP(arg);
}
audioSoundFont->drumEnvelopeArrays.push_back(drumEnvelopes);
drum.envelope = audioSoundFont->drumEnvelopeArrays.back().data();
bool hasSample = reader->ReadInt8();
std::string sampleFileName = reader->ReadString();
drum.sound.tuning = reader->ReadFloat();
drum->sound.tuning = reader->ReadFloat();
if (sampleFileName.empty()) {
drum.sound.sample = nullptr;
drum->sound.sample = nullptr;
} else {
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->drumAddresses.push_back(&audioSoundFont->drums.back());
// audioSoundFont->drums.push_back(drum);
// 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();
// 🎺🎻🎷🎸🎹 INSTRUMENTS 🎹🎸🎷🎻🎺
audioSoundFont->instruments.reserve(audioSoundFont->soundFont.numInstruments);
for (uint32_t i = 0; i < audioSoundFont->soundFont.numInstruments; i++) {
Instrument instrument;
Instrument* instrument = new Instrument;
uint8_t isValidEntry = reader->ReadUByte();
instrument.loaded = reader->ReadUByte();
instrument.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
instrument->loaded = reader->ReadUByte();
instrument->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
instrument.normalRangeLo = reader->ReadUByte();
instrument.normalRangeHi = reader->ReadUByte();
instrument.releaseRate = reader->ReadUByte();
instrument->normalRangeLo = reader->ReadUByte();
instrument->normalRangeHi = reader->ReadUByte();
instrument->releaseRate = reader->ReadUByte();
uint32_t envelopeCount = reader->ReadInt32();
audioSoundFont->instrumentEnvelopeCounts.push_back(envelopeCount);
std::vector<AdsrEnvelope> instrumentEnvelopes;
for (uint32_t j = 0; j < audioSoundFont->instrumentEnvelopeCounts.back(); j++) {
AdsrEnvelope env;
instrument->envelope = new AdsrEnvelope[envelopeCount];
for (uint32_t j = 0; j < envelopeCount; j++) {
int16_t delay = reader->ReadInt16();
int16_t arg = reader->ReadInt16();
env.delay = BE16SWAP(delay);
env.arg = BE16SWAP(arg);
instrumentEnvelopes.push_back(env);
instrument->envelope[j].delay = BE16SWAP(delay);
instrument->envelope[j].arg = BE16SWAP(arg);
}
audioSoundFont->instrumentEnvelopeArrays.push_back(instrumentEnvelopes);
instrument.envelope = audioSoundFont->instrumentEnvelopeArrays.back().data();
bool hasLowNoteSoundFontEntry = reader->ReadInt8();
if (hasLowNoteSoundFontEntry) {
bool hasSampleRef = reader->ReadInt8();
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());
instrument.lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.lowNotesSound.sample = nullptr;
instrument.lowNotesSound.tuning = 0;
instrument->lowNotesSound.sample = nullptr;
instrument->lowNotesSound.tuning = 0;
}
bool hasNormalNoteSoundFontEntry = reader->ReadInt8();
if (hasNormalNoteSoundFontEntry) {
// BENTODO remove in V3
bool hasSampleRef = reader->ReadInt8();
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());
instrument.normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.normalNotesSound.sample = nullptr;
instrument.normalNotesSound.tuning = 0;
instrument->normalNotesSound.sample = nullptr;
instrument->normalNotesSound.tuning = 0;
}
bool hasHighNoteSoundFontEntry = reader->ReadInt8();
if (hasHighNoteSoundFontEntry) {
bool hasSampleRef = reader->ReadInt8();
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());
instrument.highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.highNotesSound.sample = nullptr;
instrument.highNotesSound.tuning = 0;
instrument->highNotesSound.sample = nullptr;
instrument->highNotesSound.tuning = 0;
}
audioSoundFont->instruments.push_back(instrument);
audioSoundFont->instrumentAddresses.push_back(isValidEntry ? &audioSoundFont->instruments.back() : nullptr);
if (isValidEntry) {
audioSoundFont->instrumentAddresses.push_back(instrument);
} else {
delete[] instrument->envelope;
delete instrument;
audioSoundFont->instrumentAddresses.push_back(nullptr);
}
}
audioSoundFont->soundFont.instruments = audioSoundFont->instrumentAddresses.data();
@ -169,4 +171,302 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
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

View file

@ -2,6 +2,8 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
#include "soh/resource/type/AudioSoundFont.h"
namespace SOH {
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::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

View file

@ -1,6 +1,14 @@
#include "AudioSample.h"
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() {
return &sample;
}

View file

@ -1,14 +1,13 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Resource.h"
#include <libultraship/libultra/types.h>
namespace SOH {
typedef struct {
/* 0x00 */ uintptr_t start;
/* 0x04 */ uintptr_t end;
/* 0x00 */ u32 start;
/* 0x04 */ u32 end;
/* 0x08 */ u32 count;
/* 0x0C */ char unk_0C[0x4];
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
@ -20,24 +19,26 @@ typedef struct {
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
} AdpcmBook; // s
typedef struct {
typedef struct Sample {
union {
struct {
/* 0x00 */ u32 codec : 4;
/* 0x00 */ u32 medium : 2;
/* 0x00 */ u32 unk_bit26 : 1;
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
/* 0x01 */ u32 size : 24;
///* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
};
u32 asU32;
};
/* 0x04 */ u8* sampleAddr;
/* 0x08 */ AdpcmLoop* loop;
/* 0x0C */ AdpcmBook* book;
u32 sampleRateMagicValue; // For wav samples only...
s32 sampleRate; // For wav samples only...
} Sample; // size = 0x10
/* 0x1 */ u32 size; // Size of the sample
u32 fileSize;
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either
// rom or ram
/* 0x8 */ AdpcmLoop*
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
class AudioSample : public Ship::Resource<Sample> {
public:
@ -45,18 +46,15 @@ class AudioSample : public Ship::Resource<Sample> {
AudioSample() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSample();
Sample* GetPointer();
size_t GetPointerSize();
Sample sample;
std::vector<uint8_t> audioSampleData;
AdpcmLoop loop;
uint32_t loopStateCount;
AdpcmBook book;
uint32_t bookDataCount;
std::vector<int16_t> bookData;
// Only applies to streamed audio
float tuning = -1.0f;
};
}; // namespace SOH
}; // namespace SOH

View file

@ -9,4 +9,10 @@ Sequence* AudioSequence::GetPointer() {
size_t AudioSequence::GetPointerSize() {
return sizeof(Sequence);
}
} // namespace SOH
AudioSequence::~AudioSequence() {
delete[] sequence.seqData;
sequence.seqData = nullptr;
}
} // namespace SOH

View file

@ -1,19 +1,17 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Resource.h"
#include <libultraship/libultra/types.h>
namespace SOH {
typedef struct {
char* seqData;
int32_t seqDataSize;
uint32_t seqDataSize;
uint16_t seqNumber;
uint8_t medium;
uint8_t cachePolicy;
int32_t numFonts;
uint32_t numFonts;
uint8_t fonts[16];
} Sequence;
@ -23,11 +21,11 @@ class AudioSequence : public Ship::Resource<Sequence> {
AudioSequence() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSequence();
Sequence* GetPointer();
size_t GetPointerSize();
Sequence sequence;
std::vector<char> sequenceData;
};
}; // namespace SOH
}; // namespace SOH

View file

@ -1,6 +1,23 @@
#include "AudioSoundFont.h"
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() {
return &soundFont;
}
@ -8,4 +25,4 @@ SoundFont* AudioSoundFont::GetPointer() {
size_t AudioSoundFont::GetPointerSize() {
return sizeof(SoundFont);
}
} // namespace SOH
} // namespace SOH

View file

@ -58,6 +58,7 @@ class AudioSoundFont : public Ship::Resource<SoundFont> {
AudioSoundFont() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSoundFont();
SoundFont* GetPointer();
size_t GetPointerSize();
@ -68,15 +69,10 @@ class AudioSoundFont : public Ship::Resource<SoundFont> {
uint16_t data2;
uint16_t data3;
std::vector<Drum> drums;
std::vector<Drum*> drumAddresses;
std::vector<uint32_t> drumEnvelopeCounts;
std::vector<std::vector<AdsrEnvelope>> drumEnvelopeArrays;
std::vector<Instrument> instruments;
std::vector<Instrument*> instrumentAddresses;
std::vector<uint32_t> instrumentEnvelopeCounts;
std::vector<std::vector<AdsrEnvelope>> instrumentEnvelopeArrays;
std::vector<SoundFontSound> soundEffects;

View file

@ -41,7 +41,7 @@ void func_800DDE3C(void) {
void AudioHeap_ResetLoadStatus(void) {
s32 i;
for (i = 0; i < 0x30; i++) {
for (i = 0; i < fontMapSize; i++) {
if (gAudioContext.fontLoadStatus[i] != 5) {
gAudioContext.fontLoadStatus[i] = 0;
}
@ -940,7 +940,7 @@ void AudioHeap_Init(void) {
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
reverb->loop.start = 0;
reverb->loop.count = 1;
reverb->loop.end = reverb->windowSize;
reverb->loop.loopEnd = reverb->windowSize;
if (reverb->downsampleRate != 1) {
reverb->unk_0E = 0x8000 / reverb->downsampleRate;

View file

@ -8,6 +8,10 @@
#include "soh/Enhancements/audio/AudioCollection.h"
#include "soh/Enhancements/audio/AudioEditor.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 ASYNC_TBLTYPE(v) ((u8)(v >> 16))
@ -82,7 +86,8 @@ char** sequenceMap;
size_t sequenceMapSize;
// A map of authentic sequence IDs to their cache policies, for use with sequence swapping.
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
char* fontMap[256];
size_t fontMapSize;
char** fontMap;
uintptr_t fontStart;
uint32_t fontOffsets[8192];
@ -419,7 +424,7 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 arg1) {
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
void* sampleAddr;
if (sample->unk_bit25 == 1) {
if (sample->isRelocated == 1) {
if (sample->medium != MEDIUM_RAM) {
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
CACHE_PERSISTENT);
@ -701,7 +706,7 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
sampleBankId1 = sf->sampleBankId1;
sampleBankId2 = sf->sampleBankId2;
@ -759,7 +764,7 @@ uintptr_t AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
cachePolicy = sData.cachePolicy;
romAddr = 0;
} else if (tableType == FONT_TABLE) {
fnt = ResourceMgr_LoadAudioSoundFont(fontMap[id]);
fnt = ResourceMgr_LoadAudioSoundFontByName(fontMap[id]);
size = sizeof(SoundFont);
medium = 2;
cachePolicy = 0;
@ -887,6 +892,7 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) {
}
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo) {
return;
uintptr_t reloc;
uintptr_t reloc2;
Instrument* inst;
@ -898,7 +904,7 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
s32 numInstruments = 0;
s32 numSfx = 0;
sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
@ -1247,12 +1253,13 @@ int strcmp_sort(const void* str1, const void* str2) {
}
void AudioLoad_Init(void* heap, size_t heapSize) {
char pad[0x48];
s32 pad1[9];
s32 numFonts;
void* temp_v0_3;
s32 pad2[2];
u8* audioCtxPtr;
void* addr;
s32 i;
u64* heapP;
s16* u2974p;
s32 j;
D_801755D0 = NULL;
gAudioContext.resetTimer = 0;
@ -1266,10 +1273,12 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.unk_2960 = 20.03042f;
gAudioContext.refreshRate = 50;
break;
case OS_TV_MPAL:
gAudioContext.unk_2960 = 16.546f;
gAudioContext.refreshRate = 60;
break;
case OS_TV_NTSC:
default:
gAudioContext.unk_2960 = 16.713f;
@ -1278,7 +1287,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
Audio_InitMesgQueues();
for (i = 0; i < 3; i++) {
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) {
gAudioContext.aiBufLengths[i] = 0xA0;
}
@ -1289,12 +1298,14 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.currTask = NULL;
gAudioContext.rspTask[0].task.t.data_size = 0;
gAudioContext.rspTask[1].task.t.data_size = 0;
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,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
osCreateMesgQueue(&gAudioContext.preloadSampleQueue, gAudioContext.preloadSampleMesgBuf,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
ARRAY_COUNT(gAudioContext.preloadSampleMesgBuf));
gAudioContext.curAudioFrameDmaCount = 0;
gAudioContext.sampleDmaCount = 0;
gAudioContext.cartHandle = osCartRomInit();
@ -1304,20 +1315,24 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.audioHeapSize = D_8014A6C4.heapSize;
} else {
void** hp = &heap;
gAudioContext.audioHeap = *hp;
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;
}
// Main Pool Split (split entirety of audio heap into initPool and sessionPool)
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));
}
// Connect audio tables to their tables in memory
// gAudioContext.sequenceTable = (AudioTable*)gSequenceTable;
// gAudioContext.soundFontTable = (AudioTable*)gSoundFontTable;
// gAudioContext.sampleBankTable = (AudioTable*)gSampleBankTable;
@ -1325,31 +1340,60 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
// gAudioContext.numSequences = gAudioContext.sequenceTable->numEntries;
gAudioContext.audioResetSpecIdToLoad = 0;
gAudioContext.resetStatus = 1;
gAudioContext.resetStatus = 1; // Set reset to immediately initialize the audio heap
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 customSeqListSize = 0;
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize);
sequenceMapSize = (size_t)(AudioCollection_SequenceMapSize() + customSeqListSize);
sequenceMap = malloc(sequenceMapSize * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize * sizeof(char*));
sequenceMapSize = (size_t)(seqListSize + customSeqListSize);
sequenceMap = malloc((sequenceMapSize + 0xF) * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize);
memset(gAudioContext.seqLoadStatus, 5, sequenceMapSize);
for (size_t i = 0; i < seqListSize; i++) {
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
char* str = malloc(strlen(seqList[i]) + 1);
strcpy(str, seqList[i]);
sequenceMap[sDat.seqNumber] = str;
sequenceMap[sDat.seqNumber] = strdup(seqList[i]);
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
}
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);
// 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++) {
// 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)) {
seqNum++;
}
int j = i - startingSeqNum;
AudioCollection_AddToCollection(customSeqList[j], seqNum);
SequenceData sDat = ResourceMgr_LoadSeqByName(customSeqList[j]);
sDat.seqNumber = seqNum;
char* str = malloc(strlen(customSeqList[j]) + 1);
strcpy(str, customSeqList[j]);
sequenceMap[sDat.seqNumber] = str;
sDat->seqNumber = seqNum;
printf("%d\n", seqNum);
sequenceMap[sDat->seqNumber] = strdup(customSeqList[j]);
seqNum++;
}
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;
free(fntList);
// #end region
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
// *((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;
osSendMesg32(gAudioContext.taskStartQueueP, gAudioContext.totalTaskCnt, OS_MESG_NOBLOCK);
osSendMesg(gAudioContext.taskStartQueueP, OS_MESG_32(gAudioContext.totalTaskCnt), OS_MESG_NOBLOCK);
}
void AudioLoad_InitSlowLoads(void) {
@ -2059,7 +2116,7 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
gAudioContext.numUsedSamples = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
@ -2188,7 +2245,7 @@ void AudioLoad_LoadPermanentSamples(void) {
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, 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.sampleBankId2 = sf->sampleBankId2;

View file

@ -147,6 +147,7 @@ void Audio_NoteInit(Note* note) {
note->noteSubEu = gDefaultNoteSub;
}
extern void aOPUSFree(struct OggOpusFile* opusFile);
void Audio_NoteDisable(Note* note) {
if (note->noteSubEu.bitField0.needsInit == true) {
note->noteSubEu.bitField0.needsInit = false;
@ -159,6 +160,10 @@ void Audio_NoteDisable(Note* note) {
note->playbackState.prevParentLayer = NO_LAYER;
note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED;
note->playbackState.adsr.current = 0;
if (note->synthesisState.opusFile != NULL) {
aOPUSFree(note->synthesisState.opusFile);
note->synthesisState.opusFile = NULL;
}
}
void Audio_ProcessNotes(void) {
@ -293,13 +298,6 @@ void Audio_ProcessNotes(void) {
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.velocity *= scale;
@ -335,7 +333,7 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
}
int instCnt = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (instId >= sf->numInstruments)
return NULL;
@ -362,7 +360,7 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (drumId < sf->numDrums) {
drum = sf->drums[drumId];
}
@ -386,7 +384,7 @@ SoundFontSound* Audio_GetSfx(s32 fontId, s32 sfxId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (sfxId < sf->numSfx) {
sfx = &sf->soundEffects[sfxId];
}

View file

@ -789,7 +789,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd) {
layer->freqScale *= layer->unk_34;
if (layer->delay == 0) {
if (layer->sound != NULL) {
time = (f32)layer->sound->sample->loop->end;
time = (f32)layer->sound->sample->loop->loopEnd;
} else {
time = 0.0f;
}

View file

@ -761,7 +761,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
audioFontSample = noteSubEu->sound.soundFontSound->sample;
loopInfo = audioFontSample->loop;
loopEndPos = loopInfo->end;
loopEndPos = loopInfo->loopEnd;
sampleAddr = audioFontSample->sampleAddr;
resampledTempLen = 0;
@ -853,14 +853,27 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
s5 = samplesLenAdjusted;
goto skip;
case CODEC_S16:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted * 2) + 0x20);
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2),
audioFontSample->sampleAddr + (synthState->samplePosInt * 2));
case CODEC_OPUS:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted + 16) * 2);
flags = A_CONTINUE;
skipBytes = 0;
nSamplesProcessed = samplesLenAdjusted;
s5 = samplesLenAdjusted;
size_t bytesToRead;
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;
case CODEC_REVERB:
break;
@ -886,6 +899,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
sampleDataStartPad = (uintptr_t)sampleData & 0xF;
aligned = ALIGN16((nFramesToDecode * frameSize) + 16);
addr = DMEM_COMPRESSED_ADPCM_DATA - aligned;
aLoadBuffer(cmd++, sampleData - sampleDataStartPad, addr, aligned);
} else {
nSamplesToDecode = 0;
@ -893,7 +907,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
}
if (synthState->restart) {
aSetLoop(cmd++, audioFontSample->loop->state);
aSetLoop(cmd++, audioFontSample->loop->predictorState);
flags = A_LOOP;
synthState->restart = false;
}

View file

@ -792,7 +792,7 @@ s32 func_800E6590(s32 playerIdx, s32 arg1, s32 arg2) {
if (sound == NULL) {
return 0;
}
loopEnd = sound->sample->loop->end;
loopEnd = sound->sample->loop->loopEnd;
samplePos = note->synthesisState.samplePosInt;
return loopEnd - samplePos;
}

View file

@ -42,9 +42,6 @@ typedef struct EnElf {
/* 0x02C7 */ u8 unk_2C7;
/* 0x02C8 */ EnElfUnkFunc func_2C8;
/* 0x02CC */ EnElfActionFunc actionFunc;
// #region SOH [Randomizer]
/* */ FairyIdentity sohFairyIdentity;
// #endregion
} EnElf; // size = 0x02D0
typedef enum {

View file

@ -20,7 +20,6 @@ typedef struct EnKusa {
/* 0x0150 */ ColliderCylinder collider;
/* 0x019C */ s16 timer;
/* 0x019E */ s8 objBankIndex;
/* */ GrassIdentity grassIdentity;
} EnKusa; // size = 0x01A0
#endif

View file

@ -15,7 +15,6 @@ typedef struct ObjComb {
/* 0x0170 */ ColliderJntSphElement colliderItems[1];
/* 0x01B0 */ s16 unk_1B0;
/* 0x01B2 */ s16 unk_1B2;
/* */ BeehiveIdentity beehiveIdentity;
} ObjComb; // size = 0x01B4
void ObjComb_Break(ObjComb* objComb, PlayState* play);

View file

@ -12,7 +12,6 @@ typedef struct ObjKibako {
/* 0x0000 */ Actor actor;
/* 0x014C */ ObjKibakoActionFunc actionFunc;
/* 0x0150 */ ColliderCylinder collider;
/* */ SmallCrateIdentity smallCrateIdentity;
} ObjKibako; // size = 0x019C
#endif

View file

@ -13,7 +13,6 @@ typedef struct ObjKibako2 {
/* 0x0164 */ ColliderCylinder collider;
/* 0x01B0 */ ObjKibako2ActionFunc actionFunc;
/* 0x01B4 */ s16 collectibleFlag;
/* */ CrateIdentity crateIdentity;
} ObjKibako2; // size = 0x01B8
#endif

View file

@ -13,7 +13,6 @@ typedef struct ObjTsubo {
/* 0x014C */ ObjTsuboActionFunc actionFunc;
/* 0x0150 */ ColliderCylinder collider;
/* 0x019C */ s8 objTsuboBankIndex;
/* */ PotIdentity potIdentity;
} ObjTsubo; // size = 0x01A0
#endif