From d87404ea696052b2942308674c1c5b3d6c62d047 Mon Sep 17 00:00:00 2001 From: "Matthew D. Steele" Date: Fri, 20 Dec 2024 07:38:21 -0500 Subject: [PATCH] Add some sounds and animations for mermaid music hut machines --- src/chr.asm | 5 +- src/machine.asm | 12 +++++ src/machines/trombone.inc | 2 +- src/rooms/mermaid_hut6.asm | 67 +++++++++++++++++++----- src/sounds/beep.asm | 96 +++++++++++++++++++++++++++++++--- src/tiles/machine_trombone.ahi | 20 ++++++- src/tiles/terrain_hut3.ahi | 36 ++++++------- tests/machine.asm | 11 ++++ 8 files changed, 209 insertions(+), 40 deletions(-) diff --git a/src/chr.asm b/src/chr.asm index a7495fdc..ca908345 100644 --- a/src/chr.asm +++ b/src/chr.asm @@ -1417,7 +1417,7 @@ _chr_begin: chr_inc "multiplexer", kTileIdObjMultiplexerFirst chr_inc "platform_water", kTileIdObjPlatformWaterFirst chr_inc "bad_jelly", kTileIdObjBadJellyFirst - chr_inc "machine_trombone", kTileIdObjMachineTromboneFirst + chr_res $02 chr_inc "upgrade_opaddsub", kTileIdObjUpgradeOpAddSubFirst chr_inc "machine_drums", kTileIdObjMachineDrumsFirst chr_inc "npc_duck", kTileIdObjNpcDuckFirst @@ -1426,7 +1426,8 @@ _chr_begin: chr_res $02 chr_inc "bad_grub", kTileIdObjBadGrubFirst chr_inc "bad_slime", kTileIdObjBadSlimeFirst - chr_res $09 + chr_inc "machine_trombone", kTileIdObjMachineTromboneFirst + chr_res $05 chr_inc "raindrop", kTileIdObjRaindrop chr_inc "bad_toad", kTileIdObjBadToadFirst chr_inc "bad_bird", kTileIdObjBadBirdFirst diff --git a/src/machine.asm b/src/machine.asm index 2e895924..fee67d8a 100644 --- a/src/machine.asm +++ b/src/machine.asm @@ -28,6 +28,7 @@ .IMPORT FuncA_Machine_PlaySfxEnd .IMPORT FuncA_Machine_PlaySfxError .IMPORT FuncA_Machine_PlaySfxSync +.IMPORT Func_IsFlagSet .IMPORT Sram_Programs_sProgram_arr .IMPORTZP Zp_Current_sRoom .IMPORTZP Zp_P1ButtonsHeld_bJoypad @@ -316,6 +317,17 @@ _ReadRegB: ;; Initialize any machine-specific state. ldy #sMachine::Init_func_ptr ; param: function pointer offset jsr Func_MachineCall + ;; If the machine's breaker hasn't been activated, halt the machine. + ldy #sMachine::Breaker_eFlag + lda (Zp_Current_sMachine_ptr), y + beq @doNotHalt ; No breaker flag, so the machine always has power. + tax ; param: flag + jsr Func_IsFlagSet ; returns Z + bne @doNotHalt ; The breaker is activated, so the machine has power. + ldx Zp_MachineIndex_u8 + lda #eMachine::Halted + sta Ram_MachineStatus_eMachine_arr, x + @doNotHalt: ;; Continue to the next machine. ldx Zp_MachineIndex_u8 inx diff --git a/src/machines/trombone.inc b/src/machines/trombone.inc index b7347307..29aa4ef0 100644 --- a/src/machines/trombone.inc +++ b/src/machines/trombone.inc @@ -29,6 +29,6 @@ kChrBankDiagramTrombone = $12 kTileIdBgDiagramTromboneFirst = $f0 ;;; OBJ tile IDs used for drawing trombone machines. -kTileIdObjMachineTromboneFirst = $8a +kTileIdObjMachineTromboneFirst = $ae ;;;=========================================================================;;; diff --git a/src/rooms/mermaid_hut6.asm b/src/rooms/mermaid_hut6.asm index e8cf9ddf..74695657 100644 --- a/src/rooms/mermaid_hut6.asm +++ b/src/rooms/mermaid_hut6.asm @@ -19,10 +19,12 @@ .INCLUDE "../actor.inc" .INCLUDE "../charmap.inc" +.INCLUDE "../cursor.inc" .INCLUDE "../device.inc" .INCLUDE "../flag.inc" .INCLUDE "../machine.inc" .INCLUDE "../machines/drums.inc" +.INCLUDE "../machines/shared.inc" .INCLUDE "../machines/trombone.inc" .INCLUDE "../macros.inc" .INCLUDE "../oam.inc" @@ -37,15 +39,19 @@ .IMPORT FuncA_Machine_GenericTryMoveX .IMPORT FuncA_Machine_GenericTryMoveY .IMPORT FuncA_Machine_GetGenericMoveSpeed -.IMPORT FuncA_Machine_PlaySfxBeep +.IMPORT FuncA_Machine_PlaySfxHiHat +.IMPORT FuncA_Machine_PlaySfxOrgan +.IMPORT FuncA_Machine_PlaySfxTrombone .IMPORT FuncA_Machine_ReachedGoal .IMPORT FuncA_Machine_StartWaiting .IMPORT FuncA_Objects_Draw1x1Shape +.IMPORT FuncA_Objects_Draw1x2Shape .IMPORT FuncA_Objects_Draw2x2MirroredShape .IMPORT FuncA_Objects_DrawPumpMachine .IMPORT FuncA_Objects_MoveShapeDownByA .IMPORT FuncA_Objects_MoveShapeLeftOneTile .IMPORT FuncA_Objects_MoveShapeRightByA +.IMPORT FuncA_Objects_MoveShapeUpByA .IMPORT FuncA_Objects_SetShapePosToMachineTopLeft .IMPORT FuncA_Objects_SetShapePosToPlatformTopLeft .IMPORT Func_MovePlatformLeftTowardPointX @@ -115,11 +121,13 @@ kTileIdObjMachineDrumsBass = kTileIdObjMachineDrumsFirst + 0 kTileIdObjMachineDrumsHiHat = kTileIdObjMachineDrumsFirst + 1 kTileIdObjMachineTromboneSlideMiddle = kTileIdObjMachineTromboneFirst + 0 kTileIdObjMachineTromboneSlideEnd = kTileIdObjMachineTromboneFirst + 1 +kTileIdObjMachineTromboneBellFirst = kTileIdObjMachineTromboneFirst + 2 ;;; The OBJ palette numbers used for drawing various parts of the machines in ;;; this room. kPaletteObjDrumsBass = 0 kPaletteObjDrumsHiHat = 0 +kPaletteObjTromboneBell = 0 kPaletteObjTromboneSlide = 0 ;;;=========================================================================;;; @@ -308,7 +316,18 @@ _Devices_sDevice_arr: ;;; @prereq PRGA_Objects is loaded. ;;; @prereq Zp_MachineIndex_u8 and Zp_Current_sMachine_ptr are initialized. .PROC FuncC_Mermaid_Hut6Trombone_Draw - ;; TODO: Animate horn when playing a note. +_TromboneBell: + lda Ram_MachineSlowdown_u8_arr + kTromboneMachineIndex + beq @done + jsr FuncA_Objects_SetShapePosToMachineTopLeft + lda #17 ; param: offset + jsr FuncA_Objects_MoveShapeRightByA + lda #2 ; param: offset + jsr FuncA_Objects_MoveShapeUpByA + lda #kTileIdObjMachineTromboneBellFirst ; param: tile ID + ldy #kPaletteObjTromboneBell ; param: object flags + jsr FuncA_Objects_Draw1x2Shape + @done: _TromboneSlide: ldx #kTromboneSlidePlatformIndex ; param: platform index jsr FuncA_Objects_SetShapePosToPlatformTopLeft @@ -361,7 +380,18 @@ _MachineLight: ;;; @prereq Zp_MachineIndex_u8 and Zp_Current_sMachine_ptr are initialized. .PROC FuncC_Mermaid_Hut6Organ_Draw _Indicator: - ;; TODO: if machine is not halted, draw indicator light for selected pipe + lda Ram_MachineStatus_eMachine_arr + kOrganMachineIndex + cmp #eMachine::Halted + beq @done + jsr FuncA_Objects_SetShapePosToMachineTopLeft + lda Ram_MachineGoalHorz_u8_arr + kOrganMachineIndex ; tone + mul #4 + ora #1 ; param: offset + jsr FuncA_Objects_MoveShapeRightByA + lda #kTileIdObjCursorDimLeft ; param: tile ID + ldy #kPaletteObjMachineLight | bObj::FlipH | bObj::Pri ; param: obj flags + jsr FuncA_Objects_Draw1x1Shape + @done: _MachineLight: jmp FuncA_Objects_DrawPumpMachine .ENDPROC @@ -399,8 +429,10 @@ _MachineLight: .PROC FuncA_Machine_MermaidHut6Trombone_TryAct lda Ram_MachineGoalHorz_u8_arr + kTromboneMachineIndex ; param: tone - jsr FuncA_Machine_PlaySfxBeep ; TODO: different sound for trombone - lda #$10 ; param: num frames + jsr FuncA_Machine_PlaySfxTrombone + lda #$0b + sta Ram_MachineSlowdown_u8_arr + kTromboneMachineIndex + lda #$10 jmp FuncA_Machine_StartWaiting .ENDPROC @@ -444,21 +476,31 @@ _MachineLight: .ENDPROC .PROC FuncA_Machine_MermaidHut6Drums_Tick - ldx #kDrumsHiHatMaxPlatformTop - kDrumsHiHatStep - lda #1 + ;; Pick the goal position to move the hi-hat towards, and the speed at + ;; which to move it (either up slowly, or down quickly). + ldx #kDrumsHiHatMaxPlatformTop - kDrumsHiHatStep ; upper position + lda #1 ; param: move speed (slow) ldy Ram_MachineGoalVert_u8_arr + kDrumsMachineIndex bne @move - ldx #kDrumsHiHatMaxPlatformTop - mul #2 + ldx #kDrumsHiHatMaxPlatformTop ; lower position + mul #2 ; param: move speed (fast) @move: + ;; Move the hi-hat platform towards its goal position. stx Zp_PointY_i16 + 0 ldx #0 stx Zp_PointY_i16 + 1 ldx #kDrumsHiHatPlatformIndex ; param: platform index jsr Func_MovePlatformTopTowardPointY ; returns Z - ;; TODO: when reached Y=0, play hi-hat sound - jeq FuncA_Machine_ReachedGoal + beq @reachedGoal rts + ;; When the hi-hat reaches its goal position, if that goal position is Y=0, + ;; play a hi-hat sound. + @reachedGoal: + lda Ram_MachineGoalVert_u8_arr + kDrumsMachineIndex + bne @noHiHatSound + jsr FuncA_Machine_PlaySfxHiHat + @noHiHatSound: + jmp FuncA_Machine_ReachedGoal .ENDPROC .PROC FuncA_Machine_MermaidHut6Organ_WriteReg @@ -468,7 +510,8 @@ _MachineLight: .PROC FuncA_Machine_MermaidHut6Organ_TryAct lda Ram_MachineGoalHorz_u8_arr + kOrganMachineIndex ; param: tone - jsr FuncA_Machine_PlaySfxBeep ; TODO: different sound for organ + jsr FuncA_Machine_PlaySfxOrgan + ;; TODO: Make a little puff of air over the organ pipe. lda #$10 ; param: num frames jmp FuncA_Machine_StartWaiting .ENDPROC diff --git a/src/sounds/beep.asm b/src/sounds/beep.asm index 07ebacf5..aebd578b 100644 --- a/src/sounds/beep.asm +++ b/src/sounds/beep.asm @@ -22,31 +22,86 @@ .INCLUDE "../macros.inc" .INCLUDE "../sound.inc" +.IMPORT Func_PlaySfxOnNoiseChannel +.IMPORT Func_PlaySfxOnPulse1Channel .IMPORT Func_PlaySfxOnPulse2Channel .IMPORT Ram_Audio_sChanSfx_arr .IMPORTZP Zp_Next_sChanSfx_arr ;;;=========================================================================;;; +;;; The envelope flags (not including the volume nibble) to use in +;;; Data_Trombone_sSfx. +.LINECONT + +kTromboneEnvFlags = \ + bEnvelope::Duty18 | bEnvelope::NoLength | bEnvelope::ConstVol +.LINECONT - + +;;;=========================================================================;;; + .SEGMENT "PRG8" ;;; SFX data for the "beep" sound effect. .PROC Data_Beep_sSfx sfx_SetEnvSweep bEnvelope::Duty12 | bEnvelope::NoLength | 3, kNoSweep - sfx_Func _InitializeTimer + sfx_Func Func_InitializeSfxBeepTimer sfx_Wait 15 sfx_End -_InitializeTimer: +.ENDPROC + +;;; SFX data for the "hi-hat" sound effect. +.PROC Data_HiHat_sSfx + ;; TODO: Improve the hi-hat sound. + sfx_SetEnvTimer bEnvelope::NoLength | 1, $0001 + sfx_Wait 3 + sfx_End +.ENDPROC + +;;; SFX data for the "organ" sound effect. +.PROC Data_Organ_sSfx + sfx_SetEnv $ff + sfx_Func Func_InitializeSfxBeepTimer + sfx_Wait 15 + sfx_End +.ENDPROC + +;;; SFX data for the "trombone" sound effect. +.PROC Data_Trombone_sSfx + sfx_SetEnvSweep kTromboneEnvFlags | 4, kNoSweep + sfx_Func Func_InitializeSfxBeepTimer + sfx_Wait 1 + sfx_SetEnv kTromboneEnvFlags | 8 + sfx_Wait 1 + sfx_SetEnv kTromboneEnvFlags | 12 + sfx_Wait 10 + sfx_SetEnv kTromboneEnvFlags | 8 + sfx_Wait 2 + sfx_SetEnv kTromboneEnvFlags | 4 + sfx_Wait 2 + sfx_End +.ENDPROC + +;;; Sets the APU timer registers for the specified channel, using the tone +;;; value (0-9) stored in sChanSfx::Param1_byte to select one of the notes from +;;; Data_SfxBeepTimer*_u8_arr10. +;;; @param X The channel number (0-4) times four (so, 0, 4, 8, 12, or 16). +;;; @preserve X, T0+ +.PROC Func_InitializeSfxBeepTimer ldy Ram_Audio_sChanSfx_arr + sChanSfx::Param1_byte, x ; tone - lda _TimerLo_u8_arr10, y + lda Data_SfxBeepTimerLo_u8_arr10, y sta Hw_Channels_sChanRegs_arr5 + sChanRegs::TimerLo_wo, x - lda _TimerHi_u8_arr10, y + lda Data_SfxBeepTimerHi_u8_arr10, y sta Hw_Channels_sChanRegs_arr5 + sChanRegs::TimerHi_wo, x sec ; set C to indicate that the function is finished rts +.ENDPROC + ;;; These values represent the ten natural notes from A3 through C5. -_TimerLo_u8_arr10: .byte $fb, $c4, $ab, $7c, $52, $3f, $1c, $fd, $e1, $d5 -_TimerHi_u8_arr10: .byte $01, $01, $01, $01, $01, $01, $01, $00, $00, $00 +.PROC Data_SfxBeepTimerLo_u8_arr10 + .byte $fb, $c4, $ab, $7c, $52, $3f, $1c, $fd, $e1, $d5 +.ENDPROC +.PROC Data_SfxBeepTimerHi_u8_arr10 + .byte $01, $01, $01, $01, $01, $01, $01, $00, $00, $00 .ENDPROC ;;;=========================================================================;;; @@ -63,4 +118,33 @@ _TimerHi_u8_arr10: .byte $01, $01, $01, $01, $01, $01, $01, $00, $00, $00 jmp Func_PlaySfxOnPulse2Channel ; preserves T0+ .ENDPROC +;;; Starts playing a sound for a drum machine's hi-hat. +;;; @preserve T0+ +.EXPORT FuncA_Machine_PlaySfxHiHat +.PROC FuncA_Machine_PlaySfxHiHat + ldya #Data_HiHat_sSfx + jmp Func_PlaySfxOnNoiseChannel ; preserves T0+ +.ENDPROC + +;;; Starts playing a sound for an organ machine's ACT opcode. +;;; @param A The tone number (0-9). +;;; @preserve T0+ +.EXPORT FuncA_Machine_PlaySfxOrgan +.PROC FuncA_Machine_PlaySfxOrgan + sta Zp_Next_sChanSfx_arr + eChan::Triangle + sChanSfx::Param1_byte ; tone + ldya #Data_Organ_sSfx + stya Zp_Next_sChanSfx_arr + eChan::Triangle + sChanSfx::NextOp_sSfx_ptr + rts +.ENDPROC + +;;; Starts playing a sound for a trombone machine's ACT opcode. +;;; @param A The tone number (0-9). +;;; @preserve T0+ +.EXPORT FuncA_Machine_PlaySfxTrombone +.PROC FuncA_Machine_PlaySfxTrombone + sta Zp_Next_sChanSfx_arr + eChan::Pulse1 + sChanSfx::Param1_byte ; tone + ldya #Data_Trombone_sSfx + jmp Func_PlaySfxOnPulse1Channel ; preserves T0+ +.ENDPROC + ;;;=========================================================================;;; diff --git a/src/tiles/machine_trombone.ahi b/src/tiles/machine_trombone.ahi index bb9c3b4a..d406448b 100644 --- a/src/tiles/machine_trombone.ahi +++ b/src/tiles/machine_trombone.ahi @@ -1,4 +1,4 @@ -ahi1 f0 p1 i2 w8 h8 +ahi1 f0 p1 i4 w8 h8 0008;0;54;ECEEEC;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0 @@ -19,3 +19,21 @@ ahi1 f0 p1 i2 w8 h8 22222210 22222220 12121200 + +00000012 +00000012 +00000122 +00012222 +02222222 +22222222 +22222222 +12112222 + +02221122 +00012212 +00000121 +00000012 +00000012 +00000000 +00000000 +00000000 diff --git a/src/tiles/terrain_hut3.ahi b/src/tiles/terrain_hut3.ahi index 52534f1e..00a89d0c 100644 --- a/src/tiles/terrain_hut3.ahi +++ b/src/tiles/terrain_hut3.ahi @@ -5,11 +5,11 @@ ahi1 f0 p1 i16 w8 h8 20200000 22100000 22202020 -22102210 -22202220 -22102210 -22202220 -22102210 +22112211 +22212221 +22112211 +22212221 +22112211 00000000 00000000 @@ -18,22 +18,22 @@ ahi1 f0 p1 i16 w8 h8 20200000 22100000 22202020 -22102210 +22112211 -22202220 -22102210 -22202220 -22102210 -22202220 -22102210 -22202220 -22102210 +22212221 +22112211 +22212221 +22112211 +22212221 +22112211 +22212221 +22112211 22222222 11111111 22222222 -21222122 -21222122 +20222022 +20222022 22222222 11111111 22222222 @@ -50,8 +50,8 @@ ahi1 f0 p1 i16 w8 h8 22222222 11111112 22222212 -21222122 -21222122 +20222022 +20222022 22222212 11111112 22222220 diff --git a/tests/machine.asm b/tests/machine.asm index b3dd3ec6..70a1e4ae 100644 --- a/tests/machine.asm +++ b/tests/machine.asm @@ -187,6 +187,17 @@ _Draw: ;;;=========================================================================;;; +.SEGMENT "PRG8" + +;;; Stub implementation. +.EXPORT Func_IsFlagSet +.PROC Func_IsFlagSet + lda #0 ; Set Z to indicate that the flag is cleared. + rts +.ENDPROC + +;;;=========================================================================;;; + .SEGMENT "MAIN" sei cld