diff options
| author | robojumper <robojumper@gmail.com> | 2026-05-28 17:35:04 +0200 |
|---|---|---|
| committer | robojumper <robojumper@gmail.com> | 2026-05-28 17:55:54 +0200 |
| commit | 401bab69247514b6a604e784a17faec1ff353c08 (patch) | |
| tree | b60792d9531ce80756b910d00bf655d67bd0fe33 /src/d | |
| parent | 59af442eac2a5312704d5b3b6e9e6d2469e0efec (diff) | |
A few NPC functions
Diffstat (limited to 'src/d')
| -rw-r--r-- | src/d/a/npc/d_a_npc.cpp | 250 |
1 files changed, 247 insertions, 3 deletions
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<dAcNpcInv_c *>(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); +} |
