Shipwright/soh/src/overlays/actors/ovl_En_Vb_Ball/z_en_vb_ball.c

326 lines
13 KiB
C

/*
* 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);
}