ksys/gdt: Implement more TriggerParam functions and StageInfo

This commit is contained in:
Léo Lam 2021-04-04 18:20:42 +02:00
parent cdd2a501a0
commit 2cf1e01137
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
16 changed files with 459 additions and 9 deletions

View File

@ -49412,7 +49412,7 @@
0x00000071007ccd88,setPSavePosForStageGen,104,
0x00000071007ccdf0,setCurrentMapNameFromPlayerPos,76,
0x00000071007cce3c,getIsStageDebug,16,
0x00000071007cce4c,sub_71007CCE4C,124,
0x00000071007cce4c,sub_71007CCE4C,124,_GLOBAL__sub_I_gameStageInfo.cpp
0x00000071007ccec8,nullsub_5409,4,
0x00000071007ccecc,sinitStageSelect,292,
0x00000071007ccff0,uking::StageSelect::ctor,404,
@ -76265,8 +76265,8 @@
0x0000007100dee554,sub_7100DEE554,796,_ZN4ksys3gdt14copyFlagArraysIN4sead7Vector3IfEEEEvRNS2_8PtrArrayINS5_INS0_8FlagBaseEEEEERKS8_RNS2_8ObjArrayINS0_12TriggerParam14FlagCopyRecordEEERNS2_9SafeArrayIiLi15EEEbbb
0x0000007100dee870,sub_7100DEE870,796,_ZN4ksys3gdt14copyFlagArraysIN4sead7Vector4IfEEEEvRNS2_8PtrArrayINS5_INS0_8FlagBaseEEEEERKS8_RNS2_8ObjArrayINS0_12TriggerParam14FlagCopyRecordEEERNS2_9SafeArrayIiLi15EEEbbb
0x0000007100deeb8c,TriggerParam::resetToInitialValues,2628,_ZN4ksys3gdt12TriggerParam28resetAllFlagsToInitialValuesEv
0x0000007100def5d0,shouldSkipReviveShopItem,868,
0x0000007100def934,TriggerParam::reset,3652,
0x0000007100def5d0,shouldSkipReviveShopItem,868,_ZNK4ksys3gdt12TriggerParam26shouldSkipRevivingShopItemEPbjbRKN4sead6BufferIiEEiiii
0x0000007100def934,TriggerParam::reset,3652,_ZN4ksys3gdt12TriggerParam27resetFlagsAccordingToPolicyEN4sead7BitFlagIjEEi
0x0000007100df0778,TriggerParam::getGameDataFlagBool,32,_ZNK4ksys3gdt12TriggerParam11getBoolFlagEi
0x0000007100df0798,TriggerParam::getBoolFlag,256,_ZNK4ksys3gdt12TriggerParam17getBoolFlagAndIdxEPij
0x0000007100df0898,sub_7100DF0898,32,_ZNK4ksys3gdt12TriggerParam10getS32FlagEi
@ -80013,7 +80013,7 @@
0x0000007100ed8c8c,getCurrentMapType,12,
0x0000007100ed8c98,setCurrentMapTypeAndName,440,
0x0000007100ed8e50,setCurrentMapNameFromPos_,416,
0x0000007100ed8ff0,sinitCurrentMapStrings,168,
0x0000007100ed8ff0,sinitCurrentMapStrings,168,_GLOBAL__sub_I_StageInfo.cpp
0x0000007100ed9098,sub_7100ED9098,56,
0x0000007100ed90d0,sub_7100ED90D0,92,
0x0000007100ed912c,StagePreActorCache::createInstance,244,
@ -80313,7 +80313,7 @@
0x0000007100ee22b4,act::findLinkReferenceObj,148,
0x0000007100ee2348,act::acc::findLinkReferenceObj,680,
0x0000007100ee25f0,sub_7100EE25F0,108,
0x0000007100ee265c,getPlayerGridPosition,244,
0x0000007100ee265c,getPlayerGridPosition,244,_ZN4ksys3act22getRevivalGridPositionERKN4sead7Vector3IfEEPiS6_S6_S6_
0x0000007100ee2750,sub_7100EE2750,56,
0x0000007100ee2788,PlacementObj::getForSaleLink,44,
0x0000007100ee27b4,sub_7100EE27B4,76,

