SMG-Decomp
A decompilation of Super Mario Galaxy 1
Loading...
Searching...
No Matches
CrystalCage.cpp
1#include "Game/MapObj/CrystalCage.hpp"
2#include "Game/LiveActor/ModelObj.hpp"
3#include "Game/Util.hpp"
4#include "JSystem/JMath.hpp"
5
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) {
9 _94.identity();
10}
11
12void CrystalCage::init(const JMapInfoIter &rIter) {
13 const char* obj_name;
14 TVec3f v23;
15 MR::getObjectName(&obj_name, rIter);
16 initMapToolInfo(rIter);
17 MR::calcGravity(this);
18 initModel(obj_name);
19 MR::connectToSceneCrystal(this);
20 _E8.set<f32>(mPosition);
21 initHitSensor(1);
22 MR::addHitSensorPosMapObj(this, "body", 8, (130.0f * mScale.x), &_E8, TVec3f(0.0f, 0.0f, 0.0f));
23
24 TVec3f v21;
25
26 if (mCrystalCageType) {
27 MR::invalidateHitSensors(this);
28 }
29
30 if (mHasBinding) {
31 initBinder(50.0f, 0.0f, 0);
32 MR::setBinderOffsetVec(this, &_110, nullptr);
33 MR::setBinderExceptActor(this, this);
34 }
35
36 if (mCrystalCageType != 2) {
37 initEffectKeeper(0, nullptr, false);
38 }
39
40 MR::initCollisionParts(this, obj_name, getSensor("body"), nullptr);
41
42 f32 range = !mCrystalCageType ? 300.0f : 600.0f;
43 MR::setClippingTypeSphere(this, range * mScale.x);
44 initSound(4, false);
45
46 if (mCrystalCageType == 2) {
47 f32 mult = mScale.x * 250.0f;
48 _C4 = 2;
49
50 v21.x = 0.0f;
51 v21.y = mult;
52 v21.z = 0.0f;
53 mDisplayModel = MR::createDummyDisplayModelCrystalItem(this, 7, v21, TVec3f(0.0f, 0.0f, 0.0f));
54
55 if (_108 == -1) {
56 MR::declarePowerStar(this);
57 }
58 else {
59 MR::declarePowerStar(this, _108);
60 }
61 }
62 else {
63 if (!mCrystalCageType) {
64 v23.set<f32>(-30.0f, 100.0f, -30.0f);
65 }
66 else {
67 v23.set<f32>(0.0f, 200.0f, 0.0f);
68 }
69
70 mDisplayModel = MR::createDummyDisplayModelCrystalItem(this, rIter, v23, TVec3f(0.0f, 0.0f, 0.0f));
71
72 if (mDisplayModel) {
73 switch (MR::getDummyDisplayModelId(rIter, -1)) {
74 case 0:
75 MR::declareCoin(this, 1);
76 break;
77 case 4:
78 MR::startBva(mDisplayModel, "Freeze");
79 }
80 }
81 }
82
83 MR::startBva(this, obj_name);
84 MR::setBvaFrameAndStop(this, 0.0f);
85
86 if (_C4 > 1) {
87 mRumbleCalc = new RumbleCalculatorCosMultLinear(4.0f, 1.5707964f, 50.0f, 0x14);
88 }
89
90 MR::joinToGroupArray(this, rIter, nullptr, 0x20);
91 initNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance);
92
93 if (MR::tryRegisterDemoCast(this, rIter)) {
94 if (mDisplayModel) {
95 MR::tryRegisterDemoCast(mDisplayModel, rIter);
96 }
97 }
98
99 if (mCrystalCageType == 2) {
100 makeActorAppeared();
101 return;
102 }
103
104 if (MR::isExistStageSwitchSleep(rIter)) {
105 MR::useStageSwitchSleep(this, rIter);
106 makeActorDead();
107 return;
108 }
109
110 if (MR::useStageSwitchReadAppear(this, rIter)) {
111 MR::syncStageSwitchAppear(this);
112 makeActorDead();
113 }
114 else {
115 makeActorAppeared();
116 }
117}
118
119void CrystalCage::initAfterPlacement() {
120 if (!mIsBreakObjVisible || mHasBinding) {
121 f32 val = mCrystalCageType == 2 ? 1000.0f : 300.0f;
122 TVec3f up_vec;
123 TVec3f stack_2C;
124 TVec3f stack_20;
125 MR::calcUpVec(&up_vec, this);
126 // I realy do not like this, but it matches :c
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);
129
130 if (!MR::getFirstPolyOnLineToMapExceptActor(&_F8, 0, stack_20, stack_2C, this)) {
131 _F8.set<f32>(mPosition);
132 }
133
134 if (mHasBinding) {
135 _110.sub(_F8, mPosition);
136 JMathInlineVEC::PSVECAdd(_110.toCVec(), (up_vec * 50.0f).toCVec(), _110.toVec());
137 mVelocity.scale(-2.0f, up_vec);
138 }
139 }
140}
141
142void CrystalCage::kill() {
143 LiveActor::kill();
144 mBreakObj->kill();
145
146 if (mDisplayModel) {
147 mDisplayModel->kill();
148 }
149}
150
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);
159 }
160 else {
161 kill();
162 }
163 }
164}
165
166void CrystalCage::attackSensor(HitSensor *a1, HitSensor *a2) {
167 if (!mCrystalCageType) {
168 MR::sendMsgPush(a2, a1);
169 }
170}
171
172bool CrystalCage::receiveMsgPlayerAttack(u32 msg, HitSensor *a2, HitSensor *a3) {
173 if (!isNerve(&NrvCrystalCage::CrystalCageNrvWait::sInstance)) {
174 return 0;
175 }
176
177 if (!MR::isMsgPlayerHitAll(msg)) {
178 return false;
179 }
180
181 if (_C4 > 0 && !_C8) {
182 if (_C4 == 1) {
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);
188 return 1;
189 }
190
191 if (MR::sendArbitraryMsg(63, a2, a3)) {
192 _C8 = 20;
193 _C4 = _C4 - 1;
194
195 MR::setBvaFrameAndStop(this, 1.0f);
196 if (mCrystalCageType == 2) {
197 MR::startSound(this, "SE_OJ_CRYSTAL_CAGE_L_DAMAGE", -1, -1);
198 }
199 else {
200 MR::startSound(this, "SE_OJ_CRYSTAL_CAGE_S_DAMAGE", -1, -1);
201 }
202
203 mRumbleCalc->start(0);
204 _D0.sub(a2->mPosition, a3->mPosition);
205 MR::normalize(&_D0);
206 return 1;
207 }
208 }
209
210 return 0;
211}
212
213bool CrystalCage::receiveMsgEnemyAttack(u32 msg, HitSensor *, HitSensor *) {
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);
219 return 1;
220 }
221
222 return 0;
223}
224
225void CrystalCage::initMapToolInfo(const JMapInfoIter &rIter) {
226 MR::initDefaultPos(this, rIter);
227 _DC.set<f32>(mPosition);
228
229 if (MR::isEqualObjectName(rIter, "CrystalCageS")) {
230 mCrystalCageType = 0;
231 }
232 else if (MR::isEqualObjectName(rIter, "CrystalCageM")) {
233 mCrystalCageType = 1;
234 }
235 else {
236 mCrystalCageType = 2;
237 }
238
239 if (mCrystalCageType == 2) {
240 MR::getJMapInfoArg0NoInit(rIter, &_108);
241 }
242 else {
243 MR::useStageSwitchWriteDead(this, rIter);
244
245 if (MR::useStageSwitchReadA(this, rIter)) {
246 MR::FunctorV0M<CrystalCage *, void (CrystalCage::*)()> forceFunc = MR::Functor<CrystalCage>(this, &CrystalCage::forceBreak);
247 MR::listenStageSwitchOnA(this, forceFunc);
248 }
249
250 MR::getJMapInfoArg0NoInit(rIter, &mIsBreakObjVisible);
251 MR::getJMapInfoArg1NoInit(rIter, &mPlayRiddleSFX);
252 MR::getJMapInfoArg2NoInit(rIter, &mHasBinding);
253 MR::getJMapInfoArg3NoInit(rIter, &_104);
254 }
255}
256
257void CrystalCage::initModel(const char *pName) {
258 initModelManagerWithAnm(pName, nullptr, false);
259 TVec3f stack_8;
260 stack_8.negateInline_2(mGravity);
261 MR::makeMtxUpNoSupportPos(&_94, stack_8, _DC);
262
263 if (mCrystalCageType == 2) {
264 mBreakObj = MR::createModelObjMapObjStrongLight("クリスタルケージ[大]壊れモデル", "CrystalCageLBreak", (MtxPtr)&_94);
265 }
266 else {
267 mBreakObj = MR::createModelObjMapObjStrongLight("クリスタルケージ[小]壊れモデル", "CrystalCageSBreak", (MtxPtr)&_94);
268 }
269
270 MR::invalidateClipping(this);
271 mBreakObj->mScale.set<f32>(mScale);
272 MR::registerDemoSimpleCastAll(mBreakObj);
273 mBreakObj->makeActorDead();
274}
275
276void CrystalCage::tryOnSwitchDead() {
277 if (mCrystalCageType == 2 || !MR::isValidSwitchDead(this)) {
278 return;
279 }
280
281 s32 step = 0;
282
283 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 3) {
284 step = 10;
285 }
286
287 if (MR::isStep(this, step)) {
288 MR::onSwitchDead(this);
289 }
290}
291
292void CrystalCage::exeWait() {
293 if (_C8 > 0) {
294 _C8--;
295 }
296
297 if (mRumbleCalc) {
298 if (mRumbleCalc->_4 < mRumbleCalc->_8) {
299 mRumbleCalc->calc();
300 TVec3f v9;
301 v9.scale(mRumbleCalc->_C.y, _D0);
302 JMathInlineVEC::PSVECAdd(_DC.toCVec(), v9.toCVec(), mPosition.toVec());
303 }
304 else {
305 mPosition.set<f32>(_DC);
306 }
307 }
308
309 if (mCrystalCageType == 0) {
310 TVec3f up_vec;
311 MR::calcUpVec(&up_vec, this);
312 TVec3f v6;
313 v6.scale(-40.0f, up_vec);
314 JMathInlineVEC::PSVECAdd(v6.toCVec(), mPosition.toCVec(), v6.toVec());
315 TVec3f v5;
316 v5.scale(140.0f, up_vec);
317 JMathInlineVEC::PSVECAdd(v5.toCVec(), mPosition.toCVec(), v5.toVec());
318 MR::calcPerpendicFootToLineInside(&_E8, *MR::getPlayerPos(), v6, v5);
319 }
320}
321
322void CrystalCage::exeBreak() {
323 if (MR::isFirstStep(this)) {
324 if (mIsBreakObjVisible) {
325 MR::hideModel(this);
326 }
327 else {
328 MR::setBvaFrameAndStop(this, mCrystalCageType == 2 ? 2.0f : 1.0f);
329 mPosition.set<f32>(_F8);
330 }
331
332 if (mHasBinding) {
333 MR::offBind(this);
334 mVelocity.z = 0.0f;
335 mVelocity.y = 0.0f;
336 mVelocity.x = 0.0f;
337 }
338
339 mBreakObj->appear();
340 MR::startBck(mBreakObj, "Break", nullptr);
341
342 if (mCrystalCageType == 2) {
343 MR::startSound(this, "SE_OJ_CRYSTAL_CAGE_L_BREAK", -1, -1);
344 if (_108 == -1) {
345 MR::requestAppearPowerStar(this, mDisplayModel->mPosition);
346 }
347 else {
348 MR::requestAppearPowerStar(this, _108, mDisplayModel->mPosition);
349 }
350 }
351 else {
352 MR::emitEffect(this, "Break");
353 MR::startSound(this, "SE_OJ_CRYSTAL_CAGE_S_BREAK", -1, -1);
354
355 if (mPlayRiddleSFX) {
356 MR::startSystemSE("SE_SY_READ_RIDDLE_S", -1, -1);
357 }
358 }
359
360 if (mDisplayModel && !MR::getDummyDisplayModelId(mDisplayModel)) {
361 MR::appearCoinPop(this, mDisplayModel->mPosition, 1);
362 }
363
364 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 5) {
365 MR::startSound(this, "SE_OJ_CRY_CAGE_MV_TICO_APR", -1, -1);
366 }
367
368 if (mDisplayModel && MR::getDummyDisplayModelId(mDisplayModel) == 1) {
369 MR::startSound(this, "SE_SV_KINOPIO_PUHA", -1, -1);
370 }
371
372 if (mDisplayModel) {
373 mDisplayModel->kill();
374 }
375 }
376
377 if (mCrystalCageType != 2 && MR::isStep(this, 2)) {
378 MR::stopScene(3);
379 }
380
381 tryOnSwitchDead();
382
383 if (MR::isBckStopped(mBreakObj)) {
384 if (mIsBreakObjVisible) {
385 kill();
386 }
387 else {
388 setNerve(&NrvCrystalCage::CrystalCageNrvBreakAfter::sInstance);
389 }
390 }
391}
392
393void CrystalCage::exeBreakAfter() {
394 if (MR::isFirstStep(this)) {
395 MR::validateClipping(this);
396 mBreakObj->kill();
397 }
398}
399
400namespace NrvCrystalCage {
401 INIT_NERVE(CrystalCageNrvWait);
402 INIT_NERVE(CrystalCageNrvBreak);
403 INIT_NERVE(CrystalCageNrvBreakAfter);
404
405 void CrystalCageNrvBreakAfter::execute(Spine *pSpine) const {
406 CrystalCage* cage = reinterpret_cast<CrystalCage*>(pSpine->mExecutor);
407 cage->exeBreakAfter();
408 }
409
410 void CrystalCageNrvBreak::execute(Spine *pSpine) const {
411 CrystalCage* cage = reinterpret_cast<CrystalCage*>(pSpine->mExecutor);
412 cage->exeBreak();
413 }
414
415 void CrystalCageNrvWait::execute(Spine *pSpine) const {
416 CrystalCage* cage = reinterpret_cast<CrystalCage*>(pSpine->mExecutor);
417 cage->exeWait();
418 }
419};
420
421CrystalCage::~CrystalCage() {
422
423}
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)
Definition LiveActor.hpp:24
TVec3f mPosition
3D vector of the actor's position.
Definition LiveActor.hpp:95
TVec3f mScale
3D vector of the actor's scale.
Definition LiveActor.hpp:97
TVec3f mVelocity
3D vector of the actor's velocity.
Definition LiveActor.hpp:98
TVec3f mGravity
3D vector of the actor's gravity.
Definition LiveActor.hpp:99
HitSensor * getSensor(const char *pSensorName) const
Gets a sensor.
Definition Spine.hpp:9