mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-08-13 17:03:47 -04:00
5432 lines
220 KiB
C
5432 lines
220 KiB
C
#include "z_boss_tw.h"
|
|
#include "objects/gameplay_keep/gameplay_keep.h"
|
|
#include "objects/object_tw/object_tw.h"
|
|
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
|
|
|
|
#include <string.h>
|
|
|
|
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
|
|
|
|
typedef enum {
|
|
/* 0x00 */ TW_KOTAKE,
|
|
/* 0x01 */ TW_KOUME,
|
|
/* 0x02 */ TW_TWINROVA,
|
|
/* 0x64 */ TW_FIRE_BLAST = 0x64,
|
|
/* 0x65 */ TW_FIRE_BLAST_GROUND,
|
|
/* 0x66 */ TW_ICE_BLAST,
|
|
/* 0x67 */ TW_ICE_BLAST_GROUND,
|
|
/* 0x68 */ TW_DEATHBALL_KOTAKE,
|
|
/* 0x69 */ TW_DEATHBALL_KOUME
|
|
} TwinrovaType;
|
|
|
|
void BossTw_Init(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_Update(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_Draw(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_Reset(void);
|
|
|
|
void BossTw_TwinrovaDamage(BossTw* this, GlobalContext* globalCtx, u8 arg2);
|
|
void BossTw_TwinrovaSetupFly(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_DrawEffects(GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaLaugh(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaFly(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaGetUp(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupGetUp(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupLaugh(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaDoneBlastShoot(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupDoneBlastShoot(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupShootBlast(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupChargeBlast(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaArriveAtTarget(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaDeathCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaIntroCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_CSWait(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_DeathCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaMergeCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupMergeCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_MergeCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_Spin(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_Laugh(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupLaugh(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_FinishBeamShoot(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupFinishBeamShoot(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupHitByBeam(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_HitByBeam(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_Wait(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_ShootBeam(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_FlyTo(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupShootBeam(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TurnToPlayer(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaUpdate(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaDraw(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_SetupWait(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupIntroCS(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupFlyTo(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_SetupCSWait(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_BlastUpdate(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_BlastDraw(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_BlastFire(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_BlastIce(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_DeathBall(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_DrawDeathBall(Actor* thisx, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaStun(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSpin(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaShootBlast(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaChargeBlast(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_TwinrovaSetupSpin(BossTw* this, GlobalContext* globalCtx);
|
|
void BossTw_UpdateEffects(GlobalContext* globalCtx);
|
|
|
|
const ActorInit Boss_Tw_InitVars = {
|
|
ACTOR_BOSS_TW,
|
|
ACTORCAT_BOSS,
|
|
FLAGS,
|
|
OBJECT_TW,
|
|
sizeof(BossTw),
|
|
(ActorFunc)BossTw_Init,
|
|
(ActorFunc)BossTw_Destroy,
|
|
(ActorFunc)BossTw_Update,
|
|
(ActorFunc)BossTw_Draw,
|
|
(ActorResetFunc)BossTw_Reset,
|
|
};
|
|
|
|
static Vec3f D_8094A7D0 = { 0.0f, 0.0f, 1000.0f };
|
|
static Vec3f sZeroVector = { 0.0f, 0.0f, 0.0f };
|
|
|
|
static ColliderCylinderInit sCylinderInitBlasts = {
|
|
{
|
|
COLTYPE_NONE,
|
|
AT_ON | AT_TYPE_ALL,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_PLAYER,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_CYLINDER,
|
|
},
|
|
{
|
|
ELEMTYPE_UNK0,
|
|
{ 0xFFCFFFFF, 0x00, 0x30 },
|
|
{ 0x00100000, 0x00, 0x00 },
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
BUMP_ON,
|
|
OCELEM_ON,
|
|
},
|
|
{ 25, 35, -17, { 0, 0, 0 } },
|
|
};
|
|
|
|
static ColliderCylinderInit sCylinderInitKoumeKotake = {
|
|
{
|
|
COLTYPE_HIT3,
|
|
AT_ON | AT_TYPE_ENEMY,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_PLAYER,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_CYLINDER,
|
|
},
|
|
{
|
|
ELEMTYPE_UNK0,
|
|
{ 0xFFCFFFFF, 0x00, 0x20 },
|
|
{ 0xFFCDFFFE, 0x00, 0x00 },
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
BUMP_ON,
|
|
OCELEM_ON,
|
|
},
|
|
{ 45, 120, -30, { 0, 0, 0 } },
|
|
};
|
|
|
|
static ColliderCylinderInit sCylinderInitTwinrova = {
|
|
{
|
|
COLTYPE_HIT3,
|
|
AT_ON | AT_TYPE_ENEMY,
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
OC1_ON | OC1_TYPE_ALL,
|
|
OC2_TYPE_1,
|
|
COLSHAPE_CYLINDER,
|
|
},
|
|
{
|
|
ELEMTYPE_UNK0,
|
|
{ 0xFFCFFFFF, 0x00, 0x20 },
|
|
{ 0xFFCDFFFE, 0x00, 0x00 },
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
BUMP_ON | BUMP_HOOKABLE,
|
|
OCELEM_ON,
|
|
},
|
|
{ 45, 120, -30, { 0, 0, 0 } },
|
|
};
|
|
|
|
static Vec3f sTwinrovaPillarPos[] = {
|
|
{ 580.0f, 380.0f, 0.0f },
|
|
{ 0.0f, 380.0f, 580.0f },
|
|
{ -580.0f, 380.0f, 0.0f },
|
|
{ 0.0f, 380.0f, -580.0f },
|
|
};
|
|
|
|
u8 sTwInitalized = false;
|
|
|
|
static InitChainEntry sInitChain[] = {
|
|
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
|
|
ICHAIN_F32_DIV1000(gravity, 0, ICHAIN_CONTINUE),
|
|
ICHAIN_F32(targetArrowOffset, 0, ICHAIN_STOP),
|
|
};
|
|
|
|
static s8 sEnvType;
|
|
static u8 sGroundBlastType;
|
|
static BossTw* sKotakePtr;
|
|
static BossTw* sKoumePtr;
|
|
static BossTw* sTwinrovaPtr;
|
|
static u8 sShieldFireCharge;
|
|
static u8 sShieldIceCharge;
|
|
static f32 D_8094C854;
|
|
static f32 D_8094C858;
|
|
static u8 sTwinrovaBlastType;
|
|
static u8 sFixedBlastType;
|
|
static u8 sFixedBlatSeq;
|
|
static u8 sFreezeState;
|
|
static Vec3f sShieldHitPos;
|
|
static s16 sShieldHitYaw;
|
|
static u8 sBeamDivertTimer;
|
|
static u8 D_8094C86F;
|
|
static u8 D_8094C870;
|
|
static s16 D_8094C872;
|
|
static s16 D_8094C874;
|
|
static s16 D_8094C876;
|
|
static u8 D_8094C878;
|
|
static s16 D_8094C87A;
|
|
static s16 D_8094C87C;
|
|
static u8 D_8094C87E;
|
|
BossTwEffect sTwEffects[150];
|
|
|
|
void BossTw_AddDotEffect(GlobalContext* globalCtx, Vec3f* initalPos, Vec3f* initalSpeed, Vec3f* accel, f32 scale,
|
|
s16 args, s16 countLimit) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < countLimit; i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_DOT;
|
|
eff->pos = *initalPos;
|
|
eff->curSpeed = *initalSpeed;
|
|
eff->accel = *accel;
|
|
eff->workf[EFF_SCALE] = scale / 1000.0f;
|
|
eff->alpha = 255;
|
|
eff->frame = (s16)Rand_ZeroFloat(10.0f);
|
|
eff->work[EFF_ARGS] = args;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddDmgCloud(GlobalContext* globalCtx, s16 type, Vec3f* initialPos, Vec3f* initalSpeed, Vec3f* accel,
|
|
f32 scale, s16 alpha, s16 args, s16 countLimit) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < countLimit; i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = type;
|
|
eff->pos = *initialPos;
|
|
eff->curSpeed = *initalSpeed;
|
|
eff->accel = *accel;
|
|
eff->workf[EFF_SCALE] = scale / 1000.0f;
|
|
eff->work[EFF_ARGS] = args;
|
|
eff->alpha = alpha;
|
|
eff->frame = (s16)Rand_ZeroFloat(100.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddRingEffect(GlobalContext* globalCtx, Vec3f* initalPos, f32 scale, f32 arg3, s16 alpha, s16 args,
|
|
s16 arg6, s16 arg7) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < arg7; i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_RING;
|
|
eff->pos = *initalPos;
|
|
eff->curSpeed = sZeroVector;
|
|
eff->accel = sZeroVector;
|
|
eff->workf[EFF_SCALE] = scale * 0.0025f;
|
|
eff->workf[EFF_DIST] = arg3 * 0.0025f;
|
|
eff->work[EFF_ARGS] = args;
|
|
eff->work[EFF_UNKS1] = arg6;
|
|
eff->alpha = alpha;
|
|
eff->workf[EFF_ROLL] = Rand_ZeroFloat(M_PI);
|
|
eff->frame = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddPlayerFreezeEffect(GlobalContext* globalCtx, Actor* target) {
|
|
BossTwEffect* eff;
|
|
s16 i;
|
|
|
|
for (eff = globalCtx->specialEffects, i = 0; i < ARRAY_COUNT(sTwEffects); i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_PLYR_FRZ;
|
|
eff->curSpeed = sZeroVector;
|
|
eff->accel = sZeroVector;
|
|
eff->frame = 0;
|
|
eff->target = target;
|
|
eff->workf[EFF_DIST] = 0.0f;
|
|
eff->workf[EFF_SCALE] = 0.0f;
|
|
eff->workf[EFF_ROLL] = 0.0f;
|
|
if (target == NULL) {
|
|
eff->work[EFF_ARGS] = 100;
|
|
} else {
|
|
eff->work[EFF_ARGS] = 20;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddFlameEffect(GlobalContext* globalCtx, Vec3f* initalPos, Vec3f* initalSpeed, Vec3f* accel, f32 scale,
|
|
s16 args) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < ARRAY_COUNT(sTwEffects); i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_FLAME;
|
|
eff->pos = *initalPos;
|
|
eff->curSpeed = *initalSpeed;
|
|
eff->accel = *accel;
|
|
eff->workf[EFF_SCALE] = scale / 1000.0f;
|
|
eff->work[EFF_ARGS] = args;
|
|
eff->work[EFF_UNKS1] = 0;
|
|
eff->alpha = 0;
|
|
eff->frame = (s16)Rand_ZeroFloat(1000.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddMergeFlameEffect(GlobalContext* globalCtx, Vec3f* initialPos, f32 scale, f32 dist, s16 args) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < ARRAY_COUNT(sTwEffects); i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_MERGEFLAME;
|
|
eff->pos = *initialPos;
|
|
eff->curSpeed = sZeroVector;
|
|
eff->accel = sZeroVector;
|
|
eff->workf[EFF_SCALE] = scale / 1000.0f;
|
|
eff->work[EFF_ARGS] = args;
|
|
eff->work[EFF_UNKS1] = 0;
|
|
eff->workf[EFF_DIST] = dist;
|
|
eff->workf[EFF_ROLL] = Rand_ZeroFloat(2.0f * M_PI);
|
|
eff->alpha = 0;
|
|
eff->frame = (s16)Rand_ZeroFloat(1000.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddShieldBlastEffect(GlobalContext* globalCtx, Vec3f* initalPos, Vec3f* initalSpeed, Vec3f* accel,
|
|
f32 scale, f32 arg5, s16 alpha, s16 args) {
|
|
s16 i;
|
|
BossTwEffect* eff;
|
|
|
|
for (i = 0, eff = globalCtx->specialEffects; i < ARRAY_COUNT(sTwEffects); i++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_SHLD_BLST;
|
|
eff->pos = *initalPos;
|
|
eff->curSpeed = *initalSpeed;
|
|
eff->accel = *accel;
|
|
eff->workf[EFF_SCALE] = scale / 1000.0f;
|
|
eff->workf[EFF_DIST] = arg5 / 1000.0f;
|
|
eff->work[EFF_ARGS] = args;
|
|
eff->work[EFF_UNKS1] = 0;
|
|
eff->alpha = alpha;
|
|
eff->frame = (s16)Rand_ZeroFloat(1000.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddShieldDeflectEffect(GlobalContext* globalCtx, f32 arg1, s16 arg2) {
|
|
s16 i;
|
|
s16 j;
|
|
BossTwEffect* eff;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
sShieldHitPos = player->bodyPartsPos[15];
|
|
sShieldHitYaw = player->actor.shape.rot.y;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
for (eff = globalCtx->specialEffects, j = 0; j < ARRAY_COUNT(sTwEffects); j++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_SHLD_DEFL;
|
|
eff->pos = sShieldHitPos;
|
|
eff->curSpeed = sZeroVector;
|
|
eff->accel = sZeroVector;
|
|
eff->workf[EFF_ROLL] = i * (M_PI / 4.0f);
|
|
eff->workf[EFF_YAW] = M_PI / 2.0f;
|
|
eff->workf[EFF_DIST] = 0.0f;
|
|
eff->workf[EFF_SCALE] = arg1 / 1000.0f;
|
|
eff->work[EFF_ARGS] = arg2;
|
|
eff->work[EFF_UNKS1] = 0;
|
|
eff->alpha = 255;
|
|
eff->frame = (s16)Rand_ZeroFloat(1000.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_AddShieldHitEffect(GlobalContext* globalCtx, f32 arg1, s16 arg2) {
|
|
s16 i;
|
|
s16 j;
|
|
BossTwEffect* eff;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
sShieldHitPos = player->bodyPartsPos[15];
|
|
sShieldHitYaw = player->actor.shape.rot.y;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
for (eff = globalCtx->specialEffects, j = 0; j < ARRAY_COUNT(sTwEffects); j++, eff++) {
|
|
if (eff->type == TWEFF_NONE) {
|
|
eff->type = TWEFF_SHLD_HIT;
|
|
eff->pos = sShieldHitPos;
|
|
eff->curSpeed = sZeroVector;
|
|
eff->accel = sZeroVector;
|
|
eff->workf[EFF_ROLL] = i * (M_PI / 4.0f);
|
|
eff->workf[EFF_YAW] = M_PI / 2.0f;
|
|
eff->workf[EFF_DIST] = 0.0f;
|
|
eff->workf[EFF_SCALE] = arg1 / 1000.0f;
|
|
eff->work[EFF_ARGS] = arg2;
|
|
eff->work[EFF_UNKS1] = 0;
|
|
eff->alpha = 255;
|
|
eff->frame = (s16)Rand_ZeroFloat(1000.0f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_Init(Actor* thisx, GlobalContext* globalCtx2) {
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
s16 i;
|
|
|
|
Actor_ProcessInitChain(&this->actor, sInitChain);
|
|
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
|
|
|
|
if (this->actor.params >= TW_FIRE_BLAST) {
|
|
// Blasts
|
|
Actor_SetScale(&this->actor, 0.01f);
|
|
this->actor.update = BossTw_BlastUpdate;
|
|
this->actor.draw = BossTw_BlastDraw;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
|
|
Collider_InitCylinder(globalCtx, &this->collider);
|
|
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitBlasts);
|
|
|
|
if (this->actor.params == TW_FIRE_BLAST || this->actor.params == TW_FIRE_BLAST_GROUND) {
|
|
this->actionFunc = BossTw_BlastFire;
|
|
this->collider.info.toucher.effect = 1;
|
|
} else if (this->actor.params == TW_ICE_BLAST || this->actor.params == TW_ICE_BLAST_GROUND) {
|
|
this->actionFunc = BossTw_BlastIce;
|
|
} else if (this->actor.params >= TW_DEATHBALL_KOTAKE) {
|
|
this->actionFunc = BossTw_DeathBall;
|
|
this->actor.draw = BossTw_DrawDeathBall;
|
|
this->workf[TAIL_ALPHA] = 128.0f;
|
|
|
|
if (thisx->params == TW_DEATHBALL_KOTAKE) {
|
|
thisx->world.rot.y = sTwinrovaPtr->actor.world.rot.y + 0x4000;
|
|
} else {
|
|
thisx->world.rot.y = sTwinrovaPtr->actor.world.rot.y - 0x4000;
|
|
}
|
|
}
|
|
|
|
this->timers[1] = 150;
|
|
return;
|
|
}
|
|
|
|
Actor_SetScale(&this->actor, 2.5 * 0.01f);
|
|
this->actor.colChkInfo.mass = 255;
|
|
this->actor.colChkInfo.health = 0;
|
|
Collider_InitCylinder(globalCtx, &this->collider);
|
|
|
|
if (!sTwInitalized) {
|
|
sTwInitalized = true;
|
|
globalCtx->envCtx.unk_BF = 1;
|
|
globalCtx->envCtx.unk_BE = 1;
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
|
|
D_8094C874 = D_8094C876 = D_8094C878 = D_8094C87A = D_8094C87C = D_8094C87E = D_8094C870 = D_8094C86F =
|
|
D_8094C872 = sBeamDivertTimer = sEnvType = sGroundBlastType = sFreezeState = sTwinrovaBlastType =
|
|
sFixedBlatSeq = sShieldFireCharge = sShieldIceCharge = 0;
|
|
|
|
D_8094C858 = D_8094C854 = 0.0f;
|
|
sFixedBlastType = Rand_ZeroFloat(1.99f);
|
|
globalCtx->specialEffects = sTwEffects;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
sTwEffects[i].type = TWEFF_NONE;
|
|
}
|
|
}
|
|
|
|
if (this->actor.params == TW_KOTAKE) {
|
|
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitKoumeKotake);
|
|
this->actor.naviEnemyId = 0x33;
|
|
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_tw_Skel_0070E0, &object_tw_Anim_006F28, NULL, NULL, 0);
|
|
|
|
if (gSaveContext.eventChkInf[7] & 0x20) {
|
|
// began twinrova battle
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
this->actor.world.pos.x = -600.0f;
|
|
this->actor.world.pos.y = 400.0f;
|
|
this->actor.world.pos.z = 0.0f;
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
|
|
} else {
|
|
BossTw_SetupCSWait(this, globalCtx);
|
|
}
|
|
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_006F28, -3.0f);
|
|
this->visible = true;
|
|
} else if (this->actor.params == TW_KOUME) {
|
|
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitKoumeKotake);
|
|
this->actor.naviEnemyId = 0x32;
|
|
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_tw_Skel_01F888, &object_tw_Anim_006F28, NULL, NULL, 0);
|
|
|
|
if (gSaveContext.eventChkInf[7] & 0x20) {
|
|
// began twinrova battle
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
this->actor.world.pos.x = 600.0f;
|
|
this->actor.world.pos.y = 400.0f;
|
|
this->actor.world.pos.z = 0.0f;
|
|
} else {
|
|
BossTw_SetupCSWait(this, globalCtx);
|
|
}
|
|
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_006F28, -3.0f);
|
|
this->visible = true;
|
|
} else {
|
|
// Twinrova
|
|
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInitTwinrova);
|
|
this->actor.naviEnemyId = 0x5B;
|
|
this->actor.colChkInfo.health = 24;
|
|
this->actor.update = BossTw_TwinrovaUpdate;
|
|
this->actor.draw = BossTw_TwinrovaDraw;
|
|
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_tw_Skel_032020, &object_tw_Anim_0244B4, NULL, NULL, 0);
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_0244B4, -3.0f);
|
|
|
|
if (gSaveContext.eventChkInf[7] & 0x20) {
|
|
// began twinrova battle
|
|
BossTw_SetupWait(this, globalCtx);
|
|
} else {
|
|
BossTw_TwinrovaSetupIntroCS(this, globalCtx);
|
|
this->actor.world.pos.x = 0.0f;
|
|
this->actor.world.pos.y = 1000.0f;
|
|
this->actor.world.pos.z = 0.0f;
|
|
}
|
|
|
|
this->actor.params = TW_TWINROVA;
|
|
sTwinrovaPtr = this;
|
|
|
|
if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) {
|
|
// twinrova has been defeated.
|
|
Actor_Kill(&this->actor);
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, 600.0f, 230.0f, 0.0f, 0,
|
|
0, 0, WARP_DUNGEON_ADULT);
|
|
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, -600.0f, 230.0f, 0.0f, 0, 0, 0, 0);
|
|
} else {
|
|
sKotakePtr = (BossTw*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->actor.world.pos.x, this->actor.world.pos.y,
|
|
this->actor.world.pos.z, 0, 0, 0, TW_KOTAKE);
|
|
sKoumePtr = (BossTw*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->actor.world.pos.x, this->actor.world.pos.y,
|
|
this->actor.world.pos.z, 0, 0, 0, TW_KOUME);
|
|
sKotakePtr->actor.parent = &sKoumePtr->actor;
|
|
sKoumePtr->actor.parent = &sKotakePtr->actor;
|
|
}
|
|
}
|
|
|
|
this->fogR = globalCtx->lightCtx.fogColor[0];
|
|
this->fogG = globalCtx->lightCtx.fogColor[1];
|
|
this->fogB = globalCtx->lightCtx.fogColor[2];
|
|
this->fogNear = globalCtx->lightCtx.fogNear;
|
|
this->fogFar = 1000.0f;
|
|
}
|
|
|
|
void BossTw_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
Collider_DestroyCylinder(globalCtx, &this->collider);
|
|
if (thisx->params < TW_FIRE_BLAST) {
|
|
SkelAnime_Free(&this->skelAnime, globalCtx);
|
|
}
|
|
|
|
if (thisx->params == TW_TWINROVA) {
|
|
sTwInitalized = false;
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupTurnToPlayer(BossTw* this, GlobalContext* globalCtx) {
|
|
BossTw* otherTw = (BossTw*)this->actor.parent;
|
|
|
|
this->actionFunc = BossTw_TurnToPlayer;
|
|
|
|
if ((otherTw != NULL) && (otherTw->actionFunc == BossTw_ShootBeam)) {
|
|
this->timers[0] = 40;
|
|
} else {
|
|
this->timers[0] = 60;
|
|
}
|
|
|
|
this->rotateSpeed = 0.0f;
|
|
}
|
|
|
|
void BossTw_TurnToPlayer(BossTw* this, GlobalContext* globalCtx) {
|
|
BossTw* otherTw = (BossTw*)this->actor.parent;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachF(&this->actor.speedXZ, 0.0f, 1.0f, 1.0f);
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.shape.rot.x, 0, 5, this->rotateSpeed);
|
|
Math_ApproachF(&this->rotateSpeed, 4096.0f, 1.0f, 200.0f);
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
if (this->timers[0] == 0) {
|
|
if ((otherTw->actionFunc != BossTw_ShootBeam) && this->work[CAN_SHOOT]) {
|
|
this->work[CAN_SHOOT] = false;
|
|
BossTw_SetupShootBeam(this, globalCtx);
|
|
this->actor.speedXZ = 0.0f;
|
|
} else {
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupFlyTo(BossTw* this, GlobalContext* globalCtx) {
|
|
static Vec3f sPillarPositions[] = {
|
|
{ 600.0f, 400.0f, 0.0f }, { 0.0f, 400.0f, 600.0f }, { -600.0f, 400.0f, 0.0f }, { 0.0f, 400.0f, -600.0f }
|
|
};
|
|
BossTw* otherTw = (BossTw*)this->actor.parent;
|
|
|
|
this->unk_5F8 = 1;
|
|
this->actor.flags |= ACTOR_FLAG_0;
|
|
this->actionFunc = BossTw_FlyTo;
|
|
this->rotateSpeed = 0.0f;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_006F28, -10.0f);
|
|
if ((Rand_ZeroOne() < 0.5f) && (otherTw != NULL && otherTw->actionFunc == BossTw_ShootBeam)) {
|
|
// Other Sister is shooting a beam, go near them.
|
|
this->targetPos.x = otherTw->actor.world.pos.x + Rand_CenteredFloat(200.0f);
|
|
this->targetPos.y = Rand_ZeroFloat(200.0f) + 340.0f;
|
|
this->targetPos.z = otherTw->actor.world.pos.z + Rand_CenteredFloat(200.0f);
|
|
this->timers[0] = (s16)Rand_ZeroFloat(50.0f) + 50;
|
|
} else if (Rand_ZeroOne() < 0.5f) {
|
|
// Fly to a random spot.
|
|
this->targetPos.x = Rand_CenteredFloat(800.0f);
|
|
this->targetPos.y = Rand_ZeroFloat(200.0f) + 340.0f;
|
|
this->targetPos.z = Rand_CenteredFloat(800.0f);
|
|
this->timers[0] = (s16)Rand_ZeroFloat(50.0f) + 50;
|
|
} else {
|
|
// fly to a random pillar.
|
|
s16 idx = Rand_ZeroFloat(ARRAY_COUNT(sPillarPositions) - 0.01f);
|
|
|
|
this->targetPos = sPillarPositions[idx];
|
|
this->timers[0] = 200;
|
|
this->work[CAN_SHOOT] = true;
|
|
}
|
|
}
|
|
|
|
void BossTw_FlyTo(BossTw* this, GlobalContext* globalCtx) {
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 pitchTarget;
|
|
f32 yawTarget;
|
|
f32 xzDist;
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
Math_ApproachF(&this->scepterAlpha, 0.0f, 1.0f, 10.0f);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
xDiff = this->targetPos.x - this->actor.world.pos.x;
|
|
yDiff = this->targetPos.y - this->actor.world.pos.y;
|
|
zDiff = this->targetPos.z - this->actor.world.pos.z;
|
|
|
|
yawTarget = (s16)(Math_FAtan2F(xDiff, zDiff) * (32768.0f / M_PI));
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
pitchTarget = (s16)(Math_FAtan2F(yDiff, xzDist) * (32768.0f / M_PI));
|
|
|
|
Math_ApproachS(&this->actor.world.rot.x, pitchTarget, 0xA, this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.world.rot.y, yawTarget, 0xA, this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.shape.rot.y, yawTarget, 0xA, this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.shape.rot.x, pitchTarget, 0xA, this->rotateSpeed);
|
|
Math_ApproachF(&this->rotateSpeed, 4096.0f, 1.0f, 100.0f);
|
|
Math_ApproachF(&this->actor.speedXZ, 10.0f, 1.0f, 1.0f);
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
|
|
if ((this->timers[0] == 0) || (xzDist < 70.0f)) {
|
|
BossTw_SetupTurnToPlayer(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupShootBeam(BossTw* this, GlobalContext* globalCtx) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
this->actionFunc = BossTw_ShootBeam;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_007688, -5.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_007688);
|
|
this->timers[1] = 70;
|
|
this->targetPos = player->actor.world.pos;
|
|
this->csState1 = 0;
|
|
this->beamDist = 0.0f;
|
|
this->beamReflectionDist = 0.0f;
|
|
this->beamShootState = -1;
|
|
this->beamScale = 0.01f;
|
|
this->beamReflectionOrigin = this->beamOrigin;
|
|
this->flameAlpha = 0.0f;
|
|
this->spawnPortalAlpha = 0.0f;
|
|
this->spawnPortalScale = 2000.0f;
|
|
this->updateRate1 = 0.0f;
|
|
this->portalRotation = 0.0f;
|
|
this->updateRate2 = 0.0f;
|
|
}
|
|
|
|
void BossTw_SpawnGroundBlast(BossTw* this, GlobalContext* globalCtx, s16 blastType) {
|
|
BossTw* groundBlast;
|
|
s16 i;
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_ZeroFloat(10.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
accel.y = 0.2f;
|
|
accel.x = Rand_CenteredFloat(0.25f);
|
|
accel.z = Rand_CenteredFloat(0.25f);
|
|
pos = this->groundBlastPos;
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 8, blastType, 75);
|
|
}
|
|
|
|
if (blastType == 1) {
|
|
sGroundBlastType = 1;
|
|
groundBlast = (BossTw*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->groundBlastPos.x, this->groundBlastPos.y,
|
|
this->groundBlastPos.z, 0, 0, 0, TW_FIRE_BLAST_GROUND);
|
|
if (groundBlast != NULL) {
|
|
if (sTwinrovaPtr->actionFunc == BossTw_Wait) {
|
|
groundBlast->timers[0] = 100;
|
|
} else {
|
|
groundBlast->timers[0] = 50;
|
|
}
|
|
sKoumePtr->workf[KM_GD_FLM_A] = sKoumePtr->workf[KM_GD_SMOKE_A] = sKoumePtr->workf[KM_GRND_CRTR_A] = 255.0f;
|
|
sKoumePtr->workf[KM_GD_FLM_SCL] = 1.0f;
|
|
sKoumePtr->workf[KM_GD_CRTR_SCL] = 0.005f;
|
|
sKoumePtr->groundBlastPos2 = groundBlast->actor.world.pos;
|
|
sEnvType = 4;
|
|
}
|
|
} else {
|
|
sGroundBlastType = 2;
|
|
groundBlast = (BossTw*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->groundBlastPos.x, this->groundBlastPos.y,
|
|
this->groundBlastPos.z, 0, 0, 0, TW_ICE_BLAST_GROUND);
|
|
if (groundBlast != NULL) {
|
|
if (sTwinrovaPtr->actionFunc == BossTw_Wait) {
|
|
groundBlast->timers[0] = 100;
|
|
} else {
|
|
groundBlast->timers[0] = 50;
|
|
}
|
|
|
|
sKotakePtr->workf[UNK_F11] = 50.0f;
|
|
sKotakePtr->workf[UNK_F9] = 250.0f;
|
|
sKotakePtr->workf[UNK_F12] = 0.005f;
|
|
sKotakePtr->workf[UNK_F14] = 1.0f;
|
|
sKotakePtr->workf[UNK_F16] = 70.0f;
|
|
sKotakePtr->groundBlastPos2 = groundBlast->actor.world.pos;
|
|
sEnvType = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
s32 BossTw_BeamHitPlayerCheck(BossTw* this, GlobalContext* globalCtx) {
|
|
Vec3f offset;
|
|
Vec3f beamDistFromPlayer;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 i;
|
|
|
|
offset.x = player->actor.world.pos.x - this->beamOrigin.x;
|
|
offset.y = player->actor.world.pos.y - this->beamOrigin.y;
|
|
offset.z = player->actor.world.pos.z - this->beamOrigin.z;
|
|
|
|
Matrix_RotateX(-this->beamPitch, MTXMODE_NEW);
|
|
Matrix_RotateY(-this->beamYaw, MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&offset, &beamDistFromPlayer);
|
|
|
|
if (fabsf(beamDistFromPlayer.x) < 20.0f && fabsf(beamDistFromPlayer.y) < 50.0f && beamDistFromPlayer.z > 100.0f &&
|
|
beamDistFromPlayer.z <= this->beamDist) {
|
|
if (sTwinrovaPtr->timers[2] == 0) {
|
|
sTwinrovaPtr->timers[2] = 150;
|
|
this->beamDist = sqrtf(SQ(offset.x) + SQ(offset.y) + SQ(offset.z));
|
|
func_8002F6D4(globalCtx, &this->actor, 3.0f, this->actor.shape.rot.y, 0.0f, 0x20);
|
|
|
|
if (this->actor.params == 0) {
|
|
if (sFreezeState == 0) {
|
|
sFreezeState = 1;
|
|
}
|
|
} else if (!player->isBurning) {
|
|
for (i = 0; i < ARRAY_COUNT(player->flameTimers); i++) {
|
|
player->flameTimers[i] = Rand_S16Offset(0, 200);
|
|
}
|
|
|
|
player->isBurning = true;
|
|
func_8002F7DC(&player->actor, player->ageProperties->unk_92 + NA_SE_VO_LI_DEMO_DAMAGE);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if the beam shot by `this` will be reflected
|
|
* returns 0 if the beam will not be reflected,
|
|
* returns 1 if the beam will be reflected,
|
|
* and returns 2 if the beam will be diverted backwards
|
|
*/
|
|
s32 BossTw_CheckBeamReflection(BossTw* this, GlobalContext* globalCtx) {
|
|
Vec3f offset;
|
|
Vec3f vec;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
if (player->stateFlags1 & 0x400000 &&
|
|
(s16)(player->actor.shape.rot.y - this->actor.shape.rot.y + 0x8000) < 0x2000 &&
|
|
(s16)(player->actor.shape.rot.y - this->actor.shape.rot.y + 0x8000) > -0x2000) {
|
|
// player is shielding and facing angles are less than 45 degrees in either direction
|
|
offset.x = 0.0f;
|
|
offset.y = 0.0f;
|
|
offset.z = 10.0f;
|
|
|
|
// set beam check point to 10 units in front of link.
|
|
Matrix_RotateY(player->actor.shape.rot.y / 32768.0f * M_PI, MTXMODE_NEW);
|
|
Matrix_MultVec3f(&offset, &vec);
|
|
|
|
// calculates a vector where the origin is at the beams origin,
|
|
// and the positive z axis is pointing in the direction the beam
|
|
// is shooting
|
|
offset.x = player->actor.world.pos.x + vec.x - this->beamOrigin.x;
|
|
offset.y = player->actor.world.pos.y + vec.y - this->beamOrigin.y;
|
|
offset.z = player->actor.world.pos.z + vec.z - this->beamOrigin.z;
|
|
|
|
Matrix_RotateX(-this->beamPitch, MTXMODE_NEW);
|
|
Matrix_RotateY(-this->beamYaw, MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&offset, &vec);
|
|
|
|
if (fabsf(vec.x) < 30.0f && fabsf(vec.y) < 70.0f && vec.z > 100.0f && vec.z <= this->beamDist) {
|
|
// if the beam's origin is within 30 x units, 70 y units, is farther than 100 units
|
|
// and the distance from the beams origin to 10 units in front of link is less than the beams
|
|
// current distance (the distance of the beam is equal to or longer than the distance to 10 units
|
|
// in front of link)
|
|
if (Player_HasMirrorShieldEquipped(globalCtx)) {
|
|
// player has mirror shield equipped
|
|
this->beamDist = sqrtf(SQ(offset.x) + SQ(offset.y) + SQ(offset.z));
|
|
return 1;
|
|
}
|
|
|
|
if (sBeamDivertTimer > 10) {
|
|
return 0;
|
|
}
|
|
|
|
if (sBeamDivertTimer == 0) {
|
|
// beam hit the shield, normal shield equipped,
|
|
// divert the beam backwards from link's Y rotation
|
|
BossTw_AddShieldDeflectEffect(globalCtx, 10.0f, this->actor.params);
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
this->timers[0] = 10;
|
|
func_80078884(NA_SE_IT_SHIELD_REFLECT_MG2);
|
|
}
|
|
|
|
sBeamDivertTimer++;
|
|
this->beamDist = sqrtf(SQ(offset.x) + SQ(offset.y) + SQ(offset.z));
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 BossTw_BeamReflHitCheck(BossTw* this, Vec3f* pos) {
|
|
Vec3f offset;
|
|
Vec3f beamDistFromTarget;
|
|
|
|
offset.x = pos->x - this->beamReflectionOrigin.x;
|
|
offset.y = pos->y - this->beamReflectionOrigin.y;
|
|
offset.z = pos->z - this->beamReflectionOrigin.z;
|
|
|
|
Matrix_RotateX(-this->beamReflectionPitch, MTXMODE_NEW);
|
|
Matrix_RotateY(-this->beamReflectionYaw, MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&offset, &beamDistFromTarget);
|
|
|
|
if (fabsf(beamDistFromTarget.x) < 50.0f && fabsf(beamDistFromTarget.y) < 50.0f && beamDistFromTarget.z > 100.0f &&
|
|
beamDistFromTarget.z <= this->beamReflectionDist) {
|
|
this->beamReflectionDist = sqrtf(SQ(offset.x) + SQ(offset.y) + SQ(offset.z)) * 1.1f;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
f32 BossTw_GetFloorY(Vec3f* pos) {
|
|
Vec3f posRotated;
|
|
|
|
if (fabsf(pos->x) < 350.0f && fabsf(pos->z) < 350.0f && pos->y < 240.0f) {
|
|
if (pos->y > 200.0f) {
|
|
return 240.0f;
|
|
}
|
|
return 35.0f;
|
|
}
|
|
|
|
if (fabsf(pos->x) < 110.0f && ((fabsf(pos->z - 600.0f) < 110.0f) || (fabsf(pos->z + 600.0f) < 110.0f)) &&
|
|
(pos->y < 230.0f)) {
|
|
if (pos->y > 190.0f) {
|
|
return 230.0f;
|
|
}
|
|
return 35.0f;
|
|
}
|
|
|
|
if (fabsf(pos->z) < 110.0f && ((fabsf(pos->x - 600.0f) < 110.0f) || (fabsf(pos->x + 600.0f) < 110.0f)) &&
|
|
(pos->y < 230.0f)) {
|
|
if (pos->y > 190.0f) {
|
|
return 230.0f;
|
|
}
|
|
return 35.0f;
|
|
}
|
|
|
|
if (pos->y < -20.0f) {
|
|
return 0.0f;
|
|
}
|
|
|
|
if (fabsf(pos->x) > 1140.0f || fabsf(pos->z) > 1140.0f) {
|
|
return 35.0f;
|
|
}
|
|
|
|
Matrix_Push();
|
|
Matrix_RotateY((45.0f * (M_PI / 180.0f)), MTXMODE_NEW);
|
|
Matrix_MultVec3f(pos, &posRotated);
|
|
Matrix_Pop();
|
|
|
|
if (fabsf(posRotated.x) > 920.0f || fabsf(posRotated.z) > 920.0f) {
|
|
return 35.0f;
|
|
}
|
|
|
|
return -100.0f;
|
|
}
|
|
|
|
void BossTw_ShootBeam(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 floorY;
|
|
Vec3f sp130;
|
|
Vec3s sp128;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
BossTw* otherTw = (BossTw*)this->actor.parent;
|
|
Input* input = &globalCtx->state.input[0];
|
|
|
|
Math_ApproachF(&this->actor.world.pos.y, 400.0f, 0.05f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 5.0f, 1.0f, 0.25f);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
this->beamRoll += -0.3f;
|
|
|
|
if (this->timers[1] != 0) {
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, this->rotateSpeed);
|
|
if ((player->stateFlags1 & 0x400000) &&
|
|
((s16)((player->actor.shape.rot.y - this->actor.shape.rot.y) + 0x8000) < 0x2000) &&
|
|
((s16)((player->actor.shape.rot.y - this->actor.shape.rot.y) + 0x8000) > -0x2000)) {
|
|
Math_ApproachF(&this->targetPos.x, player->bodyPartsPos[15].x, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.y, player->bodyPartsPos[15].y, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.z, player->bodyPartsPos[15].z, 1.0f, 400.0f);
|
|
} else {
|
|
Math_ApproachF(&this->targetPos.x, player->actor.world.pos.x, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.y, player->actor.world.pos.y + 30.0f, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.z, player->actor.world.pos.z, 1.0f, 400.0f);
|
|
}
|
|
|
|
this->timers[0] = 70;
|
|
this->groundBlastPos.x = this->groundBlastPos.y = this->groundBlastPos.z = 0.0f;
|
|
this->portalRotation += this->updateRate2 * 0.0025f;
|
|
Math_ApproachF(&this->spawnPortalAlpha, 255.0f, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->updateRate2, 50.0f, 1.0f, 2.0f);
|
|
|
|
if (this->timers[1] < 50) {
|
|
if (this->timers[1] < 10) {
|
|
if (this->timers[1] == 9) {
|
|
globalCtx->envCtx.unk_D8 = 0.5f;
|
|
globalCtx->envCtx.unk_BD = 3 - this->actor.params;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_MASIC_SET);
|
|
}
|
|
|
|
if (this->timers[1] == 5) {
|
|
this->scepterAlpha = 255;
|
|
}
|
|
|
|
if (this->timers[1] > 4) {
|
|
s16 j;
|
|
for (j = 0; j < 2; j++) {
|
|
for (i = 0; i < ARRAY_COUNT(this->scepterFlamePos); i++) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
pos.x = this->scepterFlamePos[i].x;
|
|
pos.y = this->scepterFlamePos[i].y;
|
|
pos.z = this->scepterFlamePos[i].z;
|
|
velocity.x = Rand_CenteredFloat(10.0f);
|
|
velocity.y = Rand_CenteredFloat(10.0f);
|
|
velocity.z = Rand_CenteredFloat(10.0f);
|
|
accel.x = 0.0f;
|
|
accel.y = 0.0f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &accel, Rand_ZeroFloat(10.0f) + 25.0f,
|
|
this->actor.params);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->timers[1] < 20) {
|
|
Math_ApproachF(&this->flameAlpha, 0, 1.0f, 20.0f);
|
|
Math_ApproachF(&this->spawnPortalAlpha, 0, 1.0f, 30.0f);
|
|
} else {
|
|
Math_ApproachF(&this->flameAlpha, 255.0f, 1.0f, 10.0f);
|
|
if (this->actor.params == 1) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_MS_FIRE - SFX_FLAG);
|
|
} else {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_MS_FREEZE - SFX_FLAG);
|
|
}
|
|
}
|
|
|
|
this->flameRotation += this->updateRate1 * 0.0025f;
|
|
Math_ApproachF(&this->spawnPortalScale, 0.0f, 0.1f, this->updateRate1);
|
|
Math_ApproachF(&this->updateRate1, 50.0f, 1.0f, 2.0f);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_009398, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = 10000.0f;
|
|
}
|
|
|
|
if (this->timers[1] == 1) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_003614, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_003614);
|
|
this->unk_4DC = 0.0f;
|
|
this->spawnPortalAlpha = 0.0f;
|
|
this->flameAlpha = 0.0f;
|
|
sBeamDivertTimer = 0;
|
|
}
|
|
} else {
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_003E34, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = 10000.0f;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT] - 5.0f)) {
|
|
this->beamShootState = 0;
|
|
sEnvType = this->actor.params + 1;
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT] - 13.0f)) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_THROW_MASIC);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_SHOOT_VOICE);
|
|
}
|
|
|
|
xDiff = this->targetPos.x - this->beamOrigin.x;
|
|
yDiff = this->targetPos.y - this->beamOrigin.y;
|
|
zDiff = this->targetPos.z - this->beamOrigin.z;
|
|
|
|
this->beamYaw = Math_FAtan2F(xDiff, zDiff);
|
|
this->beamPitch = -Math_FAtan2F(yDiff, sqrtf(SQ(xDiff) + SQ(zDiff)));
|
|
|
|
switch (this->beamShootState) {
|
|
case -1:
|
|
break;
|
|
case 0:
|
|
if (this->timers[0] != 0) {
|
|
s32 beamReflection = BossTw_CheckBeamReflection(this, globalCtx);
|
|
|
|
if (beamReflection == 1) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
velocity.x = Rand_CenteredFloat(15.0f);
|
|
velocity.y = Rand_CenteredFloat(15.0f);
|
|
velocity.z = Rand_CenteredFloat(15.0f);
|
|
pos = player->bodyPartsPos[15];
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 5,
|
|
this->actor.params, 150);
|
|
}
|
|
|
|
this->beamShootState = 1;
|
|
func_80078914(&player->actor.projectedPos, NA_SE_IT_SHIELD_REFLECT_MG);
|
|
Matrix_MtxFToYXZRotS(&player->shieldMf, &sp128, 0);
|
|
sp128.y += 0x8000;
|
|
sp128.x = -sp128.x;
|
|
this->magicDir.x = sp128.x;
|
|
this->magicDir.y = sp128.y;
|
|
this->groundBlastPos.x = 0.0f;
|
|
this->groundBlastPos.y = 0.0f;
|
|
this->groundBlastPos.z = 0.0f;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
func_800AA000(0.0f, 0x64, 5, 4);
|
|
} else if (beamReflection == 0) {
|
|
BossTw_BeamHitPlayerCheck(this, globalCtx);
|
|
|
|
if (this->csState1 == 0) {
|
|
Math_ApproachF(&this->beamDist, 2.0f * sqrtf(SQ(xDiff) + SQ(yDiff) + SQ(zDiff)), 1.0f,
|
|
40.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &this->beamReflectionOrigin,
|
|
&this->unk_54C, &this->actor.projectedW);
|
|
|
|
if (this->actor.params == 1) {
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_SHOOT_FIRE - SFX_FLAG, &this->unk_54C, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
} else {
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_SHOOT_FREEZE - SFX_FLAG, &this->unk_54C, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (CHECK_BTN_ALL(input->cur.button, BTN_R)) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
this->beamDist = sqrtf(SQ(xDiff) + SQ(yDiff) + SQ(zDiff));
|
|
Math_ApproachF(&this->beamReflectionDist, 2000.0f, 1.0f, 40.0f);
|
|
Math_ApproachF(&this->targetPos.x, player->bodyPartsPos[15].x, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.y, player->bodyPartsPos[15].y, 1.0f, 400.0f);
|
|
Math_ApproachF(&this->targetPos.z, player->bodyPartsPos[15].z, 1.0f, 400.0f);
|
|
if ((this->work[CS_TIMER_1] % 4) == 0) {
|
|
BossTw_AddRingEffect(globalCtx, &player->bodyPartsPos[15], 0.5f, 3.0f, 0xFF, this->actor.params,
|
|
1, 150);
|
|
}
|
|
} else {
|
|
this->beamShootState = 0;
|
|
this->beamReflectionDist = 0.0f;
|
|
}
|
|
|
|
SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &this->unk_530, &this->unk_558,
|
|
&this->actor.projectedW);
|
|
|
|
if (this->actor.params == 1) {
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_SHOOT_FIRE - SFX_FLAG, &this->unk_558, 4U, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_REFL_FIRE - SFX_FLAG, &this->unk_558, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
} else {
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_SHOOT_FREEZE - SFX_FLAG, &this->unk_558, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
Audio_PlaySoundGeneral(NA_SE_EN_TWINROBA_REFL_FREEZE - SFX_FLAG, &this->unk_558, 4, &D_801333E0,
|
|
&D_801333E0, &D_801333E8);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (this->timers[0] == 0 && (sEnvType == 1 || sEnvType == 2)) {
|
|
sEnvType = 0;
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
Math_ApproachF(&this->beamScale, 0.0f, 1.0f, 0.0005f);
|
|
|
|
if (this->beamScale == 0.0f) {
|
|
BossTw_SetupFinishBeamShoot(this, globalCtx);
|
|
this->beamReflectionDist = 0.0f;
|
|
this->beamDist = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
Matrix_Translate(this->beamOrigin.x, this->beamOrigin.y, this->beamOrigin.z, MTXMODE_NEW);
|
|
Matrix_RotateY(this->beamYaw, MTXMODE_APPLY);
|
|
Matrix_RotateX(this->beamPitch, MTXMODE_APPLY);
|
|
|
|
sp130.x = 0.0f;
|
|
sp130.y = 0.0f;
|
|
sp130.z = this->beamDist + -5.0f;
|
|
|
|
Matrix_MultVec3f(&sp130, &this->beamReflectionOrigin);
|
|
|
|
if ((this->csState1 == 0) && (this->beamShootState == 0) && (this->timers[0] != 0)) {
|
|
this->groundBlastPos.y = BossTw_GetFloorY(&this->beamReflectionOrigin);
|
|
|
|
if (this->groundBlastPos.y >= 0.0f) {
|
|
this->csState1 = 1;
|
|
this->groundBlastPos.x = this->beamReflectionOrigin.x;
|
|
this->groundBlastPos.z = this->beamReflectionOrigin.z;
|
|
BossTw_SpawnGroundBlast(this, globalCtx, this->actor.params);
|
|
this->timers[0] = 20;
|
|
}
|
|
}
|
|
|
|
if (this->beamShootState == 1) {
|
|
if (this->csState1 == 0) {
|
|
Matrix_MtxFToYXZRotS(&player->shieldMf, &sp128, 0);
|
|
sp128.y += 0x8000;
|
|
sp128.x = -sp128.x;
|
|
Math_ApproachS(&this->magicDir.x, sp128.x, 5, 0x2000);
|
|
Math_ApproachS(&this->magicDir.y, sp128.y, 5, 0x2000);
|
|
this->beamReflectionPitch = (this->magicDir.x / 32768.0f) * M_PI;
|
|
this->beamReflectionYaw = (this->magicDir.y / 32768.0f) * M_PI;
|
|
}
|
|
|
|
Matrix_Translate(this->beamReflectionOrigin.x, this->beamReflectionOrigin.y, this->beamReflectionOrigin.z,
|
|
MTXMODE_NEW);
|
|
Matrix_RotateY(this->beamReflectionYaw, MTXMODE_APPLY);
|
|
Matrix_RotateX(this->beamReflectionPitch, MTXMODE_APPLY);
|
|
|
|
sp130.x = 0.0f;
|
|
sp130.y = 0.0f;
|
|
sp130.z = this->beamReflectionDist + -170.0f;
|
|
|
|
Matrix_MultVec3f(&sp130, &this->unk_530);
|
|
|
|
if (this->csState1 == 0) {
|
|
sp130.z = 0.0f;
|
|
|
|
for (i = 0; i < 200; i++) {
|
|
Vec3f spBC;
|
|
|
|
Matrix_MultVec3f(&sp130, &spBC);
|
|
floorY = BossTw_GetFloorY(&spBC);
|
|
this->groundBlastPos.y = floorY;
|
|
|
|
if (floorY >= 0.0f) {
|
|
if ((this->groundBlastPos.y != 35.0f) && (0.0f < this->beamReflectionPitch) &&
|
|
(this->timers[0] != 0)) {
|
|
this->csState1 = 1;
|
|
this->groundBlastPos.x = spBC.x;
|
|
this->groundBlastPos.z = spBC.z;
|
|
BossTw_SpawnGroundBlast(this, globalCtx, this->actor.params);
|
|
this->timers[0] = 20;
|
|
} else {
|
|
for (i = 0; i < 5; i++) {
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
|
|
accel.x = 0.0f;
|
|
accel.y = 0.0f;
|
|
accel.z = 0.0f;
|
|
|
|
BossTw_AddFlameEffect(globalCtx, &this->unk_530, &velocity, &accel,
|
|
Rand_ZeroFloat(10.0f) + 25.0f, this->actor.params);
|
|
}
|
|
|
|
this->beamReflectionDist = sp130.z;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.8f, 1.0f, 0.2f);
|
|
}
|
|
break;
|
|
}
|
|
|
|
sp130.z += 20.0f;
|
|
|
|
if (this->beamReflectionDist < sp130.z) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BossTw_BeamReflHitCheck(this, &this->actor.world.pos) && (this->work[CS_TIMER_1] % 4) == 0) {
|
|
BossTw_AddRingEffect(globalCtx, &this->unk_530, 0.5f, 3.0f, 255, this->actor.params, 1, 150);
|
|
}
|
|
|
|
if (BossTw_BeamReflHitCheck(this, &otherTw->actor.world.pos) && otherTw->actionFunc != BossTw_HitByBeam) {
|
|
for (i = 0; i < 50; i++) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
pos.x = otherTw->actor.world.pos.x + Rand_CenteredFloat(50.0f);
|
|
pos.y = otherTw->actor.world.pos.y + Rand_CenteredFloat(50.0f);
|
|
pos.z = otherTw->actor.world.pos.z + Rand_CenteredFloat(50.0f);
|
|
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
|
|
accel.x = 0.0f;
|
|
accel.y = 0.0f;
|
|
accel.z = 0.0f;
|
|
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &accel, Rand_ZeroFloat(10.0f) + 25.0f,
|
|
this->actor.params);
|
|
}
|
|
|
|
BossTw_SetupHitByBeam(otherTw, globalCtx);
|
|
Audio_PlayActorSound2(&otherTw->actor, NA_SE_EN_TWINROBA_DAMAGE_VOICE);
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
otherTw->actor.colChkInfo.health++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupFinishBeamShoot(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_FinishBeamShoot;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_004548, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_004548);
|
|
}
|
|
|
|
void BossTw_FinishBeamShoot(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachF(&this->scepterAlpha, 0.0f, 1.0f, 10.0f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
if (sTwinrovaPtr->timers[2] == 0) {
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
} else {
|
|
BossTw_SetupLaugh(this, globalCtx);
|
|
}
|
|
|
|
this->scepterAlpha = 0.0f;
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupHitByBeam(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_HitByBeam;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_00578C, 0.0f);
|
|
this->timers[0] = 53;
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
if (this->actor.params == 0) {
|
|
this->work[FOG_TIMER] = 20;
|
|
}
|
|
}
|
|
|
|
void BossTw_HitByBeam(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if ((this->work[CS_TIMER_1] % 4) == 0) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
pos.x = this->actor.world.pos.x + Rand_CenteredFloat(80.0f);
|
|
pos.y = this->actor.world.pos.y + Rand_CenteredFloat(80.0f);
|
|
pos.z = this->actor.world.pos.z + Rand_CenteredFloat(80.0f);
|
|
|
|
velocity.x = 0.0f;
|
|
velocity.y = 0.0f;
|
|
velocity.z = 0.0f;
|
|
|
|
accel.x = 0.0f;
|
|
accel.y = 0.1f;
|
|
accel.z = 0.0f;
|
|
|
|
BossTw_AddDmgCloud(globalCtx, this->actor.params + 2, &pos, &velocity, &accel, Rand_ZeroFloat(10.0f) + 15.0f, 0,
|
|
0, 150);
|
|
}
|
|
|
|
if (this->actor.params == 1) {
|
|
Math_ApproachF(&this->fogR, 255.0f, 1.0f, 30.0f);
|
|
Math_ApproachF(&this->fogG, 255.0f, 1.0f, 30.0f);
|
|
Math_ApproachF(&this->fogB, 255.0f, 1.0f, 30.0f);
|
|
Math_ApproachF(&this->fogNear, 900.0f, 1.0f, 30.0f);
|
|
Math_ApproachF(&this->fogFar, 1099.0f, 1.0f, 30.0f);
|
|
}
|
|
|
|
Math_ApproachF(&this->actor.world.pos.y, ((Math_SinS(this->work[CS_TIMER_1] * 1500) * 20.0f) + 350.0f) + 50.0f,
|
|
0.1f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 5.0f, 1.0f, 1.0f);
|
|
|
|
this->actor.world.pos.y -= 50.0f;
|
|
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 4);
|
|
this->actor.world.pos.y += 50.0f;
|
|
|
|
if (this->actor.bgCheckFlags & 1) {
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
|
|
if (this->timers[0] == 1) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_006530, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_006530);
|
|
}
|
|
|
|
if ((this->timers[0] == 0) && Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupLaugh(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_Laugh;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_0088C8, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_0088C8);
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
|
|
void BossTw_Laugh(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 10.0f)) {
|
|
if (this->actor.params == TW_KOUME) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_LAUGH);
|
|
} else {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_LAUGH2);
|
|
}
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupSpin(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_Spin;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_007CA8, -3.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_007CA8);
|
|
this->actor.speedXZ = 0.0f;
|
|
SkelAnime_Update(&this->skelAnime);
|
|
this->timers[0] = 20;
|
|
}
|
|
|
|
void BossTw_Spin(BossTw* this, GlobalContext* globalCtx) {
|
|
if (this->timers[0] != 0) {
|
|
this->collider.base.colType = COLTYPE_METAL;
|
|
this->actor.shape.rot.y -= 0x3000;
|
|
|
|
if ((this->timers[0] % 4) == 0) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_ROLL);
|
|
}
|
|
} else {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.world.rot.y, 3, 0x2000);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
BossTw_SetupFlyTo(this, globalCtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupMergeCS(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_MergeCS;
|
|
this->rotateSpeed = 0.0f;
|
|
this->actor.speedXZ = 0.0f;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_006F28, -10.0f);
|
|
}
|
|
|
|
void BossTw_MergeCS(BossTw* this, GlobalContext* globalCtx) {
|
|
Math_ApproachF(&this->scepterAlpha, 0.0f, 1.0f, 10.0f);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
}
|
|
|
|
void BossTw_SetupWait(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_Wait;
|
|
this->visible = false;
|
|
this->actor.world.pos.y = -2000.0f;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
}
|
|
|
|
void BossTw_Wait(BossTw* this, GlobalContext* globalCtx) {
|
|
if ((this->actor.params == TW_TWINROVA) && (sKoumePtr->actionFunc == BossTw_FlyTo) &&
|
|
(sKotakePtr->actionFunc == BossTw_FlyTo) &&
|
|
((sKoumePtr->actor.colChkInfo.health + sKotakePtr->actor.colChkInfo.health) >= 4)) {
|
|
|
|
BossTw_TwinrovaSetupMergeCS(this, globalCtx);
|
|
BossTw_SetupMergeCS(sKotakePtr, globalCtx);
|
|
BossTw_SetupMergeCS(sKoumePtr, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupMergeCS(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaMergeCS;
|
|
this->csState2 = 0;
|
|
this->csState1 = 0;
|
|
}
|
|
|
|
void BossTw_TwinrovaMergeCS(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
Vec3f spB0;
|
|
Vec3f spA4;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
switch (this->csState2) {
|
|
case 0:
|
|
this->csState2 = 1;
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 0x39);
|
|
this->subCamId = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, 0, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->subCamId, CAM_STAT_ACTIVE);
|
|
this->subCamDist = 800.0f;
|
|
this->subCamYaw = M_PI;
|
|
sKoumePtr->actor.world.rot.x = 0;
|
|
sKoumePtr->actor.shape.rot.x = 0;
|
|
sKotakePtr->actor.world.rot.x = 0;
|
|
sKotakePtr->actor.shape.rot.x = 0;
|
|
this->workf[UNK_F9] = 0.0f;
|
|
this->workf[UNK_F10] = 0.0f;
|
|
this->workf[UNK_F11] = 600.0f;
|
|
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xC800FF);
|
|
this->work[CS_TIMER_2] = 0;
|
|
// fallthrough
|
|
case 1:
|
|
if (this->work[CS_TIMER_2] == 20) {
|
|
Message_StartTextbox(globalCtx, 0x6059, NULL);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 80) {
|
|
Message_StartTextbox(globalCtx, 0x605A, NULL);
|
|
}
|
|
|
|
this->subCamAt.x = 0.0f;
|
|
this->subCamAt.y = 440.0f;
|
|
this->subCamAt.z = 0.0f;
|
|
|
|
spB0.x = 0.0f;
|
|
spB0.y = 0.0f;
|
|
spB0.z = this->subCamDist;
|
|
|
|
Matrix_RotateY(this->subCamYaw, MTXMODE_NEW);
|
|
Matrix_MultVec3f(&spB0, &spA4);
|
|
|
|
this->subCamEye.x = spA4.x;
|
|
this->subCamEye.y = 300.0f;
|
|
this->subCamEye.z = spA4.z;
|
|
|
|
Math_ApproachF(&this->subCamYaw, 0.3f, 0.02f, 0.03f);
|
|
Math_ApproachF(&this->subCamDist, 200.0f, 0.1f, 5.0f);
|
|
break;
|
|
|
|
case 2:
|
|
spB0.x = 0.0f;
|
|
spB0.y = 0.0f;
|
|
spB0.z = this->subCamDist;
|
|
Matrix_RotateY(this->subCamYaw, MTXMODE_NEW);
|
|
Matrix_MultVec3f(&spB0, &spA4);
|
|
this->subCamEye.x = spA4.x;
|
|
this->subCamEye.z = spA4.z;
|
|
Math_ApproachF(&this->subCamEye.y, 420.0f, 0.1f, this->subCamUpdateRate * 20.0f);
|
|
Math_ApproachF(&this->subCamAt.y, 470.0f, 0.1f, this->subCamUpdateRate * 6.0f);
|
|
Math_ApproachF(&this->subCamYaw, 0.3f, 0.02f, 0.03f);
|
|
Math_ApproachF(&this->subCamDist, 60.0f, 0.1f, this->subCamUpdateRate * 32.0f);
|
|
Math_ApproachF(&this->subCamUpdateRate, 1, 1, 0.1f);
|
|
break;
|
|
}
|
|
|
|
if (this->subCamId != 0) {
|
|
if (this->unk_5F9 == 0) {
|
|
Gameplay_CameraSetAtEye(globalCtx, this->subCamId, &this->subCamAt, &this->subCamEye);
|
|
} else {
|
|
Gameplay_CameraSetAtEye(globalCtx, this->subCamId, &this->subCamAt2, &this->subCamEye2);
|
|
}
|
|
}
|
|
|
|
switch (this->csState1) {
|
|
case 0:
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
spB0.x = this->workf[UNK_F11];
|
|
spB0.y = 400.0f;
|
|
spB0.z = 0.0f;
|
|
Matrix_RotateY(this->workf[UNK_F9], MTXMODE_NEW);
|
|
Matrix_MultVec3f(&spB0, &spA4);
|
|
sKoumePtr->actor.world.pos.x = spA4.x;
|
|
sKoumePtr->actor.world.pos.y = spA4.y;
|
|
sKoumePtr->actor.world.pos.z = spA4.z;
|
|
sKoumePtr->actor.shape.rot.y = (this->workf[UNK_F9] / M_PI) * 32768.0f;
|
|
sKotakePtr->actor.world.pos.x = -spA4.x;
|
|
sKotakePtr->actor.world.pos.y = spA4.y;
|
|
sKotakePtr->actor.world.pos.z = -spA4.z;
|
|
sKotakePtr->actor.shape.rot.y = ((this->workf[UNK_F9] / M_PI) * 32768.0f) + 32768.0f;
|
|
Math_ApproachF(&this->workf[UNK_F11], 0.0f, 0.1f, 7.0f);
|
|
this->workf[UNK_F9] -= this->workf[UNK_F10];
|
|
Math_ApproachF(&this->workf[UNK_F10], 0.5f, 1, 0.0039999997f);
|
|
if (this->workf[UNK_F11] < 10.0f) {
|
|
if (!this->work[PLAYED_CHRG_SFX]) {
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_POWERUP);
|
|
this->work[PLAYED_CHRG_SFX] = true;
|
|
}
|
|
|
|
Math_ApproachF(&sKoumePtr->actor.scale.x, 0.005000001f, 1, 0.0003750001f);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
Vec3f pos;
|
|
f32 yOffset;
|
|
f32 xScale;
|
|
|
|
xScale = sKoumePtr->actor.scale.x * 3000.0f;
|
|
yOffset = Rand_CenteredFloat(xScale * 2.0f);
|
|
pos.x = 3000.0f;
|
|
pos.y = 400.0f + yOffset;
|
|
pos.z = 0.0f;
|
|
BossTw_AddMergeFlameEffect(globalCtx, &pos, Rand_ZeroFloat(5.0f) + 10.0f,
|
|
sqrtf(SQ(xScale) - SQ(yOffset)), Rand_ZeroFloat(1.99f));
|
|
}
|
|
|
|
if (sKoumePtr->actor.scale.x <= 0.0051f) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
this->actor.world.pos.y = 400.0f;
|
|
|
|
for (i = 0; i < 50; i++) {
|
|
pos = this->actor.world.pos;
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
pos.x += velocity.x;
|
|
pos.y += velocity.y;
|
|
pos.z += velocity.z;
|
|
accel.z = accel.y = accel.x = 0.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &accel, Rand_ZeroFloat(10.0f) + 25.0f,
|
|
velocity.x < 0.0f);
|
|
}
|
|
|
|
this->csState1 = 1;
|
|
this->visible = true;
|
|
this->actor.flags |= ACTOR_FLAG_0;
|
|
this->actor.shape.rot.y = 0;
|
|
BossTw_SetupWait(sKotakePtr, globalCtx);
|
|
BossTw_SetupWait(sKoumePtr, globalCtx);
|
|
Actor_SetScale(&this->actor, 0.0f);
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_038E2C, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_038E2C);
|
|
this->timers[0] = 50;
|
|
func_8002DF54(globalCtx, &this->actor, 2);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_TRANSFORM);
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
|
|
}
|
|
}
|
|
|
|
sKotakePtr->actor.scale.x = sKotakePtr->actor.scale.y = sKotakePtr->actor.scale.z =
|
|
sKoumePtr->actor.scale.y = sKoumePtr->actor.scale.z = sKoumePtr->actor.scale.x;
|
|
break;
|
|
|
|
case 1:
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, -15.0f);
|
|
}
|
|
|
|
sEnvType = -1;
|
|
globalCtx->envCtx.unk_BD = 4;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1, 1, 0.1f);
|
|
// fallthrough
|
|
case 2:
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachF(&this->actor.scale.x, 0.0069999993f, 1, 0.0006999999f);
|
|
this->actor.scale.y = this->actor.scale.z = this->actor.scale.x;
|
|
|
|
if (this->timers[0] == 1) {
|
|
this->csState2 = 2;
|
|
this->subCamUpdateRate = 0.0f;
|
|
this->timers[1] = 65;
|
|
this->timers[2] = 90;
|
|
this->timers[3] = 50;
|
|
player->actor.world.pos.x = 0.0f;
|
|
player->actor.world.pos.y = 240.0f;
|
|
player->actor.world.pos.z = 270.0f;
|
|
player->actor.world.rot.y = player->actor.shape.rot.y = -0x8000;
|
|
this->subCamEye2.x = 0.0f;
|
|
this->subCamEye2.y = 290.0f;
|
|
this->subCamEye2.z = 222.0f;
|
|
this->subCamAt2.x = player->actor.world.pos.x;
|
|
this->subCamAt2.y = player->actor.world.pos.y + 54.0f;
|
|
this->subCamAt2.z = player->actor.world.pos.z;
|
|
}
|
|
|
|
if (this->timers[3] == 19) {
|
|
func_8002DF54(globalCtx, &this->actor, 5);
|
|
}
|
|
|
|
if (this->timers[3] == 16) {
|
|
func_8002F7DC(&player->actor, player->ageProperties->unk_92 + NA_SE_VO_LI_SURPRISE);
|
|
}
|
|
|
|
if ((this->timers[3] != 0) && (this->timers[3] < 20)) {
|
|
this->unk_5F9 = 1;
|
|
Math_ApproachF(&this->subCamEye2.z, 242.0f, 0.2f, 100.0f);
|
|
} else {
|
|
this->unk_5F9 = 0;
|
|
}
|
|
|
|
if (this->timers[1] == 8) {
|
|
this->work[TW_BLINK_IDX] = 8;
|
|
func_80078884(NA_SE_EN_TWINROBA_YOUNG_WINK);
|
|
}
|
|
if (this->timers[2] == 4) {
|
|
sEnvType = 0;
|
|
globalCtx->envCtx.unk_BE = 5;
|
|
}
|
|
|
|
if (this->timers[2] == 1) {
|
|
Camera* cam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
|
|
cam->eye = this->subCamEye;
|
|
cam->eyeNext = this->subCamEye;
|
|
cam->at = this->subCamAt;
|
|
func_800C08AC(globalCtx, this->subCamId, 0);
|
|
this->subCamId = 0;
|
|
this->csState2 = this->subCamId;
|
|
func_80064534(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 7);
|
|
this->work[TW_PLLR_IDX] = 0;
|
|
this->targetPos = sTwinrovaPillarPos[0];
|
|
BossTw_TwinrovaSetupFly(this, globalCtx);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupDeathCS(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_DeathCS;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_0004A4, -3.0f);
|
|
this->unk_5F8 = 0;
|
|
this->work[CS_TIMER_2] = Rand_ZeroFloat(20.0f);
|
|
}
|
|
|
|
void BossTw_DeathCS(BossTw* this, GlobalContext* globalCtx) {
|
|
if (this->timers[0] == 0) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
}
|
|
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->work[YAW_TGT], 5, this->rotateSpeed);
|
|
Math_ApproachF(&this->rotateSpeed, 20480.0f, 1.0f, 1000.0f);
|
|
|
|
if (sTwinrovaPtr->work[CS_TIMER_2] > 140) {
|
|
Math_ApproachF(&this->fogR, 100.0f, 1.0f, 15.0f);
|
|
Math_ApproachF(&this->fogG, 255.0f, 1.0f, 15.0f);
|
|
Math_ApproachF(&this->fogB, 255.0f, 1.0f, 15.0f);
|
|
Math_ApproachF(&this->fogNear, 850.0f, 1.0f, 15.0f);
|
|
Math_ApproachF(&this->fogFar, 1099.0f, 1.0f, 15.0f);
|
|
}
|
|
}
|
|
|
|
void BossTw_SetupCSWait(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_CSWait;
|
|
this->visible = false;
|
|
this->actor.world.pos.y = -2000.0f;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
}
|
|
|
|
/**
|
|
* Do nothing while waiting for the inital cutscene to start
|
|
*/
|
|
void BossTw_CSWait(BossTw* this, GlobalContext* globalCtx) {
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupIntroCS(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaIntroCS;
|
|
this->visible = false;
|
|
this->actor.world.pos.y = -2000.0f;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
}
|
|
|
|
void BossTw_TwinrovaIntroCS(BossTw* this, GlobalContext* globalCtx) {
|
|
u8 updateCam = 0;
|
|
s16 i;
|
|
Vec3f sp90;
|
|
Vec3f sp84;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
if (this->csSfxTimer > 220 && this->csSfxTimer < 630) {
|
|
func_80078884(NA_SE_EN_TWINROBA_UNARI - SFX_FLAG);
|
|
}
|
|
|
|
if (this->csSfxTimer == 180) {
|
|
func_80078914(&D_8094A7D0, NA_SE_EN_TWINROBA_LAUGH);
|
|
func_80078914(&D_8094A7D0, NA_SE_EN_TWINROBA_LAUGH2);
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_KOTAKE_KOUME);
|
|
}
|
|
|
|
this->csSfxTimer++;
|
|
|
|
switch (this->csState2) {
|
|
case 0:
|
|
this->csSfxTimer = 0;
|
|
|
|
if (SQ(player->actor.world.pos.x) + SQ(player->actor.world.pos.z) < SQ(150.0f)) {
|
|
player->actor.world.pos.x = player->actor.world.pos.z = .0f;
|
|
this->csState2 = 1;
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 0x39);
|
|
this->subCamId = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, 0, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->subCamId, CAM_STAT_ACTIVE);
|
|
this->subCamEye.x = 0.0f;
|
|
this->subCamEye.y = 350;
|
|
this->subCamEye.z = 200;
|
|
|
|
this->subCamEyeTarget.x = 450;
|
|
this->subCamEyeTarget.y = 900;
|
|
|
|
this->subCamAt.x = 0;
|
|
this->subCamAt.y = 270;
|
|
this->subCamAt.z = 0;
|
|
|
|
this->subCamAtTarget.x = 0;
|
|
this->subCamAtTarget.y = 240;
|
|
this->subCamAtTarget.z = 140;
|
|
|
|
this->subCamEyeTarget.z = 530;
|
|
this->subCamEyeStep.x = fabsf(this->subCamEyeTarget.x - this->subCamEye.x);
|
|
this->subCamEyeStep.y = fabsf(this->subCamEyeTarget.y - this->subCamEye.y);
|
|
this->subCamEyeStep.z = fabsf(this->subCamEyeTarget.z - this->subCamEye.z);
|
|
this->subCamAtStep.x = fabsf(this->subCamAtTarget.x - this->subCamAt.x);
|
|
this->subCamAtStep.y = fabsf(this->subCamAtTarget.y - this->subCamAt.y);
|
|
this->subCamAtStep.z = fabsf(this->subCamAtTarget.z - this->subCamAt.z);
|
|
|
|
this->subCamDistStep = 0.05f;
|
|
this->work[CS_TIMER_1] = 0;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
updateCam = 1;
|
|
|
|
if (this->work[CS_TIMER_1] == 30) {
|
|
Message_StartTextbox(globalCtx, 0x6048, NULL);
|
|
}
|
|
|
|
Math_ApproachF(&this->subCamUpdateRate, 0.01f, 1.0f, 0.0001f);
|
|
|
|
if (this->work[CS_TIMER_1] > 100) {
|
|
globalCtx->envCtx.unk_BD = 0;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.03f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 180) {
|
|
func_80078884(NA_SE_EN_TWINROBA_APPEAR_MS);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] > 180) {
|
|
this->spawnPortalScale = 0.05f;
|
|
Math_ApproachF(&this->spawnPortalAlpha, 255.0f, 1.0f, 5.f);
|
|
|
|
if (this->work[CS_TIMER_1] >= 236) {
|
|
this->csState2 = 2;
|
|
sKoumePtr->visible = 1;
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_0004A4, 0.0f);
|
|
sKoumePtr->actor.world.pos.x = 0.0f;
|
|
sKoumePtr->actor.world.pos.y = 80.0f;
|
|
sKoumePtr->actor.world.pos.z = 600.0f;
|
|
sKoumePtr->actor.shape.rot.y = sKoumePtr->actor.world.rot.y = -0x8000;
|
|
|
|
this->subCamEye.x = -30;
|
|
this->subCamEye.y = 260;
|
|
this->subCamEye.z = 470;
|
|
|
|
this->subCamAt.x = 0.0F;
|
|
this->subCamAt.y = 270;
|
|
this->subCamAt.z = 600.0F;
|
|
|
|
this->work[CS_TIMER_1] = 0;
|
|
|
|
Actor_SetScale(&sKoumePtr->actor, 0.014999999f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
SkelAnime_Update(&sKoumePtr->skelAnime);
|
|
Math_ApproachF(&sKoumePtr->actor.world.pos.y, 240.0f, 0.05f, 5.0f);
|
|
this->subCamEye.x -= 0.2f;
|
|
this->subCamEye.z += 0.2f;
|
|
|
|
if (this->work[CS_TIMER_1] > 50) {
|
|
this->csState2 = 3;
|
|
|
|
this->subCamEyeTarget.x = -30;
|
|
this->subCamEyeTarget.y = 260;
|
|
this->subCamEyeTarget.z = 530;
|
|
|
|
this->subCamAtTarget.x = 0.0f;
|
|
this->subCamAtTarget.y = 265;
|
|
this->subCamAtTarget.z = 580;
|
|
|
|
this->subCamEyeStep.x = fabsf(this->subCamEyeTarget.x - this->subCamEye.x);
|
|
this->subCamEyeStep.y = fabsf(this->subCamEyeTarget.y - this->subCamEye.y);
|
|
this->subCamEyeStep.z = fabsf(this->subCamEyeTarget.z - this->subCamEye.z);
|
|
this->subCamAtStep.x = fabsf(this->subCamAtTarget.x - this->subCamAt.x);
|
|
this->subCamAtStep.y = fabsf(this->subCamAtTarget.y - this->subCamAt.y);
|
|
this->subCamAtStep.z = fabsf(this->subCamAtTarget.z - this->subCamAt.z);
|
|
this->subCamUpdateRate = 0;
|
|
this->subCamDistStep = 0.1f;
|
|
this->work[CS_TIMER_1] = 0;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
SkelAnime_Update(&sKoumePtr->skelAnime);
|
|
updateCam = 1;
|
|
Math_ApproachF(&sKoumePtr->actor.world.pos.y, 240.0f, 0.05f, 5.0f);
|
|
Math_ApproachF(&this->subCamUpdateRate, 1.0f, 1.0f, 0.02f);
|
|
|
|
if (this->work[CS_TIMER_1] == 30) {
|
|
Message_StartTextbox(globalCtx, 0x6049, NULL);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] > 80) {
|
|
this->csState2 = 4;
|
|
this->actor.speedXZ = 0;
|
|
|
|
this->subCamEyeTarget.x = -80.0f;
|
|
this->subCamEyeTarget.y = 260.0f;
|
|
this->subCamEyeTarget.z = 430.0f;
|
|
|
|
this->subCamAtTarget.x = sKoumePtr->actor.world.pos.x;
|
|
this->subCamAtTarget.y = sKoumePtr->actor.world.pos.y + 20.0f;
|
|
this->subCamAtTarget.z = sKoumePtr->actor.world.pos.z;
|
|
|
|
this->subCamEyeStep.x = fabsf(this->subCamEyeTarget.x - this->subCamEye.x);
|
|
this->subCamEyeStep.y = fabsf(this->subCamEyeTarget.y - this->subCamEye.y);
|
|
this->subCamEyeStep.z = fabsf(this->subCamEyeTarget.z - this->subCamEye.z);
|
|
this->subCamAtStep.x = fabsf(this->subCamAtTarget.x - this->subCamAt.x);
|
|
this->subCamAtStep.y = fabsf(this->subCamAtTarget.y - this->subCamAt.y);
|
|
this->subCamAtStep.z = fabsf(this->subCamAtTarget.z - this->subCamAt.z);
|
|
this->subCamUpdateRate = 0.0f;
|
|
this->subCamDistStep = 0.05f;
|
|
Animation_MorphToPlayOnce(&sKoumePtr->skelAnime, &object_tw_Anim_000AAC, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_000AAC);
|
|
this->work[CS_TIMER_1] = 0;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
updateCam = 1;
|
|
SkelAnime_Update(&sKoumePtr->skelAnime);
|
|
this->subCamAtTarget.y = 20.0f + sKoumePtr->actor.world.pos.y;
|
|
Math_ApproachF(&sKoumePtr->actor.world.pos.y, 350, 0.1f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 9.0f, 1.0f, 0.9f);
|
|
Math_ApproachF(&this->subCamUpdateRate, 1.0f, 1.0f, 0.02f);
|
|
|
|
if (this->work[CS_TIMER_1] >= 30) {
|
|
if (this->work[CS_TIMER_1] < 45) {
|
|
globalCtx->envCtx.unk_BE = 0;
|
|
globalCtx->envCtx.unk_BD = 2;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
} else {
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.1f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 30) {
|
|
for (i = 0; i < 50; i++) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
|
|
pos.x = sKoumePtr->actor.world.pos.x + Rand_CenteredFloat(50.0f);
|
|
pos.y = sKoumePtr->actor.world.pos.y + Rand_CenteredFloat(50.0f);
|
|
pos.z = sKoumePtr->actor.world.pos.z + Rand_CenteredFloat(50.0f);
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &sZeroVector, Rand_ZeroFloat(10.0f) + 25.0f,
|
|
1);
|
|
}
|
|
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_TRANSFORM);
|
|
globalCtx->envCtx.unk_D8 = 0;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] >= 35) {
|
|
if (this->work[CS_TIMER_1] < 50) {
|
|
Math_ApproachF(&sKoumePtr->actor.scale.x,
|
|
((Math_SinS(this->work[CS_TIMER_1] * 0x4200) * 20.0f) / 10000.0f) + 0.024999999f,
|
|
1.0f, 0.005f);
|
|
} else {
|
|
if (this->work[CS_TIMER_1] == 50) {
|
|
Animation_MorphToPlayOnce(&sKoumePtr->skelAnime, &object_tw_Anim_0088C8, -5);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_0088C8);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 60) {
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_LAUGH);
|
|
}
|
|
|
|
if (Animation_OnFrame(&sKoumePtr->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_006F28, 0.f);
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
}
|
|
|
|
Math_ApproachF(&sKoumePtr->actor.scale.x, 0.024999999f, 0.1f, 0.005f);
|
|
}
|
|
|
|
Actor_SetScale(&sKoumePtr->actor, sKoumePtr->actor.scale.x);
|
|
sKoumePtr->actor.shape.rot.y = -0x8000;
|
|
sKoumePtr->unk_5F8 = 1;
|
|
|
|
if (this->work[CS_TIMER_1] == 0x64) {
|
|
this->csState2 = 10;
|
|
this->work[CS_TIMER_1] = 0;
|
|
this->subCamYawStep = 0.0f;
|
|
sKotakePtr->visible = 1;
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_0004A4, 0.0f);
|
|
sKotakePtr->actor.world.pos.x = 0.0f;
|
|
sKotakePtr->actor.world.pos.y = 80.0f;
|
|
sKotakePtr->actor.world.pos.z = -600.0f;
|
|
sKotakePtr->actor.shape.rot.y = sKotakePtr->actor.world.rot.y = 0;
|
|
this->work[CS_TIMER_1] = 0;
|
|
|
|
this->subCamEye.x = -30.0f;
|
|
this->subCamEye.y = 260.0f;
|
|
this->subCamEye.z = -470.0f;
|
|
|
|
this->subCamAt.x = 0;
|
|
this->subCamAt.y = 270.0f;
|
|
this->subCamAt.z = -600.0f;
|
|
Actor_SetScale(&sKotakePtr->actor, 0.014999999f);
|
|
}
|
|
} else {
|
|
sKoumePtr->actor.shape.rot.y = sKoumePtr->actor.shape.rot.y + (s16)this->subCamYawStep;
|
|
}
|
|
} else {
|
|
if ((this->work[CS_TIMER_1] % 8) == 0) {
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_ROLL);
|
|
}
|
|
|
|
sKoumePtr->actor.shape.rot.y = sKoumePtr->actor.shape.rot.y + (s16)this->subCamYawStep;
|
|
Math_ApproachF(&this->subCamYawStep, 12288.0f, 1.0f, 384.0f);
|
|
|
|
if (Animation_OnFrame(&sKoumePtr->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_006F28, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 10:
|
|
SkelAnime_Update(&sKotakePtr->skelAnime);
|
|
Math_ApproachF(&sKotakePtr->actor.world.pos.y, 240.0f, 0.05f, 5.0f);
|
|
this->subCamEye.x -= 0.2f;
|
|
this->subCamEye.z -= 0.2f;
|
|
|
|
if (this->work[CS_TIMER_1] >= 0x33) {
|
|
this->csState2 = 11;
|
|
this->subCamEyeTarget.x = -30;
|
|
this->subCamEyeTarget.y = 260;
|
|
this->subCamEyeTarget.z = -530;
|
|
this->subCamAtTarget.x = 0;
|
|
this->subCamAtTarget.y = 265;
|
|
this->subCamAtTarget.z = -580;
|
|
this->subCamEyeStep.x = fabsf(this->subCamEyeTarget.x - this->subCamEye.x);
|
|
this->subCamEyeStep.y = fabsf(this->subCamEyeTarget.y - this->subCamEye.y);
|
|
this->subCamEyeStep.z = fabsf(this->subCamEyeTarget.z - this->subCamEye.z);
|
|
this->subCamAtStep.x = fabsf(this->subCamAtTarget.x - this->subCamAt.x);
|
|
this->subCamAtStep.y = fabsf(this->subCamAtTarget.y - this->subCamAt.y);
|
|
this->subCamAtStep.z = fabsf(this->subCamAtTarget.z - this->subCamAt.z);
|
|
this->subCamUpdateRate = 0;
|
|
this->subCamDistStep = 0.1f;
|
|
this->work[CS_TIMER_1] = 0;
|
|
}
|
|
break;
|
|
|
|
case 11:
|
|
SkelAnime_Update(&sKotakePtr->skelAnime);
|
|
updateCam = 1;
|
|
Math_ApproachF(&sKotakePtr->actor.world.pos.y, 240.0f, 0.05f, 5.0f);
|
|
Math_ApproachF(&this->subCamUpdateRate, 1.0f, 1.0f, 0.02f);
|
|
|
|
if (this->work[CS_TIMER_1] == 30) {
|
|
Message_StartTextbox(globalCtx, 0x604A, NULL);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] > 80) {
|
|
this->csState2 = 12;
|
|
this->actor.speedXZ = 0;
|
|
|
|
this->subCamEyeTarget.y = 260.0f;
|
|
this->subCamEyeTarget.x = -80.0f;
|
|
this->subCamEyeTarget.z = -430.0f;
|
|
|
|
this->subCamAtTarget.x = sKotakePtr->actor.world.pos.x;
|
|
this->subCamAtTarget.y = sKotakePtr->actor.world.pos.y + 20.0f;
|
|
this->subCamAtTarget.z = sKotakePtr->actor.world.pos.z;
|
|
|
|
this->subCamEyeStep.x = fabsf(this->subCamEyeTarget.x - this->subCamEye.x);
|
|
this->subCamEyeStep.y = fabsf(this->subCamEyeTarget.y - this->subCamEye.y);
|
|
this->subCamEyeStep.z = fabsf(this->subCamEyeTarget.z - this->subCamEye.z);
|
|
this->subCamAtStep.x = fabsf(this->subCamAtTarget.x - this->subCamAt.x);
|
|
this->subCamAtStep.y = fabsf(this->subCamAtTarget.y - this->subCamAt.y);
|
|
this->subCamAtStep.z = fabsf(this->subCamAtTarget.z - this->subCamAt.z);
|
|
this->subCamUpdateRate = 0;
|
|
this->subCamDistStep = 0.05f;
|
|
Animation_MorphToPlayOnce(&sKotakePtr->skelAnime, &object_tw_Anim_000AAC, 0);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_000AAC);
|
|
this->work[CS_TIMER_1] = 0;
|
|
}
|
|
break;
|
|
|
|
case 12:
|
|
updateCam = 1;
|
|
SkelAnime_Update(&sKotakePtr->skelAnime);
|
|
this->subCamAtTarget.y = sKotakePtr->actor.world.pos.y + 20.0f;
|
|
Math_ApproachF(&sKotakePtr->actor.world.pos.y, 350, 0.1f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 9.0f, 1.0f, 0.9f);
|
|
Math_ApproachF(&this->subCamUpdateRate, 1.0f, 1.0f, 0.02f);
|
|
|
|
if (this->work[CS_TIMER_1] >= 30) {
|
|
if (this->work[CS_TIMER_1] < 45) {
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
} else {
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.1f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 30) {
|
|
for (i = 0; i < 50; i++) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
pos.x = sKotakePtr->actor.world.pos.x + Rand_CenteredFloat(50.0f);
|
|
pos.y = sKotakePtr->actor.world.pos.y + Rand_CenteredFloat(50.0f);
|
|
pos.z = sKotakePtr->actor.world.pos.z + Rand_CenteredFloat(50.0f);
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &sZeroVector, Rand_ZeroFloat(10.f) + 25.0f,
|
|
0);
|
|
}
|
|
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_TRANSFORM);
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] >= 35) {
|
|
if (this->work[CS_TIMER_1] < 50) {
|
|
Math_ApproachF(&sKotakePtr->actor.scale.x,
|
|
((Math_SinS(this->work[CS_TIMER_1] * 0x4200) * 20.0f) / 10000.0f) + 0.024999999f,
|
|
1.0f, 0.005f);
|
|
} else {
|
|
if (this->work[CS_TIMER_1] == 50) {
|
|
Animation_MorphToPlayOnce(&sKotakePtr->skelAnime, &object_tw_Anim_0088C8, -5.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_0088C8);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 60) {
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_LAUGH2);
|
|
}
|
|
|
|
if (Animation_OnFrame(&sKotakePtr->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_006F28, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
}
|
|
|
|
Math_ApproachF(&sKotakePtr->actor.scale.x, 0.024999999f, 0.1f, 0.005f);
|
|
}
|
|
|
|
Actor_SetScale(&sKotakePtr->actor, sKotakePtr->actor.scale.x);
|
|
sKotakePtr->actor.shape.rot.y = 0;
|
|
sKotakePtr->unk_5F8 = 1;
|
|
|
|
if (this->work[CS_TIMER_1] == 100) {
|
|
this->csState2 = 20;
|
|
this->work[CS_TIMER_1] = 0;
|
|
|
|
this->workf[UNK_F11] = 600.0f;
|
|
|
|
this->subCamEye.x = 800.0f;
|
|
this->subCamEye.y = 300.0f;
|
|
this->subCamEye.z = 0;
|
|
|
|
this->subCamAt.x = 0.0f;
|
|
this->subCamAt.y = 400.0f;
|
|
this->subCamAt.z = 0;
|
|
|
|
this->workf[UNK_F9] = -M_PI / 2.0f;
|
|
this->workf[UNK_F10] = 0.0f;
|
|
|
|
this->subCamEyeStep.x = 0.0f;
|
|
this->spawnPortalAlpha = 0.0f;
|
|
}
|
|
} else {
|
|
sKotakePtr->actor.shape.rot.y = sKotakePtr->actor.shape.rot.y + (s16)this->subCamYawStep;
|
|
}
|
|
} else {
|
|
if ((this->work[CS_TIMER_1] % 8) == 0) {
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_ROLL);
|
|
}
|
|
|
|
sKotakePtr->actor.shape.rot.y = sKotakePtr->actor.shape.rot.y + (s16)this->subCamYawStep;
|
|
Math_ApproachF(&this->subCamYawStep, 12288.0f, 1.0f, 384.0f);
|
|
|
|
if (Animation_OnFrame(&sKotakePtr->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_006F28, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 20:
|
|
if (this->work[CS_TIMER_1] > 20 && this->work[CS_TIMER_1] < 120) {
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.015f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 90) {
|
|
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x5A00FF);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 120) {
|
|
sEnvType = 0;
|
|
globalCtx->envCtx.unk_BE = 1;
|
|
globalCtx->envCtx.unk_BD = 1;
|
|
globalCtx->envCtx.unk_D8 = 0.0f;
|
|
TitleCard_InitBossName(globalCtx, &globalCtx->actorCtx.titleCtx, SEGMENTED_TO_VIRTUAL(gTwinrovaTitleCardTex), 160, 180, 128, 40, true);
|
|
gSaveContext.eventChkInf[7] |= 0x20;
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] >= 160) {
|
|
if (this->work[CS_TIMER_1] == 160) {
|
|
this->subCamEyeStep.x = 0.0f;
|
|
}
|
|
Math_ApproachF(&this->subCamEye.x, 0.0f, 0.05f, this->subCamEyeStep.x * 0.5f);
|
|
Math_ApproachF(&this->subCamEye.z, 1000.0f, 0.05f, this->subCamEyeStep.x);
|
|
Math_ApproachF(&this->subCamEyeStep.x, 40.0f, 1.0f, 1);
|
|
} else {
|
|
Math_ApproachF(&this->subCamEye.x, 300.0f, 0.05f, this->subCamEyeStep.x);
|
|
Math_ApproachF(&this->subCamEyeStep.x, 5.0f, 1.0f, 0.5f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] < 200) {
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
sp90.x = this->workf[UNK_F11];
|
|
sp90.y = 400.0f;
|
|
sp90.z = 0.0f;
|
|
Matrix_RotateY(this->workf[UNK_F9], MTXMODE_NEW);
|
|
Matrix_MultVec3f(&sp90, &sp84);
|
|
sKoumePtr->actor.world.pos.x = sp84.x;
|
|
sKoumePtr->actor.world.pos.y = sp84.y;
|
|
sKoumePtr->actor.world.pos.z = sp84.z;
|
|
sKoumePtr->actor.world.rot.y = sKoumePtr->actor.shape.rot.y = (this->workf[UNK_F9] / M_PI) * 32768.0f;
|
|
sKotakePtr->actor.world.pos.x = -sp84.x;
|
|
sKotakePtr->actor.world.pos.y = sp84.y;
|
|
sKotakePtr->actor.world.pos.z = -sp84.z;
|
|
sKotakePtr->actor.shape.rot.y = sKotakePtr->actor.world.rot.y =
|
|
((this->workf[UNK_F9] / M_PI) * 32768.0f) + 32768.0f;
|
|
Math_ApproachF(&this->workf[UNK_F11], 80.0f, 0.1f, 5.0f);
|
|
this->workf[UNK_F9] -= this->workf[UNK_F10];
|
|
Math_ApproachF(&this->workf[UNK_F10], 0.19999999f, 1.0f, 0.0019999994f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 200) {
|
|
sKoumePtr->actionFunc = BossTw_FlyTo;
|
|
sKotakePtr->actionFunc = BossTw_FlyTo;
|
|
sKoumePtr->targetPos.x = 600.0f;
|
|
sKoumePtr->targetPos.y = 400.0f;
|
|
sKoumePtr->targetPos.z = 0.0f;
|
|
sKoumePtr->timers[0] = 100;
|
|
sKotakePtr->targetPos.x = -600.0f;
|
|
sKotakePtr->targetPos.y = 400.0f;
|
|
sKotakePtr->targetPos.z = 0.0f;
|
|
sKotakePtr->timers[0] = 100;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] == 260) {
|
|
Camera* cam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
|
|
cam->eye = this->subCamEye;
|
|
cam->eyeNext = this->subCamEye;
|
|
cam->at = this->subCamAt;
|
|
func_800C08AC(globalCtx, this->subCamId, 0);
|
|
this->subCamId = 0;
|
|
this->csState2 = this->subCamId;
|
|
func_80064534(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 7);
|
|
BossTw_SetupWait(this, globalCtx);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (this->subCamId != 0) {
|
|
if (updateCam) {
|
|
Math_ApproachF(&this->subCamEye.x, this->subCamEyeTarget.x, this->subCamDistStep,
|
|
this->subCamEyeStep.x * this->subCamUpdateRate);
|
|
Math_ApproachF(&this->subCamEye.y, this->subCamEyeTarget.y, this->subCamDistStep,
|
|
this->subCamEyeStep.y * this->subCamUpdateRate);
|
|
Math_ApproachF(&this->subCamEye.z, this->subCamEyeTarget.z, this->subCamDistStep,
|
|
this->subCamEyeStep.z * this->subCamUpdateRate);
|
|
Math_ApproachF(&this->subCamAt.x, this->subCamAtTarget.x, this->subCamDistStep,
|
|
this->subCamAtStep.x * this->subCamUpdateRate);
|
|
Math_ApproachF(&this->subCamAt.y, this->subCamAtTarget.y, this->subCamDistStep,
|
|
this->subCamAtStep.y * this->subCamUpdateRate);
|
|
Math_ApproachF(&this->subCamAt.z, this->subCamAtTarget.z, this->subCamDistStep,
|
|
this->subCamAtStep.z * this->subCamUpdateRate);
|
|
}
|
|
|
|
Gameplay_CameraSetAtEye(globalCtx, this->subCamId, &this->subCamAt, &this->subCamEye);
|
|
}
|
|
}
|
|
|
|
void BossTw_DeathBall(BossTw* this, GlobalContext* globalCtx) {
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
s32 pad;
|
|
s16 i;
|
|
s16 yaw;
|
|
|
|
if ((this->work[CS_TIMER_1] % 16) == 0) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_FB_FLY);
|
|
}
|
|
|
|
if (sTwinrovaPtr->csState2 < 2) {
|
|
if (this->timers[0] == 0) {
|
|
this->timers[0] = 20;
|
|
this->targetPos.x = Rand_CenteredFloat(100.0f) + sTwinrovaPtr->actor.world.pos.x;
|
|
this->targetPos.y = Rand_CenteredFloat(50.0f) + 400.0f;
|
|
this->targetPos.z = Rand_CenteredFloat(100.0f) + sTwinrovaPtr->actor.world.pos.z;
|
|
}
|
|
|
|
this->timers[1] = 10;
|
|
this->rotateSpeed = 8192.0f;
|
|
this->actor.speedXZ = 5.0f;
|
|
} else {
|
|
if (this->timers[1] == 9) {
|
|
this->targetPos.y = 413.0f;
|
|
this->actor.world.pos.z = 0.0f;
|
|
this->actor.world.pos.x = 0.0f;
|
|
for (i = 0; i < ARRAY_COUNT(this->blastTailPos); i++) {
|
|
this->blastTailPos[i] = this->actor.world.pos;
|
|
}
|
|
}
|
|
|
|
if (this->actor.params == 0x69) {
|
|
this->targetPos.x = sKoumePtr->actor.world.pos.x;
|
|
this->targetPos.z = sKoumePtr->actor.world.pos.z;
|
|
} else {
|
|
this->targetPos.x = sKotakePtr->actor.world.pos.x;
|
|
this->targetPos.z = sKotakePtr->actor.world.pos.z;
|
|
}
|
|
|
|
Math_ApproachF(&this->targetPos.y, 263.0f, 1.0f, 2.0f);
|
|
|
|
if (this->targetPos.y == 263.0f) {
|
|
Math_ApproachF(&this->actor.speedXZ, 0.0f, 1.0f, 0.2f);
|
|
if (sTwinrovaPtr->csState2 == 3) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
}
|
|
}
|
|
|
|
xDiff = this->targetPos.x - this->actor.world.pos.x;
|
|
yDiff = this->targetPos.y - this->actor.world.pos.y;
|
|
zDiff = this->targetPos.z - this->actor.world.pos.z;
|
|
|
|
yaw = Math_FAtan2F(xDiff, zDiff) * (32768 / M_PI);
|
|
Math_ApproachS(&this->actor.world.rot.x, Math_FAtan2F(yDiff, sqrtf(SQ(xDiff) + SQ(zDiff))) * (32768 / M_PI), 5,
|
|
this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.world.rot.y, yaw, 5, this->rotateSpeed);
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupDeathCS(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaDeathCS;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_024374, -3.0f);
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
this->csState2 = this->csState1 = 0;
|
|
this->work[CS_TIMER_1] = this->work[CS_TIMER_2] = 0;
|
|
this->work[INVINC_TIMER] = 10000;
|
|
BossTw_SetupDeathCS(sKoumePtr, globalCtx);
|
|
BossTw_SetupDeathCS(sKotakePtr, globalCtx);
|
|
sKotakePtr->timers[0] = 8;
|
|
this->workf[UNK_F19] = 1.0f;
|
|
}
|
|
|
|
void BossTw_DeathCSMsgSfx(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
s32 pad2;
|
|
s32 pad3;
|
|
s16 msgId2;
|
|
s16 msgId1;
|
|
u8 kotakeAnim;
|
|
u8 koumeAnim;
|
|
u8 sp35;
|
|
|
|
msgId2 = 0;
|
|
msgId1 = 0;
|
|
kotakeAnim = 0;
|
|
koumeAnim = 0;
|
|
sp35 = 0;
|
|
|
|
if (this->work[CS_TIMER_2] == 80) {
|
|
koumeAnim = 1;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 80) {
|
|
msgId2 = 0x604B;
|
|
sp35 = 50;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 140) {
|
|
kotakeAnim = koumeAnim = 2;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 170) {
|
|
kotakeAnim = 3;
|
|
sKotakePtr->work[YAW_TGT] = -0x4000;
|
|
sKotakePtr->rotateSpeed = 0.0f;
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_SENSE);
|
|
msgId2 = 0x604C;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 210) {
|
|
D_8094C874 = 30;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 270) {
|
|
koumeAnim = 3;
|
|
sKoumePtr->work[YAW_TGT] = 0x4000;
|
|
sKoumePtr->rotateSpeed = 0.0f;
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_SENSE);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 290) {
|
|
msgId2 = 0x604D;
|
|
sp35 = 35;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 350) {
|
|
koumeAnim = kotakeAnim = 2;
|
|
sKoumePtr->work[YAW_TGT] = sKotakePtr->work[YAW_TGT] = 0;
|
|
sKoumePtr->rotateSpeed = sKotakePtr->rotateSpeed = 0.0f;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 380) {
|
|
koumeAnim = kotakeAnim = 3;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 400) {
|
|
koumeAnim = kotakeAnim = 2;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 430) {
|
|
koumeAnim = 4;
|
|
D_8094C874 = 435;
|
|
D_8094C878 = 1;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] > 440 && this->work[CS_TIMER_2] < 860) {
|
|
func_80078884(NA_SE_EN_TWINROBA_FIGHT - SFX_FLAG);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 430) {
|
|
msgId2 = 0x604E;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 480) {
|
|
kotakeAnim = 4;
|
|
sKotakePtr->work[YAW_TGT] = -0x4000;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 500) {
|
|
koumeAnim = 2;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 480) {
|
|
msgId1 = 0x604F;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 530) {
|
|
koumeAnim = 4;
|
|
sKoumePtr->work[YAW_TGT] = 0x4000;
|
|
D_8094C87A = 335;
|
|
D_8094C87E = 1;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 530) {
|
|
msgId2 = 0x6050;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 580) {
|
|
msgId1 = 0x6051;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 620) {
|
|
msgId2 = 0x6052;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 660) {
|
|
msgId1 = 0x6053;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 700) {
|
|
msgId2 = 0x6054;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 740) {
|
|
msgId1 = 0x6055;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 780) {
|
|
msgId2 = 0x6056;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 820) {
|
|
msgId1 = 0x6057;
|
|
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x5000FF);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 860) {
|
|
koumeAnim = kotakeAnim = 3;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 900) {
|
|
Audio_PlayActorSound2(&sKoumePtr->actor, NA_SE_EN_TWINROBA_DIE);
|
|
Audio_PlayActorSound2(&sKotakePtr->actor, NA_SE_EN_TWINROBA_DIE);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] == 930) {
|
|
msgId2 = 0x6058;
|
|
}
|
|
|
|
if (msgId2 != 0) {
|
|
Message_StartTextbox(globalCtx, msgId2, NULL);
|
|
|
|
if (sp35) {
|
|
D_8094C876 = 10;
|
|
D_8094C874 = sp35;
|
|
D_8094C878 = 0;
|
|
}
|
|
}
|
|
|
|
if (msgId1 != 0) {
|
|
Message_StartTextbox(globalCtx, msgId1, NULL);
|
|
}
|
|
|
|
switch (kotakeAnim) {
|
|
case 1:
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_00230C, -5.0f);
|
|
break;
|
|
case 2:
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_001D10, -5.0f);
|
|
break;
|
|
case 3:
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_0017E0, -5.0f);
|
|
break;
|
|
case 4:
|
|
Animation_MorphToLoop(&sKotakePtr->skelAnime, &object_tw_Anim_0012A4, -5.0f);
|
|
break;
|
|
}
|
|
|
|
switch (koumeAnim) {
|
|
case 1:
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_00230C, -5.0f);
|
|
break;
|
|
case 2:
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_001D10, -5.0f);
|
|
break;
|
|
case 3:
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_0017E0, -5.0f);
|
|
break;
|
|
case 4:
|
|
Animation_MorphToLoop(&sKoumePtr->skelAnime, &object_tw_Anim_0012A4, -5.0f);
|
|
break;
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] >= 120 && this->work[CS_TIMER_2] < 500) {
|
|
Math_ApproachF(&this->workf[UNK_F18], 255.0f, 0.1f, 5.0f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_2] >= 150) {
|
|
Math_ApproachF(&sKoumePtr->workf[UNK_F17], (Math_SinS(this->work[CS_TIMER_1] * 2000) * 0.05f) + 0.4f, 0.1f,
|
|
0.01f);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F17], (Math_CosS(this->work[CS_TIMER_1] * 1700) * 0.05f) + 0.4f, 0.1f,
|
|
0.01f);
|
|
|
|
if (this->work[CS_TIMER_2] >= 880) {
|
|
Math_ApproachF(&sKotakePtr->actor.world.pos.y, 2000.0f, 1.0f, this->actor.speedXZ);
|
|
Math_ApproachF(&sKoumePtr->actor.world.pos.y, 2000.0f, 1.0f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 10.0f, 1.0f, 0.25f);
|
|
|
|
if (this->work[CS_TIMER_2] >= 930) {
|
|
Math_ApproachF(&this->workf[UNK_F19], 5.0f, 1.0f, 0.05f);
|
|
Math_ApproachF(&this->workf[UNK_F18], 0.0f, 1.0f, 3.0f);
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_GOTO_HEAVEN - SFX_FLAG);
|
|
} else {
|
|
f32 yTarget = Math_CosS(this->work[CS_TIMER_2] * 1700) * 4.0f;
|
|
Math_ApproachF(&sKotakePtr->actor.world.pos.y, 20.0f + (263.0f + yTarget), 0.1f, this->actor.speedXZ);
|
|
yTarget = Math_SinS(this->work[CS_TIMER_2] * 1500) * 4.0f;
|
|
Math_ApproachF(&sKoumePtr->actor.world.pos.y, 20.0f + (263.0f + yTarget), 0.1f, this->actor.speedXZ);
|
|
Math_ApproachF(&this->actor.speedXZ, 1.0f, 1.0f, 0.05f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaDeathCS(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
Vec3f spD0;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
Camera* mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
this->work[UNK_S8] += 20;
|
|
|
|
if (this->work[UNK_S8] > 255) {
|
|
this->work[UNK_S8] = 255;
|
|
}
|
|
|
|
Math_ApproachF(&this->workf[UNK_F12], 0.0f, 1.0f, 0.05f);
|
|
this->unk_5F8 = 1;
|
|
|
|
switch (this->csState1) {
|
|
case 0:
|
|
if (this->work[CS_TIMER_1] == 15) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_0216DC, -3.0f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] >= 15) {
|
|
Math_ApproachF(&this->actor.world.pos.y, 400.0f, 0.05f, 10.0f);
|
|
}
|
|
|
|
if (this->work[CS_TIMER_1] >= 55) {
|
|
if (this->work[CS_TIMER_1] == 55) {
|
|
globalCtx->envCtx.unk_D8 = 0;
|
|
}
|
|
|
|
sEnvType = -1;
|
|
globalCtx->envCtx.unk_BE = 5;
|
|
globalCtx->envCtx.unk_BD = 0;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.015f);
|
|
Math_ApproachF(&this->actor.scale.x, 0.00024999998f, 0.1f, 0.00005f);
|
|
this->actor.shape.rot.y += (s16)this->actor.speedXZ;
|
|
this->workf[UNK_F13] += this->actor.speedXZ;
|
|
if (this->workf[UNK_F13] > 65536.0f) {
|
|
this->workf[UNK_F13] -= 65536.0f;
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_ROLL);
|
|
}
|
|
Math_ApproachF(&this->actor.speedXZ, 12288.0f, 1.0f, 256.0f);
|
|
if (this->work[CS_TIMER_1] == 135) {
|
|
Vec3f spBC;
|
|
Vec3f spB0;
|
|
Vec3f spA4 = { 0.0f, 0.0f, 0.0f };
|
|
func_80078884(NA_SE_EN_TWINROBA_TRANSFORM);
|
|
for (i = 0; i < 100; i++) {
|
|
spB0.x = Rand_CenteredFloat(5.0f);
|
|
spB0.y = Rand_CenteredFloat(5.0f);
|
|
spB0.z = Rand_CenteredFloat(5.0f);
|
|
spBC = this->actor.world.pos;
|
|
spBC.x += spB0.x;
|
|
spBC.y += spB0.y;
|
|
spBC.z += spB0.z;
|
|
BossTw_AddFlameEffect(globalCtx, &spBC, &spB0, &spA4, Rand_ZeroFloat(2.0f) + 5,
|
|
Rand_ZeroFloat(1.99f));
|
|
}
|
|
this->csState1 = 1;
|
|
this->visible = false;
|
|
this->actor.scale.x = 0.0f;
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0,
|
|
0, TW_DEATHBALL_KOUME);
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW,
|
|
this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, 0, 0,
|
|
0, TW_DEATHBALL_KOTAKE);
|
|
this->actor.flags &= ~ACTOR_FLAG_0;
|
|
}
|
|
}
|
|
Actor_SetScale(&this->actor, this->actor.scale.x);
|
|
break;
|
|
case 1:
|
|
break;
|
|
}
|
|
|
|
switch (this->csState2) {
|
|
case 0:
|
|
this->csState2 = 1;
|
|
func_80064520(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 8);
|
|
this->subCamId = Gameplay_CreateSubCamera(globalCtx);
|
|
Gameplay_ChangeCameraStatus(globalCtx, 0, CAM_STAT_WAIT);
|
|
Gameplay_ChangeCameraStatus(globalCtx, this->subCamId, CAM_STAT_ACTIVE);
|
|
this->subCamEye = mainCam->eye;
|
|
this->subCamAt = mainCam->at;
|
|
Audio_QueueSeqCmd(0x1 << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0x100FF);
|
|
break;
|
|
case 1:
|
|
spD0.x = Math_SinS(this->actor.world.rot.y) * 200.0f;
|
|
spD0.z = Math_CosS(this->actor.world.rot.y) * 200.0f;
|
|
Math_ApproachF(&this->subCamEye.x, spD0.x + this->actor.world.pos.x, 0.1f, 50.0f);
|
|
Math_ApproachF(&this->subCamEye.y, 300.0f, 0.1f, 50.0f);
|
|
Math_ApproachF(&this->subCamEye.z, spD0.z + this->actor.world.pos.z, 0.1f, 50.0f);
|
|
Math_ApproachF(&this->subCamAt.x, this->actor.world.pos.x, 0.1f, 50.0f);
|
|
Math_ApproachF(&this->subCamAt.y, this->actor.world.pos.y, 0.1f, 50.0f);
|
|
Math_ApproachF(&this->subCamAt.z, this->actor.world.pos.z, 0.1f, 50.0f);
|
|
if (this->work[CS_TIMER_1] == 170) {
|
|
this->csState2 = 2;
|
|
this->work[CS_TIMER_2] = 0;
|
|
this->subCamEye.z = 170.0f;
|
|
this->subCamDist = 170.0f;
|
|
this->subCamEye.x = 0.0f;
|
|
this->subCamAt.x = 0.0f;
|
|
this->subCamAt.z = 0.0f;
|
|
this->subCamEye.y = 260.0f;
|
|
player->actor.shape.rot.y = -0x8000;
|
|
player->actor.world.pos.x = -40.0f;
|
|
player->actor.world.pos.y = 240.0f;
|
|
player->actor.world.pos.z = 90.0f;
|
|
sKoumePtr->actor.world.pos.x = -37.0f;
|
|
sKotakePtr->actor.world.pos.x = 37.0f;
|
|
sKotakePtr->actor.world.pos.y = 263.0f;
|
|
sKoumePtr->actor.world.pos.y = sKotakePtr->actor.world.pos.y;
|
|
this->subCamAt.y = sKoumePtr->actor.world.pos.y + 17.0f;
|
|
sKotakePtr->actor.world.pos.z = 0.0f;
|
|
sKoumePtr->actor.world.pos.z = sKotakePtr->actor.world.pos.z;
|
|
sKoumePtr->work[YAW_TGT] = sKotakePtr->work[YAW_TGT] = sKoumePtr->actor.shape.rot.x =
|
|
sKotakePtr->actor.shape.rot.x = sKoumePtr->actor.shape.rot.y = sKotakePtr->actor.shape.rot.y = 0;
|
|
func_8002DF54(globalCtx, &sKoumePtr->actor, 1);
|
|
sKoumePtr->actor.flags |= ACTOR_FLAG_0;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (this->work[CS_TIMER_2] == 100) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
s32 zero = 0;
|
|
|
|
for (i = 0; i < 50; i++) {
|
|
velocity.x = Rand_CenteredFloat(3.0f);
|
|
velocity.y = Rand_CenteredFloat(3.0f);
|
|
velocity.z = Rand_CenteredFloat(3.0f);
|
|
pos = sKoumePtr->actor.world.pos;
|
|
pos.x += velocity.x * 2.0f;
|
|
pos.y += velocity.y * 2.0f;
|
|
pos.z += velocity.z * 2.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &accel, Rand_ZeroFloat(2.0f) + 5, 1);
|
|
|
|
// fake code needed to match, tricks the compiler into allocating more stack
|
|
if (1) {}
|
|
if (zero) {
|
|
accel.x *= 2.0;
|
|
}
|
|
|
|
velocity.x = Rand_CenteredFloat(3.0f);
|
|
velocity.y = Rand_CenteredFloat(3.0f);
|
|
velocity.z = Rand_CenteredFloat(3.0f);
|
|
pos = sKotakePtr->actor.world.pos;
|
|
pos.x += velocity.x * 2.0f;
|
|
pos.y += velocity.y * 2.0f;
|
|
pos.z += velocity.z * 2.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &pos, &velocity, &accel, Rand_ZeroFloat(2.0f) + 5, 0);
|
|
}
|
|
|
|
Actor_SetScale(&sKoumePtr->actor, 0.0f);
|
|
Actor_SetScale(&sKotakePtr->actor, 0.0f);
|
|
sKoumePtr->visible = 1;
|
|
sKotakePtr->visible = 1;
|
|
func_80078884(NA_SE_EN_TWINROBA_TRANSFORM);
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_KOTAKE_KOUME);
|
|
this->csState2 = 3;
|
|
this->work[CS_TIMER_2] = 0;
|
|
this->subCamYaw = this->subCamYawStep = this->actor.speedXZ = this->subCamDistStep = 0.0f;
|
|
}
|
|
break;
|
|
case 3:
|
|
BossTw_DeathCSMsgSfx(this, globalCtx);
|
|
if (this->work[CS_TIMER_2] < 150) {
|
|
globalCtx->envCtx.unk_BE = 1;
|
|
globalCtx->envCtx.unk_BD = 0;
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.1f);
|
|
} else {
|
|
globalCtx->envCtx.unk_BE = 1;
|
|
globalCtx->envCtx.unk_BD = 6;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, (Math_SinS(this->work[CS_TIMER_2] * 4096) / 4.0f) + 0.75f,
|
|
1.0f, 0.1f);
|
|
}
|
|
|
|
Math_ApproachF(&this->subCamAt.y, sKoumePtr->actor.world.pos.y + 17.0f, 0.05f, 10.0f);
|
|
|
|
if (this->work[CS_TIMER_2] >= 50) {
|
|
Math_ApproachF(&this->subCamDist, 110.0f, 0.05f, this->subCamDistStep);
|
|
Math_ApproachF(&this->subCamDistStep, 1.0f, 1.0f, 0.025f);
|
|
this->subCamEye.x = this->subCamDist * sinf(this->subCamYaw);
|
|
this->subCamEye.z = this->subCamDist * cosf(this->subCamYaw);
|
|
if (this->work[CS_TIMER_2] >= 151) {
|
|
this->subCamYaw += this->subCamYawStep;
|
|
if (this->work[CS_TIMER_2] >= 800) {
|
|
Math_ApproachF(&this->subCamYawStep, 0.0f, 1.0f, 0.0001f);
|
|
} else {
|
|
Math_ApproachF(&this->subCamYawStep, 0.015f, 1.0f, 0.0001f);
|
|
}
|
|
}
|
|
}
|
|
Math_ApproachF(&sKoumePtr->actor.scale.x, 0.009999999f, 0.1f, 0.001f);
|
|
Actor_SetScale(&sKoumePtr->actor, sKoumePtr->actor.scale.x);
|
|
Actor_SetScale(&sKotakePtr->actor, sKoumePtr->actor.scale.x);
|
|
if (this->work[CS_TIMER_2] >= 1020) {
|
|
mainCam = Gameplay_GetCamera(globalCtx, MAIN_CAM);
|
|
mainCam->eye = this->subCamEye;
|
|
mainCam->eyeNext = this->subCamEye;
|
|
mainCam->at = this->subCamAt;
|
|
func_800C08AC(globalCtx, this->subCamId, 0);
|
|
this->csState2 = 4;
|
|
this->subCamId = 0;
|
|
func_80064534(globalCtx, &globalCtx->csCtx);
|
|
func_8002DF54(globalCtx, &this->actor, 7);
|
|
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_BOSS_CLEAR);
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, 600.0f, 230.0f,
|
|
0.0f, 0, 0, 0, WARP_DUNGEON_ADULT);
|
|
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_ITEM_B_HEART, -600.0f, 230.f, 0.0f, 0, 0, 0, 0);
|
|
this->actor.world.pos.y = -2000.0f;
|
|
this->workf[UNK_F18] = 0.0f;
|
|
sKoumePtr->visible = sKotakePtr->visible = false;
|
|
if (&this->subCamEye) {} // fixes regalloc, may be fake
|
|
Flags_SetClear(globalCtx, globalCtx->roomCtx.curRoom.num);
|
|
}
|
|
break;
|
|
case 4:
|
|
sEnvType = 0;
|
|
break;
|
|
}
|
|
|
|
if (this->subCamId) {
|
|
if (1) {}
|
|
Gameplay_CameraSetAtEye(globalCtx, this->subCamId, &this->subCamAt, &this->subCamEye);
|
|
}
|
|
}
|
|
|
|
static s16 D_8094A900[] = {
|
|
0, 1, 2, 2, 1,
|
|
};
|
|
|
|
static s16 D_8094A90C[] = {
|
|
0, 1, 2, 2, 2, 2, 2, 2, 1,
|
|
};
|
|
|
|
void BossTw_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 i;
|
|
s32 pad;
|
|
|
|
this->collider.base.colType = COLTYPE_HIT3;
|
|
Math_ApproachF(&this->fogR, globalCtx->lightCtx.fogColor[0], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogG, globalCtx->lightCtx.fogColor[1], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogB, globalCtx->lightCtx.fogColor[2], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogNear, globalCtx->lightCtx.fogNear, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogFar, 1000.0f, 1.0f, 10.0f);
|
|
this->work[CS_TIMER_1]++;
|
|
this->work[CS_TIMER_2]++;
|
|
this->work[TAIL_IDX]++;
|
|
|
|
if (this->work[TAIL_IDX] >= ARRAY_COUNT(this->blastTailPos)) {
|
|
this->work[TAIL_IDX] = 0;
|
|
}
|
|
|
|
this->blastTailPos[this->work[TAIL_IDX]] = this->actor.world.pos;
|
|
|
|
if (1) {}
|
|
if (1) {}
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
if (this->work[INVINC_TIMER] != 0) {
|
|
this->work[INVINC_TIMER]--;
|
|
}
|
|
|
|
if (this->work[FOG_TIMER] != 0) {
|
|
this->work[FOG_TIMER]--;
|
|
}
|
|
|
|
if (this->actionFunc == BossTw_FlyTo || this->actionFunc == BossTw_Spin ||
|
|
this->actionFunc == BossTw_TurnToPlayer) {
|
|
if ((s16)(player->actor.shape.rot.y - this->actor.yawTowardsPlayer + 0x8000) < 0x1000 &&
|
|
(s16)(player->actor.shape.rot.y - this->actor.yawTowardsPlayer + 0x8000) > -0x1000 && player->unk_A73) {
|
|
BossTw_SetupSpin(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
|
|
if (this->actionFunc != BossTw_Wait) {
|
|
this->collider.dim.radius = 45;
|
|
|
|
if (this->actionFunc == BossTw_Spin) {
|
|
this->collider.dim.radius *= 2;
|
|
}
|
|
|
|
this->collider.dim.height = 120;
|
|
this->collider.dim.yShift = -30;
|
|
|
|
if (this->work[INVINC_TIMER] == 0) {
|
|
if (this->collider.base.acFlags & AC_HIT) {
|
|
this->collider.base.acFlags &= ~AC_HIT;
|
|
}
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider);
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
}
|
|
|
|
if (this->actor.params == 0) {
|
|
this->workf[OUTR_CRWN_TX_X2] += 1.0f;
|
|
this->workf[OUTR_CRWN_TX_Y2] -= 7.0f;
|
|
this->workf[INNR_CRWN_TX_Y1] += 1.0f;
|
|
} else {
|
|
this->workf[OUTR_CRWN_TX_X2] += 0.0f;
|
|
this->workf[INNR_CRWN_TX_X2] += 0.0f;
|
|
this->workf[OUTR_CRWN_TX_Y2] += -15.0f;
|
|
this->workf[INNR_CRWN_TX_Y2] += -10.0f;
|
|
}
|
|
|
|
if (((this->work[CS_TIMER_2] % 32) == 0) && (Rand_ZeroOne() < 0.3f)) {
|
|
this->work[BLINK_IDX] = 4;
|
|
}
|
|
|
|
this->eyeTexIdx = D_8094A900[this->work[BLINK_IDX]];
|
|
|
|
if (this->work[BLINK_IDX] != 0) {
|
|
this->work[BLINK_IDX]--;
|
|
}
|
|
|
|
if (this->actionFunc != BossTw_MergeCS && this->unk_5F8 != 0) {
|
|
Vec3f pos;
|
|
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
|
|
if (this->scepterAlpha > 0.0f) {
|
|
for (i = 0; i <= 0; i++) {
|
|
pos = this->scepterFlamePos[0];
|
|
pos.x += Rand_CenteredFloat(70.0f);
|
|
pos.y += Rand_CenteredFloat(70.0f);
|
|
pos.z += Rand_CenteredFloat(70.0f);
|
|
accel.y = 0.4f;
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 8,
|
|
this->actor.params, 37);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= 0; i++) {
|
|
pos = this->crownPos;
|
|
pos.x += Rand_CenteredFloat(70.0f);
|
|
pos.y += Rand_CenteredFloat(70.0f);
|
|
pos.z += Rand_CenteredFloat(70.0f);
|
|
accel.y = 0.4f;
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 8,
|
|
this->actor.params, 37);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaUpdate(Actor* thisx, GlobalContext* globalCtx2) {
|
|
s16 i;
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
this->actor.flags &= ~ACTOR_FLAG_10;
|
|
this->unk_5F8 = 0;
|
|
this->collider.base.colType = COLTYPE_HIT3;
|
|
|
|
Math_ApproachF(&this->fogR, globalCtx->lightCtx.fogColor[0], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogG, globalCtx->lightCtx.fogColor[1], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogB, globalCtx->lightCtx.fogColor[2], 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogNear, globalCtx->lightCtx.fogNear, 1.0f, 10.0f);
|
|
Math_ApproachF(&this->fogFar, 1000.0f, 1.0f, 10.0f);
|
|
|
|
this->work[CS_TIMER_1]++;
|
|
this->work[CS_TIMER_2]++;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
if (this->work[INVINC_TIMER] != 0) {
|
|
this->work[INVINC_TIMER]--;
|
|
}
|
|
|
|
if (this->work[FOG_TIMER] != 0) {
|
|
this->work[FOG_TIMER]--;
|
|
}
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
|
|
if (this->actionFunc != BossTw_TwinrovaShootBlast && this->actionFunc != BossTw_TwinrovaChargeBlast &&
|
|
this->visible && this->unk_5F8 == 0 &&
|
|
(s16)(player->actor.shape.rot.y - this->actor.yawTowardsPlayer + 0x8000) < 0x1000 &&
|
|
(s16)(player->actor.shape.rot.y - this->actor.yawTowardsPlayer + 0x8000) > -0x1000 && player->unk_A73 != 0) {
|
|
BossTw_TwinrovaSetupSpin(this, globalCtx);
|
|
}
|
|
|
|
this->eyeTexIdx = D_8094A900[this->work[BLINK_IDX]];
|
|
if (this->work[BLINK_IDX] != 0) {
|
|
this->work[BLINK_IDX]--;
|
|
}
|
|
|
|
if ((this->work[CS_TIMER_2] % 32) == 0) {
|
|
if (this->actionFunc != BossTw_TwinrovaMergeCS) {
|
|
if (Rand_ZeroOne() < 0.3f) {
|
|
this->work[BLINK_IDX] = 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->actionFunc == BossTw_TwinrovaMergeCS) {
|
|
this->leftEyeTexIdx = D_8094A90C[this->work[TW_BLINK_IDX]];
|
|
if (this->work[TW_BLINK_IDX] != 0) {
|
|
this->work[TW_BLINK_IDX]--;
|
|
}
|
|
} else {
|
|
if (this->actionFunc == BossTw_TwinrovaStun) {
|
|
this->eyeTexIdx = 1;
|
|
}
|
|
|
|
if (this->actionFunc == BossTw_TwinrovaDeathCS) {
|
|
this->eyeTexIdx = 2;
|
|
}
|
|
|
|
this->leftEyeTexIdx = this->eyeTexIdx;
|
|
}
|
|
|
|
if (this->visible && this->unk_5F8 == 0) {
|
|
Vec3f pos;
|
|
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
|
|
Vec3f accel;
|
|
|
|
if (this->work[UNK_S8] != 0) {
|
|
this->work[UNK_S8] -= 20;
|
|
if (this->work[UNK_S8] < 0) {
|
|
this->work[UNK_S8] = 0;
|
|
}
|
|
}
|
|
|
|
Math_ApproachF(&this->workf[UNK_F12], 1.0f, 1.0f, 0.05f);
|
|
accel.y = 0.4f;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
pos = this->leftScepterPos;
|
|
pos.x += Rand_CenteredFloat(30.0f);
|
|
pos.y += Rand_CenteredFloat(30.0f);
|
|
pos.z += Rand_CenteredFloat(30.0f);
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 7, 0, 75);
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
pos = this->rightScepterPos;
|
|
pos.x += Rand_CenteredFloat(30.0f);
|
|
pos.y += Rand_CenteredFloat(30.0f);
|
|
pos.z += Rand_CenteredFloat(30.0f);
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 7, 1, 75);
|
|
}
|
|
}
|
|
|
|
this->collider.dim.radius = 35;
|
|
|
|
if (this->actionFunc == BossTw_TwinrovaSpin) {
|
|
this->collider.dim.radius *= 2;
|
|
}
|
|
|
|
this->collider.dim.height = 150;
|
|
this->collider.dim.yShift = -60;
|
|
Collider_UpdateCylinder(&this->actor, &this->collider);
|
|
|
|
if (this->work[INVINC_TIMER] == 0) {
|
|
if (this->actionFunc != BossTw_TwinrovaStun) {
|
|
if (this->twinrovaStun != 0) {
|
|
this->twinrovaStun = 0;
|
|
this->work[FOG_TIMER] = 10;
|
|
BossTw_TwinrovaDamage(this, globalCtx, 0);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_DAMAGE);
|
|
} else if (this->collider.base.acFlags & AC_HIT) {
|
|
ColliderInfo* info = this->collider.info.acHitInfo;
|
|
|
|
this->collider.base.acFlags &= ~AC_HIT;
|
|
if (info->toucher.dmgFlags & (DMG_SLINGSHOT | DMG_ARROW)) {}
|
|
}
|
|
} else if (this->collider.base.acFlags & AC_HIT) {
|
|
u8 damage;
|
|
u8 swordDamage;
|
|
ColliderInfo* info = this->collider.info.acHitInfo;
|
|
|
|
this->collider.base.acFlags &= ~AC_HIT;
|
|
swordDamage = false;
|
|
damage = CollisionCheck_GetSwordDamage(info->toucher.dmgFlags);
|
|
|
|
if (damage == 0) {
|
|
damage = 2;
|
|
} else {
|
|
swordDamage = true;
|
|
}
|
|
|
|
if (!(info->toucher.dmgFlags & DMG_HOOKSHOT)) {
|
|
if (((s8)this->actor.colChkInfo.health < 3) && !swordDamage) {
|
|
damage = 0;
|
|
}
|
|
|
|
BossTw_TwinrovaDamage(this, globalCtx, damage);
|
|
}
|
|
}
|
|
}
|
|
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
osSyncPrintf("OooooooooooooooooooooooooooooooooCC\n");
|
|
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
|
|
|
globalCtx->envCtx.unk_DC = 2;
|
|
|
|
switch (sEnvType) {
|
|
case 0:
|
|
Math_ApproachZeroF(&globalCtx->envCtx.unk_D8, 1.0f, 0.02f);
|
|
break;
|
|
case 1:
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 0.5f, 1.0f, 0.05f);
|
|
break;
|
|
case 2:
|
|
globalCtx->envCtx.unk_BD = 2;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, (Math_SinS(this->work[CS_TIMER_1] * 0x3000) * 0.03f) + 0.5f, 1.0f,
|
|
0.05f);
|
|
break;
|
|
case 3:
|
|
globalCtx->envCtx.unk_BD = 3;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.1f);
|
|
break;
|
|
case 4:
|
|
globalCtx->envCtx.unk_BD = 2;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, (Math_SinS(this->work[CS_TIMER_1] * 0x3E00) * 0.05f) + 0.95f,
|
|
1.0f, 0.1f);
|
|
break;
|
|
case 5:
|
|
globalCtx->envCtx.unk_BD = 0;
|
|
Math_ApproachF(&globalCtx->envCtx.unk_D8, 1.0f, 1.0f, 0.05f);
|
|
break;
|
|
case -1:
|
|
break;
|
|
}
|
|
|
|
BossTw_UpdateEffects(globalCtx);
|
|
|
|
if (sFreezeState == 1) {
|
|
sFreezeState = 2;
|
|
BossTw_AddPlayerFreezeEffect(globalCtx, NULL);
|
|
func_80078914(&player->actor.projectedPos, NA_SE_VO_LI_FREEZE);
|
|
func_80078914(&player->actor.projectedPos, NA_SE_PL_FREEZE);
|
|
|
|
if (sShieldFireCharge != 0) {
|
|
sShieldFireCharge = 4;
|
|
}
|
|
}
|
|
|
|
if (player->isBurning && sShieldIceCharge != 0) {
|
|
sShieldIceCharge = 4;
|
|
}
|
|
}
|
|
|
|
s32 BossTw_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
if (limbIndex == 21) {
|
|
if (this->unk_5F8 == 0) {
|
|
if (this->actor.params == 0) {
|
|
*dList = object_tw_DL_012CE0;
|
|
} else {
|
|
*dList = object_tw_DL_0134B8;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (limbIndex == 14) {
|
|
if (this->actionFunc == BossTw_DeathCS) {
|
|
*dList = NULL;
|
|
} else if (this->scepterAlpha == 0.0f) {
|
|
if (this->actor.params == 0) {
|
|
*dList = object_tw_DL_012B38;
|
|
} else {
|
|
*dList = object_tw_DL_013310;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void BossTw_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
|
static Vec3f D_8094A944 = { 0.0f, 0.0f, 0.0f };
|
|
static Vec3f D_8094A950 = { 0.0f, 2000.0f, -2000.0f };
|
|
static Vec3f D_8094A95C[] = {
|
|
{ 0.0f, 0.0f, -10000.0f }, { 0.0f, 0.0f, -8000.0f }, { 0.0f, 0.0f, -9000.0f },
|
|
{ 0.0f, 0.0f, -11000.0f }, { 0.0f, 0.0f, -12000.0f },
|
|
};
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6168);
|
|
|
|
switch (limbIndex) {
|
|
case 21:
|
|
Matrix_MultVec3f(&D_8094A944, &this->actor.focus.pos);
|
|
Matrix_MultVec3f(&D_8094A950, &this->crownPos);
|
|
|
|
if (this->unk_5F8 != 0) {
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6190),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
if (this->actor.params == 0) {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_013AE8));
|
|
} else {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_013D68));
|
|
}
|
|
}
|
|
break;
|
|
case 14:
|
|
Matrix_MultVec3f(&D_8094A95C[0], &this->scepterFlamePos[0]);
|
|
Matrix_MultVec3f(&D_8094A95C[1], &this->scepterFlamePos[1]);
|
|
Matrix_MultVec3f(&D_8094A95C[2], &this->scepterFlamePos[2]);
|
|
Matrix_MultVec3f(&D_8094A95C[3], &this->scepterFlamePos[3]);
|
|
Matrix_MultVec3f(&D_8094A95C[4], &this->scepterFlamePos[4]);
|
|
|
|
if (this->scepterAlpha > 0.0f) {
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6221),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
if (this->actor.params == 0) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 225, 255, (s16)this->scepterAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_013E98));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (s16)this->scepterAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_013F98));
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 20, 0, (s16)this->scepterAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_014070));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 70, 0, (s16)this->scepterAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_014158));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6236);
|
|
}
|
|
|
|
void func_80941BC0(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6341);
|
|
|
|
Matrix_Push();
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
Matrix_Translate(this->groundBlastPos2.x, this->groundBlastPos2.y, this->groundBlastPos2.z, MTXMODE_NEW);
|
|
Matrix_Scale(this->workf[UNK_F12], this->workf[UNK_F12], this->workf[UNK_F12], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6358),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s16)this->workf[UNK_F11]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 40, 30, 80);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01BC00));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 215, 215, 215, (s16)this->workf[UNK_F11] * this->workf[UNK_F14]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, (u32)this->workf[UNK_F16] & 0x3F,
|
|
(this->work[CS_TIMER_2] * 4) & 0x3F, 0x10, 0x10));
|
|
Matrix_Push();
|
|
Matrix_RotateY(this->workf[UNK_F15], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6423),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01C1C0));
|
|
Matrix_Pop();
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6427),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPSegment(POLY_XLU_DISP++, 0xD,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, this->work[CS_TIMER_2] & 0x7F,
|
|
(this->work[CS_TIMER_2] * 8) & 0xFF, 0x20, 0x40, 1,
|
|
(-this->work[CS_TIMER_2] * 2) & 0x3F, 0, 0x10, 0x10));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (s16)this->workf[UNK_F9]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128);
|
|
gDPSetRenderMode(POLY_XLU_DISP++,
|
|
Z_CMP | IM_RD | CVG_DST_SAVE | ZMODE_DEC | FORCE_BL |
|
|
GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA),
|
|
G_RM_ZB_OVL_SURF2);
|
|
gSPSetGeometryMode(POLY_XLU_DISP++, G_CULL_BACK | G_FOG);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A790));
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6461);
|
|
}
|
|
|
|
void func_80942180(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6468);
|
|
|
|
Matrix_Push();
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
Matrix_Translate(this->groundBlastPos2.x, this->groundBlastPos2.y, this->groundBlastPos2.z, MTXMODE_NEW);
|
|
Matrix_Scale(this->workf[KM_GD_CRTR_SCL], this->workf[KM_GD_CRTR_SCL], this->workf[KM_GD_CRTR_SCL], MTXMODE_APPLY);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (-this->work[CS_TIMER_1]) & 0x7F, 0, 0x20, 0x20, 1,
|
|
(this->work[CS_TIMER_1] * 2) & 0x7F, 0, 0x20, 0x20));
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6497),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 40, 00, (s16)this->workf[KM_GRND_CRTR_A]);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 245, 255, 128);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_019D40));
|
|
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6514),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, this->work[CS_TIMER_1] & 0x7F,
|
|
(-this->work[CS_TIMER_1] * 6) & 0xFF, 0x20, 0x40, 1,
|
|
(this->work[CS_TIMER_1] * 2) & 0x7F, (-this->work[CS_TIMER_1] * 6) & 0xFF, 0x20, 0x40));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 80, 0, 0, (s16)this->workf[KM_GD_SMOKE_A]);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 100);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_018FC0));
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (-this->work[CS_TIMER_1] * 3) & 0x7F, 0, 0x20, 0x20, 1, 0,
|
|
(-this->work[CS_TIMER_1] * 10) & 0xFF, 0x20, 0x40));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 50, 0, (s16)(this->workf[KM_GD_FLM_A] * 0.7f));
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 200, 235, 240, 128);
|
|
Matrix_Scale(this->workf[KM_GD_FLM_SCL], this->workf[KM_GD_FLM_SCL], this->workf[KM_GD_FLM_SCL], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6575),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_019938));
|
|
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6579);
|
|
}
|
|
|
|
void func_809426F0(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
s16 i;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6587);
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, (u8)(-this->work[CS_TIMER_2] * 15), 0x20, 0x40, 1, 0, 0,
|
|
0x40, 0x40));
|
|
Matrix_Push();
|
|
Matrix_Translate(0.0f, 0.0f, 5000.0f, MTXMODE_APPLY);
|
|
Matrix_Scale(this->spawnPortalScale / 2000.0f, this->spawnPortalScale / 2000.0f, this->spawnPortalScale / 2000.0f,
|
|
MTXMODE_APPLY);
|
|
Matrix_RotateZ(this->portalRotation, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6614),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
|
|
if (this->actor.params == 0) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 135, 175, 165, (s16)this->spawnPortalAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01CEE0));
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 0, (s16)this->spawnPortalAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01DBE8));
|
|
}
|
|
|
|
Matrix_Pop();
|
|
|
|
if (this->actor.params == 0) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (s16)this->flameAlpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A998));
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, (s16)this->flameAlpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
Matrix_Push();
|
|
Matrix_Translate(0.0f, 0.0f, 5000.0f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(((i * M_PI) * 2.0f * 0.125f) + this->flameRotation, MTXMODE_APPLY);
|
|
Matrix_Translate(0.0f, this->spawnPortalScale * 1.5f, 0.0f, MTXMODE_APPLY);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, ((this->work[CS_TIMER_2] * 3) + (i * 10)) & 0x7F,
|
|
(u8)((-this->work[CS_TIMER_2] * 15) + (i * 50)), 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6751),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A430));
|
|
Matrix_Pop();
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6756);
|
|
}
|
|
|
|
void func_80942C70(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
s16 alpha;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6765);
|
|
|
|
if (this->beamDist != 0.0f) {
|
|
Matrix_Push();
|
|
gSPSegment(POLY_XLU_DISP++, 0xC,
|
|
Gfx_TexScroll(globalCtx->state.gfxCtx, 0, (u8)(this->work[CS_TIMER_1] * -0xF), 0x20, 0x40));
|
|
alpha = this->beamScale * 100.0f * 255.0f;
|
|
|
|
if (this->actor.params == 1) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 60, alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 128);
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 100, 100, 255, 128);
|
|
}
|
|
|
|
Matrix_Translate(this->beamOrigin.x, this->beamOrigin.y, this->beamOrigin.z, MTXMODE_NEW);
|
|
Matrix_RotateY(this->beamYaw, MTXMODE_APPLY);
|
|
Matrix_RotateX(this->beamPitch, MTXMODE_APPLY);
|
|
Matrix_RotateZ(this->beamRoll, MTXMODE_APPLY);
|
|
Matrix_Scale(this->beamScale, this->beamScale, (this->beamDist * 0.01f * 98.0f) / 20000.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6846),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01DDF0));
|
|
|
|
if (this->beamReflectionDist > 10.0f) {
|
|
Matrix_Translate(this->beamReflectionOrigin.x, this->beamReflectionOrigin.y, this->beamReflectionOrigin.z,
|
|
MTXMODE_NEW);
|
|
Matrix_RotateY(this->beamReflectionYaw, MTXMODE_APPLY);
|
|
Matrix_RotateX(this->beamReflectionPitch, MTXMODE_APPLY);
|
|
Matrix_RotateZ(this->beamRoll, MTXMODE_APPLY);
|
|
Matrix_Scale(this->beamScale, this->beamScale, (this->beamReflectionDist * 0.01f * 100.0f) / 20000.0f,
|
|
MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6870),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01DDF0));
|
|
}
|
|
|
|
Matrix_Pop();
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6878);
|
|
}
|
|
|
|
void func_80943028(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6885);
|
|
|
|
Matrix_Push();
|
|
Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + 57.0f, this->actor.world.pos.z, MTXMODE_NEW);
|
|
Matrix_Scale(this->workf[UNK_F17], this->workf[UNK_F17], this->workf[UNK_F17], MTXMODE_APPLY);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6908),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01F608));
|
|
func_80094044(globalCtx->state.gfxCtx);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, 200);
|
|
Matrix_Translate(this->actor.world.pos.x, 240.0f, this->actor.world.pos.z, MTXMODE_NEW);
|
|
Matrix_Scale((this->actor.scale.x * 4000.0f) / 100.0f, 1.0f, (this->actor.scale.x * 4000.0f) / 100.0f,
|
|
MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6926),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gCircleShadowDL));
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6933);
|
|
}
|
|
|
|
static void* sEyeTextures[] = {
|
|
object_tw_Tex_00A438,
|
|
object_tw_Tex_00B238,
|
|
object_tw_Tex_00B638,
|
|
};
|
|
|
|
void BossTw_Draw(Actor* thisx, GlobalContext* globalCtx2) {
|
|
static Vec3f D_8094A9A4 = { 0.0f, 200.0f, 2000.0f };
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 6947);
|
|
|
|
if (this->visible) {
|
|
gSPSegment(POLY_OPA_DISP++, 10, SEGMENTED_TO_VIRTUAL(sEyeTextures[this->eyeTexIdx]));
|
|
gSPSegment(POLY_XLU_DISP++, 10, SEGMENTED_TO_VIRTUAL(sEyeTextures[this->eyeTexIdx]));
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)this->workf[OUTR_CRWN_TX_X1] & 0x7F,
|
|
(s16)this->workf[OUTR_CRWN_TX_Y1] & 0x7F, 0x20, 0x20, 1,
|
|
(s16)this->workf[OUTR_CRWN_TX_X2] & 0x7F, (s16)this->workf[OUTR_CRWN_TX_Y2] & 0xFF,
|
|
0x20, 0x40));
|
|
|
|
if (this->actor.params == TW_KOTAKE) {
|
|
gSPSegment(POLY_XLU_DISP++, 9,
|
|
Gfx_TexScroll(globalCtx->state.gfxCtx, (s16)this->workf[INNR_CRWN_TX_X1] & 0x7F,
|
|
(s16)this->workf[INNR_CRWN_TX_Y1] & 0xFF, 0x20, 0x40));
|
|
} else {
|
|
gSPSegment(POLY_XLU_DISP++, 9,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (s16)this->workf[INNR_CRWN_TX_X1] & 0x7F,
|
|
(s16)this->workf[INNR_CRWN_TX_Y1] & 0x7F, 0x20, 0x20, 1,
|
|
(s16)this->workf[INNR_CRWN_TX_X2] & 0x7F,
|
|
(s16)this->workf[INNR_CRWN_TX_Y2] & 0xFF, 0x20, 0x40));
|
|
}
|
|
|
|
func_80093D18(globalCtx->state.gfxCtx);
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
if (this->work[FOG_TIMER] & 2) {
|
|
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 50, 0, 0, 900, 1099);
|
|
} else {
|
|
POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, (u32)this->fogR, (u32)this->fogG, (u32)this->fogB, 0,
|
|
this->fogNear, this->fogFar);
|
|
}
|
|
|
|
Matrix_Push();
|
|
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
|
this->skelAnime.dListCount, BossTw_OverrideLimbDraw, BossTw_PostLimbDraw, this);
|
|
Matrix_Pop();
|
|
POLY_OPA_DISP = Gameplay_SetFog(globalCtx, POLY_OPA_DISP);
|
|
}
|
|
|
|
if (this->actor.params == TW_KOTAKE) {
|
|
if (this->workf[UNK_F9] > 0.0f) {
|
|
if (this->workf[UNK_F11] > 0.0f) {
|
|
Vec3f diff;
|
|
diff.x = this->groundBlastPos2.x - player->actor.world.pos.x;
|
|
diff.y = this->groundBlastPos2.y - player->actor.world.pos.y;
|
|
diff.z = this->groundBlastPos2.z - player->actor.world.pos.z;
|
|
|
|
if ((fabsf(diff.y) < 10.0f) && (player->actor.bgCheckFlags & 1) &&
|
|
(sqrtf(SQ(diff.x) + SQ(diff.z)) < (this->workf[UNK_F12] * 4600.0f)) && (sFreezeState == 0) &&
|
|
(this->workf[UNK_F11] > 200.0f)) {
|
|
sFreezeState = 1;
|
|
sTwinrovaPtr->timers[2] = 100;
|
|
}
|
|
}
|
|
|
|
func_80941BC0(this, globalCtx);
|
|
}
|
|
} else {
|
|
func_80942180(this, globalCtx);
|
|
}
|
|
|
|
if (this->visible) {
|
|
if (this->actionFunc == BossTw_DeathCS) {
|
|
func_80943028(&this->actor, globalCtx);
|
|
} else {
|
|
func_809426F0(this, globalCtx);
|
|
Matrix_MultVec3f(&D_8094A9A4, &this->beamOrigin);
|
|
func_80942C70(&this->actor, globalCtx);
|
|
}
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7123);
|
|
}
|
|
|
|
void* D_8094A9B0[] = {
|
|
object_tw_Tex_02A9B0,
|
|
object_tw_Tex_02A070,
|
|
object_tw_Tex_02A470,
|
|
};
|
|
|
|
s32 BossTw_TwinrovaOverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
|
|
void* thisx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7139);
|
|
|
|
switch (limbIndex) {
|
|
case 21:
|
|
gSPSegment(POLY_OPA_DISP++, 0xC,
|
|
Gfx_TexScroll(globalCtx->state.gfxCtx, 0, (s16)(f32)this->work[CS_TIMER_1], 8, 8));
|
|
gSPSegment(POLY_OPA_DISP++, 8, SEGMENTED_TO_VIRTUAL(D_8094A9B0[this->eyeTexIdx]));
|
|
gSPSegment(POLY_OPA_DISP++, 9, SEGMENTED_TO_VIRTUAL(D_8094A9B0[this->leftEyeTexIdx]));
|
|
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, this->work[UNK_S8]);
|
|
break;
|
|
case 17:
|
|
case 41:
|
|
*dList = NULL;
|
|
gSPSegment(POLY_XLU_DISP++, 0xA,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, 0,
|
|
-this->work[CS_TIMER_1] * 0xF, 0x20, 0x40));
|
|
break;
|
|
case 18:
|
|
case 42:
|
|
*dList = NULL;
|
|
gSPSegment(POLY_XLU_DISP++, 0xB,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, 0,
|
|
-this->work[CS_TIMER_1] * 0xA, 0x20, 0x40));
|
|
break;
|
|
case 16:
|
|
case 32:
|
|
*dList = NULL;
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, this->work[CS_TIMER_1],
|
|
-this->work[CS_TIMER_1] * 7, 0x20, 0x40));
|
|
break;
|
|
case 15:
|
|
case 31:
|
|
*dList = NULL;
|
|
gSPSegment(POLY_XLU_DISP++, 9,
|
|
Gfx_TexScroll(globalCtx->state.gfxCtx, 0, this->work[CS_TIMER_1], 0x20, 0x40));
|
|
break;
|
|
case 19:
|
|
if (this->unk_5F8 != 0) {
|
|
*dList = object_tw_DL_02D940;
|
|
}
|
|
break;
|
|
|
|
case 20:
|
|
if (this->unk_5F8 != 0) {
|
|
*dList = object_tw_DL_02D890;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (this->unk_5F8 != 0 && ((limbIndex == 34) || (limbIndex == 40))) {
|
|
*dList = NULL;
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7251);
|
|
|
|
return false;
|
|
}
|
|
|
|
void BossTw_TwinrovaPostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
|
static Vec3f D_8094A9BC = { 0.0f, 0.0f, 0.0f };
|
|
static Vec3f D_8094A9C8 = { 0.0f, 2000.0f, -2000.0f };
|
|
static Vec3f D_8094A9D4 = { 13000.0f, 0.0f, 0.0f };
|
|
static Vec3f D_8094A9E0 = { 13000.0f, 0.0f, 0.0f };
|
|
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7262);
|
|
|
|
switch (limbIndex) {
|
|
case 34:
|
|
Matrix_MultVec3f(&D_8094A9D4, &this->leftScepterPos);
|
|
break;
|
|
case 40:
|
|
Matrix_MultVec3f(&D_8094A9E0, &this->rightScepterPos);
|
|
break;
|
|
case 21:
|
|
Matrix_MultVec3f(&D_8094A9BC, &this->actor.focus.pos);
|
|
Matrix_MultVec3f(&D_8094A9C8, &this->crownPos);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 31:
|
|
case 32:
|
|
case 41:
|
|
case 42:
|
|
Matrix_Push();
|
|
Matrix_Scale(this->workf[UNK_F12], this->workf[UNK_F12], this->workf[UNK_F12], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7295),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
Matrix_Pop();
|
|
gSPDisplayList(POLY_XLU_DISP++, *dList);
|
|
break;
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7301);
|
|
}
|
|
|
|
void BossTw_ShieldChargeDraw(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 temp_t0;
|
|
s16 temp_a0;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7311);
|
|
|
|
Matrix_Push();
|
|
|
|
temp_t0 = sShieldFireCharge | sShieldIceCharge;
|
|
|
|
if (temp_t0 == 1) {
|
|
func_80078884(NA_SE_IT_SHIELD_CHARGE_LV1 & ~SFX_FLAG);
|
|
} else if (temp_t0 == 2) {
|
|
func_80078884(NA_SE_IT_SHIELD_CHARGE_LV2 & ~SFX_FLAG);
|
|
} else if (temp_t0 == 3) {
|
|
func_80078884(NA_SE_IT_SHIELD_CHARGE_LV3 & ~SFX_FLAG);
|
|
}
|
|
|
|
if (temp_t0 != 0 && temp_t0 < 4) {
|
|
Math_ApproachF(&D_8094C854, 255.0f, 1.0f, 20.0f);
|
|
if (temp_t0 == 3) {
|
|
temp_t0 *= 3;
|
|
}
|
|
} else if (temp_t0 == 0) {
|
|
D_8094C854 = 0.0f;
|
|
} else {
|
|
Math_ApproachF(&D_8094C854, 0.0f, 1.0f, 10.0f);
|
|
if (D_8094C854 == 0.0f) {
|
|
sShieldIceCharge = 0;
|
|
sShieldFireCharge = 0;
|
|
}
|
|
|
|
temp_t0 = 1;
|
|
}
|
|
|
|
if (Player_HasMirrorShieldEquipped(globalCtx)) {
|
|
if (temp_t0 != 0) {
|
|
Matrix_Mult(&player->shieldMf, MTXMODE_NEW);
|
|
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7362),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
temp_a0 = (Math_SinS(this->work[CS_TIMER_1] * 2730 * temp_t0) * D_8094C854 * 0.5f) + (D_8094C854 * 0.5f);
|
|
if (sShieldFireCharge != 0) {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 245, 255, temp_a0);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01E0E0));
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (this->work[CS_TIMER_1] * 2) * temp_t0, 0, 0x20,
|
|
0x20, 1, (-this->work[CS_TIMER_1] * 2) * temp_t0, 0, 0x20, 0x20));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 20, 0, (s16)D_8094C854);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01E020));
|
|
} else {
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 225, 255, 255, temp_a0);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01E3A0));
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, (-this->work[CS_TIMER_1] * 5) * temp_t0,
|
|
0x20, 0x40, 1, (this->work[CS_TIMER_1] * 4) * temp_t0, 0, 0x20, 0x20));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 175, 205, 195, (s16)D_8094C854);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01E2C0));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (D_8094C86F != 0) {
|
|
f32 step = D_8094C872 > 0 ? 100.0f : 60.0f;
|
|
|
|
D_8094C86F--;
|
|
Math_ApproachF(&D_8094C858, 255.0f, 1.0f, step);
|
|
} else {
|
|
f32 step = D_8094C872 > 0 ? 40.0f : 20.0f;
|
|
|
|
Math_ApproachF(&D_8094C858, 0.0f, 1.0f, step);
|
|
}
|
|
|
|
if (Player_HasMirrorShieldEquipped(globalCtx) && D_8094C858 > 0.0f) {
|
|
f32 scale = D_8094C872 > 0 ? 1.3f : 1.0f;
|
|
|
|
Matrix_Mult(&player->shieldMf, MTXMODE_NEW);
|
|
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
|
|
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7486),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
if (sShieldFireCharge != 0) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 220, 20, (s16)D_8094C858);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 20, 110);
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s16)D_8094C858);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 185, 225, 205, 150);
|
|
}
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, this->work[CS_TIMER_1] * D_8094C872, 0x20, 0x40, 1,
|
|
0, this->work[CS_TIMER_1] * D_8094C872, 0x20, 0x20));
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01E9F0));
|
|
}
|
|
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7531);
|
|
}
|
|
|
|
void BossTw_SpawnPortalDraw(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7546);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
gSPSegment(
|
|
POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, -this->work[CS_TIMER_1] * 15, 0x20, 0x40, 1, 0, 0, 0x40, 0x40));
|
|
|
|
Matrix_Push();
|
|
|
|
Matrix_Translate(0.0f, 232.0f, -600.0f, MTXMODE_NEW);
|
|
Matrix_Scale(this->spawnPortalScale, this->spawnPortalScale, this->spawnPortalScale, MTXMODE_APPLY);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, (s16)this->spawnPortalAlpha);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7582),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01EC68));
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 135, 175, 165, (s16)this->spawnPortalAlpha);
|
|
Matrix_Translate(0.0f, 2.0f, 0.0f, MTXMODE_APPLY);
|
|
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7596),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01CEE0));
|
|
|
|
Matrix_Translate(0.0f, 232.0f, 600.0f, MTXMODE_NEW);
|
|
Matrix_Scale(this->spawnPortalScale, this->spawnPortalScale, this->spawnPortalScale, MTXMODE_APPLY);
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, (s16)this->spawnPortalAlpha);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7617),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01EC68));
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 0, (s16)this->spawnPortalAlpha);
|
|
Matrix_Translate(0.0f, 2.0f, 0.0f, MTXMODE_APPLY);
|
|
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7631),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01DBE8));
|
|
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7635);
|
|
}
|
|
|
|
void func_80944C50(BossTw* this, GlobalContext* globalCtx) {
|
|
s32 pad;
|
|
f32 scale;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7645);
|
|
|
|
Matrix_Push();
|
|
Matrix_Translate(0.0f, 750.0f, 0.0f, MTXMODE_NEW);
|
|
Matrix_Scale(0.35f, 0.35f, 0.35f, MTXMODE_APPLY);
|
|
Matrix_Push();
|
|
Matrix_Scale(this->workf[UNK_F19], this->workf[UNK_F19], this->workf[UNK_F19], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7671),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01F390));
|
|
|
|
Matrix_Pop();
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, -sKoumePtr->work[CS_TIMER_1] * 2, 0, 0x20, 0x20, 1,
|
|
-sKoumePtr->work[CS_TIMER_1] * 2, 0, 0x20, 0x40));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s16)this->workf[UNK_F18] / 2);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7694),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01F238));
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, -sKoumePtr->work[CS_TIMER_1] * 5,
|
|
-sKoumePtr->work[CS_TIMER_1] * 2, 0x20, 0x40, 1, 0, -sKoumePtr->work[CS_TIMER_1] * 2,
|
|
0x10, 0x10));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s16)(this->workf[UNK_F18] * 0.3f));
|
|
|
|
scale = this->workf[UNK_F18] / 150.0f;
|
|
scale = CLAMP_MAX(scale, 1.0f);
|
|
|
|
Matrix_Scale(scale, 1.0f, scale, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7728),
|
|
G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_NOPUSH);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01EEB0));
|
|
Matrix_Pop();
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7732);
|
|
}
|
|
|
|
void BossTw_TwinrovaDraw(Actor* thisx, GlobalContext* globalCtx2) {
|
|
static Vec3f D_8094A9EC = { 0.0f, 200.0f, 2000.0f };
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7748);
|
|
|
|
if (this->visible) {
|
|
func_80093D18(globalCtx->state.gfxCtx);
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
POLY_OPA_DISP = (this->work[FOG_TIMER] & 2) ? Gfx_SetFog2(POLY_OPA_DISP, 255, 50, 0, 0, 900, 1099)
|
|
: Gfx_SetFog2(POLY_OPA_DISP, (u32)this->fogR, (u32)this->fogG,
|
|
(u32)this->fogB, 0, this->fogNear, this->fogFar);
|
|
|
|
Matrix_Push();
|
|
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
|
this->skelAnime.dListCount, BossTw_TwinrovaOverrideLimbDraw, BossTw_TwinrovaPostLimbDraw,
|
|
thisx);
|
|
Matrix_Pop();
|
|
|
|
Matrix_MultVec3f(&D_8094A9EC, &this->beamOrigin);
|
|
POLY_OPA_DISP = Gfx_SetFog2(POLY_OPA_DISP, globalCtx->lightCtx.fogColor[0], globalCtx->lightCtx.fogColor[1],
|
|
globalCtx->lightCtx.fogColor[2], 0, globalCtx->lightCtx.fogNear, 1000);
|
|
}
|
|
|
|
BossTw_DrawEffects(globalCtx);
|
|
BossTw_ShieldChargeDraw(this, globalCtx);
|
|
|
|
if (this->spawnPortalAlpha > 0.0f) {
|
|
BossTw_SpawnPortalDraw(this, globalCtx);
|
|
}
|
|
|
|
if (this->workf[UNK_F18] > 0.0f) {
|
|
func_80944C50(this, globalCtx);
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 7804);
|
|
}
|
|
|
|
void BossTw_BlastFire(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 distXZ;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
Player* player2 = player;
|
|
|
|
switch (this->actor.params) {
|
|
case TW_FIRE_BLAST:
|
|
switch (this->csState1) {
|
|
case 0:
|
|
Actor_SetScale(&this->actor, 0.03f);
|
|
this->csState1 = 1;
|
|
xDiff = player->actor.world.pos.x - this->actor.world.pos.x;
|
|
yDiff = (player->actor.world.pos.y + 30.0f) - this->actor.world.pos.y;
|
|
zDiff = player->actor.world.pos.z - this->actor.world.pos.z;
|
|
// yaw
|
|
this->actor.world.rot.y = Math_FAtan2F(xDiff, zDiff) * (32768 / M_PI);
|
|
// pitch
|
|
distXZ = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
this->actor.world.rot.x = Math_FAtan2F(yDiff, distXZ) * (32768 / M_PI);
|
|
this->actor.speedXZ = 20.0f;
|
|
|
|
for (i = 0; i < 50; i++) {
|
|
this->blastTailPos[i] = this->actor.world.pos;
|
|
}
|
|
this->workf[TAIL_ALPHA] = 255.0f;
|
|
// fallthrough
|
|
case 1:
|
|
case 10:
|
|
this->blastActive = true;
|
|
if (this->timers[0] == 0) {
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_SHOOT_FIRE & ~SFX_FLAG);
|
|
} else {
|
|
Vec3f velocity;
|
|
Vec3f velDir;
|
|
Vec3s blastDir;
|
|
s16 alpha;
|
|
|
|
this->actor.world.pos = player2->bodyPartsPos[15];
|
|
this->actor.world.pos.y = -2000.0f;
|
|
Matrix_MtxFToYXZRotS(&player2->shieldMf, &blastDir, 0);
|
|
blastDir.x = -blastDir.x;
|
|
blastDir.y = blastDir.y + 0x8000;
|
|
Math_ApproachS(&this->magicDir.x, blastDir.x, 0xA, 0x800);
|
|
Math_ApproachS(&this->magicDir.y, blastDir.y, 0xA, 0x800);
|
|
|
|
if (this->timers[0] == 50) {
|
|
D_8094C86F = 10;
|
|
D_8094C872 = 7;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
|
|
if (this->timers[0] <= 50) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_SHOOT_FIRE & ~SFX_FLAG);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_REFL_FIRE & ~SFX_FLAG);
|
|
Matrix_RotateY((this->magicDir.y / 32678.0f) * M_PI, MTXMODE_NEW);
|
|
Matrix_RotateX((this->magicDir.x / 32678.0f) * M_PI, MTXMODE_APPLY);
|
|
velDir.x = 0.0f;
|
|
velDir.y = 0.0f;
|
|
velDir.z = 50.0f;
|
|
Matrix_MultVec3f(&velDir, &velocity);
|
|
alpha = this->timers[0] * 10;
|
|
alpha = CLAMP_MAX(alpha, 255);
|
|
|
|
BossTw_AddShieldBlastEffect(globalCtx, &player2->bodyPartsPos[15], &velocity, &sZeroVector,
|
|
10.0f, 80.0f, alpha, 1);
|
|
}
|
|
|
|
if (this->timers[0] == 1) {
|
|
sEnvType = 0;
|
|
sShieldFireCharge++;
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
this->groundBlastPos.y = BossTw_GetFloorY(&this->actor.world.pos);
|
|
|
|
if (this->groundBlastPos.y >= 0.0f) {
|
|
if (this->groundBlastPos.y != 35.0f) {
|
|
this->groundBlastPos.x = this->actor.world.pos.x;
|
|
this->groundBlastPos.z = this->actor.world.pos.z;
|
|
BossTw_SpawnGroundBlast(this, globalCtx, 1);
|
|
} else {
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
for (i = 0; i < 50; i++) {
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
accel.x = 0.0f;
|
|
accel.y = 0.0f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &this->actor.world.pos, &velocity, &accel,
|
|
Rand_ZeroFloat(10.0f) + 25.0f, this->blastType);
|
|
}
|
|
|
|
globalCtx->envCtx.unk_D8 = 0.5f;
|
|
}
|
|
|
|
this->csState1 = 2;
|
|
this->timers[0] = 20;
|
|
} else {
|
|
Vec3f pos;
|
|
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
pos = this->blastTailPos[(s16)Rand_ZeroFloat(29.9f)];
|
|
pos.x += Rand_CenteredFloat(40.0f);
|
|
pos.y += Rand_CenteredFloat(40.0f);
|
|
pos.z += Rand_CenteredFloat(40.0f);
|
|
accel.y = 0.4f;
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 8, 1,
|
|
75);
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
Math_ApproachF(&this->workf[TAIL_ALPHA], 0.0f, 1.0f, 15.0f);
|
|
if (this->timers[0] == 0) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TW_FIRE_BLAST_GROUND:
|
|
if (this->timers[0] != 0) {
|
|
if (this->timers[0] == 1) {
|
|
sEnvType = 0;
|
|
}
|
|
|
|
if (sGroundBlastType == 2) {
|
|
this->timers[0] = 0;
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_FIRE_EXP - SFX_FLAG);
|
|
|
|
xDiff = sKoumePtr->groundBlastPos2.x - player->actor.world.pos.x;
|
|
yDiff = sKoumePtr->groundBlastPos2.y - player->actor.world.pos.y;
|
|
zDiff = sKoumePtr->groundBlastPos2.z - player->actor.world.pos.z;
|
|
|
|
if (!player->isBurning && (player->actor.bgCheckFlags & 1) && (fabsf(yDiff) < 10.0f) &&
|
|
(sqrtf(SQ(xDiff) + SQ(zDiff)) < (sKoumePtr->workf[UNK_F13] * 4550.0f))) {
|
|
s16 j;
|
|
|
|
for (j = 0; j < 18; j++) {
|
|
player->flameTimers[j] = Rand_S16Offset(0, 200);
|
|
}
|
|
|
|
player->isBurning = 1;
|
|
|
|
if (this->work[BURN_TMR] == 0) {
|
|
func_8002F7DC(&player->actor, player->ageProperties->unk_92 + NA_SE_VO_LI_DEMO_DAMAGE);
|
|
this->work[BURN_TMR] = 40;
|
|
}
|
|
|
|
sTwinrovaPtr->timers[2] = 100;
|
|
}
|
|
|
|
Math_ApproachF(&sKoumePtr->workf[UNK_F13], 0.04f, 0.1f, 0.002f);
|
|
break;
|
|
}
|
|
|
|
{
|
|
f32 sp4C = sGroundBlastType == 2 ? 3.0f : 1.0f;
|
|
|
|
Math_ApproachF(&sKoumePtr->workf[UNK_F9], 0.0f, 1.0f, 10.0f * sp4C);
|
|
Math_ApproachF(&sKoumePtr->workf[UNK_F12], 0.0f, 1.0f, 0.03f * sp4C);
|
|
Math_ApproachF(&sKoumePtr->workf[TAIL_ALPHA], 0.0f, 1.0f, 3.0f * sp4C);
|
|
Math_ApproachF(&sKoumePtr->workf[UNK_F11], 0.0f, 1.0f, 6.0f * sp4C);
|
|
}
|
|
|
|
if (sKoumePtr->workf[TAIL_ALPHA] <= 0.0f) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BossTw_BlastIce(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 i;
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
f32 xzDist;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
Player* player2 = player;
|
|
|
|
switch (this->actor.params) {
|
|
case TW_ICE_BLAST:
|
|
switch (this->csState1) {
|
|
case 0:
|
|
Actor_SetScale(&this->actor, 0.03f);
|
|
this->csState1 = 1;
|
|
xDiff = player->actor.world.pos.x - this->actor.world.pos.x;
|
|
yDiff = (player->actor.world.pos.y + 30.0f) - this->actor.world.pos.y;
|
|
zDiff = player->actor.world.pos.z - this->actor.world.pos.z;
|
|
this->actor.world.rot.y = Math_FAtan2F(xDiff, zDiff) * (32768 / M_PI);
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
this->actor.world.rot.x = Math_FAtan2F(yDiff, xzDist) * (32768 / M_PI);
|
|
this->actor.speedXZ = 20.0f;
|
|
for (i = 0; i < 50; i++) {
|
|
this->blastTailPos[i] = this->actor.world.pos;
|
|
}
|
|
|
|
this->workf[TAIL_ALPHA] = 255.0f;
|
|
// fallthrough
|
|
case 1:
|
|
case 10:
|
|
this->blastActive = true;
|
|
|
|
if (this->timers[0] == 0) {
|
|
func_8002D908(&this->actor);
|
|
func_8002D7EC(&this->actor);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_SHOOT_FREEZE - SFX_FLAG);
|
|
} else {
|
|
Vec3f velocity;
|
|
Vec3f spF4;
|
|
Vec3s reflDir;
|
|
s16 alpha;
|
|
|
|
this->actor.world.pos = player2->bodyPartsPos[15];
|
|
this->actor.world.pos.y = -2000.0f;
|
|
Matrix_MtxFToYXZRotS(&player2->shieldMf, &reflDir, 0);
|
|
reflDir.x = -reflDir.x;
|
|
reflDir.y += 0x8000;
|
|
Math_ApproachS(&this->magicDir.x, reflDir.x, 0xA, 0x800);
|
|
Math_ApproachS(&this->magicDir.y, reflDir.y, 0xA, 0x800);
|
|
|
|
if (this->timers[0] == 50) {
|
|
D_8094C86F = 10;
|
|
D_8094C872 = 7;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
}
|
|
|
|
if (this->timers[0] <= 50) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_SHOOT_FREEZE - SFX_FLAG);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_REFL_FREEZE - SFX_FLAG);
|
|
Matrix_RotateY((this->magicDir.y / 32678.0f) * M_PI, MTXMODE_NEW);
|
|
Matrix_RotateX((this->magicDir.x / 32678.0f) * M_PI, MTXMODE_APPLY);
|
|
spF4.x = 0.0f;
|
|
spF4.y = 0.0f;
|
|
spF4.z = 50.0f;
|
|
Matrix_MultVec3f(&spF4, &velocity);
|
|
alpha = this->timers[0] * 10;
|
|
alpha = CLAMP_MAX(alpha, 255);
|
|
|
|
BossTw_AddShieldBlastEffect(globalCtx, &player2->bodyPartsPos[15], &velocity, &sZeroVector,
|
|
10.0f, 80.0f, alpha, 0);
|
|
}
|
|
|
|
if (this->timers[0] == 1) {
|
|
sEnvType = 0;
|
|
sShieldIceCharge++;
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
this->groundBlastPos.y = BossTw_GetFloorY(&this->actor.world.pos);
|
|
|
|
if (this->groundBlastPos.y >= 0.0f) {
|
|
if (this->groundBlastPos.y != 35.0f) {
|
|
this->groundBlastPos.x = this->actor.world.pos.x;
|
|
this->groundBlastPos.z = this->actor.world.pos.z;
|
|
BossTw_SpawnGroundBlast(this, globalCtx, 0);
|
|
} else {
|
|
for (i = 0; i < 50; i++) {
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
velocity.x = Rand_CenteredFloat(20.0f);
|
|
velocity.y = Rand_CenteredFloat(20.0f);
|
|
velocity.z = Rand_CenteredFloat(20.0f);
|
|
accel.x = 0.0f;
|
|
accel.y = 0.0f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &this->actor.world.pos, &velocity, &accel,
|
|
Rand_ZeroFloat(10.0f) + 25.0f, this->blastType);
|
|
}
|
|
|
|
globalCtx->envCtx.unk_D8 = 0.5f;
|
|
}
|
|
|
|
this->csState1 = 2;
|
|
this->timers[0] = 20;
|
|
} else {
|
|
Vec3f pos;
|
|
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
pos = this->blastTailPos[(s16)Rand_ZeroFloat(29.9f)];
|
|
pos.x += Rand_CenteredFloat(40.0f);
|
|
pos.y += Rand_CenteredFloat(40.0f);
|
|
pos.z += Rand_CenteredFloat(40.0f);
|
|
accel.y = 0.4f;
|
|
accel.x = Rand_CenteredFloat(0.5f);
|
|
accel.z = Rand_CenteredFloat(0.5f);
|
|
BossTw_AddDotEffect(globalCtx, &pos, &velocity, &accel, ((s16)Rand_ZeroFloat(2.0f) + 8), 0,
|
|
75);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
Math_ApproachF(&this->workf[TAIL_ALPHA], 0.0f, 1.0f, 15.0f);
|
|
if (this->timers[0] == 0) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TW_ICE_BLAST_GROUND:
|
|
if (this->timers[0] != 0) {
|
|
if (this->timers[0] == 1) {
|
|
sEnvType = 0;
|
|
}
|
|
|
|
if (sGroundBlastType == 1) {
|
|
this->timers[0] = 0;
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG);
|
|
|
|
if (this->timers[0] > (sTwinrovaPtr->actionFunc == BossTw_Wait ? 70 : 20)) {
|
|
s32 pad;
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
|
|
pos.x = sKotakePtr->groundBlastPos2.x + Rand_CenteredFloat(320.0f);
|
|
pos.z = sKotakePtr->groundBlastPos2.z + Rand_CenteredFloat(320.0f);
|
|
pos.y = sKotakePtr->groundBlastPos2.y;
|
|
velocity.x = 0.0f;
|
|
velocity.y = 0.0f;
|
|
velocity.z = 0.0f;
|
|
accel.x = 0.0f;
|
|
accel.y = 0.13f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddDmgCloud(globalCtx, 3, &pos, &velocity, &accel, Rand_ZeroFloat(5.0f) + 20.0f, 0, 0, 80);
|
|
velocity.x = Rand_CenteredFloat(10.0f);
|
|
velocity.z = Rand_CenteredFloat(10.0f);
|
|
velocity.y = Rand_ZeroFloat(3.0f) + 3.0f;
|
|
pos.x = sKotakePtr->groundBlastPos2.x + (velocity.x * 0.5f);
|
|
pos.z = sKotakePtr->groundBlastPos2.z + (velocity.z * 0.5f);
|
|
BossTw_AddDmgCloud(globalCtx, 3, &pos, &velocity, &accel, Rand_ZeroFloat(5.0f) + 15.0f, 255, 2,
|
|
130);
|
|
}
|
|
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F9], 80.0f, 1.0f, 3.0f);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F11], 255.0f, 1.0f, 10.0f);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F12], 0.04f, 0.1f, 0.002f);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F16], 70.0f, 1.0f, 5.0f);
|
|
|
|
if ((this->timers[0] == 70) || (this->timers[0] == 30)) {
|
|
sKotakePtr->workf[UNK_F16] = 10.0f;
|
|
}
|
|
|
|
if ((this->timers[0] % 4) == 0) {
|
|
sKotakePtr->workf[UNK_F15] = (2.0f * (s16)Rand_ZeroFloat(9.9f) * M_PI) / 10.0f;
|
|
}
|
|
} else {
|
|
f32 sp80;
|
|
|
|
if (sGroundBlastType == 1) {
|
|
if (sKotakePtr->workf[UNK_F11] > 1.0f) {
|
|
for (i = 0; i < 3; i++) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
pos.x = Rand_CenteredFloat(280.0f) + sKotakePtr->groundBlastPos2.x;
|
|
pos.z = Rand_CenteredFloat(280.0f) + sKotakePtr->groundBlastPos2.z;
|
|
pos.y = sKotakePtr->groundBlastPos2.y + 30.0f;
|
|
velocity.x = 0.0f;
|
|
velocity.y = 0.0f;
|
|
velocity.z = 0.0f;
|
|
accel.x = 0.0f;
|
|
accel.y = 0.13f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddDmgCloud(globalCtx, 3, &pos, &velocity, &accel, Rand_ZeroFloat(5.0f) + 20, 0, 0,
|
|
80);
|
|
}
|
|
}
|
|
sp80 = 3.0f;
|
|
} else {
|
|
sp80 = 1.0f;
|
|
}
|
|
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F14], 0.0f, 1.0f, 0.2f * sp80);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F11], 0.0f, 1.0f, 5.0f * sp80);
|
|
Math_ApproachF(&sKotakePtr->workf[UNK_F9], 0.0f, 1.0f, sp80);
|
|
|
|
if (sKotakePtr->workf[UNK_F9] <= 0.0f) {
|
|
Actor_Kill(&this->actor);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
s32 BossTw_BlastShieldCheck(BossTw* this, GlobalContext* globalCtx) {
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s32 ret = false;
|
|
ColliderInfo* info;
|
|
|
|
if (1) {}
|
|
|
|
if (this->csState1 == 1) {
|
|
if (this->collider.base.acFlags & AC_HIT) {
|
|
this->collider.base.acFlags &= ~AC_HIT;
|
|
this->collider.base.atFlags &= ~AT_HIT;
|
|
info = this->collider.info.acHitInfo;
|
|
|
|
if (info->toucher.dmgFlags & DMG_SHIELD) {
|
|
this->work[INVINC_TIMER] = 7;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
func_800AA000(0.0f, 100, 5, 4);
|
|
|
|
if (Player_HasMirrorShieldEquipped(globalCtx)) {
|
|
if (this->blastType == 1) {
|
|
if (sShieldIceCharge != 0) {
|
|
sShieldIceCharge = 0;
|
|
BossTw_AddShieldDeflectEffect(globalCtx, 10.0f, 1);
|
|
} else {
|
|
BossTw_AddShieldHitEffect(globalCtx, 10.0f, 1);
|
|
sShieldFireCharge++;
|
|
D_8094C86F = (sShieldFireCharge * 2) + 8;
|
|
D_8094C872 = -7;
|
|
}
|
|
} else {
|
|
if (sShieldFireCharge != 0) {
|
|
sShieldFireCharge = 0;
|
|
if (1) {}
|
|
BossTw_AddShieldDeflectEffect(globalCtx, 10.0f, 0);
|
|
} else {
|
|
BossTw_AddShieldHitEffect(globalCtx, 10.0f, 0);
|
|
sShieldIceCharge++;
|
|
D_8094C86F = (sShieldIceCharge * 2) + 8;
|
|
D_8094C872 = -7;
|
|
}
|
|
}
|
|
|
|
if ((sShieldIceCharge >= 3) || (sShieldFireCharge >= 3)) {
|
|
this->timers[0] = 80;
|
|
this->csState1 = 10;
|
|
Matrix_MtxFToYXZRotS(&player->shieldMf, &this->magicDir, 0);
|
|
this->magicDir.y += 0x8000;
|
|
this->magicDir.x = -this->magicDir.x;
|
|
D_8094C86F = 8;
|
|
} else {
|
|
this->csState1 = 2;
|
|
this->timers[0] = 20;
|
|
sEnvType = 0;
|
|
}
|
|
} else {
|
|
BossTw_AddShieldDeflectEffect(globalCtx, 10.0f, this->blastType);
|
|
this->csState1 = 2;
|
|
this->timers[0] = 20;
|
|
sEnvType = 0;
|
|
sShieldIceCharge = 0;
|
|
sShieldFireCharge = 0;
|
|
func_80078884(NA_SE_IT_SHIELD_REFLECT_MG2);
|
|
}
|
|
|
|
ret = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void BossTw_BlastUpdate(Actor* thisx, GlobalContext* globalCtx) {
|
|
BossTw* this = (BossTw*)thisx;
|
|
ColliderCylinder* collider;
|
|
s16 i;
|
|
|
|
this->work[CS_TIMER_1]++;
|
|
this->work[CS_TIMER_2]++;
|
|
this->work[TAIL_IDX]++;
|
|
|
|
if (this->work[TAIL_IDX] > 29) {
|
|
this->work[TAIL_IDX] = 0;
|
|
}
|
|
|
|
this->blastTailPos[this->work[TAIL_IDX]] = this->actor.world.pos;
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
if (this->timers[i] != 0) {
|
|
this->timers[i]--;
|
|
}
|
|
}
|
|
|
|
if (this->work[INVINC_TIMER] != 0) {
|
|
this->work[INVINC_TIMER]--;
|
|
}
|
|
|
|
if (this->work[BURN_TMR] != 0) {
|
|
this->work[BURN_TMR]--;
|
|
}
|
|
|
|
this->actor.focus.pos = this->actor.world.pos;
|
|
collider = &this->collider;
|
|
Collider_UpdateCylinder(&this->actor, collider);
|
|
|
|
if (this->blastActive && this->work[INVINC_TIMER] == 0 && !BossTw_BlastShieldCheck(this, globalCtx)) {
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &collider->base);
|
|
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &collider->base);
|
|
}
|
|
|
|
this->blastActive = false;
|
|
}
|
|
|
|
void BossTw_BlastDraw(Actor* thisx, GlobalContext* globalCtx2) {
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
f32 scaleFactor;
|
|
s16 tailIdx;
|
|
s16 i;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 8818);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
switch (this->actor.params) {
|
|
case TW_FIRE_BLAST:
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, (s8)this->workf[TAIL_ALPHA]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
|
|
for (i = 9; i >= 0; i--) {
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(
|
|
globalCtx->state.gfxCtx, 0, ((this->work[CS_TIMER_1] * 3) + (i * 10)) & 0x7F,
|
|
((-this->work[CS_TIMER_1] * 15) + (i * 50)) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
tailIdx = ((this->work[TAIL_IDX] - i) + 30) % 30;
|
|
Matrix_Translate(this->blastTailPos[tailIdx].x, this->blastTailPos[tailIdx].y,
|
|
this->blastTailPos[tailIdx].z, MTXMODE_NEW);
|
|
scaleFactor = 1.0f - (i * 0.09f);
|
|
Matrix_Scale(this->actor.scale.x * scaleFactor, this->actor.scale.y * scaleFactor,
|
|
this->actor.scale.z * scaleFactor, MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 8865),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A430));
|
|
}
|
|
break;
|
|
|
|
case TW_FIRE_BLAST_GROUND:
|
|
break;
|
|
|
|
case TW_ICE_BLAST:
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (s8)this->workf[TAIL_ALPHA]);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A998));
|
|
for (i = 9; i >= 0; i--) {
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(
|
|
globalCtx->state.gfxCtx, 0, ((this->work[CS_TIMER_1] * 3) + (i * 0xA)) & 0x7F,
|
|
(u8)((-this->work[CS_TIMER_1] * 0xF) + (i * 50)), 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
tailIdx = ((this->work[TAIL_IDX] - i) + 30) % 30;
|
|
Matrix_Translate(this->blastTailPos[tailIdx].x, this->blastTailPos[tailIdx].y,
|
|
this->blastTailPos[tailIdx].z, MTXMODE_NEW);
|
|
scaleFactor = 1.0f - (i * 0.09f);
|
|
Matrix_Scale(this->actor.scale.x * scaleFactor, this->actor.scale.y * scaleFactor,
|
|
this->actor.scale.z * scaleFactor, MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9004),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AB00));
|
|
}
|
|
break;
|
|
|
|
case TW_ICE_BLAST_GROUND:
|
|
break;
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9013);
|
|
}
|
|
|
|
void BossTw_DrawDeathBall(Actor* thisx, GlobalContext* globalCtx2) {
|
|
GlobalContext* globalCtx = globalCtx2;
|
|
BossTw* this = (BossTw*)thisx;
|
|
f32 scaleFactor;
|
|
s16 tailIdx;
|
|
s16 i;
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9028);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
if (this->actor.params == TW_DEATHBALL_KOUME) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, (s8)this->workf[TAIL_ALPHA]);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
|
|
|
|
for (i = 9; i >= 0; i--) {
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (((this->work[CS_TIMER_1] * 3) + (i * 0xA))) & 0x7F,
|
|
(u8)((-this->work[CS_TIMER_1] * 0xF) + (i * 50)), 0x20, 0x40, 1, 0, 0, 0x20,
|
|
0x20));
|
|
tailIdx = ((this->work[TAIL_IDX] - i) + 30) % 30;
|
|
Matrix_Translate(this->blastTailPos[tailIdx].x, this->blastTailPos[tailIdx].y,
|
|
this->blastTailPos[tailIdx].z, MTXMODE_NEW);
|
|
scaleFactor = (1.0f - (i * 0.09f));
|
|
Matrix_Scale(this->actor.scale.x * scaleFactor, this->actor.scale.y * scaleFactor,
|
|
this->actor.scale.z * scaleFactor, MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9071),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A430));
|
|
}
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (s8)this->workf[TAIL_ALPHA]);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A998));
|
|
|
|
for (i = 9; i >= 0; i--) {
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (((this->work[CS_TIMER_1] * 3) + (i * 0xA))) & 0x7F,
|
|
(u8)((-this->work[CS_TIMER_1] * 0xF) + (i * 50)), 0x20, 0x40, 1, 0, 0, 0x20,
|
|
0x20));
|
|
tailIdx = ((this->work[TAIL_IDX] - i) + 30) % 30;
|
|
Matrix_Translate(this->blastTailPos[tailIdx].x, this->blastTailPos[tailIdx].y,
|
|
this->blastTailPos[tailIdx].z, MTXMODE_NEW);
|
|
scaleFactor = (1.0f - (i * 0.09f));
|
|
Matrix_Scale(this->actor.scale.x * scaleFactor, this->actor.scale.y * scaleFactor,
|
|
this->actor.scale.z * scaleFactor, MTXMODE_APPLY);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9107),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AB00));
|
|
}
|
|
}
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_boss_tw.c", 9111);
|
|
}
|
|
|
|
void BossTw_UpdateEffects(GlobalContext* globalCtx) {
|
|
static Color_RGB8 sDotColors[] = {
|
|
{ 255, 128, 0 }, { 255, 0, 0 }, { 255, 255, 0 }, { 255, 0, 0 },
|
|
{ 100, 100, 100 }, { 255, 255, 255 }, { 150, 150, 150 }, { 255, 255, 255 },
|
|
};
|
|
Vec3f sp11C;
|
|
BossTwEffect* eff = globalCtx->specialEffects;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
u8 sp113 = 0;
|
|
s16 i;
|
|
s16 j;
|
|
s16 colorIdx;
|
|
Vec3f off;
|
|
Vec3f spF4;
|
|
Vec3f spE8;
|
|
Vec3f spDC;
|
|
Vec3f spD0;
|
|
f32 phi_f22;
|
|
Vec3f spC0;
|
|
Vec3f spB4;
|
|
Vec3f spA8;
|
|
s16 spA6;
|
|
f32 phi_f0;
|
|
Actor* unk44;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (eff->type != 0) {
|
|
eff->pos.x += eff->curSpeed.x;
|
|
eff->pos.y += eff->curSpeed.y;
|
|
eff->pos.z += eff->curSpeed.z;
|
|
eff->frame++;
|
|
eff->curSpeed.x += eff->accel.x;
|
|
eff->curSpeed.y += eff->accel.y;
|
|
eff->curSpeed.z += eff->accel.z;
|
|
|
|
if (eff->type == 1) {
|
|
colorIdx = eff->frame % 4;
|
|
|
|
if (eff->work[EFF_ARGS] == 0) {
|
|
colorIdx += 4;
|
|
}
|
|
|
|
eff->color.r = sDotColors[colorIdx].r;
|
|
eff->color.g = sDotColors[colorIdx].g;
|
|
eff->color.b = sDotColors[colorIdx].b;
|
|
eff->alpha -= 20;
|
|
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
|
|
} else if ((eff->type == 3) || (eff->type == 2)) {
|
|
if (eff->work[EFF_ARGS] == 2) {
|
|
eff->alpha -= 20;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
} else if (eff->work[EFF_ARGS] == 0) {
|
|
eff->alpha += 10;
|
|
if (eff->alpha >= 100) {
|
|
eff->work[EFF_ARGS]++;
|
|
}
|
|
} else {
|
|
eff->alpha -= 3;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
} else if (eff->type == TWEFF_FLAME) {
|
|
if (eff->work[EFF_UNKS1] != 0) {
|
|
eff->alpha = (eff->alpha - (i & 7)) - 0xD;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
} else {
|
|
eff->alpha += 300;
|
|
if (eff->alpha >= 255) {
|
|
eff->alpha = 255;
|
|
eff->work[EFF_UNKS1]++;
|
|
}
|
|
}
|
|
} else if (eff->type == TWEFF_SHLD_BLST) {
|
|
D_8094C870 = 1;
|
|
eff->work[EFF_UNKS1]++;
|
|
if (eff->work[EFF_UNKS1] > 30) {
|
|
eff->alpha -= 10;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], eff->workf[EFF_DIST], 0.1f, 0.003f);
|
|
off.x = sTwinrovaPtr->actor.world.pos.x - eff->pos.x;
|
|
off.y = (sTwinrovaPtr->actor.world.pos.y - eff->pos.y) * 0.5f;
|
|
off.z = sTwinrovaPtr->actor.world.pos.z - eff->pos.z;
|
|
|
|
if (sTwinrovaPtr->actionFunc != BossTw_TwinrovaStun) {
|
|
if ((SQ(off.x) + SQ(off.y) + SQ(off.z)) < SQ(60.0f)) {
|
|
for (j = 0; j < 50; j++) {
|
|
spF4.x = sTwinrovaPtr->actor.world.pos.x + Rand_CenteredFloat(35.0f);
|
|
spF4.y = sTwinrovaPtr->actor.world.pos.y + Rand_CenteredFloat(70.0f);
|
|
spF4.z = sTwinrovaPtr->actor.world.pos.z + Rand_CenteredFloat(35.0f);
|
|
spE8.x = Rand_CenteredFloat(20.0f);
|
|
spE8.y = Rand_CenteredFloat(20.0f);
|
|
spE8.z = Rand_CenteredFloat(20.0f);
|
|
spDC.x = 0.0f;
|
|
spDC.y = 0.0f;
|
|
spDC.z = 0.0f;
|
|
BossTw_AddFlameEffect(globalCtx, &spF4, &spE8, &spDC, Rand_ZeroFloat(10.0f) + 25.0f,
|
|
eff->work[EFF_ARGS]);
|
|
}
|
|
|
|
sTwinrovaPtr->twinrovaStun = 1;
|
|
globalCtx->envCtx.unk_D8 = 1.0f;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
} else if (eff->type == TWEFF_MERGEFLAME) {
|
|
sp11C.x = 0.0f;
|
|
sp11C.y = eff->pos.y;
|
|
sp11C.z = eff->workf[EFF_DIST];
|
|
Matrix_RotateY(sTwinrovaPtr->workf[UNK_F9] + eff->workf[EFF_ROLL], MTXMODE_NEW);
|
|
Matrix_MultVec3f(&sp11C, &eff->pos);
|
|
|
|
if (eff->work[EFF_UNKS1] != 0) {
|
|
eff->alpha -= 60;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
} else {
|
|
eff->alpha += 60;
|
|
if (eff->alpha >= 255) {
|
|
eff->alpha = 255;
|
|
eff->work[EFF_UNKS1]++;
|
|
}
|
|
}
|
|
} else if (eff->type == TWEFF_SHLD_DEFL) {
|
|
eff->work[EFF_UNKS1]++;
|
|
sp11C.x = 0.0f;
|
|
sp11C.y = 0.0f;
|
|
sp11C.z = -eff->workf[EFF_DIST];
|
|
Matrix_RotateY((sShieldHitYaw / 32768.0f) * M_PI, MTXMODE_NEW);
|
|
Matrix_RotateX(-0.2f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->workf[EFF_ROLL], MTXMODE_APPLY);
|
|
Matrix_RotateY(eff->workf[EFF_YAW], MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&sp11C, &eff->pos);
|
|
eff->pos.x += sShieldHitPos.x;
|
|
eff->pos.y += sShieldHitPos.y;
|
|
eff->pos.z += sShieldHitPos.z;
|
|
|
|
if (eff->work[EFF_UNKS1] < 10) {
|
|
Math_ApproachF(&eff->workf[EFF_DIST], 50.0f, 0.5f, 100.0f);
|
|
} else {
|
|
Math_ApproachF(&eff->workf[EFF_YAW], 0.0f, 0.5f, 10.0f);
|
|
Math_ApproachF(&eff->workf[EFF_DIST], 1000.0f, 1.0f, 10.0f);
|
|
if (eff->work[EFF_UNKS1] >= 0x10) {
|
|
if ((eff->work[EFF_UNKS1] == 16) && (sp113 == 0)) {
|
|
sp113 = 1;
|
|
spD0 = eff->pos;
|
|
if (eff->pos.y > 40.0f) {
|
|
spD0.y = 220.0f;
|
|
} else {
|
|
spD0.y = -50.0f;
|
|
}
|
|
sTwinrovaPtr->groundBlastPos.y = phi_f0 = BossTw_GetFloorY(&spD0);
|
|
if (phi_f0 >= 0.0f) {
|
|
if (sTwinrovaPtr->groundBlastPos.y != 35.0f) {
|
|
sTwinrovaPtr->groundBlastPos.x = eff->pos.x;
|
|
sTwinrovaPtr->groundBlastPos.z = eff->pos.z;
|
|
BossTw_SpawnGroundBlast(sTwinrovaPtr, globalCtx, eff->work[EFF_ARGS]);
|
|
}
|
|
}
|
|
}
|
|
eff->alpha -= 300;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BossTw_AddFlameEffect(globalCtx, &eff->pos, &sZeroVector, &sZeroVector, 10, eff->work[EFF_ARGS]);
|
|
} else if (eff->type == TWEFF_SHLD_HIT) {
|
|
eff->work[EFF_UNKS1]++;
|
|
sp11C.x = 0.0f;
|
|
sp11C.y = 0.0f;
|
|
sp11C.z = -eff->workf[EFF_DIST];
|
|
Matrix_RotateY((sShieldHitYaw / 32768.0f) * M_PI, MTXMODE_NEW);
|
|
Matrix_RotateX(-0.2f, MTXMODE_APPLY);
|
|
Matrix_RotateZ(eff->workf[EFF_ROLL], MTXMODE_APPLY);
|
|
Matrix_RotateY(eff->workf[EFF_YAW], MTXMODE_APPLY);
|
|
Matrix_MultVec3f(&sp11C, &eff->pos);
|
|
eff->pos.x += sShieldHitPos.x;
|
|
eff->pos.y += sShieldHitPos.y;
|
|
eff->pos.z += sShieldHitPos.z;
|
|
|
|
if (eff->work[EFF_UNKS1] < 5) {
|
|
Math_ApproachF(&eff->workf[EFF_DIST], 40.0f, 0.5f, 100.0f);
|
|
} else {
|
|
Math_ApproachF(&eff->workf[EFF_DIST], 0.0f, 0.2f, 5.0f);
|
|
if (eff->work[EFF_UNKS1] >= 11) {
|
|
eff->alpha -= 30;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BossTw_AddFlameEffect(globalCtx, &eff->pos, &sZeroVector, &sZeroVector, 10, eff->work[EFF_ARGS]);
|
|
} else if (eff->type == 4) {
|
|
if (eff->work[EFF_UNKS1] == 0) {
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], eff->workf[EFF_DIST], 0.05f, 1.0f);
|
|
|
|
if (eff->frame >= 16) {
|
|
eff->alpha -= 10;
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
} else {
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], eff->workf[EFF_DIST], 0.1f, 2.0f);
|
|
eff->alpha -= 15;
|
|
|
|
if (eff->alpha <= 0) {
|
|
eff->alpha = 0;
|
|
eff->type = TWEFF_NONE;
|
|
}
|
|
}
|
|
} else if (eff->type == TWEFF_PLYR_FRZ) {
|
|
if (eff->work[EFF_ARGS] < eff->frame) {
|
|
phi_f0 = 1.0f;
|
|
|
|
if (eff->target != NULL || sGroundBlastType == 1) {
|
|
phi_f0 *= 3.0f;
|
|
}
|
|
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], 0.0f, 1.0f, 0.0005f * phi_f0);
|
|
|
|
if (eff->workf[EFF_SCALE] == 0.0f) {
|
|
eff->type = TWEFF_NONE;
|
|
if (eff->target == NULL) {
|
|
player->stateFlags2 &= ~0x8000;
|
|
sFreezeState = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (sGroundBlastType == 1) {
|
|
eff->frame = 100;
|
|
}
|
|
Math_ApproachF(&eff->workf[EFF_DIST], 0.8f, 0.2f, 0.04f);
|
|
|
|
if (eff->target == NULL) {
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], 0.012f, 1.0f, 0.002f);
|
|
eff->workf[EFF_ROLL] += eff->workf[EFF_DIST];
|
|
|
|
if (eff->workf[EFF_ROLL] >= 0.8f) {
|
|
eff->workf[EFF_ROLL] -= 0.8f;
|
|
player->stateFlags2 |= 0x8000;
|
|
} else {
|
|
player->stateFlags2 &= ~0x8000;
|
|
}
|
|
|
|
if ((sKotakePtr->workf[UNK_F11] > 10.0f) && (sKotakePtr->workf[UNK_F11] < 200.0f)) {
|
|
eff->frame = 100;
|
|
}
|
|
|
|
if (!(globalCtx->gameplayFrames & 1)) {
|
|
globalCtx->damagePlayer(globalCtx, -1);
|
|
}
|
|
} else {
|
|
Math_ApproachF(&eff->workf[EFF_SCALE], 0.042f, 1.0f, 0.002f);
|
|
}
|
|
|
|
if ((eff->workf[EFF_DIST] > 0.4f) && ((eff->frame & 7) == 0)) {
|
|
spA6 = Rand_ZeroFloat(17.9f);
|
|
|
|
if (eff->target == NULL) {
|
|
spC0.x = player->bodyPartsPos[spA6].x + Rand_CenteredFloat(5.0f);
|
|
spC0.y = player->bodyPartsPos[spA6].y + Rand_CenteredFloat(5.0f);
|
|
spC0.z = player->bodyPartsPos[spA6].z + Rand_CenteredFloat(5.0f);
|
|
phi_f22 = 10.0f;
|
|
} else {
|
|
unk44 = eff->target;
|
|
spC0.x = unk44->world.pos.x + Rand_CenteredFloat(40.0f);
|
|
spC0.y = unk44->world.pos.y + Rand_CenteredFloat(40.0f);
|
|
spC0.z = unk44->world.pos.z + Rand_CenteredFloat(40.0f);
|
|
phi_f22 = 20.0f;
|
|
}
|
|
|
|
spB4.x = 0.0f;
|
|
spB4.y = 0.0f;
|
|
spB4.z = 0.0f;
|
|
spA8.x = 0.0f;
|
|
spA8.y = 0.1f;
|
|
spA8.z = 0.0f;
|
|
|
|
BossTw_AddDmgCloud(globalCtx, 3, &spC0, &spB4, &spA8, phi_f22 + Rand_ZeroFloat(phi_f22 * 0.5f),
|
|
0, 0, 150);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
eff++;
|
|
}
|
|
}
|
|
|
|
static s32 sRandSeed0;
|
|
static s32 sRandSeed1;
|
|
static s32 sRandSeed2;
|
|
|
|
void BossTw_InitRand(s32 seed0, s32 seed1, s32 seed2) {
|
|
sRandSeed0 = seed0;
|
|
sRandSeed1 = seed1;
|
|
sRandSeed2 = seed2;
|
|
}
|
|
|
|
f32 BossTw_RandZeroOne(void) {
|
|
f32 rand;
|
|
|
|
// Wichmann-Hill algorithm
|
|
sRandSeed0 = (sRandSeed0 * 171) % 30269;
|
|
sRandSeed1 = (sRandSeed1 * 172) % 30307;
|
|
sRandSeed2 = (sRandSeed2 * 170) % 30323;
|
|
|
|
rand = (sRandSeed0 / 30269.0f) + (sRandSeed1 / 30307.0f) + (sRandSeed2 / 30323.0f);
|
|
while (rand >= 1.0f) {
|
|
rand -= 1.0f;
|
|
}
|
|
|
|
return fabsf(rand);
|
|
}
|
|
|
|
void BossTw_DrawEffects(GlobalContext* globalCtx) {
|
|
u8 sp18F = 0;
|
|
s16 i;
|
|
s16 j;
|
|
s32 pad;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
s16 phi_s4;
|
|
BossTwEffect* currentEffect = globalCtx->specialEffects;
|
|
BossTwEffect* effectHead;
|
|
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
|
|
|
|
effectHead = currentEffect;
|
|
|
|
OPEN_DISPS(gfxCtx, "../z_boss_tw.c", 9592);
|
|
|
|
func_80093D84(globalCtx->state.gfxCtx);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (currentEffect->type == 1) {
|
|
if (sp18F == 0) {
|
|
gSPDisplayList(POLY_XLU_DISP++, object_tw_DL_01A528);
|
|
sp18F++;
|
|
}
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, currentEffect->color.r, currentEffect->color.g,
|
|
currentEffect->color.b, currentEffect->alpha);
|
|
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9617),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, object_tw_DL_01A5A8);
|
|
}
|
|
|
|
currentEffect++;
|
|
}
|
|
|
|
sp18F = 0;
|
|
currentEffect = effectHead;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (currentEffect->type == 3) {
|
|
if (sp18F == 0) {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A998));
|
|
sp18F++;
|
|
}
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, currentEffect->alpha);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
|
|
(currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9660),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AB00));
|
|
}
|
|
currentEffect++;
|
|
}
|
|
|
|
sp18F = 0;
|
|
currentEffect = effectHead;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (currentEffect->type == 2) {
|
|
if (sp18F == 0) {
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
|
|
sp18F++;
|
|
}
|
|
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, currentEffect->alpha);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
|
|
(currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9709),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A430));
|
|
}
|
|
|
|
currentEffect++;
|
|
}
|
|
|
|
sp18F = 0;
|
|
currentEffect = effectHead;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (currentEffect->type == 4) {
|
|
if (sp18F == 0) {
|
|
sp18F++;
|
|
}
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 0xD,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, currentEffect->frame & 0x7F,
|
|
(currentEffect->frame * 8) & 0xFF, 0x20, 0x40, 1,
|
|
(currentEffect->frame * -2) & 0x7F, 0, 0x10, 0x10));
|
|
|
|
if (currentEffect->work[EFF_ARGS] == 1) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 65, 0, currentEffect->alpha);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 128);
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, currentEffect->alpha);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128);
|
|
}
|
|
|
|
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
|
|
if (currentEffect->work[EFF_UNKS1] == 0) {
|
|
Matrix_Translate(0.0f, 0.0f, 60.0f, MTXMODE_APPLY);
|
|
} else {
|
|
Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY);
|
|
}
|
|
|
|
Matrix_RotateZ(currentEffect->workf[EFF_ROLL], MTXMODE_APPLY);
|
|
Matrix_RotateX(M_PI / 2.0f, MTXMODE_APPLY);
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], 1.0f, currentEffect->workf[EFF_SCALE], MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9775),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gDPSetRenderMode(POLY_XLU_DISP++, G_RM_PASS, G_RM_AA_ZB_XLU_SURF2);
|
|
gSPClearGeometryMode(POLY_XLU_DISP++, G_CULL_BACK | G_FOG);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A790));
|
|
}
|
|
|
|
currentEffect++;
|
|
}
|
|
|
|
sp18F = 0;
|
|
currentEffect = effectHead;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
Actor* actor;
|
|
Vec3f off;
|
|
|
|
if (currentEffect->type == TWEFF_PLYR_FRZ) {
|
|
if (sp18F == 0) {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AA50));
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, 255);
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
sp18F++;
|
|
BossTw_InitRand(1, 0x71AC, 0x263A);
|
|
}
|
|
|
|
actor = currentEffect->target;
|
|
phi_s4 = actor == NULL ? 70 : 20;
|
|
|
|
for (j = 0; j < phi_s4; j++) {
|
|
off.x = (BossTw_RandZeroOne() - 0.5f) * 30.0f;
|
|
off.y = currentEffect->workf[EFF_DIST] * j;
|
|
off.z = (BossTw_RandZeroOne() - 0.5f) * 30.0f;
|
|
|
|
if (actor != NULL) {
|
|
Matrix_Translate(actor->world.pos.x + off.x, actor->world.pos.y + off.y, actor->world.pos.z + off.z,
|
|
MTXMODE_NEW);
|
|
} else {
|
|
Matrix_Translate(player->actor.world.pos.x + off.x, player->actor.world.pos.y + off.y,
|
|
player->actor.world.pos.z + off.z, MTXMODE_NEW);
|
|
}
|
|
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE],
|
|
currentEffect->workf[EFF_SCALE], MTXMODE_APPLY);
|
|
Matrix_RotateY(BossTw_RandZeroOne() * M_PI, MTXMODE_APPLY);
|
|
Matrix_RotateX((BossTw_RandZeroOne() - 0.5f) * M_PI * 0.5f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9855),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AB00));
|
|
}
|
|
}
|
|
|
|
currentEffect++;
|
|
}
|
|
|
|
sp18F = 0;
|
|
currentEffect = effectHead;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sTwEffects); i++) {
|
|
if (currentEffect->type >= 6) {
|
|
if (currentEffect->work[EFF_ARGS] == 0) {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, currentEffect->alpha);
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A998));
|
|
} else {
|
|
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, currentEffect->alpha);
|
|
gDPPipeSync(POLY_XLU_DISP++);
|
|
gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128);
|
|
}
|
|
|
|
gSPSegment(POLY_XLU_DISP++, 8,
|
|
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
|
|
(-currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
|
|
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
|
|
Matrix_ReplaceRotation(&globalCtx->billboardMtxF);
|
|
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
|
|
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_tw.c", 9911),
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
if (currentEffect->work[EFF_ARGS] == 0) {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01AB00));
|
|
} else {
|
|
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(object_tw_DL_01A430));
|
|
}
|
|
}
|
|
|
|
currentEffect++;
|
|
}
|
|
|
|
CLOSE_DISPS(gfxCtx, "../z_boss_tw.c", 9920);
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupArriveAtTarget(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaArriveAtTarget;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, -3.0f);
|
|
this->work[CS_TIMER_1] = Rand_ZeroFloat(100.0f);
|
|
this->timers[1] = 25;
|
|
this->rotateSpeed = 0.0f;
|
|
}
|
|
|
|
void BossTw_TwinrovaArriveAtTarget(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.1f, fabsf(this->actor.velocity.x) * 1.5f);
|
|
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.1f, fabsf(this->actor.velocity.y) * 1.5f);
|
|
Math_ApproachF(&this->targetPos.y, 380.0f, 1.0f, 2.0f);
|
|
Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.1f, fabsf(this->actor.velocity.z) * 1.5f);
|
|
|
|
if (this->timers[1] == 1) {
|
|
BossTw_TwinrovaSetupChargeBlast(this, globalCtx);
|
|
}
|
|
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, this->rotateSpeed);
|
|
Math_ApproachF(&this->rotateSpeed, 4096.0f, 1.0f, 350.0f);
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupChargeBlast(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaChargeBlast;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_036FBC, -5.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_036FBC);
|
|
this->csState1 = 0;
|
|
}
|
|
|
|
void BossTw_TwinrovaChargeBlast(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.03f, fabsf(this->actor.velocity.x) * 1.5f);
|
|
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.03f, fabsf(this->actor.velocity.y) * 1.5f);
|
|
Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.03f, fabsf(this->actor.velocity.z) * 1.5f);
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
if ((s8)this->actor.colChkInfo.health < 10) {
|
|
sTwinrovaBlastType = Rand_ZeroFloat(1.99f);
|
|
} else {
|
|
if (++sFixedBlatSeq >= 4) {
|
|
sFixedBlatSeq = 1;
|
|
sFixedBlastType = !sFixedBlastType;
|
|
}
|
|
|
|
sTwinrovaBlastType = sFixedBlastType;
|
|
}
|
|
|
|
BossTw_TwinrovaSetupShootBlast(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupShootBlast(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaShootBlast;
|
|
|
|
if (sTwinrovaBlastType == 0) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_022700, 0.0f);
|
|
} else {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_023750, 0.0f);
|
|
}
|
|
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_023750);
|
|
}
|
|
|
|
void BossTw_TwinrovaShootBlast(BossTw* this, GlobalContext* globalCtx) {
|
|
BossTw* twMagic;
|
|
Vec3f* magicSpawnPos;
|
|
s32 magicParams;
|
|
s16 i;
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 8.0f)) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_THROW_MASIC);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_SHOOTVC);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 12.0f)) {
|
|
if (sTwinrovaBlastType != 0) {
|
|
magicParams = TW_FIRE_BLAST;
|
|
magicSpawnPos = &this->rightScepterPos;
|
|
} else {
|
|
magicParams = TW_ICE_BLAST;
|
|
magicSpawnPos = &this->leftScepterPos;
|
|
}
|
|
|
|
twMagic =
|
|
(BossTw*)Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_BOSS_TW, magicSpawnPos->x,
|
|
magicSpawnPos->y, magicSpawnPos->z, 0, 0, 0, magicParams);
|
|
|
|
if (twMagic != NULL) {
|
|
twMagic->blastType = magicParams == TW_ICE_BLAST ? 0 : 1;
|
|
}
|
|
|
|
sEnvType = twMagic->blastType + 1;
|
|
|
|
{
|
|
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
|
|
Vec3f accel = { 0.0f, 0.0f, 0.0f };
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
velocity.x = Rand_CenteredFloat(30.0f);
|
|
velocity.y = Rand_CenteredFloat(30.0f);
|
|
velocity.z = Rand_CenteredFloat(30.0f);
|
|
BossTw_AddDotEffect(globalCtx, magicSpawnPos, &velocity, &accel, (s16)Rand_ZeroFloat(2.0f) + 11,
|
|
twMagic->blastType, 75);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
BossTw_TwinrovaSetupDoneBlastShoot(this, globalCtx);
|
|
}
|
|
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000);
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupDoneBlastShoot(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaDoneBlastShoot;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, -10.0f);
|
|
this->timers[1] = 60;
|
|
}
|
|
|
|
void BossTw_TwinrovaDoneBlastShoot(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (this->timers[1] == 0 && D_8094C870 == 0) {
|
|
if (sTwinrovaPtr->timers[2] == 0) {
|
|
BossTw_TwinrovaSetupFly(this, globalCtx);
|
|
} else {
|
|
BossTw_TwinrovaSetupLaugh(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
D_8094C870 = 0;
|
|
Math_ApproachS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000);
|
|
}
|
|
|
|
void BossTw_TwinrovaDamage(BossTw* this, GlobalContext* globalCtx, u8 damage) {
|
|
if (this->actionFunc != BossTw_TwinrovaStun) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_0338F0, -15.0f);
|
|
this->timers[0] = 150;
|
|
this->timers[1] = 20;
|
|
this->csState1 = 0;
|
|
this->actor.velocity.y = 0.0f;
|
|
} else {
|
|
this->work[FOG_TIMER] = 10;
|
|
this->work[INVINC_TIMER] = 20;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_024374, -3.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_024374);
|
|
this->csState1 = 1;
|
|
|
|
if ((s8)(this->actor.colChkInfo.health -= damage) < 0) {
|
|
this->actor.colChkInfo.health = 0;
|
|
}
|
|
|
|
if ((s8)this->actor.colChkInfo.health <= 0) {
|
|
BossTw_TwinrovaSetupDeathCS(this, globalCtx);
|
|
Enemy_StartFinishingBlow(globalCtx, &this->actor);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_DEAD);
|
|
return;
|
|
}
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_DAMAGE2);
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_CUTBODY);
|
|
}
|
|
|
|
this->actionFunc = BossTw_TwinrovaStun;
|
|
}
|
|
|
|
void BossTw_TwinrovaStun(BossTw* this, GlobalContext* globalCtx) {
|
|
s16 cloudType;
|
|
|
|
this->unk_5F8 = 1;
|
|
this->actor.flags |= ACTOR_FLAG_10;
|
|
|
|
cloudType = sTwinrovaBlastType == 0 ? 3 : 2;
|
|
|
|
if ((this->work[CS_TIMER_1] % 8) == 0) {
|
|
Vec3f pos;
|
|
Vec3f velocity;
|
|
Vec3f accel;
|
|
pos.x = this->actor.world.pos.x + Rand_CenteredFloat(20.0f);
|
|
pos.y = this->actor.world.pos.y + Rand_CenteredFloat(40.0f) + 20;
|
|
pos.z = this->actor.world.pos.z + Rand_CenteredFloat(20.0f);
|
|
velocity.x = 0.0f;
|
|
velocity.y = 0.0f;
|
|
velocity.z = 0.0f;
|
|
accel.x = 0.0f;
|
|
accel.y = 0.1f;
|
|
accel.z = 0.0f;
|
|
BossTw_AddDmgCloud(globalCtx, cloudType, &pos, &velocity, &accel, Rand_ZeroFloat(5.0f) + 10.0f, 0, 0, 150);
|
|
}
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
this->work[UNK_S8] += 20;
|
|
|
|
if (this->work[UNK_S8] > 255) {
|
|
this->work[UNK_S8] = 255;
|
|
}
|
|
|
|
Math_ApproachF(&this->workf[UNK_F12], 0.0f, 1.0f, 0.05f);
|
|
this->actor.world.pos.y += this->actor.velocity.y;
|
|
Math_ApproachF(&this->actor.velocity.y, -5.0f, 1.0f, 0.5f);
|
|
this->actor.world.pos.y -= 30.0f;
|
|
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 50.0f, 50.0f, 100.0f, 4);
|
|
this->actor.world.pos.y += 30.0f;
|
|
|
|
if (this->csState1 == 0) {
|
|
if (this->timers[1] == 0) {
|
|
this->csState1 = 1;
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_0343B4);
|
|
Animation_Change(&this->skelAnime, &object_tw_Anim_0343B4, 1.0f, 0.0f, this->workf[ANIM_SW_TGT], 3, 0.0f);
|
|
}
|
|
} else if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_035030, 0.0f);
|
|
}
|
|
|
|
if (this->actor.bgCheckFlags & 1) {
|
|
this->actor.velocity.y = 0.0f;
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
BossTw_TwinrovaSetupGetUp(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupGetUp(BossTw* this, GlobalContext* globalCtx) {
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_035988, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_035988);
|
|
this->actionFunc = BossTw_TwinrovaGetUp;
|
|
this->timers[0] = 50;
|
|
}
|
|
|
|
void BossTw_TwinrovaGetUp(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.05f, 5.0f);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
this->workf[ANIM_SW_TGT] = 1000.0f;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, 0.0f);
|
|
}
|
|
|
|
if (this->timers[0] == 0) {
|
|
BossTw_TwinrovaSetupFly(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupFly(BossTw* this, GlobalContext* globalCtx) {
|
|
f32 xDiff;
|
|
f32 zDiff;
|
|
f32 yDiff;
|
|
f32 xzDist;
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
do {
|
|
this->work[TW_PLLR_IDX] += (s16)(((s16)Rand_ZeroFloat(2.99f)) + 1);
|
|
this->work[TW_PLLR_IDX] %= 4;
|
|
this->targetPos = sTwinrovaPillarPos[this->work[TW_PLLR_IDX]];
|
|
xDiff = this->targetPos.x - player->actor.world.pos.x;
|
|
zDiff = this->targetPos.z - player->actor.world.pos.z;
|
|
xzDist = SQ(xDiff) + SQ(zDiff);
|
|
} while (!(xzDist > SQ(300.0f)));
|
|
|
|
this->targetPos.y = 480.0f;
|
|
xDiff = this->targetPos.x - this->actor.world.pos.x;
|
|
yDiff = this->targetPos.y - this->actor.world.pos.y;
|
|
zDiff = this->targetPos.z - this->actor.world.pos.z;
|
|
this->actionFunc = BossTw_TwinrovaFly;
|
|
this->rotateSpeed = 0.0f;
|
|
this->actor.speedXZ = 0.0f;
|
|
this->actor.world.rot.y = Math_FAtan2F(xDiff, zDiff) * (32768 / M_PI);
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
this->actor.world.rot.x = Math_FAtan2F(yDiff, xzDist) * (32768 / M_PI);
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, -10.0f);
|
|
}
|
|
|
|
void BossTw_TwinrovaFly(BossTw* this, GlobalContext* globalCtx) {
|
|
f32 xDiff;
|
|
f32 yDiff;
|
|
f32 zDiff;
|
|
s32 pad;
|
|
f32 yaw;
|
|
f32 xzDist;
|
|
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_FLY - SFX_FLAG);
|
|
SkelAnime_Update(&this->skelAnime);
|
|
xDiff = this->targetPos.x - this->actor.world.pos.x;
|
|
yDiff = this->targetPos.y - this->actor.world.pos.y;
|
|
zDiff = this->targetPos.z - this->actor.world.pos.z;
|
|
// Convert from radians to degrees, then degrees to binary angle
|
|
yaw = (s16)(Math_FAtan2F(xDiff, zDiff) * ((180.0f / M_PI) * (65536.0f / 360.0f)));
|
|
xzDist = sqrtf(SQ(xDiff) + SQ(zDiff));
|
|
Math_ApproachS(&this->actor.world.rot.x,
|
|
(f32)(s16)(Math_FAtan2F(yDiff, xzDist) * ((180.0f / M_PI) * (65536.0f / 360.0f))), 0xA,
|
|
this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.world.rot.y, yaw, 0xA, this->rotateSpeed);
|
|
Math_ApproachS(&this->actor.shape.rot.y, yaw, 0xA, this->rotateSpeed);
|
|
Math_ApproachF(&this->rotateSpeed, 2000.0f, 1.0f, 100.0f);
|
|
Math_ApproachF(&this->actor.speedXZ, 30.0f, 1.0f, 2.0f);
|
|
func_8002D908(&this->actor);
|
|
Math_ApproachF(&this->actor.world.pos.x, this->targetPos.x, 0.1f, fabsf(this->actor.velocity.x) * 1.5f);
|
|
Math_ApproachF(&this->actor.world.pos.y, this->targetPos.y, 0.1f, fabsf(this->actor.velocity.y) * 1.5f);
|
|
Math_ApproachF(&this->targetPos.y, 380.0f, 1.0f, 2.0f);
|
|
Math_ApproachF(&this->actor.world.pos.z, this->targetPos.z, 0.1f, fabsf(this->actor.velocity.z) * 1.5f);
|
|
|
|
if (xzDist < 200.0f) {
|
|
BossTw_TwinrovaSetupArriveAtTarget(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupSpin(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaSpin;
|
|
Animation_MorphToLoop(&this->skelAnime, &object_tw_Anim_032BF8, 0.0f);
|
|
this->timers[0] = 20;
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
|
|
void BossTw_TwinrovaSpin(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
if (this->timers[0] != 0) {
|
|
this->collider.base.colType = COLTYPE_METAL;
|
|
this->actor.shape.rot.y -= 0x3000;
|
|
|
|
if ((this->timers[0] % 4) == 0) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_ROLL);
|
|
}
|
|
} else {
|
|
BossTw_TwinrovaSetupFly(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_TwinrovaSetupLaugh(BossTw* this, GlobalContext* globalCtx) {
|
|
this->actionFunc = BossTw_TwinrovaLaugh;
|
|
Animation_MorphToPlayOnce(&this->skelAnime, &object_tw_Anim_03A2D0, 0.0f);
|
|
this->workf[ANIM_SW_TGT] = Animation_GetLastFrame(&object_tw_Anim_03A2D0);
|
|
this->actor.speedXZ = 0.0f;
|
|
}
|
|
|
|
void BossTw_TwinrovaLaugh(BossTw* this, GlobalContext* globalCtx) {
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, 10.0f)) {
|
|
Audio_PlayActorSound2(&this->actor, NA_SE_EN_TWINROBA_YOUNG_LAUGH);
|
|
}
|
|
|
|
if (Animation_OnFrame(&this->skelAnime, this->workf[ANIM_SW_TGT])) {
|
|
BossTw_TwinrovaSetupFly(this, globalCtx);
|
|
}
|
|
}
|
|
|
|
void BossTw_Reset(void) {
|
|
sTwInitalized = false;
|
|
memset(sTwEffects, 0, sizeof(sTwEffects));
|
|
}
|