modding: alt equipment (#6062)
Implements object_custom_equip objects that adds more support to have items modified by modders without having to export with hands or do xml edits to load hands. This is autonomous if exported as a object_custom_equip Also adds non existing DisplayList for items that originally did not have a DisplayList. Longshot and Big Goron Sword Sheath is 2 examples
This commit is contained in:
118
soh/assets/objects/object_custom_equip/object_custom_equip.h
Normal file
118
soh/assets/objects/object_custom_equip/object_custom_equip.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef OBJECTS_OBJECT_CUSTOM_EQUIP_H
|
||||
#define OBJECTS_OBJECT_CUSTOM_EQUIP 1
|
||||
|
||||
#include "align_asset_macro.h"
|
||||
|
||||
// Custom Equipment Display Lists
|
||||
#define dgCustomBowDL "__OTR__objects/object_custom_equip/gCustomBowDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBowDL[] = dgCustomBowDL;
|
||||
|
||||
#define dgCustomHammerDL "__OTR__objects/object_custom_equip/gCustomHammerDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHammerDL[] = dgCustomHammerDL;
|
||||
|
||||
#define dgCustomHookshotDL "__OTR__objects/object_custom_equip/gCustomHookshotDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHookshotDL[] = dgCustomHookshotDL;
|
||||
|
||||
#define dgCustomLongshotDL "__OTR__objects/object_custom_equip/gCustomLongshotDL"
|
||||
static const ALIGN_ASSET(2) char gCustomLongshotDL[] = dgCustomLongshotDL;
|
||||
|
||||
#define dgCustomHookshotTipDL "__OTR__objects/object_custom_equip/gCustomHookshotTipDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHookshotTipDL[] = dgCustomHookshotTipDL;
|
||||
|
||||
#define dgCustomHookshotChainDL "__OTR__objects/object_custom_equip/gCustomHookshotChainDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHookshotChainDL[] = dgCustomHookshotChainDL;
|
||||
|
||||
#define dgCustomSlingshotDL "__OTR__objects/object_custom_equip/gCustomSlingshotDL"
|
||||
static const ALIGN_ASSET(2) char gCustomSlingshotDL[] = dgCustomSlingshotDL;
|
||||
|
||||
#define dgCustomFairyOcarinaDL "__OTR__objects/object_custom_equip/gCustomFairyOcarinaDL"
|
||||
static const ALIGN_ASSET(2) char gCustomFairyOcarinaDL[] = dgCustomFairyOcarinaDL;
|
||||
|
||||
#define dgCustomOcarinaOfTimeDL "__OTR__objects/object_custom_equip/gCustomOcarinaOfTimeDL"
|
||||
static const ALIGN_ASSET(2) char gCustomOcarinaOfTimeDL[] = dgCustomOcarinaOfTimeDL;
|
||||
|
||||
#define dgCustomFairyOcarinaAdultDL "__OTR__objects/object_custom_equip/gCustomFairyOcarinaAdultDL"
|
||||
static const ALIGN_ASSET(2) char gCustomFairyOcarinaAdultDL[] = dgCustomFairyOcarinaAdultDL;
|
||||
|
||||
#define dgCustomOcarinaOfTimeAdultDL "__OTR__objects/object_custom_equip/gCustomOcarinaOfTimeAdultDL"
|
||||
static const ALIGN_ASSET(2) char gCustomOcarinaOfTimeAdultDL[] = dgCustomOcarinaOfTimeAdultDL;
|
||||
|
||||
#define dgCustomBoomerangDL "__OTR__objects/object_custom_equip/gCustomBoomerangDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBoomerangDL[] = dgCustomBoomerangDL;
|
||||
|
||||
#define dgCustomKokiriSwordDL "__OTR__objects/object_custom_equip/gCustomKokiriSwordDL"
|
||||
static const ALIGN_ASSET(2) char gCustomKokiriSwordDL[] = dgCustomKokiriSwordDL;
|
||||
|
||||
#define dgCustomKokiriSwordSheathDL "__OTR__objects/object_custom_equip/gCustomKokiriSwordSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomKokiriSwordSheathDL[] = dgCustomKokiriSwordSheathDL;
|
||||
|
||||
#define dgCustomKokiriSwordInSheathDL "__OTR__objects/object_custom_equip/gCustomKokiriSwordInSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomKokiriSwordInSheathDL[] = dgCustomKokiriSwordInSheathDL;
|
||||
|
||||
#define dgCustomMasterSwordDL "__OTR__objects/object_custom_equip/gCustomMasterSwordDL"
|
||||
static const ALIGN_ASSET(2) char gCustomMasterSwordDL[] = dgCustomMasterSwordDL;
|
||||
|
||||
#define dgCustomMasterSwordSheathDL "__OTR__objects/object_custom_equip/gCustomMasterSwordSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomMasterSwordSheathDL[] = dgCustomMasterSwordSheathDL;
|
||||
|
||||
#define dgCustomMasterSwordInSheathDL "__OTR__objects/object_custom_equip/gCustomMasterSwordInSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomMasterSwordInSheathDL[] = dgCustomMasterSwordInSheathDL;
|
||||
|
||||
#define dgCustomLongswordDL "__OTR__objects/object_custom_equip/gCustomLongswordDL"
|
||||
static const ALIGN_ASSET(2) char gCustomLongswordDL[] = dgCustomLongswordDL;
|
||||
|
||||
#define dgCustomBreakableLongswordDL "__OTR__objects/object_custom_equip/gCustomBreakableLongswordDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBreakableLongswordDL[] = dgCustomBreakableLongswordDL;
|
||||
|
||||
#define dgCustomBrokenLongswordDL "__OTR__objects/object_custom_equip/gCustomBrokenLongswordDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBrokenLongswordDL[] = dgCustomBrokenLongswordDL;
|
||||
|
||||
#define dgCustomLongswordSheathDL "__OTR__objects/object_custom_equip/gCustomLongswordSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomLongswordSheathDL[] = dgCustomLongswordSheathDL;
|
||||
|
||||
#define dgCustomLongswordInSheathDL "__OTR__objects/object_custom_equip/gCustomLongswordInSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomLongswordInSheathDL[] = dgCustomLongswordInSheathDL;
|
||||
|
||||
#define dgCustomBreakableLongswordSheathDL "__OTR__objects/object_custom_equip/gCustomBreakableLongswordSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBreakableLongswordSheathDL[] = dgCustomBreakableLongswordSheathDL;
|
||||
|
||||
#define dgCustomBreakableLongswordInSheathDL "__OTR__objects/object_custom_equip/gCustomBreakableLongswordInSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBreakableLongswordInSheathDL[] = dgCustomBreakableLongswordInSheathDL;
|
||||
|
||||
#define dgCustomBrokenLongswordSheathDL "__OTR__objects/object_custom_equip/gCustomBrokenLongswordSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBrokenLongswordSheathDL[] = dgCustomBrokenLongswordSheathDL;
|
||||
|
||||
#define dgCustomBrokenLongswordInSheathDL "__OTR__objects/object_custom_equip/gCustomBrokenLongswordInSheathDL"
|
||||
static const ALIGN_ASSET(2) char gCustomBrokenLongswordInSheathDL[] = dgCustomBrokenLongswordInSheathDL;
|
||||
|
||||
#define dgCustomDekuShieldDL "__OTR__objects/object_custom_equip/gCustomDekuShieldDL"
|
||||
static const ALIGN_ASSET(2) char gCustomDekuShieldDL[] = dgCustomDekuShieldDL;
|
||||
|
||||
#define dgCustomDekuShieldOnBackDL "__OTR__objects/object_custom_equip/gCustomDekuShieldOnBackDL"
|
||||
static const ALIGN_ASSET(2) char gCustomDekuShieldOnBackDL[] = dgCustomDekuShieldOnBackDL;
|
||||
|
||||
#define dgCustomHylianShieldDL "__OTR__objects/object_custom_equip/gCustomHylianShieldDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHylianShieldDL[] = dgCustomHylianShieldDL;
|
||||
|
||||
#define dgCustomHylianShieldOnBackDL "__OTR__objects/object_custom_equip/gCustomHylianShieldOnBackDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHylianShieldOnBackDL[] = dgCustomHylianShieldOnBackDL;
|
||||
|
||||
#define dgCustomHylianShieldOnChildBackDL "__OTR__objects/object_custom_equip/gCustomHylianShieldOnChildBackDL"
|
||||
static const ALIGN_ASSET(2) char gCustomHylianShieldOnChildBackDL[] = dgCustomHylianShieldOnChildBackDL;
|
||||
|
||||
#define dgCustomMirrorShieldDL "__OTR__objects/object_custom_equip/gCustomMirrorShieldDL"
|
||||
static const ALIGN_ASSET(2) char gCustomMirrorShieldDL[] = dgCustomMirrorShieldDL;
|
||||
|
||||
#define dgCustomMirrorShieldOnBackDL "__OTR__objects/object_custom_equip/gCustomMirrorShieldOnBackDL"
|
||||
static const ALIGN_ASSET(2) char gCustomMirrorShieldOnBackDL[] = dgCustomMirrorShieldOnBackDL;
|
||||
|
||||
// Custom First Person Hand Display Lists
|
||||
#define dgCustomAdultFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultFPSHandDL"
|
||||
static const ALIGN_ASSET(2) char gCustomAdultFPSHandDL[] = dgCustomAdultFPSHandDL;
|
||||
|
||||
#define dgCustomChildFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildFPSHandDL"
|
||||
static const ALIGN_ASSET(2) char gCustomChildFPSHandDL[] = dgCustomChildFPSHandDL;
|
||||
|
||||
|
||||
|
||||
#endif // OBJECTS_OBJECT_CUSTOM_EQUIP_H
|
||||
536
soh/soh/Enhancements/customequipment.cpp
Normal file
536
soh/soh/Enhancements/customequipment.cpp
Normal file
@@ -0,0 +1,536 @@
|
||||
#include <initializer_list>
|
||||
#include "src/overlays/actors/ovl_En_Elf/z_en_elf.h"
|
||||
#include "objects/object_link_boy/object_link_boy.h"
|
||||
#include "objects/object_link_child/object_link_child.h"
|
||||
#include "objects/object_custom_equip/object_custom_equip.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
#include "soh/ResourceManagerHelpers.h"
|
||||
#include "soh_assets.h"
|
||||
#include "kaleido.h"
|
||||
#include "soh/cvar_prefixes.h"
|
||||
|
||||
extern SaveContext gSaveContext;
|
||||
extern PlayState* gPlayState;
|
||||
extern void Overlay_DisplayText(float duration, const char* text);
|
||||
void DummyPlayer_Update(Actor* actor, PlayState* play);
|
||||
|
||||
static void UpdatePatchCustomEquipmentDlists();
|
||||
static void RefreshCustomEquipment();
|
||||
static bool HasDummyPlayers();
|
||||
|
||||
static const char* ResolveCustomChain(std::initializer_list<const char*> paths) {
|
||||
const char* fallback = nullptr;
|
||||
for (auto path : paths) {
|
||||
if (path != nullptr) {
|
||||
fallback = path;
|
||||
if (ResourceMgr_FileExists(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
static const char* GetBreakableLongswordDL() {
|
||||
return ResolveCustomChain({ gCustomBreakableLongswordDL, gCustomLongswordDL });
|
||||
}
|
||||
|
||||
static const char* GetBreakableLongswordSheathDL() {
|
||||
return ResolveCustomChain({ gCustomBreakableLongswordSheathDL, gCustomLongswordSheathDL });
|
||||
}
|
||||
|
||||
static const char* GetBreakableLongswordInSheathDL() {
|
||||
return ResolveCustomChain({ gCustomBreakableLongswordInSheathDL, gCustomLongswordInSheathDL });
|
||||
}
|
||||
|
||||
static const char* GetBrokenLongswordSheathDL() {
|
||||
return ResolveCustomChain(
|
||||
{ gCustomBrokenLongswordSheathDL, gCustomBreakableLongswordSheathDL, gCustomLongswordSheathDL });
|
||||
}
|
||||
|
||||
static const char* GetBrokenLongswordInSheathDL() {
|
||||
return ResolveCustomChain(
|
||||
{ gCustomBrokenLongswordInSheathDL, gCustomBreakableLongswordInSheathDL, gCustomLongswordInSheathDL });
|
||||
}
|
||||
|
||||
static void UpdateCustomEquipmentSetModel(Player* player, u8 ModelGroup) {
|
||||
(void)ModelGroup;
|
||||
|
||||
if (player == nullptr || gPlayState == nullptr || player != GET_PLAYER(gPlayState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshCustomEquipment();
|
||||
}
|
||||
|
||||
static void UpdateCustomEquipment() {
|
||||
if (!GameInteractor::IsSaveLoaded() || gPlayState == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
if (player == nullptr || player->actor.update == DummyPlayer_Update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool altAssetsRuntime = ResourceMgr_IsAltAssetsEnabled();
|
||||
|
||||
// If multiplayer dummy actors are present, skip patching shared resources to avoid corrupting them.
|
||||
if (HasDummyPlayers() && altAssetsRuntime) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshCustomEquipment();
|
||||
}
|
||||
|
||||
static void PatchCustomEquipment() {
|
||||
COND_HOOK(OnPlayerSetModels, true, UpdateCustomEquipmentSetModel);
|
||||
COND_HOOK(OnLinkEquipmentChange, true, UpdateCustomEquipment);
|
||||
COND_HOOK(OnLinkSkeletonInit, true, UpdateCustomEquipment);
|
||||
COND_HOOK(OnAssetAltChange, true, UpdateCustomEquipment);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(PatchCustomEquipment);
|
||||
|
||||
static void RefreshCustomEquipment() {
|
||||
if (!GameInteractor::IsSaveLoaded() || gPlayState == NULL || GET_PLAYER(gPlayState) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool hasDummyPlayers = HasDummyPlayers();
|
||||
const bool altAssetsRuntime = ResourceMgr_IsAltAssetsEnabled();
|
||||
|
||||
// Keep custom patches off dummy players, but still allow unpatching when alt assets are disabled so we can
|
||||
// restore vanilla display lists.
|
||||
if (hasDummyPlayers && altAssetsRuntime) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePatchCustomEquipmentDlists();
|
||||
}
|
||||
|
||||
void PatchOrUnpatch(const char* resource, const char* gfx, const char* dlist1, const char* dlist2, const char* dlist3,
|
||||
const char* alternateDL) {
|
||||
if (resource == NULL || gfx == NULL || dlist1 == NULL || dlist2 == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool altAssetsRuntime = ResourceMgr_IsAltAssetsEnabled();
|
||||
|
||||
if (!altAssetsRuntime) {
|
||||
// Alt assets are off; ensure any prior patches using these names are reverted.
|
||||
ResourceMgr_UnpatchGfxByName(resource, dlist1);
|
||||
ResourceMgr_UnpatchGfxByName(resource, dlist2);
|
||||
if (dlist3 != NULL) {
|
||||
ResourceMgr_UnpatchGfxByName(resource, dlist3);
|
||||
}
|
||||
// Drop any cached version of the resource so it reloads clean (unpatched) next use.
|
||||
ResourceMgr_UnloadResource(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ResourceGetIsCustomByName(gfx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (alternateDL == NULL || ResourceGetIsCustomByName(alternateDL) || ResourceMgr_FileExists(alternateDL)) {
|
||||
ResourceMgr_PatchCustomGfxByName(resource, dlist1, 0, gsSPDisplayListOTRFilePath(gfx));
|
||||
if (dlist3 == NULL) {
|
||||
ResourceMgr_PatchCustomGfxByName(resource, dlist2, 1, gsSPEndDisplayList());
|
||||
} else {
|
||||
ResourceMgr_PatchCustomGfxByName(resource, dlist2, 1, gsSPDisplayListOTRFilePath(alternateDL));
|
||||
}
|
||||
if (dlist3 != NULL) {
|
||||
ResourceMgr_PatchCustomGfxByName(resource, dlist3, 2, gsSPEndDisplayList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PatchEntry {
|
||||
const char* resource;
|
||||
const char* gfx;
|
||||
const char* dlist1;
|
||||
const char* dlist2;
|
||||
const char* dlist3;
|
||||
const char* alternateDL;
|
||||
};
|
||||
|
||||
static void ApplyPatchEntries(std::initializer_list<PatchEntry> entries) {
|
||||
for (const auto& entry : entries) {
|
||||
PatchOrUnpatch(entry.resource, entry.gfx, entry.dlist1, entry.dlist2, entry.dlist3, entry.alternateDL);
|
||||
}
|
||||
}
|
||||
|
||||
static void UnpatchGroup(const char* resource, std::initializer_list<const char*> dlistNames) {
|
||||
for (const char* name : dlistNames) {
|
||||
ResourceMgr_UnpatchGfxByName(resource, name);
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplySwordlessChildPatches() {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildDekuShieldWithMatrixDL, gCustomDekuShieldOnBackDL, "customChildShieldOnly1",
|
||||
"customChildShieldOnly2", nullptr, nullptr },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, gCustomHylianShieldOnChildBackDL, "customChildHylianShieldOnly1",
|
||||
"customChildHylianShieldOnly2", nullptr, nullptr },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, gCustomMirrorShieldOnBackDL, "customAdultMirrorOnly1",
|
||||
"customAdultMirrorOnly2", nullptr, nullptr },
|
||||
});
|
||||
|
||||
UnpatchGroup(gLinkChildSwordAndSheathNearDL, { "customKokiriSwordSheath1", "customKokiriSwordSheath2" });
|
||||
UnpatchGroup(gLinkChildSheathNearDL, { "customKokiriSheath1", "customKokiriSheath2" });
|
||||
UnpatchGroup(gLinkChildDekuShieldSwordAndSheathNearDL,
|
||||
{ "customDekuShieldSword1", "customDekuShieldSword2", "customDekuShieldSword3" });
|
||||
UnpatchGroup(gLinkChildHylianShieldSwordAndSheathNearDL,
|
||||
{ "customChildHylianShieldSword1", "customChildHylianShieldSword2", "customChildHylianShieldSword3" });
|
||||
}
|
||||
|
||||
static void ApplySwordlessAdultPatches() {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, gCustomHylianShieldOnBackDL, "customAdultShieldOnly1",
|
||||
"customAdultShieldOnly2", nullptr, nullptr },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, gCustomMirrorShieldOnBackDL, "customAdultMirrorOnly1",
|
||||
"customAdultMirrorOnly2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, gCustomDekuShieldOnBackDL, "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", nullptr, nullptr },
|
||||
});
|
||||
|
||||
UnpatchGroup(gLinkAdultMasterSwordAndSheathNearDL, { "customMasterSwordSheath1", "customMasterSwordSheath2" });
|
||||
}
|
||||
|
||||
static void ApplyKokiriSwordPatches() {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildSheathNearDL, gCustomKokiriSwordSheathDL, "customKokiriSheath1", "customKokiriSheath2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkChildSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customKokiriSwordSheath1",
|
||||
"customKokiriSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", "customDekuShieldSword3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildDekuShieldAndSheathNearDL, gCustomKokiriSwordSheathDL, "customDekuShieldSheath1",
|
||||
"customDekuShieldSheath2", "customDekuShieldSheath3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customChildHylianShieldSword1",
|
||||
"customChildHylianShieldSword2", "customChildHylianShieldSword3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkChildHylianShieldAndSheathNearDL, gCustomKokiriSwordSheathDL, "customChildHylianShieldSheath1",
|
||||
"customChildHylianShieldSheath2", "customChildHylianShieldSheath3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkAdultSheathNearDL, gCustomKokiriSwordSheathDL, "customSheath1", "customSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customHylianShieldSword1",
|
||||
"customHylianShieldSword2", "customHylianShieldSword3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMasterSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customMasterSwordSheath1",
|
||||
"customMasterSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldAndSheathNearDL, gCustomKokiriSwordSheathDL, "customHylianShieldSheath1",
|
||||
"customHylianShieldSheath2", "customHylianShieldSheath3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, gCustomKokiriSwordInSheathDL, "customMirrorShieldSword1",
|
||||
"customMirrorShieldSword2", "customMirrorShieldSword3", gCustomMirrorShieldOnBackDL },
|
||||
});
|
||||
}
|
||||
|
||||
static void ApplyMasterSwordPatches() {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildDekuShieldWithMatrixDL, gCustomMasterSwordInSheathDL, "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldAndSheathNearDL, gCustomMasterSwordSheathDL, "customChildHylianShieldSheath1",
|
||||
"customChildHylianShieldSheath2", "customChildHylianShieldSheath3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkChildSheathNearDL, gCustomMasterSwordSheathDL, "customKokiriSheath1", "customKokiriSheath2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkChildSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customKokiriSwordSheath1",
|
||||
"customKokiriSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", "customDekuShieldSword3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildDekuShieldAndSheathNearDL, gCustomMasterSwordSheathDL, "customDekuShieldSheath1",
|
||||
"customDekuShieldSheath2", "customDekuShieldSheath3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customChildHylianShieldSword1",
|
||||
"customChildHylianShieldSword2", "customChildHylianShieldSword3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkAdultSheathNearDL, gCustomMasterSwordSheathDL, "customSheath1", "customSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultMasterSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customMasterSwordSheath1",
|
||||
"customMasterSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customHylianShieldSword1",
|
||||
"customHylianShieldSword2", "customHylianShieldSword3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultHylianShieldAndSheathNearDL, gCustomMasterSwordSheathDL, "customHylianShieldSheath1",
|
||||
"customHylianShieldSheath2", "customHylianShieldSheath3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, gCustomMasterSwordInSheathDL, "customMirrorShieldSword1",
|
||||
"customMirrorShieldSword2", "customMirrorShieldSword3", gCustomMirrorShieldOnBackDL },
|
||||
});
|
||||
}
|
||||
|
||||
static void ApplyBiggoronSwordPatches() {
|
||||
if (gPlayState != nullptr && GET_PLAYER(gPlayState)->sheathType == PLAYER_MODELTYPE_SHEATH_19) {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, gCustomLongswordSheathDL, "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
} else {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, gCustomLongswordInSheathDL, "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
}
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildHylianShieldAndSheathNearDL, gCustomLongswordSheathDL, "customChildHylianShieldSheath1",
|
||||
"customChildHylianShieldSheath2", "customChildHylianShieldSheath3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkChildDekuShieldAndSheathNearDL, gCustomLongswordSheathDL, "customDekuShieldSheath1",
|
||||
"customDekuShieldSheath2", "customDekuShieldSheath3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkAdultLeftHandHoldingBgsNearDL, gCustomLongswordDL, "customBGS1", "customBGS2", "customBGS3",
|
||||
gLinkAdultLeftHandClosedNearDL },
|
||||
{ gLinkAdultMasterSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customMasterSwordSheath1",
|
||||
"customMasterSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildSheathNearDL, gCustomLongswordSheathDL, "customKokiriSheath1", "customKokiriSheath2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkChildSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customKokiriSwordSheath1",
|
||||
"customKokiriSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", "customDekuShieldSword3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customChildHylianShieldSword1",
|
||||
"customChildHylianShieldSword2", "customChildHylianShieldSword3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkAdultSheathNearDL, gCustomLongswordSheathDL, "customSheath1", "customSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customHylianShieldSword1",
|
||||
"customHylianShieldSword2", "customHylianShieldSword3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultHylianShieldAndSheathNearDL, gCustomLongswordSheathDL, "customHylianShieldSheath1",
|
||||
"customHylianShieldSheath2", "customHylianShieldSheath3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, gCustomLongswordInSheathDL, "customMirrorShieldSword1",
|
||||
"customMirrorShieldSword2", "customMirrorShieldSword3", gCustomMirrorShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldAndSheathNearDL, gCustomLongswordSheathDL, "customMirrorShieldSheath1",
|
||||
"customMirrorShieldSheath2", "customMirrorShieldSheath3", gCustomMirrorShieldOnBackDL },
|
||||
});
|
||||
}
|
||||
|
||||
static void ApplyBreakableLongswordPatches() {
|
||||
if (gPlayState != nullptr && GET_PLAYER(gPlayState)->sheathType == PLAYER_MODELTYPE_SHEATH_19) {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, GetBreakableLongswordSheathDL(), "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
} else {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, GetBreakableLongswordInSheathDL(), "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
}
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildHylianShieldAndSheathNearDL, GetBreakableLongswordSheathDL(), "customChildHylianShieldSheath1",
|
||||
"customChildHylianShieldSheath2", "customChildHylianShieldSheath3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkChildDekuShieldAndSheathNearDL, GetBreakableLongswordSheathDL(), "customDekuShieldSheath1",
|
||||
"customDekuShieldSheath2", "customDekuShieldSheath3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkAdultLeftHandHoldingBgsNearDL, GetBreakableLongswordDL(), "customGK1", "customGK2", "customGK3",
|
||||
gLinkAdultLeftHandClosedNearDL },
|
||||
{ gLinkAdultMasterSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(), "customMasterSwordSheath1",
|
||||
"customMasterSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildSheathNearDL, GetBreakableLongswordSheathDL(), "customKokiriSheath1", "customKokiriSheath2",
|
||||
nullptr, nullptr },
|
||||
{ gLinkChildSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(), "customKokiriSwordSheath1",
|
||||
"customKokiriSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(), "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", "customDekuShieldSword3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(),
|
||||
"customChildHylianShieldSword1", "customChildHylianShieldSword2", "customChildHylianShieldSword3",
|
||||
gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkAdultSheathNearDL, GetBreakableLongswordSheathDL(), "customSheath1", "customSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(), "customHylianShieldSword1",
|
||||
"customHylianShieldSword2", "customHylianShieldSword3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultHylianShieldAndSheathNearDL, GetBreakableLongswordSheathDL(), "customHylianShieldSheath1",
|
||||
"customHylianShieldSheath2", "customHylianShieldSheath3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, GetBreakableLongswordInSheathDL(), "customMirrorShieldSword1",
|
||||
"customMirrorShieldSword2", "customMirrorShieldSword3", gCustomMirrorShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldAndSheathNearDL, GetBreakableLongswordSheathDL(), "customMirrorShieldSheath1",
|
||||
"customMirrorShieldSheath2", "customMirrorShieldSheath3", gCustomMirrorShieldOnBackDL },
|
||||
});
|
||||
}
|
||||
|
||||
static void ApplyBrokenKnifePatches() {
|
||||
if (gPlayState != nullptr && GET_PLAYER(gPlayState)->sheathType == PLAYER_MODELTYPE_SHEATH_19) {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, GetBrokenLongswordSheathDL(), "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
} else {
|
||||
PatchOrUnpatch(gLinkChildDekuShieldWithMatrixDL, GetBrokenLongswordInSheathDL(), "customDekuShieldBack1",
|
||||
"customDekuShieldBack2", "customDekuShieldBack2", gCustomDekuShieldOnBackDL);
|
||||
}
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildHylianShieldAndSheathNearDL, GetBrokenLongswordSheathDL(), "customChildHylianShieldSheath1",
|
||||
"customChildHylianShieldSheath2", "customChildHylianShieldSheath3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkChildDekuShieldAndSheathNearDL, GetBrokenLongswordSheathDL(), "customDekuShieldSheath1",
|
||||
"customDekuShieldSheath2", "customDekuShieldSheath3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkAdultMasterSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customMasterSwordSheath1",
|
||||
"customMasterSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildSheathNearDL, GetBrokenLongswordSheathDL(), "customKokiriSheath1", "customKokiriSheath2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkChildSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customKokiriSwordSheath1",
|
||||
"customKokiriSwordSheath2", nullptr, nullptr },
|
||||
{ gLinkChildDekuShieldSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customDekuShieldSword1",
|
||||
"customDekuShieldSword2", "customDekuShieldSword3", gCustomDekuShieldOnBackDL },
|
||||
{ gLinkChildHylianShieldSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customChildHylianShieldSword1",
|
||||
"customChildHylianShieldSword2", "customChildHylianShieldSword3", gCustomHylianShieldOnChildBackDL },
|
||||
{ gLinkAdultSheathNearDL, GetBrokenLongswordSheathDL(), "customSheath1", "customSheath2", nullptr, nullptr },
|
||||
{ gLinkAdultHylianShieldSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customHylianShieldSword1",
|
||||
"customHylianShieldSword2", "customHylianShieldSword3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultHylianShieldAndSheathNearDL, GetBrokenLongswordSheathDL(), "customHylianShieldSheath1",
|
||||
"customHylianShieldSheath2", "customHylianShieldSheath3", gCustomHylianShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldSwordAndSheathNearDL, GetBrokenLongswordInSheathDL(), "customMirrorShieldSword1",
|
||||
"customMirrorShieldSword2", "customMirrorShieldSword3", gCustomMirrorShieldOnBackDL },
|
||||
{ gLinkAdultMirrorShieldAndSheathNearDL, GetBrokenLongswordSheathDL(), "customMirrorShieldSheath1",
|
||||
"customMirrorShieldSheath2", "customMirrorShieldSheath3", gCustomMirrorShieldOnBackDL },
|
||||
});
|
||||
}
|
||||
|
||||
static void ApplyCommonEquipmentPatches() {
|
||||
const bool isChild = LINK_IS_CHILD;
|
||||
const char* rightHandClosed = isChild ? gLinkChildRightHandClosedNearDL : gLinkAdultRightHandClosedNearDL;
|
||||
const char* leftHandClosed = isChild ? gLinkChildLeftFistNearDL : gLinkAdultLeftHandClosedNearDL;
|
||||
const char* fpsHand = isChild ? gCustomChildFPSHandDL : gCustomAdultFPSHandDL;
|
||||
const char* rightHandNear = isChild ? gLinkChildRightHandNearDL : gLinkAdultRightHandNearDL;
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultLeftHandHoldingMasterSwordNearDL, gCustomMasterSwordDL, "customMasterSword1", "customMasterSword2",
|
||||
"customMasterSword3", leftHandClosed },
|
||||
{ gLinkAdultRightHandHoldingHylianShieldNearDL, gCustomHylianShieldDL, "customHylianShield1",
|
||||
"customHylianShield2", "customHylianShield3", rightHandClosed },
|
||||
{ gLinkAdultRightHandHoldingMirrorShieldNearDL, gCustomMirrorShieldDL, "customMirrorShield1",
|
||||
"customMirrorShield2", "customMirrorShield3", rightHandClosed },
|
||||
{ gLinkAdultHandHoldingBrokenGiantsKnifeDL, gCustomBrokenLongswordDL, "customBrokenBGS1", "customBrokenBGS2",
|
||||
"customBrokenBGS3", leftHandClosed },
|
||||
{ gLinkChildLeftFistAndKokiriSwordNearDL, gCustomKokiriSwordDL, "customKokiriSword1", "customKokiriSword2",
|
||||
"customKokiriSword3", leftHandClosed },
|
||||
{ gLinkChildRightFistAndDekuShieldNearDL, gCustomDekuShieldDL, "customDekuShield1", "customDekuShield2",
|
||||
"customDekuShield3", rightHandClosed },
|
||||
});
|
||||
|
||||
if (INV_CONTENT(ITEM_HOOKSHOT) == ITEM_HOOKSHOT) {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultRightHandHoldingHookshotNearDL, gCustomHookshotDL, "customHookshot1", "customHookshot2",
|
||||
"customHookshot3", rightHandClosed },
|
||||
{ gLinkAdultRightHandHoldingHookshotFarDL, gCustomHookshotDL, "customHookshotFPS1", "customHookshotFPS2",
|
||||
"customHookshotFPS3", fpsHand },
|
||||
});
|
||||
}
|
||||
|
||||
if (INV_CONTENT(ITEM_LONGSHOT) == ITEM_LONGSHOT) {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultRightHandHoldingHookshotNearDL, gCustomLongshotDL, "customHookshot1", "customHookshot2",
|
||||
"customHookshot3", rightHandClosed },
|
||||
{ gLinkAdultRightHandHoldingHookshotFarDL, gCustomLongshotDL, "customHookshotFPS1", "customHookshotFPS2",
|
||||
"customHookshotFPS3", fpsHand },
|
||||
});
|
||||
}
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultHookshotTipDL, gCustomHookshotTipDL, "customHookshotTip1", "customHookshotTip2", nullptr, nullptr },
|
||||
{ gLinkAdultHookshotChainDL, gCustomHookshotChainDL, "customHookshotChain1", "customHookshotChain2", nullptr,
|
||||
nullptr },
|
||||
});
|
||||
|
||||
if (INV_CONTENT(ITEM_OCARINA_FAIRY) == ITEM_OCARINA_FAIRY) {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultRightHandHoldingOotNearDL, isChild ? gCustomFairyOcarinaDL : gCustomFairyOcarinaAdultDL,
|
||||
"customOcarina1", "customOcarina2", "customOcarina3", rightHandNear },
|
||||
});
|
||||
}
|
||||
|
||||
if (INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME) {
|
||||
ApplyPatchEntries({
|
||||
{ gLinkAdultRightHandHoldingOotNearDL, isChild ? gCustomOcarinaOfTimeDL : gCustomOcarinaOfTimeAdultDL,
|
||||
"customOcarina1", "customOcarina2", "customOcarina3", rightHandNear },
|
||||
});
|
||||
}
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildRightHandHoldingFairyOcarinaNearDL, gCustomFairyOcarinaDL, "customFairyOcarina1",
|
||||
"customFairyOcarina2", "customFairyOcarina3", rightHandNear },
|
||||
{ gLinkChildRightHandAndOotNearDL, gCustomOcarinaOfTimeDL, "customChildOcarina1", "customChildOcarina2",
|
||||
"customChildOcarina3", rightHandNear },
|
||||
{ gLinkAdultRightHandHoldingBowNearDL, gCustomBowDL, "customBow1", "customBow2", "customBow3",
|
||||
rightHandClosed },
|
||||
{ gLinkAdultRightHandHoldingBowFirstPersonDL, gCustomBowDL, "customBowFPS1", "customBowFPS2", "customBowFPS3",
|
||||
fpsHand },
|
||||
{ gLinkAdultLeftHandHoldingHammerNearDL, gCustomHammerDL, "customHammer1", "customHammer2", "customHammer3",
|
||||
leftHandClosed },
|
||||
{ gLinkChildLeftFistAndBoomerangNearDL, gCustomBoomerangDL, "customBoomerang1", "customBoomerang2",
|
||||
"customBoomerang3", leftHandClosed },
|
||||
{ gLinkChildRightHandHoldingSlingshotNearDL, gCustomSlingshotDL, "customSlingshot1", "customSlingshot2",
|
||||
"customSlingshot3", rightHandClosed },
|
||||
{ gLinkChildRightArmStretchedSlingshotDL, gCustomSlingshotDL, "customSlingshotFPS1", "customSlingshotFPS2",
|
||||
"customSlingshotFPS3", fpsHand },
|
||||
});
|
||||
|
||||
ApplyPatchEntries({
|
||||
{ gLinkChildRightHandHoldingFairyOcarinaNearDL, gCustomFairyOcarinaDL, "customFairyOcarina1",
|
||||
"customFairyOcarina2", "customFairyOcarina3", rightHandNear },
|
||||
{ gLinkChildRightHandAndOotNearDL, gCustomOcarinaOfTimeDL, "customChildOcarina1", "customChildOcarina2",
|
||||
"customChildOcarina3", rightHandNear },
|
||||
{ gLinkChildLeftFistAndBoomerangNearDL, gCustomBoomerangDL, "customBoomerang1", "customBoomerang2",
|
||||
"customBoomerang3", leftHandClosed },
|
||||
{ gLinkChildRightHandHoldingSlingshotNearDL, gCustomSlingshotDL, "customSlingshot1", "customSlingshot2",
|
||||
"customSlingshot3", rightHandClosed },
|
||||
{ gLinkChildRightArmStretchedSlingshotDL, gCustomSlingshotDL, "customSlingshotFPS1", "customSlingshotFPS2",
|
||||
"customSlingshotFPS3", fpsHand },
|
||||
});
|
||||
|
||||
const bool equipmentAlwaysVisible = CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0) != 0;
|
||||
|
||||
if (LINK_IS_CHILD && equipmentAlwaysVisible) {
|
||||
ApplyPatchEntries({
|
||||
{ gCustomAdultFPSHandDL, gCustomChildFPSHandDL, "patchChildFPSHand1", "patchChildFPSHand2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkAdultRightHandClosedNearDL, gLinkChildRightHandClosedNearDL, "customChildRightHand1",
|
||||
"customChildRightHand2", nullptr, nullptr },
|
||||
{ gLinkAdultLeftHandClosedNearDL, gLinkChildLeftFistNearDL, "customChildLeftHand1", "customChildLeftHand2",
|
||||
nullptr, nullptr },
|
||||
});
|
||||
}
|
||||
|
||||
if (LINK_IS_ADULT && equipmentAlwaysVisible) {
|
||||
ApplyPatchEntries({
|
||||
{ gCustomChildFPSHandDL, gCustomAdultFPSHandDL, "patchAdultFPSHand1", "patchAdultFPSHand2", nullptr,
|
||||
nullptr },
|
||||
{ gLinkChildRightHandClosedNearDL, gLinkAdultRightHandClosedNearDL, "customAdultRightHand1",
|
||||
"customAdultRightHand2", nullptr, nullptr },
|
||||
{ gLinkChildLeftFistNearDL, gLinkAdultLeftHandClosedNearDL, "customAdultLeftHand1", "customAdultLeftHand2",
|
||||
nullptr, nullptr },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePatchCustomEquipmentDlists() {
|
||||
const u8 equippedSword = gSaveContext.equips.buttonItems[0];
|
||||
|
||||
if (equippedSword == ITEM_NONE) {
|
||||
if (LINK_IS_CHILD) {
|
||||
ApplySwordlessChildPatches();
|
||||
}
|
||||
if (LINK_IS_ADULT) {
|
||||
ApplySwordlessAdultPatches();
|
||||
}
|
||||
}
|
||||
|
||||
switch (equippedSword) {
|
||||
case ITEM_SWORD_KOKIRI:
|
||||
ApplyKokiriSwordPatches();
|
||||
break;
|
||||
case ITEM_SWORD_MASTER:
|
||||
ApplyMasterSwordPatches();
|
||||
break;
|
||||
case ITEM_SWORD_BGS:
|
||||
if (gSaveContext.bgsFlag) {
|
||||
ApplyBiggoronSwordPatches();
|
||||
} else {
|
||||
ApplyBreakableLongswordPatches();
|
||||
}
|
||||
break;
|
||||
case ITEM_SWORD_KNIFE:
|
||||
ApplyBrokenKnifePatches();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ApplyCommonEquipmentPatches();
|
||||
}
|
||||
|
||||
static bool HasDummyPlayers() {
|
||||
if (gPlayState == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Actor* actor = gPlayState->actorCtx.actorLists[ACTORCAT_NPC].head;
|
||||
while (actor != nullptr) {
|
||||
if (actor->id == ACTOR_EN_OE2 && actor->update == DummyPlayer_Update) {
|
||||
return true;
|
||||
}
|
||||
actor = actor->next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -43,6 +43,7 @@ DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnBossDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnTimestamp, (u8 item));
|
||||
DEFINE_HOOK(OnPlayerBonk, ());
|
||||
DEFINE_HOOK(OnPlayerSetModels, (Player * player, u8 modelGroup));
|
||||
DEFINE_HOOK(OnPlayerHealthChange, (int16_t amount));
|
||||
DEFINE_HOOK(OnPlayerBottleUpdate, (int16_t contents));
|
||||
DEFINE_HOOK(OnPlayerHoldUpShield, ());
|
||||
|
||||
@@ -201,6 +201,10 @@ void GameInteractor_ExecuteOnPlayerBonk() {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerBonk>();
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPlayerSetModels(Player* player, u8 modelGroup) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerSetModels>(player, modelGroup);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPlayerHealthChange(int16_t amount) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerHealthChange>(amount);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ void GameInteractor_ExecuteOnEnemyDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnBossDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnTimestamp(u8 item);
|
||||
void GameInteractor_ExecuteOnPlayerBonk();
|
||||
void GameInteractor_ExecuteOnPlayerSetModels(Player* player, u8 modelGroup);
|
||||
void GameInteractor_ExecuteOnPlayerHealthChange(int16_t amount);
|
||||
void GameInteractor_ExecuteOnPlayerBottleUpdate(int16_t contents);
|
||||
void GameInteractor_ExecuteOnPlayerHoldUpShield();
|
||||
|
||||
@@ -314,6 +314,9 @@ extern "C" uint8_t ResourceMgr_FileIsCustomByName(const char* path) {
|
||||
typedef struct {
|
||||
int index;
|
||||
Gfx instruction;
|
||||
const void* instructionsPtr;
|
||||
size_t instructionCount;
|
||||
bool isCustom;
|
||||
} GfxPatch;
|
||||
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, GfxPatch>> originalGfx;
|
||||
@@ -324,6 +327,10 @@ extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchNa
|
||||
auto res = std::static_pointer_cast<Fast::DisplayList>(
|
||||
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
||||
|
||||
if (res == nullptr || static_cast<size_t>(index) >= res->Instructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Leaving this here for people attempting to find the correct Dlist index to patch
|
||||
/*if (strcmp("__OTR__objects/object_gi_longsword/gGiBiggoronSwordDL", path) == 0) {
|
||||
for (int i = 0; i < res->instructions.size(); i++) {
|
||||
@@ -351,7 +358,8 @@ extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchNa
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[index];
|
||||
|
||||
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
|
||||
originalGfx[path][patchName] = { index, *gfx };
|
||||
originalGfx[path][patchName] = { index, *gfx, res->Instructions.data(), res->Instructions.size(),
|
||||
res->GetInitData()->IsCustom };
|
||||
}
|
||||
|
||||
*gfx = instruction;
|
||||
@@ -362,6 +370,11 @@ extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const ch
|
||||
auto res = std::static_pointer_cast<Fast::DisplayList>(
|
||||
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
||||
|
||||
if (res == nullptr || static_cast<size_t>(destinationIndex) >= res->Instructions.size() ||
|
||||
static_cast<size_t>(sourceIndex) >= res->Instructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not patch custom assets as they most likely do not have the same instructions as authentic assets
|
||||
if (res->GetInitData()->IsCustom) {
|
||||
return;
|
||||
@@ -371,19 +384,62 @@ extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const ch
|
||||
Gfx sourceGfx = *(Gfx*)&res->Instructions[sourceIndex];
|
||||
|
||||
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
|
||||
originalGfx[path][patchName] = { destinationIndex, *destinationGfx };
|
||||
originalGfx[path][patchName] = { destinationIndex, *destinationGfx, res->Instructions.data(),
|
||||
res->Instructions.size(), res->GetInitData()->IsCustom };
|
||||
}
|
||||
|
||||
*destinationGfx = sourceGfx;
|
||||
}
|
||||
|
||||
extern "C" void ResourceMgr_PatchCustomGfxByName(const char* path, const char* patchName, int index, Gfx instruction) {
|
||||
auto res = std::static_pointer_cast<Fast::DisplayList>(
|
||||
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
||||
|
||||
if (res == nullptr || static_cast<size_t>(index) >= res->Instructions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[index];
|
||||
|
||||
if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) {
|
||||
originalGfx[path][patchName] = { index, *gfx, res->Instructions.data(), res->Instructions.size(),
|
||||
res->GetInitData()->IsCustom };
|
||||
}
|
||||
|
||||
*gfx = instruction;
|
||||
}
|
||||
|
||||
extern "C" void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName) {
|
||||
if (originalGfx.contains(path) && originalGfx[path].contains(patchName)) {
|
||||
auto res = std::static_pointer_cast<Fast::DisplayList>(
|
||||
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
|
||||
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[originalGfx[path][patchName].index];
|
||||
*gfx = originalGfx[path][patchName].instruction;
|
||||
// If the resource is unavailable (e.g. swapped out when toggling alt assets), clean up the record and bail.
|
||||
if (res == nullptr) {
|
||||
ResourceMgr_UnloadResource(path);
|
||||
originalGfx[path].erase(patchName);
|
||||
return;
|
||||
}
|
||||
|
||||
const GfxPatch& patch = originalGfx[path][patchName];
|
||||
// Skip and clean up if the backing resource changed since we recorded the patch (e.g. alt<->vanilla swap)
|
||||
// to avoid writing instructions from a different asset onto the current one.
|
||||
if (res->Instructions.data() != patch.instructionsPtr || res->Instructions.size() != patch.instructionCount ||
|
||||
res->GetInitData()->IsCustom != patch.isCustom) {
|
||||
ResourceMgr_UnloadResource(path);
|
||||
originalGfx[path].erase(patchName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip and clean up if the loaded resource is smaller than the recorded patch index (can happen when alt assets
|
||||
// swap in shorter display lists).
|
||||
if (static_cast<size_t>(patch.index) >= res->Instructions.size()) {
|
||||
originalGfx[path].erase(patchName);
|
||||
return;
|
||||
}
|
||||
|
||||
Gfx* gfx = (Gfx*)&res->Instructions[patch.index];
|
||||
*gfx = patch.instruction;
|
||||
|
||||
originalGfx[path].erase(patchName);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
|
||||
Gfx* ResourceMgr_LoadGfxByName(const char* path);
|
||||
uint8_t ResourceMgr_FileIsCustomByName(const char* path);
|
||||
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
|
||||
void ResourceMgr_PatchCustomGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
|
||||
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
|
||||
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
|
||||
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
|
||||
@@ -65,4 +66,4 @@ int ResourceMgr_OTRSigCheck(char* imgData);
|
||||
char* ResourceMgr_GetResourceDataByNameHandlingMQ(const char* path);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -650,6 +650,7 @@ void Player_SetModels(Player* this, s32 modelGroup) {
|
||||
this->waistDLists = &sPlayerDListGroups[gPlayerModelTypes[modelGroup][4]][gSaveContext.linkAge];
|
||||
|
||||
Player_SetModelsForHoldingShield(this);
|
||||
GameInteractor_ExecuteOnPlayerSetModels(this, modelGroup);
|
||||
}
|
||||
|
||||
void Player_SetModelGroup(Player* this, s32 modelGroup) {
|
||||
@@ -1481,7 +1482,6 @@ s32 Player_OverrideLimbDrawGameplayFirstPerson(PlayState* play, s32 limbIndex, G
|
||||
*dList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user