1#include "Game/MapObj/CrystalCage.hpp"
2#include "Game/LiveActor/ModelObj.hpp"
3#include "Game/Util.hpp"
4#include "JSystem/JMath.hpp"
6CrystalCage::CrystalCage(
const char *pName) :
LiveActor(pName),
7 mCrystalCageType(0), mBreakObj(nullptr), _C4(1), _C8(0), mRumbleCalc(nullptr), _D0(0.0f, 1.0f), _DC(gZeroVec), _E8(gZeroVec),
8 mDisplayModel(nullptr), _F8(gZeroVec), _104(0), _108(-1), mIsBreakObjVisible(false), mPlayRiddleSFX(false), mHasBinding(false), _110(gZeroVec) {
15 MR::getObjectName(&obj_name, rIter);
16 initMapToolInfo(rIter);
17 MR::calcGravity(
this);
19 MR::connectToSceneCrystal(
this);
22 MR::addHitSensorPosMapObj(
this,
"body", 8, (130.0f *
mScale.x), &_E8, TVec3f(0.0f, 0.0f, 0.0f));
26 if (mCrystalCageType) {
27 MR::invalidateHitSensors(
this);
31 initBinder(50.0f, 0.0f, 0);
32 MR::setBinderOffsetVec(
this, &_110,
nullptr);
33 MR::setBinderExceptActor(
this,
this);
36 if (mCrystalCageType != 2) {
37 initEffectKeeper(0,
nullptr,
false);
40 MR::initCollisionParts(
this, obj_name,
getSensor(
"body"),
nullptr);
42 f32 range = !mCrystalCageType ? 300.0f : 600.0f;
43 MR::setClippingTypeSphere(
this, range *
mScale.x);
46 if (mCrystalCageType == 2) {
47 f32 mult =
mScale.x * 250.0f;
53 mDisplayModel = MR::createDummyDisplayModelCrystalItem(
this, 7, v21, TVec3f(0.0f, 0.0f, 0.0f));
56 MR::declarePowerStar(
this);
59 MR::declarePowerStar(
this, _108);
63 if (!mCrystalCageType) {
64 v23.set<f32>(-30.0f, 100.0f, -30.0f);
67 v23.set<f32>(0.0f, 200.0f, 0.0f);
70 mDisplayModel = MR::createDummyDisplayModelCrystalItem(
this, rIter, v23, TVec3f(0.0f, 0.0f, 0.0f));
73 switch (MR::getDummyDisplayModelId(rIter, -1)) {
75 MR::declareCoin(
this, 1);
78 MR::startBva(mDisplayModel,
"Freeze");
83 MR::startBva(
this, obj_name);
84 MR::setBvaFrameAndStop(
this, 0.0f);
90 MR::joinToGroupArray(
this, rIter,
nullptr, 0x20);
91 initNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance);
93 if (MR::tryRegisterDemoCast(
this, rIter)) {
95 MR::tryRegisterDemoCast(mDisplayModel, rIter);
99 if (mCrystalCageType == 2) {
104 if (MR::isExistStageSwitchSleep(rIter)) {
105 MR::useStageSwitchSleep(
this, rIter);
110 if (MR::useStageSwitchReadAppear(
this, rIter)) {
111 MR::syncStageSwitchAppear(
this);
119void CrystalCage::initAfterPlacement() {
120 if (!mIsBreakObjVisible || mHasBinding) {
121 f32 val = mCrystalCageType == 2 ? 1000.0f : 300.0f;
125 MR::calcUpVec(&up_vec,
this);
127 JMathInlineVEC::PSVECAdd(
mPosition.toCVec(), (Vec *) &(up_vec * (val *
mScale.x)), stack_20.toVec());
128 stack_2C.scale((-(2.0f * val) *
mScale.x), up_vec);
130 if (!MR::getFirstPolyOnLineToMapExceptActor(&_F8, 0, stack_20, stack_2C,
this)) {
136 JMathInlineVEC::PSVECAdd(_110.toCVec(), (up_vec * 50.0f).toCVec(), _110.toVec());
142void CrystalCage::kill() {
147 mDisplayModel->kill();
151void CrystalCage::forceBreak() {
152 if (isNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance)) {
153 if (!_104 || MR::isClipped(
this)) {
154 MR::tryRumblePadStrong(
this, 0);
155 MR::invalidateClipping(
this);
156 MR::invalidateCollisionParts(
this);
157 MR::invalidateHitSensors(
this);
158 setNerve(&NrvCrystalCage::CrystalCageNrvBreak::sInstance);
167 if (!mCrystalCageType) {
168 MR::sendMsgPush(a2, a1);
173 if (!isNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance)) {
177 if (!MR::isMsgPlayerHitAll(msg)) {
181 if (_C4 > 0 && !_C8) {
183 MR::invalidateClipping(
this);
184 MR::invalidateCollisionParts(
this);
185 MR::invalidateHitSensors(
this);
186 setNerve(&NrvCrystalCage::CrystalCageNrvBreak::sInstance);
187 MR::startCSSound(
"CS_SPIN_HIT",
nullptr, 0);
191 if (MR::sendArbitraryMsg(63, a2, a3)) {
195 MR::setBvaFrameAndStop(
this, 1.0f);
196 if (mCrystalCageType == 2) {
197 MR::startSound(
this,
"SE_OJ_CRYSTAL_CAGE_L_DAMAGE", -1, -1);
200 MR::startSound(
this,
"SE_OJ_CRYSTAL_CAGE_S_DAMAGE", -1, -1);
203 mRumbleCalc->start(0);
204 _D0.sub(a2->mPosition, a3->mPosition);
214 if (mCrystalCageType != 2 && isNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance)) {
215 MR::invalidateClipping(
this);
216 MR::invalidateCollisionParts(
this);
217 MR::invalidateHitSensors(
this);
218 setNerve(&NrvCrystalCage::CrystalCageNrvBreak::sInstance);
225void CrystalCage::initMapToolInfo(
const JMapInfoIter &rIter) {
226 MR::initDefaultPos(
this, rIter);
229 if (MR::isEqualObjectName(rIter,
"CrystalCageS")) {
230 mCrystalCageType = 0;
232 else if (MR::isEqualObjectName(rIter,
"CrystalCageM")) {
233 mCrystalCageType = 1;
236 mCrystalCageType = 2;
239 if (mCrystalCageType == 2) {
240 MR::getJMapInfoArg0NoInit(rIter, &_108);
243 MR::useStageSwitchWriteDead(
this, rIter);
245 if (MR::useStageSwitchReadA(
this, rIter)) {
247 MR::listenStageSwitchOnA(
this, forceFunc);
250 MR::getJMapInfoArg0NoInit(rIter, &mIsBreakObjVisible);
251 MR::getJMapInfoArg1NoInit(rIter, &mPlayRiddleSFX);
252 MR::getJMapInfoArg2NoInit(rIter, &mHasBinding);
253 MR::getJMapInfoArg3NoInit(rIter, &_104);
257void CrystalCage::initModel(
const char *pName) {
258 initModelManagerWithAnm(pName,
nullptr,
false);
261 MR::makeMtxUpNoSupportPos(&_94, stack_8, _DC);
263 if (mCrystalCageType == 2) {
264 mBreakObj = MR::createModelObjMapObjStrongLight(
"クリスタルケージ[大]壊れモデル",
"CrystalCageLBreak", (MtxPtr)&_94);
267 mBreakObj = MR::createModelObjMapObjStrongLight(
"クリスタルケージ[小]壊れモデル",
"CrystalCageSBreak", (MtxPtr)&_94);
270 MR::invalidateClipping(
this);
272 MR::registerDemoSimpleCastAll(mBreakObj);
273 mBreakObj->makeActorDead();
276void CrystalCage::tryOnSwitchDead() {
277 if (mCrystalCageType == 2 || !MR::isValidSwitchDead(
this)) {
283 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 3) {
287 if (MR::isStep(
this, step)) {
288 MR::onSwitchDead(
this);
292void CrystalCage::exeWait() {
298 if (mRumbleCalc->_4 < mRumbleCalc->_8) {
301 v9.scale(mRumbleCalc->_C.y, _D0);
302 JMathInlineVEC::PSVECAdd(_DC.toCVec(), v9.toCVec(),
mPosition.toVec());
309 if (mCrystalCageType == 0) {
311 MR::calcUpVec(&up_vec,
this);
313 v6.scale(-40.0f, up_vec);
314 JMathInlineVEC::PSVECAdd(v6.toCVec(),
mPosition.toCVec(), v6.toVec());
316 v5.scale(140.0f, up_vec);
317 JMathInlineVEC::PSVECAdd(v5.toCVec(),
mPosition.toCVec(), v5.toVec());
318 MR::calcPerpendicFootToLineInside(&_E8, *MR::getPlayerPos(), v6, v5);
322void CrystalCage::exeBreak() {
323 if (MR::isFirstStep(
this)) {
324 if (mIsBreakObjVisible) {
328 MR::setBvaFrameAndStop(
this, mCrystalCageType == 2 ? 2.0f : 1.0f);
340 MR::startBck(mBreakObj,
"Break",
nullptr);
342 if (mCrystalCageType == 2) {
343 MR::startSound(
this,
"SE_OJ_CRYSTAL_CAGE_L_BREAK", -1, -1);
345 MR::requestAppearPowerStar(
this, mDisplayModel->
mPosition);
348 MR::requestAppearPowerStar(
this, _108, mDisplayModel->
mPosition);
352 MR::emitEffect(
this,
"Break");
353 MR::startSound(
this,
"SE_OJ_CRYSTAL_CAGE_S_BREAK", -1, -1);
355 if (mPlayRiddleSFX) {
356 MR::startSystemSE(
"SE_SY_READ_RIDDLE_S", -1, -1);
360 if (mDisplayModel && !MR::getDummyDisplayModelId(mDisplayModel)) {
361 MR::appearCoinPop(
this, mDisplayModel->
mPosition, 1);
364 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 5) {
365 MR::startSound(
this,
"SE_OJ_CRY_CAGE_MV_TICO_APR", -1, -1);
368 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 1) {
369 MR::startSound(
this,
"SE_SV_KINOPIO_PUHA", -1, -1);
373 mDisplayModel->kill();
377 if (mCrystalCageType != 2 && MR::isStep(
this, 2)) {
383 if (MR::isBckStopped(mBreakObj)) {
384 if (mIsBreakObjVisible) {
388 setNerve(&NrvCrystalCage::CrystalCageNrvBreakAfter::sInstance);
393void CrystalCage::exeBreakAfter() {
394 if (MR::isFirstStep(
this)) {
395 MR::validateClipping(
this);
400namespace NrvCrystalCage {
401 INIT_NERVE(CrystalCageNrvWait);
402 INIT_NERVE(CrystalCageNrvBreak);
403 INIT_NERVE(CrystalCageNrvBreakAfter);
405 void CrystalCageNrvBreakAfter::execute(
Spine *pSpine)
const {
407 cage->exeBreakAfter();
410 void CrystalCageNrvBreak::execute(
Spine *pSpine)
const {
415 void CrystalCageNrvWait::execute(
Spine *pSpine)
const {
421CrystalCage::~CrystalCage() {
virtual void init(const JMapInfoIter &)
Intializes the NameObj and can set various settings and construct necessary classes.
The basis of a drawable actor that can contain states (see: Nerve)
TVec3f mPosition
3D vector of the actor's position.
TVec3f mScale
3D vector of the actor's scale.
TVec3f mVelocity
3D vector of the actor's velocity.
TVec3f mGravity
3D vector of the actor's gravity.
HitSensor * getSensor(const char *pSensorName) const
Gets a sensor.