From 72dd147e80db6db639e9ae79996b2d2d64456c90 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sat, 23 Aug 2025 23:25:01 +0200 Subject: [PATCH] Starting to make sense of some of these vtables in NPCs --- .../rels/d_a_npc_rival_lodNP/symbols.txt | 6 +- config/SOUE01/splits.txt | 3 + config/SOUE01/symbols.txt | 194 ++++----- include/d/a/npc/d_a_npc tke.h | 16 + include/d/a/npc/d_a_npc.h | 246 ++++++++++- include/d/d_message.h | 9 +- include/toBeSorted/event_manager.h | 1 + src/d/a/npc/d_a_npc.cpp | 388 +++++++++++++++++- src/d/d_message.cpp | 8 +- 9 files changed, 757 insertions(+), 114 deletions(-) create mode 100644 include/d/a/npc/d_a_npc tke.h diff --git a/config/SOUE01/rels/d_a_npc_rival_lodNP/symbols.txt b/config/SOUE01/rels/d_a_npc_rival_lodNP/symbols.txt index 6c725eb7..cd74c3e1 100644 --- a/config/SOUE01/rels/d_a_npc_rival_lodNP/symbols.txt +++ b/config/SOUE01/rels/d_a_npc_rival_lodNP/symbols.txt @@ -47,9 +47,9 @@ getObjectListEntry__8dAcNpc_cFv = .text:0x000008C0; // type:function size:0x8 acNpc_vt_0xE4__8dAcNpc_cFv = .text:0x000008D0; // type:function size:0x8 acNpc_vt_0xE0__8dAcNpc_cFv = .text:0x000008E0; // type:function size:0x8 acNpc_vt_0xDC__8dAcNpc_cFv = .text:0x000008F0; // type:function size:0x8 -eventFlowSwitch4__8dAcNpc_cFv = .text:0x00000900; // type:function size:0x8 -eventFlowSwitch3__8dAcNpc_cFv = .text:0x00000910; // type:function size:0x8 -eventFlowSwitch2__8dAcNpc_cFv = .text:0x00000920; // type:function size:0x8 +eventFlowSwitch3__8dAcNpc_cFUl = .text:0x00000900; // type:function size:0x8 +eventFlowSwitch2__8dAcNpc_cFUl = .text:0x00000910; // type:function size:0x8 +eventFlowSwitch1__8dAcNpc_cFUl = .text:0x00000920; // type:function size:0x8 acNpc_vt_0x98__8dAcNpc_cFv = .text:0x00000930; // type:function size:0x8 acNpc_vt_0x94__8dAcNpc_cFv = .text:0x00000940; // type:function size:0x8 acNpc_vt_0x90__8dAcNpc_cFv = .text:0x00000950; // type:function size:0x8 diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index dc72acbc..d481d933 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -141,6 +141,7 @@ d/a/e/d_a_e_base.cpp: .text start:0x8002F300 end:0x80030CB0 align:16 .ctors start:0x804DB664 end:0x804DB668 .data start:0x80501638 end:0x805016E0 + .sdata start:0x80571930 end:0x80571948 .sbss start:0x80575098 end:0x805750A0 .bss start:0x80597020 end:0x80597030 @@ -148,7 +149,9 @@ d/a/npc/d_a_npc.cpp: .text start:0x80030CB0 end:0x8003F718 align:16 .ctors start:0x804DB668 end:0x804DB66C .data start:0x805016E0 end:0x80502050 + .sdata start:0x80571948 end:0x80571A68 .sbss start:0x805750A0 end:0x805750B0 + .sdata2 start:0x80576D10 end:0x80576D98 .bss start:0x80597030 end:0x805972E0 toBeSorted/d_npc_common.cpp: diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index b341f176..cf9a02e4 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -1194,14 +1194,14 @@ fn_80030C60 = .text:0x80030C60; // type:function size:0x4 fn_80030C70 = .text:0x80030C70; // type:function size:0x4 fn_80030C80 = .text:0x80030C80; // type:function size:0x8 ActorEnemyBase__initList = .text:0x80030C90; // type:function size:0x14 -ActorNpcEventFlowManager__handleType3Flow = .text:0x80030CB0; // type:function size:0xC34 +handleEventInternal__10dFlowNpc_cFPC11MsbFlowInfo = .text:0x80030CB0; // type:function size:0xC34 setActorRef9__17daPlayerActBase_cFv = .text:0x800318F0; // type:function size:0x4 -fn_80031900 = .text:0x80031900; // type:function size:0x8 -fn_80031910 = .text:0x80031910; // type:function size:0x8 +acNpc_vt_0x1F4__8dAcNpc_cFv = .text:0x80031900; // type:function size:0x8 +acNpc_vt_0x14C__8dAcNpc_cFv = .text:0x80031910; // type:function size:0x8 fn_80031920 = .text:0x80031920; // type:function size:0x8 -ActorNpcEventFlowManager__getSwitchChoice = .text:0x80031930; // type:function size:0xA4 -fn_800319E0 = .text:0x800319E0; // type:function size:0x54 -fn_80031A40 = .text:0x80031A40; // type:function size:0x44 +getSwitchChoice__10dFlowNpc_cCFPC11MsbFlowInfoUs = .text:0x80031930; // type:function size:0xA4 +triggerEntryPoint__10dFlowNpc_cFll = .text:0x800319E0; // type:function size:0x54 +triggerEntryPoint__10dFlowNpc_cFPCc = .text:0x80031A40; // type:function size:0x44 fn_80031A90 = .text:0x80031A90; // type:function size:0xAC fn_80031B40 = .text:0x80031B40; // type:function size:0x98 fn_80031BE0 = .text:0x80031BE0; // type:function size:0x9C @@ -1214,7 +1214,7 @@ getParamAsInt = .text:0x80032020; // type:function size:0xC ActorNpcEventFlowManager__getParamsAsShortShort = .text:0x80032030; // type:function size:0x14 ActorNpcEventFlowManager__getParamsAsShortCharChar = .text:0x80032050; // type:function size:0x1C getParamsAsCharCharCharChar = .text:0x80032070; // type:function size:0x24 -fn_800320A0 = .text:0x800320A0; // type:function size:0x84 +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 @@ -1224,16 +1224,16 @@ baseID_Demo<10sStateID_c>__Fv_RC12sStateIDIf_c = .text:0x80032450; // type:funct fn_80032460 = .text:0x80032460; // type:function size:0x4 fn_80032470 = .text:0x80032470; // type:function size:0x4 npcExecute__8dAcNpc_cFv = .text:0x80032480; // type:function size:0x390 -fn_80032810 = .text:0x80032810; // type:function size:0x8 -fn_80032820 = .text:0x80032820; // type:function size:0x8 -fn_80032830 = .text:0x80032830; // type:function size:0x10 +acNpc_vt_0x204__8dAcNpc_cFv = .text:0x80032810; // type:function size:0x8 +acNpc_vt_0xDC__8dAcNpc_cFv = .text:0x80032820; // type:function size:0x8 +executeState__8dAcNpc_cFv = .text:0x80032830; // type:function size:0x10 executeState__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>Fv = .text:0x80032840; // type:function size:0x10 -fn_80032850 = .text:0x80032850; // type:function size:0x64 -fn_800328C0 = .text:0x800328C0; // type:function size:0x58 +setState__8dAcNpc_cFRC12sStateIDIf_c = .text:0x80032850; // type:function size:0x64 +isInState__8dAcNpc_cCFRC12sStateIDIf_c = .text:0x800328C0; // type:function size:0x58 getStateID__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>CFv = .text:0x80032920; // type:function size:0x10 getStateID__14sStateMethod_cCFv = .text:0x80032930; // type:function size:0x8 changeState__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>FRC12sStateIDIf_c = .text:0x80032940; // type:function size:0x10 -fn_80032950 = .text:0x80032950; // type:function size:0x8 +acNpc_vt_0x150__8dAcNpc_cFv = .text:0x80032950; // type:function size:0x8 fn_80032960 = .text:0x80032960; // type:function size:0x94 fn_80032A00 = .text:0x80032A00; // type:function size:0x44 fn_80032A50 = .text:0x80032A50; // type:function size:0x9C @@ -1245,8 +1245,8 @@ fn_80032DE0 = .text:0x80032DE0; // type:function size:0xC4 fn_80032EB0 = .text:0x80032EB0; // type:function size:0x188 fn_80033040 = .text:0x80033040; // type:function size:0xF8 fn_80033140 = .text:0x80033140; // type:function size:0xDC -fn_80033220 = .text:0x80033220; // type:function size:0x4 -fn_80033230 = .text:0x80033230; // type:function size:0x4 +acNpc_vt_0x120__8dAcNpc_cFv = .text:0x80033220; // type:function size:0x4 +acNpc_vt_0x124__8dAcNpc_cFv = .text:0x80033230; // type:function size:0x4 fn_80033240 = .text:0x80033240; // type:function size:0xD4 fn_80033320 = .text:0x80033320; // type:function size:0xD0 acNpc_vt_0xE8__8dAcNpc_cFv = .text:0x800333F0; // type:function size:0x290 @@ -1259,7 +1259,7 @@ fn_80033940 = .text:0x80033940; // type:function size:0x14 __ct__8dAcNpc_cFv = .text:0x80033960; // type:function size:0x284 __ct__24dAcRef_c<12dAcObjBase_c>Fv = .text:0x80033BF0; // type:function size:0x14 __dt__24dAcRef_c<12dAcObjBase_c>Fv = .text:0x80033C10; // type:function size:0x58 -ActorNpcEventFlowManager__dtor = .text:0x80033C70; // type:function size:0x74 +__dt__10dFlowNpc_cFv = .text:0x80033C70; // type:function size:0x74 fn_80033CF0 = .text:0x80033CF0; // type:function size:0x5C fn_80033D50 = .text:0x80033D50; // type:function size:0x9C __dt__20sFState_c<8dAcNpc_c>Fv = .text:0x80033DF0; // type:function size:0x58 @@ -1311,14 +1311,14 @@ fn_80034E70 = .text:0x80034E70; // type:function size:0x17C fn_80034FF0 = .text:0x80034FF0; // type:function size:0x54 fn_80035050 = .text:0x80035050; // type:function size:0x9C ActorNpcBase__giveItem = .text:0x800350F0; // type:function size:0x10 -fn_80035100 = .text:0x80035100; // type:function size:0x4 -fn_80035110 = .text:0x80035110; // type:function size:0x4 +acNpc_vt_0x88__8dAcNpc_cFv = .text:0x80035100; // type:function size:0x4 +acNpc_vt_0x8C__8dAcNpc_cFv = .text:0x80035110; // type:function size:0x4 fn_80035120 = .text:0x80035120; // type:function size:0x10 -fn_80035130 = .text:0x80035130; // type:function size:0x8 +acNpc_vt_0x90__8dAcNpc_cFv = .text:0x80035130; // type:function size:0x8 fn_80035140 = .text:0x80035140; // type:function size:0x10 -fn_80035150 = .text:0x80035150; // type:function size:0x8 +acNpc_vt_0x94__8dAcNpc_cFv = .text:0x80035150; // type:function size:0x8 ActorNpcEventFlowManager__makeActorDoSomething = .text:0x80035160; // type:function size:0x10 -fn_80035170 = .text:0x80035170; // type:function size:0x8 +acNpc_vt_0x98__8dAcNpc_cFv = .text:0x80035170; // type:function size:0x8 fn_80035180 = .text:0x80035180; // type:function size:0x10 fn_80035190 = .text:0x80035190; // type:function size:0x10 fn_800351A0 = .text:0x800351A0; // type:function size:0x10 @@ -1333,21 +1333,21 @@ fn_80035330 = .text:0x80035330; // type:function size:0x10 fn_80035340 = .text:0x80035340; // type:function size:0x104 fn_80035450 = .text:0x80035450; // type:function size:0x108 fn_80035560 = .text:0x80035560; // type:function size:0x24 -giveItem__8dAcNpc_cFPv7ITEM_ID = .text:0x80035590; // type:function size:0x44 +giveItem__8dAcNpc_cFUc7ITEM_ID = .text:0x80035590; // type:function size:0x44 fn_800355E0 = .text:0x800355E0; // type:function size:0x200 -NpcBase_GetPosCopy3 = .text:0x800357E0; // type:function size:0x1C +getPosCopy3__8dAcNpc_cFR7mVec3_c = .text:0x800357E0; // type:function size:0x1C fn_80035800 = .text:0x80035800; // type:function size:0x294 fn_80035AA0 = .text:0x80035AA0; // type:function size:0x100 acNpc_vt_0xB0__8dAcNpc_cFv = .text:0x80035BA0; // type:function size:0x1D0 acNpc_vt_0xB4__8dAcNpc_cFv = .text:0x80035D70; // type:function size:0x19C acNpc_vt_0xB8__8dAcNpc_cFv = .text:0x80035F10; // type:function size:0x20C acNpc_vt_0xBC__8dAcNpc_cFv = .text:0x80036120; // type:function size:0x84 -ActorNpcBase__contextRelatedEventSwitch2 = .text:0x800361B0; // type:function size:0x10 -fn_800361C0 = .text:0x800361C0; // type:function size:0x8 -ActorNpcBase__contextRelatedEventSwitch3 = .text:0x800361D0; // type:function size:0x10 -fn_800361E0 = .text:0x800361E0; // type:function size:0x8 -ActorNpcBase__contextRelatedEventSwitch4 = .text:0x800361F0; // type:function size:0x10 -fn_80036200 = .text:0x80036200; // type:function size:0x8 +doFlowSwitch1__8dAcNpc_cFUl = .text:0x800361B0; // type:function size:0x10 +eventFlowSwitch1__8dAcNpc_cFUl = .text:0x800361C0; // type:function size:0x8 +doFlowSwitch2__8dAcNpc_cFUl = .text:0x800361D0; // type:function size:0x10 +eventFlowSwitch2__8dAcNpc_cFUl = .text:0x800361E0; // type:function size:0x8 +doFlowSwitch3__8dAcNpc_cFUl = .text:0x800361F0; // type:function size:0x10 +eventFlowSwitch3__8dAcNpc_cFUl = .text:0x80036200; // type:function size:0x8 acNpc_vt_0x164__8dAcNpc_cFv = .text:0x80036210; // type:function size:0x1FC acNpc_vt_0x16C__8dAcNpc_cFv = .text:0x80036410; // type:function size:0x8 acNpc_vt_0x170__8dAcNpc_cFv = .text:0x80036420; // type:function size:0x8 @@ -1380,7 +1380,7 @@ acNpc_vt_0x1D8__8dAcNpc_cFv = .text:0x80036810; // type:function size:0x10 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 -fn_80036850 = .text:0x80036850; // type:function size:0xC8 +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 @@ -1395,8 +1395,8 @@ acNpc_vt_0xD0__8dAcNpc_cFv = .text:0x80037060; // type:function size:0x8 acNpc_vt_0xD4__8dAcNpc_cFv = .text:0x80037070; // type:function size:0x4 acNpc_vt_0xD8__8dAcNpc_cFv = .text:0x80037080; // type:function size:0x8 fn_80037090 = .text:0x80037090; // type:function size:0x200 -fn_80037290 = .text:0x80037290; // type:function size:0x8 -fn_800372A0 = .text:0x800372A0; // type:function size:0x8 +acNpc_vt_0x114__8dAcNpc_cFv = .text:0x80037290; // type:function size:0x8 +acNpc_vt_0x118__8dAcNpc_cFv = .text:0x800372A0; // type:function size:0x8 isInItemGetEvent = .text:0x800372B0; // type:function size:0xE4 fn_800373A0 = .text:0x800373A0; // type:function size:0xF4 fn_800374A0 = .text:0x800374A0; // type:function size:0x94 @@ -1443,39 +1443,39 @@ unlinkActorRef9__17daPlayerActBase_cFv = .text:0x80038E50; // type:function size fn_80038E60 = .text:0x80038E60; // type:function size:0x18 fn_80038E80 = .text:0x80038E80; // type:function size:0x28 fn_80038EB0 = .text:0x80038EB0; // type:function size:0x38 -fn_80038EF0 = .text:0x80038EF0; // type:function size:0x40 -fn_80038F30 = .text:0x80038F30; // type:function size:0x38 -fn_80038F70 = .text:0x80038F70; // type:function size:0x4 -fn_80038F80 = .text:0x80038F80; // type:function size:0xE0 -fn_80039060 = .text:0x80039060; // type:function size:0x74 -fn_800390E0 = .text:0x800390E0; // type:function size:0x2C -fn_80039110 = .text:0x80039110; // type:function size:0x20 -fn_80039130 = .text:0x80039130; // type:function size:0x24 -fn_80039160 = .text:0x80039160; // type:function size:0x18 -fn_80039180 = .text:0x80039180; // type:function size:0x24 -fn_800391B0 = .text:0x800391B0; // type:function size:0x30 -fn_800391E0 = .text:0x800391E0; // type:function size:0x24 -fn_80039210 = .text:0x80039210; // type:function size:0xA0 -fn_800392B0 = .text:0x800392B0; // type:function size:0x88 -fn_80039340 = .text:0x80039340; // type:function size:0xF4 -fn_80039440 = .text:0x80039440; // type:function size:0x1C -fn_80039460 = .text:0x80039460; // type:function size:0x88 -fn_800394F0 = .text:0x800394F0; // type:function size:0x88 -fn_80039580 = .text:0x80039580; // type:function size:0x2C -fn_800395B0 = .text:0x800395B0; // type:function size:0xCC -fn_80039680 = .text:0x80039680; // type:function size:0x3C -fn_800396C0 = .text:0x800396C0; // type:function size:0x54 -fn_80039720 = .text:0x80039720; // type:function size:0x48 -fn_80039770 = .text:0x80039770; // type:function size:0x8C -fn_80039800 = .text:0x80039800; // type:function size:0x44 -fn_80039850 = .text:0x80039850; // type:function size:0xB4 +findNodeId__FPQ23d3d13AnmMdlWrapperPCc = .text:0x80038EF0; // type:function size:0x40 +loadNodeId__21dNpcMdlCallbackBase_cFPQ23d3d13AnmMdlWrapperPCc = .text:0x80038F30; // type:function size:0x38 +timingA__21dNpcMdlCallbackBase_cFPQ34nw4r3g3d12ChrAnmResult = .text:0x80038F70; // type:function size:0x4 +timingB__21dNpcMdlCallbackBase_cFP6mMtx_c = .text:0x80038F80; // type:function size:0xE0 +__ct__20dNpcMdlCallbackAng_cFv = .text:0x80039060; // type:function size:0x74 +setMinMaxStepSize__20dNpcMdlCallbackAng_cFRC4mAngRC4mAng = .text:0x800390E0; // type:function size:0x2C +setMinMaxStepSizeX__20dNpcMdlCallbackAng_cFRC4mAngRC4mAng = .text:0x80039110; // type:function size:0x20 +reset__20dNpcMdlCallbackAng_cFv = .text:0x80039130; // type:function size:0x24 +resetTarget__20dNpcMdlCallbackAng_cFv = .text:0x80039160; // type:function size:0x18 +setTarget__20dNpcMdlCallbackAng_cFRC7mAng3_c = .text:0x80039180; // type:function size:0x24 +setTargetNow__20dNpcMdlCallbackAng_cFRC7mAng3_c = .text:0x800391B0; // type:function size:0x30 +finishTarget__20dNpcMdlCallbackAng_cFv = .text:0x800391E0; // type:function size:0x24 +calc__20dNpcMdlCallbackAng_cFv = .text:0x80039210; // type:function size:0xA0 +apply__20dNpcMdlCallbackYXZ_cCFP6mMtx_c = .text:0x800392B0; // type:function size:0x88 +apply__25dNpcMdlCallbackYXZFixed_cCFP6mMtx_c = .text:0x80039340; // type:function size:0xF4 +vt_0x20__25dNpcMdlCallbackYXZFixed_cFPC9dAcBase_c = .text:0x80039440; // type:function size:0x1C +apply__20dNpcMdlCallbackYZX_cCFP6mMtx_c = .text:0x80039460; // type:function size:0x88 +apply__20dNpcMdlCallbackXZY_cCFP6mMtx_c = .text:0x800394F0; // type:function size:0x88 +calc__21dNpcMdlCallbackQuat_cFv = .text:0x80039580; // type:function size:0x2C +apply__21dNpcMdlCallbackQuat_cCFP6mMtx_c = .text:0x800395B0; // type:function size:0xCC +newCallbackNode__22dNpcMdlCallbackMulti_cFv = .text:0x80039680; // type:function size:0x3C +createCallbackNode__22dNpcMdlCallbackMulti_cFP21dNpcMdlCallbackBase_c = .text:0x800396C0; // type:function size:0x54 +clearList__22dNpcMdlCallbackMulti_cFv = .text:0x80039720; // type:function size:0x48 +addCallback__22dNpcMdlCallbackMulti_cFP21dNpcMdlCallbackBase_c = .text:0x80039770; // type:function size:0x8C +timingA__22dNpcMdlCallbackMulti_cFUlPQ34nw4r3g3d12ChrAnmResultQ34nw4r3g3d6ResMdl = .text:0x80039800; // type:function size:0x44 +timingB__22dNpcMdlCallbackMulti_cFUlPQ34nw4r3g3d13WorldMtxManipQ34nw4r3g3d6ResMdl = .text:0x80039850; // type:function size:0xB4 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 fn_80039C50 = .text:0x80039C50; // type:function size:0x40C -fn_8003A060 = .text:0x8003A060; // type:function size:0x4 +vt_0x20__20dNpcMdlCallbackAng_cFPC9dAcBase_c = .text:0x8003A060; // type:function size:0x4 fn_8003A070 = .text:0x8003A070; // type:function size:0x12C fn_8003A1A0 = .text:0x8003A1A0; // type:function size:0x2B4 fn_8003A460 = .text:0x8003A460; // type:function size:0x14 @@ -1486,7 +1486,7 @@ fn_8003A920 = .text:0x8003A920; // type:function size:0x4 fn_8003A930 = .text:0x8003A930; // type:function size:0x54 fn_8003A990 = .text:0x8003A990; // type:function size:0x4 fn_8003A9A0 = .text:0x8003A9A0; // type:function size:0x54 -fn_8003AA00 = .text:0x8003AA00; // type:function size:0x4 +acNpc_vt_0x15C__8dAcNpc_cFv = .text:0x8003AA00; // type:function size:0x4 fn_8003AA10 = .text:0x8003AA10; // type:function size:0x8 fn_8003AA20 = .text:0x8003AA20; // type:function size:0x8 fn_8003AA30 = .text:0x8003AA30; // type:function size:0x6C @@ -1511,9 +1511,9 @@ fn_8003B670 = .text:0x8003B670; // type:function size:0x74 fn_8003B6F0 = .text:0x8003B6F0; // type:function size:0x2C fn_8003B720 = .text:0x8003B720; // type:function size:0x4C fn_8003B770 = .text:0x8003B770; // type:function size:0x14 -fn_8003B790 = .text:0x8003B790; // type:function size:0x4 +acNpc_vt_0x160__8dAcNpc_cFv = .text:0x8003B790; // type:function size:0x4 fn_8003B7A0 = .text:0x8003B7A0; // type:function size:0x14 -fn_8003B7C0 = .text:0x8003B7C0; // type:function size:0x4 +acNpc_vt_0x158__8dAcNpc_cFv = .text:0x8003B7C0; // type:function size:0x4 fn_8003B7D0 = .text:0x8003B7D0; // type:function size:0xB0 fn_8003B880 = .text:0x8003B880; // type:function size:0x68 fn_8003B8F0 = .text:0x8003B8F0; // type:function size:0x78 @@ -1546,7 +1546,7 @@ fn_8003CCA0 = .text:0x8003CCA0; // type:function size:0x150 fn_8003CDF0 = .text:0x8003CDF0; // type:function size:0x44 fn_8003CE40 = .text:0x8003CE40; // type:function size:0x520 fn_8003D360 = .text:0x8003D360; // type:function size:0x1DC -fn_8003D540 = .text:0x8003D540; // type:function size:0x8 +acNpc_vt_0xE0__8dAcNpc_cFv = .text:0x8003D540; // type:function size:0x8 fn_8003D550 = .text:0x8003D550; // type:function size:0x40 fn_8003D590 = .text:0x8003D590; // type:function size:0x30 fn_8003D5C0 = .text:0x8003D5C0; // type:function size:0x4 @@ -1592,28 +1592,28 @@ fn_8003E7D0 = .text:0x8003E7D0; // type:function size:0xC8 fn_8003E8A0 = .text:0x8003E8A0; // type:function size:0x9C fn_8003E940 = .text:0x8003E940; // type:function size:0x58 fn_8003E9A0 = .text:0x8003E9A0; // type:function size:0x8 -fn_8003E9B0 = .text:0x8003E9B0; // type:function size:0x34 -fn_8003E9F0 = .text:0x8003E9F0; // type:function size:0x14 -fn_8003EA10 = .text:0x8003EA10; // type:function size:0x34 -ActorNpcBase_GetEventFlowManager = .text:0x8003EA50; // type:function size:0x8 -fn_8003EA60 = .text:0x8003EA60; // type:function size:0x8 -fn_8003EA70 = .text:0x8003EA70; // type:function size:0x8 -fn_8003EA80 = .text:0x8003EA80; // type:function size:0x8 -fn_8003EA90 = .text:0x8003EA90; // type:function size:0x4 -fn_8003EAA0 = .text:0x8003EAA0; // type:function size:0x8 -fn_8003EAB0 = .text:0x8003EAB0; // type:function size:0x8 -fn_8003EAC0 = .text:0x8003EAC0; // type:function size:0x8 -fn_8003EAD0 = .text:0x8003EAD0; // type:function size:0x8 -fn_8003EAE0 = .text:0x8003EAE0; // type:function size:0x8 -fn_8003EAF0 = .text:0x8003EAF0; // type:function size:0x8 +acNpc_vt_0x200__8dAcNpc_cFv = .text:0x8003E9B0; // type:function size:0x34 +acNpc_vt_0x1FC__8dAcNpc_cFv = .text:0x8003E9F0; // type:function size:0x14 +acNpc_vt_0x1F8__8dAcNpc_cFv = .text:0x8003EA10; // type:function size:0x34 +acNpc_vt_0x1F0__8dAcNpc_cFv = .text:0x8003EA50; // type:function size:0x8 +acNpc_vt_0x1EC__8dAcNpc_cFv = .text:0x8003EA60; // type:function size:0x8 +acNpc_vt_0x1E8__8dAcNpc_cFv = .text:0x8003EA70; // type:function size:0x8 +acNpc_vt_0x168__8dAcNpc_cFv = .text:0x8003EA80; // type:function size:0x8 +acNpc_vt_0x154__8dAcNpc_cFv = .text:0x8003EA90; // type:function size:0x4 +acNpc_vt_0x12C__8dAcNpc_cFv = .text:0x8003EAA0; // type:function size:0x8 +acNpc_vt_0x128__8dAcNpc_cFv = .text:0x8003EAB0; // type:function size:0x8 +acNpc_vt_0xEC__8dAcNpc_cFv = .text:0x8003EAC0; // type:function size:0x8 +getObjectListEntry__8dAcNpc_cFv = .text:0x8003EAD0; // type:function size:0x8 +acNpc_vt_0xE4__8dAcNpc_cFv = .text:0x8003EAE0; // type:function size:0x8 +vt_0x38__10dFlowNpc_cCFv = .text:0x8003EAF0; // type:function size:0x8 fn_8003EB00 = .text:0x8003EB00; // type:function size:0xCC fn_8003EBD0 = .text:0x8003EBD0; // type:function size:0x1C -fn_8003EBF0 = .text:0x8003EBF0; // type:function size:0x6C -fn_8003EC60 = .text:0x8003EC60; // type:function size:0x28 -fn_8003EC90 = .text:0x8003EC90; // type:function size:0x40 -fn_8003ECD0 = .text:0x8003ECD0; // type:function size:0x40 -fn_8003ED10 = .text:0x8003ED10; // type:function size:0x40 -fn_8003ED50 = .text:0x8003ED50; // type:function size:0x40 +__dt__22dNpcMdlCallbackMulti_cFv = .text:0x8003EBF0; // type:function size:0x6C +isDone__21dNpcMdlCallbackQuat_cFv = .text:0x8003EC60; // type:function size:0x28 +__dt__21dNpcMdlCallbackQuat_cFv = .text:0x8003EC90; // type:function size:0x40 +isDone__20dNpcMdlCallbackAng_cFv = .text:0x8003ECD0; // type:function size:0x40 +__dt__20dNpcMdlCallbackYXZ_cFv = .text:0x8003ED10; // type:function size:0x40 +__dt__20dNpcMdlCallbackAng_cFv = .text:0x8003ED50; // type:function size:0x40 fn_8003ED90 = .text:0x8003ED90; // type:function size:0x84 build__23sFStateFct_c<8dAcNpc_c>FRC12sStateIDIf_c = .text:0x8003EE20; // type:function size:0x60 dispose__23sFStateFct_c<8dAcNpc_c>FRP10sStateIf_c = .text:0x8003EE80; // type:function size:0xC @@ -1633,9 +1633,9 @@ getOldStateID__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13s finalizeState__22sFStateID_c<8dAcNpc_c>CFR8dAcNpc_c = .text:0x8003EF90; // type:function size:0x30 executeState__22sFStateID_c<8dAcNpc_c>CFR8dAcNpc_c = .text:0x8003EFC0; // type:function size:0x30 initializeState__22sFStateID_c<8dAcNpc_c>CFR8dAcNpc_c = .text:0x8003EFF0; // type:function size:0x30 -fn_8003F020 = .text:0x8003F020; // type:function size:0x40 -fn_8003F060 = .text:0x8003F060; // type:function size:0x40 -fn_8003F0A0 = .text:0x8003F0A0; // type:function size:0x40 +__dt__25dNpcMdlCallbackYXZFixed_cFv = .text:0x8003F020; // type:function size:0x40 +__dt__20dNpcMdlCallbackYZX_cFv = .text:0x8003F060; // type:function size:0x40 +__dt__20dNpcMdlCallbackXZY_cFv = .text:0x8003F0A0; // type:function size:0x40 __sinit_\d_a_npc_cpp = .text:0x8003F0E0; // type:function size:0x330 scope:local __dt__22sFStateID_c<8dAcNpc_c>Fv = .text:0x8003F410; // type:function size:0x58 __dt__29sFStateVirtualID_c<8dAcNpc_c>Fv = .text:0x8003F470; // type:function size:0x5C @@ -30037,7 +30037,7 @@ __vt__46sFStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c> = .data:0x80501C18; // ty __vt__76sStateMgr_c<8dAcNpc_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c> = .data:0x80501C48; // type:object size:0x30 __vt__23sFStateFct_c<8dAcNpc_c> = .data:0x80501C78; // type:object size:0x14 __vt__20sFState_c<8dAcNpc_c> = .data:0x80501C90; // type:object size:0x18 -ActorNpcEventFlowManager__vtable = .data:0x80501CA8; // type:object size:0x44 +__vt__10dFlowNpc_c = .data:0x80501CA8; // type:object size:0x44 lbl_80501CEC = .data:0x80501CEC; // type:object size:0xC lbl_80501CF8 = .data:0x80501CF8; // type:object size:0x10 lbl_80501D08 = .data:0x80501D08; // type:object size:0x50 @@ -30050,10 +30050,16 @@ lbl_80501E00 = .data:0x80501E00; // type:object size:0x18 lbl_80501E18 = .data:0x80501E18; // type:object size:0xC lbl_80501E24 = .data:0x80501E24; // type:object size:0xC lbl_80501E30 = .data:0x80501E30; // type:object size:0x18 -lbl_80501E48 = .data:0x80501E48; // type:object size:0xA4 -lbl_80501EEC = .data:0x80501EEC; // type:object size:0x24 -lbl_80501F10 = .data:0x80501F10; // type:object size:0x40 -lbl_80501F50 = .data:0x80501F50; // type:object size:0x98 +__vt__22dNpcMdlCallbackMulti_c = .data:0x80501E48; // type:object size:0x18 +__vt__21dNpcMdlCallbackQuat_c = .data:0x80501E60; // type:object size:0x20 +__vt__20dNpcMdlCallbackXZY_c = .data:0x80501E80; // type:object size:0x24 +__vt__20dNpcMdlCallbackYZX_c = .data:0x80501EA4; // type:object size:0x24 +__vt__25dNpcMdlCallbackYXZFixed_c = .data:0x80501EC8; // type:object size:0x24 +__vt__20dNpcMdlCallbackYXZ_c = .data:0x80501EEC; // type:object size:0x24 +__vt__20dNpcMdlCallbackAng_c = .data:0x80501F10; // type:object size:0x24 +__vt__21dNpcMdlCallbackBase_c = .data:0x80501F34; // type:object size:0x1C +lbl_80501F50 = .data:0x80501F50; // type:object size:0x20 +lbl_80501F70 = .data:0x80501F70; // type:object size:0x78 __vt__29sFStateVirtualID_c<8dAcNpc_c> = .data:0x80501FE8; // type:object size:0x34 __vt__22sFStateID_c<8dAcNpc_c> = .data:0x8050201C; // type:object size:0x34 lbl_80502050 = .data:0x80502050; // type:object size:0x24 @@ -39435,11 +39441,11 @@ lbl_80571938 = .sdata:0x80571938; // type:object size:0x8 lbl_80571940 = .sdata:0x80571940; // type:object size:0x8 data:4byte lbl_80571948 = .sdata:0x80571948; // type:object size:0x4 lbl_8057194C = .sdata:0x8057194C; // type:object size:0x8 -lbl_80571954 = .sdata:0x80571954; // type:object size:0x4 data:4byte +sHeadNodeName__8dAcNpc_c = .sdata:0x80571954; // type:object size:0x4 data:4byte lbl_80571958 = .sdata:0x80571958; // type:object size:0x8 -lbl_80571960 = .sdata:0x80571960; // type:object size:0x4 data:4byte +sNeckNodeName__8dAcNpc_c = .sdata:0x80571960; // type:object size:0x4 data:4byte lbl_80571964 = .sdata:0x80571964; // type:object size:0x8 -lbl_8057196C = .sdata:0x8057196C; // type:object size:0x4 data:4byte +sSpine2NodeName__8dAcNpc_c = .sdata:0x8057196C; // type:object size:0x4 data:4byte lbl_80571970 = .sdata:0x80571970; // type:object size:0x8 data:4byte lbl_80571978 = .sdata:0x80571978; // type:object size:0x8 data:string lbl_80571980 = .sdata:0x80571980; // type:object size:0x4 data:4byte diff --git a/include/d/a/npc/d_a_npc tke.h b/include/d/a/npc/d_a_npc tke.h new file mode 100644 index 00000000..94a07545 --- /dev/null +++ b/include/d/a/npc/d_a_npc tke.h @@ -0,0 +1,16 @@ +#ifndef D_A_NPC_TKE_H +#define D_A_NPC_TKE_H + +#include "d/a/npc/d_a_npc.h" + +/** + * Actor - NPC - Talk Event (?) + * This actor has no model, so it appears to be something like a "virtual" NPC for + * purposes of event / flow stuff? + */ +class daNpcTke_c : public dAcNpc_c { +public: + void setFinishFlags(); +}; + +#endif diff --git a/include/d/a/npc/d_a_npc.h b/include/d/a/npc/d_a_npc.h index b0785692..253ec416 100644 --- a/include/d/a/npc/d_a_npc.h +++ b/include/d/a/npc/d_a_npc.h @@ -2,11 +2,228 @@ #define D_A_NPC_H #include "common.h" +#include "d/a/d_a_base.h" #include "d/a/d_a_itembase.h" #include "d/a/obj/d_a_obj_base.h" +#include "d/d_message.h" +#include "libms/flowfile.h" +#include "m/m3d/m_mdl.h" +#include "m/m_angle.h" +#include "m/m_mtx.h" +#include "m/m_quat.h" #include "m/m_vec.h" #include "s/s_State.hpp" #include "s/s_StateInterfaces.hpp" +#include "toBeSorted/d_d3d.h" + +class dAcNpc_c; + +// NPC-specific mdl callback stuff +class dNpcMdlCallbackBase_c { +protected: + /* 0x00 */ u32 mNodeId; + /* 0x04 */ mAng field_0x04; + /* 0x06 */ mAng field_0x06; + /* 0x08 */ bool mForceCalc; + + dNpcMdlCallbackBase_c() : mNodeId(-1), field_0x04(0), field_0x06(0), mForceCalc(false) {} + +public: + u32 getNodeId() const { + return mNodeId; + } + + void loadNodeId(d3d::AnmMdlWrapper *mdl, const char *nodeName); + + // vtable at 0xC + /* 0x08 */ virtual void apply(mMtx_c *result) const = 0; + /* 0x0C */ virtual void calc() = 0; + /* 0x10 */ virtual bool isDone() = 0; + /* 0x14 */ virtual void timingA(nw4r::g3d::ChrAnmResult *result); + /* 0x18 */ virtual void timingB(mMtx_c *result); +}; + +/** + * A mdl callback commonly used for controlling NPC head movement. + * NPCs will look at Link or certain objects of interest (e.g. a Bomb held by Link). + * This class smoothly interpolates the additive rotation of its node (head, neck, spine). + */ +class dNpcMdlCallbackAng_c : public dNpcMdlCallbackBase_c { +protected: + /* 0x10 */ mAng3_c mTarget; + /* 0x16 */ s16 mNumSteps; + /* 0x18 */ mAng mMaxStepSizeYZ; + /* 0x1A */ mAng mMinStepSizeYZ; + /* 0x1C */ mAng mMaxStepSizeX; + /* 0x1E */ mAng mMinStepSizeX; + /* 0x20 */ s32 mScaleZ; + /* 0x24 */ s32 mScaleX; + /* 0x28 */ s32 mScaleY; + /* 0x2C */ mAng3_c mCurrent; + + s32 getScaleX() const { + return mScaleX; + } + + s32 getScaleY() const { + return mScaleY; + } + + s32 getScaleZ() const { + return mScaleZ; + } + +public: + dNpcMdlCallbackAng_c(); + /* 0x1C */ virtual ~dNpcMdlCallbackAng_c() {} + + void setMinMaxStepSize(const mAng &max, const mAng &min); + void setMinMaxStepSizeX(const mAng &max, const mAng &min); + void reset(); + void resetTarget(); + void setTarget(const mAng3_c &target); + void setTargetNow(const mAng3_c &target); + void finishTarget(); + + /* 0x0C */ virtual void calc() override; + /* 0x10 */ virtual bool isDone() override { + // TODO - this matches, but maybe an operator overload? + return mCurrent.x == mTarget.x && mCurrent.y == mTarget.y && mCurrent.z == mTarget.z; + } + /* 0x20 */ virtual void vt_0x20(const dAcBase_c *) {} +}; + +/** + * Used by dAcOrdinaryNpc - applies rotation in YXZ order. + */ +class dNpcMdlCallbackYXZ_c : public dNpcMdlCallbackAng_c { +public: + dNpcMdlCallbackYXZ_c() {} + + /* 0x08 */ virtual void apply(mMtx_c *result) const override; + /* 0x1C */ virtual ~dNpcMdlCallbackYXZ_c() {} +}; + +/** + * Used by Salesman, Terry, Rescue Bird applies rotation in YXZ order, + * but makes sure to restore translation after applying. + */ +class dNpcMdlCallbackYXZFixed_c : public dNpcMdlCallbackAng_c { +private: + /* 0x32 */ mAng3_c mActorRotation; + +public: + dNpcMdlCallbackYXZFixed_c() {} + + /* 0x08 */ virtual void apply(mMtx_c *result) const override; + // /* 0x1C */ virtual ~dNpcMdlCallbackYXZFixed_c() {} + /* 0x20 */ virtual void vt_0x20(const dAcBase_c *) override; +}; + +/** + * Unused - applies rotation in YZX order, with X and Z swapped. + */ +class dNpcMdlCallbackYZX_c : public dNpcMdlCallbackAng_c { +public: + dNpcMdlCallbackYZX_c() {} + + /* 0x08 */ virtual void apply(mMtx_c *result) const override; + // /* 0x1C */ virtual ~dNpcMdlCallbackYZX_c() {} +}; + +/** + * Unused - applies rotation in XZY order, with X, Y, Z swizzled aroumd. + */ +class dNpcMdlCallbackXZY_c : public dNpcMdlCallbackAng_c { +public: + dNpcMdlCallbackXZY_c() {} + + /* 0x08 */ virtual void apply(mMtx_c *result) const override; + // /* 0x1C */ virtual ~dNpcMdlCallbackXZY_c() {} +}; + +/** + * Quat - used for Kikwis. + */ +class dNpcMdlCallbackQuat_c : public dNpcMdlCallbackBase_c { +protected: + /* 0x10 */ f32 mSlerpFactor; + /* 0x14 */ f32 mRatio; + /* 0x18 */ f32 mMaxStepSize; + /* 0x1C */ f32 mMinStepSize; + /* 0x20 */ mAng *mActorRotY; + /* 0x24 */ mQuat_c mStart; + /* 0x34 */ mQuat_c mTarget; + +public: + dNpcMdlCallbackQuat_c() {} + /* 0x1C */ virtual ~dNpcMdlCallbackQuat_c() {} + + /* 0x08 */ virtual void apply(mMtx_c *result) const override; + /* 0x0C */ virtual void calc() override; + /* 0x10 */ virtual bool isDone() override { + return std::fabsf(mSlerpFactor - 1.0f) < 0.001; + } +}; + +struct dNpcMdlCallbackNode { + /* 0x00 */ dNpcMdlCallbackBase_c *mpCallback; + /* 0x04 */ dNpcMdlCallbackNode *mpNext; +}; + +/** + * Since a mdl can only have one callback, this is a generic + * mechanism with which multiple callbacks can be registered. + */ +class dNpcMdlCallbackMulti_c : public m3d::callback_c { +public: + virtual ~dNpcMdlCallbackMulti_c() { + clearList(); + } + virtual void timingA(u32, nw4r::g3d::ChrAnmResult *, nw4r::g3d::ResMdl) override; + virtual void timingB(u32, nw4r::g3d::WorldMtxManip *, nw4r::g3d::ResMdl) override; + + bool addCallback(dNpcMdlCallbackBase_c *callback); + +private: + dNpcMdlCallbackNode *newCallbackNode(); + bool createCallbackNode(dNpcMdlCallbackBase_c *cb); + void clearList(); + + /* 0x04 */ dNpcMdlCallbackNode *mpHead; + /* 0x08 */ dNpcMdlCallbackNode *mpTail; + /* 0x0C */ s32 mNumNodes; +}; + +// NPC-specific "flow" / MSBF code +class dFlowNpc_c : public dFlow_c { +public: + dFlowNpc_c(dAcNpc_c *owner) : mpOwner(owner) {} + virtual ~dFlowNpc_c() {} + + /* vt 0x0C */ virtual void triggerEntryPoint(s32 labelPart1, s32 labelPart2) override; + /* vt 0x10 */ virtual void triggerEntryPoint(const char *) override; + /* vt 0x1C */ virtual bool handleEventInternal(const MsbFlowInfo *element) override; + /* vt 0x34 */ virtual void vt_0x34() override {} + /* vt 0x38 */ virtual bool vt_0x38() const override { + return true; + } + /* vt 0x3C */ virtual u16 getSwitchChoice(const MsbFlowInfo *element, u16 param) const override; + /* vt 0x40 */ virtual bool triggerEntryPointChecked(s32 labelPart1, s32 labelPart2) override; + +private: + void extract2xU16Params(const MsbFlowInfo *element, u16 *p1, u16 *p2); + void extract4xU8Params(const MsbFlowInfo *element, u8 *p1, u8 *p2, u8 *p3, u8 *p4); + + void setupActorRefs(); + + /* 0x064 */ dAcNpc_c *mpOwner; + // exact type isn't known but this Makes Sense + /* 0x068 */ dAcRef_c mObjRefs[16]; + /* 0x128 */ UNKWORD field_0x128[4]; + /* 0x138 */ UNKWORD field_0x138; + /* 0x13C */ UNKWORD field_0x13C; +}; // This is the NPC base. Most npcs actually use dAcOrdinaryNpc, but this just is a simpler one? @@ -18,7 +235,7 @@ public: dAcNpc_c(); virtual ~dAcNpc_c(); - /* vt 0x080 */ virtual bool giveItem(void *unknown, ITEM_ID item_id); + /* vt 0x080 */ virtual bool giveItem(u8 param, ITEM_ID item_id); /* vt 0x084 */ virtual void getPosCopy3(mVec3_c &outResult) { outResult.copyFrom(poscopy3); } @@ -42,13 +259,13 @@ public: /* vt 0x0B4 */ virtual void acNpc_vt_0xB4(); /* vt 0x0B8 */ virtual void acNpc_vt_0xB8(); /* vt 0x0BC */ virtual void acNpc_vt_0xBC(); - /* vt 0x0C0 */ virtual int eventFlowSwitch2() { + /* vt 0x0C0 */ virtual u16 eventFlowSwitch1(u32 arg) { return 0; } - /* vt 0x0C4 */ virtual int eventFlowSwitch3() { + /* vt 0x0C4 */ virtual u16 eventFlowSwitch2(u32 arg) { return 0; } - /* vt 0x0C8 */ virtual int eventFlowSwitch4() { + /* vt 0x0C8 */ virtual u16 eventFlowSwitch3(u32 arg) { return 0; } /* vt 0x0CC */ virtual void acNpc_vt_0xCC(); @@ -79,8 +296,7 @@ public: } /* vt 0x0F4 */ virtual void setState(const sStateIDIf_c &otherState) { - // Result is discarded, but I guess in demo builds this is used - // to prevent actors from leaving the Demo state. + // Result is discarded (void)isInState(StateID_Demo); mStateMgr.changeState(otherState); } @@ -167,7 +383,7 @@ public: return 1; } /* vt 0x1F0 */ virtual void *acNpc_vt_0x1F0() { - return field_0x364; + return &mFlow; } /* vt 0x1F4 */ virtual int acNpc_vt_0x1F4() { return 1; @@ -185,14 +401,28 @@ public: return 0; } + bool doGiveItem(u8 id, s32 item); + u16 doFlowSwitch1(u32 arg); + u16 doFlowSwitch2(u32 arg); + u16 doFlowSwitch3(u32 arg); + protected: void npcExecute(); static mVec3_c getLinkPos(); + static bool addHeadNeckSpineCallbacks( + d3d::AnmMdlWrapper *mdl, dNpcMdlCallbackMulti_c *multi, dNpcMdlCallbackBase_c *head, + dNpcMdlCallbackBase_c *neck, dNpcMdlCallbackBase_c *spine + ); + + static const char *sHeadNodeName; + static const char *sNeckNodeName; + static const char *sSpine2NodeName; private: /* 0x330 */ u8 field_0x330[0x358 - 0x330]; /* 0x358 */ fLiNdBa_c mActorListEntry; - /* 0x364 */ u8 field_0x364[0x4C0 - 0x364]; + /* 0x364 */ dFlowNpc_c mFlow; + /* 0x4A4 */ u8 field_0x4A4[0x4C0 - 0x4A4]; /* 0x4C0 */ STATE_MGR_DECLARE(dAcNpc_c); /* 0x4FC */ u8 field_0x4FC[0x684 - 0x4FC]; /* 0x684 */ u8 field_0x684; diff --git a/include/d/d_message.h b/include/d/d_message.h index 73293ac4..b832faad 100644 --- a/include/d/d_message.h +++ b/include/d/d_message.h @@ -37,6 +37,7 @@ public: // Ghidra: ActorEventFlowManager class dFlow_c : dFlowBase_c { +protected: enum BranchValue_e { BRANCH_SELECTED_OPTION_0, BRANCH_SELECTED_OPTION_1, @@ -52,9 +53,9 @@ class dFlow_c : dFlowBase_c { BRANCH_RAND_2, BRANCH_RAND_3, BRANCH_RAND_4, - BRANCH_14, // skipped - BRANCH_15, // skipped - BRANCH_16, // skipped + BRANCH_NPC_1, // handled by subclass + BRANCH_NPC_2, // handled by subclass + BRANCH_NPC_3, // handled by subclass BRANCH_FREE_SPACE_IN_POUCH, BRANCH_18, BRANCH_19, @@ -124,7 +125,7 @@ public: /* vt 0x2C */ virtual bool handleEntry() override; /* vt 0x30 */ virtual bool handleJump() override; /* vt 0x38 */ virtual bool vt_0x38() const { - return 0; + return false; } /* vt 0x3C */ virtual u16 getSwitchChoice(const MsbFlowInfo *element, u16 param) const; /* vt 0x40 */ virtual bool triggerEntryPointChecked(s32 labelPart1, s32 labelPart2); diff --git a/include/toBeSorted/event_manager.h b/include/toBeSorted/event_manager.h index 561490c8..130d54ab 100644 --- a/include/toBeSorted/event_manager.h +++ b/include/toBeSorted/event_manager.h @@ -18,6 +18,7 @@ public: static bool alsoSetAsCurrentEvent(dAcBase_c *actor, Event *event, void *unknown); static dAcObjBase_c *fn_800A08F0(fBase_c::GROUP_TYPE_e); static bool canSkipCurrentEvent(); + static dAcBase_c *getMainActorInEvent(); static EventManager *sInstance; diff --git a/src/d/a/npc/d_a_npc.cpp b/src/d/a/npc/d_a_npc.cpp index fa18bc45..e4421a7f 100644 --- a/src/d/a/npc/d_a_npc.cpp +++ b/src/d/a/npc/d_a_npc.cpp @@ -1,12 +1,120 @@ #include "d/a/npc/d_a_npc.h" +#include "c/c_math.h" +#include "common.h" +#include "d/a/d_a_base.h" +#include "d/a/npc/d_a_npc tke.h" +#include "d/d_message.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/m_mtx.h" +#include "m/m_quat.h" +#include "m/m_vec.h" +#include "nw4r/g3d/res/g3d_resmdl.h" #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" fLiMgBa_c dAcNpc_c::NPC_ACTOR_LIST; +const char *dAcNpc_c::sHeadNodeName = "Head"; +const char *dAcNpc_c::sNeckNodeName = "Neck"; +const char *dAcNpc_c::sSpine2NodeName = "Spine2"; + +bool dFlowNpc_c::handleEventInternal(const MsbFlowInfo *element) { + switch (element->param3) { + case EVENT_SET_ITEM: { + if (mpOwner->doGiveItem(element->param3, element->params1n2)) { + setField0x3C(); + } + return true; + } + case EVENT_EXIT: { + u16 exitId, trial; + extract2xU16Params(element, &exitId, &trial); + if (field_0x10) { + dAcBase_c *ac = EventManager::getMainActorInEvent(); + if (ac != nullptr && ac->profile_name == fProfile::NPC_TKE) { + static_cast(ac)->setFinishFlags(); + } else if (mpOwner->profile_name == fProfile::NPC_TKE) { + static_cast(mpOwner)->setFinishFlags(); + } + } + sExitId = exitId; + if (trial == 1) { + dScGame_c::GetInstance()->triggerExit( + dStage_c::GetInstance()->getCurrRoomId(), sExitId, SpawnInfo::RETAIN_TOD, SpawnInfo::TRIAL + ); + } else { + dScGame_c::GetInstance()->triggerExit( + dStage_c::GetInstance()->getCurrRoomId(), sExitId, SpawnInfo::RETAIN_TOD, SpawnInfo::RETAIN_TRIAL + ); + } + return false; + } + // TODO - more cases + default: { + return dFlow_c::handleEventInternal(element); + } + } +} + +u16 dFlowNpc_c::getSwitchChoice(const MsbFlowInfo *element, u16 param) const { + u16 result = 0; + dAcNpc_c *npc = mpOwner; + u32 arg = element->params1n2; + switch (param) { + case BRANCH_NPC_1: + if (npc != nullptr) { + result = npc->doFlowSwitch1(arg); + } + break; + case BRANCH_NPC_2: + if (npc != nullptr) { + result = npc->doFlowSwitch2(arg); + } + break; + case BRANCH_NPC_3: + if (npc != nullptr) { + result = npc->doFlowSwitch3(arg); + } + break; + default: result = dFlow_c::getSwitchChoice(element, param); break; + } + + return result; +} + +void dFlowNpc_c::triggerEntryPoint(s32 labelPart1, s32 labelPart2) { + setupActorRefs(); + dFlow_c::triggerEntryPoint(labelPart1, labelPart2); +} + +void dFlowNpc_c::triggerEntryPoint(const char *label) { + setupActorRefs(); + dFlow_c::triggerEntryPoint(label); +} + +void dFlowNpc_c::setupActorRefs() { + mObjRefs[0].link(mpOwner); + for (int i = 1; i < (int)ARRAY_LENGTH(mObjRefs); i++) { + mObjRefs[i].unlink(); + } + + for (int i = 0; i < ARRAY_LENGTH(field_0x128); i++) { + field_0x128[i] = 0; + } + field_0x138 = 1; + field_0x13C = 0; +} + STATE_VIRTUAL_DEFINE(dAcNpc_c, Wait); STATE_VIRTUAL_DEFINE(dAcNpc_c, Demo); @@ -36,8 +144,286 @@ SizedString<128> sNpcStr2; SizedString<128> sNpcStr3; SizedString<128> sNpcStr4; -dAcNpc_c::dAcNpc_c() : mStateMgr(*this, sStateID::null), mActorListEntry(this) {} +dAcNpc_c::dAcNpc_c() : mFlow(this), mStateMgr(*this, sStateID::null), mActorListEntry(this) {} dAcNpc_c::~dAcNpc_c() { // TODO } + +u16 dAcNpc_c::doFlowSwitch1(u32 arg) { + return eventFlowSwitch1(arg); +} + +u16 dAcNpc_c::doFlowSwitch2(u32 arg) { + return eventFlowSwitch2(arg); +} + +u16 dAcNpc_c::doFlowSwitch3(u32 arg) { + return eventFlowSwitch3(arg); +} + +bool dAcNpc_c::addHeadNeckSpineCallbacks( + d3d::AnmMdlWrapper *mdl, dNpcMdlCallbackMulti_c *multi, dNpcMdlCallbackBase_c *head, dNpcMdlCallbackBase_c *neck, + dNpcMdlCallbackBase_c *spine +) { + if (!multi->addCallback(head)) { + return false; + } + head->loadNodeId(mdl, sHeadNodeName); + + if (!multi->addCallback(neck)) { + return false; + } + neck->loadNodeId(mdl, sNeckNodeName); + + if (!multi->addCallback(spine)) { + return false; + } + spine->loadNodeId(mdl, sSpine2NodeName); + + return true; +} + +static u32 findNodeId(d3d::AnmMdlWrapper *mdl, const char *nodeName) { + return m3d::getNodeID(mdl->getModel().getResMdl(), nodeName); +} + +void dNpcMdlCallbackBase_c::loadNodeId(d3d::AnmMdlWrapper *mdl, const char *nodeName) { + mNodeId = findNodeId(mdl, nodeName); +} + +void dNpcMdlCallbackBase_c::timingA(nw4r::g3d::ChrAnmResult *result) { + // no-op +} + +void dNpcMdlCallbackBase_c::timingB(mMtx_c *result) { + mVec3_c v1(0.0f, 0.0f, 1.0f); + mVec3_c v2(0.0f, 0.0f, 1.0f); + MTXMultVecSR(*result, v2, v1); + field_0x04 = cM::atan2s(-v1.y, v1.absXZ()); + field_0x06 = cM::atan2s(v1.x, v1.z); + if (mForceCalc || !isDone()) { + apply(result); + } +} + +dNpcMdlCallbackAng_c::dNpcMdlCallbackAng_c() + : mTarget(0, 0, 0), + mNumSteps(2), + mMaxStepSizeYZ(768), + mMinStepSizeYZ(205), + mMaxStepSizeX(252), + mMinStepSizeX(1), + mCurrent(0, 0, 0) { + mScaleZ = 1; + mScaleX = 1; + mScaleY = 1; +} + +void dNpcMdlCallbackAng_c::setMinMaxStepSize(const mAng &max, const mAng &min) { + mMaxStepSizeYZ = max; + mMinStepSizeYZ = min; + mMaxStepSizeX = max; + mMinStepSizeX = min; + if (max < min) { + mMaxStepSizeYZ = min; + mMaxStepSizeX = min; + } +} + +void dNpcMdlCallbackAng_c::setMinMaxStepSizeX(const mAng &max, const mAng &min) { + mMaxStepSizeX = max; + mMinStepSizeX = min; + if (max < min) { + mMaxStepSizeX = min; + } +} + +void dNpcMdlCallbackAng_c::reset() { + s32 zero = 0; + mTarget.set(zero, zero, zero); + mCurrent.set(zero, zero, zero); + mForceCalc = false; +} + +void dNpcMdlCallbackAng_c::resetTarget() { + s32 zero = 0; + mTarget.set(zero, zero, zero); + mForceCalc = false; +} + +void dNpcMdlCallbackAng_c::setTarget(const mAng3_c &target) { + mTarget = target; + mForceCalc = true; +} + +void dNpcMdlCallbackAng_c::setTargetNow(const mAng3_c &target) { + mTarget = target; + mCurrent = target; + mForceCalc = true; +} + +void dNpcMdlCallbackAng_c::finishTarget() { + mCurrent = mTarget; + mForceCalc = true; +} + + +void dNpcMdlCallbackAng_c::calc() { + mAng3_c ang = mCurrent; + + ang.x.step(mTarget.x, mNumSteps, mMaxStepSizeX, mMinStepSizeX); + ang.y.step(mTarget.y, mNumSteps, mMaxStepSizeYZ, mMinStepSizeYZ); + ang.z.step(mTarget.z, mNumSteps, mMaxStepSizeYZ, mMinStepSizeYZ); + + mCurrent = ang; +} + +void dNpcMdlCallbackYXZ_c::apply(mMtx_c *result) const { + result->YrotM(mCurrent.y * getScaleY()); + result->XrotM(mCurrent.x * getScaleX()); + result->ZrotM(mCurrent.z * getScaleZ()); +} + +void dNpcMdlCallbackYXZFixed_c::apply(mMtx_c *result) const { + mMtx_c tmp; + mVec3_c trans; + + result->getTranslation(trans); + + // Yes, this + is needed and sort of makes sense with + // the symmetry below... + tmp.YrotS(+mActorRotation.y); + tmp.YrotM(mCurrent.y * getScaleY()); + tmp.XrotM(mCurrent.x * getScaleX()); + tmp.ZrotM(mCurrent.z * getScaleZ()); + tmp.YrotM(-mActorRotation.y); + + MTXConcat(tmp, *result, *result); + + result->setTranslation(trans); +} + +void dNpcMdlCallbackYXZFixed_c::vt_0x20(const dAcBase_c *ac) { + mActorRotation = ac->rotation; +} + +void dNpcMdlCallbackYZX_c::apply(mMtx_c *result) const { + result->YrotM(mCurrent.y * getScaleY()); + result->ZrotM(mCurrent.x * getScaleX()); + result->XrotM(mCurrent.z * getScaleZ()); +} + +void dNpcMdlCallbackXZY_c::apply(mMtx_c *result) const { + result->XrotM(mCurrent.y * getScaleY()); + result->ZrotM(mCurrent.x * getScaleX()); + result->YrotM(mCurrent.z * getScaleZ()); +} + +void dNpcMdlCallbackQuat_c::calc() { + if (mSlerpFactor < 1.0f) { + sLib::addCalc(&mSlerpFactor, 1.0f, mRatio, mMaxStepSize, mMinStepSize); + } else { + mSlerpFactor = 1.0f; + } +} + +void dNpcMdlCallbackQuat_c::apply(mMtx_c *result) const { + mMtx_c quatMtx; + mQuat_c resultQuat; + mVec3_c trans; + mMtx_c tmp; + + mStart.slerpTo(mTarget, mSlerpFactor, resultQuat); + quatMtx.fromQuat(resultQuat); + + result->getTranslation(trans); + + tmp.YrotS(*mActorRotY); + MTXConcat(tmp, quatMtx, tmp); + tmp.YrotM(-*mActorRotY); + + MTXConcat(tmp, *result, *result); + + result->setTranslation(trans); +} + +dNpcMdlCallbackNode *dNpcMdlCallbackMulti_c::newCallbackNode() { + dNpcMdlCallbackNode *node = new dNpcMdlCallbackNode; + if (node == nullptr) { + return nullptr; + } + node->mpNext = nullptr; + return node; +} + +bool dNpcMdlCallbackMulti_c::createCallbackNode(dNpcMdlCallbackBase_c *cb) { + dNpcMdlCallbackNode *node = newCallbackNode(); + if (node == nullptr) { + return false; + } + mpTail = node; + node->mpCallback = cb; + return true; +} + +void dNpcMdlCallbackMulti_c::clearList() { + dNpcMdlCallbackNode *node = mpHead; + dNpcMdlCallbackNode *next; + if (node != nullptr) { + while (node != nullptr) { + next = node->mpNext; + delete node; + node = next; + } + } +} + +bool dNpcMdlCallbackMulti_c::addCallback(dNpcMdlCallbackBase_c *callback) { + if (mpHead == nullptr) { + if (!createCallbackNode(callback)) { + return false; + } + mpHead = mpTail; + } else { + dNpcMdlCallbackNode *prev = mpTail; + if (!createCallbackNode(callback)) { + return false; + } + prev->mpNext = mpTail; + } + mNumNodes++; + return true; +} + +void dNpcMdlCallbackMulti_c::timingA(u32 nodeId, nw4r::g3d::ChrAnmResult *result, nw4r::g3d::ResMdl mdl) { + if (mpHead == nullptr) { + return; + } + dNpcMdlCallbackNode *node = mpHead; + while (node != nullptr) { + if (nodeId == node->mpCallback->getNodeId()) { + node->mpCallback->timingA(result); + return; + } + node = node->mpNext; + } +} + +void dNpcMdlCallbackMulti_c::timingB(u32 nodeId, nw4r::g3d::WorldMtxManip *manip, nw4r::g3d::ResMdl mdl) { + if (mpHead == nullptr) { + return; + } + dNpcMdlCallbackNode *node = mpHead; + while (node != nullptr) { + if (nodeId == node->mpCallback->getNodeId()) { + node->mpCallback->calc(); + mMtx_c mtx; + manip->GetMtx(mtx); + node->mpCallback->timingB(&mtx); + manip->SetMtx(mtx); + return; + } + node = node->mpNext; + } +} diff --git a/src/d/d_message.cpp b/src/d/d_message.cpp index 2f099177..7dbb76c4 100644 --- a/src/d/d_message.cpp +++ b/src/d/d_message.cpp @@ -735,7 +735,7 @@ bool dFlow_c::handleMessage() { u16 dFlow_c::getSwitchChoice(const MsbFlowInfo *element, u16 param) const { u16 result = 0; - if (param < BRANCH_14 || param > BRANCH_16) { + if (param < BRANCH_NPC_1 || param > BRANCH_NPC_3) { result = (this->*(sBranchHandlers[param]))(element); } return result; @@ -961,9 +961,9 @@ dFlow_c::BranchHandler dFlow_c::sBranchHandlers[] = { &dFlow_c::branchHandler11, // BRANCH_RAND_2 &dFlow_c::branchHandler12, // BRANCH_RAND_3 &dFlow_c::branchHandler13, // BRANCH_RAND_4 - &dFlow_c::branchHandler14, // BRANCH_14 - &dFlow_c::branchHandler15, // BRANCH_15 - &dFlow_c::branchHandler16, // BRANCH_16 + &dFlow_c::branchHandler14, // BRANCH_NPC_1 + &dFlow_c::branchHandler15, // BRANCH_NPC_2 + &dFlow_c::branchHandler16, // BRANCH_NPC_3 &dFlow_c::branchHandler17, // BRANCH_FREE_SPACE_IN_POUCH &dFlow_c::branchHandler18, // BRANCH_18 &dFlow_c::branchHandler19, // BRANCH_19