mirror of
https://github.com/zeldaret/tww.git
synced 2026-05-23 15:01:33 -04:00
a52bb789da
TP debug has an assert in d_a_obj showing the name of this variable is `M_no` there.
525 lines
16 KiB
C++
525 lines
16 KiB
C++
/**
|
|
* d_a_nh.cpp
|
|
* Forest Firely / 森のほたる (Mori no Hotaru)
|
|
*/
|
|
|
|
#include "d/actor/d_a_nh.h"
|
|
#include "f_op/f_op_actor_mng.h"
|
|
#include "d/d_com_inf_game.h"
|
|
#include "d/d_procname.h"
|
|
#include "d/d_cc_d.h"
|
|
#include "d/d_bg_s_acch.h"
|
|
#include "d/d_bg_s_gnd_chk.h"
|
|
#include "d/actor/d_a_player.h"
|
|
#include "d/d_item_data.h"
|
|
#include "m_Do/m_Do_hostIO.h"
|
|
#include "m_Do/m_Do_mtx.h"
|
|
#include "JSystem/JUtility/JUTAssert.h"
|
|
|
|
static daNh_HIO_c l_HIO;
|
|
|
|
static dCcD_SrcCyl l_cyl_src = {
|
|
// dCcD_SrcGObjInf
|
|
{
|
|
/* Flags */ 0,
|
|
/* SrcObjAt Type */ 0,
|
|
/* SrcObjAt Atp */ 0,
|
|
/* SrcObjAt SPrm */ 0,
|
|
/* SrcObjTg Type */ AT_TYPE_ALL,
|
|
/* SrcObjTg SPrm */ cCcD_TgSPrm_Set_e | cCcD_TgSPrm_IsEnemy_e,
|
|
/* SrcObjCo SPrm */ cCcD_CoSPrm_Set_e | cCcD_CoSPrm_IsOther_e | cCcD_CoSPrm_VsEnemy_e,
|
|
/* SrcGObjAt Se */ 0,
|
|
/* SrcGObjAt HitMark */ 0,
|
|
/* SrcGObjAt Spl */ 0,
|
|
/* SrcGObjAt Mtrl */ 0,
|
|
/* SrcGObjAt SPrm */ 0,
|
|
/* SrcGObjTg Se */ 0,
|
|
/* SrcGObjTg HitMark */ 0,
|
|
/* SrcGObjTg Spl */ 0,
|
|
/* SrcGObjTg Mtrl */ 0,
|
|
/* SrcGObjTg SPrm */ dCcG_TgSPrm_NoHitMark_e,
|
|
/* SrcGObjCo SPrm */ 0,
|
|
},
|
|
// cM3dGCylS
|
|
{
|
|
/* Center */ 0.0f, 0.0f, 0.0f,
|
|
/* Radius */ 10.0f,
|
|
/* Height */ 20.0f,
|
|
},
|
|
};
|
|
|
|
/* 800F95B8-800F9654 .text __ct__10daNh_HIO_cFv */
|
|
daNh_HIO_c::daNh_HIO_c() {
|
|
mNo = -1;
|
|
static const hio_prm_c init_data = {
|
|
/* field_0x08 */ 200.0f,
|
|
/* field_0x0c */ 100.0f,
|
|
/* field_0x10 */ -50.0f,
|
|
/* mGlowOffsetY */ 140.0f,
|
|
/* mGlowScale */ 0.95f,
|
|
/* mMinFrightenSpeed */ 5.0f,
|
|
/* mHeightAboveGround */ 50.0f,
|
|
/* mAscentSpeed */ 1.0f,
|
|
/* mDescentSpeed */ -1.0f,
|
|
/* mGravity */ 0.25f,
|
|
/* mMaxHomeDist */ 250.0f,
|
|
/* field_0x34 */ 600.0f,
|
|
/* mModelScale */ 2.5f,
|
|
/* field_0x3c */ 0x2000,
|
|
/* mDefaultGlowAlpha */ 0x20,
|
|
/* mBottleLifetime */ 10*30,
|
|
};
|
|
prm = init_data;
|
|
}
|
|
|
|
/* 800F9654-800F9874 .text __dt__6daNh_cFv */
|
|
daNh_c::~daNh_c() {
|
|
if (l_HIO.mNo >= 0) {
|
|
mDoHIO_deleteChild(l_HIO.mNo);
|
|
l_HIO.mNo = -1;
|
|
}
|
|
}
|
|
|
|
/* 800F9874-800F9980 .text setBaseMtx__6daNh_cFv */
|
|
void daNh_c::setBaseMtx() {
|
|
J3DModel* model = mpModel;
|
|
scale.setall(l_HIO.prm.mModelScale);
|
|
model->setBaseScale(scale);
|
|
mDoMtx_stack_c::transS(current.pos);
|
|
mDoMtx_stack_c::YrotM(shape_angle.y);
|
|
model->setBaseTRMtx(mDoMtx_stack_c::get());
|
|
|
|
cXyz glowOffset;
|
|
glowOffset.z = 0.0f;
|
|
glowOffset.x = 0.0f;
|
|
glowOffset.y = l_HIO.prm.mGlowOffsetY;
|
|
cXyz glowPos;
|
|
cMtx_multVec(mDoMtx_stack_c::get(), &glowOffset, &glowPos);
|
|
mDoMtx_stack_c::transS(glowPos);
|
|
mDoMtx_stack_c::scaleM(l_HIO.prm.mGlowScale, l_HIO.prm.mGlowScale, l_HIO.prm.mGlowScale);
|
|
cMtx_copy(mDoMtx_stack_c::get(), mGlowMtx);
|
|
}
|
|
|
|
/* 800F9980-800F9A54 .text createHeap__6daNh_cFv */
|
|
BOOL daNh_c::createHeap() {
|
|
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Always", ALWAYS_BDL_NH);
|
|
JUT_ASSERT(359, modelData != NULL);
|
|
|
|
mpModel = mDoExt_J3DModel__create(modelData, 0, 0x11020203);
|
|
if (!mpModel) {
|
|
return FALSE;
|
|
}
|
|
if (!initBrkAnm(false)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800F9A54-800F9A74 .text checkCreateHeap__FP10fopAc_ac_c */
|
|
static BOOL checkCreateHeap(fopAc_ac_c* i_this) {
|
|
return ((daNh_c*)i_this)->createHeap();
|
|
}
|
|
|
|
/* 800F9A74-800F9C8C .text create__6daNh_cFv */
|
|
s32 daNh_c::create() {
|
|
static u32 a_heap_size_tbl = 0x4000;
|
|
|
|
s32 phase_state = cPhs_COMPLEATE_e;
|
|
|
|
fopAcM_SetupActor(this, daNh_c);
|
|
|
|
if (!fopAcM_entrySolidHeap(this, checkCreateHeap, a_heap_size_tbl)) {
|
|
return cPhs_ERROR_e;
|
|
}
|
|
|
|
fopAcM_SetMtx(this, mpModel->getBaseTRMtx());
|
|
|
|
if (l_HIO.mNo < 0) {
|
|
l_HIO.mNo = mDoHIO_createChild("森のほたる", &l_HIO); // "Forest Firefly" (mori no hotaru)
|
|
l_HIO.mpActor = this;
|
|
}
|
|
if (!init()) {
|
|
phase_state = cPhs_ERROR_e;
|
|
}
|
|
|
|
return phase_state;
|
|
}
|
|
|
|
/* 800F9C8C-800F9D64 .text init__6daNh_cFv */
|
|
BOOL daNh_c::init() {
|
|
mType = fopAcM_GetParam(this) & 0xFF;
|
|
speed.y = 1.0f;
|
|
gravity = l_HIO.prm.mGravity;
|
|
mGlowAlpha = l_HIO.prm.mDefaultGlowAlpha;
|
|
mPlayerDist = 0.0f;
|
|
mAlpha = 0xFF;
|
|
mBottleTimer = l_HIO.prm.mBottleLifetime;
|
|
mGroundY = 0.0f;
|
|
|
|
BGCheck();
|
|
|
|
mStts.Init(0xFF, 0xFF, this);
|
|
mCyl.Set(l_cyl_src);
|
|
mCyl.SetStts(&mStts);
|
|
|
|
setBaseMtx();
|
|
eyePos = attention_info.position = current.pos;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800F9D64-800F9DF4 .text action__6daNh_cFPv */
|
|
void daNh_c::action(void* arg) {
|
|
if (mCurrActionFunc == NULL) {
|
|
speedF = 0.0f;
|
|
setAction(&daNh_c::waitAction, NULL);
|
|
}
|
|
(this->*mCurrActionFunc)(arg);
|
|
}
|
|
|
|
/* 800F9DF4-800F9EB8 .text setAction__6daNh_cFM6daNh_cFPCvPvPv_iPv */
|
|
BOOL daNh_c::setAction(ActionFunc actionFunc, void* arg) {
|
|
if (mCurrActionFunc != actionFunc) {
|
|
if (mCurrActionFunc != NULL) {
|
|
mActionStatus = ACTION_ENDING;
|
|
(this->*mCurrActionFunc)(arg);
|
|
}
|
|
mCurrActionFunc = actionFunc;
|
|
mActionStatus = ACTION_STARTING;
|
|
mEscapeTimer = 0;
|
|
unk696 = 0;
|
|
unk698 = 0;
|
|
unk69A = 0;
|
|
unk6A0 = 0.0f;
|
|
(this->*mCurrActionFunc)(arg);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800F9EB8-800F9F3C .text checkBinCatch__6daNh_cFv */
|
|
BOOL daNh_c::checkBinCatch() {
|
|
if (eventInfo.checkCommandCatch()) {
|
|
fopAcM_delete(this);
|
|
return TRUE;
|
|
}
|
|
|
|
dComIfGp_getAttention().CatchRequest(
|
|
this, dItem_FIREFLY_BOTTLE_e,
|
|
l_HIO.prm.field_0x08, l_HIO.prm.field_0x0c,
|
|
l_HIO.prm.field_0x10, l_HIO.prm.field_0x3c,
|
|
1
|
|
);
|
|
eventInfo.onCondition(dEvtCnd_CANCATCH_e);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* 800F9F3C-800FA108 .text searchPlayer__6daNh_cFv */
|
|
BOOL daNh_c::searchPlayer() {
|
|
if (isTypeBottle()) {
|
|
setAction(&daNh_c::escapeAction, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
daPy_py_c* player = daPy_getPlayerActorClass();
|
|
cXyz playerDelta = player->old.pos - player->current.pos;
|
|
f32 playerDist = fopAcM_searchPlayerDistance(this);
|
|
f32 playerDistDelta = mPlayerDist - playerDist;
|
|
mPlayerDist = playerDist;
|
|
if (playerDelta.absXZ() > 0.001f && playerDist < 600.0f && playerDistDelta > l_HIO.prm.mMinFrightenSpeed) {
|
|
// Player is nearby and moving closer. The Forest Firefly becomes frightened and tries to escape.
|
|
setAction(&daNh_c::escapeAction, NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* 800FA108-800FA19C .text moveProc__6daNh_cFffs */
|
|
BOOL daNh_c::moveProc(f32 targetSpeed, f32 speedStep, s16 targetAngle) {
|
|
cLib_chaseAngleS(¤t.angle.y, targetAngle, 0x400);
|
|
shape_angle.y = current.angle.y;
|
|
if (cLib_chaseF(&speedF, targetSpeed, speedStep) && targetSpeed == 0.0f) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* 800FA19C-800FA260 .text getHomeDistance__6daNh_cFv */
|
|
f32 daNh_c::getHomeDistance() {
|
|
cXyz delta = home.pos - current.pos;
|
|
return cXyz(delta.x, 0.0f, delta.z).abs();
|
|
}
|
|
|
|
/* 800FA260-800FA2E4 .text checkTimer__6daNh_cFv */
|
|
BOOL daNh_c::checkTimer() {
|
|
// Count down after being released from a bottle.
|
|
if (isTypeBottle() && cLib_calcTimer(&mBottleTimer) == 0) {
|
|
// Timer finished, start fading out.
|
|
mAlpha -= 4;
|
|
if (mAlpha < 0) {
|
|
mAlpha = 0;
|
|
}
|
|
if (mAlpha == 0) {
|
|
fopAcM_delete(this);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* 800FA2E4-800FA568 .text BGCheck__6daNh_cFv */
|
|
void daNh_c::BGCheck() {
|
|
dBgS_ObjGndChk_All gndChk;
|
|
gndChk.SetPos(¤t.pos);
|
|
f32 groundY = dComIfG_Bgsp()->GroundCross(&gndChk);
|
|
if (groundY != -1000000000.0f) {
|
|
mGroundY = groundY;
|
|
tevStr.mRoomNo = current.roomNo = dComIfG_Bgsp()->GetRoomId(gndChk);
|
|
tevStr.mEnvrIdxOverride = dComIfG_Bgsp()->GetPolyColor(gndChk);
|
|
}
|
|
}
|
|
|
|
/* 800FA568-800FA5B4 .text airMove__6daNh_cFv */
|
|
void daNh_c::airMove() {
|
|
f32 idealY = mGroundY + l_HIO.prm.mHeightAboveGround;
|
|
if (current.pos.y < idealY - 10.0f) {
|
|
maxFallSpeed = l_HIO.prm.mAscentSpeed;
|
|
} else if (current.pos.y > idealY + 10.0f) {
|
|
maxFallSpeed = l_HIO.prm.mDescentSpeed;
|
|
}
|
|
}
|
|
|
|
/* 800FA5B4-800FA674 .text waitAction__6daNh_cFPv */
|
|
BOOL daNh_c::waitAction(void*) {
|
|
if (mActionStatus == ACTION_STARTING) {
|
|
mActionStatus += 1; // ACTION_ONGOING
|
|
mPlayerDist = fopAcM_searchPlayerDistance(this);
|
|
} else if (mActionStatus != ACTION_ENDING) {
|
|
cLib_addCalc(&speedF, 0.0f, 0.1f, 10.0f, 1.0f);
|
|
if (getHomeDistance() > 50.0f) {
|
|
setAction(&daNh_c::returnAction, NULL);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FA674-800FA78C .text checkEscapeEnd__6daNh_cFv */
|
|
BOOL daNh_c::checkEscapeEnd() {
|
|
cXyz homeDelta = home.pos - current.pos;
|
|
if (!isTypeBottle()) {
|
|
if (cLib_calcTimer(&mEscapeTimer) == 0) {
|
|
setAction(&daNh_c::waitAction, NULL);
|
|
return TRUE;
|
|
}
|
|
if (homeDelta.abs2XZ() > l_HIO.prm.mMaxHomeDist*l_HIO.prm.mMaxHomeDist) {
|
|
setAction(&daNh_c::returnAction, NULL);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* 800FA78C-800FA880 .text escapeAction__6daNh_cFPv */
|
|
BOOL daNh_c::escapeAction(void*) {
|
|
// Run away after being released from a bottle.
|
|
if (mActionStatus == ACTION_STARTING) {
|
|
mActionStatus += 1; // ACTION_ONGOING
|
|
mWobbleDir = 0;
|
|
mWobbleTimer = 0;
|
|
mEscapeTimer = 5*30;
|
|
} else if (mActionStatus != ACTION_ENDING) {
|
|
if (!checkEscapeEnd()) {
|
|
s16 targetAngle = fopAcM_searchPlayerAngleY(this) + 0x8000;
|
|
if (cLib_calcTimer(&mWobbleTimer) == 0) {
|
|
mWobbleDir ^= 1;
|
|
mWobbleTimer = cLib_getRndValue(15, 20);
|
|
}
|
|
targetAngle += mWobbleDir ? -0x2000 : 0x2000;
|
|
moveProc(5.0f, 0.5f, targetAngle);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FA880-800FAA34 .text returnAction__6daNh_cFPv */
|
|
BOOL daNh_c::returnAction(void*) {
|
|
// Try to head in the direction of home (the Forest Firefly's spawn position).
|
|
if (mActionStatus == ACTION_STARTING) {
|
|
mActionStatus += 1; // ACTION_ONGOING
|
|
mWobbleDir = 0;
|
|
mWobbleTimer = 0;
|
|
mEscapeTimer = 5*30;
|
|
} else if (mActionStatus != ACTION_ENDING) {
|
|
if (getHomeDistance() < 50.0f) {
|
|
setAction(&daNh_c::waitAction, NULL);
|
|
} else {
|
|
s16 targetAngle = cLib_targetAngleY(¤t.pos, &home.pos);
|
|
cXyz homeDelta = home.pos - current.pos;
|
|
if (homeDelta.abs2XZ() < l_HIO.prm.mMaxHomeDist*l_HIO.prm.mMaxHomeDist) {
|
|
s16 angle = targetAngle - fopAcM_searchPlayerAngleY(this);
|
|
if (abs(angle) < 0x1000) {
|
|
if (angle < 0) {
|
|
targetAngle -= 0x4000;
|
|
} else {
|
|
targetAngle += 0x4000;
|
|
}
|
|
}
|
|
}
|
|
if (cLib_calcTimer(&mWobbleTimer) == 0) {
|
|
mWobbleDir ^= 1;
|
|
mWobbleTimer = cLib_getRndValue(15, 20);
|
|
}
|
|
targetAngle += mWobbleDir ? -0x2000 : 0x2000;
|
|
moveProc(5.0f, 0.5f, targetAngle);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FAA34-800FABE0 .text execute__6daNh_cFv */
|
|
BOOL daNh_c::execute() {
|
|
playBrkAnm();
|
|
|
|
mGlowAlpha = l_HIO.prm.mDefaultGlowAlpha;
|
|
|
|
if (maxFallSpeed < speed.y) {
|
|
speed.y -= gravity;
|
|
if (speed.y < maxFallSpeed) {
|
|
speed.y = maxFallSpeed;
|
|
}
|
|
} else if (maxFallSpeed > speed.y) {
|
|
speed.y += gravity;
|
|
if (speed.y > maxFallSpeed) {
|
|
speed.y = maxFallSpeed;
|
|
}
|
|
}
|
|
|
|
speed.x = speedF * cM_ssin(current.angle.y);
|
|
speed.z = speedF * cM_scos(current.angle.y);
|
|
|
|
fopAcM_posMove(this, mStts.GetCCMoveP());
|
|
|
|
BGCheck();
|
|
|
|
cXyz pos = current.pos;
|
|
pos.y -= 10.0f;
|
|
mCyl.SetC(pos);
|
|
dComIfG_Ccsp()->Set(&mCyl);
|
|
|
|
checkTimer();
|
|
|
|
if (!checkBinCatch()) {
|
|
airMove();
|
|
searchPlayer();
|
|
action(NULL);
|
|
}
|
|
|
|
setBaseMtx();
|
|
eyePos = attention_info.position = current.pos;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FABE0-800FACC4 .text initBrkAnm__6daNh_cFb */
|
|
BOOL daNh_c::initBrkAnm(bool i_modify) {
|
|
J3DModelData* modelData = mpModel->getModelData();
|
|
bool success = false;
|
|
|
|
J3DAnmTevRegKey* a_brk = (J3DAnmTevRegKey*)dComIfG_getObjectRes("Always", ALWAYS_BRK_TNH);
|
|
JUT_ASSERT(883, a_brk != NULL);
|
|
|
|
if (mBrkAnm.init(modelData, a_brk, true, J3DFrameCtrl::LOOP_REPEAT_e, 1.0f, 0, -1, i_modify, false)) {
|
|
success = true;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
/* 800FACC4-800FACE8 .text playBrkAnm__6daNh_cFv */
|
|
void daNh_c::playBrkAnm() {
|
|
mBrkAnm.play();
|
|
}
|
|
|
|
/* 800FACE8-800FAE1C .text draw__6daNh_cFv */
|
|
BOOL daNh_c::draw() {
|
|
g_env_light.settingTevStruct(TEV_TYPE_ACTOR, ¤t.pos, &tevStr);
|
|
g_env_light.setLightTevColorType(mpModel, &tevStr);
|
|
|
|
J3DModelData* modelData = mpModel->getModelData();
|
|
|
|
mBrkAnm.entry(modelData);
|
|
mDoExt_modelUpdateDL(mpModel);
|
|
modelData->getMaterialTable().removeTevRegAnimator(mBrkAnm.getBrkAnm());
|
|
|
|
J3DMaterial* mat = modelData->getMaterialNodePointer(0);
|
|
if (mat) {
|
|
J3DTevBlock* tevBlock = mat->getTevBlock();
|
|
if (tevBlock) {
|
|
GXColorS10* color = &tevBlock->getTevColor(1)->mColor;
|
|
if (color) {
|
|
mGlowAlpha = ((color->r + color->g + color->b) / 3) >> 2;
|
|
}
|
|
|
|
GXColor* kColor = &tevBlock->getTevKColor(3)->mColor;
|
|
if (kColor) {
|
|
kColor->a = mAlpha;
|
|
}
|
|
}
|
|
}
|
|
|
|
dComIfGd_setAlphaModel(dDlst_alphaModel_c::TYPE_SPHERE, mGlowMtx, mGlowAlpha);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FAE1C-800FAE3C .text daNh_Draw__FP6daNh_c */
|
|
static BOOL daNh_Draw(daNh_c* i_this) {
|
|
return i_this->draw();
|
|
}
|
|
|
|
/* 800FAE3C-800FAE5C .text daNh_Execute__FP6daNh_c */
|
|
static BOOL daNh_Execute(daNh_c* i_this) {
|
|
return i_this->execute();
|
|
}
|
|
|
|
/* 800FAE5C-800FAE64 .text daNh_IsDelete__FP6daNh_c */
|
|
static BOOL daNh_IsDelete(daNh_c* i_this) {
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FAE64-800FAE8C .text daNh_Delete__FP6daNh_c */
|
|
static BOOL daNh_Delete(daNh_c* i_this) {
|
|
i_this->~daNh_c();
|
|
return TRUE;
|
|
}
|
|
|
|
/* 800FAE8C-800FAEAC .text daNh_Create__FP10fopAc_ac_c */
|
|
static s32 daNh_Create(fopAc_ac_c* i_this) {
|
|
return ((daNh_c*)i_this)->create();
|
|
}
|
|
|
|
static actor_method_class l_daNh_Method = {
|
|
(process_method_func)daNh_Create,
|
|
(process_method_func)daNh_Delete,
|
|
(process_method_func)daNh_Execute,
|
|
(process_method_func)daNh_IsDelete,
|
|
(process_method_func)daNh_Draw,
|
|
};
|
|
|
|
actor_process_profile_definition g_profile_NH = {
|
|
/* LayerID */ fpcLy_CURRENT_e,
|
|
/* ListID */ 0x0007,
|
|
/* ListPrio */ fpcPi_CURRENT_e,
|
|
/* ProcName */ PROC_NH,
|
|
/* Proc SubMtd */ &g_fpcLf_Method.base,
|
|
/* Size */ sizeof(daNh_c),
|
|
/* SizeOther */ 0,
|
|
/* Parameters */ 0,
|
|
/* Leaf SubMtd */ &g_fopAc_Method.base,
|
|
/* Priority */ 0x013C,
|
|
/* Actor SubMtd */ &l_daNh_Method,
|
|
/* Status */ fopAcStts_CULL_e | fopAcStts_UNK40000_e,
|
|
/* Group */ fopAc_ACTOR_e,
|
|
/* CullType */ fopAc_CULLBOX_0_e,
|
|
};
|