#include "System/GameDataFunction.h"

#include <g3d/aglNW4FToNN.h>

#include "Library/Area/AreaObj.h"
#include "Library/Area/AreaObjUtil.h"
#include "Library/Base/Macros.h"
#include "Library/Layout/LayoutActor.h"
#include "Library/LiveActor/ActorPoseUtil.h"
#include "Library/Math/MathUtil.h"
#include "Library/Message/MessageHolder.h"
#include "Library/Placement/PlacementFunction.h"
#include "Library/Placement/PlacementId.h"
#include "Library/Placement/PlacementInfo.h"
#include "Library/Resource/ResourceFunction.h"
#include "Library/Scene/Scene.h"
#include "Library/Scene/SceneObjHolder.h"
#include "Library/Scene/SceneObjUtil.h"
#include "Library/Yaml/ByamlUtil.h"

#include "Camera/ScenarioStartCamera.h"
#include "Item/Shine.h"
#include "Item/ShineInfo.h"
#include "Layout/ShopLayoutInfo.h"
#include "MapObj/RiseMapPartsHolder.h"
#include "Npc/WorldTravelingNpc.h"
#include "Player/PlayerFunction.h"
#include "Scene/QuestInfo.h"
#include "Scene/QuestInfoHolder.h"
#include "Scene/TemporaryScenarioCameraHolder.h"
#include "Sequence/ChangeStageInfo.h"
#include "System/GameDataUtil.h"
#include "System/GameProgressData.h"
#include "System/MapDataHolder.h"
#include "System/MoonRockData.h"
#include "System/PlayerHitPointData.h"
#include "System/WorldList.h"
#include "Util/ClothUtil.h"
#include "Util/ScenePrepoFunction.h"
#include "Util/SpecialBuildUtil.h"
#include "Util/StageLayoutFunction.h"