Can't render this file because it is too large.

@ -1 +1 @@
Subproject commit 9ac7ac68fb0cd1adbb62fb2bfb52d56db3c5cc90
Subproject commit ffa3cd1219c6d828afbb29222ae8644efdc4a751

View File

@ -7,4 +7,6 @@ add_subdirectory(UI)
target_sources(uking PRIVATE
gameScene.cpp
gameScene.h
gameStageInfo.cpp
gameStageInfo.h
)

View File

@ -0,0 +1,10 @@
#include "Game/gameStageInfo.h"
#include "KingSystem/Utils/InitTimeInfo.h"
namespace uking {
static ksys::util::InitConstants sConstants;
sead::FixedSafeString<256> StageInfo::sStr;
StageInfo StageInfo::sInfo;
} // namespace uking

55
src/Game/gameStageInfo.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include <math/seadVector.h>
#include <prim/seadSafeString.h>
namespace uking {
// TODO: Incomplete, but all getters should be there
class StageInfo {
public:
static const sead::Vector3f& getPSavePosAngleForStageGen() {
return sInfo.mPSavePosAngleForStageGen;
}
static const sead::Vector3f& getPSavePosForStageGen() { return sInfo.mPSavePosForStageGen; }
static bool isDebugOrDevMap() { return sInfo.mIsDebugOrDevMap; }
static bool isViewerMapType() { return sInfo.mIsViewerMapType; }
static bool isDungeon() { return sInfo.mIsDungeon; }
static bool isCDungeon() { return sInfo.mIsCDungeon; }
static bool isTestDungeon() { return sInfo.mIsTestDungeon; }
static bool isMainFieldDungeon() { return sInfo.mIsMainFieldDungeon; }
static bool isActorViewer() { return sInfo.mIsActorViewer; }
static bool isStageDebug() { return sInfo.mIsStageDebug; }
static bool isRemainsElectric() { return sInfo.mIsRemainsElectric; }
static bool isRemainsFire() { return sInfo.mIsRemainsFire; }
static bool isRemainsWater() { return sInfo.mIsRemainsWater; }
static bool isRemainsWind() { return sInfo.mIsRemainsWind; }
static bool isFinalTrial() { return sInfo.mIsFinalTrial; }
static bool isAocField() { return sInfo.mIsAocField; }
static bool isMainField() { return sInfo.mIsMainField; }
static sead::FixedSafeString<256> sStr;
private:
static StageInfo sInfo;
sead::Vector3f mPSavePosAngleForStageGen;
sead::Vector3f mPSavePosForStageGen;
bool mIsDebugOrDevMap;
bool mIsViewerMapType;
bool mIsDungeon;
bool mIsCDungeon;
bool mIsTestDungeon;
bool mIsMainFieldDungeon;
bool mIsActorViewer;
bool mIsStageDebug;
bool mIsRemainsElectric;
bool mIsRemainsFire;
bool mIsRemainsWater;
bool mIsRemainsWind;
bool mIsFinalTrial;
bool mIsAocField;
bool mIsMainField;
};
} // namespace uking

View File

@ -1,6 +1,8 @@
#pragma once
#include <heap/seadDisposer.h>
#include <math/seadVector.h>
#include <prim/seadSafeString.h>
namespace ksys::act {
@ -11,6 +13,16 @@ class ActorSystem {
public:
void onBaseProcMgrCalc();
bool getAutoPlacementActorPos(const sead::SafeString& name, sead::Vector3f* pos) const;
sead::Heap* getEmergencyHeap() const { return mEmergencyHeap; }
const sead::Vector3f& getPlayerPos() const { return mPlayerPos; }
private:
u8 temp_0x20[0xd0 - 0x20];
sead::Heap* mEmergencyHeap;
sead::Vector3f mPlayerPos;
};
} // namespace ksys::act

