mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-06-23 01:29:51 -04:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0bc6ca08e0 | |||
| 16aaf2f939 | |||
| 3971e3696e | |||
| f11f97e84e | |||
| 7a00658be9 | |||
| 7bc2259c82 | |||
| 3d73faa9a0 | |||
| 134aba4aa0 | |||
| 79a29a62ef | |||
| 3f67fed073 | |||
| cbeec006ec | |||
| fd9cd9c5eb | |||
| 4a576f45ee | |||
| 32bf8cc53c | |||
| 02f7310c16 | |||
| bfe13906e9 | |||
| 32288be744 | |||
| 19be6e9b99 | |||
| 0b8cc71d0d | |||
| ced34ab68a | |||
| e163d5bc3d | |||
| 612da023f0 | |||
| 368a9015ac | |||
| ed9cb1dfd2 | |||
| fb6ea42560 | |||
| b26f2b21da | |||
| 358dd47da7 | |||
| ea1ffdd041 | |||
| ef9fc0a9ec | |||
| 19af4481c0 | |||
| 30a063b75d | |||
| cf6101f4da | |||
| 3d3b8bfc5b | |||
| 0cb4cd158a | |||
| 43fed2d77e | |||
| 11a0a00633 | |||
| 107a365b71 | |||
| bb1078e99c | |||
| 2529dc59bd | |||
| 61cf2bd323 | |||
| 16ee20c2a8 | |||
| 7ef6a434f9 | |||
| e3825ec263 | |||
| cb82e77e40 | |||
| 63cf3610e5 | |||
| dd5d8088f6 | |||
| 1da1b1a2bb | |||
| db02870a05 | |||
| 861bd09848 | |||
| 8426cc93e5 | |||
| 21796367a0 | |||
| 321c258d69 | |||
| 02938cfba2 | |||
| 37b2fc0745 | |||
| 6cb3a830bd | |||
| 96abadd904 | |||
| fa8a0e2a76 | |||
| 60faf3f750 | |||
| ef910a02f7 | |||
| f607afc754 | |||
| 865bcc57a7 | |||
| b5caf33a9b | |||
| f655ab592d | |||
| e6fc34e4c2 | |||
| d370ca93fd | |||
| fcf2141266 | |||
| e2f1cebfb5 | |||
| 907b770676 | |||
| ea49196bae | |||
| f65b711376 | |||
| 269e9faa46 | |||
| 35301556d9 | |||
| fb0f7169d7 | |||
| fbc397a131 |
@@ -191,7 +191,7 @@ jobs:
|
|||||||
needs: generate-soh-otr
|
needs: generate-soh-otr
|
||||||
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
|
runs-on: ${{ (vars.LINUX_RUNNER && fromJSON(vars.LINUX_RUNNER)) || 'ubuntu-latest' }}
|
||||||
container:
|
container:
|
||||||
image: devkitpro/devkita64:latest
|
image: devkitpro/devkita64:20240120
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -235,7 +235,6 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: ${{ !vars.LINUX_RUNNER }}
|
if: ${{ !vars.LINUX_RUNNER }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y ninja-build
|
sudo apt-get install -y ninja-build
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
+3
-3
@@ -5,9 +5,9 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
|
|||||||
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
|
||||||
project(Ship VERSION 8.0.3 LANGUAGES C CXX)
|
project(Ship VERSION 8.0.6 LANGUAGES C CXX)
|
||||||
set(PROJECT_BUILD_NAME "MacReady Delta" CACHE STRING "")
|
set(PROJECT_BUILD_NAME "MacReady Golf" CACHE STRING "" FORCE)
|
||||||
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE)
|
||||||
|
|
||||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
||||||
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
||||||
|
|||||||
+1
-1
Submodule libultraship updated: 59427a67bf...1ca7d0fa78
+1
-1
@@ -328,7 +328,7 @@ endif()
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Boost
|
Boost
|
||||||
URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz
|
URL https://archives.boost.io/release/1.81.0/source/boost_1_81_0.tar.gz
|
||||||
URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6
|
URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6
|
||||||
SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it)
|
SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it)
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change
|
DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change
|
||||||
|
|||||||
@@ -28,4 +28,10 @@
|
|||||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
</application>
|
</application>
|
||||||
</compatibility>
|
</compatibility>
|
||||||
|
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- legacy -->
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to pm if pmv2 is not available -->
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
</assembly>
|
</assembly>
|
||||||
|
|||||||
@@ -46,10 +46,18 @@ template<> struct is_char_type<std::byte>: public boost::true_type {};
|
|||||||
|
|
||||||
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
||||||
|
|
||||||
|
#if BOOST_USE_STD_TYPES
|
||||||
|
#define BOOST_ENABLE_IF std::enable_if
|
||||||
|
#define BOOST_IS_SAME std::is_same
|
||||||
|
#else
|
||||||
|
#define BOOST_ENABLE_IF boost::enable_if_
|
||||||
|
#define BOOST_IS_SAME is_same
|
||||||
|
#endif
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
inline typename boost::enable_if_<
|
inline typename BOOST_ENABLE_IF<
|
||||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||||
is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value,
|
BOOST_IS_SAME<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value,
|
||||||
std::size_t>::type
|
std::size_t>::type
|
||||||
hash_range_32( uint32_t seed, It first, It last )
|
hash_range_32( uint32_t seed, It first, It last )
|
||||||
{
|
{
|
||||||
@@ -114,4 +122,7 @@ std::size_t>::type
|
|||||||
} // namespace hash_detail
|
} // namespace hash_detail
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
#undef BOOST_ENABLE_IF
|
||||||
|
#undef BOOST_IS_SAME
|
||||||
|
|
||||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
|
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
|
||||||
|
|||||||
@@ -23,6 +23,18 @@
|
|||||||
|
|
||||||
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
#endif // #if !BOOST_VERSION_HAS_HASH_RANGE
|
||||||
|
|
||||||
|
#if BOOST_USE_STD_TYPES
|
||||||
|
#define BOOST_ENABLE_IF std::enable_if
|
||||||
|
#define BOOST_IS_INTEGRAL hash_detail::is_integral
|
||||||
|
#define BOOST_IS_UNSIGNED is_unsigned
|
||||||
|
#define BOOST_MAKE_UNSIGNED make_unsigned
|
||||||
|
#else
|
||||||
|
#define BOOST_ENABLE_IF boost::enable_if_
|
||||||
|
#define BOOST_IS_INTEGRAL boost::is_integral
|
||||||
|
#define BOOST_IS_UNSIGNED boost::is_unsigned
|
||||||
|
#define BOOST_MAKE_UNSIGNED boost::make_unsigned
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -36,7 +48,7 @@ namespace boost
|
|||||||
{
|
{
|
||||||
template<class T,
|
template<class T,
|
||||||
bool bigger_than_size_t = (sizeof(T) > sizeof(uint32_t)),
|
bool bigger_than_size_t = (sizeof(T) > sizeof(uint32_t)),
|
||||||
bool is_unsigned = boost::is_unsigned<T>::value,
|
bool is_unsigned = BOOST_IS_UNSIGNED<T>::value,
|
||||||
std::size_t size_t_bits = sizeof(uint32_t) * CHAR_BIT,
|
std::size_t size_t_bits = sizeof(uint32_t) * CHAR_BIT,
|
||||||
std::size_t type_bits = sizeof(T) * CHAR_BIT>
|
std::size_t type_bits = sizeof(T) * CHAR_BIT>
|
||||||
struct hash_integral_impl_32;
|
struct hash_integral_impl_32;
|
||||||
@@ -53,7 +65,7 @@ namespace boost
|
|||||||
{
|
{
|
||||||
static uint32_t fn( T v )
|
static uint32_t fn( T v )
|
||||||
{
|
{
|
||||||
typedef typename boost::make_unsigned<T>::type U;
|
typedef typename BOOST_MAKE_UNSIGNED<T>::type U;
|
||||||
|
|
||||||
if( v >= 0 )
|
if( v >= 0 )
|
||||||
{
|
{
|
||||||
@@ -97,7 +109,7 @@ namespace boost
|
|||||||
} // namespace hash_detail
|
} // namespace hash_detail
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename boost::enable_if_<boost::is_integral<T>::value, uint32_t>::type
|
typename BOOST_ENABLE_IF<BOOST_IS_INTEGRAL<T>::value, uint32_t>::type
|
||||||
hash_value_32( T v )
|
hash_value_32( T v )
|
||||||
{
|
{
|
||||||
return hash_detail::hash_integral_impl_32<T>::fn( v );
|
return hash_detail::hash_integral_impl_32<T>::fn( v );
|
||||||
@@ -106,7 +118,7 @@ namespace boost
|
|||||||
// contiguous ranges (string, vector, array)
|
// contiguous ranges (string, vector, array)
|
||||||
#if BOOST_VERSION_HAS_HASH_RANGE
|
#if BOOST_VERSION_HAS_HASH_RANGE
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename boost::enable_if_<container_hash::is_contiguous_range<T>::value, uint32_t>::type
|
typename BOOST_ENABLE_IF<container_hash::is_contiguous_range<T>::value, uint32_t>::type
|
||||||
hash_value_32( T const& v )
|
hash_value_32( T const& v )
|
||||||
{
|
{
|
||||||
return boost::hash_range_32( v.data(), v.data() + v.size() );
|
return boost::hash_range_32( v.data(), v.data() + v.size() );
|
||||||
@@ -168,5 +180,9 @@ namespace boost
|
|||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#undef BOOST_HASH_CHAR_TRAITS
|
#undef BOOST_HASH_CHAR_TRAITS
|
||||||
|
#undef BOOST_ENABLE_IF
|
||||||
|
#undef BOOST_IS_INTEGRAL
|
||||||
|
#undef BOOST_IS_UNSIGNED
|
||||||
|
#undef BOOST_MAKE_UNSIGNED
|
||||||
|
|
||||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_32_HPP
|
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_32_HPP
|
||||||
|
|||||||
@@ -6,4 +6,6 @@
|
|||||||
|
|
||||||
#define BOOST_VERSION_HAS_HASH_RANGE ((BOOST_VERSION / 100 % 1000) >= 81)
|
#define BOOST_VERSION_HAS_HASH_RANGE ((BOOST_VERSION / 100 % 1000) >= 81)
|
||||||
|
|
||||||
|
#define BOOST_USE_STD_TYPES ((BOOST_VERSION / 100 % 1000) >= 84)
|
||||||
|
|
||||||
#endif // #ifndef BOOST_CONTAINER_HASH_VERSION_HPP
|
#endif // #ifndef BOOST_CONTAINER_HASH_VERSION_HPP
|
||||||
|
|||||||
@@ -1259,6 +1259,8 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable,
|
|||||||
s32 dListIndex);
|
s32 dListIndex);
|
||||||
void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw,
|
void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw,
|
||||||
PostLimbDrawOpa postLimbDraw, void* arg);
|
PostLimbDrawOpa postLimbDraw, void* arg);
|
||||||
|
Gfx* SkelAnime_DrawSkeleton2(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw,
|
||||||
|
PostLimbDrawOpa postLimbDraw, void* arg, Gfx* gfx);
|
||||||
void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable,
|
void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable,
|
||||||
OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg);
|
OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg);
|
||||||
void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount,
|
void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount,
|
||||||
@@ -2458,6 +2460,8 @@ void Message_DrawText(PlayState* play, Gfx** gfxP);
|
|||||||
|
|
||||||
void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH);
|
void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH);
|
||||||
void Interface_RandoRestoreSwordless(void);
|
void Interface_RandoRestoreSwordless(void);
|
||||||
|
s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw,
|
||||||
|
bool* shouldUpdate);
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -744,7 +744,6 @@ typedef struct {
|
|||||||
/* 0x0134 */ char** doActionSegment;
|
/* 0x0134 */ char** doActionSegment;
|
||||||
/* 0x0138 */ u8* iconItemSegment;
|
/* 0x0138 */ u8* iconItemSegment;
|
||||||
/* 0x013C */ char** mapSegment;
|
/* 0x013C */ char** mapSegment;
|
||||||
char** mapSegmentName;
|
|
||||||
/* 0x0140 */ u8 mapPalette[32];
|
/* 0x0140 */ u8 mapPalette[32];
|
||||||
/* 0x0160 */ DmaRequest dmaRequest_160;
|
/* 0x0160 */ DmaRequest dmaRequest_160;
|
||||||
/* 0x0180 */ DmaRequest dmaRequest_180;
|
/* 0x0180 */ DmaRequest dmaRequest_180;
|
||||||
@@ -815,6 +814,10 @@ typedef struct {
|
|||||||
/* 0x026C */ u8 dinsNayrus; // "m_magic"; din's fire and nayru's love
|
/* 0x026C */ u8 dinsNayrus; // "m_magic"; din's fire and nayru's love
|
||||||
/* 0x026D */ u8 all; // "another"; enables all item restrictions
|
/* 0x026D */ u8 all; // "another"; enables all item restrictions
|
||||||
} restrictions;
|
} restrictions;
|
||||||
|
// #region SOH [General]
|
||||||
|
/* */ char* mapSegmentName[2]; // Tracks the map segment texture by OTR sig name
|
||||||
|
/* */ u8 mapPalettesPulse[40][32]; // Used to have unique pointers per map pulse color for the shader backend. 40 for map pulse timer x2
|
||||||
|
// #endregion
|
||||||
} InterfaceContext; // size = 0x270
|
} InterfaceContext; // size = 0x270
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -1402,6 +1405,8 @@ typedef struct PlayState {
|
|||||||
/* 0x1242B */ u8 unk_1242B;
|
/* 0x1242B */ u8 unk_1242B;
|
||||||
/* 0x1242C */ SceneTableEntry* loadedScene;
|
/* 0x1242C */ SceneTableEntry* loadedScene;
|
||||||
/* 0x12430 */ char unk_12430[0xE8];
|
/* 0x12430 */ char unk_12430[0xE8];
|
||||||
|
// SOH [Custom Models] MTX tracker for flex based skeletons
|
||||||
|
Mtx** flexLimbOverrideMTX;
|
||||||
} PlayState; // size = 0x12518
|
} PlayState; // size = 0x12518
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -7,68 +7,6 @@ export RESPATH="${SNAME%/MacOS*}/Resources"
|
|||||||
export LIBPATH="${SNAME%/MacOS*}/Frameworks"
|
export LIBPATH="${SNAME%/MacOS*}/Frameworks"
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$LIBPATH"
|
export DYLD_FALLBACK_LIBRARY_PATH="$LIBPATH"
|
||||||
|
|
||||||
remap_hashes ()
|
|
||||||
{
|
|
||||||
# Remap v64 and n64 hashes to their z64 hash equivalent
|
|
||||||
# ZAPD will handle converting the data into z64 format
|
|
||||||
case "$ROMHASH" in
|
|
||||||
a9059b56e761c9034fbe02fe4c24985aaa835dac) # v64
|
|
||||||
ROMHASH=cee6bc3c2a634b41728f2af8da54d9bf8cc14099
|
|
||||||
;;
|
|
||||||
24708102dc504d3f375a37f4ae4e149c167dc515) # n64
|
|
||||||
ROMHASH=cee6bc3c2a634b41728f2af8da54d9bf8cc14099
|
|
||||||
;;
|
|
||||||
580dd0bd1b6d2c51cc20a764eece84dba558964c) # v64
|
|
||||||
ROMHASH=0227d7c0074f2d0ac935631990da8ec5914597b4
|
|
||||||
;;
|
|
||||||
d6342c59007e57c1194661ec6880b2f078403f4e) # n64
|
|
||||||
ROMHASH=0227d7c0074f2d0ac935631990da8ec5914597b4
|
|
||||||
;;
|
|
||||||
d0bdc2eb320668b4ba6893b9aefe4040a73123ff) # v64
|
|
||||||
ROMHASH=328a1f1beba30ce5e178f031662019eb32c5f3b5
|
|
||||||
;;
|
|
||||||
4946ab250f6ac9b32d76b21f309ebb8ebc8103d2) # n64
|
|
||||||
ROMHASH=328a1f1beba30ce5e178f031662019eb32c5f3b5
|
|
||||||
;;
|
|
||||||
663c34f1b2c05a09e5beffe4d0dcd440f7d49dc7) # v64
|
|
||||||
ROMHASH=cfbb98d392e4a9d39da8285d10cbef3974c2f012
|
|
||||||
;;
|
|
||||||
24c73d378b0620a380ce5ef9f2b186c6c157a68b) # n64
|
|
||||||
ROMHASH=cfbb98d392e4a9d39da8285d10cbef3974c2f012
|
|
||||||
;;
|
|
||||||
8ebf2e29313f44f2d49e5b4191971d09919e8e48) # v64
|
|
||||||
ROMHASH=f46239439f59a2a594ef83cf68ef65043b1bffe2
|
|
||||||
;;
|
|
||||||
4264bf7b875737b8fae77d52322a5099d051fc11) # n64
|
|
||||||
ROMHASH=f46239439f59a2a594ef83cf68ef65043b1bffe2
|
|
||||||
;;
|
|
||||||
973bc6fe56010a8d646166a1182a81b4f13b8cf9) # v64
|
|
||||||
ROMHASH=50bebedad9e0f10746a52b07239e47fa6c284d03
|
|
||||||
;;
|
|
||||||
d327752c46edc70ff3668b9514083dbbee08927c) # v64
|
|
||||||
ROMHASH=50bebedad9e0f10746a52b07239e47fa6c284d03
|
|
||||||
;;
|
|
||||||
ecdeb1747560834e079c22243febea7f6f26ba3b) # v64
|
|
||||||
ROMHASH=079b855b943d6ad8bd1eb026c0ed169ecbdac7da
|
|
||||||
;;
|
|
||||||
f19f8662ec7abee29484a272a6fda53e39efe0f1) # n64
|
|
||||||
ROMHASH=079b855b943d6ad8bd1eb026c0ed169ecbdac7da
|
|
||||||
;;
|
|
||||||
ab519ce04a33818ce2c39b3c514a751d807a494a) # v64
|
|
||||||
ROMHASH=cfecfdc58d650e71a200c81f033de4e6d617a9f6
|
|
||||||
;;
|
|
||||||
c19a34f7646305e1755249fca2071e178bd7cd00) # n64
|
|
||||||
ROMHASH=cfecfdc58d650e71a200c81f033de4e6d617a9f6
|
|
||||||
;;
|
|
||||||
25e8ae79ea0839ca5c984473f7460d8040c36f9c) # v64
|
|
||||||
ROMHASH=517bd9714c73cb96c21e7c2ef640d7b55186102f
|
|
||||||
;;
|
|
||||||
166c02770d67fcc3954c443eb400a6a3573d3fc0) # n64
|
|
||||||
ROMHASH=517bd9714c73cb96c21e7c2ef640d7b55186102f
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ ! -e "$SHIP_HOME" ]; then mkdir "$SHIP_HOME"; fi
|
if [ ! -e "$SHIP_HOME" ]; then mkdir "$SHIP_HOME"; fi
|
||||||
|
|
||||||
if [ ! -e "$SHIP_HOME"/mods ]; then
|
if [ ! -e "$SHIP_HOME"/mods ]; then
|
||||||
@@ -76,178 +14,6 @@ if [ ! -e "$SHIP_HOME"/mods ]; then
|
|||||||
touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt
|
touch "$SHIP_HOME"/mods/custom_otr_files_go_here.txt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If either OTR doesn't exist kick off the OTR gen process
|
|
||||||
if [ ! -e "$SHIP_HOME"/oot.otr ] || [ ! -e "$SHIP_HOME"/oot-mq.otr ]; then
|
|
||||||
|
|
||||||
# If no ROMs exist kick off the file selection prompts
|
|
||||||
while [ ! -e "$SHIP_HOME"/*.*64 ] && [ ! -e "$SHIP_HOME"/oot*.otr ]; do
|
|
||||||
|
|
||||||
SHOULD_PROMPT_FOR_ROM=1
|
|
||||||
while [ $SHOULD_PROMPT_FOR_ROM -eq 1 ]; do
|
|
||||||
SHOULD_PROMPT_FOR_ROM=0
|
|
||||||
# Use osascript to prompt the user to chose a file
|
|
||||||
DROPROM=`osascript <<-EOF
|
|
||||||
set romFile to choose file of type {"b64","n64","v64","z64"} with prompt "Please select your ROM:"
|
|
||||||
return POSIX path of romFile
|
|
||||||
EOF`
|
|
||||||
|
|
||||||
# If no rom was selected, the user cancelled, so exit
|
|
||||||
if [[ -z $DROPROM ]] && [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then
|
|
||||||
echo "No ROM selected. Exiting..."
|
|
||||||
exit 1
|
|
||||||
elif [[ -z $DROPROM ]]; then
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If an invalid rom was selected, let the user know and ask to try again
|
|
||||||
ROMHASH="$(shasum "$DROPROM" | awk '{ print $1 }')"
|
|
||||||
|
|
||||||
remap_hashes
|
|
||||||
|
|
||||||
case "$ROMHASH" in
|
|
||||||
cee6bc3c2a634b41728f2af8da54d9bf8cc14099)
|
|
||||||
ROM_TYPE=0;;
|
|
||||||
0227d7c0074f2d0ac935631990da8ec5914597b4)
|
|
||||||
ROM_TYPE=0;;
|
|
||||||
328a1f1beba30ce5e178f031662019eb32c5f3b5)
|
|
||||||
ROM_TYPE=0;;
|
|
||||||
cfbb98d392e4a9d39da8285d10cbef3974c2f012)
|
|
||||||
ROM_TYPE=0;;
|
|
||||||
f46239439f59a2a594ef83cf68ef65043b1bffe2)
|
|
||||||
ROM_TYPE=1;;
|
|
||||||
50bebedad9e0f10746a52b07239e47fa6c284d03)
|
|
||||||
ROM_TYPE=1;;
|
|
||||||
079b855b943d6ad8bd1eb026c0ed169ecbdac7da)
|
|
||||||
ROM_TYPE=1;;
|
|
||||||
cfecfdc58d650e71a200c81f033de4e6d617a9f6)
|
|
||||||
ROM_TYPE=1;;
|
|
||||||
517bd9714c73cb96c21e7c2ef640d7b55186102f)
|
|
||||||
ROM_TYPE=1;;
|
|
||||||
*)
|
|
||||||
TRY_AGAIN_RESULT=`osascript <<-EOF
|
|
||||||
set alertText to "Incompatible ROM hash"
|
|
||||||
set alertMessage to "Incompatible ROM provided, would you like to try again?"
|
|
||||||
return display alert alertText \
|
|
||||||
message alertMessage \
|
|
||||||
as critical \
|
|
||||||
buttons {"Cancel", "Try Again"}
|
|
||||||
EOF`
|
|
||||||
if [[ "$TRY_AGAIN_RESULT" == "button returned:Try Again" ]]; then
|
|
||||||
SHOULD_PROMPT_FOR_ROM=1
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
echo "No ROM selected. Exiting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
esac
|
|
||||||
|
|
||||||
cp "$DROPROM" "$SHIP_HOME"
|
|
||||||
|
|
||||||
# Ask user if they would also like to select the other variant (MQ/Vanilla)
|
|
||||||
if [ $ROM_TYPE -eq 0 ] && [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then
|
|
||||||
UPLOAD_ANOTHER_RESULT=`osascript <<-EOF
|
|
||||||
set alertText to "Success"
|
|
||||||
set alertMessage to "Would you also like to provide a Master Quest ROM?"
|
|
||||||
return display alert alertText \
|
|
||||||
message alertMessage \
|
|
||||||
buttons {"No", "Yes"}
|
|
||||||
EOF`
|
|
||||||
elif [[ -z "$UPLOAD_ANOTHER_RESULT" ]]; then
|
|
||||||
UPLOAD_ANOTHER_RESULT=`osascript <<-EOF
|
|
||||||
set alertText to "Success"
|
|
||||||
set alertMessage to "Would you also like to provide a Vanilla (Non Master Quest) ROM?"
|
|
||||||
return display alert alertText \
|
|
||||||
message alertMessage \
|
|
||||||
buttons {"No", "Yes"}
|
|
||||||
EOF`
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$UPLOAD_ANOTHER_RESULT" == "button returned:Yes" ]]; then
|
|
||||||
UPLOAD_ANOTHER_RESULT="button returned:No"
|
|
||||||
SHOULD_PROMPT_FOR_ROM=1
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# At this point we should now have 1 or more valid roms in $SHIP_HOME directory
|
|
||||||
|
|
||||||
# Prepare tmp dir
|
|
||||||
for ROMPATH in "$SHIP_HOME"/*.*64
|
|
||||||
do
|
|
||||||
ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)"
|
|
||||||
export ASSETDIR
|
|
||||||
cp -r "$RESPATH/assets" "$ASSETDIR"
|
|
||||||
mkdir -p "$ASSETDIR"/tmp
|
|
||||||
cp "$ROMPATH" "$ASSETDIR"/tmp/rom.z64
|
|
||||||
cd "$ASSETDIR" || return
|
|
||||||
|
|
||||||
# If an invalid rom was detected, let the user know
|
|
||||||
ROMHASH="$(shasum "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')"
|
|
||||||
|
|
||||||
remap_hashes
|
|
||||||
|
|
||||||
case "$ROMHASH" in
|
|
||||||
cee6bc3c2a634b41728f2af8da54d9bf8cc14099)
|
|
||||||
ROM=GC_NMQ_D
|
|
||||||
OTRNAME="oot.otr";;
|
|
||||||
0227d7c0074f2d0ac935631990da8ec5914597b4)
|
|
||||||
ROM=GC_NMQ_PAL_F
|
|
||||||
OTRNAME="oot.otr";;
|
|
||||||
328a1f1beba30ce5e178f031662019eb32c5f3b5)
|
|
||||||
ROM=N64_PAL_10
|
|
||||||
OTRNAME="oot.otr";;
|
|
||||||
cfbb98d392e4a9d39da8285d10cbef3974c2f012)
|
|
||||||
ROM=N64_PAL_11
|
|
||||||
OTRNAME="oot.otr";;
|
|
||||||
f46239439f59a2a594ef83cf68ef65043b1bffe2)
|
|
||||||
ROM=GC_MQ_PAL_F
|
|
||||||
OTRNAME="oot-mq.otr";;
|
|
||||||
50bebedad9e0f10746a52b07239e47fa6c284d03)
|
|
||||||
ROM=GC_MQ_D
|
|
||||||
OTRNAME="oot-mq.otr";;
|
|
||||||
079b855b943d6ad8bd1eb026c0ed169ecbdac7da)
|
|
||||||
ROM=GC_MQ_D
|
|
||||||
OTRNAME="oot-mq.otr";;
|
|
||||||
cfecfdc58d650e71a200c81f033de4e6d617a9f6)
|
|
||||||
ROM=GC_MQ_D
|
|
||||||
OTRNAME="oot-mq.otr";;
|
|
||||||
517bd9714c73cb96c21e7c2ef640d7b55186102f)
|
|
||||||
ROM=GC_MQ_D
|
|
||||||
OTRNAME="oot-mq.otr";;
|
|
||||||
*)
|
|
||||||
osascript -e 'display notification "One or more invalid ROM provided" with title "Ship Of Harkinian"'
|
|
||||||
rm -r "$ASSETDIR"
|
|
||||||
cd "$SNAME"
|
|
||||||
continue;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Only generate OTR if we don't have on of this type yet
|
|
||||||
if [ -e "$SHIP_HOME"/"$OTRNAME" ]; then
|
|
||||||
rm -r "$ASSETDIR"
|
|
||||||
cd "$SNAME"
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
|
|
||||||
osascript -e 'display notification "Generating OTR..." with title "Ship Of Harkinian"'
|
|
||||||
assets/extractor/ZAPD.out ed -i assets/extractor/xmls/"${ROM}" -b tmp/rom.z64 -fl assets/extractor/filelists -o placeholder -osf placeholder -gsf 1 -rconf assets/extractor/Config_"${ROM}".xml -se OTR --portVer "@CMAKE_PROJECT_VERSION@"
|
|
||||||
if [ -e "$ASSETDIR"/oot.otr ]; then
|
|
||||||
osascript -e 'display notification "OTR successfully generated" with title "Ship Of Harkinian"'
|
|
||||||
cp "$ASSETDIR"/oot.otr "$SHIP_HOME"/"$OTRNAME"
|
|
||||||
rm -r "$ASSETDIR"
|
|
||||||
cd "$SNAME"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -e "$SHIP_HOME"/oot*.otr ]; then
|
|
||||||
osascript -e 'display notification "OTR failed to generate" with title "Ship Of Harkinian"'
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$SNAME"
|
|
||||||
|
|
||||||
arch_name="$(uname -m)"
|
arch_name="$(uname -m)"
|
||||||
launch_arch="arm64"
|
launch_arch="arm64"
|
||||||
if [ "${arch_name}" = "x86_64" ] && [ "$(sysctl -in sysctl.proc_translated)" != "1" ]; then
|
if [ "${arch_name}" = "x86_64" ] && [ "$(sysctl -in sysctl.proc_translated)" != "1" ]; then
|
||||||
|
|||||||
@@ -258,24 +258,28 @@ namespace GameControlEditor {
|
|||||||
window->EndGroupPanelPublic(0);
|
window->EndGroupPanelPublic(0);
|
||||||
|
|
||||||
UIWidgets::Spacer(0);
|
UIWidgets::Spacer(0);
|
||||||
window->BeginGroupPanelPublic("Third-Person Camera", ImGui::GetContentRegionAvail());
|
window->BeginGroupPanelPublic("Free Look/Third-person Camera", ImGui::GetContentRegionAvail());
|
||||||
|
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera");
|
UIWidgets::PaddedEnhancementCheckbox("Enable Free Look", "gFreeCamera");
|
||||||
DrawHelpIcon("Enables free camera control\nNote: You must remap C buttons off of the right stick in the "
|
DrawHelpIcon("Enables free look camera control\nNote: You must remap C buttons off of the right stick in the "
|
||||||
"controller config menu, and map the camera stick to the right stick.");
|
"controller config menu, and map the camera stick to the right stick.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis");
|
UIWidgets::PaddedEnhancementCheckbox("Invert X Axis", "gInvertXAxis");
|
||||||
DrawHelpIcon("Inverts the Camera X Axis in:\n-Free camera");
|
DrawHelpIcon("Inverts the Camera X Axis in:\n-Free Look");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
|
UIWidgets::PaddedEnhancementCheckbox("Invert Y Axis", "gInvertYAxis", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
|
||||||
DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free camera");
|
DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free Look");
|
||||||
UIWidgets::Spacer(0);
|
UIWidgets::Spacer(0);
|
||||||
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal",
|
UIWidgets::PaddedEnhancementSliderFloat("Horizontal Sensitivity: %d %%", "##ThirdPersonSensitivity Horizontal",
|
||||||
"gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
|
"gThirdPersonCameraSensitivityX", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
|
||||||
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical",
|
DrawHelpIcon("Changes the sensitivity of the X axis control for Free Look");
|
||||||
|
UIWidgets::PaddedEnhancementSliderFloat("Vertical Sensitivity: %d %%", "##ThirdPersonSensitivity Vertical",
|
||||||
"gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
|
"gThirdPersonCameraSensitivityY", 0.01f, 5.0f, "", 1.0f, true, true, false, true);
|
||||||
|
DrawHelpIcon("Changes the sensitivity of the Y axis control for Free Look");
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
|
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
|
||||||
"gFreeCameraDistMax", 100, 900, "", 185, true, false, true);
|
"gFreeCameraDistMax", 100, 900, "", 185, true, false, true);
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Camera Transition Speed: %d", "##CamTranSpeed",
|
DrawHelpIcon("How far the camera sits from Link while in Free Look mode");
|
||||||
|
UIWidgets::PaddedEnhancementSliderInt("Transition Speed: %d", "##CamTranSpeed",
|
||||||
"gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true);
|
"gFreeCameraTransitionSpeed", 0, 900, "", 25, true, false, true);
|
||||||
|
DrawHelpIcon("How quickly the camera changes to the distance specified above");
|
||||||
window->EndGroupPanelPublic(0);
|
window->EndGroupPanelPublic(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ extern "C" {
|
|||||||
#include "objects/object_gi_soldout/object_gi_soldout.h"
|
#include "objects/object_gi_soldout/object_gi_soldout.h"
|
||||||
#include "objects/object_ik/object_ik.h"
|
#include "objects/object_ik/object_ik.h"
|
||||||
#include "objects/object_link_child/object_link_child.h"
|
#include "objects/object_link_child/object_link_child.h"
|
||||||
|
#include "objects/object_ru2/object_ru2.h"
|
||||||
|
|
||||||
uint32_t ResourceMgr_GameHasMasterQuest();
|
uint32_t ResourceMgr_GameHasMasterQuest();
|
||||||
uint32_t ResourceMgr_GameHasOriginal();
|
uint32_t ResourceMgr_GameHasOriginal();
|
||||||
@@ -187,10 +188,25 @@ void PatchIronKnuckleTextureOverflow() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PatchPrincessRutoEaring() {
|
||||||
|
// FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings.
|
||||||
|
// Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so
|
||||||
|
// it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the
|
||||||
|
// earring texture loads into the same place in TMEM as the brick texture, so when it comes to rendering, TEXEL1
|
||||||
|
// uses the earring texture with different clamp settings, and it displays without noticeable error. However, both
|
||||||
|
// texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses
|
||||||
|
// our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces
|
||||||
|
// TEXEL1 with TEXEL0, which is most likely the original intention, and all is well.
|
||||||
|
ResourceMgr_PatchGfxByName(gAdultRutoHeadDL, "RutoEaringTileFix", 162,
|
||||||
|
gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED,
|
||||||
|
TEXEL0, 0, PRIM_LOD_FRAC, COMBINED));
|
||||||
|
}
|
||||||
|
|
||||||
void ApplyAuthenticGfxPatches() {
|
void ApplyAuthenticGfxPatches() {
|
||||||
PatchDekuStickTextureOverflow();
|
PatchDekuStickTextureOverflow();
|
||||||
PatchFreezardTextureOverflow();
|
PatchFreezardTextureOverflow();
|
||||||
PatchIronKnuckleTextureOverflow();
|
PatchIronKnuckleTextureOverflow();
|
||||||
|
PatchPrincessRutoEaring();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patches the Sold Out GI DL to render the texture in the mirror boundary
|
// Patches the Sold Out GI DL to render the texture in the mirror boundary
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ typedef enum {
|
|||||||
TEXT_WARP_NOCTURNE_OF_SHADOW = 0x891,
|
TEXT_WARP_NOCTURNE_OF_SHADOW = 0x891,
|
||||||
TEXT_WARP_PRELUDE_OF_LIGHT = 0x892,
|
TEXT_WARP_PRELUDE_OF_LIGHT = 0x892,
|
||||||
TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200,
|
TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200,
|
||||||
|
TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210,
|
||||||
TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range
|
TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range
|
||||||
TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range
|
TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range
|
||||||
} TextIDs;
|
} TextIDs;
|
||||||
|
|||||||
@@ -782,7 +782,7 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl
|
|||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
if (ImGui::IsItemHovered() && hasDescription) {
|
if (ImGui::IsItemHovered() && hasDescription) {
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("%s", UIWidgets::WrappedText(flagTable.flagDescriptions.at(row * 16 + flagIndex), 60));
|
ImGui::Text("%s", UIWidgets::WrappedText(flagTable.flagDescriptions.at(row * 16 + flagIndex), 60).c_str());
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|||||||
@@ -37,12 +37,19 @@ GameInteractionEffectQueryResult GameInteractor::RemoveEffect(GameInteractionEff
|
|||||||
|
|
||||||
// MARK: - Helpers
|
// MARK: - Helpers
|
||||||
|
|
||||||
bool GameInteractor::IsSaveLoaded() {
|
bool GameInteractor::IsSaveLoaded(bool allowDbgSave) {
|
||||||
Player* player;
|
Player* player;
|
||||||
if (gPlayState != NULL) {
|
if (gPlayState != NULL) {
|
||||||
player = GET_PLAYER(gPlayState);
|
player = GET_PLAYER(gPlayState);
|
||||||
}
|
}
|
||||||
return (gPlayState == NULL || player == NULL || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) ? false : true;
|
|
||||||
|
// Checking for normal game mode prevents debug saves from reporting true on title screen
|
||||||
|
if (gPlayState == NULL || player == NULL || gSaveContext.gameMode != GAMEMODE_NORMAL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid save file or debug save
|
||||||
|
return (gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2) || (allowDbgSave && gSaveContext.fileNum == 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameInteractor::IsGameplayPaused() {
|
bool GameInteractor::IsGameplayPaused() {
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#define DEFINE_HOOK(name, type) \
|
#define DEFINE_HOOK(name, type) \
|
||||||
struct name { \
|
struct name { \
|
||||||
@@ -193,10 +194,11 @@ public:
|
|||||||
|
|
||||||
DEFINE_HOOK(OnSetGameLanguage, void());
|
DEFINE_HOOK(OnSetGameLanguage, void());
|
||||||
|
|
||||||
|
DEFINE_HOOK(OnFileDropped, void(std::string filePath));
|
||||||
DEFINE_HOOK(OnAssetAltChange, void());
|
DEFINE_HOOK(OnAssetAltChange, void());
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
static bool IsSaveLoaded();
|
static bool IsSaveLoaded(bool allowDbgSave = false);
|
||||||
static bool IsGameplayPaused();
|
static bool IsGameplayPaused();
|
||||||
static bool CanSpawnActor();
|
static bool CanSpawnActor();
|
||||||
static bool CanAddOrTakeAmmo(int16_t amount, int16_t item);
|
static bool CanAddOrTakeAmmo(int16_t amount, int16_t item);
|
||||||
|
|||||||
@@ -618,7 +618,7 @@ void DrawGameplayStatsOptionsTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameplayStatsWindow::DrawElement() {
|
void GameplayStatsWindow::DrawElement() {
|
||||||
ImGui::SetNextWindowSize(ImVec2(480, 550), ImGuiCond_Appearing);
|
ImGui::SetNextWindowSize(ImVec2(480, 550), ImGuiCond_FirstUseEver);
|
||||||
if (!ImGui::Begin("Gameplay Stats", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
if (!ImGui::Begin("Gameplay Stats", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void ReloadSceneTogglingLinkAge() {
|
|||||||
|
|
||||||
void RegisterInfiniteMoney() {
|
void RegisterInfiniteMoney() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
|
if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
|
||||||
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
||||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||||
@@ -58,7 +58,7 @@ void RegisterInfiniteMoney() {
|
|||||||
|
|
||||||
void RegisterInfiniteHealth() {
|
void RegisterInfiniteHealth() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
|
if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
|
||||||
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
||||||
gSaveContext.health = gSaveContext.healthCapacity;
|
gSaveContext.health = gSaveContext.healthCapacity;
|
||||||
@@ -69,7 +69,7 @@ void RegisterInfiniteHealth() {
|
|||||||
|
|
||||||
void RegisterInfiniteAmmo() {
|
void RegisterInfiniteAmmo() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
|
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
|
||||||
// Deku Sticks
|
// Deku Sticks
|
||||||
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
||||||
@@ -106,7 +106,7 @@ void RegisterInfiniteAmmo() {
|
|||||||
|
|
||||||
void RegisterInfiniteMagic() {
|
void RegisterInfiniteMagic() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
|
if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
|
||||||
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
|
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
|
||||||
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
|
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
|
||||||
@@ -117,7 +117,7 @@ void RegisterInfiniteMagic() {
|
|||||||
|
|
||||||
void RegisterInfiniteNayrusLove() {
|
void RegisterInfiniteNayrusLove() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
|
if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
|
||||||
gSaveContext.nayrusLoveTimer = 0x44B;
|
gSaveContext.nayrusLoveTimer = 0x44B;
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ void RegisterInfiniteNayrusLove() {
|
|||||||
|
|
||||||
void RegisterMoonJumpOnL() {
|
void RegisterMoonJumpOnL() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
|
|
||||||
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
|
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
|
||||||
Player* player = GET_PLAYER(gPlayState);
|
Player* player = GET_PLAYER(gPlayState);
|
||||||
@@ -141,7 +141,7 @@ void RegisterMoonJumpOnL() {
|
|||||||
|
|
||||||
void RegisterInfiniteISG() {
|
void RegisterInfiniteISG() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
|
|
||||||
if (CVarGetInteger("gEzISG", 0) != 0) {
|
if (CVarGetInteger("gEzISG", 0) != 0) {
|
||||||
Player* player = GET_PLAYER(gPlayState);
|
Player* player = GET_PLAYER(gPlayState);
|
||||||
@@ -153,7 +153,7 @@ void RegisterInfiniteISG() {
|
|||||||
//Permanent quick put away (QPA) glitched damage value
|
//Permanent quick put away (QPA) glitched damage value
|
||||||
void RegisterEzQPA() {
|
void RegisterEzQPA() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
|
|
||||||
if (CVarGetInteger("gEzQPA", 0) != 0) {
|
if (CVarGetInteger("gEzQPA", 0) != 0) {
|
||||||
Player* player = GET_PLAYER(gPlayState);
|
Player* player = GET_PLAYER(gPlayState);
|
||||||
@@ -165,7 +165,7 @@ void RegisterEzQPA() {
|
|||||||
|
|
||||||
void RegisterUnrestrictedItems() {
|
void RegisterUnrestrictedItems() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
|
|
||||||
if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
|
if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
|
||||||
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
|
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
|
||||||
@@ -193,11 +193,14 @@ void RegisterFreezeTime() {
|
|||||||
/// Switches Link's age and respawns him at the last entrance he entered.
|
/// Switches Link's age and respawns him at the last entrance he entered.
|
||||||
void RegisterSwitchAge() {
|
void RegisterSwitchAge() {
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) {
|
static bool warped = false;
|
||||||
|
|
||||||
|
if (!GameInteractor::IsSaveLoaded(true)) {
|
||||||
CVarClear("gSwitchAge");
|
CVarClear("gSwitchAge");
|
||||||
|
warped = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static bool warped = false;
|
|
||||||
static Vec3f playerPos;
|
static Vec3f playerPos;
|
||||||
static int16_t playerYaw;
|
static int16_t playerYaw;
|
||||||
static RoomContext* roomCtx;
|
static RoomContext* roomCtx;
|
||||||
@@ -231,7 +234,7 @@ void RegisterSwitchAge() {
|
|||||||
void RegisterOcarinaTimeTravel() {
|
void RegisterOcarinaTimeTravel() {
|
||||||
|
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOcarinaSongAction>([]() {
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOcarinaSongAction>([]() {
|
||||||
if (!GameInteractor::IsSaveLoaded()) {
|
if (!GameInteractor::IsSaveLoaded(true)) {
|
||||||
CVarClear("gTimeTravel");
|
CVarClear("gTimeTravel");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1038,8 +1041,8 @@ void RegisterRandomizedEnemySizes() {
|
|||||||
uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || (actor->id == ACTOR_BOSS_SST && actor->params == -1);
|
uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || (actor->id == ACTOR_BOSS_SST && actor->params == -1);
|
||||||
|
|
||||||
// Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger.
|
// Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger.
|
||||||
uint8_t smallOnlyEnemy =
|
uint8_t smallOnlyEnemy = actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD ||
|
||||||
actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD || actor->id == ACTOR_BOSS_FD2 || ACTOR_EN_DH;
|
actor->id == ACTOR_BOSS_FD2 || actor->id == ACTOR_EN_DH;
|
||||||
|
|
||||||
// Only apply to enemies and bosses.
|
// Only apply to enemies and bosses.
|
||||||
if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || excludedEnemy) {
|
if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || excludedEnemy) {
|
||||||
|
|||||||
@@ -12,6 +12,14 @@ void clearCvars(std::vector<const char*> cvarsToClear) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string FormatLocations(std::vector<RandomizerCheck> locs) {
|
||||||
|
std::string locString = "";
|
||||||
|
for (auto loc: locs) {
|
||||||
|
locString += std::to_string(loc) + ",";
|
||||||
|
}
|
||||||
|
return locString;
|
||||||
|
}
|
||||||
|
|
||||||
void applyPreset(std::vector<PresetEntry> entries) {
|
void applyPreset(std::vector<PresetEntry> entries) {
|
||||||
for(auto& [cvar, type, value] : entries) {
|
for(auto& [cvar, type, value] : entries) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -24,6 +32,9 @@ void applyPreset(std::vector<PresetEntry> entries) {
|
|||||||
case PRESET_ENTRY_TYPE_STRING:
|
case PRESET_ENTRY_TYPE_STRING:
|
||||||
CVarSetString(cvar, std::get<const char*>(value));
|
CVarSetString(cvar, std::get<const char*>(value));
|
||||||
break;
|
break;
|
||||||
|
case PRESET_ENTRY_TYPE_CPP_STRING:
|
||||||
|
CVarSetString(cvar, std::get<std::string>(value).c_str());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -11,6 +12,7 @@ enum PresetEntryType {
|
|||||||
PRESET_ENTRY_TYPE_S32,
|
PRESET_ENTRY_TYPE_S32,
|
||||||
PRESET_ENTRY_TYPE_FLOAT,
|
PRESET_ENTRY_TYPE_FLOAT,
|
||||||
PRESET_ENTRY_TYPE_STRING,
|
PRESET_ENTRY_TYPE_STRING,
|
||||||
|
PRESET_ENTRY_TYPE_CPP_STRING,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PresetType {
|
enum PresetType {
|
||||||
@@ -36,15 +38,19 @@ enum RandomizerPreset {
|
|||||||
typedef struct PresetEntry {
|
typedef struct PresetEntry {
|
||||||
const char* cvar;
|
const char* cvar;
|
||||||
PresetEntryType type;
|
PresetEntryType type;
|
||||||
std::variant<int32_t, float, const char*> value;
|
std::variant<int32_t, float, const char*, std::string> value;
|
||||||
} PresetEntry;
|
} PresetEntry;
|
||||||
|
|
||||||
|
std::string FormatLocations(std::vector<RandomizerCheck> locs);
|
||||||
|
|
||||||
#define PRESET_ENTRY_S32(cvar, value) \
|
#define PRESET_ENTRY_S32(cvar, value) \
|
||||||
{ cvar, PRESET_ENTRY_TYPE_S32, value }
|
{ cvar, PRESET_ENTRY_TYPE_S32, value }
|
||||||
#define PRESET_ENTRY_FLOAT(cvar, value) \
|
#define PRESET_ENTRY_FLOAT(cvar, value) \
|
||||||
{ cvar, PRESET_ENTRY_TYPE_FLOAT, value }
|
{ cvar, PRESET_ENTRY_TYPE_FLOAT, value }
|
||||||
#define PRESET_ENTRY_STRING(cvar, value) \
|
#define PRESET_ENTRY_STRING(cvar, value) \
|
||||||
{ cvar, PRESET_ENTRY_TYPE_STRING, value }
|
{ cvar, PRESET_ENTRY_TYPE_STRING, value }
|
||||||
|
#define PRESET_ENTRY_CPP_STRING(cvar, value) \
|
||||||
|
{ cvar, PRESET_ENTRY_TYPE_CPP_STRING, value }
|
||||||
|
|
||||||
void DrawPresetSelector(PresetType presetType);
|
void DrawPresetSelector(PresetType presetType);
|
||||||
void clearCvars(std::vector<const char*> cvarsToClear);
|
void clearCvars(std::vector<const char*> cvarsToClear);
|
||||||
@@ -205,6 +211,8 @@ const std::vector<const char*> enhancementsCvars = {
|
|||||||
"gDisableLOD",
|
"gDisableLOD",
|
||||||
"gDisableDrawDistance",
|
"gDisableDrawDistance",
|
||||||
"gDisableKokiriDrawDistance",
|
"gDisableKokiriDrawDistance",
|
||||||
|
"gEnhancements.WidescreenActorCulling",
|
||||||
|
"gEnhancements.ExtendedCullingExcludeGlitchActors",
|
||||||
"gLowResMode",
|
"gLowResMode",
|
||||||
"gDrawLineupTick",
|
"gDrawLineupTick",
|
||||||
"gQuickBongoKill",
|
"gQuickBongoKill",
|
||||||
@@ -866,7 +874,8 @@ const std::vector<PresetEntry> spockRacePresetEntries = {
|
|||||||
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
|
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
|
||||||
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
||||||
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
|
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
|
||||||
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"),
|
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations(
|
||||||
|
{ RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })),
|
||||||
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
|
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
|
||||||
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
|
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
|
||||||
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
||||||
@@ -958,7 +967,8 @@ const std::vector<PresetEntry> spockRaceNoLogicPresetEntries = {
|
|||||||
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
|
PRESET_ENTRY_S32("gRandomizeDampeHint", 1),
|
||||||
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
||||||
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
|
PRESET_ENTRY_S32("gRandomizeEnableBombchuDrops", 1),
|
||||||
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "78,143,144,229,"),
|
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations(
|
||||||
|
{ RC_MARKET_10_BIG_POES, RC_KAK_40_GOLD_SKULLTULA_REWARD, RC_KAK_50_GOLD_SKULLTULA_REWARD, RC_ZR_FROGS_OCARINA_GAME })),
|
||||||
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
|
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_OPEN),
|
||||||
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
|
PRESET_ENTRY_S32("gRandomizeFullWallets", 1),
|
||||||
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
||||||
@@ -1011,7 +1021,7 @@ const std::vector<PresetEntry> s6PresetEntries = {
|
|||||||
PRESET_ENTRY_S32("gRandomizeBigPoeTargetCount", 1),
|
PRESET_ENTRY_S32("gRandomizeBigPoeTargetCount", 1),
|
||||||
PRESET_ENTRY_S32("gRandomizeCuccosToReturn", 4),
|
PRESET_ENTRY_S32("gRandomizeCuccosToReturn", 4),
|
||||||
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
PRESET_ENTRY_S32("gRandomizeDoorOfTime", RO_DOOROFTIME_OPEN),
|
||||||
PRESET_ENTRY_STRING("gRandomizeExcludedLocations", "48,"),
|
PRESET_ENTRY_CPP_STRING("gRandomizeExcludedLocations", FormatLocations({ RC_DEKU_THEATER_MASK_OF_TRUTH })),
|
||||||
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_CLOSED_DEKU),
|
PRESET_ENTRY_S32("gRandomizeForest", RO_FOREST_CLOSED_DEKU),
|
||||||
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
PRESET_ENTRY_S32("gRandomizeGanonTrial", RO_GANONS_TRIALS_SKIP),
|
||||||
PRESET_ENTRY_S32("gRandomizeGerudoFortress", RO_GF_FAST),
|
PRESET_ENTRY_S32("gRandomizeGerudoFortress", RO_GF_FAST),
|
||||||
|
|||||||
@@ -846,10 +846,10 @@ static void RandomizeDungeonItems() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (GerudoKeys.Is(GERUDOKEYS_ANY_DUNGEON)) {
|
if (GerudoKeys.Is(GERUDOKEYS_ANY_DUNGEON)) {
|
||||||
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; });
|
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY || i == GERUDO_FORTRESS_KEY_RING; });
|
||||||
AddElementsToPool(anyDungeonItems, gerudoKeys);
|
AddElementsToPool(anyDungeonItems, gerudoKeys);
|
||||||
} else if (GerudoKeys.Is(GERUDOKEYS_OVERWORLD)) {
|
} else if (GerudoKeys.Is(GERUDOKEYS_OVERWORLD)) {
|
||||||
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; });
|
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY || i == GERUDO_FORTRESS_KEY_RING; });
|
||||||
AddElementsToPool(overworldItems, gerudoKeys);
|
AddElementsToPool(overworldItems, gerudoKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ void AreaTable_Init_DeathMountain() {
|
|||||||
Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
|
Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
|
||||||
Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}),
|
Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}),
|
||||||
Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}}),
|
Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}}),
|
||||||
Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || GCDaruniasDoorOpenChild;}}),
|
Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && GCDaruniasDoorOpenChild);}}),
|
||||||
Entrance(GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(HOOKSHOT) && LogicGoronCityGrotto));}}),
|
Entrance(GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(HOOKSHOT) && LogicGoronCityGrotto));}}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ void AreaTable_Init_FireTemple() {
|
|||||||
}, {
|
}, {
|
||||||
//Exits
|
//Exits
|
||||||
Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}),
|
Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}),
|
||||||
Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}}),
|
Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && (LogicFireBossDoorJump || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}))) || CanUse(HOVER_BOOTS));}}),
|
||||||
});
|
});
|
||||||
|
|
||||||
areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ void AreaTable_Init_ForestTemple() {
|
|||||||
Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}),
|
Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}),
|
||||||
Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && CanJumpslash && GoronBracelet);}}),
|
Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && CanJumpslash && GoronBracelet);}}),
|
||||||
Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
||||||
Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return IsAdult && (CanUse(BOW) || CanUse(SLINGSHOT)) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}}),
|
||||||
});
|
});
|
||||||
|
|
||||||
areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ namespace Logic {
|
|||||||
Fish = HasBottle && FishAccess;
|
Fish = HasBottle && FishAccess;
|
||||||
Fairy = HasBottle && FairyAccess;
|
Fairy = HasBottle && FairyAccess;
|
||||||
|
|
||||||
FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20);
|
FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20) && (BombBag || BombchusInLogic);
|
||||||
CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag);
|
CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag);
|
||||||
HasBombchus = (BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus));
|
HasBombchus = (BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus));
|
||||||
|
|
||||||
|
|||||||
@@ -364,31 +364,16 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
|
|||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("O0")
|
#pragma GCC optimize ("O0")
|
||||||
bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
|
bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
|
||||||
try {
|
if (strcmp(spoilerFileName, "") != 0) {
|
||||||
if (strcmp(spoilerFileName, "") != 0) {
|
std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
|
||||||
std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
|
if (!spoilerFileStream) {
|
||||||
if (!spoilerFileStream) {
|
return false;
|
||||||
return false;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
json spoilerFileJson;
|
|
||||||
spoilerFileStream >> spoilerFileJson;
|
|
||||||
|
|
||||||
if (!spoilerFileJson.contains("version") || !spoilerFileJson.contains("finalSeed")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
SPDLOG_ERROR("Error checking if spoiler file exists: {}", e.what());
|
|
||||||
return false;
|
|
||||||
} catch (...) {
|
|
||||||
SPDLOG_ERROR("Error checking if spoiler file exists");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
#pragma optimize("", on)
|
#pragma optimize("", on)
|
||||||
@@ -494,6 +479,13 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
|
|||||||
"Zu {{location}}?\x1B&%gOK&No%w\x02",
|
"Zu {{location}}?\x1B&%gOK&No%w\x02",
|
||||||
"Se téléporter vers&{{location}}?\x1B&%gOK!&Non%w\x02"));
|
"Se téléporter vers&{{location}}?\x1B&%gOK!&Non%w\x02"));
|
||||||
|
|
||||||
|
// Bow Shooting Gallery reminder
|
||||||
|
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW,
|
||||||
|
CustomMessage("Come back when you have your own&bow and you'll get a %rdifferent prize%w!",
|
||||||
|
"Komm wieder sobald du deinen eigenen&Bogen hast, um einen %rspeziellen Preis%w zu&erhalten!",
|
||||||
|
"J'aurai %rune autre récompense%w pour toi&lorsque tu auras ton propre arc."));
|
||||||
|
|
||||||
|
// Lake Hylia water level system
|
||||||
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN,
|
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN,
|
||||||
CustomMessage("Water level control system.&Keep away!",
|
CustomMessage("Water level control system.&Keep away!",
|
||||||
"Wasserstand Kontrollsystem&Finger weg!",
|
"Wasserstand Kontrollsystem&Finger weg!",
|
||||||
@@ -4215,7 +4207,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
break;
|
break;
|
||||||
case RO_LACS_GREG_REWARD:
|
case RO_LACS_GREG_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount",
|
UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount",
|
||||||
"gRandomizeLacsStoneCount", 1, 4, "", 4, true, true, false);
|
"gRandomizeLacsStoneCount", 1, 4, "", 3, true, true, false);
|
||||||
break;
|
break;
|
||||||
case RO_LACS_WILDCARD_REWARD:
|
case RO_LACS_WILDCARD_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount",
|
UIWidgets::PaddedEnhancementSliderInt("Stone Count: %d", "##RandoLacsStoneCount",
|
||||||
@@ -4244,7 +4236,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
break;
|
break;
|
||||||
case RO_LACS_GREG_REWARD:
|
case RO_LACS_GREG_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount",
|
UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount",
|
||||||
"gRandomizeLacsMedallionCount", 1, 7, "", 7, true, true, false);
|
"gRandomizeLacsMedallionCount", 1, 7, "", 6, true, true, false);
|
||||||
break;
|
break;
|
||||||
case RO_LACS_WILDCARD_REWARD:
|
case RO_LACS_WILDCARD_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount",
|
UIWidgets::PaddedEnhancementSliderInt("Medallion Count: %d", "##RandoLacsMedallionCount",
|
||||||
@@ -4273,7 +4265,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
break;
|
break;
|
||||||
case RO_LACS_GREG_REWARD:
|
case RO_LACS_GREG_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount",
|
UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount",
|
||||||
"gRandomizeLacsRewardCount", 1, 10, "", 10, true, true, false);
|
"gRandomizeLacsRewardCount", 1, 10, "", 9, true, true, false);
|
||||||
break;
|
break;
|
||||||
case RO_LACS_WILDCARD_REWARD:
|
case RO_LACS_WILDCARD_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount",
|
UIWidgets::PaddedEnhancementSliderInt("Reward Count: %d", "##RandoLacsRewardCount",
|
||||||
@@ -4302,7 +4294,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
break;
|
break;
|
||||||
case RO_LACS_GREG_REWARD:
|
case RO_LACS_GREG_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount",
|
UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount",
|
||||||
"gRandomizeLacsDungeonCount", 1, 9, "", 9, true, true, false);
|
"gRandomizeLacsDungeonCount", 1, 9, "", 8, true, true, false);
|
||||||
break;
|
break;
|
||||||
case RO_LACS_WILDCARD_REWARD:
|
case RO_LACS_WILDCARD_REWARD:
|
||||||
UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount",
|
UIWidgets::PaddedEnhancementSliderInt("Dungeon Count: %d", "##RandoLacsDungeonCount",
|
||||||
@@ -4697,7 +4689,11 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
excludedLocationString += std::to_string(excludedLocationIt);
|
excludedLocationString += std::to_string(excludedLocationIt);
|
||||||
excludedLocationString += ",";
|
excludedLocationString += ",";
|
||||||
}
|
}
|
||||||
CVarSetString("gRandomizeExcludedLocations", excludedLocationString.c_str());
|
if (excludedLocationString == "") {
|
||||||
|
CVarClear("gRandomizeExcludedLocations");
|
||||||
|
} else {
|
||||||
|
CVarSetString("gRandomizeExcludedLocations", excludedLocationString.c_str());
|
||||||
|
}
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -4874,7 +4870,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
enabledTrickString += std::to_string(enabledTrickIt);
|
enabledTrickString += std::to_string(enabledTrickIt);
|
||||||
enabledTrickString += ",";
|
enabledTrickString += ",";
|
||||||
}
|
}
|
||||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
CVarClear("gRandomizeEnabledTricks");
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -5078,7 +5074,7 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
enabledTrickString += std::to_string(enabledTrickIt);
|
enabledTrickString += std::to_string(enabledTrickIt);
|
||||||
enabledTrickString += ",";
|
enabledTrickString += ",";
|
||||||
}
|
}
|
||||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
CVarClear("gRandomizeEnabledTricks");
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5116,7 +5112,11 @@ void RandomizerSettingsWindow::DrawElement() {
|
|||||||
enabledTrickString += std::to_string(enabledTrickIt);
|
enabledTrickString += std::to_string(enabledTrickIt);
|
||||||
enabledTrickString += ",";
|
enabledTrickString += ",";
|
||||||
}
|
}
|
||||||
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
if (enabledTrickString == "") {
|
||||||
|
CVarClear("gRandomizeEnabledTricks");
|
||||||
|
} else {
|
||||||
|
CVarSetString("gRandomizeEnabledTricks", enabledTrickString.c_str());
|
||||||
|
}
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
}
|
}
|
||||||
DrawTagChips(*rtObject.rtTags);
|
DrawTagChips(*rtObject.rtTags);
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ bool initialized;
|
|||||||
bool doAreaScroll;
|
bool doAreaScroll;
|
||||||
bool previousShowHidden = false;
|
bool previousShowHidden = false;
|
||||||
bool hideShopRightChecks = true;
|
bool hideShopRightChecks = true;
|
||||||
|
bool alwaysShowGS = false;
|
||||||
|
|
||||||
std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 },
|
std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 },
|
||||||
{ SCENE_BAZAAR, RC_MARKET_BAZAAR_ITEM_1 },
|
{ SCENE_BAZAAR, RC_MARKET_BAZAAR_ITEM_1 },
|
||||||
@@ -102,12 +103,30 @@ std::map<SceneID, RandomizerCheckArea> DungeonRCAreasBySceneID = {
|
|||||||
{SCENE_INSIDE_GANONS_CASTLE, RCAREA_GANONS_CASTLE},
|
{SCENE_INSIDE_GANONS_CASTLE, RCAREA_GANONS_CASTLE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Dungeon entrances with obvious visual differences between MQ and vanilla qualifying as spoiling on sight
|
||||||
|
std::vector<uint32_t> spoilingEntrances = {
|
||||||
|
0x0000, // ENTR_DEKU_TREE_0
|
||||||
|
0x0467, // ENTR_DODONGOS_CAVERN_1
|
||||||
|
0x0028, // ENTR_JABU_JABU_0
|
||||||
|
0x0407, // ENTR_JABU_JABU_1
|
||||||
|
0x0169, // ENTR_FOREST_TEMPLE_0
|
||||||
|
0x0165, // ENTR_FIRE_TEMPLE_0
|
||||||
|
0x0175, // ENTR_FIRE_TEMPLE_1
|
||||||
|
0x0423, // ENTR_WATER_TEMPLE_1
|
||||||
|
0x0082, // ENTR_SPIRIT_TEMPLE_0
|
||||||
|
0x02B2, // ENTR_SHADOW_TEMPLE_1
|
||||||
|
0x0088, // ENTR_ICE_CAVERN_0
|
||||||
|
0x0008, // ENTR_GERUDO_TRAINING_GROUNDS_0
|
||||||
|
0x0467 // ENTR_INSIDE_GANONS_CASTLE_0
|
||||||
|
};
|
||||||
|
|
||||||
std::map<RandomizerCheckArea, std::vector<RandomizerCheckObject>> checksByArea;
|
std::map<RandomizerCheckArea, std::vector<RandomizerCheckObject>> checksByArea;
|
||||||
bool areasFullyChecked[RCAREA_INVALID];
|
bool areasFullyChecked[RCAREA_INVALID];
|
||||||
u32 areasSpoiled = 0;
|
u32 areasSpoiled = 0;
|
||||||
bool showVOrMQ;
|
bool showVOrMQ;
|
||||||
s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)"
|
s8 areaChecksGotten[RCAREA_INVALID]; //| "Kokiri Forest (4/9)"
|
||||||
bool optCollapseAll; // A bool that will collapse all checks once
|
s8 areaCheckTotals[RCAREA_INVALID];
|
||||||
|
bool optCollapseAll; // A bool that will collapse all checks once
|
||||||
bool optExpandAll; // A bool that will expand all checks once
|
bool optExpandAll; // A bool that will expand all checks once
|
||||||
RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK;
|
RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK;
|
||||||
RandomizerCheckArea previousArea = RCAREA_INVALID;
|
RandomizerCheckArea previousArea = RCAREA_INVALID;
|
||||||
@@ -224,6 +243,26 @@ void TrySetAreas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecalculateAreaTotals() {
|
||||||
|
for (auto [rcArea, rcObjects] : checksByArea) {
|
||||||
|
if (rcArea == RCAREA_INVALID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
areaChecksGotten[rcArea] = 0;
|
||||||
|
areaCheckTotals[rcArea] = 0;
|
||||||
|
for (auto rcObj : rcObjects) {
|
||||||
|
if (!IsVisibleInCheckTracker(rcObj)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
areaCheckTotals[rcArea]++;
|
||||||
|
if (gSaveContext.checkTrackerData[rcObj.rc].skipped || gSaveContext.checkTrackerData[rcObj.rc].status == RCSHOW_COLLECTED
|
||||||
|
|| gSaveContext.checkTrackerData[rcObj.rc].status == RCSHOW_SAVED) {
|
||||||
|
areaChecksGotten[rcArea]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetCheckCollected(RandomizerCheck rc) {
|
void SetCheckCollected(RandomizerCheck rc) {
|
||||||
gSaveContext.checkTrackerData[rc].status = RCSHOW_COLLECTED;
|
gSaveContext.checkTrackerData[rc].status = RCSHOW_COLLECTED;
|
||||||
RandomizerCheckObject rcObj;
|
RandomizerCheckObject rcObj;
|
||||||
@@ -232,13 +271,19 @@ void SetCheckCollected(RandomizerCheck rc) {
|
|||||||
} else {
|
} else {
|
||||||
rcObj = RandomizerCheckObjects::GetAllRCObjects().find(rc)->second;
|
rcObj = RandomizerCheckObjects::GetAllRCObjects().find(rc)->second;
|
||||||
}
|
}
|
||||||
if (!gSaveContext.checkTrackerData[rc].skipped) {
|
if (IsVisibleInCheckTracker(rcObj)) {
|
||||||
areaChecksGotten[rcObj.rcArea]++;
|
if (!gSaveContext.checkTrackerData[rc].skipped) {
|
||||||
} else {
|
areaChecksGotten[rcObj.rcArea]++;
|
||||||
gSaveContext.checkTrackerData[rc].skipped = false;
|
} else {
|
||||||
|
gSaveContext.checkTrackerData[rc].skipped = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
|
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
|
||||||
|
|
||||||
|
if (!IsAreaSpoiled(rcObj.rcArea)) {
|
||||||
|
SetAreaSpoiled(rcObj.rcArea);
|
||||||
|
}
|
||||||
|
|
||||||
doAreaScroll = true;
|
doAreaScroll = true;
|
||||||
UpdateOrdering(rcObj.rcArea);
|
UpdateOrdering(rcObj.rcArea);
|
||||||
UpdateInventoryChecks();
|
UpdateInventoryChecks();
|
||||||
@@ -345,6 +390,7 @@ void ClearAreaChecksAndTotals() {
|
|||||||
for (auto& [rcArea, vec] : checksByArea) {
|
for (auto& [rcArea, vec] : checksByArea) {
|
||||||
vec.clear();
|
vec.clear();
|
||||||
areaChecksGotten[rcArea] = 0;
|
areaChecksGotten[rcArea] = 0;
|
||||||
|
areaCheckTotals[rcArea] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,9 +470,9 @@ void CheckTrackerLoadGame(int32_t fileNum) {
|
|||||||
TrySetAreas();
|
TrySetAreas();
|
||||||
for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
|
for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
|
||||||
RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc];
|
RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc];
|
||||||
if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET ||
|
if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET || !RandomizerCheckObjects::GetAllRCObjects().contains(rc)) {
|
||||||
!RandomizerCheckObjects::GetAllRCObjects().contains(rc))
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
RandomizerCheckObject realRcObj;
|
RandomizerCheckObject realRcObj;
|
||||||
if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
|
if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) {
|
||||||
@@ -434,15 +480,22 @@ void CheckTrackerLoadGame(int32_t fileNum) {
|
|||||||
} else {
|
} else {
|
||||||
realRcObj = rcObj;
|
realRcObj = rcObj;
|
||||||
}
|
}
|
||||||
if (!IsVisibleInCheckTracker(realRcObj)) continue;
|
|
||||||
|
|
||||||
checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj);
|
checksByArea.find(realRcObj.rcArea)->second.push_back(realRcObj);
|
||||||
if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) {
|
if (IsVisibleInCheckTracker(realRcObj)) {
|
||||||
areaChecksGotten[realRcObj.rcArea]++;
|
areaCheckTotals[realRcObj.rcArea]++;
|
||||||
|
if (rcTrackerData.status == RCSHOW_COLLECTED || rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) {
|
||||||
|
areaChecksGotten[realRcObj.rcArea]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (areaChecksGotten[realRcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(realRcObj.rcArea)) {
|
for (int i = RCAREA_KOKIRI_FOREST; i < RCAREA_INVALID; i++) {
|
||||||
areasSpoiled |= (1 << realRcObj.rcArea);
|
if (!IsAreaSpoiled(static_cast<RandomizerCheckArea>(i)) && (RandomizerCheckObjects::AreaIsOverworld(static_cast<RandomizerCheckArea>(i)) || !IS_RANDO ||
|
||||||
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_NONE ||
|
||||||
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SELECTION ||
|
||||||
|
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
|
||||||
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) == 12))) {
|
||||||
|
SetAreaSpoiled(static_cast<RandomizerCheckArea>(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
|
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) {
|
||||||
@@ -463,6 +516,7 @@ void CheckTrackerLoadGame(int32_t fileNum) {
|
|||||||
|
|
||||||
checksByArea.find(startingArea)->second.push_back(linksPocket);
|
checksByArea.find(startingArea)->second.push_back(linksPocket);
|
||||||
areaChecksGotten[startingArea]++;
|
areaChecksGotten[startingArea]++;
|
||||||
|
areaCheckTotals[startingArea]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
|
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
|
||||||
@@ -511,6 +565,9 @@ void CheckTrackerTransition(uint32_t sceneNum) {
|
|||||||
SetShopSeen(sceneNum, false);
|
SetShopSeen(sceneNum, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!IsAreaSpoiled(currentArea) && (RandomizerCheckObjects::AreaIsOverworld(currentArea) || std::find(spoilingEntrances.begin(), spoilingEntrances.end(), gPlayState->nextEntranceIndex) != spoilingEntrances.end())) {
|
||||||
|
SetAreaSpoiled(currentArea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckTrackerFrame() {
|
void CheckTrackerFrame() {
|
||||||
@@ -728,6 +785,7 @@ void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
|
|||||||
|
|
||||||
void InitTrackerData(bool isDebug) {
|
void InitTrackerData(bool isDebug) {
|
||||||
TrySetAreas();
|
TrySetAreas();
|
||||||
|
areasSpoiled = 0;
|
||||||
for (auto& [rc, rco] : RandomizerCheckObjects::GetAllRCObjects()) {
|
for (auto& [rc, rco] : RandomizerCheckObjects::GetAllRCObjects()) {
|
||||||
if (rc != RC_UNKNOWN_CHECK && rc != RC_MAX) {
|
if (rc != RC_UNKNOWN_CHECK && rc != RC_MAX) {
|
||||||
DefaultCheckData(rc);
|
DefaultCheckData(rc);
|
||||||
@@ -755,6 +813,7 @@ void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) {
|
|||||||
SaveManager::Instance->SaveData("hintItem", saveContext->checkTrackerData[i].hintItem);
|
SaveManager::Instance->SaveData("hintItem", saveContext->checkTrackerData[i].hintItem);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
SaveManager::Instance->SaveData("areasSpoiled", areasSpoiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
||||||
@@ -770,6 +829,7 @@ void LoadFile() {
|
|||||||
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
|
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
SaveManager::Instance->LoadData("areasSpoiled", areasSpoiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Teardown() {
|
void Teardown() {
|
||||||
@@ -781,11 +841,24 @@ void Teardown() {
|
|||||||
lastLocationChecked = RC_UNKNOWN_CHECK;
|
lastLocationChecked = RC_UNKNOWN_CHECK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsAreaSpoiled(RandomizerCheckArea rcArea) {
|
||||||
|
return areasSpoiled & (1 << rcArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAreaSpoiled(RandomizerCheckArea rcArea) {
|
||||||
|
areasSpoiled |= (1 << rcArea);
|
||||||
|
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) {
|
void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) {
|
||||||
auto area = RandomizerCheckObjects::GetAllRCObjects().find(static_cast<RandomizerCheck>(check))->second.rcArea;
|
auto area = RandomizerCheckObjects::GetAllRCObjects().find(static_cast<RandomizerCheck>(check))->second.rcArea;
|
||||||
if (!gSaveContext.checkTrackerData[check].skipped && data.skipped) {
|
if ((!gSaveContext.checkTrackerData[check].skipped && data.skipped) ||
|
||||||
|
((gSaveContext.checkTrackerData[check].status != RCSHOW_COLLECTED && gSaveContext.checkTrackerData[check].status != RCSHOW_SAVED) &&
|
||||||
|
(data.status == RCSHOW_COLLECTED || data.status == RCSHOW_SAVED))) {
|
||||||
areaChecksGotten[area]++;
|
areaChecksGotten[area]++;
|
||||||
} else if (gSaveContext.checkTrackerData[check].skipped && !data.skipped) {
|
} else if ((gSaveContext.checkTrackerData[check].skipped && !data.skipped) ||
|
||||||
|
((gSaveContext.checkTrackerData[check].status == RCSHOW_COLLECTED || gSaveContext.checkTrackerData[check].status == RCSHOW_SAVED) &&
|
||||||
|
(data.status != RCSHOW_COLLECTED && data.status != RCSHOW_SAVED))) {
|
||||||
areaChecksGotten[area]--;
|
areaChecksGotten[area]--;
|
||||||
}
|
}
|
||||||
gSaveContext.checkTrackerData[check] = data;
|
gSaveContext.checkTrackerData[check] = data;
|
||||||
@@ -795,10 +868,6 @@ void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) {
|
|||||||
void CheckTrackerWindow::DrawElement() {
|
void CheckTrackerWindow::DrawElement() {
|
||||||
ImGui::SetNextWindowSize(ImVec2(400, 540), ImGuiCond_FirstUseEver);
|
ImGui::SetNextWindowSize(ImVec2(400, 540), ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
if (!initialized && (gPlayState == nullptr || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CVarGetInteger("gCheckTrackerWindowType", TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
|
if (CVarGetInteger("gCheckTrackerWindowType", TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
|
||||||
if (CVarGetInteger("gCheckTrackerShowOnlyPaused", 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) {
|
if (CVarGetInteger("gCheckTrackerShowOnlyPaused", 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) {
|
||||||
return;
|
return;
|
||||||
@@ -819,7 +888,7 @@ void CheckTrackerWindow::DrawElement() {
|
|||||||
|
|
||||||
BeginFloatWindows("Check Tracker", mIsVisible, ImGuiWindowFlags_NoScrollbar);
|
BeginFloatWindows("Check Tracker", mIsVisible, ImGuiWindowFlags_NoScrollbar);
|
||||||
|
|
||||||
if (!GameInteractor::IsSaveLoaded()) {
|
if (!GameInteractor::IsSaveLoaded() || !initialized) {
|
||||||
ImGui::Text("Waiting for file load..."); //TODO Language
|
ImGui::Text("Waiting for file load..."); //TODO Language
|
||||||
EndFloatWindows();
|
EndFloatWindows();
|
||||||
return;
|
return;
|
||||||
@@ -830,8 +899,6 @@ void CheckTrackerWindow::DrawElement() {
|
|||||||
sceneId = (SceneID)gPlayState->sceneNum;
|
sceneId = (SceneID)gPlayState->sceneNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
areasSpoiled |= (1 << currentArea);
|
|
||||||
|
|
||||||
//Quick Options
|
//Quick Options
|
||||||
#ifdef __WIIU__
|
#ifdef __WIIU__
|
||||||
float headerHeight = 40.0f;
|
float headerHeight = 40.0f;
|
||||||
@@ -893,13 +960,11 @@ void CheckTrackerWindow::DrawElement() {
|
|||||||
Color_RGBA8 mainColor;
|
Color_RGBA8 mainColor;
|
||||||
Color_RGBA8 extraColor;
|
Color_RGBA8 extraColor;
|
||||||
std::string stemp;
|
std::string stemp;
|
||||||
s32 areaMask = 1;
|
|
||||||
|
|
||||||
for (auto& [rcArea, objs] : checksByArea) {
|
for (auto& [rcArea, objs] : checksByArea) {
|
||||||
RandomizerCheckArea thisArea = currentArea;
|
RandomizerCheckArea thisArea = currentArea;
|
||||||
|
|
||||||
const int areaChecksTotal = static_cast<int>(objs.size());
|
thisAreaFullyChecked = (areaChecksGotten[rcArea] == areaCheckTotals[rcArea]);
|
||||||
thisAreaFullyChecked = (areaChecksGotten[rcArea] == areaChecksTotal);
|
|
||||||
//Last Area needs to be cleaned up
|
//Last Area needs to be cleaned up
|
||||||
if (lastArea != RCAREA_INVALID && doDraw) {
|
if (lastArea != RCAREA_INVALID && doDraw) {
|
||||||
UIWidgets::PaddedSeparator();
|
UIWidgets::PaddedSeparator();
|
||||||
@@ -936,30 +1001,29 @@ void CheckTrackerWindow::DrawElement() {
|
|||||||
stemp = RandomizerCheckObjects::GetRCAreaName(rcArea) + "##TreeNode";
|
stemp = RandomizerCheckObjects::GetRCAreaName(rcArea) + "##TreeNode";
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f,
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f,
|
||||||
mainColor.b / 255.0f, mainColor.a / 255.0f));
|
mainColor.b / 255.0f, mainColor.a / 255.0f));
|
||||||
if (doingCollapseOrExpand)
|
if (doingCollapseOrExpand) {
|
||||||
ImGui::SetNextItemOpen(collapseLogic, ImGuiCond_Always);
|
ImGui::SetNextItemOpen(collapseLogic, ImGuiCond_Always);
|
||||||
else
|
} else {
|
||||||
ImGui::SetNextItemOpen(!thisAreaFullyChecked, ImGuiCond_Once);
|
ImGui::SetNextItemOpen(!thisAreaFullyChecked, ImGuiCond_Once);
|
||||||
|
}
|
||||||
doDraw = ImGui::TreeNode(stemp.c_str());
|
doDraw = ImGui::TreeNode(stemp.c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
|
||||||
extraColor.b / 255.0f, extraColor.a / 255.0f));
|
extraColor.b / 255.0f, extraColor.a / 255.0f));
|
||||||
|
|
||||||
isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0) || !IS_RANDO ||
|
isThisAreaSpoiled = IsAreaSpoiled(rcArea) || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0);
|
||||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_NONE ||
|
|
||||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SELECTION ||
|
|
||||||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
|
|
||||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) == 12);
|
|
||||||
|
|
||||||
if (isThisAreaSpoiled) {
|
if (isThisAreaSpoiled) {
|
||||||
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
|
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
|
||||||
if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(DungeonSceneLookupByArea(rcArea)))
|
if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(
|
||||||
ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaChecksTotal);
|
DungeonSceneLookupByArea(rcArea))) {
|
||||||
else
|
ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
||||||
ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaChecksTotal);
|
} else {
|
||||||
|
ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("(%d/%d)", areaChecksGotten[rcArea], areaChecksTotal);
|
ImGui::Text("(%d/%d)", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("???");
|
ImGui::Text("???");
|
||||||
@@ -973,13 +1037,14 @@ void CheckTrackerWindow::DrawElement() {
|
|||||||
doAreaScroll = false;
|
doAreaScroll = false;
|
||||||
}
|
}
|
||||||
for (auto rco : objs) {
|
for (auto rco : objs) {
|
||||||
if (doDraw && isThisAreaSpoiled && IsVisibleInCheckTracker(rco))
|
if (IsVisibleInCheckTracker(rco) && doDraw && isThisAreaSpoiled) {
|
||||||
DrawLocation(rco);
|
DrawLocation(rco);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (doDraw)
|
if (doDraw) {
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
areaMask <<= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable(); //Checks Lead-out
|
ImGui::EndTable(); //Checks Lead-out
|
||||||
@@ -1084,7 +1149,6 @@ void LoadSettings() {
|
|||||||
showLinksPocket = IS_RANDO ? // don't show Link's Pocket if not randomizer, or if rando and pocket is disabled
|
showLinksPocket = IS_RANDO ? // don't show Link's Pocket if not randomizer, or if rando and pocket is disabled
|
||||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING
|
||||||
:false;
|
:false;
|
||||||
hideShopRightChecks = IS_RANDO ? CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1) : false;
|
|
||||||
|
|
||||||
if (IS_RANDO) {
|
if (IS_RANDO) {
|
||||||
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) {
|
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) {
|
||||||
@@ -1148,7 +1212,7 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
|
|||||||
) &&
|
) &&
|
||||||
(rcObj.rcType != RCTYPE_MERCHANT || showMerchants) &&
|
(rcObj.rcType != RCTYPE_MERCHANT || showMerchants) &&
|
||||||
(rcObj.rcType != RCTYPE_OCARINA || showOcarinas) &&
|
(rcObj.rcType != RCTYPE_OCARINA || showOcarinas) &&
|
||||||
(rcObj.rcType != RCTYPE_SKULL_TOKEN ||
|
(rcObj.rcType != RCTYPE_SKULL_TOKEN || alwaysShowGS ||
|
||||||
(showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) ||
|
(showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) ||
|
||||||
(showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea))
|
(showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea))
|
||||||
) &&
|
) &&
|
||||||
@@ -1184,10 +1248,10 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInventoryChecks() {
|
void UpdateInventoryChecks() {
|
||||||
//For all the areas with compasses, if you have one, spoil the area
|
//For all the areas with maps, if you have one, spoil the area
|
||||||
for (auto [scene, area] : DungeonRCAreasBySceneID) {
|
for (auto [scene, area] : DungeonRCAreasBySceneID) {
|
||||||
if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, scene)) {
|
if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, scene)) {
|
||||||
areasSpoiled |= (1 << area);
|
SetAreaSpoiled(area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1197,8 +1261,6 @@ void UpdateAreaFullyChecked(RandomizerCheckArea area) {
|
|||||||
|
|
||||||
void UpdateAreas(RandomizerCheckArea area) {
|
void UpdateAreas(RandomizerCheckArea area) {
|
||||||
areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size();
|
areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size();
|
||||||
if (areaChecksGotten[area] != 0 || RandomizerCheckObjects::AreaIsOverworld(area))
|
|
||||||
areasSpoiled |= (1 << area);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAllOrdering() {
|
void UpdateAllOrdering() {
|
||||||
@@ -1226,30 +1288,36 @@ bool CompareChecks(RandomizerCheckObject i, RandomizerCheckObject j) {
|
|||||||
bool iSaved = iShow.status == RCSHOW_SAVED;
|
bool iSaved = iShow.status == RCSHOW_SAVED;
|
||||||
bool jCollected = jShow.status == RCSHOW_COLLECTED || jShow.status == RCSHOW_SAVED;
|
bool jCollected = jShow.status == RCSHOW_COLLECTED || jShow.status == RCSHOW_SAVED;
|
||||||
bool jSaved = jShow.status == RCSHOW_SAVED;
|
bool jSaved = jShow.status == RCSHOW_SAVED;
|
||||||
if (!iCollected && jCollected)
|
|
||||||
return true;
|
|
||||||
else if (iCollected && !jCollected)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!iSaved && jSaved)
|
if (!iCollected && jCollected) {
|
||||||
return true;
|
return true;
|
||||||
else if (iSaved && !jSaved)
|
} else if (iCollected && !jCollected) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!iShow.skipped && jShow.skipped)
|
if (!iSaved && jSaved) {
|
||||||
return true;
|
return true;
|
||||||
else if (iShow.skipped && !jShow.skipped)
|
} else if (iSaved && !jSaved) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsEoDCheck(i.rcType) && IsEoDCheck(j.rcType))
|
if (!iShow.skipped && jShow.skipped) {
|
||||||
return true;
|
return true;
|
||||||
else if (IsEoDCheck(i.rcType) && !IsEoDCheck(j.rcType))
|
} else if (iShow.skipped && !jShow.skipped) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (i.rc < j.rc)
|
if (!IsEoDCheck(i.rcType) && IsEoDCheck(j.rcType)) {
|
||||||
return true;
|
return true;
|
||||||
else if (i.rc > j.rc)
|
} else if (IsEoDCheck(i.rcType) && !IsEoDCheck(j.rcType)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.rc < j.rc) {
|
||||||
|
return true;
|
||||||
|
} else if (i.rc > j.rc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1267,47 +1335,54 @@ void DrawLocation(RandomizerCheckObject rcObj) {
|
|||||||
RandomizerCheckStatus status = checkData.status;
|
RandomizerCheckStatus status = checkData.status;
|
||||||
bool skipped = checkData.skipped;
|
bool skipped = checkData.skipped;
|
||||||
if (status == RCSHOW_COLLECTED) {
|
if (status == RCSHOW_COLLECTED) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerCollectedHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerCollectedHide", 0)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default) :
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default) :
|
||||||
CVarGetColor("gCheckTrackerCollectedMainColor", Color_Main_Default);
|
CVarGetColor("gCheckTrackerCollectedMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerCollectedExtraColor", Color_Collected_Extra_Default);
|
||||||
} else if (status == RCSHOW_SAVED) {
|
} else if (status == RCSHOW_SAVED) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerSavedHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerSavedHide", 0)) {
|
||||||
return;
|
return;
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default) :
|
}
|
||||||
CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default);
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default) :
|
||||||
|
CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default);
|
||||||
} else if (skipped) {
|
} else if (skipped) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerSkippedHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerSkippedHide", 0)) {
|
||||||
return;
|
return;
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default) :
|
}
|
||||||
CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default);
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default) :
|
||||||
|
CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default);
|
||||||
} else if (status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED) {
|
} else if (status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerSeenHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerSeenHide", 0)) {
|
||||||
return;
|
return;
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default) :
|
}
|
||||||
CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default);
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default) :
|
||||||
|
CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default);
|
||||||
} else if (status == RCSHOW_SCUMMED) {
|
} else if (status == RCSHOW_SCUMMED) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerKnownHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerScummedHide", 0)) {
|
||||||
return;
|
return;
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default) :
|
}
|
||||||
CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default);
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default) :
|
||||||
|
CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default);
|
||||||
} else if (status == RCSHOW_UNCHECKED) {
|
} else if (status == RCSHOW_UNCHECKED) {
|
||||||
if (!showHidden && CVarGetInteger("gCheckTrackerUncheckedHide", 0))
|
if (!showHidden && CVarGetInteger("gCheckTrackerUncheckedHide", 0)) {
|
||||||
return;
|
return;
|
||||||
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default) :
|
}
|
||||||
CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default);
|
mainColor = !IsHeartPiece(rcObj.ogItemId) && !IS_RANDO ? CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default) :
|
||||||
|
CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default);
|
||||||
extraColor = CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default);
|
extraColor = CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Main Text
|
//Main Text
|
||||||
txt = rcObj.rcShortName;
|
txt = rcObj.rcShortName;
|
||||||
if (lastLocationChecked == rcObj.rc)
|
if (lastLocationChecked == rcObj.rc) {
|
||||||
txt = "* " + txt;
|
txt = "* " + txt;
|
||||||
|
}
|
||||||
|
|
||||||
// Draw button - for Skipped/Seen/Scummed/Unchecked only
|
// Draw button - for Skipped/Seen/Scummed/Unchecked only
|
||||||
if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) {
|
if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) {
|
||||||
@@ -1382,8 +1457,9 @@ void DrawLocation(RandomizerCheckObject rcObj) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txt == "" && skipped)
|
if (txt == "" && skipped) {
|
||||||
txt = "Skipped"; //TODO language
|
txt = "Skipped"; // TODO language
|
||||||
|
}
|
||||||
|
|
||||||
if (txt != "") {
|
if (txt != "") {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f));
|
||||||
@@ -1409,8 +1485,9 @@ int hue = 0;
|
|||||||
void RainbowTick() {
|
void RainbowTick() {
|
||||||
float freqHue = hue * 2 * M_PI / (360 * CVarGetFloat("gCosmetics.RainbowSpeed", 0.6f));
|
float freqHue = hue * 2 * M_PI / (360 * CVarGetFloat("gCosmetics.RainbowSpeed", 0.6f));
|
||||||
for (auto& cvar : rainbowCVars) {
|
for (auto& cvar : rainbowCVars) {
|
||||||
if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0)
|
if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Color_RGBA8 newColor;
|
Color_RGBA8 newColor;
|
||||||
newColor.r = sin(freqHue + 0) * 127 + 128;
|
newColor.r = sin(freqHue + 0) * 127 + 128;
|
||||||
@@ -1517,8 +1594,16 @@ void CheckTrackerSettingsWindow::DrawElement() {
|
|||||||
}
|
}
|
||||||
UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers");
|
UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers");
|
||||||
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.");
|
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.");
|
||||||
UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true);
|
if (UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", "gCheckTrackerOptionHideRightShopChecks", false, "", UIWidgets::CheckboxGraphics::Cross, true)) {
|
||||||
UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops. Requires save reload.");
|
hideShopRightChecks = !hideShopRightChecks;
|
||||||
|
RecalculateAreaTotals();
|
||||||
|
}
|
||||||
|
UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops.");
|
||||||
|
if (UIWidgets::EnhancementCheckbox("Always show gold skulltulas", "gCheckTrackerOptionAlwaysShowGSLocs", false, "")) {
|
||||||
|
alwaysShowGS = !alwaysShowGS;
|
||||||
|
RecalculateAreaTotals();
|
||||||
|
}
|
||||||
|
UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings.");
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
@@ -1572,6 +1657,9 @@ void CheckTrackerWindow::InitElement() {
|
|||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>(CheckTrackerSceneFlagSet);
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>(CheckTrackerSceneFlagSet);
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(CheckTrackerFlagSet);
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>(CheckTrackerFlagSet);
|
||||||
|
|
||||||
|
hideShopRightChecks = CVarGetInteger("gCheckTrackerOptionHideRightShopChecks", 1);
|
||||||
|
alwaysShowGS = CVarGetInteger("gCheckTrackerOptionAlwaysShowGSLocs", 0);
|
||||||
|
|
||||||
LocationTable_Init();
|
LocationTable_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj);
|
|||||||
void InitTrackerData(bool isDebug);
|
void InitTrackerData(bool isDebug);
|
||||||
RandomizerCheckArea GetCheckArea();
|
RandomizerCheckArea GetCheckArea();
|
||||||
void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
|
void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
|
||||||
|
bool IsAreaSpoiled(RandomizerCheckArea rcArea);
|
||||||
|
void SetAreaSpoiled(RandomizerCheckArea rcArea);
|
||||||
} // namespace CheckTracker
|
} // namespace CheckTracker
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -398,6 +398,11 @@ void Entrance_SetSavewarpEntrance(void) {
|
|||||||
gSaveContext.entranceIndex = 0x0486; // Gerudo Fortress -> Thieve's Hideout spawn 0
|
gSaveContext.entranceIndex = 0x0486; // Gerudo Fortress -> Thieve's Hideout spawn 0
|
||||||
} else if (scene == SCENE_LINKS_HOUSE) {
|
} else if (scene == SCENE_LINKS_HOUSE) {
|
||||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE);
|
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE);
|
||||||
|
} else if (CVarGetInteger("gRememberSaveLocation", 0) && scene != SCENE_FAIRYS_FOUNTAIN && scene != SCENE_GROTTOS &&
|
||||||
|
// Use the saved entrance value with remember save location, except when in grottos/fairy fountains or if
|
||||||
|
// the entrance index is -1 (new save)
|
||||||
|
gSaveContext.entranceIndex != -1) {
|
||||||
|
return;
|
||||||
} else if (LINK_IS_CHILD) {
|
} else if (LINK_IS_CHILD) {
|
||||||
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); // Child Overworld Spawn
|
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); // Child Overworld Spawn
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||||
|
#include "randomizer_check_tracker.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -30,6 +31,8 @@ void DrawBottle(ItemTrackerItem item);
|
|||||||
void DrawQuest(ItemTrackerItem item);
|
void DrawQuest(ItemTrackerItem item);
|
||||||
void DrawSong(ItemTrackerItem item);
|
void DrawSong(ItemTrackerItem item);
|
||||||
|
|
||||||
|
int itemTrackerSectionId;
|
||||||
|
|
||||||
bool shouldUpdateVectors = true;
|
bool shouldUpdateVectors = true;
|
||||||
|
|
||||||
std::vector<ItemTrackerItem> mainWindowItems = {};
|
std::vector<ItemTrackerItem> mainWindowItems = {};
|
||||||
@@ -282,26 +285,21 @@ void ItemTrackerOnFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveNotes(uint32_t fileNum) {
|
|
||||||
CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str());
|
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidSaveFile() {
|
bool IsValidSaveFile() {
|
||||||
bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2;
|
bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2;
|
||||||
return validSave;
|
return validSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasSong(ItemTrackerItem item) {
|
bool HasSong(ItemTrackerItem item) {
|
||||||
return (1 << item.id) & gSaveContext.inventory.questItems;
|
return GameInteractor::IsSaveLoaded() ? ((1 << item.id) & gSaveContext.inventory.questItems) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasQuestItem(ItemTrackerItem item) {
|
bool HasQuestItem(ItemTrackerItem item) {
|
||||||
return (item.data & gSaveContext.inventory.questItems) != 0;
|
return GameInteractor::IsSaveLoaded() ? (item.data & gSaveContext.inventory.questItems) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasEquipment(ItemTrackerItem item) {
|
bool HasEquipment(ItemTrackerItem item) {
|
||||||
return (item.data & gSaveContext.inventory.equipment) != 0;
|
return GameInteractor::IsSaveLoaded() ? (item.data & gSaveContext.inventory.equipment) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
|
ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
|
||||||
@@ -409,8 +407,12 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
|
|||||||
#define IM_COL_GREEN IM_COL32(0, 255, 0, 255)
|
#define IM_COL_GREEN IM_COL32(0, 255, 0, 255)
|
||||||
#define IM_COL_GRAY IM_COL32(155, 155, 155, 255)
|
#define IM_COL_GRAY IM_COL32(155, 155, 155, 255)
|
||||||
#define IM_COL_PURPLE IM_COL32(180, 90, 200, 255)
|
#define IM_COL_PURPLE IM_COL32(180, 90, 200, 255)
|
||||||
|
#define IM_COL_LIGHT_YELLOW IM_COL32(255, 255, 130, 255)
|
||||||
|
|
||||||
void DrawItemCount(ItemTrackerItem item) {
|
void DrawItemCount(ItemTrackerItem item, bool hideMax) {
|
||||||
|
if (!GameInteractor::IsSaveLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
||||||
ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item);
|
ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item);
|
||||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||||
@@ -419,7 +421,7 @@ void DrawItemCount(ItemTrackerItem item) {
|
|||||||
|
|
||||||
if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) {
|
if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) {
|
||||||
std::string currentString = "";
|
std::string currentString = "";
|
||||||
std::string maxString = std::to_string(currentAndMax.maxCapacity);
|
std::string maxString = hideMax ? "???" : std::to_string(currentAndMax.maxCapacity);
|
||||||
ImU32 currentColor = IM_COL_WHITE;
|
ImU32 currentColor = IM_COL_WHITE;
|
||||||
ImU32 maxColor = IM_COL_GREEN;
|
ImU32 maxColor = IM_COL_GREEN;
|
||||||
// "Collected / Max", "Current / Collected / Max", "Current / Max"
|
// "Collected / Max", "Current / Collected / Max", "Current / Max"
|
||||||
@@ -551,7 +553,7 @@ void DrawQuest(ItemTrackerItem item) {
|
|||||||
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
||||||
|
|
||||||
if (item.id == QUEST_SKULL_TOKEN) {
|
if (item.id == QUEST_SKULL_TOKEN) {
|
||||||
DrawItemCount(item);
|
DrawItemCount(item, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
@@ -561,7 +563,7 @@ void DrawQuest(ItemTrackerItem item) {
|
|||||||
|
|
||||||
void DrawItem(ItemTrackerItem item) {
|
void DrawItem(ItemTrackerItem item) {
|
||||||
|
|
||||||
uint32_t actualItemId = INV_CONTENT(item.id);
|
uint32_t actualItemId = GameInteractor::IsSaveLoaded() ? INV_CONTENT(item.id) : ITEM_NONE;
|
||||||
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
||||||
bool hasItem = actualItemId != ITEM_NONE;
|
bool hasItem = actualItemId != ITEM_NONE;
|
||||||
std::string itemName = "";
|
std::string itemName = "";
|
||||||
@@ -620,7 +622,7 @@ void DrawItem(ItemTrackerItem item) {
|
|||||||
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded),
|
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded),
|
||||||
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
||||||
|
|
||||||
DrawItemCount(item);
|
DrawItemCount(item, false);
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
|
||||||
if (itemName == "") {
|
if (itemName == "") {
|
||||||
@@ -631,7 +633,7 @@ void DrawItem(ItemTrackerItem item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DrawBottle(ItemTrackerItem item) {
|
void DrawBottle(ItemTrackerItem item) {
|
||||||
uint32_t actualItemId = gSaveContext.inventory.items[SLOT(item.id) + item.data];
|
uint32_t actualItemId = GameInteractor::IsSaveLoaded() ? (gSaveContext.inventory.items[SLOT(item.id) + item.data]) : false;
|
||||||
bool hasItem = actualItemId != ITEM_NONE;
|
bool hasItem = actualItemId != ITEM_NONE;
|
||||||
|
|
||||||
if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) {
|
if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) {
|
||||||
@@ -650,8 +652,8 @@ void DrawDungeonItem(ItemTrackerItem item) {
|
|||||||
ImU32 dungeonColor = IM_COL_WHITE;
|
ImU32 dungeonColor = IM_COL_WHITE;
|
||||||
uint32_t bitMask = 1 << (item.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential
|
uint32_t bitMask = 1 << (item.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential
|
||||||
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
|
||||||
bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[item.data]) != 0;
|
bool hasItem = GameInteractor::IsSaveLoaded() ? (bitMask & gSaveContext.inventory.dungeonItems[item.data]) : false;
|
||||||
bool hasSmallKey = (gSaveContext.inventory.dungeonKeys[item.data]) >= 0;
|
bool hasSmallKey = GameInteractor::IsSaveLoaded() ? ((gSaveContext.inventory.dungeonKeys[item.data]) >= 0) : false;
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
if (itemId == ITEM_KEY_SMALL) {
|
if (itemId == ITEM_KEY_SMALL) {
|
||||||
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSmallKey && IsValidSaveFile() ? item.name : item.nameFaded),
|
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSmallKey && IsValidSaveFile() ? item.name : item.nameFaded),
|
||||||
@@ -662,16 +664,18 @@ void DrawDungeonItem(ItemTrackerItem item) {
|
|||||||
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ResourceMgr_IsSceneMasterQuest(item.data) && (CHECK_DUNGEON_ITEM(DUNGEON_MAP, item.data) || item.data == SCENE_GERUDO_TRAINING_GROUND || item.data == SCENE_INSIDE_GANONS_CASTLE)) {
|
if (CheckTracker::IsAreaSpoiled(RandomizerCheckObjects::GetRCAreaBySceneID(static_cast<SceneID>(item.data))) && GameInteractor::IsSaveLoaded()) {
|
||||||
dungeonColor = IM_COL_PURPLE;
|
dungeonColor = (ResourceMgr_IsSceneMasterQuest(item.data) ? IM_COL_PURPLE : IM_COL_LIGHT_YELLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemId == ITEM_KEY_SMALL) {
|
if (itemId == ITEM_KEY_SMALL) {
|
||||||
DrawItemCount(item);
|
DrawItemCount(item, !CheckTracker::IsAreaSpoiled(RandomizerCheckObjects::GetRCAreaBySceneID(static_cast<SceneID>(item.data))));
|
||||||
|
|
||||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||||
|
// offset puts the text at the correct level. for some reason, if the save is loaded, the margin is 3 pixels higher only for small keys, so we use 16 then. Otherwise, 13 is where everything else is
|
||||||
|
int offset = GameInteractor::IsSaveLoaded() ? 16 : 13;
|
||||||
std::string dungeonName = itemTrackerDungeonShortNames[item.data];
|
std::string dungeonName = itemTrackerDungeonShortNames[item.data];
|
||||||
ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + 16)));
|
ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + offset)));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, dungeonColor);
|
ImGui::PushStyleColor(ImGuiCol_Text, dungeonColor);
|
||||||
ImGui::Text("%s", dungeonName.c_str());
|
ImGui::Text("%s", dungeonName.c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
@@ -728,13 +732,15 @@ void DrawNotes(bool resizeable = false) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
ImVec2 size = resizeable ? ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y) : ImVec2(((iconSize + iconSpacing) * 6) - 8, 200);
|
ImVec2 size = resizeable ? ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y) : ImVec2(((iconSize + iconSpacing) * 6) - 8, 200);
|
||||||
if (ItemTrackerNotes::TrackerNotesInputTextMultiline("##ItemTrackerNotes", &itemTrackerNotes, size, ImGuiInputTextFlags_AllowTabInput)) {
|
if (GameInteractor::IsSaveLoaded()) {
|
||||||
notesNeedSave = true;
|
if (ItemTrackerNotes::TrackerNotesInputTextMultiline("##ItemTrackerNotes", &itemTrackerNotes, size, ImGuiInputTextFlags_AllowTabInput)) {
|
||||||
notesIdleFrames = 0;
|
notesNeedSave = true;
|
||||||
}
|
notesIdleFrames = 0;
|
||||||
if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) {
|
}
|
||||||
notesNeedSave = false;
|
if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) {
|
||||||
SaveNotes(gSaveContext.fileNum);
|
notesNeedSave = false;
|
||||||
|
SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
@@ -959,6 +965,26 @@ void UpdateVectors() {
|
|||||||
shouldUpdateVectors = false;
|
shouldUpdateVectors = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemTrackerInitFile(bool isDebug) {
|
||||||
|
itemTrackerNotes.clear();
|
||||||
|
itemTrackerNotes.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTrackerSaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
||||||
|
SaveManager::Instance->SaveData("personalNotes", std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTrackerLoadFile() {
|
||||||
|
std::string initialTrackerNotes = "";
|
||||||
|
SaveManager::Instance->LoadData("personalNotes", initialTrackerNotes);
|
||||||
|
itemTrackerNotes.resize(initialTrackerNotes.length() + 1);
|
||||||
|
if (initialTrackerNotes != "") {
|
||||||
|
SohUtils::CopyStringToCharArray(itemTrackerNotes.Data, initialTrackerNotes.c_str(), itemTrackerNotes.size());
|
||||||
|
} else {
|
||||||
|
itemTrackerNotes.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ItemTrackerWindow::DrawElement() {
|
void ItemTrackerWindow::DrawElement() {
|
||||||
UpdateVectors();
|
UpdateVectors();
|
||||||
|
|
||||||
@@ -1223,14 +1249,9 @@ void ItemTrackerWindow::InitElement() {
|
|||||||
itemTrackerNotes.push_back(0);
|
itemTrackerNotes.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadFile>([](uint32_t fileNum) {
|
SaveManager::Instance->AddInitFunction(ItemTrackerInitFile);
|
||||||
const char* initialTrackerNotes = CVarGetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), "");
|
itemTrackerSectionId = SaveManager::Instance->AddSaveFunction("itemTrackerData", 1, ItemTrackerSaveFile, true, -1);
|
||||||
itemTrackerNotes.resize(strlen(initialTrackerNotes) + 1);
|
SaveManager::Instance->AddLoadFunction("itemTrackerData", 1, ItemTrackerLoadFile);
|
||||||
strcpy(itemTrackerNotes.Data, initialTrackerNotes);
|
|
||||||
});
|
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnDeleteFile>([](uint32_t fileNum) {
|
|
||||||
CVarSetString(("gItemTrackerNotes" + std::to_string(fileNum)).c_str(), "");
|
|
||||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
|
||||||
});
|
|
||||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(ItemTrackerOnFrame);
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(ItemTrackerOnFrame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,6 +207,9 @@ extern "C" void Randomizer_InitSaveFile() {
|
|||||||
gSaveContext.randomizerInf[i] = 0;
|
gSaveContext.randomizerInf[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset triforce pieces collected
|
||||||
|
gSaveContext.triforcePiecesCollected = 0;
|
||||||
|
|
||||||
gSaveContext.cutsceneIndex = 0; // no intro cutscene
|
gSaveContext.cutsceneIndex = 0; // no intro cutscene
|
||||||
// Starts pending ice traps out at 0 before potentially incrementing them down the line.
|
// Starts pending ice traps out at 0 before potentially incrementing them down the line.
|
||||||
gSaveContext.pendingIceTrapCount = 0;
|
gSaveContext.pendingIceTrapCount = 0;
|
||||||
@@ -442,8 +445,5 @@ extern "C" void Randomizer_InitSaveFile() {
|
|||||||
gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth
|
gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset triforce pieces collected
|
|
||||||
gSaveContext.triforcePiecesCollected = 0;
|
|
||||||
|
|
||||||
SetStartingItems();
|
SetStartingItems();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ void RegisterOnInterfaceUpdateHook() {
|
|||||||
|
|
||||||
prevTimer = timer;
|
prevTimer = timer;
|
||||||
|
|
||||||
if (!GameInteractor::IsSaveLoaded()) return;
|
if (!GameInteractor::IsSaveLoaded(true)) return;
|
||||||
|
|
||||||
static int16_t lostHealth = 0;
|
static int16_t lostHealth = 0;
|
||||||
static int16_t prevHealth = 0;
|
static int16_t prevHealth = 0;
|
||||||
|
|||||||
+121
-72
@@ -118,6 +118,8 @@ CrowdControl* CrowdControl::Instance;
|
|||||||
|
|
||||||
#include "soh/config/ConfigUpdaters.h"
|
#include "soh/config/ConfigUpdaters.h"
|
||||||
|
|
||||||
|
void SoH_ProcessDroppedFiles(std::string filePath);
|
||||||
|
|
||||||
OTRGlobals* OTRGlobals::Instance;
|
OTRGlobals* OTRGlobals::Instance;
|
||||||
SaveManager* SaveManager::Instance;
|
SaveManager* SaveManager::Instance;
|
||||||
CustomMessageManager* CustomMessageManager::Instance;
|
CustomMessageManager* CustomMessageManager::Instance;
|
||||||
@@ -135,6 +137,8 @@ Color_RGB8 zoraColor = { 0x00, 0xEC, 0x64 };
|
|||||||
|
|
||||||
float previousImGuiScale;
|
float previousImGuiScale;
|
||||||
|
|
||||||
|
bool prevAltAssets = false;
|
||||||
|
|
||||||
// Same as NaviColor type from OoT src (z_actor.c), but modified to be sans alpha channel for Controller LED.
|
// Same as NaviColor type from OoT src (z_actor.c), but modified to be sans alpha channel for Controller LED.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Color_RGB8 inner;
|
Color_RGB8 inner;
|
||||||
@@ -295,6 +299,9 @@ OTRGlobals::OTRGlobals() {
|
|||||||
};
|
};
|
||||||
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
|
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
|
||||||
context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3);
|
context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3);
|
||||||
|
prevAltAssets = CVarGetInteger("gAltAssets", 0);
|
||||||
|
context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets);
|
||||||
|
SPDLOG_INFO("Starting Ship of Harkinian version {}", (char*)gBuildVersion);
|
||||||
|
|
||||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
|
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
|
||||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
||||||
@@ -1035,9 +1042,9 @@ extern "C" void InitOTR() {
|
|||||||
OTRGlobals::Instance = new OTRGlobals();
|
OTRGlobals::Instance = new OTRGlobals();
|
||||||
CustomMessageManager::Instance = new CustomMessageManager();
|
CustomMessageManager::Instance = new CustomMessageManager();
|
||||||
ItemTableManager::Instance = new ItemTableManager();
|
ItemTableManager::Instance = new ItemTableManager();
|
||||||
|
GameInteractor::Instance = new GameInteractor();
|
||||||
SaveManager::Instance = new SaveManager();
|
SaveManager::Instance = new SaveManager();
|
||||||
SohGui::SetupGuiElements();
|
SohGui::SetupGuiElements();
|
||||||
GameInteractor::Instance = new GameInteractor();
|
|
||||||
AudioCollection::Instance = new AudioCollection();
|
AudioCollection::Instance = new AudioCollection();
|
||||||
ActorDB::Instance = new ActorDB();
|
ActorDB::Instance = new ActorDB();
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@@ -1057,6 +1064,11 @@ extern "C" void InitOTR() {
|
|||||||
|
|
||||||
InitMods();
|
InitMods();
|
||||||
ActorDB::AddBuiltInCustomActors();
|
ActorDB::AddBuiltInCustomActors();
|
||||||
|
// #region SOH [Randomizer] TODO: Remove these and refactor spoiler file handling for randomizer
|
||||||
|
CVarClear("gRandomizerNewFileDropped");
|
||||||
|
CVarClear("gRandomizerDroppedFile");
|
||||||
|
// #endregion
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFileDropped>(SoH_ProcessDroppedFiles);
|
||||||
|
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
tm *tm_now = localtime(&now);
|
tm *tm_now = localtime(&now);
|
||||||
@@ -1136,8 +1148,7 @@ extern "C" uint64_t GetUnixTimestamp() {
|
|||||||
auto time = std::chrono::system_clock::now();
|
auto time = std::chrono::system_clock::now();
|
||||||
auto since_epoch = time.time_since_epoch();
|
auto since_epoch = time.time_since_epoch();
|
||||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch);
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch);
|
||||||
long now = millis.count();
|
return (uint64_t)millis.count();
|
||||||
return now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// C->C++ Bridge
|
// C->C++ Bridge
|
||||||
@@ -1145,7 +1156,7 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
|
|||||||
OTRGlobals::Instance->context->GetWindow()->MainLoop(run_one_game_iter);
|
OTRGlobals::Instance->context->GetWindow()->MainLoop(run_one_game_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool ShouldClearTextureCacheAtEndOfFrame;
|
extern bool ToggleAltAssetsAtEndOfFrame;
|
||||||
|
|
||||||
extern "C" void Graph_StartFrame() {
|
extern "C" void Graph_StartFrame() {
|
||||||
#ifndef __WIIU__
|
#ifndef __WIIU__
|
||||||
@@ -1228,14 +1239,21 @@ extern "C" void Graph_StartFrame() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case KbScancode::LUS_KB_TAB: {
|
case KbScancode::LUS_KB_TAB: {
|
||||||
// Toggle HD Assets
|
|
||||||
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
|
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
|
||||||
ShouldClearTextureCacheAtEndOfFrame = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (CVarGetInteger("gNewFileDropped", 0)) {
|
||||||
|
std::string filePath = SohUtils::Sanitize(CVarGetString("gDroppedFile", ""));
|
||||||
|
if (!filePath.empty()) {
|
||||||
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnFileDropped>(filePath);
|
||||||
|
}
|
||||||
|
CVarClear("gNewFileDropped");
|
||||||
|
CVarClear("gDroppedFile");
|
||||||
|
}
|
||||||
|
|
||||||
OTRGlobals::Instance->context->GetWindow()->StartFrame();
|
OTRGlobals::Instance->context->GetWindow()->StartFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1301,10 +1319,13 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldClearTextureCacheAtEndOfFrame) {
|
bool curAltAssets = CVarGetInteger("gAltAssets", 0);
|
||||||
|
if (prevAltAssets != curAltAssets) {
|
||||||
|
prevAltAssets = curAltAssets;
|
||||||
|
LUS::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets);
|
||||||
gfx_texture_cache_clear();
|
gfx_texture_cache_clear();
|
||||||
LUS::SkeletonPatcher::UpdateSkeletons();
|
LUS::SkeletonPatcher::UpdateSkeletons();
|
||||||
ShouldClearTextureCacheAtEndOfFrame = false;
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// OTRTODO: FIGURE OUT END FRAME POINT
|
// OTRTODO: FIGURE OUT END FRAME POINT
|
||||||
@@ -1477,10 +1498,14 @@ extern "C" uint8_t ResourceMgr_FileAltExists(const char* filePath) {
|
|||||||
return ExtensionCache.contains(path);
|
return ExtensionCache.contains(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" bool ResourceMgr_IsAltAssetsEnabled() {
|
||||||
|
return LUS::Context::GetInstance()->GetResourceManager()->IsAltAssetsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
// Unloads a resource if an alternate version exists when alt assets are enabled
|
// Unloads a resource if an alternate version exists when alt assets are enabled
|
||||||
// The resource is only removed from the internal cache to prevent it from used in the next resource lookup
|
// The resource is only removed from the internal cache to prevent it from used in the next resource lookup
|
||||||
extern "C" void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName) {
|
extern "C" void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName) {
|
||||||
if (CVarGetInteger("gAltAssets", 0) && ResourceMgr_FileAltExists((char*) resName)) {
|
if (ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileAltExists((char*) resName)) {
|
||||||
ResourceMgr_UnloadResource((char*) resName);
|
ResourceMgr_UnloadResource((char*) resName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1717,6 +1742,7 @@ extern "C" char* ResourceMgr_LoadArrayByName(const char* path)
|
|||||||
return (char*)res->Scalars.data();
|
return (char*)res->Scalars.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return of LoadArrayByNameAsVec3s must be freed by the caller
|
||||||
extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) {
|
extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) {
|
||||||
auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path));
|
auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path));
|
||||||
|
|
||||||
@@ -1849,7 +1875,7 @@ extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, Skel
|
|||||||
pathStr = pathStr.substr(sOtr.length());
|
pathStr = pathStr.substr(sOtr.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAlt = CVarGetInteger("gAltAssets", 0);
|
bool isAlt = ResourceMgr_IsAltAssetsEnabled();
|
||||||
|
|
||||||
if (isAlt) {
|
if (isAlt) {
|
||||||
pathStr = LUS::IResource::gAltAssetPrefix + pathStr;
|
pathStr = LUS::IResource::gAltAssetPrefix + pathStr;
|
||||||
@@ -2099,10 +2125,10 @@ Color_RGB8 GetColorForControllerLED() {
|
|||||||
if (source == LED_SOURCE_CUSTOM) {
|
if (source == LED_SOURCE_CUSTOM) {
|
||||||
color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
|
color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
|
||||||
}
|
}
|
||||||
if (criticalOverride || source == LED_SOURCE_HEALTH) {
|
if (gPlayState && (criticalOverride || source == LED_SOURCE_HEALTH)) {
|
||||||
if (HealthMeter_IsCritical()) {
|
if (HealthMeter_IsCritical()) {
|
||||||
color = { 0xFF, 0, 0 };
|
color = { 0xFF, 0, 0 };
|
||||||
} else if (source == LED_SOURCE_HEALTH) {
|
} else if (gSaveContext.healthCapacity != 0 && source == LED_SOURCE_HEALTH) {
|
||||||
if (gSaveContext.health / gSaveContext.healthCapacity <= 0.4f) {
|
if (gSaveContext.health / gSaveContext.healthCapacity <= 0.4f) {
|
||||||
color = { 0xFF, 0xFF, 0 };
|
color = { 0xFF, 0xFF, 0 };
|
||||||
} else {
|
} else {
|
||||||
@@ -2468,8 +2494,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
|
|||||||
randoInf = RAND_INF_MERCHANTS_CARPET_SALESMAN;
|
randoInf = RAND_INF_MERCHANTS_CARPET_SALESMAN;
|
||||||
}
|
}
|
||||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(randoInf, textId, Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_ON_HINT);
|
messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(randoInf, textId, Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_ON_HINT);
|
||||||
} else if (Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) &&
|
} else if (textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT) {
|
||||||
(textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT)) {
|
|
||||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId);
|
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId);
|
||||||
} else if (textId == TEXT_CURSED_SKULLTULA_PEOPLE) {
|
} else if (textId == TEXT_CURSED_SKULLTULA_PEOPLE) {
|
||||||
actorParams = GET_PLAYER(play)->targetActor->params;
|
actorParams = GET_PLAYER(play)->targetActor->params;
|
||||||
@@ -2488,6 +2513,8 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
|
|||||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetWarpSongMessage(textId, Randomizer_GetSettingValue(RSK_WARP_SONG_HINTS) == RO_GENERIC_OFF);
|
messageEntry = OTRGlobals::Instance->gRandomizer->GetWarpSongMessage(textId, Randomizer_GetSettingValue(RSK_WARP_SONG_HINTS) == RO_GENERIC_OFF);
|
||||||
} else if (textId == TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI || textId == TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN) {
|
} else if (textId == TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI || textId == TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN) {
|
||||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId);
|
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId);
|
||||||
|
} else if (textId == TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW) {
|
||||||
|
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW);
|
||||||
} else if (textId == 0x3052 || (textId >= 0x3069 && textId <= 0x3070)) { //Fire Temple gorons
|
} else if (textId == 0x3052 || (textId >= 0x3069 && textId <= 0x3070)) { //Fire Temple gorons
|
||||||
u16 choice = Random(0, NUM_GORON_MESSAGES);
|
u16 choice = Random(0, NUM_GORON_MESSAGES);
|
||||||
messageEntry = OTRGlobals::Instance->gRandomizer->GetGoronMessage(choice);
|
messageEntry = OTRGlobals::Instance->gRandomizer->GetGoronMessage(choice);
|
||||||
@@ -2577,70 +2604,92 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla
|
|||||||
gfx_register_blended_texture(name, mask, replacement);
|
gfx_register_blended_texture(name, mask, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #region SOH [TODO] Ideally this should move to being event based, it's currently run every frame on the file select screen
|
extern "C" void Gfx_UnregisterBlendedTexture(const char* name) {
|
||||||
extern "C" void SoH_ProcessDroppedFiles() {
|
gfx_unregister_blended_texture(name);
|
||||||
const char* droppedFile = CVarGetString("gDroppedFile", "");
|
}
|
||||||
if (CVarGetInteger("gNewFileDropped", 0) && strcmp(droppedFile, "") != 0) {
|
|
||||||
try {
|
|
||||||
std::ifstream configStream(SohUtils::Sanitize(droppedFile));
|
|
||||||
if (!configStream) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json configJson;
|
extern "C" void Gfx_TextureCacheDelete(const uint8_t* texAddr) {
|
||||||
configStream >> configJson;
|
char* imgName = (char*)texAddr;
|
||||||
|
|
||||||
if (!configJson.contains("CVars")) {
|
if (texAddr == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCvars(enhancementsCvars);
|
if (ResourceMgr_OTRSigCheck(imgName)) {
|
||||||
clearCvars(cheatCvars);
|
texAddr = (const uint8_t*)GetResourceDataByNameHandlingMQ(imgName);
|
||||||
clearCvars(randomizerCvars);
|
}
|
||||||
|
|
||||||
// Flatten everything under CVars into a single array
|
gfx_texture_cache_delete(texAddr);
|
||||||
auto cvars = configJson["CVars"].flatten();
|
}
|
||||||
|
|
||||||
for (auto& [key, value] : cvars.items()) {
|
void SoH_ProcessDroppedFiles(std::string filePath) {
|
||||||
// Replace slashes with dots in key, and remove leading dot
|
try {
|
||||||
std::string path = key;
|
std::ifstream configStream(filePath);
|
||||||
std::replace(path.begin(), path.end(), '/', '.');
|
if (!configStream) {
|
||||||
if (path[0] == '.') {
|
|
||||||
path.erase(0, 1);
|
|
||||||
}
|
|
||||||
if (value.is_string()) {
|
|
||||||
CVarSetString(path.c_str(), value.get<std::string>().c_str());
|
|
||||||
} else if (value.is_number_integer()) {
|
|
||||||
CVarSetInteger(path.c_str(), value.get<int>());
|
|
||||||
} else if (value.is_number_float()) {
|
|
||||||
CVarSetFloat(path.c_str(), value.get<float>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
|
||||||
gui->GetGuiWindow("Console")->Hide();
|
|
||||||
gui->GetGuiWindow("Actor Viewer")->Hide();
|
|
||||||
gui->GetGuiWindow("Collision Viewer")->Hide();
|
|
||||||
gui->GetGuiWindow("Save Editor")->Hide();
|
|
||||||
gui->GetGuiWindow("Display List Viewer")->Hide();
|
|
||||||
gui->GetGuiWindow("Stats")->Hide();
|
|
||||||
std::dynamic_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->ClearBindings();
|
|
||||||
|
|
||||||
gui->SaveConsoleVariablesOnNextTick();
|
|
||||||
|
|
||||||
uint32_t finalHash = boost::hash_32<std::string>{}(configJson.dump());
|
|
||||||
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Configuration Loaded. Hash: %d", finalHash);
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
SPDLOG_ERROR("Failed to load config file: {}", e.what());
|
|
||||||
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
|
||||||
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
|
|
||||||
return;
|
|
||||||
} catch (...) {
|
|
||||||
SPDLOG_ERROR("Failed to load config file");
|
|
||||||
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
|
||||||
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlohmann::json configJson;
|
||||||
|
configStream >> configJson;
|
||||||
|
|
||||||
|
// #region SOH [Randomizer] TODO: Refactor spoiler file handling for randomizer
|
||||||
|
if (configJson.contains("version") && configJson.contains("finalSeed")) {
|
||||||
|
CVarSetString("gRandomizerDroppedFile", filePath.c_str());
|
||||||
|
CVarSetInteger("gRandomizerNewFileDropped", 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
if (!configJson.contains("CVars")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCvars(enhancementsCvars);
|
||||||
|
clearCvars(cheatCvars);
|
||||||
|
clearCvars(randomizerCvars);
|
||||||
|
|
||||||
|
// Flatten everything under CVars into a single array
|
||||||
|
auto cvars = configJson["CVars"].flatten();
|
||||||
|
|
||||||
|
for (auto& [key, value] : cvars.items()) {
|
||||||
|
// Replace slashes with dots in key, and remove leading dot
|
||||||
|
std::string path = key;
|
||||||
|
std::replace(path.begin(), path.end(), '/', '.');
|
||||||
|
if (path[0] == '.') {
|
||||||
|
path.erase(0, 1);
|
||||||
|
}
|
||||||
|
if (value.is_string()) {
|
||||||
|
CVarSetString(path.c_str(), value.get<std::string>().c_str());
|
||||||
|
} else if (value.is_number_integer()) {
|
||||||
|
CVarSetInteger(path.c_str(), value.get<int>());
|
||||||
|
} else if (value.is_number_float()) {
|
||||||
|
CVarSetFloat(path.c_str(), value.get<float>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
||||||
|
gui->GetGuiWindow("Console")->Hide();
|
||||||
|
gui->GetGuiWindow("Actor Viewer")->Hide();
|
||||||
|
gui->GetGuiWindow("Collision Viewer")->Hide();
|
||||||
|
gui->GetGuiWindow("Save Editor")->Hide();
|
||||||
|
gui->GetGuiWindow("Display List Viewer")->Hide();
|
||||||
|
gui->GetGuiWindow("Stats")->Hide();
|
||||||
|
std::dynamic_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->ClearBindings();
|
||||||
|
|
||||||
|
gui->SaveConsoleVariablesOnNextTick();
|
||||||
|
|
||||||
|
uint32_t finalHash = boost::hash_32<std::string>{}(configJson.dump());
|
||||||
|
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Configuration Loaded. Hash: %d", finalHash);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
SPDLOG_ERROR("Failed to load config file: {}", e.what());
|
||||||
|
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
||||||
|
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
|
||||||
|
return;
|
||||||
|
} catch (...) {
|
||||||
|
SPDLOG_ERROR("Failed to load config file");
|
||||||
|
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
||||||
|
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size);
|
|||||||
void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size);
|
void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size);
|
||||||
|
|
||||||
uint64_t GetPerfCounter();
|
uint64_t GetPerfCounter();
|
||||||
|
bool ResourceMgr_IsAltAssetsEnabled();
|
||||||
struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime);
|
struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime);
|
||||||
void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime);
|
void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime);
|
||||||
void ResourceMgr_ClearSkeletons();
|
void ResourceMgr_ClearSkeletons();
|
||||||
@@ -173,9 +174,10 @@ void Entrance_InitEntranceTrackingData(void);
|
|||||||
void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex);
|
void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex);
|
||||||
void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex);
|
void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex);
|
||||||
void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement);
|
void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement);
|
||||||
|
void Gfx_UnregisterBlendedTexture(const char* name);
|
||||||
|
void Gfx_TextureCacheDelete(const uint8_t* addr);
|
||||||
void SaveManager_ThreadPoolWait();
|
void SaveManager_ThreadPoolWait();
|
||||||
void CheckTracker_OnMessageClose();
|
void CheckTracker_OnMessageClose();
|
||||||
void SoH_ProcessDroppedFiles();
|
|
||||||
|
|
||||||
int32_t GetGIID(uint32_t itemID);
|
int32_t GetGIID(uint32_t itemID);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+57
-40
@@ -9,6 +9,7 @@
|
|||||||
#include <variables.h>
|
#include <variables.h>
|
||||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
|
#include "SohGui.hpp"
|
||||||
|
|
||||||
#define NOGDI // avoid various windows defines that conflict with things in z64.h
|
#define NOGDI // avoid various windows defines that conflict with things in z64.h
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@@ -1025,51 +1026,67 @@ void SaveManager::SaveGlobal() {
|
|||||||
|
|
||||||
void SaveManager::LoadFile(int fileNum) {
|
void SaveManager::LoadFile(int fileNum) {
|
||||||
SPDLOG_INFO("Load File - fileNum: {}", fileNum);
|
SPDLOG_INFO("Load File - fileNum: {}", fileNum);
|
||||||
assert(std::filesystem::exists(GetFileName(fileNum)));
|
std::filesystem::path fileName = GetFileName(fileNum);
|
||||||
|
assert(std::filesystem::exists(fileName));
|
||||||
InitFile(false);
|
InitFile(false);
|
||||||
|
|
||||||
std::ifstream input(GetFileName(fileNum));
|
std::ifstream input(fileName);
|
||||||
|
|
||||||
saveBlock = nlohmann::json::object();
|
try {
|
||||||
input >> saveBlock;
|
saveBlock = nlohmann::json::object();
|
||||||
if (!saveBlock.contains("version")) {
|
input >> saveBlock;
|
||||||
SPDLOG_ERROR("Save at " + GetFileName(fileNum).string() + " contains no version");
|
if (!saveBlock.contains("version")) {
|
||||||
assert(false);
|
SPDLOG_ERROR("Save at " + fileName.string() + " contains no version");
|
||||||
}
|
|
||||||
switch (saveBlock["version"].get<int>()) {
|
|
||||||
case 1:
|
|
||||||
for (auto& block : saveBlock["sections"].items()) {
|
|
||||||
int sectionVersion = block.value()["version"];
|
|
||||||
std::string sectionName = block.key();
|
|
||||||
if (!sectionLoadHandlers.contains(sectionName)) {
|
|
||||||
// Unloadable sections aren't necessarily errors, they are probably mods that were unloaded
|
|
||||||
// TODO report in a more noticeable manner
|
|
||||||
SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + sectionName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SectionLoadHandler& handler = sectionLoadHandlers[sectionName];
|
|
||||||
if (!handler.contains(sectionVersion)) {
|
|
||||||
// A section that has a loader without a handler for the specific version means that the user has a mod
|
|
||||||
// at an earlier version than the save has. In this case, the user probably wants to load the save.
|
|
||||||
// Report the error so that the user can rectify the error.
|
|
||||||
// TODO report in a more noticeable manner
|
|
||||||
SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName +
|
|
||||||
" with an unloadable version " + std::to_string(sectionVersion));
|
|
||||||
assert(false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
currentJsonContext = &block.value()["data"];
|
|
||||||
handler[sectionVersion]();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SPDLOG_ERROR("Unrecognized save version " + std::to_string(saveBlock["version"].get<int>()) + " in " +
|
|
||||||
GetFileName(fileNum).string());
|
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
}
|
||||||
|
switch (saveBlock["version"].get<int>()) {
|
||||||
|
case 1:
|
||||||
|
for (auto& block : saveBlock["sections"].items()) {
|
||||||
|
int sectionVersion = block.value()["version"];
|
||||||
|
std::string sectionName = block.key();
|
||||||
|
if (!sectionLoadHandlers.contains(sectionName)) {
|
||||||
|
// Unloadable sections aren't necessarily errors, they are probably mods that were unloaded
|
||||||
|
// TODO report in a more noticeable manner
|
||||||
|
SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " +
|
||||||
|
sectionName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SectionLoadHandler& handler = sectionLoadHandlers[sectionName];
|
||||||
|
if (!handler.contains(sectionVersion)) {
|
||||||
|
// A section that has a loader without a handler for the specific version means that the user
|
||||||
|
// has a mod at an earlier version than the save has. In this case, the user probably wants to
|
||||||
|
// load the save. Report the error so that the user can rectify the error.
|
||||||
|
// TODO report in a more noticeable manner
|
||||||
|
SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName +
|
||||||
|
" with an unloadable version " + std::to_string(sectionVersion));
|
||||||
|
assert(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentJsonContext = &block.value()["data"];
|
||||||
|
handler[sectionVersion]();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SPDLOG_ERROR("Unrecognized save version " + std::to_string(saveBlock["version"].get<int>()) + " in " +
|
||||||
|
GetFileName(fileNum).string());
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
InitMeta(fileNum);
|
||||||
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnLoadFile>(fileNum);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
input.close();
|
||||||
|
std::filesystem::path newFile(LUS::Context::GetPathRelativeToAppDirectory("Save") + ("/file" + std::to_string(fileNum + 1) + "-" + std::to_string(GetUnixTimestamp()) + ".bak"));
|
||||||
|
#if defined(__SWITCH__) || defined(__WIIU__)
|
||||||
|
copy_file(fileName.c_str(), newFile.c_str());
|
||||||
|
#else
|
||||||
|
std::filesystem::copy_file(fileName, newFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::filesystem::remove(fileName);
|
||||||
|
SohGui::RegisterPopup("Error loading save file", "A problem occurred loading the save in slot " + std::to_string(fileNum + 1) + ".\nSave file corruption is suspected.\n" +
|
||||||
|
"The file has been renamed to prevent further issues.");
|
||||||
}
|
}
|
||||||
InitMeta(fileNum);
|
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnLoadFile>(fileNum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveManager::ThreadPoolWait() {
|
void SaveManager::ThreadPoolWait() {
|
||||||
|
|||||||
+9
-1
@@ -38,7 +38,6 @@
|
|||||||
#include "Enhancements/game-interactor/GameInteractor.h"
|
#include "Enhancements/game-interactor/GameInteractor.h"
|
||||||
#include "Enhancements/cosmetics/authenticGfxPatches.h"
|
#include "Enhancements/cosmetics/authenticGfxPatches.h"
|
||||||
|
|
||||||
bool ShouldClearTextureCacheAtEndOfFrame = false;
|
|
||||||
bool isBetaQuestEnabled = false;
|
bool isBetaQuestEnabled = false;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -125,6 +124,7 @@ namespace SohGui {
|
|||||||
std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
|
std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
|
||||||
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
|
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
|
||||||
std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
|
std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
|
||||||
|
std::shared_ptr<SohModalWindow> mModalWindow;
|
||||||
|
|
||||||
void SetupGuiElements() {
|
void SetupGuiElements() {
|
||||||
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
|
||||||
@@ -183,9 +183,13 @@ namespace SohGui {
|
|||||||
gui->AddGuiWindow(mItemTrackerSettingsWindow);
|
gui->AddGuiWindow(mItemTrackerSettingsWindow);
|
||||||
mRandomizerSettingsWindow = std::make_shared<RandomizerSettingsWindow>("gRandomizerSettingsEnabled", "Randomizer Settings");
|
mRandomizerSettingsWindow = std::make_shared<RandomizerSettingsWindow>("gRandomizerSettingsEnabled", "Randomizer Settings");
|
||||||
gui->AddGuiWindow(mRandomizerSettingsWindow);
|
gui->AddGuiWindow(mRandomizerSettingsWindow);
|
||||||
|
mModalWindow = std::make_shared<SohModalWindow>("gOpenWindows.modalWindowEnabled", "Modal Window");
|
||||||
|
gui->AddGuiWindow(mModalWindow);
|
||||||
|
mModalWindow->Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Destroy() {
|
void Destroy() {
|
||||||
|
mModalWindow = nullptr;
|
||||||
mRandomizerSettingsWindow = nullptr;
|
mRandomizerSettingsWindow = nullptr;
|
||||||
mItemTrackerWindow = nullptr;
|
mItemTrackerWindow = nullptr;
|
||||||
mItemTrackerSettingsWindow = nullptr;
|
mItemTrackerSettingsWindow = nullptr;
|
||||||
@@ -205,4 +209,8 @@ namespace SohGui {
|
|||||||
mConsoleWindow = nullptr;
|
mConsoleWindow = nullptr;
|
||||||
mSohMenuBar = nullptr;
|
mSohMenuBar = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function<void()> button1callback, std::function<void()> button2callback) {
|
||||||
|
mModalWindow->RegisterPopup(title, message, button1, button2, button1callback, button2callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "Enhancements/randomizer/randomizer_entrance_tracker.h"
|
#include "Enhancements/randomizer/randomizer_entrance_tracker.h"
|
||||||
#include "Enhancements/randomizer/randomizer_item_tracker.h"
|
#include "Enhancements/randomizer/randomizer_item_tracker.h"
|
||||||
#include "Enhancements/randomizer/randomizer_settings_window.h"
|
#include "Enhancements/randomizer/randomizer_settings_window.h"
|
||||||
|
#include "SohModals.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -37,6 +38,7 @@ namespace SohGui {
|
|||||||
void SetupGuiElements();
|
void SetupGuiElements();
|
||||||
void Draw();
|
void Draw();
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "", std::function<void()> button1callback = nullptr, std::function<void()> button2callback = nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SohGui_hpp */
|
#endif /* SohGui_hpp */
|
||||||
|
|||||||
+67
-35
@@ -28,7 +28,6 @@
|
|||||||
#include "Enhancements/randomizer/randomizer_item_tracker.h"
|
#include "Enhancements/randomizer/randomizer_item_tracker.h"
|
||||||
#include "Enhancements/randomizer/randomizer_settings_window.h"
|
#include "Enhancements/randomizer/randomizer_settings_window.h"
|
||||||
|
|
||||||
extern bool ShouldClearTextureCacheAtEndOfFrame;
|
|
||||||
extern bool isBetaQuestEnabled;
|
extern bool isBetaQuestEnabled;
|
||||||
|
|
||||||
extern "C" PlayState* gPlayState;
|
extern "C" PlayState* gPlayState;
|
||||||
@@ -51,6 +50,13 @@ std::string GetWindowButtonText(const char* text, bool menuOpen) {
|
|||||||
return buttonText;
|
return buttonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unordered_map<LUS::WindowBackend, const char*> windowBackendNames = {
|
||||||
|
{ LUS::WindowBackend::DX11, "DirectX" },
|
||||||
|
{ LUS::WindowBackend::SDL_OPENGL, "OpenGL"},
|
||||||
|
{ LUS::WindowBackend::SDL_METAL, "Metal" },
|
||||||
|
{ LUS::WindowBackend::GX2, "GX2"}
|
||||||
|
};
|
||||||
|
|
||||||
static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large" };
|
static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large" };
|
||||||
|
|
||||||
static const char* filters[3] = {
|
static const char* filters[3] = {
|
||||||
@@ -102,6 +108,24 @@ extern "C" SaveContext gSaveContext;
|
|||||||
|
|
||||||
namespace SohGui {
|
namespace SohGui {
|
||||||
|
|
||||||
|
std::unordered_map<LUS::WindowBackend, const char*> availableWindowBackendsMap;
|
||||||
|
LUS::WindowBackend configWindowBackend;
|
||||||
|
|
||||||
|
void UpdateWindowBackendObjects() {
|
||||||
|
LUS::WindowBackend runningWindowBackend = LUS::Context::GetInstance()->GetWindow()->GetWindowBackend();
|
||||||
|
int32_t configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
|
||||||
|
if (configWindowBackendId != -1 && configWindowBackendId < static_cast<int>(LUS::WindowBackend::BACKEND_COUNT)) {
|
||||||
|
configWindowBackend = static_cast<LUS::WindowBackend>(configWindowBackendId);
|
||||||
|
} else {
|
||||||
|
configWindowBackend = runningWindowBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto availableWindowBackends = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends();
|
||||||
|
for (auto& backend : *availableWindowBackends) {
|
||||||
|
availableWindowBackendsMap[backend] = windowBackendNames[backend];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DrawMenuBarIcon() {
|
void DrawMenuBarIcon() {
|
||||||
static bool gameIconLoaded = false;
|
static bool gameIconLoaded = false;
|
||||||
if (!gameIconLoaded) {
|
if (!gameIconLoaded) {
|
||||||
@@ -392,39 +416,23 @@ void DrawSettingsMenu() {
|
|||||||
|
|
||||||
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
|
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
|
||||||
|
|
||||||
static std::unordered_map<LUS::WindowBackend, const char*> windowBackendNames = {
|
|
||||||
{ LUS::WindowBackend::DX11, "DirectX" },
|
|
||||||
{ LUS::WindowBackend::SDL_OPENGL, "OpenGL"},
|
|
||||||
{ LUS::WindowBackend::SDL_METAL, "Metal" },
|
|
||||||
{ LUS::WindowBackend::GX2, "GX2"}
|
|
||||||
};
|
|
||||||
|
|
||||||
ImGui::Text("Renderer API (Needs reload)");
|
ImGui::Text("Renderer API (Needs reload)");
|
||||||
LUS::WindowBackend runningWindowBackend = LUS::Context::GetInstance()->GetWindow()->GetWindowBackend();
|
|
||||||
LUS::WindowBackend configWindowBackend;
|
|
||||||
int configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
|
|
||||||
if (configWindowBackendId != -1 && configWindowBackendId < static_cast<int>(LUS::WindowBackend::BACKEND_COUNT)) {
|
|
||||||
configWindowBackend = static_cast<LUS::WindowBackend>(configWindowBackendId);
|
|
||||||
} else {
|
|
||||||
configWindowBackend = runningWindowBackend;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) {
|
if (availableWindowBackendsMap.size() <= 1) {
|
||||||
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
|
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
|
||||||
}
|
}
|
||||||
if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) {
|
if (ImGui::BeginCombo("##RApi", availableWindowBackendsMap[configWindowBackend])) {
|
||||||
for (size_t i = 0; i < LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); i++) {
|
for (auto backend : availableWindowBackendsMap) {
|
||||||
auto backend = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i];
|
if (ImGui::Selectable(backend.second, backend.first == configWindowBackend)) {
|
||||||
if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) {
|
LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend.first));
|
||||||
LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend));
|
LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", backend.second);
|
||||||
LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name",
|
|
||||||
windowBackendNames[backend]);
|
|
||||||
LUS::Context::GetInstance()->GetConfig()->Save();
|
LUS::Context::GetInstance()->GetConfig()->Save();
|
||||||
|
UpdateWindowBackendObjects();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) {
|
if (availableWindowBackendsMap.size() <= 1) {
|
||||||
UIWidgets::ReEnableComponent("");
|
UIWidgets::ReEnableComponent("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,7 +566,7 @@ void DrawEnhancementsMenu() {
|
|||||||
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
|
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false);
|
||||||
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
|
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
|
||||||
"This doesn't work if the save was made in a grotto.");
|
"This doesn't work if the save was made in grottos/fairy fountains or dungeons.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", "gSkipArrowAnimation", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", "gSkipArrowAnimation", true, false);
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", "gSkipSaveConfirmation", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", "gSkipSaveConfirmation", true, false);
|
||||||
UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen");
|
UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen");
|
||||||
@@ -907,10 +915,7 @@ void DrawEnhancementsMenu() {
|
|||||||
if (ImGui::BeginMenu("Graphics"))
|
if (ImGui::BeginMenu("Graphics"))
|
||||||
{
|
{
|
||||||
if (ImGui::BeginMenu("Mods")) {
|
if (ImGui::BeginMenu("Mods")) {
|
||||||
if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) {
|
UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false);
|
||||||
ShouldClearTextureCacheAtEndOfFrame = true;
|
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
|
||||||
}
|
|
||||||
UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not.");
|
UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false);
|
||||||
UIWidgets::Tooltip("Disables bombs always rotating to face the camera. To be used in conjunction with mods that want to replace bombs with 3D objects.");
|
UIWidgets::Tooltip("Disables bombs always rotating to face the camera. To be used in conjunction with mods that want to replace bombs with 3D objects.");
|
||||||
@@ -923,16 +928,39 @@ void DrawEnhancementsMenu() {
|
|||||||
}
|
}
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Disable LOD", "gDisableLOD", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Disable LOD", "gDisableLOD", true, false);
|
||||||
UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance");
|
UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance");
|
||||||
if (UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false)) {
|
if (UIWidgets::EnhancementSliderInt("Increase Actor Draw Distance: %dx", "##IncreaseActorDrawDistance",
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) == 0) {
|
"gDisableDrawDistance", 1, 5, "", 1, true, false)) {
|
||||||
|
if (CVarGetInteger("gDisableDrawDistance", 1) <= 1) {
|
||||||
CVarSetInteger("gDisableKokiriDrawDistance", 0);
|
CVarSetInteger("gDisableKokiriDrawDistance", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range");
|
UIWidgets::Tooltip("Increases the range in which actors/objects are drawn");
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) == 1) {
|
if (CVarGetInteger("gDisableDrawDistance", 1) > 1) {
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false);
|
||||||
UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance");
|
UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this "
|
||||||
|
"will remove their draw distance");
|
||||||
}
|
}
|
||||||
|
UIWidgets::PaddedEnhancementCheckbox("Widescreen Actor Culling", "gEnhancements.WidescreenActorCulling",
|
||||||
|
true, false);
|
||||||
|
UIWidgets::Tooltip("Adjusts the horizontal culling plane to account for widescreen resolutions");
|
||||||
|
UIWidgets::PaddedEnhancementCheckbox(
|
||||||
|
"Cull Glitch Useful Actors", "gEnhancements.ExtendedCullingExcludeGlitchActors", true, false,
|
||||||
|
!CVarGetInteger("gEnhancements.WidescreenActorCulling", 0) &&
|
||||||
|
CVarGetInteger("gDisableDrawDistance", 1) <= 1,
|
||||||
|
"Requires Actor Draw Distance to be increased or Widescreen Actor Culling enabled");
|
||||||
|
UIWidgets::Tooltip(
|
||||||
|
"Exclude actors that are useful for glitches from the extended culling ranges.\n"
|
||||||
|
"Some actors may still draw in the extended ranges, but will not \"update\" so that certain "
|
||||||
|
"glitches that leverage the original culling requirements will still work.\n"
|
||||||
|
"\n"
|
||||||
|
"The following actors are excluded:\n"
|
||||||
|
"- White clothed Gerudos\n"
|
||||||
|
"- King Zora\n"
|
||||||
|
"- Gossip Stones\n"
|
||||||
|
"- Boulders\n"
|
||||||
|
"- Blue Warps\n"
|
||||||
|
"- Darunia\n"
|
||||||
|
"- Gold Skulltulas");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("N64 Mode", "gLowResMode", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("N64 Mode", "gLowResMode", true, false);
|
||||||
UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution");
|
UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Glitch line-up tick", "gDrawLineupTick", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Glitch line-up tick", "gDrawLineupTick", true, false);
|
||||||
@@ -1608,6 +1636,10 @@ void DrawRandomizerMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SohMenuBar::InitElement() {
|
||||||
|
UpdateWindowBackendObjects();
|
||||||
|
}
|
||||||
|
|
||||||
void SohMenuBar::DrawElement() {
|
void SohMenuBar::DrawElement() {
|
||||||
if (ImGui::BeginMenuBar()) {
|
if (ImGui::BeginMenuBar()) {
|
||||||
DrawMenuBarIcon();
|
DrawMenuBarIcon();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class SohMenuBar : public LUS::GuiMenuBar {
|
|||||||
using LUS::GuiMenuBar::GuiMenuBar;
|
using LUS::GuiMenuBar::GuiMenuBar;
|
||||||
protected:
|
protected:
|
||||||
void DrawElement() override;
|
void DrawElement() override;
|
||||||
void InitElement() override {};
|
void InitElement() override;
|
||||||
void UpdateElement() override {};
|
void UpdateElement() override {};
|
||||||
};
|
};
|
||||||
} // namespace SohGui
|
} // namespace SohGui
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include "SohModals.h"
|
||||||
|
#include "ImGui/imgui.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <libultraship/bridge.h>
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
#include "UIWidgets.hpp"
|
||||||
|
#include "OTRGlobals.h"
|
||||||
|
#include "z64.h"
|
||||||
|
|
||||||
|
extern "C" PlayState* gPlayState;
|
||||||
|
struct SohModal {
|
||||||
|
std::string title_;
|
||||||
|
std::string message_;
|
||||||
|
std::string button1_;
|
||||||
|
std::string button2_;
|
||||||
|
std::function<void()> button1callback_;
|
||||||
|
std::function<void()> button2callback_;
|
||||||
|
};
|
||||||
|
std::vector<SohModal> modals;
|
||||||
|
|
||||||
|
void SohModalWindow::DrawElement() {
|
||||||
|
if (modals.size() > 0) {
|
||||||
|
SohModal curModal = modals.at(0);
|
||||||
|
if (!ImGui::IsPopupOpen(curModal.title_.c_str())) {
|
||||||
|
ImGui::OpenPopup(curModal.title_.c_str());
|
||||||
|
}
|
||||||
|
if (ImGui::BeginPopupModal(curModal.title_.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
ImGui::Text(curModal.message_.c_str());
|
||||||
|
if (ImGui::Button(curModal.button1_.c_str())) {
|
||||||
|
if (curModal.button1callback_ != nullptr) {
|
||||||
|
curModal.button1callback_();
|
||||||
|
}
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
modals.erase(modals.begin());
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (curModal.button2_ != "") {
|
||||||
|
if (ImGui::Button(curModal.button2_.c_str())) {
|
||||||
|
if (curModal.button2callback_ != nullptr) {
|
||||||
|
curModal.button2callback_();
|
||||||
|
}
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
modals.erase(modals.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SohModalWindow::RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function<void()> button1callback, std::function<void()> button2callback) {
|
||||||
|
modals.push_back({ title, message, button1, button2, button1callback, button2callback });
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
#include "window/gui/GuiMenuBar.h"
|
||||||
|
#include "window/gui/GuiElement.h"
|
||||||
|
|
||||||
|
class SohModalWindow : public LUS::GuiWindow {
|
||||||
|
public:
|
||||||
|
using LUS::GuiWindow::GuiWindow;
|
||||||
|
|
||||||
|
void InitElement() override {};
|
||||||
|
void DrawElement() override;
|
||||||
|
void UpdateElement() override {};
|
||||||
|
void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "", std::function<void()> button1callback = nullptr, std::function<void()> button2callback = nullptr);
|
||||||
|
};
|
||||||
@@ -21,7 +21,7 @@ namespace UIWidgets {
|
|||||||
// Automatically adds newlines to break up text longer than a specified number of characters
|
// Automatically adds newlines to break up text longer than a specified number of characters
|
||||||
// Manually included newlines will still be respected and reset the line length
|
// Manually included newlines will still be respected and reset the line length
|
||||||
// If line is midword when it hits the limit, text should break at the last encountered space
|
// If line is midword when it hits the limit, text should break at the last encountered space
|
||||||
char* WrappedText(const char* text, unsigned int charactersPerLine) {
|
std::string WrappedText(const char* text, unsigned int charactersPerLine) {
|
||||||
std::string newText(text);
|
std::string newText(text);
|
||||||
const size_t tipLength = newText.length();
|
const size_t tipLength = newText.length();
|
||||||
int lastSpace = -1;
|
int lastSpace = -1;
|
||||||
@@ -43,17 +43,17 @@ namespace UIWidgets {
|
|||||||
currentLineLength++;
|
currentLineLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return strdup(newText.c_str());
|
return newText;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* WrappedText(const std::string& text, unsigned int charactersPerLine) {
|
std::string WrappedText(const std::string& text, unsigned int charactersPerLine) {
|
||||||
return WrappedText(text.c_str(), charactersPerLine);
|
return WrappedText(text.c_str(), charactersPerLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLastItemHoverText(const std::string& text) {
|
void SetLastItemHoverText(const std::string& text) {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("%s", WrappedText(text, 60));
|
ImGui::Text("%s", WrappedText(text, 60).c_str());
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ namespace UIWidgets {
|
|||||||
void SetLastItemHoverText(const char* text) {
|
void SetLastItemHoverText(const char* text) {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("%s", WrappedText(text, 60));
|
ImGui::Text("%s", WrappedText(text, 60).c_str());
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ namespace UIWidgets {
|
|||||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
|
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("%s", WrappedText(text, 60));
|
ImGui::Text("%s", WrappedText(text, 60).c_str());
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ namespace UIWidgets {
|
|||||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
|
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("%s", WrappedText(text, 60));
|
ImGui::Text("%s", WrappedText(text, 60).c_str());
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ namespace UIWidgets {
|
|||||||
|
|
||||||
void Tooltip(const char* text) {
|
void Tooltip(const char* text) {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("%s", WrappedText(text));
|
ImGui::SetTooltip("%s", WrappedText(text).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ namespace UIWidgets {
|
|||||||
constexpr float sliderButtonWidth = 30.0f;
|
constexpr float sliderButtonWidth = 30.0f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char* WrappedText(const char* text, unsigned int charactersPerLine = 60);
|
std::string WrappedText(const char* text, unsigned int charactersPerLine = 60);
|
||||||
char* WrappedText(const std::string& text, unsigned int charactersPerLine);
|
std::string WrappedText(const std::string& text, unsigned int charactersPerLine);
|
||||||
|
|
||||||
void SetLastItemHoverText(const std::string& text);
|
void SetLastItemHoverText(const std::string& text);
|
||||||
void SetLastItemHoverText(const char* text);
|
void SetLastItemHoverText(const char* text);
|
||||||
|
|||||||
+7
-1
@@ -99,8 +99,14 @@ void aClearBufferImpl(uint16_t addr, int nbytes) {
|
|||||||
memset(BUF_U8(addr), 0, nbytes);
|
memset(BUF_U8(addr), 0, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) {
|
void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbytes) {
|
||||||
|
#if __SANITIZE_ADDRESS__
|
||||||
|
for (size_t i = 0; i < ROUND_DOWN_16(nbytes); i++) {
|
||||||
|
BUF_U8(dest_addr)[i] = ((const unsigned char*)source_addr)[i];
|
||||||
|
}
|
||||||
|
#else
|
||||||
memcpy(BUF_U8(dest_addr), source_addr, ROUND_DOWN_16(nbytes));
|
memcpy(BUF_U8(dest_addr), source_addr, ROUND_DOWN_16(nbytes));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
|
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
|
||||||
|
|||||||
@@ -132,15 +132,15 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
|
|||||||
skeletonLimb->limbData.lodLimb.sibling = skeletonLimb->siblingIndex;
|
skeletonLimb->limbData.lodLimb.sibling = skeletonLimb->siblingIndex;
|
||||||
|
|
||||||
if (skeletonLimb->dListPtr != "") {
|
if (skeletonLimb->dListPtr != "") {
|
||||||
auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str());
|
skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
|
||||||
skeletonLimb->limbData.lodLimb.dLists[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr);
|
skeletonLimb->limbData.lodLimb.dLists[0] = (Gfx*)skeletonLimb->dListPtr.c_str();
|
||||||
} else {
|
} else {
|
||||||
skeletonLimb->limbData.lodLimb.dLists[0] = nullptr;
|
skeletonLimb->limbData.lodLimb.dLists[0] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skeletonLimb->dList2Ptr != "") {
|
if (skeletonLimb->dList2Ptr != "") {
|
||||||
auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str());
|
skeletonLimb->dList2Ptr = "__OTR__" + skeletonLimb->dList2Ptr;
|
||||||
skeletonLimb->limbData.lodLimb.dLists[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr);
|
skeletonLimb->limbData.lodLimb.dLists[1] = (Gfx*)skeletonLimb->dList2Ptr.c_str();
|
||||||
} else {
|
} else {
|
||||||
skeletonLimb->limbData.lodLimb.dLists[1] = nullptr;
|
skeletonLimb->limbData.lodLimb.dLists[1] = nullptr;
|
||||||
}
|
}
|
||||||
@@ -153,8 +153,8 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
|
|||||||
skeletonLimb->limbData.standardLimb.dList = nullptr;
|
skeletonLimb->limbData.standardLimb.dList = nullptr;
|
||||||
|
|
||||||
if (!skeletonLimb->dListPtr.empty()) {
|
if (!skeletonLimb->dListPtr.empty()) {
|
||||||
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str());
|
skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
|
||||||
skeletonLimb->limbData.standardLimb.dList = (Gfx*)(dList ? dList->GetRawPointer() : nullptr);
|
skeletonLimb->limbData.standardLimb.dList = (Gfx*)skeletonLimb->dListPtr.c_str();
|
||||||
}
|
}
|
||||||
} else if (skeletonLimb->limbType == LUS::LimbType::Curve) {
|
} else if (skeletonLimb->limbType == LUS::LimbType::Curve) {
|
||||||
skeletonLimb->limbData.skelCurveLimb.firstChildIdx = skeletonLimb->childIndex;
|
skeletonLimb->limbData.skelCurveLimb.firstChildIdx = skeletonLimb->childIndex;
|
||||||
@@ -163,13 +163,13 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
|
|||||||
skeletonLimb->limbData.skelCurveLimb.dList[1] = nullptr;
|
skeletonLimb->limbData.skelCurveLimb.dList[1] = nullptr;
|
||||||
|
|
||||||
if (!skeletonLimb->dListPtr.empty()) {
|
if (!skeletonLimb->dListPtr.empty()) {
|
||||||
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str());
|
skeletonLimb->dListPtr = "__OTR__" + skeletonLimb->dListPtr;
|
||||||
skeletonLimb->limbData.skelCurveLimb.dList[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr);
|
skeletonLimb->limbData.skelCurveLimb.dList[0] = (Gfx*)skeletonLimb->dListPtr.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skeletonLimb->dList2Ptr.empty()) {
|
if (!skeletonLimb->dList2Ptr.empty()) {
|
||||||
const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str());
|
skeletonLimb->dList2Ptr = "__OTR__" + skeletonLimb->dList2Ptr;
|
||||||
skeletonLimb->limbData.skelCurveLimb.dList[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr);
|
skeletonLimb->limbData.skelCurveLimb.dList[1] = (Gfx*)skeletonLimb->dList2Ptr.c_str();
|
||||||
}
|
}
|
||||||
} else if (skeletonLimb->limbType == LUS::LimbType::Skin) {
|
} else if (skeletonLimb->limbType == LUS::LimbType::Skin) {
|
||||||
skeletonLimb->limbData.skinLimb.jointPos.x = skeletonLimb->transX;
|
skeletonLimb->limbData.skinLimb.jointPos.x = skeletonLimb->transX;
|
||||||
@@ -189,14 +189,23 @@ void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) {
|
if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) {
|
||||||
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList.c_str());
|
if (skeletonLimb->skinDList != "") {
|
||||||
skeletonLimb->limbData.skinLimb.segment = res ? res->GetRawPointer() : nullptr;
|
skeletonLimb->skinDList = "__OTR__" + skeletonLimb->skinDList;
|
||||||
|
skeletonLimb->limbData.skinLimb.segment = (Gfx*)skeletonLimb->skinDList.c_str();
|
||||||
|
} else {
|
||||||
|
skeletonLimb->limbData.skinLimb.segment = nullptr;
|
||||||
|
}
|
||||||
} else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) {
|
} else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) {
|
||||||
skeletonLimb->skinAnimLimbData.totalVtxCount = skeletonLimb->skinVtxCnt;
|
skeletonLimb->skinAnimLimbData.totalVtxCount = skeletonLimb->skinVtxCnt;
|
||||||
skeletonLimb->skinAnimLimbData.limbModifCount = skeletonLimb->skinLimbModifCount;
|
skeletonLimb->skinAnimLimbData.limbModifCount = skeletonLimb->skinLimbModifCount;
|
||||||
skeletonLimb->skinAnimLimbData.limbModifications = skeletonLimb->skinLimbModifArray.data();
|
skeletonLimb->skinAnimLimbData.limbModifications = skeletonLimb->skinLimbModifArray.data();
|
||||||
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList2.c_str());
|
|
||||||
skeletonLimb->skinAnimLimbData.dlist = (Gfx*)(res ? res->GetRawPointer() : nullptr);
|
if (skeletonLimb->skinDList2 != "") {
|
||||||
|
skeletonLimb->skinDList2 = "__OTR__" + skeletonLimb->skinDList2;
|
||||||
|
skeletonLimb->skinAnimLimbData.dlist = (Gfx*)skeletonLimb->skinDList2.c_str();
|
||||||
|
} else {
|
||||||
|
skeletonLimb->skinAnimLimbData.dlist = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < skeletonLimb->skinLimbModifArray.size(); i++) {
|
for (size_t i = 0; i < skeletonLimb->skinLimbModifArray.size(); i++) {
|
||||||
skeletonLimb->skinAnimLimbData.limbModifications[i].vtxCount = skeletonLimb->skinLimbModifVertexArrays[i].size();
|
skeletonLimb->skinAnimLimbData.limbModifications[i].vtxCount = skeletonLimb->skinLimbModifVertexArrays[i].size();
|
||||||
@@ -254,8 +263,8 @@ void SkeletonLimbFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shar
|
|||||||
limbData.lodLimb.jointPos.z = skelLimb->transZ;
|
limbData.lodLimb.jointPos.z = skelLimb->transZ;
|
||||||
|
|
||||||
if (skelLimb->dListPtr != "") {
|
if (skelLimb->dListPtr != "") {
|
||||||
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess((const char*)skelLimb->dListPtr.c_str());
|
skelLimb->dListPtr = "__OTR__" + skelLimb->dListPtr;
|
||||||
limbData.lodLimb.dLists[0] = (Gfx*)(res ? res->GetRawPointer() : nullptr);
|
limbData.lodLimb.dLists[0] = (Gfx*)skelLimb->dListPtr.c_str();
|
||||||
} else {
|
} else {
|
||||||
limbData.lodLimb.dLists[0] = nullptr;
|
limbData.lodLimb.dLists[0] = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,12 +65,11 @@ void SkeletonPatcher::ClearSkeletons()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonPatcher::UpdateSkeletons() {
|
void SkeletonPatcher::UpdateSkeletons() {
|
||||||
bool isHD = CVarGetInteger("gAltAssets", 0);
|
auto resourceMgr = LUS::Context::GetInstance()->GetResourceManager();
|
||||||
|
bool isHD = resourceMgr->IsAltAssetsEnabled();
|
||||||
for (auto skel : skeletons) {
|
for (auto skel : skeletons) {
|
||||||
Skeleton* newSkel =
|
Skeleton* newSkel =
|
||||||
(Skeleton*)LUS::Context::GetInstance()->GetResourceManager()
|
(Skeleton*)resourceMgr->LoadResource((isHD ? LUS::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true).get();
|
||||||
->LoadResource((isHD ? LUS::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true)
|
|
||||||
.get();
|
|
||||||
|
|
||||||
if (newSkel != nullptr) {
|
if (newSkel != nullptr) {
|
||||||
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
|
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
|
||||||
|
|||||||
+19
-31
@@ -149,6 +149,13 @@ bool Scene_CommandMeshHeader(PlayState* play, LUS::ISceneCommand* cmd) {
|
|||||||
|
|
||||||
extern "C" void* func_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId);
|
extern "C" void* func_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId);
|
||||||
|
|
||||||
|
bool OTRfunc_800982FC(ObjectContext* objectCtx, s32 bankIndex, s16 objectId) {
|
||||||
|
|
||||||
|
objectCtx->status[bankIndex].id = -objectId;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) {
|
bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) {
|
||||||
// LUS::SetObjectList* cmdObj = static_pointer_cast<LUS::SetObjectList>(cmd);
|
// LUS::SetObjectList* cmdObj = static_pointer_cast<LUS::SetObjectList>(cmd);
|
||||||
LUS::SetObjectList* cmdObj = (LUS::SetObjectList*)cmd;
|
LUS::SetObjectList* cmdObj = (LUS::SetObjectList*)cmd;
|
||||||
@@ -164,49 +171,30 @@ bool Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) {
|
|||||||
void* nextPtr;
|
void* nextPtr;
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
// i = play->objectCtx.unk_09;
|
i = play->objectCtx.unk_09;
|
||||||
i = 0;
|
|
||||||
firstStatus = &play->objectCtx.status[0];
|
firstStatus = &play->objectCtx.status[0];
|
||||||
status = &play->objectCtx.status[i];
|
status = &play->objectCtx.status[i];
|
||||||
|
|
||||||
for (int i = 0; i < cmdObj->objects.size(); i++) {
|
// Loop until a mismatch in the object lists
|
||||||
bool alreadyIncluded = false;
|
// Then clear all object ids past that in the context object list and kill actors for those objects
|
||||||
|
for (i = play->objectCtx.unk_09, k = 0; i < play->objectCtx.num; i++, k++) {
|
||||||
for (int j = 0; j < play->objectCtx.num; j++) {
|
if (k >= cmdObj->objects.size() || play->objectCtx.status[i].id != cmdObj->objects[k]) {
|
||||||
if (play->objectCtx.status[j].id == cmdObj->objects[i]) {
|
for (j = i; j < play->objectCtx.num; j++) {
|
||||||
alreadyIncluded = true;
|
play->objectCtx.status[j].id = OBJECT_INVALID;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!alreadyIncluded) {
|
|
||||||
play->objectCtx.status[play->objectCtx.num++].id = cmdObj->objects[i];
|
|
||||||
func_80031A28(play, &play->actorCtx);
|
func_80031A28(play, &play->actorCtx);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Continuing from the last index, add the remaining object ids from the command object list
|
||||||
while (i < play->objectCtx.num) {
|
for (; k < cmdObj->objects.size(); k++, i++) {
|
||||||
if (status->id != *objectEntry) {
|
if (i < OBJECT_EXCHANGE_BANK_MAX - 1) {
|
||||||
status2 = &play->objectCtx.status[i];
|
OTRfunc_800982FC(&play->objectCtx, i, cmdObj->objects[k]);
|
||||||
for (j = i; j < play->objectCtx.num; j++) {
|
|
||||||
status2->id = OBJECT_INVALID;
|
|
||||||
status2++;
|
|
||||||
}
|
|
||||||
play->objectCtx.num = i;
|
|
||||||
func_80031A28(play, &play->actorCtx);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
|
||||||
k++;
|
|
||||||
objectEntry++;
|
|
||||||
status++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
play->objectCtx.num = i;
|
play->objectCtx.num = i;
|
||||||
*/
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -467,7 +467,7 @@ void GameState_Destroy(GameState* gameState) {
|
|||||||
// Performing clear skeletons before unload resources fixes an actor heap corruption crash due to the skeleton patching system.
|
// Performing clear skeletons before unload resources fixes an actor heap corruption crash due to the skeleton patching system.
|
||||||
ResourceMgr_ClearSkeletons();
|
ResourceMgr_ClearSkeletons();
|
||||||
|
|
||||||
if (CVarGetInteger("gAltAssets", 0)) {
|
if (ResourceMgr_IsAltAssetsEnabled()) {
|
||||||
ResourceUnloadDirectory("alt/*");
|
ResourceUnloadDirectory("alt/*");
|
||||||
gfx_texture_cache_clear();
|
gfx_texture_cache_clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ static const ALIGN_ASSET(2) char rGfxPrintFontDataAlt[] = drGfxPrintFontDataAlt;
|
|||||||
// https://github.com/HarbourMasters/Shipwright/issues/2762
|
// https://github.com/HarbourMasters/Shipwright/issues/2762
|
||||||
typedef enum {hardcoded, otrDefault, otrAlt} font_texture_t;
|
typedef enum {hardcoded, otrDefault, otrAlt} font_texture_t;
|
||||||
font_texture_t GfxPrint_TextureToUse() {
|
font_texture_t GfxPrint_TextureToUse() {
|
||||||
if (CVarGetInteger("gAltAssets", 0) && ResourceMgr_FileExists(rGfxPrintFontDataAlt)) {
|
if (ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileExists(rGfxPrintFontDataAlt)) {
|
||||||
// If we have alt assets enabled, and we have alt prefixed font texture, use that
|
// If we have alt assets enabled, and we have alt prefixed font texture, use that
|
||||||
return otrAlt;
|
return otrAlt;
|
||||||
} else if (ResourceMgr_FileExists(rGfxPrintFontData)) {
|
} else if (ResourceMgr_FileExists(rGfxPrintFontData)) {
|
||||||
|
|||||||
+110
-25
@@ -1208,20 +1208,11 @@ void Actor_Init(Actor* actor, PlayState* play) {
|
|||||||
actor->uncullZoneForward = 1000.0f;
|
actor->uncullZoneForward = 1000.0f;
|
||||||
actor->uncullZoneScale = 350.0f;
|
actor->uncullZoneScale = 350.0f;
|
||||||
actor->uncullZoneDownward = 700.0f;
|
actor->uncullZoneDownward = 700.0f;
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) != 0 && actor->id != ACTOR_EN_TORCH2 && actor->id != ACTOR_EN_BLKOBJ // Extra check for Dark Link and his room
|
|
||||||
&& actor->id != ACTOR_EN_HORSE // Check for Epona, else if we call her she will spawn at the other side of the map + we can hear her during the title screen sequence
|
|
||||||
&& actor->id != ACTOR_EN_HORSE_GANON && actor->id != ACTOR_EN_HORSE_ZELDA // check for Zelda's and Ganondorf's horses that will always be scene during cinematic whith camera paning
|
|
||||||
&& (play->sceneNum != SCENE_DODONGOS_CAVERN && actor->id != ACTOR_EN_ZF)) { // Check for DC and Lizalfos for the case where the miniboss music would still play under certains conditions and changing room
|
|
||||||
actor->uncullZoneForward = 32767.0f;
|
|
||||||
actor->uncullZoneScale = 32767.0f;
|
|
||||||
actor->uncullZoneDownward = 32767.0f;
|
|
||||||
}
|
|
||||||
CollisionCheck_InitInfo(&actor->colChkInfo);
|
CollisionCheck_InitInfo(&actor->colChkInfo);
|
||||||
actor->floorBgId = BGCHECK_SCENE;
|
actor->floorBgId = BGCHECK_SCENE;
|
||||||
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
|
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
|
||||||
//if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex))
|
if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
|
||||||
{
|
Actor_SetObjectDependency(play, actor);
|
||||||
//Actor_SetObjectDependency(play, actor);
|
|
||||||
actor->init(actor, play);
|
actor->init(actor, play);
|
||||||
actor->init = NULL;
|
actor->init = NULL;
|
||||||
|
|
||||||
@@ -2549,6 +2540,13 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) {
|
|||||||
Actor_SetObjectDependency(play, actor);
|
Actor_SetObjectDependency(play, actor);
|
||||||
actor->init(actor, play);
|
actor->init(actor, play);
|
||||||
actor->init = NULL;
|
actor->init = NULL;
|
||||||
|
|
||||||
|
GameInteractor_ExecuteOnActorInit(actor);
|
||||||
|
|
||||||
|
// For enemy health bar we need to know the max health during init
|
||||||
|
if (actor->category == ACTORCAT_ENEMY) {
|
||||||
|
actor->maximumHealth = actor->colChkInfo.health;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
actor = actor->next;
|
actor = actor->next;
|
||||||
} else if (!Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
|
} else if (!Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
|
||||||
@@ -2851,19 +2849,12 @@ s32 func_800314B0(PlayState* play, Actor* actor) {
|
|||||||
s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) {
|
s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) {
|
||||||
f32 var;
|
f32 var;
|
||||||
|
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) != 0 && actor->id != ACTOR_EN_TORCH2 && actor->id != ACTOR_EN_BLKOBJ // Extra check for Dark Link and his room
|
|
||||||
&& actor->id != ACTOR_EN_HORSE // Check for Epona, else if we call her she will spawn at the other side of the map + we can hear her during the title screen sequence
|
|
||||||
&& actor->id != ACTOR_EN_HORSE_GANON && actor->id != ACTOR_EN_HORSE_ZELDA // check for Zelda's and Ganondorf's horses that will always be scene during cinematic whith camera paning
|
|
||||||
&& (play->sceneNum != SCENE_DODONGOS_CAVERN && actor->id != ACTOR_EN_ZF)) { // Check for DC and Lizalfos for the case where the miniboss music would still play under certains conditions and changing room
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) {
|
if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) {
|
||||||
var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3;
|
var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3;
|
||||||
|
|
||||||
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 2.0f) &&
|
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 1.0f) &&
|
||||||
(((arg2->y + actor->uncullZoneDownward) * var) > -2.0f) &&
|
(((arg2->y + actor->uncullZoneDownward) * var) > -1.0f) &&
|
||||||
(((arg2->y - actor->uncullZoneScale) * var) < 2.0f)) {
|
(((arg2->y - actor->uncullZoneScale) * var) < 1.0f)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2871,6 +2862,80 @@ s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region SOH [Enhancements] Allows us to increase the draw and update distance independently,
|
||||||
|
// mostly a modified version of the function above and additional tweaks for some specfic actors
|
||||||
|
s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw,
|
||||||
|
bool* shouldUpdate) {
|
||||||
|
f32 clampedProjectedW;
|
||||||
|
|
||||||
|
// Check if the actor passes its original/vanilla culling requirements
|
||||||
|
if (func_800314D4(play, actor, projectedPos, projectedW)) {
|
||||||
|
*shouldUpdate = true;
|
||||||
|
*shouldDraw = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip cutscne actors that depend on culling to hide from camera pans
|
||||||
|
if (actor->id == ACTOR_EN_VIEWER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 multiplier = CVarGetInteger("gDisableDrawDistance", 1);
|
||||||
|
multiplier = MAX(multiplier, 1);
|
||||||
|
|
||||||
|
// Some actors have a really short forward value, so we need to add to it before the multiplier to increase the
|
||||||
|
// final strength of the forward culling
|
||||||
|
f32 adder = (actor->uncullZoneForward < 500) ? 1000.0f : 0.0f;
|
||||||
|
|
||||||
|
if ((projectedPos->z > -actor->uncullZoneScale) &&
|
||||||
|
(projectedPos->z < (((actor->uncullZoneForward + adder) * multiplier) + actor->uncullZoneScale))) {
|
||||||
|
clampedProjectedW = (projectedW < 1.0f) ? 1.0f : 1.0f / projectedW;
|
||||||
|
|
||||||
|
f32 ratioAdjusted = 1.0f;
|
||||||
|
|
||||||
|
if (CVarGetInteger("gEnhancements.WidescreenActorCulling", 0)) {
|
||||||
|
f32 originalAspectRatio = 4.0f / 3.0f;
|
||||||
|
f32 currentAspectRatio = OTRGetAspectRatio();
|
||||||
|
ratioAdjusted = MAX(currentAspectRatio / originalAspectRatio, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((fabsf(projectedPos->x) - actor->uncullZoneScale) * (clampedProjectedW / ratioAdjusted)) < 1.0f) &&
|
||||||
|
(((projectedPos->y + actor->uncullZoneDownward) * clampedProjectedW) > -1.0f) &&
|
||||||
|
(((projectedPos->y - actor->uncullZoneScale) * clampedProjectedW) < 1.0f)) {
|
||||||
|
|
||||||
|
if (CVarGetInteger("gEnhancements.ExtendedCullingExcludeGlitchActors", 0)) {
|
||||||
|
// These actors are safe to draw without impacting glitches
|
||||||
|
if ((actor->id == ACTOR_OBJ_BOMBIWA || actor->id == ACTOR_OBJ_HAMISHI ||
|
||||||
|
actor->id == ACTOR_EN_ISHI) || // Boulders (hookshot through collision)
|
||||||
|
actor->id == ACTOR_EN_GS || // Gossip stones (text delay)
|
||||||
|
actor->id == ACTOR_EN_GE1 || // White gerudos (gate clip/archery room transition)
|
||||||
|
actor->id == ACTOR_EN_KZ || // King Zora (unfreeze glitch)
|
||||||
|
actor->id == ACTOR_EN_DU || // Darunia (Fire temple BK skip)
|
||||||
|
actor->id == ACTOR_DOOR_WARP1 // Blue warps (wrong warps)
|
||||||
|
) {
|
||||||
|
*shouldDraw = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip these actors entirely as their draw funcs impacts glitches
|
||||||
|
if ((actor->id == ACTOR_EN_SW &&
|
||||||
|
(((actor->params & 0xE000) >> 0xD) == 1 ||
|
||||||
|
((actor->params & 0xE000) >> 0xD) == 2)) // Gold Skulltulas (hitbox at 0,0)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*shouldDraw = true;
|
||||||
|
*shouldUpdate = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
void func_800315AC(PlayState* play, ActorContext* actorCtx) {
|
void func_800315AC(PlayState* play, ActorContext* actorCtx) {
|
||||||
s32 invisibleActorCounter;
|
s32 invisibleActorCounter;
|
||||||
Actor* invisibleActors[INVISIBLE_ACTOR_MAX];
|
Actor* invisibleActors[INVISIBLE_ACTOR_MAX];
|
||||||
@@ -2906,18 +2971,35 @@ void func_800315AC(PlayState* play, ActorContext* actorCtx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region SOH [Enhancement] Extended culling updates
|
||||||
|
bool shipShouldDraw = false;
|
||||||
|
bool shipShouldUpdate = false;
|
||||||
if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(70) == 0)) {
|
if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(70) == 0)) {
|
||||||
if (func_800314B0(play, actor)) {
|
if (CVarGetInteger("gDisableDrawDistance", 1) > 1 ||
|
||||||
actor->flags |= ACTOR_FLAG_ACTIVE;
|
CVarGetInteger("gEnhancements.WidescreenActorCulling", 0)) {
|
||||||
|
Ship_CalcShouldDrawAndUpdate(play, actor, &actor->projectedPos, actor->projectedW, &shipShouldDraw,
|
||||||
|
&shipShouldUpdate);
|
||||||
|
|
||||||
|
if (shipShouldUpdate) {
|
||||||
|
actor->flags |= ACTOR_FLAG_ACTIVE;
|
||||||
|
} else {
|
||||||
|
actor->flags &= ~ACTOR_FLAG_ACTIVE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
actor->flags &= ~ACTOR_FLAG_ACTIVE;
|
if (func_800314B0(play, actor)) {
|
||||||
|
actor->flags |= ACTOR_FLAG_ACTIVE;
|
||||||
|
} else {
|
||||||
|
actor->flags &= ~ACTOR_FLAG_ACTIVE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor->isDrawn = false;
|
actor->isDrawn = false;
|
||||||
|
|
||||||
if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(71) == 0)) {
|
if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(71) == 0)) {
|
||||||
if ((actor->init == NULL) && (actor->draw != NULL) && (actor->flags & (ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_ACTIVE))) {
|
if ((actor->init == NULL) && (actor->draw != NULL) &&
|
||||||
|
((actor->flags & (ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_ACTIVE)) || shipShouldDraw)) {
|
||||||
|
// #endregion
|
||||||
if ((actor->flags & ACTOR_FLAG_LENS) &&
|
if ((actor->flags & ACTOR_FLAG_LENS) &&
|
||||||
((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) ||
|
((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) ||
|
||||||
play->actorCtx.lensActive || (actor->room != play->roomCtx.curRoom.num))) {
|
play->actorCtx.lensActive || (actor->room != play->roomCtx.curRoom.num))) {
|
||||||
@@ -3129,6 +3211,9 @@ void Actor_FreeOverlay(ActorDBEntry* dbEntry) {
|
|||||||
osSyncPrintf(VT_RST);
|
osSyncPrintf(VT_RST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SoH: Flag to check if actors are being spawned from the actor entry list
|
||||||
|
// This flag is checked against to allow actors which dont have an objectBankIndex in the objectCtx slot/status array to spawn
|
||||||
|
// An example of what this fixes, is that it allows hookshot to be used as child
|
||||||
int gMapLoading = 0;
|
int gMapLoading = 0;
|
||||||
|
|
||||||
Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 posX, f32 posY, f32 posZ,
|
Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 posX, f32 posY, f32 posZ,
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ s32 CollisionPoly_LineVsPoly(CollisionPoly* poly, Vec3s* vtxList, Vec3f* posA, V
|
|||||||
(poly->normal.x * posB->x + poly->normal.y * posB->y + poly->normal.z * posB->z) * COLPOLY_NORMAL_FRAC +
|
(poly->normal.x * posB->x + poly->normal.y * posB->y + poly->normal.z * posB->z) * COLPOLY_NORMAL_FRAC +
|
||||||
plane.originDist;
|
plane.originDist;
|
||||||
|
|
||||||
#ifdef __WIIU__
|
#if defined(__SWITCH__) || defined(__WIIU__)
|
||||||
// on some platforms this ends up as very small numbers due to rounding issues
|
// on some platforms this ends up as very small numbers due to rounding issues
|
||||||
if (IS_ZERO(planeDistA)) {
|
if (IS_ZERO(planeDistA)) {
|
||||||
planeDistA = 0.0f;
|
planeDistA = 0.0f;
|
||||||
@@ -1902,7 +1902,7 @@ s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResul
|
|||||||
s32 bgId2;
|
s32 bgId2;
|
||||||
f32 nx, ny, nz; // unit normal of polygon
|
f32 nx, ny, nz; // unit normal of polygon
|
||||||
|
|
||||||
if (CVarGetInteger("gNoClip", 0) != 0) {
|
if (CVarGetInteger("gNoClip", 0) && actor != NULL && actor->id == ACTOR_PLAYER) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7887,7 +7887,7 @@ s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear free camera if an action is performed that would move the camera (targeting, first person, talking)
|
// Clear free look if an action is performed that would move the camera (targeting, first person, talking)
|
||||||
if (CVarGetInteger("gFreeCamera", 0) && SetCameraManual(camera) == 1 &&
|
if (CVarGetInteger("gFreeCamera", 0) && SetCameraManual(camera) == 1 &&
|
||||||
((mode >= CAM_MODE_TARGET && mode <= CAM_MODE_BATTLE) ||
|
((mode >= CAM_MODE_TARGET && mode <= CAM_MODE_BATTLE) ||
|
||||||
(mode >= CAM_MODE_FIRSTPERSON && mode <= CAM_MODE_CLIMBZ) || mode == CAM_MODE_HANGZ ||
|
(mode >= CAM_MODE_FIRSTPERSON && mode <= CAM_MODE_CLIMBZ) || mode == CAM_MODE_HANGZ ||
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ typedef struct {
|
|||||||
union {
|
union {
|
||||||
u32 unk_00;
|
u32 unk_00;
|
||||||
struct {
|
struct {
|
||||||
u32 unk_bit0 : 1;
|
// SoH [Port] These bitfield values are unused and led to shifting in validModes for little endian systems
|
||||||
u32 unk_bit1 : 1;
|
// Removing those so that validModes can be a complete 32 bit value
|
||||||
u32 validModes : 30;
|
// u32 unk_bit0 : 1;
|
||||||
|
// u32 unk_bit1 : 1;
|
||||||
|
u32 validModes;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
CameraMode* cameraModes;
|
CameraMode* cameraModes;
|
||||||
|
|||||||
@@ -524,7 +524,6 @@ void Map_Init(PlayState* play) {
|
|||||||
interfaceCtx->unk_25A = -1;
|
interfaceCtx->unk_25A = -1;
|
||||||
|
|
||||||
interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*));
|
interfaceCtx->mapSegment = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*));
|
||||||
interfaceCtx->mapSegmentName = GAMESTATE_ALLOC_MC(&play->state, 2 * sizeof(char*));
|
|
||||||
// "MAP texture initialization scene_data_ID=%d mapSegment=%x"
|
// "MAP texture initialization scene_data_ID=%d mapSegment=%x"
|
||||||
osSyncPrintf("\n\n\nMAP テクスチャ初期化 scene_data_ID=%d\nmapSegment=%x\n\n", play->sceneNum,
|
osSyncPrintf("\n\n\nMAP テクスチャ初期化 scene_data_ID=%d\nmapSegment=%x\n\n", play->sceneNum,
|
||||||
interfaceCtx->mapSegment, play);
|
interfaceCtx->mapSegment, play);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "textures/message_static/message_static.h"
|
#include "textures/message_static/message_static.h"
|
||||||
#include "textures/message_texture_static/message_texture_static.h"
|
#include "textures/message_texture_static/message_texture_static.h"
|
||||||
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
|
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
|
||||||
|
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
|
|
||||||
@@ -1114,7 +1115,7 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (msgCtx->textDelayTimer == 0) {
|
if (msgCtx->textDelayTimer == 0) {
|
||||||
msgCtx->textDrawPos = i + CVarGetInteger("gTextSpeed", 2);
|
msgCtx->textDrawPos = i + CVarGetInteger("gTextSpeed", 1);
|
||||||
msgCtx->textDelayTimer = msgCtx->textDelay;
|
msgCtx->textDelayTimer = msgCtx->textDelay;
|
||||||
} else {
|
} else {
|
||||||
msgCtx->textDelayTimer--;
|
msgCtx->textDelayTimer--;
|
||||||
@@ -3069,7 +3070,9 @@ void Message_Draw(PlayState* play) {
|
|||||||
POLY_OPA_DISP = plusOne;
|
POLY_OPA_DISP = plusOne;
|
||||||
}
|
}
|
||||||
plusOne = Graph_GfxPlusOne(polyOpaP = POLY_OPA_DISP);
|
plusOne = Graph_GfxPlusOne(polyOpaP = POLY_OPA_DISP);
|
||||||
gSPDisplayList(OVERLAY_DISP++, plusOne);
|
if (!GameInteractor_NoUIActive()) {
|
||||||
|
gSPDisplayList(OVERLAY_DISP++, plusOne);
|
||||||
|
}
|
||||||
Message_DrawMain(play, &plusOne);
|
Message_DrawMain(play, &plusOne);
|
||||||
gSPEndDisplayList(plusOne++);
|
gSPEndDisplayList(plusOne++);
|
||||||
Graph_BranchDlist(polyOpaP, plusOne);
|
Graph_BranchDlist(polyOpaP, plusOne);
|
||||||
|
|||||||
+196
-104
@@ -1436,64 +1436,62 @@ Gfx* Gfx_TextureI8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 te
|
|||||||
return displayListHead;
|
return displayListHead;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inventory_SwapAgeEquipment(void) {
|
void Rando_Inventory_SwapAgeEquipment(void) {
|
||||||
s16 i;
|
s16 i;
|
||||||
u16 shieldEquipValue;
|
u16 shieldEquipValue;
|
||||||
|
|
||||||
if (LINK_AGE_IN_YEARS == YEARS_CHILD) {
|
if (LINK_AGE_IN_YEARS == YEARS_CHILD) {
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
gSaveContext.childEquips.buttonItems[i] = gSaveContext.equips.buttonItems[i];
|
gSaveContext.childEquips.buttonItems[i] =
|
||||||
|
gSaveContext.equips.buttonItems[i];
|
||||||
} else {
|
} else {
|
||||||
gSaveContext.childEquips.buttonItems[i] = ITEM_SWORD_KOKIRI;
|
gSaveContext.childEquips.buttonItems[i] = ITEM_SWORD_KOKIRI;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
gSaveContext.childEquips.cButtonSlots[i - 1] = gSaveContext.equips.cButtonSlots[i - 1];
|
gSaveContext.childEquips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When becoming adult, remove swordless flag since we'll get master sword
|
|
||||||
// (Unless Master Sword is shuffled)
|
|
||||||
// Only in rando to keep swordless link bugs in vanilla
|
|
||||||
if (IS_RANDO && !Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD)) {
|
|
||||||
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
gSaveContext.childEquips.equipment = gSaveContext.equips.equipment;
|
gSaveContext.childEquips.equipment = gSaveContext.equips.equipment;
|
||||||
|
|
||||||
if (gSaveContext.adultEquips.buttonItems[0] == ITEM_NONE && !(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.adultEquips.equipment)) {
|
// When becoming adult, remove swordless flag since we'll get master sword
|
||||||
if (!IS_RANDO || !Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD)) {
|
// This gets set back appropriately later in the case of master sword shuffle
|
||||||
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
|
||||||
} else {
|
|
||||||
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
// This section sets up the equipment on the first time going adult.
|
||||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
// On master sword shuffle the check for the B button is insufficient, and so checking the equipment is completely zero-ed is needed
|
||||||
}
|
// (Could just always use `gSaveContext.adultEquips.equipment == 0` for rando?)
|
||||||
|
if (gSaveContext.adultEquips.buttonItems[0] == ITEM_NONE && ((IS_RANDO && !Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD)) || (gSaveContext.adultEquips.equipment == 0))) {
|
||||||
|
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
||||||
|
|
||||||
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
|
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
|
||||||
gSaveContext.equips.buttonItems[1] = ITEM_NUT;
|
gSaveContext.equips.buttonItems[1] = ITEM_NUT;
|
||||||
gSaveContext.equips.cButtonSlots[0] = SLOT_NUT;
|
gSaveContext.equips.cButtonSlots[0] = SLOT_NUT;
|
||||||
} else {
|
} else {
|
||||||
gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] = ITEM_NONE;
|
gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] =
|
||||||
|
ITEM_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gSaveContext.equips.buttonItems[2] = ITEM_BOMB;
|
gSaveContext.equips.buttonItems[2] = ITEM_BOMB;
|
||||||
gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA];
|
gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA];
|
||||||
gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB;
|
gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB;
|
||||||
gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA;
|
gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA;
|
||||||
|
|
||||||
gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) |
|
gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) |
|
||||||
(EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) |
|
(EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) |
|
||||||
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
||||||
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
||||||
|
|
||||||
|
// In Master Sword Shuffle we want to override the equip of the master sword from the vanilla code
|
||||||
|
// First check we have the Master sword in our inventory, and if not, then unequip
|
||||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
|
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
|
||||||
gSaveContext.equips.buttonItems[0] == ITEM_NONE) {
|
!CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) {
|
||||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||||
|
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
||||||
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the dpad to nothing
|
// Set the dpad to nothing
|
||||||
gSaveContext.equips.buttonItems[4] = ITEM_NONE;
|
gSaveContext.equips.buttonItems[4] = ITEM_NONE;
|
||||||
gSaveContext.equips.buttonItems[5] = ITEM_NONE;
|
gSaveContext.equips.buttonItems[5] = ITEM_NONE;
|
||||||
@@ -1505,10 +1503,170 @@ void Inventory_SwapAgeEquipment(void) {
|
|||||||
gSaveContext.equips.cButtonSlots[6] = SLOT_NONE;
|
gSaveContext.equips.cButtonSlots[6] = SLOT_NONE;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
gSaveContext.equips.buttonItems[i] = gSaveContext.adultEquips.buttonItems[i];
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.adultEquips.buttonItems[i];
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
gSaveContext.equips.cButtonSlots[i - 1] = gSaveContext.adultEquips.cButtonSlots[i - 1];
|
gSaveContext.equips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.adultEquips.cButtonSlots[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
||||||
|
(gSaveContext.equips.buttonItems[i] <= ITEM_POE)) ||
|
||||||
|
((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) &&
|
||||||
|
(gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) {
|
||||||
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Master Sword Shuffle we want to set the swordless flag if no item is on the B button
|
||||||
|
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
|
||||||
|
gSaveContext.equips.buttonItems[0] == ITEM_NONE) {
|
||||||
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
gSaveContext.adultEquips.buttonItems[i] = gSaveContext.equips.buttonItems[i];
|
||||||
|
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.adultEquips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gSaveContext.adultEquips.equipment = gSaveContext.equips.equipment;
|
||||||
|
|
||||||
|
if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.childEquips.buttonItems[i];
|
||||||
|
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.childEquips.cButtonSlots[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
||||||
|
(gSaveContext.equips.buttonItems[i] <= ITEM_POE)) ||
|
||||||
|
((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) &&
|
||||||
|
(gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) {
|
||||||
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
||||||
|
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||||
|
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
||||||
|
}
|
||||||
|
// In Rando we need an extra case to handle starting as adult. We can use the fact that the childEquips will be uninitialised (i.e. 0) at this point
|
||||||
|
else if (gSaveContext.childEquips.equipment == 0) {
|
||||||
|
|
||||||
|
//zero out items
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.equips.cButtonSlots[i-1] = ITEM_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4)) |
|
||||||
|
(EQUIP_VALUE_SHIELD_DEKU << (EQUIP_TYPE_SHIELD * 4)) |
|
||||||
|
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
||||||
|
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// When becoming child in rando, set swordless flag and clear B button if player doesn't have kokiri sword
|
||||||
|
// Otherwise, equip sword and unset flag
|
||||||
|
if (!CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI)) {
|
||||||
|
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||||
|
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
||||||
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
|
} else {
|
||||||
|
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||||
|
gSaveContext.equips.equipment |= (EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4));
|
||||||
|
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_KOKIRI;
|
||||||
|
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shieldEquipValue = gEquipMasks[EQUIP_TYPE_SHIELD] & gSaveContext.equips.equipment;
|
||||||
|
if (shieldEquipValue) {
|
||||||
|
shieldEquipValue >>= gEquipShifts[EQUIP_TYPE_SHIELD];
|
||||||
|
if (!CHECK_OWNED_EQUIP_ALT(EQUIP_TYPE_SHIELD, shieldEquipValue - 1)) {
|
||||||
|
gSaveContext.equips.equipment &= gEquipNegMasks[EQUIP_TYPE_SHIELD];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inventory_SwapAgeEquipment(void) {
|
||||||
|
s16 i;
|
||||||
|
u16 shieldEquipValue;
|
||||||
|
|
||||||
|
// Mod Enhancments can utilise the rando flow path
|
||||||
|
if (IS_RANDO || CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) {
|
||||||
|
Rando_Inventory_SwapAgeEquipment();
|
||||||
|
CVarSetInteger("gSwitchTimeline", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LINK_AGE_IN_YEARS == YEARS_CHILD) {
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.childEquips.buttonItems[i] =
|
||||||
|
gSaveContext.equips.buttonItems[i];
|
||||||
|
} else {
|
||||||
|
gSaveContext.childEquips.buttonItems[i] = ITEM_SWORD_KOKIRI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.childEquips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gSaveContext.childEquips.equipment = gSaveContext.equips.equipment;
|
||||||
|
|
||||||
|
if (gSaveContext.adultEquips.buttonItems[0] == ITEM_NONE) {
|
||||||
|
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
|
||||||
|
|
||||||
|
if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) {
|
||||||
|
gSaveContext.equips.buttonItems[1] = ITEM_NUT;
|
||||||
|
gSaveContext.equips.cButtonSlots[0] = SLOT_NUT;
|
||||||
|
} else {
|
||||||
|
gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] =
|
||||||
|
ITEM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gSaveContext.equips.buttonItems[2] = ITEM_BOMB;
|
||||||
|
gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA];
|
||||||
|
gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB;
|
||||||
|
gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA;
|
||||||
|
gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) |
|
||||||
|
(EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) |
|
||||||
|
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
||||||
|
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
||||||
|
// Set the dpad to nothing
|
||||||
|
gSaveContext.equips.buttonItems[4] = ITEM_NONE;
|
||||||
|
gSaveContext.equips.buttonItems[5] = ITEM_NONE;
|
||||||
|
gSaveContext.equips.buttonItems[6] = ITEM_NONE;
|
||||||
|
gSaveContext.equips.buttonItems[7] = ITEM_NONE;
|
||||||
|
gSaveContext.equips.cButtonSlots[3] = SLOT_NONE;
|
||||||
|
gSaveContext.equips.cButtonSlots[4] = SLOT_NONE;
|
||||||
|
gSaveContext.equips.cButtonSlots[5] = SLOT_NONE;
|
||||||
|
gSaveContext.equips.cButtonSlots[6] = SLOT_NONE;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.adultEquips.buttonItems[i];
|
||||||
|
|
||||||
|
if (i != 0) {
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.adultEquips.cButtonSlots[i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
||||||
@@ -1524,59 +1682,25 @@ void Inventory_SwapAgeEquipment(void) {
|
|||||||
gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment;
|
gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// When becoming child, set swordless flag if player doesn't have kokiri sword
|
|
||||||
// Only in rando to keep swordless link bugs in vanilla
|
|
||||||
if (IS_RANDO && CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
|
|
||||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When using enhancements, set swordless flag if player doesn't have kokiri sword or hasn't equipped a sword yet.
|
|
||||||
// Then set the child equips button items to item none to ensure kokiri sword is not equipped
|
|
||||||
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) && (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0 || Flags_GetInfTable(INFTABLE_SWORDLESS))) {
|
|
||||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
|
||||||
gSaveContext.childEquips.buttonItems[0] = ITEM_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
gSaveContext.adultEquips.buttonItems[i] = gSaveContext.equips.buttonItems[i];
|
gSaveContext.adultEquips.buttonItems[i] = gSaveContext.equips.buttonItems[i];
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
gSaveContext.adultEquips.cButtonSlots[i - 1] = gSaveContext.equips.cButtonSlots[i - 1];
|
gSaveContext.adultEquips.cButtonSlots[i - 1] =
|
||||||
|
gSaveContext.equips.cButtonSlots[i - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gSaveContext.adultEquips.equipment = gSaveContext.equips.equipment;
|
gSaveContext.adultEquips.equipment = gSaveContext.equips.equipment;
|
||||||
// Switching age using enhancements separated out to make vanilla flow clear
|
|
||||||
if (CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) {
|
if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||||
gSaveContext.equips.buttonItems[i] = gSaveContext.childEquips.buttonItems[i];
|
gSaveContext.equips.buttonItems[i] =
|
||||||
|
gSaveContext.childEquips.buttonItems[i];
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
gSaveContext.equips.cButtonSlots[i - 1] = gSaveContext.childEquips.cButtonSlots[i - 1];
|
gSaveContext.equips.cButtonSlots[i - 1] =
|
||||||
}
|
gSaveContext.childEquips.cButtonSlots[i - 1];
|
||||||
|
|
||||||
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
|
||||||
(gSaveContext.equips.buttonItems[i] <= ITEM_POE)) ||
|
|
||||||
((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) &&
|
|
||||||
(gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) {
|
|
||||||
osSyncPrintf("Register_Item_Pt(%d)=%d\n", i, gSaveContext.equips.cButtonSlots[i - 1]);
|
|
||||||
gSaveContext.equips.buttonItems[i] =
|
|
||||||
gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
|
||||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
|
||||||
// Equips kokiri sword in the inventory screen only if kokiri sword exists in inventory and a sword has been equipped already
|
|
||||||
if (!(CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) && !Flags_GetInfTable(INFTABLE_SWORDLESS)) {
|
|
||||||
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
|
||||||
}
|
|
||||||
} else if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
|
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
|
||||||
gSaveContext.equips.buttonItems[i] = gSaveContext.childEquips.buttonItems[i];
|
|
||||||
|
|
||||||
if (i != 0) {
|
|
||||||
gSaveContext.equips.cButtonSlots[i - 1] = gSaveContext.childEquips.cButtonSlots[i - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
if (((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) &&
|
||||||
@@ -1592,43 +1716,11 @@ void Inventory_SwapAgeEquipment(void) {
|
|||||||
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
||||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||||
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
||||||
} else if (IS_RANDO && Randomizer_GetSettingValue(RSK_STARTING_AGE) == RO_AGE_ADULT) {
|
|
||||||
/*If in rando and starting age is adult, childEquips is not initialized and buttonItems[0]
|
|
||||||
will be ITEM_NONE. When changing age from adult -> child, reset equips to "default"
|
|
||||||
(only kokiri tunic/boots equipped, no sword, no C-button items, no D-Pad items).
|
|
||||||
When becoming child, set swordless flag if player doesn't have kokiri sword
|
|
||||||
Only in rando to keep swordless link bugs in vanilla*/
|
|
||||||
if (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
|
|
||||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
//zero out items
|
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
|
||||||
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
|
|
||||||
if (i != 0) {
|
|
||||||
gSaveContext.equips.cButtonSlots[i-1] = ITEM_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4)) |
|
|
||||||
(EQUIP_VALUE_SHIELD_DEKU << (EQUIP_TYPE_SHIELD * 4)) |
|
|
||||||
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
|
||||||
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) &&
|
|
||||||
(gSaveContext.equips.buttonItems[0] == ITEM_NONE)) {
|
|
||||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
|
||||||
if (gSaveContext.childEquips.equipment == 0) {
|
|
||||||
// force equip kokiri tunic and boots in scenario gSaveContext.childEquips.equipment is uninitialized
|
|
||||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
|
||||||
gSaveContext.equips.equipment |= (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) |
|
|
||||||
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CVarSetInteger("gSwitchTimeline", 0);
|
|
||||||
shieldEquipValue = gEquipMasks[EQUIP_TYPE_SHIELD] & gSaveContext.equips.equipment;
|
shieldEquipValue = gEquipMasks[EQUIP_TYPE_SHIELD] & gSaveContext.equips.equipment;
|
||||||
if (shieldEquipValue != 0) {
|
if (shieldEquipValue) {
|
||||||
shieldEquipValue >>= gEquipShifts[EQUIP_TYPE_SHIELD];
|
shieldEquipValue >>= gEquipShifts[EQUIP_TYPE_SHIELD];
|
||||||
if (!CHECK_OWNED_EQUIP_ALT(EQUIP_TYPE_SHIELD, shieldEquipValue - 1)) {
|
if (!CHECK_OWNED_EQUIP_ALT(EQUIP_TYPE_SHIELD, shieldEquipValue - 1)) {
|
||||||
gSaveContext.equips.equipment &= gEquipNegMasks[EQUIP_TYPE_SHIELD];
|
gSaveContext.equips.equipment &= gEquipNegMasks[EQUIP_TYPE_SHIELD];
|
||||||
|
|||||||
@@ -2307,10 +2307,12 @@ void Player_DrawPause(PlayState* play, u8* segment, SkelAnime* skelAnime, Vec3f*
|
|||||||
}
|
}
|
||||||
|
|
||||||
srcTable = ResourceMgr_LoadArrayByNameAsVec3s(srcTable);
|
srcTable = ResourceMgr_LoadArrayByNameAsVec3s(srcTable);
|
||||||
|
Vec3s* ogSrcTable = srcTable;
|
||||||
destTable = skelAnime->jointTable;
|
destTable = skelAnime->jointTable;
|
||||||
for (i = 0; i < skelAnime->limbCount; i++) {
|
for (i = 0; i < skelAnime->limbCount; i++) {
|
||||||
*destTable++ = *srcTable++;
|
*destTable++ = *srcTable++;
|
||||||
}
|
}
|
||||||
|
free(ogSrcTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,9 +83,10 @@ void Object_UpdateBank(ObjectContext* objectCtx) {
|
|||||||
RomFile* objectFile;
|
RomFile* objectFile;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
/*
|
|
||||||
for (i = 0; i < objectCtx->num; i++) {
|
for (i = 0; i < objectCtx->num; i++) {
|
||||||
if (status->id < 0) {
|
if (status->id < 0) {
|
||||||
|
/*
|
||||||
if (status->dmaRequest.vromAddr == 0) {
|
if (status->dmaRequest.vromAddr == 0) {
|
||||||
osCreateMesgQueue(&status->loadQueue, &status->loadMsg, 1);
|
osCreateMesgQueue(&status->loadQueue, &status->loadMsg, 1);
|
||||||
objectFile = &gObjectTable[-status->id];
|
objectFile = &gObjectTable[-status->id];
|
||||||
@@ -96,10 +97,12 @@ void Object_UpdateBank(ObjectContext* objectCtx) {
|
|||||||
} else if (!osRecvMesg(&status->loadQueue, NULL, OS_MESG_NOBLOCK)) {
|
} else if (!osRecvMesg(&status->loadQueue, NULL, OS_MESG_NOBLOCK)) {
|
||||||
status->id = -status->id;
|
status->id = -status->id;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
status->id = -status->id;
|
||||||
}
|
}
|
||||||
status++;
|
status++;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Object_GetIndex(ObjectContext* objectCtx, s16 objectId) {
|
s32 Object_GetIndex(ObjectContext* objectCtx, s16 objectId) {
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable,
|
|||||||
Vec3f pos;
|
Vec3f pos;
|
||||||
Vec3s rot;
|
Vec3s rot;
|
||||||
|
|
||||||
|
if (CVarGetInteger("gDisableLOD", 0)) {
|
||||||
|
lod = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (skeleton == NULL) {
|
if (skeleton == NULL) {
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
osSyncPrintf("Si2_Lod_draw():skelがNULLです。\n"); // "skel is NULL."
|
osSyncPrintf("Si2_Lod_draw():skelがNULLです。\n"); // "skel is NULL."
|
||||||
@@ -144,6 +148,8 @@ void SkelAnime_DrawFlexLimbLod(PlayState* play, s32 limbIndex, void** skeleton,
|
|||||||
|
|
||||||
newDList = limbDList = limb->dLists[lod];
|
newDList = limbDList = limb->dLists[lod];
|
||||||
|
|
||||||
|
play->flexLimbOverrideMTX = mtx;
|
||||||
|
|
||||||
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
|
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
|
||||||
Matrix_TranslateRotateZYX(&pos, &rot);
|
Matrix_TranslateRotateZYX(&pos, &rot);
|
||||||
if (newDList != NULL) {
|
if (newDList != NULL) {
|
||||||
@@ -191,6 +197,10 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable,
|
|||||||
Vec3s rot;
|
Vec3s rot;
|
||||||
Mtx* mtx = Graph_Alloc(play->state.gfxCtx, dListCount * sizeof(Mtx));
|
Mtx* mtx = Graph_Alloc(play->state.gfxCtx, dListCount * sizeof(Mtx));
|
||||||
|
|
||||||
|
if (CVarGetInteger("gDisableLOD", 0)) {
|
||||||
|
lod = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (skeleton == NULL) {
|
if (skeleton == NULL) {
|
||||||
osSyncPrintf(VT_FGCOL(RED));
|
osSyncPrintf(VT_FGCOL(RED));
|
||||||
osSyncPrintf("Si2_Lod_draw_SV():skelがNULLです。\n"); // "skel is NULL."
|
osSyncPrintf("Si2_Lod_draw_SV():skelがNULLです。\n"); // "skel is NULL."
|
||||||
@@ -212,6 +222,8 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable,
|
|||||||
|
|
||||||
newDList = limbDList = rootLimb->dLists[lod];
|
newDList = limbDList = rootLimb->dLists[lod];
|
||||||
|
|
||||||
|
play->flexLimbOverrideMTX = &mtx;
|
||||||
|
|
||||||
if ((overrideLimbDraw == 0) || !overrideLimbDraw(play, 1, &newDList, &pos, &rot, arg)) {
|
if ((overrideLimbDraw == 0) || !overrideLimbDraw(play, 1, &newDList, &pos, &rot, arg)) {
|
||||||
Matrix_TranslateRotateZYX(&pos, &rot);
|
Matrix_TranslateRotateZYX(&pos, &rot);
|
||||||
if (newDList != NULL) {
|
if (newDList != NULL) {
|
||||||
@@ -298,6 +310,20 @@ void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx* SkelAnime_DrawSkeleton2(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw,
|
||||||
|
PostLimbDrawOpa postLimbDraw, void* arg, Gfx* gfx)
|
||||||
|
{
|
||||||
|
if (skelAnime->skeletonHeader->skeletonType == SKELANIME_TYPE_NORMAL) {
|
||||||
|
return SkelAnime_Draw(play, skelAnime->skeleton, skelAnime->jointTable, overrideLimbDraw, postLimbDraw, arg, gfx);
|
||||||
|
} else if (skelAnime->skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
FlexSkeletonHeader* flexHeader = (FlexSkeletonHeader*)skelAnime->skeletonHeader;
|
||||||
|
return SkelAnime_DrawFlex(play, skelAnime->skeleton, skelAnime->jointTable, flexHeader->dListCount,
|
||||||
|
overrideLimbDraw, postLimbDraw, arg, gfx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfx;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw all limbs of type `StandardLimb` in a given skeleton to the polyOpa buffer
|
* Draw all limbs of type `StandardLimb` in a given skeleton to the polyOpa buffer
|
||||||
*/
|
*/
|
||||||
@@ -375,6 +401,8 @@ void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton,
|
|||||||
|
|
||||||
newDList = limbDList = limb->dList;
|
newDList = limbDList = limb->dList;
|
||||||
|
|
||||||
|
play->flexLimbOverrideMTX = limbMatricies;
|
||||||
|
|
||||||
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
|
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
|
||||||
Matrix_TranslateRotateZYX(&pos, &rot);
|
Matrix_TranslateRotateZYX(&pos, &rot);
|
||||||
if (newDList != NULL) {
|
if (newDList != NULL) {
|
||||||
|
|||||||
+60
-57
@@ -59,65 +59,68 @@ void Sram_OpenSave() {
|
|||||||
|
|
||||||
Save_LoadFile();
|
Save_LoadFile();
|
||||||
|
|
||||||
if (!CVarGetInteger("gRememberSaveLocation", 0) || gSaveContext.savedSceneNum == SCENE_FAIRYS_FOUNTAIN ||
|
switch (gSaveContext.savedSceneNum) {
|
||||||
gSaveContext.savedSceneNum == SCENE_GROTTOS) {
|
case SCENE_DEKU_TREE:
|
||||||
switch (gSaveContext.savedSceneNum) {
|
case SCENE_DODONGOS_CAVERN:
|
||||||
case SCENE_DEKU_TREE:
|
case SCENE_JABU_JABU:
|
||||||
case SCENE_DODONGOS_CAVERN:
|
case SCENE_FOREST_TEMPLE:
|
||||||
case SCENE_JABU_JABU:
|
case SCENE_FIRE_TEMPLE:
|
||||||
case SCENE_FOREST_TEMPLE:
|
case SCENE_WATER_TEMPLE:
|
||||||
case SCENE_FIRE_TEMPLE:
|
case SCENE_SPIRIT_TEMPLE:
|
||||||
case SCENE_WATER_TEMPLE:
|
case SCENE_SHADOW_TEMPLE:
|
||||||
case SCENE_SPIRIT_TEMPLE:
|
case SCENE_BOTTOM_OF_THE_WELL:
|
||||||
case SCENE_SHADOW_TEMPLE:
|
case SCENE_ICE_CAVERN:
|
||||||
case SCENE_BOTTOM_OF_THE_WELL:
|
case SCENE_GANONS_TOWER:
|
||||||
case SCENE_ICE_CAVERN:
|
case SCENE_GERUDO_TRAINING_GROUND:
|
||||||
case SCENE_GANONS_TOWER:
|
case SCENE_THIEVES_HIDEOUT:
|
||||||
case SCENE_GERUDO_TRAINING_GROUND:
|
case SCENE_INSIDE_GANONS_CASTLE:
|
||||||
case SCENE_THIEVES_HIDEOUT:
|
gSaveContext.entranceIndex = dungeonEntrances[gSaveContext.savedSceneNum];
|
||||||
case SCENE_INSIDE_GANONS_CASTLE:
|
break;
|
||||||
gSaveContext.entranceIndex = dungeonEntrances[gSaveContext.savedSceneNum];
|
case SCENE_DEKU_TREE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0;
|
||||||
case SCENE_DEKU_TREE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0;
|
case SCENE_DODONGOS_CAVERN_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 4;
|
||||||
case SCENE_DODONGOS_CAVERN_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 4;
|
case SCENE_JABU_JABU_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x28;
|
||||||
case SCENE_JABU_JABU_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x28;
|
case SCENE_FOREST_TEMPLE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x169;
|
||||||
case SCENE_FOREST_TEMPLE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x169;
|
case SCENE_FIRE_TEMPLE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x165;
|
||||||
case SCENE_FIRE_TEMPLE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x165;
|
case SCENE_WATER_TEMPLE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x10;
|
||||||
case SCENE_WATER_TEMPLE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x10;
|
case SCENE_SPIRIT_TEMPLE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x82;
|
||||||
case SCENE_SPIRIT_TEMPLE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x82;
|
case SCENE_SHADOW_TEMPLE_BOSS:
|
||||||
break;
|
gSaveContext.entranceIndex = 0x37;
|
||||||
case SCENE_SHADOW_TEMPLE_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x37;
|
case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR:
|
||||||
break;
|
case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE:
|
||||||
case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR:
|
case SCENE_GANONDORF_BOSS:
|
||||||
case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE:
|
case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR:
|
||||||
case SCENE_GANONDORF_BOSS:
|
case SCENE_GANON_BOSS:
|
||||||
case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR:
|
gSaveContext.entranceIndex = 0x41B;
|
||||||
case SCENE_GANON_BOSS:
|
break;
|
||||||
gSaveContext.entranceIndex = 0x41B;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (gSaveContext.savedSceneNum != SCENE_LINKS_HOUSE) {
|
// Use the saved entrance value with remember save location, except when in grottos/fairy fountains
|
||||||
gSaveContext.entranceIndex = (LINK_AGE_IN_YEARS == YEARS_CHILD) ? 0xBB : 0x5F4;
|
if (CVarGetInteger("gRememberSaveLocation", 0) && gSaveContext.savedSceneNum != SCENE_FAIRYS_FOUNTAIN &&
|
||||||
} else {
|
gSaveContext.savedSceneNum != SCENE_GROTTOS) {
|
||||||
gSaveContext.entranceIndex = 0xBB;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gSaveContext.savedSceneNum != SCENE_LINKS_HOUSE) {
|
||||||
|
gSaveContext.entranceIndex = (LINK_AGE_IN_YEARS == YEARS_CHILD) ? 0xBB : 0x5F4;
|
||||||
|
} else {
|
||||||
|
gSaveContext.entranceIndex = 0xBB;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
|
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
|
||||||
|
|||||||
@@ -10,10 +10,6 @@
|
|||||||
#include <stdlib.h> // malloc
|
#include <stdlib.h> // malloc
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
// OTRTODO: Replace usage of this method when we can clear the cache
|
|
||||||
// for a single texture without the need of a DL opcode in the render code
|
|
||||||
void gfx_texture_cache_clear();
|
|
||||||
|
|
||||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||||
|
|
||||||
#define LAVA_TEX_WIDTH 32
|
#define LAVA_TEX_WIDTH 32
|
||||||
@@ -69,7 +65,7 @@ static u8 sMaskTex16x32[16 * 32] = { { 0 } };
|
|||||||
static u8 sMaskTex32x16[32 * 16] = { { 0 } };
|
static u8 sMaskTex32x16[32 * 16] = { { 0 } };
|
||||||
static u8 sMaskTex8x8[8 * 8] = { { 0 } };
|
static u8 sMaskTex8x8[8 * 8] = { { 0 } };
|
||||||
static u8 sMaskTex8x32[8 * 32] = { { 0 } };
|
static u8 sMaskTex8x32[8 * 32] = { { 0 } };
|
||||||
static u8 sMaskTexLava[32 * 64] = { { 0 } };
|
static u8 sMaskTexLava[LAVA_TEX_WIDTH * LAVA_TEX_HEIGHT] = { { 0 } };
|
||||||
|
|
||||||
static u32* sLavaFloorModifiedTexRaw = NULL;
|
static u32* sLavaFloorModifiedTexRaw = NULL;
|
||||||
static u32* sLavaWavyTexRaw = NULL;
|
static u32* sLavaWavyTexRaw = NULL;
|
||||||
@@ -112,6 +108,22 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() {
|
|||||||
u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
|
u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
|
||||||
size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex);
|
size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex);
|
||||||
size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex);
|
size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex);
|
||||||
|
size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex);
|
||||||
|
|
||||||
|
// If the sizes don't match, then don't bother with the blended effect to avoid crashing
|
||||||
|
if (floorSize != lavaSize || floorSize != rockSize) {
|
||||||
|
uint8_t maskVal = !!Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num);
|
||||||
|
|
||||||
|
if (sMaskTexLava[0] != maskVal) {
|
||||||
|
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
||||||
|
sMaskTexLava[i] = maskVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, NULL);
|
||||||
|
Gfx_TextureCacheDelete(sMaskTexLava);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sLavaFloorModifiedTexRaw = malloc(lavaSize);
|
sLavaFloorModifiedTexRaw = malloc(lavaSize);
|
||||||
sLavaWavyTexRaw = malloc(floorSize);
|
sLavaWavyTexRaw = malloc(floorSize);
|
||||||
@@ -121,7 +133,6 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() {
|
|||||||
// When KD is dead, just immediately copy the rock texture
|
// When KD is dead, just immediately copy the rock texture
|
||||||
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
|
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
|
||||||
u32* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
u32* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
||||||
size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex);
|
|
||||||
memcpy(sLavaFloorModifiedTexRaw, rockTex, rockSize);
|
memcpy(sLavaFloorModifiedTexRaw, rockTex, rockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +156,16 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() {
|
|||||||
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTex);
|
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTex);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_texture_cache_clear();
|
// Set all true for the lava as it will always replace the scene texture
|
||||||
|
if (sMaskTexLava[0] == 0) {
|
||||||
|
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
||||||
|
sMaskTexLava[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx_TextureCacheDelete(sMaskTexLava);
|
||||||
|
Gfx_TextureCacheDelete(sLavaWavyTex);
|
||||||
|
Gfx_TextureCacheDelete(sLavaFloorModifiedTex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_808C12C4(u8* arg1, s16 arg2) {
|
void func_808C12C4(u8* arg1, s16 arg2) {
|
||||||
@@ -170,6 +190,11 @@ void func_808C12C4(u8* arg1, s16 arg2) {
|
|||||||
|
|
||||||
// Same as func_808C1554 but works with u32 values for RGBA32 raw textures
|
// Same as func_808C1554 but works with u32 values for RGBA32 raw textures
|
||||||
void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||||
|
// Raw lava not registered, so abort the wave modification
|
||||||
|
if (sLavaWavyTexRaw == NULL || sLavaFloorModifiedTexRaw == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
u16 width = ResourceGetTexWidthByName(arg0);
|
u16 width = ResourceGetTexWidthByName(arg0);
|
||||||
s32 size = ResourceGetTexHeightByName(arg0) * width;
|
s32 size = ResourceGetTexHeightByName(arg0) * width;
|
||||||
|
|
||||||
@@ -203,9 +228,7 @@ void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(sp54);
|
free(sp54);
|
||||||
|
Gfx_TextureCacheDelete(sLavaWavyTexRaw);
|
||||||
// Need to clear the cache after updating sLavaWavyTexRaw
|
|
||||||
gfx_texture_cache_clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modified to support CPU modified texture with the resource system
|
// Modified to support CPU modified texture with the resource system
|
||||||
@@ -234,8 +257,7 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to clear the cache after updating sLavaWavyTex
|
Gfx_TextureCacheDelete(sLavaWavyTex);
|
||||||
gfx_texture_cache_clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) {
|
void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) {
|
||||||
@@ -325,7 +347,7 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
|||||||
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
||||||
|
|
||||||
// #region SOH [General]
|
// #region SOH [General]
|
||||||
// Init mask values for all blended textures
|
// Init mask values for all KD blended textures
|
||||||
for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) {
|
for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) {
|
||||||
sMaskTex8x16[i] = 0;
|
sMaskTex8x16[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -341,10 +363,6 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
|||||||
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
|
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
|
||||||
sMaskTex32x16[i] = 0;
|
sMaskTex32x16[i] = 0;
|
||||||
}
|
}
|
||||||
// Set all true for the lava as it will always replace the scene texture
|
|
||||||
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
|
||||||
sMaskTexLava[i] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register all blended textures
|
// Register all blended textures
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL);
|
||||||
@@ -358,6 +376,13 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
|||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
|
||||||
|
|
||||||
|
// Clear cache for masks
|
||||||
|
Gfx_TextureCacheDelete(sMaskTex8x16);
|
||||||
|
Gfx_TextureCacheDelete(sMaskTex8x32);
|
||||||
|
Gfx_TextureCacheDelete(sMaskTex16x16);
|
||||||
|
Gfx_TextureCacheDelete(sMaskTex16x32);
|
||||||
|
Gfx_TextureCacheDelete(sMaskTex32x16);
|
||||||
|
|
||||||
BossDodongo_RegisterBlendedLavaTextureUpdate();
|
BossDodongo_RegisterBlendedLavaTextureUpdate();
|
||||||
|
|
||||||
// Register alt listener to update the blended lava for the replacement texture based on alt path
|
// Register alt listener to update the blended lava for the replacement texture based on alt path
|
||||||
@@ -1174,15 +1199,24 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) {
|
|||||||
|
|
||||||
for (i2 = 0; i2 < 20; i2++) {
|
for (i2 = 0; i2 < 20; i2++) {
|
||||||
s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1);
|
s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1);
|
||||||
// Compute the index to a scaled position (scaling pseudo x,y as a 1D value)
|
|
||||||
s32 indexStart = ((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale);
|
|
||||||
|
|
||||||
// From the starting index, apply extra pixels right/down based on the scale
|
// Raw lava must be registered, otherwise skip the effect for incompatible texture pack
|
||||||
for (size_t j = 0; j < heightScale; j++) {
|
// and instead set the mask to simulate the lava disappearing by turning black
|
||||||
for (size_t i3 = 0; i3 < widthScale; i3++) {
|
if (sLavaFloorModifiedTexRaw != NULL) {
|
||||||
s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1);
|
// Compute the index to a scaled position (scaling pseudo x,y as a 1D value)
|
||||||
ptr1[scaledIndex] = ptr2[scaledIndex];
|
s32 indexStart =
|
||||||
|
((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale);
|
||||||
|
|
||||||
|
// From the starting index, apply extra pixels right/down based on the scale
|
||||||
|
for (size_t j = 0; j < heightScale; j++) {
|
||||||
|
for (size_t i3 = 0; i3 < widthScale; i3++) {
|
||||||
|
s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1);
|
||||||
|
ptr1[scaledIndex] = ptr2[scaledIndex];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sMaskTexLava[new_var] = 1;
|
||||||
|
Gfx_TextureCacheDelete(sMaskTexLava);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->unk_1C2 += 37;
|
this->unk_1C2 += 37;
|
||||||
@@ -1254,6 +1288,10 @@ block_1:
|
|||||||
if (*dList != NULL) {
|
if (*dList != NULL) {
|
||||||
OPEN_DISPS(play->state.gfxCtx);
|
OPEN_DISPS(play->state.gfxCtx);
|
||||||
|
|
||||||
|
if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
|
||||||
|
}
|
||||||
|
|
||||||
mtxScaleZ = 1.0f;
|
mtxScaleZ = 1.0f;
|
||||||
mtxScaleY = 1.0f;
|
mtxScaleY = 1.0f;
|
||||||
|
|
||||||
@@ -1274,11 +1312,20 @@ block_1:
|
|||||||
Matrix_RotateX(-(this->unk_25C[limbIndex] * 0.115f), MTXMODE_APPLY);
|
Matrix_RotateX(-(this->unk_25C[limbIndex] * 0.115f), MTXMODE_APPLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD);
|
||||||
|
} else {
|
||||||
|
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
||||||
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
||||||
Matrix_Pop();
|
Matrix_Pop();
|
||||||
|
|
||||||
|
if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
(*play->flexLimbOverrideMTX)++;
|
||||||
|
}
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
{ s32 pad; } // Required to match
|
{ s32 pad; } // Required to match
|
||||||
@@ -1322,10 +1369,6 @@ void BossDodongo_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16);
|
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTex32x16);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->unk_1C6 != 0) {
|
|
||||||
gSPInvalidateTexCache(POLY_OPA_DISP++, sMaskTexLava);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) {
|
if ((this->unk_1C0 >= 2) && (this->unk_1C0 & 1)) {
|
||||||
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099);
|
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 255, 255, 0, 900, 1099);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2015,12 +2015,26 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f
|
|||||||
Matrix_TranslateRotateZYX(pos, rot);
|
Matrix_TranslateRotateZYX(pos, rot);
|
||||||
|
|
||||||
if (*dList != NULL) {
|
if (*dList != NULL) {
|
||||||
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
|
||||||
|
}
|
||||||
|
|
||||||
Matrix_Push();
|
Matrix_Push();
|
||||||
Matrix_Scale(this->eyeIrisScaleX, this->eyeIrisScaleY, 1.0f, MTXMODE_APPLY);
|
Matrix_Scale(this->eyeIrisScaleX, this->eyeIrisScaleY, 1.0f, MTXMODE_APPLY);
|
||||||
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
|
||||||
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD);
|
||||||
|
} else {
|
||||||
|
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
||||||
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
||||||
Matrix_Pop();
|
Matrix_Pop();
|
||||||
|
|
||||||
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
(*play->flexLimbOverrideMTX)++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doNotDrawLimb = true;
|
doNotDrawLimb = true;
|
||||||
@@ -2034,14 +2048,28 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f
|
|||||||
Matrix_TranslateRotateZYX(pos, rot);
|
Matrix_TranslateRotateZYX(pos, rot);
|
||||||
|
|
||||||
if (*dList != NULL) {
|
if (*dList != NULL) {
|
||||||
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
|
||||||
|
}
|
||||||
|
|
||||||
Matrix_Push();
|
Matrix_Push();
|
||||||
Matrix_Scale(this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
|
Matrix_Scale(this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
|
||||||
this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
|
this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
|
||||||
this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4], MTXMODE_APPLY);
|
this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4], MTXMODE_APPLY);
|
||||||
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
|
||||||
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD);
|
||||||
|
} else {
|
||||||
|
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
||||||
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
gSPDisplayList(POLY_OPA_DISP++, *dList);
|
||||||
Matrix_Pop();
|
Matrix_Pop();
|
||||||
|
|
||||||
|
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
|
||||||
|
(*play->flexLimbOverrideMTX)++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doNotDrawLimb = true;
|
doNotDrawLimb = true;
|
||||||
|
|||||||
@@ -192,11 +192,11 @@ void DemoGj_Explode(DemoGj* this, PlayState* play, Vec3f* initialPos, Vec3f* dir
|
|||||||
phi_s0 = 0x21;
|
phi_s0 = 0x21;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gfx* gfx = ResourceMgr_LoadGfxByName(gGanonRubbleDL);
|
// SoH [Port] Changed from &gGanonsCastleRubbleAroundArenaDL[28] to gGanonRubbleDL as it seems this was an error in the original rom/decomp
|
||||||
|
// Other calls to EffectSsKakera_Spawn with OBJECT_GEFF use gGanonRubbleDL, so this change is to match that
|
||||||
EffectSsKakera_Spawn(play, &explosionPos, &velocity, initialPos, -200, phi_s0, 10, 10, 0,
|
EffectSsKakera_Spawn(play, &explosionPos, &velocity, initialPos, -200, phi_s0, 10, 10, 0,
|
||||||
Rand_ZeroOne() * 20.0f + 20.0f, 20, 300, (s32)(Rand_ZeroOne() * 30.0f) + 30, -1,
|
Rand_ZeroOne() * 20.0f + 20.0f, 20, 300, (s32)(Rand_ZeroOne() * 30.0f) + 30, -1,
|
||||||
OBJECT_GEFF, gfx);
|
OBJECT_GEFF, gGanonRubbleDL);
|
||||||
|
|
||||||
theta += 0x2AAA;
|
theta += 0x2AAA;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1055,7 +1055,7 @@ void DoorWarp1_DrawBlueCrystal(DoorWarp1* this, PlayState* play) {
|
|||||||
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (u8)this->crystalAlpha);
|
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (u8)this->crystalAlpha);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, (u8)this->crystalAlpha);
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, (u8)this->crystalAlpha);
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, NULL,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, NULL, NULL,
|
||||||
&this->actor, POLY_XLU_DISP);
|
&this->actor, POLY_XLU_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
@@ -1079,7 +1079,7 @@ void DoorWarp1_DrawPurpleCrystal(DoorWarp1* this, PlayState* play) {
|
|||||||
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (u8)this->crystalAlpha);
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (u8)this->crystalAlpha);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 150, 0, 100, (u8)this->crystalAlpha);
|
gDPSetEnvColor(POLY_XLU_DISP++, 150, 0, 100, (u8)this->crystalAlpha);
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, NULL,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, NULL, NULL,
|
||||||
&this->actor, POLY_XLU_DISP);
|
&this->actor, POLY_XLU_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -768,7 +768,7 @@ void EnBili_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPSegment(POLY_XLU_DISP++, 0x09, D_809C1700);
|
gSPSegment(POLY_XLU_DISP++, 0x09, D_809C1700);
|
||||||
}
|
}
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnBili_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
EnBili_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ static InitChainEntry sInitChain[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static UNK_TYPE sUnused;
|
static UNK_TYPE sUnused;
|
||||||
GetItemEntry sItem;
|
|
||||||
|
|
||||||
Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0};
|
Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0};
|
||||||
Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0};
|
Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0};
|
||||||
@@ -472,7 +471,7 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) {
|
|||||||
func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos);
|
func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos);
|
||||||
if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f &&
|
if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f &&
|
||||||
Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) {
|
Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) {
|
||||||
sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F);
|
GetItemEntry sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, play->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F);
|
||||||
GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE);
|
GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE);
|
||||||
|
|
||||||
// RANDOTODO treasure chest game rando
|
// RANDOTODO treasure chest game rando
|
||||||
@@ -628,7 +627,7 @@ void EnBox_Update(Actor* thisx, PlayState* play) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (((!IS_RANDO && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) ||
|
if (((!IS_RANDO && ((this->dyna.actor.params >> 5 & 0x7F) == 0x7C)) ||
|
||||||
(IS_RANDO && ABS(sItem.getItemId) == RG_ICE_TRAP)) &&
|
(IS_RANDO && this->getItemEntry.getItemId == RG_ICE_TRAP)) &&
|
||||||
this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) {
|
this->actionFunc == EnBox_Open && this->skelanime.curFrame > 45 && this->iceSmokeTimer < 100) {
|
||||||
if (!CVarGetInteger("gAddTraps.enabled", 0)) {
|
if (!CVarGetInteger("gAddTraps.enabled", 0)) {
|
||||||
EnBox_SpawnIceSmoke(this, play);
|
EnBox_SpawnIceSmoke(this, play);
|
||||||
@@ -948,7 +947,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
|
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, EnBox_EmptyDList(play->state.gfxCtx));
|
gSPSegment(POLY_OPA_DISP++, 0x08, EnBox_EmptyDList(play->state.gfxCtx));
|
||||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, NULL,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, NULL,
|
||||||
EnBox_PostLimbDraw, this, POLY_OPA_DISP);
|
EnBox_PostLimbDraw, this, POLY_OPA_DISP);
|
||||||
} else if (this->alpha != 0) {
|
} else if (this->alpha != 0) {
|
||||||
gDPPipeSync(POLY_XLU_DISP++);
|
gDPPipeSync(POLY_XLU_DISP++);
|
||||||
@@ -959,7 +958,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) {
|
|||||||
} else {
|
} else {
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08, func_809CA4A0(play->state.gfxCtx));
|
gSPSegment(POLY_XLU_DISP++, 0x08, func_809CA4A0(play->state.gfxCtx));
|
||||||
}
|
}
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, NULL,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, NULL,
|
||||||
EnBox_PostLimbDraw, this, POLY_XLU_DISP);
|
EnBox_PostLimbDraw, this, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -856,7 +856,7 @@ void EnBw_Draw(Actor* thisx, PlayState* play2) {
|
|||||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||||
gDPSetEnvColor(POLY_OPA_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
|
gDPSetEnvColor(POLY_OPA_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnBw_OverrideLimbDraw, NULL, this, POLY_OPA_DISP);
|
EnBw_OverrideLimbDraw, NULL, this, POLY_OPA_DISP);
|
||||||
} else {
|
} else {
|
||||||
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
||||||
@@ -864,7 +864,7 @@ void EnBw_Draw(Actor* thisx, PlayState* play2) {
|
|||||||
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 0, 0, 0, this->color1.a);
|
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 0, 0, 0, this->color1.a);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
|
gDPSetEnvColor(POLY_XLU_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]);
|
gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]);
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnBw_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
EnBw_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ void EnDntJiji_Destroy(Actor* thisx, PlayState* play) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EnDntJiji_SetFlower(EnDntJiji* this, PlayState* play) {
|
void EnDntJiji_SetFlower(EnDntJiji* this, PlayState* play) {
|
||||||
|
// SOH: Due to removed object dependencies, parent was still NULL when Init was called. In order to properly set
|
||||||
|
// stage, redo it here now that we are a frame later.
|
||||||
|
this->stage = (EnDntDemo*)this->actor.parent;
|
||||||
if (this->actor.bgCheckFlags & 1) {
|
if (this->actor.bgCheckFlags & 1) {
|
||||||
this->flowerPos = this->actor.world.pos;
|
this->flowerPos = this->actor.world.pos;
|
||||||
this->actionFunc = EnDntJiji_SetupWait;
|
this->actionFunc = EnDntJiji_SetupWait;
|
||||||
|
|||||||
@@ -708,14 +708,14 @@ void EnEiyer_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
||||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255);
|
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255);
|
||||||
|
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime,
|
||||||
EnEiyer_OverrideLimbDraw, NULL, this, POLY_OPA_DISP);
|
EnEiyer_OverrideLimbDraw, NULL, this, POLY_OPA_DISP);
|
||||||
} else {
|
} else {
|
||||||
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280);
|
gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha);
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha);
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime,
|
||||||
EnEiyer_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
EnEiyer_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -1540,7 +1540,7 @@ void EnElf_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPEndDisplayList(dListHead++);
|
gSPEndDisplayList(dListHead++);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
|
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
|
||||||
(u8)(envAlpha * alphaScale));
|
(u8)(envAlpha * alphaScale));
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnElf_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
EnElf_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -837,8 +837,9 @@ void EnFirefly_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
|
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw,
|
||||||
EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, &this->actor, POLY_OPA_DISP);
|
&this->actor, POLY_OPA_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +855,7 @@ void EnFirefly_DrawInvisible(Actor* thisx, PlayState* play) {
|
|||||||
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 255);
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, this, POLY_XLU_DISP);
|
EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, this, POLY_XLU_DISP);
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1027,8 +1027,8 @@ void EnGirlA_BuyEvent_ObtainBombchuPack(PlayState* play, EnGirlA* this) {
|
|||||||
Rupees_ChangeBy(-this->basePrice);
|
Rupees_ChangeBy(-this->basePrice);
|
||||||
|
|
||||||
// Normally, buying a bombchu pack sets a flag indicating the pack is now sold out
|
// Normally, buying a bombchu pack sets a flag indicating the pack is now sold out
|
||||||
// If they're in logic for rando, skip setting that flag so they can be purchased repeatedly
|
// If we're in rando, skip setting that flag so they can be purchased repeatedly
|
||||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC)) {
|
if (IS_RANDO) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,8 +1255,7 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, PlayState* play) {
|
|||||||
this->itemGiveFunc = itemEntry->itemGiveFunc;
|
this->itemGiveFunc = itemEntry->itemGiveFunc;
|
||||||
this->buyEventFunc = itemEntry->buyEventFunc;
|
this->buyEventFunc = itemEntry->buyEventFunc;
|
||||||
// If chus are in logic, make the 10 pack affordable without a wallet upgrade
|
// If chus are in logic, make the 10 pack affordable without a wallet upgrade
|
||||||
if (IS_RANDO && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) &&
|
if (IS_RANDO && this->getItemId == GI_BOMBCHUS_10) {
|
||||||
this->getItemId == GI_BOMBCHUS_10) {
|
|
||||||
this->basePrice = 99;
|
this->basePrice = 99;
|
||||||
} else {
|
} else {
|
||||||
this->basePrice = itemEntry->price;
|
this->basePrice = itemEntry->price;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "objects/object_tite/object_tite.h"
|
#include "objects/object_tite/object_tite.h"
|
||||||
#include "objects/object_ik/object_ik.h"
|
#include "objects/object_ik/object_ik.h"
|
||||||
|
|
||||||
|
#include <string.h> // strcmp
|
||||||
|
|
||||||
#define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED
|
#define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED
|
||||||
|
|
||||||
void EnPart_Init(Actor* thisx, PlayState* play);
|
void EnPart_Init(Actor* thisx, PlayState* play);
|
||||||
@@ -297,11 +299,11 @@ void EnPart_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPSegment(POLY_OPA_DISP++, 0x08, func_80ACEAC0(play->state.gfxCtx, 255, 255, 255, 180, 180, 180));
|
gSPSegment(POLY_OPA_DISP++, 0x08, func_80ACEAC0(play->state.gfxCtx, 255, 255, 255, 180, 180, 180));
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x09, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
|
gSPSegment(POLY_OPA_DISP++, 0x09, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x0A, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
|
gSPSegment(POLY_OPA_DISP++, 0x0A, func_80ACEAC0(play->state.gfxCtx, 225, 205, 115, 25, 20, 0));
|
||||||
} else if ((thisx->params == 9) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) {
|
} else if ((thisx->params == 9) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) {
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001300);
|
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001300);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001700);
|
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001700);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_001900);
|
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_001900);
|
||||||
} else if ((thisx->params == 10) && (this->displayList == ResourceMgr_LoadGfxByName(object_tite_DL_002FF0))) {
|
} else if ((thisx->params == 10) && (strcmp((const char*)this->displayList, object_tite_DL_002FF0) == 0)) {
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001B00);
|
gSPSegment(POLY_OPA_DISP++, 0x08, object_tite_Tex_001B00);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001F00);
|
gSPSegment(POLY_OPA_DISP++, 0x09, object_tite_Tex_001F00);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_002100);
|
gSPSegment(POLY_OPA_DISP++, 0x0A, object_tite_Tex_002100);
|
||||||
|
|||||||
@@ -858,7 +858,7 @@ void EnPartner_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gSPEndDisplayList(dListHead++);
|
gSPEndDisplayList(dListHead++);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
|
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
|
||||||
(u8)(envAlpha * alphaScale));
|
(u8)(envAlpha * alphaScale));
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnPartner_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
EnPartner_OverrideLimbDraw, NULL, this, POLY_XLU_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ void EnPoDesert_Draw(Actor* thisx, PlayState* play) {
|
|||||||
} else {
|
} else {
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280 + 2);
|
gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280 + 2);
|
||||||
}
|
}
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnPoDesert_OverrideLimbDraw, EnPoDesert_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
EnPoDesert_OverrideLimbDraw, EnPoDesert_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -944,15 +944,14 @@ void EnPoField_Draw(Actor* thisx, PlayState* play) {
|
|||||||
this->lightColor.a));
|
this->lightColor.a));
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x0C, D_80116280 + 2);
|
gSPSegment(POLY_OPA_DISP++, 0x0C, D_80116280 + 2);
|
||||||
POLY_OPA_DISP =
|
POLY_OPA_DISP =
|
||||||
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_OPA_DISP);
|
EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_OPA_DISP);
|
||||||
} else {
|
} else {
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08,
|
gSPSegment(POLY_XLU_DISP++, 0x08,
|
||||||
Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b,
|
Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b,
|
||||||
this->lightColor.a));
|
this->lightColor.a));
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280);
|
gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280);
|
||||||
POLY_XLU_DISP =
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
|
||||||
EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_XLU_DISP);
|
EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
gDPPipeSync(POLY_OPA_DISP++);
|
gDPPipeSync(POLY_OPA_DISP++);
|
||||||
|
|||||||
@@ -1373,14 +1373,12 @@ void EnPoSisters_Draw(Actor* thisx, PlayState* play) {
|
|||||||
if (this->unk_22E.a == 255 || this->unk_22E.a == 0) {
|
if (this->unk_22E.a == 255 || this->unk_22E.a == 0) {
|
||||||
gDPSetEnvColor(POLY_OPA_DISP++, this->unk_22E.r, this->unk_22E.g, this->unk_22E.b, this->unk_22E.a);
|
gDPSetEnvColor(POLY_OPA_DISP++, this->unk_22E.r, this->unk_22E.g, this->unk_22E.b, this->unk_22E.a);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x09, D_80116280 + 2);
|
gSPSegment(POLY_OPA_DISP++, 0x09, D_80116280 + 2);
|
||||||
POLY_OPA_DISP =
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoSisters_OverrideLimbDraw,
|
||||||
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP);
|
||||||
EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP);
|
|
||||||
} else {
|
} else {
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->unk_22E.a);
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->unk_22E.a);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x09, D_80116280);
|
gSPSegment(POLY_XLU_DISP++, 0x09, D_80116280);
|
||||||
POLY_XLU_DISP =
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
|
||||||
EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
if (!(this->unk_199 & 0x80)) {
|
if (!(this->unk_199 & 0x80)) {
|
||||||
|
|||||||
@@ -1085,12 +1085,12 @@ void EnPoh_DrawRegular(Actor* thisx, PlayState* play) {
|
|||||||
if (this->lightColor.a == 255 || this->lightColor.a == 0) {
|
if (this->lightColor.a == 255 || this->lightColor.a == 0) {
|
||||||
gDPSetEnvColor(POLY_OPA_DISP++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a);
|
gDPSetEnvColor(POLY_OPA_DISP++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, D_80116280 + 2);
|
gSPSegment(POLY_OPA_DISP++, 0x08, D_80116280 + 2);
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_OPA_DISP);
|
EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_OPA_DISP);
|
||||||
} else {
|
} else {
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->lightColor.a);
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->lightColor.a);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280);
|
gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280);
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
gDPPipeSync(POLY_OPA_DISP++);
|
gDPPipeSync(POLY_OPA_DISP++);
|
||||||
|
|||||||
@@ -821,19 +821,6 @@ void func_80AF3F20(EnRu2* this, PlayState* play) {
|
|||||||
void EnRu2_Draw(Actor* thisx, PlayState* play) {
|
void EnRu2_Draw(Actor* thisx, PlayState* play) {
|
||||||
EnRu2* this = (EnRu2*)thisx;
|
EnRu2* this = (EnRu2*)thisx;
|
||||||
|
|
||||||
// FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings.
|
|
||||||
// Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so
|
|
||||||
// it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the
|
|
||||||
// earring texture loads into the same place in tmem as the brick texture, so when it comes to rendering, TEXEL1
|
|
||||||
// uses the earring texture with diffrent clamp settings, and it displays without noticeable error. However, both
|
|
||||||
// texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses
|
|
||||||
// our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces
|
|
||||||
// TEXEL1 with TEXEL0, which is most likely the original intention, and all is well.
|
|
||||||
Gfx* gfx = ResourceMgr_LoadGfxByName(gAdultRutoHeadDL);
|
|
||||||
Gfx patch = gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, TEXEL0, 0,
|
|
||||||
PRIM_LOD_FRAC, COMBINED);
|
|
||||||
gfx[0xA2] = patch;
|
|
||||||
|
|
||||||
if ((this->drawConfig < 0) || (this->drawConfig >= ARRAY_COUNT(sDrawFuncs)) ||
|
if ((this->drawConfig < 0) || (this->drawConfig >= ARRAY_COUNT(sDrawFuncs)) ||
|
||||||
(sDrawFuncs[this->drawConfig] == 0)) {
|
(sDrawFuncs[this->drawConfig] == 0)) {
|
||||||
// "Draw Mode is improper!"
|
// "Draw Mode is improper!"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ void EnSi_Init(Actor* thisx, PlayState* play);
|
|||||||
void EnSi_Destroy(Actor* thisx, PlayState* play);
|
void EnSi_Destroy(Actor* thisx, PlayState* play);
|
||||||
void EnSi_Update(Actor* thisx, PlayState* play);
|
void EnSi_Update(Actor* thisx, PlayState* play);
|
||||||
void EnSi_Draw(Actor* thisx, PlayState* play);
|
void EnSi_Draw(Actor* thisx, PlayState* play);
|
||||||
|
void EnSi_Reset();
|
||||||
|
|
||||||
s32 func_80AFB748(EnSi* this, PlayState* play);
|
s32 func_80AFB748(EnSi* this, PlayState* play);
|
||||||
void func_80AFB768(EnSi* this, PlayState* play);
|
void func_80AFB768(EnSi* this, PlayState* play);
|
||||||
@@ -61,7 +62,7 @@ const ActorInit En_Si_InitVars = {
|
|||||||
(ActorFunc)EnSi_Destroy,
|
(ActorFunc)EnSi_Destroy,
|
||||||
(ActorFunc)EnSi_Update,
|
(ActorFunc)EnSi_Update,
|
||||||
(ActorFunc)EnSi_Draw,
|
(ActorFunc)EnSi_Draw,
|
||||||
NULL,
|
(ActorResetFunc)EnSi_Reset,
|
||||||
};
|
};
|
||||||
|
|
||||||
void EnSi_Init(Actor* thisx, PlayState* play) {
|
void EnSi_Init(Actor* thisx, PlayState* play) {
|
||||||
@@ -224,6 +225,11 @@ void EnSi_Draw(Actor* thisx, PlayState* play) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnSi_Reset() {
|
||||||
|
textId = 0xB4;
|
||||||
|
giveItemId = ITEM_SKULL_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
void Randomizer_UpdateSkullReward(EnSi* this, PlayState* play) {
|
void Randomizer_UpdateSkullReward(EnSi* this, PlayState* play) {
|
||||||
Player* player = GET_PLAYER(play);
|
Player* player = GET_PLAYER(play);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h"
|
#include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h"
|
||||||
#include "objects/object_ossan/object_ossan.h"
|
#include "objects/object_ossan/object_ossan.h"
|
||||||
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
||||||
|
#include "soh/Enhancements/custom-message/CustomMessageTypes.h"
|
||||||
|
|
||||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON)
|
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_NO_LOCKON)
|
||||||
|
|
||||||
@@ -371,7 +372,8 @@ void EnSyatekiMan_EndGame(EnSyatekiMan* this, PlayState* play) {
|
|||||||
this->getItemId = GI_RUPEE_PURPLE;
|
this->getItemId = GI_RUPEE_PURPLE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(IS_RANDO && !Flags_GetTreasure(play, 0x1F)) {
|
// Only give the adult rando reward when the player has a quiver
|
||||||
|
if (IS_RANDO && !Flags_GetTreasure(play, 0x1F) && CUR_UPG_VALUE(UPG_QUIVER) > 0) {
|
||||||
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_SHOOTING_GALLERY_REWARD, GI_QUIVER_50);
|
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_SHOOTING_GALLERY_REWARD, GI_QUIVER_50);
|
||||||
this->getItemId = this->getItemEntry.getItemId;
|
this->getItemId = this->getItemEntry.getItemId;
|
||||||
Flags_SetTreasure(play, 0x1F);
|
Flags_SetTreasure(play, 0x1F);
|
||||||
@@ -448,6 +450,9 @@ void EnSyatekiMan_FinishPrize(EnSyatekiMan* this, PlayState* play) {
|
|||||||
Flags_SetItemGetInf(ITEMGETINF_0D);
|
Flags_SetItemGetInf(ITEMGETINF_0D);
|
||||||
} else if ((this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)) {
|
} else if ((this->getItemId == GI_QUIVER_40) || (this->getItemId == GI_QUIVER_50)) {
|
||||||
Flags_SetItemGetInf(ITEMGETINF_0E);
|
Flags_SetItemGetInf(ITEMGETINF_0E);
|
||||||
|
} else if (IS_RANDO && LINK_IS_ADULT && CUR_UPG_VALUE(UPG_QUIVER) == 0) {
|
||||||
|
// In Rando without a quiver, display a message reminding the player to come back with a bow
|
||||||
|
Message_StartTextbox(play, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW, NULL);
|
||||||
}
|
}
|
||||||
this->gameResult = SYATEKI_RESULT_NONE;
|
this->gameResult = SYATEKI_RESULT_NONE;
|
||||||
this->actor.parent = this->tempGallery;
|
this->actor.parent = this->tempGallery;
|
||||||
|
|||||||
@@ -814,7 +814,7 @@ void EnVali_Draw(Actor* thisx, PlayState* play) {
|
|||||||
|
|
||||||
EnVali_DrawBody(this, play);
|
EnVali_DrawBody(this, play);
|
||||||
|
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnVali_OverrideLimbDraw, EnVali_PostLimbDraw, this, POLY_XLU_DISP);
|
EnVali_OverrideLimbDraw, EnVali_PostLimbDraw, this, POLY_XLU_DISP);
|
||||||
|
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -640,13 +640,13 @@ void EnWeiyer_Draw(Actor* thisx, PlayState* play) {
|
|||||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
|
||||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255);
|
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255);
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnWeiyer_OverrideLimbDraw, NULL, &this->actor,
|
||||||
EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_OPA_DISP);
|
POLY_OPA_DISP);
|
||||||
} else {
|
} else {
|
||||||
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]);
|
gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha);
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha);
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_XLU_DISP);
|
EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,13 +101,18 @@ static f32 sSpawnSin;
|
|||||||
s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* pos) {
|
s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* pos) {
|
||||||
f32 phi_f12;
|
f32 phi_f12;
|
||||||
|
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, pos, &this->actor.projectedPos,
|
SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, pos, &this->actor.projectedPos,
|
||||||
&this->actor.projectedW);
|
&this->actor.projectedW);
|
||||||
|
|
||||||
|
// #region SOH [Enhancement] Use the extended culling calculation
|
||||||
|
if (CVarGetInteger("gDisableDrawDistance", 0) || CVarGetInteger("gEnhancements.WidescreenActorCulling", 0)) {
|
||||||
|
bool shipShouldDraw = false;
|
||||||
|
bool shipShouldUpdate = false;
|
||||||
|
return Ship_CalcShouldDrawAndUpdate(play, &this->actor, &this->actor.projectedPos, this->actor.projectedW,
|
||||||
|
&shipShouldDraw, &shipShouldUpdate);
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
phi_f12 = ((this->actor.projectedW == 0.0f) ? 1000.0f : fabsf(1.0f / this->actor.projectedW));
|
phi_f12 = ((this->actor.projectedW == 0.0f) ? 1000.0f : fabsf(1.0f / this->actor.projectedW));
|
||||||
|
|
||||||
if ((-this->actor.uncullZoneScale < this->actor.projectedPos.z) &&
|
if ((-this->actor.uncullZoneScale < this->actor.projectedPos.z) &&
|
||||||
|
|||||||
@@ -2252,7 +2252,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->alpha);
|
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->alpha);
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x09, &D_80116280[2]);
|
gSPSegment(POLY_OPA_DISP++, 0x09, &D_80116280[2]);
|
||||||
|
|
||||||
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_OPA_DISP);
|
EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_OPA_DISP);
|
||||||
|
|
||||||
if (this->iceTimer != 0) {
|
if (this->iceTimer != 0) {
|
||||||
@@ -2271,7 +2271,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) {
|
|||||||
gDPPipeSync(POLY_XLU_DISP++);
|
gDPPipeSync(POLY_XLU_DISP++);
|
||||||
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha);
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha);
|
||||||
gSPSegment(POLY_XLU_DISP++, 0x09, &D_80116280[0]);
|
gSPSegment(POLY_XLU_DISP++, 0x09, &D_80116280[0]);
|
||||||
POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
|
||||||
EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_XLU_DISP);
|
EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_XLU_DISP);
|
||||||
}
|
}
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
|||||||
@@ -275,7 +275,12 @@ void ObjMure_InitialAction(ObjMure* this, PlayState* play) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ObjMure_CulledState(ObjMure* this, PlayState* play) {
|
void ObjMure_CulledState(ObjMure* this, PlayState* play) {
|
||||||
if (fabsf(this->actor.projectedPos.z) < sZClip[this->type] || CVarGetInteger("gDisableDrawDistance", 0) != 0) {
|
// #region SOH [Enhancements] Extended draw distance
|
||||||
|
s32 distanceMultiplier = CVarGetInteger("gDisableDrawDistance", 1);
|
||||||
|
distanceMultiplier = MAX(distanceMultiplier, 1);
|
||||||
|
|
||||||
|
if (fabsf(this->actor.projectedPos.z) < sZClip[this->type] * distanceMultiplier) {
|
||||||
|
// #endregion
|
||||||
this->actionFunc = ObjMure_ActiveState;
|
this->actionFunc = ObjMure_ActiveState;
|
||||||
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
||||||
ObjMure_SpawnActors(this, play);
|
ObjMure_SpawnActors(this, play);
|
||||||
@@ -398,8 +403,13 @@ static ObjMureActionFunc sTypeGroupBehaviorFunc[] = {
|
|||||||
|
|
||||||
void ObjMure_ActiveState(ObjMure* this, PlayState* play) {
|
void ObjMure_ActiveState(ObjMure* this, PlayState* play) {
|
||||||
ObjMure_CheckChildren(this, play);
|
ObjMure_CheckChildren(this, play);
|
||||||
if (sZClip[this->type] + 40.0f <= fabsf(this->actor.projectedPos.z) &&
|
|
||||||
CVarGetInteger("gDisableDrawDistance", 1) != 0) {
|
// #region SOH [Enhancements] Extended draw distance
|
||||||
|
s32 distanceMultiplier = CVarGetInteger("gDisableDrawDistance", 1);
|
||||||
|
distanceMultiplier = MAX(distanceMultiplier, 1);
|
||||||
|
|
||||||
|
if ((sZClip[this->type] + 40.0f) * distanceMultiplier <= fabsf(this->actor.projectedPos.z)) {
|
||||||
|
// #endregion
|
||||||
this->actionFunc = ObjMure_CulledState;
|
this->actionFunc = ObjMure_CulledState;
|
||||||
this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
||||||
ObjMure_KillActors(this, play);
|
ObjMure_KillActors(this, play);
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ void func_80B9A658(ObjMure2* this) {
|
|||||||
|
|
||||||
void func_80B9A668(ObjMure2* this, PlayState* play) {
|
void func_80B9A668(ObjMure2* this, PlayState* play) {
|
||||||
if (Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z) <
|
if (Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z) <
|
||||||
(sDistSquared1[this->actor.params & 3] * this->unk_184) ||
|
(sDistSquared1[this->actor.params & 3] * this->unk_184)) {
|
||||||
CVarGetInteger("gDisableDrawDistance", 0) != 0) {
|
|
||||||
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
||||||
ObjMure2_SpawnActors(this, play);
|
ObjMure2_SpawnActors(this, play);
|
||||||
func_80B9A6E8(this);
|
func_80B9A6E8(this);
|
||||||
@@ -205,12 +204,8 @@ void func_80B9A6E8(ObjMure2* this) {
|
|||||||
void func_80B9A6F8(ObjMure2* this, PlayState* play) {
|
void func_80B9A6F8(ObjMure2* this, PlayState* play) {
|
||||||
func_80B9A534(this);
|
func_80B9A534(this);
|
||||||
|
|
||||||
if (CVarGetInteger("gDisableDrawDistance", 0) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sDistSquared2[this->actor.params & 3] * this->unk_184) <=
|
if ((sDistSquared2[this->actor.params & 3] * this->unk_184) <=
|
||||||
Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z)) {
|
Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z)) {
|
||||||
this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
||||||
ObjMure2_CleanupAndDie(this, play);
|
ObjMure2_CleanupAndDie(this, play);
|
||||||
func_80B9A658(this);
|
func_80B9A658(this);
|
||||||
@@ -225,5 +220,20 @@ void ObjMure2_Update(Actor* thisx, PlayState* play) {
|
|||||||
} else {
|
} else {
|
||||||
this->unk_184 = 4.0f;
|
this->unk_184 = 4.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOH [Enhancements] Extended draw distance
|
||||||
|
s32 distanceMultiplier = CVarGetInteger("gDisableDrawDistance", 1);
|
||||||
|
if (CVarGetInteger("gEnhancements.WidescreenActorCulling", 0) || distanceMultiplier > 1) {
|
||||||
|
f32 originalAspectRatio = 4.0f / 3.0f;
|
||||||
|
f32 currentAspectRatio = OTRGetAspectRatio();
|
||||||
|
// Adjust ratio difference based on field of view testing
|
||||||
|
f32 ratioAdjusted = 1.0f + (MAX(currentAspectRatio / originalAspectRatio, 1.0f) / 1.5f);
|
||||||
|
// Distance multiplier is squared due to the checks above for squared distances
|
||||||
|
distanceMultiplier = SQ(MAX(distanceMultiplier, 1));
|
||||||
|
|
||||||
|
// Prefer the largest of the three values
|
||||||
|
this->unk_184 = MAX(MAX((f32)distanceMultiplier, ratioAdjusted), this->unk_184);
|
||||||
|
}
|
||||||
|
|
||||||
this->actionFunc(this, play);
|
this->actionFunc(this, play);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10629,7 +10629,14 @@ void Player_UseTunicBoots(Player* this, PlayState* play) {
|
|||||||
s32 i;
|
s32 i;
|
||||||
s32 item;
|
s32 item;
|
||||||
s32 actionParam;
|
s32 actionParam;
|
||||||
if (!(this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED || this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS || this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE || this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN || this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING)) {
|
if (!(
|
||||||
|
this->stateFlags1 & PLAYER_STATE1_INPUT_DISABLED ||
|
||||||
|
this->stateFlags1 & PLAYER_STATE1_IN_ITEM_CS ||
|
||||||
|
this->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE ||
|
||||||
|
this->stateFlags1 & PLAYER_STATE1_TEXT_ON_SCREEN ||
|
||||||
|
this->stateFlags1 & PLAYER_STATE1_DEAD ||
|
||||||
|
this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING
|
||||||
|
)) {
|
||||||
for (i = 0; i < ARRAY_COUNT(D_80854388); i++) {
|
for (i = 0; i < ARRAY_COUNT(D_80854388); i++) {
|
||||||
if (CHECK_BTN_ALL(sControlInput->press.button, D_80854388[i])) {
|
if (CHECK_BTN_ALL(sControlInput->press.button, D_80854388[i])) {
|
||||||
break;
|
break;
|
||||||
@@ -11332,10 +11339,6 @@ void Player_Draw(Actor* thisx, PlayState* play2) {
|
|||||||
lod = 1;
|
lod = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CVarGetInteger("gDisableLOD", 0) != 0) {
|
|
||||||
lod = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
func_80093C80(play);
|
func_80093C80(play);
|
||||||
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
||||||
|
|
||||||
|
|||||||
@@ -1030,18 +1030,18 @@ void FileChoose_UpdateRandomizer() {
|
|||||||
fileSelectSpoilerFileLoaded = false;
|
fileSelectSpoilerFileLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) ||
|
if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) ||
|
||||||
(!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) {
|
(!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) {
|
||||||
if (CVarGetInteger("gNewFileDropped", 0) != 0) {
|
if (CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) {
|
||||||
CVarSetString("gSpoilerLog", CVarGetString("gDroppedFile", "None"));
|
CVarSetString("gSpoilerLog", CVarGetString("gRandomizerDroppedFile", "None"));
|
||||||
}
|
}
|
||||||
bool silent = true;
|
bool silent = true;
|
||||||
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) {
|
if ((CVarGetInteger("gRandomizerNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) {
|
||||||
silent = false;
|
silent = false;
|
||||||
}
|
}
|
||||||
CVarSetInteger("gNewSeedGenerated", 0);
|
CVarSetInteger("gNewSeedGenerated", 0);
|
||||||
CVarSetInteger("gNewFileDropped", 0);
|
CVarSetInteger("gRandomizerNewFileDropped", 0);
|
||||||
CVarSetString("gDroppedFile", "");
|
CVarSetString("gRandomizerDroppedFile", "");
|
||||||
fileSelectSpoilerFileLoaded = false;
|
fileSelectSpoilerFileLoaded = false;
|
||||||
const char* fileLoc = CVarGetString("gSpoilerLog", "");
|
const char* fileLoc = CVarGetString("gSpoilerLog", "");
|
||||||
Randomizer_LoadSettings(fileLoc);
|
Randomizer_LoadSettings(fileLoc);
|
||||||
@@ -1076,7 +1076,6 @@ void FileChoose_UpdateMainMenu(GameState* thisx) {
|
|||||||
Input* input = &this->state.input[0];
|
Input* input = &this->state.input[0];
|
||||||
bool dpad = CVarGetInteger("gDpadText", 0);
|
bool dpad = CVarGetInteger("gDpadText", 0);
|
||||||
|
|
||||||
SoH_ProcessDroppedFiles();
|
|
||||||
FileChoose_UpdateRandomizer();
|
FileChoose_UpdateRandomizer();
|
||||||
|
|
||||||
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
|
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
|
||||||
@@ -1267,7 +1266,6 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
|
|||||||
s8 i = 0;
|
s8 i = 0;
|
||||||
bool dpad = CVarGetInteger("gDpadText", 0);
|
bool dpad = CVarGetInteger("gDpadText", 0);
|
||||||
|
|
||||||
SoH_ProcessDroppedFiles();
|
|
||||||
FileChoose_UpdateRandomizer();
|
FileChoose_UpdateRandomizer();
|
||||||
|
|
||||||
if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) {
|
if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) {
|
||||||
@@ -3038,11 +3036,7 @@ void FileChoose_LoadGame(GameState* thisx) {
|
|||||||
Entrance_Init();
|
Entrance_Init();
|
||||||
|
|
||||||
// Handle randomized spawn positions after the save context has been setup from load
|
// Handle randomized spawn positions after the save context has been setup from load
|
||||||
// When remeber save location is on, set save warp if the save was in an a grotto, or
|
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
||||||
// the entrance index is -1 from shuffle overwarld spawn
|
|
||||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) && ((!CVarGetInteger("gRememberSaveLocation", 0) ||
|
|
||||||
gSaveContext.savedSceneNum == SCENE_FAIRYS_FOUNTAIN || gSaveContext.savedSceneNum == SCENE_GROTTOS) ||
|
|
||||||
(CVarGetInteger("gRememberSaveLocation", 0) && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && gSaveContext.entranceIndex == -1))) {
|
|
||||||
Entrance_SetSavewarpEntrance();
|
Entrance_SetSavewarpEntrance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,7 +456,6 @@ void FileChoose_DrawNameEntry(GameState* thisx) {
|
|||||||
this->prevConfigMode = CM_MAIN_MENU;
|
this->prevConfigMode = CM_MAIN_MENU;
|
||||||
this->configMode = CM_NAME_ENTRY_TO_MAIN;
|
this->configMode = CM_NAME_ENTRY_TO_MAIN;
|
||||||
CVarSetInteger("gOnFileSelectNameEntry", 0);
|
CVarSetInteger("gOnFileSelectNameEntry", 0);
|
||||||
CVarSetInteger("gNewFileDropped", 0);
|
|
||||||
this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200;
|
this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200;
|
||||||
this->connectorAlpha[this->buttonIndex] = 255;
|
this->connectorAlpha[this->buttonIndex] = 255;
|
||||||
func_800AA000(300.0f, 0xB4, 0x14, 0x64);
|
func_800AA000(300.0f, 0xB4, 0x14, 0x64);
|
||||||
@@ -693,6 +692,7 @@ void FileChoose_UpdateOptionsMenu(GameState* thisx) {
|
|||||||
sLastOptionButtonIndex = -1;
|
sLastOptionButtonIndex = -1;
|
||||||
osSyncPrintf("SAVE");
|
osSyncPrintf("SAVE");
|
||||||
Save_SaveGlobal();
|
Save_SaveGlobal();
|
||||||
|
CVarSave();
|
||||||
osSyncPrintf(VT_FGCOL(YELLOW));
|
osSyncPrintf(VT_FGCOL(YELLOW));
|
||||||
osSyncPrintf("Na_SetSoundOutputMode = %d\n", gSaveContext.audioSetting);
|
osSyncPrintf("Na_SetSoundOutputMode = %d\n", gSaveContext.audioSetting);
|
||||||
osSyncPrintf("Na_SetSoundOutputMode = %d\n", gSaveContext.audioSetting);
|
osSyncPrintf("Na_SetSoundOutputMode = %d\n", gSaveContext.audioSetting);
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
|
|||||||
s16 oldCursorPoint;
|
s16 oldCursorPoint;
|
||||||
s16 moveCursorResult;
|
s16 moveCursorResult;
|
||||||
bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP));
|
bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP));
|
||||||
bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) ||
|
bool pauseAnyCursor = pauseCtx->cursorSpecialPos == 0 && ((CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) ||
|
||||||
(CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON);
|
(CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON));
|
||||||
|
|
||||||
// only allow mask select when:
|
// only allow mask select when:
|
||||||
// the shop is open:
|
// the shop is open:
|
||||||
|
|||||||
@@ -312,6 +312,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
|
|||||||
KaleidoScope_DrawQuadTextureRGBA32(gfxCtx, gQuestIconGoldSkulltulaTex, 24, 24, 8);
|
KaleidoScope_DrawQuadTextureRGBA32(gfxCtx, gQuestIconGoldSkulltulaTex, 24, 24, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unique index for both pulse phases
|
||||||
|
uint8_t palettePulseIdx = (mapBgPulseStage ? 40 : 20) - mapBgPulseTimer;
|
||||||
|
|
||||||
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
||||||
stepR = (mapBgPulseR - mapBgPulseColors[mapBgPulseStage][0]) / mapBgPulseTimer;
|
stepR = (mapBgPulseR - mapBgPulseColors[mapBgPulseStage][0]) / mapBgPulseTimer;
|
||||||
stepG = (mapBgPulseG - mapBgPulseColors[mapBgPulseStage][1]) / mapBgPulseTimer;
|
stepG = (mapBgPulseG - mapBgPulseColors[mapBgPulseStage][1]) / mapBgPulseTimer;
|
||||||
@@ -324,6 +327,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
|
|||||||
interfaceCtx->mapPalette[28] = (rgba16 & 0xFF00) >> 8;
|
interfaceCtx->mapPalette[28] = (rgba16 & 0xFF00) >> 8;
|
||||||
interfaceCtx->mapPalette[29] = rgba16 & 0xFF;
|
interfaceCtx->mapPalette[29] = rgba16 & 0xFF;
|
||||||
|
|
||||||
|
interfaceCtx->mapPalettesPulse[palettePulseIdx][28] = (rgba16 & 0xFF00) >> 8;
|
||||||
|
interfaceCtx->mapPalettesPulse[palettePulseIdx][29] = rgba16 & 0xFF;
|
||||||
|
|
||||||
mapBgPulseTimer--;
|
mapBgPulseTimer--;
|
||||||
if (mapBgPulseTimer == 0) {
|
if (mapBgPulseTimer == 0) {
|
||||||
mapBgPulseStage ^= 1;
|
mapBgPulseStage ^= 1;
|
||||||
@@ -335,7 +341,8 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
|
|||||||
gDPSetTextureFilter(POLY_KAL_DISP++, G_TF_POINT);
|
gDPSetTextureFilter(POLY_KAL_DISP++, G_TF_POINT);
|
||||||
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
|
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha);
|
||||||
|
|
||||||
gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalette);
|
// Use a unique palette address per frame so the renderer/shader can cache all variations
|
||||||
|
gDPLoadTLUT_pal16(POLY_KAL_DISP++, 0, interfaceCtx->mapPalettesPulse[palettePulseIdx]);
|
||||||
gDPSetTextureLUT(POLY_KAL_DISP++, G_TT_RGBA16);
|
gDPSetTextureLUT(POLY_KAL_DISP++, G_TT_RGBA16);
|
||||||
|
|
||||||
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
|
u8 mirroredWorld = CVarGetInteger("gMirroredWorld", 0);
|
||||||
@@ -343,18 +350,15 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
|
|||||||
// Offset the U value of each vertex to be in the mirror boundary for the map textures
|
// Offset the U value of each vertex to be in the mirror boundary for the map textures
|
||||||
if (mirroredWorld) {
|
if (mirroredWorld) {
|
||||||
for (size_t i = 0; i < 8; i++) {
|
for (size_t i = 0; i < 8; i++) {
|
||||||
pauseCtx->mapPageVtx[60 + i].v.tc[0] += 48 << 5;
|
pauseCtx->mapPageVtx[60 + i].v.tc[0] += MAP_48x85_TEX_WIDTH << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[60], 8, 0);
|
gSPVertex(POLY_KAL_DISP++, &pauseCtx->mapPageVtx[60], 8, 0);
|
||||||
|
|
||||||
// The dungeon map textures are recreated each frame, so always invalidate them
|
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
|
||||||
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]);
|
MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
|
||||||
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]);
|
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
|
||||||
|
|
||||||
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | mirrorMode,
|
|
||||||
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
|
|
||||||
|
|
||||||
// Swap vertices to render left half on the right and vice-versa
|
// Swap vertices to render left half on the right and vice-versa
|
||||||
if (mirroredWorld) {
|
if (mirroredWorld) {
|
||||||
@@ -363,9 +367,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
|
|||||||
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
|
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 0,
|
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
|
||||||
G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
|
MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
|
||||||
G_TX_NOLOD);
|
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
|
||||||
|
|
||||||
if (mirroredWorld) {
|
if (mirroredWorld) {
|
||||||
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
|
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ extern u8 gItemAgeReqs[];
|
|||||||
extern u8 gAreaGsFlags[];
|
extern u8 gAreaGsFlags[];
|
||||||
extern bool gSelectingMask;
|
extern bool gSelectingMask;
|
||||||
|
|
||||||
|
#define MAP_48x85_TEX_WIDTH 48
|
||||||
|
#define MAP_48x85_TEX_HEIGHT 85
|
||||||
|
#define MAP_48x85_TEX_SIZE ((MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT) / 2) // 48x85 CI4 texture
|
||||||
|
|
||||||
#define AGE_REQ_ADULT LINK_AGE_ADULT
|
#define AGE_REQ_ADULT LINK_AGE_ADULT
|
||||||
#define AGE_REQ_CHILD LINK_AGE_CHILD
|
#define AGE_REQ_CHILD LINK_AGE_CHILD
|
||||||
#define AGE_REQ_NONE 9
|
#define AGE_REQ_NONE 9
|
||||||
|
|||||||
@@ -3315,13 +3315,121 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx) {
|
|||||||
pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16;
|
pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modifed map texture buffers for registered blend effects and the room indicator color
|
||||||
|
static uint8_t mapLeftTexModified[MAP_48x85_TEX_SIZE];
|
||||||
|
static uint8_t mapRightTexModified[MAP_48x85_TEX_SIZE];
|
||||||
|
static uint8_t* mapLeftTexModifiedRaw = NULL;
|
||||||
|
static uint8_t* mapRightTexModifiedRaw = NULL;
|
||||||
|
static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT];
|
||||||
|
|
||||||
|
// Load dungeon maps into the interface context
|
||||||
|
// SoH [General] - Modified to account for our resource system and HD textures
|
||||||
void KaleidoScope_LoadDungeonMap(PlayState* play) {
|
void KaleidoScope_LoadDungeonMap(PlayState* play) {
|
||||||
InterfaceContext* interfaceCtx = &play->interfaceCtx;
|
InterfaceContext* interfaceCtx = &play->interfaceCtx;
|
||||||
|
|
||||||
|
// Free old textures
|
||||||
|
if (mapLeftTexModifiedRaw != NULL) {
|
||||||
|
free(mapLeftTexModifiedRaw);
|
||||||
|
mapLeftTexModifiedRaw = NULL;
|
||||||
|
}
|
||||||
|
if (mapRightTexModifiedRaw != NULL) {
|
||||||
|
free(mapRightTexModifiedRaw);
|
||||||
|
mapRightTexModifiedRaw = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unload original textures to bypass cache result for lookups
|
||||||
|
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX]);
|
||||||
|
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]);
|
||||||
|
|
||||||
interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX];
|
interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX];
|
||||||
interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1];
|
interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1];
|
||||||
interfaceCtx->mapSegment[0] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX]);
|
|
||||||
interfaceCtx->mapSegment[1] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]);
|
// When the texture is HD (raw) we need to copy a dynamic amount of data
|
||||||
|
// Otherwise the original asset has a static size
|
||||||
|
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
|
||||||
|
u32 width = ResourceGetTexWidthByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
u32 height = ResourceGetTexHeightByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
size_t size = (width * height) / 2; // account for CI4 size
|
||||||
|
|
||||||
|
// Resource size being larger than the calculated CI size means it is most likely not a CI4 texture
|
||||||
|
// Abort early and unregister the blended effect to avoid crashing
|
||||||
|
if (size < ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0])) {
|
||||||
|
interfaceCtx->mapSegment[0] = NULL;
|
||||||
|
interfaceCtx->mapSegment[1] = NULL;
|
||||||
|
|
||||||
|
Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[0]);
|
||||||
|
Gfx_UnregisterBlendedTexture(interfaceCtx->mapSegmentName[1]);
|
||||||
|
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]);
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* map1TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
u8* map2TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
|
||||||
|
|
||||||
|
mapLeftTexModifiedRaw = malloc(size);
|
||||||
|
mapRightTexModifiedRaw = malloc(size);
|
||||||
|
|
||||||
|
memcpy(mapLeftTexModifiedRaw, map1TexRaw, size);
|
||||||
|
memcpy(mapRightTexModifiedRaw, map2TexRaw, size);
|
||||||
|
|
||||||
|
interfaceCtx->mapSegment[0] = mapLeftTexModifiedRaw;
|
||||||
|
interfaceCtx->mapSegment[1] = mapRightTexModifiedRaw;
|
||||||
|
} else {
|
||||||
|
u8* map1Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
u8* map2Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
|
||||||
|
|
||||||
|
memcpy(mapLeftTexModified, map1Tex, MAP_48x85_TEX_SIZE);
|
||||||
|
memcpy(mapRightTexModified, map2Tex, MAP_48x85_TEX_SIZE);
|
||||||
|
|
||||||
|
interfaceCtx->mapSegment[0] = mapLeftTexModified;
|
||||||
|
interfaceCtx->mapSegment[1] = mapRightTexModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark and register the blend mask for the copied textures
|
||||||
|
if (mapBlendMask[0] != 1) {
|
||||||
|
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
|
||||||
|
mapBlendMask[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]);
|
||||||
|
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]);
|
||||||
|
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[0]);
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegmentName[1]);
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegment[0]);
|
||||||
|
Gfx_TextureCacheDelete(interfaceCtx->mapSegment[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t registeredDungeonMapTextureHook = false;
|
||||||
|
|
||||||
|
void KaleidoScope_RegisterUpdatedDungeonMapTexture() {
|
||||||
|
if (gPlayState == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseContext* pauseCtx = &gPlayState->pauseCtx;
|
||||||
|
|
||||||
|
// Kaleido is not open in a dungeon so there is nothing to do
|
||||||
|
if (R_PAUSE_MENU_MODE < 3 || pauseCtx->state < 4 || pauseCtx->state > 7 || !sInDungeonScene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KaleidoScope_UpdateDungeonMap(gPlayState);
|
||||||
|
|
||||||
|
// KaleidoScope_UpdateDungeonMap will update the palette index for the current floor if the cursor is on the floor
|
||||||
|
// If the player toggles alt assets while the cursor is not in the floor level, then we handle the palette index here
|
||||||
|
if (gPlayState->sceneNum >= SCENE_DEKU_TREE && gPlayState->sceneNum <= SCENE_TREASURE_BOX_SHOP &&
|
||||||
|
(VREG(30) + 3) == pauseCtx->dungeonMapSlot && (VREG(30) + 3) != pauseCtx->cursorPoint[PAUSE_MAP]) {
|
||||||
|
|
||||||
|
InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx;
|
||||||
|
int32_t size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
|
||||||
|
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
|
||||||
|
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KaleidoScope_UpdateDungeonMap(PlayState* play) {
|
void KaleidoScope_UpdateDungeonMap(PlayState* play) {
|
||||||
@@ -3333,19 +3441,34 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) {
|
|||||||
KaleidoScope_LoadDungeonMap(play);
|
KaleidoScope_LoadDungeonMap(play);
|
||||||
Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3);
|
Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3);
|
||||||
|
|
||||||
|
// Copy the map palette values to all pulse palettes
|
||||||
|
for (uint8_t i = 0; i < ARRAY_COUNT(interfaceCtx->mapPalettesPulse); i++) {
|
||||||
|
memcpy(interfaceCtx->mapPalettesPulse[i], interfaceCtx->mapPalette, sizeof(interfaceCtx->mapPalette));
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 size = MAP_48x85_TEX_SIZE;
|
||||||
|
|
||||||
|
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
|
||||||
|
size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
|
||||||
|
}
|
||||||
|
|
||||||
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
||||||
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
|
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
|
||||||
// HDTODO: Handle Runtime Modified Textures (HD)
|
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
|
||||||
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], 2040, interfaceCtx->mapPaletteIndex, 14);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
|
||||||
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
|
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
|
||||||
// HDTODO: Handle Runtime Modified Textures (HD)
|
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
|
||||||
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], 2040, interfaceCtx->mapPaletteIndex, 14);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register alt listener to update the blended dungeon map textures on alt toggle
|
||||||
|
if (!registeredDungeonMapTextureHook) {
|
||||||
|
registeredDungeonMapTextureHook = true;
|
||||||
|
GameInteractor_RegisterOnAssetAltChange(KaleidoScope_RegisterUpdatedDungeonMapTexture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KaleidoScope_Update(PlayState* play)
|
void KaleidoScope_Update(PlayState* play)
|
||||||
|
|||||||
@@ -1762,6 +1762,13 @@ static MapMarkData sMapMarkJabuJabuBellyMq[] = {
|
|||||||
} },
|
} },
|
||||||
{ MAP_MARK_NONE, 0, { 0 } },
|
{ MAP_MARK_NONE, 0, { 0 } },
|
||||||
},
|
},
|
||||||
|
// Jabu-Jabu's Belly minimap 16
|
||||||
|
// SoH [General] - This entry corresponds to Big Octorok's room and is missing in the MQ game
|
||||||
|
// N64 hardware does an OoB read and lands on MQ Forest Temple room 0
|
||||||
|
// To avoid UB with OoB for SoH, the correct entry is now added below
|
||||||
|
{
|
||||||
|
{ MAP_MARK_NONE, 0, { 0 } },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static MapMarkData sMapMarkForestTempleMq[] = {
|
static MapMarkData sMapMarkForestTempleMq[] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user