mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Make the ocarina work with the dpad (#311)
This commit is contained in:
		
							parent
							
								
									b6b3bca731
								
							
						
					
					
						commit
						8319d97ad1
					
				
					 1 changed files with 230 additions and 0 deletions
				
			
		
							
								
								
									
										230
									
								
								patches/input.c
									
										
									
									
									
								
							
							
						
						
									
										230
									
								
								patches/input.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
// Decomp rename, TODO update decomp and remove this
 | 
			
		||||
#define AudioVoice_GetWord func_801A5100
 | 
			
		||||
#include "z64voice.h"
 | 
			
		||||
#include "audiothread_cmd.h"
 | 
			
		||||
 | 
			
		||||
s32 func_80847190(PlayState* play, Player* this, s32 arg2);
 | 
			
		||||
s16 func_80832754(Player* this, s32 arg1);
 | 
			
		||||
| 
						 | 
				
			
			@ -2297,3 +2298,232 @@ void draw_dpad_icons(PlayState* play) {
 | 
			
		|||
 | 
			
		||||
    CLOSE_DISPS(play->state.gfxCtx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    /* 0x0 */ s8 x;
 | 
			
		||||
    /* 0x1 */ s8 y;
 | 
			
		||||
} OcarinaControlStick; // size = 0x2
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    /* 0x0 */ SFX_CHANNEL_PLAYER0, // SfxPlayerBank
 | 
			
		||||
    /* 0x1 */ SFX_CHANNEL_PLAYER1,
 | 
			
		||||
    /* 0x2 */ SFX_CHANNEL_PLAYER2,
 | 
			
		||||
    /* 0x3 */ SFX_CHANNEL_ITEM0, // SfxItemBank
 | 
			
		||||
    /* 0x4 */ SFX_CHANNEL_ITEM1,
 | 
			
		||||
    /* 0x5 */ SFX_CHANNEL_ENV0, // SfxEnvironmentBank
 | 
			
		||||
    /* 0x6 */ SFX_CHANNEL_ENV1,
 | 
			
		||||
    /* 0x7 */ SFX_CHANNEL_ENV2,
 | 
			
		||||
    /* 0x8 */ SFX_CHANNEL_ENEMY0, // SfxEnemyBank
 | 
			
		||||
    /* 0x9 */ SFX_CHANNEL_ENEMY1,
 | 
			
		||||
    /* 0xA */ SFX_CHANNEL_ENEMY2,
 | 
			
		||||
    /* 0xB */ SFX_CHANNEL_SYSTEM0, // SfxSystemBank
 | 
			
		||||
    /* 0xC */ SFX_CHANNEL_SYSTEM1,
 | 
			
		||||
    /* 0xD */ SFX_CHANNEL_OCARINA, // SfxOcarinaBank
 | 
			
		||||
    /* 0xE */ SFX_CHANNEL_VOICE0,  // SfxVoiceBank
 | 
			
		||||
    /* 0xF */ SFX_CHANNEL_VOICE1
 | 
			
		||||
} SfxChannelIndex; // seqPlayerIndex = 2
 | 
			
		||||
 | 
			
		||||
extern u32 sOcarinaFlags;
 | 
			
		||||
extern u8 sOcarinaDropInputTimer;
 | 
			
		||||
extern u32 sOcarinaInputButtonStart;
 | 
			
		||||
extern u32 sOcarinaInputButtonCur;
 | 
			
		||||
extern u8 sCurOcarinaPitch;
 | 
			
		||||
extern u8 sCurOcarinaButtonIndex;
 | 
			
		||||
extern u32 sOcarinaInputButtonPrev;
 | 
			
		||||
extern s32 sOcarinaInputButtonPress; 
 | 
			
		||||
extern u8 sRecordingState;
 | 
			
		||||
extern s8 sCurOcarinaBendIndex;
 | 
			
		||||
extern f32 sCurOcarinaBendFreq;
 | 
			
		||||
extern s8 sCurOcarinaVibrato;
 | 
			
		||||
extern OcarinaControlStick sOcarinaInputStickRel;
 | 
			
		||||
extern u8 sPrevOcarinaPitch;
 | 
			
		||||
extern f32 sDefaultOcarinaVolume;
 | 
			
		||||
extern s8 sOcarinaInstrumentId;
 | 
			
		||||
extern f32 AudioOcarina_BendPitchTwoSemitones(s8 bendIndex);
 | 
			
		||||
 | 
			
		||||
// @recomp Patch the function in order to read DPad inputs for the ocarina as well as CButton inputs. 
 | 
			
		||||
void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) {
 | 
			
		||||
    u32 ocarinaBtnsHeld;
 | 
			
		||||
 | 
			
		||||
    // Prevents two different ocarina notes from being played on two consecutive frames
 | 
			
		||||
    if ((sOcarinaFlags != 0) && (sOcarinaDropInputTimer != 0)) {
 | 
			
		||||
        sOcarinaDropInputTimer--;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Ensures the button pressed to start the ocarina does not also play an ocarina note
 | 
			
		||||
    // @recomp Check for DPad inputs as well.
 | 
			
		||||
    if ((sOcarinaInputButtonStart == 0) ||
 | 
			
		||||
        ((sOcarinaInputButtonStart & (BTN_A | BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)) !=
 | 
			
		||||
         (sOcarinaInputButtonCur & (BTN_A | BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)))) {
 | 
			
		||||
        sOcarinaInputButtonStart = 0;
 | 
			
		||||
        if (1) {}
 | 
			
		||||
        sCurOcarinaPitch = OCARINA_PITCH_NONE;
 | 
			
		||||
        sCurOcarinaButtonIndex = OCARINA_BTN_INVALID;
 | 
			
		||||
        // @recomp Check for DPad inputs as well.
 | 
			
		||||
        ocarinaBtnsHeld = (sOcarinaInputButtonCur & (BTN_A | BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)) &
 | 
			
		||||
                          (sOcarinaInputButtonPrev & (BTN_A | BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP));
 | 
			
		||||
 | 
			
		||||
        if (!(sOcarinaInputButtonPress & ocarinaBtnsHeld) && (sOcarinaInputButtonCur != 0)) {
 | 
			
		||||
            sOcarinaInputButtonPress = sOcarinaInputButtonCur;
 | 
			
		||||
        } else {
 | 
			
		||||
            sOcarinaInputButtonPress &= ocarinaBtnsHeld;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Interprets and transforms controller input into ocarina buttons and notes
 | 
			
		||||
        if (CHECK_BTN_ANY(sOcarinaInputButtonPress, BTN_A)) {
 | 
			
		||||
            sCurOcarinaPitch = OCARINA_PITCH_D4;
 | 
			
		||||
            sCurOcarinaButtonIndex = OCARINA_BTN_A;
 | 
			
		||||
 | 
			
		||||
        // @recomp Check for DPad down input as well.
 | 
			
		||||
        } else if (CHECK_BTN_ANY(sOcarinaInputButtonPress, (BTN_CDOWN | BTN_DDOWN))) {
 | 
			
		||||
            sCurOcarinaPitch = OCARINA_PITCH_F4;
 | 
			
		||||
            sCurOcarinaButtonIndex = OCARINA_BTN_C_DOWN;
 | 
			
		||||
 | 
			
		||||
        // @recomp Check for DPad right input as well.
 | 
			
		||||
        } else if (CHECK_BTN_ANY(sOcarinaInputButtonPress, BTN_CRIGHT | BTN_DRIGHT)) {
 | 
			
		||||
            sCurOcarinaPitch = OCARINA_PITCH_A4;
 | 
			
		||||
            sCurOcarinaButtonIndex = OCARINA_BTN_C_RIGHT;
 | 
			
		||||
            
 | 
			
		||||
        // @recomp Check for DPad left input as well.
 | 
			
		||||
        } else if (CHECK_BTN_ANY(sOcarinaInputButtonPress, BTN_CLEFT | BTN_DLEFT)) {
 | 
			
		||||
            sCurOcarinaPitch = OCARINA_PITCH_B4;
 | 
			
		||||
            sCurOcarinaButtonIndex = OCARINA_BTN_C_LEFT;
 | 
			
		||||
 | 
			
		||||
        // @recomp Check for DPad up input as well.
 | 
			
		||||
        } else if (CHECK_BTN_ANY(sOcarinaInputButtonPress, BTN_CUP | BTN_DUP)) {
 | 
			
		||||
            sCurOcarinaPitch = OCARINA_PITCH_D5;
 | 
			
		||||
            sCurOcarinaButtonIndex = OCARINA_BTN_C_UP;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (sOcarinaInputButtonCur) {}
 | 
			
		||||
 | 
			
		||||
        // Pressing the R Button will raise the pitch by 1 semitone
 | 
			
		||||
        if ((sCurOcarinaPitch != OCARINA_PITCH_NONE) && CHECK_BTN_ANY(sOcarinaInputButtonCur, BTN_R) &&
 | 
			
		||||
            (sRecordingState != OCARINA_RECORD_SCARECROW_SPAWN)) {
 | 
			
		||||
            sCurOcarinaButtonIndex += OCARINA_BUTTON_FLAG_BFLAT_RAISE; // Flag to resolve B Flat 4
 | 
			
		||||
            sCurOcarinaPitch++;                                        // Raise the pitch by 1 semitone
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Pressing the Z Button will lower the pitch by 1 semitone
 | 
			
		||||
        if ((sCurOcarinaPitch != OCARINA_PITCH_NONE) && CHECK_BTN_ANY(sOcarinaInputButtonCur, BTN_Z) &&
 | 
			
		||||
            (sRecordingState != OCARINA_RECORD_SCARECROW_SPAWN)) {
 | 
			
		||||
            sCurOcarinaButtonIndex += OCARINA_BUTTON_FLAG_BFLAT_LOWER; // Flag to resolve B Flat 4
 | 
			
		||||
            sCurOcarinaPitch--;                                        // Lower the pitch by 1 semitone
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (sRecordingState != OCARINA_RECORD_SCARECROW_SPAWN) {
 | 
			
		||||
            // Bend the pitch of the note based on y control stick
 | 
			
		||||
            sCurOcarinaBendIndex = sOcarinaInputStickRel.y;
 | 
			
		||||
            sCurOcarinaBendFreq = AudioOcarina_BendPitchTwoSemitones(sCurOcarinaBendIndex);
 | 
			
		||||
 | 
			
		||||
            // Add vibrato of the ocarina note based on the x control stick
 | 
			
		||||
            sCurOcarinaVibrato = ABS_ALT(sOcarinaInputStickRel.x) >> 2;
 | 
			
		||||
            // Sets vibrato to io port 6
 | 
			
		||||
            AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 6, sCurOcarinaVibrato);
 | 
			
		||||
        } else {
 | 
			
		||||
            // no bending or vibrato for recording state OCARINA_RECORD_SCARECROW_SPAWN
 | 
			
		||||
            sCurOcarinaBendIndex = 0;
 | 
			
		||||
            sCurOcarinaVibrato = 0;
 | 
			
		||||
            sCurOcarinaBendFreq = 1.0f; // No bend
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Processes new and valid notes
 | 
			
		||||
        if ((sCurOcarinaPitch != OCARINA_PITCH_NONE) && (sPrevOcarinaPitch != sCurOcarinaPitch)) {
 | 
			
		||||
            // Sets ocarina instrument Id to io port 7, which is used
 | 
			
		||||
            // as an index in seq 0 to get the true instrument Id
 | 
			
		||||
            AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 7, sOcarinaInstrumentId - 1);
 | 
			
		||||
            // Sets pitch to io port 5
 | 
			
		||||
            AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 5, sCurOcarinaPitch);
 | 
			
		||||
            AudioSfx_PlaySfx(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sCurOcarinaBendFreq, &sDefaultOcarinaVolume,
 | 
			
		||||
                             &gSfxDefaultReverb);
 | 
			
		||||
        } else if ((sPrevOcarinaPitch != OCARINA_PITCH_NONE) && (sCurOcarinaPitch == OCARINA_PITCH_NONE) &&
 | 
			
		||||
                   !isOcarinaSfxSuppressedWhenCancelled) {
 | 
			
		||||
            // Stops ocarina sound when transitioning from playing to not playing a note
 | 
			
		||||
            AudioSfx_StopById(NA_SE_OC_OCARINA);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern u8 sOcarinaHasStartedSong;
 | 
			
		||||
extern u8 sOcarinaStaffPlayingPos;
 | 
			
		||||
extern u8 sCurOcarinaSongWithoutMusicStaff[8];
 | 
			
		||||
extern u8 sOcarinaWithoutMusicStaffPos;
 | 
			
		||||
extern u8 sFirstOcarinaSongIndex;
 | 
			
		||||
extern u32 sOcarinaAvailableSongFlags;
 | 
			
		||||
extern u8 sLastOcarinaSongIndex;
 | 
			
		||||
extern u8 sButtonToPitchMap[5];
 | 
			
		||||
extern u8 sPlayedOcarinaSongIndexPlusOne;
 | 
			
		||||
extern u8 sIsOcarinaInputEnabled;
 | 
			
		||||
extern void AudioOcarina_CheckIfStartedSong(void);
 | 
			
		||||
extern void AudioOcarina_UpdateCurOcarinaSong(void);
 | 
			
		||||
 | 
			
		||||
// @recomp Patch the L button check (for free ocarina playing) to account for DPad ocarina.
 | 
			
		||||
void AudioOcarina_CheckSongsWithoutMusicStaff(void) {
 | 
			
		||||
    u32 pitch;
 | 
			
		||||
    u8 ocarinaStaffPlayingPosStart;
 | 
			
		||||
    u8 songIndex;
 | 
			
		||||
    u8 j;
 | 
			
		||||
    u8 k;
 | 
			
		||||
 | 
			
		||||
    // @recomp Add the DPad inputs to the check.
 | 
			
		||||
    if (CHECK_BTN_ANY(sOcarinaInputButtonCur, BTN_L) &&
 | 
			
		||||
        CHECK_BTN_ANY(sOcarinaInputButtonCur, BTN_A | BTN_CRIGHT | BTN_CLEFT | BTN_CDOWN | BTN_CUP | BTN_DRIGHT | BTN_DLEFT | BTN_DDOWN | BTN_DUP)) {
 | 
			
		||||
        AudioOcarina_StartDefault(sOcarinaFlags);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AudioOcarina_CheckIfStartedSong();
 | 
			
		||||
 | 
			
		||||
    if (!sOcarinaHasStartedSong) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ocarinaStaffPlayingPosStart = sOcarinaStaffPlayingPos;
 | 
			
		||||
    if ((sPrevOcarinaPitch != sCurOcarinaPitch) && (sCurOcarinaPitch != OCARINA_PITCH_NONE)) {
 | 
			
		||||
        sOcarinaStaffPlayingPos++;
 | 
			
		||||
        if (sOcarinaStaffPlayingPos > ARRAY_COUNT(sCurOcarinaSongWithoutMusicStaff)) {
 | 
			
		||||
            sOcarinaStaffPlayingPos = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AudioOcarina_UpdateCurOcarinaSong();
 | 
			
		||||
 | 
			
		||||
        if ((ABS_ALT(sCurOcarinaBendIndex) > 20) && (ocarinaStaffPlayingPosStart != sOcarinaStaffPlayingPos)) {
 | 
			
		||||
            sCurOcarinaSongWithoutMusicStaff[sOcarinaWithoutMusicStaffPos - 1] = OCARINA_PITCH_NONE;
 | 
			
		||||
        } else {
 | 
			
		||||
            sCurOcarinaSongWithoutMusicStaff[sOcarinaWithoutMusicStaffPos - 1] = sCurOcarinaPitch;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // This nested for-loop tests to see if the notes from the ocarina are identical
 | 
			
		||||
        // to any of the songIndex from sFirstOcarinaSongIndex to sLastOcarinaSongIndex
 | 
			
		||||
 | 
			
		||||
        // Loop through each of the songs
 | 
			
		||||
        for (songIndex = sFirstOcarinaSongIndex; songIndex < sLastOcarinaSongIndex; songIndex++) {
 | 
			
		||||
            // Checks to see if the song is available to be played
 | 
			
		||||
            if ((u32)sOcarinaAvailableSongFlags & (1 << songIndex)) {
 | 
			
		||||
                // Loops through all possible starting indices?
 | 
			
		||||
                // Loops through the notes of the song?
 | 
			
		||||
                for (j = 0, k = 0; (j < gOcarinaSongButtons[songIndex].numButtons) && (k == 0) &&
 | 
			
		||||
                                   (sOcarinaWithoutMusicStaffPos >= gOcarinaSongButtons[songIndex].numButtons);) {
 | 
			
		||||
 | 
			
		||||
                    pitch = sCurOcarinaSongWithoutMusicStaff[(sOcarinaWithoutMusicStaffPos -
 | 
			
		||||
                                                              gOcarinaSongButtons[songIndex].numButtons) +
 | 
			
		||||
                                                             j];
 | 
			
		||||
 | 
			
		||||
                    if (pitch == sButtonToPitchMap[gOcarinaSongButtons[songIndex].buttonIndex[j]]) {
 | 
			
		||||
                        j++;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        k++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // This conditional is true if songIndex = i is detected
 | 
			
		||||
                if (j == gOcarinaSongButtons[songIndex].numButtons) {
 | 
			
		||||
                    sPlayedOcarinaSongIndexPlusOne = songIndex + 1;
 | 
			
		||||
                    sIsOcarinaInputEnabled = false;
 | 
			
		||||
                    sOcarinaFlags = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue