danoniplus 39.8.2 → 40.0.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 CHANGED
@@ -4,19 +4,19 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2025/02/24
7
+ * Revised : 2025/03/01
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 39.8.2`;
12
- const g_revisedDate = `2025/02/24`;
11
+ const g_version = `Ver 40.0.1`;
12
+ const g_revisedDate = `2025/03/01`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
16
16
  let g_localVersion2 = ``;
17
17
 
18
18
  // ショートカット用文字列(↓の文字列を検索することで対象箇所へジャンプできます)
19
- // 共通:water 初期化:peach タイトル:melon データ管理:pear 設定:lime ディスプレイ:lemon 拡張設定:apple キーコンフィグ:orange 譜面読込:strawberry メイン:banana 結果:grape
19
+ // 共通:water 初期化:peach タイトル:melon データ管理:pear 前提条件表示:mango 設定:lime ディスプレイ:lemon 拡張設定:apple キーコンフィグ:orange 譜面読込:strawberry メイン:banana 結果:grape
20
20
  // シーンジャンプ:Scene
21
21
 
22
22
  /**
@@ -112,6 +112,7 @@ const g_loadObj = {};
112
112
  const g_rootObj = {};
113
113
  const g_presetObj = {
114
114
  keysDataLib: [],
115
+ keysDataLocal: [],
115
116
  };
116
117
  let g_headerObj = {};
117
118
  let g_scoreObj = {};
@@ -425,6 +426,16 @@ const parseStorageData = (_keyName, _default = {}) => {
425
426
  }
426
427
  }
427
428
 
429
+ /**
430
+ * オブジェクトをキー名でソート
431
+ * @param {Object} _obj
432
+ * @returns {Object}
433
+ */
434
+ const sortObjectByKeys = _obj => Object.keys(_obj).sort().reduce((acc, key) => {
435
+ acc[key] = _obj[key];
436
+ return acc;
437
+ }, {});
438
+
428
439
  /**
429
440
  * 画面表示用インデント処理
430
441
  * @param {number} _level
@@ -448,7 +459,7 @@ const viewKeyStorage = (_name, _key = ``) => {
448
459
  if (viewKeyStorage.cache.has(cacheKey)) {
449
460
  return viewKeyStorage.cache.get(cacheKey);
450
461
  }
451
- const result = formatObject(g_storageFunc.get(_name)(_key));
462
+ const result = formatObject(g_storageFunc.get(_name)?.(_key) || setVal(_name, ``, C_TYP_CALC));
452
463
  viewKeyStorage.cache.set(cacheKey, result);
453
464
  return result;
454
465
  }
@@ -460,9 +471,10 @@ const viewKeyStorage = (_name, _key = ``) => {
460
471
  * @param {WeakSet} [seen=new WeakSet()]
461
472
  * @param {boolean} [colorFmt=true]
462
473
  * @param {string} [key='']
474
+ * @param {Object} [_parent=null]
463
475
  * @returns {string}
464
476
  */
465
- const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true, key } = {}) => {
477
+ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true, key = `` } = {}, _parent = null) => {
466
478
  if (_obj === null || typeof _obj !== 'object') {
467
479
  return JSON.stringify(_obj);
468
480
  }
@@ -474,20 +486,27 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
474
486
  const nestedIndent = getIndent(_indent + 1);
475
487
 
476
488
  // カラーコード、対応キーの色付け処理
477
- const colorCodePattern = /^#(?:[A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4})$/;
478
- const formatValue = _value => {
489
+ const colorCodePattern = /(#|0x)(?:[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{3})/g;
490
+ const formatValue = (_value, _parent) => {
479
491
  if (colorFmt) {
480
- if (typeof _value === 'string' && colorCodePattern.test(_value)) {
481
- return `"<span style="color:${_value}">◆</span>${_value}"`;
492
+ if (typeof _value === 'string') {
493
+ _value = escapeHtml(_value);
494
+ if (colorCodePattern.test(_value)) {
495
+ return _value.replace(colorCodePattern, (match) =>
496
+ `<span style="color:${match.replace(`0x`, `#`)}">◆</span>${match.replace(`0x`, `#`)}`);
497
+ }
482
498
  }
483
499
  if (Array.isArray(_value)) {
484
- let formattedArray = _value.map(item => formatValue(item));
500
+ let formattedArray = _value.map(item => formatValue(item, _value));
485
501
  if (key.startsWith(`keyCtrl`)) {
486
502
  formattedArray = formattedArray.filter(item => item !== `0`)
487
503
  .map(item => g_kCd[item] ? `${item}|<span style="color:#ffff66">${g_kCd[item]}</span>` : item);
488
504
  }
489
505
  return `[${formattedArray.join(`, `)}]`;
490
506
  }
507
+ if (typeof _value === 'object' && _value !== null) {
508
+ return formatObject(_value, _indent + 1, { seen, colorFmt, key }, _parent);
509
+ }
491
510
  }
492
511
  return JSON.stringify(_value);
493
512
  };
@@ -497,12 +516,25 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
497
516
  if (_obj.length === 0) {
498
517
  return '[]';
499
518
  }
519
+ if (colorFmt && _obj.length > 100) {
520
+ const filteredArray = _obj.reduce((result, value, index) => {
521
+ if (hasVal(value)) {
522
+ result.push(`${index}: ${formatValue(value, _obj)}`);
523
+ }
524
+ return result;
525
+ }, []);
526
+ return `{<br>${baseIndent}[<br>${filteredArray.join(',<br>')}<br>]<br>}`;
527
+ }
500
528
  const isArrayOfArrays = _obj.every(item => Array.isArray(item));
501
529
  const formattedArray = _obj
502
- .map(item => isArrayOfArrays
503
- ? `${nestedIndent}${formatValue(item)}`
504
- : formatValue(item)
505
- ).join(isArrayOfArrays ? `,<br>` : `, `);
530
+ .map(value => {
531
+ const isNestedObject = typeof value === 'object' && value !== null;
532
+ return isArrayOfArrays
533
+ ? `${nestedIndent}${formatValue(value, _obj)}`
534
+ : isNestedObject
535
+ ? formatObject(value, _indent + 1, { seen, colorFmt }, _obj)
536
+ : formatValue(value, _obj)
537
+ }).join(isArrayOfArrays ? `,<br>` : `, `);
506
538
 
507
539
  return `[${isArrayOfArrays ? `<br>` : ``}${formattedArray}${isArrayOfArrays ? `<br>${baseIndent}` : ''}]`;
508
540
  }
@@ -511,9 +543,10 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
511
543
  const formattedEntries = Object.entries(_obj)
512
544
  .map(([key, value]) => {
513
545
  const isNestedObject = typeof value === 'object' && value !== null;
546
+ const seenNew = _parent ? seen : new WeakSet();
514
547
  const formattedValue = isNestedObject
515
- ? formatObject(value, _indent + 1, { seen, colorFmt, key })
516
- : formatValue(value);
548
+ ? formatObject(value, _indent + 1, { seen: seenNew, colorFmt, key }, _obj)
549
+ : formatValue(value, _obj);
517
550
  return `<br>${nestedIndent}"${key}": ${formattedValue}`;
518
551
  }).join(`,`);
519
552
 
@@ -2353,8 +2386,9 @@ const initialControl = async () => {
2353
2386
  };
2354
2387
  g_presetObj.keysDataLib.forEach(list => importKeysData(list));
2355
2388
  if (g_presetObj.keysData !== undefined) {
2356
- importKeysData(g_presetObj.keysData);
2389
+ g_presetObj.keysDataLocal.unshift(g_presetObj.keysData);
2357
2390
  }
2391
+ g_presetObj.keysDataLocal.forEach(list => importKeysData(list));
2358
2392
  g_headerObj.keyExtraList = keysConvert(g_rootObj, {
2359
2393
  keyExtraList: makeDedupliArray(g_headerObj.undefinedKeyLists, g_rootObj.keyExtraList?.split(`,`)),
2360
2394
  });
@@ -2454,16 +2488,33 @@ const initialControl = async () => {
2454
2488
  }
2455
2489
  g_customJsObj.preTitle.forEach(func => func());
2456
2490
  titleInit();
2491
+
2492
+ // 未使用のg_keyObjプロパティを削除
2493
+ const keyProp = g_keyCopyLists.simple.concat(g_keyCopyLists.multiple, `keyCtrl`, `keyName`, `minWidth`, `ptchara`);
2494
+ const delKeyPropList = [`ptchara7`, `keyTransPattern`, `dfPtnNum`, `minKeyCtrlNum`, `minPatterns`];
2495
+ Object.keys(g_keyObj).forEach(key => {
2496
+ const type = keyProp.find(prop => key.startsWith(prop)) || ``;
2497
+ if (type !== ``) {
2498
+ const keyName = String(key.split(`_`)[0].slice(type.length));
2499
+ if (!g_headerObj.keyLists.includes(keyName) && keyName !== `` && keyName !== `Default`) {
2500
+ delete g_keyObj[key];
2501
+ }
2502
+ }
2503
+ if (key.match(/^chara7_[a-z]/) || delKeyPropList.includes(key) || g_keyObj[key] === undefined) {
2504
+ delete g_keyObj[key];
2505
+ }
2506
+ });
2457
2507
  };
2458
2508
 
2459
2509
  /**
2460
2510
  * 作品別ローカルストレージの読み込み・初期設定
2461
2511
  */
2462
2512
  const loadLocalStorage = () => {
2463
- // URLからscoreId, h(高さ)を削除
2513
+ // URLからscoreId, h(高さ), debugを削除
2464
2514
  const url = new URL(location.href);
2465
2515
  url.searchParams.delete(`scoreId`);
2466
2516
  url.searchParams.delete(`h`);
2517
+ url.searchParams.delete(`debug`);
2467
2518
  g_localStorageUrl = url.toString();
2468
2519
 
2469
2520
  /**
@@ -4898,7 +4949,7 @@ const dataMgtInit = () => {
4898
4949
  })
4899
4950
  );
4900
4951
 
4901
- g_localStorageMgt = parseStorageData(g_localStorageUrl);
4952
+ g_localStorageMgt = sortObjectByKeys(parseStorageData(g_localStorageUrl));
4902
4953
 
4903
4954
  multiAppend(divRoot,
4904
4955
 
@@ -4923,16 +4974,30 @@ const dataMgtInit = () => {
4923
4974
  keyList.forEach((key, j) => {
4924
4975
  g_stateObj[`dm_${key}`] = C_FLG_OFF;
4925
4976
  g_settings.dataMgtNum[key] = 0;
4977
+
4926
4978
  keyListSprite.appendChild(createMgtButton(key, j - 2, 0, {
4927
4979
  w: Math.max(50, getStrWidth(getKeyName(key) + ` `, g_limitObj.setLblSiz, getBasicFont())),
4928
- func: () => {
4929
- selectedKey = key;
4930
- lblKeyDataView.innerHTML = viewKeyStorage(`keyStorage`, key);
4931
- lblTargetKey.innerHTML = `(${getKeyName(key)})`;
4932
- },
4933
4980
  }));
4934
4981
  document.getElementById(`btn${key}`).innerHTML = getKeyName(key);
4982
+
4983
+ keyListSprite.appendChild(createCss2Button(`btnView${key}`, ``, evt => {
4984
+ keyList.forEach(keyx => {
4985
+ document.getElementById(`btnView${keyx}`).classList.replace(g_cssObj.button_Next, g_cssObj.button_Default);
4986
+ document.getElementById(`btnView${keyx}`).classList.replace(g_cssObj.button_ON, g_cssObj.button_OFF);
4987
+ document.getElementById(`btnView${keyx}`).textContent = ``;
4988
+ });
4989
+ document.getElementById(`btnView${key}`).classList.replace(g_cssObj.button_Default, g_cssObj.button_Next);
4990
+ document.getElementById(`btnView${key}`).classList.replace(g_cssObj.button_OFF, g_cssObj.button_ON);
4991
+ selectedKey = key;
4992
+ evt.target.textContent = `x`;
4993
+ lblKeyDataView.innerHTML = viewKeyStorage(`keyStorage`, key);
4994
+ lblKeyDataView.scrollTop = 0;
4995
+ lblTargetKey.innerHTML = `(${getKeyName(key)})`;
4996
+ }, {
4997
+ x: 0, y: g_limitObj.setLblHeight * (j - 2) + 40, w: 16, h: 20, siz: 12, borderStyle: `solid`
4998
+ }, g_cssObj.button_Default, g_cssObj.button_OFF));
4935
4999
  });
5000
+ document.getElementById(`btnView${selectedKey}`).click();
4936
5001
 
4937
5002
  // ユーザカスタムイベント(初期)
4938
5003
  g_customJsObj.dataMgt.forEach(func => func());
@@ -4943,6 +5008,11 @@ const dataMgtInit = () => {
4943
5008
  resetFunc: () => prevPage === `title` ? titleInit() : g_moveSettingWindow(false),
4944
5009
  }), g_cssObj.button_Back),
4945
5010
 
5011
+ createCss2Button(`btnPrecond`, g_lblNameObj.b_precond, () => true,
5012
+ Object.assign(g_lblPosObj.btnPrecond, {
5013
+ resetFunc: () => preconditionInit(),
5014
+ }), g_cssObj.button_Setting),
5015
+
4946
5016
  createCss2Button(`btnSafeMode`, g_lblNameObj.b_safeMode +
4947
5017
  (g_langStorage.safeMode === C_FLG_ON ? C_FLG_OFF : C_FLG_ON), () => {
4948
5018
  if (window.confirm(g_msgObj[`safeMode${g_langStorage.safeMode}Confirm`])) {
@@ -5024,6 +5094,89 @@ const dataMgtInit = () => {
5024
5094
  g_skinJsObj.dataMgt.forEach(func => func());
5025
5095
  };
5026
5096
 
5097
+
5098
+ /*-----------------------------------------------------------*/
5099
+ /* Scene : PRECONDITION [mango] */
5100
+ /*-----------------------------------------------------------*/
5101
+
5102
+ const preconditionInit = () => {
5103
+ clearWindow(true);
5104
+ const prevPage = g_currentPage;
5105
+ g_currentPage = `precondition`;
5106
+
5107
+ multiAppend(divRoot,
5108
+
5109
+ // 画面タイトル
5110
+ getTitleDivLabel(`lblTitle`,
5111
+ `<div class="settings_Title">PRECONDITION</div>`
5112
+ .replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
5113
+
5114
+ createDivCss2Label(`lblPrecondView`, viewKeyStorage(`g_rootObj`), g_lblPosObj.lblPrecondView),
5115
+ );
5116
+ setUserSelect($id(`lblPrecondView`), `text`);
5117
+
5118
+ // 1ページあたりに表示するオブジェクト数
5119
+ const numOfPrecs = Math.round((g_btnWidth(1) / 500) / 2 * 10) * 2;
5120
+
5121
+ // ボタン名切り替え
5122
+ const switchPreconditions = () => {
5123
+ g_settings.preconditionNum = nextPos(g_settings.preconditionNum, 1, Math.round(g_settings.preconditions.length / numOfPrecs) + 1);
5124
+ for (let j = 0; j < Math.min(g_settings.preconditions.length, numOfPrecs); j++) {
5125
+ if (g_settings.preconditionNum * numOfPrecs + j < g_settings.preconditions.length) {
5126
+ document.getElementById(`btnPrecond${j}`).innerHTML =
5127
+ g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + j];
5128
+ document.getElementById(`btnPrecond${j}`).style.visibility = `visible`;
5129
+ } else {
5130
+ document.getElementById(`btnPrecond${j}`).style.visibility = `hidden`;
5131
+ }
5132
+ }
5133
+ btnPrecond0.click();
5134
+ };
5135
+
5136
+ // オブジェクト表示ボタンの作成
5137
+ for (let j = 0; j < Math.min(g_settings.preconditions.length, numOfPrecs); j++) {
5138
+ divRoot.appendChild(createCss2Button(`btnPrecond${j}`, g_settings.preconditions[j], evt => {
5139
+ for (let k = 0; k < Math.min(g_settings.preconditions.length, numOfPrecs); k++) {
5140
+ document.getElementById(`btnPrecond${k}`).classList.replace(g_cssObj.button_Reset, g_cssObj.button_Default);
5141
+ }
5142
+ lblPrecondView.innerHTML = viewKeyStorage(g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + j]);
5143
+ lblPrecondView.scrollTop = 0;
5144
+ evt.target.classList.replace(g_cssObj.button_Default, g_cssObj.button_Reset);
5145
+ }, {
5146
+ x: g_btnX() + g_btnWidth((j % (numOfPrecs / 2)) / (numOfPrecs / 2 + 1)),
5147
+ y: 70 + Number(j >= numOfPrecs / 2) * 20, w: g_btnWidth(1 / (numOfPrecs / 2 + 1)), h: 20, siz: 12,
5148
+ }, g_cssObj.button_Default));
5149
+ }
5150
+ btnPrecond0.classList.replace(g_cssObj.button_Default, g_cssObj.button_Reset);
5151
+
5152
+ // 次のオブジェクト表示群の表示
5153
+ divRoot.appendChild(createCss2Button(`btnPrecondNext`, `>`, () => switchPreconditions(), {
5154
+ x: g_btnX() + g_btnWidth(numOfPrecs / 2 / (numOfPrecs / 2 + 1)),
5155
+ y: 70, w: g_btnWidth(1 / Math.max((numOfPrecs / 2 + 1), 12)), h: 40, siz: 12,
5156
+ visibility: (g_settings.preconditions.length > numOfPrecs ? `visible` : `hidden`),
5157
+ }, g_cssObj.button_Setting));
5158
+
5159
+ // ユーザカスタムイベント(初期)
5160
+ g_customJsObj.precondition.forEach(func => func());
5161
+
5162
+ multiAppend(divRoot,
5163
+ createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
5164
+ Object.assign(g_lblPosObj.btnPrecond, {
5165
+ resetFunc: () => {
5166
+ viewKeyStorage.cache = new Map();
5167
+ prevPage === `dataMgt` ? dataMgtInit() : g_moveSettingWindow(false);
5168
+ },
5169
+ }), g_cssObj.button_Back),
5170
+ );
5171
+ // キー操作イベント(デフォルト)
5172
+ setShortcutEvent(g_currentPage, () => true, { dfEvtFlg: true });
5173
+
5174
+ document.oncontextmenu = () => true;
5175
+ divRoot.oncontextmenu = () => true;
5176
+
5177
+ g_skinJsObj.precondition.forEach(func => func());
5178
+ };
5179
+
5027
5180
  /*-----------------------------------------------------------*/
5028
5181
  /* Scene : SETTINGS [lime] */
5029
5182
  /*-----------------------------------------------------------*/
@@ -5073,6 +5226,12 @@ const commonSettingBtn = _labelName => {
5073
5226
  createCss2Button(`btnReset`, g_lblNameObj.dataReset, () => {
5074
5227
  dataMgtInit();
5075
5228
  }, g_lblPosObj.btnReset, g_cssObj.button_Reset),
5229
+
5230
+ // 前提条件表示用画面へ移動(debug=trueの場合のみ)
5231
+ createCss2Button(`btnPrecond`, g_lblNameObj.b_precond, () => true,
5232
+ Object.assign(g_lblPosObj.btnPrecond, {
5233
+ resetFunc: () => preconditionInit(),
5234
+ }), g_cssObj.button_Setting),
5076
5235
  );
5077
5236
  };
5078
5237
 
@@ -8271,12 +8430,11 @@ const loadingScoreInit = async () => {
8271
8430
  let speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
8272
8431
 
8273
8432
  // Motionオプション適用時の矢印別の速度を取得(配列形式)
8274
- const motionOnFrame = setMotionOnFrame();
8275
- g_workObj.motionOnFrames = structuredClone(motionOnFrame);
8433
+ g_workObj.motionOnFrames = setMotionOnFrame();
8276
8434
 
8277
8435
  // 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
8278
8436
  const firstFrame = (g_scoreObj.frameNum === 0 ? 0 : g_scoreObj.frameNum + g_headerObj.blankFrame);
8279
- let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
8437
+ let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame);
8280
8438
 
8281
8439
  // キーパターン(デフォルト)に対応する矢印番号を格納
8282
8440
  convertReplaceNums();
@@ -8308,7 +8466,7 @@ const loadingScoreInit = async () => {
8308
8466
  lastFrame += preblankFrame;
8309
8467
  firstArrowFrame += preblankFrame;
8310
8468
  speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
8311
- arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
8469
+ arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame);
8312
8470
  g_headerObj.blankFrame += preblankFrame;
8313
8471
  }
8314
8472
  }
@@ -8361,7 +8519,7 @@ const loadingScoreInit = async () => {
8361
8519
  calcLifeVals(g_fullArrows);
8362
8520
 
8363
8521
  // 矢印・フリーズアロー・速度/色変化格納処理
8364
- pushArrows(g_scoreObj, speedOnFrame, motionOnFrame, arrivalFrame);
8522
+ pushArrows(g_scoreObj, speedOnFrame, arrivalFrame);
8365
8523
 
8366
8524
  // メインに入る前の最終初期化処理
8367
8525
  getArrowSettings();
@@ -9259,9 +9417,9 @@ const setSpeedOnFrame = (_speedData, _lastFrame) => {
9259
9417
 
9260
9418
  /**
9261
9419
  * Motionオプション適用時の矢印別の速度設定
9262
- * - 矢印が表示される最大フレーム数を 縦ピクセル数×20 と定義。
9420
+ * - 矢印が表示される最大フレーム数を 101フレーム と定義。
9263
9421
  */
9264
- const setMotionOnFrame = () => g_motionFunc.get(g_stateObj.motion)(fillArray(g_headerObj.playingHeight * 20 + 1));
9422
+ const setMotionOnFrame = () => g_motionFunc.get(g_stateObj.motion)(fillArray(101));
9265
9423
 
9266
9424
  /**
9267
9425
  * Boost用の適用関数
@@ -9317,11 +9475,10 @@ const getFountainTrace = (_frms, _spd) => {
9317
9475
  /**
9318
9476
  * 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
9319
9477
  * @param {number} _startFrame
9320
- * @param {object} _speedOnFrame
9321
- * @param {object} _motionOnFrame
9478
+ * @param {object} _speedOnFrame
9322
9479
  * @returns {number}
9323
9480
  */
9324
- const getFirstArrivalFrame = (_startFrame, _speedOnFrame, _motionOnFrame) => {
9481
+ const getFirstArrivalFrame = (_startFrame, _speedOnFrame) => {
9325
9482
  let startY = 0;
9326
9483
  let frm = _startFrame;
9327
9484
 
@@ -9336,10 +9493,9 @@ const getFirstArrivalFrame = (_startFrame, _speedOnFrame, _motionOnFrame) => {
9336
9493
  * 矢印・フリーズアロー・速度/色変化格納処理
9337
9494
  * @param {object} _dataObj
9338
9495
  * @param {object} _speedOnFrame
9339
- * @param {object} _motionOnFrame
9340
9496
  * @param {number} _firstArrivalFrame
9341
9497
  */
9342
- const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame) => {
9498
+ const pushArrows = (_dataObj, _speedOnFrame, _firstArrivalFrame) => {
9343
9499
 
9344
9500
  // 矢印・フリーズアロー・速度/色変化用 フレーム別処理配列
9345
9501
  [``, `Dummy`].forEach(header =>
@@ -9420,7 +9576,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9420
9576
  // 最後尾のデータから計算して格納
9421
9577
  const lastk = _data.length - setcnt;
9422
9578
  let arrowArrivalFrm = _data[lastk];
9423
- let tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame, _motionOnFrame);
9579
+ let tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame);
9424
9580
 
9425
9581
  startPoint[lastk] = tmpObj.frm;
9426
9582
  let frmPrev = tmpObj.frm;
@@ -9466,7 +9622,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9466
9622
  spdNext = spdPrev;
9467
9623
  spdPrev = _dataObj.speedData[spdk];
9468
9624
  }
9469
- tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame, _motionOnFrame);
9625
+ tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame);
9470
9626
 
9471
9627
  startPoint[k] = tmpObj.frm;
9472
9628
  frmPrev = tmpObj.frm;
@@ -9499,7 +9655,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9499
9655
  if (hasArrayList(_data, 2)) {
9500
9656
  let delIdx = 0;
9501
9657
  for (let k = _data.length - 2; k >= 0; k -= 2) {
9502
- const tmpObj = getArrowStartFrame(_data[k], _speedOnFrame, _motionOnFrame);
9658
+ const tmpObj = getArrowStartFrame(_data[k], _speedOnFrame);
9503
9659
  if (tmpObj.frm < g_scoreObj.frameNum) {
9504
9660
  _data[k] = g_scoreObj.frameNum;
9505
9661
  delIdx = k;
@@ -9548,7 +9704,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9548
9704
  }
9549
9705
  } else {
9550
9706
  if (calcFrameFlg) {
9551
- const tmpObj = getArrowStartFrame(baseData[k], _speedOnFrame, _motionOnFrame);
9707
+ const tmpObj = getArrowStartFrame(baseData[k], _speedOnFrame);
9552
9708
  if (tmpObj.frm < g_scoreObj.frameNum) {
9553
9709
  const diff = g_scoreObj.frameNum - tmpObj.frm;
9554
9710
  tmpObj.frm = g_scoreObj.frameNum;
@@ -9662,11 +9818,10 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9662
9818
  /**
9663
9819
  * ステップゾーン到達地点から逆算して開始フレームを取得
9664
9820
  * @param {number} _frame
9665
- * @param {object} _speedOnFrame
9666
- * @param {object} _motionOnFrame
9821
+ * @param {object} _speedOnFrame
9667
9822
  * @returns {{ frm: number, startY: number, arrivalFrm: number, motionFrm: number }}
9668
9823
  */
9669
- const getArrowStartFrame = (_frame, _speedOnFrame, _motionOnFrame) => {
9824
+ const getArrowStartFrame = (_frame, _speedOnFrame) => {
9670
9825
 
9671
9826
  const obj = {
9672
9827
  frm: _frame,
@@ -11168,7 +11323,8 @@ const mainInit = () => {
11168
11323
  if (g_workObj.currentSpeed !== 0) {
11169
11324
  const boostCnt = currentArrow.boostCnt;
11170
11325
  currentArrow.prevY = currentArrow.y;
11171
- currentArrow.y -= (g_workObj.currentSpeed * currentArrow.boostSpd + g_workObj.motionOnFrames[boostCnt] * currentArrow.boostDir) * currentArrow.dir;
11326
+ currentArrow.y -= (g_workObj.currentSpeed * currentArrow.boostSpd +
11327
+ (g_workObj.motionOnFrames[boostCnt] || 0) * currentArrow.boostDir) * currentArrow.dir;
11172
11328
  $id(arrowName).top = wUnit(currentArrow.y);
11173
11329
  currentArrow.boostCnt--;
11174
11330
  }
@@ -11314,7 +11470,7 @@ const mainInit = () => {
11314
11470
 
11315
11471
  // 移動
11316
11472
  if (g_workObj.currentSpeed !== 0) {
11317
- currentFrz.y -= movY + g_workObj.motionOnFrames[currentFrz.boostCnt] * currentFrz.dir * currentFrz.boostDir;
11473
+ currentFrz.y -= movY + (g_workObj.motionOnFrames[currentFrz.boostCnt] || 0) * currentFrz.dir * currentFrz.boostDir;
11318
11474
  $id(frzName).top = wUnit(currentFrz.y);
11319
11475
  currentFrz.boostCnt--;
11320
11476
  }
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/02/22 (v39.8.1)
8
+ * Revised : 2025/03/01 (v40.0.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -246,6 +246,10 @@ const updateWindowSiz = () => {
246
246
  btnResetBack: {
247
247
  x: g_btnX(), y: g_sHeight - 20, w: g_btnWidth(1 / 4), h: 16, siz: 12,
248
248
  },
249
+ btnPrecond: {
250
+ x: g_btnX(1 / 4), y: g_sHeight - 20, w: g_btnWidth(1 / 4), h: 16, siz: 12,
251
+ visibility: getQueryParamVal(`debug`) === `true` ? `visible` : `hidden`,
252
+ },
249
253
  btnSafeMode: {
250
254
  x: g_btnX(), siz: 18,
251
255
  },
@@ -268,6 +272,11 @@ const updateWindowSiz = () => {
268
272
  overflow: C_DIS_AUTO, background: `#222222`, color: `#cccccc`,
