danoniplus 51.2.0 → 51.3.0

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 CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2026/10/03
7
+ * Revised : 2026/10/10
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 51.2.0`;
12
- const g_revisedDate = `2026/10/03`;
11
+ const g_version = `Ver 51.3.0`;
12
+ const g_revisedDate = `2026/10/10`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -645,7 +645,7 @@ const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {})
645
645
  if (_list.findIndex(val => val === rootKey) >= 0) {
646
646
  let result = `[`;
647
647
  for (let j = 0; j < _obj.length; j += _numOfSet) {
648
- result += `<br>${nestedIndent}${_obj[j]}: ${_obj[j + 1]}`;
648
+ result += `<br>${nestedIndent}${escapeHtml(_obj[j])}: ${escapeHtml(_obj[j + 1])}`;
649
649
  for (let k = 0; k < _numOfSet - 2; k++) {
650
650
  const idx = j + k + 2;
651
651
  if (idx < _obj.length) {
@@ -708,7 +708,8 @@ const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {})
708
708
  })
709
709
  : Object.entries(_obj).map(([key, value]) => {
710
710
  const formattedValue = getNextObject(value, rootKey === `` ? key : rootKey);
711
- return `<br>${nestedIndent}"${key}": ${formattedValue}`;
711
+ const formattedKey = colorFmt ? escapeHtml(key) : key;
712
+ return `<br>${nestedIndent}"${formattedKey}": ${formattedValue}`;
712
713
  })).filter(val => !hasVal(val) || val !== `----`);
713
714
 
714
715
  // 配列なら[]で囲む、オブジェクトなら{}で囲む
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/10/03 (v51.2.0)
8
+ * Revised : 2026/10/10 (v51.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -2353,6 +2353,9 @@ const g_keycons = {
2353
2353
  cursorNum: 0,
2354
2354
  keySwitchNum: 0,
2355
2355
  colorCursorNum: 0,
2356
+
2357
+ shortcutTypes: [`Retry`, `TitleBack`, `Pause`],
2358
+ defaultShortCuts: { Retry: C_KEY_RETRY, TitleBack: C_KEY_TITLEBACK, Pause: C_KEY_PAUSE },
2356
2359
  };
2357
2360
 
2358
2361
  let g_displays = [`stepZone`, `judgment`, `lifeGauge`, `score`, `musicInfo`, `filterLine`,
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/09/23 (v51.0.1)
8
+ * Revised : 2026/10/10 (v51.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -307,12 +307,15 @@ const musicAfterLoaded = () => new Promise((resolve, reject) => {
307
307
  }
308
308
  });
309
309
 
310
+ // リトライ時にプレイ用キー割り当てを復元するための退避 (初回保存でメモリが既定値へ戻るため)
311
+ let g_keyCtrlBackup = {};
312
+
310
313
  /**
311
314
  * 譜面データの変換処理
312
315
  * - 音源データの状態に依存しない部分のみを担う(g_audio非参照)
313
316
  * - loadMusic経由(並行フロー)、executeRetry経由(曲中リトライ)の両方から呼ばれる
314
317
  */
315
- const prepareScoreData = () => {
318
+ const prepareScoreData = (_retryFlg = false) => {
316
319
 
317
320
  const tkObj = getKeyInfo();
318
321
  const [keyCtrlPtn, keyNum] = [tkObj.keyCtrlPtn, tkObj.keyNum];
@@ -458,7 +461,7 @@ const prepareScoreData = () => {
458
461
  pushArrows(g_scoreObj, speedOnFrame, arrivalFrame);
459
462
 
460
463
  // メインに入る前の最終初期化処理
461
- getArrowSettings();
464
+ getArrowSettings(_retryFlg);
462
465
 
463
466
  // ユーザカスタムイベント
464
467
  safeExecuteCustomHooks(`g_customJsObj.loading`, g_customJsObj.loading);
@@ -2141,13 +2144,22 @@ const invertSpecificTransforms = (cssString, exceptList = []) => {
2141
2144
  /**
2142
2145
  * メイン画面前の初期化処理
2143
2146
  */
2144
- const getArrowSettings = () => {
2147
+ const getArrowSettings = (_retryFlg = false) => {
2145
2148
 
2146
2149
  g_attrObj = {};
2147
2150
  const tkObj = getKeyInfo();
2148
2151
  const [keyCtrlPtn, keyNum, posMax, divideCnt] =
2149
2152
  [tkObj.keyCtrlPtn, tkObj.keyNum, tkObj.posMax, tkObj.divideCnt];
2150
2153
 
2154
+ // 新しいプレイ開始時は前回プレイの退避を破棄 (リトライ時は保持して復元に使う)
2155
+ if (!_retryFlg) {
2156
+ g_keyCtrlBackup = {};
2157
+ }
2158
+ // リトライ時: 退避済みのキー割り当てをメモリへ戻してから以降の処理を行う
2159
+ const restoredFlg = _retryFlg && g_keyCtrlBackup[keyCtrlPtn] !== undefined;
2160
+ if (restoredFlg) {
2161
+ g_keyObj[`keyCtrl${keyCtrlPtn}`] = structuredClone(g_keyCtrlBackup[keyCtrlPtn]);
2162
+ }
2151
2163
  g_keyCopyLists.simpleDef.forEach(header => updateKeyInfo(header, keyCtrlPtn));
2152
2164
  g_headerObj.tuning = g_headerObj.creatorNames[g_stateObj.scoreId];
2153
2165
 
@@ -2540,7 +2552,13 @@ const getArrowSettings = () => {
2540
2552
  }
2541
2553
 
2542
2554
  // リバース、キーコンフィグなどをローカルストレージへ保存(Data Save: ON かつ別キーモードで無い場合)
2543
- if (g_stateObj.dataSaveFlg && !hasVal(g_keyObj[`transKey${keyCtrlPtn}`])) {
2555
+ if (_retryFlg) {
2556
+ // リトライ時は初回に保存済みのため再保存しない (prevKey等も触らない)
2557
+ // 復元したキー割り当ては、初回保存時と同様にメモリ上を既定値へ戻す
2558
+ if (restoredFlg) {
2559
+ g_keyObj[`keyCtrl${keyCtrlPtn}`] = structuredClone(g_keyObj[`keyCtrl${keyCtrlPtn}d`]);
2560
+ }
2561
+ } else if (g_stateObj.dataSaveFlg && !hasVal(g_keyObj[`transKey${keyCtrlPtn}`])) {
2544
2562
 
2545
2563
  // 次回キーコンフィグ画面へ戻ったとき、保存済みキーコンフィグ設定が表示されるようにする
2546
2564
  g_keyObj.prevKey = `Dummy`;
@@ -2562,9 +2580,22 @@ const getArrowSettings = () => {
2562
2580
  storageObj[`keyCtrl${addKey}`] = setKeyCtrl(g_localKeyStorage, keyNum, keyCtrlPtn);
2563
2581
  if (g_keyObj.currentPtn !== -1) {
2564
2582
  storageObj[`keyCtrlPtn${addKey}`] = g_keyObj.currentPtn;
2583
+ g_keyObj.storagePtn = g_keyObj.currentPtn;
2584
+ g_keyCtrlBackup[keyCtrlPtn] = structuredClone(g_keyObj[`keyCtrl${keyCtrlPtn}`]);
2565
2585
  g_keyObj[`keyCtrl${keyCtrlPtn}`] = structuredClone(g_keyObj[`keyCtrl${keyCtrlPtn}d`]);
2566
2586
  }
2567
2587
 
2588
+ // ショートカットキーの保存(基盤パターンのデフォルトと異なるものだけ)
2589
+ const savedShortcut = {};
2590
+ const isDefaultShortcut = _type => g_headerObj[`key${_type}`] === getDefaultShortcut(_type);
2591
+ g_keycons.shortcutTypes.filter(type => !isDefaultShortcut(type))
2592
+ .forEach(type => savedShortcut[type] = g_headerObj[`key${type}`]);
2593
+ if (Object.keys(savedShortcut).length > 0) {
2594
+ storageObj[`shortcut${addKey}`] = savedShortcut;
2595
+ } else {
2596
+ delete storageObj[`shortcut${addKey}`];
2597
+ }
2598
+
2568
2599
  // カラーセットの保存(キー別)
2569
2600
  if (!g_keycons.colorDefTypes.includes(g_colorType)) {
2570
2601
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/09/27 (v51.1.0)
8
+ * Revised : 2026/10/10 (v51.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -1182,13 +1182,10 @@ const headerConvert = _dosObj => {
1182
1182
 
1183
1183
  // プレイ中のショートカットキー
1184
1184
  obj.keyRetry = setIntVal(getKeyCtrlVal(_dosObj.keyRetry), C_KEY_RETRY);
1185
- obj.keyRetryDef = obj.keyRetry;
1186
1185
  obj.keyRetryDef2 = obj.keyRetry;
1187
1186
  obj.keyTitleBack = setIntVal(getKeyCtrlVal(_dosObj.keyTitleBack), C_KEY_TITLEBACK);
1188
- obj.keyTitleBackDef = obj.keyTitleBack;
1189
1187
  obj.keyTitleBackDef2 = obj.keyTitleBack;
1190
1188
  obj.keyPause = setIntVal(getKeyCtrlVal(_dosObj.keyPause), C_KEY_PAUSE);
1191
- obj.keyPauseDef = obj.keyPause;
1192
1189
  obj.keyPauseDef2 = obj.keyPause;
1193
1190
 
1194
1191
  // フリーズアローの許容フレーム数設定
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/09/23 (v51.0.0)
8
+ * Revised : 2026/10/10 (v51.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -480,6 +480,21 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
480
480
  viewGroup(_type);
481
481
  };
482
482
 
483
+ /**
484
+ * ショートカットキーボタンの表示更新
485
+ * @param {string} _type Retry / TitleBack / Pause
486
+ */
487
+ const updateScButton = _type => {
488
+ const siz = wUnit(getFontSize2(getScMsg[_type](), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
489
+ document.getElementById(`sc${_type}`).textContent = getScMsg[_type]();
490
+ document.getElementById(`sc${_type}`).style.fontSize = siz;
491
+ if (g_isMac) {
492
+ scTitleBack.textContent = getScMsg.TitleBack();
493
+ scTitleBack.style.fontSize = wUnit(getFontSize2(getScMsg.TitleBack(), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
494
+ }
495
+ changeConfigColor(document.getElementById(`sc${_type}`), getScButtonColor(_type));
496
+ };
497
+
483
498
  const kcSubX = parseFloat(keyconSprite.style.width) * ((1 - g_keyObj.scale) / 4);
484
499
  const kcSubY = parseFloat(keyconSprite.style.height) / ((1 + g_keyObj.scale) / 2) - parseFloat(keyconSprite.style.height);
485
500
  multiAppend(divRoot,
@@ -494,27 +509,21 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
494
509
  cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
495
510
  selectedKc = `TitleBack`;
496
511
  }
497
- }, g_lblPosObj.scTitleBack, g_cssObj.button_Default_NoColor,
498
- g_headerObj.keyTitleBack === g_headerObj.keyTitleBackDef2 ?
499
- g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
512
+ }, g_lblPosObj.scTitleBack, g_cssObj.button_Default_NoColor, getScButtonColor(`TitleBack`)),
500
513
 
501
514
  // リトライのショートカットキー変更
502
515
  createCss2Button(`scRetry`, getScMsg.Retry(), () => {
503
516
  cursor.style.left = wUnit(g_btnX(1 / 2) + kcSubX);
504
517
  cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
505
518
  selectedKc = `Retry`;
506
- }, g_lblPosObj.scRetry, g_cssObj.button_Default_NoColor,
507
- g_headerObj.keyRetry === g_headerObj.keyRetryDef2 ?
508
- g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
519
+ }, g_lblPosObj.scRetry, g_cssObj.button_Default_NoColor, getScButtonColor(`Retry`)),
509
520
 
510
521
  // ポーズのショートカットキー変更
511
522
  createCss2Button(`scPause`, getScMsg.Pause(), () => {
512
523
  cursor.style.left = wUnit(g_btnX(3 / 4) + kcSubX);
513
524
  cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
514
525
  selectedKc = `Pause`;
515
- }, g_lblPosObj.scPause, g_cssObj.button_Default_NoColor,
516
- g_headerObj.keyPause === g_headerObj.keyPauseDef2 ?
517
- g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
526
+ }, g_lblPosObj.scPause, g_cssObj.button_Default_NoColor, getScButtonColor(`Pause`)),
518
527
 
519
528
  // 別キーモード警告メッセージ
520
529
  createDivCss2Label(
@@ -973,6 +982,10 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
973
982
  changeKeyConfigColor(j, k, g_keyObj.currentPtn === -1 ? g_cssObj.keyconfig_Defaultkey : g_cssObj.title_base);
974
983
  }
975
984
  }
985
+ g_keycons.shortcutTypes.forEach(type => {
986
+ g_headerObj[`key${type}`] = getDefaultShortcut(type);
987
+ updateScButton(type);
988
+ });
976
989
  changeConfigCursor(0);
977
990
  }
978
991
  }, g_lblPosObj.btnKcReset, g_cssObj.button_Reset),
@@ -1035,17 +1048,7 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
1035
1048
  }
1036
1049
  // プレイ中ショートカットキー変更
1037
1050
  g_headerObj[`key${selectedKc}`] = setKey;
1038
- g_headerObj[`key${selectedKc}Def`] = setKey;
1039
- document.getElementById(`sc${selectedKc}`).textContent = getScMsg[selectedKc]();
1040
- document.getElementById(`sc${selectedKc}`).style.fontSize =
1041
- wUnit(getFontSize2(getScMsg[selectedKc](), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
1042
- if (g_isMac) {
1043
- scTitleBack.textContent = getScMsg.TitleBack();
1044
- scTitleBack.style.fontSize = wUnit(getFontSize2(getScMsg.TitleBack(), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
1045
- }
1046
- changeConfigColor(document.getElementById(`sc${selectedKc}`),
1047
- g_headerObj[`key${selectedKc}`] === g_headerObj[`key${selectedKc}Def2`] ?
1048
- g_cssObj.title_base : g_cssObj.keyconfig_Changekey);
1051
+ updateScButton(selectedKc);
1049
1052
  return;
1050
1053
  }
1051
1054
 
@@ -1131,6 +1134,61 @@ const completeTransKeyPtn = (_keyList) => {
1131
1134
  });
1132
1135
  };
1133
1136
 
1137
+ /**
1138
+ * 別キーモード時、移行先キーが保持するSelf保存パターンの取得可否チェック
1139
+ * @param {string} _keyCtrlPtn 例: "7_2"
1140
+ * @returns {number[][]|undefined} 適用可能な場合はSelf保存済みkeyCtrl配列、不可ならundefined
1141
+ */
1142
+ const getTransKeySelfCtrl = (_keyCtrlPtn) => {
1143
+ const transKeyName = g_keyObj[`transKey${_keyCtrlPtn}`];
1144
+ const transKeyPtn = g_keyObj[`transKeyPtn${_keyCtrlPtn}`];
1145
+ if (!hasVal(transKeyName) || transKeyPtn === undefined) {
1146
+ return undefined;
1147
+ }
1148
+ const [storageObj, addKey] = getKeyStorageObjByName(transKeyName);
1149
+ const savedCtrl = storageObj[`keyCtrl${addKey}`];
1150
+ const savedPtn = storageObj[`keyCtrlPtn${addKey}`];
1151
+
1152
+ if (savedPtn !== transKeyPtn) {
1153
+ return undefined;
1154
+ }
1155
+
1156
+ // 現在のキー配置(基準形状)とレーン数・各レーン長が完全一致することを確認
1157
+ const baseCtrl = g_keyObj[`keyCtrl${_keyCtrlPtn}`];
1158
+ const isValidShape = hasArrayList(savedCtrl, baseCtrl.length) &&
1159
+ savedCtrl.length === baseCtrl.length &&
1160
+ baseCtrl.every((lane, j) => hasArrayList(savedCtrl[j], lane.length) && savedCtrl[j].length === lane.length);
1161
+
1162
+ return isValidShape ? savedCtrl : undefined;
1163
+ };
1164
+
1165
+ /**
1166
+ * 別キーモードの移行先Selfパターンを現在のキー配置へ反映(保存はしない)
1167
+ */
1168
+ const applyTransKeySelfPattern = () => {
1169
+ const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
1170
+ const savedCtrl = getTransKeySelfCtrl(keyCtrlPtn);
1171
+ if (savedCtrl === undefined) {
1172
+ return;
1173
+ }
1174
+ const baseKeyNum = g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length;
1175
+ for (let j = 0; j < baseKeyNum; j++) {
1176
+ for (let k = 0; k < (savedCtrl[j]?.length ?? 0); k++) {
1177
+ g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k] = setIntVal(savedCtrl[j][k], 0);
1178
+ }
1179
+ }
1180
+ // ショートカットも取込元の保存内容で上書き(レーンキーと重複するものは無視)
1181
+ const [storageObj, addKey] = getKeyStorageObjByName(g_keyObj[`transKey${keyCtrlPtn}`]);
1182
+ const savedShortcut = storageObj[`shortcut${addKey}`] ?? {};
1183
+ const usedKeys = g_keyObj[`keyCtrl${keyCtrlPtn}`].flat();
1184
+ g_keycons.shortcutTypes.forEach(type => {
1185
+ const savedKey = savedShortcut[type];
1186
+ g_headerObj[`key${type}`] = (savedKey !== undefined && !usedKeys.includes(savedKey))
1187
+ ? savedKey : getDefaultShortcut(type);
1188
+ });
1189
+ keyConfigInit();
1190
+ };
1191
+
1134
1192
  // KeyLockボタンを押したときの表示切替
1135
1193
  const toggleKcDesc = () => {
1136
1194
  if (document.getElementById(`kcDesc`) !== null) {
@@ -1152,6 +1210,44 @@ const getKcDescMsg = () =>
1152
1210
  const getKeyLockName = () =>
1153
1211
  `${g_lblNameObj.b_keyLock}${g_stateObj.keyLockFlg ? g_emojiObj.locked : g_emojiObj.unlocked}`;
1154
1212
 
1213
+ /** 保存・Self時に基準とするキーパターン番号 */
1214
+ const getBasePtn = () => g_keyObj.currentPtn === -1 ? g_keyObj.storagePtn : g_keyObj.currentPtn;
1215
+
1216
+ /**
1217
+ * ショートカットキーのデフォルト値(基盤パターン基準)
1218
+ * 優先順: ヘッダー指定 > パターン別定義(keyRetryX_Y等) > 定数
1219
+ * @params {string} _type Retry / TitleBack / Pause
1220
+ * @returns {number}
1221
+ */
1222
+ const getDefaultShortcut = _type => {
1223
+ const baseVal = g_keycons.defaultShortCuts[_type];
1224
+ const headerVal = g_headerObj[`key${_type}Def2`];
1225
+ if (headerVal !== baseVal) {
1226
+ return headerVal;
1227
+ }
1228
+ return setIntVal(getKeyCtrlVal(g_keyObj[`key${_type}${g_keyObj.currentKey}_${getBasePtn()}`]), headerVal);
1229
+ };
1230
+
1231
+ /**
1232
+ * ショートカットキーボタンの色クラスを取得
1233
+ * - ロード済みの保存値(Self)と同じ: Defaultkey
1234
+ * - 基準値(保存値 or パターンのデフォルト)と違う: Changekey
1235
+ * - 通常パターンでデフォルトのまま: title_base
1236
+ * @param {string} _type Retry / TitleBack / Pause
1237
+ * @returns {string}
1238
+ */
1239
+ const getScButtonColor = _type => {
1240
+ const current = g_headerObj[`key${_type}`];
1241
+ const loaded = g_keyObj.currentPtn === -1
1242
+ ? g_keyObj[`shortcut${g_keyObj.currentKey}_-1`]?.[_type] : undefined;
1243
+
1244
+ // ロード済みの保存値のまま
1245
+ if (loaded !== undefined && current === loaded) {
1246
+ return g_cssObj.keyconfig_Defaultkey;
1247
+ }
1248
+ // 本当のデフォルト(BackSpace/Delete/Pause)と違う場合は、変更の経緯を問わずChangekey
1249
+ return current !== g_keycons.defaultShortCuts[_type] ? g_cssObj.keyconfig_Changekey : g_cssObj.title_base;
1250
+ };
1155
1251
  /**
1156
1252
  * キーボードレイアウトプレビュー(Canvas版)
1157
1253
  *
@@ -1826,19 +1922,18 @@ const getShadowColor = (_colorPos, _arrowColor) => g_headerObj.setShadowColor[_c
1826
1922
 
1827
1923
  /**
1828
1924
  * デフォルトの曲中ショートカットをキー数・キーパターンにより切り替え
1829
- * - キーコンフィグ画面で個別に変えていた場合は変更しない
1925
+ * - Self(-1)のときは保存済みの値を優先(レーンキーと重複する場合は無視)
1926
+ * - それ以外はパターンのデフォルトへ戻す
1830
1927
  */
1831
1928
  const setPlayingShortcut = () => {
1832
1929
  const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
1833
- if (g_headerObj.keyRetryDef === C_KEY_RETRY) {
1834
- g_headerObj.keyRetry = setIntVal(getKeyCtrlVal(g_keyObj[`keyRetry${keyCtrlPtn}`]), g_headerObj.keyRetryDef);
1835
- }
1836
- if (g_headerObj.keyTitleBackDef === C_KEY_TITLEBACK) {
1837
- g_headerObj.keyTitleBack = setIntVal(getKeyCtrlVal(g_keyObj[`keyTitleBack${keyCtrlPtn}`]), g_headerObj.keyTitleBackDef);
1838
- }
1839
- if (g_headerObj.keyPauseDef === C_KEY_PAUSE) {
1840
- g_headerObj.keyPause = setIntVal(getKeyCtrlVal(g_keyObj[`keyPause${keyCtrlPtn}`]), g_headerObj.keyPauseDef);
1841
- }
1930
+ const saved = g_keyObj.currentPtn === -1 ? g_keyObj[`shortcut${g_keyObj.currentKey}_-1`] : undefined;
1931
+ const usedKeys = (g_keyObj[`keyCtrl${keyCtrlPtn}`] ?? []).flat();
1932
+ g_keycons.shortcutTypes.forEach(type => {
1933
+ const savedKey = saved?.[type];
1934
+ g_headerObj[`key${type}`] = (savedKey !== undefined && !usedKeys.includes(savedKey))
1935
+ ? savedKey : getDefaultShortcut(type);
1936
+ });
1842
1937
  };
1843
1938
 
1844
1939
  /**
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/10/03 (v51.2.0)
8
+ * Revised : 2026/10/07 (v51.2.2)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -2219,7 +2219,7 @@ const executeRetry = async (_logLabel = `Retry`) => {
2219
2219
  clearWindow(`Main`);
2220
2220
  await musicAfterLoaded();
2221
2221
  await loadChartFile();
2222
- prepareScoreData();
2222
+ prepareScoreData(true);
2223
2223
  mainInit();
2224
2224
  } catch (e) {
2225
2225
  console.warn(`${_logLabel} audio load error: ${e}`);
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/09/29 (v51.1.1)
8
+ * Revised : 2026/10/10 (v51.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -1274,52 +1274,6 @@ const getKeyStorageObjByName = (_keyName) => {
1274
1274
  }), ``];
1275
1275
  };
1276
1276
 
1277
- /**
1278
- * 別キーモード時、移行先キーが保持するSelf保存パターンの取得可否チェック
1279
- * @param {string} _keyCtrlPtn 例: "7_2"
1280
- * @returns {number[][]|undefined} 適用可能な場合はSelf保存済みkeyCtrl配列、不可ならundefined
1281
- */
1282
- const getTransKeySelfCtrl = (_keyCtrlPtn) => {
1283
- const transKeyName = g_keyObj[`transKey${_keyCtrlPtn}`];
1284
- const transKeyPtn = g_keyObj[`transKeyPtn${_keyCtrlPtn}`];
1285
- if (!hasVal(transKeyName) || transKeyPtn === undefined) {
1286
- return undefined;
1287
- }
1288
- const [storageObj, addKey] = getKeyStorageObjByName(transKeyName);
1289
- const savedCtrl = storageObj[`keyCtrl${addKey}`];
1290
- const savedPtn = storageObj[`keyCtrlPtn${addKey}`];
1291
-
1292
- if (savedPtn !== transKeyPtn) {
1293
- return undefined;
1294
- }
1295
-
1296
- // 現在のキー配置(基準形状)とレーン数・各レーン長が完全一致することを確認
1297
- const baseCtrl = g_keyObj[`keyCtrl${_keyCtrlPtn}`];
1298
- const isValidShape = hasArrayList(savedCtrl, baseCtrl.length) &&
1299
- savedCtrl.length === baseCtrl.length &&
1300
- baseCtrl.every((lane, j) => hasArrayList(savedCtrl[j], lane.length) && savedCtrl[j].length === lane.length);
1301
-
1302
- return isValidShape ? savedCtrl : undefined;
1303
- };
1304
-
1305
- /**
1306
- * 別キーモードの移行先Selfパターンを現在のキー配置へ反映(保存はしない)
1307
- */
1308
- const applyTransKeySelfPattern = () => {
1309
- const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
1310
- const savedCtrl = getTransKeySelfCtrl(keyCtrlPtn);
1311
- if (savedCtrl === undefined) {
1312
- return;
1313
- }
1314
- const baseKeyNum = g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length;
1315
- for (let j = 0; j < baseKeyNum; j++) {
1316
- for (let k = 0; k < (savedCtrl[j]?.length ?? 0); k++) {
1317
- g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k] = setIntVal(savedCtrl[j][k], 0);
1318
- }
1319
- }
1320
- keyConfigInit();
1321
- };
1322
-
1323
1277
  /**
1324
1278
  * 譜面初期化処理
1325
1279
  * - 譜面の基本設定(キー数、初期速度、リバース、ゲージ設定)をここで行う
@@ -1371,6 +1325,7 @@ const setDifficulty = (_chartChangeFlg) => {
1371
1325
  storageObj[`keyCtrlPtn${addKey}`] = 0;
1372
1326
  }
1373
1327
  getKeyCtrl(storageObj, addKey);
1328
+ g_keyObj[`shortcut${g_keyObj.currentKey}_-1`] = structuredClone(storageObj[`shortcut${addKey}`] ?? {});
1374
1329
 
1375
1330
  // カラーセット初期値設定
1376
1331
  if (storageObj[`setColor${addKey}`] === undefined) {
@@ -1401,10 +1356,9 @@ const setDifficulty = (_chartChangeFlg) => {
1401
1356
  g_keyObj[`${type}${keyCtrlPtn}`] = structuredClone(g_keyObj[`${type}${keyCtrlPtn}_0`]);
1402
1357
  }
1403
1358
  });
1404
-
1359
+ // 曲中ショートカットキーの切り替え
1360
+ setPlayingShortcut();
1405
1361
  }
1406
- // 曲中ショートカットキーの切り替え
1407
- setPlayingShortcut();
1408
1362
  }
1409
1363
 
1410
1364
  // スクロール設定用の配列を入れ替え
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "51.2.0",
3
+ "version": "51.3.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "jsdelivr": "./js/danoni_main.js",