1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-08-05 22:00:15 +00:00

DoorKiller OK (#631)

* Init done

* slight tweak

* Destroy done

* func_80995020

* func_809951C4 done

* started func_80995A84

* func_80995A84, func_80995284, func_809952B8 done

* started the mess that is func_80995368

* most functions done except for 3 trouble cases

* func_80995368 done

* func_809958E4 done

* fully matching. Documentation and cleanup to come

* fixed fake matches

* documentation progress

* More documentation

* getting close on tidying up everything

* Finalised documentation and made some comments and name changes in player and other door files

* formatting and final touches to comments

* pr stuff

* merge master

* merge

* format

* remove unused asm after merge

* review

* \n

Co-authored-by: fig02 <fig02srl@gmail.com>
This commit is contained in:
AdamKiddle 2021-03-14 15:21:15 +00:00 committed by GitHub
parent ca5a9aa7d1
commit 8a730123b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 544 additions and 1554 deletions

View file

@ -118,7 +118,7 @@ void func_8099485C(DoorGerudo* this, GlobalContext* globalCtx) {
} else if (!Flags_GetCollectible(globalCtx, (this->dyna.actor.params >> 8) & 0x1F)) {
player->naviTextId = -0x225;
} else {
player->doorType = 2;
player->doorType = PLAYER_DOORTYPE_SLIDING;
player->doorDirection = direction;
player->doorActor = &this->dyna.actor;
player->doorTimer = 10;

View file

@ -1,3 +1,9 @@
/*
* File: z_door_killer.c
* Overlay: ovl_Door_Killer
* Description: Fake doors which attack player
*/
#include "z_door_killer.h"
#include "objects/gameplay_keep/gameplay_keep.h"
@ -5,13 +11,24 @@
#define THIS ((DoorKiller*)thisx)
typedef enum {
/* 0 */ DOOR_KILLER_DOOR,
/* 1 */ DOOR_KILLER_RUBBLE_PIECE_1,
/* 2 */ DOOR_KILLER_RUBBLE_PIECE_2,
/* 3 */ DOOR_KILLER_RUBBLE_PIECE_3,
/* 4 */ DOOR_KILLER_RUBBLE_PIECE_4
} DoorKillerBehaviour;
void DoorKiller_Init(Actor* thisx, GlobalContext* globalCtx);
void DoorKiller_Destroy(Actor* thisx, GlobalContext* globalCtx);
void DoorKiller_Update(Actor* thisx, GlobalContext* globalCtx);
void DoorKiller_Wait(DoorKiller* this, GlobalContext* globalCtx);
void DoorKiller_SetProperties(DoorKiller* this, GlobalContext* globalCtx);
void DoorKiller_DrawDoor(Actor* thisx, GlobalContext* globalCtx);
void DoorKiller_DrawRubble(Actor* thisx, GlobalContext* globalCtx);
extern UNK_TYPE D_06001BC8;
extern FlexSkeletonHeader D_06001BC8;
/*
const ActorInit Door_Killer_InitVars = {
ACTOR_DOOR_KILLER,
ACTORCAT_BG,
@ -24,7 +41,7 @@ const ActorInit Door_Killer_InitVars = {
NULL,
};
static ColliderCylinderInit D_80995FB0 = {
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_METAL,
AT_ON | AT_TYPE_ENEMY,
@ -44,7 +61,7 @@ static ColliderCylinderInit D_80995FB0 = {
{ 20, 100, 0, { 0, 0, 0 } },
};
static ColliderJntSphElementInit D_80995FDC[1] = {
static ColliderJntSphElementInit sJntSphItemsInit[1] = {
{
{
ELEMTYPE_UNK0,
@ -58,7 +75,7 @@ static ColliderJntSphElementInit D_80995FDC[1] = {
},
};
static ColliderJntSphInit D_80996000 = {
static ColliderJntSphInit sJntSphInit = {
{
COLTYPE_NONE,
AT_NONE,
@ -68,41 +85,439 @@ static ColliderJntSphInit D_80996000 = {
COLSHAPE_JNTSPH,
},
1,
D_80995FDC,
sJntSphItemsInit,
};
*/
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/DoorKiller_Init.s")
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/DoorKiller_Destroy.s")
static DoorKillerTextureEntry sDoorTextures[4] = {
{ OBJECT_HIDAN_OBJECTS, 0x0600E5A0 },
{ OBJECT_MIZU_OBJECTS, 0x060035C0 },
{ OBJECT_HAKA_DOOR, 0x06000000 },
{ OBJECT_GAMEPLAY_KEEP, 0x0400EF38 },
};
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995020.s")
void DoorKiller_Init(Actor* thisx, GlobalContext* globalCtx) {
GlobalContext* globalCtx2 = globalCtx;
f32 randF;
DoorKiller* this = THIS;
s32 bankIndex;
s32 i;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_809951C4.s")
// Look in the object bank for one of the four objects containing door textures
bankIndex = -1;
for (i = 0; bankIndex < 0; i++) {
bankIndex = Object_GetIndex(&globalCtx2->objectCtx, sDoorTextures[i].objectId);
this->textureEntryIndex = i;
}
osSyncPrintf("bank_ID = %d\n", bankIndex);
osSyncPrintf("status = %d\n", this->textureEntryIndex);
this->doorObjBankIndex = bankIndex;
this->texture = sDoorTextures[this->textureEntryIndex].texture;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995284.s")
ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f);
Actor_SetScale(&this->actor, 0.01f);
this->timer = 0;
this->hasHitPlayerOrGround = 0;
this->animStyle = 0;
this->playerIsOpening = 0;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_809952B8.s")
switch ((u8)(this->actor.params & 0xFF)) {
case DOOR_KILLER_DOOR:
// `jointTable` is used for both the `jointTable` and `morphTable` args here. Because this actor doesn't
// play any animations it does not cause problems, but it would need to be changed otherwise.
SkelAnime_InitFlex(globalCtx2, &this->skelAnime, &D_06001BC8, NULL, this->jointTable, this->jointTable, 9);
this->actionFunc = DoorKiller_SetProperties;
DoorKiller_SetProperties(this, globalCtx2);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995318.s")
// manually set the overall rotation of the door
this->jointTable[1].x = this->jointTable[1].z = 0x4000;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995368.s")
// Set a cylinder collider to detect link attacks and larger sphere collider to detect explosions
Collider_InitCylinder(globalCtx2, &this->colliderCylinder);
Collider_SetCylinder(globalCtx2, &this->colliderCylinder, &this->actor, &sCylinderInit);
Collider_InitJntSph(globalCtx2, &this->colliderJntSph);
Collider_SetJntSph(globalCtx2, &this->colliderJntSph, &this->actor, &sJntSphInit,
this->colliderJntSphItems);
this->colliderJntSph.elements[0].dim.worldSphere.radius = 80;
this->colliderJntSph.elements[0].dim.worldSphere.center.x = (s16)this->actor.world.pos.x;
this->colliderJntSph.elements[0].dim.worldSphere.center.y = (s16)this->actor.world.pos.y + 50;
this->colliderJntSph.elements[0].dim.worldSphere.center.z = (s16)this->actor.world.pos.z;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995518.s")
// If tied to a switch flag and that switch flag is already set, kill the actor.
if ((((this->actor.params >> 8) & 0x3F) != 0x3F) &&
Flags_GetSwitch(globalCtx2, ((this->actor.params >> 8) & 0x3F))) {
Actor_Kill(&this->actor);
}
break;
case DOOR_KILLER_RUBBLE_PIECE_1:
case DOOR_KILLER_RUBBLE_PIECE_2:
case DOOR_KILLER_RUBBLE_PIECE_3:
case DOOR_KILLER_RUBBLE_PIECE_4:
this->actionFunc = DoorKiller_SetProperties;
DoorKiller_SetProperties(this, globalCtx2);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_809958E4.s")
this->actor.gravity = -0.6f;
this->actor.minVelocityY = -6.0f;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995A50.s")
// Random trajectories for rubble pieces
randF = Rand_CenteredFloat(8.0f);
this->actor.velocity.z = Rand_ZeroFloat(8.0f);
this->actor.velocity.x = (Math_CosS(this->actor.world.rot.y) * randF) +
(Math_SinS(this->actor.world.rot.y) * this->actor.velocity.z);
this->actor.velocity.z = (-Math_SinS(this->actor.world.rot.y) * randF) +
(Math_CosS(this->actor.world.rot.y) * this->actor.velocity.z);
this->actor.velocity.y = Rand_ZeroFloat(4.0f) + 4.0f;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995A84.s")
// These are used as the x,y,z rotational velocities in DoorKiller_FallAsRubble
this->actor.world.rot.x = Rand_CenteredFloat(0x1000);
this->actor.world.rot.y = Rand_CenteredFloat(0x1000);
this->actor.world.rot.z = Rand_CenteredFloat(0x1000);
this->timer = 80;
break;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995CDC.s")
void DoorKiller_Destroy(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995D6C.s")
if ((thisx->params & 0xFF) == DOOR_KILLER_DOOR) {
Collider_DestroyCylinder(globalCtx, &this->colliderCylinder);
Collider_DestroyJntSph(globalCtx, &this->colliderJntSph);
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/DoorKiller_Update.s")
void DoorKiller_SpawnRubble(Actor* thisx, GlobalContext* globalCtx) {
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_KILLER, thisx->world.pos.x, thisx->world.pos.y + 9.0f,
thisx->world.pos.z, thisx->shape.rot.x, thisx->shape.rot.y, thisx->shape.rot.z,
DOOR_KILLER_RUBBLE_PIECE_1);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_KILLER, thisx->world.pos.x + 7.88f,
thisx->world.pos.y + 39.8f, thisx->world.pos.z, thisx->shape.rot.x, thisx->shape.rot.y,
thisx->shape.rot.z, DOOR_KILLER_RUBBLE_PIECE_2);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_KILLER, thisx->world.pos.x - 15.86f,
thisx->world.pos.y + 61.98f, thisx->world.pos.z, thisx->shape.rot.x, thisx->shape.rot.y,
thisx->shape.rot.z, DOOR_KILLER_RUBBLE_PIECE_3);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_DOOR_KILLER, thisx->world.pos.x + 3.72f,
thisx->world.pos.y + 85.1f, thisx->world.pos.z, thisx->shape.rot.x, thisx->shape.rot.y,
thisx->shape.rot.z, DOOR_KILLER_RUBBLE_PIECE_4);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995E40.s")
/**
* action function for the individual door pieces that spawn and fall down when the door is destroyed
*/
void DoorKiller_FallAsRubble(DoorKiller* this, GlobalContext* globalCtx) {
this->actor.velocity.y += this->actor.gravity;
if (this->actor.velocity.y < this->actor.minVelocityY) {
this->actor.velocity.y = this->actor.minVelocityY;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995EC4.s")
this->actor.velocity.x *= 0.98f;
this->actor.velocity.z *= 0.98f;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_Door_Killer/func_80995F1C.s")
// world.rot is repurposed to be the rotation velocity for the rubble pieces
this->actor.shape.rot.x += this->actor.world.rot.x;
this->actor.shape.rot.y += this->actor.world.rot.y;
this->actor.shape.rot.z += this->actor.world.rot.z;
if (this->timer != 0) {
this->timer--;
} else {
Actor_Kill(&this->actor);
}
func_8002D7EC(&this->actor);
}
s32 DoorKiller_IsHit(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
if ((this->colliderCylinder.base.acFlags & 2) && (this->colliderCylinder.info.acHitInfo != NULL)) {
return true;
}
return false;
}
void DoorKiller_SetAC(DoorKiller* this, GlobalContext* globalCtx) {
Collider_UpdateCylinder(&this->actor, &this->colliderCylinder);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder.base);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base);
}
void DoorKiller_Die(DoorKiller* this, GlobalContext* globalCtx) {
s32 switchFlag = (this->actor.params >> 8) & 0x3F;
// Can set a switch flag on death based on params
if (switchFlag != 0x3F) {
Flags_SetSwitch(globalCtx, switchFlag);
}
Actor_Kill(&this->actor);
}
/**
* After slamming on the floor, rise back upright
*/
void DoorKiller_RiseBackUp(DoorKiller* this, GlobalContext* globalCtx) {
s32 i;
s16 rotation;
if (this->timer > 0) {
this->timer--;
} else {
this->actionFunc = DoorKiller_Wait;
this->timer = 16;
DoorKiller_SetAC(this, globalCtx);
return;
}
this->actor.shape.rot.x = (this->timer >= 8) ? (this->timer * 0x800) - 0x4000 : 0;
if (this->timer >= 12) {
rotation = (-this->timer * -500) - 8000;
} else if (this->timer >= 8) {
rotation = -2000;
} else if (this->timer >= 5) {
rotation = (this->timer * -500) + 2000;
} else {
rotation = 0;
}
for (i = 2; i < 9; i++) {
this->jointTable[i].z = -rotation;
}
if (this->timer < 8) {
rotation = Math_SinS(this->timer * 0x2000) * this->timer * 100.0f;
for (i = 2; i < 9; i++) {
this->jointTable[i].y = rotation;
}
}
}
/**
* After wobbling, fall over and slam onto the floor, damaging the player if they are in the way. Uses manual distance
* check for damaging player, not AT system.
*/
void DoorKiller_FallOver(DoorKiller* this, GlobalContext* globalCtx) {
s32 i;
s16 rotation;
if (this->timer > 0) {
this->timer--;
} else {
this->actionFunc = DoorKiller_RiseBackUp;
this->timer = 16;
return;
}
this->actor.shape.rot.x = (this->timer >= 4) ? 0x8000 + (-this->timer * 0x1000) : 0x4000;
if (this->timer >= 6) {
rotation = (-this->timer * -500) - 4000;
} else if (this->timer >= 4) {
rotation = -1000;
} else if (this->timer >= 3) {
rotation = (this->timer * -500) + 1000;
} else {
rotation = 0;
}
for (i = 2; i < 9; i++) {
this->jointTable[i].z = rotation;
}
if (this->timer == 4) {
// spawn 20 random dust particles just before slamming down
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
Vec3f accel = { 0.0f, 1.0f, 0.0f };
Vec3f pos;
s32 j;
f32 randF;
for (j = 0; j != 20; j++) {
pos.y = 0.0f;
randF = Rand_CenteredFloat(40.0f);
pos.z = Rand_ZeroFloat(100.0f);
pos.x = (Math_CosS(this->actor.world.rot.y) * randF) + (Math_SinS(this->actor.world.rot.y) * pos.z);
pos.z = (-Math_SinS(this->actor.world.rot.y) * randF) + (Math_CosS(this->actor.world.rot.y) * pos.z);
velocity.x = pos.x * 0.2f;
velocity.z = pos.z * 0.2f;
accel.x = -(velocity.x) * 0.1f;
accel.z = -(velocity.z) * 0.1f;
pos.x += this->actor.world.pos.x;
pos.y += this->actor.world.pos.y;
pos.z += this->actor.world.pos.z;
func_8002865C(globalCtx, &pos, &velocity, &accel, 300, 30);
}
}
if (!(this->hasHitPlayerOrGround & 1)) {
Vec3f playerPosRelToDoor;
Player* player = PLAYER;
func_8002DBD0(&this->actor, &playerPosRelToDoor, &player->actor.world.pos);
if ((fabsf(playerPosRelToDoor.y) < 20.0f) && (fabsf(playerPosRelToDoor.x) < 20.0f) &&
(playerPosRelToDoor.z < 100.0f) && (playerPosRelToDoor.z > 0.0f)) {
this->hasHitPlayerOrGround |= 1;
func_8002F6D4(globalCtx, &this->actor, 6.0f, this->actor.yawTowardsPlayer, 6.0f, 16);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_KDOOR_HIT);
func_8002F7DC(&player->actor, NA_SE_PL_BODY_HIT);
}
}
if (!(this->hasHitPlayerOrGround & 1) && (this->timer == 2)) {
this->hasHitPlayerOrGround |= 1;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_KDOOR_HIT_GND);
}
}
/**
* Wobble around, signifying the door is about to fall over. Does not set AC and so cannot be destroyed during this.
*/
void DoorKiller_Wobble(DoorKiller* this, GlobalContext* globalCtx) {
s16 rotation;
s32 i;
if ((this->timer == 16) || (this->timer == 8)) {
Audio_PlayActorSound2(&this->actor, NA_SE_EN_KDOOR_WAVE);
}
if (this->timer > 0) {
this->timer--;
} else {
this->actionFunc = DoorKiller_FallOver;
this->timer = 8;
this->hasHitPlayerOrGround &= ~1;
return;
}
rotation = Math_SinS(this->timer * 0x2000) * this->timer * 100.0f;
for (i = 2; i < 9; i++) {
this->jointTable[i].y = rotation;
}
rotation = (u16)(s32)(-Math_CosS(this->timer * 0x1000) * 1000.0f) + 1000;
for (i = 2; i < 9; i++) {
this->jointTable[i].z = rotation;
}
}
/**
* Idle while the player attempts to open the door and then begin to wobble
*/
void DoorKiller_WaitBeforeWobble(DoorKiller* this, GlobalContext* globalCtx) {
if (this->timer > 0) {
this->timer--;
} else {
this->timer = 16;
this->actionFunc = DoorKiller_Wobble;
}
}
void DoorKiller_Wait(DoorKiller* this, GlobalContext* globalCtx) {
Player* player = PLAYER;
Vec3f playerPosRelToDoor;
s16 angleToFacingPlayer;
func_8002DBD0(&this->actor, &playerPosRelToDoor, &player->actor.world.pos);
// playerIsOpening is set by player
if (this->playerIsOpening) {
this->actionFunc = DoorKiller_WaitBeforeWobble;
this->timer = 10;
this->playerIsOpening = 0;
return;
}
if (DoorKiller_IsHit(&this->actor, globalCtx)) {
// AC cylinder: wobble if hit by most weapons, die if hit by explosives or hammer
if ((this->colliderCylinder.info.acHitInfo->toucher.dmgFlags & 0x1FFA6) != 0) {
this->timer = 16;
this->actionFunc = DoorKiller_Wobble;
} else if ((this->colliderCylinder.info.acHitInfo->toucher.dmgFlags & 0x48) != 0) {
DoorKiller_SpawnRubble(&this->actor, globalCtx);
this->actionFunc = DoorKiller_Die;
Audio_PlaySoundAtPosition(globalCtx, &this->actor.world.pos, 20, NA_SE_EN_KDOOR_BREAK);
}
} else if (Actor_GetCollidedExplosive(globalCtx, &this->colliderJntSph.base) != NULL) {
// AC sphere: die if hit by explosive
DoorKiller_SpawnRubble(&this->actor, globalCtx);
this->actionFunc = DoorKiller_Die;
Audio_PlaySoundAtPosition(globalCtx, &this->actor.world.pos, 20, NA_SE_EN_KDOOR_BREAK);
} else if (!Player_InCsMode(globalCtx) && (fabsf(playerPosRelToDoor.y) < 20.0f) &&
(fabsf(playerPosRelToDoor.x) < 20.0f) && (playerPosRelToDoor.z < 50.0f) &&
(playerPosRelToDoor.z > 0.0f)) {
// Set player properties to make the door openable if within range
angleToFacingPlayer = player->actor.shape.rot.y - this->actor.shape.rot.y;
if (playerPosRelToDoor.z > 0.0f) {
angleToFacingPlayer = 0x8000 - angleToFacingPlayer;
}
if (ABS(angleToFacingPlayer) < 0x3000) {
player->doorType = PLAYER_DOORTYPE_FAKE;
player->doorDirection = (playerPosRelToDoor.z >= 0.0f) ? 1.0f : -1.0f;
player->doorActor = &this->actor;
}
}
DoorKiller_SetAC(this, globalCtx);
}
/**
* Grabs the virtual address of the texture from the relevant door object
*/
void DoorKiller_UpdateTexture(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[this->doorObjBankIndex].segment);
this->texture = SEGMENTED_TO_VIRTUAL(this->texture);
gSegments[6] = VIRTUAL_TO_PHYSICAL(globalCtx->objectCtx.status[thisx->objBankIndex].segment);
}
/**
* Gets the correct door texture, defines the appropriate draw fucntion and action function based on type behaviour
* (door or rubble).
*/
void DoorKiller_SetProperties(DoorKiller* this, GlobalContext* globalCtx) {
if (Object_IsLoaded(&globalCtx->objectCtx, this->doorObjBankIndex)) {
DoorKiller_UpdateTexture(&this->actor, globalCtx);
switch (this->actor.params & 0xFF) {
case DOOR_KILLER_DOOR:
this->actionFunc = DoorKiller_Wait;
this->actor.draw = DoorKiller_DrawDoor;
break;
case DOOR_KILLER_RUBBLE_PIECE_1:
case DOOR_KILLER_RUBBLE_PIECE_2:
case DOOR_KILLER_RUBBLE_PIECE_3:
case DOOR_KILLER_RUBBLE_PIECE_4:
this->actionFunc = DoorKiller_FallAsRubble;
this->actor.draw = DoorKiller_DrawRubble;
break;
}
}
}
void DoorKiller_Update(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
this->actionFunc(this, globalCtx);
}
void DoorKiller_SetTexture(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
u64* doorTexture = this->texture;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_door_killer.c", 883);
gSPSegment(POLY_OPA_DISP++, 0x08, doorTexture);
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_door_killer.c", 885);
}
void DoorKiller_DrawDoor(Actor* thisx, GlobalContext* globalCtx) {
DoorKiller* this = THIS;
func_800943C8(globalCtx->state.gfxCtx);
DoorKiller_SetTexture(&this->actor, globalCtx);
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
NULL, NULL, NULL);
}
void DoorKiller_DrawRubble(Actor* thisx, GlobalContext* globalCtx) {
static Gfx* dLists[] = { 0x06001250, 0x06001550, 0x060017B8, 0x06001A58 };
s32 rubblePieceIndex = (thisx->params & 0xFF) - 1;
DoorKiller* this = THIS;
if ((this->timer >= 20) || ((this->timer & 1) == 0)) {
DoorKiller_SetTexture(thisx, globalCtx);
Gfx_DrawDListOpa(globalCtx, dLists[rubblePieceIndex]);
}
}

