Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions soh/assets/objects/object_custom_equip/object_custom_equip.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ static const ALIGN_ASSET(2) char gCustomAdultFPSHandDL[] = dgCustomAdultFPSHandD
#define dgCustomChildFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildFPSHandDL"
static const ALIGN_ASSET(2) char gCustomChildFPSHandDL[] = dgCustomChildFPSHandDL;

#define dgCustomAdultGoronFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultGoronFPSHandDL"
static const ALIGN_ASSET(2) char gCustomAdultGoronFPSHandDL[] = dgCustomAdultGoronFPSHandDL;

#define dgCustomChildGoronFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildGoronFPSHandDL"
static const ALIGN_ASSET(2) char gCustomChildGoronFPSHandDL[] = dgCustomChildGoronFPSHandDL;

#define dgCustomAdultZoraFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultZoraFPSHandDL"
static const ALIGN_ASSET(2) char gCustomAdultZoraFPSHandDL[] = dgCustomAdultZoraFPSHandDL;

#define dgCustomChildZoraFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildZoraFPSHandDL"
static const ALIGN_ASSET(2) char gCustomChildZoraFPSHandDL[] = dgCustomChildZoraFPSHandDL;

#endif // OBJECTS_OBJECT_CUSTOM_EQUIP_H
173 changes: 173 additions & 0 deletions soh/soh/Enhancements/cosmetics/CustomTunicDLs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include "soh/Enhancements/cosmetics/CustomTunicDLs.h"

#include "soh/ResourceManagerHelpers.h"

#include "variables.h"
#include "z64item.h"

#include <string>
#include <string_view>
#include <unordered_map>

