From 50c5ab0fc7f0941092e3671ae7e92f6ff1d892a3 Mon Sep 17 00:00:00 2001 From: Tom Overton Date: Wed, 6 Apr 2022 18:03:27 -0700 Subject: [PATCH] En_Dragon (Deep Python) OK and documented. object_utubo documented (#771) * EnDragon_Init OK * func_80B5EDF0 OK * func_80B5EAA0 OK * EnDragon_Destroy OK * EnDragon_Update OK * func_80B60138 OK * func_80B5EE3C OK * func_80B5EF88 OK * func_80B5F418 OK * func_80B5ED90 OK * func_80B5EB40 OK (commented out because data is not imported yet) * Import data into C * Uncomment func_80B5EB40 * func_80B5EFD0 OK * func_80B5F3A4 OK * func_80B5F888 OK * func_80B5FCC0 OK * Draw functions OK * func_80B5FD68 OK * func_80B5F508 OK * func_80B5F8D8 OK * Better match on func_80B5FD68 * Use generated reloc * Remove undefined_syms for this actor * Some minor cleanup * Make the data like Anghelo said * Document object_utubo * Name a bunch of stuff * Name some more stuff * Some documentation around death * Documentation for actions * Name a bunch of junk * Use regs instead of directly accessing gGameInfo * Name the player position vars * Update weekEventReg references * Name and list out states * Name timer * Document extend stuff * Finish documentation * Respond to Anghelo's review * Respond to hensldm's review * The thing Anghelo suggested *actually* matches --- assets/xml/objects/object_utubo.xml | 87 +- include/z64.h | 2 +- spec | 3 +- .../ovl_Bg_Sinkai_Kabe/z_bg_sinkai_kabe.c | 2 +- .../actors/ovl_En_Dragon/z_en_dragon.c | 866 ++++++++++++++++-- .../actors/ovl_En_Dragon/z_en_dragon.h | 45 +- tools/disasm/functions.txt | 34 +- tools/disasm/variables.txt | 13 +- undefined_syms.txt | 5 - 9 files changed, 889 insertions(+), 168 deletions(-) diff --git a/assets/xml/objects/object_utubo.xml b/assets/xml/objects/object_utubo.xml index 68cd3e1960..a1f499eb6a 100644 --- a/assets/xml/objects/object_utubo.xml +++ b/assets/xml/objects/object_utubo.xml @@ -1,42 +1,53 @@  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/z64.h b/include/z64.h index f49686c6c2..6f8067136d 100644 --- a/include/z64.h +++ b/include/z64.h @@ -1322,7 +1322,7 @@ struct GlobalContext { /* 0x18760 */ DoorContext doorCtx; /* 0x18768 */ void (*playerInit)(Player* player, struct GlobalContext* globalCtx, FlexSkeletonHeader* skelHeader); /* 0x1876C */ void (*playerUpdate)(Player* player, struct GlobalContext* globalCtx, Input* input); - /* 0x18770 */ void* unk_18770; //! @TODO: Determine function prototype + /* 0x18770 */ void (*unk_18770)(struct GlobalContext* globalCtx, Player* player); /* 0x18774 */ s32 (*startPlayerFishing)(struct GlobalContext* globalCtx); /* 0x18778 */ s32 (*grabPlayer)(struct GlobalContext* globalCtx, Player* player); /* 0x1877C */ s32 (*startPlayerCutscene)(struct GlobalContext* globalCtx, Player* player, s32 mode); diff --git a/spec b/spec index c99b6bfa52..34a0c96e7a 100644 --- a/spec +++ b/spec @@ -4058,8 +4058,7 @@ beginseg name "ovl_En_Dragon" compress include "build/src/overlays/actors/ovl_En_Dragon/z_en_dragon.o" - include "build/data/ovl_En_Dragon/ovl_En_Dragon.data.o" - include "build/data/ovl_En_Dragon/ovl_En_Dragon.reloc.o" + include "build/src/overlays/actors/ovl_En_Dragon/ovl_En_Dragon_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_Bg_Sinkai_Kabe/z_bg_sinkai_kabe.c b/src/overlays/actors/ovl_Bg_Sinkai_Kabe/z_bg_sinkai_kabe.c index 15bac4d131..e5af3fe1f0 100644 --- a/src/overlays/actors/ovl_Bg_Sinkai_Kabe/z_bg_sinkai_kabe.c +++ b/src/overlays/actors/ovl_Bg_Sinkai_Kabe/z_bg_sinkai_kabe.c @@ -1,7 +1,7 @@ /* * File: z_bg_sinkai_kabe.c * Overlay: ovl_Bg_Sinkai_Kabe - * Description: Large Rotating Green Rupee + * Description: Manages the Deep Pythons and Seahorse in Pinnacle Rock */ #include "z_bg_sinkai_kabe.h" diff --git a/src/overlays/actors/ovl_En_Dragon/z_en_dragon.c b/src/overlays/actors/ovl_En_Dragon/z_en_dragon.c index 604be5441f..5b7091d02f 100644 --- a/src/overlays/actors/ovl_En_Dragon/z_en_dragon.c +++ b/src/overlays/actors/ovl_En_Dragon/z_en_dragon.c @@ -15,16 +15,51 @@ void EnDragon_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnDragon_Update(Actor* thisx, GlobalContext* globalCtx); void EnDragon_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_80B5ED90(EnDragon* this, GlobalContext* globalCtx); -void func_80B5EE3C(EnDragon* this, GlobalContext* globalCtx); -void func_80B5EFD0(EnDragon* this, GlobalContext* globalCtx); -void func_80B5F418(EnDragon* this, GlobalContext* globalCtx); -void func_80B5F508(EnDragon* this, GlobalContext* globalCtx); -void func_80B5F8D8(EnDragon* this, GlobalContext* globalCtx); -void func_80B5FCC0(EnDragon* this, GlobalContext* globalCtx); -void func_80B5FD68(EnDragon* this, GlobalContext* globalCtx); +void EnDragon_SetupRetreatOrIdle(EnDragon* this); +void EnDragon_RetreatOrIdle(EnDragon* this, GlobalContext* globalCtx); +void EnDragon_SetupExtend(EnDragon* this); +void EnDragon_Extend(EnDragon* this, GlobalContext* globalCtx); +void EnDragon_Grab(EnDragon* this, GlobalContext* globalCtx); +void EnDragon_SetupAttack(EnDragon* this); +void EnDragon_Attack(EnDragon* this, GlobalContext* globalCtx); +void EnDragon_Dead(EnDragon* this, GlobalContext* globalCtx); + +typedef enum { + /* 0 */ DEEP_PYTHON_ANIMATION_SMALL_SIDE_SWAY, + /* 1 */ DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY, + /* 2 */ DEEP_PYTHON_ANIMATION_VERTICAL_SWAY, + /* 3 */ DEEP_PYTHON_ANIMATION_IDLE +} DeepPythonAnimationIndex; + +typedef enum { + /* 0 */ DEEP_PYTHON_ACTION_IDLE, + /* 1 */ DEEP_PYTHON_ACTION_EXTEND, + /* 2 */ DEEP_PYTHON_ACTION_GRAB, + /* 3 */ DEEP_PYTHON_ACTION_DAMAGE, + /* 4 */ DEEP_PYTHON_ACTION_RETREAT, + /* 5 */ DEEP_PYTHON_ACTION_SETUP_DEAD, + /* 6 */ DEEP_PYTHON_ACTION_DEAD, +} DeepPythonAction; + +typedef enum { + /* 0 */ DEEP_PYTHON_EXTEND_STATE_NOT_FULLY_EXTENDED, + /* 1 */ DEEP_PYTHON_EXTEND_STATE_FULLY_EXTENDED, + /* 2 */ DEEP_PYTHON_EXTEND_STATE_REPEAT_LARGE_SWAY, + /* 3 */ DEEP_PYTHON_EXTEND_STATE_REPEAT_SMALL_SWAY, +} DeepPythonExtendState; + +typedef enum { + /* 0 */ DEEP_PYTHON_GRAB_STATE_START, + /* 1 */ DEEP_PYTHON_GRAB_STATE_GRABBED, +} DeepPythonGrabState; + +typedef enum { + /* 0 */ DEEP_PYTHON_ATTACK_STATE_START, + /* 1 */ DEEP_PYTHON_ATTACK_STATE_RELEASED, +} DeepPythonAttackState; + +static s32 sNumPythonsDead = 0; -#if 0 const ActorInit En_Dragon_InitVars = { ACTOR_EN_DRAGON, ACTORCAT_ENEMY, @@ -37,130 +72,779 @@ const ActorInit En_Dragon_InitVars = { (ActorFunc)EnDragon_Draw, }; -// static DamageTable sDamageTable = { -static DamageTable D_80B605F4 = { - /* Deku Nut */ DMG_ENTRY(0, 0x0), - /* Deku Stick */ DMG_ENTRY(0, 0x0), - /* Horse trample */ DMG_ENTRY(0, 0x0), - /* Explosives */ DMG_ENTRY(1, 0xF), - /* Zora boomerang */ DMG_ENTRY(1, 0xF), - /* Normal arrow */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0), - /* Hookshot */ DMG_ENTRY(0, 0x0), - /* Goron punch */ DMG_ENTRY(0, 0x0), - /* Sword */ DMG_ENTRY(0, 0x0), - /* Goron pound */ DMG_ENTRY(0, 0x0), - /* Fire arrow */ DMG_ENTRY(0, 0x0), - /* Ice arrow */ DMG_ENTRY(0, 0x0), - /* Light arrow */ DMG_ENTRY(0, 0x0), - /* Goron spikes */ DMG_ENTRY(0, 0x0), - /* Deku spin */ DMG_ENTRY(0, 0x0), - /* Deku bubble */ DMG_ENTRY(0, 0x0), - /* Deku launch */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x0), - /* Zora barrier */ DMG_ENTRY(1, 0xF), - /* Normal shield */ DMG_ENTRY(0, 0x0), - /* Light ray */ DMG_ENTRY(0, 0x0), - /* Thrown object */ DMG_ENTRY(0, 0x0), - /* Zora punch */ DMG_ENTRY(1, 0xF), - /* Spin attack */ DMG_ENTRY(0, 0x0), - /* Sword beam */ DMG_ENTRY(0, 0x0), - /* Normal Roll */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0), - /* Unblockable */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0), - /* Powder Keg */ DMG_ENTRY(1, 0xF), +typedef enum { + /* 0x0 */ DEEP_PYTHON_DMGEFF_NONE, + /* 0xF */ DEEP_PYTHON_DMGEFF_DAMAGE = 0xF +} DeepPythonDamageEffect; + +static DamageTable sDamageTable = { + /* Deku Nut */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Deku Stick */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Horse trample */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Explosives */ DMG_ENTRY(1, DEEP_PYTHON_DMGEFF_DAMAGE), + /* Zora boomerang */ DMG_ENTRY(1, DEEP_PYTHON_DMGEFF_DAMAGE), + /* Normal arrow */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* UNK_DMG_0x06 */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Hookshot */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Goron punch */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Sword */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Goron pound */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Fire arrow */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Ice arrow */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Light arrow */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Goron spikes */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Deku spin */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Deku bubble */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Deku launch */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* UNK_DMG_0x12 */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Zora barrier */ DMG_ENTRY(1, DEEP_PYTHON_DMGEFF_DAMAGE), + /* Normal shield */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Light ray */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Thrown object */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Zora punch */ DMG_ENTRY(1, DEEP_PYTHON_DMGEFF_DAMAGE), + /* Spin attack */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Sword beam */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Normal Roll */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* UNK_DMG_0x1B */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* UNK_DMG_0x1C */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Unblockable */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* UNK_DMG_0x1E */ DMG_ENTRY(0, DEEP_PYTHON_DMGEFF_NONE), + /* Powder Keg */ DMG_ENTRY(1, DEEP_PYTHON_DMGEFF_DAMAGE), }; -// static ColliderJntSphElementInit sJntSphElementsInit[8] = { -static ColliderJntSphElementInit D_80B60614[8] = { +static ColliderJntSphElementInit sJntSphElementsInit[8] = { { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 13, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_HEAD, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 12, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_COLLAR, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 12, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_COLLAR, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 10, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_BODY_SEGMENT_1, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 10, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_BODY_SEGMENT_1, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 9, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_BODY_SEGMENT_2, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 9, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_BODY_SEGMENT_2, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, - { 9, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, + { DEEP_PYTHON_LIMB_BODY_SEGMENT_2, { { 0, 0, 0 }, 0 }, 1 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_80B60734 = { - { COLTYPE_HIT6, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER, OC2_TYPE_1, COLSHAPE_JNTSPH, }, - 8, D_80B60614, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_HIT6, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_PLAYER, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + ARRAY_COUNT(sJntSphElementsInit), + sJntSphElementsInit, }; -#endif +void EnDragon_Init(Actor* thisx, GlobalContext* globalCtx) { + EnDragon* this = THIS; -extern DamageTable D_80B605F4; -extern ColliderJntSphElementInit D_80B60614[8]; -extern ColliderJntSphInit D_80B60734; + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &gDeepPythonSkel, &gDeepPythonSmallSideSwayAnim, this->jointTable, + this->morphTable, DEEP_PYTHON_LIMB_MAX); -extern UNK_TYPE D_060048B8; + this->actor.colChkInfo.health = 4; + this->actor.colChkInfo.damageTable = &sDamageTable; + this->actor.targetMode = 0xA; + Collider_InitAndSetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, this->colliderElements); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/EnDragon_Init.s") + this->collider.elements[0].dim.scale = this->collider.elements[1].dim.scale = this->collider.elements[2].dim.scale = + this->collider.elements[3].dim.scale = this->collider.elements[4].dim.scale = + this->collider.elements[5].dim.scale = this->collider.elements[6].dim.scale = + this->collider.elements[7].dim.scale = 1.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/EnDragon_Destroy.s") + this->collider.elements[0].dim.modelSphere.radius = 150; + this->collider.elements[0].dim.modelSphere.center.x = 420; + this->collider.elements[1].dim.modelSphere.radius = 160; + this->collider.elements[1].dim.modelSphere.center.x = 630; + this->collider.elements[2].dim.modelSphere.radius = 130; + this->collider.elements[2].dim.modelSphere.center.x = 630; + this->collider.elements[3].dim.modelSphere.radius = 170; + this->collider.elements[3].dim.modelSphere.center.x = 920; + this->collider.elements[4].dim.modelSphere.radius = 150; + this->collider.elements[4].dim.modelSphere.center.x = 530; + this->collider.elements[5].dim.modelSphere.radius = 140; + this->collider.elements[5].dim.modelSphere.center.x = 730; + this->collider.elements[6].dim.modelSphere.radius = 120; + this->collider.elements[6].dim.modelSphere.center.x = 430; + this->collider.elements[7].dim.modelSphere.radius = 110; + this->collider.elements[7].dim.modelSphere.center.x = 160; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EAA0.s") + this->pythonIndex = EN_DRAGON_GET_PYTHON_INDEX(&this->actor); + this->actor.colChkInfo.mass = MASS_IMMOVABLE; + this->action = DEEP_PYTHON_ACTION_IDLE; + this->actor.hintId = 0xE; + this->scale = 0.5f; + this->actor.flags &= ~ACTOR_FLAG_8000000; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EB40.s") + EnDragon_SetupRetreatOrIdle(this); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5ED90.s") +void EnDragon_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnDragon* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EDF0.s") + Collider_DestroyJntSph(globalCtx, &this->collider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EE3C.s") +static AnimationHeader* sAnimations[] = { + &gDeepPythonSmallSideSwayAnim, + &gDeepPythonLargeSideSwayAnim, + &gDeepPythonVerticalSwayAnim, + &gDeepPythonSmallSideSwayAnim, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EF88.s") +static u8 sAnimationModes[] = { ANIMMODE_LOOP, ANIMMODE_LOOP, ANIMMODE_ONCE, ANIMMODE_ONCE }; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5EFD0.s") +void EnDragon_ChangeAnimation(EnDragon* this, s32 animationIndex) { + f32 startFrame; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5F3A4.s") + this->animationIndex = animationIndex; + this->endFrame = Animation_GetLastFrame(sAnimations[animationIndex]); + startFrame = 0.0f; + if (this->animationIndex == DEEP_PYTHON_ANIMATION_IDLE) { + startFrame = this->endFrame; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5F418.s") + Animation_Change(&this->skelAnime, sAnimations[animationIndex], 1.0f, startFrame, this->endFrame, + sAnimationModes[this->animationIndex], -4.0f); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5F508.s") +static Color_RGBA8 sBubblePrimColors[] = { + { 255, 255, 255, 255 }, + { 150, 255, 255, 255 }, + { 100, 255, 255, 255 }, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5F888.s") +static Color_RGBA8 sBubbleEnvColors[] = { + { 150, 150, 150, 0 }, + { 0, 100, 0, 255 }, + { 0, 0, 255, 255 }, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5F8D8.s") +void EnDragon_SpawnBubbles(EnDragon* this, GlobalContext* globalCtx, Vec3f basePos) { + static Vec3f sBubbleVelocity = { 0.0f, 0.0f, 0.0f }; + static Vec3f sBubbleAccel = { 0.0f, 0.1f, 0.0f }; + s32 bubbleCount; + s16 colorIndex; + s16 scale; + Vec3f bubblePos; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5FCC0.s") + bubbleCount = (s32)randPlusMinusPoint5Scaled(5.0f) + 10; + colorIndex = 0; + if (this->action == DEEP_PYTHON_ACTION_DEAD) { + colorIndex = 1; + bubbleCount = (s32)randPlusMinusPoint5Scaled(5.0f) + 10; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B5FD68.s") + for (i = 0; i < bubbleCount; i++) { + Math_Vec3f_Copy(&bubblePos, &basePos); + sBubbleVelocity.x = Rand_ZeroFloat(1.0f) * 23.0f; + sBubbleVelocity.y = Rand_ZeroFloat(1.0f) * 10.0f; + sBubbleVelocity.z = Rand_ZeroFloat(1.0f) * 23.0f; + bubblePos.x += randPlusMinusPoint5Scaled(i * 30.0f); + bubblePos.y += randPlusMinusPoint5Scaled(5.0f); + bubblePos.z += randPlusMinusPoint5Scaled(i * 30.0f); + sBubbleAccel.y = Rand_ZeroFloat(1.0f) * 20.0f * 3.0f; + scale = Rand_S16Offset(380, 240); + EffectSsDtBubble_SpawnCustomColor(globalCtx, &bubblePos, &sBubbleVelocity, &sBubbleAccel, + &sBubblePrimColors[colorIndex], &sBubbleEnvColors[colorIndex], scale, 30, 0); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B60138.s") +void EnDragon_RetreatOnceTimerEnds(EnDragon* this, GlobalContext* globalCtx) { + if (this->timer == 0) { + func_800B8D50(globalCtx, &this->actor, 10.0f, this->actor.world.rot.y, 10.0f, 8); + EnDragon_SetupRetreatOrIdle(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/EnDragon_Update.s") +void EnDragon_SetupRetreatOrIdle(EnDragon* this) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_IDLE); + this->state = 0; + this->unk_2CC = 0; + this->hasGrabbedPlayer = false; + this->grabTimer = 0; + this->timer = 30; + this->actionFunc = EnDragon_RetreatOrIdle; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B6043C.s") +void EnDragon_RetreatOrIdle(EnDragon* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); + if (this->action == DEEP_PYTHON_ACTION_EXTEND) { + EnDragon_SetupExtend(this); + } else if ((this->timer != 0) && (fabsf(this->actor.world.pos.x - this->actor.home.pos.x) > 101.0f) && + (fabsf(this->actor.world.pos.z - this->actor.home.pos.z) > 101.0f)) { + this->actor.speedXZ = -100.0f; + } else { + this->actor.speedXZ = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/func_80B60494.s") + if ((fabsf(this->actor.world.pos.x - this->actor.home.pos.x) > 4.0f) && + (fabsf(this->actor.world.pos.z - this->actor.home.pos.z) > 4.0f)) { + Math_ApproachF(&this->actor.world.pos.x, this->actor.home.pos.x, 0.3f, 200.0f); + Math_ApproachF(&this->actor.world.pos.z, this->actor.home.pos.z, 0.3f, 200.0f); + } else if (this->action != DEEP_PYTHON_ACTION_IDLE) { + this->action = DEEP_PYTHON_ACTION_IDLE; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Dragon/EnDragon_Draw.s") +void EnDragon_SetupExtend(EnDragon* this) { + this->state = 0; + this->behindJawRetreatTimer = this->state; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_APPEAR_TRG); + this->retreatTimer = 250; + this->actionFunc = EnDragon_Extend; +} + +void EnDragon_Extend(EnDragon* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + f32 currentFrame = this->skelAnime.curFrame; + s16 yaw; + + EnDragon_SpawnBubbles(this, globalCtx, this->jawPos); + + if (this->action >= DEEP_PYTHON_ACTION_DAMAGE) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_BACK); + EnDragon_SetupRetreatOrIdle(this); + } else if (this->retreatTimer == 0) { + this->action = DEEP_PYTHON_ACTION_RETREAT; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_BACK); + EnDragon_SetupRetreatOrIdle(this); + } else if (this->state == DEEP_PYTHON_EXTEND_STATE_NOT_FULLY_EXTENDED) { + Vec3f extendedPos; + + Math_Vec3f_Copy(&extendedPos, &this->burrowEntrancePos); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_APPEAR - SFX_FLAG); + extendedPos.x += Math_SinS(this->actor.world.rot.y) * -530.0f; + extendedPos.z += Math_CosS(this->actor.world.rot.y) * -530.0f; + this->actor.speedXZ = 40.0f; + Math_SmoothStepToS(&this->jawZRotation, 0xFA0, 5, 0xBB8, 0x14); + + if ((fabsf(this->actor.world.pos.x - extendedPos.x) < 51.0f) && + (fabsf(this->actor.world.pos.z - extendedPos.z) < 51.0f)) { + this->actor.speedXZ = 0.0f; + Math_ApproachF(&this->actor.world.pos.x, extendedPos.x, 0.3f, 50.0f); + Math_ApproachF(&this->actor.world.pos.z, extendedPos.z, 0.3f, 50.0f); + if ((fabsf(this->actor.world.pos.x - extendedPos.x) < 4.0f) && + (fabsf(this->actor.world.pos.z - extendedPos.z) < 4.0f)) { + if (this->animationIndex != DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY); + } + + this->state = DEEP_PYTHON_EXTEND_STATE_FULLY_EXTENDED; + } + } + } else { + Math_SmoothStepToS(&this->jawZRotation, 0, 5, 0xBB8, 0x14); + SkelAnime_Update(&this->skelAnime); + if (this->state == DEEP_PYTHON_EXTEND_STATE_FULLY_EXTENDED) { + if (currentFrame < this->endFrame) { + return; + } + + this->state = DEEP_PYTHON_EXTEND_STATE_REPEAT_LARGE_SWAY; + } + + yaw = ABS_ALT(BINANG_SUB(Math_Vec3f_Yaw(&this->jawPos, &player->actor.world.pos), this->actor.shape.rot.y)); + if (yaw < 0x5000) { + // Player is in front of the jaw + if ((this->endFrame <= currentFrame) && (this->largeSwayWaitTimer == 0)) { + if (this->animationIndex != DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY); + } + + this->state = DEEP_PYTHON_EXTEND_STATE_REPEAT_LARGE_SWAY; + } + + this->behindJawRetreatTimer = 0; + } else { + // Player is in behind the jaw + if (this->state == DEEP_PYTHON_EXTEND_STATE_REPEAT_LARGE_SWAY) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_SMALL_SIDE_SWAY); + this->largeSwayWaitTimer = Rand_ZeroFloat(20.0f) + this->endFrame; + this->state = DEEP_PYTHON_EXTEND_STATE_REPEAT_SMALL_SWAY; + } + + this->behindJawRetreatTimer++; + if (this->behindJawRetreatTimer > 60) { + this->action = DEEP_PYTHON_ACTION_RETREAT; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_BACK); + EnDragon_SetupRetreatOrIdle(this); + } + } + } +} + +void EnDragon_CameraSetAtEye(EnDragon* this, GlobalContext* globalCtx, Vec3f eye, Vec3f at) { + this->cameraId = ActorCutscene_GetCurrentCamera(this->actor.cutscene); + Math_Vec3f_Copy(&this->cameraEye, &eye); + Math_Vec3f_Copy(&this->cameraAt, &at); + Play_CameraSetAtEye(globalCtx, this->cameraId, &this->cameraAt, &this->cameraEye); +} + +void EnDragon_SetupGrab(EnDragon* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f extendedPos; + s16 yaw; + + if (!ActorCutscene_GetCanPlayNext(this->grabCutsceneIndex)) { + ActorCutscene_SetIntentToPlay(this->grabCutsceneIndex); + } else { + ActorCutscene_StartAndSetUnkLinkFields(this->grabCutsceneIndex, &this->actor); + Math_Vec3f_Copy(&extendedPos, &this->burrowEntrancePos); + extendedPos.x += Math_SinS(this->actor.world.rot.y) * -530.0f; + extendedPos.z += Math_CosS(this->actor.world.rot.y) * -530.0f; + Math_Vec3f_Copy(&this->actor.world.pos, &extendedPos); + yaw = Math_Vec3f_Yaw(&player->actor.world.pos, &this->jawPos); + player->actor.shape.rot.y = yaw; + player->actor.world.rot.y = yaw; + this->state = DEEP_PYTHON_GRAB_STATE_START; + this->grabTimer = 0; + this->hasGrabbedPlayer = false; + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_IDLE); + this->actionFunc = EnDragon_Grab; + } +} + +static Vec3f sCameraEyePerPython[] = { + { 1600.0f, 0.0f, 1400.0f }, { 1400.0f, 0.0f, 400.0f }, { 1800.0f, 0.0f, 1400.f }, { 1100.0f, -200.0f, 1500.0f }, + { 2000.0f, 0.0f, 1500.0f }, { 1900.0f, 0.0f, 1800.0f }, { 1700.0f, 0.0f, 1100.0f }, { 1700.0f, 0.0f, 1100.0f }, +}; + +static Vec3f sCameraAtPerPython[] = { + { 300.0f, -100.0f, 1300.0f }, { 1500.0f, 0.0f, 2400.0f }, { 300.0f, -100.0f, 1300.0f }, { 1900.0f, 500.0f, 600.0f }, + { -1000.0f, 0.0f, 1000.0f }, { 1200.0f, 0.0f, 1500.0f }, { 1100.0f, 0.0f, 2000.0f }, { 1100.0f, 0.0f, 2000.0f }, +}; + +static s16 sZRotPerPython[] = { 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0BB8, 0x0000, 0x0000 }; + +static s32 sMaxGrabTimerPerPython[] = { 5, 5, 5, 4, 5, 8, 5, 5 }; + +void EnDragon_Grab(EnDragon* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + Vec3f sp50; // used as both the extended position and the camera eye + Vec3f at; + + this->cameraId = ActorCutscene_GetCurrentCamera(this->actor.cutscene); + SkelAnime_Update(&this->skelAnime); + + if (this->grabTimer == 0) { + if (!this->hasGrabbedPlayer) { + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerGrabPosition); + Math_Vec3f_Copy(&this->playerGrabPositionTemp, &this->playerGrabPosition); + this->hasGrabbedPlayer = true; + } else { + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerGrabPositionTemp); + } + + Math_Vec3f_Copy(&sp50, &this->burrowEntrancePos); + sp50.x += Math_SinS(this->actor.world.rot.y) * -930.0f; + sp50.z += Math_CosS(this->actor.world.rot.y) * -930.0f; + Math_Vec3f_Copy(&this->actor.world.pos, &sp50); + this->jawZRotation = 0x1450; + this->actor.speedXZ = 60.0f; + } + + this->grabTimer++; + Math_SmoothStepToS(&this->actor.shape.rot.z, sZRotPerPython[this->pythonIndex], 0xA, 0x1F4, 0x14); + EnDragon_SpawnBubbles(this, globalCtx, this->jawPos); + + Math_Vec3f_Copy(&sp50, &this->burrowEntrancePos); + sp50.x += Math_SinS(this->actor.world.rot.y) * sCameraEyePerPython[this->pythonIndex].x; + sp50.y += sCameraEyePerPython[this->pythonIndex].y; + sp50.z += Math_CosS(this->actor.world.rot.y) * sCameraEyePerPython[this->pythonIndex].z; + + Math_Vec3f_Copy(&at, &this->actor.world.pos); + at.x += Math_SinS(this->actor.world.rot.y) * sCameraAtPerPython[this->pythonIndex].x; + at.y += sCameraAtPerPython[this->pythonIndex].y; + at.z += Math_CosS(this->actor.world.rot.y) * sCameraAtPerPython[this->pythonIndex].z; + + EnDragon_CameraSetAtEye(this, globalCtx, sp50, at); + + if (this->grabTimer > sMaxGrabTimerPerPython[this->pythonIndex]) { + if (this->state == DEEP_PYTHON_GRAB_STATE_START) { + func_800B7298(globalCtx, &this->actor, 6); + this->state = DEEP_PYTHON_GRAB_STATE_GRABBED; + } + + globalCtx->unk_18770(globalCtx, player); + player->actor.parent = &this->actor; + player->unk_AE8 = 50; + this->action = DEEP_PYTHON_ACTION_GRAB; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_EAT); + EnDragon_SetupAttack(this); + } +} + +void EnDragon_SetupAttack(EnDragon* this) { + if (this->animationIndex != DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY); + } + + this->behindJawRetreatTimer = 0; + this->grabTimer = 0; + this->state = DEEP_PYTHON_ATTACK_STATE_START; + this->actionFunc = EnDragon_Attack; +} + +void EnDragon_Attack(EnDragon* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + f32 currentFrame = this->skelAnime.curFrame; + Vec3f sp4C; // used as both the extended position and the camera eye + Vec3f at; + + SkelAnime_Update(&this->skelAnime); + Math_SmoothStepToS(&this->actor.shape.rot.z, 0, 0xA, 0x1388, 0); + if ((globalCtx->gameplayFrames % 16) == 0) { + globalCtx->damagePlayer(globalCtx, -2); + + //! @bug: This function should only pass Player*: it uses *(this + 0x153), which is meant to be + //! player->currentMask, but in this case is garbage in the skelAnime + func_800B8E58((Player*)this, player->ageProperties->unk_92 + NA_SE_VO_LI_DAMAGE_S); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_BITE); + CollisionCheck_GreenBlood(globalCtx, NULL, &player->actor.world.pos); + } + + Math_Vec3f_Copy(&sp4C, &this->actor.world.pos); + sp4C.x += Math_SinS(this->actor.world.rot.y) * 3000.0f; + sp4C.y += 600.0f; + sp4C.z += Math_CosS(this->actor.world.rot.y) * 3000.0f; + + Math_Vec3f_Copy(&at, &this->actor.world.pos); + at.x += Math_SinS(this->actor.world.rot.y) * 1200.0f; + at.y += -100.0f; + at.z += Math_CosS(this->actor.world.rot.y) * 1200.0f; + + EnDragon_CameraSetAtEye(this, globalCtx, sp4C, at); + + player->actor.world.rot.y = player->actor.shape.rot.y = this->actor.world.rot.y; + player->actor.world.rot.x = player->actor.shape.rot.x = this->actor.world.rot.x; + player->actor.world.rot.z = player->actor.shape.rot.z = this->actor.world.rot.z - 0x36B0; + Math_Vec3f_Copy(&player->actor.world.pos, &this->playerGrabPosition); + this->jawZRotation = 0xC8; + + Math_Vec3f_Copy(&sp4C, &this->burrowEntrancePos); + sp4C.x += Math_SinS(this->actor.world.rot.y) * -530.0f; + sp4C.z += Math_CosS(this->actor.world.rot.y) * -530.0f; + Math_ApproachF(&this->actor.world.pos.x, sp4C.x, 0.3f, 200.0f); + Math_ApproachF(&this->actor.world.pos.y, sp4C.y, 0.3f, 200.0f); + Math_ApproachF(&this->actor.world.pos.z, sp4C.z, 0.3f, 200.0f); + + if ((this->state <= DEEP_PYTHON_ATTACK_STATE_START) && (this->endFrame <= currentFrame)) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_BITE); + if (this->animationIndex != DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY) { + EnDragon_ChangeAnimation(this, DEEP_PYTHON_ANIMATION_LARGE_SIDE_SWAY); + } + + this->state++; + } + + if (((this->state != DEEP_PYTHON_ATTACK_STATE_START) && (this->endFrame <= currentFrame)) || + (!(player->stateFlags2 & 0x80)) || ((this->collider.elements[0].info.bumperFlags & BUMP_HIT)) || + (this->collider.elements[1].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[2].info.bumperFlags & BUMP_HIT)) { + player->actor.parent = NULL; + this->grabWaitTimer = 30; + ActorCutscene_Stop(this->grabCutsceneIndex); + if (player->stateFlags2 & 0x80) { + player->unk_AE8 = 100; + } + + this->actor.flags &= ~ACTOR_FLAG_100000; + + if ((this->state != DEEP_PYTHON_ATTACK_STATE_START) && (this->endFrame <= currentFrame)) { + this->timer = 3; + this->actionFunc = EnDragon_RetreatOnceTimerEnds; + } else { + EnDragon_SetupRetreatOrIdle(this); + } + } +} + +void EnDragon_SetupDead(EnDragon* this, GlobalContext* globalCtx) { + if (!ActorCutscene_GetCanPlayNext(this->deathCutsceneIndex)) { + ActorCutscene_SetIntentToPlay(this->deathCutsceneIndex); + } else { + ActorCutscene_StartAndSetUnkLinkFields(this->deathCutsceneIndex, &this->actor); + this->endFrame = Animation_GetLastFrame(&gDeepPythonSmallSideSwayAnim); + Animation_Change(&this->skelAnime, &gDeepPythonSmallSideSwayAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, 0.0f); + this->timer = 20; + this->actionFunc = EnDragon_Dead; + } +} + +void EnDragon_Dead(EnDragon* this, GlobalContext* globalCtx) { + Vec3f seahorsePos; + + SkelAnime_Update(&this->skelAnime); + this->actor.shape.rot.z += 0x1000; + this->jawZRotation = 0xFA0; + EnDragon_SpawnBubbles(this, globalCtx, this->jawPos); + + if ((this->timer != 0) && (fabsf(this->actor.world.pos.x - this->actor.home.pos.x) > 121.0f) && + (fabsf(this->actor.world.pos.z - this->actor.home.pos.z) > 121.0f)) { + this->actor.speedXZ = -120.0f; + if (((this->pythonIndex & 1) == 0) && (Rand_ZeroOne() < 0.5f)) { + //! @bug: !globalCtx->gameplayFrames is 0 essentially all the time, so this code never runs. + if (((!globalCtx->gameplayFrames) & 0x1F)) { + Item_DropCollectibleRandom(globalCtx, NULL, &this->jawPos, 0x90); + } + } + + this->action = DEEP_PYTHON_ACTION_DEAD; + return; + } + + this->actor.speedXZ = 0.0f; + if ((fabsf(this->actor.world.pos.x - this->actor.home.pos.x) > 20.0f) && + (fabsf(this->actor.world.pos.z - this->actor.home.pos.z) > 20.0f)) { + Math_ApproachF(&this->actor.world.pos.x, this->actor.home.pos.x, 0.3f, 300.0f); + Math_ApproachF(&this->actor.world.pos.z, this->actor.home.pos.z, 0.3f, 300.0f); + return; + } + + sNumPythonsDead++; + if (sNumPythonsDead >= (BREG(39) + 8)) { + Math_Vec3f_Copy(&seahorsePos, &this->actor.parent->world.pos); + seahorsePos.x += (Math_SinS((this->actor.parent->world.rot.y + 0x8000)) * (500.0f + BREG(38))); + seahorsePos.y += -100.0f + BREG(33); + seahorsePos.z += (Math_CosS((this->actor.parent->world.rot.y + 0x8000)) * (500.0f + BREG(38))); + if (Actor_SpawnAsChildAndCutscene(&globalCtx->actorCtx, globalCtx, ACTOR_EN_OT, seahorsePos.x, seahorsePos.y, + seahorsePos.z, 0, this->actor.shape.rot.y, 0, 0x4000, this->actor.cutscene, + this->actor.unk20, NULL)) { + gSaveContext.save.weekEventReg[13] |= 1; + switch (this->pythonIndex) { + case 0: + gSaveContext.save.weekEventReg[83] |= 0x10; + break; + + case 1: + gSaveContext.save.weekEventReg[83] |= 0x20; + break; + + case 2: + gSaveContext.save.weekEventReg[83] |= 0x40; + break; + + case 3: + gSaveContext.save.weekEventReg[83] |= 0x80; + break; + case 4: + gSaveContext.save.weekEventReg[84] |= 1; + break; + + case 5: + gSaveContext.save.weekEventReg[84] |= 2; + break; + + case 6: + gSaveContext.save.weekEventReg[84] |= 4; + break; + + case 7: + gSaveContext.save.weekEventReg[84] |= 8; + break; + } + } + } + + Actor_MarkForDeath(&this->actor); +} + +void EnDragon_UpdateDamage(EnDragon* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + u32 sp30; + + if ((this->action == DEEP_PYTHON_ACTION_EXTEND)) { + if ((this->collider.elements[2].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[3].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[4].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[5].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[6].info.bumperFlags & BUMP_HIT) || + (this->collider.elements[7].info.bumperFlags & BUMP_HIT)) { + Actor_ApplyDamage(&this->actor); + Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 25); + if (this->actor.colChkInfo.health > 0) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_DAMAGE); + this->action = DEEP_PYTHON_ACTION_DAMAGE; + } else { + Enemy_StartFinishingBlow(globalCtx, &this->actor); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_UTSUBO_DEAD); + this->actor.flags |= ACTOR_FLAG_8000000; + this->actor.flags &= ~ACTOR_FLAG_1; + this->actor.flags |= ACTOR_FLAG_100000; + this->action = DEEP_PYTHON_ACTION_SETUP_DEAD; + this->actionFunc = EnDragon_SetupDead; + } + } + } + + if ((this->action == DEEP_PYTHON_ACTION_EXTEND) && (this->grabWaitTimer == 0) && + (player->invincibilityTimer == 0) && (this->collider.elements[0].info.ocElemFlags & OCELEM_HIT) && + (!(func_800B64FC(globalCtx, 1000.0f, &this->actor.world.pos, &sp30) >= 0.0f) || (sp30 != 1))) { + this->actor.speedXZ = 0.0f; + this->action = DEEP_PYTHON_ACTION_GRAB; + this->actor.flags |= ACTOR_FLAG_100000; + this->actionFunc = EnDragon_SetupGrab; + } +} + +void EnDragon_Update(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnDragon* this = THIS; + + if (this->retreatTimer != 0) { + this->retreatTimer--; + } + + if (this->timer != 0) { + this->timer--; + } + + if (this->largeSwayWaitTimer != 0) { + this->largeSwayWaitTimer--; + } + + if (this->grabWaitTimer != 0) { + this->grabWaitTimer--; + } + + EnDragon_UpdateDamage(this, globalCtx); + this->actor.shape.rot.y = this->actor.world.rot.y; + Math_Vec3f_Copy(&this->actor.focus.pos, &this->focusPos); + Math_Vec3s_Copy(&this->actor.focus.rot, &this->actor.world.rot); + Actor_SetScale(&this->actor, this->scale); + + this->actionFunc(this, globalCtx); + Actor_MoveWithGravity(&this->actor); + + if (this->action != DEEP_PYTHON_ACTION_GRAB) { + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + } + + if (this->action < DEEP_PYTHON_ACTION_DAMAGE) { + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + } +} + +s32 EnDragon_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, + Actor* thisx) { + EnDragon* this = THIS; + + if (limbIndex == DEEP_PYTHON_LIMB_JAW) { + rot->x += this->jawXRotation; + rot->y += this->jawYRotation; + rot->z += this->jawZRotation; + } + + return false; +} + +void EnDragon_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + EnDragon* this = THIS; + Vec3f playerGrabOffsetFromJawPos = { 350.0f, -120.0f, -60.0f }; + + if (limbIndex == DEEP_PYTHON_LIMB_JAW) { + Matrix_MultiplyVector3fByState(&gZeroVec3f, &this->jawPos); + playerGrabOffsetFromJawPos.x = 350.0f; + playerGrabOffsetFromJawPos.y = -120.0f; + playerGrabOffsetFromJawPos.z = -60.0f; + Matrix_MultiplyVector3fByState(&playerGrabOffsetFromJawPos, &this->playerGrabPosition); + } + + if (limbIndex == DEEP_PYTHON_LIMB_HEAD_AND_COLLAR_ROOT) { + Matrix_MultiplyVector3fByState(&gZeroVec3f, &this->focusPos); + } + + Collider_UpdateSpheres(limbIndex, &this->collider); +} + +void EnDragon_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnDragon* this = THIS; + + func_8012C28C(globalCtx->state.gfxCtx); + func_8012C2DC(globalCtx->state.gfxCtx); + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnDragon_OverrideLimbDraw, EnDragon_PostLimbDraw, &this->actor); +} diff --git a/src/overlays/actors/ovl_En_Dragon/z_en_dragon.h b/src/overlays/actors/ovl_En_Dragon/z_en_dragon.h index f228748046..c7ec4d81e3 100644 --- a/src/overlays/actors/ovl_En_Dragon/z_en_dragon.h +++ b/src/overlays/actors/ovl_En_Dragon/z_en_dragon.h @@ -2,16 +2,53 @@ #define Z_EN_DRAGON_H #include "global.h" +#include "objects/object_utubo/object_utubo.h" + +#define EN_DRAGON_GET_PYTHON_INDEX(thisx) (((thisx)->params >> 7) & 0x1F) struct EnDragon; typedef void (*EnDragonActionFunc)(struct EnDragon*, GlobalContext*); typedef struct EnDragon { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x104]; - /* 0x0248 */ EnDragonActionFunc actionFunc; - /* 0x024C */ char unk_24C[0x2B0]; + /* 0x000 */ Actor actor; + /* 0x144 */ SkelAnime skelAnime; + /* 0x188 */ Vec3s jointTable[DEEP_PYTHON_LIMB_MAX]; + /* 0x1E8 */ Vec3s morphTable[DEEP_PYTHON_LIMB_MAX]; + /* 0x248 */ EnDragonActionFunc actionFunc; + /* 0x24C */ s32 animationIndex; + /* 0x250 */ s32 pythonIndex; + /* 0x254 */ Vec3f jawPos; + /* 0x260 */ Vec3f burrowEntrancePos; // Vertically and horizontally centered on the burrow opening. Set by Bg_Sinkai_Kabe + /* 0x26C */ Vec3f playerGrabPosition; + /* 0x278 */ Vec3f cameraEye; + /* 0x278 */ Vec3f cameraAt; + /* 0x290 */ Vec3f playerGrabPositionTemp; + /* 0x29C */ Vec3f focusPos; + /* 0x2A8 */ s16 jawZRotation; + /* 0x2AA */ s16 jawYRotation; // Never initialized by the actor + /* 0x2AC */ s16 jawXRotation; // Never initialized by the actor + /* 0x2AE */ s16 retreatTimer; // If the Deep Python is extended and this timer reaches 0, it is forced to retreat back to its burrow + /* 0x2B0 */ s16 behindJawRetreatTimer; // If the player is behind the jaw, then this will count up. When it reaches 60, the Deep Python will retreat + /* 0x2B2 */ s16 largeSwayWaitTimer; // If the player is in front of the jaw, it won't play or replay the large sway animation unless this is zero. + /* 0x2B4 */ s16 timer; + /* 0x2B6 */ s16 grabWaitTimer; // Cannot grab the player if this is non-zero + /* 0x2B8 */ s16 hasGrabbedPlayer; + /* 0x2BA */ s16 action; + /* 0x2BC */ UNK_TYPE1 unk_2BC[0x2]; + /* 0x2BE */ s16 state; + /* 0x2C0 */ s16 grabCutsceneIndex; + /* 0x2C2 */ s16 deathCutsceneIndex; + /* 0x2C4 */ UNK_TYPE1 unk_2C4[0x4]; + /* 0x2C8 */ s16 cameraId; + /* 0x2CA */ s16 grabTimer; // Counts up from the time a grab starts until the time the actor begins attacking + /* 0x2CC */ s16 unk_2CC; // Initialized, but never used + /* 0x2CE */ UNK_TYPE1 unk_2CE[0x2]; + /* 0x2D0 */ f32 endFrame; + /* 0x2D4 */ f32 scale; + /* 0x2D8 */ UNK_TYPE1 unk_2D8[0x4]; + /* 0x2DC */ ColliderJntSph collider; + /* 0x2FC */ ColliderJntSphElement colliderElements[8]; } EnDragon; // size = 0x4FC extern const ActorInit En_Dragon_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 72fadfea59..e9443093b0 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -14130,24 +14130,24 @@ 0x80B5E1D8:("func_80B5E1D8",), 0x80B5E890:("EnDragon_Init",), 0x80B5EA74:("EnDragon_Destroy",), - 0x80B5EAA0:("func_80B5EAA0",), - 0x80B5EB40:("func_80B5EB40",), - 0x80B5ED90:("func_80B5ED90",), - 0x80B5EDF0:("func_80B5EDF0",), - 0x80B5EE3C:("func_80B5EE3C",), - 0x80B5EF88:("func_80B5EF88",), - 0x80B5EFD0:("func_80B5EFD0",), - 0x80B5F3A4:("func_80B5F3A4",), - 0x80B5F418:("func_80B5F418",), - 0x80B5F508:("func_80B5F508",), - 0x80B5F888:("func_80B5F888",), - 0x80B5F8D8:("func_80B5F8D8",), - 0x80B5FCC0:("func_80B5FCC0",), - 0x80B5FD68:("func_80B5FD68",), - 0x80B60138:("func_80B60138",), + 0x80B5EAA0:("EnDragon_ChangeAnimation",), + 0x80B5EB40:("EnDragon_SpawnBubbles",), + 0x80B5ED90:("EnDragon_RetreatOnceTimerEnds",), + 0x80B5EDF0:("EnDragon_SetupRetreatOrIdle",), + 0x80B5EE3C:("EnDragon_RetreatOrIdle",), + 0x80B5EF88:("EnDragon_SetupExtend",), + 0x80B5EFD0:("EnDragon_Extend",), + 0x80B5F3A4:("EnDragon_CameraSetAtEye",), + 0x80B5F418:("EnDragon_SetupGrab",), + 0x80B5F508:("EnDragon_Grab",), + 0x80B5F888:("EnDragon_SetupAttack",), + 0x80B5F8D8:("EnDragon_Attack",), + 0x80B5FCC0:("EnDragon_SetupDead",), + 0x80B5FD68:("EnDragon_Dead",), + 0x80B60138:("EnDragon_UpdateDamage",), 0x80B6031C:("EnDragon_Update",), - 0x80B6043C:("func_80B6043C",), - 0x80B60494:("func_80B60494",), + 0x80B6043C:("EnDragon_OverrideLimbDraw",), + 0x80B60494:("EnDragon_PostLimbDraw",), 0x80B60564:("EnDragon_Draw",), 0x80B60AD0:("ObjDora_Init",), 0x80B60C70:("ObjDora_Destroy",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index 4fac6bb9e8..c96b82408f 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -14800,15 +14800,10 @@ 0x80B60754:("D_80B60754","UNK_TYPE1","",0x1), 0x80B60758:("D_80B60758","UNK_TYPE1","",0x1), 0x80B60764:("D_80B60764","UNK_TYPE1","",0x1), - 0x80B60770:("D_80B60770","f32","",0x4), - 0x80B60774:("D_80B60774","f32","",0x4), - 0x80B60778:("D_80B60778","f32","",0x4), - 0x80B6077C:("D_80B6077C","UNK_TYPE1","",0x1), - 0x80B60780:("D_80B60780","f32","",0x4), - 0x80B60788:("D_80B60788","UNK_TYPE1","",0x1), - 0x80B60790:("D_80B60790","f32","",0x4), - 0x80B607E8:("D_80B607E8","UNK_TYPE1","",0x1), - 0x80B607F0:("D_80B607F0","f32","",0x4), + 0x80B60770:("D_80B60770","Vec3f","",0xC), + 0x80B6077C:("D_80B6077C","Vec3f","",0xC), + 0x80B60788:("D_80B60788","Vec3f","[8]",0x60), + 0x80B607E8:("D_80B607E8","Vec3f","[8]",0x60), 0x80B60848:("D_80B60848","UNK_TYPE1","",0x1), 0x80B60858:("D_80B60858","UNK_TYPE1","",0x1), 0x80B60878:("D_80B60878","UNK_TYPE4","",0x4), diff --git a/undefined_syms.txt b/undefined_syms.txt index d426e04819..5852e813c1 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -1136,11 +1136,6 @@ D_0600D640 = 0x0600D640; D_06002950 = 0x06002950; -// ovl_En_Dragon - -D_06004398 = 0x06004398; -D_060048B8 = 0x060048B8; - // ovl_En_Ds2n D_06008038 = 0x06008038;