From 401bab69247514b6a604e784a17faec1ff353c08 Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 28 May 2026 17:35:04 +0200 Subject: [PATCH] A few NPC functions --- config/SOUE01/splits.txt | 3 +- config/SOUE01/symbols.txt | 28 ++-- include/d/a/npc/d_a_npc.h | 107 +++++++++++++-- include/d/a/npc/d_a_npc_inv.h | 16 +++ include/m/m3d/m_anmmdl.h | 4 +- src/d/a/npc/d_a_npc.cpp | 250 +++++++++++++++++++++++++++++++++- 6 files changed, 380 insertions(+), 28 deletions(-) create mode 100644 include/d/a/npc/d_a_npc_inv.h diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index 4aa9b4e0..9e47132a 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -5356,11 +5356,12 @@ JSystem/JStudio/JStudio_JStage/object-light.cpp: JSystem/JStudio/JStudio_JStage/object-message.cpp: .text start:0x804C3870 end:0x804C39D4 align:16 - .data start:0x80570378 end:0x805703B8 + .data start:0x80570378 end:0x805703A0 toBeSorted/JSystem/unk_jstage_maybe.cpp: .text start:0x804C39E0 end:0x804C3FC8 align:16 .rodata start:0x804FBF98 end:0x804FBFA8 + .data start:0x805703A0 end:0x805703B8 .sdata2 start:0x8057F9A0 end:0x8057F9B8 JSystem/JStudio/JStudio_JParticle/control.cpp: diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index ca7cffb4..5756b168 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -1215,10 +1215,10 @@ ActorNpcEventFlowManager__getParamsAsShortShort = .text:0x80032030; // type:func ActorNpcEventFlowManager__getParamsAsShortCharChar = .text:0x80032050; // type:function size:0x1C getParamsAsCharCharCharChar = .text:0x80032070; // type:function size:0x24 setupActorRefs__10dFlowNpc_cFv = .text:0x800320A0; // type:function size:0x84 -fn_80032130 = .text:0x80032130; // type:function size:0x48 -fn_80032180 = .text:0x80032180; // type:function size:0x2C -fn_800321B0 = .text:0x800321B0; // type:function size:0x1CC -fn_80032380 = .text:0x80032380; // type:function size:0xC0 +getActorForId__10dFlowNpc_cFl = .text:0x80032130; // type:function size:0x48 +getObj__10dFlowNpc_cFl = .text:0x80032180; // type:function size:0x2C +flowNpcIdToProfile__10dFlowNpc_cFl = .text:0x800321B0; // type:function size:0x1CC +getIdx__10dFlowNpc_cFl = .text:0x80032380; // type:function size:0xC0 baseID_Wait<10sStateID_c>__Fv_RC12sStateIDIf_c = .text:0x80032440; // type:function size:0xC baseID_Demo<10sStateID_c>__Fv_RC12sStateIDIf_c = .text:0x80032450; // type:function size:0xC fn_80032460 = .text:0x80032460; // type:function size:0x4 @@ -1266,7 +1266,7 @@ __dt__20sFState_c<8dAcNpc_c>Fv = .text:0x80033DF0; // type:function size:0x58 __dt__23sFStateFct_c<8dAcNpc_c>Fv = .text:0x80033E50; // type:function size:0x6C __dt__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>Fv = .text:0x80033EC0; // type:function size:0xA0 __dt__46sFStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c>Fv = .text:0x80033F60; // type:function size:0xA4 -ActorNpcBase__ctor2 = .text:0x80034010; // type:function size:0x27C +__ct__8dAcNpc_cFP14dFlowMgrBase_c = .text:0x80034010; // type:function size:0x27C ActorNpcBase__addToNpcList = .text:0x80034290; // type:function size:0x50 fn_800342E0 = .text:0x800342E0; // type:function size:0x34 fn_80034320 = .text:0x80034320; // type:function size:0x88 @@ -1381,10 +1381,10 @@ acNpc_vt_0x1DC__8dAcNpc_cFv = .text:0x80036820; // type:function size:0xC acNpc_vt_0x1E0__8dAcNpc_cFv = .text:0x80036830; // type:function size:0x8 acNpc_vt_0x1E4__8dAcNpc_cFv = .text:0x80036840; // type:function size:0xC addHeadNeckSpineCallbacks__8dAcNpc_cFPQ23d3d13AnmMdlWrapperP22dNpcMdlCallbackMulti_cP21dNpcMdlCallbackBase_cP21dNpcMdlCallbackBase_cP21dNpcMdlCallbackBase_c = .text:0x80036850; // type:function size:0xC8 -fn_80036920 = .text:0x80036920; // type:function size:0x148 -fn_80036A70 = .text:0x80036A70; // type:function size:0x128 -fn_80036BA0 = .text:0x80036BA0; // type:function size:0x6C -fn_80036C10 = .text:0x80036C10; // type:function size:0x84 +initHeadNeckSpineCallbacks__8dAcNpc_cFPQ23d3d13AnmMdlWrapperP22dNpcMdlCallbackMulti_cP20dNpcMdlCallbackAng_cP20dNpcMdlCallbackAng_cP20dNpcMdlCallbackAng_c = .text:0x80036920; // type:function size:0x148 +newAnmTexSrt__8dAcNpc_cFPQ23d3d13AnmMdlWrapperP12mAllocator_cPCcPCc = .text:0x80036A70; // type:function size:0x128 +setAnmTexSrt__8dAcNpc_cFPQ23d3d13AnmMdlWrapperPQ23m3d11anmTexSrt_cPCc = .text:0x80036BA0; // type:function size:0x6C +createAnmChr__8dAcNpc_cFPQ23d3d13AnmMdlWrapperPCcPCcP12mAllocator_cPQ23m3d8anmChr_c = .text:0x80036C10; // type:function size:0x84 acNpc_vt_0x9C__8dAcNpc_cFv = .text:0x80036CA0; // type:function size:0xFC acNpc_vt_0xA0__8dAcNpc_cFv = .text:0x80036DA0; // type:function size:0xBC acNpc_vt_0xA4__8dAcNpc_cFv = .text:0x80036E60; // type:function size:0xC8 @@ -1432,7 +1432,7 @@ fn_800387A0 = .text:0x800387A0; // type:function size:0x50 getCurrentActorEventFlowManager = .text:0x800387F0; // type:function size:0x50 vt_0x38__7dFlow_cCFv = .text:0x80038840; // type:function size:0x8 fn_80038850 = .text:0x80038850; // type:function size:0x94 -fn_800388F0 = .text:0x800388F0; // type:function size:0xD4 +getPathIndexForId__8dAcNpc_cFllb = .text:0x800388F0; // type:function size:0xD4 fn_800389D0 = .text:0x800389D0; // type:function size:0x90 fn_80038A60 = .text:0x80038A60; // type:function size:0x10C fn_80038B70 = .text:0x80038B70; // type:function size:0x138 @@ -1472,8 +1472,8 @@ timingB__22dNpcMdlCallbackMulti_cFUlPQ34nw4r3g3d13WorldMtxManipQ34nw4r3g3d6ResMd fn_80039910 = .text:0x80039910; // type:function size:0x70 fn_80039980 = .text:0x80039980; // type:function size:0x70 fn_800399F0 = .text:0x800399F0; // type:function size:0x180 -fn_80039B70 = .text:0x80039B70; // type:function size:0x70 -fn_80039BE0 = .text:0x80039BE0; // type:function size:0x68 +clampAngle__FR4mAngP4mAngR4mAng = .text:0x80039B70; // type:function size:0x70 +clampAngleXY__FR7mAng3_cP4mAngP4mAngR7mAng3_c = .text:0x80039BE0; // type:function size:0x68 fn_80039C50 = .text:0x80039C50; // type:function size:0x40C vt_0x20__20dNpcMdlCallbackAng_cFPC9dAcBase_c = .text:0x8003A060; // type:function size:0x4 fn_8003A070 = .text:0x8003A070; // type:function size:0x12C @@ -13980,7 +13980,7 @@ fn_802591F0 = .text:0x802591F0; // type:function size:0x28 fn_80259220 = .text:0x80259220; // type:function size:0x338 fn_80259560 = .text:0x80259560; // type:function size:0x10 fn_80259570 = .text:0x80259570; // type:function size:0x30 -AcBomb__initModels = .text:0x802595A0; // type:function size:0xC0 +createHeap__9dAcBomb_cFv = .text:0x802595A0; // type:function size:0xC0 AcBomb__create = .text:0x80259660; // type:function size:0x3D8 fn_80259A40 = .text:0x80259A40; // type:function size:0x84 fn_80259AD0 = .text:0x80259AD0; // type:function size:0x2C @@ -14673,7 +14673,7 @@ fn_8027B4C0 = .text:0x8027B4C0; // type:function size:0x58 fn_8027B520 = .text:0x8027B520; // type:function size:0x6C fn_8027B590 = .text:0x8027B590; // type:function size:0xA0 fn_8027B630 = .text:0x8027B630; // type:function size:0xA4 -fn_8027B6E0 = .text:0x8027B6E0; // type:function size:0x38 +getActualFlowNpcId__11dAcNpcInv_cCFv = .text:0x8027B6E0; // type:function size:0x38 fn_8027B720 = .text:0x8027B720; // type:function size:0x54 fn_8027B780 = .text:0x8027B780; // type:function size:0x54 AcNpcInv__init = .text:0x8027B7E0; // type:function size:0x74 diff --git a/include/d/a/npc/d_a_npc.h b/include/d/a/npc/d_a_npc.h index 30b2666e..044d9790 100644 --- a/include/d/a/npc/d_a_npc.h +++ b/include/d/a/npc/d_a_npc.h @@ -7,7 +7,11 @@ #include "d/a/obj/d_a_obj_base.h" #include "d/d_message.h" #include "libms/flowfile.h" +#include "m/m3d/m_anmchr.h" +#include "m/m3d/m_anmtexsrt.h" #include "m/m3d/m_mdl.h" +#include "m/m3d/m_smdl.h" +#include "m/m_allocator.h" #include "m/m_angle.h" #include "m/m_mtx.h" #include "m/m_quat.h" @@ -15,6 +19,8 @@ #include "s/s_State.hpp" #include "s/s_StateInterfaces.hpp" #include "toBeSorted/d_d3d.h" +#include "toBeSorted/d_flow_mgr.h" +#include "toBeSorted/sound_info.h" class dAcNpc_c; @@ -210,6 +216,70 @@ public: /* vt 0x3C */ virtual u16 getSwitchChoice(const MsbFlowInfo *element, u16 param) const override; /* vt 0x40 */ virtual bool triggerEntryPointChecked(s32 labelPart1, s32 labelPart2) override; + enum FlowNpcId_e { + FLOW_NPC_SELF = 0, // pseudo-id + + FLOW_NPC_ZLD = 1, + FLOW_NPC_DSK, + FLOW_NPC_TALK_KENSEI, + FLOW_NPC_RVL, + FLOW_NPC_KBN, + FLOW_NPC_KBN2, + FLOW_NPC_SORAJIMA_MALE, + FLOW_NPC_SORAJIMA_FEMALE, + FLOW_NPC_SKN, + FLOW_NPC_SKN2, + FLOW_NPC_KNIGHT_LEADER, + FLOW_NPC_CE_FRIEND, + FLOW_NPC_GHM, + FLOW_NPC_OIM, + FLOW_NPC_YIM, + FLOW_NPC_MOLE_NORMAL, + FLOW_NPC_MOLE_NORMAL2, + FLOW_NPC_SENPAI, + FLOW_NPC_DRB, + FLOW_NPC_SENPAI_B, + FLOW_NPC_SORAJIMA_MOTHER, + FLOW_NPC_SLRP, + FLOW_NPC_SLB, + FLOW_NPC_GRA, + FLOW_NPC_MOLE_TACKLE2, + FLOW_NPC_PDU, + FLOW_NPC_SMA2, + FLOW_NPC_MED_HUS_NIGHT, + FLOW_NPC_MED_WIFE_NIGHT, + FLOW_NPC_DOUGUYA_NIGHT, + FLOW_NPC_DOUGUYA_MOTHER, + FLOW_NPC_AZUKARIYA_NIGHT, + FLOW_NPC_AZUKARIYA_FATHER, + FLOW_NPC_SENPAIA_MOTHER, + FLOW_NPC_AKU_HUMAN, + FLOW_NPC_SALBAGE_MORRY, + FLOW_NPC_DOUGUYA_MOTHER_LOD, + FLOW_NPC_JUNK_MOTHER_LOD, + FLOW_NPC_SENPAIA_MOTHER_LOD, + FLOW_NPC_BBRVL, + FLOW_NPC_SORAJIMA_MAN_D, + FLOW_NPC_SORAJIMA_MAN_E, + FLOW_NPC_DAISHINKAN_N, + FLOW_NPC_PMA, + FLOW_NPC_DRBC, + FLOW_NPC_MOLE_MG, + FLOW_NPC_GRD, + FLOW_NPC_GRC, + FLOW_NPC_SLB2, + FLOW_NPC_CE_LADY, + FLOW_NPC_MOLE, + + FLOW_LINK = 100, + FLOW_NPC_INV_OFFSET = 101, + }; + + dAcObjBase_c *getActorForId(s32 flowNpcId); + u16 flowNpcIdToProfile(s32 flowNpcId); + dAcObjBase_c *getObj(s32 idx); + s32 getIdx(s32 flowNpcId); + private: void extract2xU16Params(const MsbFlowInfo *element, u16 *p1, u16 *p2); void extract4xU8Params(const MsbFlowInfo *element, u8 *p1, u8 *p2, u8 *p3, u8 *p4); @@ -220,7 +290,7 @@ private: // exact type isn't known but this Makes Sense /* 0x068 */ dAcRef_c mObjRefs[16]; /* 0x128 */ UNKWORD field_0x128[4]; - /* 0x138 */ UNKWORD field_0x138; + /* 0x138 */ s32 field_0x138; /* 0x13C */ UNKWORD field_0x13C; }; @@ -232,6 +302,7 @@ private: class dAcNpc_c : public dAcObjBase_c { public: dAcNpc_c(); + dAcNpc_c(dFlowMgrBase_c *flowMgr); virtual ~dAcNpc_c(); /* vt 0x080 */ virtual bool giveItem(u8 param, ITEM_ID item_id); @@ -283,7 +354,7 @@ public: /* vt 0x0E8 */ virtual void acNpc_vt_0xE8(); /* vt 0x074 */ virtual void *getObjectListEntry() override { - return &mActorListEntry; + return &mNpcListEntry; } /* vt 0x0EC */ virtual int acNpc_vt_0xEC() { @@ -353,10 +424,10 @@ public: /* vt 0x184 */ virtual void acNpc_vt_0x184(); /* vt 0x188 */ virtual void acNpc_vt_0x188(); /* vt 0x18C */ virtual void acNpc_vt_0x18C(); - /* vt 0x190 */ virtual void acNpc_vt_0x190(); - /* vt 0x194 */ virtual void acNpc_vt_0x194(); - /* vt 0x198 */ virtual void acNpc_vt_0x198(); - /* vt 0x19C */ virtual void acNpc_vt_0x19C(); + /* vt 0x190 */ virtual const mAng &acNpc_vt_0x190(); + /* vt 0x194 */ virtual const mAng &acNpc_vt_0x194(); + /* vt 0x198 */ virtual const mAng &acNpc_vt_0x198(); + /* vt 0x19C */ virtual const mAng &acNpc_vt_0x19C(); /* vt 0x1A0 */ virtual void acNpc_vt_0x1A0(); /* vt 0x1A4 */ virtual void acNpc_vt_0x1A4(); /* vt 0x1A8 */ virtual void acNpc_vt_0x1A8(); @@ -412,14 +483,34 @@ protected: d3d::AnmMdlWrapper *mdl, dNpcMdlCallbackMulti_c *multi, dNpcMdlCallbackBase_c *head, dNpcMdlCallbackBase_c *neck, dNpcMdlCallbackBase_c *spine ); + bool initHeadNeckSpineCallbacks( + d3d::AnmMdlWrapper *mdl, dNpcMdlCallbackMulti_c *multi, dNpcMdlCallbackAng_c *head, dNpcMdlCallbackAng_c *neck, + dNpcMdlCallbackAng_c *spine + ); + + m3d::anmTexSrt_c * + newAnmTexSrt(d3d::AnmMdlWrapper *mdl, mAllocator_c *allocator, const char *mdlName, const char *anmName); + void setAnmTexSrt(d3d::AnmMdlWrapper *mdl, m3d::anmTexSrt_c *texSrt, const char *anmName); + bool createAnmChr( + d3d::AnmMdlWrapper *mdl, const char *mdlName, const char *anmName, mAllocator_c *allocator, m3d::anmChr_c *anm + ); static const char *sHeadNodeName; static const char *sNeckNodeName; static const char *sSpine2NodeName; private: - /* 0x330 */ u8 field_0x330[0x358 - 0x330]; - /* 0x358 */ fLiNdBa_c mActorListEntry; + void addToNpcList(); + void loadMainPos(f32 offsetY1, f32 offsetY2); + void loadMainPos(const mVec3_c *offset); + void loadMainAndHeadPos(f32 posYOffset, f32 headYOffset, d3d::AnmMdlWrapper *mdl); + void loadMainAndHeadPos(const mVec3_c *posOffset, const mVec3_c *headOffset, d3d::AnmMdlWrapper *mdl); + + static s32 getPathIndexForId(s32 id, s32 roomId, bool spth); + + /* 0x330 */ u8 field_0x330[0x340 - 0x330]; + /* 0x340 */ SoundInfo mSoundInfo; + /* 0x358 */ fLiNdBa_c mNpcListEntry; /* 0x364 */ dFlowNpc_c mFlow; /* 0x4A4 */ u8 field_0x4A4[0x4C0 - 0x4A4]; /* 0x4C0 */ STATE_MGR_DECLARE(dAcNpc_c); diff --git a/include/d/a/npc/d_a_npc_inv.h b/include/d/a/npc/d_a_npc_inv.h new file mode 100644 index 00000000..ff0d14b3 --- /dev/null +++ b/include/d/a/npc/d_a_npc_inv.h @@ -0,0 +1,16 @@ +#ifndef D_A_NPC_INV_H +#define D_A_NPC_INV_H + +#include "d/a/npc/d_a_npc.h" + +class dAcNpcInv_c : public dAcNpc_c { +public: + dAcNpcInv_c() {} + virtual ~dAcNpcInv_c() {} + + s32 getActualFlowNpcId() const; + +private: +}; + +#endif diff --git a/include/m/m3d/m_anmmdl.h b/include/m/m3d/m_anmmdl.h index 29cf6e2e..d154a3eb 100644 --- a/include/m/m3d/m_anmmdl.h +++ b/include/m/m3d/m_anmmdl.h @@ -60,11 +60,11 @@ public: void setAnmFile(void *data) { mAnmFile = nw4r::g3d::ResFile(data); } - nw4r::g3d::ResFile getAnmFile() { + nw4r::g3d::ResFile &getAnmFile() { return mAnmFile; } - nw4r::g3d::ResFile getMdlFile() { + nw4r::g3d::ResFile &getMdlFile() { return mMdlFile; } diff --git a/src/d/a/npc/d_a_npc.cpp b/src/d/a/npc/d_a_npc.cpp index efba2f9f..94d99430 100644 --- a/src/d/a/npc/d_a_npc.cpp +++ b/src/d/a/npc/d_a_npc.cpp @@ -3,13 +3,19 @@ #include "c/c_math.h" #include "common.h" #include "d/a/d_a_base.h" +#include "d/a/d_a_player.h" #include "d/a/npc/d_a_npc tke.h" +#include "d/a/npc/d_a_npc_inv.h" #include "d/d_message.h" +#include "d/d_room.h" #include "d/d_sc_game.h" #include "d/d_stage.h" #include "f/f_list_mg.h" #include "f/f_profile_name.h" #include "m/m3d/m3d.h" +#include "m/m3d/m_anmtexsrt.h" +#include "m/m3d/m_fanm.h" +#include "m/m_angle.h" #include "m/m_mtx.h" #include "m/m_quat.h" #include "m/m_vec.h" @@ -17,7 +23,6 @@ #include "nw4r/ut/ut_Color.h" #include "rvl/MTX/mtx.h" #include "s/s_Math.h" -#include "s/s_StateID.hpp" #include "sized_string.h" #include "toBeSorted/d_d3d.h" #include "toBeSorted/event_manager.h" @@ -115,6 +120,106 @@ void dFlowNpc_c::setupActorRefs() { field_0x13C = 0; } +dAcObjBase_c *dFlowNpc_c::getActorForId(s32 flowNpcId) { + if (flowNpcId == FLOW_LINK) { + return dAcPy_c::GetLinkM(); + } else { + return getObj(getIdx(flowNpcId)); + } +} + +u16 dFlowNpc_c::flowNpcIdToProfile(s32 flowNpcId) { + switch (flowNpcId) { + case FLOW_NPC_ZLD: return fProfile::NPC_ZLD; + case FLOW_NPC_DSK: return fProfile::NPC_DSK; + case FLOW_NPC_TALK_KENSEI: return fProfile::NPC_TALK_KENSEI; + case FLOW_NPC_RVL: return fProfile::NPC_RVL; + case FLOW_NPC_KBN: return fProfile::NPC_KBN; + case FLOW_NPC_KBN2: return fProfile::NPC_KBN2; + case FLOW_NPC_SORAJIMA_MALE: return fProfile::NPC_SORAJIMA_MALE; + case FLOW_NPC_SORAJIMA_FEMALE: return fProfile::NPC_SORAJIMA_FEMALE; + case FLOW_NPC_SKN: return fProfile::NPC_SKN; + case FLOW_NPC_SKN2: return fProfile::NPC_SKN2; + case FLOW_NPC_KNIGHT_LEADER: return fProfile::NPC_KNIGHT_LEADER; + case FLOW_NPC_CE_FRIEND: return fProfile::NPC_CE_FRIEND; + case FLOW_NPC_GHM: return fProfile::NPC_GHM; + case FLOW_NPC_OIM: return fProfile::NPC_OIM; + case FLOW_NPC_YIM: return fProfile::NPC_YIM; + case FLOW_NPC_MOLE_NORMAL: return fProfile::NPC_MOLE_NORMAL; + case FLOW_NPC_MOLE_NORMAL2: return fProfile::NPC_MOLE_NORMAL2; + case FLOW_NPC_SENPAI: return fProfile::NPC_SENPAI; + case FLOW_NPC_DRB: return fProfile::NPC_DRB; + case FLOW_NPC_SENPAI_B: return fProfile::NPC_SENPAI_B; + case FLOW_NPC_SORAJIMA_MOTHER: return fProfile::NPC_SORAJIMA_MOTHER; + case FLOW_NPC_SLRP: return fProfile::NPC_SLRP; + case FLOW_NPC_SLB: return fProfile::NPC_SLB; + case FLOW_NPC_GRA: return fProfile::NPC_GRA; + case FLOW_NPC_MOLE_TACKLE2: return fProfile::NPC_MOLE_TACKLE2; + case FLOW_NPC_PDU: return fProfile::NPC_PDU; + case FLOW_NPC_SMA2: return fProfile::NPC_SMA2; + case FLOW_NPC_MED_HUS_NIGHT: return fProfile::NPC_MED_HUS_NIGHT; + case FLOW_NPC_MED_WIFE_NIGHT: return fProfile::NPC_MED_WIFE_NIGHT; + case FLOW_NPC_DOUGUYA_NIGHT: return fProfile::NPC_DOUGUYA_NIGHT; + case FLOW_NPC_DOUGUYA_MOTHER: return fProfile::NPC_DOUGUYA_MOTHER; + case FLOW_NPC_AZUKARIYA_NIGHT: return fProfile::NPC_AZUKARIYA_NIGHT; + case FLOW_NPC_AZUKARIYA_FATHER: return fProfile::NPC_AZUKARIYA_FATHER; + case FLOW_NPC_SENPAIA_MOTHER: return fProfile::NPC_SENPAIA_MOTHER; + case FLOW_NPC_AKU_HUMAN: return fProfile::NPC_AKU_HUMAN; + case FLOW_NPC_SALBAGE_MORRY: return fProfile::NPC_SALBAGE_MORRY; + case FLOW_NPC_DOUGUYA_MOTHER_LOD: return fProfile::NPC_DOUGUYA_MOTHER_LOD; + case FLOW_NPC_JUNK_MOTHER_LOD: return fProfile::NPC_JUNK_MOTHER_LOD; + case FLOW_NPC_SENPAIA_MOTHER_LOD: return fProfile::NPC_SENPAIA_MOTHER_LOD; + case FLOW_NPC_BBRVL: return fProfile::NPC_BBRVL; + case FLOW_NPC_SORAJIMA_MAN_D: return fProfile::NPC_SORAJIMA_MAN_D; + case FLOW_NPC_SORAJIMA_MAN_E: return fProfile::NPC_SORAJIMA_MAN_E; + case FLOW_NPC_DAISHINKAN_N: return fProfile::NPC_DAISHINKAN_N; + case FLOW_NPC_PMA: return fProfile::NPC_PMA; + case FLOW_NPC_DRBC: return fProfile::NPC_DRBC; + case FLOW_NPC_MOLE_MG: return fProfile::NPC_MOLE_MG; + case FLOW_NPC_GRD: return fProfile::NPC_GRD; + case FLOW_NPC_GRC: return fProfile::NPC_GRC; + case FLOW_NPC_SLB2: return fProfile::NPC_SLB2; + case FLOW_NPC_CE_LADY: return fProfile::NPC_CE_LADY; + case FLOW_NPC_MOLE: return fProfile::NPC_MOLE; + } + if (flowNpcId >= FLOW_NPC_INV_OFFSET) { + return fProfile::NPC_INV; + } + return fProfile::PROFILE_MAX; +} + +dAcObjBase_c *dFlowNpc_c::getObj(s32 idx) { + if (0 <= idx && idx < field_0x138) { + return mObjRefs[idx].get(); + } + return nullptr; +} + +s32 dFlowNpc_c::getIdx(s32 flowNpcId) { + if (flowNpcId == FLOW_NPC_SELF) { + return 0; + } + u16 profile = flowNpcIdToProfile(flowNpcId); + if (profile == mpOwner->mProfileName) { + return 0; + } + + for (int i = 1; i < field_0x138; i++) { + if (profile == mObjRefs[i].get()->mProfileName) { + if (profile == fProfile::NPC_INV) { + if (flowNpcId - FLOW_NPC_INV_OFFSET == + static_cast(mObjRefs[i].get())->getActualFlowNpcId()) { + return i; + } + } else { + return i; + } + } + } + + return -1; +} + STATE_VIRTUAL_DEFINE(dAcNpc_c, Wait); STATE_VIRTUAL_DEFINE(dAcNpc_c, Demo); @@ -144,10 +249,46 @@ SizedString<128> sNpcStr2; SizedString<128> sNpcStr3; SizedString<128> sNpcStr4; -dAcNpc_c::dAcNpc_c() : mFlow(this), mStateMgr(*this), mActorListEntry(this) {} +void dAcNpc_c::loadMainPos(f32 offsetY1, f32 offsetY2) { + mPositionCopy3 = mPosition; + mPositionCopy3.y += offsetY1; + mPositionCopy2 = mPosition; + mPositionCopy2.y += offsetY2; +} + +void dAcNpc_c::loadMainAndHeadPos(f32 posYOffset, f32 headYOffset, d3d::AnmMdlWrapper *mdl) { + mPositionCopy3 = mPosition; + mPositionCopy3.y += posYOffset; + mMtx_c mtx; + mdl->getModel().getNodeWorldMtx(mdl->getModel().getResMdl().GetResNode(sHeadNodeName).GetID(), mtx); + mtx.getTranslation(mPositionCopy2); + mPositionCopy2.y += headYOffset; +} + +void dAcNpc_c::loadMainAndHeadPos(const mVec3_c *posOffset, const mVec3_c *headOffset, d3d::AnmMdlWrapper *mdl) { + loadMainPos(posOffset); + mMtx_c mtx; + mdl->getModel().getNodeWorldMtx(mdl->getModel().getResMdl().GetResNode(sHeadNodeName).GetID(), mtx); + mtx.getTranslation(mPositionCopy2); + mPositionCopy2 += *headOffset; +} + +dAcNpc_c::dAcNpc_c() : mSoundInfo(this), mFlow(this), mStateMgr(*this), mNpcListEntry(this) { + addToNpcList(); +} + +dAcNpc_c::dAcNpc_c(dFlowMgrBase_c *flowMgr) : mSoundInfo(this), mFlow(this), mStateMgr(*this), mNpcListEntry(this) { + addToNpcList(); +} + +void dAcNpc_c::loadMainPos(const mVec3_c *offset) { + mVec3_c v = *offset; + v.rotY(mRotation.y); + mPositionCopy3 = mPosition + v; +} dAcNpc_c::~dAcNpc_c() { - // TODO + NPC_ACTOR_LIST.remove(&mNpcListEntry); } u16 dAcNpc_c::doFlowSwitch1(u32 arg) { @@ -184,6 +325,78 @@ bool dAcNpc_c::addHeadNeckSpineCallbacks( return true; } +bool dAcNpc_c::initHeadNeckSpineCallbacks( + d3d::AnmMdlWrapper *mdl, dNpcMdlCallbackMulti_c *multi, dNpcMdlCallbackAng_c *head, dNpcMdlCallbackAng_c *neck, + dNpcMdlCallbackAng_c *spine +) { + if (!addHeadNeckSpineCallbacks(mdl, multi, head, neck, spine)) { + return false; + } + mAng max = acNpc_vt_0x198(); + mAng min = acNpc_vt_0x19C(); + mAng maxX = acNpc_vt_0x190(); + mAng minX = acNpc_vt_0x194(); + + head->setMinMaxStepSize(max, min); + head->setMinMaxStepSizeX(maxX, minX); + neck->setMinMaxStepSize(max, min); + neck->setMinMaxStepSizeX(maxX, minX); + spine->setMinMaxStepSize(max, min); + spine->setMinMaxStepSizeX(maxX, minX); + + return true; +} + +m3d::anmTexSrt_c * +dAcNpc_c::newAnmTexSrt(d3d::AnmMdlWrapper *mdl, mAllocator_c *allocator, const char *mdlName, const char *anmName) { + m3d::anmTexSrt_c *ret = new m3d::anmTexSrt_c(); + if (!ret) { + return nullptr; + } + if (!ret->create( + mdl->getMdlFile().GetResMdl(mdlName), mdl->getMdlFile().GetResAnmTexSrt(anmName), allocator, nullptr, 1 + )) { + delete ret; + return nullptr; + } + ret->setFrame(0.0f, 0); + mdl->getModel().setAnm(*ret); + return ret; +} + +void dAcNpc_c::setAnmTexSrt(d3d::AnmMdlWrapper *mdl, m3d::anmTexSrt_c *texSrt, const char *anmName) { + texSrt->setAnm(mdl->getModel(), mdl->getMdlFile().GetResAnmTexSrt(anmName), 0, m3d::PLAY_MODE_4); + texSrt->setFrame(0.0f, 0); +} + +bool dAcNpc_c::createAnmChr( + d3d::AnmMdlWrapper *mdl, const char *mdlName, const char *anmName, mAllocator_c *allocator, m3d::anmChr_c *anm +) { + // TODO - what? + return !!anm->create2(mdl->getMdlFile().GetResMdl(mdlName), mdl->getMdlFile().GetResAnmChr(anmName), allocator); +} + +s32 dAcNpc_c::getPathIndexForId(s32 pathId, s32 roomId, bool spth) { + dRoom_c *room = dStage_c::GetInstance()->getRoom(roomId); + int ret = -1; + if (spth) { + for (int i = 0; i < room->getSpthCount(); i++) { + if (room->getSpth(i)->pathId == pathId) { + ret = i; + break; + } + } + } else { + for (int i = 0; i < room->getPathCount(); i++) { + if (room->getPath(i)->pathId == pathId) { + ret = i; + break; + } + } + } + return ret; +} + static u32 findNodeId(d3d::AnmMdlWrapper *mdl, const char *nodeName) { return m3d::getNodeID(mdl->getModel().getResMdl(), nodeName); } @@ -426,3 +639,34 @@ void dNpcMdlCallbackMulti_c::timingB(u32 nodeId, nw4r::g3d::WorldMtxManip *manip node = node->mpNext; } } + +/** + * @brief Clamps an angle such that bounds[1] <= result <= bounds[0] and result + return = value + * + * @param value the input value + * @param bounds the max, min bounds + * @param result the clamped value + * @return mAng the excess + */ +extern mAng clampAngle(mAng &value, mAng *bounds, mAng &result) { + // TODO instruction order + mAng ret = value; + + if (bounds[1] <= ret && ret <= bounds[0]) { + result = ret; + ret = 0; + } else if (ret > 0) { + result = bounds[0]; + ret = ret - bounds[0]; + } else { + result = bounds[1]; + ret = ret - bounds[1]; + } + + return ret; +} + +extern void clampAngleXY(mAng3_c &value, mAng *boundsX, mAng *boundsY, mAng3_c &result) { + clampAngle(value.x, boundsX, result.x); + clampAngle(value.y, boundsY, result.y); +}