namespace {
constexpr std::string_view kOtrPrefix = "__OTR__";

enum class TunicType {
None,
Goron,
Zora,
};

TunicType GetTunicType() {
s32 tunicEquip = (gSaveContext.equips.equipment & gEquipMasks[EQUIP_TYPE_TUNIC]) >> gEquipShifts[EQUIP_TYPE_TUNIC];
switch (tunicEquip) {
case EQUIP_VALUE_TUNIC_GORON:
return TunicType::Goron;
case EQUIP_VALUE_TUNIC_ZORA:
return TunicType::Zora;
default:
return TunicType::None;
}
}

struct RemapEntry {
std::string_view base;
std::string_view goron;
std::string_view zora;
};

constexpr RemapEntry kRemapEntries[] = {
{ "objects/object_link_boy/gLinkAdultLeftHandClosedNearDL",
"objects/object_link_boy_goron/gLinkAdultLeftHandClosedNearDL",
"objects/object_link_boy_zora/gLinkAdultLeftHandClosedNearDL" },
{ "objects/object_link_boy/gLinkAdultLeftHandNearDL", "objects/object_link_boy_goron/gLinkAdultLeftHandNearDL",
"objects/object_link_boy_zora/gLinkAdultLeftHandNearDL" },
{ "objects/object_link_boy/gLinkAdultLeftHandOutNearDL",
"objects/object_link_boy_goron/gLinkAdultLeftHandOutNearDL",
"objects/object_link_boy_zora/gLinkAdultLeftHandOutNearDL" },
{ "objects/object_link_boy/gLinkAdultRightHandClosedNearDL",
"objects/object_link_boy_goron/gLinkAdultRightHandClosedNearDL",
"objects/object_link_boy_zora/gLinkAdultRightHandClosedNearDL" },
{ "objects/object_link_boy/gLinkAdultRightHandHoldingOotNearDL",
"objects/object_link_boy_goron/gLinkAdultRightHandHoldingOotNearDL",
"objects/object_link_boy_zora/gLinkAdultRightHandHoldingOotNearDL" },
{ "objects/object_link_boy/gLinkAdultRightHandNearDL", "objects/object_link_boy_goron/gLinkAdultRightHandNearDL",
"objects/object_link_boy_zora/gLinkAdultRightHandNearDL" },
{ "objects/object_link_boy/gLinkAdultRightArmOutNearDL",
"objects/object_link_boy_goron/gLinkAdultRightArmOutNearDL",
"objects/object_link_boy_zora/gLinkAdultRightArmOutNearDL" },
{ "objects/object_link_boy/gLinkAdultRightHandOutNearDL",
"objects/object_link_boy_goron/gLinkAdultRightHandOutNearDL",
"objects/object_link_boy_zora/gLinkAdultRightHandOutNearDL" },
{ "objects/object_link_boy/gLinkAdultRightHandHoldingHookshotFarDL",
"objects/object_link_boy_goron/gLinkAdultRightHandHoldingHookshotFarDL",
"objects/object_link_boy_zora/gLinkAdultRightHandHoldingHookshotFarDL" },
{ "objects/object_link_boy/gLinkAdultRightHandHoldingBowFirstPersonDL",
"objects/object_link_boy_goron/gLinkAdultRightHandHoldingBowFirstPersonDL",
"objects/object_link_boy_zora/gLinkAdultRightHandHoldingBowFirstPersonDL" },
{ "objects/object_link_child/gLinkChildLeftFistNearDL", "objects/object_link_child_goron/gLinkChildLeftFistNearDL",
"objects/object_link_child_zora/gLinkChildLeftFistNearDL" },
{ "objects/object_link_child/gLinkChildLeftHandHoldingMasterSwordDL",
"objects/object_link_child_goron/gLinkChildLeftHandHoldingMasterSwordDL",
"objects/object_link_child_zora/gLinkChildLeftHandHoldingMasterSwordDL" },
{ "objects/object_link_child/gLinkChildLeftHandNearDL", "objects/object_link_child_goron/gLinkChildLeftHandNearDL",
"objects/object_link_child_zora/gLinkChildLeftHandNearDL" },
{ "objects/object_link_child/gLinkChildLeftHandUpNearDL",
"objects/object_link_child_goron/gLinkChildLeftHandUpNearDL",
"objects/object_link_child_zora/gLinkChildLeftHandUpNearDL" },
{ "objects/object_link_child/gLinkChildRightHandClosedNearDL",
"objects/object_link_child_goron/gLinkChildRightHandClosedNearDL",
"objects/object_link_child_zora/gLinkChildRightHandClosedNearDL" },
{ "objects/object_link_child/gLinkChildRightArmStretchedSlingshotDL",
"objects/object_link_child_goron/gLinkChildRightArmStretchedSlingshotDL",
"objects/object_link_child_zora/gLinkChildRightArmStretchedSlingshotDL" },
{ "objects/object_link_child/gLinkChildRightHandNearDL",
"objects/object_link_child_goron/gLinkChildRightHandNearDL",
"objects/object_link_child_zora/gLinkChildRightHandNearDL" },
{ "objects/object_link_child/gLinkChildRightHandHoldingFairyOcarinaNearDL",
"objects/object_link_child_goron/gLinkChildRightHandHoldingFairyOcarinaNearDL",
"objects/object_link_child_zora/gLinkChildRightHandHoldingFairyOcarinaNearDL" },
{ "objects/object_link_child/gLinkChildRightHandAndOotNearDL",
"objects/object_link_child_goron/gLinkChildRightHandAndOotNearDL",
"objects/object_link_child_zora/gLinkChildRightHandAndOotNearDL" },
{ "objects/object_custom_equip/gCustomAdultFPSHandDL", "objects/object_custom_equip/gCustomAdultGoronFPSHandDL",
"objects/object_custom_equip/gCustomAdultZoraFPSHandDL" },
{ "objects/object_custom_equip/gCustomChildFPSHandDL", "objects/object_custom_equip/gCustomChildGoronFPSHandDL",
"objects/object_custom_equip/gCustomChildZoraFPSHandDL" },
{ "objects/object_link_boy/gLinkAdultLeftIronBootDL", "objects/object_link_boy_goron/gLinkAdultLeftIronBootDL",
"objects/object_link_boy_zora/gLinkAdultLeftIronBootDL" },
{ "objects/object_link_boy/gLinkAdultRightIronBootDL", "objects/object_link_boy_goron/gLinkAdultRightIronBootDL",
"objects/object_link_boy_zora/gLinkAdultRightIronBootDL" },
{ "objects/object_link_boy/gLinkAdultLeftHoverBootDL", "objects/object_link_boy_goron/gLinkAdultLeftHoverBootDL",
"objects/object_link_boy_zora/gLinkAdultLeftHoverBootDL" },
{ "objects/object_link_boy/gLinkAdultRightHoverBootDL", "objects/object_link_boy_goron/gLinkAdultRightHoverBootDL",
"objects/object_link_boy_zora/gLinkAdultRightHoverBootDL" },
};

std::string_view StripOtrPrefix(std::string_view path) {
if (path.starts_with(kOtrPrefix)) {
return path.substr(kOtrPrefix.size());
}
return path;
}

bool TargetExists(std::string_view path) {
return ResourceMgr_FileExists(path.data()) ||
(ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileAltExists(path.data()));
}

std::string_view GetRemapTarget(std::string_view view, TunicType tunicType) {
if (tunicType == TunicType::None) {
return {};
}

for (const auto& entry : kRemapEntries) {
if (view == entry.base) {
return (tunicType == TunicType::Goron) ? entry.goron : entry.zora;
}
}

return {};
}

const char* MakeRemappedPath(std::string_view target, bool hasOtrPrefix) {
std::string fullPath;
if (hasOtrPrefix) {
fullPath.reserve(kOtrPrefix.size() + target.size());
fullPath.append(kOtrPrefix);
fullPath.append(target);
} else {
fullPath.assign(target);
}

static thread_local std::unordered_map<std::string, std::string> remappedCache;
auto [it, inserted] = remappedCache.emplace(fullPath, fullPath);
return it->second.c_str();
}
} // namespace

