Compare commits

..

21 Commits

Author SHA1 Message Date
Archez 0bc6ca08e0 Bump MacReady Golf (#4279) 2024-08-12 23:26:30 -04:00
Archez 16aaf2f939 Tweak: Implement better extended culling options (#4285)
* implement better culling

* change draw distance to a slider

* remove testing code

* tweak
2024-08-12 19:39:44 -04:00
Spodi 3971e3696e Use manifest for windows DPI awareness (#3270) (#4256)
* Use manifest for windows DPI awareness (#3270)

* Update libultraship

* Update libultraship
2024-08-05 19:31:20 -04:00
Nicholas Estelami f11f97e84e Custom Skeleton Fixes for various bosses and enemies (#3436)
* Skeleton Fixes for various bosses and enemies

* cleanup

* revert breakpart changes

---------

Co-authored-by: Adam Bird <archez39@me.com>
2024-08-05 15:20:40 -04:00
Archez 7a00658be9 Fix disable lod breaking certain effects (#4245) 2024-07-21 15:30:18 -04:00
Malkierian 7bc2259c82 LUS bump and implement alt assets performance changes. (#4240)
* LUS bump and implement alt assets performance changes.

* LUS ref update.
2024-07-21 15:29:45 -04:00
Malkierian 3d73faa9a0 Port Graphics Menu lag fix from 2ship. (#4238)
* Port Graphics Menu lag fix from 2ship.

* tweak

---------

Co-authored-by: Adam Bird <archez39@me.com>
2024-07-17 15:57:11 -04:00
Kenix3 134aba4aa0 Fixes crashes on asan related to audio. (#4049)
Found in MM
2024-07-17 14:35:13 -04:00
inspectredc 79a29a62ef Use correct default value (#4194) 2024-06-15 23:43:09 -04:00
Archez 3f67fed073 Fix some memory leaks with WrappedText and LoadArrayByNameAsVec3s (#4144)
* avoid memory leaks with WrappedText

* avoid memory leak with LoadArrayByNameAsVec3s
2024-05-09 20:39:13 -05:00
Archez cbeec006ec Fix syotes scene path to use shared (#4136) 2024-05-09 00:32:29 -04:00
Archez fd9cd9c5eb Fix: add workaround for boost versions >=1.84.0 (#4098) 2024-05-01 16:41:17 -04:00
inspectredc 4a576f45ee Fix and Clean Up Swap Age Logic (#4061)
* Split and clean up swap age logic

* reorganise conditions into one statement
2024-04-20 10:43:35 -04:00
briaguya 32bf8cc53c fix wii u ci (#4056) 2024-04-19 09:42:41 -04:00
Malkierian 02f7310c16 Add keyring to check for placing Gerudo Fortess Keys in Any Dungeon or Overworld. (#4055) 2024-04-19 09:42:26 -04:00
inspectredc bfe13906e9 Make equip swap work on pause any cursor (#4052) 2024-04-19 09:42:12 -04:00
Amaro Martínez 32288be744 Save in-game language setting (#4026) 2024-04-19 09:41:55 -04:00
Malkierian 19be6e9b99 Trackers MQ Cleanup (#4009)
* Clean up grayed out items in file select.
Tie personal notes saving to `OnExitGame()` to account for save scum resets.
Hide text input box (but not window) for personal notes when a save isn't loaded to prevent saving over a save's notes while in file select.

* Allow check tracker window to be visible and show the "Waiting for file load..." text in file select (ease of positioning).

* Fix key label text placement.

* Persist `areasSpoiled`, change trigger to `OnSceneTransition`.
Add `IsAreaSpoiled` for tie-in to Item Tracker.
Add `SetAreaSpoiled` to unify bitmagic.

* Add proper spoiling evaluation based on specific entrance IDs, or first check collection.
Add light yellow color for vanilla dungeon abbreviations to match the purple for MQ.

* Initialize `areasSpoiled` to 0, so 0 gets saved on file create.

* All new conditional statements around `GameInteractor::IsSaveLoaded()` were inverted. Fixed that.

* Change some c-style casts to `static_cast`.

* Few more cleanups, plus clarifying comment.
2024-04-19 09:41:46 -04:00
Archez 0b8cc71d0d fix actor init flow with object loading (#3987) 2024-04-19 09:41:04 -04:00
inspectredc ced34ab68a [Fix] Disable Lod Applies To Everything (Macready) (#4034)
* make lod cvar affect everything

* add to more functions

* re-add to player

* only add to necessary funcs
2024-04-15 12:00:04 -04:00
inspectredc e163d5bc3d Fix switch puzzle locking issues (#4027) 2024-04-07 17:28:20 -04:00
56 changed files with 677 additions and 311 deletions
-1
View File
@@ -235,7 +235,6 @@ jobs:
- name: Install dependencies
if: ${{ !vars.LINUX_RUNNER }}
run: |
sudo apt-get update
sudo apt-get install -y ninja-build
- uses: actions/checkout@v3
with:
+3 -3
View File
@@ -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")
project(Ship VERSION 8.0.5 LANGUAGES C CXX)
set(PROJECT_BUILD_NAME "MacReady Foxtrot" CACHE STRING "")
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
project(Ship VERSION 8.0.6 LANGUAGES C CXX)
set(PROJECT_BUILD_NAME "MacReady Golf" CACHE STRING "" FORCE)
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
+6
View File
@@ -28,4 +28,10 @@
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</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>
@@ -46,10 +46,18 @@ template<> struct is_char_type<std::byte>: public boost::true_type {};
#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>
inline typename boost::enable_if_<
inline typename BOOST_ENABLE_IF<
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
hash_range_32( uint32_t seed, It first, It last )
{
@@ -114,4 +122,7 @@ std::size_t>::type
} // namespace hash_detail
} // namespace boost
#undef BOOST_ENABLE_IF
#undef BOOST_IS_SAME
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_32_HPP
@@ -23,6 +23,18 @@
#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
{
@@ -36,7 +48,7 @@ namespace boost
{
template<class 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 type_bits = sizeof(T) * CHAR_BIT>
struct hash_integral_impl_32;
@@ -53,7 +65,7 @@ namespace boost
{
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 )
{
@@ -97,7 +109,7 @@ namespace boost
} // namespace hash_detail
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 )
{
return hash_detail::hash_integral_impl_32<T>::fn( v );
@@ -106,7 +118,7 @@ namespace boost
// contiguous ranges (string, vector, array)
#if BOOST_VERSION_HAS_HASH_RANGE
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 )
{
return boost::hash_range_32( v.data(), v.data() + v.size() );
@@ -168,5 +180,9 @@ namespace boost
} // namespace boost
#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
@@ -6,4 +6,6 @@
#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
+4
View File
@@ -1259,6 +1259,8 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable,
s32 dListIndex);
void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw,
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,
OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg);
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_RandoRestoreSwordless(void);
s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw,
bool* shouldUpdate);
// #endregion
+2
View File
@@ -1405,6 +1405,8 @@ typedef struct PlayState {
/* 0x1242B */ u8 unk_1242B;
/* 0x1242C */ SceneTableEntry* loadedScene;
/* 0x12430 */ char unk_12430[0xE8];
// SOH [Custom Models] MTX tracker for flex based skeletons
Mtx** flexLimbOverrideMTX;
} PlayState; // size = 0x12518
typedef struct {
@@ -782,7 +782,7 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl
ImGui::PopStyleColor();
if (ImGui::IsItemHovered() && hasDescription) {
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::PopID();
+2
View File
@@ -211,6 +211,8 @@ const std::vector<const char*> enhancementsCvars = {
"gDisableLOD",
"gDisableDrawDistance",
"gDisableKokiriDrawDistance",
"gEnhancements.WidescreenActorCulling",
"gEnhancements.ExtendedCullingExcludeGlitchActors",
"gLowResMode",
"gDrawLineupTick",
"gQuickBongoKill",
@@ -846,10 +846,10 @@ static void RandomizeDungeonItems() {
}
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);
} 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);
}
@@ -103,6 +103,23 @@ std::map<SceneID, RandomizerCheckArea> DungeonRCAreasBySceneID = {
{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;
bool areasFullyChecked[RCAREA_INVALID];
u32 areasSpoiled = 0;
@@ -263,6 +280,10 @@ void SetCheckCollected(RandomizerCheck rc) {
}
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
if (!IsAreaSpoiled(rcObj.rcArea)) {
SetAreaSpoiled(rcObj.rcArea);
}
doAreaScroll = true;
UpdateOrdering(rcObj.rcArea);
UpdateInventoryChecks();
@@ -467,9 +488,14 @@ void CheckTrackerLoadGame(int32_t fileNum) {
areaChecksGotten[realRcObj.rcArea]++;
}
}
if (areaChecksGotten[realRcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(realRcObj.rcArea)) {
areasSpoiled |= (1 << realRcObj.rcArea);
}
for (int i = RCAREA_KOKIRI_FOREST; i < RCAREA_INVALID; i++) {
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) {
@@ -539,6 +565,9 @@ void CheckTrackerTransition(uint32_t sceneNum) {
SetShopSeen(sceneNum, false);
break;
}
if (!IsAreaSpoiled(currentArea) && (RandomizerCheckObjects::AreaIsOverworld(currentArea) || std::find(spoilingEntrances.begin(), spoilingEntrances.end(), gPlayState->nextEntranceIndex) != spoilingEntrances.end())) {
SetAreaSpoiled(currentArea);
}
}
void CheckTrackerFrame() {
@@ -756,6 +785,7 @@ void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
void InitTrackerData(bool isDebug) {
TrySetAreas();
areasSpoiled = 0;
for (auto& [rc, rco] : RandomizerCheckObjects::GetAllRCObjects()) {
if (rc != RC_UNKNOWN_CHECK && rc != RC_MAX) {
DefaultCheckData(rc);
@@ -783,6 +813,7 @@ void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) {
SaveManager::Instance->SaveData("hintItem", saveContext->checkTrackerData[i].hintItem);
});
});
SaveManager::Instance->SaveData("areasSpoiled", areasSpoiled);
}
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
@@ -798,6 +829,7 @@ void LoadFile() {
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem);
});
});
SaveManager::Instance->LoadData("areasSpoiled", areasSpoiled);
}
void Teardown() {
@@ -809,6 +841,15 @@ void Teardown() {
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) {
auto area = RandomizerCheckObjects::GetAllRCObjects().find(static_cast<RandomizerCheck>(check))->second.rcArea;
if ((!gSaveContext.checkTrackerData[check].skipped && data.skipped) ||
@@ -827,10 +868,6 @@ void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) {
void CheckTrackerWindow::DrawElement() {
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("gCheckTrackerShowOnlyPaused", 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) {
return;
@@ -851,7 +888,7 @@ void CheckTrackerWindow::DrawElement() {
BeginFloatWindows("Check Tracker", mIsVisible, ImGuiWindowFlags_NoScrollbar);
if (!GameInteractor::IsSaveLoaded()) {
if (!GameInteractor::IsSaveLoaded() || !initialized) {
ImGui::Text("Waiting for file load..."); //TODO Language
EndFloatWindows();
return;
@@ -862,8 +899,6 @@ void CheckTrackerWindow::DrawElement() {
sceneId = (SceneID)gPlayState->sceneNum;
}
areasSpoiled |= (1 << currentArea);
//Quick Options
#ifdef __WIIU__
float headerHeight = 40.0f;
@@ -925,7 +960,6 @@ void CheckTrackerWindow::DrawElement() {
Color_RGBA8 mainColor;
Color_RGBA8 extraColor;
std::string stemp;
s32 areaMask = 1;
for (auto& [rcArea, objs] : checksByArea) {
RandomizerCheckArea thisArea = currentArea;
@@ -978,11 +1012,7 @@ void CheckTrackerWindow::DrawElement() {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
extraColor.b / 255.0f, extraColor.a / 255.0f));
isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0) || !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);
isThisAreaSpoiled = IsAreaSpoiled(rcArea) || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0);
if (isThisAreaSpoiled) {
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
@@ -1015,7 +1045,6 @@ void CheckTrackerWindow::DrawElement() {
ImGui::TreePop();
}
}
areaMask <<= 1;
}
ImGui::EndTable(); //Checks Lead-out
@@ -1219,10 +1248,10 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
}
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) {
if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, scene)) {
areasSpoiled |= (1 << area);
SetAreaSpoiled(area);
}
}
}
@@ -1232,9 +1261,6 @@ void UpdateAreaFullyChecked(RandomizerCheckArea area) {
void UpdateAreas(RandomizerCheckArea area) {
areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size();
if (areaChecksGotten[area] != 0 || RandomizerCheckObjects::AreaIsOverworld(area)) {
areasSpoiled |= (1 << area);
}
}
void UpdateAllOrdering() {
@@ -50,6 +50,8 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj);
void InitTrackerData(bool isDebug);
RandomizerCheckArea GetCheckArea();
void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
bool IsAreaSpoiled(RandomizerCheckArea rcArea);
void SetAreaSpoiled(RandomizerCheckArea rcArea);
} // namespace CheckTracker
@@ -9,6 +9,7 @@
#include <vector>
#include <libultraship/libultraship.h>
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "randomizer_check_tracker.h"
#include <algorithm>
extern "C" {
@@ -290,15 +291,15 @@ bool IsValidSaveFile() {
}
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) {
return (item.data & gSaveContext.inventory.questItems) != 0;
return GameInteractor::IsSaveLoaded() ? (item.data & gSaveContext.inventory.questItems) : false;
}
bool HasEquipment(ItemTrackerItem item) {
return (item.data & gSaveContext.inventory.equipment) != 0;
return GameInteractor::IsSaveLoaded() ? (item.data & gSaveContext.inventory.equipment) : false;
}
ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
@@ -406,8 +407,12 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
#define IM_COL_GREEN IM_COL32(0, 255, 0, 255)
#define IM_COL_GRAY IM_COL32(155, 155, 155, 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);
ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item);
ImVec2 p = ImGui::GetCursorScreenPos();
@@ -416,7 +421,7 @@ void DrawItemCount(ItemTrackerItem item) {
if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) {
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 maxColor = IM_COL_GREEN;
// "Collected / Max", "Current / Collected / Max", "Current / Max"
@@ -548,7 +553,7 @@ void DrawQuest(ItemTrackerItem item) {
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
if (item.id == QUEST_SKULL_TOKEN) {
DrawItemCount(item);
DrawItemCount(item, false);
}
ImGui::EndGroup();
@@ -558,7 +563,7 @@ void DrawQuest(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);
bool hasItem = actualItemId != ITEM_NONE;
std::string itemName = "";
@@ -617,7 +622,7 @@ void DrawItem(ItemTrackerItem item) {
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded),
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
DrawItemCount(item);
DrawItemCount(item, false);
ImGui::EndGroup();
if (itemName == "") {
@@ -628,7 +633,7 @@ void DrawItem(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;
if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) {
@@ -647,8 +652,8 @@ void DrawDungeonItem(ItemTrackerItem item) {
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
int iconSize = CVarGetInteger("gItemTrackerIconSize", 36);
bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[item.data]) != 0;
bool hasSmallKey = (gSaveContext.inventory.dungeonKeys[item.data]) >= 0;
bool hasItem = GameInteractor::IsSaveLoaded() ? (bitMask & gSaveContext.inventory.dungeonItems[item.data]) : false;
bool hasSmallKey = GameInteractor::IsSaveLoaded() ? ((gSaveContext.inventory.dungeonKeys[item.data]) >= 0) : false;
ImGui::BeginGroup();
if (itemId == ITEM_KEY_SMALL) {
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSmallKey && IsValidSaveFile() ? item.name : item.nameFaded),
@@ -659,16 +664,18 @@ void DrawDungeonItem(ItemTrackerItem item) {
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)) {
dungeonColor = IM_COL_PURPLE;
if (CheckTracker::IsAreaSpoiled(RandomizerCheckObjects::GetRCAreaBySceneID(static_cast<SceneID>(item.data))) && GameInteractor::IsSaveLoaded()) {
dungeonColor = (ResourceMgr_IsSceneMasterQuest(item.data) ? IM_COL_PURPLE : IM_COL_LIGHT_YELLOW);
}
if (itemId == ITEM_KEY_SMALL) {
DrawItemCount(item);
DrawItemCount(item, !CheckTracker::IsAreaSpoiled(RandomizerCheckObjects::GetRCAreaBySceneID(static_cast<SceneID>(item.data))));
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];
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::Text("%s", dungeonName.c_str());
ImGui::PopStyleColor();
@@ -725,13 +732,15 @@ void DrawNotes(bool resizeable = false) {
}
};
ImVec2 size = resizeable ? ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y) : ImVec2(((iconSize + iconSpacing) * 6) - 8, 200);
if (ItemTrackerNotes::TrackerNotesInputTextMultiline("##ItemTrackerNotes", &itemTrackerNotes, size, ImGuiInputTextFlags_AllowTabInput)) {
notesNeedSave = true;
notesIdleFrames = 0;
}
if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) {
notesNeedSave = false;
SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true);
if (GameInteractor::IsSaveLoaded()) {
if (ItemTrackerNotes::TrackerNotesInputTextMultiline("##ItemTrackerNotes", &itemTrackerNotes, size, ImGuiInputTextFlags_AllowTabInput)) {
notesNeedSave = true;
notesIdleFrames = 0;
}
if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) {
notesNeedSave = false;
SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true);
}
}
ImGui::EndGroup();
}
+16 -8
View File
@@ -137,6 +137,8 @@ Color_RGB8 zoraColor = { 0x00, 0xEC, 0x64 };
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.
typedef struct {
Color_RGB8 inner;
@@ -297,6 +299,8 @@ OTRGlobals::OTRGlobals() {
};
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
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>());
@@ -1235,7 +1239,7 @@ extern "C" void Graph_StartFrame() {
}
#endif
case KbScancode::LUS_KB_TAB: {
ToggleAltAssetsAtEndOfFrame = true;
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
break;
}
}
@@ -1315,11 +1319,10 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
}
}
if (ToggleAltAssetsAtEndOfFrame) {
ToggleAltAssetsAtEndOfFrame = false;
// Actually update the CVar now before runing the alt asset update listeners
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
bool curAltAssets = CVarGetInteger("gAltAssets", 0);
if (prevAltAssets != curAltAssets) {
prevAltAssets = curAltAssets;
LUS::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets);
gfx_texture_cache_clear();
LUS::SkeletonPatcher::UpdateSkeletons();
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
@@ -1495,10 +1498,14 @@ extern "C" uint8_t ResourceMgr_FileAltExists(const char* filePath) {
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
// 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) {
if (CVarGetInteger("gAltAssets", 0) && ResourceMgr_FileAltExists((char*) resName)) {
if (ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileAltExists((char*) resName)) {
ResourceMgr_UnloadResource((char*) resName);
}
}
@@ -1735,6 +1742,7 @@ extern "C" char* ResourceMgr_LoadArrayByName(const char* path)
return (char*)res->Scalars.data();
}
// Return of LoadArrayByNameAsVec3s must be freed by the caller
extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) {
auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path));
@@ -1867,7 +1875,7 @@ extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, Skel
pathStr = pathStr.substr(sOtr.length());
}
bool isAlt = CVarGetInteger("gAltAssets", 0);
bool isAlt = ResourceMgr_IsAltAssetsEnabled();
if (isAlt) {
pathStr = LUS::IResource::gAltAssetPrefix + pathStr;
+1
View File
@@ -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);
uint64_t GetPerfCounter();
bool ResourceMgr_IsAltAssetsEnabled();
struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime);
void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime);
void ResourceMgr_ClearSkeletons();
-1
View File
@@ -38,7 +38,6 @@
#include "Enhancements/game-interactor/GameInteractor.h"
#include "Enhancements/cosmetics/authenticGfxPatches.h"
bool ToggleAltAssetsAtEndOfFrame = false;
bool isBetaQuestEnabled = false;
extern "C" {
+66 -36
View File
@@ -28,7 +28,6 @@
#include "Enhancements/randomizer/randomizer_item_tracker.h"
#include "Enhancements/randomizer/randomizer_settings_window.h"
extern bool ToggleAltAssetsAtEndOfFrame;
extern bool isBetaQuestEnabled;
extern "C" PlayState* gPlayState;
@@ -50,6 +49,13 @@ std::string GetWindowButtonText(const char* text, bool menuOpen) {
if (!menuOpen) { strcat(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" };
@@ -102,6 +108,24 @@ extern "C" SaveContext gSaveContext;
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() {
static bool gameIconLoaded = false;
if (!gameIconLoaded) {
@@ -391,40 +415,24 @@ void DrawSettingsMenu() {
UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements.");
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)");
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);
}
if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) {
for (size_t i = 0; i < LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); i++) {
auto backend = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i];
if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) {
LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend));
LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name",
windowBackendNames[backend]);
if (ImGui::BeginCombo("##RApi", availableWindowBackendsMap[configWindowBackend])) {
for (auto backend : availableWindowBackendsMap) {
if (ImGui::Selectable(backend.second, backend.first == configWindowBackend)) {
LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend.first));
LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", backend.second);
LUS::Context::GetInstance()->GetConfig()->Save();
UpdateWindowBackendObjects();
}
}
ImGui::EndCombo();
}
if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) {
if (availableWindowBackendsMap.size() <= 1) {
UIWidgets::ReEnableComponent("");
}
@@ -907,12 +915,7 @@ void DrawEnhancementsMenu() {
if (ImGui::BeginMenu("Graphics"))
{
if (ImGui::BeginMenu("Mods")) {
if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) {
// The checkbox will flip the alt asset CVar, but we instead want it to change at the end of the game frame
// We toggle it back while setting the flag to update the CVar later
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
ToggleAltAssetsAtEndOfFrame = true;
}
UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false);
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::Tooltip("Disables bombs always rotating to face the camera. To be used in conjunction with mods that want to replace bombs with 3D objects.");
@@ -925,16 +928,39 @@ void DrawEnhancementsMenu() {
}
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");
if (UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false)) {
if (CVarGetInteger("gDisableDrawDistance", 0) == 0) {
if (UIWidgets::EnhancementSliderInt("Increase Actor Draw Distance: %dx", "##IncreaseActorDrawDistance",
"gDisableDrawDistance", 1, 5, "", 1, true, false)) {
if (CVarGetInteger("gDisableDrawDistance", 1) <= 1) {
CVarSetInteger("gDisableKokiriDrawDistance", 0);
}
}
UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range");
if (CVarGetInteger("gDisableDrawDistance", 0) == 1) {
UIWidgets::Tooltip("Increases the range in which actors/objects are drawn");
if (CVarGetInteger("gDisableDrawDistance", 1) > 1) {
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::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);
@@ -1610,6 +1636,10 @@ void DrawRandomizerMenu() {
}
}
void SohMenuBar::InitElement() {
UpdateWindowBackendObjects();
}
void SohMenuBar::DrawElement() {
if (ImGui::BeginMenuBar()) {
DrawMenuBarIcon();
+1 -1
View File
@@ -10,7 +10,7 @@ class SohMenuBar : public LUS::GuiMenuBar {
using LUS::GuiMenuBar::GuiMenuBar;
protected:
void DrawElement() override;
void InitElement() override {};
void InitElement() override;
void UpdateElement() override {};
};
} // namespace SohGui
+8 -8
View File
@@ -21,7 +21,7 @@ namespace UIWidgets {
// 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
// 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);
const size_t tipLength = newText.length();
int lastSpace = -1;
@@ -43,17 +43,17 @@ namespace UIWidgets {
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);
}
void SetLastItemHoverText(const std::string& text) {
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("%s", WrappedText(text, 60));
ImGui::Text("%s", WrappedText(text, 60).c_str());
ImGui::EndTooltip();
}
}
@@ -61,7 +61,7 @@ namespace UIWidgets {
void SetLastItemHoverText(const char* text) {
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("%s", WrappedText(text, 60));
ImGui::Text("%s", WrappedText(text, 60).c_str());
ImGui::EndTooltip();
}
}
@@ -72,7 +72,7 @@ namespace UIWidgets {
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("%s", WrappedText(text, 60));
ImGui::Text("%s", WrappedText(text, 60).c_str());
ImGui::EndTooltip();
}
}
@@ -82,7 +82,7 @@ namespace UIWidgets {
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("%s", WrappedText(text, 60));
ImGui::Text("%s", WrappedText(text, 60).c_str());
ImGui::EndTooltip();
}
}
@@ -92,7 +92,7 @@ namespace UIWidgets {
void Tooltip(const char* text) {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", WrappedText(text));
ImGui::SetTooltip("%s", WrappedText(text).c_str());
}
}
+2 -2
View File
@@ -50,8 +50,8 @@ namespace UIWidgets {
constexpr float sliderButtonWidth = 30.0f;
#endif
char* WrappedText(const char* text, unsigned int charactersPerLine = 60);
char* WrappedText(const std::string& text, unsigned int charactersPerLine);
std::string WrappedText(const char* text, unsigned int charactersPerLine = 60);
std::string WrappedText(const std::string& text, unsigned int charactersPerLine);
void SetLastItemHoverText(const std::string& text);
void SetLastItemHoverText(const char* text);
+7 -1
View File
@@ -99,8 +99,14 @@ void aClearBufferImpl(uint16_t addr, int 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));
#endif
}
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
+3 -4
View File
@@ -65,12 +65,11 @@ void SkeletonPatcher::ClearSkeletons()
}
void SkeletonPatcher::UpdateSkeletons() {
bool isHD = CVarGetInteger("gAltAssets", 0);
auto resourceMgr = LUS::Context::GetInstance()->GetResourceManager();
bool isHD = resourceMgr->IsAltAssetsEnabled();
for (auto skel : skeletons) {
Skeleton* newSkel =
(Skeleton*)LUS::Context::GetInstance()->GetResourceManager()
->LoadResource((isHD ? LUS::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true)
.get();
(Skeleton*)resourceMgr->LoadResource((isHD ? LUS::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true).get();
if (newSkel != nullptr) {
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
+1 -1
View File
@@ -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.
ResourceMgr_ClearSkeletons();
if (CVarGetInteger("gAltAssets", 0)) {
if (ResourceMgr_IsAltAssetsEnabled()) {
ResourceUnloadDirectory("alt/*");
gfx_texture_cache_clear();
}
+1 -1
View File
@@ -141,7 +141,7 @@ static const ALIGN_ASSET(2) char rGfxPrintFontDataAlt[] = drGfxPrintFontDataAlt;
// https://github.com/HarbourMasters/Shipwright/issues/2762
typedef enum {hardcoded, otrDefault, otrAlt} font_texture_t;
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
return otrAlt;
} else if (ResourceMgr_FileExists(rGfxPrintFontData)) {
+106 -31
View File
@@ -1208,19 +1208,11 @@ void Actor_Init(Actor* actor, PlayState* play) {
actor->uncullZoneForward = 1000.0f;
actor->uncullZoneScale = 350.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);
actor->floorBgId = BGCHECK_SCENE;
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
if (Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
//Actor_SetObjectDependency(play, actor);
Actor_SetObjectDependency(play, actor);
actor->init(actor, play);
actor->init = NULL;
@@ -2548,6 +2540,13 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) {
Actor_SetObjectDependency(play, actor);
actor->init(actor, play);
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;
} else if (!Object_IsLoaded(&play->objectCtx, actor->objBankIndex)) {
@@ -2850,34 +2849,93 @@ s32 func_800314B0(PlayState* play, Actor* actor) {
s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) {
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))) {
var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3;
// #region SoH [Widescreen support]
// Doors will cull quite noticeably on wider screens. For these actors the zone is increased
f32 limit = 1.0f;
if (((actor->id == ACTOR_EN_DOOR) || (actor->id == ACTOR_DOOR_SHUTTER)) && CVarGetInteger("gIncreaseDoorUncullZones", 1)) {
limit = 2.0f;
}
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < limit) &&
(((arg2->y + actor->uncullZoneDownward) * var) > -limit) &&
(((arg2->y - actor->uncullZoneScale) * var) < limit)) {
if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 1.0f) &&
(((arg2->y + actor->uncullZoneDownward) * var) > -1.0f) &&
(((arg2->y - actor->uncullZoneScale) * var) < 1.0f)) {
return true;
}
// #endregion
}
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) {
s32 invisibleActorCounter;
Actor* invisibleActors[INVISIBLE_ACTOR_MAX];
@@ -2913,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 (func_800314B0(play, actor)) {
actor->flags |= ACTOR_FLAG_ACTIVE;
if (CVarGetInteger("gDisableDrawDistance", 1) > 1 ||
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 {
actor->flags &= ~ACTOR_FLAG_ACTIVE;
if (func_800314B0(play, actor)) {
actor->flags |= ACTOR_FLAG_ACTIVE;
} else {
actor->flags &= ~ACTOR_FLAG_ACTIVE;
}
}
}
actor->isDrawn = false;
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) &&
((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) ||
play->actorCtx.lensActive || (actor->room != play->roomCtx.curRoom.num))) {
+1 -1
View File
@@ -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 +
plane.originDist;
#ifdef __WIIU__
#if defined(__SWITCH__) || defined(__WIIU__)
// on some platforms this ends up as very small numbers due to rounding issues
if (IS_ZERO(planeDistA)) {
planeDistA = 0.0f;
+1 -1
View File
@@ -1115,7 +1115,7 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) {
}
}
if (msgCtx->textDelayTimer == 0) {
msgCtx->textDrawPos = i + CVarGetInteger("gTextSpeed", 2);
msgCtx->textDrawPos = i + CVarGetInteger("gTextSpeed", 1);
msgCtx->textDelayTimer = msgCtx->textDelay;
} else {
msgCtx->textDelayTimer--;
+178 -100
View File
@@ -1436,64 +1436,62 @@ Gfx* Gfx_TextureI8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 te
return displayListHead;
}
void Inventory_SwapAgeEquipment(void) {
void Rando_Inventory_SwapAgeEquipment(void) {
s16 i;
u16 shieldEquipValue;
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];
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.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;
if (gSaveContext.adultEquips.buttonItems[0] == ITEM_NONE && !(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.adultEquips.equipment)) {
if (!IS_RANDO || !Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD)) {
gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER;
} else {
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
Flags_SetInfTable(INFTABLE_SWORDLESS);
}
// When becoming adult, remove swordless flag since we'll get master sword
// This gets set back appropriately later in the case of master sword shuffle
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
// This section sets up the equipment on the first time going adult.
// 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) {
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[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));
(EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) |
(EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 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) &&
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.buttonItems[0] = ITEM_NONE;
Flags_SetInfTable(INFTABLE_SWORDLESS);
}
// Set the dpad to nothing
gSaveContext.equips.buttonItems[4] = ITEM_NONE;
gSaveContext.equips.buttonItems[5] = ITEM_NONE;
@@ -1505,25 +1503,25 @@ void Inventory_SwapAgeEquipment(void) {
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];
gSaveContext.equips.buttonItems[i] =
gSaveContext.adultEquips.buttonItems[i];
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))) {
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]];
}
}
// In Rando, when switching to adult for the second+ time, if a sword was not previously
// equiped in MS shuffle, then we need to set the swordless flag again
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
// 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);
}
@@ -1531,90 +1529,43 @@ void Inventory_SwapAgeEquipment(void) {
gSaveContext.equips.equipment = gSaveContext.adultEquips.equipment;
}
} 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++) {
gSaveContext.adultEquips.buttonItems[i] = gSaveContext.equips.buttonItems[i];
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;
// 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++) {
gSaveContext.equips.buttonItems[i] = gSaveContext.childEquips.buttonItems[i];
gSaveContext.equips.buttonItems[i] =
gSaveContext.childEquips.buttonItems[i];
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) &&
(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]];
}
}
// In Rando, when switching to child from a swordless adult, and child Link previously had a
// sword equiped, then we need to unset the swordless flag to match
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) &&
gSaveContext.equips.buttonItems[0] != ITEM_NONE) {
Flags_UnsetInfTable(INFTABLE_SWORDLESS);
}
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);
} 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);
}
}
// 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++) {
@@ -1629,20 +1580,147 @@ void Inventory_SwapAgeEquipment(void) {
(EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4));
}
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) &&
(gSaveContext.equips.buttonItems[0] == ITEM_NONE)) {
// 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);
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));
}
} 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);
}
}
CVarSetInteger("gSwitchTimeline", 0);
shieldEquipValue = gEquipMasks[EQUIP_TYPE_SHIELD] & gSaveContext.equips.equipment;
if (shieldEquipValue != 0) {
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) &&
(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.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))) {
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));
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
}
}
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];
+2
View File
@@ -2307,10 +2307,12 @@ void Player_DrawPause(PlayState* play, u8* segment, SkelAnime* skelAnime, Vec3f*
}
srcTable = ResourceMgr_LoadArrayByNameAsVec3s(srcTable);
Vec3s* ogSrcTable = srcTable;
destTable = skelAnime->jointTable;
for (i = 0; i < skelAnime->limbCount; i++) {
*destTable++ = *srcTable++;
}
free(ogSrcTable);
}
+28
View File
@@ -78,6 +78,10 @@ void SkelAnime_DrawLod(PlayState* play, void** skeleton, Vec3s* jointTable,
Vec3f pos;
Vec3s rot;
if (CVarGetInteger("gDisableLOD", 0)) {
lod = 0;
}
if (skeleton == NULL) {
osSyncPrintf(VT_FGCOL(RED));
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];
play->flexLimbOverrideMTX = mtx;
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
Matrix_TranslateRotateZYX(&pos, &rot);
if (newDList != NULL) {
@@ -191,6 +197,10 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable,
Vec3s rot;
Mtx* mtx = Graph_Alloc(play->state.gfxCtx, dListCount * sizeof(Mtx));
if (CVarGetInteger("gDisableLOD", 0)) {
lod = 0;
}
if (skeleton == NULL) {
osSyncPrintf(VT_FGCOL(RED));
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];
play->flexLimbOverrideMTX = &mtx;
if ((overrideLimbDraw == 0) || !overrideLimbDraw(play, 1, &newDList, &pos, &rot, arg)) {
Matrix_TranslateRotateZYX(&pos, &rot);
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
*/
@@ -375,6 +401,8 @@ void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton,
newDList = limbDList = limb->dList;
play->flexLimbOverrideMTX = limbMatricies;
if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) {
Matrix_TranslateRotateZYX(&pos, &rot);
if (newDList != NULL) {
@@ -1288,6 +1288,10 @@ block_1:
if (*dList != NULL) {
OPEN_DISPS(play->state.gfxCtx);
if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
}
mtxScaleZ = 1.0f;
mtxScaleY = 1.0f;
@@ -1308,11 +1312,20 @@ block_1:
Matrix_RotateX(-(this->unk_25C[limbIndex] * 0.115f), 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);
Matrix_Pop();
if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
(*play->flexLimbOverrideMTX)++;
}
CLOSE_DISPS(play->state.gfxCtx);
}
{ s32 pad; } // Required to match
@@ -2015,12 +2015,26 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f
Matrix_TranslateRotateZYX(pos, rot);
if (*dList != NULL) {
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
}
Matrix_Push();
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);
Matrix_Pop();
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
(*play->flexLimbOverrideMTX)++;
}
}
doNotDrawLimb = true;
@@ -2034,14 +2048,28 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f
Matrix_TranslateRotateZYX(pos, rot);
if (*dList != NULL) {
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
MATRIX_TOMTX(*play->flexLimbOverrideMTX);
}
Matrix_Push();
Matrix_Scale(this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4],
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);
Matrix_Pop();
if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) {
(*play->flexLimbOverrideMTX)++;
}
}
doNotDrawLimb = true;
@@ -1055,7 +1055,7 @@ void DoorWarp1_DrawBlueCrystal(DoorWarp1* this, PlayState* play) {
gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 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);
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);
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);
CLOSE_DISPS(play->state.gfxCtx);
@@ -768,7 +768,7 @@ void EnBili_Draw(Actor* thisx, PlayState* play) {
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);
CLOSE_DISPS(play->state.gfxCtx);
}
@@ -947,7 +947,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) {
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
gSPSegment(POLY_OPA_DISP++, 0x08, EnBox_EmptyDList(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);
} else if (this->alpha != 0) {
gDPPipeSync(POLY_XLU_DISP++);
@@ -958,7 +958,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) {
} else {
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);
}
+2 -2
View File
@@ -856,7 +856,7 @@ void EnBw_Draw(Actor* thisx, PlayState* play2) {
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gDPSetEnvColor(POLY_OPA_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
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);
} else {
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);
gDPSetEnvColor(POLY_XLU_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a);
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);
}
@@ -708,14 +708,14 @@ void EnEiyer_Draw(Actor* thisx, PlayState* play) {
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
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);
} else {
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280);
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);
}
CLOSE_DISPS(play->state.gfxCtx);
@@ -1540,7 +1540,7 @@ void EnElf_Draw(Actor* thisx, PlayState* play) {
gSPEndDisplayList(dListHead++);
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
(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);
CLOSE_DISPS(play->state.gfxCtx);
@@ -837,8 +837,9 @@ void EnFirefly_Draw(Actor* thisx, PlayState* play) {
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
}
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, &this->actor, POLY_OPA_DISP);
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw,
&this->actor, POLY_OPA_DISP);
CLOSE_DISPS(play->state.gfxCtx);
}
@@ -854,7 +855,7 @@ void EnFirefly_DrawInvisible(Actor* thisx, PlayState* play) {
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);
CLOSE_DISPS(play->state.gfxCtx);
}
@@ -858,7 +858,7 @@ void EnPartner_Draw(Actor* thisx, PlayState* play) {
gSPEndDisplayList(dListHead++);
gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b,
(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);
CLOSE_DISPS(play->state.gfxCtx);
@@ -267,7 +267,7 @@ void EnPoDesert_Draw(Actor* thisx, PlayState* play) {
} else {
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);
CLOSE_DISPS(play->state.gfxCtx);
}
@@ -944,15 +944,14 @@ void EnPoField_Draw(Actor* thisx, PlayState* play) {
this->lightColor.a));
gSPSegment(POLY_OPA_DISP++, 0x0C, D_80116280 + 2);
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);
} else {
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b,
this->lightColor.a));
gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280);
POLY_XLU_DISP =
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_XLU_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) {
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);
POLY_OPA_DISP =
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP);
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoSisters_OverrideLimbDraw,
EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP);
} else {
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->unk_22E.a);
gSPSegment(POLY_XLU_DISP++, 0x09, D_80116280);
POLY_XLU_DISP =
SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime,
EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_XLU_DISP);
}
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) {
gDPSetEnvColor(POLY_OPA_DISP++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a);
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);
} else {
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->lightColor.a);
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);
}
gDPPipeSync(POLY_OPA_DISP++);
@@ -814,7 +814,7 @@ void EnVali_Draw(Actor* thisx, PlayState* 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);
CLOSE_DISPS(play->state.gfxCtx);
@@ -640,13 +640,13 @@ void EnWeiyer_Draw(Actor* thisx, PlayState* play) {
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255);
POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_OPA_DISP);
POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnWeiyer_OverrideLimbDraw, NULL, &this->actor,
POLY_OPA_DISP);
} else {
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]);
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);
}
@@ -101,13 +101,18 @@ static f32 sSpawnSin;
s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* pos) {
f32 phi_f12;
if (CVarGetInteger("gDisableDrawDistance", 0) != 0) {
return true;
}
SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, pos, &this->actor.projectedPos,
&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));
if ((-this->actor.uncullZoneScale < this->actor.projectedPos.z) &&
+2 -2
View File
@@ -2252,7 +2252,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) {
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->alpha);
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);
if (this->iceTimer != 0) {
@@ -2271,7 +2271,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) {
gDPPipeSync(POLY_XLU_DISP++);
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha);
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);
}
CLOSE_DISPS(play->state.gfxCtx);
@@ -275,7 +275,12 @@ void ObjMure_InitialAction(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->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
ObjMure_SpawnActors(this, play);
@@ -398,8 +403,13 @@ static ObjMureActionFunc sTypeGroupBehaviorFunc[] = {
void ObjMure_ActiveState(ObjMure* this, PlayState* 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->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
ObjMure_KillActors(this, play);
@@ -190,8 +190,7 @@ void func_80B9A658(ObjMure2* this) {
void func_80B9A668(ObjMure2* this, PlayState* play) {
if (Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z) <
(sDistSquared1[this->actor.params & 3] * this->unk_184) ||
CVarGetInteger("gDisableDrawDistance", 0) != 0) {
(sDistSquared1[this->actor.params & 3] * this->unk_184)) {
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
ObjMure2_SpawnActors(this, play);
func_80B9A6E8(this);
@@ -205,12 +204,8 @@ void func_80B9A6E8(ObjMure2* this) {
void func_80B9A6F8(ObjMure2* this, PlayState* play) {
func_80B9A534(this);
if (CVarGetInteger("gDisableDrawDistance", 0) != 0) {
return;
}
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;
ObjMure2_CleanupAndDie(this, play);
func_80B9A658(this);
@@ -225,5 +220,20 @@ void ObjMure2_Update(Actor* thisx, PlayState* play) {
} else {
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);
}
@@ -11339,10 +11339,6 @@ void Player_Draw(Actor* thisx, PlayState* play2) {
lod = 1;
}
if (CVarGetInteger("gDisableLOD", 0) != 0) {
lod = 0;
}
func_80093C80(play);
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
@@ -692,6 +692,7 @@ void FileChoose_UpdateOptionsMenu(GameState* thisx) {
sLastOptionButtonIndex = -1;
osSyncPrintf("SAVE");
Save_SaveGlobal();
CVarSave();
osSyncPrintf(VT_FGCOL(YELLOW));
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 moveCursorResult;
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) ||
(CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON);
bool pauseAnyCursor = pauseCtx->cursorSpecialPos == 0 && ((CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) ||
(CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON));
// only allow mask select when:
// the shop is open: