Files
ss/src/d/tg/d_t_mass_object.cpp
T
2026-03-01 21:05:31 +01:00

1482 lines
52 KiB
C++

#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 waterHeight = dScGame_c::getCamera()->getWaterHeight();
local17C.r = mTevColor.r;
local17C.g = mTevColor.g;
local17C.b = mTevColor.b;
local17C.a = mTevColor.a;
if (local16C.y + 100.f < waterHeight && 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()->getPosition();
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);
}
}
}
}