60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { useStore } from '../store'
|
|
import { playKeyClick, playDelete, playComplete, playHint, playWordComplete } from '../sounds'
|
|
|
|
export function useSounds() {
|
|
const prevEntries = useRef<string[][] | null>(null)
|
|
const prevSolved = useRef(false)
|
|
const prevHints = useRef(0)
|
|
|
|
useEffect(() => {
|
|
const unsub = useStore.subscribe((state) => {
|
|
if (!state.puzzle) return
|
|
|
|
// letter entry or deletion
|
|
if (prevEntries.current && state.entries !== prevEntries.current) {
|
|
for (let r = 0; r < state.entries.length; r++) {
|
|
for (let c = 0; c < state.entries[r].length; c++) {
|
|
const cur = state.entries[r][c]
|
|
const old = prevEntries.current[r]?.[c] || ''
|
|
if (cur && !old) {
|
|
playKeyClick()
|
|
// word completion check
|
|
const span = state.wordSpans.find(s =>
|
|
s.cells.some(([sr, sc]) => sr === r && sc === c)
|
|
)
|
|
if (span) {
|
|
const allFilled = span.cells.every(([wr, wc]) => state.entries[wr]?.[wc])
|
|
if (allFilled) {
|
|
const wasFilled = span.cells.every(([wr, wc]) => prevEntries.current?.[wr]?.[wc])
|
|
if (!wasFilled) setTimeout(() => playWordComplete(), 50)
|
|
}
|
|
}
|
|
break
|
|
}
|
|
if (!cur && old) {
|
|
playDelete()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
prevEntries.current = state.entries
|
|
|
|
// solved
|
|
if (state.solved && !prevSolved.current) {
|
|
playComplete()
|
|
}
|
|
prevSolved.current = state.solved
|
|
|
|
// hints
|
|
if (state.hintsUsed > prevHints.current) {
|
|
playHint()
|
|
}
|
|
prevHints.current = state.hintsUsed
|
|
})
|
|
|
|
return unsub
|
|
}, [])
|
|
}
|