View file

@ -4,11 +4,35 @@
#include "ultra64.h"
#include "global.h"
/*
* Associated switch flag: (params >> 8) & 0x3F
* ((params >> 8) & 0x3F) == 0x3F means no switch flag is checked / set
*/
typedef struct {
/* 0x00 */ s16 objectId;
/* 0x04 */ u64* texture;
} DoorKillerTextureEntry; // size 0x8
struct DoorKiller;
typedef void (*DoorKillerActionFunc)(struct DoorKiller*, GlobalContext*);
typedef struct DoorKiller {
/* 0x0000 */ Actor actor;
/* 0x014C */ char unk_14C[0x138];
/* 0x014C */ SkelAnime skelAnime;
/* 0x0190 */ u8 animStyle; // Must be at same offset as animStyle in EnDoor due to the cast in func_80839800
/* 0x0191 */ u8 playerIsOpening; // Must be at same offset as playerIsOpening in EnDoor
/* 0x0192 */ Vec3s jointTable[9];
/* 0x01C8 */ ColliderCylinder colliderCylinder;
/* 0x0214 */ u64* texture;
/* 0x0218 */ u16 hasHitPlayerOrGround;
/* 0x021A */ u16 timer;
/* 0x021C */ u8 doorObjBankIndex;
/* 0x021D */ u8 textureEntryIndex;
/* 0x0220 */ ColliderJntSph colliderJntSph;
/* 0x0240 */ ColliderJntSphElement colliderJntSphItems[1];
/* 0x0280 */ DoorKillerActionFunc actionFunc;
} DoorKiller; // size = 0x0284
extern const ActorInit Door_Killer_InitVars;

View file

@ -385,7 +385,7 @@ void func_80996B0C(DoorShutter* this, GlobalContext* globalCtx) {
}
player->doorTimer = 10;
}
player->doorType = 2;
player->doorType = PLAYER_DOORTYPE_SLIDING;
player->doorDirection = doorDirection;
player->doorActor = &this->dyna.actor;
}

View file

@ -358,7 +358,7 @@ void EnArrow_Fly(EnArrow* this, GlobalContext* globalCtx) {
} else {
Math_Vec3f_Sum(&this->actor.world.pos, &this->unk_250, &this->hitActor->world.pos);
}
if (this->touchedPoly && (this->hitActor != NULL)) {
this->hitActor->flags &= ~0x8000;
this->hitActor = NULL;

View file

@ -140,7 +140,8 @@ void func_809CAEF4(EnBrob* this) {
}
void func_809CAF88(EnBrob* this) {
Animation_Change(&this->skelAnime, &D_06001750, -1.0f, Animation_GetLastFrame(&D_06001750), 0.0f, ANIMMODE_ONCE, -5.0f);
Animation_Change(&this->skelAnime, &D_06001750, -1.0f, Animation_GetLastFrame(&D_06001750), 0.0f, ANIMMODE_ONCE,
-5.0f);
this->unk_1AE = 8250;
this->actionFunc = func_809CB354;
}
@ -251,8 +252,8 @@ void func_809CB458(EnBrob* this, GlobalContext* globalCtx) {
dist2 = -dist2;
}
pos.y = (((Rand_ZeroOne() * 15000.0f) + 1000.0f) * this->dyna.actor.scale.y) + this->dyna.actor.world.pos.y;
EffectSsLightning_Spawn(globalCtx, &pos, &primColor, &envColor,
this->dyna.actor.scale.y * 8000.0f, Rand_ZeroOne() * 65536.0f, 4, 1);
EffectSsLightning_Spawn(globalCtx, &pos, &primColor, &envColor, this->dyna.actor.scale.y * 8000.0f,
Rand_ZeroOne() * 65536.0f, 4, 1);
}
if (this->timer == 0) {
@ -278,10 +279,11 @@ void EnBrob_Update(Actor* thisx, GlobalContext* globalCtx2) {
func_809CAEF4(this);
} else if ((this->colliders[0].base.atFlags & AT_HIT) || (this->colliders[1].base.atFlags & AT_HIT) ||
(acHits[0] && (this->colliders[0].info.acHitInfo->toucher.dmgFlags & 0x100)) ||
(acHits[1] && (this->colliders[1].info.acHitInfo->toucher.dmgFlags & 0x100))) {
(acHits[0] && (this->colliders[0].info.acHitInfo->toucher.dmgFlags & 0x100)) ||
(acHits[1] && (this->colliders[1].info.acHitInfo->toucher.dmgFlags & 0x100))) {
if (this->actionFunc == func_809CB114 && !(this->colliders[0].base.atFlags & AT_BOUNCED) && !(this->colliders[1].base.atFlags & AT_BOUNCED)) {
if (this->actionFunc == func_809CB114 && !(this->colliders[0].base.atFlags & AT_BOUNCED) &&
!(this->colliders[1].base.atFlags & AT_BOUNCED)) {
func_8002F71C(globalCtx, &this->dyna.actor, 5.0f, this->dyna.actor.yawTowardsPlayer, 1.0f);
} else if (this->actionFunc != func_809CB114) {
func_809CB008(this);

View file

@ -179,14 +179,14 @@ void EnDoor_SetupType(EnDoor* this, GlobalContext* globalCtx) {
void EnDoor_Idle(EnDoor* this, GlobalContext* globalCtx) {
Player* player = PLAYER;
s32 doorType;
Vec3f sp2C;
Vec3f playerPosRelToDoor;
s16 phi_v0;
doorType = this->actor.params >> 7 & 7;
func_8002DBD0(&this->actor, &sp2C, &player->actor.world.pos);
if (this->unk_191 != 0) {
func_8002DBD0(&this->actor, &playerPosRelToDoor, &player->actor.world.pos);
if (this->playerIsOpening != 0) {
this->actionFunc = EnDoor_Open;
Animation_PlayOnceSetSpeed(&this->skelAnime, D_809FCECC[this->unk_190],
Animation_PlayOnceSetSpeed(&this->skelAnime, D_809FCECC[this->animStyle],
(player->stateFlags1 & 0x8000000) ? 0.75f : 1.5f);
if (this->lockTimer != 0) {
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]--;
@ -194,9 +194,10 @@ void EnDoor_Idle(EnDoor* this, GlobalContext* globalCtx) {
Audio_PlayActorSound2(&this->actor, NA_SE_EV_CHAIN_KEY_UNLOCK);
}
} else if (!Player_InCsMode(globalCtx)) {
if (fabsf(sp2C.y) < 20.0f && fabsf(sp2C.x) < 20.0f && fabsf(sp2C.z) < 50.0f) {
if (fabsf(playerPosRelToDoor.y) < 20.0f && fabsf(playerPosRelToDoor.x) < 20.0f &&
fabsf(playerPosRelToDoor.z) < 50.0f) {
phi_v0 = player->actor.shape.rot.y - this->actor.shape.rot.y;
if (sp2C.z > 0.0f) {
if (playerPosRelToDoor.z > 0.0f) {
phi_v0 = 0x8000 - phi_v0;
}
if (ABS(phi_v0) < 0x3000) {
@ -210,8 +211,8 @@ void EnDoor_Idle(EnDoor* this, GlobalContext* globalCtx) {
player->doorTimer = 10;
}
}
player->doorType = (doorType == DOOR_AJAR) ? -1 : 1;
player->doorDirection = (sp2C.z >= 0.0f) ? 1.0f : -1.0f;
player->doorType = (doorType == DOOR_AJAR) ? PLAYER_DOORTYPE_AJAR : PLAYER_DOORTYPE_HANDLE;
player->doorDirection = (playerPosRelToDoor.z >= 0.0f) ? 1.0f : -1.0f;
player->doorActor = &this->actor;
}
} else if (doorType == DOOR_AJAR && this->actor.xzDistToPlayer > DOOR_AJAR_OPEN_RANGE) {
@ -261,8 +262,8 @@ void EnDoor_Open(EnDoor* this, GlobalContext* globalCtx) {
if (DECR(this->lockTimer) == 0) {
if (SkelAnime_Update(&this->skelAnime)) {
this->actionFunc = EnDoor_Idle;
this->unk_191 = 0;
} else if (Animation_OnFrame(&this->skelAnime, sDoorAnimOpenFrames[this->unk_190])) {
this->playerIsOpening = 0;
} else if (Animation_OnFrame(&this->skelAnime, sDoorAnimOpenFrames[this->animStyle])) {
Audio_PlayActorSound2(&this->actor,
(globalCtx->sceneNum == SCENE_HAKADAN || globalCtx->sceneNum == SCENE_HAKADANCH ||
globalCtx->sceneNum == SCENE_HIDAN)
@ -274,7 +275,7 @@ void EnDoor_Open(EnDoor* this, GlobalContext* globalCtx) {
EffectSsBubble_Spawn(globalCtx, &this->actor.world.pos, 60.0f, 100.0f, 50.0f, 0.15f);
}
}
} else if (Animation_OnFrame(&this->skelAnime, sDoorAnimCloseFrames[this->unk_190])) {
} else if (Animation_OnFrame(&this->skelAnime, sDoorAnimCloseFrames[this->animStyle])) {
Audio_PlayActorSound2(&this->actor,
(globalCtx->sceneNum == SCENE_HAKADAN || globalCtx->sceneNum == SCENE_HAKADANCH ||
globalCtx->sceneNum == SCENE_HIDAN)

View file

@ -46,8 +46,8 @@ typedef void (*EnDoorActionFunc)(struct EnDoor*, GlobalContext*);
typedef struct EnDoor {
/* 0x0000 */ Actor actor;
/* 0x014C */ SkelAnime skelAnime;
/* 0x0190 */ u8 unk_190;
/* 0x0191 */ u8 unk_191;
/* 0x0190 */ u8 animStyle; // Must be at same offset as animStyle in DoorKiller due to the cast in func_80839800
/* 0x0191 */ u8 playerIsOpening; // Must be at same offset as playerIsOpening in DoorKiller due to the cast in func_80839800
/* 0x0192 */ u8 unk_192;
/* 0x0193 */ s8 requiredObjBankIndex;
/* 0x0194 */ s8 dListIndex;

View file

@ -111,7 +111,6 @@ void EnFu_Init(Actor* thisx, GlobalContext* globalCtx) {
void EnFu_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnFu* this = THIS;
Collider_DestroyCylinder(globalCtx, &this->collider);
}

View file

@ -775,7 +775,6 @@ u16 EnGo2_GetTextId(GlobalContext* globalCtx, Actor* thisx) {
s16 EnGo2_GetState(GlobalContext* globalCtx, Actor* thisx) {
EnGo2* this = THIS;
switch (this->actor.params & 0x1F) {
case GORON_CITY_ROLLING_BIG:
return EnGo2_GetStateGoronCityRollingBig(globalCtx, this);

View file

@ -419,7 +419,6 @@ u16 EnMd_GetText(GlobalContext* globalCtx, Actor* thisx) {
s16 func_80AAAF04(GlobalContext* globalCtx, Actor* thisx) {
EnMd* this = THIS;
switch (func_80AAAC78(this, globalCtx)) {
case 0:
case 1:

View file

@ -569,7 +569,6 @@ void func_80AEBA2C(EnRu1* this, GlobalContext* globalCtx) {
f32 temp_ret_2;
CsCmdActorAction* csCmdNPCAction = func_80AEB438(globalCtx);
s32 pad2;
if (csCmdNPCAction != NULL) {
temp_ret_2 = func_80AEB7E0(csCmdNPCAction, globalCtx);
thisPos = &this->actor.world.pos;

View file

@ -143,7 +143,7 @@ void func_80B86BC8(ItemShield* this, GlobalContext* globalCtx) {
void func_80B86CA8(ItemShield* this, GlobalContext* globalCtx) {
static Vec3f D_80B871F4 = { 0.0f, 0.0f, 0.0f };
static f32 D_80B87200[] = { 0.3f, 0.6f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
static f32 D_80B87200[] = { 0.3f, 0.6f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.85f, 0.7f, 0.55f, 0.4f, 0.25f, 0.1f, 0.0f };
static f32 D_80B87240[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.8f,
0.6f, 0.4f, 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
@ -159,7 +159,8 @@ void func_80B86CA8(ItemShield* this, GlobalContext* globalCtx) {
D_80B871F4.x = this->unk_1A8[i].x;
D_80B871F4.y = this->unk_1A8[i].y + (this->actor.shape.yOffset * 0.01f) + (D_80B87200[temp] * -10.0f * 0.2f);
D_80B871F4.z = this->unk_1A8[i].z;
EffectSsFireTail_SpawnFlame(globalCtx, &this->actor, &D_80B871F4, D_80B87200[temp] * 0.2f, -1, D_80B87240[temp]);
EffectSsFireTail_SpawnFlame(globalCtx, &this->actor, &D_80B871F4, D_80B87200[temp] * 0.2f, -1,
D_80B87240[temp]);
if (this->unk_19E[i] != 0) {
this->unk_19E[i]--;
} else if (this->timer > 16) {

View file

@ -37,6 +37,13 @@ typedef struct {
#define GET_ITEM_NONE \
{ ITEM_NONE, 0, 0, 0, 0 }
typedef enum {
/* 0x00 */ KNOB_ANIM_ADULT_L,
/* 0x01 */ KNOB_ANIM_CHILD_L,
/* 0x02 */ KNOB_ANIM_ADULT_R,
/* 0x03 */ KNOB_ANIM_CHILD_R
} KnobDoorAnim;
typedef struct {
/* 0x00 */ u8 itemId;
/* 0x02 */ s16 actorId;
@ -2218,7 +2225,7 @@ s32 func_80834EB8(Player* this, GlobalContext* globalCtx) {
}
s32 func_80834F2C(Player* this, GlobalContext* globalCtx) {
if ((this->doorType == 0) && !(this->stateFlags1 & 0x2000000)) {
if ((this->doorType == PLAYER_DOORTYPE_NONE) && !(this->stateFlags1 & 0x2000000)) {
if (D_80853614 || func_80834E44(globalCtx)) {
if (func_80834D2C(this, globalCtx)) {
return func_80834EB8(this, globalCtx);
@ -4033,8 +4040,8 @@ s32 func_80839768(GlobalContext* globalCtx, Player* this, Vec3f* arg2, Collision
s32 func_80839800(Player* this, GlobalContext* globalCtx) {
DoorShutter* doorShutter;
EnDoor* enDoor;
s32 sp7C;
EnDoor* door; // Can also be DoorKiller*
s32 doorDirection;
f32 sp78;
f32 sp74;
Actor* doorActor;
@ -4046,26 +4053,26 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
CollisionPoly* sp58;
Vec3f sp4C;
if ((this->doorType != 0) &&
if ((this->doorType != PLAYER_DOORTYPE_NONE) &&
(!(this->stateFlags1 & 0x800) || ((this->heldActor != NULL) && (this->heldActor->id == ACTOR_EN_RU1)))) {
if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) || (func_8084F9A0 == this->func_674)) {
doorActor = this->doorActor;
if (this->doorType < 0) {
if (this->doorType <= PLAYER_DOORTYPE_AJAR) {
doorActor->textId = 0xD0; // "It won't open!"
func_80853148(globalCtx, doorActor);
return 0;
}
sp7C = this->doorDirection;
doorDirection = this->doorDirection;
sp78 = Math_CosS(doorActor->shape.rot.y);
sp74 = Math_SinS(doorActor->shape.rot.y);
if (this->doorType == 2) {
if (this->doorType == PLAYER_DOORTYPE_SLIDING) {
doorShutter = (DoorShutter*)doorActor;
this->currentYaw = doorShutter->dyna.actor.home.rot.y;
if (sp7C > 0) {
if (doorDirection > 0) {
this->currentYaw -= 0x8000;
}
this->actor.shape.rot.y = this->currentYaw;
@ -4080,10 +4087,10 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
this->unk_447 = this->doorType;
this->stateFlags1 |= 0x20000000;
this->unk_450.x = this->actor.world.pos.x + ((sp7C * 20.0f) * sp74);
this->unk_450.z = this->actor.world.pos.z + ((sp7C * 20.0f) * sp78);
this->unk_45C.x = this->actor.world.pos.x + ((sp7C * -120.0f) * sp74);
this->unk_45C.z = this->actor.world.pos.z + ((sp7C * -120.0f) * sp78);
this->unk_450.x = this->actor.world.pos.x + ((doorDirection * 20.0f) * sp74);
this->unk_450.z = this->actor.world.pos.z + ((doorDirection * 20.0f) * sp78);
this->unk_45C.x = this->actor.world.pos.x + ((doorDirection * -120.0f) * sp74);
this->unk_45C.z = this->actor.world.pos.z + ((doorDirection * -120.0f) * sp78);
doorShutter->unk_164 = 1;
func_80832224(this);
@ -4098,21 +4105,25 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
if (doorShutter->dyna.actor.category == ACTORCAT_DOOR) {
this->unk_46A = globalCtx->transitionActorList[(u16)doorShutter->dyna.actor.params >> 10]
.sides[(sp7C > 0) ? 0 : 1]
.sides[(doorDirection > 0) ? 0 : 1]
.effects;
func_800304B0(globalCtx);
}
} else {
enDoor = (EnDoor*)doorActor;
// This actor can be either EnDoor or DoorKiller.
// Don't try to access any struct vars other than `animStyle` and `playerIsOpening`! These two variables
// are common across the two actors' structs however most other variables are not!
door = (EnDoor*)doorActor;
enDoor->unk_190 = (sp7C < 0.0f) ? ((LINK_IS_ADULT) ? 0 : 1) : ((LINK_IS_ADULT) ? 2 : 3);
door->animStyle = (doorDirection < 0.0f) ? ((LINK_IS_ADULT) ? KNOB_ANIM_ADULT_L : KNOB_ANIM_CHILD_L)
: ((LINK_IS_ADULT) ? KNOB_ANIM_ADULT_R : KNOB_ANIM_CHILD_R);
if (enDoor->unk_190 == 0) {
if (door->animStyle == KNOB_ANIM_ADULT_L) {
sp5C = D_808539EC[this->modelAnimType];
} else if (enDoor->unk_190 == 1) {
} else if (door->animStyle == KNOB_ANIM_CHILD_L) {
sp5C = D_80853A04[this->modelAnimType];
} else if (enDoor->unk_190 == 2) {
} else if (door->animStyle == KNOB_ANIM_ADULT_R) {
sp5C = D_80853A1C[this->modelAnimType];
} else {
sp5C = D_80853A34[this->modelAnimType];
@ -4121,7 +4132,7 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
func_80835C58(globalCtx, this, func_80845EF8, 0);
func_80832528(globalCtx, this);
if (sp7C < 0) {
if (doorDirection < 0) {
this->actor.shape.rot.y = doorActor->shape.rot.y;
} else {
this->actor.shape.rot.y = doorActor->shape.rot.y - 0x8000;
@ -4129,7 +4140,7 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
this->currentYaw = this->actor.shape.rot.y;
sp6C = (sp7C * 22.0f);
sp6C = (doorDirection * 22.0f);
this->actor.world.pos.x = doorActor->world.pos.x + sp6C * sp74;
this->actor.world.pos.z = doorActor->world.pos.z + sp6C * sp78;
@ -4143,12 +4154,12 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
func_80832F54(globalCtx, this, 0x28F);
if (doorActor->parent != NULL) {
sp7C = -sp7C;
doorDirection = -doorDirection;
}
enDoor->unk_191 = 1;
door->playerIsOpening = 1;
if (this->doorType != 3) {
if (this->doorType != PLAYER_DOORTYPE_FAKE) {
this->stateFlags1 |= 0x20000000;
func_800304B0(globalCtx);
@ -4166,15 +4177,17 @@ s32 func_80839800(Player* this, GlobalContext* globalCtx) {
} else {
Camera_ChangeDoorCam(Gameplay_GetCamera(globalCtx, 0), doorActor,
globalCtx->transitionActorList[(u16)doorActor->params >> 10]
.sides[(sp7C > 0) ? 0 : 1]
.sides[(doorDirection > 0) ? 0 : 1]
.effects,
0, 38.0f * D_808535EC, 26.0f * D_808535EC, 10.0f * D_808535EC);
}
}
}
if ((this->doorType != 3) && (doorActor->category == ACTORCAT_DOOR)) {
frontRoom = globalCtx->transitionActorList[(u16)doorActor->params >> 10].sides[(sp7C > 0) ? 0 : 1].room;
if ((this->doorType != PLAYER_DOORTYPE_FAKE) && (doorActor->category == ACTORCAT_DOOR)) {
frontRoom = globalCtx->transitionActorList[(u16)doorActor->params >> 10]
.sides[(doorDirection > 0) ? 0 : 1]
.room;
if ((frontRoom >= 0) && (frontRoom != globalCtx->roomCtx.curRoom.num)) {
func_8009728C(globalCtx, &globalCtx->roomCtx, frontRoom);
@ -9168,7 +9181,7 @@ void func_808473D4(GlobalContext* globalCtx, Player* this) {
doAction = 0x14;
}
} else if ((func_8084E3C4 != this->func_674) && !(this->stateFlags2 & 0x40000)) {
if ((this->doorType != 0) &&
if ((this->doorType != PLAYER_DOORTYPE_NONE) &&
(!(this->stateFlags1 & 0x800) || ((heldActor != NULL) && (heldActor->id == ACTOR_EN_RU1)))) {
doAction = 4;
} else if ((!(this->stateFlags1 & 0x800) || (heldActor == NULL)) && (interactRangeActor != NULL) &&
@ -10121,7 +10134,7 @@ void Player_UpdateCommon(Player* this, GlobalContext* globalCtx, Input* input) {
temp_f0 = this->actor.world.pos.y - this->actor.prevPos.y;
this->doorType = 0;
this->doorType = PLAYER_DOORTYPE_NONE;
this->unk_8A1 = 0;
this->unk_684 = NULL;