/* * File: z_en_vb_ball.c * Overlay: ovl_En_Vb_Ball * Description: Volvagia's rocks and bones */ #include "z_en_vb_ball.h" #include "objects/object_fd/object_fd.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "overlays/actors/ovl_Boss_Fd/z_boss_fd.h" #define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5) void EnVbBall_Init(Actor* thisx, GlobalContext* globalCtx); void EnVbBall_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnVbBall_Update(Actor* thisx, GlobalContext* globalCtx); void EnVbBall_Draw(Actor* thisx, GlobalContext* globalCtx); const ActorInit En_Vb_Ball_InitVars = { 0, ACTORCAT_BOSS, FLAGS, OBJECT_FD, sizeof(EnVbBall), (ActorFunc)EnVbBall_Init, (ActorFunc)EnVbBall_Destroy, (ActorFunc)EnVbBall_Update, (ActorFunc)EnVbBall_Draw, NULL, }; static ColliderCylinderInit sCylinderInit = { { COLTYPE_NONE, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, { ELEMTYPE_UNK6, { 0x00100700, 0x00, 0x20 }, { 0x00100700, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, { 20, 30, 10, { 0, 0, 0 } }, }; void EnVbBall_Init(Actor* thisx, GlobalContext* globalCtx) { s32 pad; EnVbBall* this = (EnVbBall*)thisx; s32 pad2; f32 angle; if (this->actor.params >= 200) { // Volvagia's bones this->yRotVel = Rand_CenteredFloat(0x300); this->xRotVel = Rand_CenteredFloat(0x300); angle = Math_FAtan2F(this->actor.world.pos.x, this->actor.world.pos.z); this->actor.velocity.y = Rand_ZeroFloat(3.0f); this->actor.velocity.x = 2.0f * sinf(angle); this->actor.velocity.z = 2.0f * cosf(angle); this->actor.gravity = -0.8f; } else { // Volvagia's rocks Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); Actor_SetScale(&this->actor, this->actor.world.rot.z / 10000.0f); this->collider.dim.radius = this->actor.scale.y * 3000.0f; this->collider.dim.height = this->actor.scale.y * 5000.0f; this->collider.dim.yShift = this->actor.scale.y * -2500.0f; this->xRotVel = Rand_CenteredFloat(0x2000); this->yRotVel = Rand_CenteredFloat(0x2000); this->shadowSize = this->actor.scale.y * 68.0f; } } void EnVbBall_Destroy(Actor* thisx, GlobalContext* globalCtx) { s32 pad; EnVbBall* this = (EnVbBall*)thisx; if (this->actor.params < 200) { Collider_DestroyCylinder(globalCtx, &this->collider); } } void EnVbBall_SpawnDebris(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { s16 i; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_NONE) { effect->type = BFD_FX_DEBRIS; effect->pos = *position; effect->velocity = *velocity; effect->accel = *acceleration; effect->scale = scale / 1000.0f; effect->vFdFxRotX = Rand_ZeroFloat(100.0f); effect->vFdFxRotY = Rand_ZeroFloat(100.0f); break; } } } void EnVbBall_SpawnDust(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale) { s16 i; for (i = 0; i < 180; i++, effect++) { if (effect->type == BFD_FX_NONE) { effect->type = BFD_FX_DUST; effect->pos = *position; effect->velocity = *velocity; effect->accel = *acceleration; effect->timer2 = 0; effect->scale = scale / 400.0f; break; } } } void EnVbBall_UpdateBones(EnVbBall* this, GlobalContext* globalCtx) { BossFd* bossFd = (BossFd*)this->actor.parent; f32 pad2; f32 pad1; f32 angle; s16 i; Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 4); if ((this->actor.bgCheckFlags & 1) && (this->actor.velocity.y <= 0.0f)) { this->xRotVel = Rand_CenteredFloat((f32)0x4000); this->yRotVel = Rand_CenteredFloat((f32)0x4000); angle = Math_FAtan2F(this->actor.world.pos.x, this->actor.world.pos.z); this->actor.velocity.x = sinf(angle) * 10.0f; this->actor.velocity.z = cosf(angle) * 10.0f; this->actor.velocity.y *= -0.5f; if (this->actor.params & 1) { Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_LAND, &this->actor.projectedPos, 4, &D_801333E0, &D_801333E0, &D_801333E8); } for (i = 0; i < 10; i++) { Vec3f dustVel = { 0.0f, 0.0f, 0.0f }; Vec3f dustAcc = { 0.0f, 0.0f, 0.0f }; Vec3f dustPos; dustVel.x = Rand_CenteredFloat(8.0f); dustVel.y = Rand_ZeroFloat(1.0f); dustVel.z = Rand_CenteredFloat(8.0f); dustAcc.y = 0.3f; dustPos.x = Rand_CenteredFloat(20.0f) + this->actor.world.pos.x; dustPos.y = this->actor.floorHeight + 10.0f; dustPos.z = Rand_CenteredFloat(20.0f) + this->actor.world.pos.z; EnVbBall_SpawnDust(globalCtx, bossFd->effects, &dustPos, &dustVel, &dustAcc, Rand_ZeroFloat(80.0f) + 200.0f); } } if (this->actor.world.pos.y < 50.0f) { Actor_Kill(&this->actor); } } void EnVbBall_Update(Actor* thisx, GlobalContext* globalCtx2) { GlobalContext* globalCtx = globalCtx2; EnVbBall* this = (EnVbBall*)thisx; BossFd* bossFd = (BossFd*)this->actor.parent; f32 radius; f32 pad2; s16 spawnNum; s16 i; this->unkTimer2++; if (this->unkTimer1 != 0) { this->unkTimer1--; } this->actor.shape.rot.x += (s16)this->xRotVel; this->actor.shape.rot.y += (s16)this->yRotVel; this->actor.velocity.y += -1.0f; this->actor.gravity = -1.0f; func_8002D7EC(&this->actor); if (this->actor.params >= 200) { EnVbBall_UpdateBones(this, globalCtx); } else { Math_ApproachF(&this->shadowOpacity, 175.0f, 1.0f, 40.0f); radius = this->actor.scale.y * 1700.0f; this->actor.world.pos.y -= radius; Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 4); this->actor.world.pos.y += radius; if ((this->actor.bgCheckFlags & 1) && (this->actor.velocity.y <= 0.0f)) { if ((this->actor.params == 100) || (this->actor.params == 101)) { Actor_Kill(&this->actor); if (this->actor.params == 100) { func_80033E88(&this->actor, globalCtx, 5, 0xA); } if (this->actor.params == 100) { spawnNum = 2; } else { spawnNum = 2; } for (i = 0; i < spawnNum; i++) { Vec3f spawnOffset; EnVbBall* newActor; f32 xRotVel; if (this->actor.params == 100) { spawnOffset.x = Rand_CenteredFloat(13.0f); spawnOffset.y = Rand_ZeroFloat(5.0f) + 6.0f; spawnOffset.z = Rand_CenteredFloat(13); } else { spawnOffset.x = Rand_CenteredFloat(10.0f); spawnOffset.y = Rand_ZeroFloat(3.0f) + 4.0f; spawnOffset.z = Rand_CenteredFloat(10.0f); } newActor = (EnVbBall*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_VB_BALL, this->actor.world.pos.x + spawnOffset.x, this->actor.world.pos.y + spawnOffset.y, this->actor.world.pos.z + spawnOffset.z, 0, 0, this->actor.world.rot.z * 0.5f, this->actor.params + 1); if (newActor != NULL) { if ((i == 0) && (this->actor.params == 100)) { Audio_PlaySoundGeneral(NA_SE_EN_VALVAISA_ROCK, &newActor->actor.projectedPos, 4, &D_801333E0, &D_801333E0, &D_801333E8); } newActor->actor.parent = this->actor.parent; newActor->actor.velocity = spawnOffset; newActor->yRotVel = 0.0f; xRotVel = sqrtf(SQ(spawnOffset.x) + SQ(spawnOffset.z)); newActor->xRotVel = 0x1000 / 10.0f * xRotVel; newActor->actor.shape.rot.y = Math_FAtan2F(spawnOffset.x, spawnOffset.z) * ((f32)0x8000 / M_PI); newActor->shadowOpacity = 200.0f; } } for (i = 0; i < 15; i++) { Vec3f debrisVel1 = { 0.0f, 0.0f, 0.0f }; Vec3f debrisAcc1 = { 0.0f, -1.0f, 0.0f }; Vec3f debrisPos1; debrisVel1.x = Rand_CenteredFloat(25.0f); debrisVel1.y = Rand_ZeroFloat(5.0f) + 8; debrisVel1.z = Rand_CenteredFloat(25.0f); debrisPos1.x = Rand_CenteredFloat(10.0f) + this->actor.world.pos.x; debrisPos1.y = Rand_CenteredFloat(10.0f) + this->actor.world.pos.y; debrisPos1.z = Rand_CenteredFloat(10.0f) + this->actor.world.pos.z; EnVbBall_SpawnDebris(globalCtx, bossFd->effects, &debrisPos1, &debrisVel1, &debrisAcc1, (s16)Rand_ZeroFloat(12.0f) + 15); } for (i = 0; i < 10; i++) { Vec3f dustVel = { 0.0f, 0.0f, 0.0f }; Vec3f dustAcc = { 0.0f, 0.0f, 0.0f }; Vec3f dustPos; dustVel.x = Rand_CenteredFloat(8.0f); dustVel.y = Rand_ZeroFloat(1.0f); dustVel.z = Rand_CenteredFloat(8.0f); dustAcc.y = 1.0f / 2; dustPos.x = Rand_CenteredFloat(30.0f) + this->actor.world.pos.x; dustPos.y = Rand_CenteredFloat(30.0f) + this->actor.world.pos.y; dustPos.z = Rand_CenteredFloat(30.0f) + this->actor.world.pos.z; EnVbBall_SpawnDust(globalCtx, bossFd->effects, &dustPos, &dustVel, &dustAcc, Rand_ZeroFloat(100.0f) + 350.0f); } } else { for (i = 0; i < 5; i++) { Vec3f debrisVel2 = { 0.0f, 0.0f, 0.0f }; Vec3f debrisAcc2 = { 0.0f, -1.0f, 0.0f }; Vec3f debrisPos2; debrisVel2.x = Rand_CenteredFloat(10.0f); debrisVel2.y = Rand_ZeroFloat(3.0f) + 3.0f; debrisVel2.z = Rand_CenteredFloat(10.0f); debrisPos2.x = Rand_CenteredFloat(5.0f) + this->actor.world.pos.x; debrisPos2.y = Rand_CenteredFloat(5.0f) + this->actor.world.pos.y; debrisPos2.z = Rand_CenteredFloat(5.0f) + this->actor.world.pos.z; EnVbBall_SpawnDebris(globalCtx, bossFd->effects, &debrisPos2, &debrisVel2, &debrisAcc2, (s16)Rand_ZeroFloat(12.0f) + 15); } Actor_Kill(&this->actor); } } if (this->collider.base.atFlags & AT_HIT) { Player* player = GET_PLAYER(globalCtx); this->collider.base.atFlags &= ~AT_HIT; Audio_PlayActorSound2(&player->actor, NA_SE_PL_BODY_HIT); } Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base); } } void EnVbBall_Draw(Actor* thisx, GlobalContext* globalCtx) { s32 pad; EnVbBall* this = (EnVbBall*)thisx; OPEN_DISPS(globalCtx->state.gfxCtx); func_80093D18(globalCtx->state.gfxCtx); gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); if (this->actor.params >= 200) { gSPDisplayList(POLY_OPA_DISP++, SEGMENTED_TO_VIRTUAL(gVolvagiaRibsDL)); } else { gSPDisplayList(POLY_OPA_DISP++, SEGMENTED_TO_VIRTUAL(gVolvagiaRockDL)); func_80094044(globalCtx->state.gfxCtx); gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, (s8)this->shadowOpacity); Matrix_Translate(this->actor.world.pos.x, 100.0f, this->actor.world.pos.z, MTXMODE_NEW); Matrix_Scale(this->shadowSize, 1.0f, this->shadowSize, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gCircleShadowDL)); } CLOSE_DISPS(globalCtx->state.gfxCtx); }