#pragma once #include #include #include #include #include "KingSystem/ActorSystem/actAiParam.h" #include "KingSystem/Utils/Types.h" namespace ksys { struct AIDefSet; class Message; class MessageAck; struct MesTransceiverId; struct MessageType; } // namespace ksys namespace ksys::res { class AIProgram; class GParamList; } // namespace ksys::res namespace ksys::act { class Actor; class BaseProcHandle; namespace ai { class Action; enum class ActionType { AI = 0, Action = 1, }; enum class RootAiFlag; enum class RootAiFlag2; sead::SafeString* getDefaultString(); s32* getDefaultInt(); f32* getDefaultFloat(); sead::Vector3f* getDefaultVec3(); bool* getDefaultBool(); BaseProcLink* getDefaultBaseProcLink(); MesTransceiverId* getDefaultMesTransceiverId(); BaseProcHandle** getDefaultBaseProcHandle(); Rail** getDefaultRail(); sead::FixedSafeString<32>* getDefaultString32(); /// Base class for actions and AIs, which can be seen as looping actions. class ActionBase { SEAD_RTTI_BASE(ActionBase) public: struct InitArg { Actor* actor; /// The index of the query definition in the actor's AI program. s32 def_idx; s32 root_idx; }; KSYS_CHECK_SIZE_NX150(InitArg, 0x10); explicit ActionBase(const InitArg& arg); virtual ~ActionBase() = default; bool init(sead::Heap* heap, bool skip_loading_map_or_tree_params); void enter(InlineParamPack* params, const sead::SafeString& context); bool takeOver(ActionBase* src, const sead::SafeString& context); void leave(); bool oneShot(InlineParamPack* params); bool sendMessage(const MesTransceiverId& dest, const MessageType& type, void* user_data); Action* getCurrentAction(); bool handleMessage(const Message& message); bool handleAck(const MessageAck& message); Actor* getActor() const { return mActor; } s32 getDefinitionIdx() const { return mDefinitionIdx; } const char* getClassName() const; const char* getName() const; void playAS(const char* name, bool repeat, u32 slot, u32 seq_bank, f32 t); bool isFinishedAS(u32 slot, u32 seq_bank); virtual bool isFailed() const { return mFlags.isOn(Flag::Failed); } virtual bool isFinished() const { return mFlags.isOn(Flag::Finished); } virtual bool isChangeable() const { return mFlags.isOn(Flag::Changeable); } virtual bool hasPreDeleteCb() { return false; } virtual bool hasUpdateForPreDeleteCb() { return false; } virtual void m9() {} protected: virtual bool oneShot_() { return true; } virtual bool init_(sead::Heap* heap) { return true; } virtual void enter_(InlineParamPack* params) {} virtual bool reenter_(ActionBase* other, bool x); virtual void leave_() {} virtual void loadParams_() {} virtual bool handleMessage_(const Message& message) { return false; } virtual bool handleAck_(const MessageAck& message) { return false; } public: virtual bool updateForPreDelete() { return true; } virtual void onPreDelete() {} virtual void calc() {} virtual void getCurrentName(sead::BufferedSafeString* name, ActionBase* last) const; virtual ActionBase* changeChildLater(const sead::SafeString& name) { return nullptr; } virtual void getParams(ParamNameTypePairs* pairs, bool update_use_count) const; virtual s32 getNumChildren() const { return 0; } virtual bool initChildren(const AIDefSet& set, sead::Heap* heap) { return true; } virtual ActionBase* getCurrentChild() const { return nullptr; } virtual ActionType getType() const = 0; virtual bool reenter(ActionBase* other, const sead::SafeString& context) { return reenter_(other, false); } virtual void postLeave() {} virtual ActionBase* getChild(s32 idx) const { return nullptr; } protected: enum class Flag : u8 { Finished = 1, Failed = 2, Changeable = 4, TriggerAction = 8, DynamicParamChild = 0x10, _20 = 0x20, _40 = 0x40, _80 = 0x80, }; bool isRootAiParamINot5() const; bool isActorDeletedOrDeleting() const; bool isActorGoingBackToRootAi() const; void copyParams(InlineParamPack* dest, bool x) const; void setFinished(); void setFailed(); void setRootAiFlag(RootAiFlag flag) const; void resetRootAiFlag(RootAiFlag flag) const; bool testRootAiFlag2(RootAiFlag2 flag) const; void resetFlags() { mFlags.reset(Flag::Failed); mFlags.reset(Flag::Finished); mFlags.reset(Flag::Changeable); } res::AIProgram* getAIProg() const; auto& getDef() const; res::GParamList* getGParamList() const; template bool getStaticParam(T* value, const sead::SafeString& key) const; void logMissingParam(const sead::SafeString& param) const; template bool getMapUnitParam(T* value, const sead::SafeString& key) const; template bool getAITreeVariable(T** value, const sead::SafeString& key) const; template bool getDynamicParamImpl(T* value, const sead::SafeString& key, bool (ParamPack::*getter)(T* value, const sead::SafeString& key) const, T* default_value) const { auto* action = this; while (action && action->mFlags.isOff(Flag::_80)) { if ((action->mParams.*getter)(value, key)) return true; if (action->mFlags.isOff(Flag::DynamicParamChild)) goto fail; action = action->getCurrentChild(); if (!action) goto fail; } for (s32 i = 0, n = action->getNumChildren(); i < n; ++i) { auto* child = action->getChild(i); if (child->getDynamicParamImpl(value, key, getter, default_value)) return true; } fail: logMissingParam(key); *value = *default_value; return false; } // likely duplicated by compiler? template bool getDynamicParamImpl_2(T* value, const sead::SafeString& key, bool (ParamPack::*getter)(T* value, const sead::SafeString& key) const, T* default_value) const { auto* action = this; while (action && action->mFlags.isOff(Flag::_80)) { if ((action->mParams.*getter)(value, key)) return true; if (action->mFlags.isOff(Flag::DynamicParamChild)) goto fail; action = action->getCurrentChild(); if (!action) goto fail; } for (s32 i = 0, n = action->getNumChildren(); i < n; ++i) { auto* child = action->getChild(i); if (child->getDynamicParamImpl_2(value, key, getter, default_value)) return true; } fail: logMissingParam(key); *value = *default_value; return false; } template bool getDynamicParamPtrImpl(T** value, const sead::SafeString& key, T* default_value) const { return getDynamicParamImpl(value, key, &ParamPack::getPtrGeneric, &default_value); } bool getDynamicParam(sead::SafeString* value, const sead::SafeString& key) const { return getDynamicParamImpl(value, key, &ParamPack::getString, getDefaultString()); } bool getDynamicParam(int** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultInt()); } bool getDynamicParam(float** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultFloat()); } bool getDynamicParam(sead::Vector3f** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultVec3()); } bool getDynamicParam(bool** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultBool()); } bool getDynamicParam(BaseProcLink** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultBaseProcLink()); } bool getDynamicParam(MesTransceiverId** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl( value, key, getDefaultMesTransceiverId()); } bool getDynamicParam(BaseProcHandle*** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultBaseProcHandle()); } bool getDynamicParam(Rail*** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl(value, key, getDefaultRail()); } bool getDynamicParam(sead::SafeString** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl( value, key, static_cast(getDefaultString32())); } // likely duplicated by compiler? template bool getDynamicParamPtrImpl_2(T** value, const sead::SafeString& key, T* default_value) const { return getDynamicParamImpl_2(value, key, &ParamPack::getPtrGeneric_2, &default_value); } // likely duplicated by compiler? bool getDynamicParam_2(int** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl_2(value, key, getDefaultInt()); } // likely duplicated by compiler? bool getDynamicParam_2(float** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl_2(value, key, getDefaultFloat()); } // likely duplicated by compiler? bool getDynamicParam_2(sead::Vector3f** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl_2(value, key, getDefaultVec3()); } // likely duplicated by compiler? bool getDynamicParam_2(bool** value, const sead::SafeString& key) const { return getDynamicParamPtrImpl_2(value, key, getDefaultBool()); } Actor* mActor; ParamPack mParams; s16 mDefinitionIdx; s8 mRootIdx; sead::TypedBitFlag mFlags; private: void initFlags(res::AIProgram* aiprog, s32 def_idx, ActionType type); void updateBehaviorsOnEnter(); void updateBehaviorsOnLeave(); }; KSYS_CHECK_SIZE_NX150(ActionBase, 0x20); } // namespace ai } // namespace ksys::act