View File

@ -1,5 +1,6 @@
#include "KingSystem/ActorSystem/actActorUtil.h"
#include <container/seadSafeArray.h>
#include <math/seadMathCalcCommon.h>
#include "KingSystem/ActorSystem/Profiles/actRopeBase.h"
#include "KingSystem/ActorSystem/actActor.h"
#include "KingSystem/ActorSystem/actActorConstDataAccess.h"
@ -525,6 +526,30 @@ bool isAirOctaWoodPlatformDlc(const sead::SafeString& name) {
name == "FldObj_DLC_FlyShield_Wood_A_Snow_02";
}
void getRevivalGridPosition(const sead::Vector3f& pos, int* col1, int* row1, int* col2, int* row2) {
const int col = sead::clamp((int(pos.x) + 5000) / 1000, 0, 9);
const int row = sead::clamp((int(pos.z) + 4000) / 1000, 0, 7);
const auto x = (float(col) + 0.5f) * 1000.0f - 5000.0f;
const auto z = (float(row) + 0.5f) * 1000.0f - 4000.0f;
if (x < pos.x) {
*col1 = col;
*col2 = col + 1;
} else {
*col1 = col - 1;
*col2 = col;
}
if (z < pos.z) {
*row1 = row;
*row2 = row + 1;
} else {
*row1 = row - 1;
*row2 = row;
}
}
bool getSameGroupActorName(sead::SafeString* name, BaseProcLink* link) {
return getAccessor(link).getSameGroupActorName(name);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <math/seadVector.h>
#include <prim/seadSafeString.h>
namespace al {
@ -156,6 +157,8 @@ bool isAirOctaWoodPlatformDlc(const sead::SafeString& name);
const sead::SafeString& getDefaultDropActor();
void getRevivalGridPosition(const sead::Vector3f& pos, int* col1, int* row1, int* col2, int* row2);
bool getSameGroupActorName(sead::SafeString* name, BaseProcLink* link);
bool getSameGroupActorName(sead::SafeString* name, Actor* actor);
bool getSameGroupActorName(sead::SafeString* name, const sead::SafeString& default_value,

View File

@ -497,6 +497,9 @@ public:
const map::MubinIter& iter);
static bool getShopInfoIter(u32 hash, al::ByamlIter* out, const al::ByamlIter& iter,
const u32* hashes);
bool getShopSoldOutInfo(u32 hash, al::ByamlIter* out) const {
return getShopInfoIter(hash, out, getShopSoldOutInfoValues(), getShopSoldOutInfoHashes());
}
void resetBoolFlagForRadarMgr(FlagBool& flag);
void allocRetryBuffer(sead::Heap* heap);
@ -504,6 +507,11 @@ public:
void startSyncOnLoadEnd();
const al::ByamlIter& getShopAreaInfoValues() const { return mShopAreaInfoValues; }
const u32* getShopAreaInfoHashes() const { return mShopAreaInfoHashes; }
const al::ByamlIter& getShopSoldOutInfoValues() const { return mShopSoldOutInfoValues; }
const u32* getShopSoldOutInfoHashes() const { return mShopSoldOutInfoHashes; }
private:
enum class BitFlag {
_1 = 0x1,

View File

@ -2,9 +2,18 @@
#include <algorithm>
#include <devenv/seadStackTrace.h>
#include <mc/seadCoreInfo.h>
#include <time/seadTickTime.h>
#include "KingSystem/ActorSystem/actActorSystem.h"
#include "KingSystem/ActorSystem/actActorUtil.h"
#include "KingSystem/ActorSystem/actInfoCommon.h"
#include "KingSystem/ActorSystem/actInfoData.h"
#include "KingSystem/GameData/gdtFlagProxy.h"
#include "KingSystem/GameData/gdtManager.h"
#include "KingSystem/Resource/resResourceGameData.h"
#include "KingSystem/System/PlayReportMgr.h"
#include "KingSystem/System/StageInfo.h"
#include "KingSystem/System/UIGlue.h"
#include "KingSystem/Utils/Byaml/Byaml.h"
#include "KingSystem/Utils/Debug.h"
#include "KingSystem/Utils/InitTimeInfo.h"
#include "KingSystem/Utils/SafeDelete.h"
@ -1613,6 +1622,255 @@ void TriggerParam::resetAllFlagsToInitialValues() {
}
}
int TriggerParam::resetFlagsAccordingToPolicy(sead::BitFlag32 policy, int skip) {
[[maybe_unused]] sead::TickTime now;
[[maybe_unused]] sead::TickTime time_end;
auto it = mResetEntries.begin(skip);
const auto end = mResetEntries.end();
int arrows[6];
int col1 = 0;
int row1 = 0;
int col2 = 0;
int row2 = 0;
const bool main_field = StageInfo::sIsMainField;
if (policy.isOnBit(int(ResetType::ResetAtMidnight))) {
act::getRevivalGridPosition(act::ActorSystem::instance()->getPlayerPos(), &col1, &row1,
&col2, &row2);
for (int i = 0; i < 6; ++i)
arrows[i] = ui::getPorchNum(act::arrowTypeToString(static_cast<act::ArrowType>(i)));
}
sead::Buffer<int> arrow_counts(arrows);
const auto skip_flag = [&](bool* is_shop_item, FlagBase* flag) {
return flag && !flag->isInitialValue() &&
shouldSkipRevivingShopItem(is_shop_item, flag->getHash(), main_field, arrow_counts,
col1, row1, col2, row2);
};
for (int processed = 0; it != end; ++it) {
const auto& entry = *it;
if (!policy.isOnBit(entry.reset_type.mValue))
continue;
++processed;
switch (FlagType(entry.type)) {
case FlagType::Bool: {
if (entry.reset_type == ResetType::ResetAtMidnight) {
auto* flag = getBoolFlag(entry.index);
bool is_shop_item = false;
if (!flag)
goto reset_bool;
if (skip_flag(&is_shop_item, flag))
break;
if (!is_shop_item)
goto reset_bool;
al::ByamlIter iter;
if (Manager::instance()->getShopSoldOutInfo(flag->getHash(), &iter)) {
al::ByamlIter flags;
if (!iter.tryGetIterByKey(&flags, "SoldOutFlags"))
goto reset_bool;
for (int k = 0, n = flags.getSize(); k < n; ++k) {
u32 name_hash;
if (!flags.tryGetUIntByIndex(&name_hash, k))
continue;
int flag_idx;
auto* sold_out_flag = getBoolFlagAndIdx(&flag_idx, name_hash);
if (sold_out_flag && !sold_out_flag->isInitialValue())
resetBool(flag_idx, false);
}
}
}
reset_bool:
resetBool(entry.index, false);
break;
}
case FlagType::S32:
if (entry.reset_type == ResetType::ResetAtMidnight) {
auto* flag = getS32Flag(entry.index);
bool is_shop_item = false;
if (skip_flag(&is_shop_item, flag))
break;
}
resetS32(entry.index, false);
break;
case FlagType::F32:
resetF32(entry.index, false);
break;
case FlagType::String:
resetStr(entry.index, false);
break;
case FlagType::String64:
resetStr64(entry.index, false);
break;
case FlagType::String256:
resetStr256(entry.index, false);
break;
case FlagType::Vector2f:
resetVec2f(entry.index, false);
break;
case FlagType::Vector3f:
resetVec3f(entry.index, false);
break;
case FlagType::Vector4f:
resetVec4f(entry.index, false);
break;
case FlagType::BoolArray: {
int size = 0;
getBoolArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetBool(entry.index, j, false);
break;
}
case FlagType::S32Array: {
int size = 0;
getS32ArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetS32(entry.index, j, false);
break;
}
case FlagType::F32Array: {
int size = 0;
getF32ArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetF32(entry.index, j, false);
break;
}
case FlagType::StringArray: {
int size = 0;
getStrArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetStr(entry.index, j, false);
break;
}
case FlagType::String64Array: {
int size = 0;
getStr64ArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetStr64(entry.index, j, false);
break;
}
case FlagType::String256Array: {
int size = 0;
getStr256ArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetStr256(entry.index, j, false);
break;
}
case FlagType::Vector2fArray: {
int size = 0;
getVec2fArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetVec2f(entry.index, j, false);
break;
}
case FlagType::Vector3fArray: {
int size = 0;
getVec3fArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetVec3f(entry.index, j, false);
break;
}
case FlagType::Vector4fArray: {
int size = 0;
getVec4fArraySize(&size, entry.index);
for (int j = 0; j < size; ++j)
resetVec4f(entry.index, j, false);
break;
}
case FlagType::Invalid:
break;
}
if (processed > 1024)
return it.getIndex();
}
return 0;
}
bool TriggerParam::shouldSkipRevivingShopItem(bool* is_shop_item, u32 flag_hash, bool is_main_field,
const sead::Buffer<s32>& arrow_counts, s32 col1,
s32 row1, s32 col2, s32 row2) const {
al::ByamlIter info;
if (!Manager::getShopInfoIter(flag_hash, &info, Manager::instance()->getShopAreaInfoValues(),
Manager::instance()->getShopAreaInfoHashes())) {
return false;
}
*is_shop_item = true;
if (is_main_field) {
// Check that the player is in none of the shop areas.
// If there is no Area data, the area of the dealer will be used instead.
int col = 0;
int row = 0;
int num = 1;
al::ByamlIter iter;
al::ByamlIter areas;
if (!info.tryGetIterByKey(&areas, "Areas")) {
const char* dealer = nullptr;
if (!info.tryGetStringByKey(&dealer, "Dealer"))
return false;
sead::Vector3f pos;
if (!act::ActorSystem::instance()->getAutoPlacementActorPos(dealer, &pos))
return false;
col = sead::clamp((int(pos.x) + 5000) / 1000, 0, 9);
row = sead::clamp((int(pos.z) + 4000) / 1000, 0, 7);
} else {
num = areas.getSize();
if (areas.tryGetIterByIndex(&iter, 0)) {
iter.tryGetIntByIndex(&col, 0);
iter.tryGetIntByIndex(&row, 1);
}
}
int i = 1;
while (true) {
if (col >= col1 && col <= col2 && row >= row1 && row <= row2)
return true;
if (i >= num || !areas.tryGetIterByIndex(&iter, i))
break;
iter.tryGetIntByIndex(&col, 0);
iter.tryGetIntByIndex(&row, 1);
++i;
}
}
const char* item = nullptr;
if (!info.tryGetStringByKey(&item, "Item"))
return false;
auto* info_data = act::InfoData::instance();
if (!info_data)
return false;
if (info_data->hasTag(item, act::tags::Arrow)) {
sead::FixedSafeString<64> group_name;
act::getSameGroupActorName(&group_name, item);
const auto arrow_type = act::arrowTypeFromString(group_name);
if (arrow_type == act::ArrowType::Invalid)
return false;
const int revival_count = act::getItemSaleRevivalCount(info_data, item);
if (revival_count <= 0)
return false;
if (arrow_counts[int(arrow_type)] >= revival_count)
return true;
}
return false;
}
bool TriggerParam::getBoolIfCopied(bool* value, const sead::SafeString& name, bool x,
bool y) const {
if (mCopiedBoolFlags.isEmpty())

View File

@ -10,6 +10,7 @@
#include <gfx/seadColor.h>
#include <prim/seadStorageFor.h>
#include <prim/seadTypedBitFlag.h>
#include <prim/seadBitFlag.h>
#include "KingSystem/GameData/gdtFlag.h"
#include "KingSystem/Utils/Types.h"
@ -22,8 +23,8 @@ namespace ksys::gdt {
class TriggerParam {
public:
struct ResetEntry {
sead::SizedEnum<FlagType::ValueType, u8> type;
sead::SizedEnum<ResetType, u8> reset_type;
sead::SizedEnum<FlagType::ValueType, s8> type;
sead::SizedEnum<ResetType, s8> reset_type;
s16 sub_index;
s32 index;
};
@ -385,7 +386,10 @@ public:
// endregion
void resetAllFlagsToInitialValues();
void resetFlagsAccordingToPolicy();
/// @param policy A bitmask that indicates the reset policy to use.
/// @param skip The number of flags to skip processing.
/// @return the number of flags that have been processed.
int resetFlagsAccordingToPolicy(sead::BitFlag32 policy, int skip);
// region Flag getters

View File

@ -16,11 +16,15 @@ target_sources(uking PRIVATE
PlayReportMgr.h
ProductReporter.cpp
ProductReporter.h
StageInfo.cpp
StageInfo.h
StringBoard.h
SystemPauseMgr.cpp
SystemPauseMgr.h
Timer.cpp
Timer.h
UIGlue.cpp
UIGlue.h
VFR.cpp
VFR.h
VFRValue.cpp

View File

@ -0,0 +1,27 @@
#include "KingSystem/System/StageInfo.h"
namespace ksys {
static sead::Atomic<int> sUnused;
void (*StageInfo::sChangeScene)(const sead::SafeString& map_name, const sead::SafeString& pos_name,
int x, bool triggered_by_stage_select);
bool StageInfo::sIsNotDebugStage;
bool StageInfo::sIsMainFieldDungeon;
bool StageInfo::sIsDungeon;
bool StageInfo::sIsCDungeon;
bool StageInfo::sIsMainFieldDungeon2;
bool StageInfo::sIsActorViewer;
bool StageInfo::sIsStageDebug;
bool StageInfo::sIsTestDungeon;
bool StageInfo::sIsDebugOrDevMap;
bool StageInfo::sIsRemainsElectric;
bool StageInfo::sIsRemainsFire;
bool StageInfo::sIsRemainsWater;
bool StageInfo::sIsRemainsWind;
bool StageInfo::sIsFinalTrial;
bool StageInfo::sIsAocField;
bool StageInfo::sIsMainField;
sead::FixedSafeString<32> StageInfo::sCurrentMapType;
sead::FixedSafeString<32> StageInfo::sCurrentMapName;
} // namespace ksys

View File

@ -0,0 +1,32 @@
#pragma once
#include <prim/seadSafeString.h>
#include <thread/seadAtomic.h>
namespace ksys {
class StageInfo {
public:
static void (*sChangeScene)(const sead::SafeString& map_name, const sead::SafeString& pos_name,
int x, bool triggered_by_stage_select);
static bool sIsNotDebugStage;
static bool sIsMainFieldDungeon;
static bool sIsDungeon;
static bool sIsCDungeon;
static bool sIsMainFieldDungeon2;
static bool sIsActorViewer;
static bool sIsStageDebug;
static bool sIsTestDungeon;
static bool sIsDebugOrDevMap;
static bool sIsRemainsElectric;
static bool sIsRemainsFire;
static bool sIsRemainsWater;
static bool sIsRemainsWind;
static bool sIsFinalTrial;
static bool sIsAocField;
static bool sIsMainField;
static sead::FixedSafeString<32> sCurrentMapType;
static sead::FixedSafeString<32> sCurrentMapName;
};
} // namespace ksys

View File

@ -0,0 +1 @@
#include "KingSystem/System/UIGlue.h"

View File

@ -0,0 +1,9 @@
#pragma once
#include <prim/seadSafeString.h>
namespace ksys::ui {
int getPorchNum(const sead::SafeString& name);
} // namespace ksys::ui