danoniplus 39.8.1 → 40.0.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,19 +4,19 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2025/02/22
7
+ * Revised : 2025/03/01
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 39.8.1`;
12
- const g_revisedDate = `2025/02/22`;
11
+ const g_version = `Ver 40.0.0`;
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
 
@@ -7160,6 +7319,7 @@ const keyConfigInit = (_kcType = g_kcType) => {
7160
7319
  const getKeyConfigColor = (_j, _colorPos) => {
7161
7320
  let arrowColor = g_headerObj.setColor[_colorPos];
7162
7321
  if (typeof g_keyObj[`assistPos${keyCtrlPtn}`] === C_TYP_OBJECT &&
7322
+ g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay] !== undefined &&
7163
7323
  !g_autoPlaysBase.includes(g_stateObj.autoPlay)) {
7164
7324
  if (g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay][_j] === 1) {
7165
7325
  arrowColor = g_headerObj.setDummyColor[_colorPos];
@@ -8270,12 +8430,11 @@ const loadingScoreInit = async () => {
8270
8430
  let speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
8271
8431
 
8272
8432
  // Motionオプション適用時の矢印別の速度を取得(配列形式)
8273
- const motionOnFrame = setMotionOnFrame();
8274
- g_workObj.motionOnFrames = structuredClone(motionOnFrame);
8433
+ g_workObj.motionOnFrames = setMotionOnFrame();
8275
8434
 
8276
8435
  // 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
8277
8436
  const firstFrame = (g_scoreObj.frameNum === 0 ? 0 : g_scoreObj.frameNum + g_headerObj.blankFrame);
8278
- let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
8437
+ let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame);
8279
8438
 
8280
8439
  // キーパターン(デフォルト)に対応する矢印番号を格納
8281
8440
  convertReplaceNums();
@@ -8307,7 +8466,7 @@ const loadingScoreInit = async () => {
8307
8466
  lastFrame += preblankFrame;
8308
8467
  firstArrowFrame += preblankFrame;
8309
8468
  speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
8310
- arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
8469
+ arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame);
8311
8470
  g_headerObj.blankFrame += preblankFrame;
8312
8471
  }
8313
8472
  }
@@ -8360,7 +8519,7 @@ const loadingScoreInit = async () => {
8360
8519
  calcLifeVals(g_fullArrows);
8361
8520
 
8362
8521
  // 矢印・フリーズアロー・速度/色変化格納処理
8363
- pushArrows(g_scoreObj, speedOnFrame, motionOnFrame, arrivalFrame);
8522
+ pushArrows(g_scoreObj, speedOnFrame, arrivalFrame);
8364
8523
 
8365
8524
  // メインに入る前の最終初期化処理
8366
8525
  getArrowSettings();
@@ -9258,9 +9417,9 @@ const setSpeedOnFrame = (_speedData, _lastFrame) => {
9258
9417
 
9259
9418
  /**
9260
9419
  * Motionオプション適用時の矢印別の速度設定
9261
- * - 矢印が表示される最大フレーム数を 縦ピクセル数×20 と定義。
9420
+ * - 矢印が表示される最大フレーム数を 101フレーム と定義。
9262
9421
  */
9263
- 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));
9264
9423
 
9265
9424
  /**
9266
9425
  * Boost用の適用関数
@@ -9316,11 +9475,10 @@ const getFountainTrace = (_frms, _spd) => {
9316
9475
  /**
9317
9476
  * 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
9318
9477
  * @param {number} _startFrame
9319
- * @param {object} _speedOnFrame
9320
- * @param {object} _motionOnFrame
9478
+ * @param {object} _speedOnFrame
9321
9479
  * @returns {number}
9322
9480
  */
9323
- const getFirstArrivalFrame = (_startFrame, _speedOnFrame, _motionOnFrame) => {
9481
+ const getFirstArrivalFrame = (_startFrame, _speedOnFrame) => {
9324
9482
  let startY = 0;
9325
9483
  let frm = _startFrame;
9326
9484
 
@@ -9335,10 +9493,9 @@ const getFirstArrivalFrame = (_startFrame, _speedOnFrame, _motionOnFrame) => {
9335
9493
  * 矢印・フリーズアロー・速度/色変化格納処理
9336
9494
  * @param {object} _dataObj
9337
9495
  * @param {object} _speedOnFrame
9338
- * @param {object} _motionOnFrame
9339
9496
  * @param {number} _firstArrivalFrame
9340
9497
  */
9341
- const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame) => {
9498
+ const pushArrows = (_dataObj, _speedOnFrame, _firstArrivalFrame) => {
9342
9499
 
9343
9500
  // 矢印・フリーズアロー・速度/色変化用 フレーム別処理配列
9344
9501
  [``, `Dummy`].forEach(header =>
@@ -9419,7 +9576,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9419
9576
  // 最後尾のデータから計算して格納
9420
9577
  const lastk = _data.length - setcnt;
9421
9578
  let arrowArrivalFrm = _data[lastk];
9422
- let tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame, _motionOnFrame);
9579
+ let tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame);
9423
9580
 
9424
9581
  startPoint[lastk] = tmpObj.frm;
9425
9582
  let frmPrev = tmpObj.frm;
@@ -9465,7 +9622,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9465
9622
  spdNext = spdPrev;
9466
9623
  spdPrev = _dataObj.speedData[spdk];
9467
9624
  }
9468
- tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame, _motionOnFrame);
9625
+ tmpObj = getArrowStartFrame(arrowArrivalFrm, _speedOnFrame);
9469
9626
 
9470
9627
  startPoint[k] = tmpObj.frm;
9471
9628
  frmPrev = tmpObj.frm;
@@ -9498,7 +9655,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9498
9655
  if (hasArrayList(_data, 2)) {
9499
9656
  let delIdx = 0;
9500
9657
  for (let k = _data.length - 2; k >= 0; k -= 2) {
9501
- const tmpObj = getArrowStartFrame(_data[k], _speedOnFrame, _motionOnFrame);
9658
+ const tmpObj = getArrowStartFrame(_data[k], _speedOnFrame);
9502
9659
  if (tmpObj.frm < g_scoreObj.frameNum) {
9503
9660
  _data[k] = g_scoreObj.frameNum;
9504
9661
  delIdx = k;
@@ -9547,7 +9704,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9547
9704
  }
9548
9705
  } else {
9549
9706
  if (calcFrameFlg) {
9550
- const tmpObj = getArrowStartFrame(baseData[k], _speedOnFrame, _motionOnFrame);
9707
+ const tmpObj = getArrowStartFrame(baseData[k], _speedOnFrame);
9551
9708
  if (tmpObj.frm < g_scoreObj.frameNum) {
9552
9709
  const diff = g_scoreObj.frameNum - tmpObj.frm;
9553
9710
  tmpObj.frm = g_scoreObj.frameNum;
@@ -9661,11 +9818,10 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9661
9818
  /**
9662
9819
  * ステップゾーン到達地点から逆算して開始フレームを取得
9663
9820
  * @param {number} _frame
9664
- * @param {object} _speedOnFrame
9665
- * @param {object} _motionOnFrame
9821
+ * @param {object} _speedOnFrame
9666
9822
  * @returns {{ frm: number, startY: number, arrivalFrm: number, motionFrm: number }}
9667
9823
  */
9668
- const getArrowStartFrame = (_frame, _speedOnFrame, _motionOnFrame) => {
9824
+ const getArrowStartFrame = (_frame, _speedOnFrame) => {
9669
9825
 
9670
9826
  const obj = {
9671
9827
  frm: _frame,
@@ -11167,7 +11323,8 @@ const mainInit = () => {
11167
11323
  if (g_workObj.currentSpeed !== 0) {
11168
11324
  const boostCnt = currentArrow.boostCnt;
11169
11325
  currentArrow.prevY = currentArrow.y;
11170
- 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;
11171
11328
  $id(arrowName).top = wUnit(currentArrow.y);
11172
11329
  currentArrow.boostCnt--;
11173
11330
  }
@@ -11313,7 +11470,7 @@ const mainInit = () => {
11313
11470
 
11314
11471
  // 移動
11315
11472
  if (g_workObj.currentSpeed !== 0) {
11316
- 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;
11317
11474
  $id(frzName).top = wUnit(currentFrz.y);
11318
11475
  currentFrz.boostCnt--;
11319
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.0)
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 },
@@ -3503,6 +3542,7 @@ const g_lblNameObj = {
3503
3542
  b_retry: `Retry`,
3504
3543
  b_close: `Close`,
3505
3544
  b_cReset: `Reset`,
3545
+ b_precond: `Precondition`,
3506
3546
 
3507
3547
  Difficulty: `Difficulty`,
3508
3548
  Speed: `Speed`,
@@ -4045,6 +4085,7 @@ const g_customJsObj = {
4045
4085
  title: [],
4046
4086
  titleEnterFrame: [],
4047
4087
  dataMgt: [],
4088
+ precondition: [],
4048
4089
  option: [],
4049
4090
  difficulty: [],
4050
4091
  settingsDisplay: [],
@@ -4085,6 +4126,7 @@ const g_customJsObj = {
4085
4126
  const g_skinJsObj = {
4086
4127
  title: [],
4087
4128
  dataMgt: [],
4129
+ precondition: [],
4088
4130
  option: [],
4089
4131
  settingsDisplay: [],
4090
4132
  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
- }