2022-03-21 21:51:23 -04:00
|
|
|
/*
|
|
|
|
* File: z_door_ana.c
|
|
|
|
* Overlay: ovl_Door_Ana
|
|
|
|
* Description: Grottos Entrances/Exits
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "z_door_ana.h"
|
|
|
|
#include "objects/gameplay_field_keep/gameplay_field_keep.h"
|
2022-11-14 06:13:21 -05:00
|
|
|
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
2023-06-27 19:53:35 -04:00
|
|
|
#include "soh/Enhancements/randomizer/randomizer_grotto.h"
|
2022-03-21 21:51:23 -04:00
|
|
|
|
2023-05-30 15:05:04 -04:00
|
|
|
#define FLAGS ACTOR_FLAG_NO_FREEZE_OCARINA
|
2022-03-21 21:51:23 -04:00
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_Init(Actor* thisx, PlayState* play);
|
|
|
|
void DoorAna_Destroy(Actor* thisx, PlayState* play);
|
|
|
|
void DoorAna_Update(Actor* thisx, PlayState* play);
|
|
|
|
void DoorAna_Draw(Actor* thisx, PlayState* play);
|
2022-03-21 21:51:23 -04:00
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_WaitClosed(DoorAna* this, PlayState* play);
|
|
|
|
void DoorAna_WaitOpen(DoorAna* this, PlayState* play);
|
|
|
|
void DoorAna_GrabPlayer(DoorAna* this, PlayState* play);
|
2022-03-21 21:51:23 -04:00
|
|
|
|
2023-06-27 19:53:35 -04:00
|
|
|
void Grotto_OverrideActorEntrance(Actor* thisx);
|
|
|
|
|
2022-03-21 21:51:23 -04:00
|
|
|
const ActorInit Door_Ana_InitVars = {
|
|
|
|
ACTOR_DOOR_ANA,
|
|
|
|
ACTORCAT_ITEMACTION,
|
|
|
|
FLAGS,
|
|
|
|
OBJECT_GAMEPLAY_FIELD_KEEP,
|
|
|
|
sizeof(DoorAna),
|
|
|
|
(ActorFunc)DoorAna_Init,
|
|
|
|
(ActorFunc)DoorAna_Destroy,
|
|
|
|
(ActorFunc)DoorAna_Update,
|
|
|
|
(ActorFunc)DoorAna_Draw,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static ColliderCylinderInit sCylinderInit = {
|
|
|
|
{
|
|
|
|
COLTYPE_NONE,
|
|
|
|
AT_NONE,
|
|
|
|
AC_ON | AC_TYPE_PLAYER,
|
|
|
|
OC1_NONE,
|
|
|
|
OC2_NONE,
|
|
|
|
COLSHAPE_CYLINDER,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ELEMTYPE_UNK2,
|
|
|
|
{ 0x00000000, 0x00, 0x00 },
|
|
|
|
{ 0x00000048, 0x00, 0x00 },
|
|
|
|
TOUCH_NONE,
|
|
|
|
BUMP_ON,
|
|
|
|
OCELEM_NONE,
|
|
|
|
},
|
|
|
|
{ 50, 10, 0, { 0 } },
|
|
|
|
};
|
|
|
|
|
|
|
|
// array of entrance table entries to grotto destinations
|
2023-11-19 14:29:56 -05:00
|
|
|
static s16 sGrottoEntrances[] = {
|
|
|
|
ENTR_FAIRYS_FOUNTAIN_0, ENTR_GROTTOS_0, ENTR_GROTTOS_1, ENTR_GROTTOS_2, ENTR_GROTTOS_3,
|
|
|
|
ENTR_GROTTOS_4, ENTR_GROTTOS_5, ENTR_GROTTOS_6, ENTR_GROTTOS_7, ENTR_GROTTOS_8,
|
|
|
|
ENTR_GROTTOS_9, ENTR_GROTTOS_10, ENTR_GROTTOS_11, ENTR_GROTTOS_12, ENTR_GROTTOS_13,
|
2022-03-21 21:51:23 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
void DoorAna_SetupAction(DoorAna* this, DoorAnaActionFunc actionFunc) {
|
|
|
|
this->actionFunc = actionFunc;
|
|
|
|
}
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_Init(Actor* thisx, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
DoorAna* this = (DoorAna*)thisx;
|
|
|
|
|
|
|
|
this->actor.shape.rot.z = 0;
|
|
|
|
this->actor.shape.rot.y = this->actor.shape.rot.z;
|
|
|
|
// init block for grottos that are initially "hidden" (require explosives/hammer/song of storms to open)
|
|
|
|
if ((this->actor.params & 0x300) != 0) {
|
|
|
|
// only allocate collider for grottos that need bombing/hammering open
|
|
|
|
if ((this->actor.params & 0x200) != 0) {
|
2022-11-06 03:24:34 -05:00
|
|
|
Collider_InitCylinder(play, &this->collider);
|
|
|
|
Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
|
2022-03-21 21:51:23 -04:00
|
|
|
} else {
|
2023-05-30 15:05:04 -04:00
|
|
|
this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
Actor_SetScale(&this->actor, 0);
|
|
|
|
DoorAna_SetupAction(this, DoorAna_WaitClosed);
|
|
|
|
} else {
|
|
|
|
DoorAna_SetupAction(this, DoorAna_WaitOpen);
|
|
|
|
}
|
|
|
|
this->actor.targetMode = 0;
|
|
|
|
}
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_Destroy(Actor* thisx, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
DoorAna* this = (DoorAna*)thisx;
|
|
|
|
|
|
|
|
// free collider if it has one
|
|
|
|
if ((this->actor.params & 0x200) != 0) {
|
2022-11-06 03:24:34 -05:00
|
|
|
Collider_DestroyCylinder(play, &this->collider);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update routine for grottos that are currently "hidden"/unopened
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_WaitClosed(DoorAna* this, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
u32 openGrotto = false;
|
|
|
|
|
|
|
|
if (!(this->actor.params & 0x200)) {
|
|
|
|
// opening with song of storms
|
2022-11-06 03:24:34 -05:00
|
|
|
if (this->actor.xyzDistToPlayerSq < 40000.0f && Flags_GetEnv(play, 5)) {
|
2022-03-21 21:51:23 -04:00
|
|
|
openGrotto = true;
|
2023-05-30 15:05:04 -04:00
|
|
|
this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED;
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// bombing/hammering open a grotto
|
|
|
|
if (this->collider.base.acFlags & AC_HIT) {
|
|
|
|
openGrotto = true;
|
2022-11-06 03:24:34 -05:00
|
|
|
Collider_DestroyCylinder(play, &this->collider);
|
2022-03-21 21:51:23 -04:00
|
|
|
} else {
|
|
|
|
Collider_UpdateCylinder(&this->actor, &this->collider);
|
2022-11-06 03:24:34 -05:00
|
|
|
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// open the grotto
|
|
|
|
if (openGrotto) {
|
|
|
|
this->actor.params &= ~0x0300;
|
|
|
|
DoorAna_SetupAction(this, DoorAna_WaitOpen);
|
|
|
|
Audio_PlaySoundGeneral(NA_SE_SY_CORRECT_CHIME, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
|
|
|
|
}
|
2022-11-06 03:24:34 -05:00
|
|
|
func_8002F5F0(&this->actor, play);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// update routine for grottos that are open
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_WaitOpen(DoorAna* this, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
Player* player;
|
|
|
|
s32 destinationIdx;
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
player = GET_PLAYER(play);
|
2022-03-21 21:51:23 -04:00
|
|
|
if (Math_StepToF(&this->actor.scale.x, 0.01f, 0.001f)) {
|
2024-02-15 20:17:28 -05:00
|
|
|
if ((this->actor.targetMode != 0) && (play->transitionTrigger == TRANS_TRIGGER_OFF) && (player->stateFlags1 & PLAYER_STATE1_FLOOR_DISABLED) &&
|
2024-02-15 21:44:46 -05:00
|
|
|
(player->av1.actionVar1 == 0)) {
|
2022-03-21 21:51:23 -04:00
|
|
|
destinationIdx = ((this->actor.params >> 0xC) & 7) - 1;
|
2022-11-06 03:24:34 -05:00
|
|
|
Play_SetupRespawnPoint(play, RESPAWN_MODE_RETURN, 0x4FF);
|
2022-03-21 21:51:23 -04:00
|
|
|
gSaveContext.respawn[RESPAWN_MODE_RETURN].pos.y = this->actor.world.pos.y;
|
|
|
|
gSaveContext.respawn[RESPAWN_MODE_RETURN].yaw = this->actor.home.rot.y;
|
|
|
|
gSaveContext.respawn[RESPAWN_MODE_RETURN].data = this->actor.params & 0xFFFF;
|
|
|
|
if (destinationIdx < 0) {
|
|
|
|
destinationIdx = this->actor.home.rot.z + 1;
|
|
|
|
}
|
2023-11-19 14:29:56 -05:00
|
|
|
play->nextEntranceIndex = sGrottoEntrances[destinationIdx];
|
2022-11-14 06:13:21 -05:00
|
|
|
|
|
|
|
// In ER, load the correct entrance based on the grotto link is falling into
|
2023-09-26 10:20:33 -04:00
|
|
|
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
|
2022-11-14 06:13:21 -05:00
|
|
|
Grotto_OverrideActorEntrance(&this->actor);
|
|
|
|
}
|
|
|
|
|
2022-03-21 21:51:23 -04:00
|
|
|
DoorAna_SetupAction(this, DoorAna_GrabPlayer);
|
|
|
|
} else {
|
2024-02-15 20:17:28 -05:00
|
|
|
if (!Player_InCsMode(play) && !(player->stateFlags1 & (PLAYER_STATE1_ON_HORSE | PLAYER_STATE1_IN_WATER)) &&
|
2022-03-21 21:51:23 -04:00
|
|
|
this->actor.xzDistToPlayer <= 15.0f && -50.0f <= this->actor.yDistToPlayer &&
|
|
|
|
this->actor.yDistToPlayer <= 15.0f) {
|
2024-02-15 20:17:28 -05:00
|
|
|
player->stateFlags1 |= PLAYER_STATE1_FLOOR_DISABLED;
|
2022-03-21 21:51:23 -04:00
|
|
|
this->actor.targetMode = 1;
|
|
|
|
} else {
|
|
|
|
this->actor.targetMode = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Actor_SetScale(&this->actor, this->actor.scale.x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update function for after the player has triggered the grotto
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_GrabPlayer(DoorAna* this, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
Player* player;
|
|
|
|
|
|
|
|
if (this->actor.yDistToPlayer <= 0.0f && 15.0f < this->actor.xzDistToPlayer) {
|
2022-11-06 03:24:34 -05:00
|
|
|
player = GET_PLAYER(play);
|
2022-03-21 21:51:23 -04:00
|
|
|
player->actor.world.pos.x = Math_SinS(this->actor.yawTowardsPlayer) * 15.0f + this->actor.world.pos.x;
|
|
|
|
player->actor.world.pos.z = Math_CosS(this->actor.yawTowardsPlayer) * 15.0f + this->actor.world.pos.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_Update(Actor* thisx, PlayState* play) {
|
2022-03-21 21:51:23 -04:00
|
|
|
DoorAna* this = (DoorAna*)thisx;
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
this->actionFunc(this, play);
|
2023-09-14 22:51:38 -04:00
|
|
|
// Changes the grottos facing angle based on camera angle
|
|
|
|
if (!CVarGetInteger("gDisableGrottoRotation", 0)) {
|
|
|
|
this->actor.shape.rot.y = Camera_GetCamDirYaw(GET_ACTIVE_CAM(play)) + 0x8000;
|
|
|
|
}
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
void DoorAna_Draw(Actor* thisx, PlayState* play) {
|
|
|
|
OPEN_DISPS(play->state.gfxCtx);
|
2022-03-21 21:51:23 -04:00
|
|
|
|
2022-11-29 18:29:36 -05:00
|
|
|
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
|
2022-11-06 03:24:34 -05:00
|
|
|
gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
|
2022-03-21 21:51:23 -04:00
|
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
|
|
|
gSPDisplayList(POLY_XLU_DISP++, gGrottoDL);
|
|
|
|
|
2022-11-06 03:24:34 -05:00
|
|
|
CLOSE_DISPS(play->state.gfxCtx);
|
2022-03-21 21:51:23 -04:00
|
|
|
}
|