mirror of
https://github.com/zeldaret/ss
synced 2026-05-23 23:05:20 -04:00
1482 lines
52 KiB
C++
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 ¶m_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 ¶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 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);
|
|
}
|
|
}
|
|
}
|
|
}
|