|
|
|
@@ -1,10 +1,12 @@
|
|
|
|
|
/*
|
|
|
|
|
* File: z_en_famos.c
|
|
|
|
|
* Overlay: ovl_En_Famos
|
|
|
|
|
* Description: Death Armos
|
|
|
|
|
* Description: Death Armos (floating statue enemy in Inverted Stone Tower Temple)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "z_en_famos.h"
|
|
|
|
|
#include "overlays/actors/ovl_En_Bom/z_en_bom.h"
|
|
|
|
|
#include "objects/gameplay_keep/gameplay_keep.h"
|
|
|
|
|
|
|
|
|
|
#define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_4)
|
|
|
|
|
|
|
|
|
@@ -15,7 +17,39 @@ void EnFamos_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_Update(Actor* thisx, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_Draw(Actor* thisx, GlobalContext* globalCtx);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
void EnFamos_SetupAttackDebris(EnFamos* this);
|
|
|
|
|
void EnFamos_SetupDeathDebris(EnFamos* this);
|
|
|
|
|
s32 EnFamos_IsPlayerSeen(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupStillIdle(EnFamos* this);
|
|
|
|
|
void EnFamos_StillIdle(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupPathingIdle(EnFamos* this);
|
|
|
|
|
void EnFamos_PathingIdle(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupTurnHome(EnFamos* this);
|
|
|
|
|
void EnFamos_TurnHome(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupReturnHome(EnFamos* this);
|
|
|
|
|
void EnFamos_ReturnHome(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupAlert(EnFamos* this);
|
|
|
|
|
void EnFamos_Alert(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupChase(EnFamos* this);
|
|
|
|
|
void EnFamos_Chase(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupAttackAim(EnFamos* this);
|
|
|
|
|
void EnFamos_AttackAim(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupAttack(EnFamos* this);
|
|
|
|
|
void EnFamos_Attack(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupFinishAttack(EnFamos* this);
|
|
|
|
|
void EnFamos_FinishAttack(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupAttackRebound(EnFamos* this);
|
|
|
|
|
void EnFamos_AttackRebound(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupScanForPlayer(EnFamos* this);
|
|
|
|
|
void EnFamos_ScanForPlayer(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupDeathSlam(EnFamos* this);
|
|
|
|
|
void EnFamos_DeathSlam(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupDeathExplosion(EnFamos* this);
|
|
|
|
|
void EnFamos_DeathExplosion(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_SetupDeathFade(EnFamos* this);
|
|
|
|
|
void EnFamos_DeathFade(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
void EnFamos_DrawDebris(EnFamos* this, GlobalContext* globalCtx);
|
|
|
|
|
|
|
|
|
|
const ActorInit En_Famos_InitVars = {
|
|
|
|
|
ACTOR_EN_FAMOS,
|
|
|
|
|
ACTORCAT_ENEMY,
|
|
|
|
@@ -28,133 +62,810 @@ const ActorInit En_Famos_InitVars = {
|
|
|
|
|
(ActorFunc)EnFamos_Draw,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// static ColliderCylinderInit sCylinderInit = {
|
|
|
|
|
static ColliderCylinderInit D_808AE600 = {
|
|
|
|
|
{ COLTYPE_METAL, AT_NONE | AT_TYPE_ENEMY, AC_ON | AC_HARD | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, },
|
|
|
|
|
{ ELEMTYPE_UNK2, { 0x20000000, 0x04, 0x10 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, },
|
|
|
|
|
static ColliderCylinderInit sCylinderInit1 = {
|
|
|
|
|
{
|
|
|
|
|
COLTYPE_METAL,
|
|
|
|
|
AT_NONE | AT_TYPE_ENEMY,
|
|
|
|
|
AC_ON | AC_HARD | AC_TYPE_PLAYER,
|
|
|
|
|
OC1_ON | OC1_TYPE_ALL,
|
|
|
|
|
OC2_TYPE_1,
|
|
|
|
|
COLSHAPE_CYLINDER,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ELEMTYPE_UNK2,
|
|
|
|
|
{ 0x20000000, 0x04, 0x10 },
|
|
|
|
|
{ 0xF7CFFFFF, 0x00, 0x00 },
|
|
|
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
|
|
|
BUMP_ON,
|
|
|
|
|
OCELEM_ON,
|
|
|
|
|
},
|
|
|
|
|
{ 20, 80, 0, { 0, 0, 0 } },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// static ColliderCylinderInit sCylinderInit = {
|
|
|
|
|
static ColliderCylinderInit D_808AE62C = {
|
|
|
|
|
{ COLTYPE_NONE, AT_NONE | AT_TYPE_ENEMY, AC_NONE, OC1_NONE, OC2_TYPE_1, COLSHAPE_CYLINDER, },
|
|
|
|
|
{ ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x04, 0x08 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_NONE, },
|
|
|
|
|
static ColliderCylinderInit sCylinderInit2 = {
|
|
|
|
|
{
|
|
|
|
|
COLTYPE_NONE,
|
|
|
|
|
AT_NONE | AT_TYPE_ENEMY,
|
|
|
|
|
AC_NONE,
|
|
|
|
|
OC1_NONE,
|
|
|
|
|
OC2_TYPE_1,
|
|
|
|
|
COLSHAPE_CYLINDER,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ELEMTYPE_UNK0,
|
|
|
|
|
{ 0xF7CFFFFF, 0x04, 0x08 },
|
|
|
|
|
{ 0xF7CFFFFF, 0x00, 0x00 },
|
|
|
|
|
TOUCH_ON | TOUCH_SFX_NORMAL,
|
|
|
|
|
BUMP_NONE,
|
|
|
|
|
OCELEM_NONE,
|
|
|
|
|
},
|
|
|
|
|
{ 70, 10, 0, { 0, 0, 0 } },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// static ColliderJntSphElementInit sJntSphElementsInit[2] = {
|
|
|
|
|
static ColliderJntSphElementInit D_808AE658[2] = {
|
|
|
|
|
// the emblem at the from and the back is one limb running front to back through the torso
|
|
|
|
|
// this is both sides of the emblem, front and back
|
|
|
|
|
static ColliderJntSphElementInit sJntSphElementsInit[2] = {
|
|
|
|
|
{
|
|
|
|
|
{ ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x00002000, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, },
|
|
|
|
|
{ 2, { { 2500, 0, 0 }, 20 }, 100 },
|
|
|
|
|
{
|
|
|
|
|
ELEMTYPE_UNK0,
|
|
|
|
|
{ 0x00000000, 0x00, 0x00 },
|
|
|
|
|
{ 0x00002000, 0x00, 0x00 },
|
|
|
|
|
TOUCH_NONE | TOUCH_SFX_NORMAL,
|
|
|
|
|
BUMP_ON,
|
|
|
|
|
OCELEM_NONE,
|
|
|
|
|
},
|
|
|
|
|
{ FAMOS_LIMB_EMBLEM, { { 2500, 0, 0 }, 20 }, 100 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
{ ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x00002000, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, },
|
|
|
|
|
{ 2, { { -1500, 0, 0 }, 20 }, 100 },
|
|
|
|
|
{
|
|
|
|
|
ELEMTYPE_UNK0,
|
|
|
|
|
{ 0x00000000, 0x00, 0x00 },
|
|
|
|
|
{ 0x00002000, 0x00, 0x00 },
|
|
|
|
|
TOUCH_NONE | TOUCH_SFX_NORMAL,
|
|
|
|
|
BUMP_ON,
|
|
|
|
|
OCELEM_NONE,
|
|
|
|
|
},
|
|
|
|
|
{ FAMOS_LIMB_EMBLEM, { { -1500, 0, 0 }, 20 }, 100 },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// static ColliderJntSphInit sJntSphInit = {
|
|
|
|
|
static ColliderJntSphInit D_808AE6A0 = {
|
|
|
|
|
{ COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_NONE, OC2_TYPE_1, COLSHAPE_JNTSPH, },
|
|
|
|
|
2, D_808AE658, // sJntSphElementsInit,
|
|
|
|
|
static ColliderJntSphInit sJntSphInit = {
|
|
|
|
|
{
|
|
|
|
|
COLTYPE_NONE,
|
|
|
|
|
AT_NONE,
|
|
|
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
|
|
|
OC1_NONE,
|
|
|
|
|
OC2_TYPE_1,
|
|
|
|
|
COLSHAPE_JNTSPH,
|
|
|
|
|
},
|
|
|
|
|
2,
|
|
|
|
|
sJntSphElementsInit,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// static InitChainEntry sInitChain[] = {
|
|
|
|
|
static InitChainEntry D_808AE6B8[] = {
|
|
|
|
|
typedef enum {
|
|
|
|
|
/* 0 */ FAMOS_ANIMATED_MAT_NORMAL, // normal is greenish
|
|
|
|
|
/* 1 */ FAMOS_ANIMATED_MAT_FLIPPED // flipped is orange/yellowish
|
|
|
|
|
} FamosAnimatedMatArrayIndexes;
|
|
|
|
|
|
|
|
|
|
static AnimatedMaterial* sEmblemAnimatedMats[] = {
|
|
|
|
|
gFamosNormalGlowingEmblemTexAnim,
|
|
|
|
|
gFamosFlippedGlowingEmblemTexAnim,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static InitChainEntry sInitChain[] = {
|
|
|
|
|
ICHAIN_S8(hintId, 15, ICHAIN_CONTINUE),
|
|
|
|
|
ICHAIN_F32(targetArrowOffset, 3500, ICHAIN_STOP),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
static s32 sAnimatedMaterialsDesgmented = false;
|
|
|
|
|
|
|
|
|
|
extern ColliderCylinderInit D_808AE600;
|
|
|
|
|
extern ColliderCylinderInit D_808AE62C;
|
|
|
|
|
extern ColliderJntSphElementInit D_808AE658[2];
|
|
|
|
|
extern ColliderJntSphInit D_808AE6A0;
|
|
|
|
|
extern InitChainEntry D_808AE6B8[];
|
|
|
|
|
void EnFamos_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
Path* path;
|
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
extern UNK_TYPE D_060000F8;
|
|
|
|
|
extern UNK_TYPE D_06003DC8;
|
|
|
|
|
Actor_ProcessInitChain(&this->actor, sInitChain);
|
|
|
|
|
if (GET_FAMOS_PATH(thisx) != 0xFF) {
|
|
|
|
|
path = &globalCtx->setupPathList[this->actor.params];
|
|
|
|
|
this->pathPoints = Lib_SegmentedToVirtual(path->points);
|
|
|
|
|
this->pathNodeCount = path->count;
|
|
|
|
|
if (this->pathNodeCount == 1) {
|
|
|
|
|
this->pathPoints = NULL;
|
|
|
|
|
this->pathNodeCount = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/EnFamos_Init.s")
|
|
|
|
|
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawSquare, 30.0f);
|
|
|
|
|
SkelAnime_Init(globalCtx, &this->skelAnime, &gFamosSkeleton, &gFamosIdleAnim, this->jointTable, this->morphTable,
|
|
|
|
|
FAMOS_LIMB_MAX);
|
|
|
|
|
Collider_InitAndSetCylinder(globalCtx, &this->collider1, &this->actor, &sCylinderInit1);
|
|
|
|
|
Collider_InitAndSetCylinder(globalCtx, &this->collider2, &this->actor, &sCylinderInit2);
|
|
|
|
|
Collider_InitAndSetJntSph(globalCtx, &this->emblemCollider, &this->actor, &sJntSphInit,
|
|
|
|
|
this->emblemColliderElements);
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/EnFamos_Destroy.s")
|
|
|
|
|
if (!sAnimatedMaterialsDesgmented) { // init animated materials
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sEmblemAnimatedMats); i++) {
|
|
|
|
|
sEmblemAnimatedMats[i] = Lib_SegmentedToVirtual(sEmblemAnimatedMats[i]);
|
|
|
|
|
}
|
|
|
|
|
sAnimatedMaterialsDesgmented = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ACB58.s")
|
|
|
|
|
this->actor.colChkInfo.mass = 250;
|
|
|
|
|
this->baseHeight = this->actor.world.pos.y;
|
|
|
|
|
// params: [this->actor.shape.rot.x] is used to set aggro distance
|
|
|
|
|
this->aggroDistance = (GET_FAMOS_AGGRO_DISTANCE(thisx) <= 0) ? (200.0f) : (this->actor.shape.rot.x * 40.0f * 0.1f);
|
|
|
|
|
this->actor.shape.rot.x = 0;
|
|
|
|
|
this->actor.world.rot.x = 0;
|
|
|
|
|
this->hasFinishedRotating = true;
|
|
|
|
|
this->isCalm = true;
|
|
|
|
|
if (this->pathPoints != NULL) {
|
|
|
|
|
EnFamos_SetupPathingIdle(this);
|
|
|
|
|
} else {
|
|
|
|
|
EnFamos_SetupStillIdle(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ACD2C.s")
|
|
|
|
|
void EnFamos_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ACF1C.s")
|
|
|
|
|
Collider_DestroyCylinder(globalCtx, &this->collider1);
|
|
|
|
|
Collider_DestroyCylinder(globalCtx, &this->collider2);
|
|
|
|
|
Collider_DestroyJntSph(globalCtx, &this->emblemCollider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ACF98.s")
|
|
|
|
|
/**
|
|
|
|
|
* Sets 20 rocks to draw from an explosion on the ground (slam attack).
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupAttackDebris(EnFamos* this) {
|
|
|
|
|
EnFamosRock* rock;
|
|
|
|
|
f32 randFloat;
|
|
|
|
|
s16 randOffset;
|
|
|
|
|
s16 randVelDirection;
|
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD05C.s")
|
|
|
|
|
this->debrisTimer = 40;
|
|
|
|
|
rock = &this->rocks[0];
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->rocks); i++, rock++) {
|
|
|
|
|
randVelDirection = Rand_Next() >> 0x10;
|
|
|
|
|
randOffset = Rand_S16Offset(0x1800, 0x2800);
|
|
|
|
|
randFloat = Rand_ZeroFloat(5.0f) + 5.0f;
|
|
|
|
|
rock->velocity.x = randFloat * Math_CosS(randOffset) * Math_SinS(randVelDirection);
|
|
|
|
|
rock->velocity.y = Math_SinS(randOffset) * randFloat + 3.0f;
|
|
|
|
|
rock->velocity.z = randFloat * Math_CosS(randOffset) * Math_CosS(randVelDirection);
|
|
|
|
|
rock->rotation.x = Rand_Next() >> 0x10;
|
|
|
|
|
rock->rotation.y = Rand_Next() >> 0x10;
|
|
|
|
|
rock->rotation.z = Rand_Next() >> 0x10;
|
|
|
|
|
rock->pos.x = (Math_SinS(randVelDirection) * 20.0f) + this->actor.world.pos.x;
|
|
|
|
|
rock->pos.y = this->actor.floorHeight;
|
|
|
|
|
rock->pos.z = (Math_CosS(randVelDirection) * 20.0f) + this->actor.world.pos.z;
|
|
|
|
|
rock->scale = Rand_ZeroFloat(0.0015f) + (2.0f * 0.001f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD170.s")
|
|
|
|
|
/**
|
|
|
|
|
* Sets 20 rocks to draw from an explosion on death.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupDeathDebris(EnFamos* this) {
|
|
|
|
|
f32 randFloat;
|
|
|
|
|
s16 randSmaller;
|
|
|
|
|
s16 randVelDirection;
|
|
|
|
|
EnFamosRock* rock;
|
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD18C.s")
|
|
|
|
|
this->debrisTimer = 40;
|
|
|
|
|
rock = &this->rocks[0];
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->rocks); i++, rock++) {
|
|
|
|
|
randVelDirection = Rand_Next() >> 0x10;
|
|
|
|
|
randSmaller = (u32)Rand_Next() >> 0x12;
|
|
|
|
|
randFloat = Rand_ZeroFloat(6.0f) + 7.0f;
|
|
|
|
|
rock->velocity.x = randFloat * Math_CosS(randSmaller) * Math_SinS(randVelDirection);
|
|
|
|
|
rock->velocity.y = Math_SinS(randSmaller) * randFloat + 4.5f;
|
|
|
|
|
rock->velocity.z = randFloat * Math_CosS(randSmaller) * Math_CosS(randVelDirection);
|
|
|
|
|
rock->rotation.x = Rand_Next() >> 0x10;
|
|
|
|
|
rock->rotation.y = Rand_Next() >> 0x10;
|
|
|
|
|
rock->rotation.z = Rand_Next() >> 0x10;
|
|
|
|
|
rock->pos.x = Math_SinS(randVelDirection) * 20.0f + this->actor.world.pos.x;
|
|
|
|
|
rock->pos.y = randPlusMinusPoint5Scaled(60.0f) + (this->actor.world.pos.y + 40.0f);
|
|
|
|
|
rock->pos.z = Math_CosS(randVelDirection) * 20.0f + this->actor.world.pos.z;
|
|
|
|
|
rock->scale = Rand_ZeroFloat(0.002f) + (2.5f * 0.001f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD1F0.s")
|
|
|
|
|
s32 EnFamos_IsPlayerSeen(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
if ((Player_GetMask(globalCtx) != PLAYER_MASK_STONE) &&
|
|
|
|
|
(Actor_XZDistanceToPoint(&GET_PLAYER(globalCtx)->actor, &this->calmPos) < this->aggroDistance) &&
|
|
|
|
|
Actor_IsFacingPlayer(&this->actor, 0x5000)) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD294.s")
|
|
|
|
|
void EnFamos_UpdateBobbingHeight(EnFamos* this) {
|
|
|
|
|
if (this->hoverTimer == 0) {
|
|
|
|
|
this->hoverTimer = 30;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD31C.s")
|
|
|
|
|
this->hoverTimer--;
|
|
|
|
|
this->actor.world.pos.y = (Math_SinS(this->hoverTimer * 0x888) * 10.0f) + this->baseHeight;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD378.s")
|
|
|
|
|
if (ABS_ALT(this->flipRot) > 0x4000) { // is famos upside down
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT_REVERSE - SFX_FLAG);
|
|
|
|
|
} else {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT - SFX_FLAG);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD3E8.s")
|
|
|
|
|
/**
|
|
|
|
|
* Checks if emblem has been hit with light arrow.
|
|
|
|
|
* Also checks if previously flipped; handles flip status.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_UpdateFlipStatus(EnFamos* this) {
|
|
|
|
|
u8 hasFinishedRotating;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD42C.s")
|
|
|
|
|
if (this->emblemCollider.base.acFlags & AC_HIT) { // light arrow collision, flip
|
|
|
|
|
this->emblemCollider.base.acFlags &= ~AC_HIT;
|
|
|
|
|
if (this->hasFinishedRotating == true) {
|
|
|
|
|
if (this->animatedMaterialIndex != FAMOS_ANIMATED_MAT_NORMAL) {
|
|
|
|
|
this->animatedMaterialIndex = FAMOS_ANIMATED_MAT_NORMAL;
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_FAMOS_REVERSE2);
|
|
|
|
|
} else {
|
|
|
|
|
this->animatedMaterialIndex = FAMOS_ANIMATED_MAT_FLIPPED;
|
|
|
|
|
this->flippedTimer = 100;
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_FAMOS_REVERSE1);
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_EYEGOLE_DAMAGE);
|
|
|
|
|
}
|
|
|
|
|
this->hasFinishedRotating = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD54C.s")
|
|
|
|
|
} else if (this->flippedTimer > 0) {
|
|
|
|
|
this->flippedTimer--;
|
|
|
|
|
if (this->flippedTimer == 0) {
|
|
|
|
|
if (this->animatedMaterialIndex != FAMOS_ANIMATED_MAT_NORMAL) {
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_FAMOS_REVERSE2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD5B0.s")
|
|
|
|
|
this->animatedMaterialIndex = FAMOS_ANIMATED_MAT_NORMAL;
|
|
|
|
|
this->hasFinishedRotating = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD66C.s")
|
|
|
|
|
if (this->hasFinishedRotating == false) {
|
|
|
|
|
if (this->animatedMaterialIndex != FAMOS_ANIMATED_MAT_NORMAL) {
|
|
|
|
|
hasFinishedRotating = Math_ScaledStepToS(&this->flipRot, -0x8000, 0x1000);
|
|
|
|
|
} else {
|
|
|
|
|
hasFinishedRotating = Math_ScaledStepToS(&this->flipRot, 0, 0x1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD68C.s")
|
|
|
|
|
this->hasFinishedRotating = hasFinishedRotating;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD7EC.s")
|
|
|
|
|
/**
|
|
|
|
|
* If Famos path is 0xFF, famos hovers stationary in the air
|
|
|
|
|
* facing forward, only bobbing up and down, without a path to follow.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupStillIdle(EnFamos* this) {
|
|
|
|
|
this->actionFunc = EnFamos_StillIdle;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD840.s")
|
|
|
|
|
void EnFamos_StillIdle(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
if (this->isCalm) {
|
|
|
|
|
Math_Vec3f_Copy(&this->calmPos, &this->actor.world.pos);
|
|
|
|
|
}
|
|
|
|
|
if (EnFamos_IsPlayerSeen(this, globalCtx)) {
|
|
|
|
|
EnFamos_SetupAlert(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD888.s")
|
|
|
|
|
/**
|
|
|
|
|
* Regular Famos follows a path until seeing the player.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupPathingIdle(EnFamos* this) {
|
|
|
|
|
if (this->isCalm) {
|
|
|
|
|
this->currentPathNode++;
|
|
|
|
|
if (this->currentPathNode == this->pathNodeCount) {
|
|
|
|
|
this->currentPathNode = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this->isCalm = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AD8B8.s")
|
|
|
|
|
Math_Vec3s_ToVec3f(&this->targetDest, &this->pathPoints[this->currentPathNode]);
|
|
|
|
|
this->targetYaw = Actor_YawToPoint(&this->actor, &this->targetDest);
|
|
|
|
|
this->actionFunc = EnFamos_PathingIdle;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADA74.s")
|
|
|
|
|
void EnFamos_PathingIdle(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
if (this->isCalm) {
|
|
|
|
|
Math_Vec3f_Copy(&this->calmPos, &this->actor.world.pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADAE8.s")
|
|
|
|
|
if (EnFamos_IsPlayerSeen(this, globalCtx)) {
|
|
|
|
|
EnFamos_SetupAlert(this);
|
|
|
|
|
} else if (Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x200)) {
|
|
|
|
|
EnFamos_SetupReturnHome(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADB4C.s")
|
|
|
|
|
/**
|
|
|
|
|
* Famos lost player; Turning to face back toward home.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupTurnHome(EnFamos* this) {
|
|
|
|
|
this->targetYaw = Actor_YawToPoint(&this->actor, &this->calmPos);
|
|
|
|
|
Math_Vec3f_Copy(&this->targetDest, &this->calmPos);
|
|
|
|
|
this->actionFunc = EnFamos_TurnHome;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADB70.s")
|
|
|
|
|
void EnFamos_TurnHome(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
if (EnFamos_IsPlayerSeen(this, globalCtx)) {
|
|
|
|
|
EnFamos_SetupAlert(this);
|
|
|
|
|
} else if (Math_ScaledStepToS(&this->actor.shape.rot.y, this->targetYaw, 0x200)) {
|
|
|
|
|
EnFamos_SetupReturnHome(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADC40.s")
|
|
|
|
|
/**
|
|
|
|
|
* Famos has finished rotating toward home; Take off flying in straight line.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupReturnHome(EnFamos* this) {
|
|
|
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
this->actor.world.rot.x = -Actor_PitchToPoint(&this->actor, &this->targetDest);
|
|
|
|
|
this->actionFunc = EnFamos_ReturnHome;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADC64.s")
|
|
|
|
|
void EnFamos_ReturnHome(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
f32 distanceToHome = Actor_XZDistanceToPoint(&this->actor, &this->targetDest);
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADD20.s")
|
|
|
|
|
this->actor.shape.rot.y = Actor_YawToPoint(&this->actor, &this->targetDest);
|
|
|
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
if (this->isCalm) {
|
|
|
|
|
Math_Vec3f_Copy(&this->calmPos, &this->actor.world.pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADDA8.s")
|
|
|
|
|
if (EnFamos_IsPlayerSeen(this, globalCtx)) {
|
|
|
|
|
EnFamos_SetupAlert(this);
|
|
|
|
|
} else if (distanceToHome < 20.0f) {
|
|
|
|
|
if (this->pathPoints != NULL) {
|
|
|
|
|
EnFamos_SetupPathingIdle(this);
|
|
|
|
|
} else {
|
|
|
|
|
EnFamos_SetupStillIdle(this);
|
|
|
|
|
}
|
|
|
|
|
} else if (distanceToHome < 40.0f) {
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 0.5f, 0.3f);
|
|
|
|
|
} else {
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 3.0f, 0.3f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADE00.s")
|
|
|
|
|
/**
|
|
|
|
|
* Famos has spotted the player; delayed by surprise.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupAlert(EnFamos* this) {
|
|
|
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
this->stateTimer = 8;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADE74.s")
|
|
|
|
|
if (this->isCalm == true) {
|
|
|
|
|
this->isCalm = false;
|
|
|
|
|
Math_Vec3f_Copy(&this->calmPos, &this->actor.world.pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADFA4.s")
|
|
|
|
|
this->actionFunc = EnFamos_Alert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808ADFF0.s")
|
|
|
|
|
void EnFamos_Alert(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
if (ABS_ALT(this->flipRot) > 0x4000) {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT_REVERSE - SFX_FLAG);
|
|
|
|
|
} else {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT - SFX_FLAG);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AE030.s")
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
if (this->stateTimer == 0) {
|
|
|
|
|
this->actor.world.pos.y = this->baseHeight;
|
|
|
|
|
EnFamos_SetupChase(this);
|
|
|
|
|
} else {
|
|
|
|
|
this->actor.world.pos.y = Math_SinS(this->stateTimer * 0x1000) * 30.0f + this->baseHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/EnFamos_Update.s")
|
|
|
|
|
/**
|
|
|
|
|
* Famos has spotted the player; Begin chasing to attack.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupChase(EnFamos* this) {
|
|
|
|
|
this->hoverTimer = 0;
|
|
|
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
this->actionFunc = EnFamos_Chase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AE304.s")
|
|
|
|
|
void EnFamos_Chase(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
Player* player = GET_PLAYER(globalCtx);
|
|
|
|
|
Vec3f abovePlayerPos;
|
|
|
|
|
u32 surfaceType;
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AE3A8.s")
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0x800);
|
|
|
|
|
this->actor.world.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
abovePlayerPos.x = player->actor.world.pos.x;
|
|
|
|
|
abovePlayerPos.y = player->actor.world.pos.y + 100.0f;
|
|
|
|
|
abovePlayerPos.z = player->actor.world.pos.z;
|
|
|
|
|
this->actor.world.rot.x = -Actor_PitchToPoint(&this->actor, &abovePlayerPos);
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 6.0f, 0.5f);
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/func_808AE3FC.s")
|
|
|
|
|
surfaceType = func_800C9B18(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId);
|
|
|
|
|
if ((this->actor.xzDistToPlayer < 30.0f) && (this->actor.floorHeight > BGCHECK_Y_MIN) && // close enough
|
|
|
|
|
(surfaceType != 0xC && surfaceType != 0xD)) {
|
|
|
|
|
EnFamos_SetupAttackAim(this);
|
|
|
|
|
|
|
|
|
|
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Famos/EnFamos_Draw.s")
|
|
|
|
|
} else if ((Player_GetMask(globalCtx) == PLAYER_MASK_STONE) ||
|
|
|
|
|
(this->aggroDistance < Actor_XZDistanceToPoint(&GET_PLAYER(globalCtx)->actor, &this->calmPos)) ||
|
|
|
|
|
!Actor_IsFacingPlayer(&this->actor, 0x6000)) {
|
|
|
|
|
EnFamos_SetupScanForPlayer(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_SetupAttackAim(EnFamos* this) {
|
|
|
|
|
Animation_PlayOnce(&this->skelAnime, &gFamosShakeAnim);
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_AMOS_VOICE);
|
|
|
|
|
this->actionFunc = EnFamos_AttackAim;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_AttackAim(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_LAST1_FALL_OLD - SFX_FLAG);
|
|
|
|
|
if (SkelAnime_Update(&this->skelAnime)) {
|
|
|
|
|
EnFamos_SetupAttack(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_SetupAttack(EnFamos* this) {
|
|
|
|
|
this->actor.world.rot.x = -0x4000;
|
|
|
|
|
this->collider1.base.atFlags |= AT_ON;
|
|
|
|
|
this->stateTimer = 4;
|
|
|
|
|
this->actionFunc = EnFamos_Attack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_Attack(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
s32 hitFloor;
|
|
|
|
|
u32 surfaceType;
|
|
|
|
|
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 20.0f, 2.0f);
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
if (this->stateTimer == 0) {
|
|
|
|
|
this->emblemCollider.base.acFlags &= ~AC_ON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surfaceType = func_800C9B18(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId);
|
|
|
|
|
hitFloor = this->actor.bgCheckFlags & 1;
|
|
|
|
|
if (hitFloor || (this->actor.floorHeight == BGCHECK_Y_MIN) || (surfaceType == 0xC) || (surfaceType == 0xD)) {
|
|
|
|
|
this->collider1.base.atFlags &= ~AT_ON;
|
|
|
|
|
this->collider2.base.atFlags |= AT_ON;
|
|
|
|
|
if (hitFloor) {
|
|
|
|
|
func_800DFD04(globalCtx->cameraPtrs[globalCtx->activeCamera], 2, 15, 10); // camera shake?
|
|
|
|
|
func_8013ECE0(this->actor.xyzDistToPlayerSq, 180, 20, 100);
|
|
|
|
|
EnFamos_SetupAttackDebris(this);
|
|
|
|
|
|
|
|
|
|
// spawn crator on floor
|
|
|
|
|
Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_TEST, this->actor.world.pos.x,
|
|
|
|
|
this->actor.floorHeight, this->actor.world.pos.z, 0, 0, 0, 0x0);
|
|
|
|
|
|
|
|
|
|
if (this->actor.child != NULL) {
|
|
|
|
|
Actor_SetScale(this->actor.child, 0.015f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->animatedMaterialIndex != FAMOS_ANIMATED_MAT_NORMAL) {
|
|
|
|
|
this->cratorDespawnTimer = 70;
|
|
|
|
|
EnFamos_SetupDeathSlam(this);
|
|
|
|
|
} else {
|
|
|
|
|
this->cratorDespawnTimer = 20;
|
|
|
|
|
EnFamos_SetupFinishAttack(this);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this->emblemCollider.base.acFlags |= AC_ON;
|
|
|
|
|
EnFamos_SetupAttackRebound(this);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_LAST1_FALL_OLD - SFX_FLAG);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attack has hit; Wait for animation to finish before recovering from attack.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupFinishAttack(EnFamos* this) {
|
|
|
|
|
Animation_PlayOnce(&this->skelAnime, &gFamosIdleAnim);
|
|
|
|
|
SkelAnime_Update(&this->skelAnime);
|
|
|
|
|
this->emblemCollider.base.acFlags |= AC_ON;
|
|
|
|
|
this->stateTimer = 3;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_EXPLOSION);
|
|
|
|
|
this->actionFunc = EnFamos_FinishAttack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_FinishAttack(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
if (this->stateTimer == 0) {
|
|
|
|
|
this->collider2.base.atFlags &= ~AT_ON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
if (SkelAnime_Update(&this->skelAnime)) {
|
|
|
|
|
EnFamos_SetupAttackRebound(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_SetupAttackRebound(EnFamos* this) {
|
|
|
|
|
this->actor.world.rot.x = 0x4000;
|
|
|
|
|
this->actionFunc = EnFamos_AttackRebound;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_AttackRebound(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 5.0f, 0.3f);
|
|
|
|
|
if (this->actor.speedXZ > 1.0f) {
|
|
|
|
|
if (ABS_ALT(this->flipRot) > 0x4000) {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT_REVERSE - SFX_FLAG);
|
|
|
|
|
} else {
|
|
|
|
|
func_800B9010(&this->actor, NA_SE_EN_FAMOS_FLOAT - SFX_FLAG);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((this->baseHeight < this->actor.world.pos.y) || (this->actor.bgCheckFlags & 0x10)) { // touching ceiling
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
EnFamos_SetupChase(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Looking around for player.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupScanForPlayer(EnFamos* this) {
|
|
|
|
|
this->stateTimer = 60;
|
|
|
|
|
this->actionFunc = EnFamos_ScanForPlayer;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_ScanForPlayer(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos_UpdateBobbingHeight(this);
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
|
|
|
|
|
if (EnFamos_IsPlayerSeen(this, globalCtx)) {
|
|
|
|
|
EnFamos_SetupAlert(this);
|
|
|
|
|
} else if (this->stateTimer == 0) {
|
|
|
|
|
EnFamos_SetupTurnHome(this);
|
|
|
|
|
} else {
|
|
|
|
|
this->actor.shape.rot.y = (s32)(Math_SinS(this->stateTimer * 0x888) * 8192.0f) + this->actor.world.rot.y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Famos was upside down and hit the ground headfirst. This kills the Famos.
|
|
|
|
|
*/
|
|
|
|
|
void EnFamos_SetupDeathSlam(EnFamos* this) {
|
|
|
|
|
this->emblemCollider.base.acFlags &= ~AC_ON;
|
|
|
|
|
this->stateTimer = 20;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 20);
|
|
|
|
|
this->flippedTimer = -1;
|
|
|
|
|
this->actor.world.pos.y = this->actor.floorHeight - 60.0f;
|
|
|
|
|
Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_EYEGOLE_DEAD);
|
|
|
|
|
this->actionFunc = EnFamos_DeathSlam;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_DeathSlam(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
if (this->stateTimer == 17) {
|
|
|
|
|
this->collider2.base.atFlags &= ~AT_ON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->stateTimer == 0) {
|
|
|
|
|
EnFamos_SetupDeathExplosion(this);
|
|
|
|
|
} else {
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_SetupDeathExplosion(EnFamos* this) {
|
|
|
|
|
this->actor.world.rot.x = 0x4000;
|
|
|
|
|
Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, false, 4);
|
|
|
|
|
this->stateTimer = 25;
|
|
|
|
|
Math_Vec3f_Copy(&this->targetDest, &this->actor.world.pos);
|
|
|
|
|
this->actor.flags |= ACTOR_FLAG_10;
|
|
|
|
|
this->actionFunc = EnFamos_DeathExplosion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_DeathExplosion(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
Math_StepToF(&this->actor.speedXZ, 3.0f, 0.3f);
|
|
|
|
|
if (this->actor.colorFilterTimer == 0) {
|
|
|
|
|
Actor_SetColorFilter(&this->actor, 0x4000, 0xFF, false, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->actor.world.pos.x = randPlusMinusPoint5Scaled(5.0f) + this->targetDest.x;
|
|
|
|
|
this->actor.world.pos.z = randPlusMinusPoint5Scaled(5.0f) + this->targetDest.z;
|
|
|
|
|
if (this->stateTimer == 1) {
|
|
|
|
|
EnBom* explosion =
|
|
|
|
|
(EnBom*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_BOM, this->actor.world.pos.x,
|
|
|
|
|
this->actor.world.pos.y + 40.0f, this->actor.world.pos.z, 0, 0, 0, ENBOM_0);
|
|
|
|
|
if (explosion != NULL) {
|
|
|
|
|
explosion->timer = 0; // instant explosion
|
|
|
|
|
}
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
|
|
|
|
|
} else if (this->stateTimer == 0) {
|
|
|
|
|
Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.world.pos,
|
|
|
|
|
(0xD << 4)); // random item from droptable 0xD
|
|
|
|
|
EnFamos_SetupDeathFade(this);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
this->stateTimer--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_SetupDeathFade(EnFamos* this) {
|
|
|
|
|
EnFamos_SetupDeathDebris(this);
|
|
|
|
|
this->actor.flags &= ~ACTOR_FLAG_1;
|
|
|
|
|
this->actor.shape.shadowDraw = NULL;
|
|
|
|
|
this->actionFunc = EnFamos_DeathFade;
|
|
|
|
|
this->actor.speedXZ = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_DeathFade(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
Actor* enBom;
|
|
|
|
|
|
|
|
|
|
if (this->debrisTimer == 0) {
|
|
|
|
|
enBom = this->actor.child;
|
|
|
|
|
if (enBom != NULL) {
|
|
|
|
|
enBom->parent = NULL;
|
|
|
|
|
}
|
|
|
|
|
Actor_MarkForDeath(&this->actor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_UpdateDebrisPosRot(EnFamos* this) {
|
|
|
|
|
EnFamosRock* rock;
|
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
rock = &this->rocks[0];
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->rocks); i++, rock++) {
|
|
|
|
|
rock->velocity.y -= 1.0f;
|
|
|
|
|
Math_Vec3f_Sum(&rock->pos, &rock->velocity, &rock->pos);
|
|
|
|
|
// all casts seem required
|
|
|
|
|
rock->rotation.x += (s16)(((u32)Rand_Next() >> 0x17) + 0x700);
|
|
|
|
|
rock->rotation.y += (s16)(((u32)Rand_Next() >> 0x17) + 0x900);
|
|
|
|
|
rock->rotation.z += (s16)(((u32)Rand_Next() >> 0x17) + 0xB00);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|
|
|
|
s32 pad;
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
f32 oldHeight;
|
|
|
|
|
s32 oldHoverTimer; // save old value to test if changed
|
|
|
|
|
|
|
|
|
|
if (this->debrisTimer <= 0 ||
|
|
|
|
|
(this->debrisTimer--, EnFamos_UpdateDebrisPosRot(this), (this->actionFunc != EnFamos_DeathFade))) {
|
|
|
|
|
oldHoverTimer = this->hoverTimer;
|
|
|
|
|
EnFamos_UpdateFlipStatus(this);
|
|
|
|
|
if (this->cratorDespawnTimer > 0) {
|
|
|
|
|
this->cratorDespawnTimer--;
|
|
|
|
|
if (this->cratorDespawnTimer == 0) {
|
|
|
|
|
this->actor.child->parent = NULL; // child is EnTest (Crator after stomp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->actionFunc(this, globalCtx);
|
|
|
|
|
oldHeight = this->actor.world.pos.y;
|
|
|
|
|
Actor_MoveWithoutGravity(&this->actor);
|
|
|
|
|
if (oldHoverTimer != this->hoverTimer) { // test if updated in actionFunc
|
|
|
|
|
this->baseHeight += this->actor.world.pos.y - oldHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->flippedTimer >= 0) {
|
|
|
|
|
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 35.0f, 30.0f, 80.0f, 0x1F);
|
|
|
|
|
if ((this->actionFunc == EnFamos_Attack) && (this->animatedMaterialIndex != FAMOS_ANIMATED_MAT_NORMAL) &&
|
|
|
|
|
(this->actor.bgCheckFlags & 1)) { // touch floor
|
|
|
|
|
this->actor.world.pos.y -= 60.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->actor.focus.rot.y = this->actor.shape.rot.y;
|
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider1);
|
|
|
|
|
if (this->collider1.base.atFlags & AT_ON) {
|
|
|
|
|
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider1.base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider1.base);
|
|
|
|
|
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider1.base);
|
|
|
|
|
if (this->emblemCollider.base.acFlags & AC_ON) {
|
|
|
|
|
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->emblemCollider.base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->collider2.base.atFlags & AC_ON) {
|
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider2);
|
|
|
|
|
this->collider2.dim.pos.y = this->actor.floorHeight;
|
|
|
|
|
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider2.base);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 EnFamos_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot,
|
|
|
|
|
Actor* thisx) {
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
|
|
|
|
|
if (limbIndex == FAMOS_LIMB_BODY) {
|
|
|
|
|
Matrix_InsertTranslation(0.0f, 4000.0f, 0.0f, MTXMODE_APPLY);
|
|
|
|
|
Matrix_InsertZRotation_s(this->flipRot, MTXMODE_APPLY);
|
|
|
|
|
Matrix_InsertTranslation(0.0f, -4000.0f, 0.0f, MTXMODE_APPLY);
|
|
|
|
|
|
|
|
|
|
} else if (this->flippedTimer < 0) { // if set to -1, famos is dying
|
|
|
|
|
if ((limbIndex == FAMOS_LIMB_SWORD) || (limbIndex == FAMOS_LIMB_SHIELD) || (limbIndex == FAMOS_LIMB_HEAD)) {
|
|
|
|
|
*dList = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
|
|
|
|
|
if (limbIndex == FAMOS_LIMB_EMBLEM) {
|
|
|
|
|
Matrix_GetStateTranslation(&this->actor.focus.pos);
|
|
|
|
|
Collider_UpdateSpheres(limbIndex, &this->emblemCollider);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_DrawDebris(EnFamos* this, GlobalContext* globalCtx) {
|
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
if (this->debrisTimer > 0) {
|
|
|
|
|
Gfx* dispOpa;
|
|
|
|
|
EnFamosRock* rock;
|
|
|
|
|
|
|
|
|
|
OPEN_DISPS(globalCtx->state.gfxCtx);
|
|
|
|
|
dispOpa = POLY_OPA_DISP;
|
|
|
|
|
|
|
|
|
|
gSPDisplayList(&dispOpa[0], &sSetupDL[6 * 0x19]);
|
|
|
|
|
|
|
|
|
|
gDPSetPrimColor(&dispOpa[1], 0, 0x80, 255, 255, 255, 255);
|
|
|
|
|
|
|
|
|
|
gDPSetEnvColor(&dispOpa[2], 255, 255, 255, 255);
|
|
|
|
|
|
|
|
|
|
rock = &this->rocks[0];
|
|
|
|
|
for (i = 0; i < ARRAY_COUNT(this->rocks); i++, rock++) {
|
|
|
|
|
|
|
|
|
|
Matrix_SetStateRotationAndTranslation(rock->pos.x, rock->pos.y, rock->pos.z, &rock->rotation);
|
|
|
|
|
Matrix_Scale(rock->scale, rock->scale, rock->scale, MTXMODE_APPLY);
|
|
|
|
|
|
|
|
|
|
gSPMatrix(&dispOpa[3 + i * 2], Matrix_NewMtx(globalCtx->state.gfxCtx),
|
|
|
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
|
|
|
|
|
|
gSPDisplayList(&dispOpa[4 + i * 2], &gameplay_keep_DL_06AB30); // greenish brown rock DL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
POLY_OPA_DISP = &dispOpa[3 + (ARRAY_COUNT(this->rocks) * 2)];
|
|
|
|
|
|
|
|
|
|
CLOSE_DISPS(globalCtx->state.gfxCtx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnFamos_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
|
|
|
|
EnFamos* this = THIS;
|
|
|
|
|
|
|
|
|
|
func_8012C28C(globalCtx->state.gfxCtx);
|
|
|
|
|
if (this->actionFunc != EnFamos_DeathFade) {
|
|
|
|
|
AnimatedMat_Draw(globalCtx, sEmblemAnimatedMats[this->animatedMaterialIndex]);
|
|
|
|
|
SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, EnFamos_OverrideLimbDraw,
|
|
|
|
|
EnFamos_PostLimbDraw, &this->actor);
|
|
|
|
|
if (this->actor.colorFilterTimer != 0) {
|
|
|
|
|
func_800AE5A0(globalCtx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EnFamos_DrawDebris(this, globalCtx);
|
|
|
|
|
}
|
|
|
|
|