OdysseyDecomp/lib/al/Project/Action/ActionFlagCtrl.cpp
2025-11-22 15:05:55 +01:00

201 lines
7.2 KiB
C++

#include "Project/Action/ActionFlagCtrl.h"
#include "Library/Base/StringUtil.h"
#include "Library/HitSensor/HitSensorKeeper.h"
#include "Library/LiveActor/ActorClippingFunction.h"
#include "Library/LiveActor/ActorCollisionFunction.h"
#include "Library/LiveActor/ActorFlagFunction.h"
#include "Library/LiveActor/ActorModelFunction.h"
#include "Library/LiveActor/ActorResourceFunction.h"
#include "Library/LiveActor/ActorSensorUtil.h"
#include "Library/LiveActor/LiveActor.h"
#include "Library/Yaml/ByamlIter.h"
#include "Library/Yaml/ByamlUtil.h"
#include "Project/Action/InitResourceDataActionAnim.h"
#include "Project/HitSensor/HitSensor.h"
namespace al {
ActionSensorCtrlInfo::ActionSensorCtrlInfo() = default;
ActionFlagCtrlInfo::ActionFlagCtrlInfo() = default;
ActionFlagCtrl::ActionFlagCtrl(LiveActor* actor, const char* name)
: mParentActor(actor), mArchiveName(createStringIfInStack(name)) {}
ActionFlagCtrl* ActionFlagCtrl::tryCreate(LiveActor* actor, const char* name) {
if (!isExistModelResource(actor))
return nullptr;
sead::FixedSafeString<128> initFileName;
if (!tryGetActorInitFileName(&initFileName, actor, "ActionFlagCtrl", name))
createFileNameBySuffix(&initFileName, "ActionFlagCtrl", name);
if (!isExistModelResourceYaml(actor, initFileName.cstr(), nullptr))
return nullptr;
return new ActionFlagCtrl(actor, name);
}
inline CtrlFlag getCtrlFlagByKey(ByamlIter iter, const char* name) {
bool isValid = false;
if (!iter.tryGetBoolByKey(&isValid, name))
return CtrlFlag::NotFound;
return isValid ? CtrlFlag::ValidOn : CtrlFlag::ValidOff;
}
void ActionFlagCtrl::initPost() {
mHitSensorKeeper = mParentActor->getHitSensorKeeper();
sead::FixedSafeString<128> initFileName;
tryGetActorInitFileName(&initFileName, mParentActor, "ActionFlagCtrl", mArchiveName);
ByamlIter fileIter;
tryGetActorInitFileIter(&fileIter, mParentActor, initFileName.cstr(), mArchiveName);
mInfoCount = fileIter.getSize();
mCtrlInfoArray = new ActionFlagCtrlInfo*[mInfoCount];
for (s32 i = 0; i < mInfoCount; i++) {
ByamlIter iter;
fileIter.tryGetIterByIndex(&iter, i);
ActionFlagCtrlInfo* flagCtrlInfo = new ActionFlagCtrlInfo();
mCtrlInfoArray[i] = flagCtrlInfo;
iter.tryGetStringByKey(&flagCtrlInfo->actionName, "ActionName");
flagCtrlInfo->ctrlFlags = new CtrlFlag[5];
flagCtrlInfo->ctrlFlags[0] = getCtrlFlagByKey(iter, "ShowModel");
flagCtrlInfo->ctrlFlags[1] = getCtrlFlagByKey(iter, "CollisionParts");
flagCtrlInfo->ctrlFlags[2] = getCtrlFlagByKey(iter, "Collider");
flagCtrlInfo->ctrlFlags[3] = getCtrlFlagByKey(iter, "ClippingOff");
flagCtrlInfo->ctrlFlags[4] = getCtrlFlagByKey(iter, "FaceCtrl");
ByamlIter sensorListIter;
if (iter.tryGetIterByKey(&sensorListIter, "SensorList") && mHitSensorKeeper) {
flagCtrlInfo->sensorCtrlInfoArray =
new ActionSensorCtrlInfo[mHitSensorKeeper->getSensorNum()];
for (s32 j = 0; j < mHitSensorKeeper->getSensorNum(); j++) {
ActionSensorCtrlInfo* sensorInfoArray = flagCtrlInfo->sensorCtrlInfoArray;
sensorInfoArray[j].name = mHitSensorKeeper->getSensor(j)->getName();
ByamlIter sensorIter;
if (sensorListIter.tryGetIterByKey(&sensorIter, sensorInfoArray[j].name)) {
sensorInfoArray[j].state = getCtrlFlagByKey(sensorIter, "State");
tryGetByamlS16(&sensorInfoArray[j].startFrame, sensorIter, "StartFrame");
tryGetByamlS16(&sensorInfoArray[j].endFrame, sensorIter, "EndFrame");
}
}
}
}
}
void ActionFlagCtrl::start(const char* name) {
mCurrentCtrlInfo = findFlagInfo(name);
mIsUpdateNeeded = false;
if (!mCurrentCtrlInfo)
return;
startCtrlFlag();
startCtrlSensor();
}
ActionFlagCtrlInfo* ActionFlagCtrl::findFlagInfo(const char* name) const {
for (s32 i = 0; i < mInfoCount; i++) {
ActionFlagCtrlInfo* flagInfo = mCtrlInfoArray[i];
if (isEqualStringCase(flagInfo->actionName, name))
return flagInfo;
}
return nullptr;
}
// NON_MATCHING: Wrong compiler optimization https://decomp.me/scratch/3VkWo
void ActionFlagCtrl::startCtrlFlag() {
if (isFlagValidOn(0, !isHideModel(mParentActor)))
showModel(mParentActor);
else if (isFlagValidOff(0, !isHideModel(mParentActor)))
hideModel(mParentActor);
if (mParentActor->getCollisionParts()) {
if (isFlagValidOn(1, isValidCollisionParts(mParentActor)))
validateCollisionParts(mParentActor);
else if (isFlagValidOff(1, isValidCollisionParts(mParentActor)))
invalidateCollisionParts(mParentActor);
}
if (mParentActor->getCollider()) {
if (isFlagValidOn(2, !isNoCollide(mParentActor)))
onCollide(mParentActor);
else if (isFlagValidOff(2, !isNoCollide(mParentActor)))
offCollide(mParentActor);
}
if (isFlagValidOn(3, isInvalidClipping(mParentActor)))
invalidateClipping(mParentActor);
else if (isFlagValidOff(3, isInvalidClipping(mParentActor)))
validateClipping(mParentActor);
}
void ActionFlagCtrl::startCtrlSensor() {
if (!mHitSensorKeeper)
return;
for (s32 i = 0; i < mHitSensorKeeper->getSensorNum(); i++) {
ActionSensorCtrlInfo* sensor = mCurrentCtrlInfo->sensorCtrlInfoArray;
if (sensor[i].startFrame > 0) {
mIsUpdateNeeded = true;
continue;
}
if (sensor[i].endFrame > 0)
mIsUpdateNeeded = true;
switch (sensor[i].state) {
case CtrlFlag::ValidOn:
validateHitSensor(mParentActor, sensor[i].name);
break;
case CtrlFlag::ValidOff:
invalidateHitSensor(mParentActor, sensor[i].name);
break;
default:
break;
}
}
}
void ActionFlagCtrl::update(f32 frame, f32 frameRateMax, f32 frameRate, bool isStop) {
if (!mCurrentCtrlInfo || !mIsUpdateNeeded)
return;
if (!mHitSensorKeeper)
return;
updateCtrlSensor(frame, frameRateMax, frameRate, isStop);
}
void ActionFlagCtrl::updateCtrlSensor(f32 frame, f32 frameRateMax, f32 frameRate, bool isStop) {
for (s32 i = 0; i < mHitSensorKeeper->getSensorNum(); i++) {
ActionSensorCtrlInfo* ctrlInfo = mCurrentCtrlInfo->sensorCtrlInfoArray;
f32 startFrame = ctrlInfo[i].startFrame;
if (startFrame > 0 &&
alAnimFunction::checkPass(frame, frameRateMax, frameRate, isStop, startFrame))
validateHitSensor(mParentActor, ctrlInfo[i].name);
f32 endFrame = ctrlInfo[i].endFrame;
if (endFrame > 0 &&
alAnimFunction::checkPass(frame, frameRateMax, frameRate, isStop, endFrame))
invalidateHitSensor(mParentActor, ctrlInfo[i].name);
}
}
bool ActionFlagCtrl::isFlagValidOn(s32 index, bool isEnabled) const {
return mCurrentCtrlInfo && mCurrentCtrlInfo->ctrlFlags[index] == CtrlFlag::ValidOn &&
!isEnabled;
}
bool ActionFlagCtrl::isFlagValidOff(s32 index, bool isEnabled) const {
return mCurrentCtrlInfo && mCurrentCtrlInfo->ctrlFlags[index] == CtrlFlag::ValidOff &&
isEnabled;
}
} // namespace al