const char* CustomTunicDLs_RemapPath(const char* path) {
if (path == nullptr) {
return path;
}

std::string_view view(path);
bool hasOtrPrefix = view.starts_with(kOtrPrefix);
view = StripOtrPrefix(view);

TunicType tunicType = GetTunicType();
if (tunicType == TunicType::None) {
return path;
}

std::string_view target = GetRemapTarget(view, tunicType);
if (target.empty()) {
return path;
}

if (!TargetExists(target)) {
return path;
}

return MakeRemappedPath(target, hasOtrPrefix);
}
3 changes: 3 additions & 0 deletions soh/soh/Enhancements/cosmetics/CustomTunicDLs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

const char* CustomTunicDLs_RemapPath(const char* path);
7 changes: 7 additions & 0 deletions soh/soh/Enhancements/customequipment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#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/cosmetics/CustomTunicDLs.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
#include "soh/ResourceManagerHelpers.h"
Expand Down Expand Up @@ -373,6 +374,12 @@ static void ApplyCommonEquipmentPatches() {
const char* fpsHand = isChild ? gCustomChildFPSHandDL : gCustomAdultFPSHandDL;
const char* rightHandNear = isChild ? gLinkChildRightHandNearDL : gLinkAdultRightHandNearDL;

auto remapTunicHand = [](const char* path) { return CustomTunicDLs_RemapPath(path); };
rightHandClosed = remapTunicHand(rightHandClosed);
leftHandClosed = remapTunicHand(leftHandClosed);
fpsHand = remapTunicHand(fpsHand);
rightHandNear = remapTunicHand(rightHandNear);

ApplyPatchEntries({
{ gLinkAdultLeftHandHoldingMasterSwordNearDL, gCustomMasterSwordDL, "customMasterSword1", "customMasterSword2",
"customMasterSword3", leftHandClosed },
Expand Down
2 changes: 2 additions & 0 deletions soh/soh/ResourceManagerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "cvar_prefixes.h"
#include "Enhancements/enhancementTypes.h"
#include "Enhancements/randomizer/dungeon.h"
#include "Enhancements/cosmetics/CustomTunicDLs.h"
#include <libultraship/libultraship.h>
#include <soh/GameVersions.h>
#include "resource/type/SohResourceType.h"
Expand Down Expand Up @@ -297,6 +298,7 @@ extern "C" void ResourceMgr_PushCurrentDirectory(char* path) {
}

extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) {
path = CustomTunicDLs_RemapPath(path);
// When an alt resource exists for the DL, we need to unload the original asset
// to clear the cache so the alt asset will be loaded instead
// OTRTODO: If Alt loading over original cache is fixed, this line can most likely be removed
Expand Down
Loading