"use strict"; const common_vendor = require("../../../common/vendor.js"); const STORAGE_KEY = "tongji_game_sfx_enabled"; const COS = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file"; const SRC = { tap: `${COS}/20260526/20260526105128557ef8669.mp3`, swoosh: `${COS}/20260527/202605271539371ebe13672.mp3`, pop: `${COS}/20260526/202605261051282a0a94508.mp3`, buzz: `${COS}/20260527/202605271539376ff628472.mp3`, chime: `${COS}/20260528/202605280937077bad76716.mp3`, fanfare: `${COS}/20260528/20260528093707b021f5794.mp3`, blast: `${COS}/20260528/20260528093707ebd4d5733.mp3`, sparkle: `${COS}/20260528/20260528093707016f07427.mp3`, stinger: `${COS}/20260528/20260528093709c669f4659.mp3` }; const SFX = { // —— 基础素材别名(供分层音效直接调用)—— tap: { src: SRC.tap, volume: 0.32, rate: 1, pool: 3 }, pop: { src: SRC.pop, volume: 0.3, rate: 1, pool: 4 }, fanfare: { src: SRC.fanfare, volume: 0.56, rate: 1, pool: 2 }, blast: { src: SRC.blast, volume: 0.62, rate: 1, pool: 2 }, sparkle: { src: SRC.sparkle, volume: 0.5, rate: 1, pool: 2 }, // —— 交互 —— select: { src: SRC.tap, volume: 0.32, rate: 1.05, pool: 3 }, deselect: { src: SRC.tap, volume: 0.22, rate: 0.82, pool: 2 }, hint: { src: SRC.tap, volume: 0.26, rate: 1.28, pool: 2 }, swap: { src: SRC.swoosh, volume: 0.38, rate: 1, pool: 3 }, swapFail: { src: SRC.buzz, volume: 0.36, rate: 1.18, pool: 2 }, drop: { src: SRC.pop, volume: 0.3, rate: 0.88, pool: 4 }, dropLight: { src: SRC.pop, volume: 0.22, rate: 1.22, pool: 2 }, // —— 消除(按连数)—— match3: { src: SRC.chime, volume: 0.48, rate: 1, pool: 4 }, match4: { src: SRC.fanfare, volume: 0.54, rate: 1.06, pool: 3 }, match5: { src: SRC.blast, volume: 0.62, rate: 1, pool: 3 }, // —— 消除(按 GI 主色)—— matchLowGi: { src: SRC.chime, volume: 0.42, rate: 0.86, pool: 2 }, matchMidGi: { src: SRC.chime, volume: 0.46, rate: 1.02, pool: 2 }, matchHighGi: { src: SRC.buzz, volume: 0.44, rate: 0.92, pool: 2 }, // —— 连消 —— combo2: { src: SRC.fanfare, volume: 0.56, rate: 1.12, pool: 2 }, combo3: { src: SRC.blast, volume: 0.64, rate: 1.08, pool: 2 }, comboMega: { src: SRC.blast, volume: 0.72, rate: 1.22, pool: 2 }, // —— 道具 —— insulin: { src: SRC.sparkle, volume: 0.5, rate: 1.15, pool: 2 }, fiber: { src: SRC.swoosh, volume: 0.48, rate: 1.32, pool: 2 }, meal: { src: SRC.stinger, volume: 0.42, rate: 1.35, pool: 1 }, reshuffle: { src: SRC.swoosh, volume: 0.46, rate: 0.72, pool: 2 }, // —— 反馈 —— score: { src: SRC.tap, volume: 0.28, rate: 1.38, pool: 2 }, goalTick: { src: SRC.chime, volume: 0.36, rate: 1.45, pool: 2 }, meterWarn: { src: SRC.buzz, volume: 0.5, rate: 1, pool: 2 }, meterDanger: { src: SRC.buzz, volume: 0.58, rate: 0.78, pool: 2 }, meterStable: { src: SRC.pop, volume: 0.24, rate: 1.05, pool: 1 }, win: { src: SRC.fanfare, volume: 0.66, rate: 1, pool: 1 }, winStinger: { src: SRC.stinger, volume: 0.38, rate: 1.5, pool: 1 }, lose: { src: SRC.buzz, volume: 0.52, rate: 0.68, pool: 1 }, // 兼容旧名 match: { src: SRC.chime, volume: 0.48, rate: 1, pool: 4 }, combo: { src: SRC.fanfare, volume: 0.56, rate: 1.1, pool: 3 }, heal: { src: SRC.pop, volume: 0.44, rate: 1.18, pool: 2 }, boost: { src: SRC.sparkle, volume: 0.52, rate: 1, pool: 2 }, invalid: { src: SRC.buzz, volume: 0.4, rate: 1.15, pool: 2 }, danger: { src: SRC.blast, volume: 0.58, rate: 0.95, pool: 2 } }; const WARMUP_SFX = [ "select", "swap", "swapFail", "drop", "dropLight", "match3", "match4", "match5", "combo2", "combo3", "comboMega", "insulin", "sparkle", "reshuffle", "lose" ]; function createAudioContext() { if (typeof Audio !== "undefined") { const audio = new Audio(); audio.preload = "auto"; return { get src() { return audio.src; }, set src(value) { audio.src = value; }, get volume() { return audio.volume; }, set volume(value) { audio.volume = value; }, get playbackRate() { return audio.playbackRate; }, set playbackRate(value) { audio.playbackRate = value; }, play() { const promise = audio.play(); if (promise == null ? void 0 : promise.catch) promise.catch(() => { }); }, stop() { audio.pause(); try { audio.currentTime = 0; } catch (_) { } }, seek(time) { try { audio.currentTime = time; } catch (_) { } }, destroy() { audio.pause(); audio.removeAttribute("src"); } }; } return common_vendor.index.createInnerAudioContext(); } class SfxPool { constructor(src, size, volume, rate = 1) { this.src = src; this.size = size; this.volume = volume; this.rate = rate; this.list = []; this.cursor = 0; this.warmedUp = false; } createOne() { const ctx = createAudioContext(); ctx.src = this.src; ctx.obeyMuteSwitch = false; ctx.autoplay = false; ctx.volume = this.volume; try { ctx.playbackRate = this.rate; } catch (_) { } this.list.push(ctx); return ctx; } create() { while (this.list.length < this.size) this.createOne(); } warmUp() { if (this.warmedUp) return; const ctx = this.list[0] || this.createOne(); try { ctx.volume = 0; ctx.play(); setTimeout(() => { try { ctx.stop(); ctx.volume = this.volume; } catch (_) { } }, 60); } catch (_) { } if (this.size > 1) this.cursor = 1; this.warmedUp = true; } play(scale = 1, rateMul = 1) { if (this.list.length < this.size) this.create(); const ctx = this.list[this.cursor % this.list.length]; this.cursor += 1; const vol = Math.min(1, this.volume * scale); const rate = Math.min(2, Math.max(0.5, this.rate * rateMul)); try { ctx.volume = vol; try { ctx.playbackRate = rate; } catch (_) { } ctx.stop(); ctx.seek(0); ctx.play(); } catch (_) { try { ctx.play(); } catch (e) { } } } destroy() { this.list.forEach((ctx) => { try { ctx.stop(); ctx.destroy(); } catch (_) { } }); this.list = []; this.warmedUp = false; } } function dominantGi(tiles = []) { const cnt = { low: 0, mid: 0, high: 0 }; tiles.forEach((t) => { var _a; const g = (_a = t == null ? void 0 : t.type) == null ? void 0 : _a.gi; if (g && cnt[g] !== void 0) cnt[g] += 1; }); let best = "mid"; let max = 0; Object.entries(cnt).forEach(([k, v]) => { if (v > max) { max = v; best = k; } }); return best; } function useGameSfx() { const enabled = common_vendor.ref(true); const pools = {}; try { const stored = common_vendor.index.getStorageSync(STORAGE_KEY); if (stored === false || stored === "0" || stored === 0) { enabled.value = false; } } catch (_) { } function ensureAudioOption() { try { common_vendor.index.setInnerAudioOption({ obeyMuteSwitch: false, mixWithOther: true }); } catch (_) { } } function getPool(name) { const cfg = SFX[name]; if (!cfg) return null; if (!pools[name]) { pools[name] = new SfxPool(cfg.src, cfg.pool, cfg.volume, cfg.rate ?? 1); } return pools[name]; } function warmUp() { if (!enabled.value) return; ensureAudioOption(); const names = typeof Audio !== "undefined" ? ["select"] : WARMUP_SFX; names.forEach((name) => { var _a; (_a = getPool(name)) == null ? void 0 : _a.warmUp(); }); } function play(name, scale = 1, rateMul = 1) { var _a; if (!enabled.value) return; (_a = getPool(name)) == null ? void 0 : _a.play(scale, rateMul); } function playLayer(primary, secondary, delayMs = 70, secScale = 0.6) { play(primary); if (secondary) { setTimeout(() => play(secondary, secScale), delayMs); } } function playMatch({ matchCount = 3, chain = 0, tiles = [] } = {}) { if (!enabled.value) return; const giTrack = (() => { const gi = dominantGi(tiles); if (gi === "low") return "matchLowGi"; if (gi === "high") return "matchHighGi"; return "matchMidGi"; })(); if (chain >= 3) { playLayer("comboMega", giTrack, 90, 0.55); return; } if (chain === 2) { playLayer("combo3", giTrack, 80, 0.5); return; } if (chain === 1) { playLayer("combo2", giTrack, 70, 0.45); return; } if (matchCount >= 5) { playLayer("match5", "matchHighGi", 85, 0.5); } else if (matchCount >= 4) { playLayer("match4", giTrack, 65, 0.48); } else { play(giTrack, 1, 1); setTimeout(() => play("match3", 0.85), 40); } } function playDrop(count = 1) { if (!enabled.value || count <= 0) return; const name = count >= 4 ? "drop" : "dropLight"; play(name, Math.min(1.2, 0.85 + count * 0.04), count >= 6 ? 0.9 : 1); } function playMeter(delta, level) { if (!enabled.value) return; if (level > 70) play("meterDanger", 1 + (level - 70) * 0.02); else if (level < 30) play("meterWarn", 0.9, 0.95); else if (delta > 8) play("meterWarn", 0.75); else if (delta < -5) play("meterStable", 1.1); } function toggleEnabled() { enabled.value = !enabled.value; try { common_vendor.index.setStorageSync(STORAGE_KEY, enabled.value ? "1" : "0"); } catch (_) { } if (enabled.value) { warmUp(); play("select"); } } function destroyAll() { Object.keys(pools).forEach((key) => { var _a; (_a = pools[key]) == null ? void 0 : _a.destroy(); delete pools[key]; }); } common_vendor.onUnmounted(() => { destroyAll(); }); return { enabled, play, playLayer, playMatch, playDrop, playMeter, warmUp, toggleEnabled, destroyAll }; } exports.useGameSfx = useGameSfx; //# sourceMappingURL=../../../../.sourcemap/mp-weixin/tongji/endless-game/composables/useGameSfx.js.map