namespace GameDataFunction {

GameDataHolder* getGameDataHolder(const al::IUseSceneObjHolder* scene_obj_holder) {
    return al::getSceneObj<GameDataHolder>(scene_obj_holder);
}

GameDataHolder* getGameDataHolder(const al::SceneObjHolder* scene_obj_holder) {
    return scene_obj_holder->getObj<GameDataHolder>();
}

GameDataHolder* getGameDataHolder(al::GameDataHolderBase* game_data_holder) {
    return static_cast<GameDataHolder*>(game_data_holder);
}

GameDataFile* getGameDataFile(GameDataHolderWriter writer) {
    return writer->getGameDataFile();
}

void setPlayingFileId(GameDataHolderWriter writer, s32 file_id) {
    writer->setPlayingFileId(file_id);
}

void initializeData(GameDataHolderWriter writer, s32 file_id) {
    writer->initializeDataId(file_id);
}

bool isPlayDemoOpening(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoOpening();
}

bool isGameClear(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isGameClear();
}

void setRequireSave(GameDataHolderWriter writer) {
    writer->setRequireSave();
}

void setRequireSaveFrame(GameDataHolderWriter writer) {
    writer->setRequireSaveFrame();
}

s64 getPlayTimeTotal(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayTimeTotal();
}

s64 getPlayTimeAcrossFile(GameDataHolderAccessor accessor) {
    return accessor->getPlayTimeAcrossFile();
}

s64 getSaveDataIdForPrepo(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getSaveDataIdForPrepo();
}

void startDemoStage(GameDataHolderWriter writer, const char* stage_name) {
    writer->getGameDataFile()->startDemoStage(stage_name);
}

bool tryChangeNextStage(GameDataHolderWriter writer, const ChangeStageInfo* info) {
    if (info->isEmpty())
        return false;
    writer->changeNextStage(info);
    return true;
}

bool tryChangeNextStageWithStartRaceFlag(GameDataHolderWriter writer, const ChangeStageInfo* info) {
    if (info->isEmpty())
        return false;
    writer->changeNextStage(info, GameDataFile::RaceType_Flag);
    return true;
}

bool tryChangeNextStageWithStartRaceYukimaru(GameDataHolderWriter writer,
                                             const ChangeStageInfo* info) {
    if (info->isEmpty())
        return false;
    writer->changeNextStage(info, GameDataFile::RaceType_Yukimaru);
    return true;
}

bool tryChangeNextStageWithDemoWorldWarp(GameDataHolderWriter writer, const char* stage_name) {
    writer->changeNextStageWithDemoWorldWarp(stage_name);
    return true;
}

bool tryChangeNextStageWithWorldWarpHole(GameDataHolderWriter writer, const char* stage_name) {
    return writer->tryChangeNextStageWithWorldWarpHole(stage_name);
}

void changeNextStageWithStartTimeBalloon(GameDataHolderWriter writer, s32 scenario_no) {
    ChangeStageInfo info{writer, "TimeBalloonStart", getCurrentStageName(writer),
                         false,  scenario_no,        ChangeStageInfo::RESET_MINI_GAME1};
    writer->changeNextStage(&info);
}

const char* getCurrentStageName(GameDataHolderAccessor accessor) {
    return accessor->getCurrentStageName();
}

void changeNextStageWithEndTimeBalloon(GameDataHolderWriter writer) {
    ChangeStageInfo info{writer, "TimeBalloonStart", getCurrentStageName(writer)};
    writer->changeNextStage(&info);
}

void changeNextStageWithCloset(GameDataHolderWriter writer) {
    ChangeStageInfo info{writer, "ClosetStart", getCurrentStageName(writer)};
    writer->changeNextStage(&info);
}

void findAreaAndChangeNextStage(GameDataHolderWriter writer, const al::LiveActor* actor,
                                const sead::Vector3f* pos_override) {
    if (writer->getGameDataFile()->get_a2c() &&
        writer->getGameDataFile()->getChangeStageInfo()->getSubScenarioType() !=
            ChangeStageInfo::DEFAULT_SUB_SCENARIO)
        return;
    sead::Vector3f pos = al::getTrans(actor);
    if (pos_override)
        pos.set(*pos_override);
    al::AreaObj* area = al::tryFindAreaObj(actor, "ChangeStageArea", pos);
    ChangeStageInfo info{writer, *area->getPlacementInfo()};
    tryChangeNextStage(writer, &info);
}

void returnPrevStage(GameDataHolderWriter writer) {
    writer->returnPrevStage();
}

bool isTimeBalloonSequence(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getChangeStageInfo()->getSubScenarioType() ==
           ChangeStageInfo::RESET_MINI_GAME1;
}

const char* getNextStageName(GameDataHolderAccessor accessor) {
    return accessor->getNextStageName();
}

const char* getCurrentStageName(GameDataHolderAccessor accessor, s32 file_id) {
    return accessor->getCurrentStageName(file_id);
}

static bool isSeaOfTreeStage(const char* stage_name) {
    return al::isEqualString(stage_name, "ForestWorldWoodsStage") ||
           al::isEqualString(stage_name, "ForestWorldWoodsCostumeStage") ||
           al::isEqualString(stage_name, "ForestWorldWoodsTreasureStage");
}

bool isSeaOfTreeStage(GameDataHolderAccessor accessor) {
    return isSeaOfTreeStage(getCurrentStageName(accessor));
}

const char* getNextStageName(GameDataHolderAccessor accessor, s32 file_id) {
    return accessor->getNextStageName(file_id);
}

s32 calcNextScenarioNo(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcNextScenarioNo();
}

void restartStage(GameDataHolderWriter writer) {
    writer->getGameDataFile()->restartStage();
}

void missAndRestartStage(GameDataHolderWriter writer) {
    writer->validateCheckpointWarp();
    writer->enableExplainAmiibo();
    writer->getGameDataFile()->missAndRestartStage();
}

bool isMissEndPrevStageForInit(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isMissEndPrevStage();
}

bool isMissEndPrevStageForSceneDead(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isMissEndPrevStage();
}

void reenterStage(GameDataHolderWriter writer) {
    writer->set_4a();
}

s32 getNextWorldId(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getNextWorldId();
}

s32 getPrevWorldId(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPrevWorldId();
}

s32 getWorldNumForNewReleaseShop(GameDataHolderAccessor accessor) {
    const GameProgressData* game_progress_data = accessor->getGameDataFile()->getGameProgressData();
    s32 unlock_world_num = game_progress_data->getUnlockWorldNum();
    s32 count = 0;
    for (s32 i = 0; i < unlock_world_num; i++) {
        s32 world_id = game_progress_data->getWorldIdForWorldWarpHole(i);
        if (!isAlreadyGoWorld(accessor, world_id))
            continue;
        const char* world_name = getWorldDevelopName(accessor, world_id);
        const sead::PtrArray<sead::FixedSafeString<64>>& list =
            accessor->getWorldsForNewReleaseShop();
        for (s32 j = 0; j < list.size(); j++) {
            if (al::isEqualString(world_name, list[j]->cstr())) {
                count++;
                break;
            }
        }
    }
    return count;
}

// TODO: check what's happening here
static s32 blackBox(s32 value) {
    __asm__("" : "+r"(value));
    return value;
}

template <typename F>
static s32 search(s32 count, F fn) {
    for (s32 i = 0; i < count; i++) {
        s32 status = fn(i);
        if ((blackBox(status | 4) & 7) != 4)
            return status;
    }
    return 2;
}

s32 getWorldIdForNewReleaseShop(GameDataHolderAccessor accessor, s32 index) {
    const GameProgressData* game_progress_data = accessor->getGameDataFile()->getGameProgressData();
    s32 result;
    s32 status = search(game_progress_data->getUnlockWorldNum(), [&](s32 i) {
        s32 world_id = game_progress_data->getWorldIdForWorldWarpHole(i);
        if (!isAlreadyGoWorld(accessor, world_id))
            return 4;
        const char* world_name = getWorldDevelopName(accessor, world_id);
        const sead::PtrArray<sead::FixedSafeString<64>>& list =
            accessor->getWorldsForNewReleaseShop();
        for (s32 j = 0; j < list.size(); j++) {
            if (al::isEqualString(world_name, list[j]->cstr())) {
                if (index == 0) {
                    result = world_id;
                    return 1;
                } else {
                    index--;
                    return 0;
                }
            }
        }
        return 0;
    });
    return status == 2 ? 0 : result;
}

bool isForwardWorldWarpDemo(GameDataHolderAccessor accessor) {
    s32 prev_world_id = getPrevWorldId(accessor);
    s32 next_world_id = getNextWorldId(accessor);
    s32 world_num = getWorldNum(accessor);
    s32 next_world_id_for_demo = -1;
    s32 prev_world_id_for_demo = -1;
    for (s32 i = 0; i < world_num; i++) {
        s32 world_id = accessor->getGameDataFile()->getGameProgressData()->getWorldIdForWorldMap(i);
        if (world_id == prev_world_id)
            prev_world_id_for_demo = i;
        if (world_id == next_world_id)
            next_world_id_for_demo = i;
    }
    if (prev_world_id_for_demo == -1)
        prev_world_id_for_demo = prev_world_id;
    if (next_world_id_for_demo == -1)
        next_world_id_for_demo = next_world_id;
    return prev_world_id_for_demo <= next_world_id_for_demo;
}

s32 getWorldNum(GameDataHolderAccessor accessor) {
    return accessor->getWorldList()->getWorldNum();
}

bool isFirstTimeNextWorld(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isFirstTimeNextWorld();
}

bool checkIsNewWorldInAlreadyGoWorld(GameDataHolderAccessor accessor) {
    s32 world_id = getCurrentWorldIdNoDevelop(accessor);
    if (!isAlreadyGoWorld(accessor, world_id))
        return false;
    const GameProgressData* game_progress_data = accessor->getGameDataFile()->getGameProgressData();
    bool is_after_current_world = false;
    for (s32 i = 0; i < game_progress_data->getUnlockWorldNum(); i++) {
        if (!is_after_current_world) {
            if (game_progress_data->getWorldIdForWorldWarpHole(i) == world_id)
                is_after_current_world = true;
            continue;
        }
        if (accessor->getGameDataFile()->isAlreadyGoWorld(
                game_progress_data->getWorldIdForWorldWarpHole(i)))
            return false;
    }
    return is_after_current_world;
}

static s32 getScenarioNoImpl(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getScenarioNo();
}

s32 getScenarioNo(const al::LiveActor* actor) {
    return getScenarioNoImpl(actor);
}

s32 getScenarioNo(const al::LayoutActor* layout) {
    return getScenarioNoImpl(layout);
}

s32 getScenarioNoPlacement(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getScenarioNoPlacement();
}

bool isEqualScenario(const RiseMapPartsHolder* actor, s32 scenario_no) {
    return getScenarioNo(actor) == scenario_no;
}

s32 getMainQuestMin(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getWorldList()->getMainQuestMin(getCurrentWorldId(actor),
                                                     getScenarioNoImpl(actor));
}

s32 getCurrentWorldId(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCurrentWorldId();
}

s32 getCurrentWorldIdNoDevelop(GameDataHolderAccessor accessor) {
    return sead::Mathi::clampMin(getCurrentWorldId(accessor), 0);
}

void clearStartId(GameDataHolderWriter writer) {
    writer->getGameDataFile()->clearStartId();
}

void setCheckpointId(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    writer->setCheckpointId(placement_id);
}

void setRestartPointId(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    writer->getGameDataFile()->setRestartPointId(placement_id);
}

const char* tryGetRestartPointIdString(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->tryGetRestartPointIdString();
}

const char* tryGetPlayerStartId(GameDataHolderAccessor accessor) {
    return accessor->getNextPlayerStartId();
}

bool isPlayerStartObj(const al::LiveActor* actor, const al::ActorInitInfo& info) {
    return isPlayerStartObj(actor, *info.placementInfo);
}

bool isPlayerStartObj(const al::LiveActor* actor, const al::PlacementInfo& placement_info) {
    const char* str = tryGetPlayerStartId(actor);
    if (!str)
        return false;
    const char* start_id = nullptr;
    bool has_start_id = al::tryGetStringArg(&start_id, placement_info, "ChangeStageId");
    return start_id && has_start_id && al::isEqualString(str, start_id);
}

bool isPlayerStartObj(const al::LiveActor* actor, const char* start_id) {
    const char* str = tryGetPlayerStartId(actor);
    return str && al::isEqualString(str, start_id);
}

bool isPlayerStartLinkedObj(const al::LiveActor* actor, const al::ActorInitInfo& info,
                            const char* link_name) {
    s32 link_num = al::calcLinkChildNum(info, link_name);
    for (s32 i = 0; i < link_num; i++) {
        al::PlacementInfo placement_info;
        al::getLinksInfoByIndex(&placement_info, info, link_name, i);
        if (isPlayerStartObj(actor, placement_info))
            return true;
    }
    return false;
}

void setStartShine(const al::LiveActor* actor, const ShineInfo* info) {
    getGameDataHolder(actor)->getGameDataFile()->setStartShine(info);
}

s32 getStartShineNextIndex(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getStartShineNextIndex();
}

bool isAlreadyShowExplainCheckpointFlag(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isAlreadyShowExplainCheckpointFlag();
}

bool isEnableShowExplainCheckpointFlag(GameDataHolderAccessor accessor) {
    return true;
}

void showExplainCheckpointFlag(GameDataHolderAccessor accessor) {
    accessor->getGameDataFile()->showExplainCheckpointFlag();
}

void getLifeMaxUpItem(const al::LiveActor* actor) {
    if (PlayerFunction::isPlayerDeadStatus(actor))
        return;
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->getPlayerHitPointData()->getMaxUpItem();
}

s32 getPlayerHitPoint(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayerHitPointData()->getCurrent();
}

s32 getPlayerHitPointMaxCurrent(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayerHitPointData()->getMaxCurrent();
}

s32 getPlayerHitPointMaxNormal(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayerHitPointData()->getMaxWithoutItem();
}

bool isPlayerHitPointMax(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayerHitPointData()->isMaxCurrent();
}

bool isPlayerHitPointMaxWithItem(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPlayerHitPointData()->isMaxWithItem();
}

void recoveryPlayer(const al::LiveActor* actor) {
    if (PlayerFunction::isPlayerDeadStatus(actor))
        return;
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->getPlayerHitPointData()->recover();
}

void recoveryPlayerForDebug(const al::LiveActor* actor) {
    if (PlayerFunction::isPlayerDeadStatus(actor))
        return;
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->getPlayerHitPointData()->recoverForDebug();
}

void recoveryPlayerMax(const al::LiveActor* actor) {
    if (PlayerFunction::isPlayerDeadStatus(actor))
        return;
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->getPlayerHitPointData()->recoverMax();
}

void recoveryPlayerForSystem(const GameDataHolder* game_data_holder) {
    game_data_holder->getGameDataFile()->getPlayerHitPointData()->recover();
}

void recoveryPlayerMaxForSystem(const GameDataHolder* game_data_holder) {
    game_data_holder->getGameDataFile()->getPlayerHitPointData()->recoverMax();
}

void initPlayerHitPointForSystem(const GameDataHolder* game_data_holder) {
    game_data_holder->getGameDataFile()->getPlayerHitPointData()->init();
}

void damagePlayer(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getPlayerHitPointData()->damage();
}

void killPlayer(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getPlayerHitPointData()->kill();
}

bool isPlayerLifeZero(GameDataHolderAccessor accessor) {
    return getPlayerHitPoint(accessor) <= 0;
}

bool isGotShine(GameDataHolderAccessor accessor, const ShineInfo* info) {
    return accessor->getGameDataFile()->isGotShine(info);
}

bool isGotShine(GameDataHolderAccessor accessor, const al::PlacementId* placement_id) {
    ShineInfo shine_info;
    shine_info.init(getCurrentStageName(accessor), al::makeStringPlacementId(placement_id).cstr(),
                    nullptr, nullptr, ShineInfo::Type_Shine);
    return isGotShine(accessor, &shine_info);
}

bool isGotShine(GameDataHolderAccessor accessor, const char* stage_name, const char* obj_id) {
    ShineInfo shine_info;
    shine_info.init(stage_name, obj_id, nullptr, nullptr, ShineInfo::Type_Shine);
    return isGotShine(accessor, &shine_info);
}

bool isGotShine(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->isGotShine(index);
}

bool isGotShine(const Shine* shine) {
    return shine->isGot();
}

void setGotShine(GameDataHolderWriter writer, const ShineInfo* info) {
    writer->getGameDataFile()->setGotShine(info);
}

s32 getGotShineNum(GameDataHolderAccessor accessor, s32 file_id) {
    return file_id == -1 ? accessor->getGameDataFile()->getShineNum() :
                           accessor->getGameDataFile(file_id)->getShineNum();
}

const ShineInfo* getLatestGetShineInfo(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getLatestGetShineInfo();
}

s32 getCurrentShineNum(GameDataHolderAccessor accessor) {
    if (isGameClear(accessor)) {
        s32 world_num = getWorldNum(accessor);
        s32 count = 0;
        for (s32 i = 0; i < world_num; i++)
            count += sead::Mathi::clampMin(accessor->getGameDataFile()->getShineNum(i) -
                                               accessor->getGameDataFile()->getPayShineNum(i),
                                           0);
        return count;
    }
    return sead::Mathi::clampMin(accessor->getGameDataFile()->getShineNum() -
                                     accessor->getGameDataFile()->getPayShineNum(),
                                 0);
}

s32 getTotalShineNum(GameDataHolderAccessor accessor, s32 file_id) {
    return file_id == -1 ? accessor->getGameDataFile()->getTotalShineNum() :
                           accessor->getGameDataFile(file_id)->getTotalShineNum();
}

s32 getTotalShopShineNum(GameDataHolderAccessor accessor, s32 file_id) {
    return file_id == -1 ? accessor->getGameDataFile()->getTotalShopShineNum() :
                           accessor->getGameDataFile(file_id)->getTotalShopShineNum();
}

bool tryGetNextMainScenarioLabel(sead::BufferedSafeString* out_label,
                                 sead::BufferedSafeString* out_stage_name,
                                 const al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    return accessor->getGameDataFile()->tryGetNextMainScenarioLabel(out_label, out_stage_name);
}

s32 getMainScenarioNumMax(GameDataHolderAccessor accessor) {
    return 10;
}

void setMainScenarioNo(GameDataHolderWriter writer, s32 scenario_no) {
    writer->getGameDataFile()->setMainScenarioNo(scenario_no);
}

bool tryGetNextMainScenarioPos(sead::Vector3f* out, GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->tryGetNextMainScenarioPos(out);
}

bool isPlayScenarioCamera(GameDataHolderAccessor accessor, const QuestInfo* info) {
    return accessor->getGameDataFile()->isPlayScenarioCamera(info);
}

bool isPlayAlreadyScenarioStartCamera(GameDataHolderAccessor accessor, s32 quest_no) {
    return accessor->isPlayAlreadyScenarioStartCamera(quest_no);
}

bool isEnterStageFirst(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isEnterStageFirst();
}

bool isNextMainShine(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->isNextMainShine(index);
}

bool isMainShine(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->isMainShine(index);
}

bool isLatestGetMainShine(GameDataHolderAccessor accessor, const ShineInfo* info) {
    return accessor->getGameDataFile()->isLatestGetMainShine(info);
}

s32 tryFindLinkedShineIndex(const al::LiveActor* actor, const al::ActorInitInfo& info) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->tryFindLinkedShineIndex(info, actor);
}

