NSMBW-Decomp
A decompilation of New Super Mario Bros. Wii
Loading...
Searching...
No Matches
d_a_iceball.cpp
1#include <game/bases/d_a_iceball.hpp>
2#include <game/bases/d_a_player_manager.hpp>
4#include <game/bases/d_actor.hpp>
5#include <game/bases/d_eff_actor_manager.hpp>
6#include <game/bases/d_effectmanager.hpp>
7#include <game/bases/d_s_stage.hpp>
8#include <game/bases/d_cd.hpp>
9#include <game/bases/d_bg.hpp>
11#include <game/framework/f_profile_name.hpp>
12#include <game/sLib/s_GlobalData.hpp>
14
15
16ACTOR_PROFILE(ICEBALL, daIceBall_c, 2);
17
20
21template <>
23 0.75f,
24 1.05f,
25 0.6f,
26 120.0f
27};
28
29const sBcSensorPoint l_iceball_foot = { SENSOR_IS_POINT, 0, -0x3000 };
30const sBcSensorPoint l_iceball_head = { SENSOR_IS_POINT, 0, 0x3000 };
31const sBcSensorPoint l_iceball_wall = { SENSOR_IS_POINT, 0x3000, 0 };
32
33const sCcDatNewF l_fball_cc_data = {
34 0.0f, 0.0f,
35 6.0f, 6.0f,
36 CC_KIND_TAMA,
37 CC_ATTACK_ICEBALL,
38 BIT_FLAG(CC_KIND_PLAYER_ATTACK) | BIT_FLAG(CC_KIND_ENEMY) |
39 BIT_FLAG(CC_KIND_BALLOON) | BIT_FLAG(CC_KIND_ITEM) | BIT_FLAG(CC_KIND_TAMA) | BIT_FLAG(CC_KIND_KILLER),
40 BIT_FLAG(CC_ATTACK_ICE_BREAK) | BIT_FLAG(CC_ATTACK_KOOPA_FIRE) | BIT_FLAG(CC_ATTACK_YOSHI_EAT),
41 CC_STATUS_NONE,
43};
44
45const float l_cull_data[4] = { 0.0f, 0.0f, 8.0f, 8.0f };
46
47STATE_DEFINE(daIceBall_c, FireMove);
52
54 mPlayerNo = ACTOR_PARAM(PlayerNo);
55
56 CreateKind_e kind = (CreateKind_e) ACTOR_PARAM(LimitMode);
57
58 bool isCreateOK = isIceBallEnable(mPlayerNo, kind);
59
60 mAliveTimer = 60;
61
64
65 if (!isCreateOK) {
67 return CANCELED;
68 }
69
70 mCc.mAmiLine = ACTOR_PARAM(AmiLine);
71 mBc.mAmiLine = ACTOR_PARAM(AmiLine);
72 mRc.mLineKind = ACTOR_PARAM(AmiLine);
73
74 mLayer = ACTOR_PARAM(Layer);
75 mCc.mLayer = ACTOR_PARAM(Layer);
76 mBc.mLayer = ACTOR_PARAM(Layer);
77
78 mLiquidType = dBc_c::checkWater(mPos.x, mPos.y, mLayer, &mLiquidHeight);
79 mDirection = ACTOR_PARAM(Direction);
80
81 float groundHeight = 0.0f;
82 if (checkInitLine(groundHeight)) {
83 mPos.y = groundHeight + 4.0f;
84 }
85
86 if (checkInitVanish()) {
88
89 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
91 return CANCELED;
92 }
93
94 mCenterOffs.set(0.0f, 0.0f, 0.0f);
96 mActorProperties |= 0x80;
97 mAreaNo = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile)->getAreaNo(&mPos);
98
99 mCc.set(this, (sCcDatNewF *) &l_fball_cc_data);
100 mCc.mLayer = mLayer;
101 mCc.entry();
102
103 mLightMask.init(&mAllocator, 3);
104
105 float ceilingHeight;
106 mVec3_c ceilCheckPos(mPos.x, mPos.y + 4.0f, mPos.z);
107
108 if (dBc_c::checkTenjou(&ceilCheckPos, &ceilingHeight, mLayer, 1)) {
109 if (mPos.y > ceilingHeight - 6.0f) {
110 mPos.y = ceilingHeight - 6.0f;
111 }
112 }
113
114 mBc.set(this, l_iceball_foot, l_iceball_head, l_iceball_wall);
115
116 mHitEntity = false;
117 mStartPos = mPos;
118 mStateMgr.changeState(StateID_FireMove);
119
120 return SUCCEEDED;
121}
122
124 if (mHitEntity && !isState(StateID_Kill)) {
125 mStateMgr.changeState(StateID_Kill);
126 }
127 mStateMgr.executeState();
128 lightProc();
129
130 return SUCCEEDED;
131}
132
134 mLightMask.draw();
135 return SUCCEEDED;
136}
137
139
141 if (sm_IceBallCount[mPlayerNo] > 0) {
143 }
144
145 if (mAliveTimer != 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
147 }
148
149 return SUCCEEDED;
150}
151
153 if (mBc.checkWall(nullptr)) {
154 return true;
155 }
156
157 dAcPy_c *player = daPyMng_c::getPlayer(mPlayerNo);
158 mVec3_c a(player->mPos.x, mPos.y, mPos.z);
159 mVec3_c b = mPos;
160 float c = 0.0f;
161
162 return dBc_c::checkWall(&a, &b, &c, mLayer, 1, nullptr);
163}
164
165bool daIceBall_c::checkInitLine(float &groundHeight) {
166 mVec3_c pos(mPos.x, mPos.y + 10.0f, mPos.z);
167
168 float height = 0.0f;
169 if (dBc_c::checkGround(&pos, &height, mLayer, 1, -1)) {
170 if (height < pos.y && height >= mPos.y - 3.0f) {
171 groundHeight = height;
172 return true;
173 }
174 }
175
176 return false;
177}
178
180 mLightMask.set(mPos.x, mPos.y, mPos.z, sGlobalData_c<daIceBall_c>::mData.mLightRadius);
181 mLightMask.execute();
182}
183
185 this->removeCc();
186
187 mStateMgr.changeState(StateID_EatIn);
188}
189
191 if (mRc.check(mBc.checkFoot(), 0, 0)) {
192 mBc.mFlags |= dBc_c::FLAG_15;
193 }
194
195 mBc.checkWall(nullptr);
196 mBc.checkHead(0);
197
198 if (mBc.isCollision()) {
199 return true;
200 }
201
202 return false;
203}
204
206 EffectManager_c::SetIceBallMissshitEffect(&mPos);
207}
208
210 if ((other->mCcData.mVsDamage & (1 << CC_ATTACK_ICEBALL)) == 0) {
211 return;
212 }
213
214 self->mInfo |= CC_NO_HIT;
215
216 daIceBall_c *thisIceball = (daIceBall_c *) self->getOwner();
217 dActor_c *otherActor = other->getOwner();
218
219 if (otherActor->mKind == fBase_c::ENEMY) {
220 if (otherActor->mProfName == fProf::EN_MARUTA) {
221 if (thisIceball->mSpeed.y >= 0.0f) {
222 return;
223 }
224
225 if (thisIceball->isState(StateID_FireMove)) {
226 thisIceball->mStateMgr.changeState(StateID_Move);
227 return;
228 }
229 }
230
231 thisIceball->mHitEntity = true;
232 } else if (other->mCcData.mAttack == CC_ATTACK_KOOPA_FIRE) {
233 if ((otherActor->mProfName == fProf::KOOPA_FIRE) && ((int)(otherActor->mParam & 0xF) == 1)) {
234 dAudio::SndObjctCmnMap_c *map = dAudio::g_pSndObjMap;
235 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playObjSound(map, thisIceball->mPos, 0);
236 }
237
238 thisIceball->setDeleteEffect();
239 thisIceball->mHitEntity = true;
240 } else if (other->mCcData.mKind == CC_KIND_ENEMY) {
241 thisIceball->setDeleteEffect();
242 thisIceball->mHitEntity = true;
243 }
244}
245
247 if (mLayer == LAYER_1) {
248 if (dBc_c::checkWireNet(mPos.x, mPos.y, mLayer)) {
249 if (mStartPos.z >= 0.0f) {
250 mPos.z = 2000.0f;
251 } else {
252 mPos.z = mStartPos.z;
253 }
254 } else {
255 mPos.z = 2000.0f;
256 }
257 } else if (mLayer == LAYER_2) {
258 mPos.z = -1800.0f;
259 }
260}
261
263 return dActor_c::screenCullCheck(mPos, (const sRangeDataF &) l_cull_data, sRangeDataF(64.0f, 64.0f, 32.0f, 32.0f), mAreaNo);
264}
265
267 dActor_c::eatMove(actor);
268 mPos.y += 2.0f;
269}
270
272 if (mBc.isWallL() | mBc.isWallR() | mBc.isHead()) {
273 return true;
274 }
275 if ((mBc.mFlags & dBc_c::FLAG_15) && (mRc.isRideFlag(0x200) & 0xFFFF)) {
276 return true;
277 }
278 if (mBc.getFootAttr() == 3) {
279 return true;
280 }
281 if (mBc.getSakaAngle(mDirection) >= 0x2D16) {
282 return true;
283 }
284 if (mRc.getRide() && (mRc.getRide()->mFlags & 0x1000)) {
285 return true;
286 }
287 return false;
288}
289
291 int prevLiquid = mLiquidType;
292 mLiquidType = dBc_c::checkWater(mPos.x, mPos.y, mLayer, &mLiquidHeight);
293
294 bool destroyIceball = false;
295 switch (mLiquidType) {
296 case dBc_c::WATER_CHECK_WATER:
297 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
299 }
300 break;
301 case dBc_c::WATER_CHECK_WATER_BUBBLE:
302 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
303 waterSplash(mPos.y);
304 }
305 break;
306 case dBc_c::WATER_CHECK_YOGAN:
307 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
309 }
310 destroyIceball = true;
311 break;
312 case dBc_c::WATER_CHECK_POISON:
313 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
315 }
316 destroyIceball = true;
317 break;
318 default:
319 break;
320 }
321
322 return destroyIceball;
323}
324
325void daIceBall_c::waterSplash(float height) {
326 mVec3_c pos(mPos.x, height, 6500.0f);
327 dAudio::SoundEffectID_t(SE_OBJ_FIREBALL_SPLASH).playMapSound(pos, 0);
328
329 u32 splashFlags;
330 if (pos.y == mPos.y) {
331 splashFlags = mLayer << 16 | 1;
332 } else {
333 splashFlags = mLayer << 16 | 2;
334 }
335
336 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, mVec3_c(1.0f, 1.0f, 1.0f));
337 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 8);
338}
339
340void daIceBall_c::yoganSplash(float height) {
341 mVec3_c pos(mPos.x, height, 6500.0f);
342 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_LAVA).playMapSound(pos, 0);
343
344 u32 splashFlags = mLayer << 16 | 4;
345 mVec3_c scale(0.6f, 0.6f, 0.6f);
346
347 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, scale);
348 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 18);
349}
350
351void daIceBall_c::poisonSplash(float height) {
352 mVec3_c pos(mPos.x, height, 6500.0f);
353 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_POISON).playMapSound(pos, 0);
354
355 u32 splashFlags = mLayer << 16 | 6;
356 mVec3_c scale(0.6f, 0.6f, 0.6f);
357
358 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, scale);
359 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 25);
360}
361
362void daIceBall_c::initializeState_FireMove() {
363 static const float x_speeds[] = {3.6f, -3.6f};
364
365 mAccelY = -0.4375f;
366 mMaxFallSpeed = -4.0f;
367 mSpeed.set(x_speeds[mDirection], -3.0f, 0.0f);
368}
369
370void daIceBall_c::finalizeState_FireMove() {}
371
372void daIceBall_c::executeState_FireMove() {
373 EffectManager_c::SetIceBallEffect(&mPos);
374
375 if (mAliveTimer != 0 && --mAliveTimer == 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
377 }
378
380 posMove();
381 chgZpos();
382 bgCheck();
383
384 // Jump back up if we hit the ground
385 if (mBc.mFlags & dBc_c::FLAG_FOOT) {
386 mStateMgr.changeState(StateID_Move);
387 return;
388 }
389
390 // Destroy if we hit lava or poison
391 if (waterlineCheck()) {
394 return;
395 }
396
397 if (checkDeleteBg()) {
398 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
401 } else if (cullCheck()) {
403 }
404}
405
406void daIceBall_c::initializeState_Move() {
407 static const float cs_speed_x[] = {3.0f, -3.0f};
408 static const float cs_max_speed_x[] = {1.5f, -1.5f};
409
410 float playerXSpeed = daPyMng_c::getPlayer(mPlayerNo)->mSpeed.x;
411 float moveBoostThreshold = sGlobalData_c<daIceBall_c>::mData.moveBoostThreshold;
412 float moveBoostScale = sGlobalData_c<daIceBall_c>::mData.mMoveBoostScale;
413
414 float speedBoost;
415 if (playerXSpeed > moveBoostThreshold) {
416 float baseBoost = moveBoostScale * moveBoostThreshold;
417 speedBoost = baseBoost + sGlobalData_c<daIceBall_c>::mData.calcExtraBoost(playerXSpeed - moveBoostThreshold);
418 } else if (playerXSpeed < -moveBoostThreshold) {
419 float baseBoost = -moveBoostScale * moveBoostThreshold;
420 speedBoost = baseBoost + sGlobalData_c<daIceBall_c>::mData.calcExtraBoost(playerXSpeed + moveBoostThreshold);
421 } else {
422 speedBoost = moveBoostScale * playerXSpeed;
423 }
424
425 mSpeed.set(speedBoost + cs_speed_x[mDirection], 3.7f, 0.0f);
426 mAccelY = -0.15f;
427 mSpeedMax.x = cs_max_speed_x[mDirection];
428 mMaxFallSpeed = -3.0f;
429 mAccelF = 0.04f;
430}
431
432void daIceBall_c::finalizeState_Move() {}
433
434void daIceBall_c::executeState_Move() {
435 EffectManager_c::SetIceBallEffect(&mPos);
436
437 if (mAliveTimer != 0 && --mAliveTimer == 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
439 }
440
441 calcSpeedX();
443 posMove();
444 chgZpos();
445
446 if (waterlineCheck()) {
449 return;
450 }
451
452 if (bgCheck()) {
453 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
456 return;
457 }
458
459 if (mRc.getRide()) {
460 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
463 return;
464 }
465
466 if (cullCheck()) {
468 }
469}
470
471void daIceBall_c::initializeState_EatIn() {}
472
473void daIceBall_c::finalizeState_EatIn() {}
474
475void daIceBall_c::executeState_EatIn() {
476 EffectManager_c::SetIceBallEffect(&mPos);
477 if (mEatState == EAT_STATE_EATEN) {
478 mStateMgr.changeState(StateID_EatNow);
479 }
480}
481
482void daIceBall_c::initializeState_EatNow() {}
483
484void daIceBall_c::finalizeState_EatNow() {}
485
486void daIceBall_c::executeState_EatNow() {}
487
488void daIceBall_c::initializeState_Kill() {
489 removeCc();
491}
492
493void daIceBall_c::finalizeState_Kill() {}
494
495void daIceBall_c::executeState_Kill() {}
496
499 if (kind == CREATE_SPIN) {
500 return true;
501 }
502
504 return true;
505 }
506 }
507
508 return false;
509}
The player class for Mario, Luigi and the Toads.
sFStateMgr_c< dActorState_c, sStateMethodUsr_FI_c > mStateMgr
The state manager.
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 mEatState
The actor's eat state. Value is a EAT_STATE_e.
Definition d_actor.hpp:365
u8 mDirection
The actor's facing direction.
Definition d_actor.hpp:351
dCc_c mCc
The actor-to-actor collision sensor.
Definition d_actor.hpp:341
@ EAT_TYPE_ICEBALL
Yoshi can spit an iceball after eating the actor.
Definition d_actor.hpp:41
virtual void removeCc()
Disables the actor's collision.
Definition d_actor.cpp:800
virtual void eatMove(dActor_c *eatingActor)
Updates the actor's position during eating actions.
Definition d_actor.cpp:683
u8 mAreaNo
The actor's zone ID.
Definition d_actor.hpp:352
u8 mEatBehavior
The actor's eat behaviour. Value is a EAT_BEHAVIOR_e.
Definition d_actor.hpp:366
s8 mPlayerNo
The player associated with the actor, -1 if not associated to any player.
Definition d_actor.hpp:375
static int screenCullCheck(const mVec3_c &pos, const sRangeDataF &visibleBound, sRangeDataF destroyBound, u8 areaID)
Checks if the actor should be culled due to being outside the screen.
@ EAT_STATE_EATEN
The actor has been successfully eaten.
Definition d_actor.hpp:29
dActor_c()
Constructs a new actor.
Definition d_actor.cpp:46
dRc_c mRc
The actor's ride surface manager.
Definition d_actor.hpp:343
u8 mLayer
The actor's layer.
Definition d_actor.hpp:377
float mAccelF
The actor's horizontal acceleration.
mVec3_c mSpeed
The actor's speed.
mVec3_c mPos
The actor's position.
mVec3_c mSpeedMax
The actor's maximum speed.
void calcSpeedX()
Updates the actor's X speed. See here for details.
mVec3_c mCenterOffs
The offset from the position to the center of the actor (defaults to 0).
void calcFallSpeed()
Updates the actor's falling speed. See here for details.
void posMove()
Moves the actor by its speed.
float mMaxFallSpeed
The actor's maximum fall speed.
u32 mActorProperties
The actor's properties. See fProf::fActorProfile_c::mActorProperties.
float mAccelY
The actor's vertical acceleration.
Collider ("Collision Check") class - handles collisions between actors.
Definition d_cc.hpp:133
u8 mInfo
Info flags for this collider. See CC_INFO_e.
Definition d_cc.hpp:337
dActor_c * getOwner() const
Gets the owner actor of this collider.
Definition d_cc.hpp:178
sCcDatNewF mCcData
The collision data of this collider.
Definition d_cc.hpp:288
An iceball, thrown by the player.
static int sm_IceBallAliveCount[4]
The number of "alive" iceballs for each player.
bool checkInitLine(float &groundHeight)
Checks if the iceball is close to the ground so that it can spawn a bit higher up.
virtual int create()
do method for the create operation.
dBc_c::WATER_TYPE_e mLiquidType
The type of liquid the iceball is currently in contact with.
void waterSplash(float height)
Creates a water splash effect and sound at a specified height.
u32 mHitEntity
Whether the iceball has hit an entity.
static const int smc_MAX_ALIVE_ICEBALL_COUNT
bool checkInitVanish()
Checks whether the iceball should vanish on creation. This happens if the iceball is supposed to spaw...
static sFStateID_c< daIceBall_c > StateID_EatIn
The iceball is being eaten.
bool bgCheck()
Checks for collisions and returns whether a collision occurred.
mVec3_c mStartPos
The starting position of the iceball when it was created.
static sFStateID_c< daIceBall_c > StateID_Kill
The iceball has hit something and should be deleted.
void yoganSplash(float height)
Creates a lava splash effect and sound at a specified height.
virtual void eatMove(dActor_c *eatingActor)
Updates the actor's position during eating actions.
static const int smc_MAX_ICEBALL_COUNT
void setDeleteEffect()
Creates an effect for when the iceball gets destroyed.
float mLiquidHeight
The height of the liquid surface the iceball is in contact with.
static sFStateID_c< daIceBall_c > StateID_EatNow
The iceball has been eaten.
static sFStateID_c< daIceBall_c > StateID_FireMove
The iceball is moving downwards after being thrown.
virtual int doDelete()
do method for the delete operation.
bool checkDeleteBg()
Checks if the iceball should be deleted due to hitting something.
void poisonSplash(float height)
Creates a poison splash effect and sound at a specified height.
void lightProc()
Updates the iceball's light mask.
static int sm_IceBallCount[4]
The number of iceballs that currently exist for each player.
virtual void deleteReady()
Informs the base that it's about to be deleted.
void chgZpos()
Updates the iceball's Z position.
static sFStateID_c< daIceBall_c > StateID_Move
The iceball hit the ground and is doing a final bounce.
virtual void setEatTongue(dActor_c *eatingActor)
Callback for when the actor is targeted by Yoshi's tongue.
@ CREATE_SPIN
Use smc_MAX_ICEBALL_COUNT.
bool waterlineCheck()
Checks if the iceball hit the surface of a liquid. If it did, it creates a splash effect and sound.
static bool isIceBallEnable(int playerNo, CreateKind_e kind)
Checks if a new iceball can be created for a player based on the limit mode.
virtual int draw()
do method for the draw operation.
dHeapAllocator_c mAllocator
Heap allocator for the iceball.
bool cullCheck()
Checks if the iceball is within the camera's view.
static void ccCallback_Iceball(dCc_c *self, dCc_c *other)
Collision callback for the iceball.
dCircleLightMask_c mLightMask
Light mask for the iceball.
daIceBall_c()
Creates a new iceball actor.
virtual int execute()
do method for the execute operation.
u32 mAliveTimer
Timer for the iceball's lifetime. This is used to limit how quickly the player can throw multiple ice...
@ CANCELED
The operation was canceled early.
Definition f_base.hpp:37
void deleteRequest()
Requests deletion of the base.
Definition f_base.cpp:289
@ ENEMY
The base is an enemy.
Definition f_base.hpp:32
ProfileName mProfName
The base's profile name.
Definition f_base.hpp:63
u32 mParam
A bitfield that configures the base's behaviour. Its usage varies from profile to profile.
Definition f_base.hpp:62
@ SUCCEEDED
The step was completed successfully.
Definition f_base.hpp:46
A three-dimensional floating point vector.
Definition m_vec.hpp:122
static const T::GlobalData_t mData
virtual void changeState(const sStateIDIf_c &newState)
Transitions to a new state ID.
#define ACTOR_PROFILE(profName, className, properties)
Creates an actor profile, using the profile number as the execute and draw order value.
Definition f_profile.hpp:29
#define STATE_DEFINE(class, name)
Defines a state.
Definition s_State.hpp:36
A structure that contains information about a collider.
Definition d_cc.hpp:98
u8 mKind
The type of this collider. See CC_KIND_e.
Definition d_cc.hpp:101
u8 mAttack
The attack type of this collider. See CC_ATTACK_e.
Definition d_cc.hpp:102