danoniplus 40.2.0 → 40.3.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,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2025/03/07
7
+ * Revised : 2025/03/10
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 40.2.0`;
12
- const g_revisedDate = `2025/03/07`;
11
+ const g_version = `Ver 40.3.1`;
12
+ const g_revisedDate = `2025/03/10`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -475,19 +475,20 @@ const getIndent = (_level) => ' '.repeat(_level * 4);
475
475
  * ストレージ情報の取得
476
476
  * @param {string} _name g_storageFuncの実行キー名
477
477
  * @param {string} _key g_storageFuncの実行キーの引数
478
+ * @param {boolean} [_colorFmt=true]
478
479
  * @returns {string}
479
480
  */
480
- const viewKeyStorage = (_name, _key = ``) => {
481
+ const viewKeyStorage = (_name, _key = ``, _colorFmt = true) => {
481
482
 
482
483
  // キャッシュ設定
483
484
  if (!viewKeyStorage.cache) {
484
485
  viewKeyStorage.cache = new Map();
485
486
  }
486
- const cacheKey = _key + _name;
487
+ const cacheKey = _key + _name + String(_colorFmt);
487
488
  if (viewKeyStorage.cache.has(cacheKey)) {
488
489
  return viewKeyStorage.cache.get(cacheKey);
489
490
  }
490
- const result = formatObject(g_storageFunc.get(_name)?.(_key) || setVal(_name, ``, C_TYP_CALC));
491
+ const result = formatObject(g_storageFunc.get(_name)?.(_key) || setVal(_name, ``, C_TYP_CALC), 0, { colorFmt: _colorFmt });
491
492
  viewKeyStorage.cache.set(cacheKey, result);
492
493
  return result;
493
494
  }
@@ -498,11 +499,11 @@ const viewKeyStorage = (_name, _key = ``) => {
498
499
  * @param {Number} _indent
499
500
  * @param {boolean} [colorFmt=true] フォーマット加工フラグ
500
501
  * @param {string} [rootKey=''] オブジェクトの最上位プロパティ名
501
- * @param {Object} [_parent=null]
502
502
  * @returns {string}
503
503
  */
504
504
  const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {}) => {
505
- if (_obj === null || typeof _obj !== 'object') {
505
+ const isObj = _obj => typeof _obj === C_TYP_OBJECT && _obj !== null;
506
+ if (!isObj(_obj)) {
506
507
  return JSON.stringify(_obj);
507
508
  }
508
509
  const baseIndent = getIndent(_indent);
@@ -541,53 +542,101 @@ const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {})
541
542
  // keyCtrlXの対応キー表示処理
542
543
  return (g_kCd[_value] && _value !== 0) ? `${_value}|<span style="color:#ffff66">${g_kCd[_value]}</span>` : `----`;
543
544
  }
544
- } else if (typeof _value === C_TYP_OBJECT && _value !== null) {
545
+ } else if (isObj(_value)) {
545
546
  return formatObject(_value, _indent + 1, { colorFmt, rootKey: _rootKey });
546
547
  }
547
548
  }
548
549
  return JSON.stringify(_value);
549
550
  };
550
551
 
551
- // 二次元配列の整形処理
552
- if (Array.isArray(_obj)) {
553
- if (_obj.length === 0) {
554
- return '[]';
555
- }
556
- if (colorFmt && _obj.length > 100) {
557
- const filteredArray = _obj.reduce((result, value, index) => {
558
- if (hasVal(value)) {
559
- result.push(`${index}: ${formatValue(value, rootKey)}`);
552
+ /**
553
+ * 配列の装飾処理
554
+ * @param {number[]|string[]} _obj
555
+ * @returns {string}
556
+ */
557
+ const formatArrayValue = (_obj) => {
558
+
559
+ const formatSetArray = (_list, _numOfSet = 2) => {
560
+ if (_list.findIndex(val => val === rootKey) >= 0) {
561
+ let result = `[`;
562
+ for (let j = 0; j < _obj.length; j += _numOfSet) {
563
+ result += `<br>${nestedIndent}${_obj[j]}: ${_obj[j + 1]}`;
564
+ for (let k = 0; k < _numOfSet - 2; k++) {
565
+ const idx = j + k + 2;
566
+ if (idx < _obj.length) {
567
+ result += `, ${formatValue(_obj[idx], rootKey)}`;
568
+ }
569
+ }
560
570
  }
571
+ result += (_obj.length === 0 ? `` : `<br>${baseIndent}`) + `]`;
561
572
  return result;
562
- }, []);
563
- return `{<br>${baseIndent}[<br>${filteredArray.join(',<br>')}<br>]<br>}`;
564
- }
565
- const isArrayOfArrays = _obj.every(item => Array.isArray(item));
566
- const formattedArray = _obj
567
- .map(value => {
568
- const isNestedObject = typeof value === 'object' && value !== null;
569
- return isArrayOfArrays
570
- ? `${nestedIndent}${formatValue(value, rootKey)}`
571
- : isNestedObject
572
- ? formatObject(value, _indent + 1, { colorFmt, rootKey })
573
- : formatValue(value, rootKey)
574
- }).filter(val => !hasVal(val) || val !== `----`).join(isArrayOfArrays ? `,<br>` : `, `);
575
-
576
- return `[${isArrayOfArrays ? `<br>` : ``}${formattedArray}${isArrayOfArrays ? `<br>${baseIndent}` : ''}]`;
577
- }
578
-
579
- // オブジェクトのネスト整形処理
580
- const formattedEntries = Object.entries(_obj)
581
- .map(([key, value]) => {
582
- const isNestedObject = typeof value === 'object' && value !== null;
583
- const baseKey = rootKey === `` ? key : rootKey;
584
- const formattedValue = isNestedObject
585
- ? formatObject(value, _indent + 1, { colorFmt, rootKey: baseKey }, _obj)
586
- : formatValue(value, baseKey);
587
- return `<br>${nestedIndent}"${key}": ${formattedValue}`;
588
- }).filter(val => !hasVal(val) || val !== `----`).join(`,`);
589
-
590
- let result = `{${formattedEntries}<br>${baseIndent}}`;
573
+ }
574
+ return ``;
575
+ };
576
+ if (colorFmt) {
577
+ if (typeof _obj[0] === C_TYP_NUMBER) {
578
+ let result;
579
+ Object.keys(g_dataSetObj).forEach(key =>
580
+ result ||= formatSetArray(g_dataSetObj[key], Number(key)));
581
+ if (result !== ``) {
582
+ return result;
583
+ }
584
+ }
585
+ if (_obj.length > 100) {
586
+ const filteredArray = _obj.reduce((result, value, index) => {
587
+ if (hasVal(value)) {
588
+ result.push(`${index}: ${formatValue(value, rootKey)}`);
589
+ }
590
+ return result;
591
+ }, []);
592
+ return `[<br>${nestedIndent}${filteredArray.join(`,<br>${nestedIndent}`)}<br>${baseIndent}]`;
593
+ }
594
+ }
595
+ return ``;
596
+ };
597
+
598
+ /**
599
+ * 配列・オブジェクトのネスト整形処理
600
+ * @returns {string}
601
+ */
602
+ const formatCollection = () => {
603
+ const isArray = Array.isArray(_obj);
604
+ const isArrayOfArrays = isArray && _obj.every(item => Array.isArray(item));
605
+ const getNextObject = (_item, _rootKey) => isObj(_item)
606
+ ? formatObject(_item, _indent + 1, { colorFmt, rootKey: _rootKey })
607
+ : formatValue(_item, _rootKey);
608
+
609
+ if (isArray) {
610
+ let result = formatArrayValue(_obj);
611
+ if (result !== ``) {
612
+ return result;
613
+ }
614
+ }
615
+
616
+ // 配列またはオブジェクトの各要素をフォーマット
617
+ const formattedEntries = (isArray
618
+ ? _obj.map(item => {
619
+ const formattedValue = isArrayOfArrays
620
+ ? `<br>${nestedIndent}${formatValue(item, rootKey)}`
621
+ : getNextObject(item, rootKey);
622
+ return formattedValue;
623
+ })
624
+ : Object.entries(_obj).map(([key, value]) => {
625
+ const formattedValue = getNextObject(value, rootKey === `` ? key : rootKey);
626
+ return `<br>${nestedIndent}"${key}": ${formattedValue}`;
627
+ })).filter(val => !hasVal(val) || val !== `----`);
628
+
629
+ // 配列なら[]で囲む、オブジェクトなら{}で囲む
630
+ if (isArray) {
631
+ return _obj.length === 0
632
+ ? '[]'
633
+ : `[${formattedEntries.join(', ')}${isArrayOfArrays ? `<br>${baseIndent}` : ''}]`;
634
+ } else {
635
+ return `{${formattedEntries.join(',')}<br>${baseIndent}}`;
636
+ }
637
+ };
638
+
639
+ let result = formatCollection();
591
640
  if (!colorFmt) {
592
641
  result = result.replaceAll(`<br>`, `\r\n`).replaceAll(`&nbsp;`, ` `);
593
642
  }
@@ -2538,6 +2587,44 @@ const initialControl = async () => {
2538
2587
  delete g_keyObj[key];
2539
2588
  }
2540
2589
  });
2590
+
2591
+ // エディター用のフォーマッター作成
2592
+ const customKeyList = g_headerObj.keyLists.filter(val =>
2593
+ g_keyObj.defaultKeyList.findIndex(key => key === val) < 0);
2594
+
2595
+ customKeyList.forEach(key => {
2596
+ const keyBase = `${key}_0`;
2597
+ const keyCtrlPtn = `${g_keyObj.defaultProp}${keyBase}`;
2598
+ const keyGroup = g_keyObj[`keyGroup${keyBase}`];
2599
+ const keyGroupList = makeDedupliArray(keyGroup.flat());
2600
+ const orgKeyNum = g_keyObj[keyCtrlPtn].length;
2601
+ const baseX = Math.floor(Math.random() * (100 - keyGroupList.length));
2602
+
2603
+ keyGroupList.forEach((keyGroupNo, j) => {
2604
+ const keyN = keyGroupNo === `0` ? key : `${key}_${j + 1}`;
2605
+ const filterCond = (j) => keyGroup[j].findIndex(val => val === keyGroupNo) >= 0;
2606
+ const keyCtrlList = g_keyObj[keyCtrlPtn].filter((val, j) => filterCond(j));
2607
+ const charaList = g_keyObj[`chara${keyBase}`].filter((val, j) => filterCond(j));
2608
+ const colorList = g_keyObj[`color${keyBase}_0`].filter((val, j) => filterCond(j));
2609
+ const keyNum = g_keyObj[keyCtrlPtn].filter((val, j) => filterCond(j)).length;
2610
+
2611
+ g_editorTmp[keyN] = {};
2612
+ g_editorTmp[keyN].id = orgKeyNum * 100 + baseX + j;
2613
+ g_editorTmp[keyN].num = keyNum;
2614
+ g_editorTmp[keyN].chars = keyCtrlList.map(val => g_kCd[val[0]]);
2615
+ g_editorTmp[keyN].keys = keyCtrlList.map(val => g_kCdN[val[0]]).map(val => replaceStr(val, g_escapeStr.editorKey));
2616
+ g_editorTmp[keyN].alternativeKeys = keyCtrlList.map(val => val[1] === 0 ? `` : g_kCdN[val[1]]).map(val => replaceStr(val, g_escapeStr.editorKey));
2617
+ g_editorTmp[keyN].noteNames = charaList.map(val => `${val}_data`);
2618
+ g_editorTmp[keyN].freezeNames = charaList.map(val => {
2619
+ let frzName = replaceStr(val, g_escapeStr.frzName);
2620
+ if (frzName.indexOf(`frz`) === -1 && frzName.indexOf(`foni`) === -1) {
2621
+ frzName = frzName.replaceAll(frzName, `frz${toCapitalize(frzName)}`);
2622
+ }
2623
+ return `${frzName}_data`;
2624
+ });
2625
+ g_editorTmp[keyN].colorGroup = colorList.map(val => val % 3);
2626
+ });
2627
+ });
2541
2628
  };
2542
2629
 
2543
2630
  /**
@@ -5009,10 +5096,12 @@ const dataMgtInit = () => {
5009
5096
  g_stateObj[`dm_${key}`] = C_FLG_OFF;
5010
5097
  g_settings.dataMgtNum[key] = 0;
5011
5098
 
5099
+ const keyWidth = Math.min(Math.max(50, getStrWidth(getKeyName(key), g_limitObj.setLblSiz, getBasicFont())), 80);
5012
5100
  keyListSprite.appendChild(createMgtButton(key, j - 2, 0, {
5013
- w: Math.max(50, getStrWidth(getKeyName(key) + ` `, g_limitObj.setLblSiz, getBasicFont())),
5101
+ w: keyWidth,
5102
+ siz: getFontSize(getKeyName(key), keyWidth, getBasicFont(), g_limitObj.setLblSiz, 10),
5014
5103
  }));
5015
- document.getElementById(`btn${key}`).innerHTML = getKeyName(key);
5104
+ document.getElementById(`btn${toCapitalize(key)}`).innerHTML = getKeyName(key);
5016
5105
 
5017
5106
  keyListSprite.appendChild(createCss2Button(`btnView${key}`, ``, evt => {
5018
5107
  keyList.forEach(keyx => {
@@ -5146,6 +5235,11 @@ const preconditionInit = () => {
5146
5235
  .replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
5147
5236
 
5148
5237
  createDivCss2Label(`lblPrecondView`, viewKeyStorage(`g_rootObj`), g_lblPosObj.lblPrecondView),
5238
+ createCss2Button(`btnPrecondView`, g_lblNameObj.b_copyStorage, () =>
5239
+ copyTextToClipboard(
5240
+ viewKeyStorage(g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + g_settings.preconditionNumSub], ``, false),
5241
+ g_msgInfoObj.I_0007),
5242
+ g_lblPosObj.btnPrecondView, g_cssObj.button_Default, g_cssObj.button_ON),
5149
5243
  );
5150
5244
  setUserSelect($id(`lblPrecondView`), `text`);
5151
5245
 
@@ -5175,6 +5269,7 @@ const preconditionInit = () => {
5175
5269
  }
5176
5270
  lblPrecondView.innerHTML = viewKeyStorage(g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + j]);
5177
5271
  lblPrecondView.scrollTop = 0;
5272
+ g_settings.preconditionNumSub = j;
5178
5273
  evt.target.classList.replace(g_cssObj.button_Default, g_cssObj.button_Reset);
5179
5274
  }, {
5180
5275
  x: g_btnX() + g_btnWidth((j % (numOfPrecs / 2)) / (numOfPrecs / 2 + 1)),
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/03/02 (v40.1.0)
8
+ * Revised : 2025/03/10 (v40.3.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -283,6 +283,9 @@ const updateWindowSiz = () => {
283
283
  btnKeyStorage: {
284
284
  x: g_btnX(1) - 140, y: 100 + g_sHeight / 4 + 10, w: 70, h: 20, siz: 16,
285
285
  },
286
+ btnPrecondView: {
287
+ x: g_btnX(1) - 90, y: 110, w: 70, h: 20, siz: 16,
288
+ },
286
289
 
287
290
  /** 設定画面 */
288
291
  btnBack: {
@@ -785,6 +788,18 @@ const g_escapeStr = {
785
788
  [`all[]`, `sumData(g_detailObj.arrowCnt[{0}]) + sumData(g_detailObj.frzCnt[{0}])`],
786
789
  [`maxlife[]`, `g_headerObj.maxLifeVal`],
787
790
  ],
791
+ editorKey: [
792
+ [`ArrowLeft`, `KeyU`],
793
+ [`ArrowDown`, `KeyI`],
794
+ [`ArrowUp`, `Digit8`],
795
+ [`ArrowRight`, `KeyO`],
796
+ [`Space`, `KeyG`],
797
+ [`KeyB`, `KeyH`],
798
+ [`Enter`, `BackSlash`],
799
+ [`ShiftLeft`, `KeyZ`],
800
+ [`ShiftRight`, `Slash`],
801
+ [`Tab`, `KeyQ`],
802
+ ]
788
803
  };
789
804
 
790
805
  /** 設定・オプション画面用共通 */
@@ -1156,8 +1171,9 @@ const g_settings = {
1156
1171
  settingWindowNum: 0,
1157
1172
 
1158
1173
  preconditions: [`g_rootObj`, `g_headerObj`, `g_keyObj`, `g_scoreObj`, `g_workObj`,
1159
- `g_detailObj`, `g_stateObj`, `g_attrObj`],
1174
+ `g_detailObj`, `g_stateObj`, `g_attrObj`, `g_editorTmp`],
1160
1175
  preconditionNum: 0,
1176
+ preconditionNumSub: 0,
1161
1177
  };
1162
1178
 
1163
1179
  g_settings.volumeNum = g_settings.volumes.length - 1;
@@ -2487,6 +2503,7 @@ const g_keyObj = {
2487
2503
  dfPtnNum: 0,
2488
2504
 
2489
2505
  minKeyCtrlNum: 2,
2506
+ defaultKeyList: [],
2490
2507
 
2491
2508
  // キー別ヘッダー
2492
2509
  // - 譜面データ中に出てくる矢印(ノーツ)の種類と順番(ステップゾーン表示順)を管理する
@@ -3023,6 +3040,11 @@ const g_keyObj = {
3023
3040
  // g_keyObj.defaultProp の上書きを禁止
3024
3041
  Object.defineProperty(g_keyObj, `defaultProp`, { writable: false });
3025
3042
 
3043
+ // 既定のキー定義リストを動的に作成
3044
+ Object.keys(g_keyObj)
3045
+ .filter(key => key.startsWith(g_keyObj.defaultProp) && key.endsWith(`_0`))
3046
+ .forEach(key => g_keyObj.defaultKeyList.push(key.split(`_`)[0].slice(g_keyObj.defaultProp.length)));
3047
+
3026
3048
  // キーパターンのコピーリスト
3027
3049
  // ・コピー先:コピー元の順に指定する
3028
3050
  // ・上から順に処理する
@@ -3157,6 +3179,8 @@ g_keycons.groups.forEach(type => {
3157
3179
  tmpName.forEach(property => g_keyObj[`${property.slice(0, -2)}`] = g_keyObj[property].concat());
3158
3180
  });
3159
3181
 
3182
+ const g_editorTmp = {};
3183
+
3160
3184
  // 特殊キーのコピー種 (simple: 代入、multiple: 配列ごと代入)
3161
3185
  // 後でプロパティ削除に影響するため、先頭文字が全く同じ場合は長い方を先に定義する (例: divMax, div)
3162
3186
  const g_keyCopyLists = {
@@ -3235,6 +3259,17 @@ const g_dataMinObj = {
3235
3259
  style: 1,
3236
3260
  };
3237
3261
 
3262
+ /**
3263
+ * データフォーマット管理用
3264
+ * - セット数: 対象の配列名の組で記述
3265
+ */
3266
+ const g_dataSetObj = {
3267
+ 2: [`speedData`, `boostData`],
3268
+ 4: [`colorData`, `arrowCssMotionData`, `frzCssMotionData`,
3269
+ `dummyArrowCssMotionData`, `dummyFrzCssMotionData`],
3270
+ 5: [`ncolorData`, `scrollchData`],
3271
+ }
3272
+
3238
3273
  const g_dfColorObj = {
3239
3274
 
3240
3275
  // 矢印初期色情報
@@ -3447,6 +3482,7 @@ const g_lang_msgInfoObj = {
3447
3482
  I_0004: `musicUrlが設定されていないため、無音モードで再生します`,
3448
3483
  I_0005: `正規のミラー譜面で無いため、ハイスコアは保存されません`,
3449
3484
  I_0006: `ローカルストレージ情報をクリップボードにコピーしました!`,
3485
+ I_0007: `オブジェクト情報をクリップボードにコピーしました!`,
3450
3486
  },
3451
3487
  En: {
3452
3488
  W_0001: `Your browser is not guaranteed to work.<br>
@@ -3501,6 +3537,7 @@ const g_lang_msgInfoObj = {
3501
3537
  I_0004: `Play in silence mode because "musicUrl" is not set`,
3502
3538
  I_0005: `Highscore is not saved because not a regular mirrored chart.`,
3503
3539
  I_0006: `Local storage information copied to clipboard!`,
3540
+ I_0007: `Object information copied to clipboard!`,
3504
3541
  },
3505
3542
  };
3506
3543
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "40.2.0",
3
+ "version": "40.3.1",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {