diff --git a/_saves/Eustia_autoSave b/_saves/Eustia_autoSave
index 2b31cdd..2a3d507 100644
--- a/_saves/Eustia_autoSave
+++ b/_saves/Eustia_autoSave
@@ -1 +1 @@
-N4IgZgNg9lBOCSATEAuEBnALrApjzADAIwgA0IAFjrFKqAJYC2AhgOY6qXVQB0A7jgBGABzIhmAOybNMHFGGYR0OchOaM5IAMLMmYiADdURchWEsAHqgBMBO6dEoidguRZrLN1yHfNU3mQBrL3JEHDAQnzCIlFs3KAkcAE9/chwLR28cAEcAV3pzHAlMVABtAF1yellGdDoQAGMErElMOpRQQRhgp3JIFKcAX3JMGCU6YZAc/OF20HQ+OEQSIcnoBvrEelwGzHoEzlzRcisUAFZyAedJyDY5kGqcRgARfF0IVGxclRBc5QAhfACIoAGXorAoJRQXx+AH1YcocIh4cYACxEVEADgIAGYAGyYkwgeGwSTI2FojHY/GE8jMXDMdqlUAeTQAHVyqJwBEEHLODVR1jELFmZW0ukYFCgGhA5WGLPU7M53N5uX5guFzFFKFKIAAVvRcqxcpJZfKQKzOByuTy+QKhW4tUyQABpAAqADUzaQFTK0ByAOzWPHWQPWMAkR3a3Xuj0AMSFcp9FsVVtyQZDYYjmujIFYUAgiECyW9vqVNtV6odPidYsE9Aof1ytCTZbTNuYdo1UedBuYUEwklYpZTfpA1u5nbV9pzzvQVAkrAkBilMtbo/Lk671ZFc4o9GXq4468t/vTwdD5+zPbFBqR/ZHp/H58zV8jNdzWFw+GIYi/eEIatjSHBoKCHMRgMXUCh2rCx6H7OCh1/E54KgRDFwIWDUPQ1gcUfVMUAkXIIAgG8dRAJJ6DyEgTwIoiSLI3VKLyRNzVPejSI/Z1mNyPDaL9DjGIoqjOXwgTiM43cxR4s4xLkQSuOkkS8Tk1AFKk8ieIDVTCIkoSeMxHT1NrTSRIATiMvTFNM6iCDNSoMECApUAUJQfjA2BkBQbx4Q8xAtALOAUTQXBkHIeFHkYAAJA9MGCipwthCAcGYAwcBBKAGmC4BJnhAx6HQR5yXqf8fxWGFJkEIE8AkABBTBBwaQJnhkPxdIY4lYWYHB6Hihz4S2dBmEEZLio6DBsAA38dVKIgcTOSoKjlG4C2gARYCZBysBwbUiRYTAem8dBhDwLy4gm2BjACVh6CuqpijuxoDicbwWBujZ5EUZRyBaPYsHoBp7lGQcIDdJg5Dm6wzOsM5MQDMyeDMsy8TxIgzKIC5GlyWBYDBv0MdRBGzJcEmScxsxUhAQQZEwZLKcYBIS28tIMkp6mGuSlq3rkbxhCgAqEi5tgeZZ7BmCF9h6agNLnm2HBdggAZvHBCQ4BwABlWRtSOwdYChaG8TOHg8UGSY/M4WcSsmsr6hFMpZucIhrBMIhHesaxSFsOxUVcL33YuL25sxT27HdgMQ8w6xg79mGI5h33Q+scOY+jlxUTxUg5rsYnFtd4hrFRUgE+91PMJxHEI4xDO/fmuP8Triu/bOYvrFrlOI4IM5C6zggzMxXO3cL4vO+ruwMcbseu8rs4A9D1FC79oNp4X0OA1HyPS877ucTsPECAH/Oh7jpfA9RyuQ3PifMLX8/S6IAMTEDpfXADXEk8zneCAJA+naP0+77xGZSur9gGPzHifFw2IO60i9gQTEGcX64lrnnV2qIf4FyLsA9e99k7gLvvDUgD8AzwNIMTL+hcyF4gobvI+lDu5uwWqQB2h9MGwMxJvTEQDYEEBXi4WeLgM5ELMhcVwojMEoJhj/IgwcUHSI7sjTOjsiAZzzphMRsCMSYLEWIiRjDSjQy0YolhCcTA6IYUYp2HsJFWLdjY/O1hFraIsXI2Rqc7GuxkUozx9jDGuDMmgphWd75OJfqY3x4T96BJ3vfYOISImGKCQSD+xBAG5x3v7ZJyigGJOydEwBmT8lBJAdYix7sCkyLybklJVT3bb2IAGAM5RlrkBoLkWQnAXRQATFoVErAAC8YgDCKG+HMSYaUNr7AkGmMyOAcSID5IIZugZmBmXmbkYmtg+SYi7naAgYAOTIyIBEcgxp6BeRAHiQQXJBCIGIbCIgzBUTMFhKiMA8NYSYkQDiQQsIzjzWsOEVEiBEBgH8WIPY+MAw0kFEjchmJBhAA===
\ No newline at end of file
+N4IgZgNg9lBOCSATEAuEBnALrApjzADAIwgA0IAFjrFKqAJYC2AhgOY6qXVQB0A7jgBGABzIhmAOybNMHFGGYR0OchOaM5IAMLMmYiADdURchWEsAHqgCct66dEoiBF+RZrLqALQmQ75qgE5DIA1sauIIg4YOFBflExKHHownjISW5QEjgAnoHkOBaOcTgAjgCu9OY4EpioANoAuuT0sozodCAAxllYkpgdKKCCMGFO5JB5TgC+5JgwSnSzIGWVwoOg6HxwiCQzy9BdnYj0uF2Y9Fmc5aLkVigArORTzsuQbBsgrTiMACL4uggqGw5RUIHKygAQvgBDUADL0VgUOooEFggD66OUOEQmOMAHYAGwEawADgATOSACxxTGwSS49EE4lkyk04K4ZiDeqgDyaAA65SpOAIgkFDy6VPJYhY6wa2l0jAoUA0IEas156gFQpFYvKEqlMuYcpQ9RAACt6OVWOVJGqNSA+ZxBcLReLJdK3MbuSAANIAFQAavbSJrVWhBfjyYTyZHyWASF6TWaA4GAGLS9Whx1a53lKMxuMJo3JkCsKAQRAhXIhsPa116g2evze+WCegUCHlWhZut513Md2GpM+y3MKCYSSsWs58MgF0iwf6j0ln3oKgSVgSAzK1W92f1xdD5uytcUejb3ccfdOiP56Ox+/Fkfyy048cz2/z++Fp+JlullguD4MQYhAXghDNjaU5dBQU5iNBm6wVOzYWPQ45oVOoF3OhUCYZuBCobh+GsAAzJ+uYoBI5QQBAL6miAOT0BUJA3pR1G0fRZpMRUmYOreHF0QBPo8eU5FseGglcYxzFChRkk0UJp7yqJDzyXIUnCSpsmEupqCacpDGifielUYp0miaSpkGa2RmydY1nmVpdksQQ9rNBgIRVKgChKGCcGwOktLogFiBaBWcB4mguDIOQmLfIwAASF6YFFTRxeiEA4MwBg4HCUBdFFwDLJiBj0Og3yMp04EgXsaLLIIMJ4BIACCmCTl0IS/DIARmZxICYswOD0GlHmYic6DMIIWVVUMGDYBBoGmvURCkQ8zRNOqbwVtAAiwNyHlYDgJq+H0FxYPQXSfPMk4QP6TByOSDxEEQUpRjwhJ2C91hPN05SwLA93hkQDxUtYPCkXYUNQ4SDj5CAggyJgWXw4wWQ1hkKxFPDiPtVl3UsOw8PCFA5VZATbByCUFjYMwFNE5jaO5b8pw4OcEBTHEiISHAOAAMqyCaySTrAKKElSDykTwVLTMsoWcKu1ULbVnSyg0QQa6Qmva1ruv1D4pAG0bJgG0ExuGyblsWxbzQa1t5A0OUsicL6UAZloVKsAAvGIBiKKCGzLLl+2XBIebWDgpGIOKggPAQkbMNY0flNYhHx/qpKg+6BBgIK1iEkQMTkDa9DpCA5LMIghKEog1iFYgYBgFS6JUqSifooIVKEmA6JgIgU0EDgNJV3gYgXMD+KkficfWKRBBSi40xAA==
\ No newline at end of file
diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4
index b313060..10b3ad5 100644
--- a/_server/MotaAction.g4
+++ b/_server/MotaAction.g4
@@ -2243,12 +2243,12 @@ setanimate_s
tooltip : setanimate:设置帧动画/特效(此项仅储存,不播放)
helpUrl : /_docs/#/instruction
default : ["sword","","",192,192,60]
-colour : this.soundColor
+colour : this.imageColor
IntString_0 = IntString_0 ? (', "px": '+IntString_0+'') : '';
IntString_1 = IntString_1 ? (', "py": '+IntString_1+'') : '';
var imageList=animateDrawableimage_0?',"imageList": [\n'+animateDrawableimage_0.slice(0,-1)+'\n]':''
var soundList=animateDrawablesound_0?',"soundList": [\n'+animateDrawablesound_0.slice(0,-1)+'\n]':''
-var code = '{"type": "setanimate", "name": "'+EvalString_0+'",'+IntString_0+IntString_1+' "width": '+IntString_2+', "height": '+IntString_3+', "allFarme": '+IntString_4+imageList+soundList+'},\n';
+var code = '{"type": "setanimate", "name": "'+EvalString_0+'"'+IntString_0+IntString_1+' ,"width": '+IntString_2+', "height": '+IntString_3+', "allFarme": '+IntString_4+imageList+soundList+'},\n';
return code;
*/;
@@ -2322,9 +2322,9 @@ deleteanimate_s
/* deleteanimate_s
tooltip : deleteanimate:删除储存的帧动画
helpUrl : /_docs/#/instruction
-default : [""]
+default : ["zone"]
-colour : this.soundColor
+colour : this.imageColor
var code = '{"type": "deleteanimate", "name": "'+EvalString_0+'"},\n';
return code;
@@ -2338,7 +2338,7 @@ tooltip : playanimate:播放帧动画,选择跟随勇士后x、y将失效改
helpUrl : /_docs/#/instruction
default : ["zone","","",false,"",""]
-colour : this.soundColor
+colour : this.imageColor
IntString_0 = IntString_0 ? (', "x": '+IntString_0+'') : '';
IntString_1 = IntString_1 ? (', "y": '+IntString_1+'') : '';
if(EvalString_1&&!/^(0|([1-9][0-9]*))(\.[\d]+)?$/.test(EvalString_1))throw new Error("此项仅能填写小数、整数或不填");
@@ -2356,7 +2356,7 @@ clearanimate_s
tooltip : clearanimate:清空正在播放的帧动画
helpUrl : /_docs/#/instruction
-colour : this.soundColor
+colour : this.imageColor
var code = '{"type": "clearanimate"},\n';
return code;
@@ -2404,7 +2404,7 @@ stopAnimate_s
tooltip : stopAnimate:停止所有动画
helpUrl : /_docs/#/instruction
default : [false]
-colour : this.soundColor
+colour : this.imageColor
Bool_0 = Bool_0?', "doCallback": true':'';
var code = '{"type": "stopAnimate"'+Bool_0+'},\n';
return code;
diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js
index 829580d..06c2081 100644
--- a/_server/MotaActionParser.js
+++ b/_server/MotaActionParser.js
@@ -777,18 +777,18 @@ MotaActionParser = function () {
break;
case "deleteanimate":
this.next = MotaActionBlocks["deleteanimate_s"].xmlText([
- this.name,
+ data.name,
this.next,
]);
break;
case "playanimate":
this.next = MotaActionBlocks["playanimate_s"].xmlText([
- this.name,
- this.x,
- this.y,
- this.hero,
- this.scalex,
- this.scaley,
+ data.name,
+ data.x,
+ data.y,
+ data.hero,
+ data.scalex,
+ data.scaley,
this.next,
]);
break;
diff --git a/_server/config.json b/_server/config.json
index e97cbbe..bdcb574 100644
--- a/_server/config.json
+++ b/_server/config.json
@@ -1 +1 @@
-{"viewportLoc":[0,0],"editorLastFloorId":"KTV"}
\ No newline at end of file
+{"viewportLoc":[0,0],"editorLastFloorId":"jiedao"}
\ No newline at end of file
diff --git a/project/data.js b/project/data.js
index 04a1131..5b8e9ed 100644
--- a/project/data.js
+++ b/project/data.js
@@ -904,118 +904,118 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"theme.opus"
],
"sounds": [
- "aiy010000010.mp3",
- "aiy010000020.mp3",
- "aiy010000030.mp3",
- "aiy020000005.mp3",
- "aiy020000010.mp3",
- "aiy020000020.mp3",
- "aiy020000030.mp3",
- "aiy020000040.mp3",
- "aiy020000050.mp3",
- "aiy020000060.mp3",
- "aiy020000070.mp3",
- "aiy020000080.mp3",
- "aiy020000090.mp3",
- "aiy020000100.mp3",
- "aiy020000110.mp3",
- "aiy020000120.mp3",
- "aiy020000130.mp3",
- "aiy020000140.mp3",
- "aiy020000150.mp3",
- "aiy020000160.mp3",
- "aiy020000170.mp3",
- "aiy020000180.mp3",
- "aiy310000010.mp3",
- "aiy310000020.mp3",
- "aiy310000030.mp3",
- "aiy310000040.mp3",
- "aiy310000050.mp3",
- "aiy310000060.mp3",
- "aiy310000070.mp3",
- "aiy310000080.mp3",
- "aiy310000090.mp3",
- "aiy310000100.mp3",
- "aiy310000110.mp3",
- "aiy310000120.mp3",
- "aiy310000130.mp3",
- "aiy310000140.mp3",
- "aiy310000150.mp3",
- "aiy310000160.mp3",
- "aiy310000170.mp3",
- "aiy310000180.mp3",
- "aiy310000190.mp3",
- "aiy310000200.mp3",
- "aiy310000210.mp3",
- "aiy310000220.mp3",
- "aiy310000230.mp3",
- "aiy310000240.mp3",
- "aiy310000250.mp3",
- "aiy310000260.mp3",
- "aiy310000280.mp3",
- "aiy310000290.mp3",
- "aiy310000300.mp3",
- "aiy350000010.mp3",
- "aiy350000020.mp3",
- "aiy350000030.mp3",
- "aiy350000040.mp3",
- "aiy350000050.mp3",
- "aiy350000060.mp3",
- "aiy350000070.mp3",
- "aiy350000080.mp3",
- "aiy350000090.mp3",
- "aiy350000100.mp3",
- "aiy350000110.mp3",
- "aiy350000120.mp3",
- "aiy350000130.mp3",
- "aiy350000140.mp3",
- "aiy350000150.mp3",
- "aiy350000160.mp3",
- "aiy350000170.mp3",
- "aiy350000180.mp3",
- "aiy350000190.mp3",
- "aiy350000200.mp3",
- "aiy350000210.mp3",
- "aiy350000220.mp3",
- "aiy350000230.mp3",
- "aiy710000010.mp3",
- "aiy710000020.mp3",
- "aiy710000030.mp3",
- "aiy710000040.mp3",
- "aiy710000050.mp3",
- "aiy710000060.mp3",
- "aiy710000070.mp3",
- "aiy710000080.mp3",
- "aiy710000090.mp3",
- "aiy710000100.mp3",
- "aiy710000110.mp3",
- "aiy710000120.mp3",
- "aiy710000130.mp3",
- "aiy820000010.mp3",
- "aiy820000020.mp3",
- "attack.mp3",
+ "aiy010000010.opus",
+ "aiy010000020.opus",
+ "aiy010000030.opus",
+ "aiy020000005.opus",
+ "aiy020000010.opus",
+ "aiy020000020.opus",
+ "aiy020000030.opus",
+ "aiy020000040.opus",
+ "aiy020000050.opus",
+ "aiy020000060.opus",
+ "aiy020000070.opus",
+ "aiy020000080.opus",
+ "aiy020000090.opus",
+ "aiy020000100.opus",
+ "aiy020000110.opus",
+ "aiy020000120.opus",
+ "aiy020000130.opus",
+ "aiy020000140.opus",
+ "aiy020000150.opus",
+ "aiy020000160.opus",
+ "aiy020000170.opus",
+ "aiy020000180.opus",
+ "aiy310000010.opus",
+ "aiy310000020.opus",
+ "aiy310000030.opus",
+ "aiy310000040.opus",
+ "aiy310000050.opus",
+ "aiy310000060.opus",
+ "aiy310000070.opus",
+ "aiy310000080.opus",
+ "aiy310000090.opus",
+ "aiy310000100.opus",
+ "aiy310000110.opus",
+ "aiy310000120.opus",
+ "aiy310000130.opus",
+ "aiy310000140.opus",
+ "aiy310000150.opus",
+ "aiy310000160.opus",
+ "aiy310000170.opus",
+ "aiy310000180.opus",
+ "aiy310000190.opus",
+ "aiy310000200.opus",
+ "aiy310000210.opus",
+ "aiy310000220.opus",
+ "aiy310000230.opus",
+ "aiy310000240.opus",
+ "aiy310000250.opus",
+ "aiy310000260.opus",
+ "aiy310000280.opus",
+ "aiy310000290.opus",
+ "aiy310000300.opus",
+ "aiy350000010.opus",
+ "aiy350000020.opus",
+ "aiy350000030.opus",
+ "aiy350000040.opus",
+ "aiy350000050.opus",
+ "aiy350000060.opus",
+ "aiy350000070.opus",
+ "aiy350000080.opus",
+ "aiy350000090.opus",
+ "aiy350000100.opus",
+ "aiy350000110.opus",
+ "aiy350000120.opus",
+ "aiy350000130.opus",
+ "aiy350000140.opus",
+ "aiy350000150.opus",
+ "aiy350000160.opus",
+ "aiy350000170.opus",
+ "aiy350000180.opus",
+ "aiy350000190.opus",
+ "aiy350000200.opus",
+ "aiy350000210.opus",
+ "aiy350000220.opus",
+ "aiy350000230.opus",
+ "aiy710000010.opus",
+ "aiy710000020.opus",
+ "aiy710000030.opus",
+ "aiy710000040.opus",
+ "aiy710000050.opus",
+ "aiy710000060.opus",
+ "aiy710000070.opus",
+ "aiy710000080.opus",
+ "aiy710000090.opus",
+ "aiy710000100.opus",
+ "aiy710000110.opus",
+ "aiy710000120.opus",
+ "aiy710000130.opus",
+ "aiy820000010.opus",
+ "aiy820000020.opus",
"attack.opus",
- "bomb.mp3",
- "cancel.mp3",
- "centerFly.mp3",
- "confirm.mp3",
- "cursor.mp3",
- "door.mp3",
- "equip.mp3",
- "error.mp3",
- "floor.mp3",
- "gem.mp3",
- "icePickaxe.mp3",
- "item.mp3",
- "jingbao.mp3",
- "jump.mp3",
- "load.mp3",
- "open_ui.mp3",
- "pickaxe.mp3",
- "recovery.mp3",
- "save.mp3",
- "shop.mp3",
- "zone.mp3"
+ "attack.opus",
+ "bomb.opus",
+ "cancel.opus",
+ "centerFly.opus",
+ "confirm.opus",
+ "cursor.opus",
+ "door.opus",
+ "equip.opus",
+ "error.opus",
+ "floor.opus",
+ "gem.opus",
+ "icePickaxe.opus",
+ "item.opus",
+ "jingbao.opus",
+ "jump.opus",
+ "load.opus",
+ "open_ui.opus",
+ "pickaxe.opus",
+ "recovery.opus",
+ "save.opus",
+ "shop.opus",
+ "zone.opus"
],
"fonts": [
"HATTEN",
@@ -1024,29 +1024,29 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"simhei"
],
"nameMap": {
- "确定": "confirm.mp3",
- "取消": "cancel.mp3",
- "操作失败": "error.mp3",
- "光标移动": "cursor.mp3",
- "打开界面": "open_ui.mp3",
- "读档": "load.mp3",
- "存档": "save.mp3",
- "获得道具": "item.mp3",
- "回血": "recovery.mp3",
- "炸弹": "bomb.mp3",
- "飞行器": "centerFly.mp3",
- "开关门": "door.mp3",
- "上下楼": "floor.mp3",
- "跳跃": "jump.mp3",
- "破墙镐": "pickaxe.mp3",
- "破冰镐": "icePickaxe.mp3",
- "宝石": "gem.mp3",
- "阻激夹域": "zone.mp3",
- "穿脱装备": "equip.mp3",
- "背景音乐": "bgm.mp3",
- "攻击": "attack.mp3",
+ "确定": "confirm.opus",
+ "取消": "cancel.opus",
+ "操作失败": "error.opus",
+ "光标移动": "cursor.opus",
+ "打开界面": "open_ui.opus",
+ "读档": "load.opus",
+ "存档": "save.opus",
+ "获得道具": "item.opus",
+ "回血": "recovery.opus",
+ "炸弹": "bomb.opus",
+ "飞行器": "centerFly.opus",
+ "开关门": "door.opus",
+ "上下楼": "floor.opus",
+ "跳跃": "jump.opus",
+ "破墙镐": "pickaxe.opus",
+ "破冰镐": "icePickaxe.opus",
+ "宝石": "gem.opus",
+ "阻激夹域": "zone.opus",
+ "穿脱装备": "equip.opus",
+ "背景音乐": "bgm.opus",
+ "攻击": "attack.opus",
"背景图": "bg.webp",
- "商店": "shop.mp3",
+ "商店": "shop.opus",
"领域": "zone"
},
"levelChoose": null,
diff --git a/project/events.js b/project/events.js
index 3ec338a..1e860d2 100644
--- a/project/events.js
+++ b/project/events.js
@@ -146,7 +146,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"chapter0": [
{
"type": "playBgm",
- "name": "Crawler.mp3",
+ "name": "Crawler.opus",
"keep": true
},
{
@@ -892,7 +892,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "少女",
"time": 30,
"wait": 1000,
- "sound": "aiy010000010.mp3",
+ "sound": "aiy010000010.opus",
"text": "「呃······!?」",
"bodyList": [
{
@@ -1104,7 +1104,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "少女",
"time": 30,
"wait": 2000,
- "sound": "aiy010000020.mp3",
+ "sound": "aiy010000020.opus",
"text": "「······被杀」",
"bodyList": [
{
@@ -1192,7 +1192,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "少女",
"time": 30,
"wait": 1000,
- "sound": "aiy010000030.mp3",
+ "sound": "aiy010000030.opus",
"text": "「不,不要······」",
"bodyList": [
{
@@ -1204,7 +1204,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
},
{
"type": "playBgm",
- "name": "Blind_Alley.mp3",
+ "name": "Blind_Alley.opus",
"keep": true
},
{
@@ -1316,7 +1316,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000010.mp3",
+ "sound": "aiy710000010.opus",
"text": "「放开我!」",
"bodyList": [
{
@@ -1338,7 +1338,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000020.mp3",
+ "sound": "aiy710000020.opus",
"text": "「我只是在帮那个女人而已!」",
"bodyList": [
{
@@ -1369,7 +1369,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000030.mp3",
+ "sound": "aiy710000030.opus",
"text": "「你们没听到吗!?」",
"bodyList": [
{
@@ -1391,7 +1391,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000040.mp3",
+ "sound": "aiy710000040.opus",
"text": "「她是被受骗才会被卖到娼馆来的」",
"bodyList": [
{
@@ -1413,7 +1413,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000050.mp3",
+ "sound": "aiy710000050.opus",
"text": "「用肮脏的手段把钱借给她父母的,就是你们这些家伙吧!?」",
"bodyList": [
{
@@ -1444,7 +1444,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000060.mp3",
+ "sound": "aiy710000060.opus",
"text": "「给我说些什么啊」",
"bodyList": [
{
@@ -1466,7 +1466,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000010.mp3",
+ "sound": "aiy310000010.opus",
"text": "「这些话等到了娼馆再说吧」",
"bodyList": [
{
@@ -1488,7 +1488,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000020.mp3",
+ "sound": "aiy310000020.opus",
"text": "「我来抓你,只是受雇于人而已」",
"bodyList": [
{
@@ -1563,7 +1563,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000010.mp3",
+ "sound": "aiy350000010.opus",
"text": "「这不是凯伊姆先生吗,辛苦了」",
"bodyList": [
{
@@ -1585,7 +1585,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000020.mp3",
+ "sound": "aiy350000020.opus",
"text": "「委托已经完成了吗?」",
"bodyList": [
{
@@ -1607,7 +1607,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000030.mp3",
+ "sound": "aiy310000030.opus",
"text": "「啊啊,是这家伙没错吧」",
"bodyList": [
{
@@ -1651,7 +1651,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000030.mp3",
+ "sound": "aiy350000030.opus",
"text": "「没错,就是这个人」",
"bodyList": [
{
@@ -1673,7 +1673,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000040.mp3",
+ "sound": "aiy310000040.opus",
"text": "「是么」",
"bodyList": [
{
@@ -1695,7 +1695,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000070.mp3",
+ "sound": "aiy710000070.opus",
"text": "「你,你们要对我做什么」",
"bodyList": [
{
@@ -1717,7 +1717,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000040.mp3",
+ "sound": "aiy350000040.opus",
"text": "「······」",
"bodyList": [
{
@@ -1783,7 +1783,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000050.mp3",
+ "sound": "aiy350000050.opus",
"text": "「抱歉啊,总是麻烦你去做这些无聊的事」",
"bodyList": [
{
@@ -1805,7 +1805,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000060.mp3",
+ "sound": "aiy350000060.opus",
"text": "「都怪我们这边的年轻人太没用」",
"bodyList": [
{
@@ -1827,7 +1827,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000050.mp3",
+ "sound": "aiy310000050.opus",
"text": "「客套话就免了」",
"bodyList": [
{
@@ -1849,7 +1849,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000070.mp3",
+ "sound": "aiy350000070.opus",
"text": "「这还真是失礼了」",
"bodyList": [
{
@@ -1871,7 +1871,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000080.mp3",
+ "sound": "aiy350000080.opus",
"text": "「喂,来个人」",
"bodyList": [
{
@@ -1893,7 +1893,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "光头男人",
"time": 30,
"wait": 1000,
- "sound": "aiy820000010.mp3",
+ "sound": "aiy820000010.opus",
"text": "「是」",
"bodyList": [
{
@@ -1915,7 +1915,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000090.mp3",
+ "sound": "aiy350000090.opus",
"text": "「凯伊姆先生做完工作回来了」",
"bodyList": [
{
@@ -1937,7 +1937,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "光头男人",
"time": 30,
"wait": 1000,
- "sound": "aiy820000020.mp3",
+ "sound": "aiy820000020.opus",
"text": "「是,是,那个······」",
"bodyList": [
{
@@ -1959,7 +1959,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000100.mp3",
+ "sound": "aiy350000100.opus",
"text": "「我是要你拿些酒来,这个蠢材!」",
"bodyList": [
{
@@ -2047,7 +2047,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000060.mp3",
+ "sound": "aiy310000060.opus",
"text": "「不用这么麻烦」",
"bodyList": [
{
@@ -2069,7 +2069,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000070.mp3",
+ "sound": "aiy310000070.opus",
"text": "「我接下来要去《菲诺列塔》」",
"bodyList": [
{
@@ -2091,7 +2091,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000110.mp3",
+ "sound": "aiy350000110.opus",
"text": "「喔唷」",
"bodyList": [
{
@@ -2113,7 +2113,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000120.mp3",
+ "sound": "aiy350000120.opus",
"text": "「既然如此,我就不留您在这里喝难饮的劣质酒了」",
"bodyList": [
{
@@ -2157,7 +2157,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000080.mp3",
+ "sound": "aiy310000080.opus",
"text": "「用这些钱去买药」",
"bodyList": [
{
@@ -2201,7 +2201,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000130.mp3",
+ "sound": "aiy350000130.opus",
"text": "「凯伊姆先生,不用对他们这么好」",
"bodyList": [
{
@@ -2223,7 +2223,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000090.mp3",
+ "sound": "aiy310000090.opus",
"text": "「无妨」",
"bodyList": [
{
@@ -2245,7 +2245,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000100.mp3",
+ "sound": "aiy310000100.opus",
"text": "「话说回来,那个要落跑的女人呢?」",
"bodyList": [
{
@@ -2267,7 +2267,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000140.mp3",
+ "sound": "aiy350000140.opus",
"text": "「我把她交给那些年轻人了,现在应该正在体会人生的严苛吧」",
"bodyList": [
{
@@ -2289,7 +2289,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000150.mp3",
+ "sound": "aiy350000150.opus",
"text": "「正好,趁此机会凯伊姆先生也来享受一番如何?」",
"bodyList": [
{
@@ -2311,7 +2311,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000080.mp3",
+ "sound": "aiy710000080.opus",
"text": "「你,你们这些家伙,要对她做什么!?」",
"bodyList": [
{
@@ -2443,7 +2443,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000090.mp3",
+ "sound": "aiy710000090.opus",
"text": "「咕······呃咳······」",
"bodyList": [
{
@@ -2509,7 +2509,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000100.mp3",
+ "sound": "aiy710000100.opus",
"text": "「你们以为做出这种事······卫兵会坐视不理吗······」",
"bodyList": [
{
@@ -2531,7 +2531,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000160.mp3",
+ "sound": "aiy350000160.opus",
"text": "「啊啊,不会坐视不理的」",
"bodyList": [
{
@@ -2553,7 +2553,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000170.mp3",
+ "sound": "aiy350000170.opus",
"text": "「应该会拿出你的钱包,和我们商量如何瓜分吧」",
"bodyList": [
{
@@ -2575,7 +2575,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000110.mp3",
+ "sound": "aiy710000110.opus",
"text": "「那,那种事······」",
"bodyList": [
{
@@ -2619,7 +2619,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 2000,
- "sound": "aiy350000180.mp3",
+ "sound": "aiy350000180.opus",
"text": "「怎么,头一回来牢狱么?」",
"bodyList": [
{
@@ -2663,7 +2663,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000190.mp3",
+ "sound": "aiy350000190.opus",
"text": "「为了被骗的女人而来到牢狱,真是个规矩人啊」",
"bodyList": [
{
@@ -2685,7 +2685,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000200.mp3",
+ "sound": "aiy350000200.opus",
"text": "「······前提是,被骗的人不是你」",
"bodyList": [
{
@@ -2707,7 +2707,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000120.mp3",
+ "sound": "aiy710000120.opus",
"text": "「你说······我被骗了?」",
"bodyList": [
{
@@ -2729,7 +2729,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "年轻人",
"time": 30,
"wait": 1000,
- "sound": "aiy710000130.mp3",
+ "sound": "aiy710000130.opus",
"text": "「那,那是怎么回事!?」",
"bodyList": [
{
@@ -2751,7 +2751,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000210.mp3",
+ "sound": "aiy350000210.opus",
"text": "「不用急,今天晚上会好好告诉你的」",
"bodyList": [
{
@@ -2971,7 +2971,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000110.mp3",
+ "sound": "aiy310000110.opus",
"text": "「我要走了」",
"bodyList": [
{
@@ -2993,7 +2993,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000220.mp3",
+ "sound": "aiy350000220.opus",
"text": "「好的,下次再麻烦您」",
"bodyList": [
{
@@ -3015,7 +3015,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "奥兹",
"time": 30,
"wait": 1000,
- "sound": "aiy350000230.mp3",
+ "sound": "aiy350000230.opus",
"text": "「之后吉克先生会将谢礼交给您的」",
"bodyList": [
{
@@ -3037,7 +3037,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000120.mp3",
+ "sound": "aiy310000120.opus",
"text": "「啊啊」",
"bodyList": [
{
@@ -3081,7 +3081,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000130.mp3",
+ "sound": "aiy310000130.opus",
"text": "「······?」",
"bodyList": [
{
@@ -3341,7 +3341,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000140.mp3",
+ "sound": "aiy310000140.opus",
"text": "「艾莉斯」",
"bodyList": [
{
@@ -3387,7 +3387,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000005.mp3",
+ "sound": "aiy020000005.opus",
"text": "「啊,凯伊姆」",
"bodyList": [
{
@@ -3409,7 +3409,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000010.mp3",
+ "sound": "aiy020000010.opus",
"text": "「正好,我还想要去找你呢」",
"bodyList": [
{
@@ -3431,7 +3431,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000020.mp3",
+ "sound": "aiy020000020.opus",
"text": "「没想到凯伊姆会主动出现······这是命运吗?」",
"bodyList": [
{
@@ -3453,7 +3453,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000150.mp3",
+ "sound": "aiy310000150.opus",
"text": "「显然不是吧」",
"bodyList": [
{
@@ -3475,7 +3475,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000030.mp3",
+ "sound": "aiy020000030.opus",
"text": "「啊,是么」",
"bodyList": [
{
@@ -3585,7 +3585,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000040.mp3",
+ "sound": "aiy020000040.opus",
"text": "「喜欢我的眼睛吗?」",
"bodyList": [
{
@@ -3607,7 +3607,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000050.mp3",
+ "sound": "aiy020000050.opus",
"text": "「如果想要的话就给你吧?」",
"bodyList": [
{
@@ -3629,7 +3629,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000160.mp3",
+ "sound": "aiy310000160.opus",
"text": "「用不着」",
"bodyList": [
{
@@ -3651,7 +3651,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000060.mp3",
+ "sound": "aiy020000060.opus",
"text": "「阿拉,可惜」",
"bodyList": [
{
@@ -3673,7 +3673,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000170.mp3",
+ "sound": "aiy310000170.opus",
"text": "「那么,找我有什么事」",
"bodyList": [
{
@@ -3695,7 +3695,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000070.mp3",
+ "sound": "aiy020000070.opus",
"text": "「梅尔特的钱好像被偷了」",
"bodyList": [
{
@@ -3717,7 +3717,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000180.mp3",
+ "sound": "aiy310000180.opus",
"text": "「钱被偷了?都几岁了还这么没用」",
"bodyList": [
{
@@ -3739,7 +3739,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000080.mp3",
+ "sound": "aiy020000080.opus",
"text": "「不要对我说啊」",
"bodyList": [
{
@@ -3761,7 +3761,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000190.mp3",
+ "sound": "aiy310000190.opus",
"text": "「那家伙,该不会说要让我去抓那个小偷吧?」",
"bodyList": [
{
@@ -3783,7 +3783,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000090.mp3",
+ "sound": "aiy020000090.opus",
"text": "「就是这样」",
"bodyList": [
{
@@ -3805,7 +3805,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000200.mp3",
+ "sound": "aiy310000200.opus",
"text": "「笨蛋吗」",
"bodyList": [
{
@@ -3827,7 +3827,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000210.mp3",
+ "sound": "aiy310000210.opus",
"text": "「如果是小钱的话,就当做是买个教训吧」",
"bodyList": [
{
@@ -3849,7 +3849,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000100.mp3",
+ "sound": "aiy020000100.opus",
"text": "「说起来,被盗的是这个月的上纳金」",
"bodyList": [
{
@@ -3871,7 +3871,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000220.mp3",
+ "sound": "aiy310000220.opus",
"text": "「你说什么?」",
"bodyList": [
{
@@ -3893,7 +3893,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000110.mp3",
+ "sound": "aiy020000110.opus",
"text": "「用这些钱买教训,也太过奢侈了呢」",
"bodyList": [
{
@@ -3915,7 +3915,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000230.mp3",
+ "sound": "aiy310000230.opus",
"text": "「知道了,我去找」",
"bodyList": [
{
@@ -3937,7 +3937,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000240.mp3",
+ "sound": "aiy310000240.opus",
"text": "「小偷的特征呢」",
"bodyList": [
{
@@ -3959,7 +3959,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000120.mp3",
+ "sound": "aiy020000120.opus",
"text": "「男孩子」",
"bodyList": [
{
@@ -3981,7 +3981,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000130.mp3",
+ "sound": "aiy020000130.opus",
"text": "「······而且,背后有翅膀」",
"bodyList": [
{
@@ -4003,7 +4003,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000140.mp3",
+ "sound": "aiy020000140.opus",
"text": "「虽然姑且是藏在身后,但是仔细观察的话是很明显的」",
"bodyList": [
{
@@ -4025,7 +4025,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000250.mp3",
+ "sound": "aiy310000250.opus",
"text": "「羽化病吗」",
"bodyList": [
{
@@ -4047,7 +4047,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000150.mp3",
+ "sound": "aiy020000150.opus",
"text": "「那些人可是毫不留情的,所以即使是为了那个孩子,也要赶快抓到他」",
"bodyList": [
{
@@ -4069,7 +4069,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000260.mp3",
+ "sound": "aiy310000260.opus",
"text": "「注意到他逃窜的方向了吗?」",
"bodyList": [
{
@@ -4091,7 +4091,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000160.mp3",
+ "sound": "aiy020000160.opus",
"text": "「广场那边」",
"bodyList": [
{
@@ -4113,7 +4113,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000170.mp3",
+ "sound": "aiy020000170.opus",
"text": "「虽然刚才《不蚀金锁》的人去追了,不过多半是······」",
"bodyList": [
{
@@ -4135,7 +4135,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000280.mp3",
+ "sound": "aiy310000280.opus",
"text": "「偏偏还是广场吗」",
"bodyList": [
{
@@ -4157,7 +4157,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "艾莉斯",
"time": 30,
"wait": 1000,
- "sound": "aiy020000180.mp3",
+ "sound": "aiy020000180.opus",
"text": "「今天是觐见圣女大人的日子」",
"bodyList": [
{
@@ -4179,7 +4179,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000290.mp3",
+ "sound": "aiy310000290.opus",
"text": "「我知道」",
"bodyList": [
{
@@ -4201,7 +4201,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"name": "凯伊姆",
"time": 30,
"wait": 1000,
- "sound": "aiy310000300.mp3",
+ "sound": "aiy310000300.opus",
"text": "「尽量找找看就好」",
"bodyList": [
{
diff --git a/project/maps.js b/project/maps.js
index 6367155..fc722c6 100644
--- a/project/maps.js
+++ b/project/maps.js
@@ -1,11 +1,11 @@
var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
{
- "1": {"cls":"animates","id":"yellowWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{}}},
- "2": {"cls":"animates","id":"whiteWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{}}},
- "3": {"cls":"animates","id":"blueWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{}}},
+ "1": {"cls":"animates","id":"yellowWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{}}},
+ "2": {"cls":"animates","id":"whiteWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{}}},
+ "3": {"cls":"animates","id":"blueWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{}}},
"4": {"cls":"animates","id":"star","name":"星空"},
"5": {"cls":"animates","id":"lava","name":"岩浆"},
- "6": {"cls":"animates","id":"ice","doorInfo":{"time":160,"openSound":"破冰镐","closeSound":"door.mp3","keys":{"icePickaxe":1}},"animate":1},
+ "6": {"cls":"animates","id":"ice","doorInfo":{"time":160,"openSound":"破冰镐","closeSound":"door.opus","keys":{"icePickaxe":1}},"animate":1},
"7": {"cls":"terrains","id":"blueShopLeft"},
"8": {"cls":"terrains","id":"blueShopRight"},
"9": {"cls":"terrains","id":"pinkShopLeft"},
@@ -68,12 +68,12 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"71": {"cls":"items","id":"shield0"},
"72": {"cls":"items","id":"skill1"},
"73": {"cls":"items","id":"wand"},
- "81": {"cls":"animates","id":"yellowDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"yellowKey":1}},"name":"黄门"},
- "82": {"cls":"animates","id":"blueDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"blueKey":1}},"name":"蓝门"},
- "83": {"cls":"animates","id":"redDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"redKey":1}},"name":"红门"},
- "84": {"cls":"animates","id":"greenDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"greenKey":1}},"name":"绿门"},
- "85": {"cls":"animates","id":"specialDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"specialKey":1}},"name":"机关门"},
- "86": {"cls":"animates","id":"steelDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"steelKey":1}},"name":"铁门"},
+ "81": {"cls":"animates","id":"yellowDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"yellowKey":1}},"name":"黄门"},
+ "82": {"cls":"animates","id":"blueDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"blueKey":1}},"name":"蓝门"},
+ "83": {"cls":"animates","id":"redDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"redKey":1}},"name":"红门"},
+ "84": {"cls":"animates","id":"greenDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"greenKey":1}},"name":"绿门"},
+ "85": {"cls":"animates","id":"specialDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"specialKey":1}},"name":"机关门"},
+ "86": {"cls":"animates","id":"steelDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"steelKey":1}},"name":"铁门"},
"87": {"cls":"terrains","id":"upFloor","canPass":true},
"88": {"cls":"terrains","id":"downFloor","canPass":true},
"89": {"cls":"animates","id":"portal","canPass":true},
@@ -86,7 +86,7 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"102": {"cls":"animates","id":"crystalBottom"},
"103": {"cls":"animates","id":"fire"},
"104": {"cls":"animates","id":"switch"},
- "109": {"cls":"animates","id":"magentaWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{}}},
+ "109": {"cls":"animates","id":"magentaWall","canBreak":true,"animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{}}},
"121": {"cls":"npcs","id":"man"},
"122": {"cls":"npcs","id":"trader"},
"123": {"cls":"npcs","id":"thief"},
@@ -217,12 +217,12 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"316": {"cls":"terrains","id":"sWallTLR","name":"薄墙-上左右","cannotOut":["up","left","right"],"cannotIn":["up","left","right"]},
"317": {"cls":"terrains","id":"sWallTBR","name":"薄墙-上下右","cannotOut":["up","down","right"],"cannotIn":["up","down","right"]},
"318": {"cls":"terrains","id":"sWallTBL","name":"薄墙-上下左","cannotOut":["up","down","left"],"cannotIn":["up","down","left"]},
- "319": {"cls":"npc48","id":"tallYellowDoor","trigger":"openDoor","name":"高黄门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"yellowKey":1}}},
- "320": {"cls":"npc48","id":"tallBlueDoor","trigger":"openDoor","name":"高蓝门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"blueKey":1}}},
- "321": {"cls":"npc48","id":"tallRedDoor","trigger":"openDoor","name":"高红门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"redKey":1}}},
- "322": {"cls":"npc48","id":"tallGreenDoor","trigger":"openDoor","name":"高绿门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"greenKey":1}}},
- "323": {"cls":"npc48","id":"tallSpecialDoor","trigger":"openDoor","name":"高机关门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"specialKey":1}}},
- "324": {"cls":"npc48","id":"tallSteelDoor","trigger":"openDoor","name":"高铁门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"steelKey":1}}},
+ "319": {"cls":"npc48","id":"tallYellowDoor","trigger":"openDoor","name":"高黄门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"yellowKey":1}}},
+ "320": {"cls":"npc48","id":"tallBlueDoor","trigger":"openDoor","name":"高蓝门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"blueKey":1}}},
+ "321": {"cls":"npc48","id":"tallRedDoor","trigger":"openDoor","name":"高红门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"redKey":1}}},
+ "322": {"cls":"npc48","id":"tallGreenDoor","trigger":"openDoor","name":"高绿门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"greenKey":1}}},
+ "323": {"cls":"npc48","id":"tallSpecialDoor","trigger":"openDoor","name":"高机关门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"specialKey":1}}},
+ "324": {"cls":"npc48","id":"tallSteelDoor","trigger":"openDoor","name":"高铁门","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.opus","keys":{"steelKey":1}}},
"325": {"cls":"enemys","id":"keiskeiFairy"},
"326": {"cls":"enemys","id":"tulipFairy"},
"327": {"cls":"enemy48","id":"bearDown"},
diff --git a/project/plugins.js b/project/plugins.js
index 317ee03..009ae14 100644
--- a/project/plugins.js
+++ b/project/plugins.js
@@ -4196,278 +4196,279 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
}
},
"编辑器显伤": function () {
- // 在此增加新插件
- /////// 用户设置 ///////
- // 将__enable置为false将关闭插件
- var __enable = true;
- // 魔防攻速之类的属性可以在这里加 ['atk', 'def', 'mdef']
- var heroStatus = ["atk", "def", "mdef", "hp"];
- // saveHero为true 将会把每次造塔测试时的角色数据存下来 否则会读取初始属性
- // 用不着可以关了 节约缓存空间 (虽然根本没多少 还没一个存档大
- // 也可以手动清理 控制台输入core.removeLocalStorage('editorHero')即可
- var saveHero = true;
+ // 在此增加新插件
+ /////// 用户设置 ///////
+ // 将__enable置为false将关闭插件
+ var __enable = true;
+ // 魔防攻速之类的属性可以在这里加 ['atk', 'def', 'mdef']
+ var heroStatus = ["atk", "def", "mdef", "hp"];
+ // saveHero为true 将会把每次造塔测试时的角色数据存下来 否则会读取初始属性
+ // 用不着可以关了 节约缓存空间 (虽然根本没多少 还没一个存档大
+ // 也可以手动清理 控制台输入core.removeLocalStorage('editorHero')即可
+ var saveHero = true;
- // 下为具体实现 懒得写注释了 大概就是写HTML然后注册交互
- if (!__enable || main.mode != "editor") return;
- core.plugin.initEditorDamage = false;
- if (heroStatus.length >= 4 && !editor.isMobile)
- editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + "px";
- editor.statusRatio = core.getLocalStorage("statusRatio", 1);
- editor.saveHero = saveHero;
- editor._heroStatus = heroStatus;
- editor.dom.mapEdit.appendChild(core.canvas.damage.canvas);
- var HTML =
- "";
+ // 下为具体实现 懒得写注释了 大概就是写HTML然后注册交互
+ if (!__enable || main.mode != "editor") return;
+ core.plugin.initEditorDamage = false;
+ if (heroStatus.length >= 4 && !editor.isMobile)
+ editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + "px";
+ editor.statusRatio = core.getLocalStorage("statusRatio", 1);
+ editor.saveHero = saveHero;
+ editor._heroStatus = heroStatus;
+ editor.dom.mapEdit.appendChild(core.canvas.damage.canvas);
+ var HTML =
+ "";
- //if (heroStatus.length >= 4 && !editor.isMobile) editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + 'px';
- heroStatus.forEach(function (status) {
- var id = status + "set",
- id2 = status + "add",
- id3 = status + "rec",
- id4 = status + "help";
- HTML +=
- "
";
- });
- document.getElementById("viewportButtons").innerHTML = HTML;
- ["set", "add", "rec", "help"].forEach(function (e) {
- heroStatus.forEach(function (status) {
- editor.dom[status + e] = document.getElementById(status + e);
- });
- });
- var _hasItem = core.items.hasItem;
- core.items.hasItem = function (itemId) {
- if (itemId == "book" && main.mode == "editor") return true;
- return _hasItem.call(core.items, itemId);
- };
- if (main.mode == "editor") {
- var applyList = [
- "getDamageString",
- "nextCriticals",
- "getEnemyInfo",
- "getEnemyValue",
- ];
- applyList.forEach(function (name) {
- var func = core.enemys[name];
- core.enemys[name] = function () {
- var args =
- arguments.length === 1 ? [arguments[0]] :
- Array.apply(null, arguments);
- if (typeof args[0] == "string") args[0] = core.enemys.enemys[args[0]];
- return func.apply(core.enemys, args);
- };
- });
- }
+ //if (heroStatus.length >= 4 && !editor.isMobile) editor.dom.mid2.style.top = 650 + 30 * (heroStatus.length - 3) + 'px';
+ heroStatus.forEach(function (status) {
+ var id = status + "set",
+ id2 = status + "add",
+ id3 = status + "rec",
+ id4 = status + "help";
+ HTML +=
+ "
";
+ });
+ document.getElementById("viewportButtons").innerHTML = HTML;
+ ["set", "add", "rec", "help"].forEach(function (e) {
+ heroStatus.forEach(function (status) {
+ editor.dom[status + e] = document.getElementById(status + e);
+ });
+ });
+ var _hasItem = core.items.hasItem;
+ core.items.hasItem = function (itemId) {
+ if (itemId == "book" && main.mode == "editor") return true;
+ return _hasItem.call(core.items, itemId);
+ };
+ if (main.mode == "editor") {
+ var applyList = [
+ "getDamageString",
+ "nextCriticals",
+ "getEnemyInfo",
+ "getEnemyValue",
+ ];
+ applyList.forEach(function (name) {
+ var func = core.enemys[name];
+ core.enemys[name] = function () {
+ var args =
+ arguments.length === 1
+ ? [arguments[0]]
+ : Array.apply(null, arguments);
+ if (typeof args[0] == "string") args[0] = core.enemys.enemys[args[0]];
+ return func.apply(core.enemys, args);
+ };
+ });
+ }
- ////// 获得勇士属性 //////
- core.control.getStatus = function (name) {
- if (!core.status.hero) return null;
- if (name == "x" || name == "y" || name == "direction")
- return this.getHeroLoc(name);
- /*if ( main.mode == 'editor' && !core.hasFlag('__statistics__')) {
+ ////// 获得勇士属性 //////
+ core.control.getStatus = function (name) {
+ if (!core.status.hero) return null;
+ if (name == "x" || name == "y" || name == "direction")
+ return this.getHeroLoc(name);
+ /*if ( main.mode == 'editor' && !core.hasFlag('__statistics__')) {
return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero[name];
}*/
- return core.status.hero[name];
- };
+ return core.status.hero[name];
+ };
- core.control.updateDamage = function (floorId, ctx) {
- floorId = floorId || core.status.floorId;
- if (!floorId || core.status.gameOver) return;
- var onMap = ctx == null;
- if (main.mode == "editor") {
- ctx = core.canvas.damage;
- core.updateCheckBlock();
- core.clearMap(ctx);
- if (editor.uivalues.bigmap) return;
- }
+ core.control.updateDamage = function (floorId, ctx) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId || core.status.gameOver) return;
+ var onMap = ctx == null;
+ if (main.mode == "editor") {
+ ctx = core.canvas.damage;
+ core.updateCheckBlock();
+ core.clearMap(ctx);
+ if (editor.uivalues.bigmap) return;
+ }
- // 没有怪物手册
- if (!core.hasItem("book")) return;
- core.status.damage.posX = core.bigmap.posX;
- core.status.damage.posY = core.bigmap.posY;
- if (!onMap) {
- var width = core.floors[floorId].width,
- height = core.floors[floorId].height;
- // 地图过大的缩略图不绘制显伤
- if (width * height > core.bigmap.threshold) return;
- }
- this._updateDamage_damage(floorId, onMap);
- this._updateDamage_extraDamage(floorId, onMap);
- this.drawDamage(ctx);
- };
+ // 没有怪物手册
+ if (!core.hasItem("book")) return;
+ core.status.damage.posX = core.bigmap.posX;
+ core.status.damage.posY = core.bigmap.posY;
+ if (!onMap) {
+ var width = core.floors[floorId].width,
+ height = core.floors[floorId].height;
+ // 地图过大的缩略图不绘制显伤
+ if (width * height > core.bigmap.threshold) return;
+ }
+ this._updateDamage_damage(floorId, onMap);
+ this._updateDamage_extraDamage(floorId, onMap);
+ this.drawDamage(ctx);
+ };
- core.control.drawDamage = function (ctx) {
- if (
- core.status.gameOver ||
- !core.status.damage /* || main.mode != 'play'*/
- )
- return;
- var onMap = false;
- if (ctx == null) {
- ctx = core.canvas.damage;
- core.clearMap("damage");
- onMap = true;
- }
+ core.control.drawDamage = function (ctx) {
+ if (
+ core.status.gameOver ||
+ !core.status.damage /* || main.mode != 'play'*/
+ )
+ return;
+ var onMap = false;
+ if (ctx == null) {
+ ctx = core.canvas.damage;
+ core.clearMap("damage");
+ onMap = true;
+ }
- if (onMap && core.bigmap.v2) {
- // 检查是否需要重算...
- if (
- Math.abs(core.bigmap.posX - core.status.damage.posX) >=
- core.bigmap.extend - 1 ||
- Math.abs(core.bigmap.posY - core.status.damage.posY) >=
- core.bigmap.extend - 1
- ) {
- return this.updateDamage();
- }
- }
- return this._drawDamage_draw(ctx, onMap);
- };
+ if (onMap && core.bigmap.v2) {
+ // 检查是否需要重算...
+ if (
+ Math.abs(core.bigmap.posX - core.status.damage.posX) >=
+ core.bigmap.extend - 1 ||
+ Math.abs(core.bigmap.posY - core.status.damage.posY) >=
+ core.bigmap.extend - 1
+ ) {
+ return this.updateDamage();
+ }
+ }
+ return this._drawDamage_draw(ctx, onMap);
+ };
- ////// 以x,y的形式返回每个点的事件 //////
- core.maps.getMapBlocksObj = function (floorId, noCache) {
- floorId = floorId || core.status.floorId;
- if (
- core.status.mapBlockObjs[floorId] &&
- !noCache &&
- main.mode != "editor"
- )
- return core.status.mapBlockObjs[floorId];
+ ////// 以x,y的形式返回每个点的事件 //////
+ core.maps.getMapBlocksObj = function (floorId, noCache) {
+ floorId = floorId || core.status.floorId;
+ if (
+ core.status.mapBlockObjs[floorId] &&
+ !noCache &&
+ main.mode != "editor"
+ )
+ return core.status.mapBlockObjs[floorId];
- var obj = {};
- core.extractBlocks(floorId);
- core.status.maps[floorId].blocks.forEach(function (block) {
- obj[block.x + "," + block.y] = block;
- });
- core.status.mapBlockObjs[floorId] = obj;
- return obj;
- };
+ var obj = {};
+ core.extractBlocks(floorId);
+ core.status.maps[floorId].blocks.forEach(function (block) {
+ obj[block.x + "," + block.y] = block;
+ });
+ core.status.mapBlockObjs[floorId] = obj;
+ return obj;
+ };
- this.bignum = function (num, defaultValue) {
- if (num == null || num == "") return defaultValue;
- num = num + "";
- var list = {
- w: 1e4,
- e: 1e8,
- z: 1e12,
- j: 1e16,
- g: 1e20,
- };
- // 浮点数问题
- function checkFloat(num) {
- if (!core.isset(num)) return 0;
- num = num + "";
- var index = num.indexOf(".");
- if (index < 0) return 0;
- else return num.slice(index + 1).length;
- }
- var index = num.search(/w|e|z|j|g/);
- if (index <= 0) {
- num = parseInt(num);
- if (core.isset(num)) return num;
- else {
- alert("不正确的输入");
- return defaultValue;
- }
- }
- for (; index > 0; index = num.search(/w|e|z|j|g/)) {
- var p = num[index],
- q = list[p],
- n = num.slice(0, index),
- m = Math.pow(10, checkFloat(n));
- num = (n * m * q) / m + num.slice(index + 1);
- }
- return parseInt(num);
- };
+ this.bignum = function (num, defaultValue) {
+ if (num == null || num == "") return defaultValue;
+ num = num + "";
+ var list = {
+ w: 1e4,
+ e: 1e8,
+ z: 1e12,
+ j: 1e16,
+ g: 1e20,
+ };
+ // 浮点数问题
+ function checkFloat(num) {
+ if (!core.isset(num)) return 0;
+ num = num + "";
+ var index = num.indexOf(".");
+ if (index < 0) return 0;
+ else return num.slice(index + 1).length;
+ }
+ var index = num.search(/w|e|z|j|g/);
+ if (index <= 0) {
+ num = parseInt(num);
+ if (core.isset(num)) return num;
+ else {
+ alert("不正确的输入");
+ return defaultValue;
+ }
+ }
+ for (; index > 0; index = num.search(/w|e|z|j|g/)) {
+ var p = num[index],
+ q = list[p],
+ n = num.slice(0, index),
+ m = Math.pow(10, checkFloat(n));
+ num = (n * m * q) / m + num.slice(index + 1);
+ }
+ return parseInt(num);
+ };
- this.updateEditorDamage = function (noSave) {
- core.updateDamage();
- heroStatus.forEach(function (status) {
- editor.dom[status + "set"].value = core.status.hero[status];
- });
- if (!noSave && editor.saveHero)
- core.setLocalStorage("editorHero", core.status.hero);
- };
+ this.updateEditorDamage = function (noSave) {
+ core.updateDamage();
+ heroStatus.forEach(function (status) {
+ editor.dom[status + "set"].value = core.status.hero[status];
+ });
+ if (!noSave && editor.saveHero)
+ core.setLocalStorage("editorHero", core.status.hero);
+ };
- var _resizeMap = core.maps.resizeMap;
- core.maps.resizeMap = function (floorId) {
- _resizeMap.call(core.maps, floorId);
- if (!core.plugin.initEditorDamage && main.mode == "editor") {
- core.plugin.initEditorDamage = true;
- var editorHero = core.getLocalStorage("editorHero");
- if (editorHero && saveHero) core.status.hero = editorHero;
- else core.removeLocalStorage("editorHero");
- editor._heroStatus.forEach(function (e) {
- editor.dom[e + "set"].onchange = function () {
- var status = this.id.slice(0, -3);
- core.status.hero[status] = core.bignum(
- this.value,
- core.status.hero[status]
- );
- core.updateEditorDamage();
- };
- editor.dom[e + "add"].onclick = function () {
- var status = this.id.slice(0, -3);
- core.status.hero[status] += editor.statusRatio;
- core.updateEditorDamage();
- };
- editor.dom[e + "rec"].onclick = function () {
- var status = this.id.slice(0, -3);
- core.status.hero[status] -= editor.statusRatio;
- core.updateEditorDamage();
- };
- editor.dom[e + "help"].onclick = function () {
- var status = this.id.slice(0, -4),
- name = core.getStatusLabel(status);
- var ratio = parseInt(
- prompt(
- "当前属性:" +
- name +
- "\n现在的点击按钮变化值:" +
- editor.statusRatio +
- ",请输入按下一次+/-按钮的属性变化量,可以写4w 10.2e这种字母缩写"
- )
- );
- if (!core.isset(ratio)) {
- printe("不合法的输入");
- return;
- }
- editor.statusRatio = ratio;
- core.setLocalStorage("statusRatio", ratio);
- };
- });
- var _updateMap = editor.updateMap;
- editor.updateMap = function () {
- _updateMap.call(editor);
- core.updateEditorDamage(true);
- };
- editor.mode.onmode = function (mode, callback) {
- if (editor_mode.mode != mode) {
- if (mode === "save") {
- editor_mode.doActionList(
- editor_mode.mode,
- editor_mode.actionList,
- function () {
- if (callback) callback();
- core.updateEditorDamage();
- }
- );
- }
- if (editor_mode.mode === "nextChange" && mode)
- editor_mode.showMode(mode);
- if (mode !== "save") editor_mode.mode = mode;
- editor_mode.actionList = [];
- }
- };
- }
- };
-},
+ var _resizeMap = core.maps.resizeMap;
+ core.maps.resizeMap = function (floorId) {
+ _resizeMap.call(core.maps, floorId);
+ if (!core.plugin.initEditorDamage && main.mode == "editor") {
+ core.plugin.initEditorDamage = true;
+ var editorHero = core.getLocalStorage("editorHero");
+ if (editorHero && saveHero) core.status.hero = editorHero;
+ else core.removeLocalStorage("editorHero");
+ editor._heroStatus.forEach(function (e) {
+ editor.dom[e + "set"].onchange = function () {
+ var status = this.id.slice(0, -3);
+ core.status.hero[status] = core.bignum(
+ this.value,
+ core.status.hero[status]
+ );
+ core.updateEditorDamage();
+ };
+ editor.dom[e + "add"].onclick = function () {
+ var status = this.id.slice(0, -3);
+ core.status.hero[status] += editor.statusRatio;
+ core.updateEditorDamage();
+ };
+ editor.dom[e + "rec"].onclick = function () {
+ var status = this.id.slice(0, -3);
+ core.status.hero[status] -= editor.statusRatio;
+ core.updateEditorDamage();
+ };
+ editor.dom[e + "help"].onclick = function () {
+ var status = this.id.slice(0, -4),
+ name = core.getStatusLabel(status);
+ var ratio = parseInt(
+ prompt(
+ "当前属性:" +
+ name +
+ "\n现在的点击按钮变化值:" +
+ editor.statusRatio +
+ ",请输入按下一次+/-按钮的属性变化量,可以写4w 10.2e这种字母缩写"
+ )
+ );
+ if (!core.isset(ratio)) {
+ printe("不合法的输入");
+ return;
+ }
+ editor.statusRatio = ratio;
+ core.setLocalStorage("statusRatio", ratio);
+ };
+ });
+ var _updateMap = editor.updateMap;
+ editor.updateMap = function () {
+ _updateMap.call(editor);
+ core.updateEditorDamage(true);
+ };
+ editor.mode.onmode = function (mode, callback) {
+ if (editor_mode.mode != mode) {
+ if (mode === "save") {
+ editor_mode.doActionList(
+ editor_mode.mode,
+ editor_mode.actionList,
+ function () {
+ if (callback) callback();
+ core.updateEditorDamage();
+ }
+ );
+ }
+ if (editor_mode.mode === "nextChange" && mode)
+ editor_mode.showMode(mode);
+ if (mode !== "save") editor_mode.mode = mode;
+ editor_mode.actionList = [];
+ }
+ };
+ }
+ };
+ },
"手册区分特殊属性": function () {
// 在此增加新插件
this.arrsame = function (Arraya, Arrayb) {
@@ -8447,6 +8448,2106 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
}
};
},
+ "音频系统": function () {
+ // 在此增加新插件
+ /*首先,在造塔群下载所需的库文件,然后放置在塔目录下的 libs/thirdparty 或其他目录下,之后在 index.html 的最后加上下面这几行:
+
+
+
+
+
+
+ */
+ // 将__enable置为false将关闭插件
+ let __enable = true;
+ if (!__enable || main.mode === "editor") return;
+ const { OggOpusDecoderWebWorker } = window["ogg-opus-decoder"];
+ const { OggVorbisDecoderWebWorker } = window["ogg-vorbis-decoder"];
+ const { CodecParser } = window.CodecParser;
+ const { Transition, linear } = core.plugin.animate;
+
+ const audio = new Audio();
+ const AudioStatus = {
+ Playing: 0,
+ Pausing: 1,
+ Paused: 2,
+ Stoping: 3,
+ Stoped: 4,
+ };
+ const supportMap = new Map();
+ const AudioType = {
+ Mp3: "audio/mpeg",
+ Wav: 'audio/wav; codecs="1"',
+ Flac: "audio/flac",
+ Opus: 'audio/ogg; codecs="opus"',
+ Ogg: 'audio/ogg; codecs="vorbis"',
+ Aac: "audio/aac",
+ };
+ /**
+ * 检查一种音频类型是否能被播放
+ * @param type 音频类型 AudioType
+ */
+ function isAudioSupport(type) {
+ if (supportMap.has(type)) return supportMap.get(type);
+ else {
+ const support = audio.canPlayType(type);
+ const canPlay = support === "maybe" || support === "probably";
+ supportMap.set(type, canPlay);
+ return canPlay;
+ }
+ }
+
+ const typeMap = new Map([
+ ["ogg", AudioType.Ogg],
+ ["mp3", AudioType.Mp3],
+ ["wav", AudioType.Wav],
+ ["flac", AudioType.Flac],
+ ["opus", AudioType.Opus],
+ ["aac", AudioType.Aac],
+ ]);
+
+ /**
+ * 根据文件名拓展猜测其类型
+ * @param file 文件名 string
+ */
+ function guessTypeByExt(file) {
+ const ext = /\.[a-zA-Z\d]+$/.exec(file);
+ if (!ext?.[0]) return "";
+ const type = ext[0].slice(1);
+ return typeMap.get(type.toLocaleLowerCase()) ?? "";
+ }
+
+ isAudioSupport(AudioType.Ogg);
+ isAudioSupport(AudioType.Mp3);
+ isAudioSupport(AudioType.Wav);
+ isAudioSupport(AudioType.Flac);
+ isAudioSupport(AudioType.Opus);
+ isAudioSupport(AudioType.Aac);
+
+ function isNil(value) {
+ return value === void 0 || value === null;
+ }
+
+ function sleep(time) {
+ return new Promise((res) => setTimeout(res, time));
+ }
+ class AudioEffect {
+ constructor(ac) {}
+ /**
+ * 连接至其他效果器
+ * @param target 目标输入 IAudioInput
+ * @param output 当前效果器输出通道 Number
+ * @param input 目标效果器的输入通道 Number
+ */
+ connect(target, output, input) {
+ this.output.connect(target.input, output, input);
+ }
+
+ /**
+ * 与其他效果器取消连接
+ * @param target 目标输入 IAudioInput
+ * @param output 当前效果器输出通道 Number
+ * @param input 目标效果器的输入通道 Number
+ */
+ disconnect(target, output, input) {
+ if (!target) {
+ if (!isNil(output)) {
+ this.output.disconnect(output);
+ } else {
+ this.output.disconnect();
+ }
+ } else {
+ if (!isNil(output)) {
+ if (!isNil(input)) {
+ this.output.disconnect(target.input, output, input);
+ } else {
+ this.output.disconnect(target.input, output);
+ }
+ } else {
+ this.output.disconnect(target.input);
+ }
+ }
+ }
+ }
+
+ class StereoEffect extends AudioEffect {
+ constructor(ac) {
+ super(ac);
+ const panner = ac.createPanner();
+ this.input = panner;
+ this.output = panner;
+ }
+
+ /**
+ * 设置音频朝向,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户
+ * @param x 朝向x坐标 Number
+ * @param y 朝向y坐标 Number
+ * @param z 朝向z坐标 Number
+ */
+ setOrientation(x, y, z) {
+ this.output.orientationX.value = x;
+ this.output.orientationY.value = y;
+ this.output.orientationZ.value = z;
+ }
+ /**
+ * 设置音频位置,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户
+ * @param x 位置x坐标 Number
+ * @param y 位置y坐标 Number
+ * @param z 位置z坐标 Number
+ */
+ setPosition(x, y, z) {
+ this.output.positionX.value = x;
+ this.output.positionY.value = y;
+ this.output.positionZ.value = z;
+ }
+ end() {}
+
+ start() {}
+ }
+ class VolumeEffect extends AudioEffect {
+ constructor(ac) {
+ super(ac);
+ const gain = ac.createGain();
+ this.input = gain;
+ this.output = gain;
+ }
+
+ /**
+ * 设置音量大小
+ * @param volume 音量大小 Number
+ */
+ setVolume(volume) {
+ this.output.gain.value = volume;
+ }
+
+ /**
+ * 获取音量大小 Number
+ */
+ getVolume() {
+ return this.output.gain.value;
+ }
+
+ end() {}
+
+ start() {}
+ }
+ class ChannelVolumeEffect extends AudioEffect {
+ /** 所有的音量控制节点 */
+
+ constructor(ac) {
+ super(ac);
+ /** 所有的音量控制节点 */
+ this.gain = [];
+ const splitter = ac.createChannelSplitter();
+ const merger = ac.createChannelMerger();
+ this.output = merger;
+ this.input = splitter;
+ for (let i = 0; i < 6; i++) {
+ const gain = ac.createGain();
+ splitter.connect(gain, i);
+ gain.connect(merger, 0, i);
+ this.gain.push(gain);
+ }
+ }
+
+ /**
+ * 设置某个声道的音量大小
+ * @param channel 要设置的声道,可填0-5 Number
+ * @param volume 这个声道的音量大小 Number
+ */
+ setVolume(channel, volume) {
+ if (!this.gain[channel]) return;
+ this.gain[channel].gain.value = volume;
+ }
+
+ /**
+ * 获取某个声道的音量大小,可填0-5
+ * @param channel 要获取的声道 Number
+ */
+ getVolume(channel) {
+ if (!this.gain[channel]) return 0;
+ return this.gain[channel].gain.value;
+ }
+
+ end() {}
+
+ start() {}
+ }
+ class DelayEffect extends AudioEffect {
+ constructor(ac) {
+ super(ac);
+
+ const delay = ac.createDelay();
+ this.input = delay;
+ this.output = delay;
+ }
+
+ /**
+ * 设置延迟时长
+ * @param delay 延迟时长,单位秒 Number
+ */
+ setDelay(delay) {
+ this.output.delayTime.value = delay;
+ }
+
+ /**
+ * 获取延迟时长
+ */
+ getDelay() {
+ return this.output.delayTime.value;
+ }
+
+ end() {}
+
+ start() {}
+ }
+ class EchoEffect extends AudioEffect {
+ constructor(ac) {
+ super(ac);
+ /** 当前增益 */
+ this.gain = 0.5;
+ /** 是否正在播放 */
+ this.playing = false;
+ const delay = ac.createDelay();
+ const gain = ac.createGain();
+ gain.gain.value = 0.5;
+ delay.delayTime.value = 0.05;
+ delay.connect(gain);
+ gain.connect(delay);
+ /** 延迟节点 */
+ this.delay = delay;
+ /** 反馈增益节点 */
+ this.gainNode = gain;
+
+ this.input = gain;
+ this.output = gain;
+ }
+
+ /**
+ * 设置回声反馈增益大小
+ * @param gain 增益大小,范围 0-1,大于等于1的视为0.5,小于0的视为0 Number
+ */
+ setFeedbackGain(gain) {
+ const resolved = gain >= 1 ? 0.5 : gain < 0 ? 0 : gain;
+ this.gain = resolved;
+ if (this.playing) this.gainNode.gain.value = resolved;
+ }
+
+ /**
+ * 设置回声间隔时长
+ * @param delay 回声时长,范围 0.01-Infinity,小于0.01的视为0.01 Number
+ */
+ setEchoDelay(delay) {
+ const resolved = delay < 0.01 ? 0.01 : delay;
+ this.delay.delayTime.value = resolved;
+ }
+
+ /**
+ * 获取反馈节点增益
+ */
+ getFeedbackGain() {
+ return this.gain;
+ }
+
+ /**
+ * 获取回声间隔时长
+ */
+ getEchoDelay() {
+ return this.delay.delayTime.value;
+ }
+
+ end() {
+ this.playing = false;
+ const echoTime = Math.ceil(Math.log(0.001) / Math.log(this.gain)) + 10;
+ sleep(this.delay.delayTime.value * echoTime).then(() => {
+ if (!this.playing) this.gainNode.gain.value = 0;
+ });
+ }
+
+ start() {
+ this.playing = true;
+ this.gainNode.gain.value = this.gain;
+ }
+ }
+
+ class StreamLoader {
+ constructor(url) {
+ /** 传输目标 Set*/
+ this.target = new Set();
+ this.loading = false;
+ }
+
+ /**
+ * 将加载流传递给字节流读取对象
+ * @param reader 字节流读取对象 IStreamReader
+ */
+ pipe(reader) {
+ if (this.loading) {
+ console.warn(
+ "Cannot pipe new StreamReader object when stream is loading."
+ );
+ return;
+ }
+ this.target.add(reader);
+ reader.piped(this);
+ return this;
+ }
+
+ async start() {
+ if (this.loading) return;
+ this.loading = true;
+ const response = await window.fetch(this.url);
+ const stream = response.body;
+ if (!stream) {
+ console.error("Cannot get reader when fetching '" + this.url + "'.");
+ return;
+ }
+ // 获取读取器
+ /** 读取流对象 */
+ this.stream = stream;
+ const reader = response.body?.getReader();
+ const targets = [...this.target];
+
+ await Promise.all(targets.map((v) => v.start(stream, this, response)));
+ if (reader && reader.read) {
+ // 开始流传输
+ while (true) {
+ const { value, done } = await reader.read();
+ await Promise.all(
+ targets.map((v) => v.pump(value, done, response))
+ );
+ if (done) break;
+ }
+ } else {
+ // 如果不支持流传输
+ const buffer = await response.arrayBuffer();
+ const data = new Uint8Array(buffer);
+ await Promise.all(targets.map((v) => v.pump(data, true, response)));
+ }
+ // 开始流传输
+ while (true) {
+ const { value, done } = await reader.read();
+ await Promise.all(targets.map((v) => v.pump(value, done, response)));
+ if (done) break;
+ }
+
+ this.loading = false;
+ targets.forEach((v) => v.end(true));
+
+ //
+ }
+
+ cancel(reason) {
+ if (!this.stream) return;
+ this.stream.cancel(reason);
+ this.loading = false;
+ this.target.forEach((v) => v.end(false, reason));
+ }
+ }
+ const fileSignatures = [
+ [AudioType.Mp3, [0x49, 0x44, 0x33]],
+ [AudioType.Ogg, [0x4f, 0x67, 0x67, 0x53]],
+ [AudioType.Wav, [0x52, 0x49, 0x46, 0x46]],
+ [AudioType.Flac, [0x66, 0x4c, 0x61, 0x43]],
+ [AudioType.Aac, [0xff, 0xf1]],
+ [AudioType.Aac, [0xff, 0xf9]],
+ ];
+ const oggHeaders = [
+ [AudioType.Opus, [0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]],
+ ];
+
+ function checkAudioType(data) {
+ let audioType = "";
+ // 检查头文件获取音频类型,仅检查前256个字节
+ const toCheck = data.slice(0, 256);
+ for (const [type, value] of fileSignatures) {
+ if (value.every((v, i) => toCheck[i] === v)) {
+ audioType = type;
+ break;
+ }
+ }
+ if (audioType === AudioType.Ogg) {
+ // 如果是ogg的话,进一步判断是不是opus
+ for (const [key, value] of oggHeaders) {
+ const has = toCheck.some((_, i) => {
+ return value.every((v, ii) => toCheck[i + ii] === v);
+ });
+ if (has) {
+ audioType = key;
+ break;
+ }
+ }
+ }
+
+ return audioType;
+ }
+ class AudioDecoder {
+ /**
+ * 注册一个解码器
+ * @param type 要注册的解码器允许解码的类型
+ * @param decoder 解码器对象
+ */
+ static registerDecoder(type, decoder) {
+ if (!this.decoderMap) this.decoderMap = new Map();
+ if (this.decoderMap.has(type)) {
+ console.warn(
+ "Audio stream decoder for audio type '" +
+ type +
+ "' has already existed."
+ );
+ return;
+ }
+
+ this.decoderMap.set(type, decoder);
+ }
+
+ /**
+ * 解码音频数据
+ * @param data 音频文件数据
+ * @param player AudioPlayer实例
+ */
+ static async decodeAudioData(data, player) {
+ // 检查头文件获取音频类型,仅检查前256个字节
+ const toCheck = data.slice(0, 256);
+ const type = checkAudioType(data);
+ if (type === "") {
+ console.error(
+ "Unknown audio type. Header: '" + [...toCheck]
+ .map((v) => v.toString().padStart(2, "0"))
+ .join(" ")
+ .toUpperCase() +
+ "'"
+ );
+ return null;
+ }
+ if (isAudioSupport(type)) {
+ if (data.buffer instanceof ArrayBuffer) {
+ return player.ac.decodeAudioData(data.buffer);
+ } else {
+ return null;
+ }
+ } else {
+ const Decoder = this.decoderMap.get(type);
+ if (!Decoder) {
+ return null;
+ } else {
+ const decoder = new Decoder();
+ await decoder.create();
+ const decodedData = await decoder.decode(data);
+ if (!decodedData) return null;
+ const buffer = player.ac.createBuffer(
+ decodedData.channelData.length,
+ decodedData.channelData[0].length,
+ decodedData.sampleRate
+ );
+ decodedData.channelData.forEach((v, i) => {
+ buffer.copyToChannel(v, i);
+ });
+ decoder.destroy();
+ return buffer;
+ }
+ }
+ }
+ }
+
+ class VorbisDecoder {
+ /**
+ * 创建音频解码器
+ */
+ async create() {
+ this.decoder = new OggVorbisDecoderWebWorker();
+ await this.decoder.ready;
+ }
+ /**
+ * 摧毁这个解码器
+ */
+ destroy() {
+ this.decoder?.free();
+ }
+ /**
+ * 解码流数据
+ * @param data 流数据
+ */
+
+ async decode(data) {
+ return this.decoder?.decode(data);
+ }
+ /**
+ * 解码整个文件
+ * @param data 文件数据
+ */
+ async decodeAll(data) {
+ return this.decoder?.decodeFile(data);
+ }
+ /**
+ * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用
+ */
+ async flush() {
+ return this.decoder?.flush();
+ }
+ }
+
+ class OpusDecoder {
+ /**
+ * 创建音频解码器
+ */
+ async create() {
+ this.decoder = new OggOpusDecoderWebWorker();
+ await this.decoder.ready;
+ }
+ /**
+ * 摧毁这个解码器
+ */
+ destroy() {
+ this.decoder?.free();
+ }
+ /**
+ * 解码流数据
+ * @param data 流数据
+ */
+ async decode(data) {
+ return this.decoder?.decode(data);
+ }
+ /**
+ * 解码整个文件
+ * @param data 文件数据
+ */
+ async decodeAll(data) {
+ return this.decoder?.decodeFile(data);
+ }
+ /**
+ * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用
+ */
+ async flush() {
+ return await this.decoder?.flush();
+ }
+ }
+ const mimeTypeMap = {
+ [AudioType.Aac]: "audio/aac",
+ [AudioType.Flac]: "audio/flac",
+ [AudioType.Mp3]: "audio/mpeg",
+ [AudioType.Ogg]: "application/ogg",
+ [AudioType.Opus]: "application/ogg",
+ [AudioType.Wav]: "application/ogg",
+ };
+
+ function isOggPage(data) {
+ return !isNil(data.isFirstPage);
+ }
+ class AudioStreamSource {
+ constructor(context) {
+ this.output = context.createBufferSource();
+ /** 是否已经完全加载完毕 */
+ this.loaded = false;
+ /** 是否正在播放 */
+ this.playing = false;
+ /** 已经缓冲了多长时间,如果缓冲完那么跟歌曲时长一致 */
+ this.buffered = 0;
+ /** 已经缓冲的采样点数量 */
+ this.bufferedSamples = 0;
+ /** 歌曲时长,加载完毕之前保持为 0 */
+ this.duration = 0;
+ /** 在流传输阶段,至少缓冲多长时间的音频之后才开始播放,单位秒 */
+ this.bufferPlayDuration = 1;
+ /** 音频的采样率,未成功解析出之前保持为 0 */
+ this.sampleRate = 0;
+ //是否循环播放
+ this.loop = false;
+ /** 上一次播放是从何时开始的 */
+ this.lastStartWhen = 0;
+ /** 开始播放时刻 */
+ this.lastStartTime = 0;
+ /** 上一次播放的缓存长度 */
+ this.lastBufferSamples = 0;
+
+ /** 是否已经获取到头文件 */
+ this.headerRecieved = false;
+ /** 音频类型 */
+ this.audioType = "";
+ /** 每多长时间组成一个缓存 Float32Array */
+ this.bufferChunkSize = 10;
+ /** 缓存音频数据,每 bufferChunkSize 秒钟组成一个 Float32Array,用于流式解码 */
+ this.audioData = [];
+
+ this.errored = false;
+ this.ac = context;
+ }
+ /** 当前已经播放了多长时间 */
+ get currentTime() {
+ return this.ac.currentTime - this.lastStartTime + this.lastStartWhen;
+ }
+ /**
+ * 设置每个缓存数据的大小,默认为10秒钟一个缓存数据
+ * @param size 每个缓存数据的时长,单位秒
+ */
+ setChunkSize(size) {
+ if (this.controller?.loading || this.loaded) return;
+ this.bufferChunkSize = size;
+ }
+ on(event, fn, context) {}
+ piped(controller) {
+ this.controller = controller;
+ }
+
+ async pump(data, done) {
+ if (!data || this.errored) return;
+ if (!this.headerRecieved) {
+ // 检查头文件获取音频类型,仅检查前256个字节
+ const toCheck = data.slice(0, 256);
+ this.audioType = checkAudioType(data);
+ if (!this.audioType) {
+ console.error(
+ "Unknown audio type. Header: '" + [...toCheck]
+ .map((v) => v.toString(16).padStart(2, "0"))
+ .join(" ")
+ .toUpperCase() +
+ "'"
+ );
+ return;
+ }
+ // 创建解码器
+ const Decoder = AudioDecoder.decoderMap.get(this.audioType);
+ if (!Decoder) {
+ this.errored = true;
+ console.error(
+ "Cannot decode stream source type of '" +
+ this.audioType +
+ "', since there is no registered decoder for that type."
+ );
+ return Promise.reject(
+ `Cannot decode stream source type of '${this.audioType}', since there is no registered decoder for that type.`
+ );
+ }
+ this.decoder = new Decoder();
+ // 创建数据解析器
+ const mime = mimeTypeMap[this.audioType];
+ const parser = new CodecParser(mime);
+ this.parser = parser;
+ await this.decoder.create();
+ this.headerRecieved = true;
+ }
+
+ const decoder = this.decoder;
+ const parser = this.parser;
+ if (!decoder || !parser) {
+ this.errored = true;
+ return Promise.reject(
+ "No parser or decoder attached in this AudioStreamSource"
+ );
+ }
+
+ await this.decodeData(data, decoder, parser);
+ if (done) await this.decodeFlushData(decoder, parser);
+ this.checkBufferedPlay();
+ }
+
+ /**
+ * 检查采样率,如果还未解析出采样率,那么将设置采样率,如果当前采样率与之前不同,那么发出警告
+ */
+ checkSampleRate(info) {
+ for (const one of info) {
+ const frame = isOggPage(one) ? one.codecFrames[0] : one;
+ if (frame) {
+ const rate = frame.header.sampleRate;
+ if (this.sampleRate === 0) {
+ this.sampleRate = rate;
+ break;
+ } else {
+ if (rate !== this.sampleRate) {
+ console.warn("Sample rate in stream audio must be constant.");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 解析音频数据
+ */
+ async decodeData(data, decoder, parser) {
+ // 解析音频数据
+ const audioData = await decoder.decode(data);
+ if (!audioData) return;
+ // @ts-expect-error 库类型声明错误
+ const audioInfo = [...parser.parseChunk(data)];
+
+ // 检查采样率
+ this.checkSampleRate(audioInfo);
+ // 追加音频数据
+ this.appendDecodedData(audioData, audioInfo);
+ }
+
+ /**
+ * 解码剩余数据
+ */
+ async decodeFlushData(decoder, parser) {
+ const audioData = await decoder.flush();
+ if (!audioData) return;
+ // @ts-expect-error 库类型声明错误
+ const audioInfo = [...parser.flush()];
+
+ this.checkSampleRate(audioInfo);
+ this.appendDecodedData(audioData, audioInfo);
+ }
+
+ /**
+ * 追加音频数据
+ */
+ appendDecodedData(data, info) {
+ const channels = data.channelData.length;
+ if (channels === 0) return;
+ if (this.audioData.length !== channels) {
+ this.audioData = [];
+ for (let i = 0; i < channels; i++) {
+ this.audioData.push([]);
+ }
+ }
+ // 计算出应该放在哪
+ const chunk = this.sampleRate * this.bufferChunkSize;
+ const sampled = this.bufferedSamples;
+ const pushIndex = Math.floor(sampled / chunk);
+ const bufferIndex = sampled % chunk;
+ const dataLength = data.channelData[0].length;
+ let buffered = 0;
+ let nowIndex = pushIndex;
+ let toBuffer = bufferIndex;
+ while (buffered < dataLength) {
+ const rest = toBuffer !== 0 ? chunk - bufferIndex : chunk;
+
+ for (let i = 0; i < channels; i++) {
+ const audioData = this.audioData[i];
+ if (!audioData[nowIndex]) {
+ audioData.push(new Float32Array(chunk));
+ }
+ const toPush = data.channelData[i].slice(buffered, buffered + rest);
+
+ audioData[nowIndex].set(toPush, toBuffer);
+ }
+ buffered += rest;
+ nowIndex++;
+ toBuffer = 0;
+ }
+
+ this.buffered +=
+ info.reduce((prev, curr) => prev + curr.duration, 0) / 1000;
+ this.bufferedSamples += info.reduce(
+ (prev, curr) => prev + curr.samples,
+ 0
+ );
+ }
+
+ /**
+ * 检查已缓冲内容,并在未开始播放时播放
+ */
+ checkBufferedPlay() {
+ if (this.playing || this.sampleRate === 0) return;
+ const played = this.lastBufferSamples / this.sampleRate;
+ const dt = this.buffered - played;
+ if (this.loaded) {
+ this.playAudio(played);
+ return;
+ }
+ if (dt < this.bufferPlayDuration) return;
+
+ this.lastBufferSamples = this.bufferedSamples;
+ // 需要播放
+ this.mergeBuffers();
+ if (!this.buffer) return;
+ if (this.playing) this.output.stop();
+ this.createSourceNode(this.buffer);
+ this.output.loop = false;
+ this.output.start(0, played);
+ this.lastStartTime = this.ac.currentTime;
+ this.playing = true;
+ this.output.addEventListener("ended", () => {
+ this.playing = false;
+ this.checkBufferedPlay();
+ });
+ }
+
+ mergeBuffers() {
+ const buffer = this.ac.createBuffer(
+ this.audioData.length,
+ this.bufferedSamples,
+ this.sampleRate
+ );
+ const chunk = this.sampleRate * this.bufferChunkSize;
+ const bufferedChunks = Math.floor(this.bufferedSamples / chunk);
+ const restLength = this.bufferedSamples % chunk;
+ for (let i = 0; i < this.audioData.length; i++) {
+ const audio = this.audioData[i];
+ const data = new Float32Array(this.bufferedSamples);
+ for (let j = 0; j < bufferedChunks; j++) {
+ data.set(audio[j], chunk * j);
+ }
+ if (restLength !== 0) {
+ data.set(
+ audio[bufferedChunks].slice(0, restLength),
+ chunk * bufferedChunks
+ );
+ }
+
+ buffer.copyToChannel(data, i, 0);
+ }
+ this.buffer = buffer;
+ }
+
+ async start() {
+ delete this.buffer;
+ this.headerRecieved = false;
+ this.audioType = "";
+ this.errored = false;
+ this.buffered = 0;
+ this.sampleRate = 0;
+ this.bufferedSamples = 0;
+ this.duration = 0;
+ this.loaded = false;
+ if (this.playing) this.output.stop();
+ this.playing = false;
+ this.lastStartTime = this.ac.currentTime;
+ }
+
+ end(done, reason) {
+ if (done && this.buffer) {
+ this.loaded = true;
+ delete this.controller;
+ this.mergeBuffers();
+
+ this.duration = this.buffered;
+ this.audioData = [];
+ this.decoder?.destroy();
+ delete this.decoder;
+ delete this.parser;
+ } else {
+ console.warn(
+ "Unexpected end when loading stream audio, reason: '" +
+ (reason ?? "") +
+ "'"
+ );
+ }
+ }
+
+ playAudio(when) {
+ if (!this.buffer) return;
+ this.lastStartTime = this.ac.currentTime;
+ if (this.playing) this.output.stop();
+ if (this.player.status !== AudioStatus.Playing) {
+ this.player.status = AudioStatus.Playing;
+ }
+ this.createSourceNode(this.buffer);
+ this.output.start(0, when);
+ this.playing = true;
+
+ this.output.addEventListener("ended", () => {
+ this.playing = false;
+ if (this.player.status === AudioStatus.Playing) {
+ this.player.status = AudioStatus.Stoped;
+ }
+ if (this.loop && !this.output.loop) this.play(0);
+ });
+ }
+ /**
+ * 开始播放这个音频源
+ */
+ play(when) {
+ if (this.playing || this.errored) return;
+ if (this.loaded && this.buffer) {
+ this.playing = true;
+ this.playAudio(when);
+ } else {
+ this.controller?.start();
+ }
+ }
+
+ createSourceNode(buffer) {
+ if (!this.target) return;
+ const node = this.ac.createBufferSource();
+ node.buffer = buffer;
+ if (this.playing) this.output.stop();
+ this.playing = false;
+ this.output = node;
+ node.connect(this.target.input);
+ node.loop = this.loop;
+ }
+ /**
+ * 停止播放这个音频源
+ * @returns 音频暂停的时刻 number
+ */
+ stop() {
+ if (this.playing) this.output.stop();
+ this.playing = false;
+ return this.ac.currentTime - this.lastStartTime;
+ }
+ /**
+ * 连接到音频路由图上,每次调用播放的时候都会执行一次
+ * @param target 连接至的目标 IAudioInput
+ */
+ connect(target) {
+ this.target = target;
+ }
+ /**
+ * 设置是否循环播放
+ * @param loop 是否循环 boolean)
+ */
+ setLoop(loop) {
+ this.loop = loop;
+ }
+ }
+ class AudioElementSource {
+ constructor(context) {
+ const audio = new Audio();
+ audio.preload = "none";
+ this.output = context.createMediaElementSource(audio);
+ this.audio = audio;
+ this.ac = context;
+ audio.addEventListener("play", () => {
+ this.playing = true;
+ if (this.player.status !== AudioStatus.Playing) {
+ this.player.status = AudioStatus.Playing;
+ }
+ });
+ audio.addEventListener("ended", () => {
+ this.playing = false;
+ if (this.player.status === AudioStatus.Playing) {
+ this.player.status = AudioStatus.Stoped;
+ }
+ });
+ }
+ get duration() {
+ return this.audio.duration;
+ }
+ get currentTime() {
+ return this.audio.currentTime;
+ }
+ /**
+ * 设置音频源的路径
+ * @param url 音频路径
+ */
+ setSource(url) {
+ this.audio.src = url;
+ }
+
+ play(when = 0) {
+ if (this.playing) return;
+ this.audio.currentTime = when;
+ this.audio.play();
+ }
+
+ stop() {
+ this.audio.pause();
+ this.playing = false;
+ if (this.player.status === AudioStatus.Playing) {
+ this.player.status = AudioStatus.Stoped;
+ }
+ return this.audio.currentTime;
+ }
+
+ connect(target) {
+ this.output.connect(target.input);
+ }
+
+ setLoop(loop) {
+ this.audio.loop = loop;
+ }
+ }
+ class AudioBufferSource {
+ constructor(context) {
+ this.output = context.createBufferSource();
+ /** 是否循环 */
+ this.loop = false;
+ /** 上一次播放是从何时开始的 */
+ this.lastStartWhen = 0;
+ /** 播放开始时刻 */
+ this.lastStartTime = 0;
+ this.duration = 0;
+ this.ac = context;
+ }
+ get currentTime() {
+ return this.ac.currentTime - this.lastStartTime + this.lastStartWhen;
+ }
+
+ /**
+ * 设置音频源数据
+ * @param buffer 音频源,可以是未解析的 ArrayBuffer,也可以是已解析的 AudioBuffer
+ */
+ async setBuffer(buffer) {
+ if (buffer instanceof ArrayBuffer) {
+ this.buffer = await this.ac.decodeAudioData(buffer);
+ } else {
+ this.buffer = buffer;
+ }
+ this.duration = this.buffer.duration;
+ }
+
+ play(when) {
+ if (this.playing || !this.buffer) return;
+ this.playing = true;
+ this.lastStartTime = this.ac.currentTime;
+ if (this.player.status !== AudioStatus.Playing) {
+ this.player.status = AudioStatus.Playing;
+ }
+ this.createSourceNode(this.buffer);
+ this.output.start(0, when);
+ this.output.addEventListener("ended", () => {
+ this.playing = false;
+ if (this.player.status === AudioStatus.Playing) {
+ this.player.status = AudioStatus.Stoped;
+ }
+ if (this.loop && !this.output.loop) this.play(0);
+ });
+ }
+
+ createSourceNode(buffer) {
+ if (!this.target) return;
+ const node = this.ac.createBufferSource();
+ node.buffer = buffer;
+ this.output = node;
+ node.connect(this.target.input);
+ node.loop = this.loop;
+ }
+
+ stop() {
+ this.output.stop();
+ return this.ac.currentTime - this.lastStartTime;
+ }
+
+ connect(target) {
+ this.target = target;
+ }
+
+ setLoop(loop) {
+ this.loop = loop;
+ }
+ }
+ class AudioPlayer {
+ constructor() {
+ /** 音频播放上下文 */
+ this.ac = new AudioContext();
+ /** 音量节点 */
+ this.gain = this.ac.createGain();
+ this.gain.connect(this.ac.destination);
+ this.audioRoutes = new Map();
+ }
+ /**
+ * 解码音频数据
+ * @param data 音频数据
+ */
+ decodeAudioData(data) {
+ return AudioDecoder.decodeAudioData(data, this);
+ }
+ /**
+ * 设置音量
+ * @param volume 音量
+ */
+ setVolume(volume) {
+ this.gain.gain.value = volume;
+ }
+
+ /**
+ * 获取音量
+ */
+ getVolume() {
+ return this.gain.gain.value;
+ }
+
+ /**
+ * 创建一个音频源
+ * @param Source 音频源类
+ */
+ createSource(Source) {
+ return new Source(this.ac);
+ }
+
+ /**
+ * 创建一个兼容流式音频源,可以与流式加载相结合,主要用于处理 opus ogg 不兼容的情况
+ */
+ createStreamSource() {
+ return new AudioStreamSource(this.ac);
+ }
+
+ /**
+ * 创建一个通过 audio 元素播放的音频源
+ */
+ createElementSource() {
+ return new AudioElementSource(this.ac);
+ }
+
+ /**
+ * 创建一个通过 AudioBuffer 播放的音频源
+ */
+ createBufferSource() {
+ return new AudioBufferSource(this.ac);
+ }
+
+ /**
+ * 获取音频目的地
+ */
+ getDestination() {
+ return this.gain;
+ }
+
+ /**
+ * 创建一个音频效果器
+ * @param Effect 效果器类
+ */
+ createEffect(Effect) {
+ return new Effect(this.ac);
+ }
+
+ /**
+ * 创建一个修改音量的效果器
+ * ```txt
+ * |----------|
+ * Input ----> | GainNode | ----> Output
+ * |----------|
+ * ```
+ */
+ createVolumeEffect() {
+ return new VolumeEffect(this.ac);
+ }
+
+ /**
+ * 创建一个立体声效果器
+ * ```txt
+ * |------------|
+ * Input ----> | PannerNode | ----> Output
+ * |------------|
+ * ```
+ */
+ createStereoEffect() {
+ return new StereoEffect(this.ac);
+ }
+
+ /**
+ * 创建一个修改单个声道音量的效果器
+ * ```txt
+ * |----------|
+ * -> | GainNode | \
+ * |--------------| / |----------| -> |------------|
+ * Input ----> | SplitterNode | ...... | MergerNode | ----> Output
+ * |--------------| \ |----------| -> |------------|
+ * -> | GainNode | /
+ * |----------|
+ * ```
+ */
+ createChannelVolumeEffect() {
+ return new ChannelVolumeEffect(this.ac);
+ }
+
+ /**
+ * 创建一个延迟效果器
+ * |-----------|
+ * Input ----> | DelayNode | ----> Output
+ * |-----------|
+ */
+ createDelay() {
+ return new DelayEffect(this.ac);
+ }
+
+ /**
+ * 创建一个回声效果器
+ * ```txt
+ * |----------|
+ * Input ----> | GainNode | ----> Output
+ * ^ |----------| |
+ * | |
+ * | |------------| ↓
+ * |-- | Delay Node | <--
+ * |------------|
+ * ```
+ */
+ createEchoEffect() {
+ return new EchoEffect(this.ac);
+ }
+
+ /**
+ * 创建一个音频播放路由
+ * @param source 音频源
+ */
+ createRoute(source) {
+ return new AudioRoute(source, this);
+ }
+
+ /**
+ * 添加一个音频播放路由,可以直接被播放
+ * @param id 这个音频播放路由的名称
+ * @param route 音频播放路由对象
+ */
+ addRoute(id, route) {
+ if (!this.audioRoutes) this.audioRoutes = new Map();
+ if (this.audioRoutes.has(id)) {
+ console.warn(
+ "Audio route with id of '" +
+ id +
+ "' has already existed. New route will override old route."
+ );
+ }
+ this.audioRoutes.set(id, route);
+ }
+
+ /**
+ * 根据名称获取音频播放路由对象
+ * @param id 音频播放路由的名称
+ */
+ getRoute(id) {
+ return this.audioRoutes.get(id);
+ }
+ /**
+ * 移除一个音频播放路由
+ * @param id 要移除的播放路由的名称
+ */
+ removeRoute(id) {
+ this.audioRoutes.delete(id);
+ }
+ /**
+ * 播放音频
+ * @param id 音频名称
+ * @param when 从音频的哪个位置开始播放,单位秒
+ */
+ play(id, when) {
+ const route = this.getRoute(id);
+ if (!route) {
+ console.warn(
+ "Cannot play audio route '" +
+ id +
+ "', since there is not added route named it."
+ );
+ return;
+ }
+
+ route.play(when);
+ }
+
+ /**
+ * 暂停音频播放
+ * @param id 音频名称
+ * @returns 当音乐真正停止时兑现
+ */
+ pause(id) {
+ const route = this.getRoute(id);
+ if (!route) {
+ console.warn(
+ "Cannot pause audio route '" +
+ id +
+ "', since there is not added route named it."
+ );
+ return;
+ }
+ return route.pause();
+ }
+
+ /**
+ * 停止音频播放
+ * @param id 音频名称
+ * @returns 当音乐真正停止时兑现
+ */
+ stop(id) {
+ const route = this.getRoute(id);
+ if (!route) {
+ console.warn(
+ "Cannot stop audio route '" +
+ id +
+ "', since there is not added route named it."
+ );
+ return;
+ }
+ return route.stop();
+ }
+
+ /**
+ * 继续音频播放
+ * @param id 音频名称
+ */
+ resume(id) {
+ const route = this.getRoute(id);
+ if (!route) {
+ console.warn(
+ "Cannot pause audio route '" +
+ id +
+ "', since there is not added route named it."
+ );
+ return;
+ }
+ route.resume();
+ }
+
+ /**
+ * 设置听者位置,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
+ * @param x 位置x坐标
+ * @param y 位置y坐标
+ * @param z 位置z坐标
+ */
+ setListenerPosition(x, y, z) {
+ const listener = this.ac.listener;
+ listener.positionX.value = x;
+ listener.positionY.value = y;
+ listener.positionZ.value = z;
+ }
+
+ /**
+ * 设置听者朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
+ * @param x 朝向x坐标
+ * @param y 朝向y坐标
+ * @param z 朝向z坐标
+ */
+ setListenerOrientation(x, y, z) {
+ const listener = this.ac.listener;
+ listener.forwardX.value = x;
+ listener.forwardY.value = y;
+ listener.forwardZ.value = z;
+ }
+
+ /**
+ * 设置听者头顶朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
+ * @param x 头顶朝向x坐标
+ * @param y 头顶朝向y坐标
+ * @param z 头顶朝向z坐标
+ */
+ setListenerUp(x, y, z) {
+ const listener = this.ac.listener;
+ listener.upX.value = x;
+ listener.upY.value = y;
+ listener.upZ.value = z;
+ }
+ }
+ class AudioRoute {
+ constructor(source, player) {
+ this.output = source.output;
+
+ /** 效果器路由图 */
+ this.effectRoute = [];
+
+ /** 结束时长,当音频暂停或停止时,会经过这么长时间之后才真正终止播放,期间可以做音频淡入淡出等效果 */
+ this.endTime = 0;
+ /** 暂停时播放了多长时间 */
+ this.pauseCurrentTime = 0;
+ /** 当前播放状态 */
+ this.player = player;
+ this.player.status = AudioStatus.Stoped;
+ this.shouldStop = false;
+ /**
+ * 每次暂停或停止时自增,用于判断当前正在处理的情况。
+ * 假如暂停后很快播放,然后很快暂停,那么需要根据这个来判断实际是否应该执行暂停后操作
+ */
+ this.stopIdentifier = 0;
+ /** 暂停时刻 */
+ this.pauseTime = 0;
+ this.source = source;
+ this.source.player = player;
+ }
+ /** 音频时长,单位秒 */
+ get duration() {
+ return this.source.duration;
+ }
+ /** 当前播放了多长时间,单位秒 */
+ get currentTime() {
+ if (this.player.status === AudioStatus.Paused) {
+ return this.pauseCurrentTime;
+ } else {
+ return this.source.currentTime;
+ }
+ }
+ set currentTime(time) {
+ this.source.stop();
+ this.source.play(time);
+ }
+ /**
+ * 设置结束时间,暂停或停止时,会经过这么长时间才终止音频的播放,这期间可以做一下音频淡出的效果。
+ * @param time 暂停或停止时,经过多长时间之后才会结束音频的播放
+ */
+ setEndTime(time) {
+ this.endTime = time;
+ }
+
+ /**
+ * 当音频播放时执行的函数,可以用于音频淡入效果
+ * @param fn 音频开始播放时执行的函数
+ */
+ onStart(fn) {
+ this.audioStartHook = fn;
+ }
+
+ /**
+ * 当音频暂停或停止时执行的函数,可以用于音频淡出效果
+ * @param fn 音频在暂停或停止时执行的函数,不填时表示取消这个钩子。
+ * 包含两个参数,第一个参数是结束时长,第二个参数是当前音频播放路由对象
+ */
+ onEnd(fn) {
+ this.audioEndHook = fn;
+ }
+
+ /**
+ * 开始播放这个音频
+ * @param when 从音频的什么时候开始播放,单位秒
+ */
+ play(when = 0) {
+ if (this.player.status === AudioStatus.Playing) return;
+ this.link();
+ if (this.effectRoute.length > 0) {
+ const first = this.effectRoute[0];
+ this.source.connect(first);
+ const last = this.effectRoute.at(-1);
+ last.connect({ input: this.player.getDestination() });
+ } else {
+ this.source.connect({ input: this.player.getDestination() });
+ }
+ this.source.play(when);
+ this.player.status = AudioStatus.Playing;
+ this.pauseTime = 0;
+ this.audioStartHook?.(this);
+ this.startAllEffect();
+ if (this.source.player.status !== AudioStatus.Playing) {
+ this.source.player.status = AudioStatus.Playing;
+ }
+ }
+
+ /**
+ * 暂停音频播放
+ */
+ async pause() {
+ if (this.player.status !== AudioStatus.Playing) return;
+ this.player.status = AudioStatus.Pausing;
+ this.stopIdentifier++;
+ const identifier = this.stopIdentifier;
+ if (this.audioEndHook) {
+ this.audioEndHook(this.endTime, this);
+ await sleep(this.endTime);
+ }
+ if (
+ this.player.status !== AudioStatus.Pausing ||
+ this.stopIdentifier !== identifier
+ ) {
+ return;
+ }
+ this.pauseCurrentTime = this.source.currentTime;
+ const time = this.source.stop();
+ this.pauseTime = time;
+ if (this.shouldStop) {
+ this.player.status = AudioStatus.Stoped;
+ this.endAllEffect();
+
+ this.shouldStop = false;
+ } else {
+ this.player.status = AudioStatus.Paused;
+ this.endAllEffect();
+ }
+ this.endAllEffect();
+ }
+
+ /**
+ * 继续音频播放
+ */
+ resume() {
+ if (this.player.status === AudioStatus.Playing) return;
+ if (
+ this.player.status === AudioStatus.Pausing ||
+ this.player.status === AudioStatus.Stoping
+ ) {
+ this.audioStartHook?.(this);
+
+ return;
+ }
+ if (this.player.status === AudioStatus.Paused) {
+ this.play(this.pauseTime);
+ } else {
+ this.play(0);
+ }
+ this.player.status = AudioStatus.Playing;
+ this.pauseTime = 0;
+ this.audioStartHook?.(this);
+ this.startAllEffect();
+ }
+
+ /**
+ * 停止音频播放
+ */
+ async stop() {
+ if (this.status !== AudioStatus.Playing) {
+ if (this.status === AudioStatus.Pausing) {
+ this.shouldStop = true;
+ }
+ return;
+ }
+ this.status = AudioStatus.Stoping;
+ this.stopIdentifier++;
+ const identifier = this.stopIdentifier;
+ if (this.audioEndHook) {
+ this.audioEndHook(this.endTime, this);
+ await sleep(this.endTime);
+ }
+ if (
+ this.status !== AudioStatus.Stoping ||
+ this.stopIdentifier !== identifier
+ ) {
+ return;
+ }
+ this.source.stop();
+ this.status = AudioStatus.Stoped;
+ this.pauseTime = 0;
+ this.endAllEffect();
+ }
+
+ /**
+ * 添加效果器
+ * @param effect 要添加的效果,可以是数组,表示一次添加多个
+ * @param index 从哪个位置开始添加,如果大于数组长度,那么加到末尾,如果小于0,那么将会从后面往前数。默认添加到末尾
+ */
+ addEffect(effect, index) {
+ if (isNil(index)) {
+ if (effect instanceof Array) {
+ this.effectRoute.push(...effect);
+ } else {
+ this.effectRoute.push(effect);
+ }
+ } else {
+ if (effect instanceof Array) {
+ this.effectRoute.splice(index, 0, ...effect);
+ } else {
+ this.effectRoute.splice(index, 0, effect);
+ }
+ }
+ this.setOutput();
+ if (this.source.playing) this.link();
+ }
+
+ /**
+ * 移除一个效果器
+ * @param effect 要移除的效果
+ */
+ removeEffect(effect) {
+ const index = this.effectRoute.indexOf(effect);
+ if (index === -1) return;
+ this.effectRoute.splice(index, 1);
+ effect.disconnect();
+ this.setOutput();
+ if (this.source.playing) this.link();
+ }
+
+ setOutput() {
+ const effect = this.effectRoute.at(-1);
+ if (!effect) this.output = this.source.output;
+ else this.output = effect.output;
+ }
+
+ /**
+ * 连接音频路由图
+ */
+ link() {
+ this.effectRoute.forEach((v) => v.disconnect());
+ this.effectRoute.forEach((v, i) => {
+ const next = this.effectRoute[i + 1];
+ if (next) {
+ v.connect(next);
+ }
+ });
+ }
+
+ startAllEffect() {
+ this.effectRoute.forEach((v) => v.start());
+ }
+
+ endAllEffect() {
+ this.effectRoute.forEach((v) => v.end());
+ }
+ }
+
+ const audioPlayer = new AudioPlayer();
+
+ class BgmController {
+ constructor(player) {
+ this.mainGain = player.createVolumeEffect();
+ this.player = player;
+ /** bgm音频名称的前缀 */
+ this.prefix = "bgms.";
+ /** 每个 bgm 的音量控制器 */
+ this.gain = new Map();
+
+ /** 正在播放的 bgm */
+ this.playingBgm = "";
+ /** 是否正在播放 */
+ this.playing = false;
+
+ /** 是否已经启用 */
+ this.enabled = true;
+ /** 是否屏蔽所有的音乐切换 */
+ this.blocking = false;
+ /** 渐变时长 */
+ this.transitionTime = 2000;
+ }
+
+ /**
+ * 设置音频渐变时长
+ * @param time 渐变时长
+ */
+ setTransitionTime(time) {
+ this.transitionTime = time;
+ for (const [, value] of this.gain) {
+ value.transition.time(time);
+ }
+ }
+
+ /**
+ * 屏蔽音乐切换
+ */
+ blockChange() {
+ this.blocking = true;
+ }
+
+ /**
+ * 取消屏蔽音乐切换
+ */
+ unblockChange() {
+ this.blocking = false;
+ }
+
+ /**
+ * 设置总音量大小
+ * @param volume 音量大小
+ */
+ setVolume(volume) {
+ this.mainGain.setVolume(volume);
+ this._volume = volume;
+ }
+ /**
+ * 获取总音量大小
+ */
+ getVolume() {
+ return this.mainGain.getVolume();
+ }
+ /**
+ * 设置是否启用
+ * @param enabled 是否启用
+ */
+ setEnabled(enabled) {
+ if (enabled) this.resume();
+ else this.stop();
+ this.enabled = enabled;
+ }
+
+ /**
+ * 设置 bgm 音频名称的前缀
+ */
+ setPrefix(prefix) {
+ this.prefix = prefix;
+ }
+
+ getId(name) {
+ return `${this.prefix}${name}`;
+ }
+
+ /**
+ * 根据 bgm 名称获取其 AudioRoute 实例
+ * @param id 音频名称
+ */
+ get(id) {
+ return this.player.getRoute(this.getId(id));
+ }
+
+ /**
+ * 添加一个 bgm
+ * @param id 要添加的 bgm 的名称
+ * @param url 指定 bgm 的加载地址
+ */
+ addBgm(id, url = `project/bgms/${id}`) {
+ const type = guessTypeByExt(id);
+ if (!type) {
+ console.warn(
+ "Unknown audio extension name: '" +
+ id.split(".").slice(0, -1).join(".") +
+ "'"
+ );
+ return;
+ }
+ const gain = this.player.createVolumeEffect();
+ if (isAudioSupport(type)) {
+ const source = audioPlayer.createElementSource();
+ source.setSource(url);
+ source.setLoop(true);
+ const route = new AudioRoute(source, audioPlayer);
+ route.addEffect([gain, this.mainGain]);
+ audioPlayer.addRoute(this.getId(id), route);
+ this.setTransition(id, route, gain);
+ } else {
+ const source = audioPlayer.createStreamSource();
+ const stream = new StreamLoader(url);
+ stream.pipe(source);
+ source.setLoop(true);
+ const route = new AudioRoute(source, audioPlayer);
+ route.addEffect([gain, this.mainGain]);
+ audioPlayer.addRoute(this.getId(id), route);
+ this.setTransition(id, route, gain);
+ }
+ }
+
+ /**
+ * 移除一个 bgm
+ * @param id 要移除的 bgm 的名称
+ */
+ removeBgm(id) {
+ this.player.removeRoute(this.getId(id));
+ const gain = this.gain.get(id);
+ gain?.transition.ticker.destroy();
+ this.gain.delete(id);
+ }
+
+ setTransition(id, route, gain) {
+ const transition = new Transition();
+ transition
+ .time(this.transitionTime)
+ .mode(linear())
+ .transition("volume", 0);
+
+ const tick = () => {
+ gain.setVolume(transition.value.volume);
+ };
+
+ /**
+ * @param expect 在结束时应该是正在播放还是停止
+ */
+ const setTick = async (expect) => {
+ transition.ticker.remove(tick);
+ transition.ticker.add(tick);
+ const identifier = route.stopIdentifier;
+ await sleep(this.transitionTime + 500);
+ if (route.status === expect && identifier === route.stopIdentifier) {
+ transition.ticker.remove(tick);
+ if (route.status === AudioStatus.Playing) {
+ gain.setVolume(1);
+ } else {
+ gain.setVolume(0);
+ }
+ }
+ };
+
+ route.onStart(async () => {
+ transition.transition("volume", 1);
+ setTick(AudioStatus.Playing);
+ });
+ route.onEnd(() => {
+ transition.transition("volume", 0);
+ setTick(AudioStatus.Paused);
+ });
+ route.setEndTime(this.transitionTime);
+
+ this.gain.set(id, { effect: gain, transition });
+ }
+
+ /**
+ * 播放一个 bgm
+ * @param id 要播放的 bgm 名称
+ */
+ play(id, when) {
+ if (this.blocking) return;
+ if (id !== this.playingBgm && this.playingBgm) {
+ this.player.pause(this.getId(this.playingBgm));
+ }
+ this.playingBgm = id;
+ if (!this.enabled) return;
+ this.player.play(this.getId(id), when);
+ this.playing = true;
+ if (this.player.status !== AudioStatus.Playing) {
+ this.player.status = AudioStatus.Playing;
+ }
+ }
+
+ /**
+ * 继续当前的 bgm
+ */
+ resume() {
+ if (this.blocking || !this.enabled || this.playing) return;
+ if (this.playingBgm) {
+ this.player.resume(this.getId(this.playingBgm));
+ }
+ this.playing = true;
+ }
+
+ /**
+ * 暂停当前的 bgm
+ */
+ pause() {
+ if (this.blocking || !this.enabled) return;
+ if (this.playingBgm) {
+ this.player.pause(this.getId(this.playingBgm));
+ }
+ this.playing = false;
+ }
+
+ /**
+ * 停止当前的 bgm
+ */
+ stop() {
+ if (this.blocking || !this.enabled) return;
+ if (this.playingBgm) {
+ this.player.stop(this.getId(this.playingBgm));
+ }
+ this.playing = false;
+ }
+ }
+ const bgmController = new BgmController(audioPlayer);
+
+ class SoundPlayer {
+ constructor(player) {
+ /** 每个音效的唯一标识符 */
+ this.num = 0;
+ this.enabled = true;
+ this.gain = player.createVolumeEffect();
+ /** 每个音效的数据 */
+ this.buffer = new Map();
+ /** 所有正在播放的音乐 */
+ this.playing = new Set();
+ this.player = player;
+ }
+ /**
+ * 设置是否启用音效
+ * @param enabled 是否启用音效
+ */
+ setEnabled(enabled) {
+ if (!enabled) this.stopAllSounds();
+ this.enabled = enabled;
+ }
+
+ /**
+ * 设置音量大小
+ * @param volume 音量大小
+ */
+ setVolume(volume) {
+ this.gain.setVolume(volume);
+ }
+ /**
+ * 获取音量大小
+ */
+ getVolume() {
+ return this.gain.getVolume();
+ }
+ /**
+ * 添加一个音效
+ * @param id 音效名称
+ * @param data 音效的Uint8Array数据
+ */
+ async add(id, data) {
+ const buffer = await this.player.decodeAudioData(data);
+ if (!buffer) {
+ console.warn(
+ "Cannot decode sound '" +
+ id +
+ "', since audio file may not supported by 2.b."
+ );
+ return;
+ }
+ this.buffer.set(id, buffer);
+ }
+
+ /**
+ * 播放一个音效
+ * @param id 音效名称
+ * @param position 音频位置,[0, 0, 0]表示正中心,x轴指向水平向右,y轴指向水平向上,z轴指向竖直向上
+ * @param orientation 音频朝向,[0, 1, 0]表示朝向前方
+ */
+ play(id, position = [0, 0, 0], orientation = [1, 0, 0]) {
+ if (!this.enabled) return -1;
+ const buffer = this.buffer.get(id);
+ if (!buffer) {
+ console.warn(
+ "Cannot play sound '" +
+ id +
+ "', since there is no added data named it."
+ );
+ return -1;
+ }
+ const soundNum = this.num++;
+
+ const source = this.player.createBufferSource();
+ source.setBuffer(buffer);
+ const route = this.player.createRoute(source);
+ const stereo = this.player.createStereoEffect();
+ stereo.setPosition(position[0], position[1], position[2]);
+ stereo.setOrientation(orientation[0], orientation[1], orientation[2]);
+ route.addEffect([stereo, this.gain]);
+ this.player.addRoute(`sounds.${soundNum}`, route);
+ route.play();
+ source.output.addEventListener("ended", () => {
+ this.playing.delete(soundNum);
+ });
+ this.playing.add(soundNum);
+ return soundNum;
+ }
+
+ /**
+ * 停止一个音效
+ * @param num 音效的唯一 id
+ */
+ stop(num) {
+ const id = `sounds.${num}`;
+ const route = this.player.getRoute(id);
+ if (route) {
+ route.stop();
+ this.player.removeRoute(id);
+ this.playing.delete(num);
+ }
+ }
+
+ /**
+ * 停止播放所有音效
+ */
+ stopAllSounds() {
+ this.playing.forEach((v) => {
+ const id = `sounds.${v}`;
+ const route = this.player.getRoute(id);
+ if (route) {
+ route.stop();
+ this.player.removeRoute(id);
+ }
+ });
+ this.playing.clear();
+ }
+ }
+ const soundPlayer = new SoundPlayer(audioPlayer);
+
+ function loadAllBgm() {
+ const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
+ for (const bgm of data.main.bgms) {
+ bgmController.addBgm(bgm);
+ }
+ }
+ loadAllBgm();
+ AudioDecoder.registerDecoder(AudioType.Ogg, VorbisDecoder);
+ AudioDecoder.registerDecoder(AudioType.Opus, OpusDecoder);
+
+ core.plugin.audioSystem = {
+ AudioType,
+ AudioDecoder,
+ AudioStatus,
+ checkAudioType,
+ isAudioSupport,
+ audioPlayer,
+ soundPlayer,
+ bgmController,
+ guessTypeByExt,
+ BgmController,
+ SoundPlayer,
+ EchoEffect,
+ DelayEffect,
+ ChannelVolumeEffect,
+ VolumeEffect,
+ StereoEffect,
+ AudioEffect,
+ AudioPlayer,
+ AudioRoute,
+ AudioStreamSource,
+ AudioElementSource,
+ AudioBufferSource,
+ loadAllBgm,
+ StreamLoader,
+ };
+ //bgm相关复写
+ control.prototype.playBgm = (bgm, when) => {
+ bgmController.play(bgm, when);
+ core.setMusicBtn();
+ };
+ control.prototype.pauseBgm = () => {
+ bgmController.pause();
+ core.setMusicBtn();
+ };
+
+ control.prototype.resumeBgm = function () {
+ bgmController.resume();
+ core.setMusicBtn();
+ };
+ control.prototype.checkBgm = function () {
+ if (bgmController.playing) return;
+ if (core.musicStatus.bgmStatus) {
+ if (bgmController.playingBgm) {
+ bgmController.play(bgmController.playingBgm);
+ } else {
+ play(main.startBgm, 0);
+ }
+ } else {
+ pause();
+ }
+ };
+ control.prototype.triggerBgm = function () {
+ core.musicStatus.bgmStatus = !core.musicStatus.bgmStatus;
+ if (bgmController.playing) bgmController.pause();
+ else bgmController.resume();
+ core.setMusicBtn();
+ core.setLocalStorage("bgmStatus", core.musicStatus.bgmStatus);
+ };
+ //sound相关复写
+ control.prototype.playSound = function (
+ sound,
+ _pitch,
+ callback,
+ position,
+ orientation
+ ) {
+ if (main.mode != "play" || !core.musicStatus.soundStatus) return;
+ const name = core.getMappedName(sound);
+ const num = soundPlayer.play(name, position, orientation);
+ const route = audioPlayer.getRoute(`sounds.${num}`);
+ if (!route) {
+ callback?.();
+ return -1;
+ } else {
+ sleep(route.duration).then(() => callback?.());
+ return num;
+ }
+ };
+ control.prototype.stopSound = function (id) {
+ if (isNil(id)) {
+ soundPlayer.stopAllSounds();
+ } else {
+ soundPlayer.stop(id);
+ }
+ };
+ control.prototype.getPlayingSounds = function () {
+ return [...soundPlayer.playing];
+ };
+ //sound加载复写
+ loader.prototype._loadOneSound_decodeData = function (name, data) {
+ if (data instanceof Blob) {
+ var blobReader = new zip.BlobReader(data);
+ blobReader.init(function () {
+ blobReader.readUint8Array(0, blobReader.size, function (uint8) {
+ //core.loader._loadOneSound_decodeData(name, uint8.buffer);
+ soundPlayer.add(name, uint8);
+ });
+ });
+ return;
+ }
+ if (data instanceof ArrayBuffer) {
+ const uint8 = new Uint8Array(data);
+ soundPlayer.add(name, uint8);
+ }
+ };
+ //音量控制复写
+ soundPlayer.setVolume(
+ core.musicStatus.userVolume * core.musicStatus.designVolume
+ );
+ bgmController.setVolume(
+ core.musicStatus.userVolume * core.musicStatus.designVolume
+ );
+ actions.prototype._clickSwitchs_sounds_userVolume = function (delta) {
+ var value = Math.round(Math.sqrt(100 * core.musicStatus.userVolume));
+ if (value == 0 && delta < 0) return;
+ core.musicStatus.userVolume = core.clamp(
+ Math.pow(value + delta, 2) / 100,
+ 0,
+ 1
+ );
+ //audioContext 音效 不受designVolume 影响
+ if (core.musicStatus.gainNode != null)
+ core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume;
+ soundPlayer.setVolume(
+ core.musicStatus.userVolume * core.musicStatus.designVolume
+ );
+ bgmController.setVolume(
+ core.musicStatus.userVolume * core.musicStatus.designVolume
+ );
+ core.setLocalStorage("userVolume", core.musicStatus.userVolume);
+ core.playSound("确定");
+ core.ui._drawSwitchs_sounds();
+ };
+},
"怪物碎裂特效": function () {
// 在此增加新插件
// -------------------- 安装说明 -------------------- //
@@ -8580,6 +10681,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
return {
animation: ani,
+
onEnd: promise.then(() => {
ani.ticker.destroy();
onEnd();
@@ -9308,8 +11410,8 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
MotaActionFunctions.actionParser.parse(
{
time: 160,
- openSound: "door.mp3",
- closeSound: "door.mp3",
+ openSound: "door.opus",
+ closeSound: "door.opus",
keys: { yellowKey: 1, orangeKey: 1 },
},
"doorInfo"
@@ -9318,9 +11420,9 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
MotaActionBlocks["mainStyle_m"].xmlText(),
MotaActionFunctions.actionParser.parse(
{
- 背景音乐: "bgm.mp3",
- 确定: "confirm.mp3",
- 攻击: "attack.mp3",
+ 背景音乐: "bgm.opus",
+ 确定: "confirm.opus",
+ 攻击: "attack.opus",
背景图: "bg.webp",
领域: "zone",
文件名: "file.jpg",
@@ -12491,7 +14593,14 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
});
if (count > 0) list.splice(0, count);
}
- if (!main.replayChecking) core.registerAnimationFrame("pop", true, pop);
+ let now = 0;
+ if (!main.replayChecking)
+ core.registerAnimationFrame("pop", true, (temptime) => {
+ if (temptime - now > 1000 / 60) {
+ now = temptime;
+ pop();
+ }
+ });
/** 添加弹出内容 */
this.addPop = function (
@@ -12528,7 +14637,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
"warning": function () {
// 在此增加新插件
// 默认音效名
- var defaultSound = "jingbao.mp3";
+ var defaultSound = "jingbao.opus";
// 默认字体名
var defaultFont = "Verdana";
@@ -14123,7 +16232,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
}
});
bgm = core.musicStatus.playingBgm;
- core.playBgm("op.mp3");
+ core.playBgm("op.opus");
a = setTimeout(() => {
video.remove();
video1.remove();
@@ -14256,1097 +16365,941 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
};
},
"musicMode": function () {
- // 在此增加新插件
- const music = document.createElement("canvas");
- music.style.position = "absolute";
- music.style.zIndex = 300;
- music.style.display = "none";
- music.id = "music";
- main.dom.gameGroup.insertAdjacentElement("afterend", music);
- music.style.top = "50%";
- music.style.left = "50%";
- music.style.transform = "translate(-50%,-50%)";
- const ctx = music.getContext("2d");
- main.dom.music = music;
+ // 在此增加新插件
+ const music = document.createElement("canvas");
+ music.style.position = "absolute";
+ music.style.zIndex = 300;
+ music.style.display = "none";
+ music.id = "music";
+ main.dom.gameGroup.insertAdjacentElement("afterend", music);
+ music.style.top = "50%";
+ music.style.left = "50%";
+ music.style.transform = "translate(-50%,-50%)";
+ const ctx = music.getContext("2d");
+ main.dom.music = music;
- const audio = document.createElement("audio");
- audio.autoplay = true;
- audio.preload = "auto";
+ const audio = core.plugin.audioSystem.bgmController;
- function getRandomInt(min, max) {
- const minCeiled = Math.ceil(min);
- const maxFloored = Math.floor(max);
- return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
- }
- let page = 0; //初始页面
- let ischange = false;
- let isvolume = false;
+ let page = 0; //初始页面
- function shuffle(arr) {
- let n = arr.length,
- random;
- while (n) {
- random = (Math.random() * n--) >>> 0;
- [arr[n], arr[random]] = [arr[random], arr[n]];
- }
- return arr;
- }
- music.addEventListener("mousedown", function (e) {
- e.stopPropagation();
- const left = core.dom.gameGroup.offsetLeft;
- const top = core.dom.gameGroup.offsetTop;
- const px = Math.floor((e.clientX - left) / core.domStyle.scale),
- py = Math.floor((e.clientY - top) / core.domStyle.scale);
- core.ui.music.mousedown(px * 3, py * 3);
- });
- music.addEventListener("mousemove", function (e) {
- e.stopPropagation();
- const left = core.dom.gameGroup.offsetLeft;
- const top = core.dom.gameGroup.offsetTop;
- const px = Math.floor((e.clientX - left) / core.domStyle.scale),
- py = Math.floor((e.clientY - top) / core.domStyle.scale);
- core.ui.music.mousemove(px * 3, py * 3);
- });
- music.addEventListener("mouseup", function (e) {
- e.stopPropagation();
- ischange = false;
- isvolume = false;
- if (!main.core.ui.music.stop) audio.play();
- });
- music.addEventListener("mouseleave", function (e) {
- e.stopPropagation();
- ischange = false;
- isvolume = false;
- if (!main.core.ui.music.stop) audio.play();
- });
- music.addEventListener("touchstart", function (e) {
- e.preventDefault();
- const left = core.dom.gameGroup.offsetLeft;
- const top = core.dom.gameGroup.offsetTop;
- const px = Math.floor(
- (e.touches[0].clientX - left) / core.domStyle.scale
- ),
- py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale);
- core.ui.music.mousedown(px * 3, py * 3);
- });
- music.addEventListener("touchmove", function (e) {
- e.stopPropagation();
- const left = core.dom.gameGroup.offsetLeft;
- const top = core.dom.gameGroup.offsetTop;
- const px = Math.floor(
- (e.touches[0].clientX - left) / core.domStyle.scale
- ),
- py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale);
- core.ui.music.mousemove(px * 3, py * 3);
- });
- music.addEventListener("touchend", function (e) {
- e.stopPropagation();
- ischange = false;
- isvolume = false;
- if (!main.core.ui.music.stop) audio.play();
- });
- music.addEventListener("touchcancel", function (e) {
- e.stopPropagation();
- ischange = false;
- isvolume = false;
- });
+ let isvolume = false;
- audio.addEventListener("ended", function () {
- switch (main.core.ui.music.type) {
- case "danqu":
- audio.currentTime = 0;
- if (!main.core.ui.music.stop) audio.play();
- main.core.ui.music.stop = false;
- page = main.core.ui.music.selection[0];
+ function shuffle(arr) {
+ let n = arr.length,
+ random;
+ while (n) {
+ random = (Math.random() * n--) >>> 0;
+ [arr[n], arr[random]] = [arr[random], arr[n]];
+ }
+ return arr;
+ }
+ music.addEventListener("mousedown", function (e) {
+ e.stopPropagation();
+ const left = core.dom.gameGroup.offsetLeft;
+ const top = core.dom.gameGroup.offsetTop;
+ const px = Math.floor((e.clientX - left) / core.domStyle.scale),
+ py = Math.floor((e.clientY - top) / core.domStyle.scale);
+ core.ui.music.mousedown(px * 3, py * 3);
+ });
+ music.addEventListener("mousemove", function (e) {
+ e.stopPropagation();
+ const left = core.dom.gameGroup.offsetLeft;
+ const top = core.dom.gameGroup.offsetTop;
+ const px = Math.floor((e.clientX - left) / core.domStyle.scale),
+ py = Math.floor((e.clientY - top) / core.domStyle.scale);
+ core.ui.music.mousemove(px * 3, py * 3);
+ });
+ music.addEventListener("mouseup", function (e) {
+ e.stopPropagation();
- break;
- case "xunhuan":
- if (
- main.core.ui.music.selection[1] ===
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]].length -
- 1
- ) {
- if (
- main.core.ui.music.selection[0] ===
- main.core.ui.music.musicMx.length - 1
- ) {
- main.core.ui.music.selection[0] = 0;
- main.core.ui.music.selection[1] = 0;
- } else {
- main.core.ui.music.selection[0] += 1;
- main.core.ui.music.selection[1] = 0;
- }
- } else {
- main.core.ui.music.selection[1] += 1;
- }
- main.core.ui.music.randomList.indexOf(
- (v) =>
- v ===
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
- main.core.ui.music.selection[1]
- ]
- );
- page = main.core.ui.music.selection[0];
- audio.src =
- "project/bgms/" +
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
- main.core.ui.music.selection[1]
- ];
+ isvolume = false;
+ });
+ music.addEventListener("mouseleave", function (e) {
+ e.stopPropagation();
- if (!main.core.ui.music.stop) audio.play();
- main.core.ui.music.stop = false;
- break;
- case "suiji":
- if (
- main.core.ui.music.random <
- main.core.ui.music.randomList.length - 1
- ) {
- main.core.ui.music.random += 1;
- } else {
- main.core.ui.music.random = 0;
- }
- main.core.ui.music.selection[0] =
- main.core.ui.music.musicMx.findIndex((v) =>
- v.includes(
- main.core.ui.music.randomList[main.core.ui.music.random]
- )
- );
- main.core.ui.music.selection[1] = main.core.ui.music.musicMx[
- main.core.ui.music.selection[0]
- ].indexOf(main.core.ui.music.randomList[main.core.ui.music.random]);
- audio.src =
- "project/bgms/" +
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
- main.core.ui.music.selection[1]
- ];
- page = main.core.ui.music.selection[0];
+ isvolume = false;
+ });
+ music.addEventListener("touchstart", function (e) {
+ e.preventDefault();
+ const left = core.dom.gameGroup.offsetLeft;
+ const top = core.dom.gameGroup.offsetTop;
+ const px = Math.floor(
+ (e.touches[0].clientX - left) / core.domStyle.scale
+ ),
+ py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale);
+ core.ui.music.mousedown(px * 3, py * 3);
+ });
+ music.addEventListener("touchmove", function (e) {
+ e.stopPropagation();
+ const left = core.dom.gameGroup.offsetLeft;
+ const top = core.dom.gameGroup.offsetTop;
+ const px = Math.floor(
+ (e.touches[0].clientX - left) / core.domStyle.scale
+ ),
+ py = Math.floor((e.touches[0].clientY - top) / core.domStyle.scale);
+ core.ui.music.mousemove(px * 3, py * 3);
+ });
+ music.addEventListener("touchend", function (e) {
+ e.stopPropagation();
- if (!main.core.ui.music.stop) audio.play();
- main.core.ui.music.stop = false;
- break;
- }
- });
+ isvolume = false;
+ });
+ music.addEventListener("touchcancel", function (e) {
+ e.stopPropagation();
- class musicclass {
- constructor() {
- //music列表
- //需全塔属性注册并保存在bgms文件夹,每个数组为显示的一页内容
- this.musicMx = [
- ["Asphodelus_Ceui.mp3", "Blind_Alley.mp3"],
- ["Crawler.mp3", "op.mp3", "theme.mp3"],
- ];
- //音乐别名(将在播放器内显示的音乐名,music列表内的都要有对应歌名)
- this.musicname = {
- "Asphodelus_Ceui.mp3": "Asphodelus",
- "Blind_Alley.mp3": "Blind",
- "Crawler.mp3": "Crawler",
- "op.mp3": "op",
- "theme.mp3": "theme",
- };
- this.selection = [0, 0];
- this.stop = false;
- this.type = "xunhuan";
- this.randomList = [];
- this.random = 0;
- }
+ isvolume = false;
+ });
- //更新
- update() {
- this.background();
- this.drawUI();
- }
- background() {
- //画布大小设置
- if (core.domStyle.isVertical) {
- music.width = 1248;
- music.height = 2028;
- } else {
- music.width = 2028;
- music.height = 1248;
- }
- }
- mousedown(px, py) {
- //鼠标按下时
- //console.log(px, py)
- const makeBox = ([x, y], [w, h]) => {
- return [
- [x, y],
- [x + w, y + h],
- ];
- };
- const inRect = ([x, y], [[sx, sy], [dx, dy]]) => {
- return sx <= x && x <= dx && sy <= y && y <= dy;
- };
- const pos = [px, py];
- const backbox = makeBox([15, 35], [210, 90]);
- if (inRect(pos, backbox)) {
- //离开按钮是一致的,其余的记区分横竖屏
- music.style.display = "none";
- core.clearMap(ctx);
- core.unregisterAnimationFrame("music");
- audio.src = "";
- core.restart();
+ class musicclass {
+ constructor() {
+ //music列表
+ //需全塔属性注册并保存在bgms文件夹,每个数组为显示的一页内容
+ this.musicMx = [
+ ["Asphodelus_Ceui.opus", "Blind_Alley.opus"],
+ ["Crawler.opus", "op.opus", "theme.opus"],
+ ];
+ //音乐别名(将在播放器内显示的音乐名,music列表内的都要有对应歌名)
+ this.musicname = {
+ "Asphodelus_Ceui.opus": "Asphodelus",
+ "Blind_Alley.opus": "Blind",
+ "Crawler.opus": "Crawler",
+ "op.opus": "op",
+ "theme.opus": "theme",
+ };
+ this.selection = [0, 0];
+ this.stop = false;
+ this.type = "xunhuan";
+ this.randomList = [];
+ this.random = 0;
+ }
- return;
- }
- if (core.domStyle.isVertical) {
- //竖屏
+ //更新
+ update() {
+ this.background();
+ this.drawUI();
+ }
+ background() {
+ //画布大小设置
+ if (core.domStyle.isVertical) {
+ music.width = 1248;
+ music.height = 2028;
+ } else {
+ music.width = 2028;
+ music.height = 1248;
+ }
+ }
+ mousedown(px, py) {
+ //鼠标按下时
- const pageupbox = makeBox([100, 1230], [200, 100]);
- const pagedownbox = makeBox([950, 1230], [200, 100]);
- const musicbox = makeBox(
- [100, 200],
- [1048, this.musicMx[page].length * 100]
- );
- const beforebox = makeBox([120, 1720], [100, 100]);
- const afterbox = makeBox([780, 1720], [100, 100]);
- const playbox = makeBox([420, 1680], [200, 200]);
- const typebox = makeBox([1040, 1700], [120, 120]);
- const changebox = makeBox([100, 1590], [1048, 20]);
- const volumebox = makeBox([250, 1940], [1050, 20]);
- if (inRect(pos, pageupbox)) {
- if (page !== 0) page -= 1;
- return;
- }
- if (inRect(pos, pagedownbox)) {
- if (page !== this.musicMx.length - 1) page += 1;
- return;
- }
- if (inRect(pos, playbox)) {
- if (this.stop) {
- this.stop = !this.stop;
- audio.play();
- } else {
- this.stop = !this.stop;
- audio.pause();
- }
- return;
- }
- if (inRect(pos, beforebox)) {
- switch (this.type) {
- case "danqu":
- audio.currentTime = 0;
- if (!this.stop) audio.play();
- this.stop = false;
- page = this.selection[0];
+ const makeBox = ([x, y], [w, h]) => {
+ return [
+ [x, y],
+ [x + w, y + h],
+ ];
+ };
+ const inRect = ([x, y], [
+ [sx, sy],
+ [dx, dy]
+ ]) => {
+ return sx <= x && x <= dx && sy <= y && y <= dy;
+ };
+ const pos = [px, py];
+ const backbox = makeBox([15, 35], [210, 90]);
+ if (inRect(pos, backbox)) {
+ //离开按钮是一致的,其余的记区分横竖屏
+ music.style.display = "none";
+ core.clearMap(ctx);
- break;
- case "xunhuan":
- if (this.selection[1] === 0) {
- if (this.selection[0] === 0) {
- this.selection[0] = this.musicMx.length - 1;
- this.selection[1] =
- this.musicMx[this.selection[0]].length - 1;
- } else {
- this.selection[0] -= 1;
- this.selection[1] =
- this.musicMx[this.selection[0]].length - 1;
- }
- } else {
- this.selection[1] -= 1;
- }
- this.randomList.indexOf(
- this.musicMx[this.selection[0]][this.selection[1]]
- );
- page = this.selection[0];
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ core.unregisterAnimationFrame("music");
+ core.restart();
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- case "suiji":
- if (this.random > 0) {
- this.random -= 1;
- } else {
- this.random = this.randomList.length - 1;
- }
- this.selection[0] = this.musicMx.findIndex((v) =>
- v.includes(this.randomList[this.random])
- );
- this.selection[1] = this.musicMx[this.selection[0]].indexOf(
- this.randomList[this.random]
- );
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
- page = this.selection[0];
+ return;
+ }
+ if (core.domStyle.isVertical) {
+ //竖屏
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- }
- return;
- }
- if (inRect(pos, afterbox)) {
- switch (this.type) {
- case "danqu":
- audio.currentTime = 0;
- if (!this.stop) audio.play();
- this.stop = false;
- page = this.selection[0];
- break;
- case "xunhuan":
- if (
- this.selection[1] ===
- this.musicMx[this.selection[0]].length - 1
- ) {
- if (this.selection[0] === this.musicMx.length - 1) {
- this.selection[0] = 0;
- this.selection[1] = 0;
- } else {
- this.selection[0] += 1;
- this.selection[1] = 0;
- }
- } else {
- this.selection[1] += 1;
- }
- this.random = this.randomList.indexOf(
- this.musicMx[this.selection[0]][this.selection[1]]
- );
- page = this.selection[0];
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ const pageupbox = makeBox([100, 1230], [200, 100]);
+ const pagedownbox = makeBox([950, 1230], [200, 100]);
+ const musicbox = makeBox(
+ [100, 200],
+ [1048, this.musicMx[page].length * 100]
+ );
+ const beforebox = makeBox([120, 1620], [100, 100]);
+ const afterbox = makeBox([780, 1620], [100, 100]);
+ const playbox = makeBox([420, 1580], [200, 200]);
+ const typebox = makeBox([1040, 1600], [120, 120]);
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- case "suiji":
- if (this.random < this.randomList.length - 1) {
- this.random += 1;
- } else {
- this.random = 0;
- }
- this.selection[0] = this.musicMx.findIndex((v) =>
- v.includes(this.randomList[this.random])
- );
- this.selection[1] = this.musicMx[this.selection[0]].indexOf(
- this.randomList[this.random]
- );
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ const volumebox = makeBox([250, 1940], [1050, 20]);
+ if (inRect(pos, pageupbox)) {
+ if (page !== 0) page -= 1;
+ return;
+ }
+ if (inRect(pos, pagedownbox)) {
+ if (page !== this.musicMx.length - 1) page += 1;
+ return;
+ }
+ if (inRect(pos, playbox)) {
+ if (this.stop) {
+ this.stop = !this.stop;
- page = this.selection[0];
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- }
- return;
- }
- if (inRect(pos, typebox)) {
- switch (this.type) {
- case "danqu":
- this.type = "xunhuan";
- break;
- case "xunhuan":
- this.type = "suiji";
- break;
- case "suiji":
- this.type = "danqu";
- break;
- }
- return;
- }
- if (inRect(pos, musicbox)) {
- const index = Math.floor((py - 200) / 100);
- if (page !== this.selection[0] || index !== this.selection[1]) {
- this.selection[0] = page;
- this.selection[1] = index;
- this.randomList.indexOf(
- this.musicMx[this.selection[0]][this.selection[1]]
- );
- audio.src = "project/bgms/" + this.musicMx[page][index];
+ core.resumeBgm();
+ } else {
+ this.stop = !this.stop;
+ core.pauseBgm();
+ }
+ return;
+ }
+ if (inRect(pos, beforebox)) {
+ this.stop = false;
+ switch (this.type) {
+ case "danqu":
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- if (!this.stop) audio.play();
- this.stop = false;
- } else {
- if (this.stop) {
- this.stop = !this.stop;
- audio.play();
- } else {
- this.stop = !this.stop;
- audio.pause();
- }
- }
- return;
- }
- if (inRect(pos, changebox)) {
- const time = Math.floor(((px - 100) / 1000) * audio.duration);
+ page = this.selection[0];
- audio.pause();
- audio.currentTime = time;
+ break;
+ case "xunhuan":
+ if (this.selection[1] === 0) {
+ if (this.selection[0] === 0) {
+ this.selection[0] = this.musicMx.length - 1;
+ this.selection[1] =
+ this.musicMx[this.selection[0]].length - 1;
+ } else {
+ this.selection[0] -= 1;
+ this.selection[1] =
+ this.musicMx[this.selection[0]].length - 1;
+ }
+ } else {
+ this.selection[1] -= 1;
+ }
+ this.randomList.indexOf(
+ this.musicMx[this.selection[0]][this.selection[1]]
+ );
+ page = this.selection[0];
- ischange = true;
- }
- if (inRect(pos, volumebox)) {
- const time = Math.min(Math.max((px - 250) / 800, 0), 1);
- audio.volume = time;
- isvolume = true;
- }
- } else {
- //横屏
- const pageupbox = makeBox([1050, 1100], [200, 100]);
- const pagedownbox = makeBox([1550, 1100], [200, 100]);
- const musicbox = makeBox(
- [900, 100],
- [1000, this.musicMx[page].length * 100]
- );
- const beforebox = makeBox([135, 740], [50, 50]);
- const afterbox = makeBox([450, 740], [50, 50]);
- const playbox = makeBox([250, 700], [200, 200]);
- const typebox = makeBox([600, 700], [100, 100]);
- const changebox = makeBox([100, 590], [600, 20]);
- const volumebox = makeBox([100, 990], [600, 20]);
- if (inRect(pos, pageupbox)) {
- if (page !== 0) page -= 1;
- return;
- }
- if (inRect(pos, pagedownbox)) {
- if (page !== this.musicMx.length - 1) page += 1;
- return;
- }
- if (inRect(pos, playbox)) {
- if (this.stop) {
- this.stop = !this.stop;
- audio.play();
- } else {
- this.stop = !this.stop;
- audio.pause();
- }
- return;
- }
- if (inRect(pos, beforebox)) {
- switch (this.type) {
- case "danqu":
- audio.currentTime = 0;
- if (!this.stop) audio.play();
- this.stop = false;
- page = this.selection[0];
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- break;
- case "xunhuan":
- if (this.selection[1] === 0) {
- if (this.selection[0] === 0) {
- this.selection[0] = this.musicMx.length - 1;
- this.selection[1] =
- this.musicMx[this.selection[0]].length - 1;
- } else {
- this.selection[0] -= 1;
- this.selection[1] =
- this.musicMx[this.selection[0]].length - 1;
- }
- } else {
- this.selection[1] -= 1;
- }
- this.random = this.randomList.indexOf(
- this.musicMx[this.selection[0]][this.selection[1]]
- );
- page = this.selection[0];
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ break;
+ case "suiji":
+ if (this.random > 0) {
+ this.random -= 1;
+ } else {
+ this.random = this.randomList.length - 1;
+ }
+ this.selection[0] = this.musicMx.findIndex((v) =>
+ v.includes(this.randomList[this.random])
+ );
+ this.selection[1] = this.musicMx[this.selection[0]].indexOf(
+ this.randomList[this.random]
+ );
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- case "suiji":
- if (this.random > 0) {
- this.random -= 1;
- } else {
- this.random = this.randomList.length - 1;
- }
- this.selection[0] = this.musicMx.findIndex((v) =>
- v.includes(this.randomList[this.random])
- );
- this.selection[1] = this.musicMx[this.selection[0]].indexOf(
- this.randomList[this.random]
- );
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
- page = this.selection[0];
+ page = this.selection[0];
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- }
- return;
- }
- if (inRect(pos, afterbox)) {
- switch (this.type) {
- case "danqu":
- audio.currentTime = 0;
- if (!this.stop) audio.play();
- this.stop = false;
- page = this.selection[0];
- break;
- case "xunhuan":
- if (
- this.selection[1] ===
- this.musicMx[this.selection[0]].length - 1
- ) {
- if (this.selection[0] === this.musicMx.length - 1) {
- this.selection[0] = 0;
- this.selection[1] = 0;
- } else {
- this.selection[0] += 1;
- this.selection[1] = 0;
- }
- } else {
- this.selection[1] += 1;
- }
- this.randomList.findIndex(
- (v) =>
- v === this.musicMx[this.selection[0]][this.selection[1]]
- );
- page = this.selection[0];
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- case "suiji":
- if (this.random < this.randomList.length - 1) {
- this.random += 1;
- } else {
- this.random = 0;
- }
- this.selection[0] = this.musicMx.findIndex((v) =>
- v.includes(this.randomList[this.random])
- );
- this.selection[1] = this.musicMx[this.selection[0]].indexOf(
- main.core.ui.music.randomList[main.core.ui.music.random]
- );
- audio.src =
- "project/bgms/" +
- this.musicMx[this.selection[0]][this.selection[1]];
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, afterbox)) {
+ this.stop = false;
+ switch (this.type) {
+ case "danqu":
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- page = this.selection[0];
- if (!this.stop) audio.play();
- this.stop = false;
- break;
- }
- return;
- }
- if (inRect(pos, typebox)) {
- switch (this.type) {
- case "danqu":
- this.type = "xunhuan";
- break;
- case "xunhuan":
- this.type = "suiji";
- break;
- case "suiji":
- this.type = "danqu";
- break;
- }
- return;
- }
- if (inRect(pos, musicbox)) {
- const index = Math.floor((py - 100) / 100);
- if (page !== this.selection[0] || index !== this.selection[1]) {
- this.selection[0] = page;
- this.selection[1] = index;
- this.randomList.indexOf(
- (v) => v === this.musicMx[this.selection[0]][this.selection[1]]
- );
- audio.src = "project/bgms/" + this.musicMx[page][index];
+ page = this.selection[0];
+ break;
+ case "xunhuan":
+ if (
+ this.selection[1] ===
+ this.musicMx[this.selection[0]].length - 1
+ ) {
+ if (this.selection[0] === this.musicMx.length - 1) {
+ this.selection[0] = 0;
+ this.selection[1] = 0;
+ } else {
+ this.selection[0] += 1;
+ this.selection[1] = 0;
+ }
+ } else {
+ this.selection[1] += 1;
+ }
+ this.random = this.randomList.indexOf(
+ this.musicMx[this.selection[0]][this.selection[1]]
+ );
+ page = this.selection[0];
- if (!this.stop) audio.play();
- this.stop = false;
- } else {
- if (this.stop) {
- this.stop = !this.stop;
- audio.play();
- } else {
- this.stop = !this.stop;
- audio.pause();
- }
- }
- return;
- }
- if (inRect(pos, changebox)) {
- const time = Math.floor(((px - 100) / 600) * audio.duration);
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- audio.pause();
- audio.currentTime = time;
+ break;
+ case "suiji":
+ if (this.random < this.randomList.length - 1) {
+ this.random += 1;
+ } else {
+ this.random = 0;
+ }
+ this.selection[0] = this.musicMx.findIndex((v) =>
+ v.includes(this.randomList[this.random])
+ );
+ this.selection[1] = this.musicMx[this.selection[0]].indexOf(
+ this.randomList[this.random]
+ );
- ischange = true;
- }
- if (inRect(pos, volumebox)) {
- const time = Math.min(Math.max((px - 100) / 600, 0), 1);
- audio.volume = time;
- isvolume = true;
- }
- }
- }
- mousemove(px, py) {
- if (ischange) {
- if (core.domStyle.isVertical) {
- const time = Math.min(
- Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0),
- audio.duration
- );
+ page = this.selection[0];
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- audio.currentTime = time;
- } else {
- const time = Math.min(
- Math.max(Math.floor(((px - 100) / 600) * audio.duration), 0),
- audio.duration
- );
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, typebox)) {
+ switch (this.type) {
+ case "danqu":
+ this.type = "xunhuan";
+ break;
+ case "xunhuan":
+ this.type = "suiji";
+ break;
+ case "suiji":
+ this.type = "danqu";
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, musicbox)) {
+ const index = Math.floor((py - 200) / 100);
+ if (page !== this.selection[0] || index !== this.selection[1]) {
+ this.selection[0] = page;
+ this.selection[1] = index;
+ this.randomList.indexOf(
+ this.musicMx[this.selection[0]][this.selection[1]]
+ );
- audio.currentTime = time;
- }
- }
- if (isvolume) {
- if (core.domStyle.isVertical) {
- const time = Math.min(Math.max((px - 250) / 800, 0), 1);
- audio.volume = time;
- } else {
- const time = Math.min(Math.max((px - 100) / 600, 0), 1);
- audio.volume = time;
- }
- }
- }
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- drawUI() {
- //绘制页面
- core.clearMap(music);
- const bgVertical = core.material.images.images["bg_2010.webp"]; //竖屏背景
- const bg = core.material.images.images["bg_5043.webp"]; //竖屏背景
- if (core.domStyle.isVertical) {
- //竖屏
+ this.stop = false;
+ } else {
+ if (this.stop) {
+ this.stop = !this.stop;
+ core.resumeBgm();
+ } else {
+ this.stop = !this.stop;
+ core.pauseBgm();
+ }
+ }
+ return;
+ }
- core.fillRect(ctx, 0, 0, 1248, 2028, "#000000"); //黑色背景
- ctx.globalAlpha = 0.3; //透明度
- if (bgVertical)
- ctx.drawImage(bgVertical, 0, 0, 1280, 1500, 0, 0, 1248, 2028); //绘制半透明背景图片
- ctx.globalAlpha = 1; //恢复为不透明
+ if (inRect(pos, volumebox)) {
+ const time = Math.min(Math.max((px - 250) / 800, 0), 1);
+ audio.setVolume(time);
+ core.plugin.audioSystem.soundPlayer.setVolume(time);
+ isvolume = true;
+ }
+ } else {
+ //横屏
+ const pageupbox = makeBox([1050, 1100], [200, 100]);
+ const pagedownbox = makeBox([1550, 1100], [200, 100]);
+ const musicbox = makeBox(
+ [900, 100],
+ [1000, this.musicMx[page].length * 100]
+ );
+ const beforebox = makeBox([60, 620], [100, 100]);
+ const afterbox = makeBox([450, 620], [100, 100]);
+ const playbox = makeBox([200, 570], [200, 200]);
+ const typebox = makeBox([620, 600], [120, 120]);
- core.setTextAlign(ctx, "center");
- core.fillBoldText1(
- ctx,
- "◀离开",
- 110,
- 100,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
+ const volumebox = makeBox([100, 990], [600, 20]);
+ if (inRect(pos, pageupbox)) {
+ if (page !== 0) page -= 1;
+ return;
+ }
+ if (inRect(pos, pagedownbox)) {
+ if (page !== this.musicMx.length - 1) page += 1;
+ return;
+ }
+ if (inRect(pos, playbox)) {
+ if (this.stop) {
+ this.stop = !this.stop;
+ core.resumeBgm();
+ } else {
+ this.stop = !this.stop;
+ core.pauseBgm();
+ }
+ return;
+ }
+ if (inRect(pos, beforebox)) {
+ this.stop = false;
+ switch (this.type) {
+ case "danqu":
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(100, 200);
- ctx.lineTo(1148, 200);
+ page = this.selection[0];
- ctx.stroke();
- let posy = 300;
- const indexList = this.musicMx[page];
- core.setTextAlign(ctx, "left");
- for (let i = 0; i < indexList.length; i++) {
- const text = this.musicname[indexList[i]];
- core.fillBoldText1(
- ctx,
- text,
- 150,
- posy - 30,
- page === this.selection[0] && i === this.selection[1]
- ? "#FFFFFF"
- : "#444444",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(100, posy);
- ctx.lineTo(1148, posy);
- ctx.stroke();
- posy += 100;
- }
- ctx.beginPath();
- ctx.moveTo(100, 1210);
- ctx.lineTo(1148, 1210);
- ctx.moveTo(100, 1200);
- ctx.lineTo(1148, 1200);
- ctx.stroke();
+ break;
+ case "xunhuan":
+ if (this.selection[1] === 0) {
+ if (this.selection[0] === 0) {
+ this.selection[0] = this.musicMx.length - 1;
+ this.selection[1] =
+ this.musicMx[this.selection[0]].length - 1;
+ } else {
+ this.selection[0] -= 1;
+ this.selection[1] =
+ this.musicMx[this.selection[0]].length - 1;
+ }
+ } else {
+ this.selection[1] -= 1;
+ }
+ this.random = this.randomList.indexOf(
+ this.musicMx[this.selection[0]][this.selection[1]]
+ );
+ page = this.selection[0];
- core.fillBoldText1(
- ctx,
- "上一页",
- 100,
- 1300,
- page === 0 ? "#444444" : "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- core.fillBoldText1(
- ctx,
- page + 1 + "/" + this.musicMx.length,
- 580,
- 1300,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- core.fillBoldText1(
- ctx,
- "下一页",
- 950,
- 1300,
- page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
+ break;
+ case "suiji":
+ if (this.random > 0) {
+ this.random -= 1;
+ } else {
+ this.random = this.randomList.length - 1;
+ }
+ this.selection[0] = this.musicMx.findIndex((v) =>
+ v.includes(this.randomList[this.random])
+ );
+ this.selection[1] = this.musicMx[this.selection[0]].indexOf(
+ this.randomList[this.random]
+ );
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(100, 1600);
- ctx.lineTo(1148, 1600);
- ctx.stroke();
- ctx.fillStyle = "#ffffff";
- ctx.font = "bold 96px Verdana";
- ctx.fillText("|", 100, 1797);
- ctx.fillText("◀", 115, 1800);
- ctx.beginPath();
- ctx.arc(505, 1770, 80, 0, 3 * Math.PI);
- ctx.stroke();
- ctx.fillText("|", 835, 1797);
- ctx.fillText("▶", 785, 1800);
- if (this.stop) {
- ctx.fillText("▶", 473, 1797);
- } else {
- ctx.fillText("||", 453, 1794);
- }
+ page = this.selection[0];
- const img = core.material.images.images[this.type + ".webp"];
- if (img) ctx.drawImage(img, 1000, 1655, 200, 200);
- core.setTextAlign(ctx, "center");
- ctx.font = "bold 52px Verdana";
- ctx.fillText("当前歌曲", 625, 1397);
- ctx.fillText(
- this.musicname[this.musicMx[this.selection[0]][this.selection[1]]],
- 625,
- 1507
- );
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- ctx.font = "bold 36px Verdana";
- const thistime = audio.currentTime;
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, afterbox)) {
+ this.stop = false;
+ switch (this.type) {
+ case "danqu":
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- if (thistime) {
- const timetext =
- Math.floor(thistime / 60)
- .toString()
- .padStart(2, "0") +
- ":" +
- Math.floor(thistime % 60)
- .toString()
- .padStart(2, "0");
- ctx.fillText(timetext, 960, 1650);
- } else {
- const timetext = "00:00";
- ctx.fillText(timetext, 960, 1650);
- }
- ctx.fillText("/", 1030, 1650);
- const fulltime = audio.duration;
+ page = this.selection[0];
+ break;
+ case "xunhuan":
+ if (
+ this.selection[1] ===
+ this.musicMx[this.selection[0]].length - 1
+ ) {
+ if (this.selection[0] === this.musicMx.length - 1) {
+ this.selection[0] = 0;
+ this.selection[1] = 0;
+ } else {
+ this.selection[0] += 1;
+ this.selection[1] = 0;
+ }
+ } else {
+ this.selection[1] += 1;
+ }
+ this.randomList.findIndex(
+ (v) =>
+ v === this.musicMx[this.selection[0]][this.selection[1]]
+ );
+ page = this.selection[0];
- if (fulltime) {
- const timetext =
- Math.floor(fulltime / 60)
- .toString()
- .padStart(2, "0") +
- ":" +
- Math.floor(fulltime % 60)
- .toString()
- .padStart(2, "0");
- ctx.fillText(timetext, 1100, 1650);
- } else {
- const timetext = "00:00";
- ctx.fillText(timetext, 1100, 1650);
- }
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 9;
- ctx.fillStyle = "rgba(255,255,255,0.5)";
- const pointx = (1048 * thistime) / fulltime + 100;
- if (fulltime && thistime) {
- ctx.beginPath();
- ctx.moveTo(100, 1600);
- ctx.lineTo(pointx, 1600);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(pointx, 1600, 10, 0, 2 * Math.PI);
- ctx.fill();
- } else {
- ctx.beginPath();
- ctx.arc(100, 1600, 10, 0, 2 * Math.PI);
- ctx.fill();
- }
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- ctx.fillStyle = "#ffffff";
- ctx.font = "bold 48px Verdana";
- ctx.fillText("音量", 150, 1970);
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(250, 1950);
- ctx.lineTo(1050, 1950);
- ctx.stroke();
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 9;
- ctx.fillStyle = "rgba(255,255,255,0.5)";
+ break;
+ case "suiji":
+ if (this.random < this.randomList.length - 1) {
+ this.random += 1;
+ } else {
+ this.random = 0;
+ }
+ this.selection[0] = this.musicMx.findIndex((v) =>
+ v.includes(this.randomList[this.random])
+ );
+ this.selection[1] = this.musicMx[this.selection[0]].indexOf(
+ main.core.ui.music.randomList[main.core.ui.music.random]
+ );
- ctx.beginPath();
- ctx.moveTo(250, 1950);
- ctx.lineTo(800 * audio.volume + 250, 1950);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(800 * audio.volume + 250, 1950, 10, 0, 2 * Math.PI);
- ctx.fill();
- core.fillBoldText1(
- ctx,
- Math.floor(100 * audio.volume),
- 1120,
- 1970,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(48, true)
- );
- } else {
- //横屏
- core.fillRect(ctx, 0, 0, 2028, 1248, "#000000"); //黑色背景
- ctx.globalAlpha = 0.5; //透明度
- if (bg) ctx.drawImage(bg, 0, 0, 1280, 720, 0, 0, 2028, 1248); //绘制半透明背景图片
- ctx.globalAlpha = 1; //恢复为不透明
- core.setTextAlign(ctx, "center");
+ page = this.selection[0];
+ if (!this.stop)
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
- core.fillBoldText1(
- ctx,
- "◀离开",
- 110,
- 100,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- //core.fillRect(ctx, 440, 760, 50, 50)
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(800, 100);
- ctx.lineTo(800, 1148);
- ctx.moveTo(900, 100);
- ctx.lineTo(1900, 100);
- ctx.stroke();
- let posy = 200;
- const indexList = this.musicMx[page];
- core.setTextAlign(ctx, "left");
- for (let i = 0; i < indexList.length; i++) {
- const text = this.musicname[indexList[i]];
- core.fillBoldText1(
- ctx,
- text,
- 950,
- posy - 30,
- page === this.selection[0] && i === this.selection[1]
- ? "#FFFFFF"
- : "#444444",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(900, posy);
- ctx.lineTo(1900, posy);
- ctx.stroke();
- posy += 100;
- }
- core.fillBoldText1(
- ctx,
- "上一页",
- 1050,
- 1200 - 30,
- page === 0 ? "#444444" : "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, typebox)) {
+ switch (this.type) {
+ case "danqu":
+ this.type = "xunhuan";
+ break;
+ case "xunhuan":
+ this.type = "suiji";
+ break;
+ case "suiji":
+ this.type = "danqu";
+ break;
+ }
+ return;
+ }
+ if (inRect(pos, musicbox)) {
+ const index = Math.floor((py - 100) / 100);
+ if (page !== this.selection[0] || index !== this.selection[1]) {
+ this.selection[0] = page;
+ this.selection[1] = index;
+ this.randomList.indexOf(
+ (v) => v === this.musicMx[this.selection[0]][this.selection[1]]
+ );
- core.fillBoldText1(
- ctx,
- page + 1 + "/" + this.musicMx.length,
- 1350,
- 1200 - 30,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- core.fillBoldText1(
- ctx,
- "下一页",
- 1550,
- 1200 - 30,
- page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(66, true)
- );
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(100, 600);
- ctx.lineTo(700, 600);
- ctx.stroke();
- ctx.fillStyle = "#ffffff";
- ctx.font = "bold 48px Verdana";
- ctx.fillText("|", 130, 797);
- ctx.fillText("◀", 140, 800);
- ctx.beginPath();
- ctx.arc(310, 780, 50, 0, 2 * Math.PI);
- ctx.stroke();
- if (this.stop) {
- ctx.fillText("▶", 295, 797);
- } else {
- ctx.fillText("||", 285, 794);
- }
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
+ this.stop = false;
+ } else {
+ if (this.stop) {
+ this.stop = !this.stop;
+ core.resumeBgm();
+ } else {
+ this.stop = !this.stop;
+ core.pauseBgm();
+ }
+ }
+ return;
+ }
- ctx.fillText("|", 470, 797);
- ctx.fillText("▶", 450, 800);
- ctx.fillText("音量", 350, 900);
- ctx.beginPath();
- ctx.moveTo(100, 1000);
- ctx.lineTo(700, 1000);
- ctx.stroke();
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 9;
- ctx.fillStyle = "rgba(255,255,255,0.5)";
+ if (inRect(pos, volumebox)) {
+ const time = Math.min(Math.max((px - 100) / 600, 0), 1);
+ audio.setVolume(time);
+ core.plugin.audioSystem.soundPlayer.setVolume(time);
+ isvolume = true;
+ }
+ }
+ }
+ mousemove(px, py) {
+ if (isvolume) {
+ if (core.domStyle.isVertical) {
+ const time = Math.min(Math.max((px - 250) / 800, 0), 1);
+ audio.setVolume(time);
+ core.plugin.audioSystem.soundPlayer.setVolume(time);
+ } else {
+ const time = Math.min(Math.max((px - 100) / 600, 0), 1);
+ audio.setVolume(time);
+ core.plugin.audioSystem.soundPlayer.setVolume(time);
+ }
+ }
+ }
- ctx.beginPath();
- ctx.moveTo(100, 1000);
- ctx.lineTo(600 * audio.volume + 100, 1000);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(600 * audio.volume + 100, 1000, 10, 0, 2 * Math.PI);
- ctx.fill();
- core.fillBoldText1(
- ctx,
- Math.floor(100 * audio.volume),
- 720,
- 1010,
- "#FFFFFF",
- "#000000",
- 6,
- core.ui._buildFont(32, true)
- );
- const img = core.material.images.images[this.type + ".webp"];
- if (img) ctx.drawImage(img, 580, 730, 100, 100);
- core.setTextAlign(ctx, "center");
- ctx.font = "bold 48px Verdana";
- ctx.fillText("当前歌曲", 400, 297);
- ctx.fillText(
- this.musicname[this.musicMx[this.selection[0]][this.selection[1]]],
- 400,
- 397
- );
+ drawUI() {
+ //绘制页面
+ core.clearMap(music);
+ const bgVertical = core.material.images.images["bg_2010.webp"]; //竖屏背景
+ const bg = core.material.images.images["bg_5043.webp"]; //竖屏背景
+ if (core.domStyle.isVertical) {
+ //竖屏
- ctx.font = "bold 36px Verdana";
- const thistime = audio.currentTime;
+ core.fillRect(ctx, 0, 0, 1248, 2028, "#000000"); //黑色背景
+ ctx.globalAlpha = 0.3; //透明度
+ if (bgVertical)
+ ctx.drawImage(bgVertical, 0, 0, 1280, 1500, 0, 0, 1248, 2028); //绘制半透明背景图片
+ ctx.globalAlpha = 1; //恢复为不透明
- if (thistime) {
- const timetext =
- Math.floor(thistime / 60)
- .toString()
- .padStart(2, "0") +
- ":" +
- Math.floor(thistime % 60)
- .toString()
- .padStart(2, "0");
- ctx.fillText(timetext, 510, 650);
- } else {
- const timetext = "00:00";
- ctx.fillText(timetext, 510, 650);
- }
- ctx.fillText("/", 580, 650);
- const fulltime = audio.duration;
+ core.setTextAlign(ctx, "center");
+ core.fillBoldText1(
+ ctx,
+ "◀离开",
+ 110,
+ 100,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
- if (fulltime) {
- const timetext =
- Math.floor(fulltime / 60)
- .toString()
- .padStart(2, "0") +
- ":" +
- Math.floor(fulltime % 60)
- .toString()
- .padStart(2, "0");
- ctx.fillText(timetext, 650, 650);
- } else {
- const timetext = "00:00";
- ctx.fillText(timetext, 650, 650);
- }
- ctx.strokeStyle = "#ffffff";
- ctx.lineWidth = 9;
- ctx.fillStyle = "rgba(255,255,255,0.5)";
- const pointx = (600 * thistime) / fulltime + 100;
- if (fulltime && thistime) {
- ctx.beginPath();
- ctx.moveTo(100, 600);
- ctx.lineTo(pointx, 600);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(pointx, 600, 10, 0, 2 * Math.PI);
- ctx.fill();
- } else {
- ctx.beginPath();
- ctx.arc(100, 600, 10, 0, 2 * Math.PI);
- ctx.fill();
- }
- }
- }
- }
- core.ui.music = new musicclass();
- main.dom.musicMode.onclick = function () {
- //点击开始页面的CG MODE进入cg回廊
- main.core.control.checkBgm();
- main.core.control.pauseBgm();
- audio.src =
- "project/bgms/" +
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
- main.core.ui.music.selection[1]
- ];
- const arr = main.core.ui.music.musicMx.flat(Infinity);
- main.core.ui.music.randomList = shuffle(arr);
- main.core.ui.music.random = main.core.ui.music.randomList.indexOf(
- main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
- main.core.ui.music.selection[1]
- ]
- );
- page = 0;
- music.style.display = "block";
- let time = 0;
- core.registerAnimationFrame("music", null, (temptime) => {
- if (temptime > time + 1000 / 60) {
- time = temptime;
- main.core.ui.music.update();
- }
- });
- };
- },
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(100, 200);
+ ctx.lineTo(1148, 200);
+
+ ctx.stroke();
+ let posy = 300;
+ const indexList = this.musicMx[page];
+ core.setTextAlign(ctx, "left");
+ for (let i = 0; i < indexList.length; i++) {
+ const text = this.musicname[indexList[i]];
+ core.fillBoldText1(
+ ctx,
+ text,
+ 150,
+ posy - 30,
+ page === this.selection[0] && i === this.selection[1] ?
+ "#FFFFFF" :
+ "#444444",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(100, posy);
+ ctx.lineTo(1148, posy);
+ ctx.stroke();
+ posy += 100;
+ }
+ ctx.beginPath();
+ ctx.moveTo(100, 1210);
+ ctx.lineTo(1148, 1210);
+ ctx.moveTo(100, 1200);
+ ctx.lineTo(1148, 1200);
+ ctx.stroke();
+
+ core.fillBoldText1(
+ ctx,
+ "上一页",
+ 100,
+ 1300,
+ page === 0 ? "#444444" : "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+
+ core.fillBoldText1(
+ ctx,
+ page + 1 + "/" + this.musicMx.length,
+ 580,
+ 1300,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+ core.fillBoldText1(
+ ctx,
+ "下一页",
+ 950,
+ 1300,
+ page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+
+ ctx.strokeStyle = "#ffffff";
+ ctx.lineWidth = 3;
+
+ ctx.fillStyle = "#ffffff";
+ ctx.font = "bold 96px Verdana";
+ ctx.fillText("|", 100, 1697);
+ ctx.fillText("◀", 115, 1700);
+ ctx.beginPath();
+ ctx.arc(505, 1670, 80, 0, 3 * Math.PI);
+ ctx.stroke();
+ ctx.fillText("|", 835, 1697);
+ ctx.fillText("▶", 785, 1700);
+ if (this.stop) {
+ ctx.fillText("▶", 473, 1697);
+ } else {
+ ctx.fillText("||", 453, 1694);
+ }
+
+ const img = core.material.images.images[this.type + ".webp"];
+ if (img) ctx.drawImage(img, 1000, 1555, 200, 200);
+ core.setTextAlign(ctx, "center");
+ ctx.font = "bold 52px Verdana";
+ ctx.fillText("当前歌曲", 625, 1397);
+ ctx.fillText(
+ this.musicname[this.musicMx[this.selection[0]][this.selection[1]]],
+ 625,
+ 1507
+ );
+
+ ctx.fillStyle = "#ffffff";
+ ctx.font = "bold 48px Verdana";
+ ctx.fillText("音量", 150, 1970);
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(250, 1950);
+ ctx.lineTo(1050, 1950);
+ ctx.stroke();
+ ctx.strokeStyle = "#ffffff";
+ ctx.lineWidth = 9;
+ ctx.fillStyle = "rgba(255,255,255,0.5)";
+
+ ctx.beginPath();
+ ctx.moveTo(250, 1950);
+ ctx.lineTo(800 * audio.getVolume() + 250, 1950);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(800 * audio.getVolume() + 250, 1950, 10, 0, 2 * Math.PI);
+ ctx.fill();
+ core.fillBoldText1(
+ ctx,
+ Math.floor(100 * audio.getVolume()),
+ 1120,
+ 1970,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(56, true)
+ );
+ } else {
+ //横屏
+
+ core.fillRect(ctx, 0, 0, 2028, 1248, "#000000"); //黑色背景
+ ctx.globalAlpha = 0.5; //透明度
+ if (bg) ctx.drawImage(bg, 0, 0, 1280, 720, 0, 0, 2028, 1248); //绘制半透明背景图片
+ ctx.globalAlpha = 1; //恢复为不透明
+ core.setTextAlign(ctx, "center");
+
+ core.fillBoldText1(
+ ctx,
+ "◀离开",
+ 110,
+ 100,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(800, 100);
+ ctx.lineTo(800, 1148);
+ ctx.moveTo(900, 100);
+ ctx.lineTo(1900, 100);
+ ctx.stroke();
+ let posy = 200;
+ const indexList = this.musicMx[page];
+ core.setTextAlign(ctx, "left");
+ for (let i = 0; i < indexList.length; i++) {
+ const text = this.musicname[indexList[i]];
+ core.fillBoldText1(
+ ctx,
+ text,
+ 950,
+ posy - 30,
+ page === this.selection[0] && i === this.selection[1] ?
+ "#FFFFFF" :
+ "#444444",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(900, posy);
+ ctx.lineTo(1900, posy);
+ ctx.stroke();
+ posy += 100;
+ }
+ core.fillBoldText1(
+ ctx,
+ "上一页",
+ 1050,
+ 1200 - 30,
+ page === 0 ? "#444444" : "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+
+ core.fillBoldText1(
+ ctx,
+ page + 1 + "/" + this.musicMx.length,
+ 1350,
+ 1200 - 30,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+ core.fillBoldText1(
+ ctx,
+ "下一页",
+ 1550,
+ 1200 - 30,
+ page === this.musicMx.length - 1 ? "#444444" : "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(66, true)
+ );
+ ctx.strokeStyle = "#ffffff";
+ ctx.lineWidth = 3;
+
+ ctx.fillStyle = "#ffffff";
+ ctx.font = "bold 96px Verdana";
+ ctx.fillText("|", 60, 697);
+ ctx.fillText("◀", 70, 700);
+ ctx.beginPath();
+ ctx.arc(295, 670, 80, 0, 2 * Math.PI);
+ ctx.stroke();
+ if (this.stop) {
+ ctx.fillText("▶", 245, 697);
+ } else {
+ ctx.fillText("||", 245, 694);
+ }
+
+ ctx.fillText("|", 490, 697);
+ ctx.fillText("▶", 450, 700);
+ ctx.font = "bold 48px Verdana";
+ ctx.fillText("音量", 350, 900);
+ ctx.beginPath();
+ ctx.moveTo(100, 1000);
+ ctx.lineTo(700, 1000);
+ ctx.stroke();
+ ctx.strokeStyle = "#ffffff";
+ ctx.lineWidth = 9;
+ ctx.fillStyle = "rgba(255,255,255,0.5)";
+
+ ctx.beginPath();
+ ctx.moveTo(100, 1000);
+ ctx.lineTo(600 * audio.getVolume() + 100, 1000);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(600 * audio.getVolume() + 100, 1000, 10, 0, 2 * Math.PI);
+ ctx.fill();
+ core.fillBoldText1(
+ ctx,
+ Math.floor(100 * audio.getVolume()),
+ 720,
+ 1010,
+ "#FFFFFF",
+ "#000000",
+ 6,
+ core.ui._buildFont(56, true)
+ );
+ const img = core.material.images.images[this.type + ".webp"];
+ if (img) ctx.drawImage(img, 580, 560, 200, 200);
+ core.setTextAlign(ctx, "center");
+ ctx.font = "bold 48px Verdana";
+ ctx.fillText("当前歌曲", 400, 297);
+ ctx.fillText(
+ this.musicname[this.musicMx[this.selection[0]][this.selection[1]]],
+ 400,
+ 397
+ );
+ }
+ }
+ }
+ core.ui.music = new musicclass();
+ main.dom.musicMode.onclick = function () {
+ //点击开始页面的CG MODE进入cg回廊
+
+ core.playBgm(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
+
+ const arr = main.core.ui.music.musicMx.flat(Infinity);
+ main.core.ui.music.randomList = shuffle(arr);
+ main.core.ui.music.random = main.core.ui.music.randomList.indexOf(
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ );
+ page = 0;
+ music.style.display = "block";
+ let time = 0;
+ core.registerAnimationFrame("music", null, (temptime) => {
+ if (temptime > time + 1000 / 60) {
+ time = temptime;
+ main.core.ui.music.update();
+ const duration =
+ core.plugin.audioSystem.bgmController.player.getRoute(
+ "bgms." +
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ ).duration;
+
+ const currentTime =
+ core.plugin.audioSystem.bgmController.player.getRoute(
+ "bgms." +
+ main.core.ui.music.musicMx[main.core.ui.music.selection[0]][
+ main.core.ui.music.selection[1]
+ ]
+ ).currentTime;
+ if (currentTime && duration && duration - currentTime < 0.05) {
+ if (core.domStyle.isVertical) {
+ core.ui.music.mousedown(830, 1770);
+ } else {
+ core.ui.music.mousedown(475, 765);
+ }
+ }
+ }
+ });
+ };
+},
"横屏切换": function () {
// 在此增加新插件
this.triggerFullscreen = async function (full) {
@@ -15540,11 +17493,13 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
(one.farme - beforefarme)) /
(afterfarme - beforefarme || 1),
angle =
- (Math.PI * (image.angel ?? 0)) / 180 +
- ((Math.PI * (image.aangel ?? 0)) / 180 -
- ((Math.PI * (image.angel ?? 0)) / 180) *
- (one.farme - beforefarme)) /
- (afterfarme - beforefarme || 1);
+ (Math.PI *
+ ((image.image.angle ?? 0) +
+ (((image.aangle ?? 0) - (image.image.angle ?? 0)) *
+ (one.farme - beforefarme)) /
+ (afterfarme - beforefarme || 1))) /
+ 180;
+
if (one.hero) {
let sx, sy;
if (core.status.heroMoving < 0) {
@@ -15609,2062 +17564,5 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
});
}
});
- },
- "音频系统": function () {
- // 在此增加新插件
- /*首先,在造塔群下载所需的库文件,然后放置在塔目录下的 libs/thirdparty 或其他目录下,之后在 index.html 的最后加上下面这几行:
-
-
-
-
-
-
- */
- // 将__enable置为false将关闭插件
- let __enable = true;
- if (!__enable || main.mode === "editor") return;
- const { OggOpusDecoderWebWorker } = window["ogg-opus-decoder"];
- const { OggVorbisDecoderWebWorker } = window["ogg-vorbis-decoder"];
- const { CodecParser } = window.CodecParser;
- const { Transition, linear } = core.plugin.animate;
-
- const audio = new Audio();
-
- const supportMap = new Map();
- const AudioType = {
- Mp3: "audio/mpeg",
- Wav: 'audio/wav; codecs="1"',
- Flac: "audio/flac",
- Opus: 'audio/ogg; codecs="opus"',
- Ogg: 'audio/ogg; codecs="vorbis"',
- Aac: "audio/aac",
- };
- /**
- * 检查一种音频类型是否能被播放
- * @param type 音频类型 AudioType
- */
- function isAudioSupport(type) {
- if (supportMap.has(type)) return supportMap.get(type);
- else {
- const support = audio.canPlayType(type);
- const canPlay = support === "maybe" || support === "probably";
- supportMap.set(type, canPlay);
- return canPlay;
- }
- }
-
- const typeMap = new Map([
- ["ogg", AudioType.Ogg],
- ["mp3", AudioType.Mp3],
- ["wav", AudioType.Wav],
- ["flac", AudioType.Flac],
- ["opus", AudioType.Opus],
- ["aac", AudioType.Aac],
- ]);
-
- /**
- * 根据文件名拓展猜测其类型
- * @param file 文件名 string
- */
- function guessTypeByExt(file) {
- const ext = /\.[a-zA-Z\d]+$/.exec(file);
- if (!ext?.[0]) return "";
- const type = ext[0].slice(1);
- return typeMap.get(type.toLocaleLowerCase()) ?? "";
- }
-
- isAudioSupport(AudioType.Ogg);
- isAudioSupport(AudioType.Mp3);
- isAudioSupport(AudioType.Wav);
- isAudioSupport(AudioType.Flac);
- isAudioSupport(AudioType.Opus);
- isAudioSupport(AudioType.Aac);
-
- function isNil(value) {
- return value === void 0 || value === null;
- }
-
- function sleep(time) {
- return new Promise((res) => setTimeout(res, time));
- }
- class AudioEffect {
- constructor(ac) {}
- /**
- * 连接至其他效果器
- * @param target 目标输入 IAudioInput
- * @param output 当前效果器输出通道 Number
- * @param input 目标效果器的输入通道 Number
- */
- connect(target, output, input) {
- this.output.connect(target.input, output, input);
- }
-
- /**
- * 与其他效果器取消连接
- * @param target 目标输入 IAudioInput
- * @param output 当前效果器输出通道 Number
- * @param input 目标效果器的输入通道 Number
- */
- disconnect(target, output, input) {
- if (!target) {
- if (!isNil(output)) {
- this.output.disconnect(output);
- } else {
- this.output.disconnect();
- }
- } else {
- if (!isNil(output)) {
- if (!isNil(input)) {
- this.output.disconnect(target.input, output, input);
- } else {
- this.output.disconnect(target.input, output);
- }
- } else {
- this.output.disconnect(target.input);
- }
- }
- }
- }
-
- class StereoEffect extends AudioEffect {
- constructor(ac) {
- super(ac);
- const panner = ac.createPanner();
- this.input = panner;
- this.output = panner;
- }
-
- /**
- * 设置音频朝向,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户
- * @param x 朝向x坐标 Number
- * @param y 朝向y坐标 Number
- * @param z 朝向z坐标 Number
- */
- setOrientation(x, y, z) {
- this.output.orientationX.value = x;
- this.output.orientationY.value = y;
- this.output.orientationZ.value = z;
- }
- /**
- * 设置音频位置,x正方形水平向右,y正方形垂直于地面向上,z正方向垂直屏幕远离用户
- * @param x 位置x坐标 Number
- * @param y 位置y坐标 Number
- * @param z 位置z坐标 Number
- */
- setPosition(x, y, z) {
- this.output.positionX.value = x;
- this.output.positionY.value = y;
- this.output.positionZ.value = z;
- }
- end() {}
-
- start() {}
- }
- class VolumeEffect extends AudioEffect {
- constructor(ac) {
- super(ac);
- const gain = ac.createGain();
- this.input = gain;
- this.output = gain;
- }
-
- /**
- * 设置音量大小
- * @param volume 音量大小 Number
- */
- setVolume(volume) {
- this.output.gain.value = volume;
- }
-
- /**
- * 获取音量大小 Number
- */
- getVolume() {
- return this.output.gain.value;
- }
-
- end() {}
-
- start() {}
- }
- class ChannelVolumeEffect extends AudioEffect {
- /** 所有的音量控制节点 */
-
- constructor(ac) {
- super(ac);
- /** 所有的音量控制节点 */
- this.gain = [];
- const splitter = ac.createChannelSplitter();
- const merger = ac.createChannelMerger();
- this.output = merger;
- this.input = splitter;
- for (let i = 0; i < 6; i++) {
- const gain = ac.createGain();
- splitter.connect(gain, i);
- gain.connect(merger, 0, i);
- this.gain.push(gain);
- }
- }
-
- /**
- * 设置某个声道的音量大小
- * @param channel 要设置的声道,可填0-5 Number
- * @param volume 这个声道的音量大小 Number
- */
- setVolume(channel, volume) {
- if (!this.gain[channel]) return;
- this.gain[channel].gain.value = volume;
- }
-
- /**
- * 获取某个声道的音量大小,可填0-5
- * @param channel 要获取的声道 Number
- */
- getVolume(channel) {
- if (!this.gain[channel]) return 0;
- return this.gain[channel].gain.value;
- }
-
- end() {}
-
- start() {}
- }
- class DelayEffect extends AudioEffect {
- constructor(ac) {
- super(ac);
-
- const delay = ac.createDelay();
- this.input = delay;
- this.output = delay;
- }
-
- /**
- * 设置延迟时长
- * @param delay 延迟时长,单位秒 Number
- */
- setDelay(delay) {
- this.output.delayTime.value = delay;
- }
-
- /**
- * 获取延迟时长
- */
- getDelay() {
- return this.output.delayTime.value;
- }
-
- end() {}
-
- start() {}
- }
- class EchoEffect extends AudioEffect {
- constructor(ac) {
- super(ac);
- const delay = ac.createDelay();
- const gain = ac.createGain();
- gain.gain.value = 0.5;
- delay.delayTime.value = 0.05;
- delay.connect(gain);
- gain.connect(delay);
- /** 延迟节点 */
- this.delay = delay;
- /** 反馈增益节点 */
- this.gainNode = gain;
- /** 当前增益 */
- this.gain = 0.5;
- /** 是否正在播放 */
- this.playing = false;
- this.input = gain;
- this.output = gain;
- }
-
- /**
- * 设置回声反馈增益大小
- * @param gain 增益大小,范围 0-1,大于等于1的视为0.5,小于0的视为0 Number
- */
- setFeedbackGain(gain) {
- const resolved = gain >= 1 ? 0.5 : gain < 0 ? 0 : gain;
- this.gain = resolved;
- if (this.playing) this.gainNode.gain.value = resolved;
- }
-
- /**
- * 设置回声间隔时长
- * @param delay 回声时长,范围 0.01-Infinity,小于0.01的视为0.01 Number
- */
- setEchoDelay(delay) {
- const resolved = delay < 0.01 ? 0.01 : delay;
- this.delay.delayTime.value = resolved;
- }
-
- /**
- * 获取反馈节点增益
- */
- getFeedbackGain() {
- return this.gain;
- }
-
- /**
- * 获取回声间隔时长
- */
- getEchoDelay() {
- return this.delay.delayTime.value;
- }
-
- end() {
- this.playing = false;
- const echoTime = Math.ceil(Math.log(0.001) / Math.log(this.gain)) + 10;
- sleep(this.delay.delayTime.value * echoTime).then(() => {
- if (!this.playing) this.gainNode.gain.value = 0;
- });
- }
-
- start() {
- this.playing = true;
- this.gainNode.gain.value = this.gain;
- }
- }
-
- class StreamLoader {
- constructor(url) {
- /** 传输目标 Set*/
- this.target = new Set();
- this.loading = false;
- }
-
- /**
- * 将加载流传递给字节流读取对象
- * @param reader 字节流读取对象 IStreamReader
- */
- pipe(reader) {
- if (this.loading) {
- console.warn(
- "Cannot pipe new StreamReader object when stream is loading."
- );
- return;
- }
- this.target.add(reader);
- reader.piped(this);
- return this;
- }
-
- async start() {
- if (this.loading) return;
- this.loading = true;
- const response = await window.fetch(this.url);
- const stream = response.body;
- if (!stream) {
- console.error("Cannot get reader when fetching '" + this.url + "'.");
- return;
- }
- // 获取读取器
- /** 读取流对象 */
- this.stream = stream;
- const reader = response.body?.getReader();
- const targets = [...this.target];
-
-
- await Promise.all(targets.map((v) => v.start(stream, this, response)));
- if (reader && reader.read) {
- // 开始流传输
- while (true) {
- const { value, done } = await reader.read();
- await Promise.all(
- targets.map(v => v.pump(value, done, response))
- );
- if (done) break;
- }
- } else {
- // 如果不支持流传输
- const buffer = await response.arrayBuffer();
- const data = new Uint8Array(buffer);
- await Promise.all(targets.map(v => v.pump(data, true, response)));
- }
- // 开始流传输
- while (true) {
- const { value, done } = await reader.read();
- await Promise.all(targets.map((v) => v.pump(value, done, response)));
- if (done) break;
- }
-
- this.loading = false;
- targets.forEach((v) => v.end(true));
-
- //
- }
-
- cancel(reason) {
- if (!this.stream) return;
- this.stream.cancel(reason);
- this.loading = false;
- this.target.forEach((v) => v.end(false, reason));
- }
- }
- const fileSignatures = [
- [AudioType.Mp3, [0x49, 0x44, 0x33]],
- [AudioType.Ogg, [0x4f, 0x67, 0x67, 0x53]],
- [AudioType.Wav, [52, 0x49, 0x46, 0x46]],
- [AudioType.Flac, [0x66, 0x4c, 0x61, 0x43]],
- [AudioType.Aac, [0xff, 0xf1]],
- [AudioType.Aac, [0xff, 0xf9]]
- ];
- const oggHeaders = [
- [AudioType.Opus, [0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]]
- ];
-
- function checkAudioType(data) {
- let audioType = '';
- // 检查头文件获取音频类型,仅检查前256个字节
- const toCheck = data.slice(0, 256);
- for (const [type, value] of fileSignatures) {
- if (value.every((v, i) => toCheck[i] === v)) {
- audioType = type;
- break;
- }
- }
- if (audioType === AudioType.Ogg) {
- // 如果是ogg的话,进一步判断是不是opus
- for (const [key, value] of oggHeaders) {
- const has = toCheck.some((_, i) => {
- return value.every((v, ii) => toCheck[i + ii] === v);
- });
- if (has) {
- audioType = key;
- break;
- }
- }
- }
-
- return audioType;
- }
-
- const mimeTypeMap = {
- [AudioType.Aac]: "audio/aac",
- [AudioType.Flac]: "audio/flac",
- [AudioType.Mp3]: "audio/mpeg",
- [AudioType.Ogg]: "application/ogg",
- [AudioType.Opus]: "application/ogg",
- [AudioType.Wav]: "application/ogg",
- };
-
- function isOggPage(data) {
- return !isNil(data.isFirstPage);
- }
- class AudioStreamSource {
- constructor(context) {
- this.output = context.createBufferSource();
- /** 是否已经完全加载完毕 */
- this.loaded = false;
-
- /** 已经缓冲了多长时间,如果缓冲完那么跟歌曲时长一致 */
- this.buffered = 0;
- /** 已经缓冲的采样点数量 */
- this.bufferedSamples = 0;
- /** 歌曲时长,加载完毕之前保持为 0 */
- this.duration = 0;
- /** 在流传输阶段,至少缓冲多长时间的音频之后才开始播放,单位秒 */
- this.bufferPlayDuration = 1;
- /** 音频的采样率,未成功解析出之前保持为 0 */
- this.sampleRate = 0;
- //是否循环播放
- this.loop = false;
- /** 上一次播放是从何时开始的 */
- this.lastStartWhen = 0;
- /** 开始播放时刻 */
- this.lastStartTime = 0;
- /** 上一次播放的缓存长度 */
- this.lastBufferSamples = 0;
-
- /** 是否已经获取到头文件 */
- this.headerRecieved = false;
- /** 音频类型 */
- this.audioType = "";
- /** 每多长时间组成一个缓存 Float32Array */
- this.bufferChunkSize = 10;
- /** 缓存音频数据,每 bufferChunkSize 秒钟组成一个 Float32Array,用于流式解码 */
- this.audioData = [];
-
- this.errored = false;
- this.ac = context;
- }
- /** 当前已经播放了多长时间 */
- get currentTime() {
- return this.ac.currentTime - this.lastStartTime + this.lastStartWhen;
- }
- /**
- * 设置每个缓存数据的大小,默认为10秒钟一个缓存数据
- * @param size 每个缓存数据的时长,单位秒
- */
- setChunkSize(size) {
- if (this.controller?.loading || this.loaded) return;
- this.bufferChunkSize = size;
- }
-
- piped(controller) {
- this.controller = controller;
- }
-
- async pump(data, done) {
- if (!data || this.errored) return;
- if (!this.headerRecieved) {
- // 检查头文件获取音频类型,仅检查前256个字节
- const toCheck = data.slice(0, 256);
- this.audioType = checkAudioType(data);
- if (!this.audioType) {
- console.error(
- "Unknown audio type. Header: '" + [...toCheck]
- .map((v) => v.toString().padStart(2, "0"))
- .join(" ")
- .toUpperCase() +
- "'"
- );
- return;
- }
- // 创建解码器
- const Decoder = AudioDecoder.decoderMap.get(this.audioType);
- if (!Decoder) {
- this.errored = true;
- console.error(
- "Cannot decode stream source type of '" +
- this.audioType +
- "', since there is no registered decoder for that type."
- );
- return Promise.reject(
- `Cannot decode stream source type of '${this.audioType}', since there is no registered decoder for that type.`
- );
- }
- this.decoder = new Decoder();
- // 创建数据解析器
- const mime = mimeTypeMap[this.audioType];
- const parser = new CodecParser(mime);
- this.parser = parser;
- await this.decoder.create();
- this.headerRecieved = true;
- }
-
- const decoder = this.decoder;
- const parser = this.parser;
- if (!decoder || !parser) {
- this.errored = true;
- return Promise.reject(
- "No parser or decoder attached in this AudioStreamSource"
- );
- }
-
- await this.decodeData(data, decoder, parser);
- if (done) await this.decodeFlushData(decoder, parser);
- this.checkBufferedPlay();
- }
-
- /**
- * 检查采样率,如果还未解析出采样率,那么将设置采样率,如果当前采样率与之前不同,那么发出警告
- */
- checkSampleRate(info) {
- for (const one of info) {
- const frame = isOggPage(one) ? one.codecFrames[0] : one;
- if (frame) {
- const rate = frame.header.sampleRate;
- if (this.sampleRate === 0) {
- this.sampleRate = rate;
- break;
- } else {
- if (rate !== this.sampleRate) {
- console.warn("Sample rate in stream audio must be constant.");
- }
- }
- }
- }
- }
-
- /**
- * 解析音频数据
- */
- async decodeData(data, decoder, parser) {
- // 解析音频数据
- const audioData = await decoder.decode(data);
- if (!audioData) return;
- // @ts-expect-error 库类型声明错误
- const audioInfo = [...parser.parseChunk(data)];
-
- // 检查采样率
- this.checkSampleRate(audioInfo);
- // 追加音频数据
- this.appendDecodedData(audioData, audioInfo);
- }
-
- /**
- * 解码剩余数据
- */
- async decodeFlushData(decoder, parser) {
- const audioData = await decoder.flush();
- if (!audioData) return;
- // @ts-expect-error 库类型声明错误
- const audioInfo = [...parser.flush()];
-
- this.checkSampleRate(audioInfo);
- this.appendDecodedData(audioData, audioInfo);
- }
-
- /**
- * 追加音频数据
- */
- appendDecodedData(data, info) {
- const channels = data.channelData.length;
- if (channels === 0) return;
- if (this.audioData.length !== channels) {
- this.audioData = [];
- for (let i = 0; i < channels; i++) {
- this.audioData.push([]);
- }
- }
- // 计算出应该放在哪
- const chunk = this.sampleRate * this.bufferChunkSize;
- const sampled = this.bufferedSamples;
- const pushIndex = Math.floor(sampled / chunk);
- const bufferIndex = sampled % chunk;
- const dataLength = data.channelData[0].length;
- let buffered = 0;
- let nowIndex = pushIndex;
- let toBuffer = bufferIndex;
- while (buffered < dataLength) {
- const rest = toBuffer !== 0 ? chunk - bufferIndex : chunk;
-
- for (let i = 0; i < channels; i++) {
- const audioData = this.audioData[i];
- if (!audioData[nowIndex]) {
- audioData.push(new Float32Array(chunk));
- }
- const toPush = data.channelData[i].slice(buffered, buffered + rest);
-
- audioData[nowIndex].set(toPush, toBuffer);
- }
- buffered += rest;
- nowIndex++;
- toBuffer = 0;
- }
-
- this.buffered +=
- info.reduce((prev, curr) => prev + curr.duration, 0) / 1000;
- this.bufferedSamples += info.reduce(
- (prev, curr) => prev + curr.samples,
- 0
- );
- }
-
- /**
- * 检查已缓冲内容,并在未开始播放时播放
- */
- checkBufferedPlay() {
- if (this.playing || this.sampleRate === 0) return;
- const played = this.lastBufferSamples / this.sampleRate;
- const dt = this.buffered - played;
- if (this.loaded) {
- this.playAudio(played);
- return;
- }
- if (dt < this.bufferPlayDuration) return;
-
- this.lastBufferSamples = this.bufferedSamples;
- // 需要播放
- this.mergeBuffers();
- if (!this.buffer) return;
- if (this.playing) this.output.stop();
- this.createSourceNode(this.buffer);
- this.output.loop = false;
- this.output.start(0, played);
- this.lastStartTime = this.ac.currentTime;
- this.playing = true;
- this.output.addEventListener("ended", () => {
- this.playing = false;
- this.checkBufferedPlay();
- });
- }
-
- mergeBuffers() {
- const buffer = this.ac.createBuffer(
- this.audioData.length,
- this.bufferedSamples,
- this.sampleRate
- );
- const chunk = this.sampleRate * this.bufferChunkSize;
- const bufferedChunks = Math.floor(this.bufferedSamples / chunk);
- const restLength = this.bufferedSamples % chunk;
- for (let i = 0; i < this.audioData.length; i++) {
- const audio = this.audioData[i];
- const data = new Float32Array(this.bufferedSamples);
- for (let j = 0; j < bufferedChunks; j++) {
- data.set(audio[j], chunk * j);
- }
- if (restLength !== 0) {
- data.set(
- audio[bufferedChunks].slice(0, restLength),
- chunk * bufferedChunks
- );
- }
-
- buffer.copyToChannel(data, i, 0);
- }
- this.buffer = buffer;
- }
-
- async start() {
- delete this.buffer;
- this.headerRecieved = false;
- this.audioType = "";
- this.errored = false;
- this.buffered = 0;
- this.sampleRate = 0;
- this.bufferedSamples = 0;
- this.duration = 0;
- this.loaded = false;
- if (this.playing) this.output.stop();
- this.playing = false;
- this.lastStartTime = this.ac.currentTime;
- }
-
- end(done, reason) {
- if (done && this.buffer) {
- this.loaded = true;
- delete this.controller;
- this.mergeBuffers();
-
- this.duration = this.buffered;
- this.audioData = [];
- this.decoder?.destroy();
- delete this.decoder;
- delete this.parser;
- } else {
- console.warn(
- "Unexpected end when loading stream audio, reason: '" +
- (reason ?? "") +
- "'"
- );
- }
- }
-
- playAudio(when) {
- if (!this.buffer) return;
- this.lastStartTime = this.ac.currentTime;
- if (this.playing) this.output.stop();
-
- this.createSourceNode(this.buffer);
- this.output.start(0, when);
- this.playing = true;
-
-
- this.output.addEventListener("ended", () => {
- this.playing = false;
-
- if (this.loop && !this.output.loop) this.play(0);
- });
- }
- /**
- * 开始播放这个音频源
- */
- play(when) {
- if (this.playing || this.errored) return;
- if (this.loaded && this.buffer) {
- this.playing = true;
- this.playAudio(when);
- } else {
- this.controller?.start();
- }
- }
-
- createSourceNode(buffer) {
- if (!this.target) return;
- const node = this.ac.createBufferSource();
- node.buffer = buffer;
- if (this.playing) this.output.stop();
- this.playing = false;
- this.output = node;
- node.connect(this.target.input);
- node.loop = this.loop;
- }
- /**
- * 停止播放这个音频源
- * @returns 音频暂停的时刻 number
- */
- stop() {
- if (this.playing) this.output.stop();
- this.playing = false;
- return this.ac.currentTime - this.lastStartTime;
- }
- /**
- * 连接到音频路由图上,每次调用播放的时候都会执行一次
- * @param target 连接至的目标 IAudioInput
- */
- connect(target) {
- this.target = target;
- }
- /**
- * 设置是否循环播放
- * @param loop 是否循环 boolean)
- */
- setLoop(loop) {
- this.loop = loop;
- }
- }
- class AudioElementSource {
- constructor(context) {
- const audio = new Audio();
- audio.preload = "none";
- this.output = context.createMediaElementSource(audio);
- this.audio = audio;
- audio.addEventListener("play", () => {
- this.playing = true;
- });
- audio.addEventListener("ended", () => {
- this.playing = false;
- this.ac = context;
- });
- }
- get duration() {
- return this.audio.duration;
- }
- get currentTime() {
- return this.audio.currentTime;
- }
- /**
- * 设置音频源的路径
- * @param url 音频路径
- */
- setSource(url) {
- this.audio.src = url;
- }
-
- play(when = 0) {
- if (this.playing) return;
- this.audio.currentTime = when;
- this.audio.play();
- }
-
- stop() {
- this.audio.pause();
- this.playing = false;
-
- return this.audio.currentTime;
- }
-
- connect(target) {
- this.output.connect(target.input);
- }
-
- setLoop(loop) {
- this.audio.loop = loop;
- }
- }
- class AudioBufferSource {
- constructor(context) {
- this.output = context.createBufferSource();
- /** 是否循环 */
- this.loop = false;
- /** 上一次播放是从何时开始的 */
- this.lastStartWhen = 0;
- /** 播放开始时刻 */
- this.lastStartTime = 0;
- this.duration = 0;
- this.ac = context;
- }
- get currentTime() {
- return this.ac.currentTime - this.lastStartTime + this.lastStartWhen;
- }
-
- /**
- * 设置音频源数据
- * @param buffer 音频源,可以是未解析的 ArrayBuffer,也可以是已解析的 AudioBuffer
- */
- async setBuffer(buffer) {
- if (buffer instanceof ArrayBuffer) {
- this.buffer = await this.ac.decodeAudioData(buffer);
- } else {
- this.buffer = buffer;
- }
- this.duration = this.buffer.duration;
- }
-
- play(when) {
- if (this.playing || !this.buffer) return;
- this.playing = true;
- this.lastStartTime = this.ac.currentTime;
-
- this.createSourceNode(this.buffer);
- this.output.start(0, when);
- this.output.addEventListener("ended", () => {
- this.playing = false;
- if (this.loop && !this.output.loop) this.play(0);
- });
- }
-
- createSourceNode(buffer) {
- if (!this.target) return;
- const node = this.ac.createBufferSource();
- node.buffer = buffer;
- this.output = node;
- node.connect(this.target.input);
- node.loop = this.loop;
- }
-
- stop() {
- this.output.stop();
- return this.ac.currentTime - this.lastStartTime;
- }
-
- connect(target) {
- this.target = target;
- }
-
- setLoop(loop) {
- this.loop = loop;
- }
- }
- class AudioPlayer {
- constructor() {
- /** 音频播放上下文 */
- this.ac = new AudioContext();
- /** 音量节点 */
- this.gain = this.ac.createGain();
- this.gain.connect(this.ac.destination);
- this.audioRoutes = new Map();
- }
- /**
- * 解码音频数据
- * @param data 音频数据
- */
- decodeAudioData(data) {
- return AudioDecoder.decodeAudioData(data, this);
- }
- /**
- * 设置音量
- * @param volume 音量
- */
- setVolume(volume) {
- this.gain.gain.value = volume;
- }
-
- /**
- * 获取音量
- */
- getVolume() {
- return this.gain.gain.value;
- }
-
- /**
- * 创建一个音频源
- * @param Source 音频源类
- */
- createSource(Source) {
- return new Source(this.ac);
- }
-
- /**
- * 创建一个兼容流式音频源,可以与流式加载相结合,主要用于处理 opus ogg 不兼容的情况
- */
- createStreamSource() {
- return new AudioStreamSource(this.ac);
- }
-
- /**
- * 创建一个通过 audio 元素播放的音频源
- */
- createElementSource() {
- return new AudioElementSource(this.ac);
- }
-
- /**
- * 创建一个通过 AudioBuffer 播放的音频源
- */
- createBufferSource() {
- return new AudioBufferSource(this.ac);
- }
-
- /**
- * 获取音频目的地
- */
- getDestination() {
- return this.gain;
- }
-
- /**
- * 创建一个音频效果器
- * @param Effect 效果器类
- */
- createEffect(Effect) {
- return new Effect(this.ac);
- }
-
- /**
- * 创建一个修改音量的效果器
- * ```txt
- * |----------|
- * Input ----> | GainNode | ----> Output
- * |----------|
- * ```
- */
- createVolumeEffect() {
- return new VolumeEffect(this.ac);
- }
-
- /**
- * 创建一个立体声效果器
- * ```txt
- * |------------|
- * Input ----> | PannerNode | ----> Output
- * |------------|
- * ```
- */
- createStereoEffect() {
- return new StereoEffect(this.ac);
- }
-
- /**
- * 创建一个修改单个声道音量的效果器
- * ```txt
- * |----------|
- * -> | GainNode | \
- * |--------------| / |----------| -> |------------|
- * Input ----> | SplitterNode | ...... | MergerNode | ----> Output
- * |--------------| \ |----------| -> |------------|
- * -> | GainNode | /
- * |----------|
- * ```
- */
- createChannelVolumeEffect() {
- return new ChannelVolumeEffect(this.ac);
- }
-
- /**
- * 创建一个延迟效果器
- * |-----------|
- * Input ----> | DelayNode | ----> Output
- * |-----------|
- */
- createDelay() {
- return new DelayEffect(this.ac);
- }
-
- /**
- * 创建一个回声效果器
- * ```txt
- * |----------|
- * Input ----> | GainNode | ----> Output
- * ^ |----------| |
- * | |
- * | |------------| ↓
- * |-- | Delay Node | <--
- * |------------|
- * ```
- */
- createEchoEffect() {
- return new EchoEffect(this.ac);
- }
-
- /**
- * 创建一个音频播放路由
- * @param source 音频源
- */
- createRoute(source) {
- return new AudioRoute(source, this);
- }
-
- /**
- * 添加一个音频播放路由,可以直接被播放
- * @param id 这个音频播放路由的名称
- * @param route 音频播放路由对象
- */
- addRoute(id, route) {
- if (!this.audioRoutes) this.audioRoutes = new Map();
- if (this.audioRoutes.has(id)) {
- console.warn(
- "Audio route with id of '" +
- id +
- "' has already existed. New route will override old route."
- );
- }
- this.audioRoutes.set(id, route);
- }
-
- /**
- * 根据名称获取音频播放路由对象
- * @param id 音频播放路由的名称
- */
- getRoute(id) {
- return this.audioRoutes.get(id);
- }
- /**
- * 移除一个音频播放路由
- * @param id 要移除的播放路由的名称
- */
- removeRoute(id) {
- this.audioRoutes.delete(id);
- }
- /**
- * 播放音频
- * @param id 音频名称
- * @param when 从音频的哪个位置开始播放,单位秒
- */
- play(id, when) {
- const route = this.getRoute(id);
- if (!route) {
- console.warn(
- "Cannot play audio route '" +
- id +
- "', since there is not added route named it."
- );
- return;
- }
- route.play(when);
- }
-
- /**
- * 暂停音频播放
- * @param id 音频名称
- * @returns 当音乐真正停止时兑现
- */
- pause(id) {
- const route = this.getRoute(id);
- if (!route) {
- console.warn(
- "Cannot pause audio route '" +
- id +
- "', since there is not added route named it."
- );
- return;
- }
- return route.pause();
- }
-
- /**
- * 停止音频播放
- * @param id 音频名称
- * @returns 当音乐真正停止时兑现
- */
- stop(id) {
- const route = this.getRoute(id);
- if (!route) {
- console.warn(
- "Cannot stop audio route '" +
- id +
- "', since there is not added route named it."
- );
- return;
- }
- return route.stop();
- }
-
- /**
- * 继续音频播放
- * @param id 音频名称
- */
- resume(id) {
- const route = this.getRoute(id);
- if (!route) {
- console.warn(
- "Cannot pause audio route '" +
- id +
- "', since there is not added route named it."
- );
- return;
- }
- route.resume();
- }
-
- /**
- * 设置听者位置,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
- * @param x 位置x坐标
- * @param y 位置y坐标
- * @param z 位置z坐标
- */
- setListenerPosition(x, y, z) {
- const listener = this.ac.listener;
- listener.positionX.value = x;
- listener.positionY.value = y;
- listener.positionZ.value = z;
- }
-
- /**
- * 设置听者朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
- * @param x 朝向x坐标
- * @param y 朝向y坐标
- * @param z 朝向z坐标
- */
- setListenerOrientation(x, y, z) {
- const listener = this.ac.listener;
- listener.forwardX.value = x;
- listener.forwardY.value = y;
- listener.forwardZ.value = z;
- }
-
- /**
- * 设置听者头顶朝向,x正方向水平向右,y正方向垂直于地面向上,z正方向垂直屏幕远离用户
- * @param x 头顶朝向x坐标
- * @param y 头顶朝向y坐标
- * @param z 头顶朝向z坐标
- */
- setListenerUp(x, y, z) {
- const listener = this.ac.listener;
- listener.upX.value = x;
- listener.upY.value = y;
- listener.upZ.value = z;
- }
- }
- const AudioStatus = {
- Playing: 0,
- Pausing: 1,
- Paused: 2,
- Stoping: 3,
- Stoped: 4,
- };
- const AudioRouteEvent = {
- updateEffect: [],
- play: [],
- stop: [],
- pause: [],
- resume: [],
- };
- class AudioRoute {
- constructor(source, player) {
- this.output = source.output;
- /** 效果器路由图 */
- this.effectRoute = [];
-
- /** 结束时长,当音频暂停或停止时,会经过这么长时间之后才真正终止播放,期间可以做音频淡入淡出等效果 */
- this.endTime = 0;
- /** 暂停时播放了多长时间 */
- this.pauseCurrentTime = 0;
- /** 当前播放状态 */
- this.status = AudioStatus.Stoped;
- this.shouldStop = false;
- /**
- * 每次暂停或停止时自增,用于判断当前正在处理的情况。
- * 假如暂停后很快播放,然后很快暂停,那么需要根据这个来判断实际是否应该执行暂停后操作
- */
- this.stopIdentifier = 0;
- /** 暂停时刻 */
- this.pauseTime = 0;
- this.source = source;
- this.player = player;
- }
- /** 音频时长,单位秒 */
- get duration() {
- return this.source.duration;
- }
- /** 当前播放了多长时间,单位秒 */
- get currentTime() {
- if (this.status === AudioStatus.Paused) {
- return this.pauseCurrentTime;
- } else {
- return this.source.currentTime;
- }
- }
- set currentTime(time) {
- this.source.stop();
- this.source.play(time);
- }
- /**
- * 设置结束时间,暂停或停止时,会经过这么长时间才终止音频的播放,这期间可以做一下音频淡出的效果。
- * @param time 暂停或停止时,经过多长时间之后才会结束音频的播放
- */
- setEndTime(time) {
- this.endTime = time;
- }
-
- /**
- * 当音频播放时执行的函数,可以用于音频淡入效果
- * @param fn 音频开始播放时执行的函数
- */
- onStart(fn) {
- this.audioStartHook = fn;
- }
-
- /**
- * 当音频暂停或停止时执行的函数,可以用于音频淡出效果
- * @param fn 音频在暂停或停止时执行的函数,不填时表示取消这个钩子。
- * 包含两个参数,第一个参数是结束时长,第二个参数是当前音频播放路由对象
- */
- onEnd(fn) {
- this.audioEndHook = fn;
- }
-
- /**
- * 开始播放这个音频
- * @param when 从音频的什么时候开始播放,单位秒
- */
- play(when = 0) {
- if (this.status === AudioStatus.Playing) return;
- this.link();
- if (this.effectRoute.length > 0) {
- const first = this.effectRoute[0];
- this.source.connect(first);
- const last = this.effectRoute.at(-1);
- last.connect({ input: this.player.getDestination() });
- } else {
- this.source.connect({ input: this.player.getDestination() });
- }
- this.source.play(when);
- this.status = AudioStatus.Playing;
- this.pauseTime = 0;
- this.audioStartHook?.(this);
- this.startAllEffect();
- }
-
- /**
- * 暂停音频播放
- */
- async pause() {
- if (this.status !== AudioStatus.Playing) return;
- this.status = AudioStatus.Pausing;
- this.stopIdentifier++;
- const identifier = this.stopIdentifier;
- if (this.audioEndHook) {
- this.audioEndHook(this.endTime, this);
- await sleep(this.endTime);
- }
- if (
- this.status !== AudioStatus.Pausing ||
- this.stopIdentifier !== identifier
- ) {
- return;
- }
- this.pauseCurrentTime = this.source.currentTime;
- const time = this.source.stop();
- this.pauseTime = time;
- if (this.shouldStop) {
- this.status = AudioStatus.Stoped;
- this.endAllEffect();
-
- this.shouldStop = false;
- } else {
- this.status = AudioStatus.Paused;
- this.endAllEffect();
- }
- this.endAllEffect();
- }
-
- /**
- * 继续音频播放
- */
- resume() {
- if (this.status === AudioStatus.Playing) return;
- if (
- this.status === AudioStatus.Pausing ||
- this.status === AudioStatus.Stoping
- ) {
-
- this.audioStartHook?.(this);
-
- return;
- }
- if (this.status === AudioStatus.Paused) {
- this.play(this.pauseTime);
- } else {
- this.play(0);
- }
- this.status = AudioStatus.Playing;
- this.pauseTime = 0;
- this.audioStartHook?.(this);
- this.startAllEffect();
- }
-
- /**
- * 停止音频播放
- */
- async stop() {
- if (this.status !== AudioStatus.Playing) {
- if (this.status === AudioStatus.Pausing) {
- this.shouldStop = true;
- }
- return;
- }
- this.status = AudioStatus.Stoping;
- this.stopIdentifier++;
- const identifier = this.stopIdentifier;
- if (this.audioEndHook) {
- this.audioEndHook(this.endTime, this);
- await sleep(this.endTime);
- }
- if (
- this.status !== AudioStatus.Stoping ||
- this.stopIdentifier !== identifier
- ) {
- return;
- }
- this.source.stop();
- this.status = AudioStatus.Stoped;
- this.pauseTime = 0;
- this.endAllEffect();
- }
-
- /**
- * 添加效果器
- * @param effect 要添加的效果,可以是数组,表示一次添加多个
- * @param index 从哪个位置开始添加,如果大于数组长度,那么加到末尾,如果小于0,那么将会从后面往前数。默认添加到末尾
- */
- addEffect(effect, index) {
- if (isNil(index)) {
- if (effect instanceof Array) {
- this.effectRoute.push(...effect);
- } else {
- this.effectRoute.push(effect);
- }
- } else {
- if (effect instanceof Array) {
- this.effectRoute.splice(index, 0, ...effect);
- } else {
- this.effectRoute.splice(index, 0, effect);
- }
- }
- this.setOutput();
- if (this.source.playing) this.link();
- }
-
- /**
- * 移除一个效果器
- * @param effect 要移除的效果
- */
- removeEffect(effect) {
- const index = this.effectRoute.indexOf(effect);
- if (index === -1) return;
- this.effectRoute.splice(index, 1);
- effect.disconnect();
- this.setOutput();
- if (this.source.playing) this.link();
- }
-
- setOutput() {
- const effect = this.effectRoute.at(-1);
- if (!effect) this.output = this.source.output;
- else this.output = effect.output;
- }
-
- /**
- * 连接音频路由图
- */
- link() {
- this.effectRoute.forEach((v) => v.disconnect());
- this.effectRoute.forEach((v, i) => {
- const next = this.effectRoute[i + 1];
- if (next) {
- v.connect(next);
- }
- });
- }
-
- startAllEffect() {
- this.effectRoute.forEach((v) => v.start());
- }
-
- endAllEffect() {
- this.effectRoute.forEach((v) => v.end());
- }
- }
-
-
- const audioPlayer = new AudioPlayer()
-
- class AudioDecoder {
- /**
- * 注册一个解码器
- * @param type 要注册的解码器允许解码的类型
- * @param decoder 解码器对象
- */
- static registerDecoder(type, decoder) {
- if (!this.decoderMap) this.decoderMap = new Map();
- if (this.decoderMap.has(type)) {
- console.warn(
- "Audio stream decoder for audio type '" +
- type +
- "' has already existed."
- );
- return;
- }
-
- this.decoderMap.set(type, decoder);
- }
-
- /**
- * 解码音频数据
- * @param data 音频文件数据
- * @param player AudioPlayer实例
- */
- static async decodeAudioData(data, player) {
- // 检查头文件获取音频类型,仅检查前256个字节
- const toCheck = data.slice(0, 256);
- const type = checkAudioType(data);
- if (type === "") {
- console.error(
- "Unknown audio type. Header: '" + [...toCheck]
- .map((v) => v.toString().padStart(2, "0"))
- .join(" ")
- .toUpperCase() +
- "'"
- );
- return null;
- }
- if (isAudioSupport(type)) {
- if (data.buffer instanceof ArrayBuffer) {
- return player.ac.decodeAudioData(data.buffer);
- } else {
- return null;
- }
- } else {
- const Decoder = this.decoderMap.get(type);
- if (!Decoder) {
- return null;
- } else {
- const decoder = new Decoder();
- await decoder.create();
- const decodedData = await decoder.decode(data);
- if (!decodedData) return null;
- const buffer = player.ac.createBuffer(
- decodedData.channelData.length,
- decodedData.channelData[0].length,
- decodedData.sampleRate
- );
- decodedData.channelData.forEach((v, i) => {
- buffer.copyToChannel(v, i);
- });
- return buffer;
- }
- }
- }
- }
-
- class VorbisDecoder {
- /**
- * 创建音频解码器
- */
- async create() {
- this.decoder = new OggVorbisDecoderWebWorker();
- await this.decoder.ready;
- }
- /**
- * 摧毁这个解码器
- */
- destroy() {
- this.decoder?.free();
- }
- /**
- * 解码流数据
- * @param data 流数据
- */
-
- async decode(data) {
- return this.decoder?.decode(data);
- }
- async decodeAll(data) {
- return this.decoder?.decodeFile(data);
- }
- /**
- * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用
- */
- async flush() {
- return this.decoder?.flush();
- }
- }
- class OpusDecoder {
- /**
- * 创建音频解码器
- */
- async create() {
- this.decoder = new OggOpusDecoderWebWorker();
- await this.decoder.ready;
- }
- /**
- * 摧毁这个解码器
- */
- destroy() {
- this.decoder?.free();
- }
- /**
- * 解码流数据
- * @param data 流数据
- */
- async decode(data) {
- return this.decoder?.decode(data);
- }
-
- async decodeAll(data) {
- return this.decoder?.decodeFile(data);
- }
- /**
- * 当音频解码完成后,会调用此函数,需要返回之前还未解析或未返回的音频数据。调用后,该解码器将不会被再次使用
- */
- async flush() {
- return await this.decoder?.flush();
- }
- }
- class BgmController {
- constructor(player) {
- this.mainGain = player.createVolumeEffect();
- this.player = player;
- /** bgm音频名称的前缀 */
- this.prefix = "bgms.";
- /** 每个 bgm 的音量控制器 */
- this.gain = new Map();
-
- /** 正在播放的 bgm */
- this.playingBgm = "";
- /** 是否正在播放 */
- this.playing = false;
-
- /** 是否已经启用 */
- this.enabled = true;
- /** 是否屏蔽所有的音乐切换 */
- this.blocking = false;
- /** 渐变时长 */
- this.transitionTime = 2000;
- }
-
- /**
- * 设置音频渐变时长
- * @param time 渐变时长
- */
- setTransitionTime(time) {
- this.transitionTime = time;
- for (const [, value] of this.gain) {
- value.transition.time(time);
- }
- }
-
- /**
- * 屏蔽音乐切换
- */
- blockChange() {
- this.blocking = true;
- }
-
- /**
- * 取消屏蔽音乐切换
- */
- unblockChange() {
- this.blocking = false;
- }
-
- /**
- * 设置总音量大小
- * @param volume 音量大小
- */
- setVolume(volume) {
- this.mainGain.setVolume(volume);
- }
-
- /**
- * 设置是否启用
- * @param enabled 是否启用
- */
- setEnabled(enabled) {
- if (enabled) this.resume();
- else this.stop();
- this.enabled = enabled;
- }
-
- /**
- * 设置 bgm 音频名称的前缀
- */
- setPrefix(prefix) {
- this.prefix = prefix;
- }
-
- getId(name) {
- return `${this.prefix}${name}`;
- }
-
- /**
- * 根据 bgm 名称获取其 AudioRoute 实例
- * @param id 音频名称
- */
- get(id) {
- return this.player.getRoute(this.getId(id));
- }
-
- /**
- * 添加一个 bgm
- * @param id 要添加的 bgm 的名称
- * @param url 指定 bgm 的加载地址
- */
- addBgm(id, url = `project/bgms/${id}`) {
- const type = guessTypeByExt(id);
- if (!type) {
- console.warn(
- "Unknown audio extension name: '" +
- id.split(".").slice(0, -1).join(".") +
- "'"
- );
- return;
- }
- const gain = this.player.createVolumeEffect();
- if (isAudioSupport(type)) {
- const source = audioPlayer.createElementSource();
- source.setSource(url);
- source.setLoop(true);
- const route = new AudioRoute(source, audioPlayer);
- route.addEffect([gain, this.mainGain]);
- audioPlayer.addRoute(this.getId(id), route);
- this.setTransition(id, route, gain);
- } else {
- const source = audioPlayer.createStreamSource();
- const stream = new StreamLoader(url);
- stream.pipe(source);
- source.setLoop(true);
- const route = new AudioRoute(source, audioPlayer);
- route.addEffect([gain, this.mainGain]);
- audioPlayer.addRoute(this.getId(id), route);
- this.setTransition(id, route, gain);
- }
- }
-
- /**
- * 移除一个 bgm
- * @param id 要移除的 bgm 的名称
- */
- removeBgm(id) {
- this.player.removeRoute(this.getId(id));
- const gain = this.gain.get(id);
- gain?.transition.ticker.destroy();
- this.gain.delete(id);
- }
-
- setTransition(id, route, gain) {
- const transition = new Transition();
- transition
- .time(this.transitionTime)
- .mode(linear())
- .transition("volume", 0);
-
- const tick = () => {
- gain.setVolume(transition.value.volume);
- };
-
- /**
- * @param expect 在结束时应该是正在播放还是停止
- */
- const setTick = async (expect) => {
- transition.ticker.remove(tick);
- transition.ticker.add(tick);
- const identifier = route.stopIdentifier;
- await sleep(this.transitionTime + 500);
- if (route.status === expect && identifier === route.stopIdentifier) {
- transition.ticker.remove(tick);
- if (route.status === AudioStatus.Playing) {
- gain.setVolume(1);
- } else {
- gain.setVolume(0);
- }
- }
- };
-
- route.onStart(async () => {
- transition.transition("volume", 1);
- setTick(AudioStatus.Playing);
- });
- route.onEnd(() => {
- transition.transition("volume", 0);
- setTick(AudioStatus.Paused);
- });
- route.setEndTime(this.transitionTime);
-
- this.gain.set(id, { effect: gain, transition });
- }
-
- /**
- * 播放一个 bgm
- * @param id 要播放的 bgm 名称
- */
- play(id, when) {
- if (this.blocking) return;
- if (id !== this.playingBgm && this.playingBgm) {
- this.player.pause(this.getId(this.playingBgm));
- }
- this.playingBgm = id;
- if (!this.enabled) return;
- this.player.play(this.getId(id), when);
- this.playing = true;
- }
-
- /**
- * 继续当前的 bgm
- */
- resume() {
- if (this.blocking || !this.enabled || this.playing) return;
- if (this.playingBgm) {
- this.player.resume(this.getId(this.playingBgm));
- }
- this.playing = true;
- }
-
- /**
- * 暂停当前的 bgm
- */
- pause() {
- if (this.blocking || !this.enabled) return;
- if (this.playingBgm) {
- this.player.pause(this.getId(this.playingBgm));
- }
- this.playing = false;
- }
-
- /**
- * 停止当前的 bgm
- */
- stop() {
- if (this.blocking || !this.enabled) return;
- if (this.playingBgm) {
- this.player.stop(this.getId(this.playingBgm));
- }
- this.playing = false;
- }
- }
- const bgmController = new BgmController(audioPlayer);
-
-
- class SoundPlayer {
- constructor(player) {
- /** 每个音效的唯一标识符 */
- this.num = 0;
- this.enabled = true;
- this.gain = player.createVolumeEffect();
- /** 每个音效的数据 */
- this.buffer = new Map();
- /** 所有正在播放的音乐 */
- this.playing = new Set();
- this.player = player;
- }
- /**
- * 设置是否启用音效
- * @param enabled 是否启用音效
- */
- setEnabled(enabled) {
- if (!enabled) this.stopAllSounds();
- this.enabled = enabled;
- }
-
- /**
- * 设置音量大小
- * @param volume 音量大小
- */
- setVolume(volume) {
- this.gain.setVolume(volume);
- }
- /**
- * 添加一个音效
- * @param id 音效名称
- * @param data 音效的Uint8Array数据
- */
- async add(id, data) {
- const buffer = await this.player.decodeAudioData(data);
- if (!buffer) {
- console.warn(
- "Cannot decode sound '" +
- id +
- "', since audio file may not supported by 2.b."
- );
- return;
- }
- this.buffer.set(id, buffer);
- }
-
- /**
- * 播放一个音效
- * @param id 音效名称
- * @param position 音频位置,[0, 0, 0]表示正中心,x轴指向水平向右,y轴指向水平向上,z轴指向竖直向上
- * @param orientation 音频朝向,[0, 1, 0]表示朝向前方
- */
- play(id, position = [0, 0, 0], orientation = [1, 0, 0]) {
- if (!this.enabled) return -1;
- const buffer = this.buffer.get(id);
- if (!buffer) {
- console.warn(
- "Cannot play sound '" +
- id +
- "', since there is no added data named it."
- );
- return -1;
- }
- const soundNum = this.num++;
-
- const source = this.player.createBufferSource();
- source.setBuffer(buffer);
- const route = this.player.createRoute(source);
- const stereo = this.player.createStereoEffect();
- stereo.setPosition(position[0], position[1], position[2]);
- stereo.setOrientation(orientation[0], orientation[1], orientation[2]);
- route.addEffect([stereo, this.gain]);
- this.player.addRoute(`sounds.${soundNum}`, route);
- route.play();
- source.output.addEventListener("ended", () => {
- this.playing.delete(soundNum);
- });
- this.playing.add(soundNum);
- return soundNum;
- }
-
- /**
- * 停止一个音效
- * @param num 音效的唯一 id
- */
- stop(num) {
- const id = `sounds.${num}`;
- const route = this.player.getRoute(id);
- if (route) {
- route.stop();
- this.player.removeRoute(id);
- this.playing.delete(num);
- }
- }
-
- /**
- * 停止播放所有音效
- */
- stopAllSounds() {
- this.playing.forEach((v) => {
- const id = `sounds.${v}`;
- const route = this.player.getRoute(id);
- if (route) {
- route.stop();
- this.player.removeRoute(id);
- }
- });
- this.playing.clear();
- }
- }
- const soundPlayer = new SoundPlayer(audioPlayer);
-
-
-
- function loadAllBgm() {
- const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
- for (const bgm of data.main.bgms) {
- bgmController.addBgm(bgm);
- }
-
- }
- loadAllBgm();
- AudioDecoder.registerDecoder(AudioType.Ogg, VorbisDecoder);
- AudioDecoder.registerDecoder(AudioType.Opus, OpusDecoder);
-
- core.plugin.audioSystem = {
- AudioType,
- AudioDecoder,
- AudioStatus,
- checkAudioType,
- isAudioSupport,
- audioPlayer,
- soundPlayer,
- bgmController,
- guessTypeByExt,
- BgmController,
- SoundPlayer,
- EchoEffect,
- DelayEffect,
- ChannelVolumeEffect,
- VolumeEffect,
- StereoEffect,
- AudioEffect,
- AudioPlayer,
- AudioRoute,
- AudioStreamSource,
- AudioElementSource,
- AudioBufferSource,
- loadAllBgm,
- StreamLoader,
- };
- //bgm相关复写
- control.prototype.playBgm = (bgm, when) => {
- bgmController.play(bgm, when);
- core.setMusicBtn();
- };
- control.prototype.pauseBgm = () => {
- bgmController.pause();
- core.setMusicBtn();
- };
-
- control.prototype.resumeBgm = function () {
- bgmController.resume();
- core.setMusicBtn();
- };
- control.prototype.checkBgm = function () {
- if (bgmController.playing) return;
- if (core.musicStatus.bgmStatus) {
- if (bgmController.playingBgm) {
- bgmController.play(bgmController.playingBgm);
- } else {
- play(main.startBgm, 0);
- }
- } else {
- pause();
- }
- };
- control.prototype.triggerBgm = function () {
-
-
- core.musicStatus.bgmStatus = !core.musicStatus.bgmStatus;
- if (bgmController.playing) bgmController.pause();
- else bgmController.resume();
- core.setMusicBtn();
- core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus);
- };
- //sound相关复写
- control.prototype.playSound = function (
- sound,
- _pitch,
- callback,
- position,
- orientation
- ) {
- if (main.mode != 'play' || !core.musicStatus.soundStatus) return
- const name = core.getMappedName(sound);
- const num = soundPlayer.play(name, position, orientation);
- const route = audioPlayer.getRoute(`sounds.${num}`);
- if (!route) {
- callback?.();
- return -1;
- } else {
- sleep(route.duration).then(() => callback?.());
- return num;
- }
- };
- control.prototype.stopSound = function (id) {
- if (isNil(id)) {
- soundPlayer.stopAllSounds();
- } else {
- soundPlayer.stop(id);
- }
- };
- control.prototype.getPlayingSounds = function () {
- return [...soundPlayer.playing];
- };
- //sound加载复写
- loader.prototype._loadOneSound_decodeData = function (name, data) {
- if (data instanceof Blob) {
- var blobReader = new zip.BlobReader(data);
- blobReader.init(function () {
- blobReader.readUint8Array(0, blobReader.size, function (uint8) {
- //core.loader._loadOneSound_decodeData(name, uint8.buffer);
- soundPlayer.add(name, uint8)
- })
- });
- return;
- }
- if (data instanceof ArrayBuffer) {
- const uint8 = new Uint8Array(data)
- soundPlayer.add(name, uint8)
- }
- }
- //音量控制复写
- soundPlayer.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume)
- bgmController.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume)
- actions.prototype._clickSwitchs_sounds_userVolume = function (delta) {
- var value = Math.round(Math.sqrt(100 * core.musicStatus.userVolume));
- if (value == 0 && delta < 0) return;
- core.musicStatus.userVolume = core.clamp(Math.pow(value + delta, 2) / 100, 0, 1);
- //audioContext 音效 不受designVolume 影响
- if (core.musicStatus.gainNode != null) core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume;
- soundPlayer.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume)
- bgmController.setVolume(core.musicStatus.userVolume * core.musicStatus.designVolume)
- core.setLocalStorage('userVolume', core.musicStatus.userVolume);
- core.playSound('确定');
- core.ui._drawSwitchs_sounds();
- }
-}
+ }
}
\ No newline at end of file
diff --git a/project/sounds/aiy010000010.mp3 b/project/sounds/aiy010000010.mp3
deleted file mode 100644
index 4389b53..0000000
Binary files a/project/sounds/aiy010000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy010000010.opus b/project/sounds/aiy010000010.opus
new file mode 100644
index 0000000..0574c82
Binary files /dev/null and b/project/sounds/aiy010000010.opus differ
diff --git a/project/sounds/aiy010000020.mp3 b/project/sounds/aiy010000020.mp3
deleted file mode 100644
index 77111c6..0000000
Binary files a/project/sounds/aiy010000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy010000020.opus b/project/sounds/aiy010000020.opus
new file mode 100644
index 0000000..a5768d9
Binary files /dev/null and b/project/sounds/aiy010000020.opus differ
diff --git a/project/sounds/aiy010000030.mp3 b/project/sounds/aiy010000030.mp3
deleted file mode 100644
index c2b47e7..0000000
Binary files a/project/sounds/aiy010000030.mp3 and /dev/null differ
diff --git a/project/sounds/aiy010000030.opus b/project/sounds/aiy010000030.opus
new file mode 100644
index 0000000..450cf99
Binary files /dev/null and b/project/sounds/aiy010000030.opus differ
diff --git a/project/sounds/aiy020000005.mp3 b/project/sounds/aiy020000005.mp3
deleted file mode 100644
index c564818..0000000
Binary files a/project/sounds/aiy020000005.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000005.opus b/project/sounds/aiy020000005.opus
new file mode 100644
index 0000000..5e05539
Binary files /dev/null and b/project/sounds/aiy020000005.opus differ
diff --git a/project/sounds/aiy020000010.mp3 b/project/sounds/aiy020000010.mp3
deleted file mode 100644
index 850eefe..0000000
Binary files a/project/sounds/aiy020000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000010.opus b/project/sounds/aiy020000010.opus
new file mode 100644
index 0000000..257f445
Binary files /dev/null and b/project/sounds/aiy020000010.opus differ
diff --git a/project/sounds/aiy020000020.mp3 b/project/sounds/aiy020000020.mp3
deleted file mode 100644
index 0290dac..0000000
Binary files a/project/sounds/aiy020000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000020.opus b/project/sounds/aiy020000020.opus
new file mode 100644
index 0000000..4ef0df5
Binary files /dev/null and b/project/sounds/aiy020000020.opus differ
diff --git a/project/sounds/aiy020000030.mp3 b/project/sounds/aiy020000030.mp3
deleted file mode 100644
index a907ca7..0000000
Binary files a/project/sounds/aiy020000030.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000030.opus b/project/sounds/aiy020000030.opus
new file mode 100644
index 0000000..680d345
Binary files /dev/null and b/project/sounds/aiy020000030.opus differ
diff --git a/project/sounds/aiy020000040.mp3 b/project/sounds/aiy020000040.mp3
deleted file mode 100644
index 0b2b894..0000000
Binary files a/project/sounds/aiy020000040.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000040.opus b/project/sounds/aiy020000040.opus
new file mode 100644
index 0000000..7d8b8dd
Binary files /dev/null and b/project/sounds/aiy020000040.opus differ
diff --git a/project/sounds/aiy020000050.mp3 b/project/sounds/aiy020000050.mp3
deleted file mode 100644
index dc53397..0000000
Binary files a/project/sounds/aiy020000050.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000050.opus b/project/sounds/aiy020000050.opus
new file mode 100644
index 0000000..54e571a
Binary files /dev/null and b/project/sounds/aiy020000050.opus differ
diff --git a/project/sounds/aiy020000060.mp3 b/project/sounds/aiy020000060.mp3
deleted file mode 100644
index 64e8e2f..0000000
Binary files a/project/sounds/aiy020000060.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000060.opus b/project/sounds/aiy020000060.opus
new file mode 100644
index 0000000..a574a48
Binary files /dev/null and b/project/sounds/aiy020000060.opus differ
diff --git a/project/sounds/aiy020000070.mp3 b/project/sounds/aiy020000070.mp3
deleted file mode 100644
index a6dc7b2..0000000
Binary files a/project/sounds/aiy020000070.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000070.opus b/project/sounds/aiy020000070.opus
new file mode 100644
index 0000000..c4250aa
Binary files /dev/null and b/project/sounds/aiy020000070.opus differ
diff --git a/project/sounds/aiy020000080.mp3 b/project/sounds/aiy020000080.mp3
deleted file mode 100644
index b3b7b81..0000000
Binary files a/project/sounds/aiy020000080.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000080.opus b/project/sounds/aiy020000080.opus
new file mode 100644
index 0000000..5002cc3
Binary files /dev/null and b/project/sounds/aiy020000080.opus differ
diff --git a/project/sounds/aiy020000090.mp3 b/project/sounds/aiy020000090.mp3
deleted file mode 100644
index 9680e84..0000000
Binary files a/project/sounds/aiy020000090.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000090.opus b/project/sounds/aiy020000090.opus
new file mode 100644
index 0000000..cedb5f0
Binary files /dev/null and b/project/sounds/aiy020000090.opus differ
diff --git a/project/sounds/aiy020000100.mp3 b/project/sounds/aiy020000100.mp3
deleted file mode 100644
index 74349d9..0000000
Binary files a/project/sounds/aiy020000100.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000100.opus b/project/sounds/aiy020000100.opus
new file mode 100644
index 0000000..deded59
Binary files /dev/null and b/project/sounds/aiy020000100.opus differ
diff --git a/project/sounds/aiy020000110.mp3 b/project/sounds/aiy020000110.mp3
deleted file mode 100644
index 9c1625b..0000000
Binary files a/project/sounds/aiy020000110.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000110.opus b/project/sounds/aiy020000110.opus
new file mode 100644
index 0000000..574f59c
Binary files /dev/null and b/project/sounds/aiy020000110.opus differ
diff --git a/project/sounds/aiy020000120.mp3 b/project/sounds/aiy020000120.mp3
deleted file mode 100644
index e8accbe..0000000
Binary files a/project/sounds/aiy020000120.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000120.opus b/project/sounds/aiy020000120.opus
new file mode 100644
index 0000000..0e982bc
Binary files /dev/null and b/project/sounds/aiy020000120.opus differ
diff --git a/project/sounds/aiy020000130.mp3 b/project/sounds/aiy020000130.mp3
deleted file mode 100644
index 4d33949..0000000
Binary files a/project/sounds/aiy020000130.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000130.opus b/project/sounds/aiy020000130.opus
new file mode 100644
index 0000000..837d498
Binary files /dev/null and b/project/sounds/aiy020000130.opus differ
diff --git a/project/sounds/aiy020000140.mp3 b/project/sounds/aiy020000140.mp3
deleted file mode 100644
index b207d11..0000000
Binary files a/project/sounds/aiy020000140.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000140.opus b/project/sounds/aiy020000140.opus
new file mode 100644
index 0000000..b57af22
Binary files /dev/null and b/project/sounds/aiy020000140.opus differ
diff --git a/project/sounds/aiy020000150.mp3 b/project/sounds/aiy020000150.mp3
deleted file mode 100644
index d652629..0000000
Binary files a/project/sounds/aiy020000150.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000150.opus b/project/sounds/aiy020000150.opus
new file mode 100644
index 0000000..4ab93aa
Binary files /dev/null and b/project/sounds/aiy020000150.opus differ
diff --git a/project/sounds/aiy020000160.mp3 b/project/sounds/aiy020000160.mp3
deleted file mode 100644
index 317fd3c..0000000
Binary files a/project/sounds/aiy020000160.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000160.opus b/project/sounds/aiy020000160.opus
new file mode 100644
index 0000000..14cf9f9
Binary files /dev/null and b/project/sounds/aiy020000160.opus differ
diff --git a/project/sounds/aiy020000170.mp3 b/project/sounds/aiy020000170.mp3
deleted file mode 100644
index f82fb9e..0000000
Binary files a/project/sounds/aiy020000170.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000170.opus b/project/sounds/aiy020000170.opus
new file mode 100644
index 0000000..fbf0b94
Binary files /dev/null and b/project/sounds/aiy020000170.opus differ
diff --git a/project/sounds/aiy020000180.mp3 b/project/sounds/aiy020000180.mp3
deleted file mode 100644
index e41d74c..0000000
Binary files a/project/sounds/aiy020000180.mp3 and /dev/null differ
diff --git a/project/sounds/aiy020000180.opus b/project/sounds/aiy020000180.opus
new file mode 100644
index 0000000..2dfcfc2
Binary files /dev/null and b/project/sounds/aiy020000180.opus differ
diff --git a/project/sounds/aiy310000010.mp3 b/project/sounds/aiy310000010.mp3
deleted file mode 100644
index d6bf306..0000000
Binary files a/project/sounds/aiy310000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000010.opus b/project/sounds/aiy310000010.opus
new file mode 100644
index 0000000..9955fab
Binary files /dev/null and b/project/sounds/aiy310000010.opus differ
diff --git a/project/sounds/aiy310000020.mp3 b/project/sounds/aiy310000020.mp3
deleted file mode 100644
index 84ad00e..0000000
Binary files a/project/sounds/aiy310000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000020.opus b/project/sounds/aiy310000020.opus
new file mode 100644
index 0000000..99fe711
Binary files /dev/null and b/project/sounds/aiy310000020.opus differ
diff --git a/project/sounds/aiy310000030.mp3 b/project/sounds/aiy310000030.mp3
deleted file mode 100644
index ca51c6c..0000000
Binary files a/project/sounds/aiy310000030.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000030.opus b/project/sounds/aiy310000030.opus
new file mode 100644
index 0000000..e62ade9
Binary files /dev/null and b/project/sounds/aiy310000030.opus differ
diff --git a/project/sounds/aiy310000040.mp3 b/project/sounds/aiy310000040.mp3
deleted file mode 100644
index 139b9c4..0000000
Binary files a/project/sounds/aiy310000040.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000040.opus b/project/sounds/aiy310000040.opus
new file mode 100644
index 0000000..ecd0f9b
Binary files /dev/null and b/project/sounds/aiy310000040.opus differ
diff --git a/project/sounds/aiy310000050.mp3 b/project/sounds/aiy310000050.mp3
deleted file mode 100644
index b0b68b9..0000000
Binary files a/project/sounds/aiy310000050.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000050.opus b/project/sounds/aiy310000050.opus
new file mode 100644
index 0000000..12f5233
Binary files /dev/null and b/project/sounds/aiy310000050.opus differ
diff --git a/project/sounds/aiy310000060.mp3 b/project/sounds/aiy310000060.mp3
deleted file mode 100644
index 9773718..0000000
Binary files a/project/sounds/aiy310000060.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000060.opus b/project/sounds/aiy310000060.opus
new file mode 100644
index 0000000..4e36bcd
Binary files /dev/null and b/project/sounds/aiy310000060.opus differ
diff --git a/project/sounds/aiy310000070.mp3 b/project/sounds/aiy310000070.mp3
deleted file mode 100644
index 3b2667c..0000000
Binary files a/project/sounds/aiy310000070.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000070.opus b/project/sounds/aiy310000070.opus
new file mode 100644
index 0000000..db9d0e7
Binary files /dev/null and b/project/sounds/aiy310000070.opus differ
diff --git a/project/sounds/aiy310000080.mp3 b/project/sounds/aiy310000080.mp3
deleted file mode 100644
index 392969d..0000000
Binary files a/project/sounds/aiy310000080.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000080.opus b/project/sounds/aiy310000080.opus
new file mode 100644
index 0000000..c303fb3
Binary files /dev/null and b/project/sounds/aiy310000080.opus differ
diff --git a/project/sounds/aiy310000090.mp3 b/project/sounds/aiy310000090.mp3
deleted file mode 100644
index 7ace161..0000000
Binary files a/project/sounds/aiy310000090.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000090.opus b/project/sounds/aiy310000090.opus
new file mode 100644
index 0000000..63289e6
Binary files /dev/null and b/project/sounds/aiy310000090.opus differ
diff --git a/project/sounds/aiy310000100.mp3 b/project/sounds/aiy310000100.mp3
deleted file mode 100644
index 57907d8..0000000
Binary files a/project/sounds/aiy310000100.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000100.opus b/project/sounds/aiy310000100.opus
new file mode 100644
index 0000000..e62de21
Binary files /dev/null and b/project/sounds/aiy310000100.opus differ
diff --git a/project/sounds/aiy310000110.mp3 b/project/sounds/aiy310000110.mp3
deleted file mode 100644
index 955cda3..0000000
Binary files a/project/sounds/aiy310000110.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000110.opus b/project/sounds/aiy310000110.opus
new file mode 100644
index 0000000..3c6a541
Binary files /dev/null and b/project/sounds/aiy310000110.opus differ
diff --git a/project/sounds/aiy310000120.mp3 b/project/sounds/aiy310000120.mp3
deleted file mode 100644
index d387bdd..0000000
Binary files a/project/sounds/aiy310000120.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000120.opus b/project/sounds/aiy310000120.opus
new file mode 100644
index 0000000..3961d24
Binary files /dev/null and b/project/sounds/aiy310000120.opus differ
diff --git a/project/sounds/aiy310000130.mp3 b/project/sounds/aiy310000130.mp3
deleted file mode 100644
index e643d89..0000000
Binary files a/project/sounds/aiy310000130.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000130.opus b/project/sounds/aiy310000130.opus
new file mode 100644
index 0000000..e5dab39
Binary files /dev/null and b/project/sounds/aiy310000130.opus differ
diff --git a/project/sounds/aiy310000140.mp3 b/project/sounds/aiy310000140.mp3
deleted file mode 100644
index e647175..0000000
Binary files a/project/sounds/aiy310000140.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000140.opus b/project/sounds/aiy310000140.opus
new file mode 100644
index 0000000..e7bf71f
Binary files /dev/null and b/project/sounds/aiy310000140.opus differ
diff --git a/project/sounds/aiy310000150.mp3 b/project/sounds/aiy310000150.mp3
deleted file mode 100644
index 5d64a1d..0000000
Binary files a/project/sounds/aiy310000150.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000150.opus b/project/sounds/aiy310000150.opus
new file mode 100644
index 0000000..b6fe0bd
Binary files /dev/null and b/project/sounds/aiy310000150.opus differ
diff --git a/project/sounds/aiy310000160.mp3 b/project/sounds/aiy310000160.mp3
deleted file mode 100644
index 24ec45b..0000000
Binary files a/project/sounds/aiy310000160.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000160.opus b/project/sounds/aiy310000160.opus
new file mode 100644
index 0000000..1de7696
Binary files /dev/null and b/project/sounds/aiy310000160.opus differ
diff --git a/project/sounds/aiy310000170.mp3 b/project/sounds/aiy310000170.mp3
deleted file mode 100644
index 5c1950a..0000000
Binary files a/project/sounds/aiy310000170.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000170.opus b/project/sounds/aiy310000170.opus
new file mode 100644
index 0000000..55df5b4
Binary files /dev/null and b/project/sounds/aiy310000170.opus differ
diff --git a/project/sounds/aiy310000180.mp3 b/project/sounds/aiy310000180.mp3
deleted file mode 100644
index 6fbf8f1..0000000
Binary files a/project/sounds/aiy310000180.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000180.opus b/project/sounds/aiy310000180.opus
new file mode 100644
index 0000000..dc9a85c
Binary files /dev/null and b/project/sounds/aiy310000180.opus differ
diff --git a/project/sounds/aiy310000190.mp3 b/project/sounds/aiy310000190.mp3
deleted file mode 100644
index 06e7906..0000000
Binary files a/project/sounds/aiy310000190.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000190.opus b/project/sounds/aiy310000190.opus
new file mode 100644
index 0000000..821e276
Binary files /dev/null and b/project/sounds/aiy310000190.opus differ
diff --git a/project/sounds/aiy310000200.mp3 b/project/sounds/aiy310000200.mp3
deleted file mode 100644
index 68d714d..0000000
Binary files a/project/sounds/aiy310000200.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000200.opus b/project/sounds/aiy310000200.opus
new file mode 100644
index 0000000..51ba4fc
Binary files /dev/null and b/project/sounds/aiy310000200.opus differ
diff --git a/project/sounds/aiy310000210.mp3 b/project/sounds/aiy310000210.mp3
deleted file mode 100644
index f1d7e95..0000000
Binary files a/project/sounds/aiy310000210.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000210.opus b/project/sounds/aiy310000210.opus
new file mode 100644
index 0000000..4fe0fa9
Binary files /dev/null and b/project/sounds/aiy310000210.opus differ
diff --git a/project/sounds/aiy310000220.mp3 b/project/sounds/aiy310000220.mp3
deleted file mode 100644
index 4fc534d..0000000
Binary files a/project/sounds/aiy310000220.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000220.opus b/project/sounds/aiy310000220.opus
new file mode 100644
index 0000000..169de30
Binary files /dev/null and b/project/sounds/aiy310000220.opus differ
diff --git a/project/sounds/aiy310000230.mp3 b/project/sounds/aiy310000230.mp3
deleted file mode 100644
index 57f5059..0000000
Binary files a/project/sounds/aiy310000230.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000230.opus b/project/sounds/aiy310000230.opus
new file mode 100644
index 0000000..db0f37d
Binary files /dev/null and b/project/sounds/aiy310000230.opus differ
diff --git a/project/sounds/aiy310000240.mp3 b/project/sounds/aiy310000240.mp3
deleted file mode 100644
index c9d29ee..0000000
Binary files a/project/sounds/aiy310000240.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000240.opus b/project/sounds/aiy310000240.opus
new file mode 100644
index 0000000..597e491
Binary files /dev/null and b/project/sounds/aiy310000240.opus differ
diff --git a/project/sounds/aiy310000250.mp3 b/project/sounds/aiy310000250.mp3
deleted file mode 100644
index 37346d0..0000000
Binary files a/project/sounds/aiy310000250.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000250.opus b/project/sounds/aiy310000250.opus
new file mode 100644
index 0000000..e8ada96
Binary files /dev/null and b/project/sounds/aiy310000250.opus differ
diff --git a/project/sounds/aiy310000260.mp3 b/project/sounds/aiy310000260.mp3
deleted file mode 100644
index b547f31..0000000
Binary files a/project/sounds/aiy310000260.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000260.opus b/project/sounds/aiy310000260.opus
new file mode 100644
index 0000000..1d7bae9
Binary files /dev/null and b/project/sounds/aiy310000260.opus differ
diff --git a/project/sounds/aiy310000280.mp3 b/project/sounds/aiy310000280.mp3
deleted file mode 100644
index d7ad3e9..0000000
Binary files a/project/sounds/aiy310000280.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000280.opus b/project/sounds/aiy310000280.opus
new file mode 100644
index 0000000..649f1fd
Binary files /dev/null and b/project/sounds/aiy310000280.opus differ
diff --git a/project/sounds/aiy310000290.mp3 b/project/sounds/aiy310000290.mp3
deleted file mode 100644
index 2380de7..0000000
Binary files a/project/sounds/aiy310000290.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000290.opus b/project/sounds/aiy310000290.opus
new file mode 100644
index 0000000..f4222de
Binary files /dev/null and b/project/sounds/aiy310000290.opus differ
diff --git a/project/sounds/aiy310000300.mp3 b/project/sounds/aiy310000300.mp3
deleted file mode 100644
index c171f56..0000000
Binary files a/project/sounds/aiy310000300.mp3 and /dev/null differ
diff --git a/project/sounds/aiy310000300.opus b/project/sounds/aiy310000300.opus
new file mode 100644
index 0000000..32c2f49
Binary files /dev/null and b/project/sounds/aiy310000300.opus differ
diff --git a/project/sounds/aiy350000010.mp3 b/project/sounds/aiy350000010.mp3
deleted file mode 100644
index 57c17f9..0000000
Binary files a/project/sounds/aiy350000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000010.opus b/project/sounds/aiy350000010.opus
new file mode 100644
index 0000000..0f41912
Binary files /dev/null and b/project/sounds/aiy350000010.opus differ
diff --git a/project/sounds/aiy350000020.mp3 b/project/sounds/aiy350000020.mp3
deleted file mode 100644
index 6ebb9bc..0000000
Binary files a/project/sounds/aiy350000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000020.opus b/project/sounds/aiy350000020.opus
new file mode 100644
index 0000000..b99c603
Binary files /dev/null and b/project/sounds/aiy350000020.opus differ
diff --git a/project/sounds/aiy350000030.mp3 b/project/sounds/aiy350000030.mp3
deleted file mode 100644
index 2f57a03..0000000
Binary files a/project/sounds/aiy350000030.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000030.opus b/project/sounds/aiy350000030.opus
new file mode 100644
index 0000000..773d947
Binary files /dev/null and b/project/sounds/aiy350000030.opus differ
diff --git a/project/sounds/aiy350000040.mp3 b/project/sounds/aiy350000040.mp3
deleted file mode 100644
index 13d4523..0000000
Binary files a/project/sounds/aiy350000040.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000040.opus b/project/sounds/aiy350000040.opus
new file mode 100644
index 0000000..df657bf
Binary files /dev/null and b/project/sounds/aiy350000040.opus differ
diff --git a/project/sounds/aiy350000050.mp3 b/project/sounds/aiy350000050.mp3
deleted file mode 100644
index 5c763e4..0000000
Binary files a/project/sounds/aiy350000050.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000050.opus b/project/sounds/aiy350000050.opus
new file mode 100644
index 0000000..d520d2e
Binary files /dev/null and b/project/sounds/aiy350000050.opus differ
diff --git a/project/sounds/aiy350000060.mp3 b/project/sounds/aiy350000060.mp3
deleted file mode 100644
index 790d096..0000000
Binary files a/project/sounds/aiy350000060.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000060.opus b/project/sounds/aiy350000060.opus
new file mode 100644
index 0000000..47f1642
Binary files /dev/null and b/project/sounds/aiy350000060.opus differ
diff --git a/project/sounds/aiy350000070.mp3 b/project/sounds/aiy350000070.mp3
deleted file mode 100644
index 236c48a..0000000
Binary files a/project/sounds/aiy350000070.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000070.opus b/project/sounds/aiy350000070.opus
new file mode 100644
index 0000000..b02685c
Binary files /dev/null and b/project/sounds/aiy350000070.opus differ
diff --git a/project/sounds/aiy350000080.mp3 b/project/sounds/aiy350000080.mp3
deleted file mode 100644
index f6753db..0000000
Binary files a/project/sounds/aiy350000080.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000080.opus b/project/sounds/aiy350000080.opus
new file mode 100644
index 0000000..868a458
Binary files /dev/null and b/project/sounds/aiy350000080.opus differ
diff --git a/project/sounds/aiy350000090.mp3 b/project/sounds/aiy350000090.mp3
deleted file mode 100644
index 869aea1..0000000
Binary files a/project/sounds/aiy350000090.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000090.opus b/project/sounds/aiy350000090.opus
new file mode 100644
index 0000000..26a24b1
Binary files /dev/null and b/project/sounds/aiy350000090.opus differ
diff --git a/project/sounds/aiy350000100.mp3 b/project/sounds/aiy350000100.mp3
deleted file mode 100644
index f87b58f..0000000
Binary files a/project/sounds/aiy350000100.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000100.opus b/project/sounds/aiy350000100.opus
new file mode 100644
index 0000000..45199fe
Binary files /dev/null and b/project/sounds/aiy350000100.opus differ
diff --git a/project/sounds/aiy350000110.mp3 b/project/sounds/aiy350000110.mp3
deleted file mode 100644
index 553ac12..0000000
Binary files a/project/sounds/aiy350000110.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000110.opus b/project/sounds/aiy350000110.opus
new file mode 100644
index 0000000..ef10116
Binary files /dev/null and b/project/sounds/aiy350000110.opus differ
diff --git a/project/sounds/aiy350000120.mp3 b/project/sounds/aiy350000120.mp3
deleted file mode 100644
index 57f9899..0000000
Binary files a/project/sounds/aiy350000120.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000120.opus b/project/sounds/aiy350000120.opus
new file mode 100644
index 0000000..5c9fd50
Binary files /dev/null and b/project/sounds/aiy350000120.opus differ
diff --git a/project/sounds/aiy350000130.mp3 b/project/sounds/aiy350000130.mp3
deleted file mode 100644
index 62e68dc..0000000
Binary files a/project/sounds/aiy350000130.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000130.opus b/project/sounds/aiy350000130.opus
new file mode 100644
index 0000000..c07b760
Binary files /dev/null and b/project/sounds/aiy350000130.opus differ
diff --git a/project/sounds/aiy350000140.mp3 b/project/sounds/aiy350000140.mp3
deleted file mode 100644
index b4ff73c..0000000
Binary files a/project/sounds/aiy350000140.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000140.opus b/project/sounds/aiy350000140.opus
new file mode 100644
index 0000000..50ddd6d
Binary files /dev/null and b/project/sounds/aiy350000140.opus differ
diff --git a/project/sounds/aiy350000150.mp3 b/project/sounds/aiy350000150.mp3
deleted file mode 100644
index b8d9ce2..0000000
Binary files a/project/sounds/aiy350000150.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000150.opus b/project/sounds/aiy350000150.opus
new file mode 100644
index 0000000..7626306
Binary files /dev/null and b/project/sounds/aiy350000150.opus differ
diff --git a/project/sounds/aiy350000160.mp3 b/project/sounds/aiy350000160.mp3
deleted file mode 100644
index 563717f..0000000
Binary files a/project/sounds/aiy350000160.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000160.opus b/project/sounds/aiy350000160.opus
new file mode 100644
index 0000000..6a0e778
Binary files /dev/null and b/project/sounds/aiy350000160.opus differ
diff --git a/project/sounds/aiy350000170.mp3 b/project/sounds/aiy350000170.mp3
deleted file mode 100644
index 23266c1..0000000
Binary files a/project/sounds/aiy350000170.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000170.opus b/project/sounds/aiy350000170.opus
new file mode 100644
index 0000000..264c29b
Binary files /dev/null and b/project/sounds/aiy350000170.opus differ
diff --git a/project/sounds/aiy350000180.mp3 b/project/sounds/aiy350000180.mp3
deleted file mode 100644
index 0a52d64..0000000
Binary files a/project/sounds/aiy350000180.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000180.opus b/project/sounds/aiy350000180.opus
new file mode 100644
index 0000000..f30c59e
Binary files /dev/null and b/project/sounds/aiy350000180.opus differ
diff --git a/project/sounds/aiy350000190.mp3 b/project/sounds/aiy350000190.mp3
deleted file mode 100644
index 5379fbb..0000000
Binary files a/project/sounds/aiy350000190.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000190.opus b/project/sounds/aiy350000190.opus
new file mode 100644
index 0000000..c2a045a
Binary files /dev/null and b/project/sounds/aiy350000190.opus differ
diff --git a/project/sounds/aiy350000200.mp3 b/project/sounds/aiy350000200.mp3
deleted file mode 100644
index 7bf86fd..0000000
Binary files a/project/sounds/aiy350000200.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000200.opus b/project/sounds/aiy350000200.opus
new file mode 100644
index 0000000..d964326
Binary files /dev/null and b/project/sounds/aiy350000200.opus differ
diff --git a/project/sounds/aiy350000210.mp3 b/project/sounds/aiy350000210.mp3
deleted file mode 100644
index 01426ec..0000000
Binary files a/project/sounds/aiy350000210.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000210.opus b/project/sounds/aiy350000210.opus
new file mode 100644
index 0000000..dcf95ec
Binary files /dev/null and b/project/sounds/aiy350000210.opus differ
diff --git a/project/sounds/aiy350000220.mp3 b/project/sounds/aiy350000220.mp3
deleted file mode 100644
index 7687c76..0000000
Binary files a/project/sounds/aiy350000220.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000220.opus b/project/sounds/aiy350000220.opus
new file mode 100644
index 0000000..ba965cf
Binary files /dev/null and b/project/sounds/aiy350000220.opus differ
diff --git a/project/sounds/aiy350000230.mp3 b/project/sounds/aiy350000230.mp3
deleted file mode 100644
index ef72218..0000000
Binary files a/project/sounds/aiy350000230.mp3 and /dev/null differ
diff --git a/project/sounds/aiy350000230.opus b/project/sounds/aiy350000230.opus
new file mode 100644
index 0000000..88cd8a9
Binary files /dev/null and b/project/sounds/aiy350000230.opus differ
diff --git a/project/sounds/aiy710000010.mp3 b/project/sounds/aiy710000010.mp3
deleted file mode 100644
index 6e08794..0000000
Binary files a/project/sounds/aiy710000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000010.opus b/project/sounds/aiy710000010.opus
new file mode 100644
index 0000000..bcf6341
Binary files /dev/null and b/project/sounds/aiy710000010.opus differ
diff --git a/project/sounds/aiy710000020.mp3 b/project/sounds/aiy710000020.mp3
deleted file mode 100644
index d025b23..0000000
Binary files a/project/sounds/aiy710000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000020.opus b/project/sounds/aiy710000020.opus
new file mode 100644
index 0000000..f4de94a
Binary files /dev/null and b/project/sounds/aiy710000020.opus differ
diff --git a/project/sounds/aiy710000030.mp3 b/project/sounds/aiy710000030.mp3
deleted file mode 100644
index ad200f2..0000000
Binary files a/project/sounds/aiy710000030.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000030.opus b/project/sounds/aiy710000030.opus
new file mode 100644
index 0000000..c6f5d74
Binary files /dev/null and b/project/sounds/aiy710000030.opus differ
diff --git a/project/sounds/aiy710000040.mp3 b/project/sounds/aiy710000040.mp3
deleted file mode 100644
index dbdbbd2..0000000
Binary files a/project/sounds/aiy710000040.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000040.opus b/project/sounds/aiy710000040.opus
new file mode 100644
index 0000000..02e9b14
Binary files /dev/null and b/project/sounds/aiy710000040.opus differ
diff --git a/project/sounds/aiy710000050.mp3 b/project/sounds/aiy710000050.mp3
deleted file mode 100644
index f304d67..0000000
Binary files a/project/sounds/aiy710000050.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000050.opus b/project/sounds/aiy710000050.opus
new file mode 100644
index 0000000..a37c230
Binary files /dev/null and b/project/sounds/aiy710000050.opus differ
diff --git a/project/sounds/aiy710000060.mp3 b/project/sounds/aiy710000060.mp3
deleted file mode 100644
index 1366af4..0000000
Binary files a/project/sounds/aiy710000060.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000060.opus b/project/sounds/aiy710000060.opus
new file mode 100644
index 0000000..2fae4fc
Binary files /dev/null and b/project/sounds/aiy710000060.opus differ
diff --git a/project/sounds/aiy710000070.mp3 b/project/sounds/aiy710000070.mp3
deleted file mode 100644
index 1528e54..0000000
Binary files a/project/sounds/aiy710000070.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000070.opus b/project/sounds/aiy710000070.opus
new file mode 100644
index 0000000..ce2b71c
Binary files /dev/null and b/project/sounds/aiy710000070.opus differ
diff --git a/project/sounds/aiy710000080.mp3 b/project/sounds/aiy710000080.mp3
deleted file mode 100644
index 600011d..0000000
Binary files a/project/sounds/aiy710000080.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000080.opus b/project/sounds/aiy710000080.opus
new file mode 100644
index 0000000..0673c92
Binary files /dev/null and b/project/sounds/aiy710000080.opus differ
diff --git a/project/sounds/aiy710000090.mp3 b/project/sounds/aiy710000090.mp3
deleted file mode 100644
index b091686..0000000
Binary files a/project/sounds/aiy710000090.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000090.opus b/project/sounds/aiy710000090.opus
new file mode 100644
index 0000000..9990f15
Binary files /dev/null and b/project/sounds/aiy710000090.opus differ
diff --git a/project/sounds/aiy710000100.mp3 b/project/sounds/aiy710000100.mp3
deleted file mode 100644
index 3f84955..0000000
Binary files a/project/sounds/aiy710000100.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000100.opus b/project/sounds/aiy710000100.opus
new file mode 100644
index 0000000..28b109b
Binary files /dev/null and b/project/sounds/aiy710000100.opus differ
diff --git a/project/sounds/aiy710000110.mp3 b/project/sounds/aiy710000110.mp3
deleted file mode 100644
index 1095ffa..0000000
Binary files a/project/sounds/aiy710000110.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000110.opus b/project/sounds/aiy710000110.opus
new file mode 100644
index 0000000..ad02c45
Binary files /dev/null and b/project/sounds/aiy710000110.opus differ
diff --git a/project/sounds/aiy710000120.mp3 b/project/sounds/aiy710000120.mp3
deleted file mode 100644
index 81be490..0000000
Binary files a/project/sounds/aiy710000120.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000120.opus b/project/sounds/aiy710000120.opus
new file mode 100644
index 0000000..0985ea1
Binary files /dev/null and b/project/sounds/aiy710000120.opus differ
diff --git a/project/sounds/aiy710000130.mp3 b/project/sounds/aiy710000130.mp3
deleted file mode 100644
index bde952f..0000000
Binary files a/project/sounds/aiy710000130.mp3 and /dev/null differ
diff --git a/project/sounds/aiy710000130.opus b/project/sounds/aiy710000130.opus
new file mode 100644
index 0000000..07881d1
Binary files /dev/null and b/project/sounds/aiy710000130.opus differ
diff --git a/project/sounds/aiy820000010.mp3 b/project/sounds/aiy820000010.mp3
deleted file mode 100644
index 04b2978..0000000
Binary files a/project/sounds/aiy820000010.mp3 and /dev/null differ
diff --git a/project/sounds/aiy820000010.opus b/project/sounds/aiy820000010.opus
new file mode 100644
index 0000000..4503491
Binary files /dev/null and b/project/sounds/aiy820000010.opus differ
diff --git a/project/sounds/aiy820000020.mp3 b/project/sounds/aiy820000020.mp3
deleted file mode 100644
index ef06278..0000000
Binary files a/project/sounds/aiy820000020.mp3 and /dev/null differ
diff --git a/project/sounds/aiy820000020.opus b/project/sounds/aiy820000020.opus
new file mode 100644
index 0000000..e405674
Binary files /dev/null and b/project/sounds/aiy820000020.opus differ
diff --git a/project/sounds/attack.mp3 b/project/sounds/attack.mp3
deleted file mode 100644
index 16098f7..0000000
Binary files a/project/sounds/attack.mp3 and /dev/null differ
diff --git a/project/sounds/bomb.mp3 b/project/sounds/bomb.mp3
deleted file mode 100644
index 8a98067..0000000
Binary files a/project/sounds/bomb.mp3 and /dev/null differ
diff --git a/project/sounds/bomb.opus b/project/sounds/bomb.opus
new file mode 100644
index 0000000..443e6af
Binary files /dev/null and b/project/sounds/bomb.opus differ
diff --git a/project/sounds/cancel.mp3 b/project/sounds/cancel.mp3
deleted file mode 100644
index 3842eee..0000000
Binary files a/project/sounds/cancel.mp3 and /dev/null differ
diff --git a/project/sounds/cancel.opus b/project/sounds/cancel.opus
new file mode 100644
index 0000000..da26056
Binary files /dev/null and b/project/sounds/cancel.opus differ
diff --git a/project/sounds/centerFly.mp3 b/project/sounds/centerFly.mp3
deleted file mode 100644
index 8246763..0000000
Binary files a/project/sounds/centerFly.mp3 and /dev/null differ
diff --git a/project/sounds/centerFly.opus b/project/sounds/centerFly.opus
new file mode 100644
index 0000000..fd94f13
Binary files /dev/null and b/project/sounds/centerFly.opus differ
diff --git a/project/sounds/confirm.mp3 b/project/sounds/confirm.mp3
deleted file mode 100644
index 138beeb..0000000
Binary files a/project/sounds/confirm.mp3 and /dev/null differ
diff --git a/project/sounds/confirm.opus b/project/sounds/confirm.opus
new file mode 100644
index 0000000..821a7dc
Binary files /dev/null and b/project/sounds/confirm.opus differ
diff --git a/project/sounds/cursor.mp3 b/project/sounds/cursor.mp3
deleted file mode 100644
index 652bf07..0000000
Binary files a/project/sounds/cursor.mp3 and /dev/null differ
diff --git a/project/sounds/cursor.opus b/project/sounds/cursor.opus
new file mode 100644
index 0000000..7eec58d
Binary files /dev/null and b/project/sounds/cursor.opus differ
diff --git a/project/sounds/door.mp3 b/project/sounds/door.mp3
deleted file mode 100644
index ea6706d..0000000
Binary files a/project/sounds/door.mp3 and /dev/null differ
diff --git a/project/sounds/door.opus b/project/sounds/door.opus
new file mode 100644
index 0000000..dce3824
Binary files /dev/null and b/project/sounds/door.opus differ
diff --git a/project/sounds/equip.mp3 b/project/sounds/equip.mp3
deleted file mode 100644
index 36bbd02..0000000
Binary files a/project/sounds/equip.mp3 and /dev/null differ
diff --git a/project/sounds/equip.opus b/project/sounds/equip.opus
new file mode 100644
index 0000000..2bd2c63
Binary files /dev/null and b/project/sounds/equip.opus differ
diff --git a/project/sounds/error.mp3 b/project/sounds/error.mp3
deleted file mode 100644
index 329cca4..0000000
Binary files a/project/sounds/error.mp3 and /dev/null differ
diff --git a/project/sounds/error.opus b/project/sounds/error.opus
new file mode 100644
index 0000000..973ee32
Binary files /dev/null and b/project/sounds/error.opus differ
diff --git a/project/sounds/floor.mp3 b/project/sounds/floor.mp3
deleted file mode 100644
index 2b24efb..0000000
Binary files a/project/sounds/floor.mp3 and /dev/null differ
diff --git a/project/sounds/floor.opus b/project/sounds/floor.opus
new file mode 100644
index 0000000..0f603d3
Binary files /dev/null and b/project/sounds/floor.opus differ
diff --git a/project/sounds/gem.mp3 b/project/sounds/gem.mp3
deleted file mode 100644
index c29b9df..0000000
Binary files a/project/sounds/gem.mp3 and /dev/null differ
diff --git a/project/sounds/gem.opus b/project/sounds/gem.opus
new file mode 100644
index 0000000..f7bbf6c
Binary files /dev/null and b/project/sounds/gem.opus differ
diff --git a/project/sounds/icePickaxe.mp3 b/project/sounds/icePickaxe.mp3
deleted file mode 100644
index 29ed9b0..0000000
Binary files a/project/sounds/icePickaxe.mp3 and /dev/null differ
diff --git a/project/sounds/icePickaxe.opus b/project/sounds/icePickaxe.opus
new file mode 100644
index 0000000..479b8e5
Binary files /dev/null and b/project/sounds/icePickaxe.opus differ
diff --git a/project/sounds/item.mp3 b/project/sounds/item.mp3
deleted file mode 100644
index 5d82178..0000000
Binary files a/project/sounds/item.mp3 and /dev/null differ
diff --git a/project/sounds/item.opus b/project/sounds/item.opus
new file mode 100644
index 0000000..9a488f0
Binary files /dev/null and b/project/sounds/item.opus differ
diff --git a/project/sounds/jingbao.mp3 b/project/sounds/jingbao.mp3
deleted file mode 100644
index c2c4aaa..0000000
Binary files a/project/sounds/jingbao.mp3 and /dev/null differ
diff --git a/project/sounds/jingbao.opus b/project/sounds/jingbao.opus
new file mode 100644
index 0000000..b2a57e1
Binary files /dev/null and b/project/sounds/jingbao.opus differ
diff --git a/project/sounds/jump.mp3 b/project/sounds/jump.mp3
deleted file mode 100644
index b8ce8f7..0000000
Binary files a/project/sounds/jump.mp3 and /dev/null differ
diff --git a/project/sounds/jump.opus b/project/sounds/jump.opus
new file mode 100644
index 0000000..b1c8c01
Binary files /dev/null and b/project/sounds/jump.opus differ
diff --git a/project/sounds/load.mp3 b/project/sounds/load.mp3
deleted file mode 100644
index e680f4d..0000000
Binary files a/project/sounds/load.mp3 and /dev/null differ
diff --git a/project/sounds/load.opus b/project/sounds/load.opus
new file mode 100644
index 0000000..215881f
Binary files /dev/null and b/project/sounds/load.opus differ
diff --git a/project/sounds/open_ui.mp3 b/project/sounds/open_ui.mp3
deleted file mode 100644
index 0282a08..0000000
Binary files a/project/sounds/open_ui.mp3 and /dev/null differ
diff --git a/project/sounds/open_ui.opus b/project/sounds/open_ui.opus
new file mode 100644
index 0000000..dbad758
Binary files /dev/null and b/project/sounds/open_ui.opus differ
diff --git a/project/sounds/pickaxe.mp3 b/project/sounds/pickaxe.mp3
deleted file mode 100644
index f6dc258..0000000
Binary files a/project/sounds/pickaxe.mp3 and /dev/null differ
diff --git a/project/sounds/pickaxe.opus b/project/sounds/pickaxe.opus
new file mode 100644
index 0000000..2a9924d
Binary files /dev/null and b/project/sounds/pickaxe.opus differ
diff --git a/project/sounds/recovery.mp3 b/project/sounds/recovery.mp3
deleted file mode 100644
index 76b67f3..0000000
Binary files a/project/sounds/recovery.mp3 and /dev/null differ
diff --git a/project/sounds/recovery.opus b/project/sounds/recovery.opus
new file mode 100644
index 0000000..07091c8
Binary files /dev/null and b/project/sounds/recovery.opus differ
diff --git a/project/sounds/save.mp3 b/project/sounds/save.mp3
deleted file mode 100644
index 295dbf2..0000000
Binary files a/project/sounds/save.mp3 and /dev/null differ
diff --git a/project/sounds/save.opus b/project/sounds/save.opus
new file mode 100644
index 0000000..58f2c9a
Binary files /dev/null and b/project/sounds/save.opus differ
diff --git a/project/sounds/shop.mp3 b/project/sounds/shop.mp3
deleted file mode 100644
index b654aa2..0000000
Binary files a/project/sounds/shop.mp3 and /dev/null differ
diff --git a/project/sounds/shop.opus b/project/sounds/shop.opus
new file mode 100644
index 0000000..1accbf1
Binary files /dev/null and b/project/sounds/shop.opus differ
diff --git a/project/sounds/zone.mp3 b/project/sounds/zone.mp3
deleted file mode 100644
index 414b287..0000000
Binary files a/project/sounds/zone.mp3 and /dev/null differ
diff --git a/project/sounds/zone.opus b/project/sounds/zone.opus
new file mode 100644
index 0000000..ccdade8
Binary files /dev/null and b/project/sounds/zone.opus differ