danoniplus 47.0.1 → 47.1.1
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 +355 -235
- package/js/lib/danoni_constants.js +6 -3
- 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 : 2026/04/
|
|
7
|
+
* Revised : 2026/04/22
|
|
8
8
|
*
|
|
9
9
|
* https://github.com/cwtickle/danoniplus
|
|
10
10
|
*/
|
|
11
|
-
const g_version = `Ver 47.
|
|
12
|
-
const g_revisedDate = `2026/04/
|
|
11
|
+
const g_version = `Ver 47.1.1`;
|
|
12
|
+
const g_revisedDate = `2026/04/22`;
|
|
13
13
|
|
|
14
14
|
// カスタム用バージョン (danoni_custom.js 等で指定可)
|
|
15
15
|
let g_localVersion = ``;
|
|
@@ -213,6 +213,7 @@ const g_detailObj = {
|
|
|
213
213
|
speedData: [],
|
|
214
214
|
boostData: [],
|
|
215
215
|
toolDif: [],
|
|
216
|
+
miniMapParams: {},
|
|
216
217
|
scoreMinimap: {},
|
|
217
218
|
scoreMinimapReverse: {},
|
|
218
219
|
scoreMinimapHeader: {},
|
|
@@ -2731,6 +2732,7 @@ const initialControl = async () => {
|
|
|
2731
2732
|
|
|
2732
2733
|
// 譜面ヘッダー、特殊キー情報の読込
|
|
2733
2734
|
Object.assign(g_headerObj, headerConvert(g_rootObj));
|
|
2735
|
+
g_headerObj.undefinedKeyListFinal = [];
|
|
2734
2736
|
const importKeysData = _data => {
|
|
2735
2737
|
keysConvert(dosConvert(_data));
|
|
2736
2738
|
g_headerObj.undefinedKeyLists = g_headerObj.undefinedKeyLists.filter(key => g_keyObj[`${g_keyObj.defaultProp}${key}_0`] === undefined);
|
|
@@ -2744,6 +2746,20 @@ const initialControl = async () => {
|
|
|
2744
2746
|
keyExtraList: makeDedupliArray(g_headerObj.undefinedKeyLists, g_rootObj.keyExtraList?.split(`,`)),
|
|
2745
2747
|
});
|
|
2746
2748
|
|
|
2749
|
+
// キー定義でエラーになる場合は強制的にデフォルトキーへ変更して続行
|
|
2750
|
+
let hasUndefinedKey = false;
|
|
2751
|
+
for (let j = 0; j < g_headerObj.keyLabels.length; j++) {
|
|
2752
|
+
if (g_headerObj.undefinedKeyListFinal.includes(g_headerObj.keyLabels[j])) {
|
|
2753
|
+
g_headerObj.keyLists = g_headerObj.keyLists.filter(key => key !== g_headerObj.keyLabels[j]);
|
|
2754
|
+
g_headerObj.keyLabels[j] = g_keyObj.initKeyLabel;
|
|
2755
|
+
hasUndefinedKey = true;
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
if (hasUndefinedKey) {
|
|
2759
|
+
g_headerObj.keyLists = makeDedupliArray(g_headerObj.keyLists, [g_keyObj.initKeyLabel])
|
|
2760
|
+
.sort((a, b) => parseInt(a) - parseInt(b));
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2747
2763
|
// デフォルトのカラー・シャッフルグループ設定を退避
|
|
2748
2764
|
g_keycons.groups.forEach(type =>
|
|
2749
2765
|
Object.keys(g_keyObj).filter(val => val.startsWith(type))
|
|
@@ -3356,153 +3372,237 @@ const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
|
|
|
3356
3372
|
g_detailObj.playingFrame[_scoreId] = playingFrame;
|
|
3357
3373
|
g_detailObj.playingFrameWithBlank[_scoreId] = lastFrame - startFrame;
|
|
3358
3374
|
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
ctxHeader.fillStyle = '#999';
|
|
3380
|
-
ctxHeader.font = `10px ${getBasicFont()}`;
|
|
3381
|
-
ctxHeader.textAlign = 'center';
|
|
3382
|
-
|
|
3383
|
-
for (let j = 0; j < _keyNum; j++) {
|
|
3384
|
-
const x = timeMargin + j * laneWidth + laneWidth / 2;
|
|
3385
|
-
ctxHeader.fillText(g_kCd[g_keyObj[`keyCtrl${_keyCtrlPtn}`][j][0]], x, 10);
|
|
3386
|
-
ctxHeader.strokeStyle = '#444';
|
|
3387
|
-
}
|
|
3388
|
-
|
|
3389
|
-
g_detailObj.scoreMinimapHeader[_scoreId] = canvasHeader;
|
|
3390
|
-
|
|
3391
|
-
// 譜面全体のキャンバスの作成
|
|
3392
|
-
const MAX_CANVAS_HEIGHT = 10000; // 1枚あたりの高さ制限(安全圏)
|
|
3393
|
-
const canvasCount = Math.ceil((mmHeightTotal + mmMarginY * 2) / MAX_CANVAS_HEIGHT);
|
|
3394
|
-
const canvases = [];
|
|
3395
|
-
|
|
3396
|
-
for (let i = 0; i < canvasCount; i++) {
|
|
3397
|
-
const cvs = document.createElement('canvas');
|
|
3398
|
-
const h = (i === canvasCount - 1)
|
|
3399
|
-
? (mmHeightTotal + mmMarginY * 2) - (MAX_CANVAS_HEIGHT * i)
|
|
3400
|
-
: MAX_CANVAS_HEIGHT;
|
|
3401
|
-
|
|
3402
|
-
cvs.width = logicalWidth * dpr;
|
|
3403
|
-
cvs.height = h * dpr;
|
|
3404
|
-
cvs.style.width = `${logicalWidth}px`;
|
|
3405
|
-
cvs.style.height = `${h}px`;
|
|
3406
|
-
cvs.style.display = 'block'; // 隙間防止
|
|
3407
|
-
const ctx = cvs.getContext('2d');
|
|
3408
|
-
ctx.scale(dpr, dpr);
|
|
3409
|
-
canvases.push({ canvas: cvs, ctx: ctx, offsetTop: i * MAX_CANVAS_HEIGHT });
|
|
3410
|
-
}
|
|
3411
|
-
|
|
3412
|
-
// --- 描画先を振り分けるヘルパー関数 ---
|
|
3413
|
-
const drawOnTarget = (y, height, drawFunc) => {
|
|
3414
|
-
canvases.forEach(item => {
|
|
3415
|
-
// 描画要素がCanvasの範囲内に入っているか判定
|
|
3416
|
-
if (y + height >= item.offsetTop && y <= item.offsetTop + (item.canvas.height / dpr)) {
|
|
3417
|
-
item.ctx.save();
|
|
3418
|
-
item.ctx.translate(0, -item.offsetTop);
|
|
3419
|
-
drawFunc(item.ctx);
|
|
3420
|
-
item.ctx.restore();
|
|
3421
|
-
}
|
|
3422
|
-
});
|
|
3423
|
-
};
|
|
3375
|
+
// --- ミニマップ設定 ---
|
|
3376
|
+
g_detailObj.miniMapParams[_scoreId] = {
|
|
3377
|
+
_scoreId, _scoreObj, _keyNum: keyNum,
|
|
3378
|
+
_playingFrame: playingFrame,
|
|
3379
|
+
_firstArrowFrame: firstArrowFrame,
|
|
3380
|
+
_keyCtrlPtn,
|
|
3381
|
+
config: {
|
|
3382
|
+
scale: 1.5,
|
|
3383
|
+
dpr: window.devicePixelRatio || 1,
|
|
3384
|
+
timeMargin: 35,
|
|
3385
|
+
mmWidthBase: (g_sWidth - 500) / 2 + 290,
|
|
3386
|
+
mmMarginY: 2,
|
|
3387
|
+
get laneWidth() {
|
|
3388
|
+
return Math.min(Math.floor((this.mmWidthBase - this.timeMargin) / keyNum), 40);
|
|
3389
|
+
},
|
|
3390
|
+
get logicalWidth() {
|
|
3391
|
+
return this.timeMargin + (this.laneWidth * keyNum);
|
|
3392
|
+
}
|
|
3393
|
+
},
|
|
3394
|
+
};
|
|
3424
3395
|
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
// リバース:最大値(mmHeight)から上へ向かって減る
|
|
3428
|
-
const getY = (frame) => {
|
|
3429
|
-
const relativeFrame = frame - _firstArrowFrame;
|
|
3430
|
-
const rawY = relativeFrame * scale;
|
|
3431
|
-
return _isReverse ? (mmHeightTotal - rawY + mmMarginY) : (rawY + mmMarginY);
|
|
3432
|
-
};
|
|
3396
|
+
// ヘッダー生成
|
|
3397
|
+
g_detailObj.scoreMinimapHeader[_scoreId] = createMinimapHeader(g_detailObj.miniMapParams[_scoreId].config, _keyCtrlPtn, keyNum);
|
|
3433
3398
|
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
};
|
|
3399
|
+
// Canvas保存用配列を空で初期化
|
|
3400
|
+
g_detailObj.scoreMinimap[_scoreId] = null;
|
|
3401
|
+
g_detailObj.scoreMinimapReverse[_scoreId] = null;
|
|
3402
|
+
};
|
|
3439
3403
|
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
ctx.textBaseline = 'middle';
|
|
3451
|
-
ctx.beginPath();
|
|
3452
|
-
ctx.moveTo(timeMargin, y);
|
|
3453
|
-
ctx.lineTo(timeMargin + laneWidth * _keyNum, y);
|
|
3454
|
-
ctx.stroke();
|
|
3455
|
-
ctx.fillText(formatTime(currentFrame), timeMargin, y);
|
|
3456
|
-
});
|
|
3457
|
-
}
|
|
3404
|
+
/**
|
|
3405
|
+
* 指定された高さに基づいて分割されたCanvasリストを生成する
|
|
3406
|
+
* @param {number} _width
|
|
3407
|
+
* @param {number} _totalHeight
|
|
3408
|
+
* @param {number} _dpr
|
|
3409
|
+
* @return {object[]} 分割されたCanvasとそのコンテキスト、オフセット情報を含むリスト
|
|
3410
|
+
*/
|
|
3411
|
+
const createSplitCanvases = (_width, _totalHeight, _dpr) => {
|
|
3412
|
+
// バックバッファ(実際のピクセル数)の最大値を 8000 に設定(iOS Safari 8192px 対策)
|
|
3413
|
+
const BACKING_STORE_LIMIT = 8000;
|
|
3458
3414
|
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3415
|
+
// 論理上の最大高さ(CSSピクセル)を計算
|
|
3416
|
+
// dpr=2なら4000px、dpr=3なら2666px が1枚の限界になる
|
|
3417
|
+
const maxLogicalHeight = Math.max(1, Math.floor(BACKING_STORE_LIMIT / _dpr));
|
|
3418
|
+
if (_totalHeight <= 0) return [];
|
|
3419
|
+
|
|
3420
|
+
const count = Math.ceil(_totalHeight / maxLogicalHeight);
|
|
3421
|
+
const list = [];
|
|
3422
|
+
|
|
3423
|
+
for (let i = 0; i < count; i++) {
|
|
3424
|
+
const cvs = document.createElement('canvas');
|
|
3425
|
+
// 残りの高さを計算
|
|
3426
|
+
const logicalH = (i === count - 1)
|
|
3427
|
+
? _totalHeight - (maxLogicalHeight * i)
|
|
3428
|
+
: maxLogicalHeight;
|
|
3429
|
+
|
|
3430
|
+
// 実際の描画解像度をセット
|
|
3431
|
+
cvs.width = _width * _dpr;
|
|
3432
|
+
cvs.height = logicalH * _dpr;
|
|
3433
|
+
|
|
3434
|
+
// ブラウザ上の表示サイズをセット
|
|
3435
|
+
cvs.style.width = `${_width}px`;
|
|
3436
|
+
cvs.style.height = `${logicalH}px`;
|
|
3437
|
+
cvs.style.display = 'block';
|
|
3438
|
+
|
|
3439
|
+
const ctx = cvs.getContext('2d');
|
|
3440
|
+
ctx.scale(_dpr, _dpr);
|
|
3441
|
+
|
|
3442
|
+
list.push({
|
|
3443
|
+
canvas: cvs,
|
|
3444
|
+
ctx: ctx,
|
|
3445
|
+
offsetTop: i * maxLogicalHeight,
|
|
3446
|
+
logicalHeight: logicalH
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
return list;
|
|
3450
|
+
};
|
|
3451
|
+
|
|
3452
|
+
/**
|
|
3453
|
+
* 描画対象のCanvasを判定して描画を実行する
|
|
3454
|
+
* @param {HTMLCanvasElement[]} _canvases
|
|
3455
|
+
* @param {number} _y
|
|
3456
|
+
* @param {number} _h
|
|
3457
|
+
* @param {number} _dpr
|
|
3458
|
+
* @param {Function} _drawFunc
|
|
3459
|
+
*/
|
|
3460
|
+
const distributeDrawing = (_canvases, _y, _h, _dpr, _drawFunc) => {
|
|
3461
|
+
_canvases.forEach(item => {
|
|
3462
|
+
const canvasHeight = item.logicalHeight;
|
|
3463
|
+
if (_y + _h >= item.offsetTop && _y <= item.offsetTop + canvasHeight) {
|
|
3464
|
+
item.ctx.save();
|
|
3465
|
+
item.ctx.translate(0, -item.offsetTop);
|
|
3466
|
+
_drawFunc(item.ctx);
|
|
3467
|
+
item.ctx.restore();
|
|
3476
3468
|
}
|
|
3469
|
+
});
|
|
3470
|
+
};
|
|
3477
3471
|
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3472
|
+
/**
|
|
3473
|
+
* 譜面ミニマップ:キー名を表示するヘッダーキャンバスを作成する
|
|
3474
|
+
* @param {object} _config ミニマップの基本設定
|
|
3475
|
+
* @param {number} _config.dpr デバイスピクセル比
|
|
3476
|
+
* @param {number} _config.timeMargin 時間軸のマージン
|
|
3477
|
+
* @param {number} _config.laneWidth レーンの幅
|
|
3478
|
+
* @param {number} _config.logicalWidth キャンバスの論理幅
|
|
3479
|
+
* @param {string} _keyCtrlPtn キーコントロールパターン
|
|
3480
|
+
* @param {number} _keyNum キー数
|
|
3481
|
+
* @return {HTMLCanvasElement} ヘッダー用のキャンバス要素
|
|
3482
|
+
*/
|
|
3483
|
+
const createMinimapHeader = (_config, _keyCtrlPtn, _keyNum) => {
|
|
3484
|
+
const { dpr, timeMargin, laneWidth, logicalWidth } = _config;
|
|
3485
|
+
const headerHeight = 15; // ヘッダーの固定高
|
|
3486
|
+
|
|
3487
|
+
const canvas = document.createElement('canvas');
|
|
3488
|
+
const ctx = canvas.getContext('2d');
|
|
3489
|
+
|
|
3490
|
+
// 解像度と表示サイズの設定
|
|
3491
|
+
canvas.width = logicalWidth * dpr;
|
|
3492
|
+
canvas.height = headerHeight * dpr;
|
|
3493
|
+
canvas.style.width = `${logicalWidth}px`;
|
|
3494
|
+
canvas.style.height = `${headerHeight}px`;
|
|
3495
|
+
canvas.style.display = 'block';
|
|
3496
|
+
|
|
3497
|
+
ctx.scale(dpr, dpr);
|
|
3498
|
+
|
|
3499
|
+
// テキストのスタイル設定
|
|
3500
|
+
ctx.fillStyle = '#999';
|
|
3501
|
+
ctx.font = `10px ${getBasicFont()}`;
|
|
3502
|
+
ctx.textAlign = 'center';
|
|
3503
|
+
ctx.textBaseline = 'middle';
|
|
3504
|
+
|
|
3505
|
+
// 各レーンのキー名を描画
|
|
3506
|
+
for (let j = 0; j < _keyNum; j++) {
|
|
3507
|
+
// config.laneWidth を使って中央座標を計算
|
|
3508
|
+
const x = timeMargin + j * laneWidth + laneWidth / 2;
|
|
3509
|
+
const keyText = g_kCd[g_keyObj[`keyCtrl${_keyCtrlPtn}`][j][0]];
|
|
3510
|
+
|
|
3511
|
+
ctx.fillText(keyText, x, headerHeight / 2 + 2); // 視覚的な中央調整で +2px
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
return canvas;
|
|
3515
|
+
};
|
|
3516
|
+
|
|
3517
|
+
/**
|
|
3518
|
+
* 譜面ミニマップ:譜面ミニマップ本体生成
|
|
3519
|
+
* @param {object} _params ミニマップ生成のためのパラメータオブジェクト
|
|
3520
|
+
* @param {object} _params._scoreObj 譜面データオブジェクト
|
|
3521
|
+
* @param {number} _params._keyNum キー数
|
|
3522
|
+
* @param {number} _params._playingFrame 演奏時間(フレーム数)
|
|
3523
|
+
* @param {number} _params._firstArrowFrame 最初の矢印のフレーム位置
|
|
3524
|
+
* @param {string} _params._keyCtrlPtn キーコントロールパターン
|
|
3525
|
+
* @param {object} _params.config ミニマップの基本設定
|
|
3526
|
+
* @param {number} _params.config.scale ミニマップの時間軸のスケール
|
|
3527
|
+
* @param {number} _params.config.dpr デバイスピクセル比
|
|
3528
|
+
* @param {number} _params.config.timeMargin 時間軸のマージン
|
|
3529
|
+
* @param {number} _params.config.laneWidth レーンの幅
|
|
3530
|
+
* @param {number} _params.config.logicalWidth キャンバスの論理幅
|
|
3531
|
+
* @param {number} _params.config.mmMarginY ミニマップの上下マージン
|
|
3532
|
+
* @param {boolean} _isReverse ミニマップのリバース表示フラグ
|
|
3533
|
+
* @returns {HTMLCanvasElement[]} ミニマップ用のキャンバス要素の配列
|
|
3534
|
+
*/
|
|
3535
|
+
const generateMinimapData = (_params, _isReverse) => {
|
|
3536
|
+
const { _scoreObj, _keyNum, _playingFrame, _firstArrowFrame, _keyCtrlPtn, config } = _params;
|
|
3537
|
+
const { scale, dpr, timeMargin, laneWidth, logicalWidth, mmMarginY } = config;
|
|
3538
|
+
|
|
3539
|
+
const mmHeightTotal = _playingFrame * scale + mmMarginY * 2;
|
|
3540
|
+
const canvases = createSplitCanvases(logicalWidth, mmHeightTotal, dpr);
|
|
3541
|
+
|
|
3542
|
+
const getY = (frame) => {
|
|
3543
|
+
const relativeFrame = frame - _firstArrowFrame;
|
|
3544
|
+
const rawY = relativeFrame * scale;
|
|
3545
|
+
// mmHeightTotalから引くのではなく、中身の演奏時間部分(_playingFrame * scale)を基準にリバース
|
|
3546
|
+
return _isReverse
|
|
3547
|
+
? (_playingFrame * scale - rawY + mmMarginY)
|
|
3548
|
+
: (rawY + mmMarginY);
|
|
3549
|
+
};
|
|
3550
|
+
|
|
3551
|
+
// 1. 時間軸描画
|
|
3552
|
+
const interval = g_fps;
|
|
3553
|
+
for (let f = Math.ceil(_firstArrowFrame / interval) * interval; f <= _firstArrowFrame + _playingFrame; f += interval) {
|
|
3554
|
+
const y = getY(f);
|
|
3555
|
+
distributeDrawing(canvases, y - 5, 10, dpr, (ctx) => {
|
|
3556
|
+
ctx.strokeStyle = '#444';
|
|
3557
|
+
ctx.fillStyle = '#999';
|
|
3558
|
+
ctx.font = `10px ${getBasicFont()}`;
|
|
3559
|
+
ctx.textAlign = 'right';
|
|
3560
|
+
ctx.textBaseline = 'middle';
|
|
3561
|
+
ctx.beginPath(); ctx.moveTo(timeMargin, y); ctx.lineTo(timeMargin + laneWidth * _keyNum, y); ctx.stroke();
|
|
3562
|
+
const [m, s] = transFrameToTimer(f).split(':');
|
|
3563
|
+
ctx.fillText(`${m.padStart(2, '0')}:${s}`, timeMargin, y);
|
|
3564
|
+
});
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
// 2. フリーズノート
|
|
3568
|
+
for (let j = 0; j < _keyNum; j++) {
|
|
3569
|
+
const frz = _scoreObj.frzData[j];
|
|
3570
|
+
for (let k = 0; k < frz.length; k += 2) {
|
|
3571
|
+
const start = frz[k];
|
|
3572
|
+
const end = frz[k + 1];
|
|
3573
|
+
|
|
3574
|
+
// 終了地点がない、またはどちらかが数値でない場合はスキップ
|
|
3575
|
+
if (end === undefined || isNaN(start) || isNaN(end)) {
|
|
3576
|
+
console.warn(`Minimap: Incomplete freeze note pair at lane ${j}, index ${k}`);
|
|
3577
|
+
continue;
|
|
3578
|
+
}
|
|
3579
|
+
const y1 = getY(start);
|
|
3580
|
+
const y2 = getY(end);
|
|
3581
|
+
const top = Math.min(y1, y2);
|
|
3582
|
+
const h = Math.abs(y2 - y1);
|
|
3583
|
+
const x = timeMargin + j * laneWidth;
|
|
3584
|
+
distributeDrawing(canvases, top, h, dpr, (ctx) => {
|
|
3585
|
+
ctx.fillStyle = 'rgba(0, 200, 255, 0.4)';
|
|
3586
|
+
ctx.fillRect(x + 2, top, laneWidth - 3, h);
|
|
3587
|
+
ctx.strokeStyle = 'rgba(0, 200, 255, 0.8)';
|
|
3588
|
+
ctx.strokeRect(x + 2, top, laneWidth - 3, h);
|
|
3489
3589
|
});
|
|
3490
3590
|
}
|
|
3591
|
+
}
|
|
3491
3592
|
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3593
|
+
// 3. 通常ノート
|
|
3594
|
+
for (let j = 0; j < _keyNum; j++) {
|
|
3595
|
+
const color = g_dfColorObj.setColorType2[g_keyObj[`color${_keyCtrlPtn}_0`][j]] || '#ffffff';
|
|
3596
|
+
_scoreObj.arrowData[j].forEach(note => {
|
|
3597
|
+
const y = getY(parseFloat(note));
|
|
3598
|
+
distributeDrawing(canvases, y - 1.5, 3, dpr, (ctx) => {
|
|
3599
|
+
ctx.fillStyle = color;
|
|
3600
|
+
ctx.fillRect(timeMargin + j * laneWidth + 1, y - 1.5, laneWidth - 1, 3);
|
|
3601
|
+
});
|
|
3602
|
+
});
|
|
3603
|
+
}
|
|
3500
3604
|
|
|
3501
|
-
|
|
3502
|
-
// 通常版を生成
|
|
3503
|
-
generateMinimap(_scoreId, _scoreObj, keyNum, playingFrame, firstArrowFrame, false);
|
|
3504
|
-
// リバース版を生成
|
|
3505
|
-
generateMinimap(_scoreId, _scoreObj, keyNum, playingFrame, firstArrowFrame, true);
|
|
3605
|
+
return canvases.map(item => item.canvas);
|
|
3506
3606
|
};
|
|
3507
3607
|
|
|
3508
3608
|
/**
|
|
@@ -4011,7 +4111,7 @@ const headerConvert = _dosObj => {
|
|
|
4011
4111
|
obj.lifeInits.push(lifeData(`Init`, 25));
|
|
4012
4112
|
|
|
4013
4113
|
// キー数
|
|
4014
|
-
const keyLabel = difDetails[difpos.Key] ||
|
|
4114
|
+
const keyLabel = difDetails[difpos.Key] || g_keyObj.initKeyLabel;
|
|
4015
4115
|
obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] ?? keyLabel);
|
|
4016
4116
|
|
|
4017
4117
|
// 譜面名、制作者名
|
|
@@ -4031,7 +4131,7 @@ const headerConvert = _dosObj => {
|
|
|
4031
4131
|
});
|
|
4032
4132
|
} else {
|
|
4033
4133
|
makeWarningWindow(g_msgInfoObj.E_0021);
|
|
4034
|
-
obj.keyLabels = [
|
|
4134
|
+
obj.keyLabels = [g_keyObj.initKeyLabel];
|
|
4035
4135
|
obj.difLabels = [`Normal`];
|
|
4036
4136
|
obj.initSpeeds = [3.5];
|
|
4037
4137
|
obj.lifeBorders = [`x`];
|
|
@@ -5300,126 +5400,132 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
|
|
|
5300
5400
|
g_keyObj.minPatterns = 1;
|
|
5301
5401
|
g_keyObj.dfPtnNum = 0;
|
|
5302
5402
|
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5403
|
+
try {
|
|
5404
|
+
|
|
5405
|
+
// キーパターンの追記 (appendX)
|
|
5406
|
+
if (setBoolVal(_dosObj[`append${newKey}`])) {
|
|
5407
|
+
for (let j = 0; ; j++) {
|
|
5408
|
+
if (g_keyObj[`${g_keyObj.defaultProp}${newKey}_${j}`] === undefined) {
|
|
5409
|
+
break;
|
|
5410
|
+
}
|
|
5411
|
+
g_keyObj.dfPtnNum++;
|
|
5308
5412
|
}
|
|
5309
|
-
g_keyObj.dfPtnNum++;
|
|
5310
5413
|
}
|
|
5311
|
-
|
|
5312
|
-
const dfPtnNum = g_keyObj.dfPtnNum;
|
|
5414
|
+
const dfPtnNum = g_keyObj.dfPtnNum;
|
|
5313
5415
|
|
|
5314
|
-
|
|
5315
|
-
|
|
5416
|
+
// キーの名前 (keyNameX)
|
|
5417
|
+
g_keyObj[`keyName${newKey}`] = _dosObj[`keyName${newKey}`]?.split(`,`) ?? [newKey, `key`];
|
|
5316
5418
|
|
|
5317
|
-
|
|
5318
|
-
|
|
5419
|
+
// キーの最小横幅 (minWidthX)
|
|
5420
|
+
g_keyObj[`minWidth${newKey}`] = _dosObj[`minWidth${newKey}`] ?? g_keyObj[`minWidth${newKey}`] ?? g_keyObj.minWidthDefault;
|
|
5319
5421
|
|
|
5320
|
-
|
|
5321
|
-
|
|
5422
|
+
// 移動ロック (movLockX)
|
|
5423
|
+
g_keyObj[`movLock${newKey}`] = setBoolVal(_dosObj[`movLock${newKey}`] ?? g_keyObj[`movLock${newKey}`], false);
|
|
5322
5424
|
|
|
5323
|
-
|
|
5324
|
-
|
|
5425
|
+
// 位置マニュアル化 (initManualX)
|
|
5426
|
+
g_keyObj[`initManual${newKey}`] = setBoolVal(_dosObj[`initManual${newKey}`] ?? g_keyObj[`initManual${newKey}`], false);
|
|
5325
5427
|
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5428
|
+
// キーコンフィグ (keyCtrlX_Y)
|
|
5429
|
+
g_keyObj.minPatterns = newKeyMultiParam(newKey, `keyCtrl`, toKeyCtrlArray, {
|
|
5430
|
+
errCd: `E_0104`, baseCopyFlg: true,
|
|
5431
|
+
});
|
|
5330
5432
|
|
|
5331
|
-
|
|
5332
|
-
|
|
5433
|
+
// 読込変数の接頭辞 (charaX_Y)
|
|
5434
|
+
newKeyMultiParam(newKey, `chara`, toString);
|
|
5333
5435
|
|
|
5334
|
-
|
|
5335
|
-
|
|
5436
|
+
// 矢印色パターン (colorX_Y)
|
|
5437
|
+
newKeyTripleParam(newKey, `color`);
|
|
5336
5438
|
|
|
5337
|
-
|
|
5338
|
-
|
|
5439
|
+
// 矢印の回転量指定、キャラクタパターン (stepRtnX_Y)
|
|
5440
|
+
newKeyTripleParam(newKey, `stepRtn`);
|
|
5339
5441
|
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5442
|
+
// 各キーの区切り位置 (divX_Y)
|
|
5443
|
+
_dosObj[`div${newKey}`]?.split(`$`).forEach((tmpDiv, k) => {
|
|
5444
|
+
const tmpDivPtn = tmpDiv.split(`,`);
|
|
5445
|
+
const ptnName = `${newKey}_${k + dfPtnNum}`;
|
|
5344
5446
|
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5447
|
+
if (g_keyObj[`div${tmpDivPtn[0]}`] !== undefined) {
|
|
5448
|
+
// 既定キーパターンが指定された場合、存在すればその値を適用
|
|
5449
|
+
g_keyObj[`div${ptnName}`] = g_keyObj[`div${tmpDivPtn[0]}`];
|
|
5450
|
+
g_keyObj[`divMax${ptnName}`] = setVal(g_keyObj[`divMax${tmpDivPtn[0]}`], undefined, C_TYP_FLOAT);
|
|
5451
|
+
} else if (!hasVal(tmpDivPtn[0]) && setIntVal(g_keyObj[`div${ptnName}`], -1) !== -1) {
|
|
5452
|
+
// カスタムキー側のdivXが未定義だが、すでに初期設定で定義済みの場合はスキップ
|
|
5453
|
+
return;
|
|
5454
|
+
} else {
|
|
5455
|
+
// それ以外の場合は指定された値を適用(未指定時はその後で指定)
|
|
5456
|
+
g_keyObj[`div${ptnName}`] = setVal(tmpDivPtn[0], undefined, C_TYP_NUMBER);
|
|
5457
|
+
g_keyObj[`divMax${ptnName}`] = setVal(getKeyPosNum(tmpDivPtn[1], g_keyObj[`div${ptnName}`]), undefined, C_TYP_FLOAT);
|
|
5458
|
+
}
|
|
5459
|
+
});
|
|
5358
5460
|
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5461
|
+
// ステップゾーン位置 (posX_Y)
|
|
5462
|
+
newKeyMultiParam(newKey, `pos`, toFloat, {
|
|
5463
|
+
loopFunc: (k, keyheader) => {
|
|
5464
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`].forEach((val, j) =>
|
|
5465
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`][j] = getKeyPosNum(String(val), g_keyObj[`div${newKey}_${k + dfPtnNum}`]));
|
|
5466
|
+
},
|
|
5467
|
+
});
|
|
5366
5468
|
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5469
|
+
// charaX_Y, posX_Y, keyGroupX_Y, divX_Y, divMaxX_Yが未指定の場合はkeyCtrlX_Yを元に適用
|
|
5470
|
+
for (let k = 0; k < g_keyObj.minPatterns; k++) {
|
|
5471
|
+
setKeyDfVal(`${newKey}_${k + dfPtnNum}`);
|
|
5472
|
+
}
|
|
5371
5473
|
|
|
5372
|
-
|
|
5373
|
-
|
|
5474
|
+
// ステップゾーン間隔 (blankX_Y)
|
|
5475
|
+
newKeySingleParam(newKey, `blank`, C_TYP_FLOAT, g_keyObj.blank_def);
|
|
5374
5476
|
|
|
5375
|
-
|
|
5376
|
-
|
|
5477
|
+
// 矢印群の倍率 (scaleX_Y)
|
|
5478
|
+
newKeySingleParam(newKey, `scale`, C_TYP_FLOAT, g_keyObj.scale_def);
|
|
5377
5479
|
|
|
5378
|
-
|
|
5379
|
-
|
|
5480
|
+
// プレイ中ショートカット:リトライ (keyRetryX_Y)
|
|
5481
|
+
newKeySingleParam(newKey, `keyRetry`, C_TYP_STRING, C_KEY_RETRY);
|
|
5380
5482
|
|
|
5381
|
-
|
|
5382
|
-
|
|
5483
|
+
// プレイ中ショートカット:タイトルバック (keyTitleBackX_Y)
|
|
5484
|
+
newKeySingleParam(newKey, `keyTitleBack`, C_TYP_STRING, C_KEY_TITLEBACK);
|
|
5383
5485
|
|
|
5384
|
-
|
|
5385
|
-
|
|
5486
|
+
// 別キーフラグ (transKeyX_Y)
|
|
5487
|
+
newKeySingleParam(newKey, `transKey`, C_TYP_STRING, ``);
|
|
5386
5488
|
|
|
5387
|
-
|
|
5388
|
-
|
|
5489
|
+
// フラットモード (flatModeX_Y)
|
|
5490
|
+
newKeySingleParam(newKey, `flatMode`, C_TYP_BOOLEAN, false);
|
|
5389
5491
|
|
|
5390
|
-
|
|
5391
|
-
|
|
5492
|
+
// シャッフルグループ (shuffleX_Y)
|
|
5493
|
+
newKeyTripleParam(newKey, `shuffle`);
|
|
5392
5494
|
|
|
5393
|
-
|
|
5394
|
-
|
|
5495
|
+
// キーグループ (keyGroupX_Y)
|
|
5496
|
+
newKeyMultiParam(newKey, `keyGroup`, toSplitArrayStr);
|
|
5395
5497
|
|
|
5396
|
-
|
|
5397
|
-
|
|
5498
|
+
// キーグループの表示制御 (keyGroupOrderX_Y)
|
|
5499
|
+
newKeyMultiParam(newKey, `keyGroupOrder`, toString);
|
|
5398
5500
|
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5501
|
+
// スクロールパターン (scrollX_Y)
|
|
5502
|
+
// |scroll(newKey)=Cross::1,1,-1,-1,-1,1,1/Split::1,1,1,-1,-1,-1,-1$...|
|
|
5503
|
+
newKeyPairParam(newKey, `scroll`, `scrollDir`, C_FLG_HYPHEN, 1);
|
|
5402
5504
|
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5505
|
+
// アシストパターン (assistX_Y)
|
|
5506
|
+
// |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
|
|
5507
|
+
newKeyPairParam(newKey, `assist`, `assistPos`);
|
|
5406
5508
|
|
|
5407
|
-
|
|
5408
|
-
|
|
5509
|
+
// レーンごとの割当レイヤーグループ (layerGroupX_Y)
|
|
5510
|
+
newKeyMultiParam(newKey, `layerGroup`, toInt);
|
|
5409
5511
|
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5512
|
+
// レイヤーごとのアニメーション情報 (layerTransX_Y)
|
|
5513
|
+
if (hasVal(_dosObj[`layerTrans${newKey}`])) {
|
|
5514
|
+
_dosObj[`layerTrans${newKey}`] = _dosObj[`layerTrans${newKey}`]?.replaceAll(`,`, `___`);
|
|
5515
|
+
newKeyMultiParam(newKey, `layerTrans`, toSplitArrayStr, {
|
|
5516
|
+
loopFunc: (k, keyheader) => {
|
|
5517
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`][0] = g_keyObj[`${keyheader}_${k + dfPtnNum}`]?.[0]?.map(val => val.replaceAll(`___`, `,`));
|
|
5518
|
+
},
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5419
5521
|
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5522
|
+
// keyRetry, keyTitleBackのキー名をキーコードに変換
|
|
5523
|
+
const keyTypePatterns = Object.keys(g_keyObj).filter(val => val.startsWith(`keyRetry${newKey}`) || val.startsWith(`keyTitleBack${newKey}`));
|
|
5524
|
+
keyTypePatterns.forEach(name => g_keyObj[name] = getKeyCtrlVal(g_keyObj[name]));
|
|
5525
|
+
} catch (e) {
|
|
5526
|
+
g_headerObj.undefinedKeyListFinal.push(newKey);
|
|
5527
|
+
console.warn(`Error in key pattern conversion: ${newKey}`, e);
|
|
5528
|
+
}
|
|
5423
5529
|
});
|
|
5424
5530
|
|
|
5425
5531
|
return keyExtraList;
|
|
@@ -7742,10 +7848,24 @@ const drawMinimap = (_scoreId, _initFlg = false) => {
|
|
|
7742
7848
|
deleteChildspriteAll(`detailMiniMap`);
|
|
7743
7849
|
|
|
7744
7850
|
// drawMinimap 内の Canvas 追加部分
|
|
7745
|
-
const
|
|
7851
|
+
const isRev = g_stateObj.miniMapRevFlg;
|
|
7852
|
+
let savedCanvases = isRev
|
|
7746
7853
|
? g_detailObj.scoreMinimapReverse[_scoreId]
|
|
7747
7854
|
: g_detailObj.scoreMinimap[_scoreId];
|
|
7748
7855
|
|
|
7856
|
+
if (!savedCanvases) {
|
|
7857
|
+
// 未作成の場合のみミニマップを生成(Lazy Generation)
|
|
7858
|
+
const params = g_detailObj.miniMapParams[_scoreId];
|
|
7859
|
+
savedCanvases = generateMinimapData(params, isRev);
|
|
7860
|
+
|
|
7861
|
+
// 生成したものをキャッシュに保存
|
|
7862
|
+
if (isRev) {
|
|
7863
|
+
g_detailObj.scoreMinimapReverse[_scoreId] = savedCanvases;
|
|
7864
|
+
} else {
|
|
7865
|
+
g_detailObj.scoreMinimap[_scoreId] = savedCanvases;
|
|
7866
|
+
}
|
|
7867
|
+
}
|
|
7868
|
+
|
|
7749
7869
|
// --- ヘッダー部分 ---
|
|
7750
7870
|
const detailMiniMapHeader = createEmptySprite(detailMiniMap, `detailMiniMapHeader`, g_windowObj.detailMiniMapHeader);
|
|
7751
7871
|
$id(`detailMiniMapHeader`).top = (g_stateObj.miniMapRevFlg ? 230 : 0) + `px`;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Source by tickle
|
|
7
7
|
* Created : 2019/11/19
|
|
8
|
-
* Revised : 2026/04/
|
|
8
|
+
* Revised : 2026/04/21 (v47.1.0)
|
|
9
9
|
*
|
|
10
10
|
* https://github.com/cwtickle/danoniplus
|
|
11
11
|
*/
|
|
@@ -3118,6 +3118,7 @@ const g_keyObj = {
|
|
|
3118
3118
|
|
|
3119
3119
|
minKeyCtrlNum: 2,
|
|
3120
3120
|
defaultKeyList: [],
|
|
3121
|
+
initKeyLabel: `7`,
|
|
3121
3122
|
|
|
3122
3123
|
// キー別ヘッダー
|
|
3123
3124
|
// - 譜面データ中に出てくる矢印(ノーツ)の種類と順番(ステップゾーン表示順)を管理する
|
|
@@ -4288,7 +4289,8 @@ const g_lang_msgInfoObj = {
|
|
|
4288
4289
|
E_0051: `Displayオプションのデフォルト設定(XXXXChainOFF)で、<br>指定できない組み合わせが設定されています。(E-0051)`,
|
|
4289
4290
|
|
|
4290
4291
|
E_0104: `新しいキー:{0}の[keyCtrl]が未定義です。(E-0104)<br>
|
|
4291
|
-
|keyCtrl{0}=S,D,E/R,F,Space,J,M/Comma,K,L
|
|
4292
|
+
|keyCtrl{0}=S,D,E/R,F,Space,J,M/Comma,K,L|<br>
|
|
4293
|
+
未定義のキーは7keyに割り当てられます。`,
|
|
4292
4294
|
|
|
4293
4295
|
E_0201: `色変化データで指定した色変化対象が存在しません。[pattern={0}] (E-0201)`,
|
|
4294
4296
|
|
|
@@ -4336,7 +4338,8 @@ const g_lang_msgInfoObj = {
|
|
|
4336
4338
|
E_0051: `In the default setting (XXXXChainOFF) of the Display option, <br>a combination that cannot be specified is set. (E-0051)`,
|
|
4337
4339
|
|
|
4338
4340
|
E_0104: `New key: {0} [keyCtrl] is not set. (E-0104)<br>
|
|
4339
|
-
|keyCtrl{0}=S,D,E/R,F,Space,J,M/Comma,K,L
|
|
4341
|
+
|keyCtrl{0}=S,D,E/R,F,Space,J,M/Comma,K,L|<br>
|
|
4342
|
+
Undefined keymode is assigned to 7key.`,
|
|
4340
4343
|
|
|
4341
4344
|
E_0201: `The color change target specified in the color change data does not exist. [pattern={0}] (E-0201)`,
|
|
4342
4345
|
|