mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-07-29 19:18:58 -07:00
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:
parent
91720a3857
commit
f0b02d6c7e
4 changed files with 149 additions and 2 deletions
|
@ -162,3 +162,22 @@ static const ALIGN_ASSET(2) char gFileSelLanguageGERTex[] = dgFileSelLanguageGER
|
||||||
|
|
||||||
#define dgEmptyTexture "__OTR__textures/virtual/gEmptyTexture"
|
#define dgEmptyTexture "__OTR__textures/virtual/gEmptyTexture"
|
||||||
static const ALIGN_ASSET(2) char gEmptyTexture[] = dgEmptyTexture;
|
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;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "soh/SaveManager.h"
|
#include "soh/SaveManager.h"
|
||||||
#include "soh/ResourceManagerHelpers.h"
|
#include "soh/ResourceManagerHelpers.h"
|
||||||
|
#include "soh/resource/type/Skeleton.h"
|
||||||
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
|
#include "soh/Enhancements/boss-rush/BossRushTypes.h"
|
||||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||||
#include "soh/Enhancements/enhancementTypes.h"
|
#include "soh/Enhancements/enhancementTypes.h"
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||||
#include "objects/object_link_boy/object_link_boy.h"
|
#include "objects/object_link_boy/object_link_boy.h"
|
||||||
#include "objects/object_link_child/object_link_child.h"
|
#include "objects/object_link_child/object_link_child.h"
|
||||||
|
#include "soh_assets.h"
|
||||||
#include "kaleido.h"
|
#include "kaleido.h"
|
||||||
|
|
||||||
extern "C" {
|
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() {
|
void InitMods() {
|
||||||
BossRush_RegisterHooks();
|
BossRush_RegisterHooks();
|
||||||
RandomizerRegisterHooks();
|
RandomizerRegisterHooks();
|
||||||
|
@ -1479,4 +1505,5 @@ void InitMods() {
|
||||||
RegisterHurtContainerModeHandler();
|
RegisterHurtContainerModeHandler();
|
||||||
RegisterPauseMenuHooks();
|
RegisterPauseMenuHooks();
|
||||||
RandoKaleido_RegisterHooks();
|
RandoKaleido_RegisterHooks();
|
||||||
|
RegisterCustomSkeletons();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
#include "Skeleton.h"
|
#include "Skeleton.h"
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "libultraship/libultraship.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 {
|
namespace SOH {
|
||||||
SkeletonData* Skeleton::GetPointer() {
|
SkeletonData* Skeleton::GetPointer() {
|
||||||
|
@ -66,10 +73,10 @@ void SkeletonPatcher::ClearSkeletons()
|
||||||
|
|
||||||
void SkeletonPatcher::UpdateSkeletons() {
|
void SkeletonPatcher::UpdateSkeletons() {
|
||||||
auto resourceMgr = Ship::Context::GetInstance()->GetResourceManager();
|
auto resourceMgr = Ship::Context::GetInstance()->GetResourceManager();
|
||||||
bool isHD = resourceMgr->IsAltAssetsEnabled();
|
bool isAlt = resourceMgr->IsAltAssetsEnabled();
|
||||||
for (auto skel : skeletons) {
|
for (auto skel : skeletons) {
|
||||||
Skeleton* newSkel =
|
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) {
|
if (newSkel != nullptr) {
|
||||||
skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment;
|
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
|
} // namespace SOH
|
||||||
|
|
|
@ -86,8 +86,13 @@ class SkeletonPatcher {
|
||||||
static void UnregisterSkeleton(SkelAnime* skelAnime);
|
static void UnregisterSkeleton(SkelAnime* skelAnime);
|
||||||
static void ClearSkeletons();
|
static void ClearSkeletons();
|
||||||
static void UpdateSkeletons();
|
static void UpdateSkeletons();
|
||||||
|
static void UpdateCustomSkeletons();
|
||||||
|
|
||||||
static std::vector<SkeletonPatchInfo> skeletons;
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue