diff --git a/linker_scripts/code_script.txt b/linker_scripts/code_script.txt index f92cefd08c..69827605eb 100644 --- a/linker_scripts/code_script.txt +++ b/linker_scripts/code_script.txt @@ -4207,9 +4207,9 @@ SECTIONS ovl_Obj_Raillift : AT(RomLocation) { build/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.o(.text) - build/asm/overlays/ovl_Obj_Raillift_data.o(.data) + build/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.o(.data) build/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.o(.rodata) - build/asm/overlays/ovl_Obj_Raillift_rodata.o(.rodata) + build/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift_overlay.o(.ovl) } SegmentEnd = .; SegmentSize = SegmentEnd - SegmentStart; diff --git a/linker_scripts/object_script.txt b/linker_scripts/object_script.txt index f2a18694e0..7112f73f7b 100644 --- a/linker_scripts/object_script.txt +++ b/linker_scripts/object_script.txt @@ -573,6 +573,13 @@ D_06001C60 = 0x06001C60; D_06000D78 = 0x06000D78; D_06000C80 = 0x06000C80; +/* z_obj_raillift */ +D_06004FF8 = 0x06004FF8; +D_060048D0 = 0x060048D0; +D_06004BF0 = 0x06004BF0; +D_060071B8 = 0x060071B8; +D_06000208 = 0x06000208; + /* z_obj_tokei_step */ D_06000088 = 0x06000088; D_06000968 = 0x06000968; diff --git a/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.c b/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.c index 2a013494de..4e569ac155 100644 --- a/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.c +++ b/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.c @@ -1,3 +1,9 @@ +/* + * File: z_obj_raillift.c + * Overlay: Obj_Raillift + * Description: Moving Deku Flower Platform and OOT Water Temple Waterfall Platform + */ + #include "z_obj_raillift.h" #define FLAGS 0x00000010 @@ -9,7 +15,23 @@ void ObjRaillift_Destroy(Actor* thisx, GlobalContext* globalCtx); void ObjRaillift_Update(Actor* thisx, GlobalContext* globalCtx); void ObjRaillift_Draw(Actor* thisx, GlobalContext* globalCtx); -/* +void ObjRaillift_DrawDekuFlowerPlatformColorful(Actor* thisx, GlobalContext* globalCtx); +void ObjRaillift_DrawDekuFlowerPlatform(Actor* thisx, GlobalContext* globalCtx); + +void ObjRaillift_DoNothing(ObjRaillift* this, GlobalContext* globalCtx); +void ObjRaillift_Idle(ObjRaillift* this, GlobalContext* globalCtx); +void ObjRaillift_UpdatePosition(ObjRaillift* this, s32 arg1); +void ObjRaillift_StartCutscene(ObjRaillift* this, GlobalContext* globalCtx); +void ObjRaillift_Teleport(ObjRaillift* this, GlobalContext* globalCtx); +void ObjRaillift_Wait(ObjRaillift* this, GlobalContext* globalCtx); +void ObjRaillift_Move(ObjRaillift* this, GlobalContext* globalCtx); + +extern CollisionHeader D_06004FF8; +extern CollisionHeader D_060048D0; +extern Gfx D_06004BF0[]; +extern Gfx D_06000208[]; +extern Gfx D_060071B8[]; + const ActorInit Obj_Raillift_InitVars = { ACTOR_OBJ_RAILLIFT, ACTORCAT_BG, @@ -21,30 +43,249 @@ const ActorInit Obj_Raillift_InitVars = { (ActorFunc)ObjRaillift_Update, (ActorFunc)ObjRaillift_Draw, }; + +static InitChainEntry sInitChain[] = { + ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE), + ICHAIN_F32(uncullZoneScale, 200, ICHAIN_CONTINUE), + ICHAIN_F32(uncullZoneDownward, 400, ICHAIN_CONTINUE), + ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP), +}; + +static CollisionHeader* sColHeaders[] = { &D_06004FF8, &D_060048D0 }; + + +void ObjRaillift_UpdatePosition(ObjRaillift* this, s32 idx) { + Math_Vec3s_ToVec3f(&this->dyna.actor.world.pos, &this->points[idx]); +} + +void ObjRaillift_Init(Actor* thisx, GlobalContext* globalCtx) { + ObjRaillift* this = THIS; + s32 pad; + Path* path; + s32 type = OBJRAILLIFT_GET_TYPE(thisx); + s32 isColorful = false; + + Actor_ProcessInitChain(thisx, sInitChain); + + thisx->shape.rot.x = 0; + thisx->world.rot.x = 0; + thisx->shape.rot.z = 0; + thisx->world.rot.z = 0; + BcCheck3_BgActorInit(&this->dyna, 1); + BgCheck3_LoadMesh(globalCtx, &this->dyna, sColHeaders[type]); + this->speed = OBJRAILLIFT_GET_SPEED(thisx); + if (this->speed < 0.0f) { + this->speed = -this->speed; + isColorful = true; + } + if (type == DEKU_FLOWER_PLATFORM) { + Actor_SpawnWithParent(&globalCtx->actorCtx, thisx, globalCtx, ACTOR_OBJ_ETCETERA, thisx->world.pos.x, + thisx->world.pos.y, thisx->world.pos.z, thisx->shape.rot.x, thisx->shape.rot.y, + thisx->shape.rot.z, 0); + if (isColorful) { + thisx->draw = ObjRaillift_DrawDekuFlowerPlatformColorful; + } else { + thisx->draw = ObjRaillift_DrawDekuFlowerPlatform; + } + } + if (this->speed < 0.01f) { + this->actionFunc = ObjRaillift_DoNothing; + } else { + path = &globalCtx->setupPathList[OBJRAILLIFT_GET_PATH(thisx)]; + this->curPoint = OBJRAILLIFT_GET_STARTING_POINT(thisx); + this->endPoint = path->count - 1; + this->direction = 1; + this->points = (Vec3s*)Lib_SegmentedToVirtual(path->points); + ObjRaillift_UpdatePosition(this, this->curPoint); + if (OBJRAILLIFT_HAS_FLAG(thisx) && !Flags_GetSwitch(globalCtx, OBJRAILLIFT_GET_FLAG(thisx))) { + this->actionFunc = ObjRaillift_Idle; + } else { + this->actionFunc = ObjRaillift_Move; + } + } +} + +void ObjRaillift_Destroy(Actor* thisx, GlobalContext* globalCtx) { + ObjRaillift* this = THIS; + + BgCheck_RemoveActorMesh(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); +} + +void ObjRaillift_DoNothing(ObjRaillift* this, GlobalContext* globalCtx) { +} + +void ObjRaillift_Move(ObjRaillift* this, GlobalContext* globalCtx) { + s32 isTeleporting; + Vec3f nextPoint; + f32 speed; + f32 target; + f32 step; + s32 isPosUpdated; + Vec3s* initialPoint; + Vec3s* endPoint; + s32 pad; + + if (OBJRAILLIFT_HAS_FLAG(&this->dyna.actor)) { + if (!Flags_GetSwitch(globalCtx, OBJRAILLIFT_GET_FLAG(&this->dyna.actor))) { + this->actionFunc = ObjRaillift_Idle; + return; + } + + if (OBJRAILLIFT_GET_TYPE(&this->dyna.actor) == DEKU_FLOWER_PLATFORM) { + func_800B9010(&this->dyna.actor, NA_SE_EV_PLATE_LIFT_LEVEL - SFX_FLAG); + } + } + + Math_Vec3s_ToVec3f(&nextPoint, &(&this->points[this->curPoint])[this->direction]); + Math_Vec3f_Diff(&nextPoint, &this->dyna.actor.world.pos, &this->dyna.actor.velocity); + speed = Math3D_Vec3fMagnitude(&this->dyna.actor.velocity); + if ((speed < (this->speed * 8.0f)) && (this->speed > 2.0f)) { + target = ((this->speed - 2.0f) * 0.1f) + 2.0f; + step = this->speed * 0.03f; + } else { + target = this->speed; + step = this->speed * 0.16f; + } + + Math_StepToF(&this->dyna.actor.speedXZ, target, step); + if ((this->dyna.actor.speedXZ + 0.05f) < speed) { + Math_Vec3f_Scale(&this->dyna.actor.velocity, this->dyna.actor.speedXZ / speed); + this->dyna.actor.world.pos.x += this->dyna.actor.velocity.x; + this->dyna.actor.world.pos.y += this->dyna.actor.velocity.y; + this->dyna.actor.world.pos.z += this->dyna.actor.velocity.z; + } else { + this->curPoint += this->direction; + if (1) {} + this->dyna.actor.speedXZ *= 0.4f; + isTeleporting = OBJRAILLIFT_SHOULD_TELEPORT(&this->dyna.actor); + isPosUpdated = true; + if (((this->curPoint >= this->endPoint) && (this->direction > 0)) || ((this->curPoint <= 0) && (this->direction < 0))) { + if (!isTeleporting) { + this->direction = -this->direction; + this->waitTimer = 10; + this->actionFunc = ObjRaillift_Wait; + } else { + endPoint = &this->points[this->endPoint]; + this->curPoint = this->direction > 0 ? 0 : this->endPoint; + initialPoint = &this->points[0]; + if ((initialPoint->x != endPoint->x) || (initialPoint->y != endPoint->y) || (initialPoint->z != endPoint->z)) { + this->actionFunc = ObjRaillift_Teleport; + func_800C62BC(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); + isPosUpdated = false; + } + } + } + + if (isPosUpdated) { + ObjRaillift_UpdatePosition(this, this->curPoint); + } + } +} + +/* +Will teleport to what ever curpoint is set to */ +void ObjRaillift_Teleport(ObjRaillift* this, GlobalContext* globalCtx) { + if (!func_800CAF70(&this->dyna)) { + ObjRaillift_UpdatePosition(this, this->curPoint); + func_800C6314(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId); + this->actionFunc = ObjRaillift_Move; + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19910.asm") +void ObjRaillift_Wait(ObjRaillift* this, GlobalContext* globalCtx) { + this->waitTimer--; + if (this->waitTimer <= 0) { + this->actionFunc = ObjRaillift_Move; + this->dyna.actor.speedXZ = 0.0f; + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/ObjRaillift_Init.asm") +void ObjRaillift_Idle(ObjRaillift* this, GlobalContext* globalCtx) { + if (Flags_GetSwitch(globalCtx, OBJRAILLIFT_GET_FLAG(&this->dyna.actor))) { + this->dyna.actor.speedXZ = 0.0f; + ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene); + this->actionFunc = ObjRaillift_StartCutscene; + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/ObjRaillift_Destroy.asm") +void ObjRaillift_StartCutscene(ObjRaillift* this, GlobalContext* globalCtx) { + if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) { + ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor); + this->cutsceneTimer = 50; + this->actionFunc = ObjRaillift_Move; + } else { + ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene); + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19B98.asm") +void ObjRaillift_Update(Actor* thisx, GlobalContext* globalCtx) { + ObjRaillift* this = THIS; + f32 target; + f32 step; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19BA8.asm") + this->actionFunc(this, globalCtx); + Actor_SetHeight(&this->dyna.actor, 10.0f); + if (this->cutsceneTimer > 0) { + this->cutsceneTimer--; + if (this->cutsceneTimer == 0) { + ActorCutscene_Stop(this->dyna.actor.cutscene); + } + } + if (OBJRAILLIFT_SHOULD_REACT_TO_WEIGHT(thisx)) { + this->isWeightOnPrev = this->isWeightOn; + if (func_800CAF70(&this->dyna)) { + this->isWeightOn = true; + } else { + this->isWeightOn = false; + } + if ((this->isWeightOn != this->isWeightOnPrev) && (this->maxHeight < 1.0f)) { + this->cycle = -0x8000; + this->maxHeight = 6.0f; + } + this->cycle += 0xCE4; + Math_StepToF(&this->maxHeight, 0.0f, 0.12f); + step = this->isWeightOn ? Math_CosS(fabsf(this->cycleSpeed) * 2048.0f) + 0.02f : Math_SinS(fabsf(this->cycleSpeed) * 2048.0f) + 0.02f; + target = this->isWeightOn ? -8.0f : 0.0f; + Math_StepToF(&this->cycleSpeed, target, step); + this->dyna.actor.shape.yOffset = ((Math_SinS(this->cycle) * this->maxHeight) + this->cycleSpeed) * 10.0f; + dummy:; + } + if (OBJRAILLIFT_GET_TYPE(thisx) == DEKU_FLOWER_PLATFORM && this->dyna.actor.child != NULL) { + if (this->dyna.actor.child->update == NULL) { + this->dyna.actor.child = NULL; + } else { + this->dyna.actor.child->world.pos.x = this->dyna.actor.world.pos.x; + this->dyna.actor.child->world.pos.y = + this->dyna.actor.world.pos.y + (this->dyna.actor.shape.yOffset * this->dyna.actor.scale.y); + this->dyna.actor.child->world.pos.z = this->dyna.actor.world.pos.z; + } + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19E84.asm") +void ObjRaillift_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19EE0.asm") + OPEN_DISPS(globalCtx->state.gfxCtx); + func_8012C28C(globalCtx->state.gfxCtx); + gSPSegment(POLY_OPA_DISP++, 0x08, + Gfx_TwoTexScrollEnvColor(globalCtx->state.gfxCtx, 0, globalCtx->gameplayFrames, 0, 32, 32, 1, 0, 0, + 32, 32, 0, 0, 0, 160)); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, D_06004BF0); + CLOSE_DISPS(globalCtx->state.gfxCtx); +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19F18.asm") +/* +The non-colorful platforms are the ones found in Woodfall Temple +*/ +void ObjRaillift_DrawDekuFlowerPlatform(Actor* thisx, GlobalContext* globalCtx) { + func_800BDFC0(globalCtx, D_06000208); +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A19F78.asm") - -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/ObjRaillift_Update.asm") - -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/ObjRaillift_Draw.asm") - -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A1A330.asm") - -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_Obj_Raillift_0x80A19910/func_80A1A360.asm") +/* +The colorful platforms are the ones found in Deku Palace +*/ +void ObjRaillift_DrawDekuFlowerPlatformColorful(Actor* thisx, GlobalContext* globalCtx) { + func_800BDFC0(globalCtx, D_060071B8); +} diff --git a/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.h b/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.h index 8b00890e48..3aa4c395b2 100644 --- a/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.h +++ b/src/overlays/actors/ovl_Obj_Raillift/z_obj_raillift.h @@ -5,9 +5,37 @@ struct ObjRaillift; +typedef void (*ObjRailliftActionFunc)(struct ObjRaillift*, GlobalContext*); + +#define OBJRAILLIFT_GET_TYPE(thisx) (((thisx)->params >> 0xF) & 1) +#define OBJRAILLIFT_HAS_FLAG(thisx) (((thisx)->params >> 0xD) & 1) +#define OBJRAILLIFT_GET_FLAG(thisx) ((thisx)->home.rot.x & 0x7F) +#define OBJRAILLIFT_GET_PATH(thisx) ((thisx)->params & 0x7F) +#define OBJRAILLIFT_GET_STARTING_POINT(thisx) (((thisx)->params >> 7) & 0x1F) +#define OBJRAILLIFT_GET_SPEED(thisx) ((thisx)->home.rot.z * 0.1f) +#define OBJRAILLIFT_SHOULD_TELEPORT(thisx) (((thisx)->params >> 0xC) & 1) +#define OBJRAILLIFT_SHOULD_REACT_TO_WEIGHT(thisx) (((thisx)->params >> 0xE) & 1) + +typedef enum { + /* 0 */ OOT_WATER_TEMPLE_WATERFALL_PLATFORM, + /* 1 */ DEKU_FLOWER_PLATFORM +} OBJRAILLIFT_TYPE; + typedef struct ObjRaillift { - /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x48]; + /* 0x000 */ DynaPolyActor dyna; + /* 0x15C */ ObjRailliftActionFunc actionFunc; + /* 0x160 */ f32 speed; + /* 0x164 */ s32 endPoint; + /* 0x168 */ s32 curPoint; + /* 0x16C */ s32 direction; // +1 for forward, -1 for backward + /* 0x170 */ Vec3s* points; + /* 0x174 */ s32 isWeightOn; + /* 0x178 */ s32 isWeightOnPrev; + /* 0x17C */ f32 cycleSpeed; + /* 0x180 */ f32 maxHeight; + /* 0x184 */ s16 cycle; + /* 0x186 */ s16 waitTimer; + /* 0x188 */ s16 cutsceneTimer; } ObjRaillift; // size = 0x18C extern const ActorInit Obj_Raillift_InitVars; diff --git a/tables/functions.txt b/tables/functions.txt index 3f6002570b..dc26e9c513 100644 --- a/tables/functions.txt +++ b/tables/functions.txt @@ -9787,19 +9787,19 @@ 0x80A18DA0:("func_80A18DA0",), 0x80A19740:("ObjFunen_Init",), 0x80A19778:("ObjFunen_Draw",), - 0x80A19910:("func_80A19910",), + 0x80A19910:("ObjRaillift_UpdatePosition",), 0x80A1994C:("ObjRaillift_Init",), 0x80A19B64:("ObjRaillift_Destroy",), - 0x80A19B98:("func_80A19B98",), - 0x80A19BA8:("func_80A19BA8",), - 0x80A19E84:("func_80A19E84",), - 0x80A19EE0:("func_80A19EE0",), - 0x80A19F18:("func_80A19F18",), - 0x80A19F78:("func_80A19F78",), + 0x80A19B98:("ObjRaillift_DoNothing",), + 0x80A19BA8:("ObjRaillift_Move",), + 0x80A19E84:("ObjRaillift_Teleport",), + 0x80A19EE0:("ObjRaillift_Wait",), + 0x80A19F18:("ObjRaillift_Idle",), + 0x80A19F78:("ObjRaillift_StartCutscene",), 0x80A19FE0:("ObjRaillift_Update",), 0x80A1A220:("ObjRaillift_Draw",), - 0x80A1A330:("func_80A1A330",), - 0x80A1A360:("func_80A1A360",), + 0x80A1A330:("ObjRaillift_DrawDekuFlowerPlatform",), + 0x80A1A360:("ObjRaillift_DrawDekuFlowerPlatformColorful",), 0x80A1A500:("func_80A1A500",), 0x80A1A56C:("func_80A1A56C",), 0x80A1A750:("func_80A1A750",), diff --git a/tables/variables.txt b/tables/variables.txt index 30131e7480..b783ba06d4 100644 --- a/tables/variables.txt +++ b/tables/variables.txt @@ -11912,7 +11912,7 @@ 0x80A1990C:("objFunenOverlayInfoOffset","u32","",0x4), 0x80A1A390:("Obj_Raillift_InitVars","UNK_TYPE1","",0x1), 0x80A1A3B0:("D_80A1A3B0","UNK_TYPE1","",0x1), - 0x80A1A3C0:("D_80A1A3C0","UNK_TYPE1","",0x1), + 0x80A1A3C0:("sColHeaders","UNK_TYPE1","",0x1), 0x80A1A3C4:("D_80A1A3C4","UNK_TYPE1","",0x1), 0x80A1A3D0:("D_80A1A3D0","f32","",0x4), 0x80A1A3D4:("D_80A1A3D4","f32","",0x4),