diff --git a/assets/xml/objects/object_po_composer.xml b/assets/xml/objects/object_po_composer.xml index c45cf9039..4ac60c00b 100644 --- a/assets/xml/objects/object_po_composer.xml +++ b/assets/xml/objects/object_po_composer.xml @@ -1,35 +1,37 @@  + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - + - - - - - + + + + + + + @@ -42,17 +44,21 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/include/PR/os_voice.h b/include/PR/os_voice.h index c6317a28c..05704cf5b 100644 --- a/include/PR/os_voice.h +++ b/include/PR/os_voice.h @@ -29,6 +29,32 @@ typedef struct { /* 0x14 */ u16 distance[5]; // Distance value } OSVoiceData; // size = 0x20 +#define VOICE_STATUS_READY 0 /* stop/end */ +#define VOICE_STATUS_START 1 /* Voice Undetected (no voice input) */ +#define VOICE_STATUS_CANCEL 3 /* Cancel (cancel extraneous noise) */ +#define VOICE_STATUS_BUSY 5 /* Detected/Detecting (voice being input, recognition processing under way) */ +#define VOICE_STATUS_END 7 /* End recognition processing (enable execution of Get Recognition Results command) */ + +#define VOICE_WARN_TOO_SMALL 0x400 /* Voice level is too low (100 < Voice Level < 150) */ +#define VOICE_WARN_TOO_LARGE 0x800 /* Voice level is too high (Voice Level > 3500) */ +#define VOICE_WARN_NOT_FIT 0x4000 /* No words match recognition word (No. 1 Candidate Distance Value > 1600) */ +#define VOICE_WARN_TOO_NOISY 0x8000 /* Too much ambient noise (Relative Voice Level =< 400) */ + +typedef struct { + /* 0x000 */ u16 words[20][15]; // 20 words, each with up to 15 syllables + /* 0x258 */ u8 numWords; +} OSVoiceDictionary; // size = 0x25C + +typedef struct { + /* 0x00 */ OSVoiceDictionary* dict; + /* 0x04 */ s8 mode; + /* 0x08 */ OSVoiceData* data; + /* 0x0C */ u16 distance; + /* 0x0E */ u16 answerNum; + /* 0x10 */ u16 warning; + /* 0x12 */ u16 voiceLevel; + /* 0x14 */ u16 voiceRelLevel; +} OSVoiceUnk; // size = 0x18 s32 osVoiceInit(OSMesgQueue* mq, OSVoiceHandle* hd, int channel); s32 osVoiceSetWord(OSVoiceHandle* hd, u8* word); diff --git a/include/functions.h b/include/functions.h index f96bf819d..7f8941b9a 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1194,25 +1194,6 @@ u8 func_801A3950(u8 seqPlayerIndex, u8 resetChannelIO); u8 func_801A39F8(void); s32 func_801A46F8(void); -void func_801A4EB0(void); -// void func_801A4EB8(void); -void func_801A4FD8(void); -void func_801A5080(u16 arg0); -u16 func_801A5100(void); -void func_801A5118(void); -UNK_TYPE func_801A51F0(UNK_TYPE arg0); -// void func_801A5228(void); -// void func_801A5390(void); -// void func_801A53E8(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5); -// void func_801A541C(void); -// void func_801A5488(void); -// void func_801A54C4(void); -// void func_801A54D0(void); -// void func_801A5680(void); -// void func_801A5808(void); -void AudioVoice_ResetData(void); -// void func_801A5A1C(void); - void AudioSfx_MuteBanks(u16 muteMask); void AudioSfx_LowerBgmVolume(u8 channelIndex); void AudioSfx_RestoreBgmVolume(u8 channelIndex); diff --git a/include/variables.h b/include/variables.h index ae014b490..fe9104d82 100644 --- a/include/variables.h +++ b/include/variables.h @@ -305,9 +305,9 @@ extern UNK_PTR D_801D8B24; // extern UNK_TYPE2 D_801D8BD0; // extern UNK_TYPE4 D_801D8BD4; // extern UNK_TYPE1 D_801D8BE0; -// extern UNK_TYPE1 D_801D8E3C; +// extern u8 D_801D8E3C; // extern UNK_TYPE4 D_801D8E40; -// extern UNK_TYPE2 D_801D8E44; +// extern u16 sTopScoreWordId; // extern UNK_TYPE1 D_801D8E48; // extern UNK_TYPE1 D_801D8E50; // extern UNK_TYPE1 D_801D8F70; @@ -1723,7 +1723,7 @@ extern s32 D_801FD120; // extern UNK_TYPE1 D_801FD5C4; // extern UNK_TYPE1 D_801FD5C8; // extern UNK_TYPE1 D_801FD5E8; -// extern UNK_TYPE1 D_801FD608; +extern u8 sVoiceMaskPattern[]; // extern UNK_TYPE1 D_801FD610; extern ActiveSfx gActiveSfx[7][3]; extern SeqRequest sSeqRequests[][5]; diff --git a/include/z64save.h b/include/z64save.h index 6db5b8901..e1c752906 100644 --- a/include/z64save.h +++ b/include/z64save.h @@ -1369,11 +1369,10 @@ typedef enum { #define WEEKEVENTREG_86_20 PACK_WEEKEVENTREG_FLAG(86, 0x20) #define WEEKEVENTREG_86_40 PACK_WEEKEVENTREG_FLAG(86, 0x40) #define WEEKEVENTREG_86_80 PACK_WEEKEVENTREG_FLAG(86, 0x80) -#define WEEKEVENTREG_87_01 PACK_WEEKEVENTREG_FLAG(87, 0x01) - +// Currently talking to a cow using the voice recognition unit +#define WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE PACK_WEEKEVENTREG_FLAG(87, 0x01) // Set by Anju #define WEEKEVENTREG_COUPLES_MASK_CUTSCENE_STARTED PACK_WEEKEVENTREG_FLAG(87, 0x02) - #define WEEKEVENTREG_87_04 PACK_WEEKEVENTREG_FLAG(87, 0x04) #define WEEKEVENTREG_87_08 PACK_WEEKEVENTREG_FLAG(87, 0x08) #define WEEKEVENTREG_87_10 PACK_WEEKEVENTREG_FLAG(87, 0x10) diff --git a/include/z64voice.h b/include/z64voice.h new file mode 100644 index 000000000..f390993cf --- /dev/null +++ b/include/z64voice.h @@ -0,0 +1,34 @@ +#ifndef Z64VOICE_H +#define Z64VOICE_H + +#include "PR/ultratypes.h" +#include "unk.h" +#include "PR/os_voice.h" + +typedef enum { + /* 0 */ VOICE_WORD_ID_HOURS, + /* 1 */ VOICE_WORD_ID_CHEESE, + /* 2 */ VOICE_WORD_ID_WAKE_UP, + /* 3 */ VOICE_WORD_ID_SIT, + /* 4 */ VOICE_WORD_ID_MILK, + /* 5 */ VOICE_WORD_ID_HIYA, + /* 6 */ VOICE_WORD_ID_MAX, + /* -1 */ VOICE_WORD_ID_NONE = 0xFFFF +} OSVoiceWordId; + +void func_801A4EB0(void); +void func_801A4FD8(void); +void func_801A5080(u16 wordId); +u16 AudioVoice_GetWord(void); +void func_801A5118(void); +s32 func_801A51F0(s32 errorCode); +s32 func_801A5228(OSVoiceDictionary* dict); +OSVoiceData* func_801A5390(void); +void func_801A53E8(u16 distance, u16 answerNum, u16 warning, u16 voiceLevel, u16 voiceRelLevel); +u8* func_801A54C4(void); +s32 func_801A54D0(u16 wordId); +s32 func_801A5680(u16 wordId); +s32 func_801A5808(void); +void AudioVoice_ResetData(void); + +#endif diff --git a/spec b/spec index 22562d8f4..d226f35a8 100644 --- a/spec +++ b/spec @@ -591,10 +591,7 @@ beginseg include "build/asm/code/code_8019AEC0.text.o" // handwritten include "build/src/audio/code_8019AF00.o" include "build/src/audio/voice_external.o" - include "build/data/code/voice_external.data.o" include "build/src/audio/voice_internal.o" - include "build/data/code/voice_internal.data.o" - include "build/data/code/voice_internal.bss.o" pad_text include "build/src/audio/sfx_params.o" include "build/src/audio/sfx.o" @@ -1333,8 +1330,7 @@ beginseg name "ovl_En_Honotrap" compress include "build/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.o" - include "build/data/ovl_En_Honotrap/ovl_En_Honotrap.data.o" - include "build/data/ovl_En_Honotrap/ovl_En_Honotrap.reloc.o" + include "build/src/overlays/actors/ovl_En_Honotrap/ovl_En_Honotrap_reloc.o" endseg beginseg @@ -2880,9 +2876,7 @@ beginseg name "ovl_Obj_Mine" compress include "build/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.o" - include "build/data/ovl_Obj_Mine/ovl_Obj_Mine.data.o" - include "build/data/ovl_Obj_Mine/ovl_Obj_Mine.bss.o" - include "build/data/ovl_Obj_Mine/ovl_Obj_Mine.reloc.o" + include "build/src/overlays/actors/ovl_Obj_Mine/ovl_Obj_Mine_reloc.o" endseg beginseg @@ -3421,8 +3415,7 @@ beginseg name "ovl_Bg_Danpei_Movebg" compress include "build/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.o" - include "build/data/ovl_Bg_Danpei_Movebg/ovl_Bg_Danpei_Movebg.data.o" - include "build/data/ovl_Bg_Danpei_Movebg/ovl_Bg_Danpei_Movebg.reloc.o" + include "build/src/overlays/actors/ovl_Bg_Danpei_Movebg/ovl_Bg_Danpei_Movebg_reloc.o" endseg beginseg @@ -4221,8 +4214,7 @@ beginseg name "ovl_En_Po_Composer" compress include "build/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.o" - include "build/data/ovl_En_Po_Composer/ovl_En_Po_Composer.data.o" - include "build/data/ovl_En_Po_Composer/ovl_En_Po_Composer.reloc.o" + include "build/src/overlays/actors/ovl_En_Po_Composer/ovl_En_Po_Composer_reloc.o" endseg beginseg diff --git a/src/audio/voice_external.c b/src/audio/voice_external.c index eba2069d8..00d5f24a0 100644 --- a/src/audio/voice_external.c +++ b/src/audio/voice_external.c @@ -1,17 +1,142 @@ #include "global.h" +#include "z64voice.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A4EB0.s") +extern OSVoiceHandle gVoiceHandle; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A4EB8.s") +OSVoiceDictionary D_801D8BE0 = { + { + // "アトナンジカン" - "atonanjikan" - "How many hours" + { 0x8341, 0x8367, 0x8369, 0x8393, 0x8357, 0x834A, 0x8393 }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A4FD8.s") + // "ハイチーズ" - "haichīzu" - "say cheese" + { 0x836E, 0x8343, 0x8360, 0x815B, 0x8359 }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A5080.s") + // "オキロー" - "okirō" - "wake up" + { 0x8349, 0x834C, 0x838D, 0x815B }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A50C0.s") + // "オスワリ" - "osuwari" - "sit" + { 0x8349, 0x8358, 0x838F, 0x838A }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A5100.s") + // "ミルク" - "miruku" - "milk" + { 0x837E, 0x838B, 0x834E }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A510C.s") + // "ハイヤー" - "haiyā" - "hiya!" + { 0x836E, 0x8343, 0x8384, 0x815B }, + }, -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_external/func_801A5118.s") + VOICE_WORD_ID_MAX, // number of words +}; + +u8 D_801D8E3C = 0; +OSVoiceData* D_801D8E40 = NULL; +u16 sTopScoreWordId = VOICE_WORD_ID_NONE; +u8 D_801D8E48 = 0; + +void func_801A4EB0(void) { +} + +void func_801A4EB8(void) { + u8* new_var; + OSMesgQueue* serialEventQueue; + s32 index; + u8 sp38[1]; + u8 i; + + if (D_801D8E3C != 0) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + osVoiceStopReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + } + + new_var = func_801A54C4(); + + for (i = 0; i < 1; i++) { + sp38[i] = new_var[i]; + } + + if (func_801A5228(&D_801D8BE0) == 0) { + for (i = 0; i < VOICE_WORD_ID_MAX; i++) { + index = i / 8; + if (((sp38[index] >> (i % 8)) & 1) == 1) { + func_801A54D0(i); + } + } + + func_801A53E8(800, 2, VOICE_WARN_TOO_SMALL, 500, 2000); + D_801D8E3C = 1; + } +} + +// Used externally in code_8019AF00 +void func_801A4FD8(void) { + s32 errorCode; + OSMesgQueue* serialEventQueue; + + func_801A54D0(VOICE_WORD_ID_NONE); + if (D_801D8E3C != 0) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + osVoiceStopReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + errorCode = func_801A5228(&D_801D8BE0); + func_801A54D0(VOICE_WORD_ID_NONE); + if (errorCode == 0) { + func_801A53E8(800, 2, VOICE_WARN_TOO_SMALL, 500, 2000); + D_801D8E3C = 1; + } + + func_801A5080(VOICE_WORD_ID_HIYA); + func_801A5080(VOICE_WORD_ID_CHEESE); + } +} + +void func_801A5080(u16 wordId) { + if ((D_801D8E3C != 0) && (wordId < VOICE_WORD_ID_MAX)) { + func_801A5680(wordId); + } +} + +// Unused +void func_801A50C0(u16 wordId) { + if ((D_801D8E3C != 0) && (wordId < VOICE_WORD_ID_MAX)) { + func_801A54D0(wordId); + } +} + +// Used externally in many files +u16 AudioVoice_GetWord(void) { + return sTopScoreWordId; +} + +// Unused +u8 func_801A510C(void) { + return D_801D8E3C; +} + +// Used externally in Audio_Update (code_8019AF00) +void func_801A5118(void) { + if (D_801D8E3C & 2) { + D_801D8E3C &= 1; + func_801A4EB8(); + } + + if (D_801D8E3C != 0) { + if (func_801A5808() != 0) { + D_801D8E48++; + if (D_801D8E48 == 10) { + D_801D8E3C = 0; + sTopScoreWordId = VOICE_WORD_ID_NONE; + return; + } + } else { + D_801D8E48 = 0; + } + + D_801D8E40 = func_801A5390(); + if (D_801D8E40 != 0) { + sTopScoreWordId = D_801D8E40->answer[0]; + } else { + sTopScoreWordId = VOICE_WORD_ID_NONE; + } + } +} diff --git a/src/audio/voice_internal.c b/src/audio/voice_internal.c index 055b66ed1..a8a19d228 100644 --- a/src/audio/voice_internal.c +++ b/src/audio/voice_internal.c @@ -1,42 +1,349 @@ #include "global.h" +#include "z64voice.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/D_801E0EC0.s") +// internal voice functions +u8* func_801A5A1C(s8* words); -UNK_TYPE func_801A51F0(UNK_TYPE arg0) { - switch (arg0) { - case 1: - case 4: - case 5: - case 11: - case 13: - case 14: - case 15: +// BSS +OSVoiceUnk D_801FD5A0; +OSVoiceHandle gVoiceHandle; +OSVoiceData D_801FD5C8; // Intermediate Voice Data during processsing? +OSVoiceData D_801FD5E8; // Best Match Voice Data? +u8 sVoiceMaskPattern[8]; +char D_801FD610[256]; + +// Data +s8 D_801D8E50[96][3] = { + "aa", "AA", "ii", "II", "uu", "UU", "ee", "EE", "oo", "OO", "KA", "GA", "KI", "GI", "KU", "GU", + "KE", "GE", "KO", "GO", "SA", "ZA", "SI", "ZI", "SU", "ZU", "SE", "ZE", "SO", "ZO", "TA", "DA", + "TI", "DI", "tu", "TU", "DU", "TE", "DE", "TO", "DO", "NA", "NI", "NU", "NE", "NO", "HA", "BA", + "PA", "HI", "BI", "PI", "HU", "BU", "PU", "HE", "BE", "PE", "HO", "BO", "PO", "MA", "MI", "MU", + "ME", "MO", "ya", "YA", "yu", "YU", "yo", "YO", "RA", "RI", "RU", "RE", "RO", "wa", "WA", "WI", + "WE", "WO", "NN", "VU", "ka", "ke", "", "", "", "", "", "", "", "", "", "", +}; + +s8 D_801D8F70[96][3] = { + "aa", "AA", "ii", "II", "uu", "UU", "ee", "EE", "oo", "OO", "KA", "GA", "KI", "GI", "KU", "GU", + "KE", "GE", "KO", "GO", "SA", "ZA", "SI", "ZI", "SU", "ZU", "SE", "ZE", "SO", "ZO", "TA", "DA", + "TI", "DI", "tu", "TU", "DU", "TE", "DE", "TO", "DO", "NA", "NI", "NU", "NE", "NO", "HA", "BA", + "PA", "HI", "BI", "PI", "HU", "BU", "PU", "HE", "BE", "PE", "HO", "BO", "PO", "MA", "MI", " ", + "MU", "ME", "MO", "ya", "YA", "yu", "YU", "yo", "YO", "RA", "RI", "RU", "RE", "RO", "wa", "WA", + "WI", "WE", "WO", "NN", "VU", "ka", "ke", "", "", "", "", "", "", "", "", "", +}; + +const char D_801E0EC0[] = "Error %d\n"; +const char D_801E0ECC[] = "NAI_VRS:osVoiceClearDictionary %d\n"; +const char D_801E0EF0[] = "NAI_VRS:dict error! (%d-%d %s)\n"; +const char D_801E0F10[] = "NAI_VRS:Ina_SetVruGain Error!\n"; +const char D_801E0F30[] = "NAI_VRS:mask on %d\n"; +const char D_801E0F48[] = "NAI_VRS:mask off %d\n"; +const char D_801E0F60[] = "NAI_VRS:answer No.:%d Dist:%d Warn:%04X Level:%5d SN:%5d (Num:%d)\n"; +const char D_801E0FA4[] = "NAI_VRS:error !! (ANS_MAX:%d DIST:%d WARNING:%04X LEVEL:%5d SN:%5d)\n"; + +s32 func_801A51F0(s32 errorCode) { + switch (errorCode) { + case CONT_ERR_NO_CONTROLLER: + case CONT_ERR_CONTRFAIL: + case CONT_ERR_INVALID: + case CONT_ERR_DEVICE: + case CONT_ERR_VOICE_MEMORY: + case CONT_ERR_VOICE_WORD: + case CONT_ERR_VOICE_NO_RESPONSE: return -1; + default: return 0; } } -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5228.s") +s32 func_801A5228(OSVoiceDictionary* dict) { + OSMesgQueue* serialEventQueue; + s32 errorCode; + u8 numWords; + u8 i; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5390.s") + D_801FD5A0.mode = 0; + D_801FD5A0.data = NULL; + D_801FD5A0.distance = 1000; + D_801FD5A0.answerNum = 5; + D_801FD5A0.warning = 0; + D_801FD5A0.dict = dict; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A53DC.s") + numWords = dict->numWords; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A53E8.s") + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceClearDictionary(&gVoiceHandle, numWords); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A541C.s") + if (errorCode != 0) { + return errorCode; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5488.s") + for (i = 0; i < (((numWords - 1) / 8) + 1); i++) { + sVoiceMaskPattern[i] = 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A54C4.s") + for (i = 0; i < numWords; i++) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceSetWord(&gVoiceHandle, &dict->words[i]); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A54D0.s") + if (func_801A51F0(errorCode) != 0) { + func_801A5A1C(&dict->words[i]); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5680.s") + return errorCode; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5808.s") +OSVoiceData* func_801A5390(void) { + OSVoiceData* voiceData; + OSMesgQueue* serialEventQueue; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/AudioVoice_ResetData.s") + voiceData = D_801FD5A0.data; + D_801FD5A0.data = NULL; -#pragma GLOBAL_ASM("asm/non_matchings/code/voice_internal/func_801A5A1C.s") + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + osVoiceStartReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + return voiceData; +} + +// Unused +OSVoiceDictionary* func_801A53DC(void) { + return D_801FD5A0.dict; +} + +void func_801A53E8(u16 distance, u16 answerNum, u16 warning, u16 voiceLevel, u16 voiceRelLevel) { + D_801FD5A0.distance = distance; + D_801FD5A0.answerNum = answerNum; + D_801FD5A0.warning = warning; + D_801FD5A0.voiceLevel = voiceLevel; + D_801FD5A0.voiceRelLevel = voiceRelLevel; +} + +// Unused +// Could have a return? or be void return? +s32 func_801A541C(s32 analog, s32 digital) { + s32 errorCode; + OSMesgQueue* serialEventQueue; + + if (D_801FD5A0.dict != NULL) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceControlGain(&gVoiceHandle, analog, digital); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + if (errorCode != 0) { + func_801A51F0(errorCode); + } + } +} + +// Unused +s32 func_801A5488(u8* word) { + s32 errorCode; + OSMesgQueue* serialEventQueue; + + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceCheckWord(word); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + return errorCode; +} + +u8* func_801A54C4(void) { + return sVoiceMaskPattern; +} + +s32 func_801A54D0(u16 wordId) { + s32 errorCode; + u8 phi_t0 = true; + u8 numWords; + u8 i; + OSMesgQueue* serialEventQueue; + + if (D_801FD5A0.dict != NULL) { + numWords = D_801FD5A0.dict->numWords; + } else { + numWords = 20; + phi_t0 = false; + } + + if (wordId == VOICE_WORD_ID_NONE) { + for (i = 0; i < numWords; i++) { + sVoiceMaskPattern[i / 8] |= 1 << (i % 8); + } + } else { + if (sVoiceMaskPattern[wordId / 8] & (1 << (wordId % 8))) { + phi_t0 = false; + } else { + sVoiceMaskPattern[wordId / 8] |= (1 << (wordId % 8)); + } + } + + if (phi_t0) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceStopReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + if ((errorCode == 0) || (D_801FD5A0.mode == 0)) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceMaskDictionary(&gVoiceHandle, sVoiceMaskPattern, ((numWords - 1) / 8) + 1); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + } + + D_801FD5A0.mode = 0; + } + + return errorCode; +} + +s32 func_801A5680(u16 wordId) { + s32 errorCode; + u8 phi_a3 = true; + u8 numWords; + u8 i; + OSMesgQueue* serialEventQueue; + + if (D_801FD5A0.dict != NULL) { + numWords = D_801FD5A0.dict->numWords; + } else { + numWords = 20; + phi_a3 = false; + } + + if (wordId == VOICE_WORD_ID_NONE) { + for (i = 0; i < (((numWords - 1) / 8) + 1); i++) { + sVoiceMaskPattern[i] = 0; + } + } else { + if (!(sVoiceMaskPattern[wordId / 8] & (1 << (wordId % 8)))) { + phi_a3 = false; + } else { + sVoiceMaskPattern[wordId / 8] &= (1 << (wordId % 8)) ^ 0xFF; + } + } + + if (phi_a3) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceStopReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + if ((errorCode == 0) || (D_801FD5A0.mode == 0)) { + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceMaskDictionary(&gVoiceHandle, sVoiceMaskPattern, ((numWords - 1) / 8) + 1); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + } + + D_801FD5A0.mode = 0; + } + + return errorCode; +} + +s32 func_801A5808(void) { + s32 errorCode = 0; + s32 ret; + OSMesgQueue* serialEventQueue; + + switch (D_801FD5A0.mode) { + case 0: + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceStartReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + D_801FD5A0.mode = 1; + break; + + case 1: + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceGetReadData(&gVoiceHandle, &D_801FD5C8); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + if (func_801A51F0(errorCode) == 0) { + switch (gVoiceHandle.status) { + case VOICE_STATUS_READY: + D_801FD5A0.mode = 2; + break; + + case VOICE_STATUS_START: + case 2: + case VOICE_STATUS_CANCEL: + case 4: + case VOICE_STATUS_BUSY: + case 6: + break; + + case VOICE_STATUS_END: + D_801FD5A0.mode = 2; + break; + + default: + break; + } + } + break; + + case 2: + if (((D_801FD5C8.warning & D_801FD5A0.warning) == 0) && (D_801FD5A0.answerNum >= D_801FD5C8.answerNum) && + (D_801FD5A0.distance >= D_801FD5C8.distance[0]) && (D_801FD5C8.voiceLevel >= D_801FD5A0.voiceLevel) && + (D_801FD5C8.voiceRelLevel >= D_801FD5A0.voiceRelLevel)) { + D_801FD5E8 = D_801FD5C8; + D_801FD5A0.data = &D_801FD5E8; + } + + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + osVoiceStopReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + serialEventQueue = PadMgr_VoiceAcquireSerialEventQueue(); + errorCode = osVoiceStartReadData(&gVoiceHandle); + PadMgr_VoiceReleaseSerialEventQueue(serialEventQueue); + + D_801FD5A0.mode = 1; + break; + + default: + break; + } + + ret = func_801A51F0(errorCode); + + return ret; +} + +// Unused +void AudioVoice_ResetData(void) { + D_801FD5A0.dict = NULL; +} + +u8* func_801A5A1C(s8* words) { + u8 i; + u8 j; + u8 numSyllables = strlen(words); // technically twice the num of syllables + u8 syllable[2]; + + for (j = 0, i = 0; i < numSyllables; i += 2) { + syllable[0] = words[i]; + syllable[1] = words[i + 1]; + + if (syllable[0] == 0x83) { + D_801FD610[j++] = D_801D8F70[syllable[1] - 0x40][0]; + D_801FD610[j++] = D_801D8F70[syllable[1] - 0x40][1]; + } else if (syllable[0] == 0x82) { + D_801FD610[j++] = D_801D8E50[syllable[1] - 0x9F][0]; + D_801FD610[j++] = D_801D8E50[syllable[1] - 0x9F][1]; + } else if ((syllable[0] == 0x81) && (syllable[1] == 0x5B)) { + D_801FD610[j++] = '-'; + D_801FD610[j++] = '-'; + } else { + D_801FD610[j++] = ' '; + D_801FD610[j++] = ' '; + } + } + + D_801FD610[i] = '\0'; + + return D_801FD610; +} diff --git a/src/code/padmgr.c b/src/code/padmgr.c index 1b75721cb..056103dde 100644 --- a/src/code/padmgr.c +++ b/src/code/padmgr.c @@ -35,6 +35,7 @@ #include "PR/controller.h" #include "PR/os_motor.h" #include "fault.h" +#include "z64voice.h" extern FaultMgr gFaultMgr; diff --git a/src/code/sys_cfb.c b/src/code/sys_cfb.c index 32600643a..383a35cc9 100644 --- a/src/code/sys_cfb.c +++ b/src/code/sys_cfb.c @@ -1,4 +1,3 @@ -#include "prevent_bss_reordering.h" #include "z64.h" #include "regs.h" #include "functions.h" diff --git a/src/code/z_parameter.c b/src/code/z_parameter.c index 4f553860b..1ad8135a5 100644 --- a/src/code/z_parameter.c +++ b/src/code/z_parameter.c @@ -3,6 +3,7 @@ #include "sys_cfb.h" #include "z64snap.h" #include "z64view.h" +#include "z64voice.h" #include "archives/icon_item_static/icon_item_static_yar.h" #include "interface/parameter_static/parameter_static.h" #include "interface/do_action_static/do_action_static.h" @@ -2345,7 +2346,8 @@ void Interface_UpdateButtonsPart1(PlayState* play) { interfaceCtx->unk_222 = interfaceCtx->unk_224 = 0; restoreHudVisibility = true; sPictoState = PICTO_BOX_STATE_OFF; - } else if (CHECK_BTN_ALL(CONTROLLER1(&play->state)->press.button, BTN_A) || (func_801A5100() == 1)) { + } else if (CHECK_BTN_ALL(CONTROLLER1(&play->state)->press.button, BTN_A) || + (AudioVoice_GetWord() == VOICE_WORD_ID_CHEESE)) { if (!CHECK_EVENTINF(EVENTINF_41) || (CHECK_EVENTINF(EVENTINF_41) && (CutsceneManager_GetCurrentCsId() == CS_ID_NONE))) { Audio_PlaySfx(NA_SE_SY_CAMERA_SHUTTER); diff --git a/src/libultra/voice/voicegetreaddata.c b/src/libultra/voice/voicegetreaddata.c index 5e5a2b62b..a82d23a87 100644 --- a/src/libultra/voice/voicegetreaddata.c +++ b/src/libultra/voice/voicegetreaddata.c @@ -33,7 +33,7 @@ s32 osVoiceGetReadData(OSVoiceHandle* hd, OSVoiceData* result) { sHandleStatus = data[0] & 7; hd->status = sHandleStatus; - if ((sHandleStatus != 0) && (sHandleStatus != 7)) { + if ((sHandleStatus != VOICE_STATUS_READY) && (sHandleStatus != VOICE_STATUS_END)) { return CONT_ERR_NOT_READY; } // fallthrough @@ -88,7 +88,7 @@ s32 osVoiceGetReadData(OSVoiceHandle* hd, OSVoiceData* result) { } hd->status = data[34] & 7; - if ((sHandleStatus == 0) || (hd->status == 0)) { + if ((sHandleStatus == VOICE_STATUS_READY) || (hd->status == VOICE_STATUS_READY)) { break; } // fallthrough diff --git a/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.c b/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.c index 2a107ec2f..f54bdb88e 100644 --- a/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.c +++ b/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.c @@ -5,6 +5,7 @@ */ #include "z_bg_danpei_movebg.h" +#include "objects/object_d_lift/object_d_lift.h" #define FLAGS (ACTOR_FLAG_10) @@ -14,7 +15,15 @@ void BgDanpeiMovebg_Init(Actor* thisx, PlayState* play); void BgDanpeiMovebg_Destroy(Actor* thisx, PlayState* play); void BgDanpeiMovebg_Update(Actor* thisx, PlayState* play); -#if 0 +void func_80AF6EA8(BgDanpeiMovebg* this, PlayState* play); +void func_80AF70FC(BgDanpeiMovebg* this, PlayState* play); +void func_80AF74CC(Actor* thisx, PlayState* play); +u16 func_80AF705C(BgDanpeiMovebg* this, u16 flags); +void func_80AF71FC(BgDanpeiMovebg* this, PlayState* play); +void func_80AF72F8(BgDanpeiMovebg* this, PlayState* play); +void func_80AF7354(BgDanpeiMovebg* this, PlayState* play); +void func_80AF746C(BgDanpeiMovebg* this, PlayState* play); + ActorInit Bg_Danpei_Movebg_InitVars = { /**/ ACTOR_BG_DANPEI_MOVEBG, /**/ ACTORCAT_BG, @@ -27,38 +36,181 @@ ActorInit Bg_Danpei_Movebg_InitVars = { /**/ NULL, }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80AF753C[] = { +static u16 D_80AF7530[] = { OBJECT_D_LIFT, OBJECT_DANPEI_OBJECT }; + +static Gfx* D_80AF7534[] = { gDampeGraveBrownElevatorDL }; + +static CollisionHeader* D_80AF7538[] = { &gDampeGraveBrownElevatorCol }; + +static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneScale, 1500, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1100, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_CONTINUE), ICHAIN_VEC3F_DIV1000(scale, 100, ICHAIN_STOP), }; -#endif +s32 func_80AF6DE0(PlayState* this, ActorPathing* actorPathing) { + Actor* actor; + s32 res; -extern InitChainEntry D_80AF753C[]; + actor = actorPathing->actor; + res = 0; + if (actorPathing->distSqToCurPoint < actor->speed * actor->speed) { + res = 1; + } else { + actor->world.rot.x = actorPathing->rotToCurPoint.x; + actor->world.rot.y = actorPathing->rotToCurPoint.y; + } + return res; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF6DE0.s") +void BgDanpeiMovebg_Init(Actor* thisx, PlayState* play) { + BgDanpeiMovebg* this = THIS; + DynaPolyActor_Init(&this->dyna, 1); + this->bankIdx = SubS_GetObjectSlot(D_80AF7530[BGDANPEIMOVEBG_GET_TYPE(thisx)], play); + if (this->bankIdx < 0) { + Actor_Kill(&this->dyna.actor); + } + this->actionFunc = func_80AF6EA8; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/BgDanpeiMovebg_Init.s") +void func_80AF6EA8(BgDanpeiMovebg* this, PlayState* play) { + Actor* thisx = (Actor*)this; + if (SubS_IsObjectLoaded(this->bankIdx, play)) { + gSegments[6] = OS_K0_TO_PHYSICAL(play->objectCtx.slots[this->bankIdx].segment); + this->dyna.actor.objectSlot = this->bankIdx; + this->dyna.actor.draw = func_80AF74CC; + Actor_ProcessInitChain(thisx, sInitChain); + DynaPolyActor_LoadMesh(play, &this->dyna, D_80AF7538[BGDANPEIMOVEBG_GET_TYPE(thisx)]); + this->dList = D_80AF7534[BGDANPEIMOVEBG_GET_TYPE(thisx)]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF6EA8.s") + /* If D_LIFT */ + if (BGDANPEIMOVEBG_GET_TYPE(thisx) == 0) { + this->dyna.actor.gravity = 0.0f; + this->dyna.actor.speed = 1.0f; + SubS_ActorPathing_Init(play, &thisx->world.pos, thisx, &this->actorPath, play->setupPathList, + BGDANPEIMOVEBG_GET_PATH_INDEX(thisx), 0, 0, 0, 0); + this->actionFunc = func_80AF70FC; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/BgDanpeiMovebg_Destroy.s") +void BgDanpeiMovebg_Destroy(Actor* thisx, PlayState* play) { + BgDanpeiMovebg* this = THIS; + DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/BgDanpeiMovebg_Update.s") +void BgDanpeiMovebg_Update(Actor* thisx, PlayState* play) { + BgDanpeiMovebg* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF705C.s") + this->actionFunc(this, play); + this->prevFlags = this->flags; + this->flags &= ~1; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF70FC.s") +u16 func_80AF705C(BgDanpeiMovebg* this, u16 flags) { + u16 newFlags = flags & ~0x1C; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF71FC.s") + if (DynaPolyActor_IsActorOnTop(&this->dyna) && (this->flags & 1)) { + newFlags |= 4; + } + if (DynaPolyActor_IsPlayerOnTop(&this->dyna)) { + if (gSaveContext.save.playerForm == PLAYER_FORM_DEKU) { + newFlags |= 8; + } else { + newFlags |= 0x10; + } + } + return newFlags; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF72F8.s") +void func_80AF70FC(BgDanpeiMovebg* this, PlayState* play) { + this->flags = func_80AF705C(this, this->flags); + if (this->flags & 0xC) { + if (this->flags & 4) { + this->flags |= 2; + } + this->actionFunc = func_80AF71FC; + } else if (this->flags & 0x10) { + if (!(this->prevFlags & 0x10)) { + Actor_PlaySfx(&this->dyna.actor, NA_SE_EV_SINK_WOOD_FLOOR); + } + Math_SmoothStepToF(&this->dyna.actor.world.pos.y, this->dyna.actor.home.pos.y - 8.0f, 1.0f, 2.0f, 0.01f); + } else { + if (this->prevFlags & 0x10) { + Actor_PlaySfx(&this->dyna.actor, NA_SE_EV_REBOUND_WOOD_FLOOR); + } + Math_SmoothStepToF(&this->dyna.actor.world.pos.y, this->dyna.actor.home.pos.y, 1.0f, 2.0f, 0.01f); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF7354.s") +void func_80AF71FC(BgDanpeiMovebg* this, PlayState* play) { + SubS_ActorPathing_Update(play, &this->actorPath, SubS_ActorPathing_ComputePointInfo, func_80AF6DE0, + SubS_ActorPathing_MoveWithoutGravityReverse, SubS_ActorPathing_SetNextPoint); + Actor_PlaySfx_Flagged(&this->dyna.actor, NA_SE_EV_PLATE_LIFT_LEVEL - SFX_FLAG); + if (this->actorPath.flags & ACTOR_PATHING_REACHED_END_TEMPORARY) { + if (this->flags & 2) { + this->flags &= ~0x2; + } + this->actionFunc = func_80AF72F8; + } else { + this->flags = func_80AF705C(this, this->flags); + if ((this->flags & 0x10) || (this->flags & 0xC) == 0xC) { + this->actionFunc = func_80AF746C; + } else if ((this->flags & 0x1C) == 0) { + this->actorPath.flags |= ACTOR_PATHING_MOVE_BACKWARDS; + this->dyna.actor.speed = 2.0f; + this->actionFunc = func_80AF7354; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF746C.s") +void func_80AF72F8(BgDanpeiMovebg* this, PlayState* play) { + this->flags = func_80AF705C(this, this->flags); + if (!(this->flags & 0x1C)) { + this->actorPath.flags |= ACTOR_PATHING_MOVE_BACKWARDS; + this->dyna.actor.speed = 2.0f; + this->actionFunc = func_80AF7354; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Bg_Danpei_Movebg/func_80AF74CC.s") +void func_80AF7354(BgDanpeiMovebg* this, PlayState* play) { + Actor_PlaySfx_Flagged(&this->dyna.actor, NA_SE_EV_PLATE_LIFT_LEVEL - SFX_FLAG); + this->flags = func_80AF705C(this, this->flags); + SubS_ActorPathing_Update(play, &this->actorPath, SubS_ActorPathing_ComputePointInfo, func_80AF6DE0, + SubS_ActorPathing_MoveWithoutGravityReverse, SubS_ActorPathing_SetNextPoint); + if ((this->flags & 0x10) || (this->flags & 0xC) == 0xC) { + this->actionFunc = func_80AF746C; + } else if ((this->flags & 0xC) && (this->flags & 0xC) != 0xC) { + this->actorPath.flags &= ~ACTOR_PATHING_MOVE_BACKWARDS; + this->dyna.actor.speed = 1.0f; + if (this->flags & 4) { + this->flags |= 2; + } + this->actionFunc = func_80AF71FC; + } + if (this->actorPath.flags & ACTOR_PATHING_REACHED_END_TEMPORARY) { + this->actorPath.flags &= ~ACTOR_PATHING_MOVE_BACKWARDS; + this->flags &= ~2; + this->dyna.actor.speed = 1.0f; + this->actionFunc = func_80AF70FC; + } +} + +void func_80AF746C(BgDanpeiMovebg* this, PlayState* arg1) { + this->flags = func_80AF705C(this, this->flags); + if (!(this->flags & 0x18)) { + if (this->actorPath.flags & ACTOR_PATHING_MOVE_BACKWARDS) { + this->actionFunc = func_80AF7354; + } else { + this->actionFunc = func_80AF71FC; + } + } +} + +void func_80AF74CC(Actor* thisx, PlayState* play) { + BgDanpeiMovebg* this = THIS; + if (this->dList != NULL) { + Gfx_DrawDListOpa(play, this->dList); + } +} diff --git a/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.h b/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.h index c99bb813f..bd57a4822 100644 --- a/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.h +++ b/src/overlays/actors/ovl_Bg_Danpei_Movebg/z_bg_danpei_movebg.h @@ -7,12 +7,17 @@ struct BgDanpeiMovebg; typedef void (*BgDanpeiMovebgActionFunc)(struct BgDanpeiMovebg*, PlayState*); +#define BGDANPEIMOVEBG_GET_PATH_INDEX(thisx) ((thisx)->params & 0x7F) +#define BGDANPEIMOVEBG_GET_TYPE(thisx) (((thisx)->params >> 0xE) & 3) + typedef struct BgDanpeiMovebg { /* 0x000 */ DynaPolyActor dyna; /* 0x15C */ BgDanpeiMovebgActionFunc actionFunc; - /* 0x160 */ char unk_160[0x6C]; - /* 0x1CC */ u16 unk_1CC; - /* 0x1CE */ char unk_1CE[0xA]; + /* 0x160 */ ActorPathing actorPath; + /* 0x1CC */ u16 flags; + /* 0x1CE */ u16 prevFlags; + /* 0x1D0 */ Gfx* dList; + /* 0x1D4 */ s8 bankIdx; } BgDanpeiMovebg; // size = 0x1D8 #endif // Z_BG_DANPEI_MOVEBG_H diff --git a/src/overlays/actors/ovl_Bg_Dblue_Balance/z_bg_dblue_balance.c b/src/overlays/actors/ovl_Bg_Dblue_Balance/z_bg_dblue_balance.c index 949dbb0a0..21159860a 100644 --- a/src/overlays/actors/ovl_Bg_Dblue_Balance/z_bg_dblue_balance.c +++ b/src/overlays/actors/ovl_Bg_Dblue_Balance/z_bg_dblue_balance.c @@ -6,6 +6,7 @@ #include "z_bg_dblue_balance.h" #include "objects/object_dblue_object/object_dblue_object.h" +#include "prevent_bss_reordering.h" #define FLAGS 0x00000000 diff --git a/src/overlays/actors/ovl_Boss_03/z_boss_03.c b/src/overlays/actors/ovl_Boss_03/z_boss_03.c index f96626785..07ded0e90 100644 --- a/src/overlays/actors/ovl_Boss_03/z_boss_03.c +++ b/src/overlays/actors/ovl_Boss_03/z_boss_03.c @@ -48,7 +48,6 @@ * - Effect Update/Draw * - Seaweed */ - #include "z_boss_03.h" #include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h" #include "overlays/actors/ovl_En_Water_Effect/z_en_water_effect.h" diff --git a/src/overlays/actors/ovl_En_Cow/z_en_cow.c b/src/overlays/actors/ovl_En_Cow/z_en_cow.c index f9f1925d0..25ef47824 100644 --- a/src/overlays/actors/ovl_En_Cow/z_en_cow.c +++ b/src/overlays/actors/ovl_En_Cow/z_en_cow.c @@ -6,6 +6,7 @@ #include "z_en_cow.h" #include "z64horse.h" +#include "z64voice.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY) @@ -132,7 +133,7 @@ void EnCow_Init(Actor* thisx, PlayState* play) { this->actor.targetMode = TARGET_MODE_6; gHorsePlayedEponasSong = false; - func_801A5080(4); + func_801A5080(VOICE_WORD_ID_MILK); break; case EN_COW_TYPE_TAIL: @@ -158,7 +159,7 @@ void EnCow_Init(Actor* thisx, PlayState* play) { Actor_SetScale(&this->actor, 0.01f); this->flags = 0; - CLEAR_WEEKEVENTREG(WEEKEVENTREG_87_01); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE); } void EnCow_Destroy(Actor* thisx, PlayState* play) { @@ -291,11 +292,11 @@ void EnCow_Idle(EnCow* this, PlayState* play) { } } - if (this->actor.xzDistToPlayer < 150.0f && - ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 25000) { - if (func_801A5100() == 4) { - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_87_01)) { - SET_WEEKEVENTREG(WEEKEVENTREG_87_01); + if ((this->actor.xzDistToPlayer < 150.0f) && + (ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 0x61A8)) { + if (AudioVoice_GetWord() == VOICE_WORD_ID_MILK) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE)) { + SET_WEEKEVENTREG(WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE); if (Inventory_HasEmptyBottle()) { this->actor.textId = 0x32C9; // Text to give milk. } else { @@ -306,7 +307,7 @@ void EnCow_Idle(EnCow* this, PlayState* play) { this->actionFunc = EnCow_Talk; } } else { - CLEAR_WEEKEVENTREG(WEEKEVENTREG_87_01); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE); } } @@ -322,8 +323,8 @@ void EnCow_DoTail(EnCow* this, PlayState* play) { Animation_GetLastFrame(&gCowTailIdleAnim), ANIMMODE_ONCE, 1.0f); } - if (this->actor.xzDistToPlayer < 150.0f && - ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) > 25000) { + if ((this->actor.xzDistToPlayer < 150.0f) && + (ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) > 0x61A8)) { if (!(this->flags & EN_COW_FLAG_PLAYER_HAS_APPROACHED)) { this->flags |= EN_COW_FLAG_PLAYER_HAS_APPROACHED; if (this->skelAnime.animation == &gCowTailIdleAnim) { @@ -360,8 +361,8 @@ void EnCow_Update(Actor* thisx, PlayState* play2) { this->actionFunc(this, play); - if (this->actor.xzDistToPlayer < 150.0f && - ABS_ALT(Math_Vec3f_Yaw(&thisx->world.pos, &player->actor.world.pos)) < 0xC000) { + if ((this->actor.xzDistToPlayer < 150.0f) && + (ABS_ALT(Math_Vec3f_Yaw(&thisx->world.pos, &player->actor.world.pos)) < 0xC000)) { targetX = Math_Vec3f_Pitch(&thisx->focus.pos, &player->actor.focus.pos); targetY = Math_Vec3f_Yaw(&thisx->focus.pos, &player->actor.focus.pos) - this->actor.shape.rot.y; diff --git a/src/overlays/actors/ovl_En_Gs/z_en_gs.c b/src/overlays/actors/ovl_En_Gs/z_en_gs.c index c8c3016c2..5d47d222c 100644 --- a/src/overlays/actors/ovl_En_Gs/z_en_gs.c +++ b/src/overlays/actors/ovl_En_Gs/z_en_gs.c @@ -5,6 +5,7 @@ */ #include "z_en_gs.h" +#include "z64voice.h" #include "overlays/actors/ovl_En_Bom/z_en_bom.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" #include "objects/object_gs/object_gs.h" @@ -159,7 +160,7 @@ void EnGs_Init(Actor* thisx, PlayState* play) { Math_Vec3f_Copy(&this->unk_1B0[0], &gOneVec3f); Math_Vec3f_Copy(&this->unk_1B0[1], &gOneVec3f); SubS_FillCutscenesList(&this->actor, this->csIdList, ARRAY_COUNT(this->csIdList)); - func_801A5080(0); + func_801A5080(VOICE_WORD_ID_HOURS); if (this->actor.params == ENGS_1) { Actor_SetScale(&this->actor, 0.15f); this->collider.dim.radius *= 1.5f; @@ -946,7 +947,7 @@ void func_80999BC8(Actor* thisx, PlayState* play2) { EnGs* this = THIS; s32 pad; - if (this->actor.isLockedOn && !func_801A5100()) { + if (this->actor.isLockedOn && (AudioVoice_GetWord() == VOICE_WORD_ID_HOURS)) { this->unk_19D = 0; this->unk_19A |= 1; func_80999AC0(this); diff --git a/src/overlays/actors/ovl_En_Hidden_Nuts/z_en_hidden_nuts.c b/src/overlays/actors/ovl_En_Hidden_Nuts/z_en_hidden_nuts.c index c7c516d12..ed72da01a 100644 --- a/src/overlays/actors/ovl_En_Hidden_Nuts/z_en_hidden_nuts.c +++ b/src/overlays/actors/ovl_En_Hidden_Nuts/z_en_hidden_nuts.c @@ -5,6 +5,7 @@ */ #include "z_en_hidden_nuts.h" +#include "z64voice.h" #include "overlays/effects/ovl_Effect_Ss_Hahen/z_eff_ss_hahen.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_2000000) @@ -131,7 +132,7 @@ void EnHiddenNuts_Init(Actor* thisx, PlayState* play) { this->path = SubS_GetPathByIndex(play, this->pathIndex, ENHIDDENNUTS_PATH_INDEX_NONE_ALT); this->csId = this->actor.csId; - func_801A5080(2); + func_801A5080(VOICE_WORD_ID_WAKE_UP); func_80BDB268(this); } @@ -213,7 +214,7 @@ void func_80BDB2B8(EnHiddenNuts* this, PlayState* play) { if ((play->msgCtx.ocarinaMode == OCARINA_MODE_EVENT) && (play->msgCtx.lastPlayedSong == OCARINA_SONG_SONATA)) { play->msgCtx.ocarinaMode = OCARINA_MODE_END; func_80BDB788(this); - } else if (func_801A5100() == 2) { + } else if (AudioVoice_GetWord() == VOICE_WORD_ID_WAKE_UP) { func_80BDB788(this); } else { Actor_OfferTalk(&this->actor, play, BREG(13) + 100.0f); diff --git a/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.c b/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.c index bcc83766a..5dbb270a9 100644 --- a/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.c +++ b/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.c @@ -5,32 +5,74 @@ */ #include "z_en_honotrap.h" +#include "assets/objects/gameplay_keep/gameplay_keep.h" +#include "assets/objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h" #define FLAGS (ACTOR_FLAG_10) -#define THIS ((EnHonotrap*)thisx) +#define HONOTRAP_AT_ACTIVE (1 << 0) +#define HONOTRAP_AC_ACTIVE (1 << 1) +#define HONOTRAP_OC_ACTIVE (1 << 2) + +typedef enum { + /* 0 */ HONOTRAP_EYE_OPEN, + /* 1 */ HONOTRAP_EYE_HALF, + /* 2 */ HONOTRAP_EYE_CLOSE, + /* 3 */ HONOTRAP_EYE_SHUT, + /* 4 */ HONOTRAP_EYE_MAX +} EnHonotrapEyeState; void EnHonotrap_Init(Actor* thisx, PlayState* play); void EnHonotrap_Destroy(Actor* thisx, PlayState* play); void EnHonotrap_Update(Actor* thisx, PlayState* play); void EnHonotrap_Draw(Actor* thisx, PlayState* play); -void func_8092EBDC(EnHonotrap* this, PlayState* play); -void func_8092ECF0(EnHonotrap* this, PlayState* play); -void func_8092EDD8(EnHonotrap* this, PlayState* play); -void func_8092EE1C(EnHonotrap* this, PlayState* play); -void func_8092EE90(EnHonotrap* this, PlayState* play); -void func_8092EF98(EnHonotrap* this, PlayState* play); -void func_8092F074(EnHonotrap* this, PlayState* play); -void func_8092F0B8(EnHonotrap* this, PlayState* play); -void func_8092F10C(EnHonotrap* this, PlayState* play); -void func_8092F208(EnHonotrap* this, PlayState* play); -void func_8092F3D8(EnHonotrap* this, PlayState* play); -void func_8092F5EC(EnHonotrap* this, PlayState* play); -void func_8092F7BC(EnHonotrap* this, PlayState* play); -void func_8092F878(EnHonotrap* this, PlayState* play); +void EnHonotrap_GetNormal(Vec3f* normal, Vec3f* vec); +void EnHonotrap_InitEye(EnHonotrap* this, PlayState* play); +void EnHonotrap_InitFlame(EnHonotrap* this, PlayState* play); +void EnHonotrap_InitFlameGroup(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeIdle(EnHonotrap* this); +void EnHonotrap_EyeIdle(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeOpen(EnHonotrap* this); +void EnHonotrap_EyeOpen(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeAttack(EnHonotrap* this); +void EnHonotrap_EyeAttack(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeClose(EnHonotrap* this); +void EnHonotrap_EyeClose(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeIdle2(EnHonotrap* this); +void EnHonotrap_EyeIdle2(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeOpen2(EnHonotrap* this); +void EnHonotrap_EyeOpen2(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeAttack2(EnHonotrap* this); +void EnHonotrap_EyeAttack2(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupEyeClose2(EnHonotrap* this); +void EnHonotrap_EyeClose2(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameGrow(EnHonotrap* this); +void EnHonotrap_FlameGrow(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameDrop(EnHonotrap* this); +void EnHonotrap_FlameDrop(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameMove(EnHonotrap* this); +void EnHonotrap_FlameMove(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameChase(EnHonotrap* this); +void EnHonotrap_FlameChase(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameVanish(EnHonotrap* this); +void EnHonotrap_FlameVanish(EnHonotrap* this, PlayState* play); +void EnHonotrap_SetupFlameGroup(EnHonotrap* this); +void EnHonotrap_FlameGroup(EnHonotrap* this, PlayState* play); +void EnHonotrap_UpdateFlame(Actor* thisx, PlayState* play); +void EnHonotrap_UpdateFlameGroup(Actor* thisx, PlayState* play); +void EnHonotrap_DrawFlame(Actor* thisx, PlayState* play); +void EnHonotrap_DrawFlameGroup(Actor* thisx, PlayState* play); + +static TexturePtr sSilverEyeTextures[HONOTRAP_EYE_MAX] = { + gEyeSwitchSilverOpenTex, + gEyeSwitchSilverHalfTex, + gEyeSwitchSilverClosedTex, + gEyeSwitchSilverClosedTex, +}; + +static s32 sIsFirstInitEye = true; -#if 0 ActorInit En_Honotrap_InitVars = { /**/ ACTOR_EN_HONOTRAP, /**/ ACTORCAT_PROP, @@ -43,127 +85,725 @@ ActorInit En_Honotrap_InitVars = { /**/ EnHonotrap_Draw, }; -// static ColliderTrisElementInit sTrisElementsInit[2] = { -static ColliderTrisElementInit D_80930424[2] = { +static ColliderTrisElementInit sTrisElementsInit[] = { { - { ELEMTYPE_UNK4, { 0x00000000, 0x00, 0x00 }, { 0x00003820, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, + { + ELEMTYPE_UNK4, + { 0x00000000, 0x00, 0x00 }, + { 0x00003820, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, { { { 0.0f, 23.0f, 8.5f }, { -23.0f, 0.0f, 8.5f }, { 0.0f, -23.0f, 8.5f } } }, }, { - { ELEMTYPE_UNK4, { 0x00000000, 0x00, 0x00 }, { 0x00003820, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, }, + { + ELEMTYPE_UNK4, + { 0x00000000, 0x00, 0x00 }, + { 0x00003820, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_NONE, + }, { { { 0.0f, 23.0f, 8.5f }, { 0.0f, -23.0f, 8.5f }, { 23.0f, 0.0f, 8.5f } } }, }, }; -// static ColliderTrisInit sTrisInit = { -static ColliderTrisInit D_8093049C = { - { COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_NONE, OC2_NONE, COLSHAPE_TRIS, }, - ARRAY_COUNT(sTrisElementsInit), D_80930424, // sTrisElementsInit, +static ColliderTrisInit sTrisInit = { + { + COLTYPE_NONE, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_NONE, + OC2_NONE, + COLSHAPE_TRIS, + }, + ARRAY_COUNT(sTrisElementsInit), + sTrisElementsInit, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_809304AC = { - { COLTYPE_NONE, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_2, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x01, 0x04 }, { 0x00100000, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_2, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x01, 0x04 }, + { 0x00100000, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NONE, + BUMP_ON, + OCELEM_ON, + }, { 10, 25, 0, { 0, 0, 0 } }, }; -// sColChkInfoInit -static CollisionCheckInfoInit D_809304D8 = { 0, 9, 23, 1 }; +static CollisionCheckInfoInit sColChkInfoInit = { 0, 9, 23, 1 }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_809304E0[] = { +static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 100, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 100, ICHAIN_STOP), }; -#endif +void EnHonotrap_FlameCollisionCheck(EnHonotrap* this, PlayState* play) { + s32 pad[3]; -extern ColliderTrisElementInit D_80930424[2]; -extern ColliderTrisInit D_8093049C; -extern ColliderCylinderInit D_809304AC; -extern CollisionCheckInfoInit D_809304D8; -extern InitChainEntry D_809304E0[]; + Collider_UpdateCylinder(&this->actor, &this->collider.cyl); + CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.tris.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.tris.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.tris.base); + this->colChkFlags |= HONOTRAP_AT_ACTIVE; + this->colChkFlags |= HONOTRAP_AC_ACTIVE; + this->colChkFlags |= HONOTRAP_OC_ACTIVE; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092E510.s") +void EnHonotrap_GetNormal(Vec3f* normal, Vec3f* vec) { + f32 magnitude = Math3D_Vec3fMagnitude(vec); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092E5A4.s") + if (magnitude < 0.001f) { + normal->x = normal->y = 0.0f; + normal->z = 1.0f; + } else { + normal->x = vec->x * (1.0f / magnitude); + normal->y = vec->y * (1.0f / magnitude); + normal->z = vec->z * (1.0f / magnitude); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092E638.s") +void EnHonotrap_InitEye(EnHonotrap* this, PlayState* play) { + s32 i; + s32 j; + s32 k; + f32 sin = Math_SinS(this->actor.home.rot.y); + f32 cos = Math_CosS(this->actor.home.rot.y); + Vec3f triangle[3]; + Vec3f* vtx; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092E840.s") + Actor_SetScale(&this->actor, 0.1f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092E988.s") + if (sIsFirstInitEye) { + sIsFirstInitEye = false; + for (k = 0; k < HONOTRAP_EYE_MAX; k++) { + sSilverEyeTextures[k] = Lib_SegmentedToVirtual(sSilverEyeTextures[k]); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/EnHonotrap_Init.s") + Collider_InitTris(play, &this->collider.tris); + Collider_SetTris(play, &this->collider.tris, &this->actor, &sTrisInit, this->collider.elements); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/EnHonotrap_Destroy.s") + for (i = 0; i < 2; i++) { + for (j = 0, vtx = triangle; j < 3; j++, vtx++) { + Vec3f* baseVtx = &sTrisInit.elements[i].dim.vtx[j]; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EBC0.s") + vtx->x = (baseVtx->z * sin) + (baseVtx->x * cos); + vtx->y = baseVtx->y; + vtx->z = (baseVtx->z * cos) - (baseVtx->x * sin); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EBDC.s") + Math_Vec3f_Sum(vtx, &this->actor.world.pos, vtx); + } + Collider_SetTrisVertices(&this->collider.tris, i, &triangle[0], &triangle[1], &triangle[2]); + } + Actor_SetFocus(&this->actor, 0.0f); + if (this->actor.params == HONOTRAP_TYPE_EYE) { + EnHonotrap_SetupEyeIdle(this); + } else { // HONOTRAP_TYPE_EYE_MUTI_FLAME + EnHonotrap_SetupEyeIdle2(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EC9C.s") +void EnHonotrap_InitFlame(EnHonotrap* this, PlayState* play) { + s32 pad[2]; + s32 params = this->actor.params; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092ECF0.s") + Actor_SetScale(&this->actor, 0.0001f); + Collider_InitCylinder(play, &this->collider.cyl); + Collider_SetCylinder(play, &this->collider.cyl, &this->actor, &sCylinderInit); + Collider_UpdateCylinder(&this->actor, &this->collider.cyl); + this->actor.terminalVelocity = -1.0f; + CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit); + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f); + this->actor.shape.shadowAlpha = 128; + this->targetPos = GET_PLAYER(play)->actor.world.pos; + this->targetPos.y += 10.0f; + this->flameScroll = Rand_ZeroOne() * 511.0f; + Actor_PlaySfx(&this->actor, NA_SE_EV_FLAME_IGNITION); + if (params == HONOTRAP_TYPE_FLAME_DROP) { + this->actor.room = -1; + this->collider.cyl.dim.radius = 12; + this->collider.cyl.dim.height = 30; + this->actor.shape.yOffset = -1000.0f; + } + EnHonotrap_SetupFlameGrow(this); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EDC0.s") +void EnHonotrap_InitFlameGroup(EnHonotrap* this, PlayState* play) { + EnHonotrapFlameGroup* flameGroup; + s32 flameScroll; + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EDD8.s") + Actor_SetScale(&this->actor, 0.0001f); + Collider_InitCylinder(play, &this->collider.cyl); + Collider_SetCylinder(play, &this->collider.cyl, &this->actor, &sCylinderInit); + CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EE08.s") + flameScroll = Rand_ZeroOne() * 511.0f; + flameGroup = &this->flameGroup; + for (i = 0; i < ARRAY_COUNT(flameGroup->flameList); i++) { + flameGroup->flameList[i].flameScroll = flameScroll; + flameScroll += (s32)Rand_ZeroFloat(300.0f) + 100; + flameScroll &= 0x1FF; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EE1C.s") + Actor_PlaySfx(&this->actor, NA_SE_EV_FLAME_IGNITION); + EnHonotrap_SetupFlameGroup(this); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EE68.s") +void EnHonotrap_Init(Actor* thisx, PlayState* play) { + s32 params; + EnHonotrap* this = (EnHonotrap*)thisx; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EE90.s") + params = this->actor.params; + Actor_ProcessInitChain(&this->actor, sInitChain); + if ((params == HONOTRAP_TYPE_EYE) || (params == HONOTRAP_TYPE_EYE_MUTI_FLAME)) { + EnHonotrap_InitEye(this, play); + } else if (params == HONOTRAP_TYPE_FLAME_GROUP) { + EnHonotrap_InitFlameGroup(this, play); + this->actor.update = EnHonotrap_UpdateFlameGroup; + this->actor.draw = EnHonotrap_DrawFlameGroup; + this->actor.uncullZoneScale = 500.0f; + this->actor.uncullZoneDownward = 500.0f; + } else { // HONOTRAP_TYPE_FLAME_MOVE, HONOTRAP_TYPE_FLAME_DROP + EnHonotrap_InitFlame(this, play); + this->actor.update = EnHonotrap_UpdateFlame; + this->actor.draw = EnHonotrap_DrawFlame; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EF3C.s") +void EnHonotrap_Destroy(Actor* thisx, PlayState* play) { + s16 params; + EnHonotrap* this = (EnHonotrap*)thisx; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092EF98.s") + params = this->actor.params; + if ((params == HONOTRAP_TYPE_EYE) || (params == HONOTRAP_TYPE_EYE_MUTI_FLAME)) { + Collider_DestroyTris(play, &this->collider.tris); + } else { + Collider_DestroyCylinder(play, &this->collider.cyl); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F05C.s") +void EnHonotrap_SetupEyeIdle(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeIdle; + this->eyeState = HONOTRAP_EYE_SHUT; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F074.s") +void EnHonotrap_EyeIdle(EnHonotrap* this, PlayState* play) { + if (this->actor.child != NULL) { + this->timer = 200; + } else if ((this->timer <= 0) && (this->actor.xzDistToPlayer < 750.0f)) { + if ((this->actor.playerHeightRel < 0.0f) && (this->actor.playerHeightRel > -700.0f)) { + s16 angle = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F0A4.s") + if ((angle > -0x4000) && (angle < 0x4000)) { + EnHonotrap_SetupEyeOpen(this); + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F0B8.s") +void EnHonotrap_SetupEyeOpen(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeOpen; + Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 40); + this->timer = 30; + Actor_PlaySfx(&this->actor, NA_SE_EV_RED_EYE); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F0F8.s") +void EnHonotrap_EyeOpen(EnHonotrap* this, PlayState* play) { + this->eyeState--; + if (this->eyeState <= HONOTRAP_EYE_OPEN) { + EnHonotrap_SetupEyeAttack(this); + Actor_SpawnAsChild( + &play->actorCtx, &this->actor, play, ACTOR_EN_HONOTRAP, + (Math_SinS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.x, this->actor.home.pos.y - 10.0f, + (Math_CosS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.z, this->actor.home.rot.x, + this->actor.home.rot.y, this->actor.home.rot.z, HONOTRAP_TYPE_FLAME_MOVE); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F10C.s") +void EnHonotrap_SetupEyeAttack(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeAttack; + this->eyeState = HONOTRAP_EYE_OPEN; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F1A0.s") +void EnHonotrap_EyeAttack(EnHonotrap* this, PlayState* play) { + if (this->timer <= 0) { + EnHonotrap_SetupEyeClose(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F208.s") +void EnHonotrap_SetupEyeClose(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeClose; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F34C.s") +void EnHonotrap_EyeClose(EnHonotrap* this, PlayState* play) { + this->eyeState++; + if (this->eyeState >= HONOTRAP_EYE_SHUT) { + EnHonotrap_SetupEyeIdle(this); + this->timer = 200; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F3D8.s") +void EnHonotrap_SetupEyeIdle2(EnHonotrap* this) { + this->eyeState = HONOTRAP_EYE_SHUT; + this->timer = 80; + this->unk224 = 0; + this->actionFunc = EnHonotrap_EyeIdle2; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F5AC.s") +void EnHonotrap_EyeIdle2(EnHonotrap* this, PlayState* play) { + if ((this->timer <= 0) && (this->actor.xzDistToPlayer < 120.0f)) { + if ((this->actor.playerHeightRel < 0.0f) && (this->actor.playerHeightRel > -700.0f)) { + s16 angle = this->actor.yawTowardsPlayer - this->actor.shape.rot.y; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F5EC.s") + if ((angle > -0x4000) && (angle < 0x4000)) { + EnHonotrap_SetupEyeOpen2(this); + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F7A8.s") +void EnHonotrap_SetupEyeOpen2(EnHonotrap* this) { + Actor_PlaySfx(&this->actor, NA_SE_EV_RED_EYE); + Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 40); + this->timer = 40; + this->actionFunc = EnHonotrap_EyeOpen2; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F7BC.s") +void EnHonotrap_EyeOpen2(EnHonotrap* this, PlayState* play) { + s32 pad; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F854.s") + this->eyeState--; + if (this->eyeState <= HONOTRAP_EYE_OPEN) { + Actor_SpawnAsChild( + &play->actorCtx, &this->actor, play, ACTOR_EN_HONOTRAP, + (Math_SinS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.x, this->actor.home.pos.y, + (Math_CosS(this->actor.shape.rot.y) * 12.0f) + this->actor.home.pos.z, this->actor.home.rot.x, + this->actor.home.rot.y, this->actor.home.rot.z, HONOTRAP_TYPE_FLAME_GROUP); + EnHonotrap_SetupEyeAttack2(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092F878.s") +void EnHonotrap_SetupEyeAttack2(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeAttack2; + this->eyeState = HONOTRAP_EYE_OPEN; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/EnHonotrap_Update.s") +void EnHonotrap_EyeAttack2(EnHonotrap* this, PlayState* play) { + if (this->timer <= 0) { + EnHonotrap_SetupEyeClose2(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092FE44.s") +void EnHonotrap_SetupEyeClose2(EnHonotrap* this) { + this->actionFunc = EnHonotrap_EyeClose2; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_8092FEFC.s") +void EnHonotrap_EyeClose2(EnHonotrap* this, PlayState* play) { + this->eyeState++; + if (this->eyeState >= HONOTRAP_EYE_SHUT) { + EnHonotrap_SetupEyeIdle2(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/EnHonotrap_Draw.s") +void EnHonotrap_SetupFlameGrow(EnHonotrap* this) { + this->actionFunc = EnHonotrap_FlameGrow; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_80930030.s") +void EnHonotrap_FlameGrow(EnHonotrap* this, PlayState* play) { + f32 targetScale = (this->actor.params == HONOTRAP_TYPE_FLAME_MOVE) ? 0.004f : 0.0048f; + s32 targetReached = Math_StepToF(&this->actor.scale.x, targetScale, 0.0006f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Honotrap/func_80930190.s") + this->actor.scale.z = this->actor.scale.y = this->actor.scale.x; + if (targetReached) { + if (this->actor.params == HONOTRAP_TYPE_FLAME_MOVE) { + EnHonotrap_SetupFlameMove(this); + } else { // HONOTRAP_TYPE_FLAME_DROP + EnHonotrap_SetupFlameDrop(this); + } + } +} + +void EnHonotrap_SetupFlameDrop(EnHonotrap* this) { + this->timer = 40; + this->actor.velocity.y = 1.0f; + this->actor.velocity.x = 2.0f * Math_SinS(this->actor.world.rot.y); + this->actor.velocity.z = 2.0f * Math_CosS(this->actor.world.rot.y); + this->actionFunc = EnHonotrap_FlameDrop; +} + +void EnHonotrap_FlameDrop(EnHonotrap* this, PlayState* play) { + if ((this->collider.tris.base.atFlags & AT_HIT) || (this->timer <= 0)) { + if ((this->collider.tris.base.atFlags & AT_HIT) && !(this->collider.tris.base.atFlags & AT_BOUNCED)) { + func_800B8D98(play, &this->actor, 5.0f, this->actor.yawTowardsPlayer, 0.0f); + } + this->actor.velocity.z = 0.0f; + this->actor.velocity.y = 0.0f; + this->actor.velocity.x = 0.0f; + EnHonotrap_SetupFlameVanish(this); + return; + } + if (this->actor.velocity.y > 0.0f) { + this->actor.world.pos.x += this->actor.velocity.x; + this->actor.world.pos.z += this->actor.velocity.z; + Actor_UpdateBgCheckInfo(play, &this->actor, 10.0f, 12.0f, 0.0f, UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4); + } + if (!Math_StepToF(&this->actor.world.pos.y, this->actor.floorHeight + 1.0f, this->actor.velocity.y)) { + this->actor.velocity.y += 1.0f; + } else { + this->actor.velocity.y = 0.0f; + } + EnHonotrap_FlameCollisionCheck(this, play); +} + +void EnHonotrap_SetupFlameMove(EnHonotrap* this) { + f32 distInverse; + + this->actionFunc = EnHonotrap_FlameMove; + distInverse = 1.0f / (Actor_WorldDistXYZToPoint(&this->actor, &this->targetPos) + 1.0f); + this->actor.velocity.x = (this->targetPos.x - this->actor.world.pos.x) * distInverse; + this->actor.velocity.y = (this->targetPos.y - this->actor.world.pos.y) * distInverse; + this->actor.velocity.z = (this->targetPos.z - this->actor.world.pos.z) * distInverse; + this->speedMod = 0.0f; + this->timer = 160; +} + +void EnHonotrap_FlameMove(EnHonotrap* this, PlayState* play) { + Actor* thisx = &this->actor; + Vec3f speed; + s32 cond; + + Math_StepToF(&this->speedMod, 13.0f, 0.5f); + speed.x = fabsf(this->speedMod * thisx->velocity.x); + speed.y = fabsf(this->speedMod * thisx->velocity.y); + speed.z = fabsf(this->speedMod * thisx->velocity.z); + cond = true; + cond &= Math_StepToF(&thisx->world.pos.x, this->targetPos.x, speed.x); + cond &= Math_StepToF(&thisx->world.pos.y, this->targetPos.y, speed.y); + cond &= Math_StepToF(&thisx->world.pos.z, this->targetPos.z, speed.z); + Actor_UpdateBgCheckInfo(play, thisx, 10.0f, 10.0f, 0.0f, + UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4 | UPDBGCHECKINFO_FLAG_8 | + UPDBGCHECKINFO_FLAG_10); + + if (this->collider.tris.base.atFlags & AT_BOUNCED) { + Player* player = GET_PLAYER(play); + Vec3f shieldNorm; + Vec3f tempVel; + Vec3f shieldVec; + + shieldVec.x = -player->shieldMf.xz; + shieldVec.y = -player->shieldMf.yz; + shieldVec.z = -player->shieldMf.zz; + EnHonotrap_GetNormal(&shieldNorm, &shieldVec); + tempVel = thisx->velocity; + Math3D_Vec3fReflect(&tempVel, &shieldNorm, &thisx->velocity); + thisx->speed = this->speedMod * 0.5f; + thisx->world.rot.y = Math_Atan2S_XY(thisx->velocity.z, thisx->velocity.x); + EnHonotrap_SetupFlameVanish(this); + } else if (this->collider.tris.base.atFlags & AT_HIT) { + thisx->speed = 0.0f; + thisx->velocity.y = 0.0f; + EnHonotrap_SetupFlameVanish(this); + } else if (this->timer <= 0) { + EnHonotrap_SetupFlameVanish(this); + } else { + EnHonotrap_FlameCollisionCheck(this, play); + if (cond != 0) { + EnHonotrap_SetupFlameChase(this); + } + } +} + +void EnHonotrap_SetupFlameChase(EnHonotrap* this) { + this->actionFunc = EnHonotrap_FlameChase; + this->actor.speed = 0.0f; + this->actor.velocity.x = this->actor.velocity.y = this->actor.velocity.z = 0.0f; + this->timer = 100; + this->actor.world.rot.x = this->actor.world.rot.y = this->actor.world.rot.z = 0; +} + +void EnHonotrap_FlameChase(EnHonotrap* this, PlayState* play) { + s32 pad; + + Math_ScaledStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 0x300); + Math_StepToF(&this->actor.speed, 3.0f, 0.1f); + this->actor.gravity = (-this->actor.playerHeightRel < 10.0f) ? 0.08f : -0.08f; + Actor_UpdateVelocityWithGravity(&this->actor); + if (this->actor.velocity.y > 1.0f) { + this->actor.velocity.y = 1.0f; + } + this->actor.velocity.y *= 0.95f; + Actor_UpdatePos(&this->actor); + Actor_UpdateBgCheckInfo(play, &this->actor, 10.0f, 10.0f, 0.0f, + UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4 | UPDBGCHECKINFO_FLAG_8 | + UPDBGCHECKINFO_FLAG_10); + + if (this->collider.tris.base.atFlags & AT_BOUNCED) { + Player* player = GET_PLAYER(play); + Vec3s shieldRot; + + Matrix_MtxFToYXZRot(&player->shieldMf, &shieldRot, 0); + this->actor.world.rot.y = ((shieldRot.y * 2) - this->actor.world.rot.y) + 0x8000; + EnHonotrap_SetupFlameVanish(this); + } else if (this->collider.tris.base.atFlags & AT_HIT) { + this->actor.speed *= 0.1f; + this->actor.velocity.y *= 0.1f; + EnHonotrap_SetupFlameVanish(this); + } else if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) || (this->timer <= 0)) { + EnHonotrap_SetupFlameVanish(this); + } else { + EnHonotrap_FlameCollisionCheck(this, play); + } +} + +void EnHonotrap_SetupFlameVanish(EnHonotrap* this) { + this->actionFunc = EnHonotrap_FlameVanish; +} + +void EnHonotrap_FlameVanish(EnHonotrap* this, PlayState* play) { + s32 pad; + s32 targetReached = Math_StepToF(&this->actor.scale.x, 0.0001f, 0.00015f); + + this->actor.scale.z = this->actor.scale.y = this->actor.scale.x; + Actor_MoveWithGravity(&this->actor); + Actor_UpdateBgCheckInfo(play, &this->actor, 10.0f, 10.0f, 0.0f, + UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_4 | UPDBGCHECKINFO_FLAG_8 | + UPDBGCHECKINFO_FLAG_10); + if (targetReached) { + Actor_Kill(&this->actor); + } +} + +void EnHonotrap_SetupFlameGroup(EnHonotrap* this) { + this->actionFunc = EnHonotrap_FlameGroup; + this->timer = 80; + this->flameGroup.unk8 = 0.0f; +} + +void EnHonotrap_FlameGroup(EnHonotrap* this, PlayState* play) { + s32 i; + EnHonotrapFlameGroup* flameGroup = &this->flameGroup; + f32 var_fs0; + f32 temp_fs0; + f32 temp_fs1; + f32 sp88; + f32 sp84; + f32 sp80; + s32 flameScrollDisplacement; + s32 sp78 = false; + f32 var_fs0_2; + Vec3f sp68; + EnHonotrapFlameElement* flameElem; + + sp80 = fabsf(Math_CosS(Camera_GetCamDirPitch(GET_ACTIVE_CAM(play)))); + flameScrollDisplacement = (s32)(sp80 * -10.5f) - 10; + Math_StepToF(&flameGroup->unk0, 1.0f, 0.05f); + if (this->timer <= 40) { + sp78 = Math_StepToF(&flameGroup->unk4, 1.0f, 0.05f); + } else if (this->actor.parent == NULL) { + this->timer = 40; + } + for (i = 0; i < ARRAY_COUNT(flameGroup->flameList); i++) { + flameGroup->flameList[i].isDrawn = false; + } + + sp88 = Math_SinS(this->actor.shape.rot.y) * 120.0f; + sp84 = Math_CosS(this->actor.shape.rot.y) * 120.0f; + + flameGroup->unk8 += 0.050f * (1.0f - flameGroup->unk4); + + if (flameGroup->unk8 > 1.0f / 6) { + flameGroup->unk8 -= 1.0f / 6; + } + var_fs0 = flameGroup->unk4 + flameGroup->unk8; + + for (i = 0; i < ARRAY_COUNT(flameGroup->flameList) && (var_fs0 <= flameGroup->unk0); i++) { + flameElem = &flameGroup->flameList[i]; + flameElem->isDrawn = true; + + flameElem->pos.x = (sp88 * var_fs0) + this->actor.world.pos.x; + flameElem->pos.y = this->actor.world.pos.y; + flameElem->pos.z = (sp84 * var_fs0) + this->actor.world.pos.z; + + flameElem->unkC = Math_SinS((s16)(s32)(var_fs0 * 25486.223f)) * 1.6f; + if (flameElem->unkC > 1.0f) { + flameElem->unkC = 1.0f; + } else if (flameElem->unkC < 0.0f) { + flameElem->unkC = 0.0f; + } + + var_fs0 += 1.0f / 6; + flameElem->unkC *= (0.006f * (((1.0f - flameGroup->unk4) * 0.8f) + 0.2f)); + flameElem->flameScroll += flameScrollDisplacement; + flameElem->flameScroll %= 0x200u; + } + + if (sp78 || (this->timer <= 0)) { + Actor_Kill(&this->actor); + return; + } + temp_fs0 = flameGroup->unk0 * 120.0f; + temp_fs1 = flameGroup->unk4 * 120.0f; + Actor_OffsetOfPointInActorCoords(&this->actor, &sp68, &GET_PLAYER(play)->actor.world.pos); + + if (sp68.z < temp_fs1) { + sp68.z = temp_fs1; + } else if (temp_fs0 < sp68.z) { + sp68.z = temp_fs0; + } + + var_fs0_2 = Math_SinS((s16)(s32)(sp68.z * 212.3852f)) * 1.6f; + if (var_fs0_2 > 1.0f) { + var_fs0_2 = 1.0f; + } + sp80 *= ((1.0f - flameGroup->unk4) * 0.8f) + 0.2f; + if (sp80 > 0.2f) { + this->collider.cyl.dim.pos.x = + (s16)(s32)((Math_SinS(this->actor.shape.rot.y) * sp68.z) + this->actor.world.pos.x); + this->collider.cyl.dim.pos.y = (s16)(s32)(this->actor.world.pos.y - (24.0f * var_fs0_2)); + this->collider.cyl.dim.pos.z = + (s16)(s32)((Math_CosS(this->actor.shape.rot.y) * sp68.z) + this->actor.world.pos.z); + this->collider.cyl.dim.radius = (s16)(s32)(15.0f * var_fs0_2); + this->collider.cyl.dim.height = (s16)(s32)(37.5f * var_fs0_2); + CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.tris.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.tris.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.tris.base); + } +} + +void EnHonotrap_Update(Actor* thisx, PlayState* play) { + static Vec3f sVelocity = { 0.0f, 0.0f, 0.0f }; + static Vec3f sAccel = { 0.0f, 0.1f, 0.0f }; + EnHonotrap* this = (EnHonotrap*)thisx; + + if (this->timer > 0) { + this->timer--; + } + if ((this->actor.child != NULL) && (this->actor.child->update == NULL)) { + this->actor.child = NULL; + } + this->actionFunc(this, play); + if (this->collider.tris.base.acFlags & AC_HIT) { + EffectSsBomb2_SpawnLayered(play, &this->actor.world.pos, &sVelocity, &sAccel, 15, 8); + Actor_Kill(&this->actor); + return; + } + if (this->eyeState < HONOTRAP_EYE_SHUT) { + this->collider.tris.base.acFlags &= ~AC_HIT; + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.tris.base); + } +} + +void EnHonotrap_UpdateFlame(Actor* thisx, PlayState* play) { + EnHonotrap* this = (EnHonotrap*)thisx; + + if (this->timer > 0) { + this->timer--; + } + this->colChkFlags = 0; + this->bobPhase += 0x640; + if (this->actor.params != HONOTRAP_TYPE_FLAME_GROUP) { + this->actor.shape.yOffset = Math_SinS(this->bobPhase) * 1000.0f + 600.0f; + } + Actor_SetFocus(&this->actor, 5.0f); + Actor_PlaySfx(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG); + this->actionFunc(this, play); + this->flameScroll -= 20; + this->flameScroll %= 0x200u; +} + +void EnHonotrap_UpdateFlameGroup(Actor* thisx, PlayState* play) { + EnHonotrap* this = (EnHonotrap*)thisx; + Actor* parent = this->actor.parent; + + if ((parent != NULL) && (parent->update == NULL)) { + this->actor.parent = NULL; + } + if (this->timer > 0) { + this->timer--; + } + this->bobPhase += 0x640; + Actor_PlaySfx(&this->actor, NA_SE_EV_BURN_OUT - SFX_FLAG); + this->actionFunc(this, play); +} + +void EnHonotrap_Draw(Actor* thisx, PlayState* play) { + EnHonotrap* this = (EnHonotrap*)thisx; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + gSPSegment(POLY_OPA_DISP++, 0x08, sSilverEyeTextures[this->eyeState]); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, &gEyeSwitchSilverDL); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void EnHonotrap_DrawFlame(Actor* thisx, PlayState* play) { + s32 pad; + EnHonotrap* this = (EnHonotrap*)thisx; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 32, 64, 1, 0, this->flameScroll, 32, 128)); + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 200, 0, 255); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0); + Matrix_RotateYS(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play)) + 0x8000, 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); +} + +void EnHonotrap_DrawFlameGroup(Actor* thisx, PlayState* play) { + s32 pad; + EnHonotrap* this = ((EnHonotrap*)thisx); + EnHonotrapFlameElement* flameElem; + EnHonotrapFlameGroup* flameGroup = &this->flameGroup; + s32 i; + s32 pad2; + Vec3s camDir; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 200, 0, 255); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 0, 0, 0); + Camera_GetCamDir(&camDir, GET_ACTIVE_CAM(play)); + camDir.y += 0x8000; + + for (i = 0; i < ARRAY_COUNT(flameGroup->flameList); i++) { + flameElem = &flameGroup->flameList[i]; + if (flameElem->isDrawn) { + gSPSegment( + POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, flameElem->flameScroll, 0x20, 0x80)); + Matrix_SetTranslateRotateYXZ(flameElem->pos.x, flameElem->pos.y - (4000.0f * flameElem->unkC), + flameElem->pos.z, &camDir); + Matrix_Scale(((fabsf(Math_SinS((s16)(camDir.y - thisx->shape.rot.y) >> 1)) * 0.2f) + 1.7f) * + flameElem->unkC, + flameElem->unkC, 1.0f, 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_Honotrap/z_en_honotrap.h b/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.h index 570269fe2..db78f30ff 100644 --- a/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.h +++ b/src/overlays/actors/ovl_En_Honotrap/z_en_honotrap.h @@ -7,10 +7,49 @@ struct EnHonotrap; typedef void (*EnHonotrapActionFunc)(struct EnHonotrap*, PlayState*); +typedef union { + struct { + /* 0x00 */ ColliderTris tris; + /* 0x20 */ ColliderTrisElement elements[2]; + }; + /* 0x00 */ ColliderCylinder cyl; +} EnHonotrapCollider; // size = 0xD8 + +typedef struct { + /* 0x00 */ Vec3f pos; + /* 0x0C */ f32 unkC; + /* 0x10 */ s16 flameScroll; + /* 0x12 */ u8 isDrawn; +} EnHonotrapFlameElement; // size = 0x14 + +typedef struct { + /* 0x0 */ f32 unk0; + /* 0x4 */ f32 unk4; + /* 0x8 */ f32 unk8; + /* 0xC */ EnHonotrapFlameElement flameList[6]; +} EnHonotrapFlameGroup; // size = 0x84; + typedef struct EnHonotrap { /* 0x000 */ Actor actor; /* 0x144 */ EnHonotrapActionFunc actionFunc; - /* 0x148 */ char unk_148[0x17C]; + /* 0x148 */ EnHonotrapCollider collider; + /* 0x220 */ s16 timer; + /* 0x222 */ s16 eyeState; + /* 0x224 */ s16 unk224; + /* 0x228 */ Vec3f targetPos; + /* 0x234 */ f32 speedMod; + /* 0x238 */ s16 bobPhase; + /* 0x23A */ s16 flameScroll; + /* 0x23C */ EnHonotrapFlameGroup flameGroup; + /* 0x2C0 */ u8 colChkFlags; } EnHonotrap; // size = 0x2C4 +typedef enum { + /* 0 */ HONOTRAP_TYPE_EYE, + /* 1 */ HONOTRAP_TYPE_FLAME_MOVE, + /* 2 */ HONOTRAP_TYPE_FLAME_DROP, + /* 3 */ HONOTRAP_TYPE_EYE_MUTI_FLAME, + /* 4 */ HONOTRAP_TYPE_FLAME_GROUP +} EnHonotrapType; + #endif // Z_EN_HONOTRAP_H diff --git a/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/src/overlays/actors/ovl_En_Horse/z_en_horse.c index 4c549765a..a54ac46fd 100644 --- a/src/overlays/actors/ovl_En_Horse/z_en_horse.c +++ b/src/overlays/actors/ovl_En_Horse/z_en_horse.c @@ -7,6 +7,7 @@ #include "z_en_horse.h" #include "z64horse.h" #include "z64rumble.h" +#include "z64voice.h" #include "overlays/actors/ovl_En_In/z_en_in.h" #include "overlays/actors/ovl_Obj_Um/z_obj_um.h" #include "overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.h" @@ -4016,9 +4017,9 @@ void func_80886C00(EnHorse* this, PlayState* play) { if (((this->action == ENHORSE_ACTION_MOUNTED_WALK) || (this->action == ENHORSE_ACTION_MOUNTED_TROT) || (this->action == ENHORSE_ACTION_MOUNTED_GALLOP)) && - (CHECK_BTN_ALL(input->press.button, BTN_A) || (func_801A5100() == 5)) && (play->interfaceCtx.unk_212 == 8) && - !(this->stateFlags & ENHORSE_BOOST) && !(this->stateFlags & ENHORSE_FLAG_8) && - !(this->stateFlags & ENHORSE_FLAG_9)) { + (CHECK_BTN_ALL(input->press.button, BTN_A) || (AudioVoice_GetWord() == VOICE_WORD_ID_HIYA)) && + (play->interfaceCtx.unk_212 == 8) && !(this->stateFlags & ENHORSE_BOOST) && + !(this->stateFlags & ENHORSE_FLAG_8) && !(this->stateFlags & ENHORSE_FLAG_9)) { if (this->numBoosts > 0) { Rumble_Request(0.0f, 180, 20, 100); this->stateFlags |= ENHORSE_BOOST; diff --git a/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.c b/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.c index ed8606208..6444eac45 100644 --- a/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.c +++ b/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.c @@ -1,7 +1,7 @@ /* * File: z_en_po_composer.c * Overlay: ovl_En_Po_Composer - * Description: Poe Composers + * Description: Poe Composers Flat and Sharp */ #include "z_en_po_composer.h" @@ -15,19 +15,23 @@ void EnPoComposer_Destroy(Actor* thisx, PlayState* play); void EnPoComposer_Update(Actor* thisx, PlayState* play); void EnPoComposer_Draw(Actor* thisx, PlayState* play); -void func_80BC5294(EnPoComposer* this, PlayState* play); -void func_80BC52F0(EnPoComposer* this, PlayState* play); -void func_80BC53A0(EnPoComposer* this, PlayState* play); -void func_80BC5404(EnPoComposer* this, PlayState* play); -void func_80BC5570(EnPoComposer* this, PlayState* play); -void func_80BC55E0(EnPoComposer* this, PlayState* play); -void func_80BC5670(EnPoComposer* this, PlayState* play); -void func_80BC56D0(EnPoComposer* this, PlayState* play); -void func_80BC5780(EnPoComposer* this, PlayState* play); -void func_80BC5830(EnPoComposer* this, PlayState* play); -void func_80BC58E0(EnPoComposer* this, PlayState* play); +void EnPoComposer_AwaitPlayer(EnPoComposer* this, PlayState* play); +void EnPoComposer_StartCutscene(EnPoComposer* this, PlayState* play); +void EnPoComposer_StartedCutscene(EnPoComposer* this, PlayState* play); +void EnPoComposer_PlayCurse(EnPoComposer* this, PlayState* play); +void EnPoComposer_IdleStill(EnPoComposer* this, PlayState* play); +void EnPoComposer_Appear(EnPoComposer* this, PlayState* play); +void EnPoComposer_Idle(EnPoComposer* this, PlayState* play); +void EnPoComposer_RaiseArms(EnPoComposer* this, PlayState* play); +void EnPoComposer_LowerArms(EnPoComposer* this, PlayState* play); +void EnPoComposer_CutscenePlayCurse(EnPoComposer* this, PlayState* play); +void EnPoComposer_Roll(EnPoComposer* this, PlayState* play); + +void EnPoComposer_SetupAwaitPlayer(EnPoComposer* this); +void EnPoComposer_SetupStartCutscene(EnPoComposer* this); +void EnPoComposer_SetupStartedCutscene(EnPoComposer* this); +void EnPoComposer_StepLightAlpha(EnPoComposer* this); -#if 0 ActorInit En_Po_Composer_InitVars = { /**/ ACTOR_EN_PO_COMPOSER, /**/ ACTORCAT_ITEMACTION, @@ -40,32 +44,56 @@ ActorInit En_Po_Composer_InitVars = { /**/ EnPoComposer_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80BC6780 = { - { COLTYPE_HIT3, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_HIT3, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 20, 40, 20, { 0, 0, 0 } }, }; -// static ColliderJntSphElementInit sJntSphElementsInit[1] = { -static ColliderJntSphElementInit D_80BC67AC[1] = { +static ColliderJntSphElementInit sJntSphElementsInit[1] = { { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x08 }, { 0x00000000, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_ON, }, - { 9, { { 0, -1500, 0 }, 10 }, 100 }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x08 }, + { 0x00000000, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { POE_COMPOSER_LIMB_LANTERN, { { 0, -1500, 0 }, 10 }, 100 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_80BC67D0 = { - { COLTYPE_HIT3, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_JNTSPH, }, - ARRAY_COUNT(sJntSphElementsInit), D_80BC67AC, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_HIT3, + AT_ON | AT_TYPE_ENEMY, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + ARRAY_COUNT(sJntSphElementsInit), + sJntSphElementsInit, }; -// sColChkInfoInit -static CollisionCheckInfoInit D_80BC67E0 = { 4, 25, 50, 40 }; +static CollisionCheckInfoInit sColChkInfoInit = { 4, 25, 50, 40 }; -// static DamageTable sDamageTable = { -static DamageTable D_80BC67E8 = { +static DamageTable sDamageTable = { /* Deku Nut */ DMG_ENTRY(0, 0x0), /* Deku Stick */ DMG_ENTRY(2, 0x0), /* Horse trample */ DMG_ENTRY(1, 0x0), @@ -100,88 +128,619 @@ static DamageTable D_80BC67E8 = { /* Powder Keg */ DMG_ENTRY(0, 0x0), }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80BC6958[] = { +typedef enum { + /* 0 */ POE_COMPOSER_ANIM_STILL, + /* 1 */ POE_COMPOSER_ANIM_APPEAR_DISAPPEAR, + /* 2 */ POE_COMPOSER_ANIM_IDLE, + /* 3 */ POE_COMPOSER_ANIM_RAISE_ARMS, + /* 4 */ POE_COMPOSER_ANIM_ARMS_RAISED, + /* 5 */ POE_COMPOSER_ANIM_LOWER_ARMS, + /* 6 */ POE_COMPOSER_ANIM_LOOKING_DOWN, + /* 7 */ POE_COMPOSER_ANIM_BEGIN_PLAYING_CURSE, + /* 8 */ POE_COMPOSER_ANIM_PLAYING_CURSE, + /* 9 */ POE_COMPOSER_ANIM_BEGIN_ROLLING, + /* 10 */ POE_COMPOSER_ANIM_ROLLING, + /* 11 */ POE_COMPOSER_ANIM_FLEE, + /* 12 */ POE_COMPOSER_ANIM_ATTACK, + /* 13 */ POE_COMPOSER_ANIM_MAX +} EnPoComposerAnim; + +static AnimationInfo sAnimationInfo[POE_COMPOSER_ANIM_MAX] = { + /* 0 */ { &gPoeComposerStillAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 1 */ { &gPoeComposerAppearDisappearAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, 0.0f }, + /* 2 */ { &gPoeComposerIdleAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 3 */ { &gPoeComposerRaiseArmsAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 4 */ { &gPoeComposerArmsRaisedAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 5 */ { &gPoeComposerLowerArmsAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 6 */ { &gPoeComposerLookingDownAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 7 */ { &gPoeComposerBeginPlayAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 8 */ { &gPoeComposerPlayAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 9 */ { &gPoeComposerBeginRollAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 10 */ { &gPoeComposerRollAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 11 */ { &gPoeComposerFleeAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -4.0f }, + /* 12 */ { &gPoeComposerAttackAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, 0.0f }, +}; + +static Color_RGBA8 sLightColorInit = { 255, 255, 210, 0 }; + +static Color_RGBA8 sEnvColorInit = { 0, 0, 0, 255 }; + +static Color_RGBA8 sSharpClothingColor1 = { 75, 20, 25, 255 }; + +static Color_RGBA8 sFlatClothingColor1 = { 80, 110, 90, 255 }; + +static Color_RGBA8 sSharpClothingColor2 = { 90, 85, 50, 255 }; + +static Color_RGBA8 sFlatClothingColor2 = { 100, 90, 100, 255 }; + +static InitChainEntry sInitChain[] = { ICHAIN_F32(targetArrowOffset, 3200, ICHAIN_STOP), }; -#endif +static s32 sPlayerIsPlayingOcarina = false; -extern ColliderCylinderInit D_80BC6780; -extern ColliderJntSphElementInit D_80BC67AC[1]; -extern ColliderJntSphInit D_80BC67D0; -extern CollisionCheckInfoInit D_80BC67E0; -extern DamageTable D_80BC67E8; -extern InitChainEntry D_80BC6958[]; +void EnPoComposer_Init(Actor* thisx, PlayState* play) { + EnPoComposer* this = THIS; -extern UNK_TYPE D_0600188C; -extern UNK_TYPE D_06006E08; -extern UNK_TYPE D_06006FD8; + Actor_ProcessInitChain(&this->actor, sInitChain); + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f); + SkelAnime_InitFlex(play, &this->skelAnime, &gPoeComposerSkel, &gPoeComposerIdleAnim, this->jointTable, + this->morphTable, POE_COMPOSER_LIMB_MAX); + Collider_InitJntSph(play, &this->lanternCollider); + Collider_SetJntSph(play, &this->lanternCollider, &this->actor, &sJntSphInit, this->lanternColliderElements); + Collider_InitCylinder(play, &this->bodyCollider); + Collider_SetCylinder(play, &this->bodyCollider, &this->actor, &sCylinderInit); + CollisionCheck_SetInfo(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + this->lightNode = LightContext_InsertLight(play, &play->lightCtx, &this->lightInfo); + Lights_PointGlowSetInfo(&this->lightInfo, this->actor.home.pos.x, this->actor.home.pos.y, this->actor.home.pos.z, + 255, 255, 255, 0); + this->actor.flags &= ~ACTOR_FLAG_TARGETABLE; + this->lightColor = sLightColorInit; + this->envColor = sEnvColorInit; + this->cueId = POE_COMPOSER_CUEID_NONE; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/EnPoComposer_Init.s") + if (POE_COMPOSER_IS_FLAT(&this->actor)) { + this->sharpCsNum = 0; + this->inCutscene = true; + EnPoComposer_SetupStartedCutscene(this); + } else if (POE_COMPOSER_4000(&this->actor)) { + if (gSaveContext.save.entrance != ENTRANCE(IKANA_CANYON, 10)) { + Actor_Kill(&this->actor); + return; + } + this->sharpCsNum = SHARP_CS_ENCOUNTER_FIRST; + this->inCutscene = true; + EnPoComposer_SetupStartedCutscene(this); + } else { + s32 i; + s16 csId = this->actor.csId; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/EnPoComposer_Destroy.s") + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_14_04)) { + Actor_Kill(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5250.s") + for (i = 0; i < ARRAY_COUNT(this->csIds); i++) { + if (csId == CS_ID_NONE) { + break; + } + this->csIds[i] = csId; + csId = CutsceneManager_GetAdditionalCsId(csId); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5294.s") + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_14_02)) { + this->sharpCsNum = SHARP_CS_ENCOUNTER_OTHER; + } else { + this->sharpCsNum = SHARP_CS_ENCOUNTER_FIRST; + } + this->inCutscene = false; + EnPoComposer_SetupAwaitPlayer(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC52D4.s") +void EnPoComposer_Destroy(Actor* thisx, PlayState* play) { + EnPoComposer* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC52F0.s") + LightContext_RemoveLight(play, &play->lightCtx, this->lightNode); + Collider_DestroyJntSph(play, &this->lanternCollider); + Collider_DestroyCylinder(play, &this->bodyCollider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC538C.s") +void EnPoComposer_SetupAwaitPlayer(EnPoComposer* this) { + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_STILL); + this->actionFunc = EnPoComposer_AwaitPlayer; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC53A0.s") +void EnPoComposer_AwaitPlayer(EnPoComposer* this, PlayState* play) { + if (this->actor.xzDistToPlayer < 200.0f) { + EnPoComposer_SetupStartCutscene(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC53B0.s") +void EnPoComposer_SetupStartCutscene(EnPoComposer* this) { + this->inCutscene = true; + this->actionFunc = EnPoComposer_StartCutscene; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5404.s") +void EnPoComposer_StartCutscene(EnPoComposer* this, PlayState* play) { + if (CutsceneManager_IsNext(this->csIds[this->sharpCsNum])) { + CutsceneManager_Start(this->csIds[this->sharpCsNum], &this->actor); + EnPoComposer_SetupStartedCutscene(this); + } else { + if (CutsceneManager_GetCurrentCsId() == CS_ID_GLOBAL_TALK) { + CutsceneManager_Stop(CS_ID_GLOBAL_TALK); + } + CutsceneManager_Queue(this->csIds[this->sharpCsNum]); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC552C.s") +void EnPoComposer_SetupStartedCutscene(EnPoComposer* this) { + this->actionFunc = EnPoComposer_StartedCutscene; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5570.s") +void EnPoComposer_StartedCutscene(EnPoComposer* this, PlayState* play) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5580.s") +void EnPoComposer_SetupPlayCurse(EnPoComposer* this) { + this->actionTimer = 0; + this->actor.flags |= ACTOR_FLAG_TARGETABLE; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_PLAYING_CURSE); + this->actionFunc = EnPoComposer_PlayCurse; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC55E0.s") +void EnPoComposer_PlayCurse(EnPoComposer* this, PlayState* play) { + Player* player = GET_PLAYER(play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC562C.s") + // Damage the player every second + if (this->actionTimer == 20) { + func_800B8D10(play, &this->actor, 0.0f, 0, 0.0f, 1, 4); + this->actionTimer = 0; + } else { + this->actionTimer++; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5670.s") + // Ocarina check + if (player->stateFlags2 & PLAYER_STATE2_8000000) { + if (!sPlayerIsPlayingOcarina) { + // Play sound whenever the player begins playing the Ocarina + Audio_PlaySfx(NA_SE_SY_TRE_BOX_APPEAR); + } + sPlayerIsPlayingOcarina = true; + } else { + sPlayerIsPlayingOcarina = false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5680.s") + // Song check, check if player just played song of storms or song of healing + if (play->msgCtx.ocarinaMode == 3) { + switch (play->msgCtx.lastPlayedSong) { + case OCARINA_SONG_STORMS: + this->sharpCsNum = SHARP_CS_SONG_STORMS; + EnPoComposer_SetupStartCutscene(this); + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC56D0.s") + case OCARINA_SONG_HEALING: + this->sharpCsNum = SHARP_CS_SONG_HEALING; + EnPoComposer_SetupStartCutscene(this); + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5738.s") + default: + break; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5780.s") + // Play sharp's curse bgm + Audio_PlaySequenceAtPos(SEQ_PLAYER_BGM_SUB, &this->actor.projectedPos, NA_BGM_SHARPS_CURSE, 2000.0f); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC57E8.s") +void EnPoComposer_SetupIdleStill(EnPoComposer* this) { + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_STILL); + this->actionFunc = EnPoComposer_IdleStill; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5830.s") +void EnPoComposer_IdleStill(EnPoComposer* this, PlayState* play) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5898.s") +void EnPoComposer_SetupAppear(EnPoComposer* this) { + this->actionTimer = 0; + Actor_PlaySfx(&this->actor, NA_SE_EN_STALKIDS_APPEAR); + Actor_PlaySfx(&this->actor, NA_SE_EN_PO_LAUGH); + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_APPEAR_DISAPPEAR); + this->actionFunc = EnPoComposer_Appear; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC58E0.s") +void EnPoComposer_Appear(EnPoComposer* this, PlayState* play) { + this->actionTimer++; + this->actor.shape.rot.y += 0x1000; + if (this->actionTimer == 32) { + EnPoComposer_SetupIdleStill(this); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC59BC.s") +void EnPoComposer_SetupIdle(EnPoComposer* this) { + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_IDLE); + this->actionFunc = EnPoComposer_Idle; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC59EC.s") +void EnPoComposer_Idle(EnPoComposer* this, PlayState* play) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5CC8.s") +void EnPoComposer_SetupRaiseArms(EnPoComposer* this) { + this->csCueTimer = 0; + Actor_PlaySfx(&this->actor, NA_SE_EN_SHARP_REACTION); + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_RAISE_ARMS); + this->actionFunc = EnPoComposer_RaiseArms; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5D34.s") +void EnPoComposer_RaiseArms(EnPoComposer* this, PlayState* play) { + if ((this->csCueTimer == 0) && Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->csCueTimer++; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_ARMS_RAISED); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5DEC.s") +void EnPoComposer_SetupLowerArms(EnPoComposer* this) { + this->csCueTimer = 0; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_LOWER_ARMS); + this->actionFunc = EnPoComposer_LowerArms; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC5FE8.s") +void EnPoComposer_LowerArms(EnPoComposer* this, PlayState* play) { + if ((this->csCueTimer == 0) && Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->csCueTimer++; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_LOOKING_DOWN); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/EnPoComposer_Update.s") +void EnPoComposer_SetupCutscenePlayCurse(EnPoComposer* this) { + this->csCueTimer = 0; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_BEGIN_PLAYING_CURSE); + this->actionFunc = EnPoComposer_CutscenePlayCurse; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC60BC.s") +void EnPoComposer_CutscenePlayCurse(EnPoComposer* this, PlayState* play) { + if ((this->csCueTimer == 0) && Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->csCueTimer++; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_PLAYING_CURSE); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/func_80BC617C.s") +void EnPoComposer_SetupRoll(EnPoComposer* this) { + this->csCueTimer = 0; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_BEGIN_ROLLING); + this->actionFunc = EnPoComposer_Roll; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Po_Composer/EnPoComposer_Draw.s") +void EnPoComposer_Roll(EnPoComposer* this, PlayState* play) { + if (this->csCueTimer == 0) { + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + this->csCueTimer++; + Actor_PlaySfx(&this->actor, NA_SE_EN_SHARP_REACTION); + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, POE_COMPOSER_ANIM_ROLLING); + } + } else if (Animation_OnFrame(&this->skelAnime, 1.0f) && (this->lightColor.a > 32)) { + if (this->csCueTimer == 1) { + Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_DEAD_WIND2_OLD); + this->csCueTimer = 2; + } else { + Actor_PlaySfx(&this->actor, NA_SE_EN_LAST3_DEAD_WIND3_OLD); + this->csCueTimer = 1; + } + } +} + +void EnPoComposer_SharpCutsceneDone(EnPoComposer* this) { + SET_WEEKEVENTREG(WEEKEVENTREG_14_04); + Actor_Kill(&this->actor); +} + +s32 EnPoComposer_UpdateAction(EnPoComposer* this, PlayState* play) { + u16 cueType = POE_COMPOSER_IS_FLAT(&this->actor) ? CS_CMD_ACTOR_CUE_482 : CS_CMD_ACTOR_CUE_481; + s32 cueChannel; + + if (!this->inCutscene) { + return false; + } + + if (Cutscene_IsCueInChannel(play, cueType)) { + cueChannel = Cutscene_GetCueChannel(play, cueType); + + if (this->cueId != play->csCtx.actorCues[cueChannel]->id) { + this->cueId = play->csCtx.actorCues[cueChannel]->id; + + switch (play->csCtx.actorCues[cueChannel]->id) { + case POE_COMPOSER_CUEID_IDLE: // loop idle + EnPoComposer_SetupIdleStill(this); + break; + + case POE_COMPOSER_CUEID_APPEAR_SPIN: // appear/disappear -> loop idle + EnPoComposer_SetupAppear(this); + break; + + case POE_COMPOSER_CUEID_IDLE2: // loop sharp idle + EnPoComposer_SetupIdle(this); + break; + + case POE_COMPOSER_CUEID_RAISE_ARMS: // raise arms -> loop arms raised + EnPoComposer_SetupRaiseArms(this); + break; + + case POE_COMPOSER_CUEID_LOWER_ARMS: // lower arms -> loop idle + EnPoComposer_SetupLowerArms(this); + break; + + case POE_COMPOSER_CUEID_PLAY_CURSE: // begin playing -> loop playing + EnPoComposer_SetupCutscenePlayCurse(this); + break; + + case POE_COMPOSER_CUEID_ROLL: // begin rolling -> loop rolling + EnPoComposer_SetupRoll(this); + break; + + case POE_COMPOSER_CUEID_APPEAR: // appear + this->visible = true; + break; + + case POE_COMPOSER_CUEID_DISAPPEAR: // disappear + this->visible = false; + Actor_PlaySfx(&this->actor, NA_SE_EN_PO_DISAPPEAR); + break; + + case POE_COMPOSER_CUEID_DONE: + if (cueType == CS_CMD_ACTOR_CUE_481) { + EnPoComposer_SharpCutsceneDone(this); + } else { + Actor_Kill(&this->actor); + } + break; + + default: + break; + } + } + + if (this->actionFunc != EnPoComposer_Appear) { + Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel); + } else { + Cutscene_ActorTranslate(&this->actor, play, cueChannel); + } + + EnPoComposer_StepLightAlpha(this); + + if ((this->sharpCsNum == SHARP_CS_SONG_STORMS) && (play->csCtx.curFrame == 204)) { + Audio_PlaySfx(NA_SE_SY_DIZZY_EFFECT); + } + + if (this->visible == true) { + Actor_PlaySfx_Flagged(&this->actor, NA_SE_EN_SHARP_FLOAT - SFX_FLAG); + } + return true; + } + + if ((this->actionFunc != EnPoComposer_StartedCutscene) && (this->actionFunc != EnPoComposer_StartCutscene) && + (this->actionFunc != EnPoComposer_PlayCurse) && (play->csCtx.state == CS_STATE_IDLE)) { + + if (POE_COMPOSER_IS_FLAT(&this->actor)) { + EnPoComposer_SetupStartedCutscene(this); + } else if (POE_COMPOSER_4000(&this->actor)) { + EnPoComposer_SetupStartedCutscene(this); + } else { + this->inCutscene = false; + + if (this->sharpCsNum < SHARP_CS_SONG_STORMS) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_14_02)) { + SET_WEEKEVENTREG(WEEKEVENTREG_14_02); + } + EnPoComposer_SetupPlayCurse(this); + } else { + EnPoComposer_SetupStartedCutscene(this); + } + } + } + + this->cueId = POE_COMPOSER_CUEID_NONE; + return false; +} + +void EnPoComposer_StepLightAlpha(EnPoComposer* this) { + if ((this->visible == true) && (this->lightColor.a != 255)) { + if (this->lightColor.a > 247) { + this->lightColor.a = 255; + } else { + this->lightColor.a += 7; + } + } else if (!this->visible && (this->lightColor.a != 0)) { + if (this->lightColor.a < 8) { + this->lightColor.a = 0; + } else { + this->lightColor.a -= 7; + } + } +} + +void EnPoComposer_StepLightColor(EnPoComposer* this) { + s16 color; + + color = this->lightColor.r + 5; + this->lightColor.r = CLAMP_MAX(color, 255); + + color = this->lightColor.g + 5; + this->lightColor.g = CLAMP_MAX(color, 255); + + if (this->lightColor.b > 210) { + color = this->lightColor.b - 5; + this->lightColor.b = CLAMP_MIN(color, 210); + } else { + color = this->lightColor.b + 5; + this->lightColor.b = CLAMP_MAX(color, 210); + } +} + +void EnPoComposer_UpdateEnvColor(EnPoComposer* this) { + if ((this->actionFunc == EnPoComposer_Appear) && (this->skelAnime.curFrame < 12.0f)) { + // Step rgb from 55 to 255 and alpha from 0 to 200 over the first 12 frames of the appear anim + this->envColor.r = this->envColor.g = this->envColor.b = 55.0f + this->skelAnime.curFrame * 16.66f; + this->envColor.a = this->skelAnime.curFrame * (200.0f / 12.0f); + } else { + f32 rand = Rand_ZeroOne(); + + this->envColor.r = 225 + (s32)(rand * 30.0f); + this->envColor.g = 155 + (s32)(rand * 100.0f); + this->envColor.b = 95 + (s32)(rand * 160.0f); + this->envColor.a = 200; + } + if (this->lightColor.a == 0) { + this->envColor.a = 0; + } +} + +void EnPoComposer_UpdateCollision(EnPoComposer* this, PlayState* play) { + Collider_UpdateCylinder(&this->actor, &this->bodyCollider); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->bodyCollider.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->lanternCollider.base); +} + +void EnPoComposer_Update(Actor* thisx, PlayState* play) { + EnPoComposer* this = THIS; + + EnPoComposer_UpdateEnvColor(this); + SkelAnime_Update(&this->skelAnime); + Actor_SetFocus(&this->actor, 42.0f); + + this->actionFunc(this, play); + + if (!EnPoComposer_UpdateAction(this, play)) { + EnPoComposer_UpdateCollision(this, play); + } +} + +s32 EnPoComposer_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx, + Gfx** gfx) { + EnPoComposer* this = THIS; + + if ((this->lightColor.a == 0) || (limbIndex == POE_COMPOSER_LIMB_LANTERN)) { + *dList = NULL; + } else if (POE_COMPOSER_IS_FLAT(&this->actor) && (limbIndex == POE_COMPOSER_LIMB_HEAD)) { + *dList = gPoeComposerFlatHeadDL; + } + + if (limbIndex == 19) { + //! @bug skeleton does not have a limb 19, this is leftover from OoT Poes + gDPPipeSync((*gfx)++); + gDPSetEnvColor((*gfx)++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a); + } + + return false; +} + +void EnPoComposer_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, Gfx** gfx) { + EnPoComposer* this = THIS; + + Collider_UpdateSpheres(limbIndex, &this->lanternCollider); + if (limbIndex == POE_COMPOSER_LIMB_LANTERN) { + Matrix_Get(&this->lanternMtxF); + } +} + +void EnPoComposer_Draw(Actor* thisx, PlayState* play) { + EnPoComposer* this = THIS; + s32 pad; + Gfx* dl; + Color_RGBA8* clothingColor; + Color_RGBA8* var_t0; + Vec3f lightOffset; + Vec3s lightPos; + + OPEN_DISPS(play->state.gfxCtx); + + EnPoComposer_StepLightColor(this); + + // Select colors + + if (POE_COMPOSER_IS_FLAT(&this->actor)) { + clothingColor = &sFlatClothingColor1; + var_t0 = &sFlatClothingColor2; + } else { + clothingColor = &sSharpClothingColor1; + var_t0 = &sSharpClothingColor2; + } + + // Draw skeleton + + if ((this->lightColor.a == 255) || (this->lightColor.a == 0)) { + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0x08, + Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b, + this->lightColor.a)); + gSPSegment( + POLY_OPA_DISP++, 0x0A, + Gfx_EnvColor(play->state.gfxCtx, clothingColor->r, clothingColor->g, clothingColor->b, this->lightColor.a)); + gSPSegment(POLY_OPA_DISP++, 0x0B, + Gfx_EnvColor(play->state.gfxCtx, var_t0->r, var_t0->g, var_t0->b, this->lightColor.a)); + gSPSegment(POLY_OPA_DISP++, 0x0C, D_801AEFA0); + + POLY_OPA_DISP = + SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnPoComposer_OverrideLimbDraw, EnPoComposer_PostLimbDraw, &this->actor, POLY_OPA_DISP); + } else { + Gfx_SetupDL25_Opa(play->state.gfxCtx); + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b, + this->lightColor.a)); + gSPSegment( + POLY_XLU_DISP++, 0x0A, + Gfx_EnvColor(play->state.gfxCtx, clothingColor->r, clothingColor->g, clothingColor->b, this->lightColor.a)); + gSPSegment(POLY_XLU_DISP++, 0x0B, + Gfx_EnvColor(play->state.gfxCtx, var_t0->r, var_t0->g, var_t0->b, this->lightColor.a)); + gSPSegment(POLY_XLU_DISP++, 0x0C, D_801AEF88); + + POLY_XLU_DISP = + SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnPoComposer_OverrideLimbDraw, EnPoComposer_PostLimbDraw, &this->actor, POLY_XLU_DISP); + } + + if (this->lightColor.a != 0) { + // Draw lantern if visible + + if (this->lightColor.a == 255) { + Scene_SetRenderModeXlu(play, 0, 1); + dl = POLY_OPA_DISP; + } else { + Scene_SetRenderModeXlu(play, 1, 2); + dl = POLY_XLU_DISP; + } + + gDPPipeSync(&dl[0]); + gDPSetEnvColor(&dl[1], this->envColor.r, this->envColor.g, this->envColor.b, this->lightColor.a); + + Matrix_Put(&this->lanternMtxF); + gSPMatrix(&dl[2], Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPDisplayList(&dl[3], gPoeComposerLanternBaseDL); + gSPDisplayList(&dl[4], gPoeComposerLanternGlassDL); + + gDPPipeSync(&dl[5]); + gDPSetEnvColor(&dl[6], clothingColor->r, clothingColor->g, clothingColor->b, this->lightColor.a); + gSPDisplayList(&dl[7], gPoeComposerLanternTopDL); + + if (this->lightColor.a == 255) { + POLY_OPA_DISP = &dl[8]; + } else { + POLY_XLU_DISP = &dl[8]; + } + } + + Matrix_Put(&play->billboardMtxF); + Matrix_MultVecZ(15.0f, &lightOffset); + lightPos = this->lanternCollider.elements[0].dim.worldSphere.center; + lightPos.x += (s16)lightOffset.x; + lightPos.y += (s16)lightOffset.y; + lightPos.z += (s16)lightOffset.z; + + Lights_PointGlowSetInfo(&this->lightInfo, lightPos.x, lightPos.y, lightPos.z, this->envColor.r, this->envColor.g, + this->envColor.b, this->envColor.a * (200.0f / 255.0f)); + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.h b/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.h index a42b5048f..d64fc2430 100644 --- a/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.h +++ b/src/overlays/actors/ovl_En_Po_Composer/z_en_po_composer.h @@ -2,6 +2,32 @@ #define Z_EN_PO_COMPOSER_H #include "global.h" +#include "objects/object_po_composer/object_po_composer.h" + +#define POE_COMPOSER_IS_FLAT(actor) ((actor)->params & 0x8000) +#define POE_COMPOSER_4000(actor) ((actor)->params & 0x4000) + +typedef enum { + /* 1 */ POE_COMPOSER_CUEID_IDLE = 1, + /* 2 */ POE_COMPOSER_CUEID_APPEAR_SPIN, + /* 3 */ POE_COMPOSER_CUEID_IDLE2, + /* 4 */ POE_COMPOSER_CUEID_RAISE_ARMS, + /* 5 */ POE_COMPOSER_CUEID_LOWER_ARMS, + /* 6 */ POE_COMPOSER_CUEID_PLAY_CURSE, + /* 7 */ POE_COMPOSER_CUEID_ROLL, + /* 8 */ POE_COMPOSER_CUEID_APPEAR, + /* 9 */ POE_COMPOSER_CUEID_DISAPPEAR, + /* 10 */ POE_COMPOSER_CUEID_DONE, + /* 99 */ POE_COMPOSER_CUEID_NONE = 99 +} EnPoComposerCueId; + +typedef enum { + /* 0 */ SHARP_CS_ENCOUNTER_FIRST, + /* 1 */ SHARP_CS_ENCOUNTER_OTHER, + /* 2 */ SHARP_CS_SONG_HEALING, + /* 3 */ SHARP_CS_SONG_STORMS, + /* 4 */ SHARP_CS_MAX +} SharpCsIdIndex; struct EnPoComposer; @@ -9,9 +35,26 @@ typedef void (*EnPoComposerActionFunc)(struct EnPoComposer*, PlayState*); typedef struct EnPoComposer { /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0xF0]; + /* 0x144 */ ColliderCylinder bodyCollider; + /* 0x190 */ ColliderJntSph lanternCollider; + /* 0x1B0 */ ColliderJntSphElement lanternColliderElements[1]; + /* 0x1F0 */ SkelAnime skelAnime; /* 0x234 */ EnPoComposerActionFunc actionFunc; - /* 0x238 */ char unk_238[0x108]; + /* 0x238 */ MtxF lanternMtxF; + /* 0x278 */ LightNode* lightNode; + /* 0x27C */ LightInfo lightInfo; + /* 0x28A */ UNK_TYPE1 unk_28A[0x6]; + /* 0x290 */ s32 sharpCsNum; + /* 0x294 */ Vec3s jointTable[POE_COMPOSER_LIMB_MAX]; + /* 0x2DC */ Vec3s morphTable[POE_COMPOSER_LIMB_MAX]; + /* 0x324 */ s16 csIds[SHARP_CS_MAX]; + /* 0x32C */ s16 actionTimer; + /* 0x32E */ s16 csCueTimer; + /* 0x330 */ s16 inCutscene; + /* 0x332 */ s16 visible; + /* 0x334 */ u16 cueId; + /* 0x336 */ Color_RGBA8 lightColor; + /* 0x33A */ Color_RGBA8 envColor; } EnPoComposer; // size = 0x340 #endif // Z_EN_PO_COMPOSER_H diff --git a/src/overlays/actors/ovl_En_Tk/z_en_tk.c b/src/overlays/actors/ovl_En_Tk/z_en_tk.c index d6e7d4667..639a37db1 100644 --- a/src/overlays/actors/ovl_En_Tk/z_en_tk.c +++ b/src/overlays/actors/ovl_En_Tk/z_en_tk.c @@ -1297,8 +1297,8 @@ void EnTk_Update(Actor* thisx, PlayState* play) { if (platform != NULL) { if (platform->dyna.actor.id == ACTOR_BG_DANPEI_MOVEBG) { - platform->unk_1CC |= 1; - if (platform->unk_1CC & 2) { + platform->flags |= 1; + if (platform->flags & 2) { this->unk_2CA |= 1; } } diff --git a/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c b/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c index 258c57e32..b864df840 100644 --- a/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c +++ b/src/overlays/actors/ovl_Obj_Flowerpot/z_obj_flowerpot.c @@ -4,7 +4,6 @@ * Description: Breakable Pot With Grass */ -#include "prevent_bss_reordering.h" #include "z_obj_flowerpot.h" #include "objects/object_flowerpot/object_flowerpot.h" diff --git a/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.c b/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.c index 36537cfe3..f5c8e759a 100644 --- a/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.c +++ b/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.c @@ -1,154 +1,1234 @@ /* * File: z_obj_mine.c * Overlay: ovl_Obj_Mine - * Description: Spike metal Mine + * Description: Spike metal mine */ #include "z_obj_mine.h" +#include "overlays/actors/ovl_En_Bom/z_en_bom.h" +#include "objects/object_ny/object_ny.h" #define FLAGS 0x00000000 #define THIS ((ObjMine*)thisx) +#define LINK_SIZE 12.0f +#define ATTACH_OFFSET 10.0f +#define PATH_RADIUS 32.0f +#define AIR_RADIUS 20.0f +#define WATER_RADIUS 36.0f +#define BOMB_SPAWN_OFFSET 15.0f +#define WATER_KNOCKBACK 7.0f +#define AIR_KNOCKBACK 0.04f + void ObjMine_Init(Actor* thisx, PlayState* play); void ObjMine_Destroy(Actor* thisx, PlayState* play); -void ObjMine_Update(Actor* thisx, PlayState* play); -void ObjMine_Draw(Actor* thisx, PlayState* play); +void ObjMine_Path_Update(Actor* thisx, PlayState* play); +void ObjMine_Path_Draw(Actor* thisx, PlayState* play); + +void ObjMine_Path_SetupStationary(ObjMine* this); +void ObjMine_Path_Stationary(ObjMine* this, PlayState* play); +void ObjMine_Path_SetupMove(ObjMine* this); +void ObjMine_Path_Move(ObjMine* this, PlayState* play); +void ObjMine_Explode(ObjMine* this, PlayState* play); +void ObjMine_Air_SetupChained(ObjMine* this); +void ObjMine_Air_Chained(ObjMine* this, PlayState* play); +void ObjMine_Air_SetupStationary(ObjMine* this); +void ObjMine_Air_Stationary(ObjMine* this, PlayState* play); +void ObjMine_Water_SetupChained(ObjMine* this); +void ObjMine_Water_Chained(ObjMine* this, PlayState* play); +void ObjMine_Water_SetupStationary(ObjMine* this); +void ObjMine_Water_Stationary(ObjMine* this, PlayState* play); + +void ObjMine_AirWater_Update(Actor* thisx, PlayState* play); +void ObjMine_DrawExplosion(Actor* thisx, PlayState* play); +void ObjMine_Air_Draw(Actor* thisx, PlayState* play); +void ObjMine_Water_Draw(Actor* thisx, PlayState* play); -#if 0 ActorInit Obj_Mine_InitVars = { - /**/ ACTOR_OBJ_MINE, - /**/ ACTORCAT_PROP, - /**/ FLAGS, - /**/ OBJECT_NY, - /**/ sizeof(ObjMine), - /**/ ObjMine_Init, - /**/ ObjMine_Destroy, - /**/ ObjMine_Update, - /**/ ObjMine_Draw, + ACTOR_OBJ_MINE, + ACTORCAT_PROP, + FLAGS, + OBJECT_NY, + sizeof(ObjMine), + (ActorFunc)ObjMine_Init, + (ActorFunc)ObjMine_Destroy, + (ActorFunc)ObjMine_Path_Update, + (ActorFunc)ObjMine_Path_Draw, }; -// static ColliderJntSphElementInit sJntSphElementsInit[1] = { -static ColliderJntSphElementInit D_80A84570[1] = { +static ColliderJntSphElementInit sJntSphElementsInit[1] = { { - { ELEMTYPE_UNK2, { 0x00000000, 0x00, 0x00 }, { 0x01CBFFBE, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, + { + ELEMTYPE_UNK2, + { 0x00000000, 0x00, 0x00 }, + { 0x01CBFFBE, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 0, { { 0, 0, 0 }, 30 }, 100 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_80A84594 = { - { COLTYPE_METAL, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER | OC1_TYPE_1, OC2_TYPE_1, COLSHAPE_JNTSPH, }, - ARRAY_COUNT(sJntSphElementsInit), D_80A84570, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_METAL, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_PLAYER | OC1_TYPE_1, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + ARRAY_COUNT(sJntSphElementsInit), + sJntSphElementsInit, }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80A845E8[] = { +static f32 sPathSpeeds[] = { + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, +}; + +static ObjMineMtxF3 sStandardBasis = { + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, +}; + +static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneForward, 1300, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 150, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 100, ICHAIN_CONTINUE), ICHAIN_VEC3F_DIV1000(scale, 10, ICHAIN_STOP), }; -#endif +void ObjMine_Path_MoveToWaypoint(ObjMine* this, s32 index) { + Math_Vec3s_ToVec3f(&this->actor.world.pos, &this->waypoints[index]); +} -extern ColliderJntSphElementInit D_80A84570[1]; -extern ColliderJntSphInit D_80A84594; -extern InitChainEntry D_80A845E8[]; +s32 ObjMine_GetUnitVec3f(Vec3f* src, Vec3f* dst) { + f32 magnitude = Math3D_Vec3fMagnitude(src); -extern UNK_TYPE D_06000030; -extern UNK_TYPE D_06002068; + if (magnitude < 0.001f) { + return false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A811D0.s") + dst->x = src->x * (1.0f / magnitude); + dst->y = src->y * (1.0f / magnitude); + dst->z = src->z * (1.0f / magnitude); + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A8120C.s") +s32 ObjMine_GetUnitVec3fNorm(Vec3f* src, Vec3f* dst, f32* norm, f32* invNorm) { + f32 magnitude = Math3D_Vec3fMagnitude(src); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81288.s") + if (magnitude < 0.001f) { + return false; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A8131C.s") + dst->x = src->x * (1.0f / magnitude); + dst->y = src->y * (1.0f / magnitude); + dst->z = src->z * (1.0f / magnitude); + *norm = magnitude; + *invNorm = 1.0f / magnitude; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81384.s") + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A8140C.s") +void ObjMine_Path_SpawnBomb(ObjMine* this, PlayState* play) { + EnBom* bomb = (EnBom*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, this->actor.world.pos.x, + this->actor.world.pos.y - BOMB_SPAWN_OFFSET, this->actor.world.pos.z, 0, 0, 0, + BOMB_TYPE_BODY); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A8146C.s") + if (bomb != NULL) { + bomb->timer = 0; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81544.s") +void ObjMine_AirWater_SpawnBomb(ObjMine* this, PlayState* play) { + f32 x = this->collider.elements[0].dim.worldSphere.center.x; + f32 y = this->collider.elements[0].dim.worldSphere.center.y - BOMB_SPAWN_OFFSET; + f32 z = this->collider.elements[0].dim.worldSphere.center.z; + EnBom* bomb = (EnBom*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, x, y, z, 0, 0, 0, BOMB_TYPE_BODY); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81640.s") + if (bomb != NULL) { + bomb->timer = 0; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A8164C.s") +s32 ObjMine_AirWater_CheckOC(ObjMine* this) { + if (this->collider.base.ocFlags2 & OC2_HIT_PLAYER) { + return true; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81684.s") + if (this->collider.base.ocFlags1 & OC1_HIT) { + Actor* hitActor = this->collider.base.oc; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81714.s") + if ((hitActor->id == ACTOR_OBJ_MINE) && (hitActor->room == this->actor.room)) { + return true; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81818.s") + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81868.s") +void ObjMine_Air_CheckAC(ObjMine* this, s16* hitAngle, s16* torqueAngle) { + s32 pad[2]; + Vec3s* centerPos3s = &this->collider.elements[0].dim.worldSphere.center; + Vec3f centerPos; + s16 yawToAttack; + Actor* attackActor = this->collider.base.ac; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A819A4.s") + Math_Vec3s_ToVec3f(¢erPos, centerPos3s); + yawToAttack = Math_Vec3f_Yaw(&attackActor->world.pos, ¢erPos); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81A00.s") + // dmgFlag check is (DMG_DEKU_BUBBLE | DMG_FIRE_ARROW | DMG_ICE_ARROW | DMG_FIRE_ARROW | DMG_NORMAL_ARROW) + if (this->collider.elements[0].info.acHitInfo->toucher.dmgFlags & 0x13820) { + *hitAngle = attackActor->shape.rot.y; + *torqueAngle = attackActor->shape.rot.y - yawToAttack; + } else { + Vec3f hitPos; + Vec3s* hitPos3s = &this->collider.elements[0].info.bumper.hitPos; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81AA4.s") + Math_Vec3s_ToVec3f(&hitPos, hitPos3s); + *hitAngle = Actor_WorldYawTowardActor(attackActor, &this->actor); + *torqueAngle = Math_Vec3f_Yaw(&attackActor->world.pos, &hitPos) - yawToAttack; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81B14.s") +void ObjMine_Water_CheckAC(ObjMine* this, Vec3f* knockbackDir) { + Actor* attackActor = this->collider.base.ac; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81B7C.s") + // dmgFlag check is (DMG_DEKU_BUBBLE | DMG_LIGHT_ARROW | DMG_ICE_ARROW | DMG_FIRE_ARROW | DMG_NORMAL_ARROW) + if (this->collider.elements[0].info.acHitInfo->toucher.dmgFlags & 0x13820) { + Matrix_Push(); + Matrix_RotateYS(attackActor->shape.rot.y, MTXMODE_NEW); + Matrix_RotateXS(attackActor->shape.rot.x, MTXMODE_APPLY); + Matrix_MultVecZ(1.0f, knockbackDir); + Matrix_Pop(); + } else { + Vec3f posDiff; + Sphere16* sphere = &this->collider.elements[0].dim.worldSphere; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81D70.s") + posDiff.x = sphere->center.x - attackActor->world.pos.x; + posDiff.y = sphere->center.y - attackActor->world.pos.y; + posDiff.z = sphere->center.z - attackActor->world.pos.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81DEC.s") + if (!ObjMine_GetUnitVec3f(&posDiff, knockbackDir)) { + Math_Vec3f_Copy(knockbackDir, &sStandardBasis.y); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81E7C.s") +void ObjMine_AirWater_Noop(ObjMine* this) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A81FFC.s") +void ObjMine_ReplaceTranslation(Vec3f* translation) { + MtxF* matrix = Matrix_GetCurrent(); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A828A8.s") + matrix->xw = translation->x; + matrix->yw = translation->y; + matrix->zw = translation->z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A82C28.s") +void ObjMine_SetRotation(ObjMineMtxF3* basis) { + MtxF* matrix = Matrix_GetCurrent(); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/ObjMine_Init.s") + matrix->xx = basis->x.x; + matrix->yx = basis->x.y; + matrix->zx = basis->x.z; + matrix->wx = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/ObjMine_Destroy.s") + matrix->xy = basis->y.x; + matrix->yy = basis->y.y; + matrix->zy = basis->y.z; + matrix->wy = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A82F84.s") + matrix->xz = basis->z.x; + matrix->yz = basis->z.y; + matrix->zz = basis->z.z; + matrix->wz = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A82F98.s") + matrix->xw = 0.0f; + matrix->yw = 0.0f; + matrix->zw = 0.0f; + matrix->ww = 1.0f; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A82FA8.s") +s32 ObjMine_StepUntilParallel(Vec3f* value, Vec3f* target, f32 angleStep) { + Vec3f perpVec; + Vec3f prevValue; + Vec3f perpNormal; + f32 cosAngle = Math3D_Cos(value, target); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A82FC8.s") + if (Math_CosF(angleStep) <= cosAngle) { + Math_Vec3f_Copy(value, target); + return true; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83214.s") + Matrix_Push(); + Math_Vec3f_Copy(&prevValue, value); + Math3D_Vec3f_Cross(value, target, &perpVec); + if (ObjMine_GetUnitVec3f(&perpVec, &perpNormal)) { + Matrix_RotateAxisS(RAD_TO_BINANG(angleStep), &perpNormal, MTXMODE_NEW); + Matrix_MultVec3f(&prevValue, value); + } else { + Matrix_RotateXFNew(angleStep); + Matrix_MultVec3f(&prevValue, value); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83258.s") + Matrix_Pop(); + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A832BC.s") +void ObjMine_UpdateCollider(ObjMine* this) { + this->collider.elements[0].dim.worldSphere.center.x = this->actor.world.pos.x; + this->collider.elements[0].dim.worldSphere.center.y = this->actor.world.pos.y; + this->collider.elements[0].dim.worldSphere.center.z = this->actor.world.pos.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A832D0.s") +void ObjMine_Air_InitChain(ObjMine* this, s32 linkCount) { + f32 linkCountF = (f32)linkCount; + ObjMineAirChain* airChain = &this->chain.air; + ObjMineAirLink* airLink; + s32 i; + f32 wallCheckRadius = this->actor.home.rot.z * 5.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83A74.s") + airChain->basis.x.x = 1.0f; + airChain->basis.y.y = 1.0f; + airChain->basis.z.z = 1.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83A88.s") + airChain->translation.y = 1.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83B14.s") + // Sets restoring force and drag. Longer chains have lower frequency and less drag. + if (linkCount > 0) { + airChain->restore = -sqrtf((0.124992f / OBJMINE_CHAIN_MAX) / linkCountF); // constant is close to 1/8 + airChain->drag = 0.95f + ((0.02000004f / OBJMINE_CHAIN_MAX) * linkCountF); // constant is close to 1/50 + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83B28.s") + airChain->swayMax = 0.0002f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83CEC.s") + // Consecutive chain links are offset 90 degrees. + for (i = 0, airLink = airChain->links; i < linkCount; i++, airLink++) { + airLink->twist = 0x4000; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83D00.s") + if (wallCheckRadius < 0.0f) { + airChain->wallCheckDistSq = -1.0f; // Negative value means skip wall collision checks + } else if (wallCheckRadius <= AIR_RADIUS + 1.0f) { + airChain->wallCheckDistSq = 0.0f; + } else { + airChain->wallCheckDistSq = SQ(wallCheckRadius - AIR_RADIUS); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/ObjMine_Update.s") +void ObjMine_Air_InitCollider(ObjMine* this, s32 linkCount) { + Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Collider_UpdateSpheres(0, &this->collider); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83E7C.s") +void ObjMine_Air_SetBasis(ObjMine* this) { + ObjMineAirChain* airChain = &this->chain.air; + Vec3f tempVec; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/ObjMine_Draw.s") + tempVec.x = -airChain->displacement.x; + tempVec.y = 1.0f; + tempVec.z = -airChain->displacement.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A83FBC.s") + ObjMine_GetUnitVec3f(&tempVec, &airChain->basis.y); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A84088.s") + Math3D_Vec3f_Cross(&sStandardBasis.x, &airChain->basis.y, &tempVec); + ObjMine_GetUnitVec3f(&tempVec, &airChain->basis.z); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mine/func_80A84338.s") + Math3D_Vec3f_Cross(&airChain->basis.y, &airChain->basis.z, &tempVec); + ObjMine_GetUnitVec3f(&tempVec, &airChain->basis.x); +} + +void ObjMine_Air_SetWorld(ObjMine* this) { + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + f32 chainLength = ATTACH_OFFSET + (linkCount * LINK_SIZE); + + this->actor.world.pos.x = (this->chain.air.basis.y.x * -chainLength) + this->actor.home.pos.x; + this->actor.world.pos.y = (this->chain.air.basis.y.y * -chainLength) + this->actor.home.pos.y; + this->actor.world.pos.z = (this->chain.air.basis.y.z * -chainLength) + this->actor.home.pos.z; +} + +void ObjMine_Air_SetChainXZ(ObjMine* this) { + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + f32 invLength = 1.0f / (ATTACH_OFFSET + (linkCount * LINK_SIZE)); + f32 dx = this->actor.world.pos.x - this->actor.home.pos.x; + f32 dz = this->actor.world.pos.z - this->actor.home.pos.z; + + this->chain.air.displacement.x = dx * invLength; + this->chain.air.displacement.z = dz * invLength; +} + +void ObjMine_Water_InitChain(ObjMine* this, s32 linkCount) { + ObjMineWaterChain* waterChain = &this->chain.water; + ObjMineWaterLink* waterLink; + s32 i; + f32 wallCheckRadius = this->actor.home.rot.z * 5.0f; + f32 linkY; + f32 swayVel; + + waterChain->drag = 0.9f; + waterChain->swayMax = 0.003f; + + waterChain->swayPhaseVel = Rand_Next() >> (0x20 - 13); + waterChain->restoreXZ = -0.0002f; + waterChain->restoreY = -0.0002f; + + swayVel = waterChain->swayMax * (LINK_SIZE / 2.0f); + linkY = this->actor.home.pos.y; + + for (i = 0, waterLink = waterChain->links; i < linkCount; i++, waterLink++) { + linkY += LINK_SIZE; + waterLink->basis.x.x = 1.0f; + waterLink->basis.y.y = 1.0f; + waterLink->basis.z.z = 1.0f; + waterLink->pos.x = this->actor.home.pos.x; + waterLink->pos.y = linkY; + waterLink->pos.z = this->actor.home.pos.z; + waterLink->velocity.x = (Rand_ZeroOne() - 0.5f) * swayVel; + waterLink->velocity.y = (Rand_ZeroOne() - 0.5f) * swayVel; + waterLink->velocity.z = (Rand_ZeroOne() - 0.5f) * swayVel; + } + waterChain->maxY = linkY; + + // Rest position is slightly below max chain length to give slack. + waterChain->restY = waterChain->maxY * 0.97f; + linkY -= LINK_SIZE * 1.5f; + if (waterChain->restY < linkY) { // This should only happen if linkCount > 50 + waterChain->restY = linkY; + } + + if (wallCheckRadius < 0.0f) { + waterChain->wallCheckDistSq = -1.0f; // Negative value means skip wall collision checks + } else if (wallCheckRadius <= WATER_RADIUS + 1.0f) { + waterChain->wallCheckDistSq = 0.0f; + } else { + waterChain->wallCheckDistSq = SQ(wallCheckRadius - WATER_RADIUS); + } +} + +void ObjMine_Water_InitCollider(ObjMine* this, s32 linkCount) { + Matrix_Translate(this->actor.home.pos.x, this->actor.home.pos.y + (linkCount * LINK_SIZE) + ATTACH_OFFSET, + this->actor.home.pos.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Collider_UpdateSpheres(0, &this->collider); +} + +void ObjMine_Water_SetWorld(ObjMine* this) { + s32 pad; // Could be recast to thisx as in ObjMine_Path_Move + ObjMineWaterChain* waterChain = &this->chain.water; + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + + if (linkCount == 0) { + this->actor.world.pos.y = this->actor.home.pos.y + LINK_SIZE + ATTACH_OFFSET; + } else { + ObjMineWaterLink* lastLink = &waterChain->links[linkCount - 1]; + Vec3f mineOffset; + + Math_Vec3f_ScaleAndStore(&lastLink->basis.y, ATTACH_OFFSET, &mineOffset); + Math_Vec3f_Sum(&lastLink->pos, &mineOffset, &this->actor.world.pos); + } +} + +void ObjMine_Water_WallCheck(ObjMine* this, PlayState* play) { + s32 pad; // Could be recast to thisx as in ObjMine_Path_Move + ObjMineWaterChain* waterChain = &this->chain.water; + + waterChain->touchWall = false; + if (waterChain->wallCheckDistSq > -1e-6f) { + // Checks for walls if mine is sufficiently far from home. If found, sets ejection force towards home. + if (waterChain->wallCheckDistSq <= Math3D_Dist2DSq(this->actor.home.pos.x, this->actor.home.pos.z, + this->actor.world.pos.x, this->actor.world.pos.z)) { + Vec3f centerPos; + Vec3f offsetPos; + Vec3f result; // not used + Vec3f xzFromHome; + Vec3f xzDirFromHome; + CollisionPoly* poly; // not used + s32 bgId; // not used + f32 norm; // not used + f32 invNorm; // not used + + xzFromHome.x = this->actor.world.pos.x - this->actor.home.pos.x; + xzFromHome.y = 0.0f; + xzFromHome.z = this->actor.world.pos.z - this->actor.home.pos.z; + + if (ObjMine_GetUnitVec3fNorm(&xzFromHome, &xzDirFromHome, &norm, &invNorm)) { + + offsetPos.x = this->actor.world.pos.x + (xzDirFromHome.x * WATER_RADIUS); + offsetPos.y = this->actor.world.pos.y; + offsetPos.z = this->actor.world.pos.z + (xzDirFromHome.z * WATER_RADIUS); + + centerPos.x = this->actor.home.pos.x; + centerPos.y = this->actor.world.pos.y; + centerPos.z = this->actor.home.pos.z; + + if (BgCheck_EntityLineTest1(&play->colCtx, ¢erPos, &offsetPos, &result, &poly, true, false, false, + true, &bgId)) { + waterChain->touchWall = true; + waterChain->wallEject.x = xzDirFromHome.x * -0.2f; + waterChain->wallEject.z = xzDirFromHome.z * -0.2f; + } + } + } + } +} + +Vec3f sLastLinkAccel[OBJMINE_CHAIN_MAX + 1]; + +void ObjMine_Water_ApplyForces(ObjMine* this) { + ObjMineWaterChain* waterChain = &this->chain.water; + ObjMineWaterLink* waterLink; + s32 i; + s16 swayPhase = 0; + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + f32 inverseCount = 1.0f / linkCount; + f32 restoreY = (waterChain->links[linkCount - 1].pos.y - waterChain->restY) * waterChain->restoreY; + Vec3f tension; + f32 scaledKnockback; + s32 index; + s32 pad; + Vec3f* lastLinkAccel; + + // Applies the buoyant force and sway from the water. + for (i = 0, waterLink = waterChain->links, lastLinkAccel = sLastLinkAccel; i < linkCount; + i++, waterLink++, swayPhase += waterChain->swayPhaseVel, lastLinkAccel++) { + Math_Vec3f_Copy(lastLinkAccel, &waterLink->accel); + + if (waterLink->pos.y <= this->actor.home.pos.y) { + waterLink->accel.y = waterChain->restoreY * -96.0f; + } else if (restoreY > 0.0f) { + waterLink->accel.y = (i + 1) * inverseCount * (restoreY / 0.3f); + } else { + waterLink->accel.y = restoreY; + } + + waterLink->accel.x = (waterLink->pos.x - this->actor.home.pos.x) * waterChain->restoreXZ; + waterLink->accel.z = (waterLink->pos.z - this->actor.home.pos.z) * waterChain->restoreXZ; + waterLink->accel.x += waterChain->swayXZ * Math_SinS(swayPhase); + waterLink->accel.y += waterChain->swayY; + waterLink->accel.z += waterChain->swayXZ * Math_CosS(swayPhase); + } + + // Applies knockback force. Knockback on the links is scaled quadratically, possibly to account for link rotations + // being cumulative + if (waterChain->knockback > 0.0001f) { + for (i = 0, waterLink = waterChain->links; i < linkCount; i++, waterLink++) { + scaledKnockback = SQ((linkCount - i) * inverseCount); + + waterLink->accel.x += waterChain->knockbackDir.x * scaledKnockback; + waterLink->accel.y += waterChain->knockbackDir.y * scaledKnockback; + waterLink->accel.z += waterChain->knockbackDir.z * scaledKnockback; + } + } + + // Moves chain away from wall if mine is intersecting one + if (waterChain->touchWall) { + for (i = 0, waterLink = waterChain->links; i < linkCount; i++, waterLink++) { + waterLink->accel.x += waterChain->wallEject.x; + waterLink->accel.z += waterChain->wallEject.z; + } + } + + // Forces on the links from other links. This is simulated by a triangle filter on the forces from the previous + // frame. + for (i = 0, waterLink = waterChain->links; i < linkCount; i++, waterLink++) { + Math_Vec3f_Copy(&tension, &gZeroVec3f); + + if (i >= 2) { + tension.x += sLastLinkAccel[i - 2].x * 0.075f; + tension.y += sLastLinkAccel[i - 2].y * 0.075f; + tension.z += sLastLinkAccel[i - 2].z * 0.075f; + } + + if (i >= 1) { + tension.x += sLastLinkAccel[i - 1].x * 0.15f; + tension.y += sLastLinkAccel[i - 1].y * 0.15f; + tension.z += sLastLinkAccel[i - 1].z * 0.15f; + } + + tension.x += sLastLinkAccel[i].x * 0.3f; + tension.y += sLastLinkAccel[i].y * 0.3f; + tension.z += sLastLinkAccel[i].z * 0.3f; + + index = i + 1; + if (index < linkCount) { + tension.x += sLastLinkAccel[index].x * 0.15f; + tension.y += sLastLinkAccel[index].y * 0.15f; + tension.z += sLastLinkAccel[index].z * 0.15f; + } + + index = i + 2; + if (index < linkCount) { + tension.x += sLastLinkAccel[index].x * 0.075f; + tension.y += sLastLinkAccel[index].y * 0.075f; + tension.z += sLastLinkAccel[index].z * 0.075f; + } + waterLink->accel.x += tension.x; + waterLink->accel.y += tension.y; + waterLink->accel.z += tension.z; + } +} + +void ObjMine_Water_UpdateLinks(ObjMine* this) { + s32 pad; // Could be recast to thisx as in ObjMine_Path_Move + ObjMineMtxF3 newBasis; + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + ObjMineWaterChain* waterChain = &this->chain.water; + ObjMineWaterLink* waterLink; + s32 i; + Vec3f* prevBasisX; + Vec3f tempVec; + Vec3f diffDir; + Vec3f unusedLinkPos; + Vec3f jointPos; + s32 changeBasis; + f32 diffNorm; + f32 invNorm; // not used + Vec3f* tempBasisX; + + // The joint between the current link and next link is half the link's length from its center. The first link is + // assumed to be vertical and centered on home. + jointPos.x = this->actor.home.pos.x; + jointPos.y = this->actor.home.pos.y + (LINK_SIZE / 2.0f); + jointPos.z = this->actor.home.pos.z; + + for (i = 0, prevBasisX = NULL, waterLink = waterChain->links; i < linkCount; + i++, prevBasisX = &waterLink->basis.x, waterLink++) { + changeBasis = false; + + waterLink->velocity.x += waterLink->accel.x; + waterLink->velocity.y += waterLink->accel.y; + waterLink->velocity.z += waterLink->accel.z; + + Math_Vec3f_Scale(&waterLink->velocity, waterChain->drag); + Math_Vec3f_Copy(&unusedLinkPos, &waterLink->pos); + + waterLink->pos.x += waterLink->velocity.x; + waterLink->pos.y += waterLink->velocity.y; + waterLink->pos.z += waterLink->velocity.z; + + // Heavily reduce velocity if link is below home and moving downward. + if ((waterLink->pos.y <= this->actor.home.pos.y) && (waterLink->velocity.y < 0.0f)) { + waterLink->velocity.y *= 0.1f; + } + + // If the calculated position is less than 1/3 of the link's length from the joint, the chain is considered + // slack and the link keeps the same basis. Otherwise the basis is updated with the new position relative to the + // joint. The StepUntilParallel causes the chain to straighten over time. + Math_Vec3f_Diff(&waterLink->pos, &jointPos, &tempVec); + + if (ObjMine_GetUnitVec3fNorm(&tempVec, &diffDir, &diffNorm, &invNorm) && (diffNorm > LINK_SIZE / 3.0f)) { + Math_Vec3f_Copy(&newBasis.y, &waterLink->basis.y); + ObjMine_StepUntilParallel(&newBasis.y, &diffDir, M_PI / 30); + + tempBasisX = (prevBasisX == NULL) ? &sStandardBasis.x : prevBasisX; + + Math3D_Vec3f_Cross(tempBasisX, &newBasis.y, &tempVec); + + // Skips change of basis if any of the basis vectors would be zero. + if (ObjMine_GetUnitVec3f(&tempVec, &newBasis.z)) { + Math3D_Vec3f_Cross(&newBasis.y, &newBasis.z, &tempVec); + if (ObjMine_GetUnitVec3f(&tempVec, &newBasis.x)) { + changeBasis = true; + } + } + } + + if (changeBasis) { + Math_Vec3f_Copy(&waterLink->basis.x, &newBasis.x); + Math_Vec3f_Copy(&waterLink->basis.y, &newBasis.y); + Math_Vec3f_Copy(&waterLink->basis.z, &newBasis.z); + } else { + diffNorm = LINK_SIZE / 3.0f; + } + + // Sets new link position from calculated rotation basis. The check ensures displacement from the previous link + // doesn't cause the links to separate + if (diffNorm >= (LINK_SIZE / 2.0f)) { + waterLink->pos.x = jointPos.x + (waterLink->basis.y.x * (LINK_SIZE / 2.0f)); + waterLink->pos.y = jointPos.y + (waterLink->basis.y.y * (LINK_SIZE / 2.0f)); + waterLink->pos.z = jointPos.z + (waterLink->basis.y.z * (LINK_SIZE / 2.0f)); + } else { + waterLink->pos.x = jointPos.x + (waterLink->basis.y.x * diffNorm); + waterLink->pos.y = jointPos.y + (waterLink->basis.y.y * diffNorm); + waterLink->pos.z = jointPos.z + (waterLink->basis.y.z * diffNorm); + } + + // Calculate the position of the joint with the next link. + jointPos.x = waterLink->pos.x + (waterLink->basis.y.x * (LINK_SIZE / 2.0f)); + jointPos.y = waterLink->pos.y + (waterLink->basis.y.y * (LINK_SIZE / 2.0f)); + jointPos.z = waterLink->pos.z + (waterLink->basis.y.z * (LINK_SIZE / 2.0f)); + } +} + +void ObjMine_Water_UpdateChain(ObjMine* this, PlayState* play) { + ObjMine_Water_WallCheck(this, play); + ObjMine_Water_ApplyForces(this); + ObjMine_Water_UpdateLinks(this); +} + +void ObjMine_Init(Actor* thisx, PlayState* play) { + s32 pad; // Can be playstate recast. Must be gamestate recast. + ObjMine* this = THIS; + s32 pathIndex = OBJMINE_GET_PATH(&this->actor); + Path* path; + s32 bgId; // not used + s32 type = OBJMINE_GET_TYPE(&this->actor); + + Actor_ProcessInitChain(&this->actor, sInitChain); + + this->actor.shape.rot.z = 0; + this->actor.world.rot.z = 0; + + Collider_InitJntSph(play, &this->collider); + Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->colliderElements); + + if (type == OBJMINE_TYPE_PATH) { + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 45.0f); + this->actor.shape.shadowAlpha = 140; + this->pathSpeed = sPathSpeeds[OBJMINE_GET_PATH_SPEED(&this->actor)]; // sPathSpeeds[i] = i + 1.0f + if (pathIndex == 0xFF) { + ObjMine_Path_SetupStationary(this); + } else { + path = &play->setupPathList[pathIndex]; + + this->waypointIndex = 0; + this->waypointCount = path->count - 1; + this->waypoints = (Vec3s*)Lib_SegmentedToVirtual(path->points); + + ObjMine_Path_MoveToWaypoint(this, this->waypointIndex); + ObjMine_Path_SetupMove(this); + } + Matrix_SetTranslateRotateYXZ(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, + &this->actor.shape.rot); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Collider_UpdateSpheres(0, &this->collider); + this->actor.floorHeight = BgCheck_EntityRaycastFloor5(&play->colCtx, &this->actor.floorPoly, &bgId, + &this->actor, &this->actor.world.pos); + } else { + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + + this->actor.update = ObjMine_AirWater_Update; + this->actor.uncullZoneScale = 150.0f + (linkCount * (LINK_SIZE * 1.75f)); + this->actor.uncullZoneDownward = 150.0f + (linkCount * (LINK_SIZE * 1.75f)); + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 45.0f); + this->actor.shape.shadowAlpha = 140; + + if (type == OBJMINE_TYPE_AIR) { + this->actor.draw = ObjMine_Air_Draw; + ObjMine_Air_InitChain(this, linkCount); + this->actor.world.pos.y = -ATTACH_OFFSET - (linkCount * LINK_SIZE) + this->actor.home.pos.y; + ObjMine_Air_InitCollider(this, linkCount); + func_800B4AEC(play, &this->actor, 0.0f); + if (linkCount == 0) { + ObjMine_Air_SetupStationary(this); + } else { + ObjMine_Air_SetupChained(this); + } + } else { + this->actor.draw = ObjMine_Water_Draw; + ObjMine_Water_InitChain(this, linkCount); + this->actor.world.pos.y = ATTACH_OFFSET + (linkCount * LINK_SIZE) + this->actor.home.pos.y; + ObjMine_Water_InitCollider(this, linkCount); + if (linkCount == 0) { + ObjMine_Water_SetupStationary(this); + } else { + ObjMine_Water_SetupChained(this); + } + } + } +} + +void ObjMine_Destroy(Actor* thisx, PlayState* play) { + ObjMine* this = THIS; + // PlayState* play = play2; // must be in this order to match with recast + + Collider_DestroyJntSph(play, &this->collider); +} + +void ObjMine_Path_SetupStationary(ObjMine* this) { + this->actionFunc = ObjMine_Path_Stationary; +} + +void ObjMine_Path_Stationary(ObjMine* this, PlayState* play) { +} + +void ObjMine_Path_SetupMove(ObjMine* this) { + this->actor.flags |= ACTOR_FLAG_10; + this->actionFunc = ObjMine_Path_Move; +} + +void ObjMine_Path_Move(ObjMine* this, PlayState* play) { + Actor* thisx = &this->actor; // pos and velocity need this, though it can replace all `this->actor`s and match + Vec3f nextWaypoint; + f32 distToWaypoint; + f32 step; + f32 target; + s32 bgId; // not used + + // thisx->velocity is temporarily set to the vector difference to the next waypoint. + Math_Vec3s_ToVec3f(&nextWaypoint, &this->waypoints[this->waypointIndex + 1]); + Math_Vec3f_Diff(&nextWaypoint, &thisx->world.pos, &thisx->velocity); + distToWaypoint = Math3D_Vec3fMagnitude(&thisx->velocity); + + // Mine slows to 2.0f speed when 8 frames away from the next waypoint + if ((distToWaypoint < (this->pathSpeed * 8.0f)) && (this->pathSpeed > 2.0f)) { + target = 2.0f + ((this->pathSpeed - 2.0f) * 0.1f); + step = this->pathSpeed * 0.03f; + } else { + target = this->pathSpeed; + step = this->pathSpeed * 0.16f; + } + Math_StepToF(&this->actor.speed, target, step); + + // Checks if mine will reach the waypoint next frame + if ((this->actor.speed + 0.05f) < distToWaypoint) { + // Rescales thisx->velocity to be equal in magnitude to speed + Math_Vec3f_Scale(&thisx->velocity, this->actor.speed / distToWaypoint); + this->actor.world.pos.x += thisx->velocity.x; + this->actor.world.pos.y += thisx->velocity.y; + this->actor.world.pos.z += thisx->velocity.z; + } else { + this->actor.speed *= 0.4f; + this->waypointIndex++; + if (this->waypointIndex >= this->waypointCount) { + this->waypointIndex = 0; + } + ObjMine_Path_MoveToWaypoint(this, this->waypointIndex); + } + this->actor.floorHeight = + BgCheck_EntityRaycastFloor5(&play->colCtx, &this->actor.floorPoly, &bgId, &this->actor, &thisx->world.pos); + if (this->actor.flags & ACTOR_FLAG_40) { + Vec3f rotAxis; + Vec3f yhatCrossV; + MtxF rotMtxF; + + // Makes mines appear to roll while traversing the path + Math3D_Vec3f_Cross(&sStandardBasis.y, &thisx->velocity, &yhatCrossV); + if (ObjMine_GetUnitVec3f(&yhatCrossV, &rotAxis)) { + Matrix_RotateAxisF(this->actor.speed / PATH_RADIUS, &rotAxis, MTXMODE_NEW); + Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY); + Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY); + Matrix_Get(&rotMtxF); + Matrix_MtxFToYXZRot(&rotMtxF, &this->actor.shape.rot, false); + } + } +} + +void ObjMine_SetupExplode(ObjMine* this) { + this->actor.flags |= ACTOR_FLAG_10; + this->actor.draw = ObjMine_DrawExplosion; + this->actor.shape.shadowDraw = NULL; + this->actor.scale.x = 0.02f; + this->actor.scale.y = 0.02f; + this->actor.scale.z = 0.02f; + this->actionFunc = ObjMine_Explode; +} + +void ObjMine_Explode(ObjMine* this, PlayState* play) { + this->actor.scale.x *= 1.8f; + if (this->actor.scale.x > 0.02f * 1.5f * 5.832f) { // 5.832 = 1.8^3 + Actor_Kill(&this->actor); + } else { + this->actor.scale.y = this->actor.scale.x; + this->actor.scale.z = this->actor.scale.x; + } +} + +void ObjMine_Air_SetupChained(ObjMine* this) { + this->actionFunc = ObjMine_Air_Chained; +} + +void ObjMine_Air_Chained(ObjMine* this, PlayState* play) { + s32 pad; // Could be recast to thisx as in ObjMine_Path_Move + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + ObjMineAirChain* airChain = &this->chain.air; + ObjMineAirLink* airLink; + s32 i; + f32 xAccel; + f32 zAccel; + f32 spin; + s16 twistDiff; + + Math_Vec3f_Copy(&airChain->translation, &airChain->basis.y); + + // Explodes if collision with Player or another mine is detected. + if (ObjMine_AirWater_CheckOC(this)) { + ObjMine_AirWater_SpawnBomb(this, play); + ObjMine_AirWater_Noop(this); + ObjMine_SetupExplode(this); + return; + } + + // Calculates initial knockback and torque from hit scaled to chain length + if (this->collider.base.acFlags & AC_HIT) { + s16 torqueAngle; + f32 torque; + f32 torqueDiff; + + this->collider.base.acFlags &= ~AC_HIT; + airChain->knockback = AIR_KNOCKBACK; + ObjMine_Air_CheckAC(this, &airChain->knockbackAngle, &torqueAngle); + torque = Math_SinS(torqueAngle) * 0x96; + torqueDiff = -(torque / linkCount); + + for (i = 0, airLink = airChain->links; i < linkCount; i++, airLink++) { + airLink->spin += (s16)torque; + airLink->spin = CLAMP(airLink->spin, -0x320, 0x320); + torque -= torqueDiff; + } + } + + // Applies knockback force. Knockback applies over two frames, with the second at half strength + if (airChain->knockback > 0.0001f) { + xAccel = Math_SinS(airChain->knockbackAngle) * airChain->knockback; + zAccel = Math_CosS(airChain->knockbackAngle) * airChain->knockback; + airChain->velocity.x += xAccel; + airChain->velocity.z += zAccel; + Math_StepToF(&airChain->knockback, 0.0f, AIR_KNOCKBACK * 0.5f); + } + + // Applies chain sway, choosing a new sway randomly about every 32 frames + if ((Rand_Next() >> (0x20 - 5)) == 0) { + airChain->swaySize = Rand_ZeroOne() * airChain->swayMax; + airChain->swayPhase = Rand_Next() >> (0x20 - 16); + } + xAccel = Math_SinS(airChain->swayPhase) * airChain->swaySize; + zAccel = Math_CosS(airChain->swayPhase) * airChain->swaySize; + airChain->velocity.x += xAccel; + airChain->velocity.z += zAccel; + + // Applies the restoring force of gravity and chain tension using small-angle approximation + airChain->velocity.x += airChain->displacement.x * airChain->restore; + airChain->velocity.z += airChain->displacement.z * airChain->restore; + + // Applies linear drag + airChain->velocity.x *= airChain->drag; + airChain->velocity.z *= airChain->drag; + + // Updates scaled position and does a safety clamp to 5.0f. + airChain->displacement.x += airChain->velocity.x; + airChain->displacement.z += airChain->velocity.z; + + airChain->displacement.x = CLAMP(airChain->displacement.x, -5.0f, 5.0f); + airChain->displacement.z = CLAMP(airChain->displacement.z, -5.0f, 5.0f); + + ObjMine_Air_SetBasis(this); + ObjMine_Air_SetWorld(this); + + // Checks for wall collisions if sufficiently far from home. If collision detected, bounce off the wall at half + // speed. If speed is close to zero when hitting wall, weakly eject it instead. + if (airChain->wallCheckDistSq > -1e-6f) { + if (airChain->wallCheckDistSq <= Math3D_Dist2DSq(this->actor.world.pos.x, this->actor.world.pos.z, + this->actor.home.pos.x, this->actor.home.pos.z)) { + + Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, AIR_RADIUS, 0.0f, 1); + + if ((this->actor.bgCheckFlags & BGCHECKFLAG_WALL) && (this->actor.wallPoly != NULL)) { + Vec3f xzDir; + Vec3f reflectedDir; + Vec3f wallNormal; + Vec3f xzVel; + f32 xzSpeed; + f32 invNorm; // not used + + xzVel.x = airChain->velocity.x; + xzVel.y = 0.0f; + xzVel.z = airChain->velocity.z; + + if (ObjMine_GetUnitVec3fNorm(&xzVel, &xzDir, &xzSpeed, &invNorm)) { + wallNormal.x = COLPOLY_GET_NORMAL(this->actor.wallPoly->normal.x); + wallNormal.y = COLPOLY_GET_NORMAL(this->actor.wallPoly->normal.y); + wallNormal.z = COLPOLY_GET_NORMAL(this->actor.wallPoly->normal.z); + + Math3D_Vec3fReflect(&xzDir, &wallNormal, &reflectedDir); + + xzSpeed /= 2.0f; + airChain->velocity.x = reflectedDir.x * xzSpeed; + airChain->velocity.z = reflectedDir.z * xzSpeed; + } else { + airChain->velocity.x *= -0.1f; + airChain->velocity.z *= -0.1f; + } + ObjMine_Air_SetChainXZ(this); + ObjMine_Air_SetBasis(this); + ObjMine_Air_SetWorld(this); + } + } + } + + // Applies three torques to individual chain links: + // - restoring torque towards the default twist of 0x4000 + // - random torque for variance + // - linear drag torque + for (i = 0, airLink = airChain->links; i < linkCount; i++, airLink++) { + twistDiff = airLink->twist - 0x4000; + spin = airLink->spin + (twistDiff * -0.05f) + (30.0f * Rand_ZeroOne() - 15.0f); + spin *= 0.995f; + airLink->spin = spin; + airLink->twist += airLink->spin; + } + + func_800B4AEC(play, &this->actor, 0.0f); + ObjMine_UpdateCollider(this); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); +} + +void ObjMine_Air_SetupStationary(ObjMine* this) { + this->actionFunc = ObjMine_Air_Stationary; +} + +void ObjMine_Air_Stationary(ObjMine* this, PlayState* play) { + // Explodes if collision with Player or another mine is detected. + if (ObjMine_AirWater_CheckOC(this)) { + ObjMine_AirWater_SpawnBomb(this, play); + ObjMine_AirWater_Noop(this); + ObjMine_SetupExplode(this); + return; + } + + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); +} + +void ObjMine_Water_SetupChained(ObjMine* this) { + this->actionFunc = ObjMine_Water_Chained; +} + +void ObjMine_Water_Chained(ObjMine* this, PlayState* play) { + ObjMineWaterChain* waterChain = &this->chain.water; + + // Explodes if collision with Player or another mine is detected. + if (ObjMine_AirWater_CheckOC(this)) { + ObjMine_AirWater_SpawnBomb(this, play); + ObjMine_AirWater_Noop(this); + ObjMine_SetupExplode(this); + return; + } + + // Calculates knockback from AC hits + if (this->collider.base.acFlags & AC_HIT) { + this->collider.base.acFlags &= ~AC_HIT; + ObjMine_Water_CheckAC(this, &waterChain->knockbackDir); + waterChain->knockback = WATER_KNOCKBACK; + Math_Vec3f_Scale(&waterChain->knockbackDir, WATER_KNOCKBACK); + } + + // Reduces knockback each frame. Effectively makes knockback 60% on the first frame and 20% on the second. + if (waterChain->knockback > 0.0001f) { + waterChain->knockback = Math_Vec3f_StepTo(&waterChain->knockbackDir, &gZeroVec3f, WATER_KNOCKBACK * 0.4f); + } + + waterChain->drag = 0.9f; + waterChain->restoreXZ = -0.0002f; + waterChain->restoreY = -0.0002f; + waterChain->swayMax = 0.003f; + + // Chooses a new sway randomly about every 32 frames. + if (Rand_Next() >> (0x20 - 5) == 0) { + s16 randAngle = Rand_Next() >> (0x20 - 16); + + waterChain->swayXZ = Math_SinS(randAngle) * 1.8f * waterChain->swayMax; + waterChain->swayY = Math_CosS(randAngle) * 0.2f * waterChain->swayMax; + waterChain->swayPhaseVel = Rand_Next() >> (0x20 - 13); + } + + ObjMine_Water_UpdateChain(this, play); + ObjMine_Water_SetWorld(this); + ObjMine_UpdateCollider(this); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); +} + +void ObjMine_Water_SetupStationary(ObjMine* this) { + this->actionFunc = ObjMine_Water_Stationary; +} + +void ObjMine_Water_Stationary(ObjMine* this, PlayState* play) { + // Explodes if collision with Player or another mine is detected. + if (ObjMine_AirWater_CheckOC(this)) { + ObjMine_AirWater_SpawnBomb(this, play); + ObjMine_AirWater_Noop(this); + ObjMine_SetupExplode(this); + return; + } + + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); +} + +void ObjMine_Path_Update(Actor* thisx, PlayState* play) { + s32 pad; // Can be playstate recast. + ObjMine* this = THIS; + + if ((this->collider.base.ocFlags2 & OC2_HIT_PLAYER) || (this->collider.base.acFlags & AC_HIT)) { + ObjMine_Path_SpawnBomb(this, play); + ObjMine_SetupExplode(this); + } + + this->actionFunc(this, play); + + if (this->actor.update != NULL) { + this->collider.base.ocFlags1 &= ~OC1_HIT; + this->collider.base.acFlags &= ~AC_HIT; + this->collider.base.ocFlags2 &= ~OC2_HIT_PLAYER; + if ((this->actor.flags & ACTOR_FLAG_40) && (this->actionFunc != ObjMine_Explode)) { + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); + } + } +} + +void ObjMine_AirWater_Update(Actor* thisx, PlayState* play) { + ObjMine* this = THIS; + + this->actionFunc(this, play); +} + +void ObjMine_Path_Draw(Actor* thisx, PlayState* play) { + s32 pad; // Can be playstate recast + ObjMine* this = THIS; + + OPEN_DISPS(play->state.gfxCtx); + + if (this->actionFunc == ObjMine_Path_Move) { + Collider_UpdateSpheres(0, &this->collider); + } + + func_800B8050(&this->actor, play, true); + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + gSPDisplayList(POLY_OPA_DISP++, object_ny_DL_002068); + gSPDisplayList(POLY_OPA_DISP++, object_ny_DL_002188); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void ObjMine_DrawExplosion(Actor* thisx, PlayState* play) { + s32 pad; // This could be thisx recast or playstate recast. Not enough room on stack for both. + + OPEN_DISPS(play->state.gfxCtx); + + func_800B8118(thisx, play, true); + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + gDPSetRenderMode(POLY_XLU_DISP++, G_RM_PASS, G_RM_AA_ZB_XLU_SURF2); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 75); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, object_ny_DL_002068); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void ObjMine_Air_Draw(Actor* thisx, PlayState* play) { + s32 pad; // Can be playstate recast + ObjMine* this = THIS; + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + ObjMineAirChain* airChain = &this->chain.air; + ObjMineAirLink* airLink; + s32 i; + Vec3f linkPos; + Vec3f linkOffset; + Gfx* gfx; + + func_800B8050(&this->actor, play, true); + + OPEN_DISPS(play->state.gfxCtx); + gfx = POLY_OPA_DISP; + + gSPDisplayList(gfx++, &gSetupDLs[SETUPDL_25]); + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gfx++, object_ny_DL_000030); + + ObjMine_SetRotation(&airChain->basis); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + if (linkCount != 0) { + // Sets pivot point to be half a chain link length below home + Math_Vec3f_ScaleAndStore(&airChain->basis.y, -(LINK_SIZE / 2.0f), &linkOffset); + linkPos.x = this->actor.home.pos.x - linkOffset.x; + linkPos.y = this->actor.home.pos.y - (LINK_SIZE / 2.0f) - linkOffset.y; + linkPos.z = this->actor.home.pos.z - linkOffset.z; + Math_Vec3f_ScaleAndStore(&airChain->basis.y, -LINK_SIZE, &linkOffset); + + for (i = 0, airLink = airChain->links; i < linkCount; i++, airLink++) { + Matrix_RotateYS(airLink->twist, MTXMODE_APPLY); + linkPos.x += linkOffset.x; + linkPos.y += linkOffset.y; + linkPos.z += linkOffset.z; + ObjMine_ReplaceTranslation(&linkPos); + + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gfx++, object_ny_DL_000030); + } + } + + Matrix_RotateXS(0x2000, MTXMODE_APPLY); + ObjMine_ReplaceTranslation(&this->actor.world.pos); + + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPPipeSync(gfx++); + gDPSetRenderMode(gfx++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2); + gDPSetEnvColor(gfx++, 0, 0, 0, 255); + gSPDisplayList(gfx++, object_ny_DL_002068); + gSPDisplayList(gfx++, object_ny_DL_002188); + + POLY_OPA_DISP = gfx; + + CLOSE_DISPS(play->state.gfxCtx); +} + +void ObjMine_Water_Draw(Actor* thisx, PlayState* play) { + s32 pad; // Can be playstate recast + ObjMine* this = THIS; + s32 linkCount = OBJMINE_GET_LINK_COUNT(&this->actor); + ObjMineWaterChain* waterChain = &this->chain.water; + ObjMineWaterLink* waterLink; + s32 i; + Gfx* gfx; + + func_800B8050(&this->actor, play, true); + + OPEN_DISPS(play->state.gfxCtx); + gfx = POLY_OPA_DISP; + + gSPDisplayList(gfx++, &gSetupDLs[SETUPDL_25]); + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gfx++, object_ny_DL_000030); + + for (i = 0, waterLink = waterChain->links; i < linkCount; i++, waterLink++) { + ObjMine_SetRotation(&waterLink->basis); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + // Consecutive chain links are offset 90 degrees. + if ((i % 2) == 0) { + Matrix_RotateYS(0x4000, MTXMODE_APPLY); + } + ObjMine_ReplaceTranslation(&waterLink->pos); + + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(gfx++, object_ny_DL_000030); + } + + Matrix_RotateXS(0x2000, MTXMODE_APPLY); + ObjMine_ReplaceTranslation(&this->actor.world.pos); + + gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPPipeSync(gfx++); + gDPSetRenderMode(gfx++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2); + gDPSetEnvColor(gfx++, 0, 0, 0, 255); + gSPDisplayList(gfx++, object_ny_DL_002068); + gSPDisplayList(gfx++, object_ny_DL_002188); + + POLY_OPA_DISP = gfx; + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.h b/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.h index 257a6ff3a..26b93be37 100644 --- a/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.h +++ b/src/overlays/actors/ovl_Obj_Mine/z_obj_mine.h @@ -7,11 +7,89 @@ struct ObjMine; typedef void (*ObjMineActionFunc)(struct ObjMine*, PlayState*); +#define OBJMINE_GET_LINK_COUNT(thisx) ((thisx)->params & 0x3F) +#define OBJMINE_GET_PATH(thisx) ((thisx)->params & 0xFF) +#define OBJMINE_GET_PATH_SPEED(thisx) (((thisx)->params >> 8) & 7) +#define OBJMINE_GET_TYPE(thisx) (((thisx)->params >> 12) & 3) + +#define OBJMINE_PARAM(type, linkCount, pathIndex, pathSpeed) (((type) << 0xC) | ((type == OBJMINE_TYPE_PATH) ? ((pathIndex) | ((pathSpeed) << 8)) : (linkCount))) +#define OBJMINE_PATH_PARAM(pathIndex, pathSpeed) OBJMINE_PARAM(OBJMINE_TYPE_PATH, 0, pathIndex, pathSpeed) +#define OBJMINE_AIR_PARAM(linkCount) OBJMINE_PARAM(OBJMINE_TYPE_AIR, linkCount, 0, 0) +#define OBJMINE_WATER_PARAM(linkCount) OBJMINE_PARAM(OBJMINE_TYPE_WATER, linkCount, 0, 0) + +#define OBJMINE_CHAIN_MAX 63 + +typedef enum { + /* 0 */ OBJMINE_TYPE_PATH, + /* 1 */ OBJMINE_TYPE_AIR, + /* 2 */ OBJMINE_TYPE_WATER +} ObjMineType; + +typedef struct { + /* 0x00 */ Vec3f x; + /* 0x0C */ Vec3f y; + /* 0x18 */ Vec3f z; +} ObjMineMtxF3; // size = 0x24 + +typedef struct { + /* 0x0 */ s16 twist; + /* 0x2 */ s16 spin; +} ObjMineAirLink; // size = 0x4 + +typedef struct { + /* 0x00 */ ObjMineMtxF3 basis; + /* 0x24 */ Vec3f translation; // unused + /* 0x30 */ Vec2f displacement; + /* 0x38 */ Vec2f velocity; + /* 0x40 */ f32 restore; + /* 0x44 */ f32 drag; + /* 0x48 */ f32 knockback; + /* 0x4C */ s16 knockbackAngle; + /* 0x50 */ f32 swaySize; + /* 0x54 */ s16 swayPhase; + /* 0x58 */ f32 swayMax; + /* 0x5C */ f32 wallCheckDistSq; + /* 0x60 */ ObjMineAirLink links[OBJMINE_CHAIN_MAX]; +} ObjMineAirChain; // size = 0x15C + +typedef struct { + /* 0x00 */ ObjMineMtxF3 basis; + /* 0x24 */ Vec3f pos; + /* 0x30 */ Vec3f velocity; + /* 0x3C */ Vec3f accel; +} ObjMineWaterLink; // size = 0x48 + +typedef struct { + /* 0x00 */ f32 drag; + /* 0x04 */ Vec3f knockbackDir; + /* 0x10 */ f32 knockback; + /* 0x14 */ f32 swayXZ; + /* 0x18 */ f32 swayY; + /* 0x1C */ f32 swayMax; + /* 0x20 */ s16 swayPhaseVel; + /* 0x24 */ f32 restoreXZ; + /* 0x28 */ f32 maxY; + /* 0x2C */ f32 restY; + /* 0x30 */ f32 restoreY; + /* 0x34 */ f32 wallCheckDistSq; + /* 0x38 */ Vec2f wallEject; + /* 0x40 */ s8 touchWall; + /* 0x44 */ ObjMineWaterLink links[OBJMINE_CHAIN_MAX]; +} ObjMineWaterChain; // size = 0x11FC + typedef struct ObjMine { /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x60]; + /* 0x0144 */ ColliderJntSph collider; + /* 0x0164 */ ColliderJntSphElement colliderElements[1]; /* 0x01A4 */ ObjMineActionFunc actionFunc; - /* 0x01A8 */ char unk_1A8[0x120C]; + /* 0x01A8 */ f32 pathSpeed; + /* 0x01AC */ s32 waypointCount; + /* 0x01B0 */ s32 waypointIndex; + /* 0x01B4 */ Vec3s* waypoints; + /* 0x01B8 */ union { + ObjMineAirChain air; + ObjMineWaterChain water; + } chain; } ObjMine; // size = 0x13B4 #endif // Z_OBJ_MINE_H diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 5e0e50ddd..b43da62e0 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -4014,7 +4014,7 @@ 0x801A4FD8:("func_801A4FD8",), 0x801A5080:("func_801A5080",), 0x801A50C0:("func_801A50C0",), - 0x801A5100:("func_801A5100",), + 0x801A5100:("AudioVoice_GetWord",), 0x801A510C:("func_801A510C",), 0x801A5118:("func_801A5118",), 0x801A51F0:("func_801A51F0",), @@ -11150,53 +11150,53 @@ 0x80A80508:("EnEgol_SpawnEffect",), 0x80A80750:("EnEgol_UpdateEffects",), 0x80A80904:("EnEgol_DrawEffects",), - 0x80A811D0:("func_80A811D0",), - 0x80A8120C:("func_80A8120C",), - 0x80A81288:("func_80A81288",), - 0x80A8131C:("func_80A8131C",), - 0x80A81384:("func_80A81384",), - 0x80A8140C:("func_80A8140C",), - 0x80A8146C:("func_80A8146C",), - 0x80A81544:("func_80A81544",), - 0x80A81640:("func_80A81640",), - 0x80A8164C:("func_80A8164C",), - 0x80A81684:("func_80A81684",), - 0x80A81714:("func_80A81714",), - 0x80A81818:("func_80A81818",), - 0x80A81868:("func_80A81868",), - 0x80A819A4:("func_80A819A4",), - 0x80A81A00:("func_80A81A00",), - 0x80A81AA4:("func_80A81AA4",), - 0x80A81B14:("func_80A81B14",), - 0x80A81B7C:("func_80A81B7C",), - 0x80A81D70:("func_80A81D70",), - 0x80A81DEC:("func_80A81DEC",), - 0x80A81E7C:("func_80A81E7C",), - 0x80A81FFC:("func_80A81FFC",), - 0x80A828A8:("func_80A828A8",), - 0x80A82C28:("func_80A82C28",), + 0x80A811D0:("ObjMine_Path_MoveToWaypoint",), + 0x80A8120C:("ObjMine_GetUnitVec3f",), + 0x80A81288:("ObjMine_GetUnitVec3fNorm",), + 0x80A8131C:("ObjMine_Path_SpawnBomb",), + 0x80A81384:("ObjMine_AirWater_SpawnBomb",), + 0x80A8140C:("ObjMine_AirWater_CheckOC",), + 0x80A8146C:("ObjMine_Air_CheckAC",), + 0x80A81544:("ObjMine_Water_CheckAC",), + 0x80A81640:("ObjMine_AirWater_Noop",), + 0x80A8164C:("ObjMine_ReplaceTranslation",), + 0x80A81684:("ObjMine_ReplaceRotation",), + 0x80A81714:("ObjMine_StepUntilParallel",), + 0x80A81818:("ObjMine_UpdateCollider",), + 0x80A81868:("ObjMine_Air_InitChain",), + 0x80A819A4:("ObjMine_Air_SetCollider",), + 0x80A81A00:("ObjMine_Air_SetBasis",), + 0x80A81AA4:("ObjMine_Air_SetWorld",), + 0x80A81B14:("ObjMine_Air_SetChainXZ",), + 0x80A81B7C:("ObjMine_Water_InitChain",), + 0x80A81D70:("ObjMine_Water_SetCollider",), + 0x80A81DEC:("ObjMine_Water_SetWorld",), + 0x80A81E7C:("ObjMine_Water_WallCheck",), + 0x80A81FFC:("ObjMine_Water_ApplyForces",), + 0x80A828A8:("ObjMine_Water_UpdateLinks",), + 0x80A82C28:("ObjMine_Water_UpdateChain",), 0x80A82C5C:("ObjMine_Init",), 0x80A82F58:("ObjMine_Destroy",), - 0x80A82F84:("func_80A82F84",), - 0x80A82F98:("func_80A82F98",), - 0x80A82FA8:("func_80A82FA8",), - 0x80A82FC8:("func_80A82FC8",), - 0x80A83214:("func_80A83214",), - 0x80A83258:("func_80A83258",), - 0x80A832BC:("func_80A832BC",), - 0x80A832D0:("func_80A832D0",), - 0x80A83A74:("func_80A83A74",), - 0x80A83A88:("func_80A83A88",), - 0x80A83B14:("func_80A83B14",), - 0x80A83B28:("func_80A83B28",), - 0x80A83CEC:("func_80A83CEC",), - 0x80A83D00:("func_80A83D00",), - 0x80A83D8C:("ObjMine_Update",), - 0x80A83E7C:("func_80A83E7C",), - 0x80A83EA0:("ObjMine_Draw",), - 0x80A83FBC:("func_80A83FBC",), - 0x80A84088:("func_80A84088",), - 0x80A84338:("func_80A84338",), + 0x80A82F84:("ObjMine_Path_SetupStationary",), + 0x80A82F98:("ObjMine_Path_Stationary",), + 0x80A82FA8:("ObjMine_Path_SetupMove",), + 0x80A82FC8:("ObjMine_Path_Move",), + 0x80A83214:("ObjMine_SetupExplode",), + 0x80A83258:("ObjMine_Explode",), + 0x80A832BC:("ObjMine_Air_SetupChained",), + 0x80A832D0:("ObjMine_Air_Chained",), + 0x80A83A74:("ObjMine_Air_SetupStationary",), + 0x80A83A88:("ObjMine_Air_Stationary",), + 0x80A83B14:("ObjMine_Water_SetupChained",), + 0x80A83B28:("ObjMine_Water_Chained",), + 0x80A83CEC:("ObjMine_Water_SetupStationary",), + 0x80A83D00:("ObjMine_Water_Stationary",), + 0x80A83D8C:("ObjMine_Path_Update",), + 0x80A83E7C:("ObjMine_AirWater_Update",), + 0x80A83EA0:("ObjMine_Path_Draw",), + 0x80A83FBC:("ObjMine_DrawExplosion",), + 0x80A84088:("ObjMine_Air_Draw",), + 0x80A84338:("ObjMine_Water_Draw",), 0x80A84CD0:("ObjPurify_SetSysMatrix",), 0x80A84CF8:("ObjPurify_IsPurified",), 0x80A84D68:("ObjPurify_Init",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index 85cfd284a..2c93781db 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -2287,7 +2287,7 @@ 0x801D8BE0:("D_801D8BE0","UNK_TYPE1","",0x1), 0x801D8E3C:("D_801D8E3C","UNK_TYPE1","",0x1), 0x801D8E40:("D_801D8E40","UNK_TYPE4","",0x4), - 0x801D8E44:("D_801D8E44","UNK_TYPE2","",0x2), + 0x801D8E44:("sTopScoreWordId","UNK_TYPE2","",0x2), 0x801D8E48:("D_801D8E48","UNK_TYPE1","",0x1), 0x801D8E50:("D_801D8E50","UNK_TYPE1","",0x1), 0x801D8F70:("D_801D8F70","UNK_TYPE1","",0x1), @@ -4173,7 +4173,7 @@ 0x801FD5C4:("D_801FD5C4","UNK_TYPE1","",0x1), 0x801FD5C8:("D_801FD5C8","UNK_TYPE1","",0x1), 0x801FD5E8:("D_801FD5E8","UNK_TYPE1","",0x1), - 0x801FD608:("D_801FD608","UNK_TYPE1","",0x1), + 0x801FD608:("sVoiceMaskPattern","UNK_TYPE1","",0x1), 0x801FD610:("D_801FD610","UNK_TYPE1","",0x1), 0x801FD710:("sSfxPlayerBank","UNK_TYPE1","",0x1), 0x801FD8C0:("sSfxItemBank","UNK_TYPE1","",0x1), @@ -12068,7 +12068,7 @@ 0x80A84698:("D_80A84698","f32","",0x4), 0x80A8469C:("D_80A8469C","f32","",0x4), 0x80A846A0:("D_80A846A0","f32","",0x4), - 0x80A849D0:("D_80A849D0","UNK_TYPE4","",0x4), + 0x80A849D0:("sLastLinkAccel","Vec3f[]","",0x4), 0x80A85460:("Obj_Purify_InitVars","UNK_TYPE1","",0x1), 0x80A85480:("ObjPurifyInfoList","UNK_TYPE1","",0x1), 0x80A854A0:("D_80A854A0","UNK_TYPE1","",0x1), diff --git a/tools/namefixer.py b/tools/namefixer.py index 4d8cf80fb..419a8424d 100755 --- a/tools/namefixer.py +++ b/tools/namefixer.py @@ -911,16 +911,13 @@ wordReplace = { "func_8010A000": "Map_GetDungeonOrBossAreaIndex", "func_8010A074": "Map_IsInDungeonOrBossArea", "func_8010A0F0": "Map_GetDungeonAreaIndex", - "func_8010A164": "Map_IsInDungeonArea", "Map_IsInDungeonArea": "Map_IsInDungeonScene", "func_8010A194": "Map_GetBossAreaIndex", - "func_8010A208": "Map_IsInBossArea", "Map_IsInBossArea": "Map_IsInBossScene", "func_8010A2DC": "Minimap_SavePlayerRoomInitInfo", "func_8010A33C": "Map_InitRoomData", "func_8010A410": "Map_Destroy", "func_8010A430": "Map_Init", - "func_8010A54C": "Minimap_Draw", "Minimap_Draw": "Map_DrawMinimap", "func_8010A580": "Map_Update", @@ -1271,7 +1268,7 @@ wordReplace = { "play->actorCtx.targetCtx.unk4C": "play->actorCtx.targetCtx.lockOnIndex", "play->actorCtx.targetCtx.unk50": "play->actorCtx.targetCtx.lockOnTriangleSets", "play->actorCtx.targetCtx.unk8C": "play->actorCtx.targetCtx.nextTarget", - "play->doorCtx.transitionActorList": "play->transitionActors.list" + "play->doorCtx.transitionActorList": "play->transitionActors.list", "play->nextEntranceIndex": "play->nextEntrance", "play->sceneNum": "play->sceneId", "play->pauseCtx.unk_1F0": "play->pauseCtx.bombersNotebookOpen", diff --git a/tools/sizes/code_functions.csv b/tools/sizes/code_functions.csv index 223268eb0..5622d0212 100644 --- a/tools/sizes/code_functions.csv +++ b/tools/sizes/code_functions.csv @@ -3531,7 +3531,7 @@ asm/non_matchings/code/voice_external/func_801A4EB8.s,func_801A4EB8,0x801A4EB8,0 asm/non_matchings/code/voice_external/func_801A4FD8.s,func_801A4FD8,0x801A4FD8,0x2A asm/non_matchings/code/voice_external/func_801A5080.s,func_801A5080,0x801A5080,0x10 asm/non_matchings/code/voice_external/func_801A50C0.s,func_801A50C0,0x801A50C0,0x10 -asm/non_matchings/code/voice_external/func_801A5100.s,func_801A5100,0x801A5100,0x3 +asm/non_matchings/code/voice_external/AudioVoice_GetWord.s,AudioVoice_GetWord,0x801A5100,0x3 asm/non_matchings/code/voice_external/func_801A510C.s,func_801A510C,0x801A510C,0x3 asm/non_matchings/code/voice_external/func_801A5118.s,func_801A5118,0x801A5118,0x36 asm/non_matchings/code/voice_internal/func_801A51F0.s,func_801A51F0,0x801A51F0,0xE diff --git a/tools/weekeventregconvert.py b/tools/weekeventregconvert.py index 0d721654e..6f8a2c1c2 100755 --- a/tools/weekeventregconvert.py +++ b/tools/weekeventregconvert.py @@ -700,7 +700,7 @@ weekEventReg = { (86 << 8) | 0x20: "WEEKEVENTREG_86_20", (86 << 8) | 0x40: "WEEKEVENTREG_86_40", (86 << 8) | 0x80: "WEEKEVENTREG_86_80", - (87 << 8) | 0x01: "WEEKEVENTREG_87_01", + (87 << 8) | 0x01: "WEEKEVENTREG_TALKING_TO_COW_WITH_VOICE", (87 << 8) | 0x02: "WEEKEVENTREG_COUPLES_MASK_CUTSCENE_STARTED", (87 << 8) | 0x04: "WEEKEVENTREG_87_04", (87 << 8) | 0x08: "WEEKEVENTREG_87_08",