399 lines
14 KiB
C
399 lines
14 KiB
C
/*
|
|
* 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, "../z_en_ice_hono.c", 695);
|
|
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, "../z_en_ice_hono.c", 718),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, gEffFire1DL);
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_ice_hono.c", 722);
|
|
}
|