1#include <game/bases/d_a_en_snake_block.hpp>
2#include <game/bases/d_rail.hpp>
3#include <game/bases/d_s_stage.hpp>
5#include <game/mLib/m_allocator_dummy_heap.hpp>
6#include <game/bases/d_bg_parameter.hpp>
19 nw4r::g3d::ResMdl mdl =
mResFile.GetResMdl(
"block_snake_ice");
20 mModel.create(mdl, allocator,
21 nw4r::g3d::ScnMdl::ANM_TEXSRT | nw4r::g3d::ScnMdl::ANM_MATCLR | nw4r::g3d::ScnMdl::BUFFER_RESMATMISC,
31 nw4r::g3d::ResAnmClr resAnmClr =
mResFile.GetResAnmClr(
"ridden");
32 mAnmClr.create(mdl, resAnmClr, allocator,
nullptr, 1);
50 nw4r::g3d::ResAnmClr res =
mResFile.GetResAnmClr(name);
60 mMtx_c mtx = mMtx_c::createTrans(drawPos);
78 mBgCtr.set(
mpOwner, dx - 8.0f, dy + 8.0f, dx + 8.0f, dy - 8.0f,
94 mBgCtr.setOfs(dx - 8.0f, dy + 8.0f, dx + 8.0f, dy - 8.0f,
nullptr);
107 static mVec2_c offsets[MOVE_DIR_COUNT] = {
118 if (dir == MOVE_DIR_NONE) {
122 mPos.x += offsets[dir].x;
123 mPos.y += offsets[dir].y;
125 if (delta.length() >= 16.0f) {
135 bool isPlayer =
false;
153 mVec2_c(0.0f, -1.0f),
154 mVec2_c(-1.0f, 0.0f),
183 mPos.x += speed * dir.x;
184 mPos.y += speed * dir.y;
206 if (
g_SnakeNum > 0 && ACTOR_PARAM(RailStartIdx) != 0) {
239 static const float sc_shakeOffsetX[2] = {
243 mVec3_c offset(0.0f, 0.0f, 0.0f);
245 offset.x += sc_shakeOffsetX[(
mShakeTimer >> 1) & 1];
248 getHeadBlock().draw(offset);
249 getTailBlock().draw(offset);
260 if (
mAllocator.mpHeap != mAllocatorDummyHeap_c::getInstance()) {
281 dCdFile_c *file = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile);
284 node = &node[ACTOR_PARAM(RailStartIdx)];
285 bool icy = ACTOR_PARAM(SnakeType);
287 float nodeX = node->mX;
288 float nodeY = node->mY;
289 float blockPosX = nodeX +
mBlockCount * 16.0f + 8.0f;
290 float blockPosY = -nodeY - 8.0f;
292 mVec3_c headPos(blockPosX, blockPosY, 1516.0f);
293 getHeadBlock().initCollision(
this, headPos, icy);
299 mVec3_c blockPos(blockPosX, blockPosY, 1500.0f);
308 getTailBlock().initCollision(
this, tailPos, icy);
311 getTailBlock().mMoveSequenceIdx = 1;
318 getHeadBlock().calcAnm();
319 getTailBlock().calcAnm();
336 getHeadBlock().deleteBlock();
337 getTailBlock().deleteBlock();
356 getHeadBlock().calcCollision();
357 getTailBlock().calcCollision();
358 getTailBlock().mBgCtr.mFlags |= 1;
367 dCdFile_c *cdFile = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile);
376 int startIdx = ACTOR_PARAM(RailStartIdx);
377 u16 railNodeCount = rail->mCount;
379 for (
int i = startIdx; i < railNodeCount - 1; i++) {
382 dx = abs((nextNode->mX >> 4) - (currNode->mX >> 4));
383 dy = abs((nextNode->mY >> 4) - (currNode->mY >> 4));
392 for (
int i = startIdx; i < rail->mCount - 1; i++) {
395 dx = (nextNode->mX >> 4) - (currNode->mX >> 4);
396 dy = (nextNode->mY >> 4) - (currNode->mY >> 4);
401 MoveDir_e xDir = MOVE_DIR_NONE;
402 MoveDir_e yDir = MOVE_DIR_NONE;
405 xDir = MOVE_DIR_RIGHT;
407 xDir = MOVE_DIR_LEFT;
413 yDir = MOVE_DIR_DOWN;
418 if (dx_abs <= dy_abs) {
419 for (
int j = 0; j < dx_abs; j++) {
420 idx = currIdx + moveCount;
425 for (
int j = 0; j < dy_abs - dx_abs; j++) {
426 idx = currIdx + moveCount;
431 for (
int j = 0; j < dy_abs; j++) {
432 idx = currIdx + moveCount;
437 for (
int j = 0; j < dx_abs - dy_abs; j++) {
438 idx = currIdx + moveCount;
444 currIdx += moveCount;
456 pos.x = currBlock->getPos().x;
457 pos.y = currBlock->getPos().y;
459 nextBlock->setPos(pos);
466 pos.x = getHeadBlock().getPos().x;
467 pos.y = getHeadBlock().getPos().y;
473 mPos.x = getHeadBlock().getPos().x;
474 mPos.y = getHeadBlock().getPos().y;
479 return getTailBlock().getPos().y < dBgParameter_c::ms_Instance_p->yEnd() - 16.0f;
487 return mPos.x >= dBgParameter_c::ms_Instance_p->xEnd() + 512.0f;
490void daEnSnakeBlock_c::initializeState_Wait() {}
491void daEnSnakeBlock_c::finalizeState_Wait() {}
492void daEnSnakeBlock_c::executeState_Wait() {}
494void daEnSnakeBlock_c::initializeState_Move() {
495 getHeadBlock().setAnmClr(
"create");
496 getHeadBlock().mAnmClr.setRate(0.0f, 0);
497 getHeadBlock().mAnmClr.setFrame(25.0f, 0);
498 getTailBlock().setAnmClr(
"ridden");
500 mBlocks[0].setAnmClr(
"create");
502 mBlocks[i].setAnmClr(
"ridden");
505 getHeadBlock().mLastPos = getHeadBlock().mPos;
506 getTailBlock().mLastPos = getTailBlock().mPos;
508 int framesPerBlock = 16.0f /
sc_SnakeSpeeds[ACTOR_PARAM(SnakeSpeed)];
513void daEnSnakeBlock_c::finalizeState_Move() {}
515void daEnSnakeBlock_c::executeState_Move() {
519 bool headBlockSeqCompleted =
false;
520 bool tailBlockSeqCompleted =
false;
522 if (headBlockMoved || tailBlockMoved) {
523 headBlockSeqCompleted = getHeadBlock().nextTravelMove(
mpMoveSequence);
524 tailBlockSeqCompleted = getTailBlock().nextTravelMove(
mpMoveSequence);
536 int framesPerBlock = 16.0f /
sc_SnakeSpeeds[ACTOR_PARAM(SnakeSpeed)];
541 block->setAnmClr(
"create");
542 block->mAnmClr.setFrame(animFrame, 0);
544 animFrame += framesPerBlock;
548 if (headBlockSeqCompleted || tailBlockSeqCompleted) {
557void daEnSnakeBlock_c::initializeState_Shake() {
559 getHeadBlock().mAnmClr.setRate(0.0f, 0);
560 getTailBlock().setAnmClr(
"ridden");
561 getTailBlock().mAnmClr.setRate(0.0f, 0);
565 curr.setAnmClr(
"ridden");
566 curr.mAnmClr.setRate(0.0f, 0);
572void daEnSnakeBlock_c::finalizeState_Shake() {}
574void daEnSnakeBlock_c::executeState_Shake() {
580void daEnSnakeBlock_c::initializeState_Stop() {
581 getHeadBlock().setAnmClr(
"ridden");
582 getHeadBlock().mAnmClr.setRate(0.0f, 0);
583 getTailBlock().setAnmClr(
"ridden");
584 getTailBlock().mAnmClr.setRate(0.0f, 0);
588 block.setAnmClr(
"ridden");
589 block.mAnmClr.setRate(0.0f, 0);
593void daEnSnakeBlock_c::finalizeState_Stop() {}
594void daEnSnakeBlock_c::executeState_Stop() {}
596void daEnSnakeBlock_c::initializeState_Collapse1() {
597 static mVec2_c sc_collapseSpeeds[MOVE_DIR_COUNT] = {
600 mVec2_c(0.0f, -1.0f),
605 getHeadBlock().mLastPos = getHeadBlock().mPos;
606 getTailBlock().mLastPos = getTailBlock().mPos;
609 block.mLastPos = block.mPos;
613 int idx = block->mMoveSequenceIdx;
616 block->mMoveSequenceIdx = idx;
619 getTailBlock().mMoveSequenceIdx = idx;
622 mVec2_c collapseSpeed = sc_collapseSpeeds[dir];
623 getHeadBlock().mSpeed.set(collapseSpeed.x, collapseSpeed.y, 0.0f);
624 getTailBlock().mSpeed.set(collapseSpeed.x, collapseSpeed.y, 0.0f);
627 block.mSpeed.set(collapseSpeed.x, collapseSpeed.y, 0.0f);
631void daEnSnakeBlock_c::finalizeState_Collapse1() {}
633void daEnSnakeBlock_c::executeState_Collapse1() {
645void daEnSnakeBlock_c::initializeState_Collapse2() {
647 getHeadBlock().mSpeed.set(0.0f, 0.0f, 0.0f);
648 getTailBlock().mSpeed.set(0.0f, 0.0f, 0.0f);
651 block.mSpeed.set(0.0f, 0.0f, 0.0f);
655void daEnSnakeBlock_c::finalizeState_Collapse2() {}
657void daEnSnakeBlock_c::executeState_Collapse2() {
658 getHeadBlock().releaseBgCtr();
659 getHeadBlock().calcFallSpeed();
660 getHeadBlock().posMove();
663 getTailBlock().releaseBgCtr();
664 getTailBlock().calcFallSpeed();
665 getTailBlock().posMove();
673 for (
int i = 0; i < collapsingBlockCount + 1; i++) {
675 block.mBgCtr.release();
676 block.releaseBgCtr();
677 block.calcFallSpeed();
687void daEnSnakeBlock_c::initializeState_Collapse3() {
688 getHeadBlock().mSpeed.set(0.0f, 0.0f, 0.0f);
689 getTailBlock().mSpeed.set(0.0f, 0.0f, 0.0f);
693 block.mSpeed.set(0.0f, 0.0f, 0.0f);
697void daEnSnakeBlock_c::finalizeState_Collapse3() {}
699void daEnSnakeBlock_c::executeState_Collapse3() {
700 getHeadBlock().releaseBgCtr();
701 getHeadBlock().calcFallSpeed();
702 getHeadBlock().mPos += getHeadBlock().mSpeed;
704 getTailBlock().releaseBgCtr();
705 getTailBlock().calcFallSpeed();
706 getTailBlock().mPos += getTailBlock().mSpeed;
710 block.releaseBgCtr();
711 block.calcFallSpeed();
712 block.mPos += block.mSpeed;
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.
void deleteActor(u8 deleteForever)
Deletes the actor and optionally disables respawn.
static void setSoftLight_MapObj(m3d::bmdl_c &mdl)
Sets the soft light effect for map objects.
virtual s8 & getPlrNo()
Gets the player number associated with the actor. See mPlayerNo.
u8 mKind
The actor's kind. Value is a STAGE_ACTOR_KIND_e.
static void changePosAngle(mVec3_c *pos, mAng3_c *ang, int param3)
Adjusts the actor's position to account for looping stages.
dActor_c()
Constructs a new actor.
@ STAGE_ACTOR_YOSHI
The Yoshi actor.
@ STAGE_ACTOR_PLAYER
The player actor.
mVec3_c mPos
The actor's position.
void calcFallSpeed()
Updates the actor's falling speed. See here for details.
Course data file holder. A course data file contains the actual course elements - areas,...
virtual void changeState(const sStateIDIf_c &newState)
Changes the actor's state to the given state.
static sRailInfoData * getRailInfoP(u8 id)
Gets the rail data for the specified ID.
static dResMng_c * m_instance
The instance of this class.
A single block segment within the Snake Block actor.
void deleteBlock()
Releases the model and associated animation resources.
mVec3_c mLastPos
The block's position in the previous movement.
void releaseBgCtr()
Releases the block's collision.
static dBg_ctr_c::CallbackH callBackH
The ceiling collision callback.
void draw(const mVec3_c &offset)
Renders the block model.
void calcCollapse1(s8 *moveSequence)
Updates the block's position when in the Collapse1 state.
mVec3_c mSpeed
The block' speed.
daEnSnakeBlock_c * mpOwner
The parent Snake Block actor.
int mMoveSequenceIdx
The block's current step in the movement sequence.
m3d::anmMatClr_c mAnmClr
The color animation.
void calcAnm()
Advances the animations for the block.
dBg_ctr_c mBgCtr
The collision.
mVec3_c mPos
The block's position (center of block).
nw4r::g3d::ResAnmTexSrt mResTexSrt
The texture animation resource.
nw4r::g3d::ResFile mResFile
The resource file.
void calcCollision()
Updates the block's collision based on its offset from the parent.
static dBg_ctr_c::CallbackW callBackW
The side collision callback.
void initCollision(daEnSnakeBlock_c *parent, mVec3_c &blockPos, bool icy)
Initializes the block's collision.
m3d::anmTexSrt_c mAnmTexSrt
The texture animation.
void calcFallSpeed()
Updates the block's falling speed.
void setAnmClr(const char *name)
Sets the color animation for the block.
void createMdl(mAllocator_c *allocator)
Initializes the 3D model, textures, and color animations.
m3d::mdl_c mModel
The block model.
static dBg_ctr_c::CallbackF callBackF
The floor collision callback.
SnakeSpeed_e
The possible speed modes of a Snake Block.
bool moveBlock(s8 *moveSequence)
Moves the block in the direction specified by the current sequence step.
SnakeSpeed_e mSnakeSpeed
The speed mode for this block.
bool nextTravelMove(s8 *moveSequence)
Snaps the block to the grid and advances the sequence index to the next step.
A Snake Block which travels along a rail.
int mBlockCount
The number of blocks between the head and tail.
sStateID_c * mpStopState
The state to transition to when the Snake Block stops.
int mSnakeType
The snake type.
bool chkOffScreen()
Checks whether the Snake Block is far past the right edge of the screen.
static const mVec2_c sc_TravelDirs[MOVE_DIR_COUNT]
The unit vector for each movement direction.
void initMoveSequence()
Rasterizes the rail path into the sequence of movements.
static const float sc_FallMaxSpeed
The terminal velocity applied during a collapse.
dHeapAllocator_c mAllocator
The allocator.
static const int scSnakeSoundID
The sound effect ID played while the snake moves.
static const float sc_FallAccel
The gravity acceleration applied during a collapse.
int mGradientActiveBlocks
The number of blocks currently displaying the gradient animation.
void createMdl()
Creates the model and animations for each block.
void calcAnm()
Advances the animations for all blocks in the Snake Block.
void deleteBlocks()
Releases the resources for each block.
int mMoveSequenceIdx
The current index into mpMoveSequence.
dBlock_c mBlocks[20]
The blocks between the head and tail. Only the first mBlockCount of these are used.
bool chkCollapseDelete()
Checks whether the tail block is below the screen edge.
virtual int execute()
do method for the execute operation.
int mCollapseTimer
The timer used by the Collapse2 state to delay the fall of each block.
virtual int create()
do method for the create operation.
static sFStateID_c< daEnSnakeBlock_c > StateID_Collapse1
Collapse mode 1: Blocks travel all the way to the final rail node and then fall.
s8 * mpMoveSequence
The precalculated sequence of movements each block has to perform to reach the end of the rail.
void calcActorPos()
Updates the Snake Block's position to match the head block's.
void calcBlockPos()
Updates each body block's position.
void calcCollision()
Updates each block's collision.
s16 mShakeTimer
Counts down frames for the shake animation at the end of the rail.
virtual int doDelete()
do method for the delete operation.
static const float sc_SnakeSpeeds2[dCtrlBlock_c::SNAKE_SPEED_COUNT]
Alternate array of speed values.
static sFStateID_c< daEnSnakeBlock_c > StateID_Stop
Stopped at the end of the rail.
void initBlockCollision()
Initializes the collision for the head, body, and tail segments.
virtual void deleteReady()
Informs the base that it's about to be deleted.
void setStopState()
Sets the state to transition to after the Snake Block reaches the end of the rail.
daEnSnakeBlock_c()
Creates a Snake Block.
static sFStateID_c< daEnSnakeBlock_c > StateID_Move
Moving along the rail.
void initBlocks()
Initializes various components.
static sFStateID_c< daEnSnakeBlock_c > StateID_Collapse3
Collapse mode 3: Blocks fall all at once.
static sFStateID_c< daEnSnakeBlock_c > StateID_Shake
Shaking before collapsing.
static const float sc_SnakeSpeeds[dCtrlBlock_c::SNAKE_SPEED_COUNT]
The speed values corresponding to SnakeSpeed_e.
static sFStateID_c< daEnSnakeBlock_c > StateID_Wait
Waiting for a player to land on the Snake Block to start moving.
int mGradientMaxBlocks
The maximum number of blocks the gradient animation can cover.
static sFStateID_c< daEnSnakeBlock_c > StateID_Collapse2
Collapse mode 2: Blocks fall one after another, with a delay between each.
static int g_SnakeNum
Global counter for the active Snake Blocks.
virtual int draw()
do method for the draw operation.
void deleteRequest()
Requests deletion of the base.
@ NOT_READY
The step could not completed at this time.
@ SUCCEEDED
The step was completed successfully.
An allocator class that wraps an EGG:Allocator .
A two-dimensional floating point vector.
A three-dimensional floating point vector.
A generic implementation of a state ID.
#define ACTOR_PROFILE(profName, className, properties)
Creates an actor profile, using the profile number as the execute and draw order value.
@ FORWARD_ONCE
Play the animation forward once.
@ FORWARD_LOOP
Play the animation forward in a loop.
@ GAME_HEAP_DEFAULT
The default game heap (alias of MEM1 or MEM2).
@ OPT_NONE
No special allocation options.
EGG::ExpHeap * g_gameHeaps[GAME_HEAP_COUNT]
The game heaps.
#define STATE_DEFINE(class, name)
Defines a state.