Files
ss/src/REL/d/t/d_t_reaction.cpp
T
2025-05-10 22:20:16 +02:00

296 lines
8.6 KiB
C++

#include "d/t/d_t_reaction.h"
#include "c/c_lib.h"
#include "c/c_math.h"
#include "d/a/d_a_item.h"
#include "d/a/d_a_player.h"
#include "d/col/c/c_cc_d.h"
#include "d/col/cc/d_cc_s.h"
#include "d/d_pouch.h"
#include "d/flag/sceneflag_manager.h"
#include "m/m_angle.h"
#include "toBeSorted/small_sound_mgr.h"
SPECIAL_ACTOR_PROFILE(TAG_REACTION, dTgReaction_c, fProfile::TAG_REACTION, 0x0151, 0, 0);
STATE_DEFINE(dTgReaction_c, Wait);
#pragma explicit_zero_data on
const u32 fZero = 0;
#pragma explicit_zero_data off
const f32 dTgReaction_c::sRadius = 100.0f;
const f32 dTgReaction_c::sHeight = 100.0f;
// clang-format off
dCcD_SrcCyl dTgReaction_c::sCcSrc = {
{{0, 0, 0, 0, 0, 0, 0, 0, 0},
{AT_TYPE_BELLOWS, 0x213, {0, 0, 0x8},0x8},
{0xE8}},
{dTgReaction_c::sRadius, dTgReaction_c::sHeight}
};
// clang-format on
#pragma explicit_zero_data on
static u32 initialRotX = 0;
#pragma explicit_zero_data off
bool dTgReaction_c::createHeap() {
return true;
}
extern "C" bool isHeroMode();
int dTgReaction_c::create() {
// Note the double _c here
if (!initAllocatorWork1Heap(0x1000, "dTgReaction_c_c::m_allocator", 0x20)) {
return FAILED;
}
if (getReactType() != REACT_UNDERWATER) {
if (getSceneFlag() >= 0xFF) {
return FAILED;
}
if (SceneflagManager::sInstance->checkBoolFlag(roomid, getSceneFlag())) {
return FAILED;
}
}
field_0x4E0 = rotation.x & 0xFF;
angle.x = initialRotX;
rotation.x = angle.x;
if (field_0x4E0 < 0xFF && !SceneflagManager::sInstance->checkBoolFlag(roomid, field_0x4E0)) {
return FAILED;
}
if (isHeroMode()) {
if (getParam0x10() == 1) {
field_0x4DE = 1;
}
if (field_0x4DE) {
u32 heartMedalCount = adventurePouchCountItem(ITEM_HEART_MEDAL);
if (heartMedalCount == 0) {
return FAILED;
} else if (heartMedalCount == 1 && cM::rnd() < 0.5f) {
return FAILED;
}
}
}
mStts.SetRank(0);
mCollision.Set(sCcSrc);
mCollision.SetStts(mStts);
switch (getReactType()) {
case REACT_SLINGSHOT:
mCollision.SetTgType(AT_TYPE_SLINGSHOT);
mCollision.SetTgFlag_0xA(0);
mCollision.SetR(sCcSrc.mCylInf.mRadius * mScale.x);
mCollision.SetH(sCcSrc.mCylInf.mHeight * mScale.y);
break;
case REACT_GUST_BELLOWS:
mCollision.SetTgType(AT_TYPE_BELLOWS);
mCollision.SetTgFlag_0xA(8);
mCollision.SetR(sCcSrc.mCylInf.mRadius * mScale.x);
mCollision.SetH(sCcSrc.mCylInf.mHeight * mScale.y);
break;
case REACT_UNDERWATER:
mCollision.SetTgType(AT_TYPE_BUBBLE);
mCollision.SetTgFlag_0xA(0);
mCollision.SetR(sCcSrc.mCylInf.mRadius * mScale.x);
mCollision.SetH(sCcSrc.mCylInf.mHeight * mScale.y);
break;
case REACT_BONK:
case REACT_4: break;
}
int item = getParam0x10();
if (item != 0xF) {
DowsingTarget::DowsingSlot slot;
if (item == 0) {
slot = DowsingTarget::SLOT_RUPEE;
} else if (item == 1) {
slot = DowsingTarget::SLOT_HEART;
} else {
return FAILED;
}
mVec3_c dwsOffset;
if (!getParam0x14()) {
field_0x4E4 = mScale.y * sCcSrc.mCylInf.mHeight * 0.5f;
dwsOffset = mVec3_c(0.0f, sCcSrc.mCylInf.mHeight * 0.5f, 0.0f);
} else {
dwsOffset = mVec3_c::Zero;
}
mDowsingTarget.initialize(slot, 0, &dwsOffset, 5000.0f);
mDowsingTarget.doRegister();
mHasDowsingTarget = true;
}
mStateMgr.changeState(StateID_Wait);
return SUCCEEDED;
}
int dTgReaction_c::doDelete() {
onDelete();
return SUCCEEDED;
}
int dTgReaction_c::actorExecute() {
if (SceneflagManager::sInstance->checkBoolFlag(roomid, getSceneFlag())) {
onDelete();
return SUCCEEDED;
} else {
mStateMgr.executeState();
return SUCCEEDED;
}
}
int dTgReaction_c::draw() {
return SUCCEEDED;
}
void dTgReaction_c::initializeState_Wait() {}
void dTgReaction_c::executeState_Wait() {
switch (getReactType()) {
case REACT_BONK:
case REACT_4: checkForBonkItem(); break;
case REACT_SLINGSHOT:
case REACT_GUST_BELLOWS: checkForSlingBellowsItem(); break;
case REACT_UNDERWATER: checkForBubble(); break;
}
}
void dTgReaction_c::finalizeState_Wait() {}
void dTgReaction_c::checkForBonkItem() {
if (dAcPy_c::LINK != nullptr && dAcPy_c::LINK->checkFlags0x350(0x2000)) {
mVec3_c diff = position - dAcPy_c::LINK->position;
f32 dist = diff.x * diff.x + diff.z * diff.z;
f32 rad = mScale.x * 100.0f;
if (!(dist < rad * rad)) {
return;
}
if (getReactType() == REACT_4) {
if (field_0x4DD == 0) {
mVec3_c c = mVec3_c::Ez * rad;
mVec3_c c2 = position;
c.rotY(rotation.y);
c2 += c;
c2.y += field_0x4E4;
u32 newItemParms = dAcItem_c::createItemParams(ITEM_HEART_PIECE, 1, 0, getSceneFlag(), 1, 0xFF);
if (dAcObjBase_c::create(fProfile::ITEM, roomid, newItemParms, &c2, nullptr, nullptr, 0xFFFFFFFF)) {
field_0x4DD = 1;
onDelete();
SmallSoundManager::GetInstance()->playSound(SE_S_READ_RIDDLE_A);
}
}
} else {
u32 uVar3;
mVec3_c pos = position;
int p = getParam0x08();
if (p == 0) {
uVar3 = 6;
} else if (p == 0xFF) {
uVar3 = 5;
} else if (p == 1) {
uVar3 = 5;
mVec3_c c = mVec3_c::Ez * rad;
c.rotY(rotation.y);
pos += c;
} else {
uVar3 = 6;
}
pos.y += field_0x4E4;
if (fn_578_DB0(pos, uVar3)) {
SmallSoundManager::GetInstance()->playSound(SE_S_READ_RIDDLE_B);
}
SceneflagManager::sInstance->setFlag(roomid, getSceneFlag());
onDelete();
}
}
}
void dTgReaction_c::checkForBubble() {
if (mCollision.ChkTgHit() && mCollision.ChkTgAtHitType(AT_TYPE_BUBBLE)) {
if (dAcPy_c::LINK != nullptr && dAcPy_c::LINK->checkFlags0x350(0x40)) {
mVec3_c spawnPos = position;
dAcObjBase_c::create(fProfile::OBJ_BUBBLE, roomid, 0x4, &spawnPos, nullptr, nullptr, 0xFFFFFFFF);
}
}
mCollision.SetC(position);
dCcS::GetInstance()->Set(&mCollision);
}
void dTgReaction_c::checkForSlingBellowsItem() {
if (mCollision.ChkTgHit()) {
u8 p = getParam0x08();
u32 uVar3;
if (p == 0) {
uVar3 = 6;
} else {
uVar3 = 6;
if ((int)p == 0xFF) {
uVar3 = 5;
}
}
mVec3_c spawnPos = position;
spawnPos.y += field_0x4E4;
if (fn_578_DB0(spawnPos, uVar3)) {
SmallSoundManager::GetInstance()->playSound(SE_S_READ_RIDDLE_B);
}
SceneflagManager::sInstance->setFlag(roomid, getSceneFlag());
onDelete();
}
mCollision.SetC(position);
dCcS::GetInstance()->Set(&mCollision);
}
void dTgReaction_c::onDelete() {
if (mHasDowsingTarget) {
mDowsingTarget.doUnregister();
mHasDowsingTarget = false;
}
}
bool dTgReaction_c::fn_578_DB0(const mVec3_c &position, u32 arg) {
return true;
}
static s32 SOME_ANG = -3641;
bool dTgReaction_c::spawnHearts(s32 params, const mVec3_c &pos, s32 velocity_type, mAng angle) {
int numHearts = params == 6 ? 3 : 1;
mAng3_c ang(0, 0, 0);
// This is annoying because we don't know which operators
// mAng supports
s32 max;
s32 min;
if (velocity_type == 6) {
max = angle;
min = SOME_ANG;
} else {
max = (s16)cLib::targetAngleY(dAcPy_c::LINK->position, pos) + 0x4000;
min = -0x8000;
}
s16 stepSize = s16(min) / numHearts;
mAng range = stepSize / 2;
s32 step = s16(max) + range;
mAng rndMax = range / 2;
mAng rndMin = -rndMax;
for (int i = 0; i < numHearts; i++) {
ang.y = mAng(step) + cM::rndRange(rndMin, rndMax);
if (velocity_type == 5) {
dAcItem_c::spawnItem(ITEM_HEART, roomid, pos, ang, 0xFFFFFFFF, 1);
} else if (velocity_type == 6) {
dAcItem_c::spawnItem(ITEM_HEART, roomid, pos, ang, 0xFFFFFFFF, 0);
} else {
dAcItem_c::spawnDrop(ITEM_HEART, roomid, pos, ang);
}
step = mAng(step) - stepSize;
}
return true;
}