370 lines
17 KiB
C++
370 lines
17 KiB
C++
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <optional>
|
||
|
|
|
||
|
|
#include <Unreal/FText.hpp>
|
||
|
|
#include <Unreal/NameTypes.hpp>
|
||
|
|
|
||
|
|
#include <Api/UnrealWrapper.hpp>
|
||
|
|
#include <Static/LogGate.hpp>
|
||
|
|
#include "PalIndividual.hpp"
|
||
|
|
#include "PalTypes.hpp"
|
||
|
|
|
||
|
|
namespace PalUIExtension::Api::Pal
|
||
|
|
{
|
||
|
|
|
||
|
|
class PalDatabaseCharacterParameter : public UnrealWrapper
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalDatabaseCharacterParameter"); }
|
||
|
|
static auto DebugTag() -> const TCHAR* { return STR("PalDatabase"); }
|
||
|
|
|
||
|
|
PalDatabaseCharacterParameter() = default;
|
||
|
|
explicit PalDatabaseCharacterParameter(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalDatabaseCharacterParameter>(), DebugTag()) {}
|
||
|
|
|
||
|
|
|
||
|
|
static auto StripVariantPrefix(FName CharacterId) -> std::optional<FName>
|
||
|
|
{
|
||
|
|
const StringType Id = CharacterId.ToString();
|
||
|
|
|
||
|
|
static const StringType Prefixes[] = {
|
||
|
|
STR("BOSS_"), STR("PREDATOR_"), STR("RAID_"), STR("GYM_"),
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const StringType& Prefix : Prefixes)
|
||
|
|
{
|
||
|
|
if (Id.size() <= Prefix.size()) continue;
|
||
|
|
if (!StartsWithNoCase(Id, Prefix)) continue;
|
||
|
|
|
||
|
|
return FName(StringViewType(Id).substr(Prefix.size()), FNAME_Add);
|
||
|
|
}
|
||
|
|
return std::nullopt;
|
||
|
|
}
|
||
|
|
|
||
|
|
static auto ResolveBaseRowName(FName CharacterId) -> FName
|
||
|
|
{
|
||
|
|
return StripVariantPrefix(CharacterId).value_or(CharacterId);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- row lookups by species FName -----------------------------
|
||
|
|
|
||
|
|
auto GetZukanIndex(FName RowName) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetZukanIndex"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetZukanIndexResolved(FName CharacterId) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
if (auto Direct = GetZukanIndex(CharacterId); Direct.has_value() && *Direct > 0)
|
||
|
|
{
|
||
|
|
return Direct;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto Base = StripVariantPrefix(CharacterId);
|
||
|
|
if (!Base.has_value()) return std::nullopt;
|
||
|
|
|
||
|
|
auto Fallback = GetZukanIndex(*Base);
|
||
|
|
if (!Fallback.has_value() || *Fallback <= 0) return std::nullopt;
|
||
|
|
|
||
|
|
if constexpr (Static::kVerboseLogging)
|
||
|
|
{
|
||
|
|
Output::send<LogLevel::Verbose>(
|
||
|
|
STR("[PalDatabase] ZukanIndex: '{}' had none, resolved via base '{}' -> {}\n"),
|
||
|
|
CharacterId.ToString(), Base->ToString(), *Fallback);
|
||
|
|
}
|
||
|
|
|
||
|
|
return Fallback;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
auto GetLocalizedBaseCharacterName(FName CharacterId) -> std::optional<FText>
|
||
|
|
{
|
||
|
|
return GetLocalizedCharacterName(ResolveBaseRowName(CharacterId));
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetTribe(FName RowName) -> std::optional<EPalTribeID_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalTribeID_ ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetTribe"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetSize(FName RowName) -> std::optional<EPalSizeType_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalSizeType_ ReturnValue; } p{ RowName, EPalSizeType_::None };
|
||
|
|
return CallForReturn(STR("GetSize"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetGenusCategory(FName RowName) -> std::optional<EPalGenusCategoryType_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalGenusCategoryType_ ReturnValue; } p{ RowName, EPalGenusCategoryType_::None };
|
||
|
|
return CallForReturn(STR("GetGenusCategory"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetOrganizationType(FName RowName) -> std::optional<EPalOrganizationType_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalOrganizationType_ ReturnValue; } p{ RowName, EPalOrganizationType_::None };
|
||
|
|
return CallForReturn(STR("GetOrganizationType"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetWeaponType(FName RowName) -> std::optional<EPalWeaponType_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalWeaponType_ ReturnValue; } p{ RowName, EPalWeaponType_::None };
|
||
|
|
return CallForReturn(STR("GetWeaponType"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetBattleBGM(FName RowName) -> std::optional<EPalBattleBGMType_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalBattleBGMType_ ReturnValue; } p{ RowName, EPalBattleBGMType_::None };
|
||
|
|
return CallForReturn(STR("GetBattleBGM"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetPalAwakeningItemElement(FName ItemId) -> std::optional<EPalElementType_>
|
||
|
|
{
|
||
|
|
struct P { FName ItemId; EPalElementType_ ReturnValue; } p{ ItemId, EPalElementType_::None };
|
||
|
|
return CallForReturn(STR("GetPalAwakeningItemElement"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
struct ElementTypePair { EPalElementType_ Primary{}; EPalElementType_ Secondary{}; };
|
||
|
|
// void return, two out-params -- not CallForReturn's shape.
|
||
|
|
auto GetElementType(FName RowName) -> std::optional<ElementTypePair>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalElementType_ Element1; EPalElementType_ Element2; }
|
||
|
|
p{ RowName, EPalElementType_::None, EPalElementType_::None };
|
||
|
|
if (!Call(STR("GetElementType"), p)) return std::nullopt;
|
||
|
|
return ElementTypePair{ p.Element1, p.Element2 };
|
||
|
|
}
|
||
|
|
|
||
|
|
// void return, one out-param.
|
||
|
|
auto GetBestWorkSuitability(FName RowName) -> std::optional<EPalWorkSuitability_>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; EPalWorkSuitability_ BestWorkSuitability; }
|
||
|
|
p{ RowName, EPalWorkSuitability_::None };
|
||
|
|
if (!Call(STR("GetBestWorkSuitability"), p)) return std::nullopt;
|
||
|
|
return p.BestWorkSuitability;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetWeaponEquip(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetWeaponEquip"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetUseBossHPGauge(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetUseBossHPGauge"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetNocturnal(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetNocturnal"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsTowerBoss(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsTowerBoss"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsRaidBoss(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsRaidBoss"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsPredatorBoss(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsPredatorBoss"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsPal(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsPal"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsLegend(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsLegend"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetIsBoss(FName RowName) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
|
||
|
|
return CallForReturn(STR("GetIsBoss"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto IsArenaUnusableItem(FName ItemId) -> std::optional<bool>
|
||
|
|
{
|
||
|
|
struct P { FName ItemId; bool ReturnValue; } p{ ItemId, false };
|
||
|
|
return CallForReturn(STR("IsArenaUnusableItem"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetViewingDistance_cm(FName RowName) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetViewingDistance_cm"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetViewingAngle_Degree(FName RowName) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetViewingAngle_Degree"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetRarity(FName RowName) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetRarity"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetFoodAmount(FName RowName) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
|
||
|
|
return CallForReturn(STR("GetFoodAmount"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetPriceRate(FName RowName) -> std::optional<float>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
|
||
|
|
return CallForReturn(STR("GetPriceRate"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetHearingRate(FName RowName) -> std::optional<float>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
|
||
|
|
return CallForReturn(STR("GetHearingRate"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetExpRatio(FName RowName) -> std::optional<float>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
|
||
|
|
return CallForReturn(STR("GetExpRatio"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetCaptureRateCorrect(FName RowName) -> std::optional<float>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
|
||
|
|
return CallForReturn(STR("GetCaptureRateCorrect"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetBPClassName(FName RowName) -> std::optional<FName>
|
||
|
|
{
|
||
|
|
struct P { FName RowName; FName ReturnValue; } p{ RowName, {} };
|
||
|
|
return CallForReturn(STR("GetBPClassName"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetFirstDefeatRewardItemID(FName CharacterID) -> std::optional<FName>
|
||
|
|
{
|
||
|
|
struct P { FName CharacterID; FName ReturnValue; } p{ CharacterID, {} };
|
||
|
|
return CallForReturn(STR("GetFirstDefeatRewardItemID"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
// void return, FName out-param -- not a FString, no ownership question, just an index pair like every other FName here.
|
||
|
|
auto GetPrefixNameMsgID(FName CharacterID) -> std::optional<FName>
|
||
|
|
{
|
||
|
|
struct P { FName CharacterID; FName OutMsgID; } p{ CharacterID, {} };
|
||
|
|
if (!Call(STR("GetPrefixNameMsgID"), p)) return std::nullopt;
|
||
|
|
return p.OutMsgID;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto GetLocalizedCharacterName(FName CharacterID) -> std::optional<FText>
|
||
|
|
{
|
||
|
|
struct P { FName CharacterID; FText OutText; } p{ CharacterID, {} };
|
||
|
|
if (!Call(STR("GetLocalizedCharacterName"), p)) return std::nullopt;
|
||
|
|
return p.OutText;
|
||
|
|
}
|
||
|
|
auto GetLocalizedUniqueNPCName(FName UniqueNPCID) -> std::optional<FText>
|
||
|
|
{
|
||
|
|
struct P { FName UniqueNPCID; FText OutText; } p{ UniqueNPCID, {} };
|
||
|
|
if (!Call(STR("GetLocalizedUniqueNPCName"), p)) return std::nullopt;
|
||
|
|
return p.OutText;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- friendship ------------------------------------------------
|
||
|
|
|
||
|
|
auto GetMinFriendshipRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMinFriendshipRank")); }
|
||
|
|
auto GetMaxFriendshipRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMaxFriendshipRank")); }
|
||
|
|
auto GetFriendshipRank(int32 FriendshipPoint) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { int32 FriendshipPoint; int32 ReturnValue; } p{ FriendshipPoint, 0 };
|
||
|
|
return CallForReturn(STR("GetFriendshipRank"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto CalcFriendshipProgress(int32 FriendshipPoint) -> std::optional<float>
|
||
|
|
{
|
||
|
|
struct P { int32 FriendshipPoint; float ReturnValue; } p{ FriendshipPoint, 0.f };
|
||
|
|
return CallForReturn(STR("CalcFriendshipProgress"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
// bool return + int32& out-param.
|
||
|
|
auto GetFriendshipRequiredPointByRank(int32 FriendshipRank) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { int32 FriendshipRank; int32 OutRequiredPoint; bool ReturnValue; }
|
||
|
|
p{ FriendshipRank, 0, false };
|
||
|
|
if (!Call(STR("GetFriendshipRequiredPointByRank"), p) || !p.ReturnValue) return std::nullopt;
|
||
|
|
return p.OutRequiredPoint;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- derived from a live UPalIndividualCharacterParameter* ---------
|
||
|
|
|
||
|
|
auto GetHP(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetHP"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetMeleeAttack(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetMeleeAttack"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetShotAttack(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetShotAttack"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetDefense(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetDefense"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetCraftSpeed(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetCraftSpeed"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto GetSupport(UObject* IndividualParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
|
||
|
|
return CallForReturn(STR("GetSupport"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
auto HigherLevelOtomoFromTrainer(UObject* IndividualCharacterParameter) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualCharacterParameter; int32 ReturnValue; } p{ IndividualCharacterParameter, 0 };
|
||
|
|
return CallForReturn(STR("HigherLevelOtomoFromTrainer"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto UpdateApplyDatabaseToIndividualParameter(UObject* IndividualParameter) -> bool
|
||
|
|
{
|
||
|
|
struct P { UObject* IndividualParameter; } p{ IndividualParameter };
|
||
|
|
return Call(STR("UpdateApplyDatabaseToIndividualParameter"), p);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Raw UObject* return -- UPalPettingPresset isn't modeled anywhere
|
||
|
|
auto GetPettingPreset() -> UObject*
|
||
|
|
{
|
||
|
|
struct P { UObject* ReturnValue; } p{ nullptr };
|
||
|
|
auto Result = CallForReturn(STR("GetPettingPreset"), p, &P::ReturnValue);
|
||
|
|
return (Result && *Result) ? *Result : nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
// WorldContextObject is a plain UObject* at the native signature
|
||
|
|
// level -- the meta=(WorldContext=...) annotation only affects
|
||
|
|
// the Blueprint editor node, not the ProcessEvent frame. Pass
|
||
|
|
// any live UObject with a valid world (a player controller, an
|
||
|
|
// actor, etc.).
|
||
|
|
auto CalcCorrectedLevel(int32 TrainerLevel, int32 TargetCharacterLevel, UObject* WorldContextObject) -> std::optional<int32>
|
||
|
|
{
|
||
|
|
struct P { int32 TrainerLevel; int32 TargetCharacterLevel; UObject* WorldContextObject; int32 ReturnValue; }
|
||
|
|
p{ TrainerLevel, TargetCharacterLevel, WorldContextObject, 0 };
|
||
|
|
return CallForReturn(STR("CalcCorrectedLevel"), p, &P::ReturnValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
|
||
|
|
static auto StartsWithNoCase(const StringType& Str, const StringType& Prefix) -> bool
|
||
|
|
{
|
||
|
|
if (Str.size() < Prefix.size()) return false;
|
||
|
|
for (size_t i = 0; i < Prefix.size(); ++i)
|
||
|
|
{
|
||
|
|
CharType A = Str[i];
|
||
|
|
CharType B = Prefix[i];
|
||
|
|
if (A >= STR('a') && A <= STR('z')) A = static_cast<CharType>(A - STR('a') + STR('A'));
|
||
|
|
if (B >= STR('a') && B <= STR('z')) B = static_cast<CharType>(B - STR('a') + STR('A'));
|
||
|
|
if (A != B) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|