s32 tryFindLinkedShineIndex(const al::LiveActor* actor, const al::ActorInitInfo& info,
                            s32 link_index) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->tryFindLinkedShineIndex(info, link_index, actor);
}

s32 tryFindLinkedShineIndexByLinkName(const al::LiveActor* actor, const al::ActorInitInfo& info,
                                      const char* link_name) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->tryFindLinkedShineIndexByLinkName(actor, info, link_name);
}

s32 calcLinkedShineNum(const al::LiveActor* actor, const al::ActorInitInfo& info) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->calcLinkedShineNum(info);
}

s32 tryFindShineIndex(const al::LiveActor* actor, const al::ActorInitInfo& info) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->tryFindShineIndex(info);
}

s32 tryFindShineIndex(const al::LiveActor* actor, const char* stage_name, const char* obj_id) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->tryFindShineIndex(stage_name, obj_id);
}

s32 tryFindShineUniqueId(const al::Scene* scene, const ShineInfo* shine_info) {
    GameDataHolderAccessor accessor{scene};
    return accessor->getGameDataFile()->tryFindUniqueId(shine_info);
}

void disableHintByShineIndex(const al::LiveActor* actor, s32 index) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->disableHintById(index);
}

void enableHintByShineIndex(const al::LiveActor* actor, s32 index) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->enableHintById(index);
}

bool calcIsGetMainShineAll(const al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    return accessor->getGameDataFile()->calcIsGetMainShineAll(scene_obj_holder);
}

bool calcIsGetShineAllInWorld(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->calcIsGetShineAllInWorld(world_id);
}

bool calcIsGetShineAllInAllWorld(GameDataHolderAccessor accessor) {
    for (s32 i = 0; i < getWorldNum(accessor); i++)
        if (!calcIsGetShineAllInWorld(accessor, i))
            return false;
    return true;
}

bool tryFindAndInitShineInfoByOptionalId(ShineInfo* info, GameDataHolderAccessor accessor,
                                         const char* optional_id) {
    return accessor->getGameDataFile()->tryFindAndInitShineInfoByOptionalId(info, optional_id);
}

namespace {

class SceneObjAccessor : public al::IUseSceneObjHolder {
public:
    SceneObjAccessor(al::SceneObjHolder* scene_obj_holder) : mSceneObjHolder(scene_obj_holder) {}

    al::SceneObjHolder* getSceneObjHolder() const override { return mSceneObjHolder; }

private:
    al::SceneObjHolder* mSceneObjHolder;
};

}  // namespace

bool isGotLinkedShineBeforeInitActor(const al::ActorInitInfo& actor_info, const char* link_name) {
    SceneObjAccessor scene_obj_accessor{actor_info.actorSceneInfo.sceneObjHolder};
    GameDataHolderAccessor accessor{&scene_obj_accessor};
    return accessor->getGameDataFile()->isGotShine(
        accessor->getGameDataFile()->tryFindLinkedShineIndexByLinkName(&scene_obj_accessor,
                                                                       actor_info, link_name));
}

bool checkIsComplete(const al::IUseSceneObjHolder* scene_obj_holder, s32 file_id) {
    const GameDataFile* game_data_file =
        getGameDataHolder(scene_obj_holder)->getGameDataFile(file_id);
    for (s32 i = 0; i < getWorldNum(scene_obj_holder); i++)
        if (!game_data_file->calcIsGetShineAllInWorld(i))
            return false;

    al::Resource* resource = al::findOrCreateResource("SystemData/HackObjList", nullptr);
    al::ByamlIter iter{al::findResourceYaml(resource, "HackObjList", nullptr)};
    s32 hack_obj_count = iter.getSize();
    for (s32 i = 0; i < hack_obj_count; i++) {
        al::ByamlIter subiter;
        iter.tryGetIterByIndex(&subiter, i);
        if (al::tryGetByamlKeyBoolOrFalse(subiter, "IsDebug"))
            continue;
        const char* hack_name = al::getByamlKeyString(subiter, "HackName");
        if (!isExistInHackDictionary(scene_obj_holder, hack_name, file_id))
            return false;
    }

    if (!rs::isCompleteCloth(scene_obj_holder, file_id) ||
        !rs::isCompleteCap(scene_obj_holder, file_id) ||
        !rs::checkCompleteGift(scene_obj_holder, file_id) ||
        !rs::checkCompleteSticker(scene_obj_holder, file_id))
        return false;

    if (getCollectedBgmNum(scene_obj_holder, file_id) != getCollectedBgmMaxNum(scene_obj_holder))
        return false;

    return true;
}

bool isEnableOpenMoonRock(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->isEnableOpenMoonRock(getCurrentWorldIdNoDevelop(actor));
}

void openMoonRock(const al::LiveActor* actor, const al::PlacementId*) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->unlockHintAddByMoonRock();
}

bool isOpenMoonRock(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isOpenMoonRock(getCurrentWorldIdNoDevelop(accessor));
}

bool isEnableShowDemoOpenMoonRockFirst(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMoonRockData()->isEnableShowDemoOpenMoonRockFirst();
}

bool isEnableShowDemoOpenMoonRockWorld(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMoonRockData()->isEnableShowDemoOpenMoonRockWorld(
        getCurrentWorldIdNoDevelop(accessor));
}

void showDemoOpenMoonRockFirst(GameDataHolderAccessor accessor) {
    accessor->getGameDataFile()->getMoonRockData()->showDemoOpenMoonRockFirst();
}

void showDemoOpenMoonRockWorld(GameDataHolderAccessor accessor) {
    accessor->getGameDataFile()->getMoonRockData()->showDemoOpenMoonRockWorld(
        getCurrentWorldIdNoDevelop(accessor));
}

s32 calcMoonRockTalkMessageIndex(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMoonRockData()->calcMoonRockTalkMessageIndex();
}

void addMoonRockTalkMessageIndex(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getMoonRockData()->addMoonRockTalkMessageIndex(
        getCurrentWorldId(writer));
}

bool isAppearedMoonRockTalkMessage(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMoonRockData()->isAppearedMoonRockTalkMessage(
        getCurrentWorldId(accessor));
}

void addPayShine(GameDataHolderWriter writer, s32 count) {
    writer->getGameDataFile()->addPayShine(count);
}

void addPayShineCurrentAll(GameDataHolderWriter writer) {
    writer->getGameDataFile()->addPayShineCurrentAll();
}

s32 getPayShineNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPayShineNum();
}

s32 getPayShineNum(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getPayShineNum(world_id);
}

s32 getTotalPayShineNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getTotalPayShineNum();
}

s32 getTotalPayShineNumClamp(GameDataHolderAccessor accessor) {
    return sead::Mathi::clampMax(getTotalPayShineNum(accessor), 999);
}

bool isPayShineAllInAllWorld(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPayShineAllInAllWorld();
}

void addKey(GameDataHolderWriter writer, s32 count) {
    writer->getGameDataFile()->addKey(count);
}

s32 getKeyNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getKeyNum();
}

s32 getCurrentKeyNum(GameDataHolderAccessor accessor) {
    return getKeyNum(accessor) - getOpenDoorLockNum(accessor);
}

s32 getOpenDoorLockNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getOpenDoorLockNum();
}

void openDoorLock(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    if (isOpenDoorLock(writer, placement_id))
        return;
    writer->getGameDataFile()->addOpenDoorLockNum(1);
    writer->getGameDataFile()->setStartedObj(placement_id);
}

bool isOpenDoorLock(GameDataHolderAccessor accessor, const al::PlacementId* placement_id) {
    return accessor->getGameDataFile()->isStartedObj(placement_id);
}

void setObjStarted(GameDataHolder* game_data_holder, const al::PlacementId* placement_id) {
    game_data_holder->getGameDataFile()->setStartedObj(placement_id);
}

bool isObjStarted(const GameDataHolder* game_data_holder, const al::PlacementId* placement_id) {
    return game_data_holder->getGameDataFile()->isStartedObj(placement_id);
}

bool isObjStarted(GameDataHolderAccessor accessor, const char* stage_name, const char* obj_id) {
    return accessor->getGameDataFile()->isStartedObj(stage_name, obj_id);
}

void saveObjS32(GameDataHolderWriter writer, const al::PlacementId* placement_id, s32 value) {
    writer->getGameDataFile()->setSaveObjS32(placement_id, value);
}

bool tryFindSaveObjS32Value(s32* out, GameDataHolderAccessor accessor,
                            const al::PlacementId* placement_id) {
    if (const GameDataFile::SaveObjS32* obj =
            accessor->getGameDataFile()->tryFindSaveObjS32(placement_id)) {
        *out = obj->value;
        return true;
    }
    return false;
}

void onObjNoWriteSaveData(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    writer->onObjNoWriteSaveData(placement_id);
}

void offObjNoWriteSaveData(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    writer->offObjNoWriteSaveData(placement_id);
}

bool isOnObjNoWriteSaveData(GameDataHolderAccessor accessor, const al::PlacementId* placement_id) {
    return accessor->isOnObjNoWriteSaveData(placement_id);
}

