summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Thomas <42302100+elijah-thomas774@users.noreply.github.com>2026-02-14 17:48:09 -0500
committerGitHub <noreply@github.com>2026-02-14 17:48:09 -0500
commit79bc8e9333b173face96617164f21f97983c5286 (patch)
tree817c9a2d4fb95589912ca7ea387103a6f8e9410a
parentb2d191f4a4fe8c2528ecc8af5ef5782a318e680b (diff)
parent3c3585efeb19390cd83883b8e2d8043bee52c6c0 (diff)
Merge pull request #294 from lepelog/d_t_mass_obj
d_t_mass_obj 99%
-rw-r--r--config/SOUE01/splits.txt2
-rw-r--r--config/SOUE01/symbols.txt116
-rw-r--r--include/c/c_counter.h16
-rw-r--r--include/d/a/d_a_base.h12
-rw-r--r--include/d/col/c/c_cc_d.h16
-rw-r--r--include/d/col/cc/d_cc_mass_s.h3
-rw-r--r--include/d/d_light_env.h30
-rw-r--r--include/d/d_player_act.h8
-rw-r--r--include/d/t/d_t_mass_obj.h301
-rw-r--r--include/egg/math/eggQuat.h22
-rw-r--r--include/egg/math/eggVector.h4
-rw-r--r--include/m/m_mtx.h5
-rw-r--r--include/nw4r/ut/ut_Color.h12
-rw-r--r--src/d/tg/d_t_mass_object.cpp1481
14 files changed, 1967 insertions, 61 deletions
diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt
index cba06a37..9eaec2c6 100644
--- a/config/SOUE01/splits.txt
+++ b/config/SOUE01/splits.txt
@@ -1539,7 +1539,7 @@ d/tg/d_t_mass_object.cpp:
.rodata start:0x804EE5A8 end:0x804EE6C0
.data start:0x80536478 end:0x80536608
.sbss start:0x80575930 end:0x80575938
- .bss start:0x805B57A8 end:0x805B57C0
+ .bss start:0x805B57A8 end:0x805B57BC
d/tg/d_t_camera.cpp:
.text start:0x8027A0B0 end:0x8027A370 align:16
diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt
index dca5d34b..0aa76de2 100644
--- a/config/SOUE01/symbols.txt
+++ b/config/SOUE01/symbols.txt
@@ -14557,56 +14557,56 @@ initializeState__21sFStateID_c<7dTgSw_c>CFR7dTgSw_c = .text:0x80275280; // type:
__sinit_\d_t_switch_cpp = .text:0x802752B0; // type:function size:0x338 scope:local
__dt__21sFStateID_c<7dTgSw_c>Fv = .text:0x802755F0; // type:function size:0x58 scope:weak
isSameName__21sFStateID_c<7dTgSw_c>CFPCc = .text:0x80275650; // type:function size:0x88 scope:weak
-TgMassObj__ctor = .text:0x802756E0; // type:function size:0x4C
-getCurrentStageGrassSubtype = .text:0x80275730; // type:function size:0x124
-fn_80275860 = .text:0x80275860; // type:function size:0x8
-TgMassObj__init = .text:0x80275870; // type:function size:0x85C
-fn_802760D0 = .text:0x802760D0; // type:function size:0x14
-TgMassObj__destroy = .text:0x802760F0; // type:function size:0xB4
-fn_802761B0 = .text:0x802761B0; // type:function size:0x7C
-TgMassObj__update = .text:0x80276230; // type:function size:0xEC
-TgMassObj__draw = .text:0x80276320; // type:function size:0x74
+dTgMassObj_c_classInit__Fv = .text:0x802756E0; // type:function size:0x4C
+getCurrentStageGrassSubtype__12dTgMassObj_cFv = .text:0x80275730; // type:function size:0x124
+actorCreate__12dTgMassObj_cFv = .text:0x80275860; // type:function size:0x8
+actorPostCreate__12dTgMassObj_cFv = .text:0x80275870; // type:function size:0x85C
+__ct__29TList<18dTgMassObjInstance,0>Fv = .text:0x802760D0; // type:function size:0x14
+doDelete__12dTgMassObj_cFv = .text:0x802760F0; // type:function size:0xB4
+__dt__10GrassModelFv = .text:0x802761B0; // type:function size:0x7C
+actorExecute__12dTgMassObj_cFv = .text:0x80276230; // type:function size:0xEC
+draw__12dTgMassObj_cFv = .text:0x80276320; // type:function size:0x74
unloadRoom__12dTgMassObj_cFUs = .text:0x802763A0; // type:function size:0x60
-fn_80276400 = .text:0x80276400; // type:function size:0x250
-fn_80276650 = .text:0x80276650; // type:function size:0x260
-fn_802768B0 = .text:0x802768B0; // type:function size:0xB4
-fn_80276970 = .text:0x80276970; // type:function size:0x60
-fn_802769D0 = .text:0x802769D0; // type:function size:0x40
-fn_80276A10 = .text:0x80276A10; // type:function size:0x40
-fn_80276A50 = .text:0x80276A50; // type:function size:0x3C8
-fn_80276E20 = .text:0x80276E20; // type:function size:0x20
-fn_80276E40 = .text:0x80276E40; // type:function size:0x3C
-fn_80276E80 = .text:0x80276E80; // type:function size:0x44
-fn_80276ED0 = .text:0x80276ED0; // type:function size:0x288
-fn_80277160 = .text:0x80277160; // type:function size:0x94
-fn_80277200 = .text:0x80277200; // type:function size:0x58
-fn_80277260 = .text:0x80277260; // type:function size:0x74
-fn_802772E0 = .text:0x802772E0; // type:function size:0xD8
-fn_802773C0 = .text:0x802773C0; // type:function size:0x80
-fn_80277440 = .text:0x80277440; // type:function size:0xE0
-fn_80277520 = .text:0x80277520; // type:function size:0xB4
-fn_802775E0 = .text:0x802775E0; // type:function size:0xA0
-fn_80277680 = .text:0x80277680; // type:function size:0x150
-fn_802777D0 = .text:0x802777D0; // type:function size:0x48
-fn_80277820 = .text:0x80277820; // type:function size:0x28
-fn_80277850 = .text:0x80277850; // type:function size:0x1EC
-fn_80277A40 = .text:0x80277A40; // type:function size:0x20C
-fn_80277C50 = .text:0x80277C50; // type:function size:0x1014
-fn_80278C70 = .text:0x80278C70; // type:function size:0x5A0
-fn_80279210 = .text:0x80279210; // type:function size:0x394
-fn_802795B0 = .text:0x802795B0; // type:function size:0xBC
-fn_80279670 = .text:0x80279670; // type:function size:0xC8
-fn_80279740 = .text:0x80279740; // type:function size:0x84
-fn_802797D0 = .text:0x802797D0; // type:function size:0x48
-fn_80279820 = .text:0x80279820; // type:function size:0xD0
-fn_802798F0 = .text:0x802798F0; // type:function size:0x64
-fn_80279960 = .text:0x80279960; // type:function size:0x60
-fn_802799C0 = .text:0x802799C0; // type:function size:0x64
-fn_80279A30 = .text:0x80279A30; // type:function size:0x1D4
-fn_80279C10 = .text:0x80279C10; // type:function size:0x418
-fn_8027A030 = .text:0x8027A030; // type:function size:0x5C
-fn_8027A090 = .text:0x8027A090; // type:function size:0x4
-fn_8027A0A0 = .text:0x8027A0A0; // type:function size:0x4
+initializeCircle__12dTgMassObj_cFP10GrassModelP7mVec3_cP7mVec3_clP6mMtx_clUlUcilUcf = .text:0x80276400; // type:function size:0x250
+initializeBox__12dTgMassObj_cFP10GrassModelP7mVec3_cP7mVec3_ciP6mMtx_ciUlUcilUcf = .text:0x80276650; // type:function size:0x260
+remove__10GrassModelFv = .text:0x802768B0; // type:function size:0xB4
+__dt__14GrassModelDataFv = .text:0x80276970; // type:function size:0x60
+__dt__18dTgMassObjInstanceFv = .text:0x802769D0; // type:function size:0x40
+__dt__19dTgMassObjTransformFv = .text:0x80276A10; // type:function size:0x40
+setModelInfo__10GrassModelFffilUsUsiUclUlP16mHeapAllocator_c = .text:0x80276A50; // type:function size:0x3C8
+__ct__14GrassModelDataFv = .text:0x80276E20; // type:function size:0x20
+__ct__18dTgMassObjInstanceFv = .text:0x80276E40; // type:function size:0x3C
+initResForModel__10GrassModelFlQ34nw4r3g3d6ResMatQ34nw4r3g3d6ResShp = .text:0x80276E80; // type:function size:0x44
+spawnSingleGrass__10GrassModelFiUsP7mVec3_cUsliilUc = .text:0x80276ED0; // type:function size:0x288
+addToRoom__10GrassModelFUllP18dTgMassObjInstance = .text:0x80277160; // type:function size:0x94
+addToFreeInstances__10GrassModelFP18dTgMassObjInstance = .text:0x80277200; // type:function size:0x58
+unloadRoom__10GrassModelFUs = .text:0x80277260; // type:function size:0x74
+update__10GrassModelFv = .text:0x802772E0; // type:function size:0xD8
+draw__10GrassModelFv = .text:0x802773C0; // type:function size:0x80
+aquireTransform__10GrassModelFv = .text:0x80277440; // type:function size:0xE0
+releaseTransform__10GrassModelFP19dTgMassObjTransform = .text:0x80277520; // type:function size:0xB4
+__ct__19dTgMassObjTransformFv = .text:0x802775E0; // type:function size:0xA0
+update__19dTgMassObjTransformFv = .text:0x80277680; // type:function size:0x150
+releaseDynamicTransform__18dTgMassObjInstanceFP10GrassModel = .text:0x802777D0; // type:function size:0x48
+reset__18dTgMassObjInstanceFv = .text:0x80277820; // type:function size:0x28
+getDrawMatrix__18dTgMassObjInstanceFP6mMtx_c = .text:0x80277850; // type:function size:0x1EC
+checkForHit__18dTgMassObjInstanceFP10GrassModelP14GrassModelDataUs = .text:0x80277A40; // type:function size:0x20C
+checkForHit__18dTgMassObjInstanceFUlR15dCcMassS_HitInfP12dAcObjBase_cP10GrassModelP14GrassModelDataUl = .text:0x80277C50; // type:function size:0x1014
+FUN_80278c70__18dTgMassObjInstanceFUlR15dCcMassS_HitInfP9dAcBase_cP10GrassModel = .text:0x80278C70; // type:function size:0x5A0
+handleLinkSpinAttack__18dTgMassObjInstanceFP10GrassModel = .text:0x80279210; // type:function size:0x394
+isHidden__18dTgMassObjInstanceFff = .text:0x802795B0; // type:function size:0xBC
+handleTimeshiftZone__18dTgMassObjInstanceFv = .text:0x80279670; // type:function size:0xC8
+tryCreateLinkedLists__14GrassModelDataFlPQ23EGG4Heap = .text:0x80279740; // type:function size:0x84
+destroyLinkedLists__14GrassModelDataFv = .text:0x802797D0; // type:function size:0x48
+unloadRoom__14GrassModelDataFP10GrassModeli = .text:0x80279820; // type:function size:0xD0
+initRes__14GrassModelDataFQ34nw4r3g3d6ResMatQ34nw4r3g3d6ResShp = .text:0x802798F0; // type:function size:0x64
+addToRoom__14GrassModelDataFlP18dTgMassObjInstance = .text:0x80279960; // type:function size:0x60
+removeFromRoom__14GrassModelDataFlP18dTgMassObjInstance = .text:0x802799C0; // type:function size:0x64
+update__14GrassModelDataFP10GrassModel = .text:0x80279A30; // type:function size:0x1D4
+draw__14GrassModelDataFffPQ34nw4r4math5MTX34 = .text:0x80279C10; // type:function size:0x418
+__dt__12dTgMassObj_cFv = .text:0x8027A030; // type:function size:0x5C
+drawXlu__10GrassModelFv = .text:0x8027A090; // type:function size:0x4
+drawOpa__10GrassModelFv = .text:0x8027A0A0; // type:function size:0x4
TgCamera__ctor = .text:0x8027A0B0; // type:function size:0x4C
TgCamera__init = .text:0x8027A100; // type:function size:0x54
fn_8027A160 = .text:0x8027A160; // type:function size:0x68
@@ -28649,8 +28649,10 @@ lbl_804EE3B8 = .rodata:0x804EE3B8; // type:object size:0xC0 data:4byte
@LOCAL@checkIsClear__9dAcTbox_cCFv@fsIdxes@0 = .rodata:0x804EE478; // type:object size:0xD0 data:4byte
lbl_804EE548 = .rodata:0x804EE548; // type:object size:0x30
lbl_804EE578 = .rodata:0x804EE578; // type:object size:0x30 align:4 data:float
-TgMassObj__GRASS_A_TYPES = .rodata:0x804EE5A8; // type:object size:0xF8 data:4byte
-lbl_804EE6A0 = .rodata:0x804EE6A0; // type:object size:0x20
+GRASS_A_TYPES = .rodata:0x804EE5A8; // type:object size:0x8C data:4byte
+GRASS_MODEL_NAMES = .rodata:0x804EE634; // type:object size:0x3C data:4byte
+GRASS_VECS = .rodata:0x804EE670; // type:object size:0x30 data:4byte
+@LOCAL@FUN_80279c10__14GrassModelDataFffP6mMtx_c@fifoMtx = .rodata:0x804EE6A0; // type:object size:0x20
lbl_804EE6C0 = .rodata:0x804EE6C0; // type:object size:0x40 data:4byte
lbl_804EE700 = .rodata:0x804EE700; // type:object size:0x28 data:4byte
lbl_804EE728 = .rodata:0x804EE728; // type:object size:0x28
@@ -36451,9 +36453,9 @@ lbl_80536500 = .data:0x80536500; // type:object size:0xA data:string
lbl_8053650C = .data:0x8053650C; // type:object size:0xA data:string
lbl_80536518 = .data:0x80536518; // type:object size:0x1A data:string
jumptable_80536534 = .data:0x80536534; // type:object size:0x28 scope:local
-TgMassObj__vtable = .data:0x8053655C; // type:object size:0x74
-lbl_805365D0 = .data:0x805365D0; // type:object size:0x2C
-lbl_805365FC = .data:0x805365FC; // type:object size:0xC
+__vt__12dTgMassObj_c = .data:0x8053655C; // type:object size:0x74
+__vt__10GrassModel = .data:0x805365D0; // type:object size:0x2C
+__vt__14GrassModelData = .data:0x805365FC; // type:object size:0xC
g_profile_CAMERA_TAG = .data:0x80536608; // type:object size:0x10
TgCamera__vtable = .data:0x80536618; // type:object size:0x10
lbl_80536628 = .data:0x80536628; // type:object size:0x68
@@ -42578,7 +42580,7 @@ sCurrentObtainingItemOarcName = .sbss:0x80575918; // type:object size:0x4 data:4
@GUARD@checkIsClear__9dAcTbox_cCFv@offsets = .sbss:0x80575927; // type:object size:0x1 data:byte
lbl_80575928 = .sbss:0x80575928; // type:object size:0x8 data:byte
sInstance__12dTgMassObj_c = .sbss:0x80575930; // type:object size:0x4 data:4byte
-lbl_80575934 = .sbss:0x80575934; // type:object size:0x4 data:4byte
+sAllocator__12dTgMassObj_c = .sbss:0x80575934; // type:object size:0x4 data:4byte
sDisp00ArrowRotation__14dLytPauseMgr_c = .sbss:0x80575938; // type:object size:0x4 align:4 data:float
sDisp00ArrowLength__14dLytPauseMgr_c = .sbss:0x8057593C; // type:object size:0x4 align:4 data:float
sInstance__14dLytPauseMgr_c = .sbss:0x80575940; // type:object size:0x4 data:4byte
@@ -42648,7 +42650,7 @@ Udchuff = .sbss:0x80575B40; // type:object size:0x20 data:4byte
Ydchuff = .sbss:0x80575B60; // type:object size:0x8 data:4byte
sm_numberMemo__10sStateID_c = .sbss:0x80575B68; // type:object size:0x4 data:4byte
sAssertCallback__7sAssert = .sbss:0x80575B70; // type:object size:0x4 data:4byte
-cCounter_c__m_gameFrame = .sbss:0x80575B78; // type:object size:0x4 data:4byte
+m_gameFrame__10cCounter_c = .sbss:0x80575B78; // type:object size:0x4 data:4byte
lbl_80575B7C = .sbss:0x80575B7C; // type:object size:0x4 data:4byte
mFirst__24DynamicModuleControlBase = .sbss:0x80575B80; // type:object size:0x4 data:4byte
mLast__24DynamicModuleControlBase = .sbss:0x80575B84; // type:object size:0x4 data:4byte
@@ -52403,7 +52405,7 @@ StateID_On__7dTgSw_c = .bss:0x805B56F8; // type:object size:0x30 data:4byte
StateID_OffWait__7dTgSw_c = .bss:0x805B5738; // type:object size:0x30 data:4byte
@5126 = .bss:0x805B5768; // type:object size:0xC scope:local
StateID_Off__7dTgSw_c = .bss:0x805B5778; // type:object size:0x30 data:4byte
-lbl_805B57A8 = .bss:0x805B57A8; // type:object size:0x18 data:4byte
+sGrassModels__12dTgMassObj_c = .bss:0x805B57A8; // type:object size:0x14 data:4byte
lbl_805B57C0 = .bss:0x805B57C0; // type:object size:0x10
TgTkEvnt__STATE_WAIT = .bss:0x805B57D0; // type:object size:0x30 data:4byte
lbl_805B5800 = .bss:0x805B5800; // type:object size:0x10
diff --git a/include/c/c_counter.h b/include/c/c_counter.h
new file mode 100644
index 00000000..8efe5f26
--- /dev/null
+++ b/include/c/c_counter.h
@@ -0,0 +1,16 @@
+#ifndef C_COUNTER_H
+#define C_COUNTER_H
+
+#include "common.h"
+
+class cCounter_c {
+public:
+ static s32 GetGameFrame() {
+ return m_gameFrame;
+ }
+
+private:
+ static s32 m_gameFrame;
+};
+
+#endif
diff --git a/include/d/a/d_a_base.h b/include/d/a/d_a_base.h
index ee2350c6..360397b2 100644
--- a/include/d/a/d_a_base.h
+++ b/include/d/a/d_a_base.h
@@ -158,6 +158,9 @@ public:
mVec3_c &getPosition() {
return mPosition;
}
+ mVec3_c const &getPosition() const {
+ return mPosition;
+ }
mAng3_c &getRotation() {
return mRotation;
}
@@ -166,6 +169,11 @@ public:
return mPosition - other.mPosition;
}
+ void getPostionDifferenceOut(const mVec3_c &other, mVec3_c &result) const {
+ mVec3_c diff = (other - mPosition);
+ result = diff;
+ }
+
f32 getHeightDifference(const dAcBase_c &b) const {
return mPosition.y - b.mPosition.y;
}
@@ -194,6 +202,10 @@ public:
return mRoomID == room;
}
+ void setRoomId(u32 room) {
+ mRoomID = room;
+ }
+
void unsetActorProperty(u32 property) {
mActorProperties &= ~property;
}
diff --git a/include/d/col/c/c_cc_d.h b/include/d/col/c/c_cc_d.h
index b4f7f4f2..58bf05e9 100644
--- a/include/d/col/c/c_cc_d.h
+++ b/include/d/col/c/c_cc_d.h
@@ -751,6 +751,13 @@ public:
const mVec3_c &GetAtHitPos() const;
mVec3_c &GetAtHitPos();
+ const mVec3_c &GetAtHitPosInline() const {
+ return mAt.mHitPos;
+ }
+
+ mVec3_c &GetAtHitPosInline() {
+ return mAt.mHitPos;
+ }
bool GetAtFlag0x2() const;
bool GetAtFlag0x4() const;
bool GetAtFlag0x8() const;
@@ -773,6 +780,9 @@ public:
bool ChkTgAtHitType(u32) const;
u32 GetTgAtHitType() const;
+ bool ChkAtType(u32 mask) const {
+ return mAt.MskType(mask);
+ }
bool ChkTgBit14() const;
u8 GetTgDamage() const;
u16 GetTgDamageFlags() const;
@@ -1051,6 +1061,12 @@ public:
u32 ChkCo_0x40000000() {
return mCo.MskSPrm(0x40000000);
}
+ u32 ChkCo_0x10() {
+ return mCo.MskSPrm(0x10);
+ }
+ u32 ChkCo_0x2() {
+ return mCo.MskSPrm(0x2);
+ }
/**
* SET HIT
diff --git a/include/d/col/cc/d_cc_mass_s.h b/include/d/col/cc/d_cc_mass_s.h
index 056ec3cf..581120ea 100644
--- a/include/d/col/cc/d_cc_mass_s.h
+++ b/include/d/col/cc/d_cc_mass_s.h
@@ -63,6 +63,9 @@ public:
cCcD_Obj *GetAtHitObj() const {
return mpAtObj;
}
+ cCcD_Obj *GetCoHitObj() const {
+ return mpCoObj;
+ }
};
class dCcMassS_Mng {
diff --git a/include/d/d_light_env.h b/include/d/d_light_env.h
index 5e48e39e..350a7d9f 100644
--- a/include/d/d_light_env.h
+++ b/include/d/d_light_env.h
@@ -434,6 +434,30 @@ public:
return field_0x2F1C;
}
+ bool getfield_0x38B0() const {
+ return field_0x38B0;
+ }
+
+ void setfield_0x38B0(bool val) {
+ field_0x38B0 = val;
+ }
+
+ f32 getfield_0x38C0() const {
+ return field_0x38C0;
+ }
+
+ const mVec3_c &getfield_0x38B4() const {
+ return field_0x38B4;
+ }
+
+ mVec3_c &getfield_0x38C8() {
+ return field_0x38C8;
+ }
+
+ void setfield_0x38C4(s32 val) {
+ field_0x38C4 = val;
+ }
+
s32 getField_0x38DC() const {
return field_0x38DC;
}
@@ -442,6 +466,10 @@ public:
field_0x38DC = v;
}
+ f32 getfield_0x5D44() const {
+ return field_0x5D44;
+ }
+
void setField_0x5D48(f32 val) {
field_0x5D48 = val;
}
@@ -503,7 +531,7 @@ private:
/* 0x48E4 */ Bpm4 field_0x48E4;
/* 0x5CE4 */ PaletteDefaultMCF field_0x5CE4;
/* 0x5D04 */ TwoPaletteDefaultMCF field_0x5D04;
- /* 0x5D44 */ u8 field_0x5D44[0x5D48 - 0x5D44];
+ /* 0x5D44 */ f32 field_0x5D44;
/* 0x5D48 */ f32 field_0x5D48;
/* 0x5D4C */ u8 field_0x5D4C[0x5D59 - 0x5D4C];
/* 0x5D59 */ struct { // Anonymous until more is known
diff --git a/include/d/d_player_act.h b/include/d/d_player_act.h
index 4d3b9dc2..c8deccaa 100644
--- a/include/d/d_player_act.h
+++ b/include/d/d_player_act.h
@@ -61,8 +61,8 @@ public:
/* vt 0x0C0 */ virtual bool isUsingWhip() const {
return false;
}
- /* vt 0x0C4 */ virtual bool anotherThingWithWhip() {
- return false;
+ /* vt 0x0C4 */ virtual const mVec3_c *anotherThingWithWhip() {
+ return nullptr;
}
/* vt 0x0C8 */ virtual bool somethingWithWHip() {
return false;
@@ -650,6 +650,10 @@ public:
return vt_0x1C0() != nullptr;
}
+ static s32 getCurrentSwordTypeInline() {
+ return sCurrentSword;
+ }
+
static bool isInEvent();
bool isAttackingLeft() const;
bool isAttackingRight() const;
diff --git a/include/d/t/d_t_mass_obj.h b/include/d/t/d_t_mass_obj.h
index bfb7166a..db751857 100644
--- a/include/d/t/d_t_mass_obj.h
+++ b/include/d/t/d_t_mass_obj.h
@@ -1,7 +1,251 @@
#ifndef D_T_MASS_OBJ_H
#define D_T_MASS_OBJ_H
+#include "common.h"
#include "d/t/d_tg.h"
+#include "egg/core/eggHeap.h"
+#include "egg/math/eggQuat.h"
+#include "m/m3d/m_proc.h"
+#include "m/m_angle.h"
+#include "m/m_mtx.h"
+#include "m/m_quat.h"
+#include "m/m_vec.h"
+#include "nw4r/g3d/res/g3d_resmat.h"
+#include "nw4r/g3d/res/g3d_resshp.h"
+#include "nw4r/math/math_types.h"
+#include "rvl/GX/GXTypes.h"
+#include "toBeSorted/tlist.h"
+
+class dTgMassObjInstance;
+class dTgMassObjTransform;
+class GrassModel;
+class GrassModelData;
+class dCcMassS_HitInf;
+class dAcObjBase_c;
+
+typedef TList<dTgMassObjInstance, 0> dTgMassObjInstanceList;
+typedef TList<dTgMassObjTransform, 0> dTgMassObjTransformList;
+
+// a single piece of grass
+// dTgMassObjInstance
+// size: 0x34
+class dTgMassObjInstance {
+public:
+ enum Flags {
+ TG_MASS_UNK2_IS_HIDDEN = 1,
+ TG_MASS_UNK2_IS_CUT = 2,
+ TG_MASS_UNK2_TIMESHIFT_RELATED = 4,
+ };
+ dTgMassObjInstance() {
+ reset();
+ }
+ ~dTgMassObjInstance() {}
+ void reset();
+ void releaseDynamicTransform(GrassModel *param_2);
+ bool checkForHit(GrassModel *param2, GrassModelData *param3, u16 roomid);
+ bool checkForHit(
+ u32 param_2, dCcMassS_HitInf &param_3, dAcObjBase_c *param_4, GrassModel *param_5, GrassModelData *param_6,
+ undefined4 roomid
+ );
+ bool FUN_80278c70(u32 param_2, dCcMassS_HitInf &param_3, dAcBase_c *param_4, GrassModel *param_5);
+ bool handleLinkSpinAttack(GrassModel *param_2);
+ bool handleTimeshiftZone();
+ void getDrawMatrix(mMtx_c *pOut);
+ bool isHidden(f32 param2, f32 param3);
+ bool isItemDrop10() const {
+ return mSpecialItemDropId == 10;
+ }
+
+ // private:
+ /* 0x00 */ TListNode<dTgMassObjInstance> mLink;
+ /* 0x08 */ GXColorS10 mTevColor;
+ /* 0x10 */ mVec3_c mGroundHeight;
+ /* 0x1C */ dTgMassObjTransform *mInitPosTransform;
+ /* 0x20 */ dTgMassObjTransform *mDynamicTransform;
+ /* 0x24 */ f32 field_0x24; // unused?
+ /* 0x28 */ f32 mScale;
+ /* 0x2C */ u16 mGrassFlags;
+ /* 0x2E */ u16 yRotation;
+ /* 0x30 */ u8 mSpecialItemDropId;
+ /* 0x31 */ u8 mLightingCode;
+ /* 0x32 */ u8 mMassObjSubtype;
+ /* 0x33 */ bool mActiveInPresent;
+};
+
+// a transform for a single piece of grass
+// size: 0x50
+class dTgMassObjTransform {
+public:
+ dTgMassObjTransform();
+ ~dTgMassObjTransform() {}
+ void update();
+ const mMtx_c &getMtx() const {
+ return mMtx;
+ }
+
+ void setQuat(const mQuat_c &quat) {
+ mQuat.set(quat);
+ }
+
+ void setMtxFromQuat(const mQuat_c &quat) {
+ mMtx.fromQuat(quat);
+ }
+
+ /* 0x00 */ s32 field_0x00;
+ /* 0x04 */ s32 field_0x04;
+ /* 0x08 */ mMtx_c mMtx;
+ /* 0x38 */ mAng mRotY;
+ /* 0x3A */ mAng mRotX;
+ /* 0x3C */ s16 mRotXSpeed;
+ /* 0x40 */ EGG::Quatf mQuat;
+};
+
+class GrassModelData {
+public:
+ GrassModelData() : mLinkedLists(nullptr) {}
+ virtual ~GrassModelData() {
+ destroyLinkedLists();
+ }
+ void initRes(nw4r::g3d::ResMat pResMat, nw4r::g3d::ResShp pResShp);
+ void addToRoom(s32 room, dTgMassObjInstance *p3);
+ void removeFromRoom(s32 room, dTgMassObjInstance *p3);
+ void update(GrassModel *);
+ bool tryCreateLinkedLists(s32 entrycount, EGG::Heap *heap);
+ void destroyLinkedLists();
+ void unloadRoom(GrassModel *param_2, int roomid);
+ void draw(f32 param_1, f32 param_2, nw4r::math::MTX34 *param_4);
+
+private:
+ /* 0x04 */ nw4r::g3d::ResMat mResMat;
+ /* 0x08 */ nw4r::g3d::ResShp mResShp;
+ /* 0x0C */ dTgMassObjInstanceList *mLinkedLists;
+ /* 0x10 */ u16 mLinkedListsCount;
+};
+
+struct GrassModelInfo {
+ /* 0x00 */ char *mArcName;
+ /* 0x04 */ char *mModelName;
+ /* 0x08 */ char *mCutModelName;
+ /* 0x0C */ u32 field_0x0C;
+ /* 0x10 */ u16 mRadius;
+ /* 0x12 */ u16 field_0x12;
+ /* 0x14 */ u16 mInstanceCount;
+ /* 0x16 */ u16 mStaticTransformCount;
+ /* 0x18 */ u16 mDynamicTransformCount;
+ /* 0x1A */ u8 field_0x1A;
+ /* 0x1B */ u8 field_0x1B; // might be padding
+};
+
+struct GrassModelNames {
+ /* 0x00 */ char *mArcName;
+ /* 0x04 */ char *mModelName;
+ /* 0x08 */ char *mCutModelName;
+};
+
+class GrassModel : public m3d::proc_c {
+public:
+ GrassModel()
+ : mpModelData(nullptr),
+ mInstanceList(nullptr),
+ mStaticTransformationList(nullptr),
+ mDynamicTransformationList(nullptr),
+ mCutCounter(0) {}
+ /* vt 0x08 */ virtual ~GrassModel() {
+ remove();
+ }
+ bool setModelInfo(
+ f32 radius, f32 param_2, int param_4, s32 roomCount, u16 instanceListLength, u16 staticTransformationListLength,
+ int dynamicTransformationListLength, undefined1 param_9, s32 opaDrawPrio, u32 xluDrawPrio,
+ mHeapAllocator_c *allocator
+ );
+ bool spawnSingleGrass(
+ int modelSubtype, u16 roomid, mVec3_c *groundHeight, u16 yRotation, s32 specialItemDropId,
+ int affectedByTimeshift, int activeInPresent, s32 massObjSubtype, u8 lightingCode
+ );
+ void addToFreeInstances(dTgMassObjInstance *param_2);
+ bool addToRoom(u32 param2, s32 roomid, dTgMassObjInstance *param4);
+ void unloadRoom(u16 roomid);
+ void initResForModel(s32 param_2, nw4r::g3d::ResMat pResMat, nw4r::g3d::ResShp pResShp);
+ dTgMassObjTransform *aquireTransform();
+ void update();
+ void releaseTransform(dTgMassObjTransform *);
+ void setModelInfo(const GrassModelInfo *modelInfo, mHeapAllocator_c *heap) {
+ setModelInfo(
+ modelInfo->mRadius, modelInfo->field_0x0C, modelInfo->field_0x12, 0x3F, modelInfo->mInstanceCount,
+ modelInfo->mStaticTransformCount, modelInfo->mDynamicTransformCount, (f32)modelInfo->field_0x1A, 0x7F,
+ 0xFFFFFFFF, heap
+ );
+ }
+
+ void setRadius(f32 r) {
+ mRadius = r;
+ mRadiusSquared = r * r;
+ }
+
+ void setInstanceLength(s32 len) {
+ mInstanceListLength = len;
+ }
+
+ s32 getInstanceListLength() const {
+ return mInstanceListLength;
+ }
+
+ s32 getDynamicTransformListLength() const {
+ return mDynamicTransformationListLength;
+ }
+
+ dTgMassObjInstanceList &getFree() {
+ return mFreeInstances;
+ }
+
+ bool testSpecialItemtype(s32 itemtype) {
+ return itemtype == 10;
+ }
+
+ /* vt 0x10 */ virtual void remove() override;
+ // /* vt 0x14 */ virtual int entry();
+ /* vt 0x18 */ virtual void drawOpa() override {
+ draw();
+ }
+ /* vt 0x1C */ virtual void drawXlu() override {
+ draw();
+ }
+ void draw();
+
+ void calcCutCounter() {
+ mCutCounter = (mCutCounter != 0) ? mCutCounter - 1 : mCutCounter;
+ }
+
+ dTgMassObjTransformList &GetUnk3Too() {
+ return mAquiredTransforms;
+ }
+
+ dTgMassObjTransformList &GetUnk3() {
+ return mAvailableTransforms;
+ }
+
+ // private:
+ /* 0x18 */ GrassModelData *mpModelData;
+ /* 0x1C */ dTgMassObjInstance *mInstanceList;
+ /* 0x20 */ dTgMassObjTransform *mStaticTransformationList;
+ /* 0x24 */ dTgMassObjTransform *mDynamicTransformationList;
+ /* 0x28 */ dTgMassObjInstanceList mFreeInstances;
+ /* 0x34 */ dTgMassObjTransformList mAquiredTransforms;
+ /* 0x40 */ dTgMassObjTransformList mAvailableTransforms;
+ /* 0x4C */ f32 mRadius;
+ /* 0x50 */ f32 mRadiusSquared;
+ /* 0x54 */ f32 field_0x54;
+ /* 0x58 */ u16 field_0x58;
+ /* 0x5A */ u16 mRoomCount;
+ /* 0x5C */ u16 mInstanceListLength;
+ /* 0x5E */ u16 mStaticTransformationListLength;
+ /* 0x60 */ u16 mDynamicTransformationListLength;
+ /* 0x62 */ u8 field_0x62;
+ /* 0x63 */ u8 field_0x63;
+ /* 0x64 */ s16 mCutCounter;
+ /* 0x66 */ u8 field_0x66;
+ /* 0x67 */ u8 field_0x67;
+};
class dTgMassObj_c : public dTg_c {
public:
@@ -12,10 +256,67 @@ public:
return sInstance;
}
+ static u8 getCurrentStageGrassSubtype();
+
void unloadRoom(u16 roomid);
+ int initializeCircle(
+ GrassModel *grassModel, mVec3_c *bbStart, mVec3_c *bbEnd, s32 xzDisplacement, mMtx_c *param_7,
+ s32 specialItemDropId, undefined4 affectedByTimeshift, u8 activeInPresent, int randInt, s32 massObjSubtype,
+ u8 lightingCode, f32 fParam
+ );
+
+ int initializeBox(
+ GrassModel *grassModel, mVec3_c *minVec, mVec3_c *maxVec, int xzDisplacement, mMtx_c *boundsMtx,
+ int specialItemDropId, undefined4 affectedByTimeshift, u8 activeInPresent, int randInt, s32 massObjSubtype,
+ u8 lightingCode, f32 fParam
+ );
+
+ virtual int actorExecute() override;
+ virtual int actorCreate() override;
+ virtual int actorPostCreate() override;
+ virtual int draw() override;
+ virtual int doDelete() override;
+
+ mMtx_c getPreparedMtx() const {
+ mMtx_c mtx;
+ mtx.transS(mPosition);
+ mtx.YrotM(mRotation.y);
+ mtx.scaleM(mScale);
+ mMtx_c mtx2 = mtx;
+ mtx2.inverse();
+ return mtx2;
+ }
+
+ GrassModel *getGrassModel(s32 i) {
+ return sGrassModels[i];
+ }
+
+ void toGlobalRoom() {
+ s8 roomid = getRoomId();
+ addActorToRoom(-1);
+ mRoomID = roomid;
+ }
+
+ s32 getGrassTypeFromParams() {
+ return getFromParams(0, 7);
+ }
+
+ mMtx_c makeBoundsMtx() {
+ mMtx_c mtx;
+ mtx.transS(mPosition);
+ mtx.YrotM(mRotation.y);
+ mtx.scaleM(mScale);
+ return mtx;
+ }
+
private:
static dTgMassObj_c *sInstance;
+ static mHeapAllocator_c *sAllocator;
+ static GrassModel *sGrassModels[5];
+
+ /* 0x0FC */ s32 mMassSubtype;
+ /* 0x100 */ u8 field_0xFC[0x104 - 0x100];
};
#endif
diff --git a/include/egg/math/eggQuat.h b/include/egg/math/eggQuat.h
index a752b229..aa33b73b 100644
--- a/include/egg/math/eggQuat.h
+++ b/include/egg/math/eggQuat.h
@@ -44,10 +44,26 @@ struct Quatf {
Vector3f rotateVector(const Vector3f &);
Vector3f rotateVectorInv(const Vector3f &); // not in SS
void slerpTo(const Quatf &, f32, Quatf &out) const;
+ void slerpTo2(f32 fparam, const Quatf &param1, Quatf &out) const {
+ const Quatf &tmp = param1;
+ slerpTo(tmp, fparam, out);
+ }
void limitSlerpTo(const Quatf &, f32, f32, Quatf &out) const;
void makeVectorRotationLimit(Vector3f &, Vector3f &, f32); // not in SS
void makeVectorRotation(const Vector3f &, const Vector3f &);
+ // not sure about the name
+ f32 dot(const Quatf &other) const {
+ f32 ret = v.dot(other.v);
+ ret += w * other.w;
+ return ret;
+ }
+
+ void set(const Quatf &other) {
+ v.set(other.v);
+ w = other.w;
+ }
+
void multScalar(f32 s) {
w *= s;
v.x *= s;
@@ -58,6 +74,12 @@ struct Quatf {
set(1.0f, 0.0f, 0.0f, 0.0f);
}
+ void makeWPositive() {
+ if (w < 0.f) {
+ multScalar(-1.f);
+ }
+ }
+
Vector3f v;
f32 w;
};
diff --git a/include/egg/math/eggVector.h b/include/egg/math/eggVector.h
index abcf1176..e69f0649 100644
--- a/include/egg/math/eggVector.h
+++ b/include/egg/math/eggVector.h
@@ -1,12 +1,16 @@
#ifndef EGG_VECTOR_H
#define EGG_VECTOR_H
+#include "JSystem/JMath/JMath.h"
#include "common.h"
#include "egg/math/eggMath.h"
+#include "nw4r/math/math_arithmetic.h"
#include "nw4r/math/math_triangular.h"
#include "nw4r/math.h"
+#include <cmath>
+
namespace EGG {
struct Vector3f : public nw4r::math::VEC3 {
diff --git a/include/m/m_mtx.h b/include/m/m_mtx.h
index ac131169..fb18660f 100644
--- a/include/m/m_mtx.h
+++ b/include/m/m_mtx.h
@@ -87,6 +87,11 @@ public:
void inverse() {
MTXInverse(*this, *this);
}
+ mMtx_c copyInverse() {
+ mMtx_c ret = *this;
+ ret.inverse();
+ return ret;
+ }
void multVecZero(nw4r::math::VEC3 &out) const; ///< Converts the matrix to a vector.
void zero(); ///< Zeroes out the matrix.
diff --git a/include/nw4r/ut/ut_Color.h b/include/nw4r/ut/ut_Color.h
index e94ba43a..494d0b89 100644
--- a/include/nw4r/ut/ut_Color.h
+++ b/include/nw4r/ut/ut_Color.h
@@ -2,6 +2,8 @@
#define NW4R_UT_COLOR_H
#include "nw4r/types_nw4r.h"
+#include "rvl/GX/GXTypes.h"
+
#include "rvl/GX.h" // IWYU pragma: export
namespace nw4r {
@@ -61,6 +63,16 @@ public:
operator u32() const {
return ToU32ref();
}
+
+ operator GXColorS10() const {
+ GXColorS10 c;
+ c.r = r;
+ c.g = g;
+ c.b = b;
+ c.a = a;
+ return c;
+ }
+
// clang-format off
static const u32 RED = 0xFF0000FF;
static const u32 GREEN = 0x00FF00FF;
diff --git a/src/d/tg/d_t_mass_object.cpp b/src/d/tg/d_t_mass_object.cpp
new file mode 100644
index 00000000..15cc73b2
--- /dev/null
+++ b/src/d/tg/d_t_mass_object.cpp
@@ -0,0 +1,1481 @@
+#include "c/c_counter.h"
+#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/obj/d_a_obj_base.h"
+#include "d/col/bg/d_bg_s.h"
+#include "d/col/bg/d_bg_s_gnd_chk.h"
+#include "d/col/c/c_cc_d.h"
+#include "d/col/cc/d_cc_mass_s.h"
+#include "d/col/cc/d_cc_s.h"
+#include "d/d_camera.h"
+#include "d/d_heap.h"
+#include "d/d_heap_alloc.h"
+#include "d/d_light_env.h"
+#include "d/d_player_act.h"
+#include "d/d_sc_game.h"
+#include "d/d_stage.h"
+#include "d/d_stage_mgr.h"
+#include "d/snd/d_snd_small_effect_mgr.h"
+#include "d/t/d_t_mass_obj.h"
+#include "egg/core/eggHeap.h"
+#include "egg/math/eggQuat.h"
+#include "f/f_base.h"
+#include "m/m3d/m3d.h"
+#include "m/m3d/m_scnleaf.h"
+#include "m/m_allocator.h"
+#include "m/m_angle.h"
+#include "m/m_color.h"
+#include "m/m_heap.h"
+#include "m/m_mtx.h"
+#include "m/m_quat.h"
+#include "m/m_vec.h"
+#include "nw4r/g3d/g3d_draw1mat1shp.h"
+#include "nw4r/g3d/g3d_scnobj.h"
+#include "nw4r/g3d/g3d_state.h"
+#include "nw4r/g3d/platform/g3d_gpu.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_types.h"
+#include "rvl/GX/GXTev.h"
+#include "rvl/GX/GXTransform.h"
+#include "rvl/GX/GXTypes.h"
+#include "rvl/MTX/mtx.h"
+#include "s/s_Math.h"
+#include "toBeSorted/d_emitter.h"
+#include "toBeSorted/special_item_drop_mgr.h"
+#include "toBeSorted/time_area_mgr.h"
+
+SPECIAL_ACTOR_PROFILE(MASS_OBJ_TAG, dTgMassObj_c, fProfile::MASS_OBJ_TAG, 0x28A, 0, 4);
+
+GrassModel *dTgMassObj_c::sGrassModels[5] = {};
+dTgMassObj_c *dTgMassObj_c::sInstance = nullptr;
+mHeapAllocator_c *dTgMassObj_c::sAllocator = nullptr;
+
+u8 dTgMassObj_c::getCurrentStageGrassSubtype() {
+ u8 ret = 0;
+ if (dStageMgr_c::GetInstance()->isSTIFAreaFaron()) {
+ if (dScGame_c::isCurrentStage("D100") || dScGame_c::isCurrentStage("B100")) {
+ ret = 4;
+ } else {
+ ret = 3;
+ }
+ } else if (dStageMgr_c::GetInstance()->isSTIFAreaEldin()) {
+ ret = 2;
+ } else if (dStageMgr_c::GetInstance()->isSTIFAreaLanayru()) {
+ ret = 1;
+ }
+ if (dScGame_c::isCurrentStage("D003")) {
+ ret = 0;
+ } else if (dScGame_c::isCurrentStage("D003_1") || dScGame_c::isCurrentStage("D003_2")) {
+ ret = 2;
+ } else if (dScGame_c::isCurrentStage("D003_3") || dScGame_c::isCurrentStage("D003_4")) {
+ ret = 1;
+ } else if (dScGame_c::isCurrentStage("D003_5") || dScGame_c::isCurrentStage("D003_6")) {
+ ret = 3;
+ }
+ return ret;
+}
+
+int dTgMassObj_c::actorCreate() {
+ return SUCCEEDED;
+}
+
+static const GrassModelInfo GRASS_A_TYPES[5] = {
+ {
+ "GrassA", "GrassA",
+ "GrassACut", 0x1770,
+ 0x64, 0x2,
+ 0x7D0, 0x8,
+ 0x80, 0,
+ 0, },
+ {
+ "GrassA", "GrassA",
+ "GrassACut", 0x1770,
+ 0x64, 0x2,
+ 0x3E8, 0x8,
+ 0x80, 0,
+ 0, },
+ {
+ "FlowerA00", "FlowerA00",
+ "FlowerA00Cut", 0x1770,
+ 0x64, 0x2,
+ 0x12C, 0x8,
+ 0x20, 0x2,
+ 0, },
+ {
+ "FlowerB00", "FlowerB00",
+ "FlowerB00Cut", 0x1770,
+ 0x64, 0x2,
+ 0x12C, 0x8,
+ 0x20, 0x2,
+ 0, },
+ {
+ "FlowerB01", "FlowerB01",
+ "FlowerB01Cut", 0x1770,
+ 0x64, 0x2,
+ 0x12C, 0x8,
+ 0x20, 0x2,
+ 0, },
+};
+
+static const GrassModelNames GRASS_MODEL_NAMES[5] = {
+ {
+ "GrassA", "GrassA",
+ "GrassACut", },
+ {
+ "GrassB", "GrassB",
+ "GrassBCut", },
+ {
+ "GrassC", "GrassC",
+ "GrassCCut", },
+ {
+ "GrassD", "GrassD",
+ "GrassDCut", },
+ {
+ "GrassE", "GrassE",
+ "GrassECut", },
+};
+
+static const Vec GRASS_VECS[4] = {
+ {
+ -0.5f,
+ 0.5f,-0.5f,
+ },
+ {
+ 0.5f, 0.5f,
+ -0.5f,
+ },
+ {
+ 0.5f, -0.5f,
+ 0.5f, },
+ {
+ -0.5f,
+ -0.5f,
+ 0.5f, },
+};
+
+int dTgMassObj_c::actorPostCreate() {
+ s32 grassModelIndex = getGrassTypeFromParams();
+ s32 retVar = SUCCEEDED;
+ if (sInstance == nullptr) {
+ sInstance = this;
+ toGlobalRoom();
+ sAllocator = new (dHeap::work1Heap.heap) mHeapAllocator_c();
+ for (s32 i = 0; i < 5; i++) {
+ sGrassModels[i] = new (dHeap::work1Heap.heap) GrassModel();
+ }
+ if (!sAllocator->createFrmHeap(
+ 0xFFFFFFFF, dHeap::work1Heap.heap, "dTgMassObj_c::m_allocator", 0x20, mHeap::OPT_NONE
+ )) {
+ return FAILED;
+ }
+ u8 grassSubtype = getCurrentStageGrassSubtype();
+ for (s32 i = 0; i < 5; i++) {
+ const GrassModelInfo *modelInfo;
+ modelInfo = &GRASS_A_TYPES[i];
+ sGrassModels[i]->setModelInfo(modelInfo, sAllocator);
+ if (i == 0) {
+ void *file = dAcObjBase_c::getOarcResFile(GRASS_MODEL_NAMES[grassSubtype].mArcName);
+ nw4r::g3d::ResFile res(file);
+ nw4r::g3d::ResMdl mdl = res.GetResMdl(GRASS_MODEL_NAMES[grassSubtype].mModelName);
+ sGrassModels[i]->initResForModel(0, mdl.GetResMat(0), mdl.GetResShp(0));
+ mdl = res.GetResMdl(GRASS_MODEL_NAMES[grassSubtype].mCutModelName);
+ sGrassModels[i]->initResForModel(1, mdl.GetResMat(0), mdl.GetResShp(0));
+ } else {
+ void *file = dAcObjBase_c::getOarcResFile(modelInfo->mArcName);
+ nw4r::g3d::ResFile res(file);
+ nw4r::g3d::ResMdl mdl = res.GetResMdl(modelInfo->mModelName);
+ sGrassModels[i]->initResForModel(0, mdl.GetResMat(0), mdl.GetResShp(0));
+ mdl = res.GetResMdl(modelInfo->mCutModelName);
+ sGrassModels[i]->initResForModel(1, mdl.GetResMat(0), mdl.GetResShp(0));
+ }
+ }
+ sAllocator->adjustFrmHeap();
+ } else {
+ retVar = 2;
+ }
+ if (grassModelIndex == 0) {
+ grassModelIndex = 0;
+ mMassSubtype = getCurrentStageGrassSubtype();
+ if (getFromParams(3, 1) != 0) {
+ if (getFromParams(0x12, 1) != 0) {
+ mMassSubtype = 1;
+ grassModelIndex = 0;
+ } else {
+ mMassSubtype = 0;
+ grassModelIndex = 1;
+ }
+ }
+ } else if (grassModelIndex == 1) {
+ mMassSubtype = 9;
+ grassModelIndex = 4;
+ } else if (grassModelIndex == 2) {
+ mMassSubtype = 7;
+ grassModelIndex = 2;
+ } else if (grassModelIndex == 3) {
+ if (s32(mParams >> 0x19) == 1) {
+ mMassSubtype = 9;
+ grassModelIndex = 4;
+ } else {
+ mMassSubtype = 8;
+ grassModelIndex = 3;
+ }
+ }
+
+ s32 fromParam4 = getFromParams(4, 0x7F);
+ s32 fromParamB = getFromParams(0xB, 0x7F);
+ s32 affectedByTimeshift = getFromParams(3, 1);
+ s32 activeInPresent = getFromParams(0x12, 1);
+ s32 uVar6 = fromParam4 * 10;
+ f32 xzStep = uVar6;
+ s32 xzDisplacement = xzStep * (fromParamB / 100.f);
+ GrassModel **tmpGrassModel = &sGrassModels[grassModelIndex];
+
+ mMtx_c mtx;
+ mtx.transS(mPosition);
+ mtx.YrotM(mRotation.y);
+ mtx.scaleM(mScale);
+ mMtx_c boundsMtx = mtx.copyInverse();
+ mVec3_c minVec(FLOAT_MAX, FLOAT_MAX, FLOAT_MAX);
+ mVec3_c maxVec(FLOAT_MIN, FLOAT_MIN, FLOAT_MIN);
+
+ const Vec *loop = &GRASS_VECS[0];
+ for (s32 i = 0; i < ARRAY_LENGTH(GRASS_VECS); i++) {
+ mVec3_c mult = mtx * *(loop++);
+ if (mult.x < minVec.x) {
+ minVec.x = mult.x;
+ }
+ if (mult.x > maxVec.x) {
+ maxVec.x = mult.x;
+ }
+ if (mult.y < minVec.y) {
+ minVec.y = mult.y;
+ }
+ if (mult.y > maxVec.y) {
+ maxVec.y = mult.y;
+ }
+ if (mult.z < minVec.z) {
+ minVec.z = mult.z;
+ }
+ if (mult.z > maxVec.z) {
+ maxVec.z = mult.z;
+ }
+ }
+ minVec.x += uVar6 - ((s32)minVec.x % uVar6);
+ minVec.z += uVar6 - ((s32)minVec.z % uVar6);
+ maxVec.x -= (s32)maxVec.x % uVar6;
+ maxVec.z -= (s32)maxVec.z % uVar6;
+ s32 specialItemDropId = getParams2UpperByte();
+ fillUpperParams2Byte();
+ mVec3_c groundCheckPos = mPosition;
+ groundCheckPos.y += 200;
+ u8 lightingCode = dBgS::GetInstance()->GetLightingCode(&groundCheckPos);
+ s32 rnd = 0;
+ // special item drop for farore's tear, unused
+ if (specialItemDropId == 10) {
+ if (getFromParams(0x15, 0xF) == 0) {
+ s32 tmp = initializeCircle(
+ *tmpGrassModel, &minVec, &maxVec, xzDisplacement, &boundsMtx, specialItemDropId, affectedByTimeshift,
+ activeInPresent, -1, mMassSubtype, lightingCode, xzStep
+ );
+ rnd = cM::rndInt(tmp);
+ } else {
+ s32 tmp = initializeBox(
+ *tmpGrassModel, &minVec, &maxVec, xzDisplacement, &boundsMtx, specialItemDropId, affectedByTimeshift,
+ activeInPresent, -1, mMassSubtype, lightingCode, xzStep
+ );
+ rnd = cM::rndInt(tmp);
+ }
+ }
+ if (getFromParams(0x15, 0xF) == 0) {
+ initializeCircle(
+ *tmpGrassModel, &minVec, &maxVec, xzDisplacement, &boundsMtx, specialItemDropId, affectedByTimeshift,
+ activeInPresent, rnd, mMassSubtype, lightingCode, xzStep
+ );
+ } else {
+ initializeBox(
+ *tmpGrassModel, &minVec, &maxVec, xzDisplacement, &boundsMtx, specialItemDropId, affectedByTimeshift,
+ activeInPresent, rnd, mMassSubtype, lightingCode, xzStep
+ );
+ }
+ return retVar;
+}
+
+int dTgMassObj_c::doDelete() {
+ if (sInstance == this) {
+ GrassModel **modelP = sGrassModels;
+ for (s32 i = 0; i < 5; i++, modelP++) {
+ delete *modelP;
+ *modelP = nullptr;
+ }
+ delete sAllocator;
+ sAllocator = nullptr;
+ sInstance = nullptr;
+ }
+ return SUCCEEDED;
+}
+
+int dTgMassObj_c::actorExecute() {
+ dLightEnv_c &lightEnv = dLightEnv_c::GetInstance();
+ if (sInstance == nullptr) {
+ return NOT_READY;
+ } else {
+ dCcS::GetInstance()->GetMassMng().Prepare();
+ GrassModel **modelP = sGrassModels;
+ for (s32 i = 0; i < 5; i++) {
+ if ((cCounter_c::GetGameFrame() & 1) == 0) {
+ (*modelP)->calcCutCounter();
+ }
+ if (lightEnv.getfield_0x5D44() > 0.f) {
+ (*modelP)->setPriorityDraw(0x1C, 0);
+ } else {
+ (*modelP)->setPriorityDraw(0x7F, 0);
+ }
+ (*modelP++)->update();
+ }
+ return SUCCEEDED;
+ }
+}
+
+int dTgMassObj_c::draw() {
+ if (sInstance == nullptr) {
+ return NOT_READY;
+ } else {
+ GrassModel **modelP = sGrassModels;
+ for (s32 i = 0; i < 5; i++) {
+ (*modelP++)->entry();
+ }
+ return SUCCEEDED;
+ }
+}
+
+void dTgMassObj_c::unloadRoom(u16 roomid) {
+ GrassModel **modelP = sGrassModels;
+ for (s32 i = 0; i < 5; i++) {
+ (*modelP++)->unloadRoom(roomid);
+ }
+}
+
+int dTgMassObj_c::initializeCircle(
+ GrassModel *grassModel, mVec3_c *bbStart, mVec3_c *bbEnd, s32 xzDisplacement, mMtx_c *param_7,
+ s32 specialItemDropIdParam, undefined4 affectedByTimeshift, u8 activeInPresent, int randInt, s32 massObjSubtype,
+ u8 lightingCode, f32 fParam
+) {
+ f32 p4z = bbStart->z;
+ s32 iVar3 = 0;
+ while (p4z < bbEnd->z) {
+ f32 p4x = bbStart->x;
+ while (p4x < bbEnd->x) {
+ mVec3_c position(p4x + cM::rndFX(xzDisplacement), bbEnd->y, p4z + cM::rndFX(xzDisplacement));
+ mVec3_c multiplied;
+ param_7->multVec(position, multiplied);
+ mVec3_c nul(0, 0, 0);
+ multiplied.y = 0.f;
+ f32 length = multiplied.distance(nul);
+ if (length < 0.5f && dBgS_ObjGndChk::CheckPos(position) &&
+ dBgS_ObjGndChk::GetGroundHeight() >= (bbStart->y - 100.f)) {
+ if (randInt >= 0) {
+ position.y = dBgS_ObjGndChk::GetGroundHeight();
+ s32 specialItemDropId = specialItemDropIdParam;
+ if (specialItemDropId == 10) {
+ if (randInt == iVar3) {
+ specialItemDropIdParam = 0xFF;
+ } else {
+ specialItemDropId = 0xFF;
+ }
+ }
+ if (!grassModel->spawnSingleGrass(
+ 0, getRoomId(), &position, 0, specialItemDropId, affectedByTimeshift, activeInPresent,
+ massObjSubtype, lightingCode
+ )) {
+ return 0;
+ }
+ }
+ iVar3++;
+ }
+
+ p4x += fParam;
+ }
+ p4z += fParam;
+ }
+ return iVar3;
+}
+
+int dTgMassObj_c::initializeBox(
+ GrassModel *grassModel, mVec3_c *minVec, mVec3_c *maxVec, int xzDisplacement, mMtx_c *boundsMtx,
+ int specialItemDropIdParam, undefined4 affectedByTimeshift, u8 activeInPresent, int randInt, s32 massObjSubtype,
+ u8 lightingCode, f32 fParam
+) {
+ f32 p4z = minVec->z;
+ s32 iVar3 = 0;
+ while (p4z < maxVec->z) {
+ f32 p4x = minVec->x;
+ while (p4x < maxVec->x) {
+ mVec3_c position(p4x + cM::rndFX(xzDisplacement), maxVec->y, p4z + cM::rndFX(xzDisplacement));
+ mVec3_c multiplied;
+ boundsMtx->multVec(position, multiplied);
+ if (-0.5f <= multiplied.x && multiplied.x <= 0.5f && -0.5f <= multiplied.z && multiplied.z <= 0.5f &&
+ dBgS_ObjGndChk::CheckPos(position)) {
+ if (dBgS_ObjGndChk::GetGroundHeight() >= (minVec->y - 100.f)) {
+ if (randInt >= 0) {
+ position.y = dBgS_ObjGndChk::GetGroundHeight();
+ s32 specialItemDropId = specialItemDropIdParam;
+ if (specialItemDropId == 10) {
+ if (randInt == iVar3) {
+ specialItemDropIdParam = 0xFF;
+ } else {
+ specialItemDropId = 0xFF;
+ }
+ }
+ if (!grassModel->spawnSingleGrass(
+ 0, getRoomId(), &position, 0, specialItemDropId, affectedByTimeshift, activeInPresent,
+ massObjSubtype, lightingCode
+ )) {
+ return 0;
+ }
+ }
+ }
+ iVar3++;
+ }
+
+ p4x += fParam;
+ }
+ p4z += fParam;
+ }
+ return iVar3;
+}
+
+void GrassModel::remove() {
+ if (mpModelData != nullptr) {
+ delete[] mpModelData;
+ mpModelData = nullptr;
+ }
+ if (mInstanceList != nullptr) {
+ delete[] mInstanceList;
+ mInstanceList = nullptr;
+ }
+ if (mStaticTransformationList != nullptr) {
+ delete[] mStaticTransformationList;
+ mStaticTransformationList = nullptr;
+ }
+ if (mDynamicTransformationList != nullptr) {
+ delete[] mDynamicTransformationList;
+ mDynamicTransformationList = nullptr;
+ }
+ m3d::scnLeaf_c::remove();
+}
+
+bool GrassModel::setModelInfo(
+ f32 radius, f32 param_2, int param_4, s32 roomCount, u16 instanceListLength, u16 staticTransformationListLength,
+ int dynamicTransformationListLength, undefined1 param_9, s32 opaDrawPrio, u32 xluDrawPrio,
+ mHeapAllocator_c *allocator
+) {
+ if (!create(allocator, nullptr)) {
+ return false;
+ }
+ EGG::Heap *heap = allocator->mHeap;
+ mpModelData = new (heap, 4) GrassModelData[param_4];
+ if (!mpModelData) {
+ remove();
+ return false;
+ }
+ GrassModelData *modelData = &mpModelData[0];
+ for (s32 i = 0; i < param_4; i++) {
+ if (!(modelData++)->tryCreateLinkedLists(roomCount, heap)) {
+ remove();
+ return false;
+ }
+ }
+ mInstanceList = new (heap, 4) dTgMassObjInstance[instanceListLength];
+ if (!mInstanceList) {
+ remove();
+ return false;
+ }
+ mStaticTransformationList = new (heap, 4) dTgMassObjTransform[staticTransformationListLength];
+ if (!mStaticTransformationList) {
+ remove();
+ return false;
+ }
+ mDynamicTransformationList = new (heap, 4) dTgMassObjTransform[dynamicTransformationListLength];
+ if (!mDynamicTransformationList) {
+ remove();
+ return false;
+ }
+ field_0x58 = param_4;
+ mRoomCount = roomCount;
+ mInstanceListLength = instanceListLength;
+ mStaticTransformationListLength = staticTransformationListLength;
+ mDynamicTransformationListLength = dynamicTransformationListLength;
+ mRadius = radius;
+ mRadiusSquared = radius * radius;
+ field_0x54 = param_2;
+ field_0x62 = param_9;
+ {
+ dTgMassObjInstance *itr1 = mInstanceList;
+ s32 i = 0;
+ if (getInstanceListLength() > 0) {
+ for (; i < getInstanceListLength(); i++) {
+ // regswap
+ mFreeInstances.append(itr1++);
+ }
+ }
+ }
+ {
+ dTgMassObjTransform *itr2 = mDynamicTransformationList;
+ s32 i = 0;
+ if (getDynamicTransformListLength() > 0) {
+ for (; i < getDynamicTransformListLength(); i++) {
+ // regswap
+ mAvailableTransforms.append(itr2++);
+ }
+ }
+ }
+ if (opaDrawPrio >= 0) {
+ setPriorityDraw(opaDrawPrio, 0);
+ setOption(nw4r::g3d::ScnObj::OPTION_DISABLE_DRAW_XLU, 1);
+ } else {
+ setPriorityDraw(0, xluDrawPrio);
+ setOption(nw4r::g3d::ScnObj::OPTION_DISABLE_DRAW_OPA, 1);
+ }
+ return true;
+}
+
+void GrassModel::initResForModel(s32 room, nw4r::g3d::ResMat pResMat, nw4r::g3d::ResShp pResShp) {
+ mpModelData[room].initRes(pResMat, pResShp);
+}
+
+// non matching
+bool GrassModel::spawnSingleGrass(
+ int modelSubtype, u16 roomid, mVec3_c *groundHeight, u16 yRotation, s32 specialItemDropId, int affectedByTimeshift,
+ int activeInPresent, s32 massObjSubtype, u8 lightingCode
+) {
+ const dLightEnv_c &lightEnv = dLightEnv_c::GetInstance();
+ if (mFreeInstances.mCount == 0) {
+ return false;
+ }
+ // almost
+ dTgMassObjInstance &first = *mFreeInstances.GetBeginIter();
+ mFreeInstances.remove(&first);
+ first.reset();
+ first.mGroundHeight.set(*groundHeight);
+ first.yRotation = yRotation;
+ first.mSpecialItemDropId = specialItemDropId;
+ first.mDynamicTransform = nullptr;
+ s32 chosen = cM::rndInt(mStaticTransformationListLength);
+ first.mInitPosTransform = &mStaticTransformationList[chosen];
+ first.field_0x24 = cM::rndFX(0.2f) + 1.f;
+ first.mMassObjSubtype = massObjSubtype;
+ first.mLightingCode = lightingCode;
+ first.mTevColor = lightEnv.GetCurrentSpf().mActorPalette.field_0x02C;
+ if (first.mLightingCode == 0) {
+ first.mTevColor.r = 0.7f * first.mTevColor.r;
+ first.mTevColor.r &= 0xFF;
+ first.mTevColor.g = 0.6f * first.mTevColor.g;
+ first.mTevColor.g &= 0xFF;
+ first.mTevColor.b = 0.7f * first.mTevColor.b;
+ first.mTevColor.b &= 0xFF;
+ }
+ if (affectedByTimeshift) {
+ first.mGrassFlags |= dTgMassObjInstance::TG_MASS_UNK2_TIMESHIFT_RELATED;
+ if (activeInPresent) {
+ first.mActiveInPresent = true;
+ } else {
+ first.mScale = 0.f;
+ }
+ }
+ mpModelData[modelSubtype].addToRoom(roomid, &first);
+ return true;
+}
+
+bool GrassModel::addToRoom(u32 modelSubtype, s32 roomid, dTgMassObjInstance *pInstance) {
+ mpModelData[modelSubtype].addToRoom(roomid, pInstance);
+ if (modelSubtype == 1) {
+ SpecialItemDropMgr::GetInstance()->giveSpecialDropItem(
+ pInstance->mSpecialItemDropId, roomid, &pInstance->mGroundHeight, 0, 0, -1
+ );
+ pInstance->mSpecialItemDropId = 0xFF;
+ }
+ return true;
+}
+
+void GrassModel::addToFreeInstances(dTgMassObjInstance *param_2) {
+ mFreeInstances.append(param_2);
+}
+
+void GrassModel::unloadRoom(u16 roomid) {
+ GrassModelData *modelData = mpModelData;
+ for (s32 i = 0; i < field_0x58; i++) {
+ (modelData++)->unloadRoom(this, roomid);
+ }
+}
+
+inline void SetMassMngAttr(f32 radius, f32 height, u8 param_2, u8 param_3) {
+ dCcS::GetInstance()->GetMassMng().SetAttr(radius, height, param_2, param_3);
+}
+
+void GrassModel::update() {
+ dTgMassObjTransform *obj = mStaticTransformationList;
+ for (s32 i = 0; i < mStaticTransformationListLength; obj++, i++) {
+ obj->update();
+ }
+ SetMassMngAttr(mRadius, mRadius * 2, 0xB, field_0x62);
+ GrassModelData *modelData = mpModelData;
+ for (s32 i = 0; i < field_0x58; i++) {
+ (modelData++)->update(this);
+ }
+}
+
+void GrassModel::draw() {
+ nw4r::math::MTX34 cameraMtx;
+ m3d::getCurrentCamera().GetCameraMtx(&cameraMtx);
+ GrassModelData *data = mpModelData;
+ for (s32 i = 0; i < field_0x58; data++, i++) {
+ data->draw(mRadius, field_0x54, &cameraMtx);
+ }
+}
+
+// non matching
+dTgMassObjTransform *GrassModel::aquireTransform() {
+ if (mAvailableTransforms.mCount == 0) {
+ return nullptr;
+ }
+ // not exactly, this produces an additional instruction
+ dTgMassObjTransform &first = *mAvailableTransforms.GetBeginIter();
+ mAvailableTransforms.remove(&first);
+ mAquiredTransforms.append(&first);
+ return &first;
+}
+
+// regalloc, should be equivalent
+void GrassModel::releaseTransform(dTgMassObjTransform *param2) {
+ mAquiredTransforms.remove(param2);
+ mAvailableTransforms.append(param2);
+}
+
+dTgMassObjTransform::dTgMassObjTransform() {
+ field_0x00 = 0;
+ field_0x04 = 0;
+ mRotXSpeed = 0;
+ mRotY = cM::rndInt(0x10000);
+ mRotX = 0x1000;
+ mQuat.setUnit();
+ s32 rnd = cM::rndInt(100);
+ for (s32 i = 0; i < rnd; i++) {
+ update();
+ }
+}
+
+void dTgMassObjTransform::update() {
+ mRotXSpeed -= (s16)(mRotX * 0.005f);
+ mRotXSpeed = cM::minMaxLimit<s16>(mRotXSpeed, -0x4B, 0x4B);
+ mRotX += mRotXSpeed;
+ mVec3_c tmp1(0, 1, 0);
+ mVec3_c tmp2(0, 1, 0);
+ tmp2.rotX(mRotX);
+ tmp2.rotY(mRotY);
+ EGG::Quatf quat;
+ quat.makeVectorRotation(tmp1, tmp2);
+ mQuat.slerpTo(quat, 0.5f, mQuat);
+ mQuat.normalise();
+ mQuat.makeWPositive();
+ mMtx.fromQuat(mQuat);
+}
+
+void dTgMassObjInstance::releaseDynamicTransform(GrassModel *param_2) {
+ if (mDynamicTransform != nullptr) {
+ param_2->releaseTransform(mDynamicTransform);
+ mDynamicTransform = nullptr;
+ }
+}
+
+void dTgMassObjInstance::reset() {
+ mGrassFlags = 0;
+ mTevColor.a = 0;
+ mTevColor.b = 0;
+ mTevColor.g = 0;
+ mTevColor.r = 0;
+ mActiveInPresent = false;
+ mScale = 1;
+}
+
+// matches besides data
+void dTgMassObjInstance::getDrawMatrix(mMtx_c *pOut) {
+ if (mDynamicTransform != nullptr) {
+ *pOut = mDynamicTransform->getMtx();
+ } else if (mInitPosTransform != nullptr) {
+ *pOut = mInitPosTransform->getMtx();
+ } else {
+ pOut->YrotS(yRotation);
+ }
+ pOut->setBase(3, mGroundHeight);
+ pOut->scaleM(mScale, mScale, mScale);
+ s32 sure = ((s16)mGroundHeight.x >> 1) & 7;
+ pOut->scaleM(sure * 0.015f + 1.f, sure * 0.015f + 1.f, sure * 0.015f + 1.f);
+}
+
+bool dTgMassObjInstance::checkForHit(GrassModel *param_2, GrassModelData *param_3, u16 roomid) {
+ dCcMassS_HitInf massHitInf;
+ dAcObjBase_c *actor;
+ u32 chk = dCcS::GetInstance()->GetMassMng().Chk(&mGroundHeight, &actor, &massHitInf);
+ if (!checkForHit(chk, massHitInf, actor, param_2, param_3, roomid) &&
+ !FUN_80278c70(chk, massHitInf, actor, param_2) && !handleLinkSpinAttack(param_2)) {
+ if (mDynamicTransform != nullptr) {
+ EGG::Quatf &dynQuat = mDynamicTransform->mQuat;
+ f32 fVar2 = (mInitPosTransform->mQuat.dot(dynQuat));
+ fVar2 *= 0.1f;
+ if (fVar2 < 0.1f) {
+ fVar2 = 0.1f;
+ }
+ dynQuat.slerpTo(mInitPosTransform->mQuat, fVar2, dynQuat);
+ mDynamicTransform->mQuat.normalise();
+ mDynamicTransform->mQuat.makeWPositive();
+ mDynamicTransform->mMtx.fromQuat(mDynamicTransform->mQuat);
+ if (mInitPosTransform->mQuat.dot(mDynamicTransform->mQuat) >= 1.f) {
+ param_2->releaseTransform(mDynamicTransform);
+ mDynamicTransform = nullptr;
+ }
+ }
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool dTgMassObjInstance::checkForHit(
+ u32 param_2, dCcMassS_HitInf &param_3, dAcObjBase_c *param_4, GrassModel *param_5, GrassModelData *param_6,
+ undefined4 roomid
+) {
+ dAcPy_c *link = dAcPy_c::GetLinkM();
+ if (link == nullptr) {
+ return false;
+ }
+ if ((param_2 & 1) == 0 || param_4 == nullptr) {
+ return false;
+ }
+ f32 impactDistanceFactor;
+ f32 impactFactor;
+ f32 maybeMaxImpactDistance = 0.f;
+ f32 distance;
+ s32 isNotCut;
+ f32 fVar20;
+ f32 fVar5;
+ f32 fVar4;
+ f32 fVar2;
+ f32 fVar21;
+ mVec3_c localB4(0.f, 1.f, 0.f);
+ cCcD_Obj *hitObj = param_3.GetAtHitObj();
+ if (hitObj != nullptr) {
+ mVec3_c &p4Pos = param_4->getPosition();
+ mVec3_c hitPosition = param_4->mPosition;
+ s32 needsLightingRelated = 0;
+ impactFactor = 0.f;
+ if (hitObj->ChkAtType(AT_TYPE_BELLOWS)) {
+ hitPosition = link->mPosition;
+ needsLightingRelated = 1;
+ maybeMaxImpactDistance = 1000.f;
+ impactFactor = cM::rndF(0.5f) + 0.5f;
+ isNotCut = 1;
+ } else if (hitObj->ChkAtType(AT_TYPE_SLINGSHOT)) {
+ maybeMaxImpactDistance = 120.f;
+ impactFactor = cM::rndF(0.06f) + 0.6f;
+ isNotCut = 1;
+ } else if (hitObj->ChkAtType(AT_TYPE_0x200000) || hitObj->ChkAtType(AT_TYPE_BUGNET)) {
+ maybeMaxImpactDistance = 1000.f;
+ impactFactor = cM::rndF(0.2f) + 0.6f;
+ isNotCut = 1;
+ } else if (hitObj->ChkAtType(AT_TYPE_0x40)) {
+ mVec3_c localCC = mGroundHeight;
+ isNotCut = 1;
+ if (std::fabsf(localCC.y - param_4->mPosition.y) < 60.f) {
+ localCC.y = param_4->mPosition.y;
+ f32 dist = localCC.distance(p4Pos);
+ if (dist < 160.f) {
+ isNotCut = 0;
+ }
+ }
+ if (isNotCut == 1) {
+ maybeMaxImpactDistance = 600.f;
+ impactFactor = cM::rndF(0.3f) + 0.3f;
+ }
+ needsLightingRelated = 1;
+
+ } else if (hitObj->ChkAtType(AT_TYPE_BEETLE)) {
+ mVec3_c localD8 = mGroundHeight;
+ isNotCut = 1;
+ if (std::fabsf(localD8.y - param_4->mPosition.y) < 80.f) {
+ localD8.y = param_4->mPosition.y;
+ f32 dist = localD8.distance(param_4->mPosition);
+ if (dist < 160.f) {
+ isNotCut = 0;
+ }
+ }
+ if (isNotCut == 1) {
+ maybeMaxImpactDistance = 800.f;
+ impactFactor = cM::rndF(0.2f) + 0.5f;
+ }
+
+ } else if (hitObj->ChkAtType(AT_TYPE_WHIP)) {
+ mVec3_c localE4 = mGroundHeight;
+ hitPosition = *link->anotherThingWithWhip();
+ if (localE4.distance(hitPosition) < 120.f) {
+ isNotCut = 0;
+ } else {
+ maybeMaxImpactDistance = 300.f;
+ impactFactor = cM::rndF(0.05f) + 0.5f;
+ isNotCut = 1;
+ }
+ } else if (hitObj->ChkAtType(AT_TYPE_0x800000)) {
+ isNotCut = 0;
+ } else if (hitObj->ChkAtType(AT_TYPE_ARROW)) {
+ mVec3_c localE4 = mGroundHeight;
+ if (localE4.distance(param_4->mPosition) < 80.f) {
+ isNotCut = 0;
+ } else {
+ maybeMaxImpactDistance = 200.f;
+ impactFactor = cM::rndF(0.04f) + 0.4f;
+ isNotCut = 1;
+ }
+ } else if (hitObj->ChkAtType(AT_TYPE_BOMB)) {
+ mVec3_c localE4 = mGroundHeight;
+ if (localE4.distance(param_4->mPosition) < 300.f) {
+ isNotCut = 0;
+ } else {
+ maybeMaxImpactDistance = 5000.f;
+ impactFactor = cM::rndF(0.09f) + 0.9f;
+ isNotCut = 1;
+ }
+ } else if (hitObj->ChkAtType(AT_TYPE_SWORD)) {
+ s32 currentSword = daPlayerActBase_c::getCurrentSwordTypeInline();
+ fVar20 = 120.f;
+ fVar21 = 260.f;
+ fVar5 = 430.f;
+ fVar4 = 305.f;
+ fVar2 = 1000.f;
+ if (currentSword == 0) {
+ fVar5 = 200.f;
+ fVar21 = 150.f;
+ fVar2 = 180.f;
+ fVar4 = 200.f;
+ } else if (currentSword == 1) {
+ fVar21 = 170.f;
+ fVar5 = 400.f;
+ fVar4 = 250.f;
+ fVar2 = 200.f;
+ } else if (currentSword == 2 || currentSword == 3) {
+ fVar20 = 130.f;
+ fVar21 = 200.f;
+ fVar5 = 420.f;
+ fVar4 = 290.f;
+ fVar2 = 250.f;
+ }
+ hitPosition = link->mPosition;
+ distance = mGroundHeight.distance(hitPosition);
+ if ((s32)link->getSpecificAttackDirection() == dAcPy_c::ATTACK_DIRECTION_DOWN ||
+ (s32)link->getSpecificAttackDirection() == dAcPy_c::ATTACK_DIRECTION_UP ||
+ (s32)link->getSpecificAttackDirection() == dAcPy_c::ATTACK_DIRECTION_STAB) {
+ if (distance < fVar20) {
+ isNotCut = 0;
+ } else {
+ maybeMaxImpactDistance = 300.f;
+ impactFactor = cM::rndF(0.05f) + 0.5f;
+ isNotCut = 1;
+ if (distance >= fVar20 + 60.f) {
+ return true;
+ }
+ }
+ } else {
+ if (mMassObjSubtype == 8 || mMassObjSubtype == 9) {
+ fVar21 = fVar20 * 0.8f;
+ hitPosition = dAcPy_c::GetLink()->getSwordPos();
+
+ distance = mGroundHeight.distance(hitPosition);
+ if ((s32)link->getSpecificAttackDirection() != dAcPy_c::ATTACK_DIRECTION_DOWNRIGHT &&
+ (s32)link->getSpecificAttackDirection() != dAcPy_c::ATTACK_DIRECTION_DOWNLEFT) {
+ return true;
+ }
+ if (distance >= fVar21) {
+ return true;
+ }
+ }
+ if (link->isAttackingSpin()) {
+ if (link->checkSwordAndMoreStates(daPlayerActBase_c::SKYWARD_STRIKE_ACTIVE)) {
+ fVar21 = fVar5;
+ } else {
+ fVar21 = fVar4;
+ }
+ }
+ if (distance < fVar21) {
+ isNotCut = 0;
+ } else if (distance < fVar2) {
+ maybeMaxImpactDistance = 5000.f;
+ impactFactor = cM::rndF(0.5f) + 0.5f;
+ isNotCut = 1;
+ } else {
+ return true;
+ }
+ }
+ } else {
+ isNotCut = 0;
+ }
+ if (isNotCut == 1) {
+ // grass is not cut, just move
+ f32 fVar20 = cM::rndFX(0.025f) + 0.05f;
+ if (!hitObj->ChkAtType(AT_TYPE_WHIP) && !hitObj->ChkAtType(AT_TYPE_BELLOWS)) {
+ if ((!link->isAttackingSpin())) {
+ hitPosition = param_4->mPosition;
+ }
+ }
+ f32 tempDistance = mGroundHeight.distance(hitPosition);
+ if (tempDistance > maybeMaxImpactDistance) {
+ tempDistance = maybeMaxImpactDistance;
+ }
+ // check this for regalloc
+ impactDistanceFactor =
+ (1.f - (tempDistance / maybeMaxImpactDistance) * (tempDistance / maybeMaxImpactDistance));
+ if (mDynamicTransform == nullptr) {
+ mDynamicTransform = param_5->aquireTransform();
+ if (mDynamicTransform == nullptr) {
+ return false;
+ }
+ mDynamicTransform->mQuat.set(mInitPosTransform->mQuat);
+ mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat);
+ }
+ if (param_4 == nullptr) {
+ return false;
+ }
+ mVec3_c local108 = mGroundHeight - hitPosition;
+ local108.rotY(0x4000);
+ local108.normalize();
+ mVec3_c local114 = hitObj->mAt.mVec;
+ mVec3_c local120 = local114;
+ if (needsLightingRelated) {
+ fVar20 = cM::rndF(0.5f) + 0.15f;
+ hitPosition.y += 50.f;
+ dLightEnv_c::GetPInstance()->get_vectle_calc(&hitPosition, &mGroundHeight, &local120);
+ if (!local120.normalizeRS()) {
+ local120.x = 1.f;
+ local120.z = 0.f;
+ }
+ if (!local120.normalizeRS()) {
+ local120 = localB4;
+ }
+ // regalloc
+ } else if (cM::isZero(local114.getSquareMag())) {
+ local120 = mGroundHeight - hitPosition;
+ if (!local120.normalizeRS()) {
+ local120.x = 1.f;
+ local120.z = 0.f;
+ }
+ local120.y = 0.5f;
+ if (!local120.normalizeRS()) {
+ local120 = localB4;
+ }
+ fVar20 = cM::rndF(0.5f) + 0.5f;
+ } else {
+ local114.y = 0.f;
+ local114.normalize();
+ f32 fVar2 = local108.inprodXZ(local114);
+ if (fVar2 != 0.f) {
+ local120.y = 2.f / fVar2;
+ }
+ if (local108.inprodXZ(local114) >= 0.f) {
+ local120.rotY(-0x4000);
+ } else {
+ local120.rotY(0x4000);
+ }
+ if (!local120.normalizeRS()) {
+ local120 = localB4;
+ }
+ }
+ mQuat_c local130;
+ local130.makeVectorRotation(localB4, local120);
+ local130.slerpTo(mInitPosTransform->mQuat, 1.f - impactFactor * impactDistanceFactor, local130);
+ local130.normalise();
+ local130.makeWPositive();
+ mQuat_c local140;
+ mDynamicTransform->mMtx.toQuat(local140);
+ local140.slerpTo(local130, fVar20, local140);
+ local140.normalise();
+ local140.makeWPositive();
+ mDynamicTransform->mQuat.set(local130);
+ mDynamicTransform->mMtx.fromQuat(local140);
+ } else if (hitObj->ChkAtType(AT_TYPE_WIND)) {
+ if (mDynamicTransform == nullptr) {
+ mDynamicTransform = param_5->aquireTransform();
+ if (mDynamicTransform == nullptr) {
+ return false;
+ }
+ mDynamicTransform->mQuat.set(mInitPosTransform->mQuat);
+ mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat);
+ }
+ if (param_4 == nullptr) {
+ return false;
+ }
+ mVec3_c local150 = mGroundHeight - param_4->mPosition;
+ mQuat_c local160;
+ local150.y = 0.f;
+ local150.x *= (cM::rndFX(0.5f) + 0.5f);
+ local150.z *= (cM::rndFX(0.5f) + 0.5f);
+ if (!local150.normalizeRS()) {
+ local150 = localB4;
+ }
+ local160.makeVectorRotation(localB4, local150);
+ // float regalloc
+ f32 fVar2 = (local160.dot(mDynamicTransform->mQuat));
+ fVar2 *= 0.1f;
+ if (fVar2 < 0.1f) {
+ fVar2 = 0.1f;
+ }
+ local160.slerpTo2(cM::rndF(0.4f) + 0.3f, mInitPosTransform->mQuat, local160);
+ local160.normalise();
+ local160.makeWPositive();
+ mDynamicTransform->mQuat.slerpTo(local160, fVar2, mDynamicTransform->mQuat);
+ mDynamicTransform->mQuat.normalise();
+ if (mDynamicTransform->mQuat.w < 0) {
+ mDynamicTransform->mQuat.multScalar(-1);
+ }
+ mDynamicTransform->mMtx.fromQuat(mDynamicTransform->mQuat);
+ } else {
+ // grass is cut
+ param_6->removeFromRoom(roomid, this);
+ param_5->addToRoom(1, roomid, this);
+ mGrassFlags |= TG_MASS_UNK2_IS_CUT;
+ if (mDynamicTransform != nullptr) {
+ // this is wrong...
+ yRotation = *(u16 *)mDynamicTransform->mRotY.ref();
+ param_5->releaseTransform(mDynamicTransform);
+ mDynamicTransform = nullptr;
+ }
+ yRotation = *(u16 *)mInitPosTransform->mRotY.ref();
+ mInitPosTransform = nullptr;
+ if (param_5->mCutCounter < 0x19) {
+ param_5->mCutCounter++;
+ mVec3_c local16C(mGroundHeight.x, mGroundHeight.y, mGroundHeight.z);
+ mColor local17C = 0xFFFFFFFF;
+ f32 camField2A8 = dScGame_c::getCamera()->getField_0x2A8();
+ local17C.r = mTevColor.r;
+ local17C.g = mTevColor.g;
+ local17C.b = mTevColor.b;
+ local17C.a = mTevColor.a;
+ if (local16C.y + 100.f < camField2A8 && mMassObjSubtype <= 5) {
+ if (dScGame_c::isCurrentStage("D100")) {
+ mMassObjSubtype = 6;
+ } else {
+ mMassObjSubtype = 5;
+ }
+ }
+ dEmitterBase_c *ret;
+ switch (mMassObjSubtype) {
+ case 0:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_120_, local16C, nullptr, &local17C
+ );
+ break;
+ case 1:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_121_, local16C, nullptr, &local17C
+ );
+ break;
+ case 2:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_122_, local16C, nullptr, &local17C
+ );
+ break;
+ case 3:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_123_, local16C, nullptr, &local17C
+ );
+ break;
+ case 4:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_124_, local16C, nullptr, &local17C
+ );
+ break;
+ case 5:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_687_, local16C, nullptr, &local17C
+ );
+ break;
+ case 6:
+ dJEffManager_c::createMassObjEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_800_, local16C, nullptr, &local17C
+ );
+ break;
+ case 7:
+ ret = dJEffManager_c::spawnEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_838_, local16C, nullptr, nullptr, &local17C, nullptr, 0, 0
+ );
+ if (ret != nullptr) {
+ ret->bindShpEmitter(dJEffManager_c::FlowerA00F, true);
+ }
+ ret = dJEffManager_c::spawnEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_839_, local16C, nullptr, nullptr, &local17C, nullptr, 0, 0
+ );
+ if (ret != nullptr) {
+ ret->bindShpEmitter(dJEffManager_c::FlowerA00L, true);
+ }
+ break;
+ case 8:
+ ret = dJEffManager_c::spawnEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_840_, local16C, nullptr, nullptr, &local17C, nullptr, 0, 0
+ );
+ if (ret != nullptr) {
+ ret->bindShpEmitter(dJEffManager_c::FlowerB00, true);
+ }
+ break;
+ case 9:
+ ret = dJEffManager_c::spawnEffect(
+ PARTICLE_RESOURCE_ID_MAPPING_841_, local16C, nullptr, nullptr, &local17C, nullptr, 0, 0
+ );
+ if (ret != nullptr) {
+ ret->bindShpEmitter(dJEffManager_c::FlowerB01, true);
+ }
+ break;
+ }
+ dSndSmallEffectMgr_c::GetInstance()->playSoundAtPosition(SE_O_GRASS_CUT, mGroundHeight);
+ }
+ }
+ }
+ return true;
+}
+
+// non matching
+bool dTgMassObjInstance::FUN_80278c70(u32 param_2, dCcMassS_HitInf &param_3, dAcBase_c *param_4, GrassModel *param_5) {
+ mVec3_c local54 = mGroundHeight;
+ f32 fVar12 = 1000.f;
+ s32 iVar11 = 0;
+ f32 fVar1 = 0.55f;
+ if ((param_2 & 2) == 0) {
+ return false;
+ }
+ if (param_4 == nullptr) {
+ param_4 = dAcPy_c::GetLinkM();
+ }
+ if (param_3.GetCoHitObj()->ChkCo_0x10() && dAcPy_c::GetLink() != nullptr) {
+ mVec3_c local60 = mGroundHeight;
+ mVec3_c local6C;
+ if (dAcPy_c::GetLink()->isUsingBugnet()) {
+ local6C = dAcPy_c::GetLink()->getBugNetPos();
+ } else {
+ local6C = dAcPy_c::GetLink()->vt_0x278();
+ local6C += (dAcPy_c::GetLink()->getSwordPos() - dAcPy_c::GetLink()->vt_0x278()) * 0.5f;
+ }
+ local60.y += 60.f;
+ local54 = local60 - local6C;
+ fVar12 = local60.distance(local6C);
+ if (fVar12 > 40.f) {
+ iVar11 = 1;
+ } else {
+ fVar12 = 1 - fVar12 / 250.f;
+ }
+ } else {
+ iVar11 = param_3.GetCoHitObj()->ChkCo_0x2() ? 1 : 2;
+ }
+ if (iVar11 != 0) {
+ f32 fVar13;
+ f32 fVar12_2 = 100.f;
+ if (iVar11 == 2) {
+ fVar12_2 = 200.f;
+ fVar1 = 0.8f;
+ }
+ f32 radSq = param_5->mRadiusSquared;
+ local54 = mGroundHeight - param_4->mPosition;
+ if (local54.squareMagXZ() > radSq) {
+ return false;
+ }
+ f32 distance = mGroundHeight.distance(param_4->getPosition());
+ fVar13 = distance;
+ if (distance > fVar12_2) {
+ fVar13 = fVar12_2;
+ } else {
+ if (iVar11 == 1) {
+ param_4->getSoundSource()->holdSound(SE_L_GRASS_RUSTLE_LV);
+ }
+ }
+ fVar12 = 1 - fVar13 / fVar12_2;
+ }
+ mVec3_c local78(0.f, 1.f, 0.f);
+ if (mDynamicTransform == nullptr) {
+ mDynamicTransform = param_5->aquireTransform();
+ if (mDynamicTransform == nullptr) {
+ return false;
+ }
+ mDynamicTransform->mQuat.set(mInitPosTransform->mQuat);
+ mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat);
+ }
+ // regalloc
+ if (cM::isZero(local54.getSquareMag())) {
+ local54.set(1.f, 0.5f, 0.f);
+ }
+ mQuat_c local88;
+ mVec3_c local98 = local54;
+ if (!local98.normalizeRS()) {
+ local98.x = 1.f;
+ local98.z = 0.f;
+ }
+ local98.y = 0.5f;
+ if (!local98.normalizeRS()) {
+ local98 = local78;
+ }
+ local88.makeVectorRotation(local78, local98);
+ local88.slerpTo(mInitPosTransform->mQuat, 1 - fVar1 * fVar12, local88);
+ local88.normalise();
+ local88.makeWPositive();
+ mQuat_c localA8;
+ mDynamicTransform->mMtx.toQuat(localA8);
+ localA8.slerpTo(local88, cM::rndF(0.2f) + 0.2f, localA8);
+ localA8.normalise();
+ localA8.makeWPositive();
+ mDynamicTransform->setQuat(local88);
+ mDynamicTransform->setMtxFromQuat(localA8);
+ return true;
+}
+
+// non matching
+bool dTgMassObjInstance::handleLinkSpinAttack(GrassModel *param_2) {
+ const dAcPy_c *link = dAcPy_c::GetLink();
+ if (link == nullptr) {
+ return false;
+ }
+ if (!link->isAttackingSpin()) {
+ return false;
+ }
+ mVec3_c local3C;
+ dAcPy_c::GetLink()->getPostionDifferenceOut(mGroundHeight, local3C);
+ f32 dist = mGroundHeight.distance(dAcPy_c::GetLinkM()->getPosition());
+ f32 comparison = 350.f;
+ if (link->isAttackingDown()) {
+ comparison = 150.f;
+ } else if (link->checkSwordAndMoreStates(daPlayerActBase_c::SKYWARD_STRIKE_ACTIVE)) {
+ comparison = 450.f;
+ }
+ if (dist > comparison) {
+ return false;
+ }
+ mVec3_c local48(0.f, 1.f, 0.f);
+ if (mDynamicTransform == nullptr) {
+ mDynamicTransform = param_2->aquireTransform();
+ if (mDynamicTransform == nullptr) {
+ return false;
+ }
+ mDynamicTransform->mQuat.set(mInitPosTransform->mQuat);
+ mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat);
+ }
+ // regalloc
+ if (cM::isZero(local3C.getSquareMag())) {
+ local3C.set(1.f, 0.5f, 0.f);
+ }
+ mQuat_c local58;
+ mVec3_c local68 = local3C;
+ if (!local68.normalizeRS()) {
+ local68.x = 1.f;
+ local68.z = 0.f;
+ }
+ local68.y = 0.5f;
+ if (!local68.normalizeRS()) {
+ local68 = local48;
+ }
+ local58.makeVectorRotation(local48, local68);
+ local58.slerpTo2(cM::rndF(0.5f), mInitPosTransform->mQuat, local58);
+ local58.normalise();
+ local58.makeWPositive();
+ mQuat_c local78;
+ mDynamicTransform->mMtx.toQuat(local78);
+ local78.slerpTo(local58, cM::rndF(0.3f) + 0.5f, local78);
+ local78.normalise();
+ local78.makeWPositive();
+ mDynamicTransform->mQuat.set(local58);
+ mDynamicTransform->setMtxFromQuat(local78);
+ return true;
+}
+
+extern "C" bool fn_801BB700(EGG::Quatf *, f32);
+
+bool dTgMassObjInstance::isHidden(f32 param2, f32 param3) {
+ bool uVar1 = mSpecialItemDropId != 10;
+ if (uVar1) {
+ mVec3_c tmp2(mGroundHeight.x, mGroundHeight.y + param2, mGroundHeight.z);
+ EGG::Quatf tmp(param2 + 700.f, tmp2);
+ uVar1 = fn_801BB700(&tmp, param3);
+ }
+ if (uVar1) {
+ mGrassFlags |= dTgMassObjInstance::TG_MASS_UNK2_IS_HIDDEN;
+ return true;
+ } else {
+ mGrassFlags &= ~dTgMassObjInstance::TG_MASS_UNK2_IS_HIDDEN;
+ return false;
+ }
+}
+
+bool dTgMassObjInstance::handleTimeshiftZone() {
+ bool ret = true;
+ f32 fVar2 = dTimeAreaMgr_c::GetInstance()->checkPositionIsInPastState(-1, mGroundHeight, nullptr, 8.f);
+ if (mActiveInPresent == false) {
+ sLib::addCalc(&mScale, fVar2, 0.5f, 0.2f, 0.01f);
+ if (mScale <= 0) {
+ ret = false;
+ }
+ } else if (mActiveInPresent == true) {
+ sLib::addCalc(&mScale, 1.f - fVar2, 0.5f, 0.2f, 0.01f);
+ if (mScale <= 0) {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+bool GrassModelData::tryCreateLinkedLists(s32 entrycount, EGG::Heap *heap) {
+ mLinkedLists = new (heap, 4) dTgMassObjInstanceList[entrycount];
+ if (mLinkedLists == nullptr) {
+ destroyLinkedLists();
+ return false;
+ } else {
+ mLinkedListsCount = entrycount;
+ return true;
+ }
+}
+
+void GrassModelData::destroyLinkedLists() {
+ if (mLinkedLists != nullptr) {
+ delete[] mLinkedLists;
+ mLinkedLists = nullptr;
+ }
+}
+
+void GrassModelData::unloadRoom(GrassModel *param_2, int roomid) {
+ dTgMassObjInstanceList &gll = mLinkedLists[roomid];
+ dTgMassObjInstanceList::Iterator it = gll.GetBeginIter();
+ while (it != gll.GetEndIter()) {
+ dTgMassObjInstance &lst = *it;
+ ++it;
+ lst.releaseDynamicTransform(param_2);
+ gll.remove(&lst);
+ param_2->addToFreeInstances(&lst);
+ }
+}
+
+void GrassModelData::initRes(nw4r::g3d::ResMat pResMat, nw4r::g3d::ResShp pResShp) {
+ mResMat = pResMat;
+ mResShp = pResShp;
+ nw4r::g3d::ResMatChan chan = mResMat.GetResMatChan();
+ chan.GXSetChanAmbColor(GX_COLOR0, mColor(0xFF, 0xFF, 0xFF, 0xFF));
+}
+
+void GrassModelData::addToRoom(s32 room, dTgMassObjInstance *p3) {
+ mLinkedLists[room].append(p3);
+}
+
+// regalloc
+void GrassModelData::removeFromRoom(s32 room, dTgMassObjInstance *p3) {
+ mLinkedLists[room].remove(p3);
+}
+
+void GrassModelData::update(GrassModel *param2) {
+ mVec3_c groundHeight(999999.f, 999999.f, 999999.f);
+ dLightEnv_c &lightEnv = dLightEnv_c::GetInstance();
+ bool bVar1 = false;
+ s32 count = 0;
+ f32 minDist = lightEnv.getfield_0x38C0();
+ dTgMassObjInstanceList *grassList = mLinkedLists;
+ for (s32 roomid = 0; roomid < mLinkedListsCount; roomid++, grassList++) {
+ if (grassList->mCount == 0 || dStage_c::GetInstance()->getRoom(roomid)->checkFlag(4)) {
+ continue;
+ }
+ dTgMassObjInstanceList::Iterator it = grassList->GetBeginIter();
+ while (it != grassList->GetEndIter()) {
+ dTgMassObjInstance &lst = *it;
+ ++it;
+ if ((lst.mGrassFlags & dTgMassObjInstance::TG_MASS_UNK2_TIMESHIFT_RELATED) && !lst.handleTimeshiftZone()) {
+ lst.mGrassFlags |= dTgMassObjInstance::TG_MASS_UNK2_IS_HIDDEN;
+ } else {
+ if ((lst.mGrassFlags & dTgMassObjInstance::TG_MASS_UNK2_IS_HIDDEN) == 0 &&
+ (lst.mGrassFlags & dTgMassObjInstance::TG_MASS_UNK2_IS_CUT) == 0) {
+ lst.checkForHit(param2, this, roomid);
+ }
+ if (lightEnv.getfield_0x38B0() == 1) {
+ if (lightEnv.getfield_0x38B4().distance(lst.mGroundHeight) < minDist) {
+ minDist = lightEnv.getfield_0x38B4().distance(lst.mGroundHeight);
+ groundHeight = lst.mGroundHeight;
+ }
+ if (lightEnv.getfield_0x38B4().distance(lst.mGroundHeight) < lightEnv.getfield_0x38C0()) {
+ bVar1 = true;
+ count++;
+ }
+ }
+ }
+ }
+ }
+ if (lightEnv.getfield_0x38B0() == 1) {
+ lightEnv.setfield_0x38B0(0);
+ if (bVar1) {
+ lightEnv.getfield_0x38C8() = groundHeight;
+ }
+ lightEnv.setfield_0x38C4(count);
+ }
+}
+
+extern void LoadMaterial(
+ nw4r::g3d::ResMat mat, u32 ctrl, nw4r::g3d::Draw1Mat1ShpSwap *pSwap, nw4r::g3d::G3DState::IndMtxOp *pIndMtxOp,
+ bool bIgnoreMaterial
+);
+
+void GrassModelData::draw(f32 param_1, f32 param_2, nw4r::math::MTX34 *pMtx) {
+ mVec3_c cameraPosition = dScGame_c::getCamera()->getPositionMaybe();
+ bool isInFaronWoods = dScGame_c::isCurrentStage("F100");
+ nw4r::g3d::ResMatMisc miscData(mResMat.GetResMatMisc());
+ miscData.SetLightSetIdx(1);
+ miscData.SetFogIdx(0);
+ LoadMaterial(mResMat, 0, nullptr, nullptr, false);
+ nw4r::g3d::G3DState::LoadResShpPrePrimitive(mResShp);
+ const static u32 fifoMtx[8] = {
+ GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY, GX_IDENTITY,
+ };
+ nw4r::g3d::fifo::GDSetCurrentMtx(fifoMtx);
+ GXSetCurrentMtx(0);
+ dTgMassObjInstanceList *grassList = mLinkedLists;
+ for (s32 roomid = 0; roomid < mLinkedListsCount; roomid++, grassList++) {
+ if (grassList->mCount == 0 || dStage_c::GetInstance()->getRoom(roomid)->checkFlag(4)) {
+ continue;
+ }
+ dTgMassObjInstanceList::Iterator it = grassList->GetBeginIter();
+ for (; it != grassList->GetEndIter(); ++it) {
+ dTgMassObjInstance &lst = *it;
+ if (!lst.isHidden(param_1, param_2)) {
+ mMtx_c local160;
+ lst.getDrawMatrix(&local160);
+ f32 cameraDist = lst.mGroundHeight.distance(cameraPosition);
+ f32 fVar6 = param_2 * 0.6f;
+ if (cameraDist > fVar6) {
+ f32 fVar7 = (cameraDist - fVar6) / (param_2 - fVar6);
+ if (fVar7 > 1.f) {
+ fVar7 = 1.f;
+ }
+ if (fVar7 < 0.f) {
+ fVar7 = 0.f;
+ continue;
+ } else {
+ f32 scale = 1. - fVar7; // double
+ local160.scaleM(scale, scale, scale);
+ }
+ }
+ if (isInFaronWoods && lst.mGroundHeight.x <= -5200.f && lst.mGroundHeight.x >= -5500.f &&
+ lst.mGroundHeight.z <= -5900.f && lst.mGroundHeight.z >= -6100.f) {
+ local160.scaleM(1.f, 1.5f, 1.f);
+ }
+ f32 fVar7 = ((s32)(lst.mGroundHeight.x + lst.mGroundHeight.z) & 0x1F) / 31.f;
+ f32 scale = fVar7 * 0.1f + 1.f;
+ local160.scaleM(scale, scale, scale);
+ local160.YrotM(fVar7 * 65535.f);
+ MTXConcat(*pMtx, local160, local160);
+ GXLoadPosMtxImm(local160, 0);
+ GXLoadNrmMtxImm(local160, 0);
+ GXSetTevColorS10(GX_TEVREG1, lst.mTevColor);
+ mResShp.CallPrimitiveDisplayList(false);
+ }
+ }
+ }
+}