/* * File: z_en_ice_hono.c * Overlay: ovl_En_Ice_Hono * Description: The various types of Blue Fire */ #include "z_en_ice_hono.h" #include "objects/gameplay_keep/gameplay_keep.h" #define FLAGS 0 void EnIceHono_Init(Actor* thisx, GlobalContext* globalCtx); void EnIceHono_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnIceHono_Update(Actor* thisx, GlobalContext* globalCtx); void EnIceHono_Draw(Actor* thisx, GlobalContext* globalCtx); void EnIceHono_CapturableFlame(EnIceHono* this, GlobalContext* globalCtx); void EnIceHono_DropFlame(EnIceHono* this, GlobalContext* globalCtx); void EnIceHono_SpreadFlames(EnIceHono* this, GlobalContext* globalCtx); void EnIceHono_SmallFlameMove(EnIceHono* this, GlobalContext* globalCtx); void EnIceHono_SetupActionCapturableFlame(EnIceHono* this); void EnIceHono_SetupActionDroppedFlame(EnIceHono* this); void EnIceHono_SetupActionSpreadFlames(EnIceHono* this); void EnIceHono_SetupActionSmallFlame(EnIceHono* this); const ActorInit En_Ice_Hono_InitVars = { ACTOR_EN_ICE_HONO, ACTORCAT_ITEMACTION, FLAGS, OBJECT_GAMEPLAY_KEEP, sizeof(EnIceHono), (ActorFunc)EnIceHono_Init, (ActorFunc)EnIceHono_Destroy, (ActorFunc)EnIceHono_Update, (ActorFunc)EnIceHono_Draw, NULL, }; static ColliderCylinderInit sCylinderInitCapturableFlame = { { 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, }, { 25, 80, 0, { 0, 0, 0 } }, }; static ColliderCylinderInit sCylinderInitDroppedFlame = { { COLTYPE_NONE, AT_ON | AT_TYPE_OTHER, AC_NONE, OC1_ON | OC1_TYPE_2, OC2_TYPE_2, COLSHAPE_CYLINDER, }, { ELEMTYPE_UNK0, { 0xFFCFFFFF, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_ON, }, { 12, 60, 0, { 0, 0, 0 } }, }; static InitChainEntry sInitChainCapturableFlame[] = { ICHAIN_U8(targetMode, 0, ICHAIN_CONTINUE), ICHAIN_F32(targetArrowOffset, 60, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 400, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP), }; static InitChainEntry sInitChainDroppedFlame[] = { ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 400, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP), }; static InitChainEntry sInitChainSmallFlame[] = { ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 400, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP), }; f32 EnIceHono_XZDistanceSquared(Vec3f* v1, Vec3f* v2) { return SQ(v1->x - v2->x) + SQ(v1->z - v2->z); } void EnIceHono_InitCapturableFlame(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; Actor_ProcessInitChain(&this->actor, sInitChainCapturableFlame); Actor_SetScale(&this->actor, 0.0074f); this->actor.flags |= ACTOR_FLAG_0; Actor_SetFocus(&this->actor, 10.0f); Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitCapturableFlame); Collider_UpdateCylinder(&this->actor, &this->collider); this->actor.colChkInfo.mass = MASS_IMMOVABLE; EnIceHono_SetupActionCapturableFlame(this); } void EnIceHono_InitDroppedFlame(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; Actor_ProcessInitChain(&this->actor, sInitChainDroppedFlame); this->actor.scale.x = this->actor.scale.z = this->actor.scale.y = 0.00002f; this->actor.gravity = -0.3f; this->actor.minVelocityY = -4.0f; this->actor.shape.yOffset = 0.0f; this->actor.shape.rot.x = this->actor.shape.rot.y = this->actor.shape.rot.z = this->actor.world.rot.x = this->actor.world.rot.y = this->actor.world.rot.z = 0; Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitDroppedFlame); Collider_UpdateCylinder(&this->actor, &this->collider); this->collider.dim.radius = this->actor.scale.x * 4000.4f; this->collider.dim.height = this->actor.scale.y * 8000.2f; this->actor.colChkInfo.mass = 253; EnIceHono_SetupActionDroppedFlame(this); } void EnIceHono_InitSmallFlame(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; Actor_ProcessInitChain(&this->actor, sInitChainSmallFlame); this->actor.scale.x = this->actor.scale.z = this->actor.scale.y = 0.0008f; this->actor.gravity = -0.3f; this->actor.minVelocityY = -4.0f; this->actor.shape.yOffset = 0.0f; EnIceHono_SetupActionSmallFlame(this); } void EnIceHono_Init(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; s16 params = this->actor.params; switch (this->actor.params) { case -1: EnIceHono_InitCapturableFlame(&this->actor, globalCtx); break; case 0: EnIceHono_InitDroppedFlame(&this->actor, globalCtx); break; case 1: case 2: EnIceHono_InitSmallFlame(&this->actor, globalCtx); break; } if ((this->actor.params == -1) || (this->actor.params == 0)) { Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, (s16)this->actor.world.pos.y + 10, this->actor.world.pos.z, 155, 210, 255, 0); this->lightNode = LightContext_InsertLight(globalCtx, &globalCtx->lightCtx, &this->lightInfo); this->unk_154 = Rand_ZeroOne() * (0x1FFFF / 2.0f); this->unk_156 = Rand_ZeroOne() * (0x1FFFF / 2.0f); osSyncPrintf("(ice 炎)(arg_data 0x%04x)\n", this->actor.params); // "(ice flame)" } } void EnIceHono_Destroy(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; if ((this->actor.params == -1) || (this->actor.params == 0)) { LightContext_RemoveLight(globalCtx, &globalCtx->lightCtx, this->lightNode); Collider_DestroyCylinder(globalCtx, &this->collider); } } u32 EnIceHono_InBottleRange(EnIceHono* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); if (this->actor.xzDistToPlayer < 60.0f) { Vec3f tempPos; tempPos.x = Math_SinS(this->actor.yawTowardsPlayer + 0x8000) * 40.0f + player->actor.world.pos.x; tempPos.y = player->actor.world.pos.y; tempPos.z = Math_CosS(this->actor.yawTowardsPlayer + 0x8000) * 40.0f + player->actor.world.pos.z; //! @bug: this check is superfluous: it is automatically satisfied if the coarse check is satisfied. It may have //! been intended to check the actor is in front of Player, but yawTowardsPlayer does not depend on Player's //! world rotation. if (EnIceHono_XZDistanceSquared(&tempPos, &this->actor.world.pos) <= SQ(40.0f)) { return true; } } return false; } void EnIceHono_SetupActionCapturableFlame(EnIceHono* this) { this->actionFunc = EnIceHono_CapturableFlame; this->alpha = 255; this->actor.shape.yOffset = -1000.0f; } void EnIceHono_CapturableFlame(EnIceHono* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { this->actor.parent = NULL; } else if (EnIceHono_InBottleRange(this, globalCtx)) { // GI_MAX in this case allows the player to catch the actor in a bottle func_8002F434(&this->actor, globalCtx, GI_MAX, 60.0f, 100.0f); } if (this->actor.xzDistToPlayer < 200.0f) { CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } func_8002F8F0(&this->actor, NA_SE_EV_FIRE_PILLAR_S - SFX_FLAG); } void EnIceHono_SetupActionDroppedFlame(EnIceHono* this) { this->actionFunc = EnIceHono_DropFlame; this->timer = 200; this->alpha = 255; } void EnIceHono_DropFlame(EnIceHono* this, GlobalContext* globalCtx) { u32 bgFlag = this->actor.bgCheckFlags & 1; Math_StepToF(&this->actor.scale.x, 0.0017f, 0.00008f); this->actor.scale.z = this->actor.scale.x; Math_StepToF(&this->actor.scale.y, 0.0017f, 0.00008f); if (bgFlag != 0) { s32 i; for (i = 0; i < 8; i++) { Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ICE_HONO, this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, ((s32)(Rand_ZeroOne() * 1000.0f) + i * 0x2000) - 0x1F4, 0, 1); } EnIceHono_SetupActionSpreadFlames(this); } Actor_MoveForward(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 10.0f, this->actor.scale.x * 3500.0f, 0.0f, 5); Collider_UpdateCylinder(&this->actor, &this->collider); this->collider.dim.radius = this->actor.scale.x * 4000.0f; this->collider.dim.height = this->actor.scale.y * 8000.0f; CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); if (this->timer <= 0) { Actor_Kill(&this->actor); } } void EnIceHono_SetupActionSpreadFlames(EnIceHono* this) { this->actionFunc = EnIceHono_SpreadFlames; this->timer = 60; this->alpha = 255; } void EnIceHono_SpreadFlames(EnIceHono* this, GlobalContext* globalCtx) { if (this->timer > 20) { Math_StepToF(&this->actor.scale.x, 0.011f, 0.00014f); Math_StepToF(&this->actor.scale.y, 0.006f, 0.00012f); } else { Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f); Math_StepToF(&this->actor.scale.y, 0.0001f, 0.00015f); } this->actor.scale.z = this->actor.scale.x; Actor_MoveForward(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 10.0f, this->actor.scale.x * 3500.0f, 0.0f, 4); if (this->timer < 25) { this->alpha -= 10; this->alpha = CLAMP(this->alpha, 0, 255); } if ((this->alpha > 100) && (this->timer < 40)) { Collider_UpdateCylinder(&this->actor, &this->collider); this->collider.dim.radius = this->actor.scale.x * 6000.0f; this->collider.dim.height = this->actor.scale.y * 8000.0f; CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } if (this->timer == 46) { s32 i; for (i = 0; i < 10; i++) { s32 rot = i * 0x1999; Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ICE_HONO, this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, ((s32)(Rand_ZeroOne() * 1000.0f) + rot) - 0x1F4, 0, 2); } } if (this->timer <= 0) { Actor_Kill(&this->actor); } } void EnIceHono_SetupActionSmallFlame(EnIceHono* this) { this->actionFunc = EnIceHono_SmallFlameMove; this->timer = 44; this->alpha = 255; if (this->actor.params == 1) { this->smallFlameTargetYScale = (Rand_ZeroOne() * 0.005f) + 0.004f; this->actor.speedXZ = (Rand_ZeroOne() * 1.6f) + 0.5f; } else { this->smallFlameTargetYScale = (Rand_ZeroOne() * 0.005f) + 0.003f; this->actor.speedXZ = (Rand_ZeroOne() * 2.0f) + 0.5f; } } void EnIceHono_SmallFlameMove(EnIceHono* this, GlobalContext* globalCtx) { if (this->timer > 20) { Math_StepToF(&this->actor.scale.x, 0.006f, 0.00016f); Math_StepToF(&this->actor.scale.y, this->smallFlameTargetYScale * 0.667f, 0.00014f); } else { Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f); Math_StepToF(&this->actor.scale.y, 0.0001f, 0.00015f); } this->actor.scale.z = this->actor.scale.x; Math_StepToF(&this->actor.speedXZ, 0, 0.06f); Actor_MoveForward(&this->actor); Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 10.0f, 10.0f, 0.0f, 5); if (this->timer < 25) { this->alpha -= 10; this->alpha = CLAMP(this->alpha, 0, 255); } if (this->timer <= 0) { Actor_Kill(&this->actor); } } void EnIceHono_Update(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; s32 pad1; f32 intensity; s32 pad2; f32 sin154; f32 sin156; if (this->timer > 0) { this->timer--; } if (this->actor.params == 0) { func_8002F8F0(&this->actor, NA_SE_IT_FLAME - SFX_FLAG); } if ((this->actor.params == -1) || (this->actor.params == 0)) { this->unk_154 += 0x1111; this->unk_156 += 0x4000; sin156 = Math_SinS(this->unk_156); sin154 = Math_SinS(this->unk_154); intensity = (Rand_ZeroOne() * 0.05f) + ((sin154 * 0.125f) + (sin156 * 0.1f)) + 0.425f; if ((intensity > 0.7f) || (intensity < 0.2f)) { osSyncPrintf("ありえない値(ratio = %f)\n", intensity); // "impossible value(ratio = %f)" } Lights_PointNoGlowSetInfo(&this->lightInfo, this->actor.world.pos.x, (s16)this->actor.world.pos.y + 10, this->actor.world.pos.z, (s32)(155.0f * intensity), (s32)(210.0f * intensity), (s32)(255.0f * intensity), 1400); } if (this->actionFunc != NULL) { this->actionFunc(this, globalCtx); } } void EnIceHono_Draw(Actor* thisx, GlobalContext* globalCtx) { EnIceHono* this = (EnIceHono*)thisx; u32 pad; OPEN_DISPS(globalCtx->state.gfxCtx); func_80093D84(globalCtx->state.gfxCtx); gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 32, 64, 1, 0, (globalCtx->state.frames * -20) % 512, 32, 128)); gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 170, 255, 255, this->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 0, 150, 255, 0); Matrix_RotateY((s16)(Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->actor.shape.rot.y + 0x8000) * (M_PI / 0x8000), MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, gEffFire1DL); CLOSE_DISPS(globalCtx->state.gfxCtx); }