/* * File: z_en_heishi3.c * Overlay: ovl_En_Heishi3 * Description: Hyrule Castle Guard */ #include "z_en_heishi3.h" #include "objects/object_sd/object_sd.h" #include "vt.h" #define FLAGS 0 void EnHeishi3_Init(Actor* thisx, GlobalContext* globalCtx); void EnHeishi3_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnHeishi3_Update(Actor* thisx, GlobalContext* globalCtx); void EnHeishi3_Draw(Actor* thisx, GlobalContext* globalCtx); void EnHeishi3_SetupGuardType(EnHeishi3* this, GlobalContext* globalCtx); void EnHeishi3_StandSentinelInGrounds(EnHeishi3* this, GlobalContext* globalCtx); void EnHeishi3_StandSentinelInCastle(EnHeishi3* this, GlobalContext* globalCtx); void EnHeishi3_CatchStart(EnHeishi3* this, GlobalContext* globalCtx); void EnHeishi3_ResetAnimationToIdle(EnHeishi3* this, GlobalContext* globalCtx); void func_80A55D00(EnHeishi3* this, GlobalContext* globalCtx); void func_80A55BD4(EnHeishi3* this, GlobalContext* globalCtx); static s16 sPlayerCaught = 0; const ActorInit En_Heishi3_InitVars = { ACTOR_EN_HEISHI3, ACTORCAT_NPC, FLAGS, OBJECT_SD, sizeof(EnHeishi3), (ActorFunc)EnHeishi3_Init, (ActorFunc)EnHeishi3_Destroy, (ActorFunc)EnHeishi3_Update, (ActorFunc)EnHeishi3_Draw, NULL, }; static ColliderCylinderInit sCylinderInit = { { COLTYPE_NONE, AT_NONE, AC_NONE, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_2, COLSHAPE_CYLINDER, }, { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, TOUCH_NONE, BUMP_NONE, OCELEM_ON, }, { 15, 70, 0, { 0, 0, 0 } }, }; void EnHeishi3_Init(Actor* thisx, GlobalContext* globalCtx) { EnHeishi3* this = (EnHeishi3*)thisx; sPlayerCaught = 0; if (this->actor.params <= 0) { this->unk_278 = 0; } else { this->unk_278 = 1; if (this->actor.world.pos.x < -290.0f) { this->unk_278 = 2; } } Actor_SetScale(&this->actor, 0.01f); ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f); SkelAnime_Init(globalCtx, &this->skelAnime, &gEnHeishiSkel, &gEnHeishiIdleAnim, this->jointTable, this->morphTable, 17); this->actor.colChkInfo.mass = MASS_IMMOVABLE; this->actor.targetMode = 6; Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); // "Castle Gate Soldier - Power Up" osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 城門兵パワーアップ ☆☆☆☆☆ \n" VT_RST); this->actor.gravity = -3.0f; this->actor.focus.pos = this->actor.world.pos; this->actionFunc = EnHeishi3_SetupGuardType; } void EnHeishi3_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnHeishi3* this = (EnHeishi3*)thisx; Collider_DestroyCylinder(globalCtx, &this->collider); } void EnHeishi3_SetupGuardType(EnHeishi3* this, GlobalContext* globalCtx) { f32 frameCount = Animation_GetLastFrame(&gEnHeishiIdleAnim); Animation_Change(&this->skelAnime, &gEnHeishiIdleAnim, 1.0f, 0.0f, (s16)frameCount, ANIMMODE_LOOP, -10.0f); if (this->unk_278 == 0) { this->actionFunc = EnHeishi3_StandSentinelInGrounds; } else { this->actionFunc = EnHeishi3_StandSentinelInCastle; } } /** * Handles the guards standing on Hyrule Castle Grounds. **/ void EnHeishi3_StandSentinelInGrounds(EnHeishi3* this, GlobalContext* globalCtx) { Player* player; s16 yawDiff; s16 yawDiffNew; f32 sightRange; player = GET_PLAYER(globalCtx); SkelAnime_Update(&this->skelAnime); yawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; yawDiffNew = ABS(yawDiff); if (yawDiffNew < 0x4300) { if (IS_DAY) { sightRange = 250.0f; } else { sightRange = 200.0f; } } else { if (IS_DAY) { sightRange = 150.0f; } else { sightRange = 100.0f; } } if ((this->actor.xzDistToPlayer < sightRange) && (fabsf(player->actor.world.pos.y - this->actor.world.pos.y) < 100.0f) && (sPlayerCaught == 0)) { sPlayerCaught = 1; Message_StartTextbox(globalCtx, 0x702D, &this->actor); func_80078884(NA_SE_SY_FOUND); osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 発見! ☆☆☆☆☆ \n" VT_RST); // "Discovered!" func_8002DF54(globalCtx, &this->actor, 1); this->actionFunc = EnHeishi3_CatchStart; } } /** * Handles the guards standing in front of Hyrule Castle. **/ void EnHeishi3_StandSentinelInCastle(EnHeishi3* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); SkelAnime_Update(&this->skelAnime); if ((player->actor.world.pos.x < -190.0f) && (player->actor.world.pos.x > -380.0f) && (fabsf(player->actor.world.pos.y - this->actor.world.pos.y) < 100.0f) && (player->actor.world.pos.z < 1020.0f) && (player->actor.world.pos.z > 700.0f) && (sPlayerCaught == 0)) { if (this->unk_278 == 1) { if ((player->actor.world.pos.x < -290.0f)) { return; } } else { if (player->actor.world.pos.x > -290.0f) { return; } } sPlayerCaught = 1; Message_StartTextbox(globalCtx, 0x702D, &this->actor); func_80078884(NA_SE_SY_FOUND); osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 発見! ☆☆☆☆☆ \n" VT_RST); // "Discovered!" func_8002DF54(globalCtx, &this->actor, 1); this->actionFunc = EnHeishi3_CatchStart; } } void EnHeishi3_CatchStart(EnHeishi3* this, GlobalContext* globalCtx) { f32 frameCount = Animation_GetLastFrame(&gEnHeishiWalkAnim); Animation_Change(&this->skelAnime, &gEnHeishiWalkAnim, 1.0f, 0.0f, (s16)frameCount, ANIMMODE_LOOP, -10.0f); this->caughtTimer = 20; this->actionFunc = func_80A55BD4; this->actor.speedXZ = 2.5f; } void func_80A55BD4(EnHeishi3* this, GlobalContext* globalCtx) { SkelAnime_Update(&this->skelAnime); if (Animation_OnFrame(&this->skelAnime, 1.0f) || Animation_OnFrame(&this->skelAnime, 17.0f)) { Audio_PlayActorSound2(&this->actor, NA_SE_EV_KNIGHT_WALK); } if (this->caughtTimer == 0) { this->actionFunc = EnHeishi3_ResetAnimationToIdle; this->actor.speedXZ = 0.0f; } else { Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 5, 3000, 0); } } void EnHeishi3_ResetAnimationToIdle(EnHeishi3* this, GlobalContext* globalCtx) { f32 frameCount = Animation_GetLastFrame(&gEnHeishiIdleAnim); Animation_Change(&this->skelAnime, &gEnHeishiIdleAnim, 1.0f, 0.0f, (s16)frameCount, ANIMMODE_LOOP, -10.0f); this->actionFunc = func_80A55D00; } // This function initiates the respawn after the player gets caught. void func_80A55D00(EnHeishi3* this, GlobalContext* globalCtx) { SkelAnime_Update(&this->skelAnime); if ((Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(globalCtx) && (this->respawnFlag == 0)) { gSaveContext.eventChkInf[4] |= 0x4000; globalCtx->nextEntranceIndex = 0x47E; // Hyrule Castle from Guard Capture (outside) globalCtx->sceneLoadFlag = 0x14; this->respawnFlag = 1; globalCtx->fadeTransition = 0x2E; gSaveContext.nextTransition = 0x2E; } } void EnHeishi3_Update(Actor* thisx, GlobalContext* globalCtx) { EnHeishi3* this = (EnHeishi3*)thisx; s32 pad; Actor_SetFocus(&this->actor, 60.0f); this->unk_274 += 1; if (this->caughtTimer != 0) { this->caughtTimer -= 1; } this->actionFunc(this, globalCtx); this->actor.shape.rot = this->actor.world.rot; Actor_MoveForward(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 20.0f, 20.0f, 50.0f, 0x1C); Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } s32 EnHeishi3_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) { EnHeishi3* this = (EnHeishi3*)thisx; if (limbIndex == 9) { rot->x += this->unk_26E; } if (limbIndex == 16) { rot->x += this->unk_262; rot->z += this->unk_264; } return false; } void EnHeishi3_Draw(Actor* thisx, GlobalContext* globalCtx) { EnHeishi3* this = (EnHeishi3*)thisx; func_80093D18(globalCtx->state.gfxCtx); SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, EnHeishi3_OverrideLimbDraw, NULL, this); }