EnWarpTag OK (Warping pedestals in Goron Trial) (#747)

* EnWarpTag: OK

* Apply suggestions from code review

Co-authored-by: Anghelo Carvajal <angheloalf95@gmail.com>

* WarpTag: move macros

* WarpTag: format

* WarpTag: fix save entrance index

Co-authored-by: Isghj8 <isghj8@gmail.com>
Co-authored-by: Anghelo Carvajal <angheloalf95@gmail.com>
This commit is contained in:
Isghj 2022-03-29 10:21:36 -07:00 committed by GitHub
parent 9af2914992
commit cbffe83c9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 265 additions and 38 deletions

View File

@ -75,15 +75,19 @@
<DList Name="gameplay_dangeon_keep_DL_01D980" Offset="0x1D980" /> <DList Name="gameplay_dangeon_keep_DL_01D980" Offset="0x1D980" />
<Texture Name="gameplay_dangeon_keep_Tex_01DC70" OutName="tex_01DC70" Format="rgba16" Width="32" Height="32" Offset="0x1DC70" /> <Texture Name="gameplay_dangeon_keep_Tex_01DC70" OutName="tex_01DC70" Format="rgba16" Width="32" Height="32" Offset="0x1DC70" />
<Texture Name="gameplay_dangeon_keep_Tex_01E470" OutName="tex_01E470" Format="rgba16" Width="32" Height="32" Offset="0x1E470" /> <Texture Name="gameplay_dangeon_keep_Tex_01E470" OutName="tex_01E470" Format="rgba16" Width="32" Height="32" Offset="0x1E470" />
<!-- snowhead(?) floor changing stone staircase stone textures -->
<Texture Name="gameplay_dangeon_keep_Tex_01EC70" OutName="tex_01EC70" Format="rgba16" Width="32" Height="32" Offset="0x1EC70" /> <Texture Name="gameplay_dangeon_keep_Tex_01EC70" OutName="tex_01EC70" Format="rgba16" Width="32" Height="32" Offset="0x1EC70" />
<Texture Name="gameplay_dangeon_keep_Tex_01F470" OutName="tex_01F470" Format="i4" Width="64" Height="64" Offset="0x1F470" /> <Texture Name="gameplay_dangeon_keep_Tex_01F470" OutName="tex_01F470" Format="i4" Width="64" Height="64" Offset="0x1F470" />
<Texture Name="gameplay_dangeon_keep_Tex_01FC70" OutName="tex_01FC70" Format="i4" Width="64" Height="64" Offset="0x1FC70" /> <Texture Name="gameplay_dangeon_keep_Tex_01FC70" OutName="tex_01FC70" Format="i4" Width="64" Height="64" Offset="0x1FC70" />
<Texture Name="gameplay_dangeon_keep_Tex_020470" OutName="tex_020470" Format="i4" Width="64" Height="64" Offset="0x20470" /> <Texture Name="gameplay_dangeon_keep_Tex_020470" OutName="tex_020470" Format="i4" Width="64" Height="64" Offset="0x20470" />
<Texture Name="gameplay_dangeon_keep_Tex_020C70" OutName="tex_020C70" Format="i4" Width="64" Height="64" Offset="0x20C70" /> <Texture Name="gameplay_dangeon_keep_Tex_020C70" OutName="tex_020C70" Format="i4" Width="64" Height="64" Offset="0x20C70" />
<!-- snowhead(?) floor changing stone staircase -->
<DList Name="gameplay_dangeon_keep_DL_0219E0" Offset="0x219E0" /> <DList Name="gameplay_dangeon_keep_DL_0219E0" Offset="0x219E0" />
<DList Name="gameplay_dangeon_keep_DL_021EF0" Offset="0x21EF0" />
<Texture Name="gameplay_dangeon_keep_Tex_021FF8" OutName="tex_021FF8" Format="rgba32" Width="32" Height="32" Offset="0x21FF8" /> <!-- En_Warp_tag assets -->
<TextureAnimation Name="gameplay_dangeon_keep_Matanimheader_023008" Offset="0x23008" /> <DList Name="gWarpTagGoronTrialBaseDL" Offset="0x21EF0" />
<Collision Name="gameplay_dangeon_keep_Colheader_02324C" Offset="0x2324C" /> <Texture Name="gWarpTagRainbowTex" OutName="warptag_rainbow" Format="rgba32" Width="32" Height="32" Offset="0x21FF8" />
<TextureAnimation Name="gWarpTagRainbowAnimMat" Offset="0x23008" />
<Collision Name="gWarpTagGoronTrialBaseCollider" Offset="0x2324C" />
</File> </File>
</Root> </Root>

View File

@ -3582,7 +3582,7 @@ void Audio_SetCutsceneFlag(u8 flag);
// void func_801A3FB4(void); // void func_801A3FB4(void);
// void func_801A3FFC(UNK_TYPE1 param_1); // void func_801A3FFC(UNK_TYPE1 param_1);
void audio_setBGM(u32 bgmID); void audio_setBGM(u32 bgmID);
// void func_801A4058(void); void func_801A4058(UNK_TYPE arg0);
// void func_801A41C8(void); // void func_801A41C8(void);
// void func_801A41F8(void); // void func_801A41F8(void);
// void func_801A429C(void); // void func_801A429C(void);

3
spec
View File

@ -2346,8 +2346,7 @@ beginseg
name "ovl_En_Warp_tag" name "ovl_En_Warp_tag"
compress compress
include "build/src/overlays/actors/ovl_En_Warp_tag/z_en_warp_tag.o" include "build/src/overlays/actors/ovl_En_Warp_tag/z_en_warp_tag.o"
include "build/data/ovl_En_Warp_tag/ovl_En_Warp_tag.data.o" include "build/src/overlays/actors/ovl_En_Warp_tag/ovl_En_Warp_tag_reloc.o"
include "build/data/ovl_En_Warp_tag/ovl_En_Warp_tag.reloc.o"
endseg endseg
beginseg beginseg

View File

@ -2,9 +2,11 @@
* File: z_en_warp_tag.c * File: z_en_warp_tag.c
* Overlay: ovl_En_Warp_tag * Overlay: ovl_En_Warp_tag
* Description: Warp to Trial Entrance * Description: Warp to Trial Entrance
* if GoronTrial, has model: Uses GAMEPLAY_DANGEON_KEEP object assigned in EnWarptag_Init
*/ */
#include "z_en_warp_tag.h" #include "z_en_warp_tag.h"
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
#define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_10 | ACTOR_FLAG_2000000 | ACTOR_FLAG_8000000) #define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_10 | ACTOR_FLAG_2000000 | ACTOR_FLAG_8000000)
@ -13,15 +15,15 @@
void EnWarptag_Init(Actor* thisx, GlobalContext* globalCtx); void EnWarptag_Init(Actor* thisx, GlobalContext* globalCtx);
void EnWarptag_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnWarptag_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnWarptag_Update(Actor* thisx, GlobalContext* globalCtx); void EnWarptag_Update(Actor* thisx, GlobalContext* globalCtx);
void EnWarpTag_Draw(Actor* thisx, GlobalContext* globalCtx);
void func_809C085C(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_CheckDungeonKeepObject(EnWarptag* this, GlobalContext* globalCtx);
void func_809C08E0(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_WaitForPlayer(EnWarptag* this, GlobalContext* globalCtx);
void func_809C09A0(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_Unused809C09A0(EnWarptag* this, GlobalContext* globalCtx);
void func_809C0A20(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_Unused809C0A20(EnWarptag* this, GlobalContext* globalCtx);
void func_809C0AB4(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_RespawnPlayer(EnWarptag* this, GlobalContext* globalCtx);
void func_809C0E30(EnWarptag* this, GlobalContext* globalCtx); void EnWarpTag_GrottoReturn(EnWarptag* this, GlobalContext* globalCtx);
#if 0
const ActorInit En_Warp_tag_InitVars = { const ActorInit En_Warp_tag_InitVars = {
ACTOR_EN_WARP_TAG, ACTOR_EN_WARP_TAG,
ACTORCAT_ITEMACTION, ACTORCAT_ITEMACTION,
@ -34,32 +36,238 @@ const ActorInit En_Warp_tag_InitVars = {
(ActorFunc)NULL, (ActorFunc)NULL,
}; };
// static InitChainEntry sInitChain[] = { // this appears to be unused, as the code never accesses it in known vanilla cases
static InitChainEntry D_809C1008[] = { // these unknown values get passed to a unknown z_message function
u8 D_809C1000[] = { 0x28, 0x29, 0x2A, 0x2B, 0x2D, 0x2C, 0, 0 };
static InitChainEntry sInitChain[] = {
ICHAIN_VEC3F(scale, 1, ICHAIN_CONTINUE), ICHAIN_VEC3F(scale, 1, ICHAIN_CONTINUE),
ICHAIN_VEC3S(shape.rot, 0, ICHAIN_STOP), ICHAIN_VEC3S(shape.rot, 0, ICHAIN_STOP),
}; };
#endif void EnWarptag_Init(Actor* thisx, GlobalContext* globalCtx) {
EnWarptag* this = THIS;
extern InitChainEntry D_809C1008[]; Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
Actor_SetFocus(&this->dyna.actor, 0.0f);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/EnWarptag_Init.s") if (GET_WARPTAG_3C0_MAX(thisx) == WARPTAG_3C0_MAX) {
this->dyna.actor.flags &= ~ACTOR_FLAG_1;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/EnWarptag_Destroy.s") if (GET_WARPTAG_INVISIBLE(&this->dyna.actor)) {
this->actionFunc = EnWarpTag_WaitForPlayer;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C085C.s") } else {
if ((this->dangeonKeepObject = Object_GetIndex(&globalCtx->objectCtx, GAMEPLAY_DANGEON_KEEP)) < 0) {
Actor_MarkForDeath(&this->dyna.actor);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C08E0.s") this->actionFunc = EnWarpTag_CheckDungeonKeepObject;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C09A0.s") } else { // not used by known variants
this->actionFunc = EnWarpTag_Unused809C09A0;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C0A20.s") void EnWarptag_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnWarptag* this = THIS;
if (this->dyna.actor.draw != NULL) {
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C0AB4.s") /**
* Loads DynaPoly from GAMEPLAY_DANGEON_KEEP.
*/
void EnWarpTag_CheckDungeonKeepObject(EnWarptag* this, GlobalContext* globalCtx) {
if (Object_IsLoaded(&globalCtx->objectCtx, this->dangeonKeepObject)) {
this->actionFunc = EnWarpTag_WaitForPlayer;
DynaPolyActor_Init(&this->dyna, 0x1);
DynaPolyActor_LoadMesh(globalCtx, &this->dyna, &gWarpTagGoronTrialBaseCollider);
this->dyna.actor.objBankIndex = this->dangeonKeepObject;
this->dyna.actor.draw = EnWarpTag_Draw;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C0E30.s") void EnWarpTag_WaitForPlayer(EnWarptag* this, GlobalContext* globalCtx) {
if (!Player_InCsMode(&globalCtx->state) && (this->dyna.actor.xzDistToPlayer <= 30.0f) &&
(this->dyna.actor.playerHeightRel <= 10.0f)) {
if (GET_WARPTAG_INVISIBLE(&this->dyna.actor)) {
func_800B7298(globalCtx, NULL, 0x51);
this->actionFunc = EnWarpTag_GrottoReturn;
} else {
func_800B7298(globalCtx, NULL, 0xF);
this->actionFunc = EnWarpTag_RespawnPlayer;
}
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/EnWarptag_Update.s") /**
* Unused ActionFunc: assigned in EnWarpTag_Init, no known variants use.
*/
void EnWarpTag_Unused809C09A0(EnWarptag* this, GlobalContext* globalCtx) {
if (func_800B8718(&this->dyna.actor, &globalCtx->state)) {
// func above: checks for ACTOR_FLAG_20000000, returns true and resets if set, else return false
// this actor doesnt have that flag set default, or in init, and this is called shortly after init
// and I doubt its set externally by another actor, so I believe this is unused
// might be a bug, they might have meant to set actor flag (0x2000 0000) up above but mistyped (0x200 0000)
// also GET_WARPTAG_3C0 should always return 2C0 -> 0xF for all known in-game uses, which is OOB
func_80152434(globalCtx, D_809C1000[GET_WARPTAG_3C0(&this->dyna.actor)]); // unk message function
this->actionFunc = EnWarpTag_Unused809C0A20;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Warp_tag/func_809C0F3C.s") } else {
func_800B8804(&this->dyna.actor, globalCtx, 50.0f); // updates player->unk_A90
}
}
/**
* Unused ActionFunc: assigned by EnWarpTag_Unused809C09A0, no known variants use.
*/
void EnWarpTag_Unused809C0A20(EnWarptag* this, GlobalContext* globalCtx) {
if (globalCtx->msgCtx.ocarinaMode == 9) {
func_800B7298(globalCtx, NULL, 7);
this->actionFunc = EnWarpTag_RespawnPlayer;
ActorCutscene_Stop(ActorCutscene_GetCurrentIndex());
} else if (globalCtx->msgCtx.ocarinaMode >= 2) {
globalCtx->msgCtx.ocarinaMode = 4;
this->actionFunc = EnWarpTag_Unused809C09A0;
}
}
/**
* ActionFunc: Goron Trial (Moon), respawn at the beginning of goron rolling track, try again.
*/
void EnWarpTag_RespawnPlayer(EnWarptag* this, GlobalContext* globalCtx) {
ActorEntry* playerActorEntry;
Player* player;
s32 playerSpawnIndex;
s32 new15E;
s32 entranceIndex;
u32 playerSpawnIndexPerForm[PLAYER_FORM_MAX];
u8 playerForm;
s16 playerParams;
player = GET_PLAYER(globalCtx);
if (globalCtx->playerActorCsIds[4] >= 0 && ActorCutscene_GetCurrentIndex() != globalCtx->playerActorCsIds[4]) {
if (ActorCutscene_GetCanPlayNext(globalCtx->playerActorCsIds[4]) == 0) {
ActorCutscene_SetIntentToPlay(globalCtx->playerActorCsIds[4]);
} else {
ActorCutscene_StartAndSetUnkLinkFields(globalCtx->playerActorCsIds[4], &this->dyna.actor);
func_800B8E58(player, NA_SE_PL_WARP_PLATE);
func_8016566C(0);
}
} else {
f32 diffX = player->actor.world.pos.x - this->dyna.actor.world.pos.x;
Vec3f newRespawnPos;
f32 diffZ = player->actor.world.pos.z - this->dyna.actor.world.pos.z;
f32 distance = sqrtf(SQ(diffX) + SQ(diffZ));
// some weird float behavior prevention?
if (distance != 0.0f) {
distance = (distance - 1.0f) / distance;
distance = CLAMP_MIN(distance, 0.0f);
}
player->actor.world.pos.x = this->dyna.actor.world.pos.x + (diffX * distance);
player->actor.world.pos.z = this->dyna.actor.world.pos.z + (diffZ * distance);
if (Math_StepToS(&this->unkValue15E, 0x2710, 0xC8)) {
player->stateFlags3 |= 0x1;
player->actor.gravity = -0.5f;
if (this->dyna.actor.playerHeightRel < -80.0f) {
playerSpawnIndexPerForm[PLAYER_FORM_FIERCE_DEITY] = GET_WARPTAG_EXIT_INDEX(&this->dyna.actor);
playerSpawnIndexPerForm[PLAYER_FORM_HUMAN] = playerSpawnIndexPerForm[PLAYER_FORM_FIERCE_DEITY];
playerSpawnIndexPerForm[PLAYER_FORM_GORON] = this->dyna.actor.world.rot.x;
playerSpawnIndexPerForm[PLAYER_FORM_ZORA] = this->dyna.actor.world.rot.y;
playerSpawnIndexPerForm[PLAYER_FORM_DEKU] = this->dyna.actor.world.rot.z;
if (this->dyna.actor.draw != NULL) {
playerForm = PLAYER_BOOTS_FIERCE_DEITY;
} else {
playerForm = player->transformation;
}
entranceIndex = gSaveContext.save.entranceIndex;
playerSpawnIndex = playerSpawnIndexPerForm[playerForm];
playerActorEntry = &globalCtx->linkActorEntry[playerSpawnIndex];
newRespawnPos.x = playerActorEntry->pos.x;
newRespawnPos.y = playerActorEntry->pos.y;
newRespawnPos.z = playerActorEntry->pos.z;
if (GET_WARPTAG_3C0_MAX(&this->dyna.actor) == WARPTAG_3C0_MAX) {
playerParams = 0x9FF;
} else { // not used by any known variant
playerParams = 0x8FF;
}
// why are we getting player home rotation from the room data? doesnt player have home.rot.y?
// especially because we are converting from deg to binang, but isnt home.rot.y already in binang??
Play_SetRespawnData(
&globalCtx->state, 0, entranceIndex, // parameter 3 is called "sceneSetup"
globalCtx->setupEntranceList[playerSpawnIndex].room, playerParams, &newRespawnPos,
((((playerActorEntry->rot.y >> 7) & 0x1FF) / 180.0f) * 32768.0f)); // DEG_TO_BINANG ?
func_80169EFC(&globalCtx->state);
gSaveContext.respawnFlag = ~0x4;
func_80165690();
}
}
player->actor.shape.rot.y += this->unkValue15E;
new15E = this->unkValue15E - 0xFA0;
if (new15E < 0) {
new15E = 0;
}
func_80165658(new15E * 0.04f); // unknown Play_ function
}
}
/**
* ActionFunc: Deku Playground, return to North Clock Town.
*/
void EnWarpTag_GrottoReturn(EnWarptag* this, GlobalContext* globalCtx) {
if (ActorCutscene_GetCurrentIndex() != this->dyna.actor.cutscene) {
if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) {
ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor);
} else {
ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene);
}
}
if (this->grottoExitDelay++ == 10) {
globalCtx->nextEntranceIndex = globalCtx->setupExitList[GET_WARPTAG_EXIT_INDEX(&this->dyna.actor)];
Scene_SetExitFade(globalCtx);
globalCtx->sceneLoadFlag = 0x14;
func_8019F128(NA_SE_OC_SECRET_HOLE_OUT);
func_801A4058(5);
if (1) {}
gSaveContext.seqIndex = 0xFF;
gSaveContext.nightSeqIndex = 0xFF;
}
}
void EnWarptag_Update(Actor* thisx, GlobalContext* globalCtx) {
EnWarptag* this = THIS;
this->actionFunc(this, globalCtx);
}
/**
* Only draws for Goron Trial (a rainblow animated target).
*/
void EnWarpTag_Draw(Actor* thisx, GlobalContext* globalCtx) {
OPEN_DISPS(globalCtx->state.gfxCtx);
func_8012C28C(globalCtx->state.gfxCtx);
AnimatedMat_Draw(globalCtx, Lib_SegmentedToVirtual(&gWarpTagRainbowAnimMat));
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gWarpTagGoronTrialBaseDL);
CLOSE_DISPS(globalCtx->state.gfxCtx);
}

View File

@ -8,11 +8,27 @@ struct EnWarptag;
typedef void (*EnWarptagActionFunc)(struct EnWarptag*, GlobalContext*); typedef void (*EnWarptagActionFunc)(struct EnWarptag*, GlobalContext*);
typedef struct EnWarptag { typedef struct EnWarptag {
/* 0x0000 */ Actor actor; /* 0x000 */ DynaPolyActor dyna;
/* 0x0144 */ char unk_144[0x1C]; /* 0x15C */ s8 dangeonKeepObject;
/* 0x0160 */ EnWarptagActionFunc actionFunc; /* 0x15E */ union {
s16 reusedValue; // default name
s16 unkValue15E; // passed to unk play func, mods player rotation, stepped to 0x2710
s16 grottoExitDelay; // 10 frame delay before player can leave the grotto
};
/* 0x160 */ EnWarptagActionFunc actionFunc;
} EnWarptag; // size = 0x164 } EnWarptag; // size = 0x164
extern const ActorInit En_Warp_tag_InitVars; extern const ActorInit En_Warp_tag_InitVars;
// Only two known Variants:
// Goron Trial (MOON): 0x03C1
// Deku Playground: 0x83C0
#define GET_WARPTAG_3C0_MAX(thisx) ((thisx)->params & 0x3C0)
#define GET_WARPTAG_3C0(thisx) (((thisx)->params >> 6) & 0xF)
#define GET_WARPTAG_EXIT_INDEX(thisx) ((thisx)->params & 0x3F)
#define GET_WARPTAG_INVISIBLE(thisx) ((thisx)->params < 0) // 0x8000 flag
#define WARPTAG_3C0_MAX 0x3C0
#endif // Z_EN_WARP_TAG_H #endif // Z_EN_WARP_TAG_H

View File

@ -8989,14 +8989,14 @@
0x809BD858:("func_809BD858",), 0x809BD858:("func_809BD858",),
0x809C0760:("EnWarptag_Init",), 0x809C0760:("EnWarptag_Init",),
0x809C0824:("EnWarptag_Destroy",), 0x809C0824:("EnWarptag_Destroy",),
0x809C085C:("func_809C085C",), 0x809C085C:("EnWarpTag_CheckDungeonKeepObject",),
0x809C08E0:("func_809C08E0",), 0x809C08E0:("EnWarpTag_WaitForPlayer",),
0x809C09A0:("func_809C09A0",), 0x809C09A0:("EnWarpTag_Unused809C09A0",),
0x809C0A20:("func_809C0A20",), 0x809C0A20:("EnWarpTag_Unused809C0A20",),
0x809C0AB4:("func_809C0AB4",), 0x809C0AB4:("EnWarpTag_RespawnPlayer",),
0x809C0E30:("func_809C0E30",), 0x809C0E30:("EnWarpTag_GrottoReturn",),
0x809C0F18:("EnWarptag_Update",), 0x809C0F18:("EnWarptag_Update",),
0x809C0F3C:("func_809C0F3C",), 0x809C0F3C:("EnWarpTag_Draw",),
0x809C10B0:("func_809C10B0",), 0x809C10B0:("func_809C10B0",),
0x809C1124:("func_809C1124",), 0x809C1124:("func_809C1124",),
0x809C1158:("func_809C1158",), 0x809C1158:("func_809C1158",),