void onObjNoWriteSaveDataResetMiniGame(GameDataHolderWriter writer,
                                       const al::PlacementId* placement_id) {
    writer->onObjNoWriteSaveDataResetMiniGame(placement_id);
}

void offObjNoWriteSaveDataResetMiniGame(GameDataHolderWriter writer,
                                        const al::PlacementId* placement_id) {
    writer->offObjNoWriteSaveDataResetMiniGame(placement_id);
}

bool isOnObjNoWriteSaveDataResetMiniGame(GameDataHolderAccessor accessor,
                                         const al::PlacementId* placement_id) {
    return accessor->isOnObjNoWriteSaveDataResetMiniGame(placement_id);
}

void onObjNoWriteSaveDataInSameScenario(GameDataHolder* game_data_holder,
                                        const al::PlacementId* placement_id) {
    game_data_holder->onObjNoWriteSaveDataInSameScenario(placement_id);
}

bool isOnObjNoWriteSaveDataInSameScenario(const GameDataHolder* game_data_holder,
                                          const al::PlacementId* placement_id) {
    return game_data_holder->isOnObjNoWriteSaveDataInSameScenario(placement_id);
}

void setSessionEventProgress(GameDataHolderWriter writer, const SessionEventProgress& progress) {
    writer->getGameDataFile()->setSessionEventProgress(progress);
}

const SessionEventProgress& getSessionEventProgress(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getSessionEventProgress();
}

bool isPayCoinToSphinx(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->isPayCoinToSphinx();
}

void payCoinToSphinx(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->payCoinToSphinx();
}

static GameDataFile::CapStatus getCapStatusForJango(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCapStatusForJango();
}

static void setCapStatusForJango(GameDataHolderAccessor accessor, GameDataFile::CapStatus status) {
    return accessor->getGameDataFile()->setCapStatusForJango(status);
}

static GameDataFile::CapStatus getCapStatusForJangoSubArea(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCapStatusForJangoSubArea();
}

static void setCapStatusForJangoSubArea(GameDataHolderAccessor accessor,
                                        GameDataFile::CapStatus status) {
    return accessor->getGameDataFile()->setCapStatusForJangoSubArea(status);
}

bool isRemovedCapByJango(const al::LiveActor* actor) {
    if (!isMainStage(actor))
        return getCapStatusForJangoSubArea(actor) == GameDataFile::CapStatus::Removed;
    return getCapStatusForJango(actor) == GameDataFile::CapStatus::Removed;
}

bool isGetCapFromJango(const al::LiveActor* actor) {
    if (!isMainStage(actor))
        return getCapStatusForJangoSubArea(actor) == GameDataFile::CapStatus::GotBack;
    return getCapStatusForJango(actor) == GameDataFile::CapStatus::GotBack;
}

void removeCapByJango(const al::LiveActor* actor) {
    if (!isMainStage(actor)) {
        setCapStatusForJangoSubArea(actor, GameDataFile::CapStatus::Removed);
        return;
    }
    setCapStatusForJango(actor, GameDataFile::CapStatus::Removed);
}

void getCapFromJango(const al::LiveActor* actor) {
    if (!isMainStage(actor)) {
        setCapStatusForJangoSubArea(actor, GameDataFile::CapStatus::GotBack);
        return;
    }
    setCapStatusForJango(actor, GameDataFile::CapStatus::GotBack);
}

void addJangoCount(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->addJangoCount();
}

s32 getJangoCount(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->getJangoCount();
}

bool isFirstWorldTravelingStatus(const WorldTravelingNpc* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->isFirstWorldTravelingStatus();
}

void saveWorldTravelingStatus(const WorldTravelingNpc* actor, const char* status) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->saveWorldTravelingStatus(status);
}

const char* getWorldTravelingStatus(const WorldTravelingNpc* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->getWorldTravelingStatus();
}

bool isRaceStart(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isRaceStart();
}

bool isRaceStartFlag(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceType() == GameDataFile::RaceType_Flag;
}

bool isRaceStartYukimaru(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceType() == GameDataFile::RaceType_Yukimaru;
}

bool isRaceStartYukimaruTutorial(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceType() == GameDataFile::RaceType_YukimaruTutorial;
}

bool isRaceWin(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceResult() == GameDataFile::RaceResult_Win;
}

bool isRaceWin(GameDataHolderAccessor, s32) {
    return false;
}

bool isRaceResultSecond(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceResult() == GameDataFile::RaceResult_Second;
}

bool isRaceResultThird(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceResult() == GameDataFile::RaceResult_Third;
}

bool isRaceLose(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceResult() == GameDataFile::RaceResult_Lose;
}

bool isRaceCancel(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceResult() == GameDataFile::RaceResult_Cancel;
}

void winRace(GameDataHolderWriter writer) {
    writer->getGameDataFile()->winRace();
}

void endRaceResultSecond(GameDataHolderWriter writer) {
    writer->getGameDataFile()->setRaceResult(GameDataFile::RaceResult_Second);
}

void endRaceResultThird(GameDataHolderWriter writer) {
    writer->getGameDataFile()->setRaceResult(GameDataFile::RaceResult_Third);
}

void loseRace(GameDataHolderWriter writer) {
    writer->getGameDataFile()->setRaceResult(GameDataFile::RaceResult_Lose);
}

static s32 getRaceRivalLevelImpl(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceRivalLevel();
}

s32 getRaceRivalLevel(const al::LiveActor* actor) {
    return getRaceRivalLevelImpl(actor);
}

s32 getRaceRivalLevel(const al::Scene* scene) {
    return getRaceRivalLevelImpl(scene);
}

void setRaceRivalLevel(const al::LiveActor* actor, s32 level) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setRaceRivalLevel(level);
}

void setLastRaceRanking(GameDataHolderAccessor accessor, s32 ranking) {
    accessor->getGameDataFile()->setLastRaceRanking(ranking);
}

s32 getLastRaceRanking(GameDataHolderWriter writer) {
    return writer->getGameDataFile()->getLastRaceRanking();
}

void incrementRaceLoseCount(const al::Scene* scene, s32 level) {
    GameDataHolderAccessor accessor{scene};
    accessor->getGameDataFile()->incrementRaceLoseCount(level);
}

s32 getRaceLoseCount(const al::LiveActor* actor, s32 level) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->getRaceLoseCount(level);
}

void addCoinCollect(GameDataHolderWriter writer, const al::PlacementId* placement_id) {
    writer->getGameDataFile()->addCoinCollect(placement_id);
}

void useCoinCollect(GameDataHolderWriter writer, s32 count) {
    writer->getGameDataFile()->useCoinCollect(count);
}

bool isGotCoinCollect(GameDataHolderAccessor accessor, const al::ActorInitInfo& actor_info) {
    al::PlacementId placement_id;
    al::tryGetPlacementId(&placement_id, actor_info);
    return accessor->getGameDataFile()->isGotCoinCollect(&placement_id);
}

s32 getCoinCollectNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCoinCollectNum();
}

s32 getCoinCollectGotNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCoinCollectGotNum();
}

s32 getCoinCollectGotNum(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getCoinCollectGotNum(world_id);
}

s32 getCoinCollectNumMax(GameDataHolderAccessor accessor) {
    return accessor->getCoinCollectNumMax(getCurrentWorldId(accessor));
}

s32 getCoinCollectNumMax(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getCoinCollectNumMax(world_id);
}

bool tryFindExistCoinCollectStagePosExcludeHomeStageInCurrentWorld(
    sead::Vector3f* out_pos, const char** out_stage_name, GameDataHolderAccessor accessor) {
    s32 world_id = getCurrentWorldIdNoDevelop(accessor);
    if (const char* stage_name =
            accessor->getGameDataFile()->tryFindExistCoinCollectStageName(world_id)) {
        if (accessor->getWorldList()->tryFindTransOnMainStageByStageName(
                out_pos, stage_name, getWorldScenarioNo(accessor, world_id))) {
            *out_stage_name = stage_name;
            return true;
        }
    }
    return false;
}

s32 getWorldScenarioNo(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getScenarioNo(world_id);
}

void addCoin(GameDataHolderWriter writer, s32 count) {
    writer->getGameDataFile()->addCoin(count);
}

void subCoin(GameDataHolderWriter writer, s32 count) {
    writer->getGameDataFile()->addCoin(-count);
}

s32 getCoinNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCoinNum();
}

s32 getTotalCoinNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getTotalCoinNum();
}

bool isAppearCourseName(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isAppearCourseName();
}

void setStageHakoniwa(GameDataHolderWriter writer) {
    writer->getGameDataFile()->setStageHakoniwa();
}

bool isEnableCheckpointWarp(GameDataHolderAccessor accessor) {
    return accessor->isEnableCheckpointWarp();
}

void validateCheckpointWarp(GameDataHolderWriter writer) {
    writer->validateCheckpointWarp();
}

void invalidateCheckpointWarp(GameDataHolderWriter writer) {
    writer->invalidateCheckpointWarp();
}

s32 getCheckpointNumMaxInWorld(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCheckpointNumMaxInWorld();
}

const sead::Vector3f& getCheckpointTransInWorld(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getCheckpointTransInWorld(
        getCheckpointObjIdInWorld(accessor, index));
}

const sead::Vector3f& getCheckpointTransInWorld(GameDataHolderAccessor accessor,
                                                const char* obj_id) {
    return accessor->getGameDataFile()->getCheckpointTransInWorld(obj_id);
}

const char* getCheckpointObjIdInWorld(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getCheckpointObjIdInWorld(index);
}

bool isGotCheckpointInWorld(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->isGotCheckpointInWorld(index);
}

bool isGotCheckpoint(GameDataHolderAccessor accessor, al::PlacementId* placement_id) {
    return accessor->getGameDataFile()->isGotCheckpoint(placement_id);
}

s32 calcGotCheckpointNumInWorld(GameDataHolderAccessor accessor) {
    s32 max = getCheckpointNumMaxInWorld(accessor);
    s32 count = 0;
    for (s32 i = 0; i < max; i++)
        if (isGotCheckpointInWorld(accessor, i))
            count++;
    return count;
}

void changeNextSceneByGotCheckpoint(GameDataHolderWriter writer, s32 index) {
    writer->getGameDataFile()->changeNextSceneByGotCheckpoint(index);
}

void changeNextSceneByHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->changeNextSceneByHome();
}

bool isWarpCheckpoint(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isWarpCheckpoint();
}

const char* getCheckpointWarpObjId(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCheckpointWarpObjId();
}

void registerCheckpointTrans(GameDataHolderWriter writer, const al::PlacementId* placement_id,
                             const sead::Vector3f& trans) {
    writer->getGameDataFile()->registerCheckpointTrans(placement_id, trans);
}

bool isEnableUnlockHint(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isEnableUnlockHint();
}

void unlockHint(GameDataHolderWriter writer) {
    writer->getGameDataFile()->unlockHint();
}

void unlockHintAmiibo(GameDataHolderWriter writer) {
    writer->getGameDataFile()->unlockHintAmiibo();
}

s32 calcHintNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcHintNum();
}

s32 calcRestHintNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcRestHintNum();
}

bool checkExistHint(GameDataHolderAccessor accessor) {
    return calcHintNum(accessor) > 0;
}

s32 getHintNumMax(GameDataHolderAccessor accessor) {
    return 70;
}

const sead::Vector3f& calcHintTrans(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->calcHintTrans(index);
}

const sead::Vector3f& getLatestHintTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getLatestHint()->trans;
}

bool checkLatestHintSeaOfTree(GameDataHolderAccessor accessor) {
    return isSeaOfTreeStage(accessor->getGameDataFile()->getLatestHint()->stageName.cstr());
}

s32 calcHintMoonRockNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcHintMoonRockNum();
}

s32 getHintMoonRockNumMax(GameDataHolderAccessor accessor) {
    return 25;
}

const sead::Vector3f& calcHintMoonRockTrans(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->calcHintMoonRockTrans(index);
}

void initializeHintList(GameDataHolderWriter writer) {
    writer->getGameDataFile()->initializeHintList();
}

const sead::Vector3f& calcHintTransMostEasy(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcHintTransMostEasy();
}

bool calcHintTransMostNear(sead::Vector3f* out, GameDataHolderAccessor accessor,
                           const sead::Vector3f& pos) {
    s32 hint_num = calcHintNum(accessor);
    if (hint_num == 0)
        return false;
    f32 min_dist = sead::Mathf::maxNumber();
    for (s32 i = 0; i < hint_num; i++) {
        sead::Vector3f trans = calcHintTrans(accessor, i);
        f32 dist = (trans - pos).length();
        if (dist < min_dist) {
            out->set(trans);
            min_dist = dist;
        }
    }
    return true;
}

bool checkHintSeaOfTree(GameDataHolderAccessor accessor, s32 index) {
    return isSeaOfTreeStage(accessor->getGameDataFile()->findHint(index).stageName.cstr());
}

bool checkHintSeaOfTreeMoonRock(GameDataHolderAccessor accessor, s32 index) {
    return isSeaOfTreeStage(accessor->getGameDataFile()->findHintMoonRock(index).stageName.cstr());
}

s32 findUnlockShineNum(bool* out_is_game_clear, GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->findUnlockShineNumCurrentWorld(out_is_game_clear);
}

s32 findUnlockShineNumByWorldId(bool* out_is_game_clear, GameDataHolderAccessor accessor,
                                s32 world_id) {
    return accessor->findUnlockShineNum(out_is_game_clear, world_id);
}

bool isUnlockedWorld(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->isUnlockedWorld(world_id);
}

bool isUnlockedNextWorld(GameDataHolderAccessor accessor) {
    bool is_game_clear = false;
    s32 unlock_shine_num = findUnlockShineNum(&is_game_clear, accessor);
    return is_game_clear || getPayShineNum(accessor) >= unlock_shine_num;
}

bool isUnlockedAllWorld(GameDataHolderAccessor accessor) {
    return isUnlockedWorld(accessor, getWorldIndexSpecial2());
}

bool isUnlockedCurrentWorld(GameDataHolderAccessor accessor) {
    return isUnlockedWorld(accessor, getCurrentWorldIdNoDevelop(accessor));
}

bool isCollectShineForNextWorldAndNotUnlockNextWorld(const al::LiveActor* actor) {
    return !isUnlockedNextWorld(actor) && rs::checkGetEnoughShineInCurrentWorld(actor);
}

bool isAlreadyGoWorld(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->isAlreadyGoWorld(world_id);
}

bool isMainStage(GameDataHolderAccessor accessor) {
    return al::isEqualString(getMainStageName(accessor, getCurrentWorldId(accessor)),
                             getCurrentStageName(accessor));
}

const char* getMainStageName(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getWorldList()->getMainStageName(world_id);
}

const char* tryGetCurrentMainStageName(GameDataHolderAccessor accessor) {
    s32 world_id = getCurrentWorldId(accessor);
    if (world_id >= 1) {
        const char* stage_name = getMainStageName(accessor, world_id);
        if (stage_name && !al::isEqualString(stage_name, ""))
            return stage_name;
    }
    return getMainStageName(accessor, 0);
}

const char16* tryGetWorldName(const al::LayoutActor* layout, s32 world_id) {
    al::StringTmp<128> label;
    label.format("WorldName_%s", getWorldDevelopName(layout, world_id));
    return al::getSystemMessageString(layout, "StageName", label.cstr());
}

const char16* tryGetWorldNameCurrent(const al::LayoutActor* layout) {
    return tryGetWorldName(layout, getCurrentWorldId(layout));
}

const char16* tryGetRegionNameCurrent(const al::LayoutActor* layout) {
    s32 world_id = getCurrentWorldId(layout);
    al::StringTmp<128> label;
    label.format("RegionName_%s", getWorldDevelopName(layout, world_id));
    return al::getSystemMessageString(layout, "StageName", label.cstr());
}

const char* getWorldDevelopName(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getWorldList()->getWorldDevelopName(sead::Mathi::max(world_id, 0));
}

const char* getWorldDevelopNameCurrent(GameDataHolderAccessor accessor) {
    return accessor->getWorldList()->getWorldDevelopName(
        accessor->getGameDataFile()->getCurrentWorldIdNoDevelop());
}

s32 getWorldScenarioNum(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getWorldList()->getWorldScenarioNum(sead::Mathi::max(world_id, 0));
}

const char* findMainStageNameByDevelopName(GameDataHolderAccessor accessor, const char* name) {
    for (s32 i = 0; i < getWorldNum(accessor); i++)
        if (al::isEqualString(getWorldDevelopName(accessor, i), name))
            return getMainStageName(accessor, i);
    return nullptr;
}

s32 findWorldIdByDevelopName(GameDataHolderAccessor accessor, const char* name) {
    for (s32 i = 0; i < getWorldNum(accessor); i++)
        if (al::isEqualString(getWorldDevelopName(accessor, i), name))
            return i;
    return 0;
}

static s32 tryFindWorldIdByMainStageNameImpl(GameDataHolderAccessor accessor,
                                             const char* stage_name) {
    return accessor->getWorldList()->tryFindWorldIndexByMainStageName(stage_name);
}

s32 tryFindWorldIdByMainStageName(const al::Scene* scene, const char* stage_name) {
    return tryFindWorldIdByMainStageNameImpl(scene, stage_name);
}

s32 tryFindWorldIdByMainStageName(const al::IUseSceneObjHolder* scene_obj_holder,
                                  const char* stage_name) {
    return tryFindWorldIdByMainStageNameImpl(scene_obj_holder, stage_name);
}

bool checkEnableUnlockWorldSpecial1(const al::LiveActor* actor) {
    if (isUnlockedWorld(actor, getWorldIndexSpecial1()) ||
        isUnlockedWorld(actor, getWorldIndexSpecial2()))
        return false;
    bool is_game_clear = false;
    s32 unlock_shine_num = findUnlockShineNum(&is_game_clear, actor);
    return is_game_clear && getTotalPayShineNum(actor) >= unlock_shine_num;
}

bool checkEnableUnlockWorldSpecial2(const al::LiveActor* actor) {
    if (!isUnlockedWorld(actor, getWorldIndexSpecial1()) ||
        isUnlockedWorld(actor, getWorldIndexSpecial2()))
        return false;
    bool is_game_clear = false;
    s32 unlock_shine_num = findUnlockShineNum(&is_game_clear, actor);
    return is_game_clear && getTotalPayShineNum(actor) >= unlock_shine_num;
}

const char16* tryGetWorldNameByFileId(const al::LayoutActor* layout, s32 file_id) {
    GameDataHolderAccessor accessor{layout};
    s32 world_id = accessor->getGameDataFile(file_id)->getCurrentWorldIdForDisp();
    return tryGetWorldName(layout, world_id);
}

bool isNewSaveDataByFileId(const al::LayoutActor* layout, s32 file_id) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile(file_id)->isPlayDemoOpening();
}

u64 getLastUpdateFileTime(const al::LayoutActor* layout, s32 file_id) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile(file_id)->getLastUpdateTime();
}

static bool isGotShine(const GameDataHolder* game_data_holder, const char* stage_name,
                       const char* obj_id) {
    ShineInfo shine_info;
    shine_info.init(stage_name, obj_id, nullptr, nullptr, ShineInfo::Type_Shine);
    return game_data_holder->getGameDataFile()->isGotShine(&shine_info);
}

