Merge pull request #334 from lepelog/bee

Bee
This commit is contained in:
robojumper
2026-07-26 19:08:51 +02:00
committed by GitHub
12 changed files with 911 additions and 38 deletions
+83 -32
View File
@@ -2,46 +2,97 @@ _prolog = .text:0x00000000; // type:function size:0x2C scope:global
_epilog = .text:0x00000030; // type:function size:0x2C scope:global
_unresolved = .text:0x00000060; // type:function size:0x4 scope:global
dAcNpcBee_c_classInit__Fv = .text:0x00000070; // type:function size:0xD0
fn_14_140 = .text:0x00000140; // type:function size:0x58
fn_14_1A0 = .text:0x000001A0; // type:function size:0x58
fn_14_200 = .text:0x00000200; // type:function size:0x5C
AcNpcBeeSingleBee__ctor = .text:0x00000260; // type:function size:0x68
fn_14_2D0 = .text:0x000002D0; // type:function size:0x90
AcNpcBeeSingleBee__dtor = .text:0x00000360; // type:function size:0x9C
fn_14_400 = .text:0x00000400; // type:function size:0xD0
AcNpcBee__init = .text:0x000004D0; // type:function size:0x1DC
fn_14_6B0 = .text:0x000006B0; // type:function size:0x8
AcNpcBee__actuallyUpdateSwarmBees = .text:0x000006C0; // type:function size:0x6CC
AcNpcBee__handleBeeCrawlingOnHive = .text:0x00000D90; // type:function size:0x5BC
fn_14_1350 = .text:0x00001350; // type:function size:0xBEC
fn_14_1F40 = .text:0x00001F40; // type:function size:0x1B0
fn_14_20F0 = .text:0x000020F0; // type:function size:0x1B4
AcNpcBee__update = .text:0x000022B0; // type:function size:0x88
AcNpcBee__updateSwarmBeeColliders = .text:0x00002340; // type:function size:0x2E4
fn_14_2630 = .text:0x00002630; // type:function size:0x5C
fn_14_2690 = .text:0x00002690; // type:function size:0x1D4
fn_14_2870 = .text:0x00002870; // type:function size:0x8
fn_14_2880 = .text:0x00002880; // type:function size:0x4
fn_14_2890 = .text:0x00002890; // type:function size:0x4
fn_14_28A0 = .text:0x000028A0; // type:function size:0x8
__ct__11dShpProc1_cFv = .text:0x00000140; // type:function size:0x58
__dt__14dShpProcBase_cFv = .text:0x000001A0; // type:function size:0x58
__dt__11dShpProc1_cFv = .text:0x00000200; // type:function size:0x5C
__ct__18dAcNpcBeeSingleBeeFv = .text:0x00000260; // type:function size:0x68
__dt__15dCcD_Linked_SphFv = .text:0x000002D0; // type:function size:0x90
__dt__18dAcNpcBeeSingleBeeFv = .text:0x00000360; // type:function size:0x9C
createHeap__11dAcNpcBee_cFv = .text:0x00000400; // type:function size:0xD0
create__11dAcNpcBee_cFv = .text:0x000004D0; // type:function size:0x1DC
doDelete__11dAcNpcBee_cFv = .text:0x000006B0; // type:function size:0x8
actuallyUpdateSwarmBees__11dAcNpcBee_cFv = .text:0x000006C0; // type:function size:0x6CC
handleBeeCrawlingOnHive__11dAcNpcBee_cFP18dAcNpcBeeSingleBee = .text:0x00000D90; // type:function size:0x5BC
handleBeeFlyingStates__11dAcNpcBee_cFP18dAcNpcBeeSingleBee = .text:0x00001350; // type:function size:0xBEC
handleBeeRising__11dAcNpcBee_cFP18dAcNpcBeeSingleBee = .text:0x00001F40; // type:function size:0x1B0
handleBeeBlownAway__11dAcNpcBee_cFP18dAcNpcBeeSingleBee = .text:0x000020F0; // type:function size:0x1B4
actorExecute__11dAcNpcBee_cFv = .text:0x000022B0; // type:function size:0x88
updateSwarmBeeColliders__11dAcNpcBee_cFv = .text:0x00002340; // type:function size:0x2E4
draw__11dAcNpcBee_cFv = .text:0x00002630; // type:function size:0x5C
beeCheckWallFloorCollision__11dAcNpcBee_cFP18dAcNpcBeeSingleBee = .text:0x00002690; // type:function size:0x1D4
vt_0x88__11dAcEnBase_cFi = .text:0x00002870; // type:function size:0x8
vt_0x84__11dAcEnBase_cFv = .text:0x00002880; // type:function size:0x4
vt_0x80__11dAcEnBase_cFv = .text:0x00002890; // type:function size:0x4
getObjectListEntry__11dAcEnBase_cFv = .text:0x000028A0; // type:function size:0x8
__dt__11dAcNpcBee_cFv = .text:0x000028B0; // type:function size:0xC4
fn_14_2980 = .text:0x00002980; // type:function size:0x4
fn_14_2990 = .text:0x00002990; // type:function size:0x4
fn_14_29A0 = .text:0x000029A0; // type:function size:0x8
drawXlu__11dShpProc1_cFv = .text:0x00002980; // type:function size:0x4
drawOpa__11dShpProc1_cFv = .text:0x00002990; // type:function size:0x4
@272@__dt__15dCcD_Linked_SphFv = .text:0x000029A0; // type:function size:0x8
_ctors = .ctors:0x00000000; // type:label scope:global
_dtors = .dtors:0x00000000; // type:label scope:global
lbl_14_rodata_0 = .rodata:0x00000000; // type:object size:0xC4 data:float
lbl_14_rodata_0 = .rodata:0x00000000; // type:object size:0x4 data:float
lbl_14_rodata_4 = .rodata:0x00000004; // type:object size:0x4 data:float
lbl_14_rodata_8 = .rodata:0x00000008; // type:object size:0x4 data:float
lbl_14_rodata_c = .rodata:0x0000000C; // type:object size:0x4 data:float
lbl_14_rodata_10 = .rodata:0x00000010; // type:object size:0x4 data:float
lbl_14_rodata_14 = .rodata:0x00000014; // type:object size:0x4 data:float
lbl_14_rodata_18 = .rodata:0x00000018; // type:object size:0x4 data:float
lbl_14_rodata_1c = .rodata:0x0000001C; // type:object size:0x4 data:float
lbl_14_rodata_20 = .rodata:0x00000020; // type:object size:0x4 data:float
lbl_14_rodata_24 = .rodata:0x00000024; // type:object size:0x4 data:float
lbl_14_rodata_28 = .rodata:0x00000028; // type:object size:0x4 data:float
lbl_14_rodata_2c = .rodata:0x0000002C; // type:object size:0x4 data:float
lbl_14_rodata_30 = .rodata:0x00000030; // type:object size:0x4 data:float
lbl_14_rodata_34 = .rodata:0x00000034; // type:object size:0x4 data:float
lbl_14_rodata_38 = .rodata:0x00000038; // type:object size:0x4 data:float
lbl_14_rodata_3c = .rodata:0x0000003C; // type:object size:0x4 data:float
lbl_14_rodata_40 = .rodata:0x00000040; // type:object size:0x4 data:float
lbl_14_rodata_44 = .rodata:0x00000044; // type:object size:0x4 data:float
lbl_14_rodata_48 = .rodata:0x00000048; // type:object size:0x4 data:float
lbl_14_rodata_4c = .rodata:0x0000004C; // type:object size:0x4 data:float
lbl_14_rodata_50 = .rodata:0x00000050; // type:object size:0x4 data:float
lbl_14_rodata_54 = .rodata:0x00000054; // type:object size:0x4 data:float
lbl_14_rodata_58 = .rodata:0x00000058; // type:object size:0x4 data:float
lbl_14_rodata_5c = .rodata:0x0000005C; // type:object size:0x4 data:float
lbl_14_rodata_60 = .rodata:0x00000060; // type:object size:0x4 data:float
lbl_14_rodata_64 = .rodata:0x00000064; // type:object size:0x4 data:float
lbl_14_rodata_68 = .rodata:0x00000068; // type:object size:0x4 data:float
lbl_14_rodata_6c = .rodata:0x0000006C; // type:object size:0x4 data:float
lbl_14_rodata_70 = .rodata:0x00000070; // type:object size:0x4 data:float
lbl_14_rodata_74 = .rodata:0x00000074; // type:object size:0x4 data:float
lbl_14_rodata_78 = .rodata:0x00000078; // type:object size:0x4 data:float
lbl_14_rodata_7c = .rodata:0x0000007C; // type:object size:0x4 data:float
lbl_14_rodata_80 = .rodata:0x00000080; // type:object size:0x4 data:float
lbl_14_rodata_84 = .rodata:0x00000084; // type:object size:0x4 data:float
lbl_14_rodata_88 = .rodata:0x00000088; // type:object size:0x4 data:float
lbl_14_rodata_8c = .rodata:0x0000008C; // type:object size:0x4 data:float
lbl_14_rodata_90 = .rodata:0x00000090; // type:object size:0x4 data:float
lbl_14_rodata_94 = .rodata:0x00000094; // type:object size:0x4 data:float
lbl_14_rodata_98 = .rodata:0x00000098; // type:object size:0x4 data:float
lbl_14_rodata_9c = .rodata:0x0000009C; // type:object size:0x4 data:float
lbl_14_rodata_a0 = .rodata:0x000000A0; // type:object size:0x4 data:float
lbl_14_rodata_a4 = .rodata:0x000000A4; // type:object size:0x4 data:float
lbl_14_rodata_a8 = .rodata:0x000000A8; // type:object size:0x4 data:float
lbl_14_rodata_ac = .rodata:0x000000AC; // type:object size:0x4 data:float
lbl_14_rodata_b0 = .rodata:0x000000B0; // type:object size:0x4 data:float
lbl_14_rodata_b4 = .rodata:0x000000B4; // type:object size:0x4 data:float
lbl_14_rodata_b8 = .rodata:0x000000B8; // type:object size:0x4 data:float
lbl_14_rodata_bc = .rodata:0x000000BC; // type:object size:0x4 data:float
lbl_14_rodata_c0 = .rodata:0x000000C0; // type:object size:0x4 data:float
g_profile_NPC_BEE = .data:0x00000000; // type:object size:0x10 data:4byte
lbl_14_data_10 = .data:0x00000010; // type:object size:0x2C
beeColliderSrc = .data:0x00000010; // type:object size:0x2C
lbl_14_data_3C = .data:0x0000003C; // type:object size:0x6 data:string
lbl_14_data_44 = .data:0x00000044; // type:object size:0x6 data:string
lbl_14_data_4C = .data:0x0000004C; // type:object size:0x7 data:string
lbl_14_data_54 = .data:0x00000054; // type:object size:0x7 data:string
lbl_14_data_60 = .data:0x00000060; // type:object size:0x10 data:4byte
@LOCAL@createHeap__11dAcNpcBee_cFv@sModelNames = .data:0x00000060; // type:object size:0x10 data:4byte
lbl_14_data_70 = .data:0x00000070; // type:object size:0x4 data:string
lbl_14_data_74 = .data:0x00000074; // type:object size:0x28
AcNpcBee__vtable = .data:0x0000009C; // type:object size:0x8C
lbl_14_data_128 = .data:0x00000128; // type:object size:0x70
lbl_14_data_198 = .data:0x00000198; // type:object size:0x58
lbl_14_data_74 = .data:0x00000074; // type:object size:0x19 data:string
lbl_14_data_90 = .data:0x00000090; // type:object size:0x4
lbl_14_data_94 = .data:0x00000094; // type:object size:0x4
lbl_14_data_98 = .data:0x00000098; // type:object size:0x4
__vt__11dAcNpcBee_c = .data:0x0000009C; // type:object size:0x8C
__vt__15dCcD_Linked_Sph = .data:0x00000128; // type:object size:0x70
__vt__11dShpProc1_c = .data:0x00000198; // type:object size:0x58
lbl_14_bss_8 = .bss:0x00000008; // type:object size:0x1 data:byte
lbl_14_bss_C = .bss:0x0000000C; // type:object size:0xC align:4 data:float
@@ -102,7 +102,7 @@ fn_66_2E30 = .text:0x00002E30; // type:function size:0x1C
shouldEndBugMaybeMinigameTooLowHealthMaybeMaybe = .text:0x00002E50; // type:function size:0x70
fn_66_2EC0 = .text:0x00002EC0; // type:function size:0xC0
fn_66_2F80 = .text:0x00002F80; // type:function size:0x138
fn_66_30C0 = .text:0x000030C0; // type:function size:0xB4
fn_66_30C0__16dAcNpcIcgKobun_cFUl = .text:0x000030C0; // type:function size:0xB4
fn_66_3180 = .text:0x00003180; // type:function size:0x174
fn_66_3300 = .text:0x00003300; // type:function size:0x210
fn_66_3510 = .text:0x00003510; // type:function size:0xB4
+1 -1
View File
@@ -17102,7 +17102,7 @@ AcOSpore__stateWaitEnter = .text:0x802D8B50; // type:function size:0x4
AcOSpore__stateWaitUpdate = .text:0x802D8B60; // type:function size:0x304
AcOSpore__stateWaitLeave = .text:0x802D8E70; // type:function size:0x4
fn_802D8E80 = .text:0x802D8E80; // type:function size:0x10
fn_802D8E90 = .text:0x802D8E90; // type:function size:0x8
getListHead__11dAcOSpore_cFv = .text:0x802D8E90; // type:function size:0x8
fBase__deleteRequest3 = .text:0x802D8EA0; // type:function size:0x4
fn_802D8EB0 = .text:0x802D8EB0; // type:function size:0x80
fn_802D8F30 = .text:0x802D8F30; // type:function size:0xE4
+1 -1
View File
@@ -72,7 +72,7 @@ public:
enum AcProperties_e {
AC_PROP_0x1 = (1 << 0),
AC_PROP_0x2 = (1 << 1),
AC_PROP_0x4 = (1 << 2),
AC_PROP_0x4 = (1 << 2), // when set, also update in event
AC_PROP_0x100 = (1 << 8),
AC_PROP_0x400 = (1 << 10),
AC_PROP_0x800 = (1 << 11),
+6
View File
@@ -45,8 +45,14 @@ public:
STATE_FUNC_DECLARE(dAcEbc_c, AAttack);
STATE_FUNC_DECLARE(dAcEbc_c, ADamage);
u8 getField_0x130D() const {
return field_0x130D;
}
private:
/* 0x??? */ STATE_MGR_DECLARE(dAcEbc_c);
/* 0x??? */ u8 field_unk[0xF59];
/* 0x130D */ u8 field_0x130D;
};
#endif
+78 -1
View File
@@ -1,14 +1,91 @@
#ifndef D_A_NPC_BEE_H
#define D_A_NPC_BEE_H
#include "common.h"
#include "d/a/d_a_base.h"
#include "d/a/e/d_a_en_base.h"
#include "d/a/npc/d_a_npc_honeycomb.h"
#include "d/a/obj/d_a_obj_base.h"
#include "d/col/cc/d_cc_d.h"
#include "d/d_cc.h"
#include "m/m3d/m_proc.h"
#include "m/m_angle.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
class dAcOSpore_c;
class dAcNpcBeeSingleBee {
public:
enum State {
BEE_STATE_DEAD = 0,
BEE_STATE_CHASE = 1,
BEE_STATE_FLY_TO_HIVE = 2,
BEE_STATE_FLY_UP = 3,
BEE_STATE_BLOWN_AWAY = 4,
BEE_STATE_RISE = 5,
BEE_STATE_CRAWL = 0xA,
};
/* 0x000 */ u8 mIndex;
/* 0x001 */ u8 mBeeState; // see State enum
/* 0x002 */ u8 mActionTimer;
/* 0x003 */ bool mIsFlying;
/* 0x004 */ u8 field_0x004; // unused
/* 0x005 */ u8 mSubState;
/* 0x006 */ u8 mDisableAttackTimer;
/* 0x007 */ u8 mSwordDodgeTimer;
/* 0x008 */ bool mHide;
/* 0x009 */ u8 mAttackCooldownTimer;
/* 0x00A */ bool mIsAttacking;
/* 0x00B */ u8 mWallReflectTimer;
/* 0x00C */ s16 mTimer; // only counts up, used for kinda random calculations
/* 0x00E */ s16 mFlyingStatesTimer; // used for vanishing after flying up and something else
/* 0x010 */ f32 mCrawlingSpeed;
/* 0x014 */ f32 mSpeed;
/* 0x018 */ mVec3_c mPos;
/* 0x024 */ mVec3_c field_0x024;
/* 0x030 */ mVec3_c mSwordDodgeOffset;
/* 0x03C */ mVec3_c mOldPos;
/* 0x048 */ mVec3_c field_0x048;
/* 0x054 */ mVec3_c mTargetPos; // Either an absolute target or relative to the attacked actor
/* 0x060 */ mAng3_c mCrawlingRotation;
/* 0x066 */ mAng3_c mModelRotation;
/* 0x06C */ dCcD_Linked_Sph mCollider;
};
class dAcNpcBee_c : public dAcEnBase_c {
public:
dAcNpcBee_c() {}
dAcNpcBee_c() : mRes(nullptr) {}
virtual ~dAcNpcBee_c() {}
virtual bool createHeap() override;
virtual int create() override;
virtual int actorExecute() override;
virtual int draw() override;
virtual int doDelete() override;
u32 updateSwarmBeeColliders();
void actuallyUpdateSwarmBees();
void handleBeeCrawlingOnHive(dAcNpcBeeSingleBee *bee);
void handleBeeFlyingStates(dAcNpcBeeSingleBee *bee);
void handleBeeRising(dAcNpcBeeSingleBee *bee);
s32 beeCheckWallFloorCollision(dAcNpcBeeSingleBee *bee);
void handleBeeBlownAway(dAcNpcBeeSingleBee *bee);
private:
/* 0x0378 */ u8 mSwarmBeeCount;
/* 0x0379 */ u8 mRumbleTimer;
/* 0x037A */ u8 mSceneflag;
/* 0x037C */ s16 mFrameCounter; // used to only search for new targets every 16 frames
/* 0x0380 */ f32 mAttackActorDistFromHome;
/* 0x0384 */ u8 field_0x0384[4]; // unused
/* 0x0388 */ nw4r::g3d::ResFile mRes;
/* 0x038C */ dShpProc1_c mBeeModels[4];
/* 0x045C */ dAcNpcBeeSingleBee mBees[100]; // only 20 slots are used
/* 0xB80C */ dAcRef_c<dAcNpcHc_c> mHiveRef;
/* 0xB818 */ dAcRef_c<dAcObjBase_c> mAttackRef;
/* 0xB824 */ dColliderLinkedList mColliderList;
/* 0xB830 */ mVec3_c mAliveBeePos; // overwritten by all alive bees, so it's the last on in the list
/* 0xB83C */ dAcObjBase_c *mAttackActor;
/* 0xB840 */ dAcOSpore_c *mSporeActor;
};
#endif
+7 -1
View File
@@ -2,13 +2,19 @@
#define D_A_NPC_HONEYCOMB_H
#include "d/a/e/d_a_en_base.h"
#include "m/m_vec.h"
class dAcNpcHc_c : public dAcEnBase_c {
public:
dAcNpcHc_c() {}
virtual ~dAcNpcHc_c() {}
private:
// private:
/* 0x378 */ u8 field_0x378[0x915 - 0x378];
/* 0x915 */ u8 field_0x915;
/* 0x916 */ u8 field_0x916;
/* 0x917 */ u8 field_0x917[0x928 - 0x917];
/* 0x928 */ mVec3_c field_0x928;
};
#endif
@@ -8,6 +8,7 @@ class dAcNpcIcgKobun_c : public dAcNpc_c {
public:
dAcNpcIcgKobun_c() : mStateMgr(*this) {}
virtual ~dAcNpcIcgKobun_c() {}
void fn_66_30C0(u32 itemId);
private:
/* 0x??? */ STATE_MGR_DECLARE(dAcNpcIcgKobun_c);
+11
View File
@@ -1,13 +1,24 @@
#ifndef D_A_O_SPORE_H
#define D_A_O_SPORE_H
#include "common.h"
#include "d/a/obj/d_a_obj_base.h"
#include "f/f_list_mg.h"
class dAcOSpore_c : public dAcObjBase_c {
public:
dAcOSpore_c() {}
virtual ~dAcOSpore_c() {}
static fLiNdBa_c *getListHead();
s32 getSporeType() const {
return mParams & 0xF;
}
bool isGlitteringSpore() const {
return getSporeType() == 1;
}
private:
static fLiMgBa_c sSpores;
};
#endif
+4
View File
@@ -276,6 +276,10 @@ public:
return cM::atan2s(y, absXZ());
}
s32 atan2sXZ_Y() const {
return -atan2sY_XZ();
}
f32 angle(const mVec3_c &other) const {
return EGG::Vector3f::angle(other);
}
+6 -1
View File
@@ -6,13 +6,15 @@
#include "m/m_allocator.h"
#include "m/m_mtx.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
#include "nw4r/g3d/res/g3d_resmat.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "nw4r/g3d/res/g3d_resshp.h"
/** a process for drawing shapes directly */
class dShpProcBase_c : public m3d::proc_c {
public:
dShpProcBase_c(): mLightSetId(1) {}
dShpProcBase_c() : mLightSetId(1) {}
virtual ~dShpProcBase_c() {}
void setResMat(nw4r::g3d::ResMat mat);
@@ -59,6 +61,9 @@ public:
}
bool create(nw4r::g3d::ResMat mat, nw4r::g3d::ResShp shp, s32 count, mHeapAllocator_c *alloc, bool xlu, u32 *pSize);
bool create(nw4r::g3d::ResMdl mdl, s32 count, mHeapAllocator_c *alloc, bool xlu, u32 *pSize) {
return create(mdl.GetResMat(0), mdl.GetResShp(0), count, alloc, xlu, pSize);
}
void draw();
void setTransform(s32 idx, const mMtx_c &transform) {
+712
View File
@@ -1,3 +1,715 @@
#include "d/a/npc/d_a_npc_bee.h"
#include "c/c_lib.h"
#include "c/c_math.h"
#include "common.h"
#include "d/a/d_a_itembase.h"
#include "d/a/d_a_player.h"
#include "d/a/e/d_a_e_bc.h"
#include "d/a/npc/d_a_npc_honeycomb.h"
#include "d/a/npc/d_a_npc_insect_capture_game_kobun.h"
#include "d/a/obj/d_a_obj_base.h"
#include "d/a/obj/d_a_obj_spore.h"
#include "d/col/bg/d_bg_s.h"
#include "d/col/bg/d_bg_s_gnd_chk.h"
#include "d/col/bg/d_bg_s_lin_chk.h"
#include "d/col/c/c_cc_d.h"
#include "d/col/cc/d_cc_d.h"
#include "d/d_camera.h"
#include "d/d_player_act.h"
#include "d/d_rumble.h"
#include "d/d_sc_game.h"
#include "d/flag/sceneflag_manager.h"
#include "d/snd/d_snd_wzsound.h"
#include "f/f_base.h"
#include "f/f_manager.h"
#include "f/f_profile_name.h"
#include "m/m_angle.h"
#include "m/m_mtx.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
#include "nw4r/g3d/res/g3d_resmat.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "nw4r/g3d/res/g3d_resshp.h"
#include "nw4r/math/math_arithmetic.h"
#include "nw4r/math/math_triangular.h"
#include "s/s_Math.h"
#include "toBeSorted/d_emitter.h"
#include <cmath>
SPECIAL_ACTOR_PROFILE(NPC_BEE, dAcNpcBee_c, fProfile::NPC_BEE, 0x123, 0, 0);
static dCcD_SrcSph beeColliderSrc = {
/* mObjInf */ {/* mObjAt */ {AT_TYPE_0x2000000, 0x20000F, {0, 0, 0}, 1, 0, 0, 0, 0, 0},
/* mObjTg */ {AT_TYPE_BUGNET | AT_TYPE_BELLOWS | AT_TYPE_BOMB, 0x00004011, {0, 00, 0x40F}, 8, 0},
/* mObjCo */ {0}},
/* mSphInf */
{15.0f}
};
bool dAcNpcBee_c::createHeap() {
mRes = nw4r::g3d::ResFile(getOarcResFile("Bee"));
static const char *sModelNames[4] = {
"fly_A",
"fly_B",
"walk_A",
"walk_B",
};
mSwarmBeeCount = 20;
for (int i = 0; i < (int)ARRAY_LENGTH(sModelNames); i++) {
nw4r::g3d::ResMdl mdl = mRes.GetResMdl(sModelNames[i]);
TRY_CREATE(mBeeModels[i].create(mdl, mSwarmBeeCount, &mAllocator, true, nullptr));
}
return SUCCEEDED;
}
int dAcNpcBee_c::create() {
mSceneflag = getFromParams(0x10, 0xFF);
if (mSceneflag != 0xFF && SceneflagManager::sInstance &&
SceneflagManager::sInstance->checkFlag(getRoomId(), mSceneflag)) {
return FAILED;
}
CREATE_ALLOCATOR(dAcNpcBee_c);
dAcNpcBeeSingleBee *bee = &mBees[0];
for (int i = 0; i < mSwarmBeeCount; i++, bee++) {
bee->mIndex = i;
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_CRAWL;
bee->mPos = mPosition;
bee->mTimer = cM::rndF(65536);
mColliderList.addCc(bee->mCollider, beeColliderSrc);
bee->mCollider.mTg.OffSPrm(0x100);
bee->mCollider.mAt.OnSPrm(0x100);
// hide half of the bees until the hive breaks
if (i < mSwarmBeeCount / 2) {
bee->mHide = true;
}
}
setInteractionFlags(0x80);
mStts.SetRank(3);
mColliderList.SetStts(mStts);
mFrameCounter = cM::rndF(65536);
dAcObjBase_c *honeycomb =
dAcObjBase_c::create(fProfile::NPC_HONEYCOMB, -1, mParams, &mPosition, nullptr, nullptr, -1);
if (honeycomb == nullptr) {
return FAILED;
} else {
mHiveRef.link(static_cast<dAcNpcHc_c *>(honeycomb));
mAttackRef.link(dAcPy_c::GetLinkM());
}
return SUCCEEDED;
}
int dAcNpcBee_c::doDelete() {
return SUCCEEDED;
}
// non matching
void dAcNpcBee_c::actuallyUpdateSwarmBees() {
if (mHiveRef.isLinked()) {
setStartingPosition(mHiveRef.get()->field_0x928);
}
dAcPy_c *player = dAcPy_c::GetLinkM();
if ((mFrameCounter & 0xF) == 0) {
mAttackRef.link(player);
bool noSporeFound = true;
fLiNdBa_c *current = dAcOSpore_c::getListHead();
if (current != nullptr) {
for (; current != nullptr; current = current->getNext()) {
dAcOSpore_c *spore = static_cast<dAcOSpore_c *>(current->p_owner);
if (spore != nullptr && spore->isGlitteringSpore()) {
mVec3_c &sporePos = spore->mPosition;
if (spore->mPosition.squareDistanceToXZ(mAliveBeePos) < 1000000.f &&
std::fabsf(spore->mPosition.y - mAliveBeePos.y) < 500.f) {
if (!dBgS_ObjLinChk::LineCross(&mAliveBeePos, &sporePos, this)) {
mAttackRef.link(spore);
noSporeFound = false;
mSporeActor = spore;
break;
}
}
}
}
}
if (noSporeFound) {
dAcEbc_c *boko = nullptr;
while ((boko = static_cast<dAcEbc_c *>(fManager_c::searchBaseByProfName(fProfile::E_BC, boko)))) {
if (boko->getField_0x130D()) {
continue;
}
f32 distToPlayer = mAliveBeePos.distance(dAcPy_c::GetLink()->mPositionCopy2);
f32 distToBoko = mAliveBeePos.distance(boko->mPositionCopy2);
if (distToBoko < distToPlayer) {
mAttackRef.link(boko);
break;
}
}
}
}
mAttackActor = mAttackRef.get();
if (mAttackActor == nullptr) {
mAttackActor = player;
}
dAcNpcBeeSingleBee *bee = &mBees[0];
u8 beesAlive = 0;
int beeModelIndex = 0;
static mVec3_c colliderDisabledPos(10000.f, -20000.f, 50000.f);
dCamera_c *camera = dScGame_c::getCamera();
bool hideBee;
bool isFirst = true;
int flyingBeeCount = 0;
mAttackActorDistFromHome = mStartingPos.distance(mAttackActor->mPositionCopy2);
mPosition = mStartingPos;
for (u32 i = 0; (s32)i < mSwarmBeeCount; i++, bee++) {
hideBee = true;
mMtx_c mtx;
if (bee->mBeeState != dAcNpcBeeSingleBee::BEE_STATE_DEAD) {
beesAlive++;
bee->mOldPos = bee->mPos;
if (bee->mActionTimer) {
bee->mActionTimer--;
}
if (bee->mDisableAttackTimer) {
bee->mDisableAttackTimer--;
}
if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_CRAWL) {
handleBeeCrawlingOnHive(bee);
bee->mDisableAttackTimer = 5;
} else {
bee->mTimer++;
if (bee->mBeeState <= dAcNpcBeeSingleBee::BEE_STATE_FLY_UP) {
handleBeeFlyingStates(bee);
flyingBeeCount++;
if (isFirst) {
isFirst = false;
mPosition = bee->mPos;
}
} else if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_BLOWN_AWAY) {
handleBeeBlownAway(bee);
} else if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_RISE) {
handleBeeRising(bee);
}
}
mVec3_c localA4;
mVec3_c localB0;
if (!bee->mHide) {
localA4 = bee->mPos - camera->getPosition();
// float constants should be in a different order
if (localA4.absXZ() < 3000.f) {
localA4.normalize();
localB0 = camera->getTarget() - camera->getPosition();
localB0.normalize();
if (localB0.dot(localA4) > 0.5f) {
if (bee->mIsFlying) {
if (bee->mTimer & 1) {
beeModelIndex = 0; // MODEL_FLY_A
} else {
beeModelIndex = 1; // MODEL_FLY_B
}
} else {
beeModelIndex = (bee->mTimer >> 2 & 1) ? 2 /* MODEL_WALK_A */ : 3 /* MODEL_WALK_B */;
}
if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_CRAWL) {
mtx.transS(bee->mPos);
mtx.ZrotM(bee->mCrawlingRotation.x);
mtx.XrotM(bee->mCrawlingRotation.z);
mtx.YrotM(bee->mCrawlingRotation.y);
mtx.XrotM(0x8000);
} else {
mtx.transS(bee->mPos);
mtx.YrotM(bee->mModelRotation.y);
mtx.XrotM(bee->mModelRotation.x);
mtx.ZrotM(bee->mModelRotation.z);
}
hideBee = false;
}
}
}
mAliveBeePos = bee->mPos;
}
for (u8 j = 0; j < ARRAY_LENGTH(mBeeModels); j++) {
if (!hideBee && j == (u8)beeModelIndex) {
mBeeModels[j].setDrawDisabled(i, false);
mBeeModels[j].setTransform(i, mtx);
} else {
mBeeModels[j].setDrawDisabled(i, true);
}
}
if (!hideBee && bee->mDisableAttackTimer == 0) {
bee->mCollider.SetC(bee->mPos);
} else {
bee->mCollider.SetC(colliderDisabledPos);
}
}
if (flyingBeeCount != 0) {
holdSoundWithIntParam(SE_Bee_FLY_LV, flyingBeeCount);
}
mColliderList.registerColliders();
if (!beesAlive) {
deleteRequest();
}
}
void dAcNpcBee_c::handleBeeCrawlingOnHive(dAcNpcBeeSingleBee *bee) {
#define CRAWLING_SUBSTATE_NONMOVING 0
#define CRAWLING_SUBSTATE_MOVE 1
#define CRAWLING_SUBSTATE_FLY 2
#define CRAWLING_SUBSTATE_LAND 3
#define CRAWLING_SUBSTATE_PRE_RISE 4
f32 targetSpeed = 0.0f;
dAcNpcHc_c *hive = mHiveRef.get();
if (hive == nullptr || hive->mHealth == 0) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_DEAD;
} else {
if (bee->mHide) {
if (hive->mHealth == 1) {
bee->mHide = false;
bee->field_0x024.x = cM::rndFX(300.f);
bee->field_0x024.z = cM::rndFX(300.f);
} else {
bee->mPos = mStartingPos;
return;
}
}
if (dAcPy_c::GetLink()->getRidingActorType() != daPlayerActBase_c::RIDING_LOFTWING &&
(mAttackActor->getPosition().y - getPosition().y) < 0.f && bee->mSubState != CRAWLING_SUBSTATE_PRE_RISE) {
// using getSpeed inline breaks the match
f32 aggroDistance = mAttackActor->mSpeed * 20.f + 350.f;
if (hive->field_0x915 >= 5 || hive->mHealth == 1 ||
(hive->field_0x916 == 0 && mAttackActorDistFromHome < aggroDistance)) {
bee->mSubState = CRAWLING_SUBSTATE_PRE_RISE;
bee->mActionTimer = cM::rndF(15.f);
} else if (bee->mSubState != CRAWLING_SUBSTATE_FLY && hive->field_0x915 != 0) {
bee->mActionTimer = cM::rndF(70.f) + 30.f;
bee->mSubState = CRAWLING_SUBSTATE_FLY;
}
}
bee->mIsFlying = false;
mVec3_c local_74;
local_74 = bee->mTargetPos - bee->field_0x024;
if (bee->mSubState == CRAWLING_SUBSTATE_NONMOVING) {
bee->mCrawlingSpeed = 0.f;
if (bee->mActionTimer == 0) {
if (cM::rnd() < 0.02f) {
bee->mActionTimer = cM::rndF(70.f) + 30.f;
bee->mSubState = CRAWLING_SUBSTATE_FLY;
} else {
bee->mActionTimer = cM::rndF(30.f) + 5.f;
bee->mTargetPos.x = cM::rndFX(300.f);
bee->mTargetPos.z = cM::rndFX(300.f);
bee->mSubState = CRAWLING_SUBSTATE_MOVE;
}
}
} else if (bee->mSubState == CRAWLING_SUBSTATE_MOVE) {
bee->mTimer++;
sLib::addCalcAngle(bee->mCrawlingRotation.y.ref(), local_74.atan2sX_Z(), 2, 0x400);
if (bee->mActionTimer == 0 || local_74.absXZ() < 10.f) {
bee->mSubState = CRAWLING_SUBSTATE_NONMOVING;
bee->mActionTimer = cM::rndF(15.f) + 2.f;
}
targetSpeed = 2.f;
} else if (bee->mSubState == CRAWLING_SUBSTATE_FLY) {
bee->mIsFlying = true;
sLib::addCalcScaledDiff(&bee->mCrawlingSpeed, 50.f, 0.1f, 5.f);
sLib::addCalcAngle(bee->mCrawlingRotation.y.ref(), local_74.atan2sX_Z(), 2, 0x800);
if ((bee->mActionTimer & 0x7) == 0) {
bee->mTargetPos.x = cM::rndFX(300.f);
bee->mTargetPos.z = cM::rndFX(300.f);
}
if (bee->mActionTimer == 0) {
bee->mSubState = CRAWLING_SUBSTATE_LAND;
}
targetSpeed = 5.f;
} else if (bee->mSubState == CRAWLING_SUBSTATE_LAND) {
bee->mIsFlying = true;
sLib::addCalcScaled(&bee->mCrawlingSpeed, 1.f, 5.f);
if (bee->mCrawlingSpeed <= 0.1f) {
bee->mSubState = CRAWLING_SUBSTATE_NONMOVING;
}
} else if (bee->mSubState == CRAWLING_SUBSTATE_PRE_RISE && bee->mActionTimer == 0) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_RISE;
bee->mSubState = 0;
}
sLib::addCalcScaledDiff(&bee->mSpeed, targetSpeed, 0.5f, 0.5f);
mMtx_c mtx;
mtx.YrotS(bee->mCrawlingRotation.y);
local_74.set(0.f, 0.f, bee->mSpeed);
mtx.multVec(local_74, bee->field_0x048);
bee->field_0x024 += bee->field_0x048;
s16 xRot = -bee->field_0x024.x * 32768.f / 200.f;
s16 zRot = bee->field_0x024.z * 32768.f / 200.f;
local_74.set(0.f, -68.f - bee->mCrawlingSpeed, 0.f);
mtx.scaleS(1.f, 1.15f, 1.f);
mtx.YrotM(hive->mRotation.y);
mtx.ZrotM(xRot);
mtx.XrotM(zRot);
mtx.multVec(local_74, bee->mPos);
bee->mPos += mStartingPos;
if (!bee->mIsFlying) {
sLib::addCalcAngle(bee->mCrawlingRotation.x.ref(), xRot, 2, 0x800);
sLib::addCalcAngle(bee->mCrawlingRotation.z.ref(), zRot, 2, 0x800);
} else {
bee->mTimer++;
sLib::addCalcAngle(bee->mCrawlingRotation.x.ref(), 0, 1, 0x1000);
sLib::addCalcAngle(bee->mCrawlingRotation.z.ref(), -0x8000, 1, 0x1000);
}
}
}
// non matching
void dAcNpcBee_c::handleBeeFlyingStates(dAcNpcBeeSingleBee *bee) {
bee->mIsFlying = true;
dAcNpcHc_c *hive = mHiveRef.get();
bee->mCollider.ClrAtSet();
bool isFlyingAway = false;
bool isAttacking = false;
bool dodgedSword;
mMtx_c mtx;
mVec3_c offsetToTarget;
mVec3_c local_98;
if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_CHASE) {
if (bee->mAttackCooldownTimer != 0) {
bee->mAttackCooldownTimer--;
}
if (bee->mSwordDodgeTimer != 0) {
bee->mSwordDodgeTimer--;
bee->mPos += bee->mSwordDodgeOffset;
bee->mSwordDodgeOffset *= 0.8f;
} else {
if (mAttackActor == dAcPy_c::GetLink() && dAcPy_c::GetLink()->checkFlags0x354(4) &&
bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_CHASE) {
dodgedSword = false;
local_98 = dAcPy_c::GetLink()->getPosition() - bee->mPos;
if (local_98.squareMagXZ() < 90000.f) {
if (dAcPy_c::GetLink()->getSpecificAttackDirection() ==
(s16)daPlayerActBase_c::ATTACK_DIRECTION_LEFT ||
dAcPy_c::GetLink()->getSpecificAttackDirection() ==
(s16)daPlayerActBase_c::ATTACK_DIRECTION_RIGHT) {
local_98.y += 150.f;
if (std::fabsf(local_98.y) < 50.f) {
if (local_98.y < 0.f) {
bee->mSwordDodgeOffset.y = 10.f;
} else {
bee->mSwordDodgeOffset.y = -10.f;
}
bee->mSwordDodgeOffset.y *= (50.f - std::fabsf(local_98.y)) * (cM::rndF(0.02f) + 0.02f);
bee->mSwordDodgeOffset.x = cM::rndFX(5.f);
bee->mSwordDodgeOffset.z = cM::rndFX(5.f);
dodgedSword = true;
}
} else {
mtx.YrotS(-dAcPy_c::GetLink()->mRotation.y);
mtx.multVec(local_98, local_98);
f32 xAbs = std::fabsf(local_98.x);
if (xAbs < 130.f) {
if (local_98.x > 0.f) {
local_98.x = -15.f;
} else {
local_98.x = 15.f;
}
local_98.x *= (130.f - xAbs) * (cM::rndF(0.005f) + 0.005f);
local_98.y = cM::rndFX(7.f);
local_98.z = cM::rndFX(7.f);
mtx.YrotS(dAcPy_c::GetLink()->mRotation.y);
mtx.multVec(local_98, bee->mSwordDodgeOffset);
dodgedSword = true;
}
}
if (dodgedSword) {
bee->mActionTimer = bee->mSwordDodgeTimer = cM::rndF(5.f) + 10.f;
bee->mSpeed = 0.f;
}
}
}
}
offsetToTarget = mAttackActor->mPositionCopy2 - bee->mPos;
f32 distToTarget = offsetToTarget.squareMagXZ();
// targeted actor is less than 300 units away and not moving
if (distToTarget < 90000.f && mAttackActor->getSpeed() < 10.f) {
if ((bee->mAttackCooldownTimer != 0 && bee->mSpeed > 10.f) || distToTarget < 400.f) {
bee->mActionTimer = 0;
}
if (bee->mActionTimer == 0) {
bee->mIsAttacking = false;
if (bee->mAttackCooldownTimer != 0 || cM::rnd() < 0.95f) {
// don't actually attack
bee->mSpeed = cM::rndF(5.f) + 5.f;
bee->mTargetPos.x = cM::rndFX(200.f);
bee->mTargetPos.y = cM::rndFX(50.f);
bee->mTargetPos.z = cM::rndF(50.f) + 100.f;
mtx.YrotS(mAttackActor->mRotation.y);
mtx.multVec(bee->mTargetPos, bee->mTargetPos);
bee->mActionTimer = cM::rndF(15.f) + 15.f;
} else {
// attack
bee->mSpeed = cM::rndF(5.f) + 17.f;
bee->mTargetPos.x = 0.f;
bee->mTargetPos.y = 0.f;
bee->mTargetPos.z = 0.f;
bee->mActionTimer = 20;
bee->mIsAttacking = true;
isAttacking = true;
}
}
} else {
bee->mIsAttacking = false;
if (bee->mActionTimer == 0) {
bee->mActionTimer = cM::rndF(15.f) + 15.f;
bee->mSpeed = cM::rndF(5.f) + 17.f + 2.f;
bee->mTargetPos.x = cM::rndFX(100.f);
bee->mTargetPos.y = cM::rndFX(50.f);
bee->mTargetPos.z = cM::rndFX(100.f);
}
bee->mAttackCooldownTimer = 80;
}
offsetToTarget += bee->mTargetPos;
f32 maxDist = 1000000.f;
if ((bee->mFlyingStatesTimer == 0 || distToTarget > maxDist) ||
(mAttackActor == dAcPy_c::LINK && dAcPy_c::LINK->checkActionFlags(0x40000))) {
if (mSporeActor == mAttackActor || (hive != nullptr && mAttackActorDistFromHome < 300.f)) {
bee->mFlyingStatesTimer = cM::rndF(30.f) + 20.f;
} else {
if (hive != nullptr) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_FLY_TO_HIVE;
bee->mTargetPos = mStartingPos;
} else {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_FLY_UP;
mtx.YrotS(cM::rndF(65536.f));
offsetToTarget.y = cM::rndF(2000.f) + 6000.f;
offsetToTarget.x = 0.f;
offsetToTarget.z = 8000.f;
mtx.multVec(offsetToTarget, local_98);
bee->mTargetPos = local_98 + mAttackActor->mPositionCopy2;
bee->mFlyingStatesTimer = cM::rndF(55.f) + 200.f;
}
bee->mSpeed = cM::rndF(5.f) + 17.f;
bee->mIsAttacking = false;
}
}
if (bee->mSpeed >= 10.f && mSporeActor != mAttackActor) {
bee->mCollider.OnAtSet();
}
} else if (
bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_FLY_TO_HIVE ||
bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_FLY_UP
) {
isFlyingAway = true;
offsetToTarget = bee->mTargetPos - bee->mPos;
f32 distToTarget;
f32 fVar17;
if (hive != nullptr) {
fVar17 = hive->mScale.x * 55.f;
} else {
fVar17 = 55.f;
}
distToTarget = offsetToTarget.mag();
if (fVar17 < 55.f) {
fVar17 = 55.f;
}
if (distToTarget < fVar17) {
if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_FLY_TO_HIVE) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_CRAWL;
bee->mSpeed = 0.f;
}
} else {
if (distToTarget > 500.f) {
distToTarget = 500.f;
}
// seems fake, I suspect there is an inline that takes s16
offsetToTarget.x += distToTarget * nw4r::math::SinIdx((s16)(bee->mTimer * 0x400));
offsetToTarget.y += distToTarget * nw4r::math::CosIdx(bee->mTimer * 0x300) * 0.5f;
offsetToTarget.z += distToTarget * nw4r::math::CosIdx(bee->mTimer * 0x500);
}
if (bee->mBeeState == dAcNpcBeeSingleBee::BEE_STATE_FLY_UP && bee->mFlyingStatesTimer == 0) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_DEAD;
}
}
if (bee->mWallReflectTimer == 0) {
if (isAttacking) {
bee->mCrawlingRotation.y = offsetToTarget.atan2sX_Z();
bee->mCrawlingRotation.x = offsetToTarget.atan2sXZ_Y();
} else {
s32 fVar17 = nw4r::math::SinIdx(bee->mTimer * 3500) * 1500.f;
s32 fVar16 = nw4r::math::SinIdx(bee->mTimer * 3000) * 1500.f;
sLib::addCalcAngle(bee->mCrawlingRotation.y.ref(), fVar17 + cM::atan2s(offsetToTarget.x, offsetToTarget.z), 1, 0x1000);
sLib::addCalcAngle(bee->mCrawlingRotation.x.ref(), fVar16 - cM::atan2s(offsetToTarget.y, offsetToTarget.absXZ()), 1, 0x1000);
}
}
mtx.YrotS(bee->mCrawlingRotation.y);
mtx.XrotM(bee->mCrawlingRotation.x);
offsetToTarget.set(0.f, 0.f, bee->mSpeed);
mtx.multVec(offsetToTarget, bee->field_0x048);
bee->mPos += bee->field_0x048;
if (bee->mFlyingStatesTimer != 0) {
bee->mFlyingStatesTimer--;
}
if (isFlyingAway) {
sLib::addCalcAngle(bee->mModelRotation.y.ref(), bee->mCrawlingRotation.y, 2, 0x800);
sLib::addCalcAngle(bee->mModelRotation.x.ref(), bee->mCrawlingRotation.x, 2, 0x800);
} else {
local_98 = mAttackActor->mPositionCopy2 - bee->mPos;
s16 sVar15 = local_98.atan2sX_Z();
sLib::addCalcAngle(bee->mModelRotation.y.ref(), sVar15, 2, 0x1000);
if (bee->mIsAttacking) {
sLib::addCalcAngle(bee->mModelRotation.x.ref(), -0x4000, 2, 0x1000);
} else {
sLib::addCalcAngle(bee->mModelRotation.x.ref(), 0, 2, 0x1000);
}
}
if (bee->mWallReflectTimer == 0) {
// if wall hit
// potential @bug, doesn't catch when both wall and floor are hit
if (beeCheckWallFloorCollision(bee) == 2) {
bee->mWallReflectTimer = cM::rndF(5.f) + 10.f;
bee->mCrawlingRotation.y += ((s16)cM::rndFX(8000.f)) + 0x8000;
}
} else {
bee->mWallReflectTimer--;
}
if ((bee->mTimer & 0xF) == 0 && cM::rnd() < 0.5f) {
bee->mCrawlingRotation.z = cM::rndFX(5000.f);
}
sLib::addCalcAngle(bee->mModelRotation.z.ref(), bee->mCrawlingRotation.z, 2, 0x200);
}
void dAcNpcBee_c::handleBeeRising(dAcNpcBeeSingleBee *bee) {
bee->mIsFlying = true;
switch (bee->mSubState) {
case 0: {
bee->mTargetPos = mStartingPos + (bee->mPos - mStartingPos) * (cM::rndF(0.5f) + 1.5f);
bee->mActionTimer = 20;
bee->mSubState = 1;
// fallthrough
}
case 1: {
cLib::addCalcPos2(&bee->mPos, bee->mTargetPos, 0.2f, 15.0f);
sLib::addCalcAngle(
bee->mCrawlingRotation.y.ref(), cLib::targetAngleY(bee->mPos, mAttackActor->mPositionCopy2), 2, 0x800
);
sLib::addCalcAngle(bee->mCrawlingRotation.x.ref(), 0, 2, 0x800);
sLib::addCalcAngle(bee->mCrawlingRotation.z.ref(), 0, 2, 0x800);
if (bee->mActionTimer == 0) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_CHASE;
bee->mSubState = 0;
bee->mFlyingStatesTimer = cM::rndF(155.f) + 300.f;
}
}
}
}
void dAcNpcBee_c::handleBeeBlownAway(dAcNpcBeeSingleBee *bee) {
bee->mPos += bee->field_0x048;
bee->mPos.x += nw4r::math::SinIdx(bee->mTimer * 0x900) * 10.f;
bee->mPos.y += nw4r::math::SinIdx(bee->mTimer * 0xa00) * 10.f;
bee->mPos.z += nw4r::math::SinIdx(bee->mTimer * 0xb00) * 10.f;
if (bee->mIndex & 1) {
bee->mModelRotation.y += 0xD00;
} else {
bee->mModelRotation.y -= 0xD00;
}
bee->mModelRotation.x += 0xA00;
if (bee->mActionTimer == 0) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_CHASE;
bee->mSubState = 0;
bee->mFlyingStatesTimer = cM::rndF(155.f) + 300.f;
}
beeCheckWallFloorCollision(bee);
}
int dAcNpcBee_c::actorExecute() {
mFrameCounter++;
updateSwarmBeeColliders();
actuallyUpdateSwarmBees();
if (mRumbleTimer) {
mRumbleTimer--;
if (mRumbleTimer == 7) {
dRumble_c::start(dRumble_c::sRumblePreset1, 1);
} else if (mRumbleTimer == 5) {
dRumble_c::stop(-1);
}
}
return SUCCEEDED;
}
u32 dAcNpcBee_c::updateSwarmBeeColliders() {
mMtx_c mtx;
mtx.YrotS(dAcPy_c::LINK->mRotation.y);
dAcNpcBeeSingleBee *bee = &mBees[0];
for (int i = 0; i < mSwarmBeeCount; i++, bee++) {
if (bee->mBeeState != dAcNpcBeeSingleBee::BEE_STATE_DEAD) {
if (bee->mCollider.ChkTgHit()) {
if (bee->mCollider.ChkTgAtHitType(AT_TYPE_BUGNET)) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_DEAD;
dAcPy_c::LINK->bugNetCollectTreasure(ITEM_DEKU_HORNET);
dAcNpcIcgKobun_c *npc =
static_cast<dAcNpcIcgKobun_c *>(fManager_c::searchBaseByProfName(fProfile::NPC_ICGK));
if (npc != nullptr) {
npc->fn_66_30C0(ITEM_DEKU_HORNET);
}
} else if (bee->mCollider.ChkTgAtHitType(AT_TYPE_BOMB)) {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_DEAD;
dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_394_, bee->mPos, nullptr, nullptr, nullptr, nullptr, 0, 0
);
} else {
bee->mBeeState = dAcNpcBeeSingleBee::BEE_STATE_BLOWN_AWAY;
bee->field_0x048 = bee->mCollider.GetTgAtHitDir();
bee->field_0x048.normalize();
if (bee->mCollider.ChkTgAtHitType(AT_TYPE_BELLOWS)) {
bee->field_0x048 *= cM::rndF(5.f) + 15.f;
bee->mActionTimer = cM::rndF(5.f) + 15.f;
mRumbleTimer |= 8;
} else {
// can this even be reached? all possible AT types should be handled
bee->field_0x048 *= cM::rndF(5.f) + 25.f;
bee->field_0x048.y = cM::rndF(5.f) + 15.f;
mVec3_c local_b8(cM::rndFX(20.f), 0.f, 0.f);
mtx.multVec(local_b8, local_b8);
bee->field_0x048 += local_b8;
bee->mActionTimer = cM::rndF(50.f) + 200.f;
}
}
}
}
}
return 1;
}
int dAcNpcBee_c::draw() {
dShpProc1_c *model = &mBeeModels[0];
for (int i = 0; i < 4; i++, model++) {
model->entry();
}
return 1;
}
/**
* Returns bits when a collision is detected, 2 is wall, 1 is floor
*/
s32 dAcNpcBee_c::beeCheckWallFloorCollision(dAcNpcBeeSingleBee *bee) {
dBgS_ObjGndChk gndChk;
dBgS_ObjLinChk linChk;
mVec3_c local_148;
mVec3_c scaled;
u32 ret = 0;
local_148 = bee->mPos - bee->mOldPos;
local_148.y = 0.f;
local_148.normalize();
scaled = local_148 * 50.f;
local_148 = bee->mPos + scaled;
linChk.Set(&bee->mPos, &local_148, nullptr);
if (dBgS::GetInstance()->LineCross(&linChk)) {
ret = 2;
bee->mPos.x = linChk.GetLinEnd().x - scaled.x;
bee->mPos.z = linChk.GetLinEnd().z - scaled.z;
}
local_148 = bee->mPos;
local_148.y += 100.f;
gndChk.SetPos(&local_148);
if (bee->mPos.y <= dBgS::GetInstance()->GroundCross(&gndChk) + 15.f) {
// imagine using temp variables...
bee->mPos.y = dBgS::GetInstance()->GroundCross(&gndChk) + 15.f;
ret |= 1;
}
return ret;
}