#ifndef TOBESORTED_ATTENTION_H #define TOBESORTED_ATTENTION_H #include "common.h" #include "d/a/obj/d_a_obj_base.h" #include "m/m3d/m_anmchr.h" #include "m/m3d/m_anmmatclr.h" #include "m/m3d/m_anmtexpat.h" #include "m/m3d/m_smdl.h" #include "m/m_allocator.h" #include "toBeSorted/d_emitter.h" #include "toBeSorted/raii_ptr.h" static const u32 OFF = 'off '; static const u32 NONE = 'none'; static const u32 KEEP = 'keep'; static const u32 NEXT = 'next'; static const u32 ON = 'on '; static const u32 AWAY = 'away'; class InteractionMdl { public: m3d::smdl_c mMdl; m3d::anmMatClr_c mAnmClr; m3d::anmTexPat_c mAnmTex; RaiiPtr mAnmChr; u8 field_0x78; u8 field_0x79; InteractionMdl() {} ~InteractionMdl() {} }; enum InteractionType { /* 0 */ UNK_0, /* 1 */ PICK_UP, /* 2 */ OPEN, /* 3 */ UNK_3, /* 4 */ TALK, /* 5 */ EXAMINE_TALK, /* 6 */ EXAMINE_6, /* 7 */ UNK_7, /* 8 */ GET_IN, /* 9 */ READY_SWORD, /* 10 */ UNK_10, /* 11 */ UNK_11, /* 12 */ READ, /* 13 */ GRAB, /* 14 */ CATCH, /* 15 */ UNK_15, /* 16 */ UNK_16, /* 17 */ DIG, /* 18 */ UNK_18, /* 19 */ SIT, /* 20 */ UNK_20, UNK_0x58 = 0x58, }; class AttentionInfo { public: AttentionInfo() {} ~AttentionInfo() {} /* 0x00 */ u8 unk; /* 0x01 */ u8 mActorIdx; /* 0x02 */ u8 mInteractionType; /* 0x03 */ u8 field_0x03; /* 0x04 */ f32 field_0x04; /* 0x08 */ mVec3_c field_0x08; }; class AttentionPool { public: AttentionPool() {} ~AttentionPool() {} dAcRef_c mRefs[8]; AttentionInfo mInfos[8]; s32 mNumUsedRefs; int fn_80096190(dAcObjBase_c *actor, u8 unk, InteractionType interactionType); bool insertTarget( dAcObjBase_c *actor, u32 unk1, mVec3_c *pos, InteractionType interactionType, u8 field_0x03, f32 field_0x04 ); dAcObjBase_c *getActor(s32 i) { // This only matches if the comparision is always true // Logic is hard sometimes I guess xD return i < mNumUsedRefs && mInfos[i].mActorIdx != -1 ? mRefs[mInfos[i].mActorIdx].get() : nullptr; } void clear() { for (int i = 0; i < 8; i++) { mInfos[i].unk = 0; mInfos[i].mActorIdx = -1; mInfos[i].field_0x04 = 0.0f; mInfos[i].field_0x03 = 0; mInfos[i].mInteractionType = 0; mRefs[i].unlink(); } mNumUsedRefs = 0; } }; class AttentionGroup { public: AttentionGroup() {} ~AttentionGroup() {} AttentionPool mPools[2]; u32 mWhichPool; AttentionPool *getOtherPool() { return &mPools[mWhichPool ^ 1]; } AttentionPool *getPool() { return &mPools[mWhichPool]; } void fn_800964B0(); }; struct InteractionTargetDef { s32 field_0x00; u32 field_0x04; u32 field_0x08; InteractionType interactType; u32 interactFlags; f32 field_0x14; f32 field_0x18; f32 field_0x1C; f32 field_0x20; f32 field_0x24; f32 field_0x28; f32 field_0x2C; }; // TODO this may include more things from AttentionManager, see AttentionManager's dtor class InteractionModels { public: /* 0x00 */ UNKWORD field_0xA5C; /* 0x04 */ s32 mCurrentTargetInfoIdx; /* 0x08 */ u32 mState; /* 0x0C */ nw4r::g3d::ResFile mResFile; /* 0x10 */ InteractionMdl mMdls[2]; }; class AttentionManager { mHeapAllocator_c mAllocator; /* 0x01C */ AttentionGroup mGroups[5]; /* 0xA58 */ bool mTargeted; /* 0xA59 */ bool mHoldingZ; /* 0xA5A */ u8 field_0xA58[0xA5C - 0xA5A]; /* 0xA5C */ InteractionModels mModels; /* 0xB64 */ u8 mHasTarget; /* 0xB65 */ u8 field_0xB65[0xB68 - 0xB65]; /* 0xB68 */ UNKWORD field_0xB68; /* 0xB6C */ dEmitter_c mEffect1; /* 0xBA0 */ dEmitter_c mEffect2; /* 0xBD4 */ u8 field_0xBD4; /* 0xBD5 */ u8 field_0xBD5; public: AttentionManager(); /* vt at 0xBDC */ virtual ~AttentionManager(); static AttentionManager *GetInstance() { return sInstance; } private: /* 0xBDC */ u8 field_0xBDC; public: static AttentionManager *sInstance; enum Flags_e { FLAGS_0, FLAGS_1, FLAGS_2, FLAGS_3, }; bool create(); bool createHeap(); bool execute(); bool draw(); void addTarget(dAcObjBase_c &actor, const InteractionTargetDef &def, u32, mVec3_c *); void addPickUpTarget(dAcObjBase_c &actor, f32 field_0x14); void addSitTarget(dAcObjBase_c &actor, f32 field_0x14, Flags_e flags); void addTalkTarget_unused(dAcObjBase_c &actor); void addExamineTalkTarget(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 ignored, f32 field_0x20, f32 field_0x24); void addExamineTalkTarget(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 field_0x20, f32 field_0x24); void addCatchTarget(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg); void addCatchLikeTarget( dAcObjBase_c &actor, InteractionType interactionType, u32 flags, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg ); void addUnk3Target(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg); void addUnk3Target(dAcObjBase_c &actor, u32 flags, f32 arg5, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg); void addUnk3Target( dAcObjBase_c &actor, u32 arg2, mVec3_c *arg3, u32 flags, f32 arg5, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg ); void addNpcTalkTarget(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 ignored, f32 field_0x20, f32 field_0x24); void addUnk7Target(dAcObjBase_c &actor, u32 flags, f32 arg5, f32 field_0x14, f32 field_0x24_neg, f32 field_0x20_neg); void addReadTarget(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 ignored, f32 field_0x20, f32 field_0x24); void addReadTarget2(dAcObjBase_c &actor, u32 flags, f32 field_0x14, f32 field_0x20, f32 field_0x24); bool checkLink2() const; dAcObjBase_c *getTargetedActor() { if (!isInNormalGameState() || !mTargeted) { return nullptr; } return getTargetedActorUnchecked(); } dAcObjBase_c *getTargetedActorUnchecked() { return mGroups[1].getOtherPool()->getActor(mModels.mCurrentTargetInfoIdx); } private: bool isInNormalGameState() const; bool checkZButtonPressed() const; bool checkZButtonHeld() const; bool checkLink1() const; bool switchTarget(s32 target); bool playTargetAnim(s32 target); bool isZButtonPressed() const; bool isZButtonHeld() const; bool checkUnknown() const; bool collisionCheck0(const mVec3_c &a, const mVec3_c &b); bool collisionCheck1(const mVec3_c &a, const mVec3_c &b); bool collisionCheck2(const mVec3_c &a, const mVec3_c &b); bool fn_80096B40(dAcObjBase_c *actor); f32 targetScore(dAcObjBase_c *target, dAcObjBase_c *origin); }; #endif