void makeTextureSaveDataFileName(sead::BufferedSafeString* out, const nn::g3d::ResFile* res_file,
                                 const GameDataHolder* game_data_holder, s32 file_id) {
    const GameDataFile* game_data_file = game_data_holder->getGameDataFile(file_id);
    s32 world_id = sead::Mathi::clampMin(game_data_file->getCurrentWorldIdForDisp(), 0);
    const char* world_name = game_data_holder->getWorldList()->getWorldDevelopName(world_id);
    s32 main_scenario_no = game_data_file->getMainScenarioNo(world_id);
    s32 scenario_no = game_data_file->getScenarioNo(world_id);

    if (world_id == getWorldIndexPeach()) {
        if (game_data_file->getTotalPayShineNumForDisp() == 999) {
            out->format("PeachWorldCapOn");
            if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
                return;
        }
        out->format("PeachWorld");
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
    }

    if (game_data_holder->getWorldList()->isEqualMoonRockScenarioNo(world_id, scenario_no)) {
        out->format("%sWorldMoonRock", world_name);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
        out->format("%sWorldED", world_name);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
        out->format("%sWorld", world_name);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
        return;
    }

    if (game_data_holder->getWorldList()->isEqualAfterEndingScenarioNo(world_id, scenario_no)) {
        out->format("%sWorldED", world_name);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
        out->format("%sWorld", world_name);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
        return;
    }

    if (world_id == getWorldIndexCity()) {
        if (scenario_no == 1) {
            out->format("CityWorld00");
            return;
        }
        if (scenario_no == 2) {
            if (main_scenario_no <= 3) {
                out->format("CityWorld01");
                return;
            }
            out->format("CityWorld02");
            return;
        }
        if (isCityWorldCeremonyAll(world_id, scenario_no)) {
            out->format("CityWorld03");
            return;
        }
        out->format("CityWorld");
        return;
    }

    if (world_id == getWorldIndexSea()) {
        if (scenario_no == 1) {
            if (main_scenario_no == 0) {
                s32 count = 0;
                if (isGotShine(game_data_holder, "SeaWorldHomeStage", "obj382"))
                    count++;
                if (isGotShine(game_data_holder, "SeaWorldLighthouseZone", "obj16"))
                    count++;
                if (isGotShine(game_data_holder, "SeaWorldLavaZone", "obj168"))
                    count++;
                if (isGotShine(game_data_holder, "SeaWorldDamageBallZone", "obj60"))
                    count++;
                if (count == 0) {
                    out->format("SeaWorld00");
                    return;
                }
                out->format("SeaWorld01");
                return;
            }
            if (main_scenario_no == 1) {
                out->format("SeaWorld02");
                return;
            }
        }
        out->format("SeaWorld");
        return;
    }

    if (game_data_file->isPlayDemoOpening()) {
        out->format("Empty");
        return;
    }

    if (main_scenario_no >= 0) {
        out->format("%sWorld%02d", world_name, main_scenario_no);
        if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
            return;
    }

    out->format("%sWorld", world_name);
    if (agl::g3d::ResFile::GetTextureIndex(res_file, out->cstr()) != -1)
        return;
}

void unlockWorld(GameDataHolderWriter writer, s32 world_id) {
    writer->getGameDataFile()->unlockWorld(world_id);
}

static s32 getUnlockWorldIdForWorldMapImpl(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getGameProgressData()->getWorldIdForWorldMap(world_id);
}

s32 getUnlockWorldIdForWorldMap(const al::LayoutActor* layout, s32 world_id) {
    return getUnlockWorldIdForWorldMapImpl(layout, world_id);
}

s32 getUnlockWorldIdForWorldMap(const al::LiveActor* actor, s32 world_id) {
    return getUnlockWorldIdForWorldMapImpl(actor, world_id);
}

s32 getUnlockWorldIdForWorldMap(const al::Scene* scene, s32 world_id) {
    return getUnlockWorldIdForWorldMapImpl(scene, world_id);
}

s32 getUnlockWorldIdForWorldMap(const GameDataHolder* game_data_holder, s32 world_id) {
    return game_data_holder->getGameDataFile()->getGameProgressData()->getWorldIdForWorldMap(
        world_id);
}

static s32 getUnlockWorldNumForWorldMapImpl(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->getUnlockWorldNum();
}

s32 getUnlockWorldNumForWorldMap(const al::Scene* scene) {
    return getUnlockWorldNumForWorldMapImpl(scene);
}

s32 getUnlockWorldNumForWorldMap(const al::LiveActor* actor) {
    return getUnlockWorldNumForWorldMapImpl(actor);
}

s32 getUnlockWorldNumForWorldMap(const al::LayoutActor* layout) {
    return getUnlockWorldNumForWorldMapImpl(layout);
}

static s32 calcNextLockedWorldIdForWorldMapImpl(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getGameProgressData()->calcNextLockedWorldIdForWorldMap(
        world_id);
}

s32 calcNextLockedWorldIdForWorldMap(const al::LayoutActor* layout, s32 world_id) {
    return calcNextLockedWorldIdForWorldMapImpl(layout, world_id);
}

s32 calcNextLockedWorldIdForWorldMap(const al::Scene* scene, s32 world_id) {
    return calcNextLockedWorldIdForWorldMapImpl(scene, world_id);
}

static s32 calcNextLockedWorldNumForWorldMapImpl(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->calcNextLockedWorldNumForWorldMap();
}

s32 calcNextLockedWorldNumForWorldMap(const al::Scene* scene) {
    return calcNextLockedWorldNumForWorldMapImpl(scene);
}

s32 calcNextLockedWorldNumForWorldMap(const al::LayoutActor* layout) {
    return calcNextLockedWorldNumForWorldMapImpl(layout);
}

s32 getWorldIdForShineList(const al::LayoutActor* layout, s32 world_id) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile()->getGameProgressData()->getWorldIdForShineList(world_id);
}

s32 calcWorldNumForShineList(const al::LayoutActor* layout) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile()->getGameProgressData()->calcWorldNumForShineList();
}

s32 getLatestUnlockWorldIdForShineTowerMeter(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->getGameProgressData()->getWorldIdForWorldWarpHole(
        getUnlockWorldNumForWorldMapImpl(accessor) - 1);
}

bool isClearSandWorldScenario1(const al::Scene* scene) {
    GameDataHolderAccessor accessor{scene};
    s32 world_id = accessor->getWorldList()->tryFindWorldIndexByDevelopName("Sand");
    return getWorldScenarioNo(scene, world_id) > 1;
}

bool isClearCityWorldScenario1(const al::Scene* scene) {
    GameDataHolderAccessor accessor{scene};
    s32 world_id = accessor->getWorldList()->tryFindWorldIndexByDevelopName("City");
    return getWorldScenarioNo(scene, world_id) > 1;
}

bool isClearSkyWorldScenario1(const al::Scene* scene) {
    GameDataHolderAccessor accessor{scene};
    s32 world_id = accessor->getWorldList()->tryFindWorldIndexByDevelopName("Sky");
    return getWorldScenarioNo(scene, world_id) > 1;
}

bool isCityWorldScenario2(const al::IUseSceneObjHolder* scene_obj_holder) {
    if (isWorldCity(scene_obj_holder) && rs::getActiveQuestNum(scene_obj_holder) > 0) {
        s32 quest_no = rs::getActiveQuestNo(scene_obj_holder);
        if (quest_no >= 2 && quest_no <= 6)
            return true;
    }
    return false;
}

s32 calcNextWorldId(GameDataHolderAccessor accessor) {
    return accessor->getWorldList()->tryFindWorldIndexByMainStageName(accessor->getNextStageName());
}

bool isPlayDemoWorldWarp(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoWorldWarp();
}

bool isPlayDemoWorldWarpHole(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoWorldWarpHole();
}

void noPlayDemoWorldWarp(GameDataHolderWriter writer) {
    writer->getGameDataFile()->noPlayDemoWorldWarp();
}

bool isPlayDemoReturnToHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoReturnToHome();
}

void requestPlayDemoReturnToHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->requestPlayDemoReturnToHome();
}

bool isPlayDemoAwardSpecial(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoAwardSpecial();
}

void requestPlayDemoAwardSpecial(GameDataHolderWriter writer) {
    writer->getGameDataFile()->requestPlayDemoAwardSpecial();
}

bool isPlayDemoLavaErupt(GameDataHolderAccessor accessor) {
    return accessor->isPlayDemoLavaErupt();
}

bool isPlayDemoPlayerDownForBattleKoopaAfter(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isPlayDemoPlayerDownForBattleKoopaAfter();
}

void disablePlayDemoPlayerDownForBattleKoopaAfter(GameDataHolderWriter writer) {
    writer->getGameDataFile()->disablePlayDemoPlayerDownForBattleKoopaAfter();
}

void enteredStage(GameDataHolderWriter writer) {
    writer->getGameDataFile()->enteredStage();
    writer->resetTemporaryScenarioCameraHolder();
}

const char* getCurrentCostumeTypeName(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCurrentCostumeName();
}

const char* getCurrentCapTypeName(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getCurrentCapName();
}

void wearCostume(GameDataHolderWriter writer, const char* name) {
    writer->getGameDataFile()->wearCostume(name);
    rs::trySavePrepoChangeClothEvent(name, getPlayTimeTotal(writer), getSaveDataIdForPrepo(writer),
                                     getPlayTimeAcrossFile(writer));
}

void wearCap(GameDataHolderWriter writer, const char* name) {
    writer->getGameDataFile()->wearCap(name);
    rs::trySavePrepoChangeCapEvent(name, getPlayTimeTotal(writer), getSaveDataIdForPrepo(writer),
                                   getPlayTimeAcrossFile(writer));
}

void wearCostumeRandom(al::IUseSceneObjHolder* scene_obj_holder) {
    const char* current = getCurrentCostumeTypeName(scene_obj_holder);
    const char* target = "Mario";
    s32 total_num = rs::calcHaveClothNum(scene_obj_holder);
    if (total_num != 1) {
        s32 seen_num = 1;
        for (s32 i = 0; i < rs::getClothListSize(scene_obj_holder); i++) {
            if (!rs::isHaveCloth(scene_obj_holder, i) ||
                al::isEqualString(current, rs::getClothList(scene_obj_holder)[i]->name))
                continue;
            f32 chance = 100.0f / (total_num - seen_num++);
            if (al::getRandom(0.0f, 100.0f) < chance) {
                target = rs::getClothList(scene_obj_holder)[i]->name;
                break;
            }
        }
    }
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->wearCostume(target);
}

void wearCapRandom(al::IUseSceneObjHolder* scene_obj_holder) {
    const char* current = getCurrentCapTypeName(scene_obj_holder);
    const char* target = "Mario";
    s32 total_num = rs::calcHaveCapNum(scene_obj_holder);
    if (total_num != 1) {
        s32 seen_num = 1;
        for (s32 i = 0; i < rs::getCapListSize(scene_obj_holder); i++) {
            if (!rs::isHaveCap(scene_obj_holder, i) ||
                al::isEqualString(current, rs::getClothList(scene_obj_holder)[i]->name))
                continue;
            f32 chance = 100.0f / (total_num - seen_num++);
            if (al::getRandom(0.0f, 100.0f) < chance) {
                target = rs::getCapList(scene_obj_holder)[i]->name;
                break;
            }
        }
    }
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->wearCap(target);
}

