/* * File: z_en_po_desert.c * Overlay: ovl_En_Po_Desert * Description: Guide Poe (Haunted Wasteland) */ #include "z_en_po_desert.h" #include "objects/object_po_field/object_po_field.h" #define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_7 | ACTOR_FLAG_12) void EnPoDesert_Init(Actor* thisx, GlobalContext* globalCtx); void EnPoDesert_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnPoDesert_Update(Actor* thisx, GlobalContext* globalCtx); void EnPoDesert_Draw(Actor* thisx, GlobalContext* globalCtx); void EnPoDesert_SetNextPathPoint(EnPoDesert* this, GlobalContext* globalCtx); void EnPoDesert_WaitForPlayer(EnPoDesert* this, GlobalContext* globalCtx); void EnPoDesert_MoveToNextPoint(EnPoDesert* this, GlobalContext* globalCtx); void EnPoDesert_Disappear(EnPoDesert* this, GlobalContext* globalCtx); const ActorInit En_Po_Desert_InitVars = { ACTOR_EN_PO_DESERT, ACTORCAT_BG, FLAGS, OBJECT_PO_FIELD, sizeof(EnPoDesert), (ActorFunc)EnPoDesert_Init, (ActorFunc)EnPoDesert_Destroy, (ActorFunc)EnPoDesert_Update, (ActorFunc)EnPoDesert_Draw, NULL, }; static ColliderCylinderInit sColliderInit = { { COLTYPE_HIT3, AT_NONE, AC_NONE, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0xFFCFFFFF, 0x00, 0x00 }, TOUCH_NONE, BUMP_ON, OCELEM_ON, }, { 25, 50, 20, { 0, 0, 0 } }, }; static InitChainEntry sInitChain[] = { ICHAIN_S8(naviEnemyId, 0x5C, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneForward, 2000, ICHAIN_CONTINUE), ICHAIN_F32(targetArrowOffset, 3200, ICHAIN_STOP), }; void EnPoDesert_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; EnPoDesert* this = (EnPoDesert*)thisx; Actor_ProcessInitChain(&this->actor, sInitChain); SkelAnime_Init(globalCtx, &this->skelAnime, &gPoeFieldSkel, &gPoeFieldFloatAnim, this->jointTable, this->morphTable, 10); Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sColliderInit); this->lightColor.r = 255; this->lightColor.g = 255; this->lightColor.b = 210; this->lightColor.a = 255; this->lightNode = LightContext_InsertLight(globalCtx, &globalCtx->lightCtx, &this->lightInfo); Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, 255, 255, 255, 200); ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 37.0f); this->currentPathPoint = 1; this->actor.params = (this->actor.params >> 8) & 0xFF; this->targetY = this->actor.world.pos.y; EnPoDesert_SetNextPathPoint(this, globalCtx); } void EnPoDesert_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnPoDesert* this = (EnPoDesert*)thisx; LightContext_RemoveLight(globalCtx, &globalCtx->lightCtx, this->lightNode); Collider_DestroyCylinder(globalCtx, &this->collider); } void EnPoDesert_SetNextPathPoint(EnPoDesert* this, GlobalContext* globalCtx) { Path* path = &globalCtx->setupPathList[this->actor.params]; Vec3s* pathPoint; Animation_MorphToLoop(&this->skelAnime, &gPoeFieldDisappearAnim, -6.0f); pathPoint = &((Vec3s*)SEGMENTED_TO_VIRTUAL(path->points))[this->currentPathPoint]; this->actor.home.pos.x = pathPoint->x; this->actor.home.pos.y = pathPoint->y; this->actor.home.pos.z = pathPoint->z; this->initDistToNextPoint = Actor_WorldDistXZToPoint(&this->actor, &this->actor.home.pos); this->initDistToNextPoint = CLAMP_MIN(this->initDistToNextPoint, 1.0f); this->currentPathPoint++; this->yDiff = this->actor.home.pos.y - this->actor.world.pos.y; this->actor.speedXZ = 0.0f; if (path->count == this->currentPathPoint) { this->currentPathPoint = 0; } this->actionFunc = EnPoDesert_WaitForPlayer; } void EnPoDesert_SetupMoveToNextPoint(EnPoDesert* this) { Animation_MorphToLoop(&this->skelAnime, &gPoeFieldFloatAnim, -5.0f); this->actionFunc = EnPoDesert_MoveToNextPoint; } void EnPoDesert_SetupDisappear(EnPoDesert* this) { Animation_MorphToPlayOnce(&this->skelAnime, &gPoeFieldDisappearAnim, -6.0f); this->actionTimer = 16; this->actor.speedXZ = 0.0f; Audio_PlayActorSound2(&this->actor, NA_SE_EN_PO_DISAPPEAR); this->actionFunc = EnPoDesert_Disappear; } void EnPoDesert_UpdateSpeedModifier(EnPoDesert* this) { if (this->speedModifier == 0) { this->speedModifier = 32; } if (this->speedModifier != 0) { this->speedModifier--; } this->actor.world.pos.y = Math_SinS(this->speedModifier * 0x800) * 13.0f + this->targetY; } void EnPoDesert_WaitForPlayer(EnPoDesert* this, GlobalContext* globalCtx) { func_8002F974(&this->actor, NA_SE_EN_PO_FLY - SFX_FLAG); if (this->actor.xzDistToPlayer < 200.0f && (this->currentPathPoint != 2 || globalCtx->actorCtx.unk_03)) { if (this->currentPathPoint == 2) { if (Gameplay_InCsMode(globalCtx)) { this->actor.shape.rot.y += 0x800; return; } Message_StartTextbox(globalCtx, 0x600B, NULL); } EnPoDesert_SetupMoveToNextPoint(this); } else { this->actor.shape.rot.y += 0x800; } } void EnPoDesert_MoveToNextPoint(EnPoDesert* this, GlobalContext* globalCtx) { f32 temp_f20; if (this->actionTimer != 0) { this->actionTimer--; } temp_f20 = sinf(this->actionTimer * (M_PI / 20.0f)) * 5.0f; this->actor.world.pos.x += temp_f20 * Math_CosS(this->actor.shape.rot.y); this->actor.world.pos.z += temp_f20 * Math_SinS(this->actor.shape.rot.y); if (this->actionTimer == 0) { this->actionTimer = 40; } temp_f20 = Actor_WorldDistXZToPoint(&this->actor, &this->actor.home.pos); this->actor.world.rot.y = Actor_WorldYawTowardPoint(&this->actor, &this->actor.home.pos); Math_ApproachS(&this->actor.shape.rot.y, this->actor.world.rot.y + 0x8000, 5, 0x400); this->actor.speedXZ = sinf(this->speedModifier * (M_PI / 32.0f)) * 2.5f + 5.5f; func_8002F974(&this->actor, NA_SE_EN_PO_FLY - SFX_FLAG); this->targetY = this->actor.home.pos.y - ((temp_f20 * this->yDiff) / this->initDistToNextPoint); if (temp_f20 < 40.0f) { if (this->currentPathPoint != 0) { EnPoDesert_SetNextPathPoint(this, globalCtx); } else { EnPoDesert_SetupDisappear(this); } } } void EnPoDesert_Disappear(EnPoDesert* this, GlobalContext* globalCtx) { if (this->actionTimer != 0) { this->actionTimer--; } this->actor.shape.rot.y += 0x2000; this->lightColor.a = this->actionTimer * 15.9375f; this->actor.shape.shadowAlpha = this->lightColor.a; if (this->actionTimer == 0) { Actor_Kill(&this->actor); } } void EnPoDesert_Update(Actor* thisx, GlobalContext* globalCtx) { EnPoDesert* this = (EnPoDesert*)thisx; s32 pad; SkelAnime_Update(&this->skelAnime); this->actionFunc(this, globalCtx); Actor_MoveForward(&this->actor); EnPoDesert_UpdateSpeedModifier(this); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 0.0f, 27.0f, 60.0f, 4); Actor_SetFocus(&this->actor, 42.0f); Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); if (globalCtx->actorCtx.unk_03) { this->actor.flags |= ACTOR_FLAG_0 | ACTOR_FLAG_7; this->actor.shape.shadowDraw = ActorShadow_DrawCircle; } else { this->actor.shape.shadowDraw = NULL; this->actor.flags &= ~(ACTOR_FLAG_0 | ACTOR_FLAG_7); } } s32 EnPoDesert_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx, Gfx** gfxP) { EnPoDesert* this = (EnPoDesert*)thisx; f32 mtxScale; if (this->actionFunc == EnPoDesert_Disappear && limbIndex == 7) { mtxScale = this->actionTimer / 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); } if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) { *dList = NULL; } return false; } void EnPoDesert_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx, Gfx** gfxP) { static Vec3f baseLightPos = { 0.0f, 1400.0f, 0.0f }; EnPoDesert* this = (EnPoDesert*)thisx; f32 rand; Color_RGBA8 color; Vec3f lightPos; if (limbIndex == 7) { Matrix_MultVec3f(&baseLightPos, &lightPos); rand = Rand_ZeroOne(); color.r = (s16)(rand * 30.0f) + 225; color.g = (s16)(rand * 100.0f) + 155; color.b = (s16)(rand * 160.0f) + 95; if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_7)) { gDPPipeSync((*gfxP)++); gDPSetEnvColor((*gfxP)++, color.r, color.g, color.b, 255); gSPMatrix((*gfxP)++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList((*gfxP)++, gPoeFieldLanternDL); gSPDisplayList((*gfxP)++, gPoeFieldLanternTopDL); gDPPipeSync((*gfxP)++); gDPSetEnvColor((*gfxP)++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a); } Lights_PointNoGlowSetInfo(&this->lightInfo, lightPos.x, lightPos.y, lightPos.z, color.r, color.g, color.b, 200); } } void EnPoDesert_Draw(Actor* thisx, GlobalContext* globalCtx) { EnPoDesert* this = (EnPoDesert*)thisx; OPEN_DISPS(globalCtx->state.gfxCtx); func_80093D84(globalCtx->state.gfxCtx); gSPSegment(POLY_XLU_DISP++, 0x0A, Gfx_EnvColor(globalCtx->state.gfxCtx, 255, 85, 0, 255)); gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_EnvColor(globalCtx->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a)); if (this->actionFunc == EnPoDesert_Disappear) { gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280); } else { gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280 + 2); } POLY_XLU_DISP = SkelAnime_Draw(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, EnPoDesert_OverrideLimbDraw, EnPoDesert_PostLimbDraw, &this->actor, POLY_XLU_DISP); CLOSE_DISPS(globalCtx->state.gfxCtx); }