danoniplus 49.3.3 → 49.4.2

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/08/01
7
+ * Revised : 2026/08/12
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 49.3.3`;
12
- const g_revisedDate = `2026/08/01`;
11
+ const g_version = `Ver 49.4.2`;
12
+ const g_revisedDate = `2026/08/12`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -5619,6 +5619,8 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
5619
5619
  },
5620
5620
  });
5621
5621
  }
5622
+ // カスタムキーで定義されたtransKeyPtnを補完
5623
+ completeTransKeyPtn([newKey]);
5622
5624
 
5623
5625
  // keyRetry, keyTitleBackのキー名をキーコードに変換
5624
5626
  const keyTypePatterns = Object.keys(g_keyObj).filter(val => val.startsWith(`keyRetry${newKey}`) || val.startsWith(`keyTitleBack${newKey}`));
@@ -8078,6 +8080,66 @@ const drawMinimap = (_scoreId, { _initFlg = false, _fadeinFlg = false } = {}) =>
8078
8080
  }
8079
8081
  };
8080
8082
 
8083
+ /**
8084
+ * 指定したキー名のキー別ストレージオブジェクトを取得
8085
+ * @param {string} _keyName
8086
+ * @returns {[Object, string]} [storageObj, addKey]
8087
+ */
8088
+ const getKeyStorageObjByName = (_keyName) => {
8089
+ if (g_headerObj.keyExtraList.includes(_keyName)) {
8090
+ return [g_localStorage, _keyName];
8091
+ }
8092
+ return [parseStorageData(`danonicw-${_keyName}k`, {
8093
+ reverse: C_FLG_OFF, keyCtrl: [[]], keyCtrlPtn: 0, setColor: [],
8094
+ }), ``];
8095
+ };
8096
+
8097
+ /**
8098
+ * 別キーモード時、移行先キーが保持するSelf保存パターンの取得可否チェック
8099
+ * @param {string} _keyCtrlPtn 例: "7_2"
8100
+ * @returns {number[][]|undefined} 適用可能な場合はSelf保存済みkeyCtrl配列、不可ならundefined
8101
+ */
8102
+ const getTransKeySelfCtrl = (_keyCtrlPtn) => {
8103
+ const transKeyName = g_keyObj[`transKey${_keyCtrlPtn}`];
8104
+ const transKeyPtn = g_keyObj[`transKeyPtn${_keyCtrlPtn}`];
8105
+ if (!hasVal(transKeyName) || transKeyPtn === undefined) {
8106
+ return undefined;
8107
+ }
8108
+ const [storageObj, addKey] = getKeyStorageObjByName(transKeyName);
8109
+ const savedCtrl = storageObj[`keyCtrl${addKey}`];
8110
+ const savedPtn = storageObj[`keyCtrlPtn${addKey}`];
8111
+
8112
+ if (savedPtn !== transKeyPtn) {
8113
+ return undefined;
8114
+ }
8115
+
8116
+ // 現在のキー配置(基準形状)とレーン数・各レーン長が完全一致することを確認
8117
+ const baseCtrl = g_keyObj[`keyCtrl${_keyCtrlPtn}`];
8118
+ const isValidShape = hasArrayList(savedCtrl, baseCtrl.length) &&
8119
+ savedCtrl.length === baseCtrl.length &&
8120
+ baseCtrl.every((lane, j) => hasArrayList(savedCtrl[j], lane.length) && savedCtrl[j].length === lane.length);
8121
+
8122
+ return isValidShape ? savedCtrl : undefined;
8123
+ };
8124
+
8125
+ /**
8126
+ * 別キーモードの移行先Selfパターンを現在のキー配置へ反映(保存はしない)
8127
+ */
8128
+ const applyTransKeySelfPattern = () => {
8129
+ const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
8130
+ const savedCtrl = getTransKeySelfCtrl(keyCtrlPtn);
8131
+ if (savedCtrl === undefined) {
8132
+ return;
8133
+ }
8134
+ const baseKeyNum = g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length;
8135
+ for (let j = 0; j < baseKeyNum; j++) {
8136
+ for (let k = 0; k < (savedCtrl[j]?.length ?? 0); k++) {
8137
+ g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k] = setIntVal(savedCtrl[j][k], 0);
8138
+ }
8139
+ }
8140
+ keyConfigInit();
8141
+ };
8142
+
8081
8143
  /**
8082
8144
  * 譜面初期化処理
8083
8145
  * - 譜面の基本設定(キー数、初期速度、リバース、ゲージ設定)をここで行う
@@ -8114,24 +8176,11 @@ const setDifficulty = (_initFlg) => {
8114
8176
  g_keyObj.currentPtn = 0;
8115
8177
  g_keycons.keySwitchNum = 0;
8116
8178
  }
8117
- let storageObj, addKey = ``;
8118
-
8119
- if (!g_stateObj.extraKeyFlg) {
8120
-
8121
- // キー別のローカルストレージの初期設定 ※特殊キーは除く
8122
- g_localKeyStorage = parseStorageData(`danonicw-${g_keyObj.currentKey}k`, {
8123
- reverse: C_FLG_OFF,
8124
- keyCtrl: [[]],
8125
- keyCtrlPtn: 0,
8126
- setColor: [],
8127
- });
8128
- storageObj = g_localKeyStorage;
8129
-
8130
- } else {
8131
- storageObj = g_localStorage;
8132
- addKey = g_keyObj.currentKey;
8133
- }
8179
+ const [storageObj, addKey] = getKeyStorageObjByName(g_keyObj.currentKey);
8134
8180
  if (isNotSameKey) {
8181
+ if (!g_stateObj.extraKeyFlg) {
8182
+ g_localKeyStorage = storageObj;
8183
+ }
8135
8184
  getKeyReverse(storageObj, addKey);
8136
8185
 
8137
8186
  // キーコンフィグ初期値設定
@@ -10419,6 +10468,14 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
10419
10468
  }, g_cssObj.button_Default_NoColor, g_cssObj.title_base)
10420
10469
  );
10421
10470
  }
10471
+ if (g_isDebug) {
10472
+ keyconSprite.appendChild(
10473
+ createDivCss2Label(`arrowChara${j}`, g_keyObj[`chara${keyCtrlPtn}`][j], {
10474
+ x: keyconX, y: keyconY + 40, w: C_ARW_WIDTH, h: 10, siz: 10, align: C_ALIGN_CENTER,
10475
+ background: g_headerObj.baseBrightFlg ? `rgba(255,255,255,0.5)` : `rgba(0,0,0,0.5)`,
10476
+ }, g_cssObj.title_base)
10477
+ );
10478
+ }
10422
10479
 
10423
10480
  // 割り当て先のキー名を表示
10424
10481
  for (let k = 0; k < g_keyObj[`keyCtrl${keyCtrlPtn}`][j].length; k++) {
@@ -10730,6 +10787,9 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
10730
10787
  if (document.getElementById(`sArrow${_j}`) !== null) {
10731
10788
  $id(`sArrow${_j}`).display = _display;
10732
10789
  }
10790
+ if (document.getElementById(`arrowChara${_j}`) !== null) {
10791
+ $id(`arrowChara${_j}`).display = _display;
10792
+ }
10733
10793
  const ctrlPtn = g_keyObj[`keyCtrl${g_headerObj.keyLabels[g_stateObj.scoreId]}_${g_keyObj.currentPtn}`][_j];
10734
10794
  for (let k = 0; k < ctrlPtn.length; k++) {
10735
10795
  $id(`keycon${_j}_${k}`).display = _display;
@@ -11077,6 +11137,18 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
11077
11137
  );
11078
11138
  toggleKcDesc();
11079
11139
 
11140
+ // Selfパターン取込ボタン(条件成立時のみ表示)
11141
+ const keyCtrlPtnForSelf = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
11142
+ if (getTransKeySelfCtrl(keyCtrlPtnForSelf) !== undefined) {
11143
+ divRoot.appendChild(
11144
+ createCss2Button(`btnPtnSelf`, `Self`, () => applyTransKeySelfPattern(), {
11145
+ x: g_lblPosObj.lblPattern.x + g_lblPosObj.lblPattern.w - 50,
11146
+ y: g_lblPosObj.lblPattern.y - 14,
11147
+ w: 50, h: 14, siz: 10, title: g_msgObj.ptnSelfImport,
11148
+ }, g_cssObj.button_Mini)
11149
+ );
11150
+ }
11151
+
11080
11152
  // キーボード押下時処理
11081
11153
  setShortcutEvent(g_currentPage, (kbCode) => {
11082
11154
  const C_KEY_ESCAPE = 27;
@@ -11179,6 +11251,35 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
11179
11251
  document.oncontextmenu = () => false;
11180
11252
  };
11181
11253
 
11254
+ /**
11255
+ * transKeyPtnの自動補完処理
11256
+ * - 明示指定(transKeyPtn)が無いパターンについて、
11257
+ * キー内で同一のtransKey対象へ向かうパターンを出現順(パターン番号昇順)に
11258
+ * 0から連番で補完する
11259
+ * @param {string[]} _keyList 対象とするキー名一覧
11260
+ */
11261
+ const completeTransKeyPtn = (_keyList) => {
11262
+ _keyList.forEach(keyName => {
11263
+ const counterMap = {};
11264
+ let ptnNum = 0;
11265
+ while (g_keyObj[`keyCtrl${keyName}_${ptnNum}`] !== undefined) {
11266
+ const keyPtn = `${keyName}_${ptnNum}`;
11267
+ const targetKey = g_keyObj[`transKey${keyPtn}`];
11268
+ if (hasVal(targetKey)) {
11269
+ if (g_keyObj[`transKeyPtn${keyPtn}`] === undefined) {
11270
+ counterMap[targetKey] = counterMap[targetKey] ?? 0;
11271
+ g_keyObj[`transKeyPtn${keyPtn}`] = counterMap[targetKey];
11272
+ counterMap[targetKey]++;
11273
+ } else {
11274
+ // 明示指定がある場合は以降の自動採番と重複しないよう位置を合わせる
11275
+ counterMap[targetKey] = Math.max(counterMap[targetKey] ?? 0, g_keyObj[`transKeyPtn${keyPtn}`] + 1);
11276
+ }
11277
+ }
11278
+ ptnNum++;
11279
+ }
11280
+ });
11281
+ };
11282
+
11182
11283
  const toggleKcDesc = () => {
11183
11284
  if (document.getElementById(`kcDesc`) !== null) {
11184
11285
  kcDesc.textContent = getKcDescMsg();
@@ -12906,7 +13007,10 @@ const scoreConvert = (_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
12906
13007
  let layerTrans = tmpScrollchData[4] ?? ``;
12907
13008
  maxLayerGroup = Math.max(maxLayerGroup, layerGroup);
12908
13009
  if (g_stateObj.reverse === C_FLG_ON) {
12909
- layerTrans = invertSpecificTransforms(layerTrans);
13010
+ layerTrans = invertSpecificTransforms(layerTrans, [`translateX`]);
13011
+ }
13012
+ if (g_stateObj.swapping === `Mirror+`) {
13013
+ layerTrans = invertSpecificTransforms(layerTrans, [`translateY`]);
12910
13014
  }
12911
13015
 
12912
13016
  scrollchData.push([frame, arrowNum, frame, scrollDir, layerGroup, layerTrans]);
@@ -14067,15 +14171,20 @@ const pushScrollchs = (_header, _frameArrow, _val, _frameStep, _scrollDir, _laye
14067
14171
  /**
14068
14172
  * ホワイトリストに登録されたCSS関数内の数値符号のみを反転する関数
14069
14173
  * @param {string} cssString
14174
+ * @param {string[]} exceptList 反転対象から除外するCSS関数名のリスト
14070
14175
  * @returns {string}
14071
14176
  */
14072
- const invertSpecificTransforms = (cssString) => {
14177
+ const invertSpecificTransforms = (cssString, exceptList = []) => {
14073
14178
  // 反転対象にしたいCSS関数名を指定(ホワイトリスト)
14074
- const targetFunctions = [
14179
+ const baseTargetFunctions = [
14075
14180
  `rotate`, `rotateX`, `rotateY`, `rotateZ`, `rotate3d`,
14076
14181
  `translate`, `translateX`, `translateY`, `translateZ`, `translate3d`,
14077
14182
  `skew`, `skewX`, `skewY`
14078
14183
  ];
14184
+ const targetFunctions = baseTargetFunctions.filter(pattern => !exceptList.includes(pattern));
14185
+ if (targetFunctions.length === 0) {
14186
+ return cssString; // 反転対象がない場合は元の文字列を返す
14187
+ }
14079
14188
 
14080
14189
  // RegExパターンを作成: /(rotate|translate...)\(([^)]+)\)/g
14081
14190
  const pattern = new RegExp(`\\b(${targetFunctions.join(`|`)})\\(([^)]+)\\)`, `g`);
@@ -14167,7 +14276,12 @@ const getArrowSettings = () => {
14167
14276
  if (g_keyObj[`layerTrans${keyCtrlPtn}`]?.[0]) {
14168
14277
  g_workObj.layerTrans = structuredClone(g_keyObj[`layerTrans${keyCtrlPtn}`][0]);
14169
14278
  if (g_stateObj.reverse === C_FLG_ON) {
14170
- g_workObj.layerTrans = g_workObj.layerTrans.map(val => invertSpecificTransforms(val));
14279
+ // Reverse時はX軸反転のため、X軸の座標変換では符号を変換しない
14280
+ g_workObj.layerTrans = g_workObj.layerTrans.map(val => invertSpecificTransforms(val, [`translateX`]));
14281
+ }
14282
+ if (g_stateObj.swapping === `Mirror+`) {
14283
+ // Swapping: Mirror+ はY軸反転のため、Y軸の座標変換では符号を変換しない
14284
+ g_workObj.layerTrans = g_workObj.layerTrans.map(val => invertSpecificTransforms(val, [`translateY`]));
14171
14285
  }
14172
14286
  }
14173
14287
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/08/01 (v49.3.3)
8
+ * Revised : 2026/08/06 (v49.4.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -3676,7 +3676,7 @@ const g_keyObj = {
3676
3676
  keyTitleBack11j_0: 27, // 27: Escape
3677
3677
 
3678
3678
  // 別キー
3679
- transKey8_2: '12',
3679
+ transKey8_2: '12u',
3680
3680
  transKey15A_1: '15B', // 15A/15Bはキーパターンをコピーして生成するため、transKeyを明示的に指定
3681
3681
  transKey15B_0: '', // 15A/15Bはキーパターンをコピーして生成するため、transKeyを明示的に指定
3682
3682
 
@@ -4136,6 +4136,9 @@ g_keycons.groups.forEach(type => {
4136
4136
  tmpName.forEach(property => g_keyObj[`${property.slice(0, -2)}`] = g_keyObj[property].concat());
4137
4137
  });
4138
4138
 
4139
+ // デフォルトで定義されたキーパターンのtransKeyPtnを補完する
4140
+ completeTransKeyPtn(g_keyObj.defaultKeyList);
4141
+
4139
4142
  // 外部エディター用テンプレート
4140
4143
  // g_editorTmp: Dancing☆Onigiriエディター (CW Edition対応)
4141
4144
  // g_editorTmp2: ダンおに譜面作成エディタ ver3.x
@@ -4177,7 +4180,7 @@ const g_editorTmp2Template = `
4177
4180
  // 後でプロパティ削除に影響するため、先頭文字が全く同じ場合は長い方を先に定義する (例: divMax, div)