void tryWearCostumeRandomIfEnable(al::IUseSceneObjHolder* scene_obj_holder) {
    if (isCostumeRandomMode(scene_obj_holder))
        wearCostumeRandom(scene_obj_holder);
}

void tryWearCapRandomIfEnable(al::IUseSceneObjHolder* scene_obj_holder) {
    if (isCapRandomMode(scene_obj_holder))
        wearCapRandom(scene_obj_holder);
}

bool isCostumeRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    return accessor->getGameDataFile()->isCostumeRandom();
}

bool isCapRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    return accessor->getGameDataFile()->isCapRandom();
}

void setCostumeRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->setCostumeRandom(true);
    rs::trySavePrepoChangeClothEvent("Random", getPlayTimeTotal(scene_obj_holder),
                                     getSaveDataIdForPrepo(scene_obj_holder),
                                     getPlayTimeAcrossFile(scene_obj_holder));
}

void setCapRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->setCapRandom(true);
    rs::trySavePrepoChangeCapEvent("Random", getPlayTimeTotal(scene_obj_holder),
                                   getSaveDataIdForPrepo(scene_obj_holder),
                                   getPlayTimeAcrossFile(scene_obj_holder));
}

void resetCostumeRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->setCostumeRandom(false);
}

void resetCapRandomMode(al::IUseSceneObjHolder* scene_obj_holder) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->setCapRandom(false);
}

const sead::PtrArray<ShopItem::ShopItemInfo>& getShopItemInfoList(GameDataHolderAccessor accessor) {
    return *&accessor->getShopItemInfoList();
}

bool isExistHackObjInfo(GameDataHolderAccessor accessor, const char* hack_name) {
    return getHackObjInfo(accessor, hack_name) != nullptr;
}

const HackObjInfo* getHackObjInfo(GameDataHolderAccessor accessor, const char* hack_name) {
    const sead::PtrArray<HackObjInfo>& list = accessor->getHackObjList();
    for (s32 i = 0; i < list.size(); i++)
        if (al::isEqualString(list.unsafeAt(i)->hackName, hack_name))
            return list.unsafeAt(i);
    return nullptr;
}

void addHackDictionary(GameDataHolderWriter writer, const char* hack_name) {
    writer->getGameDataFile()->addHackDictionary(hack_name);
}

bool isExistInHackDictionary(GameDataHolderAccessor accessor, const char* hack_name) {
    return accessor->getGameDataFile()->isExistInHackDictionary(hack_name);
}

bool isExistInHackDictionary(GameDataHolderAccessor accessor, const char* hack_name, s32 file_id) {
    return accessor->getGameDataFile(file_id)->isExistInHackDictionary(hack_name);
}

bool isShowHackTutorial(GameDataHolderAccessor accessor, const char* hack_name,
                        const char* suffix) {
    return accessor->isShowHackTutorial(hack_name, suffix);
}

void setShowHackTutorial(GameDataHolderWriter writer, const char* hack_name, const char* suffix) {
    writer->setShowHackTutorial(hack_name, suffix);
}

bool isShowBindTutorial(GameDataHolderAccessor accessor, const BindInfo& bind_info) {
    return accessor->isShowBindTutorial(bind_info.name);
}

void setShowBindTutorial(GameDataHolderWriter writer, const BindInfo& bind_info) {
    writer->setShowBindTutorial(bind_info.name);
}

bool isGotShine(GameDataHolderAccessor accessor, s32 world_id, s32 index) {
    return accessor->getGameDataFile()->isGotShine(world_id, index);
}

bool isOpenShineName(const al::LayoutActor* layout, s32 world_id, s32 index) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile()->isOpenShineName(world_id, index);
}

bool checkAchievementShine(const al::LayoutActor* layout, s32 world_id, s32 index) {
    GameDataHolderAccessor accessor{layout};
    return accessor->getGameDataFile()->checkAchievementShine(world_id, index);
}

s32 calcShineNumInOneShine(const al::LayoutActor* layout, s32 world_id, s32 index) {
    GameDataHolderAccessor accessor{layout};
    return sead::Mathi::clampMax(
        accessor->getGameDataFile()->calcShineNumInOneShine(world_id, index), 99);
}

ALWAYS_INLINE static const char16* getShineMessage(const al::IUseSceneObjHolder* scene_obj_holder,
                                                   const al::IUseMessageSystem* message_system,
                                                   s32 world_id, s32 index) {
    const GameDataFile::HintInfo* info =
        getGameDataHolder(scene_obj_holder)->getGameDataFile()->findShine(world_id, index);
    al::StringTmp<128> label;
    al::PlacementId placement_id{info->objId.cstr(), nullptr, nullptr};
    rs::makeMessageLabel(&label, &placement_id, "ScenarioName");
    return al::isExistLabelInStageMessage(message_system, info->stageName.cstr(), label.cstr()) ?
               al::getStageMessageString(message_system, info->stageName.cstr(), label.cstr()) :
               u"シャイン名未設定";
}

const char16* tryFindShineMessage(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return getShineMessage(layout, layout, world_id, index);
}

const char16* tryFindShineMessage(const al::LiveActor* actor,
                                  const al::IUseMessageSystem* message_system, s32 world_id,
                                  s32 index) {
    return getShineMessage(actor, message_system, world_id, index);
}

u64 findShineGetTime(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return getGameDataHolder(layout)->getGameDataFile()->findShine(world_id, index)->getTime;
}

bool checkMoonRockShineForShineList(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return getGameDataHolder(layout)->getGameDataFile()->findShine(world_id, index)->isMoonRock;
}

bool checkUnlockHintByHintNpcForShineList(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return getGameDataHolder(layout)
        ->getGameDataFile()
        ->findShine(world_id, index)
        ->isHintStatusUnlockByNpc();
}

bool checkUnlockHintByAmiiboForShineList(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return getGameDataHolder(layout)
        ->getGameDataFile()
        ->findShine(world_id, index)
        ->isHintStatusUnlockByAmiibo();
}

bool checkShineSeaOfTreeForShineList(const al::LayoutActor* layout, s32 world_id, s32 index) {
    return isSeaOfTreeStage(
        getGameDataHolder(layout)->getGameDataFile()->findShine(world_id, index)->stageName.cstr());
}

s32 getWorldTotalShineNum(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getWorldTotalShineNum(world_id);
}

s32 getWorldTotalShineNumMax(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->getGameDataFile()->getWorldTotalShineNumMax(world_id);
}

void findShineTrans(sead::Vector3f* out, GameDataHolderAccessor accessor, s32 world_id, s32 index) {
    out->set(accessor->getGameDataFile()->findShine(world_id, index)->trans);
}

const sead::Vector3f& getHomeTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getHomeTrans();
}

bool isExistHome(GameDataHolderAccessor accessor) {
    return isGameClear(accessor) || (isActivateHome(accessor) && isUnlockedCurrentWorld(accessor));
}

bool isActivateHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isActivateHome();
}

s32 getMiniGameNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcMiniGameNum();
}

s32 getMiniGameNumMax(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMiniGameNumMax();
}

const sead::Vector3f& getMiniGameTrans(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getMiniGameTrans(index);
}

const char* getMiniGameName(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getMiniGameName(index);
}

const sead::Vector3f& getRaceStartTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceStartTrans();
}

const sead::Vector3f& getRaceGoalTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getRaceGoalTrans();
}

const sead::Vector3f& getHintNpcTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getHintNpcTrans();
}

const sead::Vector3f& getShopNpcTrans(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getShopNpcTrans(index);
}

bool isShopSellout(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->isShopSellout(index);
}

s32 calcShopNum(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->calcShopNum();
}

s32 getShopNpcIconNumMax(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getShopNpcIconNumMax();
}

bool isExistRaceStartNpc(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistRaceStartNpc();
}

bool isExistHintNpc(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistHintNpc();
}

const sead::Matrix34f& getCurrentMapView(GameDataHolderAccessor accessor) {
    return accessor->getMapDataHolder()->findViewMtx(getCurrentWorldIdNoDevelop(accessor));
}

bool isExistJango(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistJango();
}

const sead::Vector3f& getJangoTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getJangoTrans();
}

bool isExistAmiiboNpc(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistAmiiboNpc();
}

const sead::Vector3f& getAmiiboNpcTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getAmiiboNpcTrans();
}

bool isInInvalidOpenMapStage(GameDataHolderAccessor accessor) {
    return accessor->isInvalidOpenMapStage(getCurrentStageName(accessor),
                                           getScenarioNoImpl(accessor));
}

const sead::Vector3f& getStageMapPlayerPos(GameDataHolderAccessor accessor) {
    return accessor->getStageMapPlayerPos();
}

bool isExistTimeBalloonNpc(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistTimeBalloonNpc();
}

const sead::Vector3f& getTimeBalloonNpcTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getTimeBalloonNpcTrans();
}

bool isExistPoetter(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isExistPoetter();
}

const sead::Vector3f& getPoetterTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getPoetterTrans();
}

const sead::Vector3f& getMoonRockTrans(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getMoonRockTrans();
}

void setHomeTrans(const al::LiveActor* actor, const sead::Vector3f& trans) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setHomeTrans(trans);
}

void setRaceStartNpcTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setRaceStartNpcTrans(al::getTrans(actor));
}

void setRaceStartTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setRaceStartTrans(al::getTrans(actor));
}

void setRaceGoalTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setRaceGoalTrans(al::getTrans(actor));
}

void setHintNpcTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setHintNpcTrans(al::getTrans(actor));
}

void setJangoTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setJangoTrans(al::getTrans(actor));
}

void disableJangoTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->disableJangoTrans();
}

void setAmiiboNpcTrans(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setAmiiboNpcTrans(al::getTrans(actor));
}

void setShopNpcTrans(const al::LiveActor* actor, const char* name, s32 type) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->setShopNpcTrans(al::getTrans(actor), name, type);
}

