summaryrefslogtreecommitdiff
path: root/src/Game/DLC
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2026-09-28 03:39:31 +0200
committerLéo Lam <leo@leolam.fr>2026-10-06 03:19:39 +0200
commitc4c7c00e85df3137d57cc899302a160ff94fa71b (patch)
tree302fc5bbae0f9b9da17d1e41790b41b8fa44630a /src/Game/DLC
parent38905c8c075ec4ed8f8fcf858aef46bc5e05f8e2 (diff)
aoc: Manager is ksys, the DLC managers stay game-side
aoc::Manager is created during engine start-up and called by gdt, map and StarterPackMgr; only game code uses HardModeManager and ChampionBalladManager. (AI assisted using Claude Fable 5.1 and Claude Opus 5.5)
Diffstat (limited to 'src/Game/DLC')
-rw-r--r--src/Game/DLC/CMakeLists.txt8
-rw-r--r--src/Game/DLC/aocChampionBalladManager.cpp32
-rw-r--r--src/Game/DLC/aocChampionBalladManager.h26
-rw-r--r--src/Game/DLC/aocHardModeManager.cpp335
-rw-r--r--src/Game/DLC/aocHardModeManager.h81
-rw-r--r--src/Game/DLC/aocManager.cpp546
-rw-r--r--src/Game/DLC/aocManager.h132
7 files changed, 0 insertions, 1160 deletions
diff --git a/src/Game/DLC/CMakeLists.txt b/src/Game/DLC/CMakeLists.txt
deleted file mode 100644
index 0b0579b0..00000000
--- a/src/Game/DLC/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-target_sources(uking PRIVATE
- aocChampionBalladManager.cpp
- aocChampionBalladManager.h
- aocHardModeManager.cpp
- aocHardModeManager.h
- aocManager.cpp
- aocManager.h
-)
diff --git a/src/Game/DLC/aocChampionBalladManager.cpp b/src/Game/DLC/aocChampionBalladManager.cpp
deleted file mode 100644
index 0a0833a0..00000000
--- a/src/Game/DLC/aocChampionBalladManager.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "Game/DLC/aocChampionBalladManager.h"
-
-namespace uking {
-
-SEAD_SINGLETON_DISPOSER_IMPL(ChampionBalladManager)
-
-void ChampionBalladManager::init() {
- mBlightCounts = {};
-}
-
-void ChampionBalladManager::setBlightRematchCount(s8 count, BlightType blight_type) {
- if (count >= 0 && blight_type <= BlightType::Water) {
- if (count >= 30) {
- count = 30;
- }
- mBlightCounts[u32(blight_type)] = count;
- }
-}
-
-void ChampionBalladManager::incrementBlightRematchCount(BlightType blight_type) {
- if (blight_type <= BlightType::Water) {
- s8 count = mBlightCounts[u32(blight_type)] + 1;
- setBlightRematchCount(count, blight_type);
- }
-}
-
-s8 ChampionBalladManager::getBlightRematchCount(BlightType blight_type) const {
- if (blight_type <= BlightType::Water)
- return mBlightCounts[u32(blight_type)];
- return 0;
-}
-} // namespace uking
diff --git a/src/Game/DLC/aocChampionBalladManager.h b/src/Game/DLC/aocChampionBalladManager.h
deleted file mode 100644
index 22c07b60..00000000
--- a/src/Game/DLC/aocChampionBalladManager.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <array>
-#include <container/seadSafeArray.h>
-#include <heap/seadDisposer.h>
-
-namespace uking {
-
-enum class BlightType : u32 { Wind, Electric, Fire, Water };
-
-class ChampionBalladManager {
- SEAD_SINGLETON_DISPOSER(ChampionBalladManager)
- ChampionBalladManager() = default;
- virtual ~ChampionBalladManager() = default;
-
-public:
- void init();
- void setBlightRematchCount(s8 count, BlightType blight_type);
- void incrementBlightRematchCount(BlightType blight_type);
- s8 getBlightRematchCount(BlightType blight_type) const;
-
-private:
- sead::SafeArray<u8, 4> mBlightCounts;
-};
-
-} // namespace uking
diff --git a/src/Game/DLC/aocHardModeManager.cpp b/src/Game/DLC/aocHardModeManager.cpp
deleted file mode 100644
index 9d8faef9..00000000
--- a/src/Game/DLC/aocHardModeManager.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-#include "Game/DLC/aocHardModeManager.h"
-#include <math/seadMathCalcCommon.h>
-#include "KingSystem/ActorSystem/actActor.h"
-#include "KingSystem/ActorSystem/actActorUtil.h"
-#include "KingSystem/ActorSystem/actTag.h"
-#include "KingSystem/Utils/InitTimeInfo.h"
-
-namespace uking::aoc {
-
-SEAD_SINGLETON_DISPOSER_IMPL(HardModeManager)
-
-namespace {
-struct aoc2StaticData {
- ksys::util::InitConstants init_constants;
- sead::SafeString flag_name_HardMode_HighScore{"HardMode_HighScore"};
- sead::SafeString flag_name_AoC_HardMode_Enabled{"AoC_HardMode_Enabled"};
- sead::SafeString flag_name_IsLastPlayHardMode{"IsLastPlayHardMode"};
-};
-
-aoc2StaticData sData;
-sead::FixedSafeString<64> sStr{""};
-} // namespace
-
-HardModeManager::HardModeManager()
- : mGdtResetSlot(this, &HardModeManager::setHardModeEnabledFlag),
- mGdtReinitSlot(this, &HardModeManager::initFlagHandles) {
- mMultipliers.fill(0.5);
-
- setHardModeChange(HardModeChange::IsLastPlayHardMode, true);
- setHardModeChange(HardModeChange::EnableShorterEnemyNotice, true);
- setHardModeChange(HardModeChange::EnableLifeRegen, true);
- setHardModeChange(HardModeChange::DisableNoDeathDamage, true);
- setHardModeChange(HardModeChange::PatchGanonStunLock, true);
- setHardModeChange(HardModeChange::RandomizeGuardianChargeBeam, true);
- setHardModeChange(HardModeChange::ApplyDamageMultiplier, true);
-}
-
-void HardModeManager::setHardModeEnabledFlag(ksys::gdt::Manager::ResetEvent*) {
- ksys::gdt::Manager::instance()->setBool(true, mAoCHardModeEnabledFlag);
- mGdtResetSlot.release();
-}
-
-void HardModeManager::initFlagHandles(ksys::gdt::Manager::ReinitEvent*) {
- auto* gdm = ksys::gdt::Manager::instance();
- mHardModeHighScoreFlag = gdm->getS32Handle(sData.flag_name_HardMode_HighScore);
- mAoCHardModeEnabledFlag = gdm->getBoolHandle(sData.flag_name_AoC_HardMode_Enabled);
- mIsLastPlayHardModeFlag = gdm->getBoolHandle(sData.flag_name_IsLastPlayHardMode);
-}
-
-HardModeManager::~HardModeManager() {
- mFileHandle.requestUnload2();
- if (_120) {
- // TODO: use the normal operator delete once we figure out what _120 is
- ::operator delete(_120);
- _120 = nullptr;
- }
-}
-
-void HardModeManager::init(sead::Heap*) {
- init_();
-}
-
-void HardModeManager::init_() {
- initFlagHandles();
- ksys::gdt::Manager::instance()->addReinitCallback(mGdtReinitSlot);
-}
-
-void HardModeManager::nerfHpRestore(f32* hp) const {
- *hp = sead::Mathf::clampMin(*hp * getMultiplier(MultiplierType::HpRestore), 1.0f);
-}
-
-void HardModeManager::nerfHpRestore(s32* hp) const {
- *hp = sead::Mathi::clampMin(*hp * getMultiplier(MultiplierType::HpRestore), 1);
-}
-
-void HardModeManager::modifyEnemyNoticeDuration(f32* value) const {
- *value = sead::Mathf::clampMin(*value * getMultiplier(MultiplierType::EnemyNoticeDuration), 0);
-}
-
-bool HardModeManager::shouldCreateLifeRecoverInfo(ksys::act::Actor* actor) {
- // Health regen should only apply to enemy actors.
- if (!ksys::act::isEnemyProfile(actor))
- return false;
-
- // But not to wolves or bears...
- if (ksys::act::isWolfOrBear(actor))
- return false;
-
- // and not to Dark Beast Ganon...
- if (actor->getName() == "Enemy_GanonBeast")
- return false;
-
- // and not to enemy swarms...
- if (actor->getProfile() == "EnemySwarm")
- return false;
-
- return actor->getMaxLife() > 1;
-}
-
-bool HardModeManager::shouldApplyMasterModeDamageMultiplier(
- const ksys::act::ActorConstDataAccess& accessor) {
- if (!accessor.hasProc())
- return false;
-
- ksys::act::ActorConstDataAccess parent;
- if (accessor.hasConnectedCalcParent() && accessor.acquireConnectedCalcParent(&parent))
- return shouldApplyMasterModeDamageMultiplier(parent);
-
- if (accessor.hasTag(ksys::act::tags::IsMasterModeDamageMultiplierActor) ||
- (HardModeManager::instance() && HardModeManager::instance()->isTestOfStrengthShrine() &&
- accessor.hasTag(ksys::act::tags::AncientGuardTarget))) {
- return true;
- }
-
- const sead::SafeString& profile = accessor.getProfile();
- const sead::SafeString& name = accessor.getName();
-
- if (profile == "LastBoss" || profile == "SiteBoss")
- return true;
-
- if (name == "Enemy_GanonBeast" || name == "GanonShockWave" || name == "EnemyGanonShockWave" ||
- name == "GanonSeaOfFlame" || name == "GanonFlameBall" || name == "GanonPillarOfFlame" ||
- name == "GanonNormalArrow" || name == "GanonSpearForThrowing" || name == "CurseGanonBeam" ||
- name == "GanonBeam" || name == "GanonIceBullet" || name == "GanonThunder" ||
- name == "GanonIronPile" || name == "GanonTornado" || name == "GanonBeastBeam" ||
- name == "SiteBossSeaOfFlame" || name == "SiteBossSeaOfFlameRotate" ||
- name == "SiteBossFlameBall" || name == "SiteBossBigFlameBall" ||
- name == "SiteBossPillarOfFlame" || name == "SiteBossWearFlame" ||
- name == "SiteBossDrawingFlameTornado" || name == "SiteBossGaleArrow" ||
- name == "SiteBossNormalArrow" || name == "SiteBossSpearForThrowing" ||
- name == "SiteBossReflectArrow" || name == "ArrowRainChild" ||
- name == "SiteBossSpearIceBullet" || name == "SiteBossTornado" ||
- name == "LastBossThunder" || name == "Enemy_Assassin_Senior" ||
- name == "AssassinRockBall" || name == "AssassinIronBall") {
- return true;
- }
-
- return false;
-}
-
-void HardModeManager::buffDamage(s32& damage) {
- damage = damage * 1.5f;
- if (damage == 1) {
- damage = 2;
- }
-}
-
-void HardModeManager::loadIsLastPlayHardModeFlag() {
- bool value{};
- ksys::gdt::Manager::instance()->getBool(mIsLastPlayHardModeFlag, &value);
- const bool x = value;
-#ifdef MATCHING_HACK_NX_CLANG
- asm("");
-#endif
- setFlag(Flag::EnableHardMode, x);
-}
-
-void HardModeManager::loadIsHardModeFlag() {
- bool value{};
- ksys::gdt::Manager::instance()->getBool(mAoCHardModeEnabledFlag, &value);
- const bool x = value;
-#ifdef MATCHING_HACK_NX_CLANG
- asm("");
-#endif
- setFlag(Flag::EnableHardMode, x);
-}
-
-void HardModeManager::storeIsLastPlayHardModeFlag() {
- ksys::gdt::Manager::instance()->setBool(checkFlag(Flag::EnableHardMode),
- mIsLastPlayHardModeFlag);
-}
-
-void HardModeManager::resetIsLastPlayHardModeFlag() {
- ksys::gdt::Manager::instance()->setBool(false, "IsLastPlayHardMode");
-}
-
-bool HardModeManager::isTestOfStrengthShrine() const {
- if (mMapType != "CDungeon")
- return false;
-
- // There are 20 ToS shrines in the base game (070-089).
- if (mMapName.startsWith("Dungeon07") || mMapName.startsWith("Dungeon08"))
- return true;
-
- // Ruvo Korbah
- if (mMapName == "Dungeon135")
- return true;
-
- return false;
-}
-
-void HardModeManager::calc() {
- volatile u32 unused = 0;
- static_cast<void>(unused);
-}
-
-bool HardModeManager::rankUpEnemy(const sead::SafeString& actor_name, const ksys::map::Object& obj,
- const char** new_name) {
- if (obj.getFlags().isOn(ksys::map::Object::Flag::HasUniqueName) ||
- obj.getHardModeFlags().isOn(ksys::map::Object::HardModeFlag::DisableRankup)) {
- return false;
- }
-
- if (!actor_name.startsWith("Enemy"))
- return false;
-
- if (isTestOfStrengthShrine())
- return false;
-
- sead::SafeString next = "";
-
- /// @bug Yes, this is duplicated and shouldn't exist.
- if (!actor_name.startsWith("Enemy"))
- return false;
-
- if (actor_name == "Enemy_Assassin_Junior")
- next = "Enemy_Assassin_Middle";
- else if (actor_name == "Enemy_Assassin_Middle")
- next = "Enemy_Assassin_Senior";
- else if (actor_name == "Enemy_Assassin_Shooter_Junior")
- next = "Enemy_Assassin_Shooter_Azito_Junior";
-
- else if (actor_name == "Enemy_Bokoblin_Junior")
- next = "Enemy_Bokoblin_Middle";
- else if (actor_name == "Enemy_Bokoblin_Middle")
- next = "Enemy_Bokoblin_Senior";
- else if (actor_name == "Enemy_Bokoblin_Senior")
- next = "Enemy_Bokoblin_Dark";
- else if (actor_name == "Enemy_Bokoblin_Dark")
- next = "Enemy_Bokoblin_Gold";
-
- else if (actor_name == "Enemy_Bokoblin_Guard_Junior")
- next = "Enemy_Bokoblin_Guard_Middle";
-
- else if (actor_name == "Enemy_Bokoblin_Guard_Junior_Ambush")
- next = "Enemy_Bokoblin_Guard_Middle_Ambush";
-
- else if (actor_name == "Enemy_Bokoblin_Guard_Junior_TreeHouseTop")
- next = "Enemy_Bokoblin_Guard_Middle_TreeHouseTop";
-
- /// @bug Yes, this is duplicated and shouldn't exist.
- else if (actor_name == "Enemy_Bokoblin_Guard_Junior_Ambush")
- next = "Enemy_Bokoblin_Guard_Middle_Ambush";
-
- else if (actor_name == "Enemy_Chuchu_Electric_Junior")
- next = "Enemy_Chuchu_Electric_Middle";
- else if (actor_name == "Enemy_Chuchu_Electric_Middle")
- next = "Enemy_Chuchu_Electric_Senior";
-
- else if (actor_name == "Enemy_Chuchu_Fire_Junior")
- next = "Enemy_Chuchu_Fire_Middle";
- else if (actor_name == "Enemy_Chuchu_Fire_Middle")
- next = "Enemy_Chuchu_Fire_Senior";
-
- else if (actor_name == "Enemy_Chuchu_Ice_Junior")
- next = "Enemy_Chuchu_Ice_Middle";
- else if (actor_name == "Enemy_Chuchu_Ice_Middle")
- next = "Enemy_Chuchu_Ice_Senior";
-
- else if (actor_name == "Enemy_Chuchu_Junior")
- next = "Enemy_Chuchu_Middle";
- else if (actor_name == "Enemy_Chuchu_Middle")
- next = "Enemy_Chuchu_Senior";
-
- else if (actor_name == "Enemy_Giant_Junior")
- next = "Enemy_Giant_Middle";
- else if (actor_name == "Enemy_Giant_Middle")
- next = "Enemy_Giant_Senior";
-
- else if (actor_name == "Enemy_Golem_Junior")
- next = "Enemy_Golem_Middle";
- else if (actor_name == "Enemy_Golem_Middle")
- next = "Enemy_Golem_Senior";
-
- else if (actor_name == "Enemy_Guardian_Mini_Baby")
- next = "Enemy_Guardian_Mini_Junior";
- else if (actor_name == "Enemy_Guardian_Mini_Junior")
- next = "Enemy_Guardian_Mini_Middle";
- else if (actor_name == "Enemy_Guardian_Mini_Middle")
- next = "Enemy_Guardian_Mini_Senior";
-
- else if (actor_name == "Enemy_Guardian_Mini_Junior_DetachLineBeam")
- next = "Enemy_Guardian_Mini_Middle_DetachLineBeam";
-
- else if (actor_name == "Enemy_Lizalfos_Junior")
- next = "Enemy_Lizalfos_Middle";
- else if (actor_name == "Enemy_Lizalfos_Middle")
- next = "Enemy_Lizalfos_Senior";
- else if (actor_name == "Enemy_Lizalfos_Senior")
- next = "Enemy_Lizalfos_Dark";
- else if (actor_name == "Enemy_Lizalfos_Dark")
- next = "Enemy_Lizalfos_Gold";
-
- else if (actor_name == "Enemy_Lizalfos_Guard_Junior")
- next = "Enemy_Lizalfos_Guard_Middle";
-
- else if (actor_name == "Enemy_Lizalfos_Guard_Junior_LongVisibility")
- next = "Enemy_Lizalfos_Guard_Middle_LongVisibility";
-
- else if (actor_name == "Enemy_Lizalfos_Junior_Guard_Ambush")
- next = "Enemy_Lizalfos_Middle_Guard_Ambush";
-
- else if (actor_name == "Enemy_Lynel_Junior")
- next = "Enemy_Lynel_Middle";
- else if (actor_name == "Enemy_Lynel_Middle")
- next = "Enemy_Lynel_Senior";
- else if (actor_name == "Enemy_Lynel_Senior")
- next = "Enemy_Lynel_Dark";
- else if (actor_name == "Enemy_Lynel_Dark")
- next = "Enemy_Lynel_Gold";
-
- else if (actor_name == "Enemy_Moriblin_Junior")
- next = "Enemy_Moriblin_Middle";
- else if (actor_name == "Enemy_Moriblin_Middle")
- next = "Enemy_Moriblin_Senior";
- else if (actor_name == "Enemy_Moriblin_Senior")
- next = "Enemy_Moriblin_Dark";
- else if (actor_name == "Enemy_Moriblin_Dark")
- next = "Enemy_Moriblin_Gold";
-
- else if (actor_name == "Enemy_Wizzrobe_Electric")
- next = "Enemy_Wizzrobe_Electric_Senior";
- else if (actor_name == "Enemy_Wizzrobe_Fire")
- next = "Enemy_Wizzrobe_Fire_Senior";
- else if (actor_name == "Enemy_Wizzrobe_Ice")
- next = "Enemy_Wizzrobe_Ice_Senior";
-
- if (next.isEmpty())
- return false;
-
- *new_name = next.cstr();
- return true;
-}
-
-} // namespace uking::aoc
diff --git a/src/Game/DLC/aocHardModeManager.h b/src/Game/DLC/aocHardModeManager.h
deleted file mode 100644
index 375438a2..00000000
--- a/src/Game/DLC/aocHardModeManager.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#pragma once
-
-#include <heap/seadDisposer.h>
-#include <prim/seadBitFlag.h>
-#include <prim/seadEnum.h>
-#include <prim/seadSafeString.h>
-#include "KingSystem/ActorSystem/actActorConstDataAccess.h"
-#include "KingSystem/GameData/gdtManager.h"
-#include "KingSystem/Map/mapObject.h"
-#include "KingSystem/Resource/resHandle.h"
-#include "KingSystem/Utils/Types.h"
-
-namespace uking::aoc {
-
-class HardModeManager final {
- SEAD_SINGLETON_DISPOSER(HardModeManager)
-
- HardModeManager();
- virtual ~HardModeManager();
-
-public:
- SEAD_ENUM(HardModeChange, IsLastPlayHardMode = 0, NerfHpRestore = 1, _2 = 2,
- DisableNoDeathDamage = 3, PatchGanonStunLock = 4, EnableLifeRegen = 5,
- RandomizeGuardianChargeBeam = 6, ApplyDamageMultiplier = 7,
- EnableShorterEnemyNotice = 8)
- SEAD_ENUM(Flag, EnableHardMode = 0)
- SEAD_ENUM(MultiplierType, HpRestore = 0, _1 = 1, EnemyNoticeDuration = 2)
-
- void init(sead::Heap* heap);
-
- void loadIsLastPlayHardModeFlag();
- void loadIsHardModeFlag();
-
- void storeIsLastPlayHardModeFlag();
- void resetIsLastPlayHardModeFlag();
-
- void calc();
-
- void nerfHpRestore(f32* hp) const;
- void nerfHpRestore(s32* hp) const;
- void modifyEnemyNoticeDuration(f32* value) const;
-
- static bool shouldCreateLifeRecoverInfo(ksys::act::Actor* actor);
- static bool
- shouldApplyMasterModeDamageMultiplier(const ksys::act::ActorConstDataAccess& accessor);
- static void buffDamage(s32& damage);
-
- bool isTestOfStrengthShrine() const;
-
- bool rankUpEnemy(const sead::SafeString& actor_name, const ksys::map::Object& obj,
- const char** new_name);
-
- void setHardModeChange(HardModeChange flag, bool on) { mHardModeChanges.changeBit(flag, on); }
- bool isHardModeChangeOn(HardModeChange flag) const { return mHardModeChanges.isOnBit(flag); }
-
- void setFlag(Flag flag, bool on) { mFlags.changeBit(flag, on); }
- bool checkFlag(Flag flag) const { return mFlags.isOnBit(flag); }
-
- f32 getMultiplier(MultiplierType type) const { return mMultipliers[type]; }
-
-private:
- void setHardModeEnabledFlag(ksys::gdt::Manager::ResetEvent* event = nullptr);
- void initFlagHandles(ksys::gdt::Manager::ReinitEvent* event = nullptr);
- void init_();
-
- sead::BitFlag32 mHardModeChanges;
- sead::BitFlag32 mFlags;
- sead::SafeArray<f32, 3> mMultipliers;
- ksys::gdt::Manager::ResetSignal::Slot mGdtResetSlot;
- ksys::gdt::Manager::ReinitSignal::Slot mGdtReinitSlot;
- void* _120 = nullptr;
- ksys::res::Handle mFileHandle;
- ksys::gdt::FlagHandle mHardModeHighScoreFlag = ksys::gdt::InvalidHandle;
- ksys::gdt::FlagHandle mAoCHardModeEnabledFlag = ksys::gdt::InvalidHandle;
- ksys::gdt::FlagHandle mIsLastPlayHardModeFlag = ksys::gdt::InvalidHandle;
- sead::FixedSafeString<256> mMapType;
- sead::FixedSafeString<256> mMapName;
-};
-KSYS_CHECK_SIZE_NX150(HardModeManager, 0x3b8);
-
-} // namespace uking::aoc
diff --git a/src/Game/DLC/aocManager.cpp b/src/Game/DLC/aocManager.cpp
deleted file mode 100644
index bb7ca50c..00000000
--- a/src/Game/DLC/aocManager.cpp
+++ /dev/null
@@ -1,546 +0,0 @@
-#include "Game/DLC/aocManager.h"
-#include <container/seadBuffer.h>
-#include <filedevice/seadFileDeviceMgr.h>
-#include <prim/seadStringBuilder.h>
-#include <resource/seadSharcArchiveRes.h>
-#include "KingSystem/Resource/resLoadRequest.h"
-#include "KingSystem/Resource/resResourceMgrTask.h"
-#include "KingSystem/Utils/InitTimeInfo.h"
-#include "KingSystem/Utils/SafeDelete.h"
-
-#ifdef NNSDK
-#include <filedevice/nin/seadNinAocFileDeviceNin.h>
-#include <nn/aoc.h>
-#include <nn/fs.h>
-#include <prim/seadStringUtil.h>
-#endif
-
-namespace uking::aoc {
-
-namespace {
-
-struct DungeonInfo {
- int number;
- sead::SafeString flag;
-};
-
-ksys::util::InitConstants sInitConstants;
-DungeonInfo sDungeonInfoData[] = {
- {120, "Defeat_OneHitDungeon001"},
- {121, "BalladOfHeroGerudo_AppearDungeon03"},
- {122, "Defeat_OneHitDungeon002"},
- {123, "Defeat_OneHitDungeon003"},
- {124, "BalladOfHeroZora_AppearDungeon01"},
- {125, "BalladOfHeroZora_AppearDungeon02"},
- {126, "BalladOfHeroZora_AppearDungeon03"},
- {127, "BalladOfHeroRito_TargetHittingSuccess"},
- {128, "BalladOfHeroRito_AppearDungeon03"},
- {129, "BalladOfHeroRito_AppearDungeon02"},
- {130, "BalladOfHeroGoron_FirstKillGolemR"},
- {131, "BalladOfHeroGoron_AppearDungeon01"},
- {132, "BalladOfHeroGoron_AppearDungeon03"},
- {133, "BalladOfHeroGerudo_AppearDungeon02"},
- {134, "BalladOfHeroGerudo_AppearDungeon01"},
- {135, "Defeat_OneHitDungeon004"},
-};
-sead::Buffer<DungeonInfo> sDungeonInfo{sDungeonInfoData};
-constexpr int NumDungeons = 16;
-
-} // namespace
-
-SEAD_SINGLETON_DISPOSER_IMPL(Manager)
-
-Manager::Manager() : mVersionFile(), mGdtReinitSlot{this, &Manager::onGdtReinit} {
- resetFlags();
-}
-
-Manager::~Manager() {
- if (auto* gdm = ksys::gdt::Manager::instance())
- gdm->removeReinitCallback(mGdtReinitSlot);
-
- mAocMainFieldPackPrefix.deregister();
- mAocPackPrefix.deregister();
- mVersionFileDevPrefix.deregister();
-
- if (mFileDevice) {
- sead::FileDeviceMgr::instance()->unmount("aoc");
- ksys::util::safeDelete(mFileDevice);
- }
-
-#ifdef NNSDK
- if (mAocFsCache) {
- nn::fs::Unmount("aoc");
- ksys::util::safeDelete(mAocFsCache);
- }
-#endif
-}
-
-void Manager::resetFlags() {
- mFlagAocVerAtLastPlay = ksys::gdt::InvalidHandle;
- mFlagLatestAocVerPlayed = ksys::gdt::InvalidHandle;
- mFlagHasAocVer1 = ksys::gdt::InvalidHandle;
- mFlagHasAocVer2 = ksys::gdt::InvalidHandle;
- mFlagHasAocVer3 = ksys::gdt::InvalidHandle;
-}
-
-void Manager::init(sead::Heap* heap) {
-#ifdef NNSDK
- std::array<int, 2> dlc_info;
- if (nn::aoc::ListAddOnContent(dlc_info.data(), 0, dlc_info.size()) == dlc_info.size() &&
- (dlc_info[0] == 1 || dlc_info[1] == 1)) {
- size_t cache_size = 0;
- nn::fs::QueryMountAddOnContentCacheSize(&cache_size, 1);
- const size_t cache_size_ = cache_size;
- mAocFsCache = static_cast<u8*>(heap->tryAlloc(cache_size_, sizeof(void*)));
-
- nn::fs::MountAddOnContent("aoc", 1, mAocFsCache, cache_size);
-
- mFileDevice = new (heap) sead::NinAocFileDevice("aoc");
- sead::FileDeviceMgr::instance()->mount(mFileDevice, "aoc");
- loadVersionFile();
- }
-#endif
-}
-
-void Manager::loadVersionFile() {
- if (!mFileDevice)
- return;
-
- mVersionFileDevPrefix.registerPrefix("Aoc/0010/", mFileDevice, false);
-
- ksys::res::LoadRequest req;
- req.mRequester = "aocManager";
- req._26 = false;
- req.mAocFileDevice = mFileDevice;
- const sead::SafeString path = "System/AocVersion.txt";
- mVersionFile.file_handle.requestLoad(path, &req);
-}
-
-void Manager::loadAocMainFieldPack(ksys::OverlayArena* arena) {
- if (!hasAoc3())
- return;
-
- auto* device = mFileDevice;
- if (!device)
- return;
-
- ksys::res::LoadRequest req;
- req.mRequester = "aocManager";
- req._8 = true;
- req._26 = false;
- req.mAocFileDevice = device;
- req.mArena = arena;
- mAocMainFieldPack.requestLoad("Pack/AocMainField.pack", &req);
-}
-
-void Manager::registerAocMainFieldPack() {
- mAocMainFieldPack.waitForReady();
- mAocMainFieldPack.parseResource(nullptr);
- if (mAocMainFieldPack.isSuccess())
- mAocMainFieldPackPrefix.registerPrefix("Aoc/0010/", mAocMainFieldPack.getResource(), false);
-}
-
-void Manager::unloadAocMainFieldPack() {
- mAocMainFieldPackPrefix.deregister();
- mAocMainFieldPack.requestUnload();
-}
-
-sead::FileDevice* Manager::getFileDeviceForMapFile(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- auto* device = mFileDevice;
-
- if (aocPackHasFile(path))
- return nullptr;
-
- if (path.startsWith("Map/MainField/"))
- return device;
-
- if (hasAoc3() && path.startsWith("Map/MainFieldDungeon/"))
- return device;
-
- if (isAocFile(path, "Map/", "Map/AocField/", "Map/MainFieldDungeon/", "Map/CDungeon/"))
- return device;
-
- return nullptr;
-}
-
-bool Manager::getFileDeviceForMap(sead::FileDevice** p_file_device, ksys::res::Handle** p_handle,
- const sead::SafeString& path) {
- if (!hasAoc2())
- return false;
-
- auto* device = mFileDevice;
-
- if (path.startsWith("Map/MainField/")) {
- if (mAocMainFieldPack.isSuccess())
- *p_handle = &mAocMainFieldPack;
- else
- *p_file_device = device;
- return true;
- }
-
- if (aocPackHasFile(path))
- return false;
-
- if (hasAoc3() && path.startsWith("Map/MainFieldDungeon/")) {
- *p_file_device = device;
- return true;
- }
-
- if (isAocFile(path, "Map/", "Map/AocField/", "Map/MainFieldDungeon/", "Map/CDungeon/")) {
- *p_file_device = device;
- return true;
- }
-
- return false;
-}
-
-sead::FileDevice* Manager::getFileDeviceForStaticCompound(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- auto* device = mFileDevice;
-
- if (aocPackHasFile(path))
- return nullptr;
-
- if (isAocFile(path, "Physics/StaticCompound/", "Physics/StaticCompound/AocField/",
- "Physics/StaticCompound/MainFieldDungeon/", "Physics/StaticCompound/CDungeon/")) {
- return device;
- }
-
- return nullptr;
-}
-
-sead::FileDevice* Manager::getFileDeviceForTeraMesh(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- if (path.startsWith("Physics/TeraMeshRigidBody/AocField/"))
- return mFileDevice;
-
- return nullptr;
-}
-
-sead::FileDevice* Manager::getFileDeviceForNavMesh(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- auto* device = mFileDevice;
-
- if (aocPackHasFile(path))
- return nullptr;
-
- if (isAocFile(path, "NavMesh/", "NavMesh/AocField/", "NavMesh/MainFieldDungeon/",
- "NavMesh/CDungeon/")) {
- return device;
- }
-
- return nullptr;
-}
-
-sead::FileDevice* Manager::getFileDeviceForTerrain(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- if (path.startsWith("Terrain/A/AocField"))
- return mFileDevice;
-
- return nullptr;
-}
-
-sead::FileDevice* Manager::getFileDeviceForGame(const sead::SafeString& path) const {
- if (!hasAoc2())
- return nullptr;
-
- if (path.startsWith("Game/AocField/"))
- return mFileDevice;
-
- return nullptr;
-}
-
-sead::FileDevice* Manager::getFileDeviceForUI(const sead::SafeString& path) const {
- if (!hasAoc3())
- return nullptr;
-
- if (path.startsWith("UI/StaffRollDLC/"))
- return mFileDevice;
-
- return nullptr;
-}
-
-bool Manager::isAocFile(const sead::SafeString& path, const sead::SafeString& dir,
- const sead::SafeString& dir_aoc_field,
- const sead::SafeString& dir_main_field_dungeon,
- const sead::SafeString& dir_cdungeon) const {
- if (!path.startsWith(dir))
- return false;
-
- if (path.startsWith(dir_aoc_field))
- return true;
-
- if (path.startsWith(dir_main_field_dungeon)) {
- const auto rel_path = path.getPart(dir_main_field_dungeon.calcLength());
- if (rel_path.startsWith("RemainsElectric"))
- return false;
- if (rel_path.startsWith("RemainsFire"))
- return false;
- if (rel_path.startsWith("RemainsWater"))
- return false;
- if (rel_path.startsWith("RemainsWind"))
- return false;
- return true;
- }
-
- if (path.startsWith(dir_cdungeon)) {
- const auto rel_path = path.getPart(dir_cdungeon.calcLength());
- return isAocDungeon(rel_path);
- }
-
- return false;
-}
-
-static bool isAocDungeonNumber(const sead::SafeString& number) {
- int num;
- sead::FixedSafeString<4> buffer;
- buffer.copy(number, 3);
- return sead::StringUtil::tryParseS32(&num, buffer, sead::StringUtil::CardinalNumber::Base10) &&
- num >= 120;
-}
-
-bool Manager::isAocDungeon(const sead::SafeString& map_name) {
- if (!map_name.startsWith("Dungeon"))
- return true;
- const auto number = map_name.getPart(sead::SafeString("Dungeon").calcLength());
- return isAocDungeonNumber(number);
-}
-
-bool Manager::isAocMap(const sead::SafeString& map_type, const sead::SafeString& map_name) {
- if (isAocField(map_type))
- return true;
-
- if (map_type == "MainFieldDungeon") {
- if (map_name == "RemainsElectric")
- return false;
- if (map_name == "RemainsFire")
- return false;
- if (map_name == "RemainsWater")
- return false;
- if (map_name == "RemainsWind")
- return false;
- return true;
- }
-
- if (map_type == "CDungeon")
- return isAocDungeon(map_name);
-
- return false;
-}
-
-bool Manager::isAocField(const sead::SafeString& map_type) {
- return map_type == "AocField";
-}
-
-sead::FileDevice* Manager::getFileDeviceForDungeonPack(const sead::SafeString& path) const {
- if (!hasAoc3())
- return nullptr;
-
- auto* device = mFileDevice;
-
- const sead::SafeString prefix = "Pack/";
- const auto prefix_len = prefix.calcLength();
-
- if (!path.startsWith(prefix))
- return nullptr;
-
- const auto rel_path = path.getPart(prefix_len);
-
- if (rel_path.startsWith("Dungeon") && !isAocDungeon(rel_path))
- device = nullptr;
-
- return device;
-}
-
-void Manager::registerAocPack(ksys::res::Handle* pack) {
- mAocPack = pack;
- if (pack) {
- mAocPackPrefix.registerPrefix("Aoc/0010/", pack->getResource(), true);
- } else {
- mAocPackPrefix.deregister();
- }
-}
-
-bool Manager::aocPackHasFile(const sead::SafeString& path) const {
- if (!mAocPack)
- return false;
-
- const auto* res = sead::DynamicCast<sead::SharcArchiveRes>(mAocPack->getResource());
- if (!res)
- return false;
-
- sead::FixedStringBuilder<0x81> builder;
- builder.copy(path.cstr());
- ksys::res::ResourceMgrTask::instance()->addSExtensionPrefix(builder);
- return res->isExistFile(builder);
-}
-
-bool Manager::changeMoviePath(sead::BufferedSafeString& path) const {
- if (!hasAoc3())
- return false;
-
- const sead::SafeString prefix = "Movie/";
- const auto prefix_len = prefix.calcLength();
- if (!path.startsWith(prefix))
- return false;
-
- const auto rel_path = path.getPart(prefix_len);
- if (!rel_path.startsWith("Demo6"))
- return false;
-
- path.prepend("aoc://");
- return true;
-}
-
-bool Manager::parseVersion() {
- if (!mVersionFile.readVersion())
- return false;
-
- if (mVersionFile.string.isEmpty()) {
- mVersion = 0;
- return true;
- }
-
- {
- const int dot_index = mVersionFile.string.findIndex(".");
- const int minor_index = dot_index + 1;
- if (dot_index <= 0 || minor_index >= mVersionFile.string.calcLength()) {
- mVersionFile.string.clear();
- mVersion = 0;
- return true;
- }
-
- u32 major, minor;
- const auto parse = [&] {
- sead::FixedSafeString<16> major_str;
- major_str.copy(mVersionFile.string, dot_index);
-
- constexpr auto base = sead::StringUtil::CardinalNumber::Base10;
- if (!sead::StringUtil::tryParseU32(&major, major_str, base))
- return false;
-
- const auto minor_str = mVersionFile.string.getPart(minor_index);
- if (!sead::StringUtil::tryParseU32(&minor, minor_str, base))
- return false;
-
- return true;
- };
-
- if (!parse()) {
- mVersionFile.string.clear();
- mVersion = 0;
- return true;
- }
-
- mVersion = (major << 8) + minor;
- }
-
- checkVersion();
- return true;
-}
-
-// NON_MATCHING: stack and duplicated branch -- volatile variables are painful
-void Manager::checkVersion() {
- if (mVersion == 0)
- return;
-
- const auto fail = [this](VersionError error) {
- mVersionFlags.setBit(error);
- mVersion = 0;
- };
-
- if (mVersion < 0x300) {
- fail(VersionError::TooOld);
- } else if (mVersion >= 0x400) {
- fail(VersionError::TooNew);
- }
-
- mVersionFlags.isOnBit(VersionError(VersionError::TooOld));
- mVersionFlags.isOnBit(VersionError(VersionError::TooNew));
-}
-
-bool Manager::VersionFile::readVersion() {
- if (!file_handle.requestedLoad())
- return true;
-
- if (file_handle.isSuccess()) {
- auto* res = sead::DynamicCast<sead::DirectResource>(file_handle.getResource());
- string.copy(reinterpret_cast<const char*>(res->getRawData()), res->getRawSize());
- } else {
- if (!file_handle.checkLoadStatus())
- return false;
- string.clear();
- }
-
- file_handle.requestUnload();
- return true;
-}
-
-void Manager::initGameData() {
- reinitFlags();
- ksys::gdt::Manager::instance()->addReinitCallback(mGdtReinitSlot);
-}
-
-static const sead::SafeString& getDungeonFlag(int number) {
- for (auto it = sDungeonInfo.begin(); it != sDungeonInfo.end(); ++it) {
- if (it->number == number)
- return it->flag;
- }
- return sead::SafeString::cEmptyString;
-}
-
-void Manager::reinitFlags() {
- mFlagAocVerAtLastPlay = ksys::gdt::Manager::instance()->getS32Handle("AoCVerAtLastPlay");
- mFlagLatestAocVerPlayed = ksys::gdt::Manager::instance()->getS32Handle("LatestAoCVerPlayed");
- mFlagHasAocVer1 =
- ksys::gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer1));
- mFlagHasAocVer2 =
- ksys::gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer2));
- mFlagHasAocVer3 =
- ksys::gdt::Manager::instance()->getBoolHandle(GameDataFlag::text(GameDataFlag::HasAoCVer3));
-
- for (int i = 0; i < mDLCPositions.size(); ++i) {
- ksys::gdt::FlagHandle handle = ksys::gdt::InvalidHandle;
-
- if (i < NumDungeons) {
- if (mDLCPositions[i].flag_handle == ksys::gdt::InvalidHandle)
- continue;
-
- handle = ksys::gdt::Manager::instance()->getBoolHandle(getDungeonFlag(i + 120));
- }
-
- mDLCPositions[i].flag_handle = handle;
- }
-}
-
-void Manager::setGameDataFlags() const {
- ksys::gdt::Manager::instance()->setS32(mVersion, mFlagAocVerAtLastPlay);
-
- s32 latest_ver;
- if (ksys::gdt::Manager::instance()->getS32(mFlagLatestAocVerPlayed, &latest_ver)) {
- if (u32(latest_ver) < mVersion)
- ksys::gdt::Manager::instance()->setS32(mVersion, mFlagLatestAocVerPlayed);
- }
-
- const auto ver = mVersion;
- ksys::gdt::Manager::instance()->setBool(ver >= 0x100, mFlagHasAocVer1);
- ksys::gdt::Manager::instance()->setBool(ver >= 0x200, mFlagHasAocVer2);
- ksys::gdt::Manager::instance()->setBool(ver >= 0x300, mFlagHasAocVer3);
-}
-
-void Manager::onGdtReinit(ksys::gdt::Manager::ReinitEvent* event) {
- reinitFlags();
-}
-
-} // namespace uking::aoc
diff --git a/src/Game/DLC/aocManager.h b/src/Game/DLC/aocManager.h
deleted file mode 100644
index 9dd19636..00000000
--- a/src/Game/DLC/aocManager.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#pragma once
-
-#include <container/seadSafeArray.h>
-#include <heap/seadDisposer.h>
-#include <math/seadVector.h>
-#include <prim/seadBitFlag.h>
-#include <prim/seadEnum.h>
-#include <prim/seadSafeString.h>
-#include "KingSystem/GameData/gdtManager.h"
-#include "KingSystem/Resource/resHandle.h"
-#include "KingSystem/Resource/resResourceMgrTask.h"
-#include "KingSystem/Utils/Types.h"
-
-namespace ksys {
-class OverlayArena;
-}
-
-namespace sead {
-class FileDevice;
-}
-
-namespace uking::aoc {
-
-// TODO
-class Manager {
- SEAD_SINGLETON_DISPOSER(Manager)
- Manager();
- ~Manager();
-
-public:
- void init(sead::Heap* heap);
-
- u32 getVersion() const { return mVersion; }
-
- /// @return Whether the Master Trials DLC is supported.
- bool hasAoc2() const { return mVersion >= 0x200; }
-
- /// @return Whether the Champion's Ballad DLC is supported.
- bool hasAoc3() const { return mVersion >= 0x300; }
-
- void loadAocMainFieldPack(ksys::OverlayArena* arena);
- void registerAocMainFieldPack();
- void unloadAocMainFieldPack();
-
- sead::FileDevice* getFileDeviceForMapFile(const sead::SafeString& path) const;
- bool getFileDeviceForMap(sead::FileDevice** p_file_device, ksys::res::Handle** p_handle,
- const sead::SafeString& path);
- sead::FileDevice* getFileDeviceForStaticCompound(const sead::SafeString& path) const;
- sead::FileDevice* getFileDeviceForTeraMesh(const sead::SafeString& path) const;
- sead::FileDevice* getFileDeviceForNavMesh(const sead::SafeString& path) const;
- sead::FileDevice* getFileDeviceForTerrain(const sead::SafeString& path) const;
- sead::FileDevice* getFileDeviceForGame(const sead::SafeString& path) const;
- sead::FileDevice* getFileDeviceForUI(const sead::SafeString& path) const;
-
- bool isAocFile(const sead::SafeString& path, const sead::SafeString& dir,
- const sead::SafeString& dir_aoc_field,
- const sead::SafeString& dir_main_field_dungeon,
- const sead::SafeString& dir_cdungeon) const;
- static bool isAocDungeon(const sead::SafeString& map_name);
- static bool isAocMap(const sead::SafeString& map_type, const sead::SafeString& map_name);
- static bool isAocField(const sead::SafeString& map_type);
-
- sead::FileDevice* getFileDeviceForDungeonPack(const sead::SafeString& path) const;
- void registerAocPack(ksys::res::Handle* pack);
- bool aocPackHasFile(const sead::SafeString& path) const;
-
- bool changeMoviePath(sead::BufferedSafeString& path) const;
-
- void parseAocMainFieldStaticInfo(const al::ByamlIter& iter);
- // TODO: figure out what this does
- bool getSomePos(sead::Vector3f* translate, u32* p_mask, u32* mask);
-
- bool parseVersion();
- void setGameDataFlags() const;
-
-private:
- SEAD_ENUM(GameDataFlag, AoCVerAtLastPlay ,LatestAoCVerPlayed ,HasAoCVer1 ,HasAoCVer2 ,HasAoCVer3)
- SEAD_ENUM(VersionError, TooNew, TooOld)
-
- struct DLCPosition {
- sead::Vector3f translate = sead::Vector3f::zero;
- sead::Vector3f rotate = sead::Vector3f::zero;
- sead::Vector3f translate2 = sead::Vector3f::zero;
- float scale = 0.0;
- ksys::gdt::FlagHandle flag_handle = ksys::gdt::InvalidHandle;
- };
- KSYS_CHECK_SIZE_NX150(DLCPosition, 0x2c);
-
- struct VersionFile {
- bool readVersion();
-
- ksys::res::Handle file_handle;
- sead::FixedSafeString<16> string;
- };
- KSYS_CHECK_SIZE_NX150(VersionFile, 0x78);
-
- void loadVersionFile();
- void checkVersion();
-
- void resetFlags();
- void initGameData();
- void reinitFlags();
- void onGdtReinit(ksys::gdt::Manager::ReinitEvent* event);
-
- sead::FileDevice* mFileDevice{};
-
- ksys::res::FileDevicePrefix mVersionFileDevPrefix;
- VersionFile mVersionFile{};
- u32 mVersion{};
-
- ksys::res::Handle mAocMainFieldPack;
- ksys::res::FileDevicePrefix mAocMainFieldPackPrefix;
- ksys::res::Handle* mAocPack{};
- ksys::res::FileDevicePrefix mAocPackPrefix;
-
- sead::SafeArray<DLCPosition, 20> mDLCPositions;
-
- ksys::gdt::FlagHandle mFlagAocVerAtLastPlay{};
- ksys::gdt::FlagHandle mFlagLatestAocVerPlayed{};
- ksys::gdt::FlagHandle mFlagHasAocVer1{};
- ksys::gdt::FlagHandle mFlagHasAocVer2{};
- ksys::gdt::FlagHandle mFlagHasAocVer3{};
- ksys::gdt::Manager::ReinitSignal::Slot mGdtReinitSlot;
-
- sead::BitFlag8 mVersionFlags{};
-#ifdef NNSDK
- u8* mAocFsCache{};
-#endif
-};
-KSYS_CHECK_SIZE_NX150(Manager, 0x598);
-
-} // namespace uking::aoc