summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpetrie911 <69443847+petrie911@users.noreply.github.com>2020-12-28 19:56:24 -0600
committerGitHub <noreply@github.com>2020-12-28 20:56:24 -0500
commit42f2d38b8fb8e97330bc12e06d71bd35ea2c33e2 (patch)
tree2c904f252f415b9ef2336190620b60d773c63a0e /src
parent1e6bd7f623dead2c5bcbdb5c89a0c9e65c7a86e4 (diff)
En_Torch2 (#486)
* Darkmeiro decompilation Bg_Gnd_Darkmeiro decompiled, matched, and documented. * give this a shot * fix conflict * one more try * Oh boy more giant functions * now functional, but not equivalent * Now only non-matching * cleaned up illusion room * much closer. static variables still suck though * much closer. static variables still suck though * some docs and cleanup. matching is horrible. * static varaibles are a troublesome lot * ifdef * merge ZAP * merge again * small cleanup * small fixes * swordstate * resolve conflict * comments and such Co-authored-by: fig <fig02srl@gmail.com> Co-authored-by: petrie911 <pmontag@DESKTOP-LG8A167.localdomain>
Diffstat (limited to 'src')
-rw-r--r--src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c94
-rw-r--r--src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.h4
-rw-r--r--src/overlays/actors/ovl_En_Torch2/z_en_torch2.c757
3 files changed, 796 insertions, 59 deletions
diff --git a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c
index 840af5d73..29bbc360f 100644
--- a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c
+++ b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c
@@ -15,10 +15,10 @@ void EnBlkobj_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnBlkobj_Update(Actor* thisx, GlobalContext* globalCtx);
void EnBlkobj_Draw(Actor* thisx, GlobalContext* globalCtx);
-void func_809C2148(EnBlkobj* this, GlobalContext* globalCtx);
-void func_809C21A0(EnBlkobj* this, GlobalContext* globalCtx);
-void func_809C2218(EnBlkobj* this, GlobalContext* globalCtx);
-void func_809C22F4(EnBlkobj* this, GlobalContext* globalCtx);
+void EnBlkobj_Wait(EnBlkobj* this, GlobalContext* globalCtx);
+void EnBlkobj_SpawnDarkLink(EnBlkobj* this, GlobalContext* globalCtx);
+void EnBlkobj_DarkLinkFight(EnBlkobj* this, GlobalContext* globalCtx);
+void EnBlkobj_DoNothing(EnBlkobj* this, GlobalContext* globalCtx);
const ActorInit En_Blkobj_InitVars = {
ACTOR_EN_BLKOBJ,
@@ -39,109 +39,109 @@ static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneDownward, 300, ICHAIN_STOP),
};
-static Gfx D_809C2590[] = {
+static Gfx sSetupOpaDL[] = {
gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2),
gsSPEndDisplayList(),
};
-static Gfx D_809C25A0[] = {
+static Gfx sSetupXluDL[] = {
gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2),
gsSPEndDisplayList(),
};
extern Gfx D_060014E0[];
extern Gfx D_060053D0[];
-extern UNK_TYPE D_06007564;
+extern ColHeader D_06007564;
-void func_809C2060(EnBlkobj* this, EnBlkobjActionFunc actionFunc) {
+void EnBlkobj_SetupAction(EnBlkobj* this, EnBlkobjActionFunc actionFunc) {
this->actionFunc = actionFunc;
- this->unk_166 = 0;
+ this->timer = 0;
}
void EnBlkobj_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnBlkobj* this = THIS;
- s32 localC = 0;
+ ColHeader* colHeader = NULL;
Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
DynaPolyInfo_SetActorMove(&this->dyna, 0);
if (Flags_GetClear(globalCtx, this->dyna.actor.room)) {
- this->unk_164 = 0xFF;
- func_809C2060(this, func_809C22F4);
+ this->alpha = 255;
+ EnBlkobj_SetupAction(this, EnBlkobj_DoNothing);
} else {
- DynaPolyInfo_Alloc(&D_06007564, &localC);
+ DynaPolyInfo_Alloc(&D_06007564, &colHeader);
this->dyna.dynaPolyId =
- DynaPolyInfo_RegisterActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, localC);
- func_809C2060(this, func_809C2148);
+ DynaPolyInfo_RegisterActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, colHeader);
+ EnBlkobj_SetupAction(this, EnBlkobj_Wait);
}
}
void EnBlkobj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
+ s32 pad;
EnBlkobj* this = THIS;
DynaPolyInfo_Free(globalCtx, &globalCtx->colCtx.dyna, this->dyna.dynaPolyId);
}
-void func_809C2148(EnBlkobj* this, GlobalContext* globalCtx) {
+void EnBlkobj_Wait(EnBlkobj* this, GlobalContext* globalCtx) {
Player* player = PLAYER;
if (this->dyna.actor.xzDistFromLink < 120.0f) {
- func_809C2060(this, func_809C21A0);
+ EnBlkobj_SetupAction(this, EnBlkobj_SpawnDarkLink);
}
- player->stateFlags2 |= 0x4000000;
+ player->stateFlags2 |= 0x04000000;
}
-void func_809C21A0(EnBlkobj* this, GlobalContext* globalCtx) {
+void EnBlkobj_SpawnDarkLink(EnBlkobj* this, GlobalContext* globalCtx) {
if (!(this->dyna.actor.flags & 0x40)) {
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_TORCH2, this->dyna.actor.posRot.pos.x,
this->dyna.actor.posRot.pos.y, this->dyna.actor.posRot.pos.z, 0, this->dyna.actor.yawTowardsLink, 0,
0);
- func_809C2060(this, func_809C2218);
+ EnBlkobj_SetupAction(this, EnBlkobj_DarkLinkFight);
}
}
-void func_809C2218(EnBlkobj* this, GlobalContext* globalCtx) {
- s32 temp;
+void EnBlkobj_DarkLinkFight(EnBlkobj* this, GlobalContext* globalCtx) {
+ s32 alphaMod;
- if (this->unk_166 == 0) {
+ if (this->timer == 0) {
if (Actor_Find(&globalCtx->actorCtx, ACTOR_EN_TORCH2, ACTORTYPE_BOSS) == NULL) {
Flags_SetClear(globalCtx, this->dyna.actor.room);
- this->unk_166 += 1;
+ this->timer++;
}
- } else {
- if (this->unk_166++ > 100) {
- temp = (this->unk_166 - 100) >> 2;
- if (temp > 5) {
- temp = 5;
- }
- this->unk_164 += temp;
- if (this->unk_164 > 255) {
- this->unk_164 = 255;
- func_809C2060(this, func_809C22F4);
- DynaPolyInfo_Free(globalCtx, &globalCtx->colCtx.dyna, this->dyna.dynaPolyId);
- }
+ } else if (this->timer++ > 100) {
+ alphaMod = (this->timer - 100) >> 2;
+ if (alphaMod > 5) {
+ alphaMod = 5;
+ }
+ this->alpha += alphaMod;
+ if (this->alpha > 255) {
+ this->alpha = 255;
+ EnBlkobj_SetupAction(this, EnBlkobj_DoNothing);
+ DynaPolyInfo_Free(globalCtx, &globalCtx->colCtx.dyna, this->dyna.dynaPolyId);
}
}
}
-void func_809C22F4(EnBlkobj* this, GlobalContext* globalCtx) {
+void EnBlkobj_DoNothing(EnBlkobj* this, GlobalContext* globalCtx) {
}
void EnBlkobj_Update(Actor* thisx, GlobalContext* globalCtx) {
+ s32 pad;
EnBlkobj* this = THIS;
this->actionFunc(this, globalCtx);
}
-void func_809C2324(GlobalContext* globalCtx, Gfx* dList, s32 alpha) {
+void EnBlkobj_DrawAlpha(GlobalContext* globalCtx, Gfx* dList, s32 alpha) {
Gfx* segment;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_blkobj.c", 322);
if (alpha == 255) {
- segment = D_809C2590;
+ segment = sSetupOpaDL;
} else {
- segment = D_809C25A0;
+ segment = sSetupXluDL;
}
gSPSegment(POLY_XLU_DISP++, 0x08, segment);
@@ -152,9 +152,9 @@ void func_809C2324(GlobalContext* globalCtx, Gfx* dList, s32 alpha) {
}
void EnBlkobj_Draw(Actor* thisx, GlobalContext* globalCtx) {
- EnBlkobj* this = THIS;
s32 pad;
- s32 temp_a3;
+ EnBlkobj* this = THIS;
+ s32 illusionAlpha;
u32 gameplayFrames;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_blkobj.c", 349);
@@ -168,12 +168,12 @@ void EnBlkobj_Draw(Actor* thisx, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_blkobj.c", 363),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
- if (this->unk_164 != 0) {
- func_809C2324(globalCtx, D_060014E0, this->unk_164);
+ if (this->alpha != 0) {
+ EnBlkobj_DrawAlpha(globalCtx, D_060014E0, this->alpha);
}
- temp_a3 = 255 - this->unk_164;
- if (temp_a3 != 0) {
- func_809C2324(globalCtx, D_060053D0, temp_a3);
+ illusionAlpha = 255 - this->alpha;
+ if (illusionAlpha != 0) {
+ EnBlkobj_DrawAlpha(globalCtx, D_060053D0, illusionAlpha);
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_blkobj.c", 375);
diff --git a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.h b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.h
index 4104d578b..a2b089399 100644
--- a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.h
+++ b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.h
@@ -10,8 +10,8 @@ typedef void (*EnBlkobjActionFunc)(struct EnBlkobj*, GlobalContext*);
typedef struct EnBlkobj {
/* 0x0000 */ DynaPolyActor dyna;
- /* 0x0164 */ s16 unk_164;
- /* 0x0166 */ s16 unk_166;
+ /* 0x0164 */ s16 alpha;
+ /* 0x0166 */ s16 timer;
/* 0x0168 */ EnBlkobjActionFunc actionFunc;
} EnBlkobj; // size = 0x016C
diff --git a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c
index 752a678e6..e6bc82de7 100644
--- a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c
+++ b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c
@@ -10,12 +10,51 @@
#define THIS ((Player*)thisx)
+typedef enum {
+ /* 0 */ ENTORCH2_WAIT,
+ /* 1 */ ENTORCH2_ATTACK,
+ /* 2 */ ENTORCH2_DEATH,
+ /* 3 */ ENTORCH2_DAMAGE
+} EnTorch2ActionStates;
+
+typedef enum {
+ /* 0 */ FORWARD_SLASH_1H,
+ /* 1 */ FORWARD_SLASH_2H,
+ /* 2 */ FORWARD_COMBO_1H,
+ /* 3 */ FORWARD_COMBO_2H,
+ /* 4 */ RIGHT_SLASH_1H,
+ /* 5 */ RIGHT_SLASH_2H,
+ /* 6 */ RIGHT_COMBO_1H,
+ /* 7 */ RIGHT_COMBO_2H,
+ /* 8 */ LEFT_SLASH_1H,
+ /* 9 */ LEFT_SLASH_2H,
+ /* 10 */ LEFT_COMBO_1H,
+ /* 11 */ LEFT_COMBO_2H,
+ /* 12 */ STAB_1H,
+ /* 13 */ STAB_2H,
+ /* 14 */ STAB_COMBO_1H,
+ /* 15 */ STAB_COMBO_2H,
+ /* 16 */ FLIPSLASH_START,
+ /* 17 */ JUMPSLASH_START,
+ /* 18 */ FLIPSLASH_FINISH,
+ /* 19 */ JUMPSLASH_FINISH,
+ /* 20 */ BACKSLASH_RIGHT,
+ /* 21 */ BACKSLASH_LEFT,
+ /* 22 */ HAMMER_FORWARD,
+ /* 23 */ HAMMER_SIDE,
+ /* 24 */ SPIN_ATTACK_1H,
+ /* 25 */ SPIN_ATTACK_2H,
+ /* 26 */ BIG_SPIN_1H,
+ /* 27 */ BIG_SPIN_2H
+} PlayerSwordAnimation;
+
void EnTorch2_Init(Actor* thisx, GlobalContext* globalCtx);
void EnTorch2_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnTorch2_Update(Actor* thisx, GlobalContext* globalCtx);
void EnTorch2_Draw(Actor* thisx, GlobalContext* globalCtx);
-/*
+extern FlexSkeletonHeader D_06004764;
+
const ActorInit En_Torch2_InitVars = {
ACTOR_EN_TORCH2,
ACTORTYPE_BOSS,
@@ -27,21 +66,719 @@ const ActorInit En_Torch2_InitVars = {
(ActorFunc)EnTorch2_Update,
(ActorFunc)EnTorch2_Draw,
};
-*/
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/EnTorch2_Init.s")
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/EnTorch2_Destroy.s")
+/* static */ f32 sStickTilt = 0.0f;
+/* static */ s16 sStickAngle = 0;
+/* static */ f32 sSwordJumpHeight = 0.0f;
+/* static */ s32 sHoldShieldTimer = 0;
+/* static */ u8 sZTargetFlag = false;
+/* static */ u8 sDeathFlag = false;
+
+/* static */ Input sInput;
+/* static */ u8 sSwordJumpState;
+/* static */ Vec3f sSpawnPoint;
+/* static */ u8 sJumpslashTimer;
+/* static */ u8 sJumpslashFlag;
+/* static */ u8 sActionState;
+/* static */ u8 sSwordJumpTimer;
+/* static */ u8 sCounterState;
+/* static */ u8 sDodgeRollState;
+/* static */ u8 sStaggerCount;
+/* static */ u8 sStaggerTimer;
+/* static */ s8 sLastSwordAnim;
+/* static */ u8 sAlpha;
+
+static DamageTable sDamageTable = {
+ 0x10, 0x02, 0x01, 0x02, 0x10, 0x02, 0x02, 0x10, 0x01, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0xE2, 0x60, 0xD3, 0x00, 0x00, 0x01, 0x04, 0x02, 0x02, 0x08, 0x04, 0x00, 0x00, 0x04, 0x00,
+};
+
+void EnTorch2_Init(Actor* thisx, GlobalContext* globalCtx2) {
+ GlobalContext* globalCtx = globalCtx2;
+ Player* this = THIS;
+
+ sInput.cur.button = sInput.press.button = sInput.rel.button = 0;
+ sInput.cur.stick_x = sInput.cur.stick_y = 0;
+ this->currentShield = PLAYER_SHIELD_HYLIAN;
+ this->heldItemActionParam = this->heldItemId = PLAYER_AP_SWORD_MASTER;
+ Player_SetModelGroup(this, 2);
+ globalCtx->playerInit(this, globalCtx, &D_06004764);
+ this->actor.naviEnemyId = 0x26;
+ this->cylinder.base.acFlags = 9;
+ this->swordQuads[0].base.atFlags = this->swordQuads[1].base.atFlags = 0x11;
+ this->swordQuads[0].base.acFlags = this->swordQuads[1].base.acFlags = 0xD;
+ this->swordQuads[0].base.type = this->swordQuads[1].base.type = 9;
+ this->swordQuads[0].body.toucher.damage = this->swordQuads[1].body.toucher.damage = 8;
+ this->swordQuads[0].body.bumperFlags = this->swordQuads[1].body.bumperFlags = 1;
+ this->shieldQuad.base.atFlags = 0x11;
+ this->shieldQuad.base.acFlags = 0xD;
+ this->actor.colChkInfo.damageTable = &sDamageTable;
+ this->actor.colChkInfo.health = gSaveContext.healthCapacity >> 3;
+ this->actor.colChkInfo.unk_10 = 60;
+ this->actor.colChkInfo.unk_12 = 100;
+ globalCtx->func_11D54(this, globalCtx);
+
+ sActionState = ENTORCH2_WAIT;
+ sDodgeRollState = 0;
+ sSwordJumpHeight = 0.0f;
+ sSwordJumpState = 0;
+ sJumpslashTimer = 0;
+ sJumpslashFlag = false;
+ sCounterState = sStaggerTimer = sStaggerCount = 0;
+ sLastSwordAnim = 0;
+ sAlpha = 95;
+ sSpawnPoint = this->actor.initPosRot.pos;
+}
+
+void EnTorch2_Destroy(Actor* thisx, GlobalContext* globalCtx) {
+ s32 pad;
+ Player* this = THIS;
+
+ Effect_Delete(globalCtx, this->swordEffectIndex);
+ func_800F5B58();
+ Collider_DestroyCylinder(globalCtx, &this->cylinder);
+ Collider_DestroyQuad(globalCtx, &this->swordQuads[0]);
+ Collider_DestroyQuad(globalCtx, &this->swordQuads[1]);
+ Collider_DestroyQuad(globalCtx, &this->shieldQuad);
+}
+
+Actor* EnTorch2_GetAttackItem(GlobalContext* globalCtx, Player* this) {
+ Actor* rangedItem = func_80033780(globalCtx, &this->actor, 4000.0f);
+
+ if (rangedItem != NULL) {
+ return rangedItem;
+ } else {
+ return func_80033684(globalCtx, &this->actor);
+ }
+}
+
+s32 EnTorch2_SwingSword(GlobalContext* globalCtx, Input* input, Player* this) {
+ f32 noAttackChance = 0.0f;
+ s32 attackDelay = 7;
+ Player* player = PLAYER;
+
+ if ((this->linearVelocity < 0.0f) || (player->linearVelocity < 0.0f)) {
+ return 0;
+ }
+ if (gSaveContext.health < 0x50) {
+ attackDelay = 15;
+ noAttackChance += 0.3f;
+ }
+ if (sAlpha != 255) {
+ noAttackChance += 2.0f;
+ }
+ if ((((globalCtx->gameplayFrames & attackDelay) == 0) || (sSwordJumpState != 0)) &&
+ (noAttackChance <= Rand_ZeroOne())) {
+ if (sSwordJumpState == 0) {
+ switch ((s32)(Rand_ZeroOne() * 7.0f)) {
+ case 1:
+ case 5:
+ sStickAngle += 0x4000;
+ sStickTilt = 127.0f;
+ break;
+ case 2:
+ case 6:
+ sStickAngle -= 0x4000;
+ sStickTilt = 127.0f;
+ break;
+ }
+ }
+ input->cur.button = BTN_B;
+ return 1;
+ }
+ return 0;
+}
+
+void EnTorch2_Backflip(Player* this, Input* input, Actor* thisx) {
+ thisx->posRot.rot.y = thisx->shape.rot.y = thisx->yawTowardsLink;
+ sStickAngle = thisx->yawTowardsLink + 0x8000;
+ sStickTilt = 127.0f;
+ sZTargetFlag = true;
+ input->cur.button = BTN_A;
+ this->invincibilityTimer = 10;
+ sCounterState = 0;
+}
+
+#ifdef NON_MATCHING
+/**
+ * Static variables are sometimes loaded from pointers and sometimes directly. While
+ * neither this nor the original are consistent about it, unfortunately they're not
+ * inconsistent in the same way. Also a small instruction mismatch in the input section
+ */
+void EnTorch2_Update(Actor* thisx, GlobalContext* globalCtx2) {
+ GlobalContext* globalCtx = globalCtx2;
+ Player* player = PLAYER;
+ Player* this = THIS;
+ Input* input = &sInput;
+ u16 phi_a2;
+ s8 tempX;
+ s8 tempY;
+ Camera* camera;
+ u8 staggerThreshold;
+ s8 temp;
+ s16 sp66;
+ u32 phi_v0;
+ Actor* attackItem;
+ s16 sp5A;
+ s16 pad58;
+ s32 pad54;
+ f32 sp50;
+ s16 sp4E;
+ s16 pad4C;
+
+ sp5A = player->actor.shape.rot.y - this->actor.shape.rot.y;
+ input->cur.button = 0;
+ camera = Gameplay_GetCamera(globalCtx, 0);
+ attackItem = EnTorch2_GetAttackItem(globalCtx, this);
+ switch (sActionState) {
+ case ENTORCH2_WAIT:
+ this->actor.shape.rot.y = this->actor.posRot.rot.y = this->actor.yawTowardsLink;
+ this->skelAnime.animCurrentFrame = 0.0f;
+ this->skelAnime.animPlaybackSpeed = 0.0f;
+ this->actor.posRot.pos.x = (Math_SinS(this->actor.posRot.rot.y) * 25.0f) + sSpawnPoint.x;
+ this->actor.posRot.pos.z = (Math_CosS(this->actor.posRot.rot.y) * 25.0f) + sSpawnPoint.z;
+ if ((this->actor.xzDistFromLink <= 120.0f) || func_80033A84(globalCtx, &this->actor) ||
+ (attackItem != NULL)) {
+ if (attackItem != NULL) {
+ sDodgeRollState = 1;
+ sStickAngle = this->actor.yawTowardsLink;
+ sStickTilt = 127.0f;
+ input->cur.button = BTN_A;
+ sZTargetFlag = false;
+ sp66 = camera->camDir.y - sStickAngle;
+ input->cur.stick_x = sStickTilt * Math_SinS(sp66);
+ temp = sStickTilt * Math_CosS(sp66);
+ input->cur.stick_y = temp;
+ }
+ func_800F5ACC(0x38);
+ sActionState = ENTORCH2_ATTACK;
+ }
+ break;
+
+ case ENTORCH2_ATTACK:
+ sStickTilt = 0.0f;
+
+ // Handles Dark Link's sword clanking on Link's sword
+
+ if ((this->swordQuads[0].base.acFlags & 0x80) || (this->swordQuads[1].base.acFlags & 0x80)) {
+ this->swordQuads[0].base.acFlags &= ~0x80;
+ this->swordQuads[1].base.acFlags &= ~0x80;
+ this->swordQuads[0].base.atFlags |= 4; // Loads these out of order
+ this->swordQuads[1].base.atFlags |= 4;
+ this->cylinder.base.acFlags &= ~2;
+
+ if (sLastSwordAnim != this->swordAnimation) {
+ sStaggerCount++;
+ sLastSwordAnim = this->swordAnimation;
+ }
+ /*! @bug
+ * This code is needed to reset sCounterState, and should run regardless
+ * of how much health Link has. Without it, sCounterState stays at 2 until
+ * something else resets it, preventing Dark Link from using his shield and
+ * creating a hole in his defenses. This also makes Dark Link harder at low
+ * health, while the other health checks are intended to make him easier.
+ */
+ if ((gSaveContext.health < 0x50) && (sCounterState != 0)) { // Loads in wrong order
+ sCounterState = 0;
+ sStaggerTimer = 50;
+ }
+ }
+ if ((sCounterState != 0) && (this->swordState != 0)) {
+ CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->swordQuads[0].base);
+ CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->swordQuads[1].base);
+ }
+
+ // Ignores hits when jumping on Link's sword
+ if ((this->invincibilityTimer < 0) && (sActionState != ENTORCH2_DAMAGE) &&
+ (this->cylinder.base.acFlags & 2)) {
+ this->cylinder.base.acFlags &= ~2;
+ }
+
+ // Handles Dark Link rolling to dodge item attacks
+
+ if (sDodgeRollState != 0) {
+ sStickTilt = 127.0f;
+ } else if (attackItem != NULL) {
+ sDodgeRollState = 1;
+ sStickAngle = this->actor.yawTowardsLink;
+ sStickTilt = 127.0f;
+ input->cur.button = BTN_A;
+ } else if (sJumpslashTimer == 0) {
+
+ // Handles Dark Link's initial reaction to jumpslashes
+
+ if (((player->swordState != 0) || (player->actor.velocity.y > -3.0f)) &&
+ (player->swordAnimation == JUMPSLASH_START)) {
+ this->actor.posRot.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsLink;
+
+ if (globalCtx->gameplayFrames % 2) {
+ sStickAngle = this->actor.yawTowardsLink + 0x4000;
+ } else {
+ sStickAngle = this->actor.yawTowardsLink - 0x4000;
+ }
+ sStickTilt = 127.0f; // Does not store with pointer
+ sJumpslashFlag = false; // Does not store with POinter
+ input->cur.button |= BTN_A;
+ sJumpslashTimer = 15;
+
+ // Handles jumping on Link's sword
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/func_80B1DB98.s")
+ } else if (sSwordJumpState != 0) {
+ sStickTilt = 0.0f;
+ player->stateFlags3 |= 4;
+ Math_SmoothStepToF(&this->actor.posRot.pos.x,
+ (Math_SinS(player->actor.shape.rot.y - 0x3E8) * 45.0f) +
+ player->actor.posRot.pos.x,
+ 1.0f, 5.0f, 0.0f);
+ Math_SmoothStepToF(&this->actor.posRot.pos.z,
+ (Math_CosS(player->actor.shape.rot.y - 0x3E8) * 45.0f) +
+ player->actor.posRot.pos.z,
+ 1.0f, 5.0f, 0.0f);
+ sSwordJumpTimer--;
+ if ((sSwordJumpTimer == 0) || ((player->invincibilityTimer > 0) && (this->swordState == 0))) {
+ this->actor.posRot.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsLink;
+ input->cur.button = BTN_A;
+ player->stateFlags3 &= ~4;
+ sStickTilt = 127.0f;
+ player->skelAnime.animCurrentFrame = 3.0f;
+ sStickAngle = this->actor.yawTowardsLink + 0x8000;
+ sSwordJumpTimer = sSwordJumpState = 0;
+ this->actor.flags |= 1;
+ } else if (sSwordJumpState == 1) {
+ if (sSwordJumpTimer < 16) {
+ EnTorch2_SwingSword(globalCtx, input, this);
+ sSwordJumpState++;
+ } else if (sSwordJumpTimer == 19) {
+ func_800F4190(&this->actor.projectedPos, NA_SE_VO_LI_AUTO_JUMP);
+ }
+ }
+ } else {
+ // This does nothing, as sHoldShieldTimer is never set.
+ if (sHoldShieldTimer != 0) {
+ sHoldShieldTimer--;
+ input->cur.button = BTN_R;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/func_80B1DBD8.s")
+ // Handles Dark Link's reaction to sword attack other than jumpslashes
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/func_80B1DD70.s")
+ if (func_800354B4(globalCtx, &this->actor, 120.0f, 0x7FFF, 0x7FFF, this->actor.posRot.rot.y)) {
+ // Loads arguments in wrong order. Probably related to static variables problem.
+ if ((player->swordAnimation == STAB_1H) && (this->actor.xzDistFromLink < 90.0f)) {
+ // Handles the reaction to a one-handed stab. If the conditions are satisfied,
+ // Dark Link jumps on Link's sword. Otherwise he backflips away.
+
+ if ((this->swordState == 0) && (sCounterState == 0) && (player->invincibilityTimer == 0) &&
+ (player->swordAnimation == STAB_1H) && (this->actor.xzDistFromLink <= 85.0f) &&
+ func_80033A84(globalCtx, &this->actor)) {
+
+ sStickTilt = 0.0f;
+ sSwordJumpState = 1;
+ player->stateFlags3 |= 4;
+ this->actor.flags &= ~1;
+ sSwordJumpTimer = 27;
+ player->swordState = 0;
+ player->linearVelocity = 0.0f;
+ this->invincibilityTimer = -7;
+ this->linearVelocity = 0.0f;
+ player->skelAnime.animCurrentFrame = 2.0f;
+ func_800A3BC0(globalCtx, &player->skelAnime);
+ sHoldShieldTimer = 0;
+ input->cur.button = BTN_A;
+ } else {
+ EnTorch2_Backflip(this, input, &this->actor);
+ }
+ } else {
+
+ // Handles reactions to all other sword attacks
+
+ sStickAngle = this->actor.yawTowardsLink; // Not loaded into pointer
+ input->cur.button = BTN_B;
+
+ if (player->swordAnimation <= FORWARD_COMBO_2H) {
+ sStickTilt = 0.0f;
+ } else if (player->swordAnimation <= RIGHT_COMBO_2H) {
+ sStickTilt = 127.0f;
+ sStickAngle += sStickAngle; // Not loaded from pointer
+ } else if (player->swordAnimation <= LEFT_COMBO_2H) {
+ sStickTilt = 127.0f;
+ sStickAngle += -0x4000; // Not loaded from pointer
+ } else if (player->swordAnimation <= HAMMER_SIDE) {
+ input->cur.button = BTN_R;
+ } else if (player->swordAnimation <= BIG_SPIN_2H) {
+ EnTorch2_Backflip(this, input, &this->actor);
+ } else {
+ EnTorch2_Backflip(this, input, &this->actor);
+ }
+ if (CHECK_BTN_ANY(input->cur.button, BTN_A | BTN_R) && (this->swordState == 0) &&
+ (player->swordState != 0)) {
+ sCounterState = 1;
+ }
+ }
+ } else {
+
+ // Handles movement and attacks when not reacting to Link's actions
+
+ sStickAngle = this->actor.yawTowardsLink;
+ sp50 = 0.0f;
+ if ((90.0f >= this->actor.xzDistFromLink) && (this->actor.xzDistFromLink > 70.0f) &&
+ (ABS(sp5A) >= 0x7800) &&
+ ((this->actor.unk_10C != 0) || !(player->stateFlags1 & 0x00400000))) {
+ EnTorch2_SwingSword(globalCtx, input, this);
+ } else if (((this->actor.xzDistFromLink <= 70.0f) ||
+ ((this->actor.xzDistFromLink <= 80.0f + sp50) && (player->swordState != 0))) &&
+ (this->swordState == 0)) {
+ if (!EnTorch2_SwingSword(globalCtx, input, this) && (this->swordState == 0) &&
+ (sCounterState == 0)) {
+ EnTorch2_Backflip(this, input, &this->actor);
+ }
+ } else if (this->actor.xzDistFromLink <= 50 + sp50) {
+ sStickTilt = 127.0f;
+ sStickAngle = this->actor.yawTowardsLink;
+ if (this->actor.unk_10C == 0) {
+ Math_SmoothStepToS(&sStickAngle, player->actor.shape.rot.y + 0x7FFF, 1, 0x2328, 0);
+ }
+ } else if (this->actor.xzDistFromLink > 100.0f + sp50) {
+ if ((player->swordState == 0) || (player->swordAnimation < SPIN_ATTACK_1H) ||
+ (player->swordAnimation > BIG_SPIN_2H) || (this->actor.xzDistFromLink >= 280.0f)) {
+ sStickTilt = 127.0f;
+ sStickAngle = this->actor.yawTowardsLink;
+ if (this->actor.unk_10C == 0) {
+ Math_SmoothStepToS(&sStickAngle, player->actor.shape.rot.y + 0x7FFF, 1, 0x2328, 0);
+ }
+ } else {
+ EnTorch2_Backflip(this, input, &this->actor);
+ }
+ } else if (((ABS(sp5A) < 0x7800) && (ABS(sp5A) >= 0x3000)) ||
+ !EnTorch2_SwingSword(globalCtx, input, this)) {
+ sStickAngle = this->actor.yawTowardsLink;
+ sStickTilt = 127.0f;
+ if (this->actor.unk_10C == 0) {
+ Math_SmoothStepToS(&sStickAngle, player->actor.shape.rot.y + 0x7FFF, 1, 0x2328, 0);
+ }
+ }
+ }
+ }
+
+ // Handles Dark Link's counterattack to jumpslashes
+
+ } else if (sJumpslashFlag && (sAlpha == 255) && (this->actor.velocity.y > 0)) {
+ input->cur.button |= BTN_B;
+ } else if (!sJumpslashFlag && (this->actor.bgCheckFlags & 1)) {
+ sStickAngle = this->actor.posRot.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsLink;
+ if (sAlpha != 255) {
+ sStickAngle += 0x8000;
+ sStickTilt = 127.0f; // Not loaded from pointer
+ sZTargetFlag = true;
+ }
+ input->cur.button |= BTN_A;
+ sJumpslashFlag = true;
+ this->invincibilityTimer = 10;
+ }
+
+ // Rotates Dark Link's stick angle from Link-relative to camera-relative.
+
+ sp66 = camera->camDir.y - sStickAngle;
+ input->cur.stick_x = Math_SinS(sp66) * sStickTilt;
+ temp = Math_CosS(sp66) * sStickTilt;
+ input->cur.stick_y = temp;
+
+ if ((sAlpha != 255) && ((globalCtx->gameplayFrames % 8) == 0)) {
+ sAlpha++;
+ }
+ break;
+
+ case ENTORCH2_DAMAGE:
+ this->swordState = 0;
+ input->cur.stick_x = input->cur.stick_y = 0;
+ if ((this->invincibilityTimer > 0) && (this->actor.posRot.pos.y < (this->actor.groundY - 160.0f))) {
+ this->stateFlags3 &= ~1;
+ this->actor.flags |= 1;
+ this->invincibilityTimer = 0;
+ this->actor.velocity.y = 0.0f;
+ this->actor.posRot.pos.y = sSpawnPoint.y + 40.0f;
+ this->actor.posRot.pos.x =
+ (Math_SinS(player->actor.shape.rot.y) * -120.0f) + player->actor.posRot.pos.x;
+ this->actor.posRot.pos.z =
+ (Math_CosS(player->actor.shape.rot.y) * -120.0f) + player->actor.posRot.pos.z;
+ if (func_8002DB6C(&this->actor, &sSpawnPoint) > 800.0f) {
+ sp50 = Rand_ZeroOne() * 20.0f;
+ sp4E = Rand_CenteredFloat(4000.0f);
+ this->actor.shape.rot.y = this->actor.posRot.rot.y =
+ Math_Vec3f_Yaw(&sSpawnPoint, &player->actor.posRot.pos);
+ this->actor.posRot.pos.x =
+ (Math_SinS(this->actor.posRot.rot.y + sp4E) * (25.0f + sp50)) + sSpawnPoint.x;
+ this->actor.posRot.pos.z =
+ (Math_CosS(this->actor.posRot.rot.y + sp4E) * (25.0f + sp50)) + sSpawnPoint.z;
+ this->actor.posRot.pos.y = sSpawnPoint.y;
+ } else {
+ this->actor.posRot.pos.y = this->actor.groundY;
+ }
+ Math_Vec3f_Copy(&this->actor.initPosRot.pos, &this->actor.posRot.pos);
+ globalCtx->func_11D54(this, globalCtx);
+ sActionState = ENTORCH2_ATTACK;
+ sStickTilt = 0.0f;
+ if (sAlpha != 255) {
+ sStaggerCount = 0;
+ sStaggerTimer = 0;
+ }
+ }
+ break;
+
+ case ENTORCH2_DEATH:
+ if (sAlpha - 13 <= 0) {
+ sAlpha = 0;
+ Actor_Kill(&this->actor);
+ return;
+ }
+ sAlpha -= 13;
+ this->actor.shape.unk_14 -= 13;
+ break;
+ }
+
+ // Causes Dark Link to shield in place when Link is using magic attacks other than the spin attack
+
+ if ((gSaveContext.unk_13F0 == 3) && (player->swordState == 0 || (player->swordAnimation < SPIN_ATTACK_1H) ||
+ (player->swordAnimation > BIG_SPIN_2H))) {
+ sStickTilt = 0.0f;
+ input->cur.stick_x = 0;
+ input->cur.stick_y = 0;
+ input->cur.button = BTN_R;
+ }
+
+ if ((sActionState == ENTORCH2_ATTACK) && (this->actor.xzDistFromLink <= 610.0f) && sZTargetFlag) {
+ input->cur.button |= BTN_Z;
+ }
+
+ // Updates Dark Link's "controller". The conditional seems to cause him to
+ // stop targeting and hold shield if he's been holding it long enough.
+
+ phi_a2 = input->cur.button;
+ pad54 = input->cur.button ^ input->prev.button;
+ input->press.button = input->cur.button & pad54;
+ phi_v0 = input->cur.button;
+ if (input->cur.button & BTN_R) {
+ input->cur.button = phi_a2;
+ phi_a2 = ((sCounterState == 0) && (this->swordState == 0)) ? BTN_R : phi_v0 ^ BTN_R;
+ phi_v0 = phi_a2; // instruction mismatch
+ }
+ input->rel.button = input->prev.button & pad54;
+ input->prev.button = phi_v0 & 0x3FFF; // & ~(BTN_A | BTN_B)
+ input->cur.button = phi_a2;
+ PadUtils_UpdateRelXY(input);
+
+ input->press.stick_x += (s8)(input->cur.stick_x - input->prev.stick_x);
+ input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y);
+
+ // Handles Dark Link being damaged
+
+ if ((this->actor.colChkInfo.health == 0) && sDeathFlag) {
+ this->csMode = 0x18;
+ this->unk_448 = &player->actor;
+ this->unk_46A = 1;
+ sDeathFlag = false;
+ }
+ if ((this->invincibilityTimer == 0) && (this->actor.colChkInfo.health != 0) && (this->cylinder.base.acFlags & 2) &&
+ !(this->stateFlags1 & 0x04000000) && !(this->swordQuads[0].base.atFlags & 2) &&
+ !(this->swordQuads[1].base.atFlags & 2)) {
+
+ if (!Actor_ApplyDamage(&this->actor)) {
+ func_800F5B58();
+ this->actor.flags &= ~5;
+ this->unk_8A1 = 2;
+ this->unk_8A4 = 6.0f;
+ this->unk_8A8 = 6.0f;
+ this->unk_8A0 = this->actor.colChkInfo.damage;
+ this->unk_8A2 = this->actor.yawTowardsLink + 0x8000;
+ sDeathFlag++;
+ sActionState = ENTORCH2_DEATH;
+ func_80032C7C(globalCtx, &this->actor);
+ Item_DropCollectibleRandom(globalCtx, &this->actor, &this->actor.posRot.pos, 0xC0);
+ this->stateFlags3 &= ~4;
+ } else {
+ func_800F5ACC(0x38);
+ if (this->actor.colChkInfo.damageEffect == 1) {
+ if (sAlpha == 255) {
+ func_8003426C(&this->actor, 0, 0xFF, 0, 0x50);
+ } else {
+ func_8003426C(&this->actor, 0, 0xFF, 0x2000, 0x50);
+ }
+ } else {
+ this->actor.flags &= ~1;
+ this->unk_8A1 = 1;
+ this->unk_8A8 = 6.0f;
+ this->unk_8A0 = this->actor.colChkInfo.damage;
+ this->unk_8A4 = 8.0f;
+ this->unk_8A2 = this->actor.yawTowardsLink + 0x8000;
+ func_80035650(&this->actor, &this->cylinder.body, 1);
+ this->stateFlags3 &= ~4;
+ this->stateFlags3 |= 1;
+ sActionState = ENTORCH2_DAMAGE;
+ if (sAlpha == 255) {
+ func_8003426C(&this->actor, 0x4000, 0xFF, 0, 0xC);
+ } else {
+ func_8003426C(&this->actor, 0x4000, 0xFF, 0x2000, 0xC);
+ }
+ }
+ }
+ this->actor.colChkInfo.damage = 0;
+ this->unk_8A0 = 0;
+ }
+
+ // Handles being frozen by a deku nut
+
+ if ((this->actor.dmgEffectTimer == 0) || (this->actor.dmgEffectParams & 0x4000)) {
+ this->stateFlags3 &= ~4;
+ } else {
+ this->stateFlags3 |= 4;
+ this->stateFlags1 &= ~0x04000000;
+ this->invincibilityTimer = 0;
+ input->press.stick_x = input->press.stick_y = 0;
+ /*! @bug
+ * Setting cur.button to 0 clears the Z-trigger, causing Dark Link to break his
+ * lock on Link. If he presses A while not locked on, he'll put his sword away.
+ * This clears his held item param permanently and makes him unable to attack.
+ */
+ input->cur.button = 0;
+ input->press.button = 0;
+ this->linearVelocity = 0.0f;
+ }
+
+ globalCtx->playerUpdate(this, globalCtx, input);
+
+ /*
+ * Handles sword clanks and removes their recoil for both Links. Dark Link staggers
+ * if he's had to counter with enough different sword animations in a row.
+ */
+ if (this->linearVelocity == -18.0f) {
+ staggerThreshold = (u32)Rand_CenteredFloat(2.0f) + 6;
+ if (gSaveContext.health < 0x50) {
+ staggerThreshold = (u32)Rand_CenteredFloat(2.0f) + 3;
+ }
+ if (this->actor.xzDistFromLink > 80.0f) {
+ this->linearVelocity = 1.2f;
+ } else if (this->actor.xzDistFromLink < 70.0f) {
+ this->linearVelocity = -1.5f;
+ } else {
+ this->linearVelocity = 1.0f;
+ }
+ if (staggerThreshold < sStaggerCount) {
+ this->skelAnime.animPlaybackSpeed *= 0.6f;
+ func_800F4190(&this->actor.projectedPos, NA_SE_PL_DAMAGE);
+ sStaggerTimer = 0;
+ sStaggerCount = 0;
+ }
+ }
+ if (player->linearVelocity == -18.0f) {
+ if (this->actor.xzDistFromLink > 80.0f) {
+ player->linearVelocity = 1.2f;
+ } else if (this->actor.xzDistFromLink < 70.0f) {
+ player->linearVelocity = -1.5f;
+ } else {
+ player->linearVelocity = 1.0f;
+ }
+ }
+ /*
+ * This ensures Dark Link's counter animation mirrors Link's exactly.
+ */
+ if ((sCounterState != 0) && (sCounterState == 1)) {
+ if (this->swordState == 0) {
+ sCounterState = 0;
+ } else {
+ sCounterState = 2;
+ this->swordState = 1;
+ this->skelAnime.animCurrentFrame = player->skelAnime.animCurrentFrame - player->skelAnime.animPlaybackSpeed;
+ this->skelAnime.animPlaybackSpeed = player->skelAnime.animPlaybackSpeed;
+ func_800A3BC0(globalCtx, &this->skelAnime);
+ Collider_QuadSetAT(globalCtx, &this->swordQuads[0].base);
+ Collider_QuadSetAT(globalCtx, &this->swordQuads[1].base);
+ }
+ }
+ if (sStaggerTimer != 0) {
+ sStaggerTimer--;
+ if (sStaggerTimer == 0) {
+ sCounterState = 0;
+ sStaggerCount = 0;
+ }
+ }
+ if (sDodgeRollState != 0) {
+ if (sDodgeRollState == 1) {
+ this->invincibilityTimer = 20;
+ }
+ sDodgeRollState = (this->invincibilityTimer > 0) ? 2 : 0;
+ }
+ if (this->invincibilityTimer != 0) {
+ this->cylinder.base.type = 0xA;
+ this->cylinder.body.flags = 5;
+ } else {
+ this->cylinder.base.type = 5;
+ this->cylinder.body.flags = 1;
+ }
+ /*
+ * Handles the jump movement onto Link's sword. Dark Link doesn't move during the
+ * sword jump. Instead, his shape y-offset is increased (see below). Once the sword
+ * jump is finished, the offset is added to his position to fix the discrepancy.
+ */
+ if (sSwordJumpState != 0) {
+ Math_SmoothStepToF(&sSwordJumpHeight, 2630.0f, 1.0f, 2000.0f, 0.0f);
+ this->actor.velocity.y -= 0.6f;
+ } else if (sSwordJumpHeight != 0) {
+ this->actor.posRot.pos.y += sSwordJumpHeight * 0.01f;
+ sSwordJumpHeight = 0;
+ }
+ if ((sActionState == ENTORCH2_WAIT) || (this->invincibilityTimer < 0)) {
+ sZTargetFlag = false;
+ } else {
+ sZTargetFlag = true;
+ }
+ if (sJumpslashTimer != 0) {
+ sJumpslashTimer--;
+ }
+ this->actor.posRot2.pos = this->actor.posRot.pos;
+ this->actor.posRot2.pos.y += 20.0f;
+ this->actor.shape.unk_08 = sSwordJumpHeight;
+}
+#else
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/EnTorch2_Update.s")
+#endif
+
+s32 EnTorch2_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx,
+ Gfx** gfx) {
+ Player* this = THIS;
+
+ return func_8008FCC8(globalCtx, limbIndex, dList, pos, rot, &this->actor);
+}
+
+void EnTorch2_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx, Gfx** gfx) {
+ Player* this = THIS;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/func_80B1F7A8.s")
+ func_80090D20(globalCtx, limbIndex, dList, rot, &this->actor);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/func_80B1F7D4.s")
+void EnTorch2_Draw(Actor* thisx, GlobalContext* globalCtx2) {
+ GlobalContext* globalCtx = globalCtx2;
+ Player* this = THIS;
+ s32 pad;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Torch2/EnTorch2_Draw.s")
+ OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_torch2.c", 1050);
+ func_80093C80(globalCtx);
+ func_80093D84(globalCtx->state.gfxCtx);
+ if (sAlpha == 255) {
+ gDPSetEnvColor(POLY_OPA_DISP++, 255, 0, 0, sAlpha);
+ gSPSegment(POLY_OPA_DISP++, 0x0C, D_80116280 + 2);
+ func_8002EBCC(&this->actor, globalCtx, 0);
+ func_8002ED80(&this->actor, globalCtx, 0);
+ POLY_OPA_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl,
+ this->skelAnime.dListCount, EnTorch2_OverrideLimbDraw, EnTorch2_PostLimbDraw,
+ this, POLY_OPA_DISP);
+ } else {
+ gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, sAlpha);
+ gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280);
+ func_8002EBCC(&this->actor, globalCtx, 0);
+ func_8002ED80(&this->actor, globalCtx, 0);
+ POLY_XLU_DISP = SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl,
+ this->skelAnime.dListCount, EnTorch2_OverrideLimbDraw, EnTorch2_PostLimbDraw,
+ this, POLY_XLU_DISP);
+ }
+ CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_torch2.c", 1114);
+}