void setShopNpcTrans(GameDataHolderAccessor accessor, const al::PlacementInfo& placement_info) {
    sead::Vector3f trans = sead::Vector3f::zero;
    al::getTrans(&trans, placement_info);
    const char* name = nullptr;
    if (al::tryGetStringArg(&name, placement_info, "StoreName"))
        accessor->getGameDataFile()->setShopNpcTrans(trans, name, 0);
}

void setMiniGameInfo(GameDataHolderAccessor accessor, const al::PlacementInfo& placement_info) {
    sead::Vector3f trans = sead::Vector3f::zero;
    al::getTrans(&trans, placement_info);
    const char* name = nullptr;
    if (al::tryGetStringArg(&name, placement_info, "MiniGameName"))
        accessor->getGameDataFile()->setMiniGameInfo(trans, name);
}

void setTimeBalloonTrans(GameDataHolderAccessor accessor, const sead::Vector3f& trans) {
    accessor->getGameDataFile()->setTimeBalloonNpcTrans(trans);
}

void setPoetterTrans(GameDataHolderAccessor accessor, const sead::Vector3f& trans) {
    accessor->getGameDataFile()->setPoetterTrans(trans);
}

void setStageMapPlayerPos(GameDataHolderWriter writer, const sead::Vector3f& pos) {
    writer->setStageMapPlayerPos(pos);
}

void setMoonRockTrans(GameDataHolderWriter writer, const sead::Vector3f& trans) {
    writer->getGameDataFile()->setMoonRockTrans(trans);
}

s32 getHomeLevel(GameDataHolderAccessor accessor) {
    if (rs::isModeE3Rom() || rs::isModeE3LiveRom())
        return 3;
    return accessor->getGameDataFile()->getGameProgressData()->getHomeLevel();
}

void upHomeLevel(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->upHomeLevel();
}

void activateHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->setActivateHome();
}

bool isLaunchHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isLaunchHome();
}

void launchHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->launchHome();
}

bool isCrashHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isCrashHome();
}

void crashHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->crashHome();
}

bool isRepairHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isRepairHome();
}

void repairHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->repairHome();
}

bool isBossAttackedHome(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isBossAttackedHome();
}

void bossAttackHome(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->bossAttackHome();
}

bool isRepairHomeByCrashedBoss(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isRepairHomeByCrashedBoss();
}

void repairHomeByCrashedBoss(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->repairHomeByCrashedBoss();
}

bool isFindKoopaNext(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->isFindKoopaNext(world_id);
}

bool isBossAttackedHomeNext(GameDataHolderAccessor accessor, s32 world_id) {
    return accessor->isBossAttackedHomeNext(world_id);
}

bool isFindKoopa(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->getGameProgressData()->isFindKoopa();
}

void findKoopa(GameDataHolderWriter writer) {
    writer->getGameDataFile()->getGameProgressData()->findKoopa();
}

bool isEnableCap(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isEnableCap();
}

bool isMeetCap(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isMeetCap();
}

void enableCap(GameDataHolderWriter writer) {
    writer->getGameDataFile()->meetCap();
}

void disableCapByPlacement(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->disableCapByPlacement();
}

bool isTalkedCapNearHomeInWaterfall(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    return accessor->getGameDataFile()->getGameProgressData()->isTalkedCapNearHomeInWaterfall();
}

void talkCapNearHomeInWaterfall(const al::LiveActor* actor) {
    GameDataHolderAccessor accessor{actor};
    accessor->getGameDataFile()->getGameProgressData()->talkCapNearHomeInWaterfall();
}

bool isFlagOnTalkMessageInfo(const al::IUseSceneObjHolder* scene_obj_holder, s32 index) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    return accessor->getGameDataFile()->isFlagOnTalkMessageInfo(index);
}

void onFlagTalkMessageInfo(const al::IUseSceneObjHolder* scene_obj_holder, s32 index) {
    GameDataHolderAccessor accessor{scene_obj_holder};
    accessor->getGameDataFile()->setFlagOnTalkMessageInfo(index);
}

s32 getWorldIndexHat() {
    return 0;
}

s32 getWorldIndexWaterfall() {
    return 1;
}

s32 getWorldIndexSand() {
    return 2;
}

s32 getWorldIndexForest() {
    return 3;
}

s32 getWorldIndexLake() {
    return 4;
}

s32 getWorldIndexCloud() {
    return 5;
}

s32 getWorldIndexClash() {
    return 6;
}

s32 getWorldIndexCity() {
    return 7;
}

s32 getWorldIndexSea() {
    return 8;
}

s32 getWorldIndexSnow() {
    return 9;
}

s32 getWorldIndexLava() {
    return 10;
}

s32 getWorldIndexBoss() {
    return 11;
}

s32 getWorldIndexSky() {
    return 12;
}

s32 getWorldIndexMoon() {
    return 13;
}

s32 getWorldIndexPeach() {
    return 14;
}

s32 getWorldIndexSpecial1() {
    return 15;
}

s32 getWorldIndexSpecial2() {
    return 16;
}

bool isWorldCap(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Cap");
}

bool isWorldWaterfall(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)),
                             "Waterfall");
}

bool isWorldSand(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Sand");
}

bool isWorldForest(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Forest");
}

bool isWorldLake(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Lake");
}

bool isWorldCloud(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Cloud");
}

bool isWorldClash(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Clash");
}

bool isWorldCity(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "City");
}

bool isWorldSnow(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Snow");
}

bool isWorldSea(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Sea");
}

bool isWorldBoss(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Attack");
}

bool isWorldSky(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Sky");
}

bool isWorldMoon(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Moon");
}

bool isWorldPeach(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)), "Peach");
}

bool isWorldSpecial1(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)),
                             "Special1");
}

bool isWorldSpecial2(GameDataHolderAccessor accessor) {
    return al::isEqualString(getWorldDevelopName(accessor, getCurrentWorldId(accessor)),
                             "Special2");
}

bool isWorldTypeMoon(GameDataHolderAccessor, s32 world_id) {
    return world_id == getWorldIndexMoon() || world_id == getWorldIndexSpecial1() ||
           world_id == getWorldIndexSpecial2();
}

bool isSnowMainScenario1(const al::IUseSceneObjHolder* scene_obj_holder) {
    return rs::getActiveQuestNum(scene_obj_holder) > 0 &&
           rs::getActiveQuestList(scene_obj_holder)[0]->getQuestNo() == 0;
}

bool isSnowMainScenario2(const al::IUseSceneObjHolder* scene_obj_holder) {
    return rs::getActiveQuestNum(scene_obj_holder) > 0 &&
           rs::getActiveQuestList(scene_obj_holder)[0]->getQuestNo() == 1;
}

bool isHomeShipStage(const GameDataHolder* game_data_holder) {
    return al::isEqualString(game_data_holder->getCurrentStageName(), getHomeShipStageName());
}

const char* getHomeShipStageName() {
    return "HomeShipInsideStage";
}

bool isCityWorldCeremonyAll(s32 world_id, s32 scenario_no) {
    if (world_id != getWorldIndexCity())
        return false;
    switch (scenario_no) {
    case 3:
    case 7:
    case 11:
        return true;
    default:
        return false;
    }
}

bool isCityWorldCeremonyAgain(s32 world_id, s32 scenario_no) {
    if (world_id != getWorldIndexCity())
        return false;
    switch (scenario_no) {
    case 7:
    case 11:
        return true;
    default:
        return false;
    }
}

bool isGoToCeremonyFromInsideHomeShip(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isGoToCeremonyFromInsideHomeShip();
}

void registerScenarioStartCameraInfo(const ScenarioStartCamera* actor, s32 id,
                                     al::CameraTicket* camera) {
    getGameDataHolder(actor)->getTemporaryScenarioCameraHolder()->registInfo(id, camera);
}

bool isEnableExplainAmiibo(GameDataHolderAccessor accessor) {
    return accessor->isEnableExplainAmiibo();
}

void endExplainAmiibo(GameDataHolderWriter writer) {
    writer->disableExplainAmiibo();
}

void startSearchHintByAmiibo(GameDataHolderWriter writer) {
    writer->startSearchHintByAmiibo();
}

void endSearchHintByAmiibo(GameDataHolderWriter writer) {
    writer->endSearchHintByAmiibo();
}

void setKidsModeOn(const al::Scene* scene) {
    GameDataHolderAccessor accessor{scene};
    accessor->getGameDataFile()->setKidsMode(true);
}

void setKidsModeOff(const al::Scene* scene) {
    GameDataHolderAccessor accessor{scene};
    accessor->getGameDataFile()->setKidsMode(false);
}

bool isCollectedBgm(GameDataHolderAccessor accessor, const char* name, const char* situation_name) {
    return accessor->getGameDataFile()->isCollectedBgm(name, situation_name);
}

const CollectBgm& getCollectBgmByIndex(GameDataHolderAccessor accessor, s32 index) {
    return accessor->getGameDataFile()->getCollectBgmByIndex(index);
}

bool trySetCollectedBgm(GameDataHolderWriter writer, const char* name, const char* situation_name) {
    return writer->getGameDataFile()->trySetCollectedBgm(name, situation_name);
}

s32 getCollectedBgmNum(GameDataHolderWriter writer) {
    return writer->getGameDataFile()->getCollectedBgmNum();
}

s32 getCollectedBgmNum(GameDataHolderAccessor accessor, s32 file_id) {
    return accessor->getGameDataFile(file_id)->getCollectedBgmNum();
}

s32 getCollectedBgmMaxNum(GameDataHolderWriter writer) {
    return writer->getGameDataFile()->getCollectedBgmMaxNum();
}

void registerShineInfo(GameDataHolderAccessor accessor, const ShineInfo* info,
                       const sead::Vector3f& trans) {
    accessor->getGameDataFile()->registerShineInfo(info, trans);
}

void setHintTrans(GameDataHolderAccessor accessor, s32 index, const sead::Vector3f& trans) {
    if (isMainStage(accessor))
        accessor->getGameDataFile()->setHintTrans(index, trans);
}

void resetHintTrans(GameDataHolderAccessor accessor, s32 index) {
    accessor->getGameDataFile()->resetHintTrans(index);
}

bool isKoopaLv3(GameDataHolderAccessor accessor) {
    return accessor->getGameDataFile()->isKoopaLv3();
}

}  // namespace GameDataFunction
