Custom Tunics (#4774)

* Custom Tunics

Co-authored-by: MoriyaFaith 46070717+MoriyaFaith@users.noreply.github.com

* Works for necessary scenarios

* make variable static again
This commit is contained in:
inspectredc 2025-01-05 09:05:12 +00:00 committed by GitHub
parent 91720a3857
commit f0b02d6c7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 149 additions and 2 deletions

View File

@ -162,3 +162,22 @@ static const ALIGN_ASSET(2) char gFileSelLanguageGERTex[] = dgFileSelLanguageGER
#define dgEmptyTexture "__OTR__textures/virtual/gEmptyTexture"
static const ALIGN_ASSET(2) char gEmptyTexture[] = dgEmptyTexture;
// Custom Tunic Models
#define dgLinkChildKokiriTunicSkel "__OTR__objects/object_link_child_kokiri/gLinkChildKokiriTunicSkel"
static const ALIGN_ASSET(2) char gLinkChildKokiriTunicSkel[] = dgLinkChildKokiriTunicSkel;
#define dgLinkChildGoronTunicSkel "__OTR__objects/object_link_child_goron/gLinkChildGoronTunicSkel"
static const ALIGN_ASSET(2) char gLinkChildGoronTunicSkel[] = dgLinkChildGoronTunicSkel;
#define dgLinkChildZoraTunicSkel "__OTR__objects/object_link_child_zora/gLinkChildZoraTunicSkel"
static const ALIGN_ASSET(2) char gLinkChildZoraTunicSkel[] = dgLinkChildZoraTunicSkel;
#define dgLinkAdultKokiriTunicSkel "__OTR__objects/object_link_boy_kokiri/gLinkAdultKokiriTunicSkel"
static const ALIGN_ASSET(2) char gLinkAdultKokiriTunicSkel[] = dgLinkAdultKokiriTunicSkel;
#define dgLinkAdultGoronTunicSkel "__OTR__objects/object_link_boy_goron/gLinkAdultGoronTunicSkel"
static const ALIGN_ASSET(2) char gLinkAdultGoronTunicSkel[] = dgLinkAdultGoronTunicSkel;
#define dgLinkAdultZoraTunicSkel "__OTR__objects/object_link_boy_zora/gLinkAdultZoraTunicSkel"
static const ALIGN_ASSET(2) char gLinkAdultZoraTunicSkel[] = dgLinkAdultZoraTunicSkel;

View File

@ -5,6 +5,7 @@
#include "soh/OTRGlobals.h"
#include "soh/SaveManager.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/resource/type/Skeleton.h"
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
#include "soh/Enhancements/boss-rush/BossRush.h"
#include "soh/Enhancements/enhancementTypes.h"
@ -38,6 +39,7 @@
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
#include "soh_assets.h"
#include "kaleido.h"
extern "C" {
@ -1435,6 +1437,30 @@ void RegisterRandomizerCompasses() {
});
}
void RegisterCustomSkeletons() {
static int8_t previousTunic = -1;
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!GameInteractor::IsSaveLoaded() || gPlayState == NULL) {
return;
}
if (CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC) != previousTunic) {
SOH::SkeletonPatcher::UpdateCustomSkeletons();
}
previousTunic = CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC);
});
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnAssetAltChange>([]() {
if (!GameInteractor::IsSaveLoaded() || gPlayState == NULL) {
return;
}
SOH::SkeletonPatcher::UpdateCustomSkeletons();
});
}
void InitMods() {
BossRush_RegisterHooks();
RandomizerRegisterHooks();
@ -1479,4 +1505,5 @@ void InitMods() {
RegisterHurtContainerModeHandler();
RegisterPauseMenuHooks();
RandoKaleido_RegisterHooks();
RegisterCustomSkeletons();
}

View File

@ -2,6 +2,13 @@
#include "Skeleton.h"
#include "soh/OTRGlobals.h"
#include "libultraship/libultraship.h"
#include <soh_assets.h>
#include <objects/object_link_child/object_link_child.h>
#include <objects/object_link_boy/object_link_boy.h>
extern "C" SaveContext gSaveContext;
extern "C" u16 gEquipMasks[4];
extern "C" u8 gEquipShifts[4];
namespace SOH {
SkeletonData* Skeleton::GetPointer() {
@ -66,10 +73,10 @@ void SkeletonPatcher::ClearSkeletons()
void SkeletonPatcher::UpdateSkeletons() {
auto resourceMgr = Ship::Context::GetInstance()->GetResourceManager();
bool isHD = resourceMgr->IsAltAssetsEnabled();
bool isAlt = resourceMgr->IsAltAssetsEnabled();
for (auto skel : skeletons) {
Skeleton* newSkel =
(Skeleton*)resourceMgr->LoadResource((isHD ? Ship::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true).get();
(Skeleton*)resourceMgr->LoadResource((isAlt ? Ship::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true).get();
if (newSkel != nullptr) {
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
@ -78,4 +85,93 @@ void SkeletonPatcher::UpdateSkeletons() {
}
}
}
void SkeletonPatcher::UpdateCustomSkeletons() {
for (auto skel : skeletons) {
UpdateTunicSkeletons(skel);
}
}
void SkeletonPatcher::UpdateTunicSkeletons(SkeletonPatchInfo& skel) {
std::string skeletonPath = "";
// Check if this is one of Link's skeletons
if (sOtr + skel.vanillaSkeletonPath == std::string(gLinkAdultSkel)) {
// Check what Link's current tunic is
switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) {
case PLAYER_TUNIC_KOKIRI:
skeletonPath = std::string(gLinkAdultKokiriTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_GORON:
skeletonPath = std::string(gLinkAdultGoronTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_ZORA:
skeletonPath = std::string(gLinkAdultZoraTunicSkel).substr(sOtr.length());
break;
default:
return;
}
UpdateCustomSkeletonFromPath(skeletonPath, skel);
} else if (sOtr + skel.vanillaSkeletonPath == std::string(gLinkChildSkel)) {
// Check what Link's current tunic is
switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) {
case PLAYER_TUNIC_KOKIRI:
skeletonPath = std::string(gLinkChildKokiriTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_GORON:
skeletonPath = std::string(gLinkChildGoronTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_ZORA:
skeletonPath = std::string(gLinkChildZoraTunicSkel).substr(sOtr.length());
break;
default:
return;
}
UpdateCustomSkeletonFromPath(skeletonPath, skel);
}
}
void SkeletonPatcher::UpdateCustomSkeletonFromPath(const std::string& skeletonPath, SkeletonPatchInfo& skel) {
Skeleton* newSkel = nullptr;
Skeleton* altSkel = nullptr;
auto resourceMgr = Ship::Context::GetInstance()->GetResourceManager();
bool isAlt = resourceMgr->IsAltAssetsEnabled();
// If alt assets are on, look for alt tagged skeletons
if (isAlt) {
altSkel =
(Skeleton*)Ship::Context::GetInstance()
->GetResourceManager()
->LoadResource(Ship::IResource::gAltAssetPrefix + skeletonPath, true)
.get();
// Override non-alt skeleton if necessary
if (altSkel != nullptr) {
newSkel = altSkel;
}
}
// Load new skeleton based on the custom model if it exists
if (altSkel == nullptr) {
newSkel =
(Skeleton*)Ship::Context::GetInstance()
->GetResourceManager()
->LoadResource(skeletonPath, true)
.get();
}
// Change back to the original skeleton if no skeleton's were found
if (newSkel == nullptr && skeletonPath != skel.vanillaSkeletonPath) {
UpdateCustomSkeletonFromPath(skel.vanillaSkeletonPath, skel);
return;
}
if (newSkel != nullptr) {
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
uintptr_t skelPtr = (uintptr_t)newSkel->GetPointer();
memcpy(&skel.skelAnime->skeletonHeader, &skelPtr, sizeof(uintptr_t));
}
}
} // namespace SOH

View File

@ -86,8 +86,13 @@ class SkeletonPatcher {
static void UnregisterSkeleton(SkelAnime* skelAnime);
static void ClearSkeletons();
static void UpdateSkeletons();
static void UpdateCustomSkeletons();
static std::vector<SkeletonPatchInfo> skeletons;
private:
inline static const std::string sOtr = "__OTR__";
static void UpdateTunicSkeletons(SkeletonPatchInfo& skel);
static void UpdateCustomSkeletonFromPath(const std::string& skeletonPath, SkeletonPatchInfo& skel);
};