269
273
  whiteSpace: `nowrap`,
270
274
  },
275
+ lblPrecondView: {
276
+ x: g_btnX(), y: 110, w: g_btnWidth(1), h: g_sHeight - 140, siz: 12, align: C_ALIGN_LEFT,
277
+ overflow: C_DIS_AUTO, background: `#222222`, color: `#cccccc`,
278
+ whiteSpace: `nowrap`,
279
+ },
271
280
  btnWorkStorage: {
272
281
  x: g_btnX(1) - 140, y: 100, w: 70, h: 20, siz: 16,
273
282
  },
@@ -1145,6 +1154,10 @@ const g_settings = {
1145
1154
 
1146
1155
  settingWindows: [optionInit, settingsDisplayInit, exSettingInit],
1147
1156
  settingWindowNum: 0,
1157
+
1158
+ preconditions: [`g_rootObj`, `g_headerObj`, `g_keyObj`, `g_scoreObj`, `g_workObj`,
1159
+ `g_detailObj`, `g_stateObj`, `g_attrObj`],
1160
+ preconditionNum: 0,
1148
1161
  };
1149
1162
 
1150
1163
  g_settings.volumeNum = g_settings.volumes.length - 1;
@@ -1334,7 +1347,7 @@ const g_storageFunc = new Map([
1334
1347
 
1335
1348
  // キー別のストレージ情報
1336
1349
  ['keyStorage', (_key) => {
1337
- let keyStorage = parseStorageData(`danonicw-${_key}k`);
1350
+ let keyStorage = sortObjectByKeys(parseStorageData(`danonicw-${_key}k`));
1338
1351
  if (Object.keys(keyStorage).length === 0) {
1339
1352
 
1340
1353
  // キー別の情報が見つからない場合は作品別の情報から検索
@@ -1992,6 +2005,30 @@ const g_shortcutObj = {
1992
2005
  ShiftLeft_Tab: { id: `btnBack` },
1993
2006
  ShiftRight_Tab: { id: `btnBack` },
1994
2007
  },
2008
+ precondition: {
2009
+ Digit1: { id: `btnPrecond0` },
2010
+ Digit2: { id: `btnPrecond1` },
2011
+ Digit3: { id: `btnPrecond2` },
2012
+ Digit4: { id: `btnPrecond3` },
2013
+ Digit5: { id: `btnPrecond4` },
2014
+ Digit6: { id: `btnPrecond5` },
2015
+ Digit7: { id: `btnPrecond6` },
2016
+ Digit8: { id: `btnPrecond7` },
2017
+ Digit9: { id: `btnPrecond8` },
2018
+ Digit0: { id: `btnPrecond9` },
2019
+ Numpad1: { id: `btnPrecond0` },
2020
+ Numpad2: { id: `btnPrecond1` },
2021
+ Numpad3: { id: `btnPrecond2` },
2022
+ Numpad4: { id: `btnPrecond3` },
2023
+ Numpad5: { id: `btnPrecond4` },
2024
+ Numpad6: { id: `btnPrecond5` },
2025
+ Numpad7: { id: `btnPrecond6` },
2026
+ Numpad8: { id: `btnPrecond7` },
2027
+ Numpad9: { id: `btnPrecond8` },
2028
+ Numpad0: { id: `btnPrecond9` },
2029
+ Escape: { id: `btnBack` },
2030
+ ShiftLeft_Tab: { id: `btnBack` },
2031
+ },
1995
2032
  option: {
1996
2033
  ShiftLeft_KeyD: { id: `lnkDifficultyL` },
1997
2034
  ShiftRight_KeyD: { id: `lnkDifficultyL` },
@@ -2292,6 +2329,7 @@ const g_btnWaitFrame = {
2292
2329
  initial: { b_frame: 0, s_frame: 0 },
2293
2330
  title: { b_frame: 0, s_frame: 0 },
2294
2331
  dataMgt: { b_frame: 0, s_frame: 0 },
2332
+ precondition: { b_frame: 0, s_frame: 0 },
2295
2333
  option: { b_frame: 0, s_frame: 0, initial: true },
2296
2334
  difSelector: { b_frame: 0, s_frame: 0 },
2297
2335
  settingsDisplay: { b_frame: 0, s_frame: 0 },
@@ -2307,6 +2345,7 @@ const g_btnWaitFrame = {
2307
2345
  const g_btnPatterns = {
2308
2346
  title: { Start: 0, Comment: -10 },
2309
2347
  dataMgt: { Back: 0, Environment: -35, Highscores: -35, CustomKey: -35, Others: -35 },
2348
+ precondition: { Back: 0 },
2310
2349
  option: { Back: 0, KeyConfig: 0, Play: 0, Display: -5, Save: -10, Graph: -25 },
2311
2350
  difSelector: {},
2312
2351
  settingsDisplay: { Back: 0, KeyConfig: 0, Play: 0, Save: -10, Settings: -5 },
@@ -3109,10 +3148,11 @@ g_keycons.groups.forEach(type => {
3109
3148
  });
3110
3149
 
3111
3150
  // 特殊キーのコピー種 (simple: 代入、multiple: 配列ごと代入)
3151
+ // 後でプロパティ削除に影響するため、先頭文字が全く同じ場合は長い方を先に定義する (例: divMax, div)
3112
3152
  const g_keyCopyLists = {
3113
3153
  simpleDef: [`blank`, `scale`],
3114
- simple: [`div`, `divMax`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
3115
- multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroup`, `keyGroupOrder`, `layerGroup`, `layerTrans`],
3154
+ simple: [`divMax`, `div`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
3155
+ multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroupOrder`, `keyGroup`, `layerGroup`, `layerTrans`],
3116
3156
  };
3117
3157
 
3118
3158
  // タイトル画面関連のリスト群
@@ -3503,6 +3543,7 @@ const g_lblNameObj = {
3503
3543
  b_retry: `Retry`,
3504
3544
  b_close: `Close`,
3505
3545
  b_cReset: `Reset`,
3546
+ b_precond: `Precondition`,
3506
3547
 
3507
3548
  Difficulty: `Difficulty`,
3508
3549
  Speed: `Speed`,
@@ -4045,6 +4086,7 @@ const g_customJsObj = {
4045
4086
  title: [],
4046
4087
  titleEnterFrame: [],
4047
4088
  dataMgt: [],
4089
+ precondition: [],
4048
4090
  option: [],
4049
4091
  difficulty: [],
4050
4092
  settingsDisplay: [],
@@ -4085,6 +4127,7 @@ const g_customJsObj = {
4085
4127
  const g_skinJsObj = {
4086
4128
  title: [],
4087
4129
  dataMgt: [],
4130
+ precondition: [],
4088
4131
  option: [],
4089
4132
  settingsDisplay: [],
4090
4133
  exSetting: [],
@@ -20,7 +20,7 @@
20
20
  /**
21
21
  * タイトル画面
22
22
  */
23
- function customTitleInit() {
23
+ g_customJsObj.title.push(() => {
24
24
 
25
25
  multiAppend(divRoot,
26
26
  // 背景の矢印オブジェクトを表示
@@ -35,7 +35,7 @@ function customTitleInit() {
35
35
  resetFunc: _ => customCommentInit(),
36
36
  }, g_cssObj.button_Tweet)
37
37
  );
38
- }
38
+ });
39
39
 
40
40
  /**
41
41
  * カスタム画面(コメントとか)
@@ -72,38 +72,3 @@ function customCommentInit() {
72
72
  createCss2Button(`btnBack`, g_lblNameObj.b_back, _ => true, { resetFunc: _ => titleInit() }, g_cssObj.button_Back),
73
73
  )
74
74
  }
75
-
76
- /**
77
- * オプション画面(初期表示)
78
- */
79
- function customOptionInit() {
80
-
81
- }
82
-
83
- /**
84
- * キーコンフィグ画面(初期表示)
85
- */
86
- function customKeyConfigInit() {
87
-
88
- }
89
-
90
- /**
91
- * メイン画面(初期表示)
92
- */
93
- function customMainInit() {
94
-
95
- }
96
-
97
- /**
98
- * メイン画面(フレーム毎表示)
99
- */
100
- function customMainEnterFrame() {
101
-
102
- }
103
-
104
- /**
105
- * 結果画面(初期表示)
106
- */
107
- function customResultInit() {
108
-
109
- }