danoniplus 43.2.0 → 43.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/danoni_main.js +180 -75
- package/package.json +1 -1
package/js/danoni_main.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Source by tickle
|
|
6
6
|
* Created : 2018/10/08
|
|
7
|
-
* Revised : 2025/12/
|
|
7
|
+
* Revised : 2025/12/30
|
|
8
8
|
*
|
|
9
9
|
* https://github.com/cwtickle/danoniplus
|
|
10
10
|
*/
|
|
11
|
-
const g_version = `Ver 43.2.
|
|
12
|
-
const g_revisedDate = `2025/12/
|
|
11
|
+
const g_version = `Ver 43.2.2`;
|
|
12
|
+
const g_revisedDate = `2025/12/30`;
|
|
13
13
|
|
|
14
14
|
// カスタム用バージョン (danoni_custom.js 等で指定可)
|
|
15
15
|
let g_localVersion = ``;
|
|
@@ -115,6 +115,9 @@ const waitUntilLoaded = () => {
|
|
|
115
115
|
// fps(デフォルトは60)
|
|
116
116
|
let g_fps = 60;
|
|
117
117
|
|
|
118
|
+
// プレイ画面再生時の内部スケジューリング用のマージン時間(100ms)
|
|
119
|
+
let g_scheduleLead = 0.1;
|
|
120
|
+
|
|
118
121
|
// 譜面データの&区切りを有効にするか
|
|
119
122
|
let g_enableAmpersandSplit = true;
|
|
120
123
|
|
|
@@ -2350,13 +2353,25 @@ class AudioPlayer {
|
|
|
2350
2353
|
this._eventListeners[`canplaythrough`]?.forEach(_listener => _listener());
|
|
2351
2354
|
}
|
|
2352
2355
|
|
|
2356
|
+
/**
|
|
2357
|
+
* 再生処理
|
|
2358
|
+
* @param {number} _adjustmentTime
|
|
2359
|
+
* - 実際の再生開始時間は、scheduleLead + _adjustmentTime から開始される
|
|
2360
|
+
* - ただしゲーム内での経過時間計算は _adjustmentTime を基準に行う
|
|
2361
|
+
* - scheduleLead は安定した再生タイミングを確保するための内部マージン
|
|
2362
|
+
*/
|
|
2353
2363
|
play(_adjustmentTime = 0) {
|
|
2354
2364
|
this._source = this._context.createBufferSource();
|
|
2355
2365
|
this._source.buffer = this._buffer;
|
|
2356
2366
|
this._source.playbackRate.value = this.playbackRate;
|
|
2357
2367
|
this._source.connect(this._gain);
|
|
2358
|
-
|
|
2359
|
-
|
|
2368
|
+
|
|
2369
|
+
// 実際の予約時刻(内部スケジューリング用のマージンを含む)
|
|
2370
|
+
const startAt = this._context.currentTime + g_scheduleLead + _adjustmentTime;
|
|
2371
|
+
this._source.start(startAt, this._fadeinPosition);
|
|
2372
|
+
|
|
2373
|
+
// ゲーム側の論理的開始時刻(g_scheduleLead を含めない)
|
|
2374
|
+
this._startTime = this._context.currentTime + _adjustmentTime;
|
|
2360
2375
|
}
|
|
2361
2376
|
|
|
2362
2377
|
pause() {
|
|
@@ -5542,7 +5557,7 @@ const pauseBGM = () => {
|
|
|
5542
5557
|
}
|
|
5543
5558
|
[`bgmLooped`, `bgmFadeIn`, `bgmFadeOut`].forEach(id => {
|
|
5544
5559
|
if (g_stateObj[id]) {
|
|
5545
|
-
|
|
5560
|
+
clearTimeout(g_stateObj[id]);
|
|
5546
5561
|
g_stateObj[id] = null;
|
|
5547
5562
|
}
|
|
5548
5563
|
});
|
|
@@ -5566,95 +5581,177 @@ const playBGM = async (_num, _currentLoopNum = g_settings.musicLoopNum) => {
|
|
|
5566
5581
|
const musicEnd = g_headerObj.musicEnds?.[currentIdx] ?? 0;
|
|
5567
5582
|
const isTitle = () => g_currentPage === `title` && _currentLoopNum === g_settings.musicLoopNum;
|
|
5568
5583
|
|
|
5584
|
+
/**
|
|
5585
|
+
* 汎用フェード処理
|
|
5586
|
+
* @param {number} startVolume - 開始音量 (0〜1)
|
|
5587
|
+
* @param {number} endVolume - 終了音量 (0〜1)
|
|
5588
|
+
* @param {number} step - 1ステップの増減量
|
|
5589
|
+
* @param {function} onEnd - フェード完了時の処理
|
|
5590
|
+
* @param {function} isValid - フェード継続条件(true: 継続, false: 中断)
|
|
5591
|
+
* @returns {number} timeoutId
|
|
5592
|
+
*/
|
|
5593
|
+
const fadeVolume = (startVolume, endVolume, step, onEnd, isValid) => {
|
|
5594
|
+
|
|
5595
|
+
// 開始時点で終了音量とイコールの場合は終了
|
|
5596
|
+
if (startVolume === endVolume || step === 0) {
|
|
5597
|
+
g_audio.volume = endVolume;
|
|
5598
|
+
onEnd(true);
|
|
5599
|
+
return null;
|
|
5600
|
+
}
|
|
5601
|
+
|
|
5602
|
+
let volume = startVolume;
|
|
5603
|
+
g_audio.volume = startVolume;
|
|
5604
|
+
|
|
5605
|
+
const stepFunc = () => {
|
|
5606
|
+
// 継続条件チェック
|
|
5607
|
+
if (!isValid()) {
|
|
5608
|
+
onEnd(false); // 中断
|
|
5609
|
+
return;
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5612
|
+
// 終了判定
|
|
5613
|
+
const reached =
|
|
5614
|
+
(startVolume < endVolume && volume >= endVolume) ||
|
|
5615
|
+
(startVolume > endVolume && volume <= endVolume);
|
|
5616
|
+
|
|
5617
|
+
if (reached) {
|
|
5618
|
+
g_audio.volume = endVolume;
|
|
5619
|
+
onEnd(true); // 正常終了
|
|
5620
|
+
return;
|
|
5621
|
+
}
|
|
5622
|
+
|
|
5623
|
+
// 音量更新
|
|
5624
|
+
volume += step;
|
|
5625
|
+
g_audio.volume = Math.min(Math.max(volume, 0), 1);
|
|
5626
|
+
|
|
5627
|
+
// 次のステップへ
|
|
5628
|
+
setTimeout(stepFunc, FADE_INTERVAL_MS);
|
|
5629
|
+
};
|
|
5630
|
+
|
|
5631
|
+
return setTimeout(stepFunc, FADE_INTERVAL_MS);
|
|
5632
|
+
};
|
|
5633
|
+
|
|
5634
|
+
/**
|
|
5635
|
+
* 汎用ポーリング(監視)処理
|
|
5636
|
+
* @param {function} check - 条件チェック関数(true なら終了)
|
|
5637
|
+
* @param {function} onEnd - 終了時の処理
|
|
5638
|
+
* @param {function} isValid - 継続条件(true: 継続, false: 中断)
|
|
5639
|
+
* @returns {number} timeoutId
|
|
5640
|
+
*/
|
|
5641
|
+
const poll = (check, onEnd, isValid) => {
|
|
5642
|
+
const step = () => {
|
|
5643
|
+
// 継続条件チェック
|
|
5644
|
+
if (!isValid()) {
|
|
5645
|
+
onEnd(false); // 中断
|
|
5646
|
+
return;
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
// 条件成立
|
|
5650
|
+
if (check()) {
|
|
5651
|
+
onEnd(true); // 正常終了
|
|
5652
|
+
return;
|
|
5653
|
+
}
|
|
5654
|
+
|
|
5655
|
+
// 次のチェックへ
|
|
5656
|
+
setTimeout(step, FADE_INTERVAL_MS);
|
|
5657
|
+
};
|
|
5658
|
+
|
|
5659
|
+
return setTimeout(step, FADE_INTERVAL_MS);
|
|
5660
|
+
};
|
|
5661
|
+
|
|
5569
5662
|
/**
|
|
5570
5663
|
* BGMのフェードアウトとシーク
|
|
5571
5664
|
*/
|
|
5572
5665
|
const fadeOutAndSeek = () => {
|
|
5573
|
-
|
|
5574
|
-
const
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5666
|
+
const start = g_audio.volume;
|
|
5667
|
+
const end = 0;
|
|
5668
|
+
|
|
5669
|
+
g_stateObj.bgmFadeOut = fadeVolume(
|
|
5670
|
+
start,
|
|
5671
|
+
end,
|
|
5672
|
+
-FADE_STEP,
|
|
5673
|
+
/* onEnd */
|
|
5674
|
+
(finished) => {
|
|
5580
5675
|
g_stateObj.bgmFadeOut = null;
|
|
5676
|
+
|
|
5677
|
+
if (!finished) return; // 中断された
|
|
5678
|
+
|
|
5581
5679
|
g_audio.pause();
|
|
5582
5680
|
g_audio.currentTime = musicStart;
|
|
5583
5681
|
|
|
5584
|
-
// フェードイン開始
|
|
5585
5682
|
if (isTitle()) {
|
|
5586
5683
|
setTimeout(() => {
|
|
5587
5684
|
fadeIn();
|
|
5588
|
-
if (encodeFlg)
|
|
5589
|
-
// base64エンコード時はtimeupdateイベントが発火しないため、
|
|
5590
|
-
// setIntervalで時間を取得する
|
|
5591
|
-
repeatBGM();
|
|
5592
|
-
}
|
|
5685
|
+
if (encodeFlg) repeatBGM();
|
|
5593
5686
|
}, FADE_DELAY_MS);
|
|
5594
5687
|
} else {
|
|
5595
5688
|
pauseBGM();
|
|
5596
5689
|
}
|
|
5597
|
-
}
|
|
5598
|
-
|
|
5599
|
-
|
|
5690
|
+
},
|
|
5691
|
+
/* isValid */
|
|
5692
|
+
() =>
|
|
5693
|
+
isTitle() &&
|
|
5694
|
+
g_stateObj.bgmFadeOut !== null
|
|
5695
|
+
);
|
|
5600
5696
|
};
|
|
5601
5697
|
|
|
5602
5698
|
/**
|
|
5603
5699
|
* BGMのフェードイン
|
|
5604
5700
|
*/
|
|
5605
5701
|
const fadeIn = () => {
|
|
5606
|
-
if (!(g_audio instanceof AudioPlayer) && !g_audio.src)
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5702
|
+
if (!(g_audio instanceof AudioPlayer) && !g_audio.src) return;
|
|
5703
|
+
|
|
5704
|
+
const start = 0;
|
|
5705
|
+
const end = g_stateObj.bgmVolume / 100;
|
|
5706
|
+
|
|
5707
|
+
g_audio.volume = 0;
|
|
5610
5708
|
g_audio.play();
|
|
5611
|
-
const fadeInterval = setInterval(() => {
|
|
5612
|
-
if (volume < g_stateObj.bgmVolume / 100 && isTitle()) {
|
|
5613
|
-
volume += FADE_STEP;
|
|
5614
|
-
g_audio.volume = Math.min(volume, 1);
|
|
5615
|
-
} else {
|
|
5616
|
-
clearInterval(fadeInterval);
|
|
5617
|
-
g_stateObj.bgmFadeIn = null;
|
|
5618
|
-
}
|
|
5619
5709
|
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5710
|
+
g_stateObj.bgmFadeIn = fadeVolume(
|
|
5711
|
+
start,
|
|
5712
|
+
end,
|
|
5713
|
+
FADE_STEP,
|
|
5714
|
+
/* onEnd */
|
|
5715
|
+
() => {
|
|
5624
5716
|
g_stateObj.bgmFadeIn = null;
|
|
5625
|
-
}
|
|
5626
|
-
|
|
5627
|
-
|
|
5717
|
+
},
|
|
5718
|
+
/* isValid */
|
|
5719
|
+
() =>
|
|
5720
|
+
isTitle() &&
|
|
5721
|
+
g_stateObj.bgmFadeIn !== null &&
|
|
5722
|
+
currentIdx === g_headerObj.musicIdxList[g_settings.musicIdxNum]
|
|
5723
|
+
);
|
|
5628
5724
|
};
|
|
5629
5725
|
|
|
5630
5726
|
/**
|
|
5631
|
-
* BGMのループ処理
|
|
5727
|
+
* BGMのループ処理 (base64エンコード時用)
|
|
5728
|
+
* - base64エンコード時はtimeupdateイベントが発火しないため、setIntervalで時間を取得する
|
|
5632
5729
|
*/
|
|
5633
5730
|
const repeatBGM = () => {
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5731
|
+
const numAtStart = g_settings.musicIdxNum;
|
|
5732
|
+
|
|
5733
|
+
g_stateObj.bgmLooped = poll(
|
|
5734
|
+
/* check */
|
|
5735
|
+
() => {
|
|
5637
5736
|
try {
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
} catch (e) {
|
|
5645
|
-
clearInterval(repeatCheck);
|
|
5646
|
-
g_stateObj.bgmLooped = null;
|
|
5737
|
+
return (
|
|
5738
|
+
g_audio.elapsedTime >= musicEnd ||
|
|
5739
|
+
numAtStart !== g_settings.musicIdxNum
|
|
5740
|
+
);
|
|
5741
|
+
} catch {
|
|
5742
|
+
return true; // エラー時は終了扱い
|
|
5647
5743
|
}
|
|
5648
|
-
},
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
if (g_audio.currentTime >= musicEnd) {
|
|
5744
|
+
},
|
|
5745
|
+
/* onEnd */
|
|
5746
|
+
(finished) => {
|
|
5747
|
+
g_stateObj.bgmLooped = null;
|
|
5748
|
+
if (finished) {
|
|
5654
5749
|
fadeOutAndSeek();
|
|
5655
5750
|
}
|
|
5656
|
-
}
|
|
5657
|
-
|
|
5751
|
+
},
|
|
5752
|
+
/* isValid */
|
|
5753
|
+
() => g_stateObj.bgmLooped !== null
|
|
5754
|
+
);
|
|
5658
5755
|
};
|
|
5659
5756
|
|
|
5660
5757
|
if (encodeFlg) {
|
|
@@ -5676,9 +5773,10 @@ const playBGM = async (_num, _currentLoopNum = g_settings.musicLoopNum) => {
|
|
|
5676
5773
|
g_audio = tmpAudio;
|
|
5677
5774
|
}
|
|
5678
5775
|
g_audio.volume = g_stateObj.bgmVolume / 100;
|
|
5679
|
-
if (g_currentPage === `title`) {
|
|
5776
|
+
if (g_currentPage === `title` && musicEnd > 0) {
|
|
5680
5777
|
g_audio.currentTime = musicStart;
|
|
5681
5778
|
g_audio.play();
|
|
5779
|
+
repeatBGM();
|
|
5682
5780
|
}
|
|
5683
5781
|
} catch (e) {
|
|
5684
5782
|
// 音源の読み込みに失敗した場合、エラーを表示
|
|
@@ -5698,9 +5796,14 @@ const playBGM = async (_num, _currentLoopNum = g_settings.musicLoopNum) => {
|
|
|
5698
5796
|
g_audio.currentTime = musicStart;
|
|
5699
5797
|
g_audio.play();
|
|
5700
5798
|
}, { once: true });
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5799
|
+
|
|
5800
|
+
if (musicEnd > 0) {
|
|
5801
|
+
g_stateObj.bgmTimeupdateEvtId = g_handler.addListener(g_audio, "timeupdate", () => {
|
|
5802
|
+
if (g_audio.currentTime >= musicEnd) {
|
|
5803
|
+
fadeOutAndSeek();
|
|
5804
|
+
}
|
|
5805
|
+
});
|
|
5806
|
+
}
|
|
5704
5807
|
}
|
|
5705
5808
|
};
|
|
5706
5809
|
|
|
@@ -7824,26 +7927,28 @@ const gaugeFormat = (_mode, _border, _rcv, _dmg, _init, _lifeValFlg) => {
|
|
|
7824
7927
|
const initVal = g_headerObj.maxLifeVal * _init / 100;
|
|
7825
7928
|
const borderVal = g_headerObj.maxLifeVal * _border / 100;
|
|
7826
7929
|
|
|
7827
|
-
// 整形用にライフ初期値を整数、回復・ダメージ量を小数第
|
|
7930
|
+
// 整形用にライフ初期値を整数、回復・ダメージ量を小数第2位に丸める
|
|
7828
7931
|
const init = Math.round(initVal);
|
|
7829
7932
|
const borderText = (_mode === C_LFE_BORDER && _border !== 0 ? Math.round(borderVal) : `-`);
|
|
7830
|
-
const
|
|
7933
|
+
const round2 = _val => Math.round(_val * 100) / 100;
|
|
7831
7934
|
|
|
7832
|
-
let rcvText =
|
|
7935
|
+
let rcvText = round2(_rcv), dmgText = round2(_dmg);
|
|
7833
7936
|
let realRcv = _rcv, realDmg = _dmg;
|
|
7834
7937
|
const allCnt = sumData(g_detailObj.arrowCnt[g_stateObj.scoreId]) +
|
|
7835
7938
|
(g_headerObj.frzStartjdgUse ? 2 : 1) * sumData(g_detailObj.frzCnt[g_stateObj.scoreId]);
|
|
7836
7939
|
|
|
7940
|
+
// ゲージ設定が矢印数依存の場合、実際の値に変換して表示する
|
|
7941
|
+
// 表示上、計算した値は小数第二位までの表示とする(それ以外はそのまま)
|
|
7837
7942
|
if (_lifeValFlg === C_FLG_ON) {
|
|
7838
7943
|
rcvText = ``, dmgText = ``;
|
|
7839
7944
|
if (allCnt > 0) {
|
|
7840
7945
|
realRcv = Math.min(calcLifeVal(_rcv, allCnt), g_headerObj.maxLifeVal);
|
|
7841
7946
|
realDmg = Math.min(calcLifeVal(_dmg, allCnt), g_headerObj.maxLifeVal);
|
|
7842
|
-
rcvText = `${
|
|
7843
|
-
dmgText = `${
|
|
7947
|
+
rcvText = `${realRcv.toFixed(2)}<br>`;
|
|
7948
|
+
dmgText = `${realDmg.toFixed(2)}<br>`;
|
|
7844
7949
|
}
|
|
7845
|
-
rcvText += `<span class="settings_lifeVal">(${
|
|
7846
|
-
dmgText += `<span class="settings_lifeVal">(${
|
|
7950
|
+
rcvText += `<span class="settings_lifeVal">(${round2(_rcv)})</span>`;
|
|
7951
|
+
dmgText += `<span class="settings_lifeVal">(${round2(_dmg)})</span>`;
|
|
7847
7952
|
}
|
|
7848
7953
|
|
|
7849
7954
|
// 達成率(Accuracy)・許容ミス数の計算
|
|
@@ -10435,7 +10540,7 @@ const calcLifeVals = _allArrows => {
|
|
|
10435
10540
|
* @param {number} _val
|
|
10436
10541
|
* @param {number} _allArrows
|
|
10437
10542
|
*/
|
|
10438
|
-
const calcLifeVal = (_val, _allArrows) =>
|
|
10543
|
+
const calcLifeVal = (_val, _allArrows) => _val * g_headerObj.maxLifeVal / _allArrows;
|
|
10439
10544
|
|
|
10440
10545
|
/**
|
|
10441
10546
|
* 最終フレーム数の取得
|
|
@@ -12953,7 +13058,7 @@ const mainInit = () => {
|
|
|
12953
13058
|
// WebAudioAPIが使用できる場合は小数フレーム分だけ音源位置を調整
|
|
12954
13059
|
if (g_audio instanceof AudioPlayer) {
|
|
12955
13060
|
const musicStartAdjustment = (g_headerObj.blankFrame - g_stateObj.decimalAdjustment + 1) / g_fps;
|
|
12956
|
-
musicStartTime = performance.now() + musicStartAdjustment * 1000;
|
|
13061
|
+
musicStartTime = performance.now() + (musicStartAdjustment + g_scheduleLead) * 1000;
|
|
12957
13062
|
g_audio.play(musicStartAdjustment);
|
|
12958
13063
|
}
|
|
12959
13064
|
|