From c3c08e944cc9548726b73a0d699ede34ba4e1017 Mon Sep 17 00:00:00 2001 From: Tom Overton Date: Sat, 1 Oct 2022 08:14:06 -0700 Subject: [PATCH] EnWiz (Wizrobe) OK and documented, EnWizFire (Wizrobe Magic) documented, object_wiz documented (#1054) * Good start * Limb draw stuff OK * A ton more functions * func_80A477E8 OK * func_80A456A0 OK * func_80A460A4 OK * func_80A46990 OK * func_80A46414 OK * EnWiz_Update OK * func_80A45CD8 OK Co-authored-by: petrie911 * EnWiz_Draw OK * Use generated reloc and object symbols * Document object stuff related to Wizzrobe itself * Some more names * A bunch more names * Name even more stuff (sensing a pattern?) * Document damage tables and damage effects * Bunch of stuff mostly related to ghosts * Name all struct vars and functions * Fix WizFire build issue * Split up dmgFlags * Apparently it's spelled "Wizrobe" in this game * Name all assets EXCEPT the ones used by wiz_fire * Apparently, the blob is vertices * Name all remaining variables * Some function comments * (Probably) the final touches on EnWiz docs before PR * Name a ton of stuff in EnWizFire * Finish naming everything in EnWizFire * Finish documentation * Respond to Engineer's clean-up review * Respond to Anghelo's first review * Use TATL_HINT_ID enum * Enum comments for animations, and better names for some damage effects * Fix build after merging master * Respond to Elliptic's review * Define INITIAL_CUR_PLATFORM_INDEX * Drop _CUR_ from the name * Rename one of the enum values * Respond to Elliptic's WizFire review * Every switch has a default --- assets/xml/objects/object_wiz.xml | 242 ++- spec | 3 +- src/overlays/actors/ovl_En_Fz/z_en_fz.c | 4 +- src/overlays/actors/ovl_En_Wiz/z_en_wiz.c | 1607 +++++++++++++++-- src/overlays/actors/ovl_En_Wiz/z_en_wiz.h | 73 +- .../actors/ovl_En_Wiz_Brock/z_en_wiz_brock.c | 33 +- .../actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h | 11 +- .../actors/ovl_En_Wiz_Fire/z_en_wiz_fire.c | 716 ++++---- .../actors/ovl_En_Wiz_Fire/z_en_wiz_fire.h | 83 +- tools/disasm/functions.txt | 72 +- tools/disasm/variables.txt | 32 +- undefined_syms.txt | 8 - 12 files changed, 2178 insertions(+), 706 deletions(-) diff --git a/assets/xml/objects/object_wiz.xml b/assets/xml/objects/object_wiz.xml index 2928083aa2..51fcae3a79 100644 --- a/assets/xml/objects/object_wiz.xml +++ b/assets/xml/objects/object_wiz.xml @@ -1,102 +1,148 @@  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec b/spec index b4a8a61082..9ad5e4cca9 100644 --- a/spec +++ b/spec @@ -2715,8 +2715,7 @@ beginseg name "ovl_En_Wiz" compress include "build/src/overlays/actors/ovl_En_Wiz/z_en_wiz.o" - include "build/data/ovl_En_Wiz/ovl_En_Wiz.data.o" - include "build/data/ovl_En_Wiz/ovl_En_Wiz.reloc.o" + include "build/src/overlays/actors/ovl_En_Wiz/ovl_En_Wiz_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Fz/z_en_fz.c b/src/overlays/actors/ovl_En_Fz/z_en_fz.c index 198166b007..58d5a6f5fc 100644 --- a/src/overlays/actors/ovl_En_Fz/z_en_fz.c +++ b/src/overlays/actors/ovl_En_Fz/z_en_fz.c @@ -241,10 +241,10 @@ void EnFz_Destroy(Actor* thisx, PlayState* play) { Collider_DestroyCylinder(play, &this->collider3); if ((this->actor.parent != NULL) && (this->unk_BC4 == 0) && (this->actor.parent->id == ACTOR_EN_WIZ) && - (this->actor.parent->update != NULL) && (((EnWiz*)this->actor.parent)->unk_448 != 0)) { + (this->actor.parent->update != NULL) && (((EnWiz*)this->actor.parent)->freezard != NULL)) { EnWiz* wiz = (EnWiz*)this->actor.parent; - wiz->unk_448 = 0; + wiz->freezard = NULL; } } diff --git a/src/overlays/actors/ovl_En_Wiz/z_en_wiz.c b/src/overlays/actors/ovl_En_Wiz/z_en_wiz.c index 82cc5f2e27..0abf1fe565 100644 --- a/src/overlays/actors/ovl_En_Wiz/z_en_wiz.c +++ b/src/overlays/actors/ovl_En_Wiz/z_en_wiz.c @@ -1,10 +1,12 @@ /* * File: z_en_wiz.c * Overlay: ovl_En_Wiz - * Description: Wizzrobe + * Description: Wizrobe */ #include "z_en_wiz.h" +#include "objects/gameplay_keep/gameplay_keep.h" +#include "overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h" #define FLAGS \ (ACTOR_FLAG_1 | ACTOR_FLAG_4 | ACTOR_FLAG_10 | ACTOR_FLAG_20 | ACTOR_FLAG_1000 | ACTOR_FLAG_100000 | \ @@ -17,7 +19,67 @@ void EnWiz_Destroy(Actor* thisx, PlayState* play); void EnWiz_Update(Actor* thisx, PlayState* play); void EnWiz_Draw(Actor* thisx, PlayState* play); -#if 0 +void EnWiz_StartIntroCutscene(EnWiz* this, PlayState* play); +void EnWiz_SetupAppear(EnWiz* this, PlayState* play); +void EnWiz_Appear(EnWiz* this, PlayState* play); +void EnWiz_SetupDance(EnWiz* this); +void EnWiz_Dance(EnWiz* this, PlayState* play); +void EnWiz_SetupSecondPhaseCutscene(EnWiz* this, PlayState* play); +void EnWiz_SecondPhaseCutscene(EnWiz* this, PlayState* play); +void EnWiz_SetupWindUp(EnWiz* this); +void EnWiz_WindUp(EnWiz* this, PlayState* play); +void EnWiz_SetupAttack(EnWiz* this); +void EnWiz_Attack(EnWiz* this, PlayState* play); +void EnWiz_SetupDisappear(EnWiz* this); +void EnWiz_Disappear(EnWiz* this, PlayState* play); +void EnWiz_Damaged(EnWiz* this, PlayState* play); +void EnWiz_SetupDead(EnWiz* this); +void EnWiz_Dead(EnWiz* this, PlayState* play); + +// This number is almost-entirely arbirary, with the only requirement being +// that cannot be a valid curPlatformIndex. Any negative number, or any number +// larger than 10, would work just as well. +#define INITIAL_PLATFORM_INDEX 777 + +typedef enum { + /* 1 */ EN_WIZ_ACTION_APPEAR = 1, + /* 2 */ EN_WIZ_ACTION_RUN_BETWEEN_PLATFORMS, + /* 3 */ EN_WIZ_ACTION_DISAPPEAR, + /* 4 */ EN_WIZ_ACTION_DAMAGED, + /* 5 */ EN_WIZ_ACTION_DEAD, + /* 6 */ EN_WIZ_ACTION_BURST_INTO_FLAMES, + /* 7 */ EN_WIZ_ACTION_RUN_IN_CIRCLES, + /* 8 */ EN_WIZ_ACTION_ATTACK, + /* 9 */ EN_WIZ_ACTION_DANCE, +} EnWizAction; + +typedef enum { + /* 0 */ EN_WIZ_INTRO_CS_NOT_STARTED, + /* 1 */ EN_WIZ_INTRO_CS_CAMERA_MOVE_TO_PLATFORM, + /* 2 */ EN_WIZ_INTRO_CS_APPEAR, + /* 3 */ EN_WIZ_INTRO_CS_CAMERA_SPIN_TO_FACE_WIZROBE, + /* 4 */ EN_WIZ_INTRO_CS_WAIT_BEFORE_RUN, + /* 5 */ EN_WIZ_INTRO_CS_RUN_IN_CIRCLES, + /* 6 */ EN_WIZ_INTRO_CS_DISAPPEAR, + /* 7 */ EN_WIZ_INTRO_CS_END +} EnWizIntroCutsceneState; + +typedef enum { + /* 0 */ EN_WIZ_FIGHT_STATE_FIRST_PHASE, + /* 1 */ EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE, + /* 2 */ EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_COPY_WIZROBE, + /* 3 */ EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND, +} EnWizFightState; + +typedef enum { + /* 0 */ EN_WIZ_ANIM_IDLE, + /* 1 */ EN_WIZ_ANIM_RUN, + /* 2 */ EN_WIZ_ANIM_DANCE, + /* 3 */ EN_WIZ_ANIM_WIND_UP, + /* 4 */ EN_WIZ_ANIM_ATTACK, + /* 5 */ EN_WIZ_ANIM_DAMAGE, +} EnWizAnimation; + const ActorInit En_Wiz_InitVars = { ACTOR_EN_WIZ, ACTORCAT_ENEMY, @@ -30,199 +92,1470 @@ const ActorInit En_Wiz_InitVars = { (ActorFunc)EnWiz_Draw, }; -// static ColliderJntSphElementInit sJntSphElementsInit[10] = { -static ColliderJntSphElementInit D_80A48B50[10] = { +static ColliderJntSphElementInit sJntSphElementsInit[10] = { { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0x01000202, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 1 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0x01000202, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 1 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, - { 1, { { 0, 0, 0 }, 0 }, 0 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, + { WIZROBE_LIMB_PELVIS, { { 0, 0, 0 }, 0 }, 0 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_80A48CB8 = { - { COLTYPE_HIT2, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_NONE, OC2_TYPE_1, COLSHAPE_JNTSPH, }, - ARRAY_COUNT(sJntSphElementsInit), D_80A48B50, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_HIT2, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_NONE, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + ARRAY_COUNT(sJntSphElementsInit), + sJntSphElementsInit, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80A48CC8 = { - { COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x08, 0x04 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_NONE, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x08, 0x04 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 35, 130, 0, { 0, 0, 0 } }, }; -// static DamageTable sDamageTable = { -static DamageTable D_80A48CF4 = { - /* Deku Nut */ DMG_ENTRY(0, 0x1), - /* Deku Stick */ DMG_ENTRY(1, 0xF), - /* Horse trample */ DMG_ENTRY(0, 0x0), - /* Explosives */ DMG_ENTRY(1, 0xF), - /* Zora boomerang */ DMG_ENTRY(1, 0xF), - /* Normal arrow */ DMG_ENTRY(1, 0xF), - /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0), - /* Hookshot */ DMG_ENTRY(1, 0xF), - /* Goron punch */ DMG_ENTRY(1, 0xF), - /* Sword */ DMG_ENTRY(1, 0xF), - /* Goron pound */ DMG_ENTRY(3, 0xF), - /* Fire arrow */ DMG_ENTRY(1, 0x2), - /* Ice arrow */ DMG_ENTRY(2, 0x3), - /* Light arrow */ DMG_ENTRY(2, 0x4), - /* Goron spikes */ DMG_ENTRY(0, 0x0), - /* Deku spin */ DMG_ENTRY(1, 0xF), - /* Deku bubble */ DMG_ENTRY(1, 0xF), - /* Deku launch */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x1), - /* Zora barrier */ DMG_ENTRY(0, 0x0), - /* Normal shield */ DMG_ENTRY(0, 0x0), - /* Light ray */ DMG_ENTRY(0, 0x0), - /* Thrown object */ DMG_ENTRY(1, 0xF), - /* Zora punch */ DMG_ENTRY(1, 0xF), - /* Spin attack */ DMG_ENTRY(1, 0xF), - /* 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 */ EN_WIZ_DMGEFF_IMMUNE, // Deals no damage + /* 0x1 */ EN_WIZ_DMGEFF_UNK1, // Deals no damage. Was probably originally intended for destroying ghosts. + /* 0x2 */ EN_WIZ_DMGEFF_FIRE, // Damages and sets Ice Wizrobes on fire + /* 0x3 */ EN_WIZ_DMGEFF_FREEZE, // Damages and surrounds Fire Wizrobes with ice + /* 0x4 */ EN_WIZ_DMGEFF_LIGHT_ORB, // Damages and surrounds the Wizrobe with light orbs + /* 0xF */ EN_WIZ_DMGEFF_NONE = 0xF, // Deals regular damage and has no special effect +} EnWizDamageEffect; + +static DamageTable sFireWizrobeDamageTable = { + /* Deku Nut */ DMG_ENTRY(0, EN_WIZ_DMGEFF_UNK1), + /* Deku Stick */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Horse trample */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Explosives */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Zora boomerang */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Normal arrow */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* UNK_DMG_D_06 */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Hookshot */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Goron punch */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Sword */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Goron pound */ DMG_ENTRY(3, EN_WIZ_DMGEFF_NONE), + /* Fire arrow */ DMG_ENTRY(1, EN_WIZ_DMGEFF_FIRE), + /* Ice arrow */ DMG_ENTRY(2, EN_WIZ_DMGEFF_FREEZE), + /* Light arrow */ DMG_ENTRY(2, EN_WIZ_DMGEFF_LIGHT_ORB), + /* Goron spikes */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Deku spin */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Deku bubble */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Deku launch */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x12 */ DMG_ENTRY(0, EN_WIZ_DMGEFF_UNK1), + /* Zora barrier */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Normal shield */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Light ray */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Thrown object */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Zora punch */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Spin attack */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Sword beam */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Normal Roll */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1B */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1C */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Unblockable */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1E */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Powder Keg */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), }; -// static DamageTable sDamageTable = { -static DamageTable D_80A48D14 = { - /* Deku Nut */ DMG_ENTRY(0, 0x1), - /* Deku Stick */ DMG_ENTRY(1, 0xF), - /* Horse trample */ DMG_ENTRY(0, 0x0), - /* Explosives */ DMG_ENTRY(1, 0xF), - /* Zora boomerang */ DMG_ENTRY(1, 0xF), - /* Normal arrow */ DMG_ENTRY(1, 0xF), - /* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0), - /* Hookshot */ DMG_ENTRY(1, 0xF), - /* Goron punch */ DMG_ENTRY(2, 0xF), - /* Sword */ DMG_ENTRY(1, 0xF), - /* Goron pound */ DMG_ENTRY(3, 0xF), - /* Fire arrow */ DMG_ENTRY(2, 0x2), - /* Ice arrow */ DMG_ENTRY(1, 0x3), - /* Light arrow */ DMG_ENTRY(2, 0x4), - /* Goron spikes */ DMG_ENTRY(0, 0x0), - /* Deku spin */ DMG_ENTRY(1, 0xF), - /* Deku bubble */ DMG_ENTRY(1, 0xF), - /* Deku launch */ DMG_ENTRY(0, 0x0), - /* UNK_DMG_0x12 */ DMG_ENTRY(0, 0x1), - /* Zora barrier */ DMG_ENTRY(0, 0x0), - /* Normal shield */ DMG_ENTRY(0, 0x0), - /* Light ray */ DMG_ENTRY(0, 0x0), - /* Thrown object */ DMG_ENTRY(1, 0xF), - /* Zora punch */ DMG_ENTRY(1, 0xF), - /* Spin attack */ DMG_ENTRY(1, 0xF), - /* 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), +static DamageTable sIceWizrobeDamageTable = { + /* Deku Nut */ DMG_ENTRY(0, EN_WIZ_DMGEFF_UNK1), + /* Deku Stick */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Horse trample */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Explosives */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Zora boomerang */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Normal arrow */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* UNK_DMG_D_06 */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Hookshot */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Goron punch */ DMG_ENTRY(2, EN_WIZ_DMGEFF_NONE), + /* Sword */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Goron pound */ DMG_ENTRY(3, EN_WIZ_DMGEFF_NONE), + /* Fire arrow */ DMG_ENTRY(2, EN_WIZ_DMGEFF_FIRE), + /* Ice arrow */ DMG_ENTRY(1, EN_WIZ_DMGEFF_FREEZE), + /* Light arrow */ DMG_ENTRY(2, EN_WIZ_DMGEFF_LIGHT_ORB), + /* Goron spikes */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Deku spin */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Deku bubble */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Deku launch */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x12 */ DMG_ENTRY(0, EN_WIZ_DMGEFF_UNK1), + /* Zora barrier */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Normal shield */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Light ray */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Thrown object */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Zora punch */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Spin attack */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), + /* Sword beam */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Normal Roll */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1B */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1C */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Unblockable */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* UNK_DMG_0x1E */ DMG_ENTRY(0, EN_WIZ_DMGEFF_IMMUNE), + /* Powder Keg */ DMG_ENTRY(1, EN_WIZ_DMGEFF_NONE), }; -#endif +void EnWiz_Init(Actor* thisx, PlayState* play) { + s32 pad; + EnWiz* this = THIS; -extern ColliderJntSphElementInit D_80A48B50[10]; -extern ColliderJntSphInit D_80A48CB8; -extern ColliderCylinderInit D_80A48CC8; -extern DamageTable D_80A48CF4; -extern DamageTable D_80A48D14; + SkelAnime_InitFlex(play, &this->skelAnime, &gWizrobeSkel, &gWizrobeIdleAnim, this->jointTable, this->morphTable, + WIZROBE_LIMB_MAX); + SkelAnime_InitFlex(play, &this->ghostSkelAnime, &gWizrobeSkel, &gWizrobeIdleAnim, this->ghostBaseJointTable, + this->ghostMorphTable, WIZROBE_LIMB_MAX); + Actor_SetScale(&this->actor, 0.0f); + this->platformLightAlpha = 0; + this->alpha = 255; + this->actor.colChkInfo.mass = MASS_IMMOVABLE; + this->actor.targetMode = 3; + this->unk_450 = 1.0f; + this->actor.shape.yOffset = 700.0f; + Collider_InitAndSetJntSph(play, &this->ghostColliders, &this->actor, &sJntSphInit, this->ghostColliderElements); + Collider_InitAndSetCylinder(play, &this->collider, &this->actor, &sCylinderInit); + this->staffFlameScroll = Rand_S16Offset(0, 7); + this->switchFlag = EN_WIZ_GET_SWITCHFLAG(&this->actor); + this->type = EN_WIZ_GET_TYPE(&this->actor); -extern UNK_TYPE D_0600211C; -extern UNK_TYPE D_060025F0; -extern UNK_TYPE D_060066C0; + if (this->switchFlag == 0x7F) { + this->switchFlag = -1; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/EnWiz_Init.s") + if ((this->type == EN_WIZ_TYPE_FIRE) || (this->type == EN_WIZ_TYPE_FIRE_NO_BGM)) { + this->actor.colChkInfo.damageTable = &sFireWizrobeDamageTable; + this->actor.colChkInfo.health = 8; + this->actor.flags &= ~ACTOR_FLAG_100000; + } else { + this->actor.colChkInfo.damageTable = &sIceWizrobeDamageTable; + this->actor.colChkInfo.health = 6; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/EnWiz_Destroy.s") + if ((this->switchFlag >= 0) && (Flags_GetSwitch(play, this->switchFlag))) { + Actor_MarkForDeath(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A455C4.s") + this->actor.hintId = TATL_HINT_ID_WIZROBE; + this->curPlatformIndex = INITIAL_PLATFORM_INDEX; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A456A0.s") + // Setting the radius and scale to zero here effectively disables all of the ghost colliders. + this->ghostColliders.elements[0].dim.modelSphere.radius = 0; + this->ghostColliders.elements[0].dim.scale = 0.0f; + this->ghostColliders.elements[0].dim.modelSphere.center.x = 0; + this->ghostColliders.elements[0].dim.modelSphere.center.y = 0; + this->ghostColliders.elements[0].dim.modelSphere.center.z = 0; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A45CD8.s") + this->actionFunc = EnWiz_StartIntroCutscene; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A460A4.s") +void EnWiz_Destroy(Actor* thisx, PlayState* play) { + s32 pad; + EnWiz* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46280.s") + Collider_DestroyCylinder(play, &this->collider); + Collider_DestroyJntSph(play, &this->ghostColliders); + if (this->type != EN_WIZ_TYPE_FIRE_NO_BGM) { + Audio_RestorePrevBgm(); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A462F8.s") +static AnimationHeader* sAnimations[] = { + &gWizrobeIdleAnim, // EN_WIZ_ANIM_IDLE + &gWizrobeRunAnim, // EN_WIZ_ANIM_RUN + &gWizrobeDanceAnim, // EN_WIZ_ANIM_DANCE + &gWizrobeWindUpAnim, // EN_WIZ_ANIM_WIND_UP + &gWizrobeAttackAnim, // EN_WIZ_ANIM_ATTACK + &gWizrobeDamageAnim, // EN_WIZ_ANIM_DAMAGE +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46414.s") +static u8 sAnimationModes[] = { + ANIMMODE_LOOP, // EN_WIZ_ANIM_IDLE + ANIMMODE_LOOP, // EN_WIZ_ANIM_RUN + ANIMMODE_LOOP, // EN_WIZ_ANIM_DANCE + ANIMMODE_LOOP, // EN_WIZ_ANIM_WIND_UP + ANIMMODE_LOOP, // EN_WIZ_ANIM_ATTACK + ANIMMODE_ONCE, // EN_WIZ_ANIM_DAMAGE +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A4668C.s") +void EnWiz_ChangeAnim(EnWiz* this, s32 animIndex, s32 updateGhostAnim) { + this->endFrame = Animation_GetLastFrame(sAnimations[animIndex]); + Animation_Change(&this->skelAnime, sAnimations[animIndex], 1.0f, 0.0f, this->endFrame, sAnimationModes[animIndex], + -2.0f); + if (updateGhostAnim) { + Animation_Change(&this->ghostSkelAnime, sAnimations[animIndex], 1.0f, 0.0f, this->endFrame, + sAnimationModes[animIndex], -2.0f); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46764.s") +/** + * Responsible for moving the camera around and making the Wizrobe run in circles during the intro cutscene. + */ +void EnWiz_HandleIntroCutscene(EnWiz* this, PlayState* play) { + Camera* subCam; + Vec3f eyeNext; + Vec3f atNext; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A468CC.s") + if (this->introCutsceneState < EN_WIZ_INTRO_CS_DISAPPEAR) { + subCam = Play_GetCamera(play, this->subCamId); + switch (this->introCutsceneState) { + case EN_WIZ_INTRO_CS_NOT_STARTED: + this->introCutsceneTimer = 100; + this->introCutsceneCameraAngle = this->actor.world.rot.y; + this->introCutsceneState++; + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46990.s") + case EN_WIZ_INTRO_CS_CAMERA_MOVE_TO_PLATFORM: + Math_Vec3f_Copy(&eyeNext, &this->actor.world.pos); + Math_Vec3f_Copy(&atNext, &this->actor.world.pos); + eyeNext.x += Math_SinS(this->introCutsceneCameraAngle) * 200.0f; + eyeNext.y += 100.0f; + eyeNext.z += Math_CosS(this->introCutsceneCameraAngle) * 200.0f; + atNext.y += 80.0f; + Math_ApproachF(&subCam->eye.x, eyeNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->eye.z, eyeNext.z, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.x, atNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.z, atNext.z, 0.3f, 30.0f); + subCam->eye.y = eyeNext.y; + subCam->at.y = atNext.y; + if ((fabsf(subCam->eye.x - eyeNext.x) < 2.0f) && (fabsf(subCam->eye.y - eyeNext.y) < 2.0f) && + (fabsf(subCam->eye.z - eyeNext.z) < 2.0f) && (fabsf(subCam->at.x - atNext.x) < 2.0f) && + (fabsf(subCam->at.y - atNext.y) < 2.0f) && (fabsf(subCam->at.z - atNext.z) < 2.0f)) { + Player* player = GET_PLAYER(play); + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46C88.s") + this->actor.world.rot.y = this->actor.shape.rot.y = + Math_Vec3f_Yaw(&this->actor.world.pos, &player->actor.world.pos); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46CC4.s") + for (i = 0; i < this->platformCount; i++) { + this->ghostRot[i].y = Math_Vec3f_Yaw(&this->ghostPos[i], &player->actor.world.pos); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46DDC.s") + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_IDLE, true); + this->shouldStartTimer = false; + this->targetPlatformLightAlpha = 255; + Math_Vec3f_Copy(&this->platformLightPos, &this->actor.world.pos); + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_UNARI); + } else { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_VOICE - SFX_FLAG); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A46E24.s") + this->introCutsceneTimer = 40; + this->introCutsceneState++; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A47000.s") + case EN_WIZ_INTRO_CS_APPEAR: + if (this->introCutsceneTimer == 0) { + this->introCutsceneTimer = 20; + this->introCutsceneState++; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A470D8.s") + case EN_WIZ_INTRO_CS_CAMERA_SPIN_TO_FACE_WIZROBE: + Math_Vec3f_Copy(&eyeNext, &this->actor.world.pos); + Math_Vec3f_Copy(&atNext, &this->actor.world.pos); + eyeNext.x += Math_SinS(this->actor.world.rot.y) * 160.0f; + eyeNext.y += 70.0f; + eyeNext.z += Math_CosS(this->actor.world.rot.y) * 140.0f; + atNext.x += -10.0f; + atNext.y += 100.0f; + Math_ApproachF(&subCam->eye.x, eyeNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->eye.z, eyeNext.z, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.x, atNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.z, atNext.z, 0.3f, 30.0f); + subCam->eye.y = eyeNext.y; + subCam->at.y = atNext.y; + if (this->introCutsceneTimer == 0) { + this->introCutsceneTimer = 10; + this->introCutsceneState++; + this->introCutsceneCameraAngle = this->actor.world.rot.y; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A47298.s") + case EN_WIZ_INTRO_CS_WAIT_BEFORE_RUN: + if (this->introCutsceneTimer == 0) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_RUN, false); + this->rotationalVelocity = 0; + this->introCutsceneTimer = 34; + this->introCutsceneState++; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A473B8.s") + case EN_WIZ_INTRO_CS_RUN_IN_CIRCLES: + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_RUN - SFX_FLAG); + if (this->introCutsceneTimer == 0) { + this->animLoopCounter = this->introCutsceneCameraAngle = 0; + this->introCutsceneState = EN_WIZ_INTRO_CS_DISAPPEAR; + } else { + Math_SmoothStepToS(&this->rotationalVelocity, 0x1388, 0x64, 0x3E8, 0x3E8); + this->actor.world.rot.y += this->rotationalVelocity; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A4767C.s") + Math_Vec3f_Copy(&eyeNext, &this->actor.world.pos); + Math_Vec3f_Copy(&atNext, &this->actor.world.pos); + eyeNext.x += Math_SinS(this->introCutsceneCameraAngle) * 200.0f; + eyeNext.y += 100.0f; + eyeNext.z += Math_CosS(this->introCutsceneCameraAngle) * 200.0f; + atNext.y += 80.0f; + Math_ApproachF(&subCam->eye.x, eyeNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->eye.z, eyeNext.z, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.x, atNext.x, 0.3f, 30.0f); + Math_ApproachF(&subCam->at.z, atNext.z, 0.3f, 30.0f); + subCam->eye.y = eyeNext.y; + subCam->at.y = atNext.y; + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A476C8.s") + default: + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A477E8.s") + if (this->musicStartTimer < 11) { + this->musicStartTimer++; + if ((this->type != EN_WIZ_TYPE_FIRE_NO_BGM) && (this->musicStartTimer == 11)) { + Audio_PlayBgm_StorePrevBgm(NA_BGM_MINI_BOSS); + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/EnWiz_Update.s") +/** + * Chooses which platform the Wizrobe should appear at, and updates its position accordingly. + * It also updates the position and alpha of all the ghosts. + */ +void EnWiz_SelectPlatform(EnWiz* this, PlayState* play) { + Actor* prop; + s32 i; + s32 j; + s16 ghostAlpha; + s16 type; + s16 curPlatformIndex; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A47FCC.s") + for (i = 0; i < ARRAY_COUNT(this->platforms); i++) { + this->platforms[i] = NULL; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/func_80A48138.s") + prop = play->actorCtx.actorLists[ACTORCAT_PROP].first; + i = 0; + while (prop != NULL) { + if (prop->id != ACTOR_EN_WIZ_BROCK) { + prop = prop->next; + continue; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wiz/EnWiz_Draw.s") + this->platforms[i] = prop; + i++; + if (this->action != EN_WIZ_ACTION_BURST_INTO_FLAMES) { + type = this->type; + if (type == EN_WIZ_TYPE_FIRE_NO_BGM) { + type = EN_WIZ_TYPE_FIRE; + } + + prop->colChkInfo.health = type + EN_WIZ_BROCK_PLATFORM_TYPE_FIRE; + prop = prop->next; + } else { + prop->colChkInfo.health = EN_WIZ_BROCK_PLATFORM_TYPE_INACTIVE; + prop = prop->next; + } + } + + if (this->action != EN_WIZ_ACTION_DEAD) { + this->platformCount = i; + if (i < 0) { + i = 0; + } else if (this->platformCount > 10) { + this->platformCount = 10; + } + + curPlatformIndex = Rand_ZeroFloat(i); + while ((this->curPlatformIndex == curPlatformIndex) || ((s16)i == curPlatformIndex)) { + curPlatformIndex = Rand_ZeroFloat(i); + if (1) {} + } + + this->curPlatformIndex = curPlatformIndex; + switch (this->fightState) { + case EN_WIZ_FIGHT_STATE_FIRST_PHASE: + Math_Vec3f_Copy(&this->actor.world.pos, &this->platforms[curPlatformIndex]->world.pos); + break; + + case EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE: + Math_Vec3f_Copy(&this->actor.world.pos, &this->platforms[0]->world.pos); + for (i = 0, ghostAlpha = 128; i < this->platformCount; i++, ghostAlpha -= 10) { + Math_Vec3f_Copy(&this->ghostPos[i], &this->actor.world.pos); + this->ghostAlpha[i] = ghostAlpha; + } + break; + + default: + Math_Vec3f_Copy(&this->actor.world.pos, &this->platforms[curPlatformIndex]->world.pos); + for (i--; i >= 0; i--) { + if (curPlatformIndex != i) { + Math_Vec3f_Copy(&this->ghostPos[i], &this->platforms[i]->world.pos); + this->ghostRot[i] = this->actor.world.rot; + this->ghostAlpha[i] = 100; + this->ghostNextPlatformIndex[i] = i; + for (j = 0; j < ARRAY_COUNT(this->jointTable); j++) { + this->ghostJointTables[i][j] = this->jointTable[j]; + } + } else { + Math_Vec3f_Copy(&this->ghostPos[i], &gZeroVec3f); + } + } + break; + } + } +} + +/** + * Makes the ghosts run around the room from platform to platform. + */ +void EnWiz_MoveGhosts(EnWiz* this) { + s32 i; + s32 ghostNextPlatformIndex; + s32 playSfx = false; + + for (i = 0; i < this->platformCount; i++) { + if (this->ghostPos[i].x != 0.0f && this->ghostPos[i].z != 0.0f) { + f32 diffX; + f32 diffZ; + + ghostNextPlatformIndex = this->ghostNextPlatformIndex[i]; + diffX = this->platforms[ghostNextPlatformIndex]->world.pos.x - this->ghostPos[i].x; + diffZ = this->platforms[ghostNextPlatformIndex]->world.pos.z - this->ghostPos[i].z; + playSfx++; + + if (sqrtf(SQ(diffX) + SQ(diffZ)) < 30.0f) { + this->ghostNextPlatformIndex[i]--; + if (this->ghostNextPlatformIndex[i] < 0) { + this->ghostNextPlatformIndex[i] = this->platformCount - 1; + } + } + + ghostNextPlatformIndex = this->ghostNextPlatformIndex[i]; + Math_ApproachF(&this->ghostPos[i].x, this->platforms[ghostNextPlatformIndex]->world.pos.x, 0.3f, 30.0f); + Math_ApproachF(&this->ghostPos[i].y, this->platforms[ghostNextPlatformIndex]->world.pos.y, 0.3f, 30.0f); + Math_ApproachF(&this->ghostPos[i].z, this->platforms[ghostNextPlatformIndex]->world.pos.z, 0.3f, 30.0f); + this->ghostRot[i].y = + Math_Vec3f_Yaw(&this->ghostPos[i], &this->platforms[ghostNextPlatformIndex]->world.pos); + } + } + + if (playSfx) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_RUN - SFX_FLAG); + } +} + +void EnWiz_StartIntroCutscene(EnWiz* this, PlayState* play) { + if (ActorCutscene_GetCanPlayNext(this->actor.cutscene)) { + ActorCutscene_StartAndSetFlag(this->actor.cutscene, &this->actor); + this->subCamId = ActorCutscene_GetCurrentSubCamId(this->actor.cutscene); + this->actor.flags |= ACTOR_FLAG_100000; + EnWiz_SetupAppear(this, play); + } else { + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } +} + +void EnWiz_SetupAppear(EnWiz* this, PlayState* play) { + Player* player = GET_PLAYER(play); + s32 i; + s16 angle; + + this->action = EN_WIZ_ACTION_APPEAR; + + if (this->timer == 0) { + EnWiz_SelectPlatform(this, play); + + if (this->introCutsceneState != EN_WIZ_INTRO_CS_NOT_STARTED) { + angle = Math_Vec3f_Yaw(&this->actor.world.pos, &player->actor.world.pos); + this->actor.shape.rot.y = angle; + this->actor.world.rot.y = angle; + for (i = 0; i < this->platformCount; i++) { + this->ghostRot[i].y = Math_Vec3f_Yaw(&this->ghostPos[i], &player->actor.world.pos); + } + + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_IDLE, true); + this->shouldStartTimer = false; + this->targetPlatformLightAlpha = 255; + Math_Vec3f_Copy(&this->platformLightPos, &this->actor.world.pos); + + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_UNARI); + } else { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_VOICE - SFX_FLAG); + } + } + + this->actionFunc = EnWiz_Appear; + } +} + +/** + * Makes the Wizrobe grow in scale and become more opaque. + * During the first phase, it also increases the alpha for the platform's light. + * If the player gets too close during the first phase, this will set up the Wizrobe to disappear. + */ +void EnWiz_Appear(EnWiz* this, PlayState* play) { + Vec3f staffTargetFlameScale = { 0.006f, 0.006f, 0.006f }; + Player* player = GET_PLAYER(play); + + EnWiz_HandleIntroCutscene(this, play); + + if (this->introCutsceneState >= EN_WIZ_INTRO_CS_APPEAR) { + SkelAnime_Update(&this->skelAnime); + + if ((this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) && + (this->introCutsceneState >= EN_WIZ_INTRO_CS_DISAPPEAR) && + ((this->actor.xzDistToPlayer < 200.0f) || + ((player->unk_D57 != 0) && + ((ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y)) < 0x7D0)) && + (ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, BINANG_ADD(player->actor.shape.rot.y, 0x8000))) < + 0x7D0)))) { + EnWiz_SetupDisappear(this); + } else { + Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0xA, 0xBB8, 0); + + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 10, 10, 10); + if (!this->shouldStartTimer) { + this->timer = 20; + this->shouldStartTimer = true; + } + } else { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_VOICE - SFX_FLAG); + } + + if (this->timer == 0) { + Math_ApproachF(&this->scale, 0.015f, 0.05f, 0.01f); + Math_SmoothStepToS(&this->alpha, 255, 1, 5, 0); + } + + if (this->scale < 0.0138f) { + return; + } else { + this->action = EN_WIZ_ACTION_RUN_IN_CIRCLES; + this->actor.flags &= ~ACTOR_FLAG_8000000; + this->ghostColliders.elements[0].info.bumper.dmgFlags = 0x1013A22; + Math_Vec3f_Copy(&this->staffTargetFlameScale, &staffTargetFlameScale); + this->targetPlatformLightAlpha = 0; + + if (this->introCutsceneState == EN_WIZ_INTRO_CS_DISAPPEAR) { + this->timer = 0; + this->introCutsceneTimer = 20; + EnWiz_SetupDisappear(this); + } else if (this->introCutsceneState >= EN_WIZ_INTRO_CS_END) { + if (this->fightState == EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE) { + this->actionFunc = EnWiz_SetupSecondPhaseCutscene; + } else { + EnWiz_SetupDance(this); + } + } + } + } + } +} + +void EnWiz_SetupDance(EnWiz* this) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_DANCE, false); + Math_ApproachF(&this->scale, 0.015f, 0.05f, 0.001f); + this->rotationalVelocity = 0; + this->animLoopCounter = 0; + this->action = EN_WIZ_ACTION_DANCE; + if (this->fightState >= EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_COPY_WIZROBE) { + Animation_Change(&this->ghostSkelAnime, &gWizrobeRunAnim, 1.0f, 0.0f, Animation_GetLastFrame(&gWizrobeRunAnim), + ANIMMODE_LOOP, 0.0f); + this->fightState = EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND; + } + + Math_SmoothStepToS(&this->alpha, 255, 1, 5, 0); + this->actionFunc = EnWiz_Dance; +} + +/** + * Makes the Wizrobe spin around and dance until there are no active projectiles + * and it completes at least three loops of its dancing animation. + */ +void EnWiz_Dance(EnWiz* this, PlayState* play) { + f32 curFrame = this->skelAnime.curFrame; + s32 i; + + Math_SmoothStepToS(&this->alpha, 255, 1, 5, 0); + Math_ApproachF(&this->scale, 0.015f, 0.05f, 0.001f); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_RUN - SFX_FLAG); + this->actor.world.rot.y += this->rotationalVelocity; + if (this->fightState >= EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND) { + EnWiz_MoveGhosts(this); + } else { + for (i = 0; i < this->platformCount; i++) { + this->ghostRot[i].y += this->rotationalVelocity; + } + } + + Math_SmoothStepToS(&this->rotationalVelocity, 0x1388, 0x64, 0x3E8, 0x3E8); + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 20, 50, 10); + if (this->endFrame <= curFrame) { + if (this->animLoopCounter < 10) { + this->animLoopCounter++; + } + } + + if ((this->animLoopCounter >= 3) && (!this->hasActiveProjectile)) { + this->targetPlatformLightAlpha = 0; + EnWiz_SetupWindUp(this); + } +} + +void EnWiz_SetupSecondPhaseCutscene(EnWiz* this, PlayState* play) { + s16 secondPhaseCutscene = ActorCutscene_GetAdditionalCutscene(this->actor.cutscene); + + if (!ActorCutscene_GetCanPlayNext(secondPhaseCutscene)) { + ActorCutscene_SetIntentToPlay(secondPhaseCutscene); + } else { + ActorCutscene_StartAndSetFlag(secondPhaseCutscene, &this->actor); + this->subCamId = ActorCutscene_GetCurrentSubCamId(secondPhaseCutscene); + this->actor.flags |= ACTOR_FLAG_100000; + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_DANCE, false); + this->action = EN_WIZ_ACTION_RUN_BETWEEN_PLATFORMS; + this->nextPlatformIndex = 1; + this->hasRunToEveryPlatform = false; + Math_SmoothStepToS(&this->alpha, 255, 1, 5, 0); + this->actionFunc = EnWiz_SecondPhaseCutscene; + } +} + +/** + * Makes the Wizrobe run between every platform in the room once before returning to its + * original platform and disappearing. Ghosts trail behind the Wizrobe as it runs. + */ +void EnWiz_SecondPhaseCutscene(EnWiz* this, PlayState* play) { + Camera* subCam; + s32 i; + + Math_SmoothStepToS(&this->alpha, 255, 1, 5, 0); + subCam = Play_GetCamera(play, this->subCamId); + Math_Vec3f_Copy(&subCam->at, &this->actor.focus.pos); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_RUN - SFX_FLAG); + if (this->platforms[this->nextPlatformIndex] != NULL) { + f32 diffX = this->actor.world.pos.x - this->platforms[this->nextPlatformIndex]->world.pos.x; + f32 diffZ = this->actor.world.pos.z - this->platforms[this->nextPlatformIndex]->world.pos.z; + s32 pad; + + if (sqrtf(SQ(diffX) + SQ(diffZ)) < 30.0f) { + if (!this->hasRunToEveryPlatform) { + this->nextPlatformIndex++; + if (this->nextPlatformIndex >= this->platformCount) { + this->hasRunToEveryPlatform = true; + this->nextPlatformIndex = 0; + } + } else { + f32 diffX = this->actor.world.pos.x - this->ghostPos[this->platformCount].x; + f32 diffZ = this->actor.world.pos.z - this->ghostPos[this->platformCount].z; + s32 pad; + s32 i; + + this->actor.flags |= ACTOR_FLAG_8000000; + if (sqrtf(SQ(diffX) + SQ(diffZ)) < 20.0f) { + for (i = 0; i < this->platformCount; i++) { + Math_Vec3f_Copy(&this->ghostPos[i], &gZeroVec3f); + } + + this->nextPlatformIndex = 0; + this->platformCount = 0; + this->fightState = EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_COPY_WIZROBE; + this->timer = 0; + ActorCutscene_Stop(ActorCutscene_GetAdditionalCutscene(this->actor.cutscene)); + this->actor.flags &= ~ACTOR_FLAG_100000; + EnWiz_SetupDisappear(this); + return; + } + } + } + } + + Math_Vec3f_Copy(this->ghostPos, &this->actor.world.pos); + this->ghostRot[0].y = this->actor.world.rot.y; + Math_ApproachF(&this->actor.world.pos.x, this->platforms[this->nextPlatformIndex]->world.pos.x, 0.3f, 30.0f); + Math_ApproachF(&this->actor.world.pos.y, this->platforms[this->nextPlatformIndex]->world.pos.y, 0.3f, 30.0f); + Math_ApproachF(&this->actor.world.pos.z, this->platforms[this->nextPlatformIndex]->world.pos.z, 0.3f, 30.0f); + for (i = this->platformCount; i > 0; i--) { + Math_Vec3f_Copy(&this->ghostPos[i], &this->ghostPos[i - 1]); + this->ghostRot[i].y = this->ghostRot[i - 1].y; + } + + this->actor.world.rot.y = + Math_Vec3f_Yaw(&this->actor.world.pos, &this->platforms[this->nextPlatformIndex]->world.pos); +} + +void EnWiz_SetupWindUp(EnWiz* this) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_WIND_UP, false); + this->animLoopCounter = 0; + this->actionFunc = EnWiz_WindUp; +} + +/** + * Plays the wind up animation for at least two animation loops before attacking. + */ +void EnWiz_WindUp(EnWiz* this, PlayState* play) { + f32 curFrame = this->skelAnime.curFrame; + s32 i; + + Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0xC8, 0x1F40, 0x1388); + if (this->fightState >= EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND) { + EnWiz_MoveGhosts(this); + } else { + for (i = 0; i < this->platformCount; i++) { + Math_SmoothStepToS(&this->ghostRot[i].y, this->actor.yawTowardsPlayer, 0xC8, 0x1F40, 0x1388); + } + } + + if (this->endFrame <= curFrame) { + this->animLoopCounter++; + if (this->animLoopCounter >= 2) { + EnWiz_SetupAttack(this); + } + } + + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 10, 10, 10); +} + +void EnWiz_SetupAttack(EnWiz* this) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_ATTACK, false); + this->timer = 0; + this->shouldStartTimer = false; + this->action = EN_WIZ_ACTION_ATTACK; + this->actionFunc = EnWiz_Attack; +} + +/** + * Spawns an EnWizFire projectile that is pointed at the player, then disappears. + */ +void EnWiz_Attack(EnWiz* this, PlayState* play) { + f32 curFrame = this->skelAnime.curFrame; + + if (this->fightState >= EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND) { + EnWiz_MoveGhosts(this); + } + + if (this->timer == 0) { + if ((Animation_OnFrame(&this->skelAnime, 6.0f)) && (!this->hasActiveProjectile)) { + Player* player = GET_PLAYER(play); + Vec3f pos; + s32 type = this->type; + + Math_Vec3f_Copy(&pos, &this->actor.world.pos); + pos.x += Math_SinS(this->actor.world.rot.y) * 40.0f; + pos.y += 60.0f; + pos.z += Math_CosS(this->actor.world.rot.y) * 40.0f; + if (type == EN_WIZ_TYPE_FIRE_NO_BGM) { + type = EN_WIZ_TYPE_FIRE; + } + + Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_EN_WIZ_FIRE, pos.x, pos.y, pos.z, + Math_Vec3f_Pitch(&pos, &player->actor.world.pos), + Math_Vec3f_Yaw(&pos, &player->actor.world.pos), 0, type * 4); + this->hasActiveProjectile = true; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_ATTACK); + Actor_PlaySfxAtPos(&this->actor, NA_SE_PL_MAGIC_FIRE); + } + + if ((curFrame >= 8.0f) && !this->shouldStartTimer) { + this->timer = 3; + this->shouldStartTimer = true; + } + + if (this->endFrame <= curFrame) { + EnWiz_SetupDisappear(this); + } + } +} + +void EnWiz_SetupDisappear(EnWiz* this) { + if (this->action != EN_WIZ_ACTION_DAMAGED) { + this->rotationalVelocity = 0x2710; + this->timer = 0; + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_IDLE, false); + this->action = EN_WIZ_ACTION_DISAPPEAR; + } else { + this->rotationalVelocity = 0x2710; + this->actor.world.rot.y += this->rotationalVelocity; + } + + this->targetPlatformLightAlpha = 0; + this->actor.flags |= ACTOR_FLAG_8000000; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_DISAPPEAR); + Math_SmoothStepToS(&this->rotationalVelocity, 0x1388, 0x64, 0x3E8, 0x3E8); + this->actor.world.rot.y += this->rotationalVelocity; + this->actor.flags &= ~ACTOR_FLAG_1; + this->actionFunc = EnWiz_Disappear; +} + +/** + * Spin the Wizrobe around and shrink it so that it disappears into its platform. + * Afterwards, set it up to appear again. + */ +void EnWiz_Disappear(EnWiz* this, PlayState* play) { + s32 i; + + Math_SmoothStepToS(&this->rotationalVelocity, 0, 0xA, 0xBB8, 0x14); + this->actor.world.rot.y += this->rotationalVelocity; + if ((this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) || (this->action == EN_WIZ_ACTION_DAMAGED)) { + Math_ApproachZeroF(&this->scale, 0.3f, 0.01f); + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 5, 50, 0); + } else { + Math_ApproachZeroF(&this->scale, 0.3f, 0.001f); + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 10, 50, 0); + for (i = 0; i < this->platformCount; i++) { + this->ghostRot[i].y += this->rotationalVelocity; + } + } + + Math_Vec3f_Copy(&this->staffTargetFlameScale, &gZeroVec3f); + if (this->scale < 0.001f) { + this->scale = 0.0f; + + if ((this->introCutsceneState == EN_WIZ_INTRO_CS_DISAPPEAR) && (this->introCutsceneTimer == 0)) { + this->introCutsceneState = EN_WIZ_INTRO_CS_END; + ActorCutscene_Stop(this->actor.cutscene); + this->actor.flags &= ~ACTOR_FLAG_100000; + } + + if (this->introCutsceneState != EN_WIZ_INTRO_CS_DISAPPEAR) { + this->alpha = 0; + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + this->ghostColliders.elements[0].info.bumper.dmgFlags = 0x1000202; + } + + this->actor.flags |= ACTOR_FLAG_1; + this->actionFunc = EnWiz_SetupAppear; + } + } +} + +void EnWiz_SetupDamaged(EnWiz* this, PlayState* play) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_DAMAGE, false); + Actor_SetColorFilter(&this->actor, 0x4000, 255, 0, 8); + this->timer = 20; + + if ((this->fightState != EN_WIZ_FIGHT_STATE_FIRST_PHASE) && (this->actor.colChkInfo.health <= 0)) { + Enemy_StartFinishingBlow(play, &this->actor); + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_DEAD); + this->timer = 0; + this->actor.flags &= ~ACTOR_FLAG_1; + } else { + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_DAMAGE); + } + + this->scale = 0.015f; + this->platformCount = 0; + this->targetPlatformLightAlpha = 0; + if ((this->drawDmgEffTimer != 0) && + ((this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FIRE) || (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_LIGHT_ORBS))) { + this->timer = 0; + } + + this->rotationalVelocity = 0x4E20; + if ((this->drawDmgEffTimer != 0) && (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_SFX)) { + this->rotationalVelocity = 0; + this->timer = 0; + } + + this->action = EN_WIZ_ACTION_DAMAGED; + this->actionFunc = EnWiz_Damaged; +} + +/** + * Spins the Wizrobe around quickly and makes it jump in the air if it was defeated or if + * it was damaged in a certain way. Afterwards, the Wizrobe either disappears or dies. + */ +void EnWiz_Damaged(EnWiz* this, PlayState* play) { + s32 i; + + if ((this->drawDmgEffTimer < 50) && (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_SFX)) { + Actor_SpawnIceEffects(play, &this->actor, this->bodyPartsPos, ARRAY_COUNT(this->bodyPartsPos), 2, 1.0f, 0.7f); + this->drawDmgEffTimer = 0; + this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FIRE; + this->rotationalVelocity = 0x4E20; + this->actor.velocity.y = 30.0f; + this->actor.gravity = -3.0f; + } + + if ((this->drawDmgEffTimer != 0) && (this->drawDmgEffTimer < 30) && + ((this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FIRE) || (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_LIGHT_ORBS))) { + this->actor.velocity.y = 30.0f; + this->actor.gravity = -3.0f; + this->drawDmgEffTimer = 0; + this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FIRE; + } else if (!this->isDead && (this->fightState != EN_WIZ_FIGHT_STATE_FIRST_PHASE) && + (this->actor.colChkInfo.health <= 0)) { + this->actor.velocity.y = 30.0f; + this->actor.gravity = -3.0f; + this->isDead = true; + } + + this->actor.world.rot.y += this->rotationalVelocity; + Math_SmoothStepToS(&this->rotationalVelocity, 0, 0xA, 0xBB8, 0x14); + for (i = 0; i < this->platformCount; i++) { + this->ghostRot[i].y += this->rotationalVelocity; + } + + if ((this->timer == 1) || + ((this->actor.velocity.y < 0.0f) && + (this->actor.world.pos.y < (this->platforms[this->curPlatformIndex]->world.pos.y + 11.0f)))) { + this->timer = 0; + this->actor.velocity.y = 0.0f; + this->actor.gravity = 0.0f; + this->drawDmgEffTimer = this->timer; + this->drawDmgEffType = this->timer; + + if (this->actor.colChkInfo.health <= 0) { + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + this->fightState = EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE; + if ((this->type == EN_WIZ_TYPE_FIRE) || (this->type == EN_WIZ_TYPE_FIRE_NO_BGM)) { + this->actor.colChkInfo.health = 8; + } else { + this->actor.colChkInfo.health = 6; + } + + EnWiz_SetupDisappear(this); + } else { + EnWiz_SetupDead(this); + } + } else { + EnWiz_SetupDisappear(this); + } + + this->actor.flags |= ACTOR_FLAG_8000000; + } + + Math_SmoothStepToS(&this->platformLightAlpha, this->targetPlatformLightAlpha, 20, 50, 10); + Actor_MoveWithGravity(&this->actor); + Actor_UpdateBgCheckInfo(play, &this->actor, 35.0f, 40.0f, 40.0f, 0x1F); +} + +void EnWiz_SetupDead(EnWiz* this) { + EnWiz_ChangeAnim(this, EN_WIZ_ANIM_DAMAGE, false); + this->rotationalVelocity = 0x2710; + this->action = EN_WIZ_ACTION_DEAD; + this->timer = 0; + this->actionFunc = EnWiz_Dead; +} + +/** + * Slows the Wizrobe's rotation to a stop, then makes it burst into flames. + * If the Wizrobe has a switch flag, it will set that switch flag when it dies. + */ +void EnWiz_Dead(EnWiz* this, PlayState* play) { + s32 i; + + this->actor.world.rot.y += this->rotationalVelocity; + Math_SmoothStepToS(&this->rotationalVelocity, 0, 0xA, 0xBB8, 0x14); + if (this->rotationalVelocity < 0x1E) { + Math_SmoothStepToS(&this->alpha, 0, 10, 30, 20); + for (i = 0; i < this->platformCount; i++) { + Math_SmoothStepToS(&this->ghostAlpha[i], 0, 10, 30, 20); + } + + this->action = EN_WIZ_ACTION_BURST_INTO_FLAMES; + } + + if (this->alpha < 30) { + EnWiz_SelectPlatform(this, play); + SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 50, NA_SE_EN_EXTINCT); + Actor_MarkForDeath(&this->actor); + if (this->switchFlag >= 0) { + Flags_SetSwitch(play, this->switchFlag); + } + } +} + +static Color_RGBA8 sDustPrimColor = { 250, 250, 250, 255 }; +static Color_RGBA8 sDustEnvTimer = { 180, 180, 180, 255 }; + +void EnWiz_UpdateDamage(EnWiz* this, PlayState* play) { + s32 i; + s32 attackDealsDamage = false; + + if (this->collider.base.acFlags & AC_HIT) { + this->ghostColliders.base.acFlags &= ~AC_HIT; + if (this->action < EN_WIZ_ACTION_RUN_IN_CIRCLES) { + return; + } + + switch (this->actor.colChkInfo.damageEffect) { + case EN_WIZ_DMGEFF_NONE: + attackDealsDamage = true; + break; + + case EN_WIZ_DMGEFF_FIRE: + if (this->type == EN_WIZ_TYPE_ICE) { + this->drawDmgEffTimer = 40; + this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FIRE; + } + + attackDealsDamage = true; + break; + + case EN_WIZ_DMGEFF_FREEZE: + if ((this->type == EN_WIZ_TYPE_FIRE) || (this->type == EN_WIZ_TYPE_FIRE_NO_BGM)) { + this->drawDmgEffTimer = 80; + this->drawDmgEffType = ACTOR_DRAW_DMGEFF_FROZEN_SFX; + this->drawDmgEffScale = 0.0f; + this->drawDmgEffFrozenSteamScale = 1.5f; + } + + Actor_ApplyDamage(&this->actor); + EnWiz_SetupDamaged(this, play); + break; + + case EN_WIZ_DMGEFF_LIGHT_ORB: + if (((this->drawDmgEffType != ACTOR_DRAW_DMGEFF_FROZEN_SFX) && + (this->drawDmgEffType != ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX)) || + (this->drawDmgEffTimer == 0)) { + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_CLEAR_TAG, this->actor.focus.pos.x, + this->actor.focus.pos.y, this->actor.focus.pos.z, 0, 0, 0, CLEAR_TAG_LARGE_LIGHT_RAYS); + this->drawDmgEffTimer = 40; + this->drawDmgEffType = ACTOR_DRAW_DMGEFF_LIGHT_ORBS; + attackDealsDamage = true; + } + break; + } + + this->alpha = 255; + if (attackDealsDamage) { + Actor_ApplyDamage(&this->actor); + EnWiz_SetupDamaged(this, play); + return; + } + } + + if ((this->platformCount != 0) && (this->fightState != EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE)) { + for (i = 0; i < this->platformCount; i++) { + Vec3f accel; + Vec3f velocity; + Vec3f pos; + f32 scaleStep; + s32 j; + + // If the player throws a Deku Nut or hits a ghost's collider (something that is impossible + // in the final game, since EnWiz_Init effectively disables them), then the below code will + // "destroy" the ghost by turning into a cloud of smoke. + if ((iREG(50) != 0) || (this->ghostColliders.elements[i + 1].info.bumperFlags & BUMP_HIT)) { + //! @bug: If a single ghost is destroyed, then changing the fight state here will cause + //! strange behavior; the ghosts will stand still and pretend to attack the player like + //! the real Wizrobe. Since Deku Nuts destroy all ghosts at once, and since the ghost + //! colliders are effectively disabled, this doesn't cause any problems in the final + //! game, but it becomes an issue if the ghost colliders are enabled. + this->fightState = EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_COPY_WIZROBE; + this->ghostColliders.base.acFlags &= ~BUMP_HIT; + if (this->ghostPos[i].x != .0f || this->ghostPos[i].z != .0f) { + for (j = 0; j < 9; j++) { + accel.x = 0.0f; + accel.y = 1.0f; + accel.z = 0.0f; + velocity.x = 0.0f; + velocity.y = 1.0f; + velocity.z = 0.0f; + scaleStep = Rand_S16Offset(20, 10); + Math_Vec3f_Copy(&pos, &this->ghostPos[i]); + pos.x += (f32)Rand_S16Offset(20, 20) * ((Rand_ZeroOne() < 0.5f) ? -1 : 1); + pos.y += 70.0f + randPlusMinusPoint5Scaled(30.0f); + pos.z += (f32)Rand_S16Offset(20, 20) * ((Rand_ZeroOne() < 0.5f) ? -1 : 1); + func_800B0DE0(play, &pos, &velocity, &accel, &sDustPrimColor, &sDustEnvTimer, + Rand_S16Offset(350, 100), scaleStep); + } + + SoundSource_PlaySfxAtFixedWorldPos(play, &this->ghostPos[i], 50, NA_SE_EN_WIZ_LAUGH); + Math_Vec3f_Copy(&this->ghostPos[i], &gZeroVec3f); + } + } + } + } +} + +void EnWiz_Update(Actor* thisx, PlayState* play) { + s32 pad; + EnWiz* this = THIS; + s32 i; + s32 j; + + if (this->action != EN_WIZ_ACTION_APPEAR) { + SkelAnime_Update(&this->skelAnime); + SkelAnime_Update(&this->ghostSkelAnime); + } + + Actor_SetFocus(&this->actor, 60.0f); + Actor_SetScale(&this->actor, this->scale); + EnWiz_UpdateDamage(this, play); + this->actionFunc(this, play); + + this->actor.shape.rot.y = this->actor.world.rot.y; + + DECR(this->timer); + DECR(this->introCutsceneTimer); + DECR(this->drawDmgEffTimer); + + this->collider.dim.radius = 35; + this->collider.dim.height = 130; + this->collider.dim.yShift = 0; + if (this->action >= EN_WIZ_ACTION_RUN_IN_CIRCLES) { + CollisionCheck_SetAC(play, &play->colChkCtx, &this->ghostColliders.base); + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + } + + Math_ApproachF(&this->staffFlameScale.x, this->staffTargetFlameScale.x, 0.3f, 0.002f); + Math_ApproachF(&this->staffFlameScale.y, this->staffTargetFlameScale.y, 0.3f, 0.002f); + Math_ApproachF(&this->staffFlameScale.z, this->staffTargetFlameScale.z, 0.3f, 0.002f); + + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + this->platformCount = 0; + } else if (this->fightState == EN_WIZ_FIGHT_STATE_SECOND_PHASE_GHOSTS_RUN_AROUND) { + for (i = 0; i < this->platformCount; i++) { + for (j = 0; j < ARRAY_COUNT(this->ghostBaseJointTable); j++) { + this->ghostJointTables[i][j] = this->ghostBaseJointTable[j]; + } + } + } else { + for (i = 0; i < this->platformCount; i++) { + for (j = 0; j < ARRAY_COUNT(this->jointTable); j++) { + this->ghostJointTables[i][j] = this->jointTable[j]; + } + } + } +} + +void EnWiz_PostLimbDrawOpa(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + Vec3f staffFlamePos = { 0.0f, 0.0f, 0.0f }; + EnWiz* this = THIS; + + if (limbIndex == WIZROBE_LIMB_STAFF) { + staffFlamePos.x = 7300.0f; + staffFlamePos.y = -1500.0f; + if (this->action != EN_WIZ_ACTION_DANCE) { + staffFlamePos.y = 0.0f; + staffFlamePos.x = 5300.0f; + } + + Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Matrix_MultVec3f(&staffFlamePos, &this->staffFlamePos); + } + + Collider_UpdateSpheres(limbIndex, &this->ghostColliders); + + if ((limbIndex == WIZROBE_LIMB_PELVIS) || (limbIndex == WIZROBE_LIMB_TORSO) || + (limbIndex == WIZROBE_LIMB_LEFT_UPPER_ARM) || (limbIndex == WIZROBE_LIMB_LEFT_FOREARM) || + (limbIndex == WIZROBE_LIMB_RIGHT_UPPER_ARM) || (limbIndex == WIZROBE_LIMB_RIGHT_FOREARM) || + (limbIndex == WIZROBE_LIMB_NECK) || (limbIndex == WIZROBE_LIMB_HEAD) || (limbIndex == WIZROBE_LIMB_JAW) || + (limbIndex == WIZROBE_LIMB_LEFT_SHIN) || (limbIndex == WIZROBE_LIMB_RIGHT_SHIN) || + (limbIndex == WIZROBE_LIMB_LOINCLOTH)) { + Matrix_MultZero(&this->bodyPartsPos[this->bodyPartsPosIndex]); + this->bodyPartsPosIndex++; + if (this->bodyPartsPosIndex >= ARRAY_COUNT(this->bodyPartsPos)) { + this->bodyPartsPosIndex = 0; + } + } +} + +void EnWiz_PostLimbDrawXlu(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, Gfx** gfx) { + Vec3f staffFlamePos = { 0.0f, 0.0f, 0.0f }; + s32 pad; + EnWiz* this = THIS; + + if (this->action != EN_WIZ_ACTION_BURST_INTO_FLAMES) { + if (limbIndex == WIZROBE_LIMB_STAFF) { + staffFlamePos.x = 7300.0f; + staffFlamePos.y = -1500.0f; + if (this->action != EN_WIZ_ACTION_DANCE) { + staffFlamePos.y = 0.0f; + staffFlamePos.x = 5300.0f; + } + + Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Matrix_MultVec3f(&staffFlamePos, &this->staffFlamePos); + } + } else { + if (this->timer == 0) { + Vec3f flamePos; + + Matrix_Translate(0.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Matrix_MultVec3f(&staffFlamePos, &flamePos); + flamePos.x += randPlusMinusPoint5Scaled(4.0f); + flamePos.y += randPlusMinusPoint5Scaled(7.0f); + flamePos.z += randPlusMinusPoint5Scaled(5.0f); + func_800B3030(play, &flamePos, &gZeroVec3f, &gZeroVec3f, ((Rand_ZeroFloat(1.0f) * 50.0f) + 70.0f), 10, 1); + SoundSource_PlaySfxAtFixedWorldPos(play, &flamePos, 10, NA_SE_EN_EXTINCT); + } + + if ((limbIndex >= WIZROBE_LIMB_RIGHT_FOOT) && (this->timer == 0)) { + this->timer = 4; + } + } + + if ((limbIndex == WIZROBE_LIMB_PELVIS) || (limbIndex == WIZROBE_LIMB_TORSO) || + (limbIndex == WIZROBE_LIMB_LEFT_UPPER_ARM) || (limbIndex == WIZROBE_LIMB_LEFT_FOREARM) || + (limbIndex == WIZROBE_LIMB_RIGHT_UPPER_ARM) || (limbIndex == WIZROBE_LIMB_RIGHT_FOREARM) || + (limbIndex == WIZROBE_LIMB_NECK) || (limbIndex == WIZROBE_LIMB_HEAD) || (limbIndex == WIZROBE_LIMB_JAW) || + (limbIndex == WIZROBE_LIMB_LEFT_SHIN) || (limbIndex == WIZROBE_LIMB_RIGHT_SHIN) || + (limbIndex == WIZROBE_LIMB_LOINCLOTH)) { + Matrix_MultZero(&this->bodyPartsPos[this->bodyPartsPosIndex]); + this->bodyPartsPosIndex++; + if (this->bodyPartsPosIndex >= ARRAY_COUNT(this->bodyPartsPos)) { + this->bodyPartsPosIndex = 0; + } + } +} + +void EnWiz_Draw(Actor* thisx, PlayState* play) { + s32 pad; + EnWiz* this = THIS; + + OPEN_DISPS(play->state.gfxCtx); + + func_8012C28C(play->state.gfxCtx); + func_8012C2DC(play->state.gfxCtx); + + if ((this->action == EN_WIZ_ACTION_BURST_INTO_FLAMES) || (this->alpha != 255)) { + Scene_SetRenderModeXlu(play, 1, 2); + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha); + POLY_XLU_DISP = + SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + NULL, EnWiz_PostLimbDrawXlu, &this->actor, POLY_XLU_DISP); + } else { + Scene_SetRenderModeXlu(play, 0, 1); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, this->alpha); + SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + NULL, EnWiz_PostLimbDrawOpa, &this->actor); + } + + if (this->drawDmgEffTimer != 0) { + f32 drawDmgEffAlpha = this->drawDmgEffTimer * 0.05f; + + if ((this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_SFX) || + (this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX)) { + this->drawDmgEffScale += 0.3f; + if (this->drawDmgEffScale > 0.5f) { + this->drawDmgEffScale = 0.5f; + } + + Math_ApproachF(&this->drawDmgEffFrozenSteamScale, this->drawDmgEffScale, 0.1f, 0.04f); + } else { + this->drawDmgEffScale = 0.8f; + this->drawDmgEffFrozenSteamScale = 0.8f; + } + + Actor_DrawDamageEffects(play, &this->actor, this->bodyPartsPos, ARRAY_COUNT(this->bodyPartsPos), + this->drawDmgEffScale, this->drawDmgEffFrozenSteamScale, drawDmgEffAlpha, + this->drawDmgEffType); + } + + if (this->platformCount > 0) { + s32 i; + s16 platformCount; + + Matrix_Push(); + + platformCount = this->platformCount; + if (this->fightState == EN_WIZ_FIGHT_STATE_SECOND_PHASE_CUTSCENE) { + platformCount = 10; + } + + for (i = 0; i < platformCount; i++) { + func_8012C28C(play->state.gfxCtx); + func_8012C2DC(play->state.gfxCtx); + + if ((this->ghostPos[i].x != 0.0f) && (this->ghostPos[i].z != 0.0f)) { + Matrix_Translate(this->ghostPos[i].x, this->ghostPos[i].y + 10.0f, this->ghostPos[i].z, MTXMODE_NEW); + Matrix_Scale(this->scale, this->scale, this->scale, MTXMODE_APPLY); + Matrix_RotateYS(this->ghostRot[i].y, MTXMODE_APPLY); + Matrix_RotateXS(this->ghostRot[i].x, MTXMODE_APPLY); + Matrix_RotateZS(this->ghostRot[i].z, MTXMODE_APPLY); + Scene_SetRenderModeXlu(play, 1, 2); + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->ghostAlpha[i]); + POLY_XLU_DISP = + SkelAnime_DrawFlex(play, this->ghostSkelAnime.skeleton, this->ghostJointTables[i], + this->ghostSkelAnime.dListCount, NULL, NULL, &this->actor, POLY_XLU_DISP); + this->ghostColliders.elements[i + 1].dim.worldSphere.center.x = this->ghostPos[i].x; + this->ghostColliders.elements[i + 1].dim.worldSphere.center.y = this->ghostPos[i].y + 50.0f; + this->ghostColliders.elements[i + 1].dim.worldSphere.center.z = this->ghostPos[i].z; + this->ghostColliders.elements[i + 1].dim.worldSphere.radius = + this->ghostColliders.elements[0].dim.modelSphere.radius; + this->ghostColliders.elements[i + 1].dim.scale = this->ghostColliders.elements[0].dim.scale; + } + } + + Matrix_Pop(); + } + + func_8012C2DC(play->state.gfxCtx); + func_8012C28C(play->state.gfxCtx); + + // Draw the light emanating from the Wizrobe's platform + if (this->fightState == EN_WIZ_FIGHT_STATE_FIRST_PHASE) { + Matrix_Push(); + + AnimatedMat_Draw(play, Lib_SegmentedToVirtual(&gWizrobePlatformLightTexAnim)); + Matrix_Translate(this->platformLightPos.x, this->platformLightPos.y, this->platformLightPos.z, MTXMODE_NEW); + Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY); + gDPPipeSync(POLY_XLU_DISP++); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 255, 255, 255, this->platformLightAlpha); + + if ((this->type == EN_WIZ_TYPE_FIRE) || (this->type == EN_WIZ_TYPE_FIRE_NO_BGM)) { + gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 100, 255); + } else { + gDPSetEnvColor(POLY_XLU_DISP++, 50, 0, 255, 255); + } + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gWizrobePlatformLightDL); + + Matrix_Pop(); + } + + // Draw the flame at the tip of the Wizrobe's staff + Matrix_Translate(this->staffFlamePos.x, this->staffFlamePos.y, this->staffFlamePos.z, MTXMODE_NEW); + Matrix_Scale(this->staffFlameScale.x, this->staffFlameScale.y, this->staffFlameScale.z, MTXMODE_APPLY); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 32, 64, 1, 0, + ((this->staffFlameScroll * 10) - (play->state.frames * 20)) % 512, 32, 128)); + gDPPipeSync(POLY_XLU_DISP++); + + if ((this->type == EN_WIZ_TYPE_FIRE) || (this->type == EN_WIZ_TYPE_FIRE_NO_BGM)) { + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 170, 255); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 50, 0, 255); + } else { + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 170, 255, 255, 255); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 50, 255, 255); + } + + Matrix_Mult(&play->billboardMtxF, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gEffFire1DL); + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Wiz/z_en_wiz.h b/src/overlays/actors/ovl_En_Wiz/z_en_wiz.h index a1ae32032c..3d18abab25 100644 --- a/src/overlays/actors/ovl_En_Wiz/z_en_wiz.h +++ b/src/overlays/actors/ovl_En_Wiz/z_en_wiz.h @@ -2,6 +2,16 @@ #define Z_EN_WIZ_H #include "global.h" +#include "objects/object_wiz/object_wiz.h" + +#define EN_WIZ_GET_SWITCHFLAG(thisx) ((thisx)->params & 0x7F) +#define EN_WIZ_GET_TYPE(thisx) (((thisx)->params >> 8) & 0xFF) + +typedef enum { + /* 0 */ EN_WIZ_TYPE_FIRE, + /* 1 */ EN_WIZ_TYPE_ICE, + /* 2 */ EN_WIZ_TYPE_FIRE_NO_BGM, // does not request the mini-boss BGM +} EnWizType; struct EnWiz; @@ -9,15 +19,62 @@ typedef void (*EnWizActionFunc)(struct EnWiz*, PlayState*); typedef struct EnWiz { /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x268]; + /* 0x144 */ SkelAnime skelAnime; + /* 0x188 */ Vec3s jointTable[WIZROBE_LIMB_MAX]; + /* 0x200 */ Vec3s morphTable[WIZROBE_LIMB_MAX]; + /* 0x278 */ SkelAnime ghostSkelAnime; + /* 0x2BC */ Vec3s ghostBaseJointTable[WIZROBE_LIMB_MAX]; + /* 0x334 */ Vec3s ghostMorphTable[WIZROBE_LIMB_MAX]; /* 0x3AC */ EnWizActionFunc actionFunc; - /* 0x3B0 */ char unk_3B0[0xA]; - /* 0x3BA */ s16 unk_3BA; - /* 0x3BC */ char unk_3BC[0x8C]; - /* 0x448 */ s32 unk_448; - /* 0x44C */ char unk_44C[0x2FE]; - /* 0x74A */ s16 unk_74A; - /* 0x74C */ char unk_74C[0x634]; + /* 0x3B0 */ s16 action; + /* 0x3B2 */ s16 timer; + /* 0x3B4 */ s16 introCutsceneTimer; + /* 0x3B6 */ s16 fightState; + /* 0x3B8 */ s16 staffFlameScroll; + /* 0x3BA */ s16 hasActiveProjectile; + /* 0x3BC */ s16 hasRunToEveryPlatform; // used for the second phase cutscene to make sure the Wizrobe visits every platform + /* 0x3BE */ s16 unk_3BE; // unused, inferred from surrounding members + /* 0x3C0 */ s16 rotationalVelocity; + /* 0x3C2 */ s16 alpha; + /* 0x3C4 */ s16 platformLightAlpha; + /* 0x3C6 */ s16 targetPlatformLightAlpha; + /* 0x3C8 */ s16 introCutsceneCameraAngle; + /* 0x3CA */ u8 shouldStartTimer; + /* 0x3CB */ u8 introCutsceneState; + /* 0x3CC */ s32 musicStartTimer; + /* 0x3D0 */ f32 endFrame; + /* 0x3D4 */ f32 scale; + /* 0x3D8 */ Vec3f staffFlamePos; + /* 0x3E4 */ Vec3f staffFlameScale; + /* 0x3F0 */ Vec3f staffTargetFlameScale; + /* 0x3FC */ Vec3f unk_3FC; // unused, inferred from surrounding members + /* 0x408 */ Vec3f unk_408; // unused, inferred from surrounding members + /* 0x414 */ Vec3f platformLightPos; + /* 0x420 */ Actor* platforms[10]; + /* 0x448 */ Actor* freezard; + /* 0x44C */ s16 animLoopCounter; + /* 0x450 */ f32 unk_450; // set to 1.0f, but never used + /* 0x454 */ ColliderJntSph ghostColliders; + /* 0x474 */ ColliderJntSphElement ghostColliderElements[10]; + /* 0x6F4 */ ColliderCylinder collider; + /* 0x740 */ s32 platformCount; + /* 0x744 */ s32 nextPlatformIndex; // used for the second phase cutscene to dictate where the Wizrobe should run to next + /* 0x748 */ s16 curPlatformIndex; + /* 0x74A */ s16 type; + /* 0x74C */ s16 switchFlag; + /* 0x74E */ s16 subCamId; + /* 0x750 */ s16 isDead; + /* 0x752 */ s16 drawDmgEffTimer; + /* 0x754 */ s16 drawDmgEffType; + /* 0x758 */ f32 drawDmgEffScale; + /* 0x75C */ f32 drawDmgEffFrozenSteamScale; + /* 0x760 */ Vec3f bodyPartsPos[12]; + /* 0x7F0 */ s16 bodyPartsPosIndex; + /* 0x7F2 */ s16 ghostAlpha[10]; + /* 0x806 */ s16 ghostNextPlatformIndex[10]; + /* 0x81C */ Vec3f ghostPos[10]; + /* 0x894 */ Vec3s ghostRot[10]; + /* 0x8D0 */ Vec3s ghostJointTables[10][WIZROBE_LIMB_MAX]; } EnWiz; // size = 0xD80 extern const ActorInit En_Wiz_InitVars; diff --git a/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.c b/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.c index d49e71c08c..ce13687a7c 100644 --- a/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.c +++ b/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.c @@ -1,7 +1,7 @@ /* * File: z_en_wiz_brock.c * Overlay: ovl_En_Wiz_Brock - * Description: Wizzrobe Warp Platform + * Description: Wizrobe Warp Platform */ #include "z_en_wiz_brock.h" @@ -11,13 +11,6 @@ #define THIS ((EnWizBrock*)thisx) -typedef enum { - PLATFORM_TYPE_INACTIVE, - PLATFORM_TYPE_FIRE, - PLATFORM_TYPE_ICE, - PLATFORM_TYPE_MAX, -} PlatformType; - void EnWizBrock_Init(Actor* thisx, PlayState* play); void EnWizBrock_Destroy(Actor* thisx, PlayState* play); void EnWizBrock_Update(Actor* thisx, PlayState* play); @@ -26,7 +19,7 @@ void EnWizBrock_Draw(Actor* thisx, PlayState* play); void EnWizBrock_SetupUpdateStatus(EnWizBrock* this, PlayState* play); void EnWizBrock_UpdateStatus(EnWizBrock* this, PlayState* play); -s16 platformCount = 0; +s16 sPlatformIndex = 0; const ActorInit En_Wiz_Brock_InitVars = { ACTOR_EN_WIZ_BROCK, @@ -45,13 +38,13 @@ void EnWizBrock_Init(Actor* thisx, PlayState* play) { CollisionHeader* colHeader = NULL; DynaPolyActor_Init(&this->dyna, 0); - CollisionHeader_GetVirtual(&object_wiz_Colheader_001690, &colHeader); + CollisionHeader_GetVirtual(&gWizrobePlatformCol, &colHeader); this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, colHeader); this->dyna.actor.colChkInfo.mass = MASS_IMMOVABLE; this->dyna.actor.colChkInfo.health = 3; this->unk_1A6 = 0; Actor_SetScale(&this->dyna.actor, 0.01f); - this->platformNum = platformCount++; + this->platformIndex = sPlatformIndex++; this->actionFunc = EnWizBrock_SetupUpdateStatus; this->dyna.actor.scale.x = this->dyna.actor.scale.y = this->dyna.actor.scale.z = 0.01f; this->alpha = 255.0f; @@ -68,12 +61,12 @@ void EnWizBrock_SetupUpdateStatus(EnWizBrock* this, PlayState* play) { } /** - * @brief Checks the platform status, when the Wizzrobe is defeated, which triggers timer to + * @brief Checks the platform status, when the Wizrobe is defeated, which triggers timer to * count up to 30 at which point the platforms are despawned. */ void EnWizBrock_UpdateStatus(EnWizBrock* this, PlayState* play) { - if (this->platformType == PLATFORM_TYPE_INACTIVE) { - if (this->dyna.actor.colChkInfo.health != PLATFORM_TYPE_MAX) { + if (this->platformType == EN_WIZ_BROCK_PLATFORM_TYPE_INACTIVE) { + if (this->dyna.actor.colChkInfo.health != EN_WIZ_BROCK_PLATFORM_TYPE_MAX) { this->platformType = this->dyna.actor.colChkInfo.health; } } @@ -115,30 +108,30 @@ void EnWizBrock_Draw(Actor* thisx, PlayState* play) { Scene_SetRenderModeXlu(play, 0, 1); gDPPipeSync(POLY_OPA_DISP++); gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255); - Gfx_DrawDListOpa(play, gWizzrobePlatform); + Gfx_DrawDListOpa(play, gWizrobePlatformDL); } else { Scene_SetRenderModeXlu(play, 1, 2); gDPPipeSync(POLY_XLU_DISP++); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, (s16)this->alpha); - Gfx_DrawDListXlu(play, gWizzrobePlatform); + Gfx_DrawDListXlu(play, gWizrobePlatformDL); } CLOSE_DISPS(play->state.gfxCtx); - if (this->platformType != PLATFORM_TYPE_INACTIVE) { + if (this->platformType != EN_WIZ_BROCK_PLATFORM_TYPE_INACTIVE) { OPEN_DISPS(play->state.gfxCtx); - AnimatedMat_Draw(play, Lib_SegmentedToVirtual(&gWizzrobePlatformTexAnim)); + AnimatedMat_Draw(play, Lib_SegmentedToVirtual(&gWizrobePlatformCenterTexAnim)); gDPPipeSync(POLY_XLU_DISP++); gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 255, 255); - if (this->platformType == PLATFORM_TYPE_FIRE) { + if (this->platformType == EN_WIZ_BROCK_PLATFORM_TYPE_FIRE) { gDPSetEnvColor(POLY_XLU_DISP++, 255, 00, 100, (s16)this->alpha); } else { gDPSetEnvColor(POLY_XLU_DISP++, 50, 00, 255, (s16)this->alpha); } gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, &gWizzrobePlatformCenter); + gSPDisplayList(POLY_XLU_DISP++, &gWizrobePlatformCenterDL); CLOSE_DISPS(play->state.gfxCtx); } diff --git a/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h b/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h index 0f01506976..3b23d08b0f 100644 --- a/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h +++ b/src/overlays/actors/ovl_En_Wiz_Brock/z_en_wiz_brock.h @@ -3,6 +3,13 @@ #include "global.h" +typedef enum { + /* 0 */ EN_WIZ_BROCK_PLATFORM_TYPE_INACTIVE, + /* 1 */ EN_WIZ_BROCK_PLATFORM_TYPE_FIRE, + /* 2 */ EN_WIZ_BROCK_PLATFORM_TYPE_ICE, + /* 3 */ EN_WIZ_BROCK_PLATFORM_TYPE_MAX, +} EnWizBrockPlatformType; + struct EnWizBrock; typedef void (*EnWizBrockActionFunc)(struct EnWizBrock*, PlayState*); @@ -12,8 +19,8 @@ typedef struct EnWizBrock { /* 0x15C */ UNK_TYPE1 unk_15C[0x44]; /* 0x1A0 */ EnWizBrockActionFunc actionFunc; /* 0x1A4 */ s16 timer; // Counter for despawing blocks (Max of 37) - /* 0x1A6 */ s16 unk_1A6; // TODO: set but not used maybe used in wizzrobe? - /* 0x1A8 */ s16 platformNum; // Numeric identifier for platform + /* 0x1A6 */ s16 unk_1A6; // set to 0, but never used + /* 0x1A8 */ s16 platformIndex; // Numeric identifier for platform /* 0x1AA */ s16 platformType; // Determines element type for platform (ice/fire) /* 0x1AC */ f32 alpha; } EnWizBrock; // size = 0x1B0 diff --git a/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.c b/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.c index 666a5156bd..eea112f894 100644 --- a/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.c +++ b/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.c @@ -1,7 +1,7 @@ /* * File: z_en_wiz_fire.c * Overlay: ovl_En_Wiz_Fire - * Description: Wizzrobe Fire/Ice Attack + * Description: Wizrobe Fire/Ice Attack */ #include "z_en_wiz_fire.h" @@ -17,18 +17,25 @@ void EnWizFire_Destroy(Actor* thisx, PlayState* play); void EnWizFire_Update(Actor* thisx, PlayState* play); void EnWizFire_Draw(Actor* thisx, PlayState* play); -void func_80A4984C(EnWizFire* this, PlayState* play); -void func_80A49A44(EnWizFire* this, PlayState* play); -void func_80A49F38(EnWizFire* this, PlayState* play); -void func_80A49FD8(EnWizFire* this, PlayState* play); -void func_80A4A11C(EnWizFire* this, PlayState* play); -void func_80A4A608(EnWizFire* this, PlayState* play); -void func_80A4BAB4(Actor* thisx, PlayState* play); -void func_80A4BC74(EnWizFire* this, Vec3f* arg1, Vec3f* arg2); -void func_80A4BDDC(EnWizFire* this, PlayState* play); -void func_80A4BF78(EnWizFire* this, PlayState* play); +void EnWiz_SetupMoveMagicProjectile(EnWizFire* this, PlayState* play); +void EnWiz_MoveMagicProjectile(EnWizFire* this, PlayState* play); +void EnWiz_SetupSmallFlame(EnWizFire* this, PlayState* play); +void EnWiz_SmallFlame(EnWizFire* this, PlayState* play); +void EnWiz_Pool(EnWizFire* this, PlayState* play); +void EnWiz_KillMagicProjectile(EnWizFire* this, PlayState* play); +void EnWizFire_DrawSmallFlame(Actor* thisx, PlayState* play); +void EnWizFire_InitializeEffect(EnWizFire* this, Vec3f* pos, Vec3f* accel); +void EnWizFire_UpdateEffects(EnWizFire* this, PlayState* play); +void EnWizFire_DrawEffects(EnWizFire* this, PlayState* play); -static s32 D_80A4C1C0 = 0; +typedef enum { + /* 0 */ EN_WIZ_FIRE_ACTION_MOVE_MAGIC_PROJECTILE, + /* 1 */ EN_WIZ_FIRE_ACTION_SMALL_FLAME, + /* 2 */ EN_WIZ_FIRE_ACTION_POOL, + /* 3 */ EN_WIZ_FIRE_ACTION_KILL_MAGIC_PROJECTILE, +} EnWizFireAction; + +static s32 sPoolHitByIceArrow = false; const ActorInit En_Wiz_Fire_InitVars = { ACTOR_EN_WIZ_FIRE, @@ -66,48 +73,52 @@ void EnWizFire_Init(Actor* thisx, PlayState* play) { EnWizFire* this = THIS; Collider_InitAndSetCylinder(play, &this->collider, &this->actor, &sCylinderInit); - this->unk_162 = this->actor.params; + this->type = EN_WIZ_FIRE_GET_TYPE(&this->actor); this->actor.targetMode = 3; - this->unk_172 = 10; - this->unk_1FC = 255.0f; + this->wallCheckTimer = 10; + this->alpha = 255.0f; this->actor.flags &= ~ACTOR_FLAG_1; if (!Player_HasMirrorShieldEquipped(play)) { this->collider.info.toucher.dmgFlags = 0x20000000; } - switch (this->unk_162) { - case 4: - this->unk_166 = 1; + switch (this->type) { + case EN_WIZ_FIRE_TYPE_ICE_MAGIC_PROJECTILE: + this->isIceType = true; this->collider.info.toucher.damage = 8; this->collider.info.toucher.effect = 2; this->collider.info.bumper.dmgFlags = (0x1000000 | 0x800 | 0x200 | 0x2); - this->unk_162 = 0; - - case 0: - if (this->unk_162 == 4) { - this->unk_162 = 0; + this->type = EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE; + // fallthrough + case EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE: + if (this->type == EN_WIZ_FIRE_TYPE_ICE_MAGIC_PROJECTILE) { + this->type = EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE; this->collider.info.toucher.damage = 8; } - - case 1: - case 3: - this->actionFunc = func_80A4984C; + // fallthrough + case EN_WIZ_FIRE_TYPE_ARCING_MAGIC_PROJECTILE: + case EN_WIZ_FIRE_TYPE_REFLECTED_MAGIC_PROJECTILE: + this->actionFunc = EnWiz_SetupMoveMagicProjectile; break; - case 2: - this->actor.draw = func_80A4BAB4; - this->unk_170 = Rand_S16Offset(0, 10000); - this->unk_160 = 1; + case EN_WIZ_FIRE_TYPE_SMALL_FLAME: + this->actor.draw = EnWizFire_DrawSmallFlame; + this->smallFlameScroll = Rand_S16Offset(0, 10000); + this->action = EN_WIZ_FIRE_ACTION_SMALL_FLAME; this->collider.info.toucher.damage = 2; - this->actionFunc = func_80A49F38; + this->actionFunc = EnWiz_SetupSmallFlame; + break; + + default: + break; } } void EnWizFire_Destroy(Actor* thisx, PlayState* play) { EnWizFire* this = THIS; - if (this->unk_162 == 0) { + if (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { play->envCtx.lightSettings.fogColor[2] = 0; play->envCtx.lightSettings.fogColor[1] = play->envCtx.lightSettings.fogColor[2]; play->envCtx.lightSettings.fogColor[0] = play->envCtx.lightSettings.fogColor[2]; @@ -122,146 +133,159 @@ void EnWizFire_Destroy(Actor* thisx, PlayState* play) { play->envCtx.lightSettings.ambientColor[0] = play->envCtx.lightSettings.fogColor[2]; play->envCtx.lightSettings.fogNear = play->envCtx.lightSettings.fogColor[2]; } + Collider_DestroyCylinder(play, &this->collider); } -void func_80A4984C(EnWizFire* this, PlayState* play) { - Vec3f sp44 = { 0.0f, 0.0f, 0.0f }; +void EnWiz_SetupMoveMagicProjectile(EnWizFire* this, PlayState* play) { + Vec3f velocity = { 0.0f, 0.0f, 0.0f }; s32 i; - for (i = 0; i < ARRAY_COUNT(this->unk_178); i++) { - this->unk_178[i] = this->actor.world.pos; + for (i = 0; i < ARRAY_COUNT(this->magicProjectilePos); i++) { + this->magicProjectilePos[i] = this->actor.world.pos; } - this->unk_16E = 0; + this->lowestUsedIndex = 0; + Matrix_Push(); Matrix_RotateYS(this->actor.world.rot.y, MTXMODE_NEW); Matrix_RotateXS(this->actor.world.rot.x, MTXMODE_APPLY); - if (this->unk_162 != 0) { - sp44.z = randPlusMinusPoint5Scaled(2.0f) + 8.0f; + if (this->type != EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { + velocity.z = randPlusMinusPoint5Scaled(2.0f) + 8.0f; } else { - sp44.z = 12.0f; + velocity.z = 12.0f; } - Matrix_MultVec3f(&sp44, &this->actor.velocity); + Matrix_MultVec3f(&velocity, &this->actor.velocity); Matrix_Pop(); + this->actor.world.rot.x = this->actor.world.rot.y = this->actor.world.rot.z = 0; - this->unk_168 = 50; - if (this->unk_162 != 0) { + this->timer = 50; + + if (this->type != EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { this->actor.velocity.y = 10.0f; this->actor.gravity = -1.0f; - this->unk_150 = 0.01f; + this->targetScale = 0.01f; } else { - this->unk_150 = 0.02f; - this->unk_168 = 100; + this->targetScale = 0.02f; + this->timer = 100; } - this->unk_160 = 0; - this->actionFunc = func_80A49A44; + + this->action = EN_WIZ_FIRE_ACTION_MOVE_MAGIC_PROJECTILE; + this->actionFunc = EnWiz_MoveMagicProjectile; } -void func_80A49A44(EnWizFire* this, PlayState* play) { - Vec3f sp54 = { 0.0f, 0.0f, 0.0f }; +/** + * Moves all types of magic projectiles around, including arcing ones created by the + * Fire Wizrobe's attack or ones reflected by the Mirror Shield. + */ +void EnWiz_MoveMagicProjectile(EnWizFire* this, PlayState* play) { + Vec3f velocity = { 0.0f, 0.0f, 0.0f }; this->actor.world.rot.z += 5000; - if (this->unk_162 != 0) { - this->unk_150 = 0.01f; + if (this->type != EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { + this->targetScale = 0.01f; } else { - this->unk_150 = 0.02f; + this->targetScale = 0.02f; } - if ((this->unk_168 == 0) && (this->unk_14C < 0.001f)) { + if ((this->timer == 0) && (this->scale < 0.001f)) { Math_Vec3f_Copy(&this->actor.velocity, &gZeroVec3f); - this->unk_160 = 3; - this->unk_16A = 0; - this->actionFunc = func_80A4A608; + this->action = EN_WIZ_FIRE_ACTION_KILL_MAGIC_PROJECTILE; + this->increaseLowestUsedIndexTimer = 0; + this->actionFunc = EnWiz_KillMagicProjectile; return; } - if (this->unk_168 == 0) { - this->unk_150 = 0.0f; + if (this->timer == 0) { + this->targetScale = 0.0f; } - Math_ApproachF(&this->unk_14C, this->unk_150, 0.2f, 0.01f); + Math_ApproachF(&this->scale, this->targetScale, 0.2f, 0.01f); - if (this->unk_172 == 0) { - if ((this->actor.bgCheckFlags & 8) && (this->unk_162 == 0) && (this->unk_168 != 0) && + if (this->wallCheckTimer == 0) { + if ((this->actor.bgCheckFlags & 8) && (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && (this->timer != 0) && (this->actor.bgCheckFlags & 8)) { - D_80A4C1C0 = 0; - this->unk_168 = 0; - this->unk_150 = 0.0f; + sPoolHitByIceArrow = false; + this->timer = 0; + this->targetScale = 0.0f; } } - if ((this->actor.bgCheckFlags & 1) && (this->unk_16A == 0)) { + if ((this->actor.bgCheckFlags & 1) && (this->poolTimer == 0)) { s32 i; - s16 phi_s0; - s32 temp; + s16 arcingProjectileRotY; + s32 pad; - if (this->unk_162 == 1) { - this->unk_16A = 10; + if (this->type == EN_WIZ_FIRE_TYPE_ARCING_MAGIC_PROJECTILE) { + this->increaseLowestUsedIndexTimer = 10; Matrix_Push(); Matrix_RotateYS((s16)randPlusMinusPoint5Scaled(0x100) + this->actor.world.rot.y, MTXMODE_NEW); - sp54.z = randPlusMinusPoint5Scaled(2.0f) + 8.0f; - Matrix_MultVec3f(&sp54, &this->actor.velocity); + velocity.z = randPlusMinusPoint5Scaled(2.0f) + 8.0f; + Matrix_MultVec3f(&velocity, &this->actor.velocity); Matrix_Pop(); this->actor.velocity.y = 6.0f; this->actor.gravity = -0.7f; - if (this->unk_164 == 0) { + if (!this->hasSpawnedSmallFlame) { Actor_Spawn(&play->actorCtx, play, ACTOR_EN_WIZ_FIRE, this->actor.world.pos.x, - this->actor.world.pos.y - 10.0f, this->actor.world.pos.z, 0, 0, 0, 2); - this->unk_164 = 1; + this->actor.world.pos.y - 10.0f, this->actor.world.pos.z, 0, 0, 0, + EN_WIZ_FIRE_TYPE_SMALL_FLAME); + this->hasSpawnedSmallFlame = true; } - this->unk_168 = 0; - this->unk_14C = 0.0f; + this->timer = 0; + this->scale = 0.0f; Math_Vec3f_Copy(&this->actor.velocity, &gZeroVec3f); - this->unk_160 = 3; - this->unk_16A = 0; - this->actionFunc = func_80A4A608; + this->action = EN_WIZ_FIRE_ACTION_KILL_MAGIC_PROJECTILE; + this->increaseLowestUsedIndexTimer = 0; + this->actionFunc = EnWiz_KillMagicProjectile; return; } - if ((this->unk_162 == 0) && (this->unk_168 != 0)) { + if ((this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && (this->timer != 0)) { if (this->actor.floorBgId == BGCHECK_SCENE) { - this->unk_16A = 100; - if (this->unk_166 == 0) { - phi_s0 = 0; + this->poolTimer = 100; + if (!this->isIceType) { + arcingProjectileRotY = 0; for (i = 0; i < 5; i++) { Actor_Spawn(&play->actorCtx, play, ACTOR_EN_WIZ_FIRE, this->actor.world.pos.x, - this->actor.world.pos.y, this->actor.world.pos.z, 0, phi_s0, 0, 1); - phi_s0 += BINANG_ADD((s32)randPlusMinusPoint5Scaled(0x1000), 0x3333); + this->actor.world.pos.y, this->actor.world.pos.z, 0, arcingProjectileRotY, 0, + EN_WIZ_FIRE_TYPE_ARCING_MAGIC_PROJECTILE); + arcingProjectileRotY += BINANG_ADD((s32)randPlusMinusPoint5Scaled(0x1000), 0x3333); } Actor_PlaySfxAtPos(&this->actor, NA_SE_IT_BOMB_EXPLOSION); - this->unk_16A = Rand_S16Offset(70, 30); - if (this->unk_16A != 0) { + this->poolTimer = Rand_S16Offset(70, 30); + if (this->poolTimer != 0) { Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_EXP - SFX_FLAG); } - } else if (this->unk_16A != 0) { + } else if (this->poolTimer != 0) { Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG); } + Math_Vec3f_Copy(&this->actor.velocity, &gZeroVec3f); - this->unk_168 = 0; - this->unk_160 = 2; - this->unk_14C = 0.0f; - this->actionFunc = func_80A4A11C; + this->timer = 0; + this->action = EN_WIZ_FIRE_ACTION_POOL; + this->scale = 0.0f; + this->actionFunc = EnWiz_Pool; } + return; } } - if ((this->unk_162 != 3) && (this->unk_168 != 0)) { + if ((this->type != EN_WIZ_FIRE_TYPE_REFLECTED_MAGIC_PROJECTILE) && (this->timer != 0)) { if (this->collider.base.acFlags & AC_HIT) { this->collider.base.acFlags &= ~AC_HIT; if (this->collider.info.acHitInfo->toucher.dmgFlags == 0x1000) { - this->unk_168 = 0; - this->unk_148 = 1; + this->timer = 0; + this->hitByIceArrow = true; SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 50, NA_SE_EV_ICE_MELT); } } @@ -272,104 +296,111 @@ void func_80A49A44(EnWizFire* this, PlayState* play) { this->collider.base.atFlags |= AT_TYPE_PLAYER; this->collider.info.toucher.dmgFlags = 0x20; this->collider.info.toucher.damage = 2; - this->unk_168 = 100; - this->unk_162 = 3; + this->timer = 100; + this->type = EN_WIZ_FIRE_TYPE_REFLECTED_MAGIC_PROJECTILE; this->actor.velocity.x *= -1.0f; this->actor.velocity.y *= -0.5f; this->actor.velocity.z *= -1.0f; if ((this->actor.parent != NULL) && (this->actor.parent->id == ACTOR_EN_WIZ) && (this->actor.parent->update != NULL)) { - ((EnWiz*)this->actor.parent)->unk_3BA = 0; + ((EnWiz*)this->actor.parent)->hasActiveProjectile = false; } } } } -void func_80A49F38(EnWizFire* this, PlayState* play) { - this->unk_150 = 0.02f; - this->unk_168 = Rand_S16Offset(50, 50); - this->unk_154 = randPlusMinusPoint5Scaled(1.0f) * 0.007f; - this->unk_158 = randPlusMinusPoint5Scaled(1.0f) * 0.005f; - this->unk_15C = randPlusMinusPoint5Scaled(1.0f) * 0.007f; - this->actionFunc = func_80A49FD8; +void EnWiz_SetupSmallFlame(EnWizFire* this, PlayState* play) { + this->targetScale = 0.02f; + this->timer = Rand_S16Offset(50, 50); + this->scaleMod.x = randPlusMinusPoint5Scaled(1.0f) * 0.007f; + this->scaleMod.y = randPlusMinusPoint5Scaled(1.0f) * 0.005f; + this->scaleMod.z = randPlusMinusPoint5Scaled(1.0f) * 0.007f; + this->actionFunc = EnWiz_SmallFlame; } -void func_80A49FD8(EnWizFire* this, PlayState* play) { - if (this->unk_168 > 10) { - Math_ApproachF(&this->unk_14C, this->unk_150, 0.3f, 0.01f); +/** + * Manages the small flame that is created when the arcing projectiles from the Fire Wizrobe's + * attack hit the floor. + */ +void EnWiz_SmallFlame(EnWizFire* this, PlayState* play) { + if (this->timer > 10) { + Math_ApproachF(&this->scale, this->targetScale, 0.3f, 0.01f); } else { - Math_ApproachF(&this->unk_14C, 2.0f * this->unk_150, 0.2f, 0.002f); - Math_ApproachZeroF(&this->unk_1FC, 1.0f, 35.0f); - if ((this->unk_168 == 0) && (this->unk_1FC < 2.0f)) { + Math_ApproachF(&this->scale, 2.0f * this->targetScale, 0.2f, 0.002f); + Math_ApproachZeroF(&this->alpha, 1.0f, 35.0f); + if ((this->timer == 0) && (this->alpha < 2.0f)) { Actor_MarkForDeath(&this->actor); } return; } if (this->collider.base.acFlags & AC_HIT) { - if (this->unk_168 != 0) { + if (this->timer != 0) { this->collider.base.acFlags &= ~AC_HIT; - if (this->unk_168 > 10) { - this->unk_168 -= 10; + if (this->timer > 10) { + this->timer -= 10; } if (this->collider.info.acHitInfo->toucher.dmgFlags == 0x1000) { - this->unk_168 = 0; - this->unk_148 = 1; + this->timer = 0; + this->hitByIceArrow = true; SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 50, NA_SE_EV_ICE_MELT); } } } - if (this->unk_168 != 0) { + if (this->timer != 0) { Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG); } } -void func_80A4A11C(EnWizFire* this, PlayState* play) { +/** + * Manages the pool of fire or ice that is created when a magic projectile hits the floor. + */ +void EnWiz_Pool(EnWizFire* this, PlayState* play) { s32 pad; if ((this->actor.parent != NULL) && (this->actor.parent->id == ACTOR_EN_WIZ) && (this->actor.parent->update != NULL) && (this->actor.parent->colChkInfo.health == 0)) { - this->unk_16A = 0; - this->unk_174 = 1; + this->poolTimer = 0; + this->playerHitByIceProjectile = true; } - this->unk_16E++; + this->lowestUsedIndex++; - if (this->unk_16E > 10) { - this->unk_16E = 10; + if (this->lowestUsedIndex > 10) { + this->lowestUsedIndex = 10; } - if (this->unk_16A != 0) { - Math_ApproachF(&this->unk_200, 60.0f, 0.5f, 10.0f); - if (this->unk_166 == 1) { - Vec3f sp40 = { 0.0f, 0.0f, 0.0f }; - Vec3f sp34; + if (this->poolTimer != 0) { + Math_ApproachF(&this->blendScale, 60.0f, 0.5f, 10.0f); + if (this->isIceType == true) { + Vec3f accel = { 0.0f, 0.0f, 0.0f }; + Vec3f pos; - sp40.x = randPlusMinusPoint5Scaled(3.0f) / 10.0f; - sp40.y = 0.23f; - sp40.z = randPlusMinusPoint5Scaled(3.0f) / 10.0f; + accel.x = randPlusMinusPoint5Scaled(3.0f) / 10.0f; + accel.y = 0.23f; + accel.z = randPlusMinusPoint5Scaled(3.0f) / 10.0f; - Math_Vec3f_Copy(&sp34, &this->actor.world.pos); - sp34.x += randPlusMinusPoint5Scaled(150.0f); - sp34.z += randPlusMinusPoint5Scaled(150.0f); + Math_Vec3f_Copy(&pos, &this->actor.world.pos); + pos.x += randPlusMinusPoint5Scaled(150.0f); + pos.z += randPlusMinusPoint5Scaled(150.0f); - Math_ApproachF(&this->unk_1F0, 0.022f, 0.3f, 0.01f); - this->collider.dim.radius = this->unk_1F0 * 4300.0f; + Math_ApproachF(&this->poolScale, 0.022f, 0.3f, 0.01f); + this->collider.dim.radius = this->poolScale * 4300.0f; this->collider.dim.height = 30; this->collider.dim.yShift = 15; - func_80A4BC74(this, &sp34, &sp40); + EnWizFire_InitializeEffect(this, &pos, &accel); Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG); return; } - Math_ApproachF(&this->unk_1F0, 0.02f, 0.3f, 0.002f); - Math_ApproachF(&this->unk_1F8, 0.02f, 0.3f, 0.002f); - Math_ApproachF(&this->unk_1F4, 0.02f, 0.3f, 0.2f); - this->collider.dim.radius = this->unk_1F0 * 4000.0f; - this->collider.dim.height = this->unk_1F4 * 1850.0f; + Math_ApproachF(&this->poolScale, 0.02f, 0.3f, 0.002f); + Math_ApproachF(&this->fireSmokeScale, 0.02f, 0.3f, 0.002f); + Math_ApproachF(&this->bigFlameScale, 0.02f, 0.3f, 0.2f); + this->collider.dim.radius = this->poolScale * 4000.0f; + this->collider.dim.height = this->bigFlameScale * 1850.0f; this->collider.dim.yShift = -15; if (this->collider.dim.height < 2) { @@ -378,231 +409,228 @@ void func_80A4A11C(EnWizFire* this, PlayState* play) { if (this->collider.base.acFlags & AC_HIT) { this->collider.base.acFlags &= ~AC_HIT; - if ((D_80A4C1C0 == 0) && (this->collider.info.acHitInfo->toucher.dmgFlags == 0x1000)) { - D_80A4C1C0 = 1; - this->unk_148 = 1; - this->unk_16A = 0; + if (!sPoolHitByIceArrow && (this->collider.info.acHitInfo->toucher.dmgFlags == 0x1000)) { + sPoolHitByIceArrow = true; + this->hitByIceArrow = true; + this->poolTimer = 0; SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 50, NA_SE_EV_ICE_MELT); } } + this->actor.world.pos.y = this->actor.floorHeight + 10.0f; Actor_SetFocus(&this->actor, 0.0f); return; } - Math_ApproachZeroF(&this->unk_200, 0.2f, 3.0f); + Math_ApproachZeroF(&this->blendScale, 0.2f, 3.0f); - if (this->unk_166 == 1) { - Math_ApproachZeroF(&this->unk_1F0, 0.046f, 0.001f); + if (this->isIceType == true) { + Math_ApproachZeroF(&this->poolScale, 0.046f, 0.001f); Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG); - if (this->unk_164 == 0) { - if ((this->actor.parent != NULL) && (this->actor.parent->id == ACTOR_EN_WIZ) && (this->unk_1F0 < 0.05f)) { + if (!this->shouldPoolFadeOut) { + if ((this->actor.parent != NULL) && (this->actor.parent->id == ACTOR_EN_WIZ) && (this->poolScale < 0.05f)) { EnWiz* wiz = (EnWiz*)this->actor.parent; this->collider.dim.yShift = -15; - this->unk_164 = 1; - wiz->unk_3BA = 0; + this->shouldPoolFadeOut = true; + wiz->hasActiveProjectile = false; } } - if ((this->unk_164 != 0) && (this->unk_1F0 < 0.05f)) { - Math_ApproachZeroF(&this->unk_1FC, 1.0f, 5.0f); + if (this->shouldPoolFadeOut && (this->poolScale < 0.05f)) { + Math_ApproachZeroF(&this->alpha, 1.0f, 5.0f); } - if ((this->unk_1F0 < 0.001f) && (this->unk_204 < 0.001f)) { - D_80A4C1C0 = 0; + if ((this->poolScale < 0.001f) && (this->blendScaleFrac < 0.001f)) { + sPoolHitByIceArrow = false; Actor_MarkForDeath(&this->actor); } + return; } - Math_ApproachZeroF(&this->unk_1F4, 0.1f, 0.01f); + Math_ApproachZeroF(&this->bigFlameScale, 0.1f, 0.01f); - if (this->unk_1F4 < 0.01f) { - Math_ApproachZeroF(&this->unk_1FC, 1.0f, 10.0f); - if ((this->unk_1FC < 10.0f) && (this->unk_204 < 0.001f)) { - D_80A4C1C0 = 0; - if ((this->actor.parent != NULL) && (this->unk_162 == 0) && (this->actor.parent->id == ACTOR_EN_WIZ) && - (this->actor.parent->update != NULL)) { + if (this->bigFlameScale < 0.01f) { + Math_ApproachZeroF(&this->alpha, 1.0f, 10.0f); + if ((this->alpha < 10.0f) && (this->blendScaleFrac < 0.001f)) { + sPoolHitByIceArrow = false; + if ((this->actor.parent != NULL) && (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && + (this->actor.parent->id == ACTOR_EN_WIZ) && (this->actor.parent->update != NULL)) { EnWiz* wiz = (EnWiz*)this->actor.parent; - wiz->unk_3BA = 0; + wiz->hasActiveProjectile = false; } + Actor_MarkForDeath(&this->actor); } } } -void func_80A4A608(EnWizFire* this, PlayState* play) { - if (this->unk_16A == 0) { - this->unk_16A = 2; - this->unk_16E++; - if (this->unk_16E >= 6) { - if ((this->actor.parent != NULL) && (this->unk_162 == 0) && (this->actor.parent->id == ACTOR_EN_WIZ)) { +void EnWiz_KillMagicProjectile(EnWizFire* this, PlayState* play) { + if (this->increaseLowestUsedIndexTimer == 0) { + this->increaseLowestUsedIndexTimer = 2; + this->lowestUsedIndex++; + if (this->lowestUsedIndex >= 6) { + if ((this->actor.parent != NULL) && (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && + (this->actor.parent->id == ACTOR_EN_WIZ)) { EnWiz* wiz = (EnWiz*)this->actor.parent; - D_80A4C1C0 = 0; + sPoolHitByIceArrow = false; if (wiz->actor.update != NULL) { - wiz->unk_3BA = 0; + wiz->hasActiveProjectile = false; } } + Actor_MarkForDeath(&this->actor); } } } void EnWizFire_Update(Actor* thisx, PlayState* play2) { - static Color_RGB8 D_80A4C234[] = { - { 100, 40, 40 }, { 180, 0x78, 80 }, { 155, 80, 80 }, { 125, 20, 0 }, - { 0, 0, 0 }, { 200, 250, 250 }, { 100, 250, 250 }, { 225, 255, 235 }, + // These are AmbientColor, DiffuseColor1, DiffuseColor2, and fogColor + static Color_RGB8 lightSettingsColors[] = { + { 100, 40, 40 }, { 180, 120, 80 }, { 155, 80, 80 }, { 125, 20, 0 }, // Fire + { 0, 0, 0 }, { 200, 250, 250 }, { 100, 250, 250 }, { 225, 255, 235 }, // Ice }; - static Color_RGBA8 D_80A4C24C = { 250, 250, 250, 255 }; - static Color_RGBA8 D_80A4C250 = { 180, 180, 180, 255 }; PlayState* play = play2; EnWizFire* this = THIS; Player* player = GET_PLAYER(play); s32 j; - s16 temp_s0; - s16 idx; + s16 randomScale; + s16 index; - Actor_SetScale(&this->actor, this->unk_14C); - func_80A4BDDC(this, play); - this->unk_204 = this->unk_200 / 60.0f; + Actor_SetScale(&this->actor, this->scale); + EnWizFire_UpdateEffects(this, play); + this->blendScaleFrac = this->blendScale / 60.0f; - if (this->unk_162 == 0) { + if (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { Actor* wiz = this->actor.parent; - if ((wiz != NULL) && (wiz->id == ACTOR_EN_WIZ) && (wiz->update != NULL) && (((EnWiz*)wiz)->unk_74A != 2)) { - f32 phi_f0; + if ((wiz != NULL) && (wiz->id == ACTOR_EN_WIZ) && (wiz->update != NULL) && + (((EnWiz*)wiz)->type != EN_WIZ_TYPE_FIRE_NO_BGM)) { + f32 fogNear; - idx = this->unk_166 * 4; - - phi_f0 = 970.0f; - if (this->unk_166 == 0) { - phi_f0 = 968.0f; + index = this->isIceType * 4; + fogNear = 970.0f; + if (!this->isIceType) { + fogNear = 968.0f; } - play->envCtx.lightSettings.fogNear = (phi_f0 - (s16)play->envCtx.unk_C4.fogNear) * this->unk_204; + play->envCtx.lightSettings.fogNear = (fogNear - (s16)play->envCtx.unk_C4.fogNear) * this->blendScaleFrac; play->envCtx.lightSettings.ambientColor[0] = - ((f32)D_80A4C234[idx].r - play->envCtx.unk_C4.ambientColor[0]) * this->unk_204; + ((f32)lightSettingsColors[index].r - play->envCtx.unk_C4.ambientColor[0]) * this->blendScaleFrac; play->envCtx.lightSettings.ambientColor[1] = - ((f32)D_80A4C234[idx].g - play->envCtx.unk_C4.ambientColor[1]) * this->unk_204; + ((f32)lightSettingsColors[index].g - play->envCtx.unk_C4.ambientColor[1]) * this->blendScaleFrac; play->envCtx.lightSettings.ambientColor[2] = - ((f32)D_80A4C234[idx].b - play->envCtx.unk_C4.ambientColor[2]) * this->unk_204; + ((f32)lightSettingsColors[index].b - play->envCtx.unk_C4.ambientColor[2]) * this->blendScaleFrac; - idx++; + index++; play->envCtx.lightSettings.diffuseColor1[0] = - ((f32)D_80A4C234[idx].r - play->envCtx.unk_C4.diffuseColor1[0]) * this->unk_204; + ((f32)lightSettingsColors[index].r - play->envCtx.unk_C4.diffuseColor1[0]) * this->blendScaleFrac; play->envCtx.lightSettings.diffuseColor1[1] = - ((f32)D_80A4C234[idx].g - play->envCtx.unk_C4.diffuseColor1[1]) * this->unk_204; + ((f32)lightSettingsColors[index].g - play->envCtx.unk_C4.diffuseColor1[1]) * this->blendScaleFrac; play->envCtx.lightSettings.diffuseColor1[2] = - ((f32)D_80A4C234[idx].b - play->envCtx.unk_C4.diffuseColor1[2]) * this->unk_204; + ((f32)lightSettingsColors[index].b - play->envCtx.unk_C4.diffuseColor1[2]) * this->blendScaleFrac; - idx++; + index++; play->envCtx.lightSettings.diffuseColor2[0] = - ((f32)D_80A4C234[idx].r - play->envCtx.unk_C4.diffuseColor[0]) * this->unk_204; + ((f32)lightSettingsColors[index].r - play->envCtx.unk_C4.diffuseColor[0]) * this->blendScaleFrac; play->envCtx.lightSettings.diffuseColor2[1] = - ((f32)D_80A4C234[idx].g - play->envCtx.unk_C4.diffuseColor[1]) * this->unk_204; + ((f32)lightSettingsColors[index].g - play->envCtx.unk_C4.diffuseColor[1]) * this->blendScaleFrac; play->envCtx.lightSettings.diffuseColor2[2] = - ((f32)D_80A4C234[idx].b - play->envCtx.unk_C4.diffuseColor[2]) * this->unk_204; + ((f32)lightSettingsColors[index].b - play->envCtx.unk_C4.diffuseColor[2]) * this->blendScaleFrac; - idx++; + index++; play->envCtx.lightSettings.fogColor[0] = - ((f32)D_80A4C234[idx].r - play->envCtx.unk_C4.fogColor[0]) * this->unk_204; + ((f32)lightSettingsColors[index].r - play->envCtx.unk_C4.fogColor[0]) * this->blendScaleFrac; play->envCtx.lightSettings.fogColor[1] = - ((f32)D_80A4C234[idx].g - play->envCtx.unk_C4.fogColor[1]) * this->unk_204; + ((f32)lightSettingsColors[index].g - play->envCtx.unk_C4.fogColor[1]) * this->blendScaleFrac; play->envCtx.lightSettings.fogColor[2] = - ((f32)D_80A4C234[idx].b - play->envCtx.unk_C4.fogColor[2]) * this->unk_204; + ((f32)lightSettingsColors[index].b - play->envCtx.unk_C4.fogColor[2]) * this->blendScaleFrac; } } - this->unk_170++; + this->smallFlameScroll++; this->actionFunc(this, play); this->actor.shape.yOffset = 10.0f; Actor_UpdatePos(&this->actor); - this->unk_178[0] = this->actor.world.pos; + this->magicProjectilePos[0] = this->actor.world.pos; - for (j = 8; j >= 0; j--) { - this->unk_178[j + 1] = this->unk_178[j]; + for (j = ARRAY_COUNT(this->magicProjectilePos) - 2; j >= 0; j--) { + this->magicProjectilePos[j + 1] = this->magicProjectilePos[j]; } this->actor.velocity.y += this->actor.gravity; - if (this->unk_172 != 0) { - this->unk_172--; - } - - if (this->unk_168 != 0) { - this->unk_168--; - } - - if (this->unk_16C != 0) { - this->unk_16C--; - } - - if (this->unk_16A != 0) { - this->unk_16A--; - } + DECR(this->wallCheckTimer); + DECR(this->timer); + DECR(this->steamSpawnTimer); + DECR(this->poolTimer); Actor_UpdateBgCheckInfo(play, &this->actor, 20.0f, 5.0f, 10, 0x1D); - if (((this->unk_148 != 0) || (D_80A4C1C0 != 0)) && (this->unk_16C == 0)) { - Vec3f sp70; - Vec3f sp64; - Vec3f sp58; - f32 sp54; + if ((this->hitByIceArrow || sPoolHitByIceArrow) && (this->steamSpawnTimer == 0)) { + Vec3f accel; + Vec3f velocity; + Vec3f pos; + f32 scaleStep; s32 i; - sp70.x = 0.0f; - sp70.y = 1.0f; - sp70.z = 0.0f; - sp64.x = 0.0f; - sp64.y = 1.0f; - sp64.z = 0.0f; + accel.x = 0.0f; + accel.y = 1.0f; + accel.z = 0.0f; + velocity.x = 0.0f; + velocity.y = 1.0f; + velocity.z = 0.0f; - sp54 = Rand_S16Offset(20, 10); - if (this->unk_162 == 0) { - sp54 = Rand_S16Offset(40, 20); + scaleStep = Rand_S16Offset(20, 10); + if (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { + scaleStep = Rand_S16Offset(40, 20); } - this->unk_16C = Rand_S16Offset(2, 2); + this->steamSpawnTimer = Rand_S16Offset(2, 2); for (i = 0; i < 2; i++) { - temp_s0 = Rand_S16Offset(20, 20); - sp58.x = ((f32)((Rand_ZeroOne() < 0.5f) ? -1 : 1) * temp_s0) + this->actor.world.pos.x; - sp58.y = (Rand_ZeroOne() * 20.0f) + this->actor.floorHeight; - temp_s0 = Rand_S16Offset(20, 20); - sp58.z = ((f32)((Rand_ZeroOne() < .5f) ? -1 : 1) * temp_s0) + this->actor.world.pos.z; - func_800B0DE0(play, &sp58, &sp64, &sp70, &D_80A4C24C, &D_80A4C250, Rand_S16Offset(350, 100), sp54); + static Color_RGBA8 sSteamPrimColor = { 250, 250, 250, 255 }; + static Color_RGBA8 sSteamEnvColor = { 180, 180, 180, 255 }; + + randomScale = Rand_S16Offset(20, 20); + pos.x = ((f32)((Rand_ZeroOne() < 0.5f) ? -1 : 1) * randomScale) + this->actor.world.pos.x; + pos.y = (Rand_ZeroOne() * 20.0f) + this->actor.floorHeight; + randomScale = Rand_S16Offset(20, 20); + pos.z = ((f32)((Rand_ZeroOne() < .5f) ? -1 : 1) * randomScale) + this->actor.world.pos.z; + func_800B0DE0(play, &pos, &velocity, &accel, &sSteamPrimColor, &sSteamEnvColor, Rand_S16Offset(350, 100), + scaleStep); } } - if (this->unk_160 < 2) { - this->collider.dim.radius = (this->unk_14C * 15.0f) + 25.0f; - this->collider.dim.height = (this->unk_14C * 15.0f) + 25.0f; - this->collider.dim.yShift = (this->unk_14C * -0.75f) - 5.0f; + if (this->action < EN_WIZ_FIRE_ACTION_POOL) { + this->collider.dim.radius = (this->scale * 15.0f) + 25.0f; + this->collider.dim.height = (this->scale * 15.0f) + 25.0f; + this->collider.dim.yShift = (this->scale * -0.75f) - 5.0f; } - if (this->unk_162 == 2) { + if (this->type == EN_WIZ_FIRE_TYPE_SMALL_FLAME) { this->collider.dim.radius = 10; - this->collider.dim.height = this->unk_14C * 5000.0f; + this->collider.dim.height = this->scale * 5000.0f; this->collider.dim.yShift = 0; } if (this->collider.base.atFlags & AT_HIT) { this->collider.base.atFlags &= ~AT_HIT; - if (this->unk_162 == 0) { + if (this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) { Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_WIZ_LAUGH2); if (player->invincibilityTimer > 0) { player->invincibilityTimer += 40; - if (this->unk_166 != 0) { + if (this->isIceType) { player->invincibilityTimer += 50; - this->unk_174 = 1; + this->playerHitByIceProjectile = true; } } } @@ -612,7 +640,8 @@ void EnWizFire_Update(Actor* thisx, PlayState* play2) { player->unk_AE8 = 90; } - if ((this->unk_148 == 0) && (D_80A4C1C0 == 0) && ((this->unk_162 != 0) || (this->unk_1FC > 200.0f))) { + if (!this->hitByIceArrow && !sPoolHitByIceArrow && + ((this->type != EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) || (this->alpha > 200.0f))) { Collider_UpdateCylinder(&this->actor, &this->collider); CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); if (player->invincibilityTimer == 0) { @@ -621,61 +650,63 @@ void EnWizFire_Update(Actor* thisx, PlayState* play2) { } } -void func_80A4B0C8(EnWizFire* this, PlayState* play) { +void EnWizFire_DrawIcePool(EnWizFire* this, PlayState* play) { s32 pad; OPEN_DISPS(play->state.gfxCtx); - if ((this->unk_162 == 0) && (this->unk_160 == 2)) { + if ((this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && (this->action == EN_WIZ_FIRE_ACTION_POOL)) { func_8012C28C(play->state.gfxCtx); func_8012C2DC(play->state.gfxCtx); Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z, MTXMODE_NEW); - Matrix_Scale(this->unk_1F0, this->unk_1F0, this->unk_1F0, MTXMODE_APPLY); + Matrix_Scale(this->poolScale, this->poolScale, this->poolScale, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gDPPipeSync(POLY_XLU_DISP++); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s8)this->unk_1FC); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s8)this->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 0, 40, 30, 80); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_005190); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 215, 215, 215, (s8)this->unk_1FC); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeIcePoolDL); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 215, 215, 215, (s8)this->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128); gSPSegment(POLY_XLU_DISP++, 0x08, - Gfx_TwoTexScroll(play->state.gfxCtx, 0, -play->state.frames & 0x7F, -play->state.frames & 0x7F, 0x20, - 0x40, 1, play->state.frames & 0xFF, play->state.frames & 0xFF, 0x10, 0x10)); + Gfx_TwoTexScroll(play->state.gfxCtx, 0, -play->state.frames & 0x7F, -play->state.frames & 0x7F, 32, + 64, 1, play->state.frames & 0xFF, play->state.frames & 0xFF, 16, 16)); Matrix_RotateYS(0, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_005750); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeIcePoolShineDL); } - func_80A4BF78(this, play); + EnWizFire_DrawEffects(this, play); CLOSE_DISPS(play->state.gfxCtx); } -void func_80A4B33C(EnWizFire* this, PlayState* play2) { +void EnWizFire_DrawFirePoolAndFlame(EnWizFire* this, PlayState* play2) { PlayState* play = play2; OPEN_DISPS(play->state.gfxCtx); - if ((this->unk_162 == 0) && (this->unk_160 == 2)) { + if ((this->type == EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE) && (this->action == EN_WIZ_FIRE_ACTION_POOL)) { func_8012C28C(play->state.gfxCtx); func_8012C2DC(play->state.gfxCtx); + Matrix_Push(); Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z, MTXMODE_NEW); - Matrix_Scale(this->unk_1F0, this->unk_1F0, this->unk_1F0, MTXMODE_APPLY); + Matrix_Scale(this->poolScale, this->poolScale, this->poolScale, MTXMODE_APPLY); gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_TwoTexScroll(play->state.gfxCtx, 0, -play->state.frames % 128, 0, 0x20, 0x20, 1, (play->state.frames * 2) % 128, 0, 0x20, 0x20)); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gDPPipeSync(POLY_XLU_DISP++); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 40, 0, (s8)this->unk_1FC); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 100, 40, 0, (s8)this->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 255, 245, 255, 128); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_003120); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeFirePoolDL); Matrix_Pop(); + Matrix_Push(); Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z, MTXMODE_NEW); Matrix_ReplaceRotation(&play->billboardMtxF); @@ -684,16 +715,17 @@ void func_80A4B33C(EnWizFire* this, PlayState* play2) { Gfx_TwoTexScroll(play->state.gfxCtx, 0, play->state.frames % 128, (-play->state.frames * 6) % 256, 0x20, 0x40, 1, (play->state.frames * 2) % 128, (-play->state.frames * 6) % 256, 0x20, 0x40)); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 80, 0, 0, (s8)this->unk_1FC); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 80, 0, 0, (s8)this->alpha); gDPPipeSync(POLY_XLU_DISP++); gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 100); - Matrix_Scale(this->unk_1F8, this->unk_1F8, this->unk_1F8, MTXMODE_APPLY); + Matrix_Scale(this->fireSmokeScale, this->fireSmokeScale, this->fireSmokeScale, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_003640); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeFireSmokeDL); Matrix_Pop(); + Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight, this->actor.world.pos.z, MTXMODE_NEW); Matrix_ReplaceRotation(&play->billboardMtxF); @@ -704,10 +736,10 @@ void func_80A4B33C(EnWizFire* this, PlayState* play2) { gDPPipeSync(POLY_XLU_DISP++); gDPSetEnvColor(POLY_XLU_DISP++, 200, 235, 240, 128); - Matrix_Scale(this->unk_1F4, this->unk_1F4, this->unk_1F4, MTXMODE_APPLY); + Matrix_Scale(this->bigFlameScale, this->bigFlameScale, this->bigFlameScale, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_003FC0); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeBigFlameDL); } CLOSE_DISPS(play->state.gfxCtx); @@ -724,11 +756,11 @@ void EnWizFire_Draw(Actor* thisx, PlayState* play2) { func_8012C2DC(play->state.gfxCtx); Matrix_Push(); - for (i = 9; i >= this->unk_16E; i--) { - f32 temp_f20 = this->actor.scale.x - (i * -0.0019f); + for (i = ARRAY_COUNT(this->magicProjectilePos) - 1; i >= this->lowestUsedIndex; i--) { + f32 scale = this->actor.scale.x - (i * -0.0019f); - if (temp_f20 > 0.0f) { - if (this->unk_166 == 0) { + if (scale > 0.0f) { + if (!this->isIceType) { gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255 - (i * 25), 0, 255 - (i * 25)); gDPSetEnvColor(POLY_XLU_DISP++, 255 - (i * 25), 0, 0, 0); } else { @@ -736,14 +768,14 @@ void EnWizFire_Draw(Actor* thisx, PlayState* play2) { gDPSetEnvColor(POLY_XLU_DISP++, 220, 255, 235, 0); } - Matrix_Translate(this->unk_178[i].x, this->unk_178[i].y + this->actor.shape.yOffset, this->unk_178[i].z, - MTXMODE_NEW); - Matrix_Scale(temp_f20, temp_f20, temp_f20, MTXMODE_APPLY); + Matrix_Translate(this->magicProjectilePos[i].x, this->magicProjectilePos[i].y + this->actor.shape.yOffset, + this->magicProjectilePos[i].z, MTXMODE_NEW); + Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); Matrix_ReplaceRotation(&play->billboardMtxF); Matrix_RotateZS(this->actor.world.rot.z, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_002B40); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeMagicProjectileDL); } } @@ -751,92 +783,92 @@ void EnWizFire_Draw(Actor* thisx, PlayState* play2) { CLOSE_DISPS(play->state.gfxCtx); - if (this->unk_166 == 0) { - func_80A4B33C(this, play); + if (!this->isIceType) { + EnWizFire_DrawFirePoolAndFlame(this, play); } else { - func_80A4B0C8(this, play); + EnWizFire_DrawIcePool(this, play); } } -void func_80A4BAB4(Actor* thisx, PlayState* play) { +void EnWizFire_DrawSmallFlame(Actor* thisx, PlayState* play) { s32 pad; EnWizFire* this = THIS; OPEN_DISPS(play->state.gfxCtx); Matrix_Translate(this->actor.world.pos.x, this->actor.floorHeight + 20.0f, this->actor.world.pos.z, MTXMODE_NEW); - Matrix_Scale(this->unk_14C + this->unk_154, this->unk_14C + this->unk_158, this->unk_14C + this->unk_15C, + Matrix_Scale(this->scale + this->scaleMod.x, this->scale + this->scaleMod.y, this->scale + this->scaleMod.z, MTXMODE_APPLY); gSPSegment(POLY_XLU_DISP++, 0x08, - Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 0x20, 0x20, 1, this->unk_170 & 0x7F, - (-this->unk_170 * 10) & 0x7F, 0x20, 0x20)); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 100, 50, 0, (s8)this->unk_1FC); + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 32, 32, 1, this->smallFlameScroll & 0x7F, + (-this->smallFlameScroll * 10) & 0x7F, 32, 32)); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 100, 50, 0, (s8)this->alpha); gDPSetEnvColor(POLY_XLU_DISP++, 200, 235, 245, 255); Matrix_Mult(&play->billboardMtxF, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_002630); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeSmallFlameDL); CLOSE_DISPS(play->state.gfxCtx); } -void func_80A4BC74(EnWizFire* this, Vec3f* arg1, Vec3f* arg2) { +void EnWizFire_InitializeEffect(EnWizFire* this, Vec3f* pos, Vec3f* accel) { s16 i; - EnWizFireStruct* ptr = this->unk_254; + EnWizFireEffect* effect = &this->effects[0]; - for (i = 0; i < ARRAY_COUNT(this->unk_254); i++, ptr++) { - if (ptr->unk_00 == 0) { - ptr->unk_00 = 1; - Math_Vec3f_Copy(&ptr->unk_1C, &gZeroVec3f); - ptr->unk_01 = Rand_ZeroFloat(100.0f); - ptr->unk_10 = *arg1; - ptr->unk_28 = *arg2; - ptr->unk_0C = (Rand_ZeroFloat(5.0f) + 20.0f) * 0.001f; - ptr->unk_08 = 0; - ptr->unk_06 = 0; + for (i = 0; i < ARRAY_COUNT(this->effects); i++, effect++) { + if (!effect->isEnabled) { + effect->isEnabled = true; + Math_Vec3f_Copy(&effect->velocity, &gZeroVec3f); + effect->smokeScroll = Rand_ZeroFloat(100.0f); + effect->pos = *pos; + effect->accel = *accel; + effect->scale = (Rand_ZeroFloat(5.0f) + 20.0f) * 0.001f; + effect->shouldDecreaseAlpha = 0; + effect->alpha = 0; break; } } } -void func_80A4BDDC(EnWizFire* this, PlayState* play) { +void EnWizFire_UpdateEffects(EnWizFire* this, PlayState* play) { s32 i; - EnWizFireStruct* ptr = &this->unk_254[0]; + EnWizFireEffect* effect = &this->effects[0]; - for (i = 0; i < ARRAY_COUNT(this->unk_254); i++, ptr++) { - if (ptr->unk_00 != 0) { - ptr->unk_01++; + for (i = 0; i < ARRAY_COUNT(this->effects); i++, effect++) { + if (effect->isEnabled) { + effect->smokeScroll++; - ptr->unk_10.x += ptr->unk_1C.x; - ptr->unk_10.y += ptr->unk_1C.y; - ptr->unk_10.z += ptr->unk_1C.z; + effect->pos.x += effect->velocity.x; + effect->pos.y += effect->velocity.y; + effect->pos.z += effect->velocity.z; - ptr->unk_1C.x += ptr->unk_28.x; - ptr->unk_1C.y += ptr->unk_28.y; - ptr->unk_1C.z += ptr->unk_28.z; + effect->velocity.x += effect->accel.x; + effect->velocity.y += effect->accel.y; + effect->velocity.z += effect->accel.z; - if (ptr->unk_08 == 0) { - ptr->unk_06 += 10; - if (ptr->unk_06 >= 100) { - ptr->unk_08 = 1; + if (!effect->shouldDecreaseAlpha) { + effect->alpha += 10; + if (effect->alpha >= 100) { + effect->shouldDecreaseAlpha = true; } } else { - ptr->unk_06 -= 8; - if (ptr->unk_06 <= 0) { - ptr->unk_06 = 0; - ptr->unk_00 = 0; + effect->alpha -= 8; + if (effect->alpha <= 0) { + effect->alpha = 0; + effect->isEnabled = false; } } } } } -void func_80A4BF78(EnWizFire* this, PlayState* play) { +void EnWizFire_DrawEffects(EnWizFire* this, PlayState* play) { s16 i; - u8 flag; - EnWizFireStruct* ptr = &this->unk_254[0]; + u8 materialFlag; + EnWizFireEffect* effect = &this->effects[0]; GraphicsContext* gfxCtx = play->state.gfxCtx; OPEN_DISPS(gfxCtx); @@ -844,27 +876,27 @@ void func_80A4BF78(EnWizFire* this, PlayState* play) { func_8012C28C(play->state.gfxCtx); func_8012C2DC(play->state.gfxCtx); - flag = false; - for (i = 0; i < ARRAY_COUNT(this->unk_254); i++, ptr++) { - if (ptr->unk_00 != 0) { - if (!flag) { - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_000E70); - flag++; + materialFlag = false; + for (i = 0; i < ARRAY_COUNT(this->effects); i++, effect++) { + if (effect->isEnabled) { + if (!materialFlag) { + gSPDisplayList(POLY_XLU_DISP++, gWizrobeIceSmokeMaterialDL); + materialFlag++; } - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, ptr->unk_06); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, effect->alpha); gSPSegment(POLY_XLU_DISP++, 0x08, - Gfx_TwoTexScroll(play->state.gfxCtx, 0, (ptr->unk_01 * 3) & 0x7F, (ptr->unk_01 * 0xF) & 0xFF, - 0x20, 0x40, 1, 0, 0, 0x20, 0x20)); + Gfx_TwoTexScroll(play->state.gfxCtx, 0, (effect->smokeScroll * 3) & 0x7F, + (effect->smokeScroll * 0xF) & 0xFF, 32, 64, 1, 0, 0, 32, 32)); - Matrix_Translate(ptr->unk_10.x, ptr->unk_10.y, ptr->unk_10.z, MTXMODE_NEW); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); Matrix_ReplaceRotation(&play->billboardMtxF); - Matrix_Scale(ptr->unk_0C, ptr->unk_0C, 1.0f, MTXMODE_APPLY); + Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gDPSetRenderMode(POLY_XLU_DISP++, G_RM_PASS, G_RM_AA_ZB_XLU_SURF2); gSPClearGeometryMode(POLY_XLU_DISP++, G_CULL_BACK | G_FOG); - gSPDisplayList(POLY_XLU_DISP++, object_wiz_DL_000FD8); + gSPDisplayList(POLY_XLU_DISP++, gWizrobeIceSmokeModelDL); } } diff --git a/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.h b/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.h index b628404bba..180192d4c5 100644 --- a/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.h +++ b/src/overlays/actors/ovl_En_Wiz_Fire/z_en_wiz_fire.h @@ -3,52 +3,65 @@ #include "global.h" +typedef enum { + /* 0 */ EN_WIZ_FIRE_TYPE_MAGIC_PROJECTILE, + /* 1 */ EN_WIZ_FIRE_TYPE_ARCING_MAGIC_PROJECTILE, + /* 2 */ EN_WIZ_FIRE_TYPE_SMALL_FLAME, + /* 3 */ EN_WIZ_FIRE_TYPE_REFLECTED_MAGIC_PROJECTILE, + /* 4 */ EN_WIZ_FIRE_TYPE_ICE_MAGIC_PROJECTILE +} EnWizFireType; + +#define EN_WIZ_FIRE_GET_TYPE(thisx) ((thisx)->params) + struct EnWizFire; typedef void (*EnWizFireActionFunc)(struct EnWizFire*, PlayState*); typedef struct { - /* 0x00 */ u8 unk_00; - /* 0x01 */ u8 unk_01; + /* 0x00 */ u8 isEnabled; + /* 0x01 */ u8 smokeScroll; /* 0x02 */ UNK_TYPE1 unk02[0x4]; - /* 0x06 */ s16 unk_06; - /* 0x08 */ s16 unk_08; - /* 0x0A */ UNK_TYPE1 unk0A[0x2]; - /* 0x0C */ f32 unk_0C; - /* 0x10 */ Vec3f unk_10; - /* 0x1C */ Vec3f unk_1C; - /* 0x28 */ Vec3f unk_28; -} EnWizFireStruct; // size = 0x34 + /* 0x06 */ s16 alpha; + /* 0x08 */ s16 shouldDecreaseAlpha; + /* 0x0C */ f32 scale; + /* 0x10 */ Vec3f pos; + /* 0x1C */ Vec3f velocity; + /* 0x28 */ Vec3f accel; +} EnWizFireEffect; // size = 0x34 typedef struct EnWizFire { /* 0x0000 */ Actor actor; /* 0x0144 */ EnWizFireActionFunc actionFunc; - /* 0x0148 */ u8 unk_148; - /* 0x014C */ f32 unk_14C; - /* 0x0150 */ f32 unk_150; - /* 0x0154 */ f32 unk_154; - /* 0x0158 */ f32 unk_158; - /* 0x015C */ f32 unk_15C; - /* 0x0160 */ s16 unk_160; - /* 0x0162 */ s16 unk_162; - /* 0x0164 */ u8 unk_164; - /* 0x0166 */ s16 unk_166; - /* 0x0168 */ s16 unk_168; - /* 0x016A */ s16 unk_16A; - /* 0x016C */ s16 unk_16C; - /* 0x016E */ s16 unk_16E; - /* 0x0170 */ s16 unk_170; - /* 0x0172 */ s16 unk_172; - /* 0x0174 */ s8 unk_174; - /* 0x0178 */ Vec3f unk_178[10]; - /* 0x01F0 */ f32 unk_1F0; - /* 0x01F4 */ f32 unk_1F4; - /* 0x01F8 */ f32 unk_1F8; - /* 0x01FC */ f32 unk_1FC; - /* 0x0200 */ f32 unk_200; - /* 0x0204 */ f32 unk_204; + /* 0x0148 */ u8 hitByIceArrow; + /* 0x014C */ f32 scale; + /* 0x0150 */ f32 targetScale; + /* 0x0154 */ Vec3f scaleMod; + /* 0x0160 */ s16 action; + /* 0x0162 */ s16 type; + /* 0x0164 */ union { + u8 shouldPoolFadeOut; + u8 hasSpawnedSmallFlame; + }; + /* 0x0166 */ s16 isIceType; + /* 0x0168 */ s16 timer; + /* 0x016A */ union { + s16 poolTimer; + s16 increaseLowestUsedIndexTimer; + }; + /* 0x016C */ s16 steamSpawnTimer; + /* 0x016E */ s16 lowestUsedIndex; + /* 0x0170 */ s16 smallFlameScroll; + /* 0x0172 */ s16 wallCheckTimer; // The projectile won't check for impacts with walls until this is zero + /* 0x0174 */ s8 playerHitByIceProjectile; // Set, but never used + /* 0x0178 */ Vec3f magicProjectilePos[10]; + /* 0x01F0 */ f32 poolScale; + /* 0x01F4 */ f32 bigFlameScale; + /* 0x01F8 */ f32 fireSmokeScale; + /* 0x01FC */ f32 alpha; + /* 0x0200 */ f32 blendScale; + /* 0x0204 */ f32 blendScaleFrac; /* 0x0208 */ ColliderCylinder collider; - /* 0x0254 */ EnWizFireStruct unk_254[200]; + /* 0x0254 */ EnWizFireEffect effects[200]; } EnWizFire; // size = 0x2AF4 extern const ActorInit En_Wiz_Fire_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 519550a83b..ef47869a5d 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -10441,31 +10441,31 @@ 0x80A45164:("EnSekihi_Draw",), 0x80A45360:("EnWiz_Init",), 0x80A45568:("EnWiz_Destroy",), - 0x80A455C4:("func_80A455C4",), - 0x80A456A0:("func_80A456A0",), - 0x80A45CD8:("func_80A45CD8",), - 0x80A460A4:("func_80A460A4",), - 0x80A46280:("func_80A46280",), - 0x80A462F8:("func_80A462F8",), - 0x80A46414:("func_80A46414",), - 0x80A4668C:("func_80A4668C",), - 0x80A46764:("func_80A46764",), - 0x80A468CC:("func_80A468CC",), - 0x80A46990:("func_80A46990",), - 0x80A46C88:("func_80A46C88",), - 0x80A46CC4:("func_80A46CC4",), - 0x80A46DDC:("func_80A46DDC",), - 0x80A46E24:("func_80A46E24",), - 0x80A47000:("func_80A47000",), - 0x80A470D8:("func_80A470D8",), - 0x80A47298:("func_80A47298",), - 0x80A473B8:("func_80A473B8",), - 0x80A4767C:("func_80A4767C",), - 0x80A476C8:("func_80A476C8",), - 0x80A477E8:("func_80A477E8",), + 0x80A455C4:("EnWiz_ChangeAnim",), + 0x80A456A0:("EnWiz_HandleIntroCutscene",), + 0x80A45CD8:("EnWiz_SelectPlatform",), + 0x80A460A4:("EnWiz_MoveGhosts",), + 0x80A46280:("EnWiz_StartIntroCutscene",), + 0x80A462F8:("EnWiz_SetupAppear",), + 0x80A46414:("EnWiz_Appear",), + 0x80A4668C:("EnWiz_SetupDance",), + 0x80A46764:("EnWiz_Dance",), + 0x80A468CC:("EnWiz_SetupSecondPhaseCutscene",), + 0x80A46990:("EnWiz_SecondPhaseCutscene",), + 0x80A46C88:("EnWiz_SetupWindUp",), + 0x80A46CC4:("EnWiz_WindUp",), + 0x80A46DDC:("EnWiz_SetupAttack",), + 0x80A46E24:("EnWiz_Attack",), + 0x80A47000:("EnWiz_SetupDisappear",), + 0x80A470D8:("EnWiz_Disappear",), + 0x80A47298:("EnWiz_SetupDamaged",), + 0x80A473B8:("EnWiz_Damaged",), + 0x80A4767C:("EnWiz_SetupDead",), + 0x80A476C8:("EnWiz_Dead",), + 0x80A477E8:("EnWiz_UpdateDamage",), 0x80A47C6C:("EnWiz_Update",), - 0x80A47FCC:("func_80A47FCC",), - 0x80A48138:("func_80A48138",), + 0x80A47FCC:("EnWiz_PostLimbDrawOpa",), + 0x80A48138:("EnWiz_PostLimbDrawXlu",), 0x80A483B4:("EnWiz_Draw",), 0x80A48FE0:("EnWizBrock_Init",), 0x80A490B0:("EnWizBrock_Destroy",), @@ -10475,20 +10475,20 @@ 0x80A49308:("EnWizBrock_Draw",), 0x80A496A0:("EnWizFire_Init",), 0x80A497D4:("EnWizFire_Destroy",), - 0x80A4984C:("func_80A4984C",), - 0x80A49A44:("func_80A49A44",), - 0x80A49F38:("func_80A49F38",), - 0x80A49FD8:("func_80A49FD8",), - 0x80A4A11C:("func_80A4A11C",), - 0x80A4A608:("func_80A4A608",), + 0x80A4984C:("EnWiz_SetupMoveMagicProjectile",), + 0x80A49A44:("EnWiz_MoveMagicProjectile",), + 0x80A49F38:("EnWiz_SetupSmallFlame",), + 0x80A49FD8:("EnWiz_SmallFlame",), + 0x80A4A11C:("EnWiz_Pool",), + 0x80A4A608:("EnWiz_KillMagicProjectile",), 0x80A4A698:("EnWizFire_Update",), - 0x80A4B0C8:("func_80A4B0C8",), - 0x80A4B33C:("func_80A4B33C",), + 0x80A4B0C8:("EnWizFire_DrawIcePool",), + 0x80A4B33C:("EnWizFire_DrawFirePoolAndFlame",), 0x80A4B804:("EnWizFire_Draw",), - 0x80A4BAB4:("func_80A4BAB4",), - 0x80A4BC74:("func_80A4BC74",), - 0x80A4BDDC:("func_80A4BDDC",), - 0x80A4BF78:("func_80A4BF78",), + 0x80A4BAB4:("EnWizFire_DrawSmallFlame",), + 0x80A4BC74:("EnWizFire_InitializeEffect",), + 0x80A4BDDC:("EnWizFire_UpdateEffects",), + 0x80A4BF78:("EnWizFire_DrawEffects",), 0x80A4C490:("EffChange_Init",), 0x80A4C54C:("EffChange_Destroy",), 0x80A4C578:("EffChange_SetColors",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index eac44b02df..57d876acbb 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -11517,18 +11517,18 @@ 0x80A452A4:("D_80A452A4","UNK_TYPE1","",0x1), 0x80A452B0:("D_80A452B0","UNK_TYPE4","",0x4), 0x80A48B30:("En_Wiz_InitVars","UNK_TYPE1","",0x1), - 0x80A48B50:("D_80A48B50","UNK_TYPE1","",0x1), - 0x80A48CB8:("D_80A48CB8","UNK_PTR","",0x4), - 0x80A48CC8:("D_80A48CC8","UNK_TYPE1","",0x1), - 0x80A48CF4:("D_80A48CF4","UNK_TYPE1","",0x1), - 0x80A48D14:("D_80A48D14","UNK_TYPE1","",0x1), - 0x80A48D34:("D_80A48D34","UNK_TYPE1","",0x1), - 0x80A48D4C:("D_80A48D4C","UNK_TYPE1","",0x1), - 0x80A48D54:("D_80A48D54","UNK_TYPE4","",0x4), - 0x80A48D60:("D_80A48D60","UNK_TYPE1","",0x1), - 0x80A48D64:("D_80A48D64","UNK_TYPE1","",0x1), - 0x80A48D68:("D_80A48D68","UNK_TYPE4","",0x4), - 0x80A48D74:("D_80A48D74","UNK_TYPE4","",0x4), + 0x80A48B50:("sJntSphElementsInit","UNK_TYPE1","",0x1), + 0x80A48CB8:("sJntSphInit","UNK_PTR","",0x4), + 0x80A48CC8:("sCylinderInit","UNK_TYPE1","",0x1), + 0x80A48CF4:("sFireWizrobeDamageTable","UNK_TYPE1","",0x1), + 0x80A48D14:("sIceWizrobeDamageTable","UNK_TYPE1","",0x1), + 0x80A48D34:("sAnimations","UNK_TYPE1","",0x1), + 0x80A48D4C:("sAnimationModes","UNK_TYPE1","",0x1), + 0x80A48D54:("staffTargetFlameScale","UNK_TYPE4","",0x4), + 0x80A48D60:("sDustPrimColor","UNK_TYPE1","",0x1), + 0x80A48D64:("sDustEnvTimer","UNK_TYPE1","",0x1), + 0x80A48D68:("staffFlamePos","UNK_TYPE4","",0x4), + 0x80A48D74:("staffFlamePos","UNK_TYPE4","",0x4), 0x80A48D80:("jtbl_80A48D80","UNK_PTR","",0x4), 0x80A48D98:("D_80A48D98","f32","",0x4), 0x80A48D9C:("D_80A48D9C","f32","",0x4), @@ -11556,15 +11556,15 @@ 0x80A495F8:("D_80A495F8","f32","",0x4), 0x80A495FC:("D_80A495FC","f32","",0x4), 0x80A49600:("D_80A49600","f32","",0x4), - 0x80A4C1C0:("D_80A4C1C0","UNK_TYPE4","",0x4), + 0x80A4C1C0:("sPoolHitByIceArrow","UNK_TYPE4","",0x4), 0x80A4C1C4:("En_Wiz_Fire_InitVars","UNK_TYPE1","",0x1), 0x80A4C1E4:("D_80A4C1E4","UNK_TYPE1","",0x1), 0x80A4C210:("D_80A4C210","UNK_TYPE4","",0x4), 0x80A4C21C:("D_80A4C21C","UNK_TYPE4","",0x4), 0x80A4C228:("D_80A4C228","UNK_TYPE4","",0x4), - 0x80A4C234:("D_80A4C234","UNK_TYPE1","",0x1), - 0x80A4C24C:("D_80A4C24C","UNK_TYPE1","",0x1), - 0x80A4C250:("D_80A4C250","UNK_TYPE1","",0x1), + 0x80A4C234:("lightSettingsColors","UNK_TYPE1","",0x1), + 0x80A4C24C:("sSteamPrimColor","UNK_TYPE1","",0x1), + 0x80A4C250:("sSteamEnvColor","UNK_TYPE1","",0x1), 0x80A4C260:("jtbl_80A4C260","UNK_PTR","",0x4), 0x80A4C274:("D_80A4C274","f32","",0x4), 0x80A4C278:("D_80A4C278","f32","",0x4), diff --git a/undefined_syms.txt b/undefined_syms.txt index aae06790f4..073840341b 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -1375,14 +1375,6 @@ D_060014C0 = 0x060014C0; D_060015B0 = 0x060015B0; D_06001E20 = 0x06001E20; -// ovl_En_Wiz - -D_06001860 = 0x06001860; -D_0600211C = 0x0600211C; -D_060025F0 = 0x060025F0; -D_060066C0 = 0x060066C0; -D_0600B320 = 0x0600B320; - // ovl_En_Zl4 D_06013328 = 0x06013328;