NSMBW-Decomp
A decompilation of New Super Mario Bros. Wii
Loading...
Searching...
No Matches
d_enemy.cpp
1#include <game/bases/d_enemy.hpp>
2#include <game/bases/d_bc.hpp>
3#include <game/bases/d_quake.hpp>
4#include <game/bases/d_a_player.hpp>
5#include <game/bases/d_a_player_manager.hpp>
6#include <game/bases/d_bg.hpp>
7#include <game/bases/d_score_manager.hpp>
8#include <game/bases/d_ef.hpp>
9#include <game/bases/d_effectmanager.hpp>
10#include <game/bases/d_eff_actor_manager.hpp>
12#include <game/bases/d_multi_manager.hpp>
13#include <game/bases/d_bg_parameter.hpp>
14#include <game/bases/d_enemy_manager.hpp>
15#include <game/mLib/m_effect.hpp>
17
18const s8 l_EnMuki[] = { 1, -1 };
19const s16 l_base_angleY[] = { 0x2000, -0x2000 };
20const s16 l_base_angleY_add[] = { 0x400, -0x400 };
21const float l_base_fall_speed_x[] = { 1.5f, -1.5f };
22
23const float dEn_c::smc_WATER_GRAVITY = -0.0625f;
24const float dEn_c::smc_WATER_YMAXSPD = 1.5f;
25const float dEn_c::smc_WATER_FALLMAXSPD = -1.5f;
26const float dEn_c::smc_WATER_ROLL_DEC_RATE = 0.5f;
27
29 m_24(0), mFootPush(mVec3_c(0.0f, 0.0f, 0.0f)),
30 mKilledByLiquid(false), mFootAttr3(false), mFootAttr1(false), mDeathInfo(),
31 mBoyoMng(this), mIceMng(this),
32 mTimer1(0), mTimer2(0), mCombo(dEnCombo_c::COMBO_REGULAR), mFumiProc(this)
33{
34 mFumiProc.refresh(new NonUniqueFumiCheck_c());
35
36 mAccelY = -0.1875f;
37 mSpeedMax.set(0.0f, -4.0f, 0.0f);
38 mAirAccelY = -0.1875f;
39 mAirSpeedMaxY = -4.0f;
40 mAirMaxFallSpeed = -4.0f;
41
44
45 mFlags = 0;
46
47 for (int i = 0; i < PLAYER_COUNT; i++) {
48 mNoHitPlayer.mTimer[i] = 0;
49 }
50}
51
53
55 boyonInit();
56 if (dBc_c::checkWater(mPos.x, mPos.y, mLayer, nullptr)) {
57 mInLiquid = true;
58 }
59
61}
62
65 return NOT_READY;
66 }
67
68 if (!mNoRespawn && !isState(StateID_Ice) && isQuakeDamage()) {
69 if (dQuake_c::m_instance->mFlags & dQuake_c::FLAG_1) {
70 if (checkDispIn()) {
71 setDeathInfo_Quake(0);
72 }
73 } else if (dQuake_c::m_instance->mFlags & dQuake_c::FLAG_2) {
74 if (checkDispIn()) {
75 setDeathInfo_Quake(1);
76 }
77 } else if (dQuake_c::m_instance->mFlags & dQuake_c::FLAG_0) {
79 }
80 }
81
82 if (mDeathInfo.mIsDead) {
83 if (!mNoRespawn) {
84 mNoRespawn = true;
85 setNicePoint_Death();
86 changeState(*mDeathInfo.mDeathState);
87 }
88 mDeathInfo.mIsDead = false;
89 } else {
90 if (mTimer3 != 0) {
91 mTimer3--;
92 }
93 if (mTimer1 != 0) {
94 mTimer1--;
95 }
96 if (mTimer2 != 0) {
97 mTimer2--;
98 }
99 for (u32 i = 0; i < PLAYER_COUNT; i++) {
100 mNoHitPlayer.update(i);
101 }
102 }
103
104 calcBoyonScale();
106}
107
109 if (status == SUCCESS && !(dActor_c::mExecStop & BIT_FLAG(ACTOR_MAP_ENEMY))) {
110 mBgCollFlags = 0;
111 }
112 dActor_c::postExecute(status);
113}
114
116 if (dActor_c::preDraw() == NOT_READY) {
117 return NOT_READY;
118 }
119 return SUCCEEDED;
120}
121
122void dEn_c::hitdamageEffect(const mVec3_c &pos) {
123 mVec3_c efPos = pos;
124 efPos.z = 5500.0f;
125 mEf::createEffect("Wm_en_hit", 0, &efPos, nullptr, nullptr);
126}
127
128void dEn_c::fumidamageEffect(const mVec3_c &pos) {
129 hitdamageEffect(pos);
130}
131
132void dEn_c::hipatkEffect(const mVec3_c &pos) {
133 if (mFlags & EN_IS_HARD) {
134 dEf::createEffect_change("Wm_mr_hardhit", 0, &pos, nullptr, nullptr);
135 } else {
136 dEf::createEffect_change("Wm_mr_softhit", 0, &pos, nullptr, nullptr);
137 }
138}
139
140void dEn_c::fumidamageSE(const mVec3_c &, int) {
141 dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0);
142}
143
145 mSpeed.y += 2.0f;
146}
147
148void dEn_c::posMove() {
149 u16 ang = mBc.getSakaMoveAngle(mSpeed.x < 0.0f);
150 mVec3_c move;
151 if (mFootAttr3) {
152 move.set(0.0f, 0.0f, 0.0f);
153 } else {
154 float speedX = std::fabs(mSpeed.x);
155 float cos = mAng(ang).cos();
156 float sin = mAng(ang).sin();
157 move.x = speedX * cos;
158 move.y = mSpeed.y + speedX * sin;
159 move.z = mSpeed.z;
160
161 if (mInLiquid) {
162 mFootPush2.set(0.0f, 0.0f, 0.0f);
163 move.x /= 2;
164 } else {
165 bool ok = mDeathInfo.mIsDead || mNoRespawn;
166 if (!ok && mSpeed.y <= 0.0f) {
167 move.x += mFootPush2.x;
168 }
169 }
170 }
171 move += mFootPush;
172 mPos += move;
173}
174
175void dEn_c::Bound(float epsY, float scaleX, float scaleY) {
176 if (!mBc.isFoot()) {
177 return;
178 }
179
180 if (scaleX < 1.0f) {
181 mSpeed.x *= scaleX;
182 if (std::fabs(mSpeed.x) < 1.0f / 16.0f) {
183 mSpeed.x = 0.0f;
184 }
185 }
186
187 if (mSpeed.y < 0.0f) {
188 mSpeed.y = -mSpeed.y;
189 mSpeed.y *= scaleY;
190 if (mSpeed.y < epsY) {
191 mSpeed.y = 0.0f;
192 }
193 }
194}
195
196bool dEn_c::checkDispIn() {
197 float x = getCenterPos().x;
198 float y = getCenterPos().y;
199
200 dBgParameter_c *bgParam = dBgParameter_c::ms_Instance_p;
201 float xStart = bgParam->xStart();
202 float xEnd = bgParam->xEnd();
203 float yStart = bgParam->yStart();
204 float yEnd = bgParam->yEnd();
205
206 if (x < xStart) {
207 return false;
208 }
209 if (x > xEnd) {
210 return false;
211 }
212 if (y > yStart) {
213 return false;
214 }
215 if (y < yEnd) {
216 return false;
217 }
218 return true;
219}
220
221void dEn_c::normal_collcheck(dCc_c *self, dCc_c *other) {
222 dEn_c *actor1 = (dEn_c *) self->getOwner();
223 dActor_c *actor2 = (dActor_c *) other->getOwner();
224
225 if (actor1->mDeathInfo.mIsDead) {
226 self->mInfo |= CC_NO_HIT;
227 return;
228 }
229
230 u32 kind = actor2->mKind;
231 if (kind == STAGE_ACTOR_ENEMY) {
232 if (actor1->EnDamageCheck(self, other)) {
233 self->mInfo |= CC_NO_HIT;
234 } else {
235 actor1->Normal_VsEnHitCheck(self, other);
236 }
237 } else if (kind == STAGE_ACTOR_PLAYER) {
238 if (actor1->mFlags & EN_FLAG_24 || !CeilCheck(actor1->mPos.y, self)) {
239 if (actor1->PlDamageCheck(self, other)) {
240 actor1->mCcValue = self->mCanBounce;
241 self->mInfo |= CC_NO_HIT;
242 } else if (other->mCcData.mKind != CC_KIND_PLAYER_ATTACK) {
243 s8 *plrNo = actor2->getPlrNo();
244 if (*plrNo >= 0 && *plrNo < PLAYER_COUNT) {
245 if (actor1->mNoHitPlayer.mTimer[*plrNo] == 0) {
246 actor1->mNoHitPlayer.mTimer[*plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT;
247 actor1->Normal_VsPlHitCheck(self, other);
248 }
249 }
250 }
251 }
252 } else if (kind == STAGE_ACTOR_YOSHI) {
253 s8 *plrNo = actor2->getPlrNo();
254 if (*plrNo >= 0 && *plrNo < PLAYER_COUNT) {
255 if (other->mCcData.mAttack == CC_ATTACK_YOSHI_EAT) {
256 actor1->hitYoshiEat(self, other);
257 } else {
258 if (!CeilCheck(actor1->mPos.y, self)) {
259 if (actor1->YoshiDamageCheck(self, other)) {
260 actor1->mCcValue = self->mCanBounce;
261 self->mInfo |= CC_NO_HIT;
262 } else if (actor1->mNoHitPlayer.mTimer[*plrNo] == 0) {
263 actor1->mNoHitPlayer.mTimer[*plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT;
264 actor1->Normal_VsYoshiHitCheck(self, other);
265 }
266 }
267 }
268 }
269 } else {
270 if (actor1->EtcDamageCheck(self, other)) {
271 actor1->mCcValue = self->mCanBounce;
272 self->mInfo |= CC_NO_HIT;
273 }
274 }
275}
276
277void dEn_c::Normal_VsEnHitCheck(dCc_c *self, dCc_c *other) {}
278
279void dEn_c::Normal_VsPlHitCheck(dCc_c *self, dCc_c *other) {
280 dActor_c *owner = (dActor_c *) other->getOwner();
281 if (!LineBoundaryCheck(owner)){
282 setDamage(owner);
283 }
284}
285
286void dEn_c::Normal_VsYoshiHitCheck(dCc_c *self, dCc_c *other) {
287 dActor_c *owner = (dActor_c *) other->getOwner();
288 if (!LineBoundaryCheck(owner)){
289 setDamage(owner);
290 }
291}
292
293bool dEn_c::EnDamageCheck(dCc_c *self, dCc_c *other) {
294 if (other->mCcData.mAttack == CC_ATTACK_SHELL) {
295 if (hitCallback_Shell(self, other)) {
296 return true;
297 }
298 }
299 return false;
300}
301
302bool dEn_c::PlDamageCheck(dCc_c *self, dCc_c *other) {
303 daPlBase_c *owner = (daPlBase_c *) other->getOwner();
304 if (owner->mKind != STAGE_ACTOR_PLAYER) {
305 return false;
306 }
307
308 if (other->mCcData.mAttack == CC_ATTACK_STAR && hitCallback_Star(self, other)) {
309 return true;
310 }
311 if (other->mCcData.mAttack == CC_ATTACK_HIP_ATTACK) {
312 if (owner->isMameAction()) {
313 return false;
314 }
315 if (hitCallback_HipAttk(self, other)) {
316 return true;
317 }
318 }
319 if (other->mCcData.mAttack == CC_ATTACK_SLIP) {
320 if (self->mCcData.mVsDamage & (1 << CC_ATTACK_SLIP) && hitCallback_Slip(self, other)) {
321 return true;
322 }
323 }
324 if (other->mCcData.mAttack == CC_ATTACK_PENGUIN_SLIDE) {
325 if (mActorProperties & 0x200) {
326 return false;
327 }
328 if (hitCallback_PenguinSlide(self, other)) {
329 return true;
330 }
331 }
332 if (other->mCcData.mAttack == CC_ATTACK_SPIN_FALL && hitCallback_Spin(self, other)) {
333 return true;
334 }
335 if (other->mCcData.mAttack == CC_ATTACK_CANNON && hitCallback_Cannon(self, other)) {
336 return true;
337 }
338 if (other->mCcData.mAttack == CC_ATTACK_WIRE_NET && hitCallback_WireNet(self, other)) {
339 return true;
340 }
341 return false;
342}
343
344bool dEn_c::YoshiDamageCheck(dCc_c *self, dCc_c *other) {
345 daPlBase_c *owner = (daPlBase_c *) other->getOwner();
346 if (owner->mKind != STAGE_ACTOR_YOSHI) {
347 return false;
348 }
349
350 if (other->mCcData.mAttack == CC_ATTACK_STAR && hitCallback_Star(self, other)) {
351 return true;
352 }
353 if (other->mCcData.mAttack == CC_ATTACK_HIP_ATTACK && hitCallback_YoshiHipAttk(self, other)) {
354 return true;
355 }
356 if (other->mCcData.mAttack == CC_ATTACK_SLIP) {
357 if (self->mCcData.mVsDamage & (1 << CC_ATTACK_SLIP) && hitCallback_Slip(self, other)) {
358 return true;
359 }
360 }
361 return false;
362}
363
364bool dEn_c::EtcDamageCheck(dCc_c *self, dCc_c *other) {
365 dEn_c *owner = (dEn_c *) self->getOwner();
366 if (other->mCcData.mAttack == CC_ATTACK_SHELL && owner->hitCallback_Shell(self, other)) {
367 return true;
368 }
369 if (other->mCcData.mAttack == CC_ATTACK_FIREBALL) {
370 if (self->mCcData.mVsDamage & (1 << CC_ATTACK_FIREBALL) && owner->hitCallback_Fire(self, other)) {
371 return true;
372 }
373 }
374 if (other->mCcData.mAttack == CC_ATTACK_YOSHI_FIRE) {
375 if (self->mCcData.mVsDamage & (1 << CC_ATTACK_YOSHI_FIRE) && owner->hitCallback_YoshiFire(self, other)) {
376 return true;
377 }
378 }
379 if (other->mCcData.mAttack == CC_ATTACK_FIRE_2 && owner->hitCallback_Fire(self, other)) {
380 return true;
381 }
382 if (other->mCcData.mAttack == CC_ATTACK_ICEBALL && self->mCcData.mVsDamage & (1 << CC_ATTACK_ICEBALL) ||
383 other->mCcData.mAttack == CC_ATTACK_ICE_2 && self->mCcData.mVsDamage & (1 << CC_ATTACK_ICE_2)) {
384 if (owner->hitCallback_Ice(self, other)) {
385 return true;
386 }
387 }
388 if (other->mCcData.mAttack == CC_ATTACK_YOSHI_BULLET) {
389 if (self->mCcData.mVsDamage & (1 << CC_ATTACK_YOSHI_BULLET) && owner->hitCallback_YoshiBullet(self, other)) {
390 return true;
391 }
392 }
393 return false;
394}
395
396void dEn_c::hitYoshiEat(dCc_c *self, dCc_c *other) {}
397
398bool dEn_c::getPl_LRflag(const mVec3_c &pos) {
399 mVec2_c playerPos;
400 mVec2_c pos2D(pos.x, pos.y);
401 if (searchNearPlayer_Main(playerPos, pos2D) == nullptr) {
402 return false;
403 }
404 return playerPos.x < 0;
405}
406
407bool dEn_c::getPl_UDflag(const mVec3_c &pos) {
408 mVec2_c playerPos;
409 mVec2_c pos2D(pos.x, pos.y);
410 if (searchNearPlayer_Main(playerPos, pos2D) == nullptr) {
411 return false;
412 }
413 return playerPos.y < 0;
414}
415
416bool dEn_c::CeilCheck(float y, dCc_c *cc) {
417 return dBgParameter_c::getInstance()->check(y + cc->mCcData.mOffset.y, cc->mCcData.mSize.y);
418}
419
420bool dEn_c::carry_check(dActor_c *actor) {
421 dAcPy_c *pl = (dAcPy_c *) actor;
422 if (pl->FUN_8012e540(this, true)) {
423 mPlayerNo = *actor->getPlrNo();
424 return true;
425 }
426 return false;
427}
428
430 float dir = l_EnMuki[mDirection];
431 mBc.checkWall(&dir);
432 mVec3_c truePos = mPos;
433 truePos += mCenterOffs;
434 return mBc.checkBg(truePos.x, truePos.y, mLayer, l_Ami_Line[mAmiLayer], 0x819);
435}
436
437int dEn_c::Enfumi_check(dCc_c *self, dCc_c *other, int step) {
438 dActor_c *owner;
439 FumiCcInfo_c fumiInfo(self, other);
440 int fumiRes = mFumiProc.operate(fumiInfo, 1);
441 owner = (dActor_c *) other->getOwner();
442 switch (fumiRes) {
443 case 1:
444 if ((int) owner->mKind == STAGE_ACTOR_PLAYER) {
445 if (step == 0) {
446 fumiSE(owner);
447 fumiEffect(owner);
448 } else if (step == 1) {
449 fumistepSE(owner);
450 }
451 FumiJumpSet(owner);
452 FumiScoreSet(owner);
453 } else {
454 if (step == 0) {
455 yoshifumiSE(owner);
456 yoshifumiEffect(owner);
457 } else if (step == 1) {
458 yoshifumistepSE(owner);
459 }
460 YoshiFumiJumpSet(owner);
461 YoshiFumiScoreSet(owner);
462 }
463 break;
464 case 2:
465 MameFumiJumpSet(owner);
466 mamefumiSE(owner);
467 mamefumiEffect(owner);
468 break;
469 case 3:
470 if (step == 0) {
471 spinfumiSE(owner);
472 spinfumiEffect(owner);
473 } else if (step == 1) {
474 fumistepSE(owner);
475 }
476 SpinFumiJumpSet(owner);
477 SpinFumiScoreSet(owner);
478 break;
479 }
480 return fumiRes;
481}
482
483void dEn_c::FumiScoreSet(dActor_c *actor) {
484 setFumiComboScore(actor);
485}
486
487void dEn_c::FumiJumpSet(dActor_c *actor) {
488 PlayerFumiJump(actor, dAcPy_c::msc_JUMP_SPEED + 0.2815f);
489}
490
491void dEn_c::MameFumiJumpSet(dActor_c *actor) {
492 float jumpSpeed = (dAcPy_c::msc_JUMP_SPEED + 0.2815f);
493 jumpSpeed *= 0.8125f;
494 if (mSpeed.y > 0.0f) {
495 jumpSpeed += mSpeed.y * 0.2f;
496 }
497 PlayerFumiJump(actor, jumpSpeed);
498}
499
500void dEn_c::YoshiFumiJumpSet(dActor_c *actor) {
501 PlayerFumiJump(actor, dAcPy_c::msc_JUMP_SPEED + 0.2815f);
502}
503
504void dEn_c::YoshiFumiScoreSet(dActor_c *actor) {
505 FumiScoreSet(actor);
506}
507
508void dEn_c::SpinFumiJumpSet(dActor_c *actor) {
509 FumiJumpSet(actor);
510}
511
512void dEn_c::SpinFumiScoreSet(dActor_c *actor) {
513 FumiScoreSet(actor);
514}
515
516void dEn_c::PlayerFumiJump(dActor_c *actor, float param_2) {
517 ((daPlBase_c *) actor)->vf3fc(param_2, actor->mSpeedF, 1, 0, 2);
518 dEnemyMng_c::m_instance->m_138 = 1;
519}
520
521void dEn_c::setFumiComboScore(dActor_c *actor) {
522 int treadCount = dEnCombo_c::calcPlFumiCnt(actor);
523 if (treadCount >= 0) {
524 mVec3_c pos = getCenterPos();
525 float scY = dScoreMng_c::smc_SCORE_Y;
526 pos.y = mPos.y + scY;
527 switch (mCombo.mType) {
528 case dEnCombo_c::COMBO_REGULAR: {
529 dScoreMng_c *instance = dScoreMng_c::getInstance();
530 instance->ScoreSet(pos, treadCount, *actor->getPlrNo(), 1);
531 break;
532 }
533 case dEnCombo_c::COMBO_SHORT: {
534 dScoreMng_c *instance = dScoreMng_c::getInstance();
535 instance->ScoreSet2(pos, treadCount, *actor->getPlrNo());
536 break;
537 }
538 default:
539 break;
540 }
541 }
542}
543
545 /// @unofficial
546 static const int claps[] = { 7, 7, 4 };
547 return num >= claps[mCombo.mType];
548}
549
550void dEn_c::fumiSE(dActor_c *actor) {
551 const static dAudio::SoundEffectID_t cs_combo_se[] = {
552 SE_EMY_FUMU_1,
553 SE_EMY_FUMU_2,
554 SE_EMY_FUMU_3,
555 SE_EMY_FUMU_4,
556 SE_EMY_FUMU_5,
557 SE_EMY_FUMU_6,
558 SE_EMY_FUMU_7,
559 SE_EMY_FUMU_7,
560 SE_EMY_FUMU_7
561 };
562
563 int count = ((daPlBase_c *) actor)->getTreadCount();
564 if (count >= ARRAY_SIZE(cs_combo_se)) {
565 count = ARRAY_SIZE(cs_combo_se) - 1;
566 };
567 if (checkComboClap(count)) {
569 }
570
571 cs_combo_se[count].playEmySound(getCenterPos(), 0);
572}
573
574void dEn_c::spinfumiSE(dActor_c *actor) {
575 const static dAudio::SoundEffectID_t cs_combo_se[] = {
576 SE_EMY_DOWN_SPIN_1,
577 SE_EMY_DOWN_SPIN_2,
578 SE_EMY_DOWN_SPIN_3,
579 SE_EMY_DOWN_SPIN_4,
580 SE_EMY_DOWN_SPIN_5,
581 SE_EMY_DOWN_SPIN_6,
582 SE_EMY_DOWN_SPIN_7,
583 SE_EMY_DOWN_SPIN_7,
584 SE_EMY_DOWN_SPIN_7
585 };
586
587 int count = ((daPlBase_c *) actor)->getTreadCount();
588 if (count >= ARRAY_SIZE(cs_combo_se)) {
589 count = ARRAY_SIZE(cs_combo_se) - 1;
590 };
591 if (checkComboClap(count)) {
593 }
594
595 cs_combo_se[count].playEmySound(getCenterPos(), 0);
596}
597
598void dEn_c::yoshifumiSE(dActor_c *actor) {
599 const static dAudio::SoundEffectID_t cs_combo_se[] = {
600 SE_EMY_YOSHI_FUMU_1,
601 SE_EMY_YOSHI_FUMU_2,
602 SE_EMY_YOSHI_FUMU_3,
603 SE_EMY_YOSHI_FUMU_4,
604 SE_EMY_YOSHI_FUMU_5,
605 SE_EMY_YOSHI_FUMU_6,
606 SE_EMY_YOSHI_FUMU_7,
607 SE_EMY_YOSHI_FUMU_7,
608 SE_EMY_YOSHI_FUMU_7
609 };
610
611 int count = ((daPlBase_c *) actor)->getTreadCount();
612 if (count >= ARRAY_SIZE(cs_combo_se)) {
613 count = ARRAY_SIZE(cs_combo_se) - 1;
614 };
615 if (checkComboClap(count)) {
617 }
618
619 cs_combo_se[count].playEmySound(getCenterPos(), 0);
620}
621
622void dEn_c::mamefumiSE(dActor_c *actor) {
623 dAudio::SoundEffectID_t(SE_EMY_MAME_STEP).playEmySound(getCenterPos(), 0);
624}
625
626void dEn_c::fumistepSE(dActor_c *actor) {
627 dAudio::SoundEffectID_t(SE_EMY_CMN_STEP).playEmySound(getCenterPos(), 0);
628}
629
630void dEn_c::yoshifumistepSE(dActor_c *actor) {
631 dAudio::SoundEffectID_t(SE_EMY_YOSHI_STEP).playEmySound(getCenterPos(), 0);
632}
633
634void dEn_c::fumiEffect(dActor_c *actor) {
635 if (actor->mKind != STAGE_ACTOR_PLAYER && actor->mKind != STAGE_ACTOR_YOSHI) {
636 return;
637 }
638
639 daPlBase_c *pl = (daPlBase_c *) actor;
640 mVec3_c efPos;
641 efPos.x = pl->getAnkleCenterX();
642 efPos.y = pl->getAnkleCenterY();
643 efPos.z = 5500.0f;
644 mEf::createEffect("Wm_en_hit", 0, &efPos, nullptr, nullptr);
645}
646
647void dEn_c::spinfumiEffect(dActor_c *actor) {
648 mVec3_c efPos;
649 efPos.x = actor->mPos.x;
650 efPos.y = actor->mPos.y;
651 efPos.z = 5500.0f;
652 mEf::createEffect("Wm_en_hit", 0, &efPos, nullptr, nullptr);
653}
654
655void dEn_c::yoshifumiEffect(dActor_c *actor) {}
656
657void dEn_c::mamefumiEffect(dActor_c *actor) {}
658
659u32 dEn_c::EnBgCheck() {
660 u32 flags = 0;
661 u32 footCheckRes = EnBgCheckFoot();
662 if (footCheckRes) {
663 flags |= 1;
664 mSpeed.y = 0.0f;
665 }
666 u32 checkHeadRes = mBc.checkHead(footCheckRes);
667 if (checkHeadRes) {
668 flags |= 2;
669 }
670 u32 bgCheckWallRes = EnBgCheckWall();
671 if (bgCheckWallRes) {
672 flags |= 4;
673 }
674 u32 arg = checkHeadRes | bgCheckWallRes;
675 u32 actArg = arg | footCheckRes;
676 if (mBc.mFlags & 0x8000 && mBc.mFlags & 3 && mBc.mpRc != nullptr) {
677 int v = 0;
678 if (mSpeed.y > 0.0f) {
679 v |= 1;
680 }
681 if (!mBc.mpRc->check2(actArg & 0x1f6000, v, 0)) {
682 mBc.mFlags &= 0xffff7fff;
683 }
684 }
685 return flags;
686}
687
688u32 dEn_c::EnBgCheckFoot() {
689 if (!mBc.hasSensorFoot()) {
690 mFootPush2.set(0.0f, 0.0f, 0.0f);
691 return false;
692 }
693 u32 res = mBc.checkFootEnm();
694 mFootAttr3 = false;
695 mFootAttr1 = false;
696 if (mBc.isFoot()) {
697 u16 footAttr = mBc.getFootAttr();
698 if (footAttr == 3) {
699 mFootAttr3 = true;
700 }
701 if (footAttr == 1) {
702 mFootAttr1 = true;
703 }
704 mFootPush = mBc.mPushForce;
705 mFootPush2.set(0.0f, 0.0f, 0.0f);
706 } else {
707 mFootPush.set(0.0f, 0.0f, 0.0f);
708 }
709 return res;
710}
711
712u32 dEn_c::EnBgCheckWall() {
713 if (!mBc.hasSensorWall()) {
714 return 0;
715 }
716 float tmpX = mBc.m_4c;
717 u8 dir = mPos.x - tmpX < 0.0f;
718 float dirVal = l_EnMuki[dir];
719 u32 flags = mBc.checkWallEnm(&dirVal);
720 dirVal = l_EnMuki[dir ^ 1];
721 u32 wallFlags = mBc.checkWallEnm(&dirVal);
722 if (mBgCollFlags & 3) {
723 wallFlags |= mBc.checkWallEnm(&dirVal);
724 }
725 mBc.mFlags |= flags | wallFlags;
726 return flags;
727}
728
729void dEn_c::WaterCheck(mVec3_c &pos, float h) {
730 if (mKilledByLiquid) {
731 return;
732 }
733 int waterLineRes = WaterLineProc(pos, h);
734 if (waterLineRes == dBc_c::WATER_CHECK_YOGAN) {
735 setDeathInfo_Smoke(nullptr);
736 mKilledByLiquid = true;
737 } else if (waterLineRes != dBc_c::WATER_CHECK_NONE && mNoRespawn) {
738 mKilledByLiquid = true;
739 }
740}
741
742bool dEn_c::LineBoundaryCheck(dActor_c *actor) {
743 daPlBase_c *pl = (daPlBase_c *) actor;
744 if ((pl->mPos.z > 0.0f && mAmiLayer == 1) || (pl->mPos.z < 0.0f && mAmiLayer == 0)) {
745 if (pl->mFlags & 0x80000 || pl->mFlags & 0x100000) {
746 return true;
747 }
748 }
749 return false;
750}
751
752dBc_c::WATER_TYPE_e dEn_c::WaterLineProc(const mVec3_c &pos, float h) {
753 float height = 0.0f;
754 dBc_c::WATER_TYPE_e res = dBc_c::checkWater(pos.x, pos.y, mLayer, &height);
755 mVec3_c waterPos(mPos.x, height, 6500.0f);
756 switch (res) {
757 case dBc_c::WATER_CHECK_WATER:
758 case dBc_c::WATER_CHECK_WATER_BUBBLE:
759 if (!mInLiquid) {
760 mInLiquid = true;
764 setWaterSpeed();
765 waterSplashEffect(waterPos, h);
766 }
767 break;
768 case dBc_c::WATER_CHECK_YOGAN:
769 if (!mInLiquid) {
770 mInLiquid = true;
771 yoganSplashEffect(waterPos, h);
772 }
773 break;
774 case dBc_c::WATER_CHECK_POISON:
775 if (!mInLiquid) {
776 mInLiquid = true;
777 poisonSplashEffect(waterPos, h);
778 }
779 break;
780 default:
781 if (mInLiquid) {
785 }
786 mInLiquid = false;
787 break;
788 }
789 return res;
790}
791
792void dEn_c::yoganSplashEffect(const mVec3_c &pos, float scale) {
793 mVec3_c efPos(pos, 6500.0f);
794 mVec3_c efScale(scale, scale, scale);
795 u32 flags = mLayer << 16 | 5;
796 dEffActorMng_c::m_instance->createWaterSplashEff(efPos, flags, -1, efScale);
797
798 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_LAVA).playMapSound(efPos, 0);
799
800 if (scale < 1.0f) {
801 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 16);
802 } else {
803 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 14);
804 }
805}
806
807void dEn_c::poisonSplashEffect(const mVec3_c &pos, float scale) {
808 mVec3_c efPos(pos, 6500.0f);
809 mVec3_c efScale(scale, scale, scale);
810 u32 flags = mLayer << 16 | 7;
811 dEffActorMng_c::m_instance->createWaterSplashEff(efPos, flags, -1, efScale);
812
813 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_POISON).playMapSound(pos, 0);
814
815 if (scale < 1.0f) {
816 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 23);
817 } else {
818 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 21);
819 }
820}
821
822bool dEn_c::EnLavaCheck(const mVec3_c &pos) {
823 float height = 0.0f;
824 dBc_c::WATER_TYPE_e res = dBc_c::checkWater(pos.x, pos.y, mLayer, &height);
825 if (res == dBc_c::WATER_CHECK_YOGAN) {
826 if (height < 0.0f && mLastPos.y > height && mPos.y <= height) {
827 yoganSplashEffect(mVec3_c(pos.x, height, 6000.0f), 1.0f);
828 }
829 return true;
830 }
831 return false;
832}
833
834bool dEn_c::EnWaterCheck(const mVec3_c &pos) {
835 if (EnWaterFlagCheck(pos) != dBc_c::WATER_CHECK_NONE) {
836 return true;
837 }
838 mSpeedMax.y = -4.0f;
839 mMaxFallSpeed = -4.0f;
840 return false;
841}
842
843bool dEn_c::EnWaterFlagCheck(const mVec3_c &pos) {
844 switch (dBc_c::checkWater(pos.x, pos.y, mLayer, nullptr)) {
845 case dBc_c::WATER_CHECK_WATER:
846 case dBc_c::WATER_CHECK_WATER_BUBBLE:
847 setWaterSpeed();
848 return true;
849 default:
850 return false;
851 }
852}
853
854void dEn_c::setWaterSpeed() {
855 mAccelY = smc_WATER_GRAVITY;
856
857 if (mSpeedMax.y < -smc_WATER_YMAXSPD) {
858 mSpeedMax.y = -smc_WATER_YMAXSPD;
859 } else if (mSpeedMax.y > smc_WATER_YMAXSPD) {
860 mSpeedMax.y = smc_WATER_YMAXSPD;
861 }
862
863 if (mMaxFallSpeed < smc_WATER_FALLMAXSPD) {
864 mMaxFallSpeed = smc_WATER_FALLMAXSPD;
865 } else if (mMaxFallSpeed > -smc_WATER_FALLMAXSPD) {
866 mMaxFallSpeed = -smc_WATER_FALLMAXSPD;
867 }
868
869 if (mSpeed.y < -smc_WATER_YMAXSPD) {
870 mSpeed.y = -smc_WATER_YMAXSPD;
871 } else if (mSpeed.y > smc_WATER_YMAXSPD) {
872 mSpeed.y = smc_WATER_YMAXSPD;
873 }
874}
875
876bool dEn_c::Area_X_check(float x) {
877 for (int i = 0; i < PLAYER_COUNT; i++) {
878 dAcPy_c *player = daPyMng_c::getPlayer(i);
879 if (player != nullptr && daPyMng_c::checkPlayer(i)) {
880 mVec3_c playerPos = player->mPos;
881 float diff = std::fabs(playerPos.x - mPos.x);
882 if (diff < x) {
883 return true;
884 }
885 }
886 }
887 return false;
888}
889
890bool dEn_c::Area_XY_check(float x, float y) {
891 for (int i = 0; i < PLAYER_COUNT; i++) {
892 dAcPy_c *player = daPyMng_c::getPlayer(i);
893 if (player != nullptr && daPyMng_c::checkPlayer(i)) {
894 mVec3_c playerPos = player->mPos;
895 if (std::fabs(playerPos.x - mPos.x) < x && std::fabs(playerPos.y - mPos.y) < y) {
896 return true;
897 }
898 }
899 }
900 return false;
901}
902
903bool dEn_c::PlayerCarryCheck(dActor_c *actor) {
904 for (int i = 0; i < PLAYER_COUNT; i++) {
905 dAcPy_c *player = daPyMng_c::getPlayer(i);
906 if (player != nullptr && fManager_c::searchBaseByID(player->mCarryActorID) == this) {
907 return true;
908 }
909 }
910 return false;
911}
912
913mVec3_c dEn_c::calcCarryPos(const mVec3_c &pos) {
914 dAcPy_c *player = daPyMng_c::getPlayer(mPlayerNo);
915 if (player->isStatus(4)) {
916 return mPos;
917 }
918 mMtx_c mtx = player->getCarryMtx();
919 mMtx_c transposeMtx = mMtx_c::createTrans(pos);
920 mVec3_c res;
921 mtx.concat(transposeMtx).multVecZero(res);
922 return res;
923}
924
925bool dEn_c::turnangle_calc(const short *target, const short *delta) {
926 mAngle.y += delta[mDirection];
927 if (target[0] <= mAngle.y || mAngle.y <= target[1]) {
928 mAngle.y = target[mDirection];
929 return true;
930 }
931 return false;
932}
933
934void dEn_c::slipBound(dActor_c *actor) {
935 static const float cs_jump_xspeed[] = { 1.5f, -1.5f };
936 daPlBase_c *pl = (daPlBase_c *) actor;
937
938 u8 idx = !(pl->mPos.x >= mPos.x);
939 pl->vf3fc(3.0f, cs_jump_xspeed[idx], 1, 0, 0);
940
941 int plrNo = *pl->getPlrNo();
942 mNoHitPlayer.mTimer[plrNo] = 3;
943}
944
946 removeCc();
948 changeState(StateID_EatIn);
949}
950
952 reviveCc();
954 changeState(*mStateMgr.getOldStateID());
955}
956
958 calcSpitOutPos(actor);
959 int plrNo = *actor->getPlrNo();
961 mDirection = actor->mDirection;
962 reviveCc();
964 changeState(StateID_EatOut);
965 return true;
966}
967
970 mBoyoMng.mCounter = 0;
971}
972
973void dEn_c::setNicePoint_Death() {
974 int killedBy = mDeathInfo.mKilledBy;
975 if (mDeathInfo.mKilledBy >= 0 && mDeathInfo.mKilledBy < PLAYER_COUNT) {
976 dMultiMng_c::mspInstance->incEnemyDown(killedBy);
977 }
978}
979
980void dEn_c::fireballInvalid(dCc_c *self, dCc_c *other) {
981 dAudio::g_pSndObjMap->startSound(SE_OBJ_FIREBALL_DISAPP, other->getOwner()->mPos, 0);
982}
983
984void dEn_c::iceballInvalid(dCc_c *self, dCc_c *other) {
985 dBaseActor_c *owner = other->getOwner();
986 dAudio::g_pSndObjMap->startSound(SE_OBJ_PNGN_ICEBALL_DISAPP, owner->mPos, 0);
987
988 mVec3_c efPos(owner->mPos.x, owner->mPos.y, 5500.0f);
989 EffectManager_c::SetIceBallMissshitEffect(&efPos);
990}
991
992void dEn_c::setDamage(dActor_c *actor) {
993 daPlBase_c *pl = (daPlBase_c *) actor;
994 pl->setDamage(this, daPlBase_c::DAMAGE_NONE);
995}
996
997void dEn_c::boyonInit() {
998 mBoyoMng.mScale = mBoyoMng.mpOwner->mScale;
999}
1000
1001void dEn_c::boyonBegin() {
1002 mBoyoMng.begin(dEnBoyoMng_c::smc_BOYON_TIME, dEnBoyoMng_c::smc_DELTA_SCALE);
1003}
1004
1006 u8 dir = mDeathFallDirection;
1007 s8 plrNo = *getPlrNo();
1008
1009 mVec3_c efPos(mVec2_c(mPos.x, mPos.y), 5500.0f);
1010
1011 hitdamageEffect(efPos);
1012 dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0);
1013
1015 l_base_fall_speed_x[dir],
1016 3.0f,
1017 -4.0f,
1018 -0.1875f,
1019 &StateID_DieFall,
1020 -1,
1021 -1,
1022 dir,
1023 (u8) plrNo
1024 };
1025}
bool FUN_8012e540(dActor_c *, bool)
bool isState(const sStateIDIf_c &other) const
Checks if the actor is currently in the given state.
sFStateStateMgr_c< dActorMultiState_c, sStateMethodUsr_FI_c, sStateMethodUsr_FI_c > mStateMgr
The state manager.
The minimum required implementation for a stage actor.
Definition d_actor.hpp:15
static u8 mExecStop
The actors for which the execute operation is currently disabled.
Definition d_actor.hpp:397
u8 mExecStopMask
The mask required to disable the execute operation for the actor.
Definition d_actor.hpp:376
virtual void postCreate(fBase_c::MAIN_STATE_e status)
post method for the create operation.
Definition d_actor.cpp:88
mVec3_c mPreEatScale
The actor's scale before being eaten.
Definition d_actor.hpp:367
bool mNoRespawn
Whether the actor should not respawn after being deleted.
Definition d_actor.hpp:378
virtual void reviveCc()
Enables the actor's collision.
Definition d_actor.cpp:804
dBc_c mBc
The actor-to-tile collision sensor.
Definition d_actor.hpp:342
u8 mKind
The actor's kind. Value is a STAGE_ACTOR_KIND_e.
Definition d_actor.hpp:374
u8 mAmiLayer
The actor's layer for chainlink fences.
Definition d_actor.hpp:379
u8 mDirection
The actor's facing direction.
Definition d_actor.hpp:351
virtual void removeCc()
Disables the actor's collision.
Definition d_actor.cpp:800
static dAcPy_c * searchNearPlayer_Main(mVec2_c &delta, const mVec2_c &pos)
See searchNearPlayerFunc.
Definition d_actor.cpp:195
virtual void postExecute(fBase_c::MAIN_STATE_e status)
post method for the execute operation.
Definition d_actor.cpp:122
void setKind(u8 kind)
Sets the actor's kind. See STAGE_ACTOR_KIND_e.
Definition d_actor.cpp:176
virtual int preExecute()
pre method for the execute operation.
Definition d_actor.cpp:104
s8 mPlayerNo
The player associated with the actor, -1 if not associated to any player.
Definition d_actor.hpp:375
virtual void waterSplashEffect(const mVec3_c &pos, float size)
Generates a water splash effect.
Definition d_actor.cpp:731
dActor_c()
Constructs a new actor.
Definition d_actor.cpp:46
virtual void calcEatInScale(dActor_c *eatingActor)
Adjusts the actor's scale while being eaten.
Definition d_actor.cpp:674
virtual int preDraw()
pre method for the draw operation.
Definition d_actor.cpp:140
virtual s8 * getPlrNo()
Gets the player number associated with the actor. See mPlayerNo.
Definition d_actor.hpp:105
virtual void setAfterEatScale()
Restores the actor's scale once spat out.
Definition d_actor.cpp:647
@ STAGE_ACTOR_ENEMY
An enemy actor.
Definition d_actor.hpp:49
@ STAGE_ACTOR_YOSHI
The Yoshi actor.
Definition d_actor.hpp:48
@ STAGE_ACTOR_PLAYER
The player actor.
Definition d_actor.hpp:47
virtual void calcSpitOutPos(dActor_c *eatingActor)
Calculates the position where the actor will be spat out.
Definition d_actor.cpp:651
u8 mLayer
The actor's layer.
Definition d_actor.hpp:377
u8 mBgCollFlags
The collision directions that the actor can respond to.
Definition d_actor.hpp:353
mVec3_c mScale
The actor's scale (defaults to 1).
mVec3_c mSpeed
The actor's speed.
mVec3_c mPos
The actor's position.
mVec3_c mSpeedMax
The actor's maximum speed.
mVec3_c mCenterOffs
The offset from the position to the center of the actor (defaults to 0).
float mSpeedF
The actor's horizontal speed.
void posMove()
Moves the actor by its speed.
float mMaxFallSpeed
The actor's maximum fall speed.
mVec3_c getCenterPos() const
Gets the actor's centered position.
mAng3_c mAngle
The actor's rotation (for 2D actors).
u32 mActorProperties
The actor's properties. See fProfile::fActorProfile_c::mActorProperties.
float mAccelY
The actor's vertical acceleration.
@ ACTOR_MAP_ENEMY
A map enemy (dWmEnemy_c).
dBaseActor_c()
Constructs a new actor.
Collider ("Collision Check") class - handles collisions between actors.
Definition d_cc.hpp:111
u8 mInfo
Info flags for this collider. See CC_INFO_e.
Definition d_cc.hpp:312
dActor_c * getOwner() const
Gets the owner actor of this collider.
Definition d_cc.hpp:156
u32 mCanBounce
[used by Giant Wigglers to allow jumping].
Definition d_cc.hpp:261
sCcDatNewF mCcData
The collision data of this collider.
Definition d_cc.hpp:263
static const u16 smc_NO_HIT_PLAYER_TIMER_DEFAULT
Definition d_enemy.hpp:309
float mAirMaxFallSpeed
The maximum fall speed before entering a liquid.
Definition d_enemy.hpp:285
virtual ~dEn_c()
Destroys the actor.
Definition d_enemy.cpp:52
u16 mTimer2
[Used in EN_HATENA_BALLON, for example]
Definition d_enemy.hpp:288
bool getPl_LRflag(const mVec3_c &pos)
Checks whether the nearest player is to the left of pos.
Definition d_enemy.cpp:398
u8 mDeathFallDirection
The X direction to move towards on death.
Definition d_enemy.hpp:273
u16 m_24
Definition d_enemy.hpp:269
void WaterCheck(mVec3_c &pos, float h)
Definition d_enemy.cpp:729
virtual bool setEatSpitOut(dActor_c *)
Callback for when the actor is about to be spat out.
Definition d_enemy.cpp:957
u32 checkWallAndBg()
Definition d_enemy.cpp:429
float mAirAccelY
The Y acceleration before entering a liquid.
Definition d_enemy.hpp:283
dDeathInfo_c mDeathInfo
The parameters for the death animation.
Definition d_enemy.hpp:267
virtual void postCreate(fBase_c::MAIN_STATE_e status)
post method for the create operation.
Definition d_enemy.cpp:54
dIceMng_c mIceMng
The ice manager for this enemy.
Definition d_enemy.hpp:282
dEnCombo_c mCombo
The enemy combo manager.
Definition d_enemy.hpp:296
u16 mTimer1
[Used in EN_HATENA_BALLON, for example]
Definition d_enemy.hpp:287
dEn_c()
Constructs a new enemy actor.
Definition d_enemy.cpp:28
static const u16 smc_NO_HIT_PLAYER_TIMER_SPIT_OUT
Definition d_enemy.hpp:310
bool mKilledByLiquid
Whether the enemy was killed by falling in a liquid.
Definition d_enemy.hpp:275
virtual void quakeAction()
Definition d_enemy.cpp:144
virtual void setEatTongueOff(dActor_c *)
Callback for when the eating action is canceled.
Definition d_enemy.cpp:951
virtual int preExecute()
pre method for the execute operation.
Definition d_enemy.cpp:63
virtual void block_hit_init()
Callback for when a block directly beneath the actor is hit.
Definition d_enemy.cpp:1005
float mAirSpeedMaxY
The maximum Y speed before entering a liquid.
Definition d_enemy.hpp:284
dPlayerDownTimer_c mNoHitPlayer
Hit cooldown timers for each player. This is used to prevent, for example, a thrown shell from hittin...
Definition d_enemy.hpp:293
virtual void postExecute(fBase_c::MAIN_STATE_e status)
post method for the execute operation.
Definition d_enemy.cpp:108
virtual void calcEatInScale(dActor_c *)
Adjusts the actor's scale while being eaten.
Definition d_enemy.cpp:968
virtual void poisonSplashEffect(const mVec3_c &, float)
Generates a poison water splash effect.
Definition d_enemy.cpp:807
virtual void setEatTongue(dActor_c *)
Callback for when the actor is targeted by Yoshi's tongue.
Definition d_enemy.cpp:945
virtual void yoganSplashEffect(const mVec3_c &, float)
Generates a lava splash effect.
Definition d_enemy.cpp:792
virtual int preDraw()
pre method for the draw operation.
Definition d_enemy.cpp:115
u32 mFlags
Flags for this actor. See FLAGS_e.
Definition d_enemy.hpp:286
bool getPl_UDflag(const mVec3_c &pos)
Checks whether the nearest player is below pos.
Definition d_enemy.cpp:407
bool mInLiquid
Whether the enemy is in a liquid.
Definition d_enemy.hpp:278
virtual void changeState(const sStateIDIf_c &newState)
Changes the actor's state to the given state.
virtual bool checkComboClap(int max)
Definition d_enemy.cpp:544
void setClapSE()
Plays the clap sound effect.
static dMultiMng_c * mspInstance
The instance of this class.
virtual u32 vf3fc(float, float, int, int, int)
MAIN_STATE_e
The possible operation results.
Definition f_base.hpp:34
@ SUCCESS
The operation was completed successfully.
Definition f_base.hpp:37
bool mDeleteRequested
If deletion of the base was requested, but the delete operation has not been scheduled yet.
Definition f_base.hpp:68
@ NOT_READY
The step could not completed at this time.
Definition f_base.hpp:43
@ SUCCEEDED
The step was completed successfully.
Definition f_base.hpp:44
static fBase_c * searchBaseByID(fBaseID_e id)
Searches for a base with the given ID.
Definition f_manager.cpp:18
void multVecZero(nw4r::math::VEC3 &out) const
Extracts the translation vector from the matrix.
Definition m_mtx.cpp:135
A two-dimensional floating point vector.
Definition m_vec.hpp:16
A three-dimensional floating point vector.
Definition m_vec.hpp:107
const u8 l_Ami_Line[]
The sub-layer for each side of chainlink fences.
Definition d_actor.cpp:38
u8 mKind
The type of this collider. See CC_KIND_e.
Definition d_cc.hpp:89
u8 mAttack
The attack type of this collider. See CC_ATTACK_e.
Definition d_cc.hpp:90
mVec2_POD_c mOffset
The offset of the collider.
Definition d_cc.hpp:83