diff --git a/assets/xml/objects/object_wf.xml b/assets/xml/objects/object_wf.xml index cd9a297c9e2..9d2d9d97f3b 100644 --- a/assets/xml/objects/object_wf.xml +++ b/assets/xml/objects/object_wf.xml @@ -1,79 +1,76 @@ - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - + - + @@ -83,161 +80,152 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/overlays/actors/ovl_En_Wf/z_en_wf.c b/src/overlays/actors/ovl_En_Wf/z_en_wf.c index fbae4f022b1..0d156f101f5 100644 --- a/src/overlays/actors/ovl_En_Wf/z_en_wf.c +++ b/src/overlays/actors/ovl_En_Wf/z_en_wf.c @@ -1,11 +1,11 @@ /* * File: z_en_wf.c * Overlay: ovl_En_Wf - * Description: Wolfos (Normal and White) + * Description: Wolfos */ #include "z_en_wf.h" -#include "overlays/actors/ovl_En_Encount1/z_en_encount1.h" +#include "src/overlays/actors/ovl_En_Encount1/z_en_encount1.h" #include "libc64/qrand.h" #include "array_count.h" @@ -19,7 +19,6 @@ #include "sfx.h" #include "sys_matrix.h" #include "terminal.h" -#include "translation.h" #include "z_en_item00.h" #include "z_lib.h" #include "audio.h" @@ -36,34 +35,51 @@ void EnWf_Destroy(Actor* thisx, PlayState* play); void EnWf_Update(Actor* thisx, PlayState* play); void EnWf_Draw(Actor* thisx, PlayState* play); -void EnWf_SetupWaitToAppear(EnWf* this); -void EnWf_WaitToAppear(EnWf* this, PlayState* play); -void EnWf_SetupWait(EnWf* this); -void EnWf_Wait(EnWf* this, PlayState* play); -void EnWf_SetupRunAtPlayer(EnWf* this, PlayState* play); -void EnWf_RunAtPlayer(EnWf* this, PlayState* play); -void EnWf_SetupSearchForPlayer(EnWf* this); -void EnWf_SearchForPlayer(EnWf* this, PlayState* play); -void EnWf_SetupRunAroundPlayer(EnWf* this); -void EnWf_RunAroundPlayer(EnWf* this, PlayState* play); -void EnWf_SetupSlash(EnWf* this); -void EnWf_Slash(EnWf* this, PlayState* play); -void EnWf_RecoilFromBlockedSlash(EnWf* this, PlayState* play); -void EnWf_SetupBackflipAway(EnWf* this); -void EnWf_BackflipAway(EnWf* this, PlayState* play); +void EnWf_SetupWaitAppear(EnWf* this); +void EnWf_WaitAppear(EnWf* this, PlayState* play); +void EnWf_SetupIdle(EnWf* this); +void EnWf_Idle(EnWf* this, PlayState* play); +void EnWf_SetupRunToAttack(EnWf* this, PlayState* play); +void EnWf_RunToAttack(EnWf* this, PlayState* play); +void EnWf_SetupTurnTowardsPlayer(EnWf* this); +void EnWf_TurnTowardsPlayer(EnWf* this, PlayState* play); +void EnWf_SetupCirclePlayer(EnWf* this); +void EnWf_CirclePlayer(EnWf* this, PlayState* play); +void EnWf_SetupAttack(EnWf* this); +void EnWf_Attack(EnWf* this, PlayState* play); +void EnWf_AttackBouncedOff(EnWf* this, PlayState* play); +void EnWf_SetupBackflipBackward(EnWf* this); +void EnWf_BackflipBackward(EnWf* this, PlayState* play); void EnWf_Stunned(EnWf* this, PlayState* play); void EnWf_Damaged(EnWf* this, PlayState* play); -void EnWf_SetupSomersaultAndAttack(EnWf* this); -void EnWf_SomersaultAndAttack(EnWf* this, PlayState* play); -void EnWf_SetupBlocking(EnWf* this); -void EnWf_Blocking(EnWf* this, PlayState* play); -void EnWf_SetupSidestep(EnWf* this, PlayState* play); -void EnWf_Sidestep(EnWf* this, PlayState* play); +void EnWf_SetupBackflipForward(EnWf* this); +void EnWf_BackflipForward(EnWf* this, PlayState* play); +void EnWf_SetupBlock(EnWf* this); +void EnWf_Block(EnWf* this, PlayState* play); +void EnWf_SetupShortCirclePlayer(EnWf* this, PlayState* play); +void EnWf_ShortCirclePlayer(EnWf* this, PlayState* play); void EnWf_SetupDie(EnWf* this); void EnWf_Die(EnWf* this, PlayState* play); -s32 EnWf_DodgeRanged(PlayState* play, EnWf* this); - -static ColliderJntSphElementInit sJntSphElementsInit[] = { +s32 EnWf_ReactToProjectile(PlayState* play, EnWf* this); + +typedef enum EnWfAction { + ENWF_ACTION_WAIT_APPEAR, + ENWF_ACTION_DIE = 2, + ENWF_ACTION_DAMAGED, + ENWF_ACTION_BACKFLIP_FORWARD, + ENWF_ACTION_BACKFLIP_BACKWARD, + ENWF_ACTION_IDLE, + ENWF_ACTION_BLOCK, + ENWF_ACTION_ATTACK, + ENWF_ACTION_RUN_TO_ATTACK, + ENWF_ACTION_TURN_TOWARDS_PLAYER, + ENWF_ACTION_CIRCLE_PLAYER, + ENWF_ACTION_ATTACK_BOUNCED_OFF, + ENWF_ACTION_SHORT_CIRCLE_PLAYER = 14, + ENWF_ACTION_STUNNED +} EnWfAction; + +static ColliderJntSphElementInit sAttackAndBlockJntSphElementsInit[] = { { { ELEM_MATERIAL_UNK0, @@ -73,7 +89,7 @@ static ColliderJntSphElementInit sJntSphElementsInit[] = { ACELEM_NONE, OCELEM_NONE, }, - { WOLFOS_LIMB_FRONT_RIGHT_CLAW, { { 0, 0, 0 }, 15 }, 100 }, + { WOLFOS_LIMB_RIGHT_CLAWS, { { 0, 0, 0 }, 15 }, 100 }, }, { { @@ -84,7 +100,7 @@ static ColliderJntSphElementInit sJntSphElementsInit[] = { ACELEM_NONE, OCELEM_NONE, }, - { WOLFOS_LIMB_FRONT_LEFT_CLAW, { { 0, 0, 0 }, 15 }, 100 }, + { WOLFOS_LIMB_LEFT_CLAWS, { { 0, 0, 0 }, 15 }, 100 }, }, { { @@ -106,11 +122,11 @@ static ColliderJntSphElementInit sJntSphElementsInit[] = { ACELEM_ON | ACELEM_HOOKABLE, OCELEM_ON, }, - { WOLFOS_LIMB_THORAX, { { 0, 0, 0 }, 30 }, 100 }, + { WOLFOS_LIMB_TORSO, { { 0, 0, 0 }, 30 }, 100 }, }, }; -static ColliderJntSphInit sJntSphInit = { +static ColliderJntSphInit sAttackAndBlockJntSphInit = { { COL_MATERIAL_METAL, AT_ON | AT_TYPE_ENEMY, @@ -119,8 +135,8 @@ static ColliderJntSphInit sJntSphInit = { OC2_TYPE_1, COLSHAPE_JNTSPH, }, - ARRAY_COUNT(sJntSphElementsInit), - sJntSphElementsInit, + ARRAY_COUNT(sAttackAndBlockJntSphElementsInit), + sAttackAndBlockJntSphElementsInit, }; static ColliderCylinderInit sBodyCylinderInit = { @@ -164,12 +180,12 @@ static ColliderCylinderInit sTailCylinderInit = { }; typedef enum EnWfDamageReaction { - /* 0 */ ENWF_DMG_REACT_NONE, - /* 1 */ ENWF_DMG_REACT_STUN, - /* 6 */ ENWF_DMG_REACT_ICE_MAGIC = 6, - /* 13 */ ENWF_DMG_REACT_LIGHT_MAGIC = 13, - /* 14 */ ENWF_DMG_REACT_FIRE, - /* 15 */ ENWF_DMG_REACT_UNDEF // used like STUN in the code, but not in the table + ENWF_DMG_REACT_NONE, + ENWF_DMG_REACT_STUN, + ENWF_DMG_REACT_6 = 6, + ENWF_DMG_REACT_D = 0xD, + ENWF_DMG_REACT_FIRE, + ENWF_DMG_REACT_F } EnWfDamageReaction; static DamageTable sDamageTable = { @@ -191,8 +207,8 @@ static DamageTable sDamageTable = { /* Unk arrow 2 */ DMG_ENTRY(2, ENWF_DMG_REACT_NONE), /* Unk arrow 3 */ DMG_ENTRY(2, ENWF_DMG_REACT_NONE), /* Fire magic */ DMG_ENTRY(4, ENWF_DMG_REACT_FIRE), - /* Ice magic */ DMG_ENTRY(0, ENWF_DMG_REACT_ICE_MAGIC), - /* Light magic */ DMG_ENTRY(3, ENWF_DMG_REACT_LIGHT_MAGIC), + /* Ice magic */ DMG_ENTRY(0, ENWF_DMG_REACT_6), + /* Light magic */ DMG_ENTRY(3, ENWF_DMG_REACT_D), /* Shield */ DMG_ENTRY(0, ENWF_DMG_REACT_NONE), /* Mirror Ray */ DMG_ENTRY(0, ENWF_DMG_REACT_NONE), /* Kokiri spin */ DMG_ENTRY(1, ENWF_DMG_REACT_NONE), @@ -219,282 +235,283 @@ ActorProfile En_Wf_Profile = { /**/ EnWf_Draw, }; -static InitChainEntry sInitChain[] = { +static InitChainEntry sInitChain[2] = { ICHAIN_F32(lockOnArrowOffset, 2000, ICHAIN_CONTINUE), ICHAIN_F32_DIV1000(gravity, -3000, ICHAIN_STOP), }; - -void EnWf_SetupAction(EnWf* this, EnWfActionFunc actionFunc) { +static Vec3f D_80B37AD0 = { 0.0f, 0.5f, 0.0f }; +static Vec3f D_80B37ADC = { 1200.0f, 0.0f, 0.0f }; +static Vec3f sZeroVec = { 0.0f, 0.0f, 0.0f }; +static void* sWolfosGrayEyeTextures[4] = { gWolfosGrayEyeOpenTex, gWolfosGrayEyeHalfTex, gWolfosGrayEyeClosedTex, + gWolfosGrayEyeHalfTex }; +static void* sWolfosWhiteEyeTextures[4] = { gWolfosWhiteEyeOpenTex, gWolfosWhiteEyeHalfTex, gWolfosWhiteEyeClosedTex, + gWolfosWhiteEyeHalfTex }; + +void EnWf_SetupAction(EnWf* this, void (*actionFunc)(EnWf*, PlayState*)) { this->actionFunc = actionFunc; } void EnWf_Init(Actor* thisx, PlayState* play) { - s32 pad; EnWf* this = (EnWf*)thisx; + s32 pad; - Actor_ProcessInitChain(thisx, sInitChain); - thisx->colChkInfo.damageTable = &sDamageTable; - ActorShape_Init(&thisx->shape, 0.0f, ActorShadow_DrawCircle, 0.0f); - thisx->focus.pos = thisx->world.pos; - thisx->colChkInfo.mass = MASS_HEAVY; - thisx->colChkInfo.health = 8; - thisx->colChkInfo.cylRadius = 50; - thisx->colChkInfo.cylHeight = 100; + Actor_ProcessInitChain(&this->actor, sInitChain); + this->actor.colChkInfo.damageTable = &sDamageTable; + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 0.0f); + this->actor.focus.pos = this->actor.world.pos; + this->actor.colChkInfo.mass = MASS_HEAVY; + this->actor.colChkInfo.health = 8; + this->actor.colChkInfo.cylRadius = 50; + this->actor.colChkInfo.cylHeight = 100; this->switchFlag = PARAMS_GET_U(thisx->params, 8, 8); - thisx->params &= 0xFF; + this->actor.params = PARAMS_GET_U(this->actor.params, 0, 8); this->eyeIndex = 0; - this->unk_2F4 = 10.0f; // Set and not used - - Collider_InitJntSph(play, &this->colliderJntSph); - Collider_SetJntSph(play, &this->colliderJntSph, thisx, &sJntSphInit, this->colliderJntSphElements); - Collider_InitCylinder(play, &this->bodyColliderCylinder); - Collider_SetCylinder(play, &this->bodyColliderCylinder, thisx, &sBodyCylinderInit); - Collider_InitCylinder(play, &this->tailColliderCylinder); - Collider_SetCylinder(play, &this->tailColliderCylinder, thisx, &sTailCylinderInit); - - if (thisx->params == WOLFOS_NORMAL) { - SkelAnime_InitFlex(play, &this->skelAnime, &gWolfosNormalSkel, &gWolfosWaitingAnim, this->jointTable, + this->unk_2F4 = 10.0f; + Collider_InitJntSph(play, &this->attackAndBlockCollider); + Collider_SetJntSph(play, &this->attackAndBlockCollider, &this->actor, &sAttackAndBlockJntSphInit, + this->attackAndBlockColliderElements); + Collider_InitCylinder(play, &this->bodyCollider); + Collider_SetCylinder(play, &this->bodyCollider, &this->actor, &sBodyCylinderInit); + Collider_InitCylinder(play, &this->tailCollider); + Collider_SetCylinder(play, &this->tailCollider, &this->actor, &sTailCylinderInit); + if (this->actor.params == 0) { + SkelAnime_InitFlex(play, &this->skelAnime, &gWolfosGraySkel, &gWolfosIdleAnim, this->jointTable, this->morphTable, WOLFOS_LIMB_MAX); - Actor_SetScale(thisx, 0.0075f); - thisx->naviEnemyId = NAVI_ENEMY_WOLFOS; - } else { // WOLFOS_WHITE - SkelAnime_InitFlex(play, &this->skelAnime, &gWolfosWhiteSkel, &gWolfosWaitingAnim, this->jointTable, + Actor_SetScale(&this->actor, 0.0075f); + this->actor.naviEnemyId = NAVI_ENEMY_WOLFOS; + } else { + SkelAnime_InitFlex(play, &this->skelAnime, &gWolfosWhiteSkel, &gWolfosIdleAnim, this->jointTable, this->morphTable, WOLFOS_LIMB_MAX); - Actor_SetScale(thisx, 0.01f); - this->colliderJntSph.elements[0].base.atDmgInfo.damage = - this->colliderJntSph.elements[1].base.atDmgInfo.damage = 8; - thisx->naviEnemyId = NAVI_ENEMY_WHITE_WOLFOS; + Actor_SetScale(&this->actor, 0.01f); + this->attackAndBlockCollider.elements[0].base.atDmgInfo.damage = + this->attackAndBlockCollider.elements[1].base.atDmgInfo.damage = 8; + this->actor.naviEnemyId = NAVI_ENEMY_WHITE_WOLFOS; } - - EnWf_SetupWaitToAppear(this); - + EnWf_SetupWaitAppear(this); if ((this->switchFlag != 0xFF) && Flags_GetSwitch(play, this->switchFlag)) { - Actor_Kill(thisx); + Actor_Kill(&this->actor); } } void EnWf_Destroy(Actor* thisx, PlayState* play) { EnWf* this = (EnWf*)thisx; + EnEncount1* parent; - Collider_DestroyJntSph(play, &this->colliderJntSph); - Collider_DestroyCylinder(play, &this->bodyColliderCylinder); - Collider_DestroyCylinder(play, &this->tailColliderCylinder); - - if ((this->actor.params != WOLFOS_NORMAL) && (this->switchFlag != 0xFF)) { + Collider_DestroyJntSph(play, &this->attackAndBlockCollider); + Collider_DestroyCylinder(play, &this->bodyCollider); + Collider_DestroyCylinder(play, &this->tailCollider); + if ((this->actor.params != 0) && (this->switchFlag != 0xFF)) { func_800F5B58(); } - if (this->actor.parent != NULL) { - EnEncount1* parent = (EnEncount1*)this->actor.parent; - + parent = (EnEncount1*)this->actor.parent; if (parent->actor.update != NULL) { + if (parent->curNumSpawn > 0) { parent->curNumSpawn--; } - PRINTF("\n\n"); - PRINTF(VT_FGCOL(GREEN) T("☆☆☆☆☆ 同時発生数 ☆☆☆☆☆%d\n", "☆☆☆☆☆ Number of simultaneous spawns ☆☆☆☆☆%d\n") - VT_RST, - parent->curNumSpawn); + PRINTF(VT_FGCOL(GREEN) "☆☆☆☆☆ 同時発生数 ☆☆☆☆☆%d\n" VT_RST, parent->curNumSpawn); PRINTF("\n\n"); } } } -s32 EnWf_ChangeAction(PlayState* play, EnWf* this, s16 mustChoose) { - Player* player = GET_PLAYER(play); +/** + * Pick an action based on the player's current doings and location. + * @return true if an action was picked + */ +s32 EnWf_PickAction(PlayState* play, EnWf* this, s16 mustPick) { + Player* player; s32 pad; - s16 wallYawDiff; - s16 playerYawDiff; + s16 absRelWallYaw; + s16 absRelYawTowardsPlayer; + + player = GET_PLAYER(play); - wallYawDiff = this->actor.wallYaw - this->actor.shape.rot.y; - wallYawDiff = ABS(wallYawDiff); - playerYawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - playerYawDiff = ABS(playerYawDiff); + absRelWallYaw = this->actor.wallYaw - this->actor.shape.rot.y; + if (absRelWallYaw < 0) { + absRelWallYaw *= -1; + } + absRelYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if (absRelYawTowardsPlayer < 0) { + absRelYawTowardsPlayer *= -1; + } if (func_800354B4(play, &this->actor, 100.0f, 0x2710, 0x2EE0, this->actor.shape.rot.y)) { if (player->meleeWeaponAnimation == PLAYER_MWA_JUMPSLASH_START) { - EnWf_SetupBlocking(this); + EnWf_SetupBlock(this); return true; } - - if ((play->gameplayFrames % 2) != 0) { - EnWf_SetupBlocking(this); + if (play->gameplayFrames & 1) { + EnWf_SetupBlock(this); return true; } } if (func_800354B4(play, &this->actor, 100.0f, 0x5DC0, 0x2AA8, this->actor.shape.rot.y)) { this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.yawTowardsPlayer; - - if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (ABS(wallYawDiff) < 0x2EE0) && + if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (ABS(absRelWallYaw) < 0x2EE0) && (this->actor.xzDistToPlayer < 120.0f)) { - EnWf_SetupSomersaultAndAttack(this); + EnWf_SetupBackflipForward(this); return true; } else if (player->meleeWeaponAnimation == PLAYER_MWA_JUMPSLASH_START) { - EnWf_SetupBlocking(this); + EnWf_SetupBlock(this); return true; - } else if ((this->actor.xzDistToPlayer < 80.0f) && (play->gameplayFrames % 2) != 0) { - EnWf_SetupBlocking(this); + } else if ((this->actor.xzDistToPlayer < 80.0f) && (play->gameplayFrames & 1)) { + EnWf_SetupBlock(this); return true; } else { - EnWf_SetupBackflipAway(this); + EnWf_SetupBackflipBackward(this); return true; } } else { - Actor* explosive = Actor_FindNearby(play, &this->actor, -1, ACTORCAT_EXPLOSIVE, 80.0f); + Actor* explosive; + explosive = Actor_FindNearby(play, &this->actor, -1, ACTORCAT_EXPLOSIVE, 80.0f); if (explosive != NULL) { this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.yawTowardsPlayer; - - if (((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (wallYawDiff < 0x2EE0)) || + if (((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (absRelWallYaw < 0x2EE0)) || (explosive->id == ACTOR_EN_BOM_CHU)) { if ((explosive->id == ACTOR_EN_BOM_CHU) && (Actor_WorldDistXYZToActor(&this->actor, explosive) < 80.0f) && - (s16)((this->actor.shape.rot.y - explosive->world.rot.y) + 0x8000) < 0x3E80) { - EnWf_SetupSomersaultAndAttack(this); + ((s16)(this->actor.shape.rot.y - explosive->world.rot.y + 0x8000) < 0x3E80)) { + EnWf_SetupBackflipForward(this); return true; } else { - EnWf_SetupSidestep(this, play); + EnWf_SetupShortCirclePlayer(this, play); return true; } } else { - EnWf_SetupBackflipAway(this); + EnWf_SetupBackflipBackward(this); return true; } } } - if (mustChoose) { - s16 playerFacingAngleDiff; + if (mustPick) { + s16 yawDiff; - if (playerYawDiff >= 0x1B58) { - EnWf_SetupSidestep(this, play); + if (absRelYawTowardsPlayer >= 0x1B58) { + EnWf_SetupShortCirclePlayer(this, play); return true; } - playerFacingAngleDiff = player->actor.shape.rot.y - this->actor.shape.rot.y; - + yawDiff = player->actor.shape.rot.y - this->actor.shape.rot.y; if ((this->actor.xzDistToPlayer <= 80.0f) && !Actor_OtherIsLockedOn(play, &this->actor) && - (((play->gameplayFrames % 8) != 0) || (ABS(playerFacingAngleDiff) < 0x38E0))) { - EnWf_SetupSlash(this); + (((play->gameplayFrames & 7) != 0) || (ABS(yawDiff) < 0x38E0))) { + EnWf_SetupAttack(this); + return true; + } else { + EnWf_SetupCirclePlayer(this); return true; } - - EnWf_SetupRunAroundPlayer(this); - return true; } return false; } -void EnWf_SetupWaitToAppear(EnWf* this) { - Animation_Change(&this->skelAnime, &gWolfosRearingUpFallingOverAnim, 0.5f, 0.0f, 7.0f, ANIMMODE_ONCE_INTERP, 0.0f); +/** + * Actor is squished underground and waits for the player to be in range to rise above ground. + */ +void EnWf_SetupWaitAppear(EnWf* this) { + Animation_Change(&this->skelAnime, &gWolfosHowlAnim, 0.5f, 0.0f, 7.0f, ANIMMODE_ONCE_INTERP, 0.0f); this->actor.world.pos.y = this->actor.home.pos.y - 5.0f; - this->actionTimer = 20; + this->timer = 20; this->unk_300 = false; - this->action = WOLFOS_ACTION_WAIT_TO_APPEAR; + this->action = ENWF_ACTION_WAIT_APPEAR; this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; this->actor.scale.y = 0.0f; this->actor.gravity = 0.0f; - EnWf_SetupAction(this, EnWf_WaitToAppear); + EnWf_SetupAction(this, EnWf_WaitAppear); } -void EnWf_WaitToAppear(EnWf* this, PlayState* play) { - if (this->actionTimer >= 6) { +void EnWf_WaitAppear(EnWf* this, PlayState* play) { + if (this->timer > 5) { this->actor.world.pos.y = this->actor.home.pos.y - 5.0f; - if (this->actor.xzDistToPlayer < 240.0f) { - this->actionTimer = 5; + this->timer = 5; this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; - - if ((this->actor.params != WOLFOS_NORMAL) && (this->switchFlag != 0xFF)) { + if ((this->actor.params != 0) && (this->switchFlag != 0xFF)) { func_800F5ACC(NA_BGM_MINI_BOSS); } } - } else if (this->actionTimer != 0) { - this->actor.scale.y += this->actor.scale.x * 0.2f; + } else if (this->timer != 0) { + this->actor.scale.y += this->actor.scale.x * (1 / 5.0f); this->actor.world.pos.y += 0.5f; - Math_SmoothStepToF(&this->actor.shape.shadowScale, 70.0f, 1.0f, 14.0f, 0.0f); - this->actionTimer--; - - if (this->actionTimer == 0) { + Math_SmoothStepToF(&this->actor.shape.shadowScale, 70.0f, 1.0f, 70.0f / 5, 0.0f); + this->timer--; + if (this->timer == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_APPEAR); } - } else { // actionTimer == 0 + } else { if (SkelAnime_Update(&this->skelAnime)) { this->actor.scale.y = this->actor.scale.x; this->actor.gravity = -2.0f; - EnWf_SetupWait(this); + EnWf_SetupIdle(this); } } } -void EnWf_SetupWait(EnWf* this) { - Animation_MorphToLoop(&this->skelAnime, &gWolfosWaitingAnim, -4.0f); - this->action = WOLFOS_ACTION_WAIT; - this->actionTimer = (Rand_ZeroOne() * 10.0f) + 2.0f; +void EnWf_SetupIdle(EnWf* this) { + Animation_MorphToLoop(&this->skelAnime, &gWolfosIdleAnim, -4.0f); + this->action = ENWF_ACTION_IDLE; + this->timer = (Rand_ZeroOne() * 10.0f) + 2.0f; this->actor.speed = 0.0f; this->actor.world.rot.y = this->actor.shape.rot.y; - EnWf_SetupAction(this, EnWf_Wait); + EnWf_SetupAction(this, EnWf_Idle); } -void EnWf_Wait(EnWf* this, PlayState* play) { +void EnWf_Idle(EnWf* this, PlayState* play) { Player* player; s32 pad; - s16 angle; + s16 yaw; player = GET_PLAYER(play); SkelAnime_Update(&this->skelAnime); - - if (this->unk_2E2 != 0) { - angle = (this->actor.yawTowardsPlayer - this->actor.shape.rot.y) - this->unk_4D4.y; - - if (ABS(angle) > 0x2000) { - this->unk_2E2--; + if (this->idleTimer != 0) { + yaw = this->actor.yawTowardsPlayer - this->actor.shape.rot.y - this->headRot; + if (ABS(yaw) > 0x2000) { + this->idleTimer--; return; } - - this->unk_2E2 = 0; + this->idleTimer = 0; } - - angle = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - angle = ABS(angle); - - if (!EnWf_DodgeRanged(play, this)) { - // Only use of unk_2E0: never not zero, so this if block never runs + yaw = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if (yaw < 0) { + yaw *= -1; + } + if (!EnWf_ReactToProjectile(play, this)) { + // unk_2E0 is always 0 if (this->unk_2E0 != 0) { this->unk_2E0--; - - if (angle >= 0x1FFE) { - return; - } - this->unk_2E0 = 0; - } else { - if (EnWf_ChangeAction(play, this, false)) { + if (yaw < 0x1FFE) { + this->unk_2E0 = 0; + } else { return; } + } else if (EnWf_PickAction(play, this, false)) { + return; } - - angle = player->actor.shape.rot.y - this->actor.shape.rot.y; - angle = ABS(angle); - - if ((this->actor.xzDistToPlayer < 80.0f) && (player->meleeWeaponState != 0) && (angle >= 0x1F40)) { + yaw = player->actor.shape.rot.y - this->actor.shape.rot.y; + if (yaw < 0) { + yaw *= -1; + } + if ((this->actor.xzDistToPlayer < 80.0f) && (player->meleeWeaponState != 0) && (yaw >= 0x1F40)) { this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.yawTowardsPlayer; - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } else { - this->actionTimer--; - - if (this->actionTimer == 0) { + this->timer--; + if (this->timer == 0) { if (Actor_IsFacingPlayer(&this->actor, 0x1555)) { if (Rand_ZeroOne() > 0.3f) { - EnWf_SetupRunAtPlayer(this, play); + EnWf_SetupRunToAttack(this, play); } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } } else { - EnWf_SetupSearchForPlayer(this); + EnWf_SetupTurnTowardsPlayer(this); } - if ((play->gameplayFrames & 95) == 0) { + if ((play->gameplayFrames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } } @@ -502,83 +519,85 @@ void EnWf_Wait(EnWf* this, PlayState* play) { } } -void EnWf_SetupRunAtPlayer(EnWf* this, PlayState* play) { - f32 lastFrame = Animation_GetLastFrame(&gWolfosRunningAnim); - - Animation_Change(&this->skelAnime, &gWolfosRunningAnim, 1.0f, 0.0f, lastFrame, ANIMMODE_LOOP_INTERP, -4.0f); - this->action = WOLFOS_ACTION_RUN_AT_PLAYER; - EnWf_SetupAction(this, EnWf_RunAtPlayer); +/** + * Run towards the player with the intent to attack. + */ +void EnWf_SetupRunToAttack(EnWf* this, PlayState* play) { + Animation_Change(&this->skelAnime, &gWolfosRunAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gWolfosRunAnim), + ANIMMODE_LOOP_INTERP, -4.0f); + this->action = ENWF_ACTION_RUN_TO_ATTACK; + EnWf_SetupAction(this, EnWf_RunToAttack); } -void EnWf_RunAtPlayer(EnWf* this, PlayState* play) { +void EnWf_RunToAttack(EnWf* this, PlayState* play) { s32 prevFrame; s32 beforeCurFrame; s32 pad; - f32 baseRange = 0.0f; - s16 playerFacingAngleDiff; - Player* player = GET_PLAYER(play); - s32 absPlaySpeed; + f32 sp50_real; + s32 pad2; + Player* player; + s32 pad3; + s16 temp_v1_real; + s16 var_v0_real; + f32 absPlaySpeed; + s32 pad4; - if (!EnWf_DodgeRanged(play, this)) { + sp50_real = 0.0f; + player = GET_PLAYER(play); + if (!EnWf_ReactToProjectile(play, this)) { Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 1, 0x2EE, 0); this->actor.world.rot.y = this->actor.shape.rot.y; - if (Actor_OtherIsLockedOn(play, &this->actor)) { - baseRange = 150.0f; + sp50_real = 150.0f; } - - if (this->actor.xzDistToPlayer <= (50.0f + baseRange)) { + if (this->actor.xzDistToPlayer <= (50.0f + sp50_real)) { Math_SmoothStepToF(&this->actor.speed, -8.0f, 1.0f, 1.5f, 0.0f); - } else if ((65.0f + baseRange) < this->actor.xzDistToPlayer) { + } else if (this->actor.xzDistToPlayer > (65.0f + sp50_real)) { Math_SmoothStepToF(&this->actor.speed, 8.0f, 1.0f, 1.5f, 0.0f); } else { Math_SmoothStepToF(&this->actor.speed, 0.0f, 1.0f, 6.65f, 0.0f); } - this->skelAnime.playSpeed = this->actor.speed * 0.175f; - playerFacingAngleDiff = player->actor.shape.rot.y - this->actor.shape.rot.y; - playerFacingAngleDiff = ABS(playerFacingAngleDiff); - - if ((this->actor.xzDistToPlayer < (150.0f + baseRange)) && (player->meleeWeaponState != 0) && - (playerFacingAngleDiff >= 8000)) { + var_v0_real = player->actor.shape.rot.y - this->actor.shape.rot.y; + if (var_v0_real < 0) { + var_v0_real *= -1; + } + if ((this->actor.xzDistToPlayer < (150.0f + sp50_real)) && (player->meleeWeaponState != 0) && + (var_v0_real >= 0x1F40)) { this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.yawTowardsPlayer; - if (Rand_ZeroOne() > 0.7f) { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); return; } } - prevFrame = (s32)this->skelAnime.curFrame; SkelAnime_Update(&this->skelAnime); - beforeCurFrame = (s32)(this->skelAnime.curFrame - ABS(this->skelAnime.playSpeed)); - absPlaySpeed = (s32)(f32)ABS(this->skelAnime.playSpeed); - + absPlaySpeed = ABS(this->skelAnime.playSpeed); + beforeCurFrame = (s32)(this->skelAnime.curFrame - absPlaySpeed); + absPlaySpeed = ABS(this->skelAnime.playSpeed); if (!Actor_IsFacingPlayer(&this->actor, 0x11C7)) { if (Rand_ZeroOne() > 0.5f) { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } else { - EnWf_SetupWait(this); + EnWf_SetupIdle(this); } - } else if (this->actor.xzDistToPlayer < (90.0f + baseRange)) { - s16 temp_v1 = player->actor.shape.rot.y - this->actor.shape.rot.y; - + } else if (this->actor.xzDistToPlayer < (90.0f + sp50_real)) { + temp_v1_real = player->actor.shape.rot.y - this->actor.shape.rot.y; if (!Actor_OtherIsLockedOn(play, &this->actor) && - ((Rand_ZeroOne() > 0.03f) || ((this->actor.xzDistToPlayer <= 80.0f) && (ABS(temp_v1) < 0x38E0)))) { - EnWf_SetupSlash(this); - } else if (Actor_OtherIsLockedOn(play, &this->actor) && (Rand_ZeroOne() > 0.5f)) { - EnWf_SetupBackflipAway(this); + ((Rand_ZeroOne() > 0.03f) || ((this->actor.xzDistToPlayer <= 80.0f) && (ABS(temp_v1_real) < 0x38E0)))) { + EnWf_SetupAttack(this); + } else if ((Actor_OtherIsLockedOn(play, &this->actor)) && (Rand_ZeroOne() > 0.5f)) { + EnWf_SetupBackflipBackward(this); } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } } - - if (!EnWf_ChangeAction(play, this, false)) { - if ((play->gameplayFrames & 95) == 0) { + if (!EnWf_PickAction(play, this, false)) { + if ((play->gameplayFrames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } if ((prevFrame != (s32)this->skelAnime.curFrame) && (beforeCurFrame <= 0) && - ((absPlaySpeed + prevFrame) > 0)) { + (((s32)absPlaySpeed + prevFrame) > 0)) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_WALK); Actor_SpawnFloorDustRing(play, &this->actor, &this->actor.world.pos, 20.0f, 3, 3.0f, 50, 50, true); } @@ -586,301 +605,293 @@ void EnWf_RunAtPlayer(EnWf* this, PlayState* play) { } } -void EnWf_SetupSearchForPlayer(EnWf* this) { - Animation_MorphToLoop(&this->skelAnime, &gWolfosSidesteppingAnim, -4.0f); - this->action = WOLFOS_ACTION_SEARCH_FOR_PLAYER; - EnWf_SetupAction(this, EnWf_SearchForPlayer); +void EnWf_SetupTurnTowardsPlayer(EnWf* this) { + Animation_MorphToLoop(&this->skelAnime, &gWolfosSideStepAnim, -4.0f); + this->action = ENWF_ACTION_TURN_TOWARDS_PLAYER; + EnWf_SetupAction(this, EnWf_TurnTowardsPlayer); } -void EnWf_SearchForPlayer(EnWf* this, PlayState* play) { - s16 yawDiff; - s16 phi_v1; - f32 phi_f2; +void EnWf_TurnTowardsPlayer(EnWf* this, PlayState* play) { + f32 animPlaySpeed; + s16 relYawTowardsPlayer; + s16 yawSpeed; - if (!EnWf_DodgeRanged(play, this) && !EnWf_ChangeAction(play, this, false)) { - yawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - phi_v1 = (yawDiff > 0) ? (yawDiff * 0.25f) + 2000.0f : (yawDiff * 0.25f) - 2000.0f; - this->actor.shape.rot.y += phi_v1; + if (!EnWf_ReactToProjectile(play, this) && !EnWf_PickAction(play, this, false)) { + relYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if (relYawTowardsPlayer > 0) { + yawSpeed = (relYawTowardsPlayer * 0.25f) + 2000.0f; + } else { + yawSpeed = (relYawTowardsPlayer * 0.25f) - 2000.0f; + } + this->actor.shape.rot.y += yawSpeed; this->actor.world.rot.y = this->actor.shape.rot.y; - - if (yawDiff > 0) { - phi_f2 = phi_v1 * 0.5f; - phi_f2 = CLAMP_MAX(phi_f2, 1.0f); + if (relYawTowardsPlayer > 0) { + animPlaySpeed = yawSpeed * 0.5f; + if (animPlaySpeed > 1.0f) { + animPlaySpeed = 1.0f; + } } else { - phi_f2 = phi_v1 * 0.5f; - phi_f2 = CLAMP_MIN(phi_f2, -1.0f); + animPlaySpeed = yawSpeed * 0.5f; + if (animPlaySpeed < -1.0f) { + animPlaySpeed = -1.0f; + } } - - this->skelAnime.playSpeed = -phi_f2; + this->skelAnime.playSpeed = -animPlaySpeed; SkelAnime_Update(&this->skelAnime); - if (Actor_IsFacingPlayer(&this->actor, 0x1555)) { if (Rand_ZeroOne() > 0.8f) { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } else { - EnWf_SetupRunAtPlayer(this, play); + EnWf_SetupRunToAttack(this, play); } } - - if ((play->gameplayFrames & 95) == 0) { + if ((play->gameplayFrames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } } } -void EnWf_SetupRunAroundPlayer(EnWf* this) { - f32 lastFrame = Animation_GetLastFrame(&gWolfosRunningAnim); - - Animation_Change(&this->skelAnime, &gWolfosRunningAnim, 1.0f, 0.0f, lastFrame, ANIMMODE_LOOP_INTERP, -4.0f); - +/** + * Run around the player in a circular fashion. + */ +void EnWf_SetupCirclePlayer(EnWf* this) { + Animation_Change(&this->skelAnime, &gWolfosRunAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gWolfosRunAnim), + ANIMMODE_LOOP_INTERP, -4.0f); if (Rand_ZeroOne() > 0.5f) { - this->runAngle = 16000; + this->circlePlayerDirection = 0x3E80; } else { - this->runAngle = -16000; + this->circlePlayerDirection = -0x3E80; } - - this->skelAnime.playSpeed = this->actor.speed = 6.0f; - this->skelAnime.playSpeed *= 0.175f; + this->actor.speed = 6.0f; + this->skelAnime.playSpeed = this->actor.speed * 0.175f; this->actor.world.rot.y = this->actor.shape.rot.y; - this->actionTimer = (Rand_ZeroOne() * 30.0f) + 30.0f; - this->action = WOLFOS_ACTION_RUN_AROUND_PLAYER; - this->runSpeed = 0.0f; - - EnWf_SetupAction(this, EnWf_RunAroundPlayer); + this->timer = (Rand_ZeroOne() * 30.0f) + 30.0f; + this->action = ENWF_ACTION_CIRCLE_PLAYER; + this->circlePlayerExtraSpeed = 0.0f; + EnWf_SetupAction(this, EnWf_CirclePlayer); } -void EnWf_RunAroundPlayer(EnWf* this, PlayState* play) { - s16 angle1; - s16 angle2; - s32 pad; - f32 baseRange = 0.0f; +void EnWf_CirclePlayer(EnWf* this, PlayState* play) { + s16 sp56_real; + s32 new_var; + f32 extraRadius; s32 prevFrame; s32 beforeCurFrame; s32 absPlaySpeed; - Player* player = GET_PLAYER(play); - - Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer + this->runAngle, 1, 4000, 1); + Player* player; + s16 yawWallRelToTarget; - if (!EnWf_DodgeRanged(play, this) && !EnWf_ChangeAction(play, this, false)) { + extraRadius = 0.0f; + player = GET_PLAYER(play); + Math_SmoothStepToS(&this->actor.shape.rot.y, (s16)(this->actor.yawTowardsPlayer + this->circlePlayerDirection), 1, + 0xFA0, 1); + if (!EnWf_ReactToProjectile(play, this) && !EnWf_PickAction(play, this, false)) { this->actor.world.rot.y = this->actor.shape.rot.y; - angle1 = player->actor.shape.rot.y + this->runAngle + 0x8000; - - // Actor_TestFloorInDirection is useless here (see comment below) + sp56_real = player->actor.shape.rot.y + this->circlePlayerDirection + 0x8000; if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) || !Actor_TestFloorInDirection(&this->actor, play, this->actor.speed, this->actor.shape.rot.y)) { - angle2 = (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) - ? (this->actor.wallYaw - this->actor.yawTowardsPlayer) - this->runAngle - : 0; - - // This is probably meant to reverse direction if the edge of a floor is encountered, but does nothing - // unless bgCheckFlags & BGCHECKFLAG_WALL anyway, since angle2 = 0 otherwise - if (ABS(angle2) > 0x2EE0) { - this->runAngle = -this->runAngle; + // If there's a wall in the way, switch direction + if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) { + yawWallRelToTarget = this->actor.wallYaw - this->actor.yawTowardsPlayer - this->circlePlayerDirection; + } else { + yawWallRelToTarget = 0; + } + if (ABS(yawWallRelToTarget) > 0x2EE0) { + this->circlePlayerDirection = -this->circlePlayerDirection; } } - if (Actor_OtherIsLockedOn(play, &this->actor)) { - baseRange = 150.0f; + extraRadius = 150.0f; } - - if (this->actor.xzDistToPlayer <= (60.0f + baseRange)) { - Math_SmoothStepToF(&this->runSpeed, -4.0f, 1.0f, 1.5f, 0.0f); - } else if ((80.0f + baseRange) < this->actor.xzDistToPlayer) { - Math_SmoothStepToF(&this->runSpeed, 4.0f, 1.0f, 1.5f, 0.0f); + if (this->actor.xzDistToPlayer <= (60.0f + extraRadius)) { + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, -4.0f, 1.0f, 1.5f, 0.0f); + } else if (this->actor.xzDistToPlayer > (80.0f + extraRadius)) { + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, 4.0f, 1.0f, 1.5f, 0.0f); } else { - Math_SmoothStepToF(&this->runSpeed, 0.0f, 1.0f, 6.65f, 0.0f); + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, 0.0f, 1.0f, 6.65f, 0.0f); } - - if (this->runSpeed != 0.0f) { - this->actor.world.pos.x += Math_SinS(this->actor.shape.rot.y) * this->runSpeed; - this->actor.world.pos.z += Math_CosS(this->actor.shape.rot.y) * this->runSpeed; + if (this->circlePlayerExtraSpeed != 0.0f) { + this->actor.world.pos.x += Math_SinS(this->actor.shape.rot.y) * this->circlePlayerExtraSpeed; + this->actor.world.pos.z += Math_CosS(this->actor.shape.rot.y) * this->circlePlayerExtraSpeed; } - - if (ABS(this->runSpeed) < ABS(this->actor.speed)) { + if (ABS(this->circlePlayerExtraSpeed) < ABS(this->actor.speed)) { this->skelAnime.playSpeed = this->actor.speed * 0.175f; } else { - this->skelAnime.playSpeed = this->runSpeed * 0.175f; + this->skelAnime.playSpeed = this->circlePlayerExtraSpeed * 0.175f; } this->skelAnime.playSpeed = CLAMP(this->skelAnime.playSpeed, -3.0f, 3.0f); - prevFrame = (s32)this->skelAnime.curFrame; SkelAnime_Update(&this->skelAnime); beforeCurFrame = (s32)(this->skelAnime.curFrame - ABS(this->skelAnime.playSpeed)); - absPlaySpeed = (s32)(f32)ABS(this->skelAnime.playSpeed); - - if ((prevFrame != (s32)this->skelAnime.curFrame) && (beforeCurFrame <= 0) && (absPlaySpeed + prevFrame > 0)) { + absPlaySpeed = new_var = (s32)ABS(this->skelAnime.playSpeed); + if ((prevFrame != (s32)this->skelAnime.curFrame) && (beforeCurFrame <= 0) && ((absPlaySpeed + prevFrame) > 0)) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_WALK); Actor_SpawnFloorDustRing(play, &this->actor, &this->actor.world.pos, 20.0f, 3, 3.0f, 50, 50, true); } - - if ((play->gameplayFrames & 95) == 0) { + if ((play->gameplayFrames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } - - if ((Math_CosS(angle1 - this->actor.shape.rot.y) < -0.85f) && !Actor_OtherIsLockedOn(play, &this->actor) && + if ((Math_CosS(sp56_real - this->actor.shape.rot.y) < -0.85f) && !Actor_OtherIsLockedOn(play, &this->actor) && (this->actor.xzDistToPlayer <= 80.0f)) { - EnWf_SetupSlash(this); + EnWf_SetupAttack(this); } else { - this->actionTimer--; - - if (this->actionTimer == 0) { + this->timer--; + if (this->timer == 0) { if (Actor_OtherIsLockedOn(play, &this->actor) && (Rand_ZeroOne() > 0.5f)) { - EnWf_SetupBackflipAway(this); + EnWf_SetupBackflipBackward(this); } else { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 3.0f) + 1.0f; + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 3.0f) + 1.0f; } } } } } -void EnWf_SetupSlash(EnWf* this) { - Animation_PlayOnce(&this->skelAnime, &gWolfosSlashingAnim); - this->colliderJntSph.base.atFlags &= ~AT_BOUNCED; +void EnWf_SetupAttack(EnWf* this) { + Animation_PlayOnce(&this->skelAnime, &gWolfosAttackAnim); + this->attackAndBlockCollider.base.atFlags &= ~AT_BOUNCED; this->actor.shape.rot.y = this->actor.yawTowardsPlayer; - this->action = WOLFOS_ACTION_SLASH; - this->unk_2FA = 0; // Set and not used - this->actionTimer = 7; + this->action = ENWF_ACTION_ATTACK; + this->unk_2FA = 0; + this->timer = 7; this->skelAnime.endFrame = 20.0f; this->actor.speed = 0.0f; - - EnWf_SetupAction(this, EnWf_Slash); + EnWf_SetupAction(this, EnWf_Attack); } -void EnWf_Slash(EnWf* this, PlayState* play) { +void EnWf_Attack(EnWf* this, PlayState* play) { Player* player = GET_PLAYER(play); - s16 shapeAngleDiff = player->actor.shape.rot.y - this->actor.shape.rot.y; - s16 yawAngleDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - s32 curFrame = this->skelAnime.curFrame; - - shapeAngleDiff = ABS(shapeAngleDiff); - yawAngleDiff = ABS(yawAngleDiff); + s16 absYawDiffWithPlayer; + s16 absRelYawTowardsPlayer; + s32 animCurFrame; + + absYawDiffWithPlayer = player->actor.shape.rot.y - this->actor.shape.rot.y; + absRelYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + animCurFrame = (s32)this->skelAnime.curFrame; + absYawDiffWithPlayer = ABS(absYawDiffWithPlayer); + absRelYawTowardsPlayer = ABS(absRelYawTowardsPlayer); this->actor.speed = 0.0f; - - if (((curFrame >= 9) && (curFrame <= 12)) || ((curFrame >= 17) && (curFrame <= 19))) { - if (this->slashStatus == 0) { + if (((animCurFrame >= 9) && (animCurFrame <= 12)) || ((animCurFrame >= 17) && (animCurFrame <= 19))) { + if (this->attackState == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_ATTACK); } - - this->slashStatus = 1; + this->attackState = 1; } else { - this->slashStatus = 0; + this->attackState = 0; } - - if (((curFrame == 15) && !Actor_IsLockedOn(play, &this->actor) && + if (((animCurFrame == 15) && !Actor_IsLockedOn(play, &this->actor) && (!Actor_IsFacingPlayer(&this->actor, 0x2000) || (this->actor.xzDistToPlayer >= 100.0f))) || SkelAnime_Update(&this->skelAnime)) { - if ((curFrame != 15) && (this->actionTimer != 0)) { - this->actor.shape.rot.y += (s16)(3276.0f * (1.5f + (this->actionTimer - 4) * 0.4f)); + if ((animCurFrame != 15) && (this->timer != 0)) { + this->actor.shape.rot.y += (s16)(s32)(3276.0f * (1.5f + ((this->timer - 4) * 0.4f))); Actor_SpawnFloorDustRing(play, &this->actor, &this->actor.world.pos, 15.0f, 1, 2.0f, 50, 50, true); - this->actionTimer--; - } else if (!Actor_IsFacingPlayer(&this->actor, 0x1554) && (curFrame != 15)) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 5.0f) + 5.0f; - - if (yawAngleDiff > 13000) { - this->unk_2E2 = 7; + this->timer--; + } else if (!Actor_IsFacingPlayer(&this->actor, 0x1554) && (animCurFrame != 15)) { + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 5.0f) + 5.0f; + if (absRelYawTowardsPlayer > 0x32C8) { + this->idleTimer = 7; } } else if ((Rand_ZeroOne() > 0.7f) || (this->actor.xzDistToPlayer >= 120.0f)) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 5.0f) + 5.0f; + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 5.0f) + 5.0f; } else { this->actor.world.rot.y = this->actor.yawTowardsPlayer; - if (Rand_ZeroOne() > 0.7f) { - EnWf_SetupSidestep(this, play); - } else if (shapeAngleDiff <= 10000) { - if (yawAngleDiff > 16000) { + EnWf_SetupShortCirclePlayer(this, play); + } else if (absYawDiffWithPlayer <= 0x2710) { + if (absRelYawTowardsPlayer > 0x3E80) { this->actor.world.rot.y = this->actor.yawTowardsPlayer; - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } else { - EnWf_ChangeAction(play, this, true); + EnWf_PickAction(play, this, true); } } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } } } } -void EnWf_SetupRecoilFromBlockedSlash(EnWf* this) { - f32 endFrame = 1.0f; +void EnWf_SetupAttackBouncedOff(EnWf* this) { + f32 animEndFrame; + animEndFrame = 1.0f; if ((s32)this->skelAnime.curFrame >= 16) { - endFrame = 15.0f; + animEndFrame = 15.0f; } - - Animation_Change(&this->skelAnime, &gWolfosSlashingAnim, -0.5f, this->skelAnime.curFrame - 1.0f, endFrame, + Animation_Change(&this->skelAnime, &gWolfosAttackAnim, -0.5f, this->skelAnime.curFrame - 1.0f, animEndFrame, ANIMMODE_ONCE_INTERP, 0.0f); - this->action = WOLFOS_ACTION_RECOIL_FROM_BLOCKED_SLASH; - this->slashStatus = 0; - EnWf_SetupAction(this, EnWf_RecoilFromBlockedSlash); + this->action = ENWF_ACTION_ATTACK_BOUNCED_OFF; + this->attackState = 0; + EnWf_SetupAction(this, EnWf_AttackBouncedOff); } -void EnWf_RecoilFromBlockedSlash(EnWf* this, PlayState* play) { +void EnWf_AttackBouncedOff(EnWf* this, PlayState* play) { Player* player = GET_PLAYER(play); - s16 angle1 = player->actor.shape.rot.y - this->actor.shape.rot.y; - s16 angle2 = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - - angle1 = ABS(angle1); - angle2 = ABS(angle2); + s16 absYawDiffWithPlayer; + s16 absRelYawTowardsPlayer; + absYawDiffWithPlayer = player->actor.shape.rot.y - this->actor.shape.rot.y; + absRelYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if (absYawDiffWithPlayer < 0) { + absYawDiffWithPlayer *= -1; + } + if (absRelYawTowardsPlayer < 0) { + absRelYawTowardsPlayer *= -1; + } if (SkelAnime_Update(&this->skelAnime)) { if (!Actor_IsFacingPlayer(&this->actor, 0x1554)) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 5.0f) + 5.0f; - - if (angle2 > 0x32C8) { - this->unk_2E2 = 30; + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 5.0f) + 5.0f; + if (absRelYawTowardsPlayer > 0x32C8) { + this->idleTimer = 30; } + } else if ((Rand_ZeroOne() > 0.7f) || (this->actor.xzDistToPlayer >= 120.0f)) { + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 5.0f) + 5.0f; } else { - if ((Rand_ZeroOne() > 0.7f) || (this->actor.xzDistToPlayer >= 120.0f)) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 5.0f) + 5.0f; - } else { - this->actor.world.rot.y = this->actor.yawTowardsPlayer; - - if (Rand_ZeroOne() > 0.7f) { - EnWf_SetupSidestep(this, play); - } else if (angle1 <= 0x2710) { - if (angle2 > 0x3E80) { - this->actor.world.rot.y = this->actor.yawTowardsPlayer; - EnWf_SetupRunAroundPlayer(this); - } else { - EnWf_ChangeAction(play, this, true); - } + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + if (Rand_ZeroOne() > 0.7f) { + EnWf_SetupShortCirclePlayer(this, play); + } else if (absYawDiffWithPlayer <= 0x2710) { + if (absRelYawTowardsPlayer > 0x3E80) { + this->actor.world.rot.y = this->actor.yawTowardsPlayer; + EnWf_SetupCirclePlayer(this); } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_PickAction(play, this, true); } + } else { + EnWf_SetupCirclePlayer(this); } } } } -void EnWf_SetupBackflipAway(EnWf* this) { - Animation_MorphToPlayOnce(&this->skelAnime, &gWolfosBackflippingAnim, -3.0f); +void EnWf_SetupBackflipBackward(EnWf* this) { + Animation_MorphToPlayOnce(&this->skelAnime, &gWolfosBackflipAnim, -3.0f); + this->timer = 0; + this->unk_300 = true; + this->action = ENWF_ACTION_BACKFLIP_BACKWARD; this->actor.speed = -6.0f; this->actor.shape.rot.y = this->actor.world.rot.y = this->actor.yawTowardsPlayer; - this->actionTimer = 0; - this->unk_300 = true; - this->action = WOLFOS_ACTION_BACKFLIP_AWAY; Actor_PlaySfx(&this->actor, NA_SE_EN_STAL_JUMP); - EnWf_SetupAction(this, EnWf_BackflipAway); + EnWf_SetupAction(this, EnWf_BackflipBackward); } -void EnWf_BackflipAway(EnWf* this, PlayState* play) { +void EnWf_BackflipBackward(EnWf* this, PlayState* play) { if (SkelAnime_Update(&this->skelAnime)) { if (!Actor_OtherIsLockedOn(play, &this->actor) && (this->actor.xzDistToPlayer < 170.0f) && (this->actor.xzDistToPlayer > 140.0f) && (Rand_ZeroOne() < 0.2f)) { - EnWf_SetupRunAtPlayer(this, play); - } else if ((play->gameplayFrames % 2) != 0) { - EnWf_SetupSidestep(this, play); + EnWf_SetupRunToAttack(this, play); + } else if (play->gameplayFrames & 1) { + EnWf_SetupShortCirclePlayer(this, play); } else { - EnWf_SetupWait(this); + EnWf_SetupIdle(this); } } - if ((play->state.frames & 95) == 0) { + if ((play->state.frames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } } @@ -889,10 +900,9 @@ void EnWf_SetupStunned(EnWf* this) { if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { this->actor.speed = 0.0f; } - Actor_PlaySfx(&this->actor, NA_SE_EN_GOMA_JR_FREEZE); Animation_PlayOnceSetSpeed(&this->skelAnime, &gWolfosDamagedAnim, 0.0f); - this->action = WOLFOS_ACTION_STUNNED; + this->action = ENWF_ACTION_STUNNED; EnWf_SetupAction(this, EnWf_Stunned); } @@ -900,320 +910,305 @@ void EnWf_Stunned(EnWf* this, PlayState* play) { if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND_TOUCH) { this->actor.speed = 0.0f; } - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { if (this->actor.speed < 0.0f) { this->actor.speed += 0.05f; } - this->unk_300 = false; } - if ((this->actor.colorFilterTimer == 0) && (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) { if (this->actor.colChkInfo.health == 0) { EnWf_SetupDie(this); } else { - EnWf_ChangeAction(play, this, true); + EnWf_PickAction(play, this, true); } } } void EnWf_SetupDamaged(EnWf* this) { Animation_MorphToPlayOnce(&this->skelAnime, &gWolfosDamagedAnim, -4.0f); - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { this->unk_300 = false; this->actor.speed = -4.0f; } else { this->unk_300 = true; } - - this->unk_2E2 = 0; + this->idleTimer = 0; this->actor.world.rot.y = this->actor.yawTowardsPlayer; Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_DAMAGE); - this->action = WOLFOS_ACTION_DAMAGED; + this->action = ENWF_ACTION_DAMAGED; EnWf_SetupAction(this, EnWf_Damaged); } void EnWf_Damaged(EnWf* this, PlayState* play) { - s16 angleToWall; + s16 absRelWallYaw; if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND_TOUCH) { this->actor.speed = 0.0f; } - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { if (this->actor.speed < 0.0f) { this->actor.speed += 0.05f; } - this->unk_300 = false; } - - Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 1, 4500, 0); - - if (!EnWf_ChangeAction(play, this, false) && SkelAnime_Update(&this->skelAnime)) { - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { - angleToWall = this->actor.wallYaw - this->actor.shape.rot.y; - angleToWall = ABS(angleToWall); - - if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (ABS(angleToWall) < 12000) && - (this->actor.xzDistToPlayer < 120.0f)) { - EnWf_SetupSomersaultAndAttack(this); - } else if (!EnWf_DodgeRanged(play, this)) { - if ((this->actor.xzDistToPlayer <= 80.0f) && !Actor_OtherIsLockedOn(play, &this->actor) && - ((play->gameplayFrames % 8) != 0)) { - EnWf_SetupSlash(this); - } else if (Rand_ZeroOne() > 0.5f) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 5.0f) + 5.0f; - this->unk_2E2 = 30; - } else { - EnWf_SetupBackflipAway(this); - } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 1, 0x1194, 0); + if (!EnWf_PickAction(play, this, false) && SkelAnime_Update(&this->skelAnime) && + (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) { + absRelWallYaw = this->actor.wallYaw - this->actor.shape.rot.y; + if (absRelWallYaw < 0) { + absRelWallYaw *= -1; + } + if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (ABS(absRelWallYaw) < 0x2EE0) && + (this->actor.xzDistToPlayer < 120.0f)) { + EnWf_SetupBackflipForward(this); + } else if (!EnWf_ReactToProjectile(play, this)) { + if ((this->actor.xzDistToPlayer <= 80.0f) && !Actor_OtherIsLockedOn(play, &this->actor) && + ((play->gameplayFrames & 7) != 0)) { + EnWf_SetupAttack(this); + } else if (Rand_ZeroOne() > 0.5f) { + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 5.0f) + 5.0f; + this->idleTimer = 30; + } else { + EnWf_SetupBackflipBackward(this); } } } } -void EnWf_SetupSomersaultAndAttack(EnWf* this) { - f32 lastFrame = Animation_GetLastFrame(&gWolfosBackflippingAnim); - - Animation_Change(&this->skelAnime, &gWolfosBackflippingAnim, -1.0f, lastFrame, 0.0f, ANIMMODE_ONCE, -3.0f); - this->actionTimer = 0; +void EnWf_SetupBackflipForward(EnWf* this) { + Animation_Change(&this->skelAnime, &gWolfosBackflipAnim, -1.0f, Animation_GetLastFrame(&gWolfosBackflipAnim), 0.0f, + ANIMMODE_ONCE, -3.0f); + this->timer = 0; this->unk_300 = false; - this->action = WOLFOS_ACTION_TURN_TOWARDS_PLAYER; + this->action = ENWF_ACTION_BACKFLIP_FORWARD; this->actor.speed = 6.5f; this->actor.velocity.y = 15.0f; Actor_PlaySfx(&this->actor, NA_SE_EN_STAL_JUMP); this->actor.world.rot.y = this->actor.shape.rot.y; - EnWf_SetupAction(this, EnWf_SomersaultAndAttack); + EnWf_SetupAction(this, EnWf_BackflipForward); } -void EnWf_SomersaultAndAttack(EnWf* this, PlayState* play) { - Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 1, 4000, 1); - +void EnWf_BackflipForward(EnWf* this, PlayState* play) { + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 1, 0xFA0, 1); if (this->actor.velocity.y >= 5.0f) { - //! @bug unk_4C8 and unk_4BC are used but not set (presumably intended to be feet positions like other actors) + //! @bug unk_4C8 and unk_4BC are never set, so this spawns effects at 0,0,0 func_800355B8(play, &this->unk_4C8); func_800355B8(play, &this->unk_4BC); } - if (SkelAnime_Update(&this->skelAnime) && - (this->actor.bgCheckFlags & (BGCHECKFLAG_GROUND | BGCHECKFLAG_GROUND_TOUCH))) { - this->actor.world.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsPlayer; + ((this->actor.bgCheckFlags & (BGCHECKFLAG_GROUND | BGCHECKFLAG_GROUND_TOUCH)) != 0)) { this->actor.shape.rot.x = 0; - this->actor.speed = this->actor.velocity.y = 0.0f; + this->actor.world.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsPlayer; + this->actor.velocity.y = 0.0f; + this->actor.speed = 0.0f; this->actor.world.pos.y = this->actor.floorHeight; - if (!Actor_OtherIsLockedOn(play, &this->actor)) { - EnWf_SetupSlash(this); + EnWf_SetupAttack(this); } else { - EnWf_SetupWait(this); + EnWf_SetupIdle(this); } } } -void EnWf_SetupBlocking(EnWf* this) { - f32 lastFrame = Animation_GetLastFrame(&gWolfosBlockingAnim); +void EnWf_SetupBlock(EnWf* this) { + f32 animEndFrame; - if (this->slashStatus != 0) { - this->slashStatus = -1; + animEndFrame = (f32)Animation_GetLastFrame(&gWolfosBlockAnim); + if (this->attackState != 0) { + this->attackState = -1; } - this->actor.speed = 0.0f; - this->action = WOLFOS_ACTION_BLOCKING; - this->actionTimer = 10; - - Animation_Change(&this->skelAnime, &gWolfosBlockingAnim, 0.0f, 0.0f, lastFrame, ANIMMODE_ONCE_INTERP, -4.0f); - EnWf_SetupAction(this, EnWf_Blocking); + this->action = ENWF_ACTION_BLOCK; + this->timer = 0xA; + Animation_Change(&this->skelAnime, &gWolfosBlockAnim, 0.0f, 0.0f, animEndFrame, ANIMMODE_ONCE_INTERP, -4.0f); + EnWf_SetupAction(this, EnWf_Block); } -void EnWf_Blocking(EnWf* this, PlayState* play) { - Player* player = GET_PLAYER(play); +void EnWf_Block(EnWf* this, PlayState* play) { + Player* player; s32 pad; + s16 pad2; + s16 yawDiff; + s16 relYawTowardsPlayer; - if (this->actionTimer != 0) { - this->actionTimer--; + player = GET_PLAYER(play); + if (this->timer != 0) { + this->timer -= 1; } else { this->skelAnime.playSpeed = 1.0f; } - if (SkelAnime_Update(&this->skelAnime)) { - s16 yawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - - if ((ABS(yawDiff) <= 0x4000) && (this->actor.xzDistToPlayer < 60.0f) && + relYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if ((ABS(relYawTowardsPlayer) <= 0x4000) && (this->actor.xzDistToPlayer < 60.0f) && (ABS(this->actor.yDistToPlayer) < 50.0f)) { - if (func_800354B4(play, &this->actor, 100.0f, 10000, 0x4000, this->actor.shape.rot.y)) { + if (func_800354B4(play, &this->actor, 100.0f, 0x2710, 0x4000, this->actor.shape.rot.y)) { if (player->meleeWeaponAnimation == PLAYER_MWA_JUMPSLASH_START) { - EnWf_SetupBlocking(this); - } else if ((play->gameplayFrames % 2) != 0) { - EnWf_SetupBlocking(this); + EnWf_SetupBlock(this); + } else if (play->gameplayFrames & 1) { + EnWf_SetupBlock(this); } else { - EnWf_SetupBackflipAway(this); + EnWf_SetupBackflipBackward(this); } - } else { - s16 angleFacingLink = player->actor.shape.rot.y - this->actor.shape.rot.y; - + yawDiff = player->actor.shape.rot.y - this->actor.shape.rot.y; if (!Actor_OtherIsLockedOn(play, &this->actor) && - (((play->gameplayFrames % 2) != 0) || (ABS(angleFacingLink) < 0x38E0))) { - EnWf_SetupSlash(this); + ((play->gameplayFrames & 1) || (ABS(yawDiff) < 0x38E0))) { + EnWf_SetupAttack(this); } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } } } else { - EnWf_SetupRunAroundPlayer(this); + EnWf_SetupCirclePlayer(this); } - } else if (this->actionTimer == 0) { - if (func_800354B4(play, &this->actor, 100.0f, 10000, 0x4000, this->actor.shape.rot.y)) { - if (player->meleeWeaponAnimation == PLAYER_MWA_JUMPSLASH_START) { - EnWf_SetupBlocking(this); - } else if ((play->gameplayFrames % 2) != 0) { - EnWf_SetupBlocking(this); - } else { - EnWf_SetupBackflipAway(this); - } + } else if ((this->timer == 0) && + func_800354B4(play, &this->actor, 100.0f, 0x2710, 0x4000, this->actor.shape.rot.y)) { + if (player->meleeWeaponAnimation == PLAYER_MWA_JUMPSLASH_START) { + EnWf_SetupBlock(this); + } else if (play->gameplayFrames & 1) { + EnWf_SetupBlock(this); + } else { + EnWf_SetupBackflipBackward(this); } } } -void EnWf_SetupSidestep(EnWf* this, PlayState* play) { +/** + * Run a short circle arc around the player. + */ +void EnWf_SetupShortCirclePlayer(EnWf* this, PlayState* play) { s16 angle; Player* player; - f32 lastFrame = Animation_GetLastFrame(&gWolfosRunningAnim); - - Animation_Change(&this->skelAnime, &gWolfosRunningAnim, 1.0f, 0.0f, lastFrame, ANIMMODE_LOOP_INTERP, -4.0f); + Animation_Change(&this->skelAnime, &gWolfosRunAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gWolfosRunAnim), + ANIMMODE_LOOP_INTERP, -4.0f); player = GET_PLAYER(play); - angle = player->actor.shape.rot.y + this->runAngle; - + angle = player->actor.shape.rot.y + this->circlePlayerDirection; if (Math_SinS(angle - this->actor.yawTowardsPlayer) > 0.0f) { - this->runAngle = 16000; + this->circlePlayerDirection = 0x3E80; } else if (Math_SinS(angle - this->actor.yawTowardsPlayer) < 0.0f) { - this->runAngle = -16000; - } else if (Rand_ZeroOne() > 0.5f) { - this->runAngle = 16000; + this->circlePlayerDirection = -0x3E80; } else { - this->runAngle = -16000; + if (Rand_ZeroOne() > 0.5f) { + this->circlePlayerDirection = 0x3E80; + } else { + this->circlePlayerDirection = -0x3E80; + } } - - this->skelAnime.playSpeed = this->actor.speed = 6.0f; - this->skelAnime.playSpeed *= 0.175f; + this->actor.speed = 6.0f; + this->skelAnime.playSpeed = this->actor.speed * 0.175f; this->actor.world.rot.y = this->actor.shape.rot.y; - this->runSpeed = 0.0f; - this->actionTimer = (Rand_ZeroOne() * 10.0f) + 5.0f; - this->action = WOLFOS_ACTION_SIDESTEP; - - EnWf_SetupAction(this, EnWf_Sidestep); + this->circlePlayerExtraSpeed = 0.0f; + this->timer = (Rand_ZeroOne() * 10.0f) + 5.0f; + this->action = ENWF_ACTION_SHORT_CIRCLE_PLAYER; + EnWf_SetupAction(this, EnWf_ShortCirclePlayer); } -void EnWf_Sidestep(EnWf* this, PlayState* play) { - s16 angleDiff1; - Player* player = GET_PLAYER(play); +void EnWf_ShortCirclePlayer(EnWf* this, PlayState* play) { + Player* player2; + Player* player; s32 prevFrame; s32 beforeCurFrame; + s32 new_var; + f32 extraRadius; s32 absPlaySpeed; - f32 baseRange = 0.0f; + s16 yawWallRelToTarget; + s16 behindPlayerYawAbs; + s16 behindPlayerYaw; - Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer + this->runAngle, 1, 3000, 1); - - // Actor_TestFloorInDirection is useless here (see comment below) + player = GET_PLAYER(play); + extraRadius = 0.0f; + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer + this->circlePlayerDirection, 1, 0xBB8, + 1); if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) || !Actor_TestFloorInDirection(&this->actor, play, this->actor.speed, this->actor.shape.rot.y)) { - s16 angle = (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) - ? (this->actor.wallYaw - this->actor.yawTowardsPlayer) - this->runAngle - : 0; - - // This is probably meant to reverse direction if the edge of a floor is encountered, but does nothing - // unless bgCheckFlags & 8 anyway, since angle = 0 otherwise - if (ABS(angle) > 0x2EE0) { - this->runAngle = -this->runAngle; + // If there's a wall in the way, switch direction + if (this->actor.bgCheckFlags & BGCHECKFLAG_WALL) { + yawWallRelToTarget = this->actor.wallYaw - this->actor.yawTowardsPlayer - this->circlePlayerDirection; + } else { + yawWallRelToTarget = 0; + } + if (ABS(yawWallRelToTarget) > 0x2EE0) { + this->circlePlayerDirection = -this->circlePlayerDirection; } } - this->actor.world.rot.y = this->actor.shape.rot.y; - if (Actor_OtherIsLockedOn(play, &this->actor)) { - baseRange = 150.0f; + extraRadius = 150.0f; } - - if (this->actor.xzDistToPlayer <= (60.0f + baseRange)) { - Math_SmoothStepToF(&this->runSpeed, -4.0f, 1.0f, 1.5f, 0.0f); - } else if ((80.0f + baseRange) < this->actor.xzDistToPlayer) { - Math_SmoothStepToF(&this->runSpeed, 4.0f, 1.0f, 1.5f, 0.0f); + if (this->actor.xzDistToPlayer <= (60.0f + extraRadius)) { + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, -4.0f, 1.0f, 1.5f, 0.0f); + } else if (this->actor.xzDistToPlayer > (80.0f + extraRadius)) { + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, 4.0f, 1.0f, 1.5f, 0.0f); } else { - Math_SmoothStepToF(&this->runSpeed, 0.0f, 1.0f, 6.65f, 0.0f); + Math_SmoothStepToF(&this->circlePlayerExtraSpeed, 0.0f, 1.0f, 6.65f, 0.0f); } - - if (this->runSpeed != 0.0f) { - this->actor.world.pos.x += Math_SinS(this->actor.shape.rot.y) * this->runSpeed; - this->actor.world.pos.z += Math_CosS(this->actor.shape.rot.y) * this->runSpeed; + if (this->circlePlayerExtraSpeed != 0.0f) { + this->actor.world.pos.x += Math_SinS(this->actor.shape.rot.y) * this->circlePlayerExtraSpeed; + this->actor.world.pos.z += Math_CosS(this->actor.shape.rot.y) * this->circlePlayerExtraSpeed; } - - if (ABS(this->runSpeed) < ABS(this->actor.speed)) { + if (ABS(this->circlePlayerExtraSpeed) < ABS(this->actor.speed)) { this->skelAnime.playSpeed = this->actor.speed * 0.175f; } else { - this->skelAnime.playSpeed = this->runSpeed * 0.175f; + this->skelAnime.playSpeed = this->circlePlayerExtraSpeed * 0.175f; } this->skelAnime.playSpeed = CLAMP(this->skelAnime.playSpeed, -3.0f, 3.0f); - prevFrame = (s32)this->skelAnime.curFrame; SkelAnime_Update(&this->skelAnime); beforeCurFrame = (s32)(this->skelAnime.curFrame - ABS(this->skelAnime.playSpeed)); - absPlaySpeed = (s32)(f32)ABS(this->skelAnime.playSpeed); - - if (!EnWf_ChangeAction(play, this, false)) { - this->actionTimer--; - - if (this->actionTimer == 0) { - angleDiff1 = player->actor.shape.rot.y - this->actor.yawTowardsPlayer; - angleDiff1 = ABS(angleDiff1); - - if (angleDiff1 >= 0x3A98) { - EnWf_SetupWait(this); - this->actionTimer = (Rand_ZeroOne() * 3.0f) + 1.0f; + absPlaySpeed = new_var = ABS(this->skelAnime.playSpeed); + if (!EnWf_PickAction(play, this, false)) { + this->timer--; + if (this->timer == 0) { + behindPlayerYawAbs = player->actor.shape.rot.y - this->actor.yawTowardsPlayer; + //! @bug behindPlayerYawAbs is a s16, so it can't hold 0x8000, the absolute value of -0x8000. + //! So -0x8000 just "stays" -0x8000, causing the behindPlayerYawAbs check below to wrongfully not pass. + //! behindPlayerYawAbs is typically exactly -0x8000 when locking on the actor. + //! Note the same problem of storing absolute angles into s16 variables happens elsewhere in this file, but + //! problematic -0x8000 happens rarely in those other spots. + if (behindPlayerYawAbs < 0) { + behindPlayerYawAbs *= -1; + } + if (behindPlayerYawAbs >= 0x3A98) { + EnWf_SetupIdle(this); + this->timer = (Rand_ZeroOne() * 3.0f) + 1.0f; } else { - Player* player2 = GET_PLAYER(play); - s16 angleDiff2 = player2->actor.shape.rot.y - this->actor.yawTowardsPlayer; - + player2 = GET_PLAYER(play); + behindPlayerYaw = player2->actor.shape.rot.y - this->actor.yawTowardsPlayer; this->actor.world.rot.y = this->actor.shape.rot.y; - if ((this->actor.xzDistToPlayer <= 80.0f) && !Actor_OtherIsLockedOn(play, &this->actor) && - (((play->gameplayFrames % 4) == 0) || (ABS(angleDiff2) < 0x38E0))) { - EnWf_SetupSlash(this); + (((play->gameplayFrames & 3) == 0) || (ABS(behindPlayerYaw) < 0x38E0))) { + EnWf_SetupAttack(this); } else { - EnWf_SetupRunAtPlayer(this, play); + EnWf_SetupRunToAttack(this, play); } } } - - if ((prevFrame != (s32)this->skelAnime.curFrame) && (beforeCurFrame <= 0) && ((absPlaySpeed + prevFrame) > 0)) { + if ((prevFrame != (s32)this->skelAnime.curFrame) && (beforeCurFrame <= 0) && + (((s32)absPlaySpeed + prevFrame) > 0)) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_WALK); Actor_SpawnFloorDustRing(play, &this->actor, &this->actor.world.pos, 20.0f, 3, 3.0f, 50, 50, true); } - - if ((play->gameplayFrames & 95) == 0) { + if ((play->gameplayFrames & 0x5F) == 0) { Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_CRY); } } } void EnWf_SetupDie(EnWf* this) { - Animation_MorphToPlayOnce(&this->skelAnime, &gWolfosRearingUpFallingOverAnim, -4.0f); + Animation_MorphToPlayOnce(&this->skelAnime, &gWolfosHowlAnim, -4.0f); this->actor.world.rot.y = this->actor.yawTowardsPlayer; - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { this->unk_300 = false; this->actor.speed = -6.0f; } else { this->unk_300 = true; } - - this->action = WOLFOS_ACTION_DIE; + this->action = ENWF_ACTION_DIE; this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; - this->actionTimer = this->skelAnime.animLength; + this->timer = this->skelAnime.animLength; Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_DEAD); EnWf_SetupAction(this, EnWf_Die); } @@ -1222,98 +1217,85 @@ void EnWf_Die(EnWf* this, PlayState* play) { if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND_TOUCH) { this->actor.speed = 0.0f; } - if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { Math_SmoothStepToF(&this->actor.speed, 0.0f, 1.0f, 0.5f, 0.0f); this->unk_300 = false; } - if (SkelAnime_Update(&this->skelAnime)) { Item_DropCollectibleRandom(play, &this->actor, &this->actor.world.pos, COLLECTIBLE_DROP_RANDOM_PARAMS(COLLECTIBLE_DROP_TABLE_13, false)); - if (this->switchFlag != 0xFF) { Flags_SetSwitch(play, this->switchFlag); } - Actor_Kill(&this->actor); } else { s32 i; Vec3f pos; - Vec3f velAndAccel = { 0.0f, 0.5f, 0.0f }; - - this->actionTimer--; - - for (i = ((s32)this->skelAnime.animLength - this->actionTimer) >> 1; i >= 0; i--) { - pos.x = Rand_CenteredFloat(60.0f) + this->actor.world.pos.x; - pos.z = Rand_CenteredFloat(60.0f) + this->actor.world.pos.z; - pos.y = Rand_CenteredFloat(50.0f) + (this->actor.world.pos.y + 20.0f); - EffectSsDeadDb_Spawn(play, &pos, &velAndAccel, &velAndAccel, 100, 0, 255, 255, 255, 255, 0, 0, 255, 1, 9, - true); + Vec3f velAccel; + + velAccel = D_80B37AD0; + this->timer--; + for (i = ((s32)this->skelAnime.animLength - this->timer) >> 1; i >= 0; i--) { + pos.x = this->actor.world.pos.x + Rand_CenteredFloat(60.0f); + pos.z = this->actor.world.pos.z + Rand_CenteredFloat(60.0f); + pos.y = this->actor.world.pos.y + 20.0f + Rand_CenteredFloat(50.0f); + EffectSsDeadDb_Spawn(play, &pos, &velAccel, &velAccel, 100, 0, 255, 255, 255, 255, 0, 0, 255, 1, 9, 1); } } } -void func_80B36F40(EnWf* this, PlayState* play) { - if ((this->action == WOLFOS_ACTION_WAIT) && (this->unk_2E2 != 0)) { - this->unk_4D4.y = Math_SinS(this->unk_2E2 * 4200) * 8920.0f; - } else if (this->action != WOLFOS_ACTION_STUNNED) { - if (this->action != WOLFOS_ACTION_SLASH) { - Math_SmoothStepToS(&this->unk_4D4.y, this->actor.yawTowardsPlayer - this->actor.shape.rot.y, 1, 1500, 0); - this->unk_4D4.y = CLAMP(this->unk_4D4.y, -0x3127, 0x3127); +void EnWf_UpdateHeadRot(EnWf* this, PlayState* play) { + if ((this->action == ENWF_ACTION_IDLE) && (this->idleTimer != 0)) { + this->headRot = Math_SinS(this->idleTimer * 0x1068) * 8920.0f; + } else if (this->action != ENWF_ACTION_STUNNED) { + if (this->action != ENWF_ACTION_ATTACK) { + Math_SmoothStepToS(&this->headRot, this->actor.yawTowardsPlayer - this->actor.shape.rot.y, 1, 0x5DC, 0); + this->headRot = CLAMP(this->headRot, -0x3127, 0x3127); } else { - this->unk_4D4.y = 0; + this->headRot = 0; } } } -void EnWf_UpdateDamage(EnWf* this, PlayState* play) { - if (this->colliderJntSph.base.acFlags & AC_BOUNCED) { - this->colliderJntSph.base.acFlags &= ~(AC_HIT | AC_BOUNCED); - this->bodyColliderCylinder.base.acFlags &= ~AC_HIT; - this->tailColliderCylinder.base.acFlags &= ~AC_HIT; - } else if ((this->bodyColliderCylinder.base.acFlags & AC_HIT) || - (this->tailColliderCylinder.base.acFlags & AC_HIT)) { - if (this->action >= WOLFOS_ACTION_WAIT) { - s16 yawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; - - if ((!(this->bodyColliderCylinder.base.acFlags & AC_HIT) && - (this->tailColliderCylinder.base.acFlags & AC_HIT)) || - (ABS(yawDiff) > 19000)) { - this->actor.colChkInfo.damage *= 4; - } - - this->bodyColliderCylinder.base.acFlags &= ~AC_HIT; - this->tailColliderCylinder.base.acFlags &= ~AC_HIT; - - if (this->actor.colChkInfo.damageReaction != ENWF_DMG_REACT_ICE_MAGIC) { - this->damageReaction = this->actor.colChkInfo.damageReaction; - Actor_SetDropFlag(&this->actor, &this->bodyColliderCylinder.elem, true); +void EnWf_CheckCollide(EnWf* this, PlayState* play) { + s16 relYawTowardsPlayer; + + if (this->attackAndBlockCollider.base.acFlags & AC_BOUNCED) { + this->attackAndBlockCollider.base.acFlags &= ~(AC_HIT | AC_BOUNCED); + this->bodyCollider.base.acFlags &= ~AC_HIT; + this->tailCollider.base.acFlags &= ~AC_HIT; + } else if (((this->bodyCollider.base.acFlags & AC_HIT) || (this->tailCollider.base.acFlags & AC_HIT)) && + (this->action >= ENWF_ACTION_IDLE)) { + relYawTowardsPlayer = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; + if (!((this->bodyCollider.base.acFlags & AC_HIT) || !(this->tailCollider.base.acFlags & AC_HIT)) || + (ABS(relYawTowardsPlayer) > 0x4A38)) { + this->actor.colChkInfo.damage *= 4; + } + this->bodyCollider.base.acFlags &= ~AC_HIT; + this->tailCollider.base.acFlags &= ~AC_HIT; + if (this->actor.colChkInfo.damageReaction != ENWF_DMG_REACT_6) { + this->lastDamageReaction = this->actor.colChkInfo.damageReaction; + Actor_SetDropFlag(&this->actor, &this->bodyCollider.elem, true); #if OOT_VERSION >= PAL_1_0 - this->slashStatus = 0; + this->attackState = 0; #endif - - if ((this->actor.colChkInfo.damageReaction == ENWF_DMG_REACT_STUN) || - (this->actor.colChkInfo.damageReaction == ENWF_DMG_REACT_UNDEF)) { - if (this->action != WOLFOS_ACTION_STUNNED) { - Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_BLUE, 120, COLORFILTER_BUFFLAG_OPA, - 80); - Actor_ApplyDamage(&this->actor); - EnWf_SetupStunned(this); - } - } else { // LIGHT_MAGIC, FIRE, NONE - Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 8); - - if (this->damageReaction == ENWF_DMG_REACT_FIRE) { - this->fireTimer = 40; - } - - if (Actor_ApplyDamage(&this->actor) == 0) { - EnWf_SetupDie(this); - Enemy_StartFinishingBlow(play, &this->actor); - } else { - EnWf_SetupDamaged(this); - } + if ((this->actor.colChkInfo.damageReaction == ENWF_DMG_REACT_STUN) || + (this->actor.colChkInfo.damageReaction == ENWF_DMG_REACT_F)) { + if (this->action != ENWF_ACTION_STUNNED) { + Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_BLUE, 120, COLORFILTER_BUFFLAG_OPA, 80); + Actor_ApplyDamage(&this->actor); + EnWf_SetupStunned(this); + } + } else { + Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 8); + if (this->lastDamageReaction == ENWF_DMG_REACT_FIRE) { + this->onFireTimer = 40; + } + if (Actor_ApplyDamage(&this->actor) == 0) { + EnWf_SetupDie(this); + Enemy_StartFinishingBlow(play, &this->actor); + } else { + EnWf_SetupDamaged(this); } } } @@ -1321,55 +1303,46 @@ void EnWf_UpdateDamage(EnWf* this, PlayState* play) { } void EnWf_Update(Actor* thisx, PlayState* play) { - s32 pad; EnWf* this = (EnWf*)thisx; + s32 pad; - EnWf_UpdateDamage(this, play); - - if (this->actor.colChkInfo.damageReaction != ENWF_DMG_REACT_ICE_MAGIC) { + EnWf_CheckCollide(this, play); + if (this->actor.colChkInfo.damageReaction != ENWF_DMG_REACT_6) { Actor_MoveXZGravity(&this->actor); Actor_UpdateBgCheckInfo(play, &this->actor, 32.0f, 30.0f, 60.0f, UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2 | UPDBGCHECKINFO_FLAG_3 | UPDBGCHECKINFO_FLAG_4); this->actionFunc(this, play); - func_80B36F40(this, play); + EnWf_UpdateHeadRot(this, play); } - if (this->actor.bgCheckFlags & (BGCHECKFLAG_GROUND | BGCHECKFLAG_GROUND_TOUCH)) { func_800359B8(&this->actor, this->actor.shape.rot.y, &this->actor.shape.rot); } else { - Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 1000, 0); - Math_SmoothStepToS(&this->actor.shape.rot.z, 0, 1, 1000, 0); + Math_SmoothStepToS(&this->actor.shape.rot.x, 0, 1, 0x3E8, 0); + Math_SmoothStepToS(&this->actor.shape.rot.z, 0, 1, 0x3E8, 0); } - - CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderJntSph.base); - - if (this->action >= WOLFOS_ACTION_WAIT) { - if ((this->actor.colorFilterTimer == 0) || !(this->actor.colorFilterParams & 0x4000)) { - Collider_UpdateCylinder(&this->actor, &this->bodyColliderCylinder); - CollisionCheck_SetAC(play, &play->colChkCtx, &this->tailColliderCylinder.base); - CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyColliderCylinder.base); - } + CollisionCheck_SetOC(play, &play->colChkCtx, &this->attackAndBlockCollider.base); + if ((this->action >= ENWF_ACTION_IDLE) && + ((this->actor.colorFilterTimer == 0) || !(this->actor.colorFilterParams & 0x4000))) { + Collider_UpdateCylinder(&this->actor, &this->bodyCollider); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->tailCollider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyCollider.base); } - - if (this->action == WOLFOS_ACTION_BLOCKING) { - CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderJntSph.base); + if (this->action == ENWF_ACTION_BLOCK) { + CollisionCheck_SetAC(play, &play->colChkCtx, &this->attackAndBlockCollider.base); } - - if (this->slashStatus > 0) { - if (!(this->colliderJntSph.base.atFlags & AT_BOUNCED)) { - CollisionCheck_SetAT(play, &play->colChkCtx, &this->colliderJntSph.base); + if (this->attackState > 0) { + if (!(this->attackAndBlockCollider.base.atFlags & AT_BOUNCED)) { + CollisionCheck_SetAT(play, &play->colChkCtx, &this->attackAndBlockCollider.base); } else { - EnWf_SetupRecoilFromBlockedSlash(this); + EnWf_SetupAttackBouncedOff(this); } } - this->actor.focus.pos = this->actor.world.pos; this->actor.focus.pos.y += 25.0f; - if (this->eyeIndex == 0) { - if ((Rand_ZeroOne() < 0.2f) && ((play->gameplayFrames % 4) == 0) && (this->actor.colorFilterTimer == 0)) { - this->eyeIndex++; + if ((Rand_ZeroOne() < 0.2f) && ((play->gameplayFrames & 3) == 0) && (this->actor.colorFilterTimer == 0)) { + this->eyeIndex += 1; } } else { this->eyeIndex = (this->eyeIndex + 1) & 3; @@ -1377,73 +1350,64 @@ void EnWf_Update(Actor* thisx, PlayState* play) { } s32 EnWf_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) { - EnWf* this = (EnWf*)thisx; + EnWf* this = thisx; if ((limbIndex == WOLFOS_LIMB_HEAD) || (limbIndex == WOLFOS_LIMB_EYES)) { - rot->y -= this->unk_4D4.y; + rot->y -= this->headRot; } - - return false; + return 0; } void EnWf_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { - static Vec3f colliderVec = { 1200.0f, 0.0f, 0.0f }; - static Vec3f bodyPartVec = { 0.0f, 0.0f, 0.0f }; - EnWf* this = (EnWf*)thisx; - s32 bodyPartIndex = -1; - - Collider_UpdateSpheres(limbIndex, &this->colliderJntSph); + EnWf* this = thisx; + s32 bodyPartIndex; + Vec3f tailColliderPos; + Vec3f bodyPartPos; + bodyPartIndex = -1; + Collider_UpdateSpheres(limbIndex, &this->attackAndBlockCollider); if (limbIndex == WOLFOS_LIMB_TAIL) { - Vec3f colliderPos; - - bodyPartIndex = -1; - Matrix_MultVec3f(&colliderVec, &colliderPos); - this->tailColliderCylinder.dim.pos.x = colliderPos.x; - this->tailColliderCylinder.dim.pos.y = colliderPos.y; - this->tailColliderCylinder.dim.pos.z = colliderPos.z; + Matrix_MultVec3f(&D_80B37ADC, &tailColliderPos); + this->tailCollider.dim.pos.x = tailColliderPos.x; + this->tailCollider.dim.pos.y = tailColliderPos.y; + this->tailCollider.dim.pos.z = tailColliderPos.z; } - - if ((this->fireTimer != 0) || ((this->actor.colorFilterTimer != 0) && (this->actor.colorFilterParams & 0x4000))) { + if ((this->onFireTimer != 0) || ((this->actor.colorFilterTimer != 0) && (this->actor.colorFilterParams & 0x4000))) { switch (limbIndex) { case WOLFOS_LIMB_EYES: bodyPartIndex = 0; break; - case WOLFOS_LIMB_FRONT_RIGHT_LOWER_LEG: + case WOLFOS_LIMB_RIGHT_FOREARM: bodyPartIndex = 1; break; - case WOLFOS_LIMB_FRONT_LEFT_LOWER_LEG: + case WOLFOS_LIMB_LEFT_FOREARM: bodyPartIndex = 2; break; - case WOLFOS_LIMB_THORAX: + case WOLFOS_LIMB_TORSO: bodyPartIndex = 3; break; - case WOLFOS_LIMB_ABDOMEN: + case WOLFOS_LIMB_WAIST: bodyPartIndex = 4; break; case WOLFOS_LIMB_TAIL: bodyPartIndex = 5; break; - case WOLFOS_LIMB_BACK_RIGHT_SHIN: + case WOLFOS_LIMB_RIGHT_SHIN: bodyPartIndex = 6; break; case 37: - //! @bug There is no limb with index this large, so bodyPartsPos[7] is uninitialised. Thus a flame will - //! be drawn at 0,0,0 when the Wolfos is on fire. + //! @bug 37 is not a valid limb index bodyPartIndex = 7; break; - case WOLFOS_LIMB_BACK_RIGHT_PASTERN: + case WOLFOS_LIMB_RIGHT_ANKLE: bodyPartIndex = 8; break; - case WOLFOS_LIMB_BACK_LEFT_PAW: + case WOLFOS_LIMB_LEFT_FOOT: bodyPartIndex = 9; break; } - if (bodyPartIndex >= 0) { - Vec3f bodyPartPos; - - Matrix_MultVec3f(&bodyPartVec, &bodyPartPos); + Matrix_MultVec3f(&sZeroVec, &bodyPartPos); this->bodyPartsPos[bodyPartIndex].x = bodyPartPos.x; this->bodyPartsPos[bodyPartIndex].y = bodyPartPos.y; this->bodyPartsPos[bodyPartIndex].z = bodyPartPos.z; @@ -1451,71 +1415,63 @@ void EnWf_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, } } -static void* sWolfosNormalEyeTextures[] = { gWolfosNormalEyeOpenTex, gWolfosNormalEyeHalfTex, gWolfosNormalEyeNarrowTex, - gWolfosNormalEyeHalfTex }; -static void* sWolfosWhiteEyeTextures[] = { gWolfosWhiteEyeOpenTex, gWolfosWhiteEyeHalfTex, gWolfosWhiteEyeNarrowTex, - gWolfosWhiteEyeHalfTex }; - void EnWf_Draw(Actor* thisx, PlayState* play) { EnWf* this = (EnWf*)thisx; OPEN_DISPS(play->state.gfxCtx, "../z_en_wf.c", 2157); - - // This conditional will always evaluate to true, since unk_300 is false whenever action is - // WOLFOS_ACTION_WAIT_TO_APPEAR. - if ((this->action != WOLFOS_ACTION_WAIT_TO_APPEAR) || !this->unk_300) { + if ((this->action != ENWF_ACTION_WAIT_APPEAR) || !this->unk_300) { Gfx_SetupDL_25Opa(play->state.gfxCtx); - - if (this->actor.params == WOLFOS_NORMAL) { - gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sWolfosNormalEyeTextures[this->eyeIndex])); + if (this->actor.params == 0) { + gSPSegment(POLY_OPA_DISP++, 8, SEGMENTED_TO_VIRTUAL(sWolfosGrayEyeTextures[this->eyeIndex])); } else { - gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sWolfosWhiteEyeTextures[this->eyeIndex])); + gSPSegment(POLY_OPA_DISP++, 8, SEGMENTED_TO_VIRTUAL(sWolfosWhiteEyeTextures[this->eyeIndex])); } - SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, - EnWf_OverrideLimbDraw, EnWf_PostLimbDraw, &this->actor); - - if (this->fireTimer != 0) { + EnWf_OverrideLimbDraw, EnWf_PostLimbDraw, this); + if (this->onFireTimer != 0) { this->actor.colorFilterTimer++; if (1) {} - this->fireTimer--; + this->onFireTimer -= 1; + if ((this->onFireTimer & 3) == 0) { + s32 bodyPartIndex = this->onFireTimer >> 2; - if ((this->fireTimer % 4) == 0) { - s32 fireIndex = this->fireTimer >> 2; - - EffectSsEnFire_SpawnVec3s(play, &this->actor, &this->bodyPartsPos[fireIndex], 75, 0, 0, fireIndex); + EffectSsEnFire_SpawnVec3s(play, &this->actor, &this->bodyPartsPos[bodyPartIndex], 75, 0, 0, + bodyPartIndex); } } } - CLOSE_DISPS(play->state.gfxCtx, "../z_en_wf.c", 2190); } -s32 EnWf_DodgeRanged(PlayState* play, EnWf* this) { - Actor* actor = Actor_GetProjectileActor(play, &this->actor, 600.0f); - - if (actor != NULL) { - s16 angleToFacing; - s16 pad; - f32 dist; - - angleToFacing = Actor_WorldYawTowardActor(&this->actor, actor) - this->actor.shape.rot.y; - this->actor.world.rot.y = (u16)this->actor.shape.rot.y & 0xFFFF; - dist = Actor_WorldDistXYZToPoint(&this->actor, &actor->world.pos); - - if ((ABS(angleToFacing) < 0x2EE0) && (sqrt(dist) < 400.0)) { - EnWf_SetupBlocking(this); +/** + * React to projectiles by picking an adequate action. + * @return true if an action was picked + */ +s32 EnWf_ReactToProjectile(PlayState* play, EnWf* this) { + Actor* projectile; + s16 relYawTowardsProjectile; + f32 projectileDist; + + projectile = Actor_GetProjectileActor(play, &this->actor, 600.0f); + if (projectile != NULL) { + relYawTowardsProjectile = Actor_WorldYawTowardActor(&this->actor, projectile) - this->actor.shape.rot.y; + this->actor.world.rot.y = (u16)(s16)(this->actor.shape.rot.y + 0); + projectileDist = Actor_WorldDistXYZToPoint(&this->actor, &projectile->world.pos); + //! @bug Using sqrt on a non-squared distance + if ((ABS(relYawTowardsProjectile) < 0x2EE0) && (sqrt((f64)projectileDist) < 400.0)) { + EnWf_SetupBlock(this); } else { this->actor.world.rot.y = this->actor.shape.rot.y + 0x3FFF; - if ((ABS(angleToFacing) < 0x2000) || (ABS(angleToFacing) > 0x5FFF)) { - EnWf_SetupSidestep(this, play); + if ((ABS(relYawTowardsProjectile) < 0x2000) || (ABS(relYawTowardsProjectile) >= 0x6000)) { + EnWf_SetupShortCirclePlayer(this, play); this->actor.speed *= 2.0f; - } else if (ABS(angleToFacing) < 0x5FFF) { - EnWf_SetupBackflipAway(this); + } else if (ABS(relYawTowardsProjectile) < 0x5FFF) { + EnWf_SetupBackflipBackward(this); } } + //! @bug If ABS(relYawTowardsProjectile) == 0x5FFF the function returns true + //! even though no action has been chosen return true; } - return false; } diff --git a/src/overlays/actors/ovl_En_Wf/z_en_wf.h b/src/overlays/actors/ovl_En_Wf/z_en_wf.h index cc69df8ad49..010f2025c35 100644 --- a/src/overlays/actors/ovl_En_Wf/z_en_wf.h +++ b/src/overlays/actors/ovl_En_Wf/z_en_wf.h @@ -4,88 +4,44 @@ #include "ultra64.h" #include "actor.h" -struct EnWf; - -typedef void (*EnWfActionFunc)(struct EnWf*, struct PlayState*); - -typedef enum EnWfLimb { - /* 0 */ WOLFOS_LIMB_NONE, - /* 1 */ WOLFOS_LIMB_ROOT, - /* 2 */ WOLFOS_LIMB_BACK_LEFT_THIGH, - /* 3 */ WOLFOS_LIMB_BACK_LEFT_SHIN, - /* 4 */ WOLFOS_LIMB_BACK_LEFT_PASTERN, - /* 5 */ WOLFOS_LIMB_BACK_LEFT_PAW, - /* 6 */ WOLFOS_LIMB_TAIL, - /* 7 */ WOLFOS_LIMB_ABDOMEN, - /* 8 */ WOLFOS_LIMB_BACK_RIGHT_THIGH, - /* 9 */ WOLFOS_LIMB_BACK_RIGHT_SHIN, - /* 10 */ WOLFOS_LIMB_BACK_RIGHT_PASTERN, - /* 11 */ WOLFOS_LIMB_BACK_RIGHT_PAW, - /* 12 */ WOLFOS_LIMB_THORAX, - /* 13 */ WOLFOS_LIMB_FRONT_RIGHT_UPPER_LEG, - /* 14 */ WOLFOS_LIMB_FRONT_RIGHT_LOWER_LEG, - /* 15 */ WOLFOS_LIMB_FRONT_RIGHT_CLAW, - /* 16 */ WOLFOS_LIMB_HEAD_ROOT, - /* 17 */ WOLFOS_LIMB_HEAD, - /* 18 */ WOLFOS_LIMB_EYES, - /* 19 */ WOLFOS_LIMB_FRONT_LEFT_UPPER_LEG, - /* 20 */ WOLFOS_LIMB_FRONT_LEFT_LOWER_LEG, - /* 21 */ WOLFOS_LIMB_FRONT_LEFT_CLAW, - /* 22 */ WOLFOS_LIMB_MAX -} EnWfLimb; +#include "assets/objects/object_wf/object_wf.h" -typedef enum EnWfAction { - /* 0 */ WOLFOS_ACTION_WAIT_TO_APPEAR, - /* 2 */ WOLFOS_ACTION_DIE = 2, - /* 3 */ WOLFOS_ACTION_DAMAGED, - /* 4 */ WOLFOS_ACTION_TURN_TOWARDS_PLAYER, - /* 5 */ WOLFOS_ACTION_BACKFLIP_AWAY, - /* 6 */ WOLFOS_ACTION_WAIT, - /* 7 */ WOLFOS_ACTION_BLOCKING, - /* 8 */ WOLFOS_ACTION_SLASH, - /* 9 */ WOLFOS_ACTION_RUN_AT_PLAYER, - /* 10 */ WOLFOS_ACTION_SEARCH_FOR_PLAYER, - /* 11 */ WOLFOS_ACTION_RUN_AROUND_PLAYER, - /* 12 */ WOLFOS_ACTION_RECOIL_FROM_BLOCKED_SLASH, - /* 14 */ WOLFOS_ACTION_SIDESTEP = 14, - /* 15 */ WOLFOS_ACTION_STUNNED -} EnWfAction; +struct EnWf; typedef struct EnWf { - /* 0x0000 */ Actor actor; - /* 0x014C */ Vec3s bodyPartsPos[10]; - /* 0x0188 */ SkelAnime skelAnime; - /* 0x01CC */ Vec3s jointTable[WOLFOS_LIMB_MAX]; - /* 0x0250 */ Vec3s morphTable[WOLFOS_LIMB_MAX]; - /* 0x02D4 */ s32 action; // Used instead of checking the actionFunc directly (but also in range comparisons) - /* 0x02D8 */ char unk_2D8[4]; // Unused - /* 0x02DC */ EnWfActionFunc actionFunc; - /* 0x02E0 */ s16 unk_2E0; // Used, but has no effect - /* 0x02E2 */ s16 unk_2E2; - /* 0x02E4 */ s16 fireTimer; - /* 0x02E6 */ u8 damageReaction; - /* 0x02E8 */ s32 actionTimer; // Used to make an action last for a certain amount of time - /* 0x02EC */ f32 runSpeed; - /* 0x02F0 */ char unk_2F0[4]; - /* 0x02F4 */ f32 unk_2F4; // Set and not used - /* 0x02F8 */ s16 slashStatus; // Whether to slash again or not, and whether to cry - /* 0x02FA */ s16 unk_2FA; // Set and not used - /* 0x02FC */ s16 switchFlag; - /* 0x02FE */ s16 runAngle; - /* 0x0300 */ s16 unk_300; // Set, but ineffectual (see comment in Draw) - /* 0x0302 */ u8 eyeIndex; - /* 0x0304 */ ColliderJntSph colliderJntSph; - /* 0x0324 */ ColliderJntSphElement colliderJntSphElements[4]; - /* 0x0424 */ ColliderCylinder bodyColliderCylinder; - /* 0x0470 */ ColliderCylinder tailColliderCylinder; - /* 0x04BC */ Vec3f unk_4BC; - /* 0x04C8 */ Vec3f unk_4C8; - /* 0x04D4 */ Vec3s unk_4D4; -} EnWf; // size = 0x04DC - -typedef enum EnWfType { - /* 0 */ WOLFOS_NORMAL, - /* 1 */ WOLFOS_WHITE -} EnWfType; + /* 0x000 */ Actor actor; + /* 0x14C */ Vec3s bodyPartsPos[10]; + /* 0x188 */ SkelAnime skelAnime; + /* 0x1CC */ Vec3s jointTable[WOLFOS_LIMB_MAX]; + /* 0x250 */ Vec3s morphTable[WOLFOS_LIMB_MAX]; + /* 0x2D4 */ s32 action; + /* 0x2D8 */ char pad_2D8[4]; + /* 0x2DC */ void (*actionFunc)(struct EnWf*, struct PlayState*); + /* 0x2E0 */ s16 unk_2E0; + /* 0x2E2 */ s16 idleTimer; + /* 0x2E4 */ s16 onFireTimer; + /* 0x2E6 */ u8 lastDamageReaction; + /* 0x2E7 */ char pad_2E7[1]; + /* 0x2E8 */ s32 timer; + /* 0x2EC */ f32 circlePlayerExtraSpeed; + /* 0x2F0 */ char pad_2F0[4]; + /* 0x2F4 */ f32 unk_2F4; + /* 0x2F8 */ s16 attackState; + /* 0x2FA */ s16 unk_2FA; + /* 0x2FC */ s16 switchFlag; + /* 0x2FE */ s16 circlePlayerDirection; + /* 0x300 */ s16 unk_300; + /* 0x302 */ u8 eyeIndex; + /* 0x303 */ char pad_303[1]; + /* 0x304 */ ColliderJntSph attackAndBlockCollider; + /* 0x324 */ ColliderJntSphElement attackAndBlockColliderElements[4]; + /* 0x424 */ ColliderCylinder bodyCollider; + /* 0x470 */ ColliderCylinder tailCollider; + /* 0x4BC */ Vec3f unk_4BC; + /* 0x4C8 */ Vec3f unk_4C8; + /* 0x4D4 */ char pad_4D4[2]; + /* 0x4D6 */ s16 headRot; + /* 0x4D8 */ char pad_4D8[4]; +} EnWf; // size = 0x4DC #endif