diff options
| author | lepelog <25211966+lepelog@users.noreply.github.com> | 2025-12-13 01:23:37 +0100 |
|---|---|---|
| committer | lepelog <25211966+lepelog@users.noreply.github.com> | 2026-02-01 18:14:38 +0100 |
| commit | b017949c4b37acbfea90fdd5641dbdceaee688a7 (patch) | |
| tree | 1648b752fd8a55070ac3555ea9615e09dd95a7b1 /src | |
| parent | 62fc066b605680af84cc921aba070b62e7df8ff7 (diff) | |
d_t_mass_obj 99%
Diffstat (limited to 'src')
| -rw-r--r-- | src/d/tg/d_t_mass_object.cpp | 1509 |
1 files changed, 1509 insertions, 0 deletions
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..a6cae7f3 --- /dev/null +++ b/src/d/tg/d_t_mass_object.cpp @@ -0,0 +1,1509 @@ +#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_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 "d/d_heap_alloc.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_geometry.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" +#include <cmath> + + +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 f32 GRASS_VECS[4][3] = { + { + -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) == 0) { + 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 f32 (*loop)[3] = &GRASS_VECS[0]; + for (s32 i = 0; i < ARRAY_LENGTH(GRASS_VECS); i++) { + mVec3_c mult = mtx.multVec2(mVec3_c(*(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(); +} + +undefined4 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 0; + } + EGG::Heap* heap = allocator->mHeap; + mpModelData = new (heap, 4) GrassModelData[param_4]; + if (!mpModelData) { + remove(); + return 0; + } + GrassModelData* modelData = &mpModelData[0]; + for (s32 i = 0; i < param_4; i++) { + if (!(modelData++)->tryCreateLinkedLists(roomCount, heap)) { + remove(); + return 0; + } + } + mInstanceList = new (heap, 4) dTgMassObjInstance[instanceListLength]; + if (!mInstanceList) { + remove(); + return 0; + } + mStaticTransformationList = new (heap, 4) dTgMassObjTransform[staticTransformationListLength]; + if (!mStaticTransformationList) { + remove(); + return 0; + } + mDynamicTransformationList = new (heap, 4) dTgMassObjTransform[dynamicTransformationListLength]; + if (!mDynamicTransformationList) { + remove(); + return 0; + } + 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 1; +} + +void GrassModel::initResForModel(s32 room,nw4r::g3d::ResMat pResMat,nw4r::g3d::ResShp pResShp) { + mpModelData[room].initRes(pResMat, pResShp); +} + +undefined4 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 0; + } + // 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 1; +} + +s32 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 1; +} + +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); + } +} + +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); +} + +static s32 lbl_80573AF0 = 0x1000; + +dTgMassObjTransform::dTgMassObjTransform() { + field_0x00 = 0; + field_0x04 = 0; + mRotXSpeed = 0; + mRotY = cM::rndInt(0x10000); + mRotX = lbl_80573AF0; + mQuat.setUnit(); + s32 rnd = cM::rndInt(100); + for (s32 i = 0; i < rnd; i++) { + update(); + } +} + +#define CLAMP2(low, high, x) ((x) < (low) ? (low) : ((x) > (high) ? (high) : (x))) + +// matches besides data +void dTgMassObjTransform::update() { + mRotXSpeed -= (s16)(mRotX * 0.005f); + mRotXSpeed = CLAMP2(-0x4B, 0x4B, mRotXSpeed); + 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 + ); +} + +// matches besides data +s32 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); + s32 iVar5 = checkForHit(chk, massHitInf, actor, param_2, param_3, roomid); + if (iVar5 == 0 + && FUN_80278c70(chk, massHitInf, actor, param_2) == 0 + && handleLinkSpinAttack(param_2) == 0) { + 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 0; + } else { + return 1; + } +} + +// matches besides data +undefined4 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 0; + } + if ((param_2 & 1) == 0 || param_4 == nullptr) { + return 0; + } + 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 (link->getSpecificAttackDirection() == 1 + || link->getSpecificAttackDirection() == 0x10 + || link->getSpecificAttackDirection() == 0x100) { + if (distance < fVar20) { + isNotCut = 0; + } else { + maybeMaxImpactDistance = 300.f; + impactFactor = cM::rndF(0.05f) + 0.5f; + isNotCut = 1; + if (distance >= fVar20 + 60.f) { + return 1; + } + } + } else { + if (mMassObjSubtype == 8 || mMassObjSubtype == 9) { + fVar21 = fVar20 * 0.8f; + hitPosition = dAcPy_c::GetLink()->getSwordPos(); + + distance = mGroundHeight.distance(hitPosition); + if (link->getSpecificAttackDirection() != 2 && link->getSpecificAttackDirection() != 0x80) { + return 1; + } + if (distance >= fVar21) { + return 1; + } + } + 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 1; + } + } + } 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 0; + } + mDynamicTransform->mQuat.set(mInitPosTransform->mQuat); + mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat); + } + if (param_4 == nullptr) { + return 0; + } + 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; + } + } else if (local114.isZero2()) { + 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 0; + } + mDynamicTransform->mQuat.set(mInitPosTransform->mQuat); + mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat); + } + if (param_4 == nullptr) { + return 0; + } + 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(0x24, true); + } + ret = dJEffManager_c::spawnEffect(PARTICLE_RESOURCE_ID_MAPPING_839_, local16C, nullptr, nullptr, &local17C, nullptr, 0, 0); + if (ret != nullptr) { + ret->bindShpEmitter(0x25, 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(0x26, 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(0x27, true); + } + break; + } + dSndSmallEffectMgr_c::GetInstance()->playSoundAtPosition(SE_O_GRASS_CUT, mGroundHeight); + } + } + } + return 1; +} + +// non matching +undefined4 dTgMassObjInstance::FUN_80278c70(u32 param_2,dCcMassS_HitInf ¶m_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 0; + } + 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) { + // TODO here + f32 fVar12_2 = 100.f; + if (iVar11 == 2) { + fVar12_2 = 200.f; + fVar1 = 0.8f; + } + local54 = mGroundHeight - param_4->getPosition(); + if (param_5->mRadiusSquared < local54.squareMagXZ()) { + return 0; + } + f32 distance = mGroundHeight.distance(param_4->getPosition()); + f32 fVar13; + if (distance > fVar12_2) { + fVar13 = fVar12_2; + } else { + fVar13 = distance; + 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 0; + } + mDynamicTransform->mQuat.set(mInitPosTransform->mQuat); + mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat); + } + if (local54.isZero2()) { + 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 1; +} + +// matches besides data +undefined4 dTgMassObjInstance::handleLinkSpinAttack(GrassModel *param_2) { + const dAcPy_c* link = dAcPy_c::GetLink(); + if (link == nullptr) { + return 0; + } + if (!link->isAttackingSpin()) { + return 0; + } else { + 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 0; + } + mVec3_c local48(0.f, 1.f, 0.f); + if (mDynamicTransform == nullptr) { + mDynamicTransform = param_2->aquireTransform(); + if (mDynamicTransform == nullptr) { + return 0; + } + mDynamicTransform->mQuat.set(mInitPosTransform->mQuat); + mDynamicTransform->mMtx.fromQuat(mInitPosTransform->mQuat); + } + if (local3C.isZero2()) { + 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 1; + } +} + +extern "C" bool fn_801BB700(EGG::Quatf*,f32); + +// matches besides data +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; + } +} + +// matches besides data +s32 dTgMassObjInstance::handleTimeshiftZone() { + s32 uVar1 = 1; + 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) { + uVar1 = 0; + } + } else if (mActiveInPresent == true) { + sLib::addCalc(&mScale, 1.f - fVar2, 0.5f, 0.2f, 0.01f); + if (mScale <= 0) { + uVar1 = 0; + } + } + return uVar1; +} + +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); +} + +// matches besides data +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); + +// matches besides data +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] = { + 0x3C, + 0x3C, + 0x3C, + 0x3C, + 0x3C, + 0x3C, + 0x3C, + 0x3C, + }; + 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); + } + } + } +} |