4178
4181
  const g_keyCopyLists = {
4179
4182
  simpleDef: [`blank`, `scale`],
4180
- simple: [`divMax`, `div`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
4183
+ simple: [`divMax`, `div`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKeyPtn`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
4181
4184
  multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroupOrder`, `keyGroup`, `layerGroup`, `layerTrans`],
4182
4185
  };
4183
4186
 
@@ -4902,7 +4905,7 @@ const g_lang_lblNameObj = {
4902
4905
  kcShortcutDesc: `Shortcut during play:`,
4903
4906
  kcShortcutDesc1: `Return to title: {0}`,
4904
4907
  kcShortcutDesc2: `Retry the game: {1}`,
4905
- transKeyDesc: `Key config, Color type, etc. are not saved in another key mode`,
4908
+ transKeyDesc: `Key config, Color type, etc. are not saved for alternate keymode`,
4906
4909
  colorTypeDesc: `With the current ColorType setting, color change (Display:Color) will be automatically turned OFF.`,
4907
4910
  sdShortcutDesc: `When "Hidden+" or "Sudden+" select, "pageUp" cover up / "pageDown" cover down`,
4908
4911
  displayPreviewDesc: `If you drag the judgment character section or shortcut display, it will be adjusted to that position.`,
@@ -5073,6 +5076,7 @@ const g_lang_msgObj = {
5073
5076
  pickColorR: `設定する矢印色の種類を切り替えます。`,
5074
5077
  pickColorCopy: `このボタンを押すと、フリーズアローの配色を矢印(枠)の色で上書きします。\nヒット時のフリーズアローの色も上書きします。`,
5075
5078
  pickColorReset: `矢印・フリーズアローの配色を元に戻します。`,
5079
+ ptnSelfImport: `対応する別キーで保存されているキーコンフィグを読み込みます。`,
5076
5080
 
5077
5081
  customFunctionError: `初回の実行エラーが発生しました。修正されるまでこの処理は無視されます。`,
5078
5082
  },
@@ -5181,6 +5185,7 @@ const g_lang_msgObj = {
5181
5185
  pickColorR: `Switches the arrow color type to be set.`,
5182
5186
  pickColorCopy: `Pressing this button will override the color scheme of the freeze arrow with the frame color of the arrow. \nIt also overrides the color of the freeze arrow on hit.`,
5183
5187
  pickColorReset: `Restore the color scheme for arrows and freeze arrows.`,
5188
+ ptnSelfImport: `Load the key config saved for the corresponding alternate keymode.`,
5184
5189
 
5185
5190
  customFunctionError: `An error occurred during the first execution. This process will be ignored until the error is resolved.`,
5186
5191
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "49.3.3",
3
+ "version": "49.4.2",
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",