1#include <game/bases/d_a_en_noko.hpp>
2#include <game/bases/d_actor_manager.hpp>
3#include <game/bases/d_a_tag_wind.hpp>
5#include <game/mLib/m_allocator_dummy_heap.hpp>
6#include <game/bases/d_a_player_base.hpp>
10const sBcSensorLine l_noko_foot = { SENSOR_IS_LINE, -0x4000, 0x4000, 0x0 };
11const sBcSensorLine l_noko_wall = { SENSOR_IS_LINE, 0x6000, 0x9000, 0x6000 };
17 BIT_FLAG(CC_KIND_PLAYER) | BIT_FLAG(CC_KIND_PLAYER_ATTACK) | BIT_FLAG(CC_KIND_YOSHI) |
18 BIT_FLAG(CC_KIND_ENEMY) | BIT_FLAG(CC_KIND_TAMA),
19 (u32) ~BIT_FLAG(CC_ATTACK_NONE) & ~BIT_FLAG(CC_ATTACK_YOSHI_MOUTH) & ~BIT_FLAG(CC_ATTACK_SPIN_LIFT_UP) & ~BIT_FLAG(CC_ATTACK_SAND_PILLAR),
21 dEn_c::normal_collcheck
24const float l_walk_speed[2] = { 0.5f, -0.5f };
25const s16 l_turn_speed[2] = { ANGLE_360_DIV(32), -ANGLE_360_DIV(32) };
26const s16 l_turn_target_angle[2] = { DEG_TO_ANGLE(90), -DEG_TO_ANGLE(90) };
45 mScale.set(1.0f, 1.0f, 1.0f);
55 mAngle.y = l_turn_target_angle[dir];
57 mFlags |= dEn_c::EN_FLAG_16;
65 mSensorHead = l_noko_head;
66 mSensorWall = l_noko_wall;
67 mSensorFootNormal = l_noko_foot;
69 mCcData.set(l_noko_cc);
73 mBaseZPos = dActorMng_c::m_instance->mGoombaZOrderThing * 16.0f;
74 dActorMng_c::m_instance->mGoombaZOrderThing = (dActorMng_c::m_instance->mGoombaZOrderThing + 1) & 0xF;
78 mBc.set(
this, mSensorFootNormal, mSensorHead, mSensorWall);
84void daEnNoko_c::createModel() {
89 nw4r::g3d::ResMdl mdl =
mNokoResFile.GetResMdl(
"nokonokoA");
90 mNokoModel.create(mdl, &
mNokoAllocator, nw4r::g3d::ScnMdl::BUFFER_RESMATMISC | nw4r::g3d::ScnMdl::BUFFER_RESTEXOBJ | nw4r::g3d::ScnMdl::BUFFER_RESTLUTOBJ, 1,
nullptr);
93 nw4r::g3d::ResAnmChr anm =
mNokoResFile.GetResAnmChr(
"walkA");
107 if (ACTOR_PARAM(SpawnMode) == SPAWN_MODE_SLEEP) {
110 }
else if (ACTOR_PARAM(BlockAppear)) {
112 }
else if (ACTOR_PARAM(SpitOut)) {
125 if (dAudio::isBgmAccentSign(BIT_FLAG(1))) {
126 danceWithMove(BGM_anim_walkA_1);
127 }
else if (dAudio::isBgmAccentSign(BIT_FLAG(2))) {
129 }
else if (dAudio::isBgmAccentSign(BIT_FLAG(3))) {
130 danceWithMove(BGM_anim_walkA_3);
162 if (mShellMode == SHELL_MODE_BASE) {
175 if (
mNokoAllocator.mpHeap != mAllocatorDummyHeap_c::getInstance()) {
188 u32 type = dBc_c::getUnitType(pos.x, pos.y,
mLayer);
189 u8 kind = dBc_c::getUnitKind(pos.x, pos.y,
mLayer) >> 16;
191 if (type & BIT_FLAG(15) && kind == 3) {
201 mVec3_c efPos(center.x, center.y, 5500.0f);
202 mQuicksandEffect.createEffect(
"Wm_en_quicksand", 0, &efPos,
nullptr,
nullptr);
205bool daEnNoko_c::canDance() {
219void daEnNoko_c::danceWithMove(
int move) {
224void daEnNoko_c::calcMdl() {
226 mVec3_c pos = getPos();
239void daEnNoko_c::calcShellEffectPos() {
240 m3d::mdl_c &model = mModel;
241 nw4r::g3d::ResMdl resMdl = model.getResMdl();
242 nw4r::g3d::ResNode resNode = resMdl.GetResNode(
"nokonoko_shell_model");
245 model.getNodeWorldMtx(resNode.GetID(), &matrix);
248 mSlideEffectPos.y -= 16.0f;
252bool daEnNoko_c::setPlayerDamage(
dActor_c *actor) {
253 daPlBase_c *player = (daPlBase_c *) actor;
255 if (player->setDamage(
this, daPlBase_c::DAMAGE_DEFAULT) && isWalking()) {
265 u8 mode = mShellMode;
267 if (
mDirection == dir || mode == SHELL_MODE_BASE) {
272 mAngle.y = l_turn_target_angle[dir];
280 mSensorHead = l_noko_head;
281 mSensorWall = l_noko_wall;
282 mSensorFootNormal = l_noko_foot;
283 mBc.set(
this, mSensorFootNormal, mSensorHead, mSensorWall);
286void daEnNoko_c::turnAround() {
294bool daEnNoko_c::turnProc() {
297 doTurn(&turnDir, &turnSpeed);
300 mAng target = l_turn_target_angle[turnDir];
301 if (
mAngle.y.abs() >= target.abs()) {
309void daEnNoko_c::doTurn(
int *dir, s16 *turnSpeed) {
311 *turnSpeed = l_turn_speed[*dir];
314void daEnNoko_c::setZPos() {
322void daEnNoko_c::updateAmiLine() {
323 float width =
mCc.mCcData.mBase.mSize.x;
324 float offX =
mCc.mCcData.mBase.mOffset.x;
325 float offY =
mCc.mCcData.mBase.mOffset.y;
327 float x =
mPos.x + offX;
328 float y =
mPos.y + offY;
330 u32 typeRight = dBc_c::getUnitType(x + width, y,
mLayer);
331 u8 kindRight = dBc_c::getUnitKind(x + width, y,
mLayer) & 0xFF;
332 u32 typeLeft = dBc_c::getUnitType(x - width, y,
mLayer);
333 u8 kindLeft = dBc_c::getUnitKind(x - width, y,
mLayer) & 0xFF;
336 typeRight & BIT_FLAG(10) && kindRight >= 2 ||
337 typeLeft & BIT_FLAG(10) && kindLeft >= 2
349void daEnNoko_c::walkTurn() {
350 static const s16 sc_walkAngle[2] = { -DEG_TO_ANGLE(30), DEG_TO_ANGLE(30) };
354bool daEnNoko_c::createIceActor() {
355 static const int sc_iceMode[2] = { 0, 1 };
356 static const float cs_iceOffsetY[2] = { -2.0f, -4.0f };
364 iceSize.set(1.05f, 1.0f, 1.75f);
366 iceMode = sc_iceMode[mShellMode];
367 icePos.set(
mPos.x,
mPos.y + cs_iceOffsetY[mShellMode],
mPos.z);
368 iceSize.set(1.05f, 1.0f, 1.05f);
371 dIceInfo iceInfo[] = {
379 return mIceMng.createIce(iceInfo, ARRAY_SIZE(iceInfo));
382bool daEnNoko_c::checkSleep() {
383 if (ACTOR_PARAM(SpawnMode) == SPAWN_MODE_SLEEP) {
387 return daEnShell_c::checkSleep();
390void daEnNoko_c::beginFunsui() {
397 mSpeed.set(0.0f, 0.0f, 0.0f);
399 if (mShellMode == SHELL_MODE_BASE) {
406void daEnNoko_c::endFunsui() {
409 if (mShellMode != SHELL_MODE_BASE) {
415float daEnNoko_c::getWindStrength() {
418 if (tagWind ==
nullptr) {
422 return tagWind->mStrength;
425void daEnNoko_c::setMoveAnimation(
const char *name,
m3d::playMode_e mode,
float frame) {
430void daEnNoko_c::setBaseAnimation(
const char *name,
m3d::playMode_e mode,
float frame) {
431 mAnim.setAnm(mModel, mResFile.GetResAnmChr(name), mode);
432 mModel.setAnm(mAnim, frame);
436 static const float sc_offsetX[2] = { 2.5f, -2.5f };
439 u8 kind = dBc_c::getUnitKind(pos.x,
mPos.y - 2.0f,
mLayer) >> 16;
446 if (dBc_c::checkGround(&pos, &height,
mLayer, 1, -1) && height < pos.y && height >
mPos.y - 5.0f) {
453void daEnNoko_c::landEffect() {
456 if (
mBc.getFootAttr() == 12) {
457 mEf::createEffect(
"Wm_en_sndlandsmk_s", 0, &pos,
nullptr,
nullptr);
459 mEf::createEffect(
"Wm_en_landsmoke_s", 0, &pos,
nullptr,
nullptr);
463void daEnNoko_c::initializeState_Walk() {
473 mShellMode = SHELL_MODE_NOKO_WALK;
477 mSensorFootNormal = l_noko_foot;
482void daEnNoko_c::finalizeState_Walk() {}
484void daEnNoko_c::executeState_Walk() {
487 float wind = getWindStrength();
488 if (std::fabs(wind) > 0.475f) {
503 u32 prevFoot =
mBc.isFoot();
512 mFootPush2.x +=
m_1eb.x;
520void daEnNoko_c::initializeState_Wakeup() {
523 mShellMode = SHELL_MODE_NOKO_WALK;
525 daEnShell_c::initializeState_Wakeup();
528void daEnNoko_c::finalizeState_Wakeup() {
529 mAnim.setFrame(0.0f);
530 mCc.mCcData.mBase.mOffset.x = 0.0f;
531 mCc.mCcData.mBase.mSize.x = 8.0f;
534void daEnNoko_c::executeState_Wakeup() {
540 u32 bgCheck = EnBgCheck();
553void daEnNoko_c::initializeState_WakeupTurn() {
555 daEnShell_c::initializeState_WakeupTurn();
558void daEnNoko_c::finalizeState_WakeupTurn() {
559 daEnShell_c::finalizeState_WakeupTurn();
562void daEnNoko_c::executeState_WakeupTurn() {
564 daEnShell_c::executeState_WakeupTurn();
567void daEnNoko_c::initializeState_Turn() {
573void daEnNoko_c::finalizeState_Turn() {}
575void daEnNoko_c::executeState_Turn() {
580 if (EnBgCheck() & 1) {
590void daEnNoko_c::initializeState_WindTurn() {
596void daEnNoko_c::finalizeState_WindTurn() {}
598void daEnNoko_c::executeState_WindTurn() {
603 if (EnBgCheck() & 1) {
609 if (std::fabs(getWindStrength()) < 0.25f) {
614void daEnNoko_c::initializeState_BlockAppear() {
620void daEnNoko_c::finalizeState_BlockAppear() {
624void daEnNoko_c::executeState_BlockAppear() {
630void daEnNoko_c::initializeState_SpitOut_Ready() {
634void daEnNoko_c::finalizeState_SpitOut_Ready() { }
636void daEnNoko_c::executeState_SpitOut_Ready() {
642 if (eatActor ==
nullptr) {
645 setSlideThrowSpeed(eatActor);
651void daEnNoko_c::initializeState_BgmDance() {
652 static const char *sc_bgmDanceAnim[DANCE_MOVE_COUNT] = {
664void daEnNoko_c::finalizeState_BgmDance() {}
666void daEnNoko_c::executeState_BgmDance() {
671 if (EnBgCheck() & 1) {
687void daEnNoko_c::initializeState_BgmDanceEd() {
694void daEnNoko_c::finalizeState_BgmDanceEd() {}
696void daEnNoko_c::executeState_BgmDanceEd() {
701 if (EnBgCheck() & 1) {
716void daEnNoko_c::nodeCallback_c::timingB(ulong nodeId, nw4r::g3d::WorldMtxManip *manip, nw4r::g3d::ResMdl resMdl) {
718 if (strcmp(resMdl.GetResNode(nodeId).GetName(),
"head") == 0) {
719 manip->GetMatrix(&mtx);
720 mtx.
XrotM(mpOwner->mHeadAngle);
721 manip->SetMatrix(mtx);
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.
fBaseID_e mEatenByID
The unique identifier of the eating actor.
virtual s8 & getPlrNo()
Gets the player number associated with the actor. See mPlayerNo.
bool mNoRespawn
Whether the actor should not respawn after being deleted.
dBc_c mBc
The actor-to-tile collision sensor.
static bool getTrgToSrcDir_Main(float trgX, float srcX)
See getTrgToSrcDirFunc.
static void setSoftLight_Enemy(m3d::bmdl_c &mdl)
Sets the soft light effect for enemies.
void clrComboCnt()
Clears the actor's combo counter.
static void changePosAngle(mVec3_c *pos, mAng3_c *ang, int param3)
Adjusts the actor's position to account for looping stages.
u8 mAmiLayer
The actor's layer for chainlink fences.
u8 mDirection
The actor's facing direction.
dCc_c mCc
The actor-to-actor collision sensor.
mVec2_c mVisibleAreaSize
The size of the area inside which the actor is visible.
s8 mPlayerNo
The player associated with the actor, -1 if not associated to any player.
dActor_c()
Constructs a new actor.
u8 mLayer
The actor's layer.
mVec2_c mVisibleAreaOffset
The offset applied to the area size.
mMtx_c mMatrix
The actor's partial transformation matrix. See makeMtx() for details.
mVec3_c mScale
The actor's scale (defaults to 1).
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 posMove()
Moves the actor by its speed.
mVec3_c getCenterPos() const
Gets the actor's centered position.
mAng3_c mAngle
The actor's rotation (for 2D actors).
float mAccelY
The actor's vertical acceleration.
void calcSpeedY()
Updates the actor's Y speed. See here for details.
bool getPl_LRflag(const mVec3_c &pos)
Checks whether the nearest player is to the left of pos.
void WaterCheck(mVec3_c &pos, float h)
dIceMng_c mIceMng
The ice manager for this enemy.
u16 mTimer1
[Used in EN_HATENA_BALLON, for example]
virtual void changeState(const sStateIDIf_c &newState)
Changes the actor's state to the given state.
virtual int preExecute()
pre method for the execute operation.
dPlayerDownTimer_c mNoHitPlayer
Hit cooldown timers for each player. This is used to prevent, for example, a thrown shell from hittin...
u32 mFlags
Flags for this actor. See FLAGS_e.
bool mInLiquid
Whether the enemy is in a liquid.
static dResMng_c * m_instance
The instance of this class.
static sFStateVirtualID_c< daEnCarry_c > StateID_Carry
The enemy is being carried.
static sFStateID_c< daEnNoko_c > StateID_Walk
Walking on the ground.
int mDanceTimer
Timer for starting and ending the dance.
@ BGM_anim_walkA_2
Actually uses the same animation as BGM_anim_walkA_1.
nw4r::g3d::ResAnmTexPat mNokoResAnmTex
The animated texture resource of the Koopa.
bool checkRyusa()
Checks if the actor is inside quicksand.
static sFStateID_c< daEnNoko_c > StateID_WindTurn
Being turned around by the wind.
mVec3_c mCreatePos
The position where the Koopa was spawned.
float mXSpeedBeforeFunsui
The horizontal speed of the Koopa before being blown by a fountain.
m3d::anmChr_c mWalkAnim
The walk animation of the Koopa.
@ NOKO_RED
Red Koopas turn around on ledges.
static sFStateID_c< daEnNoko_c > StateID_SpitOut_Ready
About to be spit out by Yoshi.
u8 mNokoType
Is a NOKO_TYPE_e.
void ryusaEffect()
Creates the quicksand effect.
static sFStateID_c< daEnNoko_c > StateID_BgmDanceEd
Returning from a dance move to walking.
int execute() override
do method for the execute operation.
m3d::mdl_c mNokoModel
The model of the Koopa.
int preExecute() override
pre method for the execute operation.
static sFStateID_c< daEnNoko_c > StateID_BlockAppear
Spawning from a block.
m3d::anmTexPat_c mNokoAnimTex
The animated texture of the Koopa.
int draw() override
do method for the draw operation.
static sFStateID_c< daEnNoko_c > StateID_BgmDance
Doing a dance move to the background music.
virtual void deleteResExtra()
Subclasses can override this function to delete additional resources.
BOOL mIsFunsui
Whether the Koopa is being blown upwards by a fountain.
u32 mDanceMove
The dance move to perform.
virtual void createModelExtra()
Subclasses can override this function to create additional models.
bool playerDamageTurn(dActor_c *)
Returns whether the Koopa should turn around after damaging the player.
bool checkLedge()
Checks if there is a ledge in front of the Koopa.
dHeapAllocator_c mNokoAllocator
The allocator used for the resources of this actor.
static sFStateID_c< daEnNoko_c > StateID_Turn
Turning around while walking.
void setNokoBc()
Reverts the collision to a regular Koopa.
virtual void setInitialState()
Initializes the state of the Koopa after creation.
int doDelete() override
do method for the delete operation.
nw4r::g3d::ResFile mNokoResFile
The resource file containing the resources of this actor.
int create() override
do method for the create operation.
mAng mBgmDanceRotSpeed
The rotation speed for turning toward the target rotation for a dance.
bool mIsFlipped
Whether the shell is flipped upside down from a block hit.
static sFStateVirtualID_c< daEnShell_c > StateID_Wakeup
Waking up from the sleep state.
static sFStateVirtualID_c< daEnShell_c > StateID_Slide
Sliding across the ground after being kicked.
static sFStateVirtualID_c< daEnShell_c > StateID_Sleep
Remaining stationary after being jumped on.
void createShell(const char *arcName, const char *resPath, const char *modelName, const char *anmTexName, float animFrame)
Loads the resources for the shell model and animation.
static sFStateVirtualID_c< daEnShell_c > StateID_WakeupTurn
Turning around after waking up.
void deleteRequest()
Requests deletion of the base.
@ NOT_READY
The step could not completed at this time.
@ SUCCEEDED
The step was completed successfully.
static fBase_c * searchBaseByID(fBaseID_e id)
Searches for a base with the given ID.
static fBase_c * searchBaseByProfName(ProfileName profID, const fBase_c *parent)
Searches for a base with a given profile name, optionally under a given parent.
void multVecZero(nw4r::math::VEC3 &out) const
Extracts the translation vector from the matrix.
void XrotM(mAng angle)
Rotates the matrix on the X axis by the given angle.
A three-dimensional floating point vector.
const u8 l_Ami_Line[]
The sub-layer for each side of chainlink fences.
const float l_Ami_Zpos[]
The additional Z offset for each side of chainlink fences.
@ BASE_ID_NULL
Represents the null base.
#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).
EGG::ExpHeap * g_gameHeaps[GAME_HEAP_COUNT]
The game heaps.
BOOL chaseAngle(s16 *value, s16 target, s16 step)
Moves value towards target by a fixed step amount.
#define STATE_DEFINE(class, name)
Defines a state.
#define STATE_VIRTUAL_DEFINE(class, name)
Defines a virtual state.
A structure that contains information about a collider.