diff --git a/include/z64.h b/include/z64.h index 0bbd064f45..3896b5f764 100644 --- a/include/z64.h +++ b/include/z64.h @@ -858,7 +858,7 @@ typedef struct PlayState { /* 0x11E14 */ u8 skyboxId; /* 0x11E15 */ s8 transitionTrigger; // "fade_direction" /* 0x11E16 */ s16 unk_11E16; - /* 0x11E18 */ s16 unk_11E18; + /* 0x11E18 */ s16 bgCoverAlpha; /* 0x11E1A */ s16 nextEntranceIndex; /* 0x11E1C */ char unk_11E1C[0x40]; /* 0x11E5C */ s8 shootingGalleryStatus; diff --git a/src/code/z_play.c b/src/code/z_play.c index 8381d6a828..825dad33b6 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -370,7 +370,7 @@ void Play_Init(GameState* thisx) { this->state.destroy = Play_Destroy; this->transitionTrigger = TRANS_TRIGGER_END; this->unk_11E16 = 0xFF; - this->unk_11E18 = 0; + this->bgCoverAlpha = 0; this->haltAllActors = false; if (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN) { @@ -1207,7 +1207,7 @@ void Play_Draw(PlayState* this) { } if ((R_HREG_MODE != HREG_MODE_PLAY) || (R_PLAY_DRAW_ROOM_FLAGS != 0)) { - Environment_FillScreen(gfxCtx, 0, 0, 0, this->unk_11E18, FILL_SCREEN_OPA); + Environment_FillScreen(gfxCtx, 0, 0, 0, this->bgCoverAlpha, FILL_SCREEN_OPA); } if ((R_HREG_MODE != HREG_MODE_PLAY) || R_PLAY_DRAW_ACTORS) { diff --git a/src/code/z_room.c b/src/code/z_room.c index e775acfd1a..d636080b19 100644 --- a/src/code/z_room.c +++ b/src/code/z_room.c @@ -607,10 +607,10 @@ s32 func_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum) { &roomCtx->loadQueue, NULL, "../z_room.c", 1036); roomCtx->unk_30 ^= 1; - return 1; + return true; } - return 0; + return false; } s32 func_800973FC(PlayState* play, RoomContext* roomCtx) { diff --git a/src/overlays/actors/ovl_En_Holl/z_en_holl.c b/src/overlays/actors/ovl_En_Holl/z_en_holl.c index 613cf80a3a..1dc2dd138b 100644 --- a/src/overlays/actors/ovl_En_Holl/z_en_holl.c +++ b/src/overlays/actors/ovl_En_Holl/z_en_holl.c @@ -2,26 +2,79 @@ #define FLAGS ACTOR_FLAG_4 -// Horizontal Plane parameters +/* + * Horizontal holls parameters (`ENHOLL_H_*`) + * All horizontal holls are cuboids which react to how far (depth) and in which direction (side) the player is from the + * actor, in the actor's local z direction. + */ -#define PLANE_Y_MIN -50.0f -#define PLANE_Y_MAX 200.0f +// Defines the height of horizontal holls (all kinds) with a Y range relative to the actor position. +#define ENHOLL_H_Y_MIN -50.0f +#define ENHOLL_H_Y_MAX 200.0f -#define PLANE_HALFWIDTH 100.0f -#define PLANE_HALFWIDTH_2 200.0f +// Defines the width of horizontal holls (all kinds), +// with a half-width extending on both lateral sides (towards local +x and -x). +#define ENHOLL_H_HALFWIDTH_NARROW 100.0f +#define ENHOLL_H_HALFWIDTH 200.0f + +// Defines the depth range from horizontal invisible holls (`ENHOLL_H_INVISIBLE`, `ENHOLL_H_INVISIBLE_NARROW`), +// at which rooms get loaded. +// i.e. when the player's distance from the actor (along local z) is within this range, the corresponding room is loaded +// Note: This means there is a depth range in the middle of `2 * ENHOLL_H_INVISIBLE_LOAD_DEPTH_MIN` where nothing +// happens. That range where nothing happens is useful to avoid quickly repeated room swaps. +// Note: This means the player is expected to be inside the depth range at some point. +// i.e. this range needs to be deep enough so that the player cannot move past it in a single frame. +#define ENHOLL_H_INVISIBLE_LOAD_DEPTH_MAX 100.0f +#define ENHOLL_H_INVISIBLE_LOAD_DEPTH_MIN 50.0f + +// Defines the depth from horizontal switch flag holls (`ENHOLL_H_BGCOVER_SWITCHFLAG`), +// - at which the background geometry starts fading black; +#define ENHOLL_H_SWITCHFLAG_BGCOVER_DEPTH 100.0f +// - at which the background geometry is fully faded black, +// and rooms are loaded if needed according to the side the player is on (along local z). +#define ENHOLL_H_SWITCHFLAG_LOAD_DEPTH 50.0f + +/* + * Vertical holls parameters (`ENHOLL_V_*`) + * All vertical holls are cylinders which react to how far (y dist) and in which direction (side) the player is from the + * actor, along the vertical y axis. + */ + +// Vertical down holls parameters (`ENHOLL_V_DOWN_BGCOVER_LARGE`) +#define ENHOLL_V_DOWN_RADIUS 500.0f +// Y dist at which the background geometry starts fading black. +#define ENHOLL_V_DOWN_BGCOVER_YDIST 605.0f +// Y dist at which the background geometry is fully faded black, and the room down is loaded. +#define ENHOLL_V_DOWN_LOAD_YDIST 95.0f + +// Radius for other vertical holls (`ENHOLL_V_BGCOVER`, `ENHOLL_V_INVISIBLE`) +#define ENHOLL_V_RADIUS 120.0f + +// Vertical bg cover holls parameters (`ENHOLL_V_BGCOVER`) +// Y dist at which the background geometry starts fading black. +#define ENHOLL_V_BGCOVER_BGCOVER_YDIST 200.0f +// Y dist at which the background geometry is fully faded black, +// and rooms are loaded if needed according to the side the player is on (along y). +#define ENHOLL_V_BGCOVER_LOAD_YDIST 50.0f + +// Vertical invisible holls parameters (`ENHOLL_V_INVISIBLE`) +// Similar to the range defined by `ENHOLL_H_INVISIBLE_LOAD_DEPTH_MAX` and min above for horizontal planes, +// but vertically (along y). +#define ENHOLL_V_INVISIBLE_LOAD_YDIST_MAX 200.0f +#define ENHOLL_V_INVISIBLE_LOAD_YDIST_MIN 50.0f void EnHoll_Init(Actor* thisx, PlayState* play); void EnHoll_Destroy(Actor* thisx, PlayState* play); void EnHoll_Update(Actor* thisx, PlayState* play); void EnHoll_Draw(Actor* thisx, PlayState* play); -void EnHoll_NextAction(EnHoll* this, PlayState* play); -void func_80A58DD4(EnHoll* this, PlayState* play); -void func_80A59014(EnHoll* this, PlayState* play); -void func_80A591C0(EnHoll* this, PlayState* play); -void func_80A593A4(EnHoll* this, PlayState* play); -void func_80A59520(EnHoll* this, PlayState* play); -void func_80A59618(EnHoll* this, PlayState* play); +void EnHoll_WaitRoomLoaded(EnHoll* this, PlayState* play); +void EnHoll_HorizontalVisibleNarrow(EnHoll* this, PlayState* play); +void EnHoll_HorizontalInvisible(EnHoll* this, PlayState* play); +void EnHoll_VerticalDownBgCoverLarge(EnHoll* this, PlayState* play); +void EnHoll_VerticalBgCover(EnHoll* this, PlayState* play); +void EnHoll_VerticalInvisible(EnHoll* this, PlayState* play); +void EnHoll_HorizontalBgCoverSwitchFlag(EnHoll* this, PlayState* play); ActorInit En_Holl_InitVars = { ACTOR_EN_HOLL, @@ -36,7 +89,13 @@ ActorInit En_Holl_InitVars = { }; static EnHollActionFunc sActionFuncs[] = { - func_80A58DD4, func_80A591C0, func_80A59520, func_80A59618, func_80A59014, func_80A593A4, func_80A59014, + EnHoll_HorizontalVisibleNarrow, // ENHOLL_H_VISIBLE_NARROW + EnHoll_VerticalDownBgCoverLarge, // ENHOLL_V_DOWN_BGCOVER_LARGE + EnHoll_VerticalInvisible, // ENHOLL_V_INVISIBLE + EnHoll_HorizontalBgCoverSwitchFlag, // ENHOLL_H_BGCOVER_SWITCHFLAG + EnHoll_HorizontalInvisible, // ENHOLL_H_INVISIBLE + EnHoll_VerticalBgCover, // ENHOLL_V_BGCOVER + EnHoll_HorizontalInvisible, // ENHOLL_H_INVISIBLE_NARROW }; static InitChainEntry sInitChain[] = { @@ -45,32 +104,6 @@ static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneDownward, 400, ICHAIN_STOP), }; -/** - * These are all absolute distances in the relative z direction. That is, moving - * towards or away from the "face" of the loading plane regardless of orientation. - * Moving within these distances of the load plane have the following effects: - * [0] : Load the room on this side of the loading plane if not already loaded - * [1] : Load the room on the other side of the loading plane - * [2] : Fade Region (opaque -> transparent if approaching, transparent -> opaque if receding) - * [3] : Transparent Region - * - * When traversing a loading plane of this kind, it attempts to: - * Load Current Room (fails as it is already loaded) - * Load Next Room - * Load Previous Room - * Load Next Room - * - * @bug The striped nature of loading planes can cause some actors to unload due to - * conflicting Object Lists between the two rooms - * - * @bug If you can get around to the other side of the loading plane without triggering it, - * you can load the room on the other side multiple times - */ -static f32 sHorizTriggerDists[2][4] = { - { 200.0f, 150.0f, 100.0f, 50.0f }, - { 100.0f, 75.0f, 50.0f, 25.0f }, -}; - void EnHoll_SetupAction(EnHoll* this, EnHollActionFunc func) { this->actionFunc = func; } @@ -80,11 +113,10 @@ s32 EnHoll_IsKokiriLayer8(void) { } void EnHoll_ChooseAction(EnHoll* this) { - s32 action; + s32 type = ENHOLL_GET_TYPE(&this->actor); - action = (this->actor.params >> 6) & 7; - EnHoll_SetupAction(this, sActionFuncs[action]); - if (action != 0) { + EnHoll_SetupAction(this, sActionFuncs[type]); + if (type != ENHOLL_H_VISIBLE_NARROW) { this->actor.draw = NULL; } else { this->planeAlpha = 255; @@ -96,12 +128,12 @@ void EnHoll_Init(Actor* thisx, PlayState* play) { Actor_ProcessInitChain(&this->actor, sInitChain); EnHoll_ChooseAction(this); - this->unk_14F = 0; + this->resetBgCoverAlpha = false; } void EnHoll_Destroy(Actor* thisx, PlayState* play) { - s32 transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(thisx); - TransitionActorEntry* transitionEntry = &play->transiActorCtx.list[transitionActorIdx]; + s32 transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(thisx); + TransitionActorEntry* transitionEntry = &play->transiActorCtx.list[transitionActorIndex]; transitionEntry->id = -transitionEntry->id; } @@ -116,34 +148,69 @@ void EnHoll_SwapRooms(PlayState* play) { play->roomCtx.unk_30 ^= 1; } -// Horizontal Planes -void func_80A58DD4(EnHoll* this, PlayState* play) { - Player* player = GET_PLAYER(play); - s32 phi_t0 = ((play->sceneId == SCENE_SPIRIT_TEMPLE) ? 1 : 0) & 0xFFFFFFFF; - Vec3f vec; - f32 absZ; - s32 transitionActorIdx; +/** + * These are all absolute distances in the relative z direction. That is, moving + * towards or away from the "face" of the holl regardless of orientation. + * Moving within these distances of the holl have the following effects: + * [0] : Load the room on this side of the holl if not already loaded + * [1] : Load the room on the other side of the holl + * [2] : Start of fade region, where the plane is fully opaque + * [3] : End of fade region region, where the plane is fully transparent + * + * Within the fade region, the plane goes: + * opaque -> transparent if approaching, + * transparent -> opaque if receding + */ +static f32 sHorizontalVisibleNarrowTriggerDists[2][4] = { + { 200.0f, 150.0f, 100.0f, 50.0f }, // default + { 100.0f, 75.0f, 50.0f, 25.0f }, // SCENE_SPIRIT_TEMPLE +}; - func_8002DBD0(&this->actor, &vec, &player->actor.world.pos); - this->side = (vec.z < 0.0f) ? 0 : 1; - absZ = fabsf(vec.z); - if (vec.y > PLANE_Y_MIN && vec.y < PLANE_Y_MAX && fabsf(vec.x) < PLANE_HALFWIDTH && - absZ < sHorizTriggerDists[phi_t0][0]) { - transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - if (absZ > sHorizTriggerDists[phi_t0][1]) { +/** + * When traversing a holl of this kind, it attempts to: + * Load Current Room (fails as it is already loaded) + * Load Next Room + * Load Previous Room + * Load Next Room + * + * @bug The striped nature of holls can cause some actors to unload due to + * conflicting Object Lists between the two rooms + * + * @bug If you can get around to the other side of the holl without triggering it, + * you can load the room on the other side multiple times + */ +void EnHoll_HorizontalVisibleNarrow(EnHoll* this, PlayState* play) { + Player* player = GET_PLAYER(play); + s32 triggerDistsIndex = (u32)((play->sceneId == SCENE_SPIRIT_TEMPLE) ? 1 : 0); + Vec3f relPlayerPos; + f32 orthogonalDistToPlayer; + s32 transitionActorIndex; + + func_8002DBD0(&this->actor, &relPlayerPos, &player->actor.world.pos); + this->side = (relPlayerPos.z < 0.0f) ? 0 : 1; + orthogonalDistToPlayer = fabsf(relPlayerPos.z); + if (relPlayerPos.y > ENHOLL_H_Y_MIN && relPlayerPos.y < ENHOLL_H_Y_MAX && + fabsf(relPlayerPos.x) < ENHOLL_H_HALFWIDTH_NARROW && + orthogonalDistToPlayer < sHorizontalVisibleNarrowTriggerDists[triggerDistsIndex][0]) { + + transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + if (orthogonalDistToPlayer > sHorizontalVisibleNarrowTriggerDists[triggerDistsIndex][1]) { if (play->roomCtx.prevRoom.num >= 0 && play->roomCtx.status == 0) { - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[this->side].room; + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[this->side].room; EnHoll_SwapRooms(play); func_80097534(play, &play->roomCtx); } } else { - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[this->side ^ 1].room; + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[this->side ^ 1].room; if (play->roomCtx.prevRoom.num < 0) { func_8009728C(play, &play->roomCtx, this->actor.room); } else { - this->planeAlpha = (255.0f / (sHorizTriggerDists[phi_t0][2] - sHorizTriggerDists[phi_t0][3])) * - (absZ - sHorizTriggerDists[phi_t0][3]); + this->planeAlpha = + (255.0f / (sHorizontalVisibleNarrowTriggerDists[triggerDistsIndex][2] - + sHorizontalVisibleNarrowTriggerDists[triggerDistsIndex][3])) * + (orthogonalDistToPlayer - sHorizontalVisibleNarrowTriggerDists[triggerDistsIndex][3]); this->planeAlpha = CLAMP(this->planeAlpha, 0, 255); + if (play->roomCtx.curRoom.num != this->actor.room) { EnHoll_SwapRooms(play); } @@ -152,162 +219,186 @@ void func_80A58DD4(EnHoll* this, PlayState* play) { } } -// Horizontal Planes -void func_80A59014(EnHoll* this, PlayState* play) { +void EnHoll_HorizontalInvisible(EnHoll* this, PlayState* play) { Player* player = GET_PLAYER(play); s32 useViewEye = gDebugCamEnabled || play->csCtx.state != CS_STATE_IDLE; - Vec3f vec; - s32 temp; - f32 planeHalfWidth; - f32 absZ; + Vec3f relSubjectPos; + s32 isKokiriLayer8; + f32 hollHalfWidth; + f32 orthogonalDistToSubject; - func_8002DBD0(&this->actor, &vec, (useViewEye) ? &play->view.eye : &player->actor.world.pos); - planeHalfWidth = (((this->actor.params >> 6) & 7) == 6) ? PLANE_HALFWIDTH : PLANE_HALFWIDTH_2; + func_8002DBD0(&this->actor, &relSubjectPos, useViewEye ? &play->view.eye : &player->actor.world.pos); + hollHalfWidth = + (ENHOLL_GET_TYPE(&this->actor) == ENHOLL_H_INVISIBLE_NARROW) ? ENHOLL_H_HALFWIDTH_NARROW : ENHOLL_H_HALFWIDTH; - temp = EnHoll_IsKokiriLayer8(); - if (temp || (PLANE_Y_MIN < vec.y && vec.y < PLANE_Y_MAX && fabsf(vec.x) < planeHalfWidth && - (absZ = fabsf(vec.z), 100.0f > absZ && absZ > 50.0f))) { - s32 transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - s32 side = (vec.z < 0.0f) ? 0 : 1; - TransitionActorEntry* transitionEntry = &play->transiActorCtx.list[transitionActorIdx]; + isKokiriLayer8 = EnHoll_IsKokiriLayer8(); + if (isKokiriLayer8 || (relSubjectPos.y > ENHOLL_H_Y_MIN && relSubjectPos.y < ENHOLL_H_Y_MAX && + fabsf(relSubjectPos.x) < hollHalfWidth && + (orthogonalDistToSubject = fabsf(relSubjectPos.z), + orthogonalDistToSubject < ENHOLL_H_INVISIBLE_LOAD_DEPTH_MAX && + orthogonalDistToSubject > ENHOLL_H_INVISIBLE_LOAD_DEPTH_MIN))) { + s32 transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + s32 side = (relSubjectPos.z < 0.0f) ? 0 : 1; + TransitionActorEntry* transitionEntry = &play->transiActorCtx.list[transitionActorIndex]; s32 room = transitionEntry->sides[side].room; this->actor.room = room; - if (temp) {} + if (isKokiriLayer8) {} if (this->actor.room != play->roomCtx.curRoom.num) { if (room) {} if (func_8009728C(play, &play->roomCtx, this->actor.room)) { - EnHoll_SetupAction(this, EnHoll_NextAction); + EnHoll_SetupAction(this, EnHoll_WaitRoomLoaded); } } } } -// Vertical Planes -void func_80A591C0(EnHoll* this, PlayState* play) { +void EnHoll_VerticalDownBgCoverLarge(EnHoll* this, PlayState* play) { Player* player = GET_PLAYER(play); - f32 absY = fabsf(this->actor.yDistToPlayer); - s32 transitionActorIdx; + f32 absYDistToPlayer = fabsf(this->actor.yDistToPlayer); + s32 transitionActorIndex; - if (this->actor.xzDistToPlayer < 500.0f && absY < 700.0f) { - transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - if (absY < 95.0f) { - play->unk_11E18 = 0xFF; - } else if (absY > 605.0f) { - play->unk_11E18 = 0; + if (this->actor.xzDistToPlayer < ENHOLL_V_DOWN_RADIUS && + // Nothing happens if `absYDistToPlayer > ENHOLL_V_DOWN_BGCOVER_YDIST`, + // so this check may as well compare to ENHOLL_V_DOWN_BGCOVER_YDIST + absYDistToPlayer < (ENHOLL_V_DOWN_BGCOVER_YDIST + 95.0f)) { + + transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + + if (absYDistToPlayer < ENHOLL_V_DOWN_LOAD_YDIST) { + play->bgCoverAlpha = 255; + } else if (absYDistToPlayer > ENHOLL_V_DOWN_BGCOVER_YDIST) { + play->bgCoverAlpha = 0; } else { - play->unk_11E18 = (s16)(605.0f - absY) * 0.5f; + play->bgCoverAlpha = (s16)(ENHOLL_V_DOWN_BGCOVER_YDIST - absYDistToPlayer) * + (255 / (ENHOLL_V_DOWN_BGCOVER_YDIST - ENHOLL_V_DOWN_LOAD_YDIST)); } - if (absY < 95.0f) { - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[1].room; + + if (absYDistToPlayer < ENHOLL_V_DOWN_LOAD_YDIST) { + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[1].room; Math_SmoothStepToF(&player->actor.world.pos.x, this->actor.world.pos.x, 1.0f, 50.0f, 10.0f); Math_SmoothStepToF(&player->actor.world.pos.z, this->actor.world.pos.z, 1.0f, 50.0f, 10.0f); if (this->actor.room != play->roomCtx.curRoom.num && - func_8009728C(play, &play->roomCtx, this->actor.room) != 0) { - EnHoll_SetupAction(this, EnHoll_NextAction); - this->unk_14F = 1; + func_8009728C(play, &play->roomCtx, this->actor.room)) { + EnHoll_SetupAction(this, EnHoll_WaitRoomLoaded); + this->resetBgCoverAlpha = true; player->actor.speed = 0.0f; } } - } else if (this->unk_14F != 0) { - play->unk_11E18 = 0; - this->unk_14F = 0; + } else { + if (this->resetBgCoverAlpha) { + play->bgCoverAlpha = 0; + this->resetBgCoverAlpha = false; + } } } -// Vertical Planes -void func_80A593A4(EnHoll* this, PlayState* play) { - f32 absY; +void EnHoll_VerticalBgCover(EnHoll* this, PlayState* play) { + f32 absYDistToPlayer; s32 side; - s32 transitionActorIdx; + s32 transitionActorIndex; - if ((this->actor.xzDistToPlayer < 120.0f) && (absY = fabsf(this->actor.yDistToPlayer), absY < 200.0f)) { - if (absY < 50.0f) { - play->unk_11E18 = 0xFF; + if ((this->actor.xzDistToPlayer < ENHOLL_V_RADIUS) && + (absYDistToPlayer = fabsf(this->actor.yDistToPlayer), absYDistToPlayer < ENHOLL_V_BGCOVER_BGCOVER_YDIST)) { + + if (absYDistToPlayer < ENHOLL_V_BGCOVER_LOAD_YDIST) { + play->bgCoverAlpha = 255; } else { - play->unk_11E18 = (200.0f - absY) * 1.7f; + play->bgCoverAlpha = (ENHOLL_V_BGCOVER_BGCOVER_YDIST - absYDistToPlayer) * + (255 / (ENHOLL_V_BGCOVER_BGCOVER_YDIST - ENHOLL_V_BGCOVER_LOAD_YDIST)); } - if (absY > 50.0f) { - transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - side = (0.0f < this->actor.yDistToPlayer) ? 0 : 1; - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[side].room; + + if (absYDistToPlayer > ENHOLL_V_BGCOVER_LOAD_YDIST) { + transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + side = (this->actor.yDistToPlayer > 0.0f) ? 0 : 1; + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[side].room; if (this->actor.room != play->roomCtx.curRoom.num && - func_8009728C(play, &play->roomCtx, this->actor.room) != 0) { - EnHoll_SetupAction(this, EnHoll_NextAction); - this->unk_14F = 1; + func_8009728C(play, &play->roomCtx, this->actor.room)) { + EnHoll_SetupAction(this, EnHoll_WaitRoomLoaded); + this->resetBgCoverAlpha = true; } } - } else if (this->unk_14F != 0) { - this->unk_14F = 0; - play->unk_11E18 = 0; - } -} - -// Vertical Planes -void func_80A59520(EnHoll* this, PlayState* play) { - f32 absY; - s8 side; - s32 transitionActorIdx; - - if (this->actor.xzDistToPlayer < 120.0f) { - absY = fabsf(this->actor.yDistToPlayer); - if (absY < 200.0f && absY > 50.0f) { - transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - side = (0.0f < this->actor.yDistToPlayer) ? 0 : 1; - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[side].room; - if (this->actor.room != play->roomCtx.curRoom.num && - func_8009728C(play, &play->roomCtx, this->actor.room) != 0) { - EnHoll_SetupAction(this, EnHoll_NextAction); - } - } - } -} - -// Horizontal Planes -void func_80A59618(EnHoll* this, PlayState* play) { - Player* player = GET_PLAYER(play); - Vec3f vec; - f32 absZ; - s32 side; - s32 transitionActorIdx; - - if (!Flags_GetSwitch(play, this->actor.params & 0x3F)) { - if (this->unk_14F != 0) { - play->unk_11E18 = 0; - this->unk_14F = 0; - } } else { - func_8002DBD0(&this->actor, &vec, &player->actor.world.pos); - absZ = fabsf(vec.z); - if (PLANE_Y_MIN < vec.y && vec.y < PLANE_Y_MAX && fabsf(vec.x) < PLANE_HALFWIDTH_2 && absZ < 100.0f) { - this->unk_14F = 1; - transitionActorIdx = GET_TRANSITION_ACTOR_INDEX(&this->actor); - play->unk_11E18 = 0xFF - (s32)((absZ - 50.0f) * 5.9f); - if (play->unk_11E18 >= 0x100) { - play->unk_11E18 = 0xFF; - } else if (play->unk_11E18 < 0) { - play->unk_11E18 = 0; - } - if (absZ < 50.0f) { - side = (vec.z < 0.0f) ? 0 : 1; - this->actor.room = play->transiActorCtx.list[transitionActorIdx].sides[side].room; - if (this->actor.room != play->roomCtx.curRoom.num && - func_8009728C(play, &play->roomCtx, this->actor.room) != 0) { - EnHoll_SetupAction(this, EnHoll_NextAction); - } - } - } else if (this->unk_14F != 0) { - play->unk_11E18 = 0; - this->unk_14F = 0; + if (this->resetBgCoverAlpha) { + this->resetBgCoverAlpha = false; + play->bgCoverAlpha = 0; } } } -void EnHoll_NextAction(EnHoll* this, PlayState* play) { +void EnHoll_VerticalInvisible(EnHoll* this, PlayState* play) { + f32 absYDistToPlayer; + s8 side; + s32 transitionActorIndex; + + if (this->actor.xzDistToPlayer < ENHOLL_V_RADIUS) { + absYDistToPlayer = fabsf(this->actor.yDistToPlayer); + if (absYDistToPlayer < ENHOLL_V_INVISIBLE_LOAD_YDIST_MAX && + absYDistToPlayer > ENHOLL_V_INVISIBLE_LOAD_YDIST_MIN) { + transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + side = (this->actor.yDistToPlayer > 0.0f) ? 0 : 1; + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[side].room; + if (this->actor.room != play->roomCtx.curRoom.num && + func_8009728C(play, &play->roomCtx, this->actor.room)) { + EnHoll_SetupAction(this, EnHoll_WaitRoomLoaded); + } + } + } +} + +void EnHoll_HorizontalBgCoverSwitchFlag(EnHoll* this, PlayState* play) { + Player* player = GET_PLAYER(play); + Vec3f relPlayerPos; + f32 orthogonalDistToPlayer; + s32 side; + s32 transitionActorIndex; + + if (!Flags_GetSwitch(play, ENHOLL_GET_SWITCH_FLAG(&this->actor))) { + if (this->resetBgCoverAlpha) { + play->bgCoverAlpha = 0; + this->resetBgCoverAlpha = false; + } + } else { + func_8002DBD0(&this->actor, &relPlayerPos, &player->actor.world.pos); + orthogonalDistToPlayer = fabsf(relPlayerPos.z); + + if (ENHOLL_H_Y_MIN < relPlayerPos.y && relPlayerPos.y < ENHOLL_H_Y_MAX && + fabsf(relPlayerPos.x) < ENHOLL_H_HALFWIDTH && orthogonalDistToPlayer < ENHOLL_H_SWITCHFLAG_BGCOVER_DEPTH) { + + this->resetBgCoverAlpha = true; + transitionActorIndex = GET_TRANSITION_ACTOR_INDEX(&this->actor); + + play->bgCoverAlpha = + 255 - (s32)((orthogonalDistToPlayer - ENHOLL_H_SWITCHFLAG_LOAD_DEPTH) * + (255 / (ENHOLL_H_SWITCHFLAG_BGCOVER_DEPTH - ENHOLL_H_SWITCHFLAG_LOAD_DEPTH) + 0.8f)); + if (play->bgCoverAlpha > 255) { + play->bgCoverAlpha = 255; + } else if (play->bgCoverAlpha < 0) { + play->bgCoverAlpha = 0; + } + + if (orthogonalDistToPlayer < ENHOLL_H_SWITCHFLAG_LOAD_DEPTH) { + side = (relPlayerPos.z < 0.0f) ? 0 : 1; + this->actor.room = play->transiActorCtx.list[transitionActorIndex].sides[side].room; + if (this->actor.room != play->roomCtx.curRoom.num && + func_8009728C(play, &play->roomCtx, this->actor.room)) { + EnHoll_SetupAction(this, EnHoll_WaitRoomLoaded); + } + } + } else { + if (this->resetBgCoverAlpha) { + play->bgCoverAlpha = 0; + this->resetBgCoverAlpha = false; + } + } + } +} + +void EnHoll_WaitRoomLoaded(EnHoll* this, PlayState* play) { if (!EnHoll_IsKokiriLayer8() && play->roomCtx.status == 0) { func_80097534(play, &play->roomCtx); - if (play->unk_11E18 == 0) { - this->unk_14F = 0; + if (play->bgCoverAlpha == 0) { + this->resetBgCoverAlpha = false; } EnHoll_ChooseAction(this); } @@ -324,7 +415,7 @@ void EnHoll_Update(Actor* thisx, PlayState* play) { void EnHoll_Draw(Actor* thisx, PlayState* play) { EnHoll* this = (EnHoll*)thisx; Gfx* gfxP; - u32 setupDlIdx; + u32 setupDLIndex; // Only draw the plane if not invisible if (this->planeAlpha != 0) { @@ -332,12 +423,12 @@ void EnHoll_Draw(Actor* thisx, PlayState* play) { if (this->planeAlpha == 255) { gfxP = POLY_OPA_DISP; - setupDlIdx = SETUPDL_37; + setupDLIndex = SETUPDL_37; } else { gfxP = POLY_XLU_DISP; - setupDlIdx = SETUPDL_0; + setupDLIndex = SETUPDL_0; } - gfxP = Gfx_SetupDL(gfxP, setupDlIdx); + gfxP = Gfx_SetupDL(gfxP, setupDLIndex); if (this->side == 0) { Matrix_RotateY(M_PI, MTXMODE_APPLY); } diff --git a/src/overlays/actors/ovl_En_Holl/z_en_holl.h b/src/overlays/actors/ovl_En_Holl/z_en_holl.h index 452de700a0..cbc4ddb39e 100644 --- a/src/overlays/actors/ovl_En_Holl/z_en_holl.h +++ b/src/overlays/actors/ovl_En_Holl/z_en_holl.h @@ -4,6 +4,35 @@ #include "ultra64.h" #include "global.h" +#define ENHOLL_GET_TYPE(thisx) (((thisx)->params >> 6) & 7) +#define ENHOLL_GET_SWITCH_FLAG(thisx) ((thisx)->params & 0x3F) + +/** + * Two kinds of holls: + * Horizontal (H): + * For the player to move horizontally between rooms. + * Cuboid-shaped: + * - height: 200 units high plus 50 units into the ground + * - width: 400 units wide or, if narrow, 200 units wide + * Vertical (V): + * For the player to move vertically between rooms. + * Cylinder-shaped, radius of 120 units. + * + * Three kinds of visual effects: + * Visible: A plane is drawn at the holl location, and fades away as the player approaches. + * Bg Cover: The background geometry (e.g. room geometry but not actors) fades black as the player approaches. + * Invisible: Approaching the holl does not cause any particular visual effect. + */ +typedef enum { + /* 0 */ ENHOLL_H_VISIBLE_NARROW, + /* 1 */ ENHOLL_V_DOWN_BGCOVER_LARGE, // Only allows downwards transitions. 500 units radius. Used in fire temple drops. + /* 2 */ ENHOLL_V_INVISIBLE, + /* 3 */ ENHOLL_H_BGCOVER_SWITCHFLAG, // Enabled if a switch flag is set. Used in Dampe's race. + /* 4 */ ENHOLL_H_INVISIBLE, + /* 5 */ ENHOLL_V_BGCOVER, + /* 6 */ ENHOLL_H_INVISIBLE_NARROW +} EnHollType; + struct EnHoll; typedef void (*EnHollActionFunc)(struct EnHoll*, PlayState*); @@ -12,7 +41,7 @@ typedef struct EnHoll { /* 0x0000 */ Actor actor; /* 0x014C */ s16 planeAlpha; /* 0x014E */ u8 side; - /* 0x014F */ u8 unk_14F; + /* 0x014F */ u8 resetBgCoverAlpha; /* 0x0150 */ EnHollActionFunc actionFunc; } EnHoll; // size = 0x0154