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 bool isCreateOK = CheckIceballLimit(mPlayerNo, ACTOR_PARAM(LimitMode));
57
58 mAliveTimer = 60;
59
62
63 if (!isCreateOK) {
65 return CANCELED;
66 }
67
68 mCc.mAmiLine = ACTOR_PARAM(AmiLine);
69 mBc.mAmiLine = ACTOR_PARAM(AmiLine);
70 mRc.mLineKind = ACTOR_PARAM(AmiLine);
71
72 mLayer = ACTOR_PARAM(Layer);
73 mCc.mLayer = ACTOR_PARAM(Layer);
74 mBc.mLayer = ACTOR_PARAM(Layer);
75
76 mLiquidType = dBc_c::checkWater(mPos.x, mPos.y, mLayer, &mLiquidHeight);
77 mDirection = ACTOR_PARAM(Direction);
78
79 float groundHeight = 0.0f;
80 if (checkInitLine(groundHeight)) {
81 mPos.y = groundHeight + 4.0f;
82 }
83
84 if (checkInitVanish()) {
86
87 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
89 return CANCELED;
90 }
91
92 mCenterOffs.set(0.0f, 0.0f, 0.0f);
94 mActorProperties |= 0x80;
95 mAreaNo = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile)->getAreaNo(&mPos);
96
97 mCc.set(this, (sCcDatNewF *) &l_fball_cc_data);
98 mCc.mLayer = mLayer;
99 mCc.entry();
100
101 mLightMask.init(&mAllocator, 3);
102
103 float ceilingHeight;
104 mVec3_c ceilCheckPos(mPos.x, mPos.y + 4.0f, mPos.z);
105
106 if (dBc_c::checkTenjou(&ceilCheckPos, &ceilingHeight, mLayer, 1)) {
107 if (mPos.y > ceilingHeight - 6.0f) {
108 mPos.y = ceilingHeight - 6.0f;
109 }
110 }
111
112 mBc.set(this, l_iceball_foot, l_iceball_head, l_iceball_wall);
113
114 mHitEntity = false;
115 mStartPos = mPos;
116 mStateMgr.changeState(StateID_FireMove);
117
118 return SUCCEEDED;
119}
120
122 if (mHitEntity && !isState(StateID_Kill)) {
123 mStateMgr.changeState(StateID_Kill);
124 }
125 mStateMgr.executeState();
126 lightProc();
127
128 return SUCCEEDED;
129}
130
132 mLightMask.draw();
133 return SUCCEEDED;
134}
135
137
139 if (sm_IceBallCount[mPlayerNo] > 0) {
141 }
142
143 if (mAliveTimer != 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
145 }
146
147 return SUCCEEDED;
148}
149
151 if (mBc.checkWall(nullptr)) {
152 return true;
153 }
154
155 dAcPy_c *player = daPyMng_c::getPlayer(mPlayerNo);
156 mVec3_c a(player->mPos.x, mPos.y, mPos.z);
157 mVec3_c b = mPos;
158 float c = 0.0f;
159
160 return dBc_c::checkWall(&a, &b, &c, mLayer, 1, nullptr);
161}
162
163bool daIceBall_c::checkInitLine(float &groundHeight) {
164 mVec3_c pos(mPos.x, mPos.y + 10.0f, mPos.z);
165
166 float height = 0.0f;
167 if (dBc_c::checkGround(&pos, &height, mLayer, 1, -1)) {
168 if (height < pos.y && height >= mPos.y - 3.0f) {
169 groundHeight = height;
170 return true;
171 }
172 }
173
174 return false;
175}
176
178 mLightMask.set(mPos.x, mPos.y, mPos.z, sGlobalData_c<daIceBall_c>::mData.mLightRadius);
179 mLightMask.execute();
180}
181
183 this->removeCc();
184
185 mStateMgr.changeState(StateID_EatIn);
186}
187
189 if (mRc.check(mBc.checkFoot(), 0, 0)) {
190 mBc.mFlags |= dBc_c::FLAG_15;
191 }
192
193 mBc.checkWall(nullptr);
194 mBc.checkHead(0);
195
196 if (mBc.isCollision()) {
197 return true;
198 }
199
200 return false;
201}
202
204 EffectManager_c::SetIceBallMissshitEffect(&mPos);
205}
206
208 if ((other->mCcData.mVsDamage & (1 << CC_ATTACK_ICEBALL)) == 0) {
209 return;
210 }
211
212 self->mInfo |= CC_NO_HIT;
213
214 daIceBall_c *thisIceball = (daIceBall_c *) self->getOwner();
215 dActor_c *otherActor = other->getOwner();
216
217 if (otherActor->mKind == fBase_c::ENEMY) {
218 if (otherActor->mProfName == fProfile::EN_MARUTA) {
219 if (thisIceball->mSpeed.y >= 0.0f) {
220 return;
221 }
222
223 if (thisIceball->isState(StateID_FireMove)) {
224 thisIceball->mStateMgr.changeState(StateID_Move);
225 return;
226 }
227 }
228
229 thisIceball->mHitEntity = true;
230 } else if (other->mCcData.mAttack == CC_ATTACK_KOOPA_FIRE) {
231 if ((otherActor->mProfName == fProfile::KOOPA_FIRE) && ((int)(otherActor->mParam & 0xF) == 1)) {
232 dAudio::SndObjctCmnMap_c *map = dAudio::g_pSndObjMap;
233 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playObjSound(map, thisIceball->mPos, 0);
234 }
235
236 thisIceball->setDeleteEffect();
237 thisIceball->mHitEntity = true;
238 } else if (other->mCcData.mKind == CC_KIND_ENEMY) {
239 thisIceball->setDeleteEffect();
240 thisIceball->mHitEntity = true;
241 }
242}
243
245 if (mLayer == 0) {
246 if (dBc_c::checkWireNet(mPos.x, mPos.y, mLayer)) {
247 if (mStartPos.z >= 0.0f) {
248 mPos.z = 2000.0f;
249 } else {
250 mPos.z = mStartPos.z;
251 }
252 } else {
253 mPos.z = 2000.0f;
254 }
255 } else if (mLayer == 1) {
256 mPos.z = -1800.0f;
257 }
258}
259
261 return dActor_c::screenCullCheck(mPos, (const sRangeDataF &) l_cull_data, sRangeDataF(64.0f, 64.0f, 32.0f, 32.0f), mAreaNo);
262}
263
265 dActor_c::eatMove(actor);
266 mPos.y += 2.0f;
267}
268
270 if (mBc.isWallL() | mBc.isWallR() | mBc.isHead()) {
271 return true;
272 }
273 if ((mBc.mFlags & dBc_c::FLAG_15) && (mRc.isRideFlag(0x200) & 0xFFFF)) {
274 return true;
275 }
276 if (mBc.getFootAttr() == 3) {
277 return true;
278 }
279 if (mBc.getSakaAngle(mDirection) >= 0x2D16) {
280 return true;
281 }
282 if (mRc.getRide() && (mRc.getRide()->mFlags & 0x1000)) {
283 return true;
284 }
285 return false;
286}
287
289 int prevLiquid = mLiquidType;
290 mLiquidType = dBc_c::checkWater(mPos.x, mPos.y, mLayer, &mLiquidHeight);
291
292 bool destroyIceball = false;
293 switch (mLiquidType) {
294 case dBc_c::WATER_CHECK_WATER:
295 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
297 }
298 break;
299 case dBc_c::WATER_CHECK_WATER_BUBBLE:
300 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
301 waterSplash(mPos.y);
302 }
303 break;
304 case dBc_c::WATER_CHECK_YOGAN:
305 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
307 }
308 destroyIceball = true;
309 break;
310 case dBc_c::WATER_CHECK_POISON:
311 if (prevLiquid == dBc_c::WATER_CHECK_NONE) {
313 }
314 destroyIceball = true;
315 break;
316 default:
317 break;
318 }
319
320 return destroyIceball;
321}
322
323void daIceBall_c::waterSplash(float height) {
324 mVec3_c pos(mPos.x, height, 6500.0f);
325 dAudio::SoundEffectID_t(SE_OBJ_FIREBALL_SPLASH).playMapSound(pos, 0);
326
327 u32 splashFlags;
328 if (pos.y == mPos.y) {
329 splashFlags = mLayer << 16 | 1;
330 } else {
331 splashFlags = mLayer << 16 | 2;
332 }
333
334 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, mVec3_c(1.0f, 1.0f, 1.0f));
335 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 8);
336}
337
338void daIceBall_c::yoganSplash(float height) {
339 mVec3_c pos(mPos.x, height, 6500.0f);
340 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_LAVA).playMapSound(pos, 0);
341
342 u32 splashFlags = mLayer << 16 | 4;
343 mVec3_c scale(0.6f, 0.6f, 0.6f);
344
345 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, scale);
346 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 18);
347}
348
349void daIceBall_c::poisonSplash(float height) {
350 mVec3_c pos(mPos.x, height, 6500.0f);
351 dAudio::SoundEffectID_t(SE_OBJ_CMN_SPLASH_POISON).playMapSound(pos, 0);
352
353 u32 splashFlags = mLayer << 16 | 6;
354 mVec3_c scale(0.6f, 0.6f, 0.6f);
355
356 dEffActorMng_c::m_instance->createWaterSplashEff(pos, splashFlags, -1, scale);
357 dBg_c::m_bg_p->setWaterInWave(pos.x, pos.y, 25);
358}
359
360void daIceBall_c::initializeState_FireMove() {
361 static const float x_speeds[] = {3.6f, -3.6f};
362
363 mAccelY = -0.4375f;
364 mMaxFallSpeed = -4.0f;
365 mSpeed.set(x_speeds[mDirection], -3.0f, 0.0f);
366}
367
368void daIceBall_c::finalizeState_FireMove() {}
369
370void daIceBall_c::executeState_FireMove() {
371 EffectManager_c::SetIceBallEffect(&mPos);
372
373 if (mAliveTimer != 0 && --mAliveTimer == 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
375 }
376
378 posMove();
379 chgZpos();
380 bgCheck();
381
382 // Jump back up if we hit the ground
383 if (mBc.mFlags & dBc_c::FLAG_FOOT) {
384 mStateMgr.changeState(StateID_Move);
385 return;
386 }
387
388 // Destroy if we hit lava or poison
389 if (waterlineCheck()) {
392 return;
393 }
394
395 if (checkDeleteBg()) {
396 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
399 } else if (cullCheck()) {
401 }
402}
403
404void daIceBall_c::initializeState_Move() {
405 static const float cs_speed_x[] = {3.0f, -3.0f};
406 static const float cs_max_speed_x[] = {1.5f, -1.5f};
407
408 float playerXSpeed = daPyMng_c::getPlayer(mPlayerNo)->mSpeed.x;
409 float moveBoostThreshold = sGlobalData_c<daIceBall_c>::mData.moveBoostThreshold;
410 float moveBoostScale = sGlobalData_c<daIceBall_c>::mData.mMoveBoostScale;
411
412 float speedBoost;
413 if (playerXSpeed > moveBoostThreshold) {
414 float baseBoost = moveBoostScale * moveBoostThreshold;
415 speedBoost = baseBoost + sGlobalData_c<daIceBall_c>::mData.calcExtraBoost(playerXSpeed - moveBoostThreshold);
416 } else if (playerXSpeed < -moveBoostThreshold) {
417 float baseBoost = -moveBoostScale * moveBoostThreshold;
418 speedBoost = baseBoost + sGlobalData_c<daIceBall_c>::mData.calcExtraBoost(playerXSpeed + moveBoostThreshold);
419 } else {
420 speedBoost = moveBoostScale * playerXSpeed;
421 }
422
423 mSpeed.set(speedBoost + cs_speed_x[mDirection], 3.7f, 0.0f);
424 mAccelY = -0.15f;
425 mSpeedMax.x = cs_max_speed_x[mDirection];
426 mMaxFallSpeed = -3.0f;
427 mAccelF = 0.04f;
428}
429
430void daIceBall_c::finalizeState_Move() {}
431
432void daIceBall_c::executeState_Move() {
433 EffectManager_c::SetIceBallEffect(&mPos);
434
435 if (mAliveTimer != 0 && --mAliveTimer == 0 && sm_IceBallAliveCount[mPlayerNo] > 0) {
437 }
438
439 calcSpeedX();
441 posMove();
442 chgZpos();
443
444 if (waterlineCheck()) {
447 return;
448 }
449
450 if (bgCheck()) {
451 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
454 return;
455 }
456
457 if (mRc.getRide()) {
458 dAudio::SoundEffectID_t(SE_OBJ_PNGN_ICEBALL_DISAPP).playMapSound(mPos, 0);
461 return;
462 }
463
464 if (cullCheck()) {
466 }
467}
468
469void daIceBall_c::initializeState_EatIn() {}
470
471void daIceBall_c::finalizeState_EatIn() {}
472
473void daIceBall_c::executeState_EatIn() {
474 EffectManager_c::SetIceBallEffect(&mPos);
475 if (mEatState == EAT_STATE_EATEN) {
476 mStateMgr.changeState(StateID_EatNow);
477 }
478}
479
480void daIceBall_c::initializeState_EatNow() {}
481
482void daIceBall_c::finalizeState_EatNow() {}
483
484void daIceBall_c::executeState_EatNow() {}
485
486void daIceBall_c::initializeState_Kill() {
487 removeCc();
489}
490
491void daIceBall_c::finalizeState_Kill() {}
492
493void daIceBall_c::executeState_Kill() {}
494
495bool daIceBall_c::CheckIceballLimit(int playerId, int limitMode) {
497 if (limitMode == 1) {
498 return true;
499 }
500
502 return true;
503 }
504 }
505
506 return false;
507}
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 mEatBehaviour
The actor's eat behaviour. Value is a EAT_BEHAVIOR_e.
Definition d_actor.hpp:366
u8 mAreaNo
The actor's zone ID.
Definition d_actor.hpp:352
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 fProfile::fActorProfile_c::mActorProperties.
float mAccelY
The actor's vertical acceleration.
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
sCcDatNewF mCcData
The collision data of this collider.
Definition d_cc.hpp:263
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.
static bool CheckIceballLimit(int playerNo, int limitMode)
Checks if a new iceball can be created for a player based on the limit mode.
virtual void setEatTongue(dActor_c *eatingActor)
Callback for when the actor is targeted by Yoshi's tongue.
bool waterlineCheck()
Checks if the iceball hit the surface of a liquid. If it did, it creates a splash effect and sound.
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:35
void deleteRequest()
Requests deletion of the base.
Definition f_base.cpp:289
@ ENEMY
The base is an enemy.
Definition f_base.hpp:30
ProfileName mProfName
The base's profile name.
Definition f_base.hpp:61
u32 mParam
A bitfield that configures the base's behaviour. Its usage varies from profile to profile.
Definition f_base.hpp:60
@ SUCCEEDED
The step was completed successfully.
Definition f_base.hpp:44
A three-dimensional floating point vector.
Definition m_vec.hpp:107
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:82
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