danoniplus 45.3.0 → 45.4.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/03/01
7
+ * Revised : 2026/03/04
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 45.3.0`;
12
- const g_revisedDate = `2026/03/01`;
11
+ const g_version = `Ver 45.4.0`;
12
+ const g_revisedDate = `2026/03/04`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -2786,7 +2786,10 @@ const initialControl = async () => {
2786
2786
  titleInit(true);
2787
2787
 
2788
2788
  // 未使用のg_keyObjプロパティを削除
2789
- const keyProp = g_keyCopyLists.simple.concat(g_keyCopyLists.multiple, `keyCtrl`, `keyName`, `minWidth`, `ptchara`);
2789
+ const keyProp = g_keyCopyLists.simple.concat(
2790
+ g_keyCopyLists.multiple,
2791
+ `keyCtrl`, `keyName`, `minWidth`, `movLock`, `initManual`, `ptchara`
2792
+ );
2790
2793
  const delKeyPropList = [`ptchara7`, `dfPtnNum`, `minKeyCtrlNum`, `minPatterns`];
2791
2794
  Object.keys(g_keyObj).forEach(key => {
2792
2795
  const type = keyProp.find(prop => key.startsWith(prop)) || ``;
@@ -8689,9 +8692,67 @@ const exSettingInit = () => {
8689
8692
  createEmptySprite(divRoot, `optionsprite`, g_windowObj.optionSprite);
8690
8693
  const spriteList = setSpriteList(g_settingPos.exSetting);
8691
8694
 
8692
- createGeneralSetting(spriteList.playWindow, `playWindow`);
8695
+ /**
8696
+ * 拡張ボタンの表示・非表示と通常ボタンの幅変更
8697
+ * @param {string} _name
8698
+ * @param {string} _default
8699
+ */
8700
+ const setExpandedBtnSiz = (_name, _default = C_FLG_OFF) => {
8701
+ const camelH = toCapitalize(_name);
8702
+ if (g_stateObj[_name] === _default) {
8703
+ $id(`lnk${camelH}Type`).display = C_DIS_NONE;
8704
+ $id(`lnk${camelH}`).left = wUnit(g_limitObj.setLblLeft);
8705
+ $id(`lnk${camelH}`).width = wUnit(g_limitObj.setLblWidth);
8706
+ } else {
8707
+ $id(`lnk${camelH}Type`).display = C_DIS_INHERIT;
8708
+ $id(`lnk${camelH}`).left = wUnit(g_limitObj.setLblLeftShort);
8709
+ $id(`lnk${camelH}`).width = wUnit(g_limitObj.setLblWidthShort);
8710
+ }
8711
+ };
8712
+
8713
+ /**
8714
+ * 拡張ボタンの作成
8715
+ * @param {string} _name
8716
+ * @returns {HTMLDivElement}
8717
+ */
8718
+ const createExpandedBtn = _name =>
8719
+ createCss2Button(`lnk${toCapitalize(_name)}Type`, getStgDetailName(g_stateObj[`${_name}Type`]),
8720
+ () => {
8721
+ setSetting(1, `${_name}Type`);
8722
+ createExpandedScView(_name);
8723
+ },
8724
+ Object.assign(g_lblPosObj.btnReverse, {
8725
+ cxtFunc: () => {
8726
+ setSetting(-1, `${_name}Type`);
8727
+ createExpandedScView(_name);
8728
+ },
8729
+ title: g_msgObj[`${_name}Type`] ?? ``,
8730
+ }), g_cssObj.button_Default, g_cssObj[`button_RevON`]);
8731
+
8732
+ /**
8733
+ * 拡張ボタンのショートカット表示
8734
+ * @param {string} _name
8735
+ */
8736
+ const createExpandedScView = _name =>
8737
+ createScText(document.getElementById(`lnk${toCapitalize(_name)}Type`), `${toCapitalize(_name)}Type`, {
8738
+ displayName: `exSetting`, targetLabel: `lnk${toCapitalize(_name)}Type`, x: -13
8739
+ });
8740
+
8741
+ createGeneralSetting(spriteList.playWindow, `playWindow`, {
8742
+ addRFunc: () => setExpandedBtnSiz(`playWindow`, `Default`),
8743
+ });
8744
+ spriteList.playWindow.appendChild(createExpandedBtn(`playWindow`));
8745
+ setExpandedBtnSiz(`playWindow`, `Default`);
8746
+ createExpandedScView(`playWindow`);
8747
+
8693
8748
  createGeneralSetting(spriteList.stepArea, `stepArea`);
8694
- createGeneralSetting(spriteList.frzReturn, `frzReturn`);
8749
+ createGeneralSetting(spriteList.frzReturn, `frzReturn`, {
8750
+ addRFunc: () => setExpandedBtnSiz(`frzReturn`),
8751
+ });
8752
+ spriteList.frzReturn.appendChild(createExpandedBtn(`frzReturn`));
8753
+ setExpandedBtnSiz(`frzReturn`);
8754
+ createExpandedScView(`frzReturn`);
8755
+
8695
8756
  createGeneralSetting(spriteList.shaking, `shaking`);
8696
8757
  createGeneralSetting(spriteList.effect, `effect`, {
8697
8758
  addRFunc: () => {
@@ -11692,7 +11753,7 @@ const getArrowSettings = () => {
11692
11753
 
11693
11754
  if (g_stateObj.playWindow.endsWith(`SideScroll`)) {
11694
11755
  if (g_stateObj.rotateEnabled) {
11695
- const sign = g_stateObj.playWindow === `SideScroll` ? 1 : -1;
11756
+ const sign = g_stateObj.playWindowType === `Reverse` ? -1 : 1;
11696
11757
  changeStepRtn(`stepRtn`, 90 * sign);
11697
11758
  changeStepRtn(`stepHitRtn`, 90 * sign);
11698
11759
  changeStepRtn(`arrowRtn`, 90 * sign);
@@ -11895,6 +11956,11 @@ const getArrowSettings = () => {
11895
11956
 
11896
11957
  // FrzReturnの初期化
11897
11958
  g_workObj.frzReturnFlg = false;
11959
+ g_workObj.frzReturnSeq = g_frzReturnSeqFunc.get(g_stateObj.frzReturnType)();
11960
+ if (g_workObj.frzReturnTimerId) {
11961
+ clearTimeout(g_workObj.frzReturnTimerId);
11962
+ g_workObj.frzReturnTimerId = null;
11963
+ }
11898
11964
 
11899
11965
  // AutoRetryの初期化
11900
11966
  g_workObj.autoRetryFlg = false;
@@ -11967,9 +12033,11 @@ const getArrowSettings = () => {
11967
12033
  }
11968
12034
  }
11969
12035
 
11970
- // Shaking: Drunkでの画面揺れ設定 (X方向、Y方向)
12036
+ // Shaking: Drunkでの画面揺れ設定 (X方向、Y方向、移動軸条件、回転軸条件)
11971
12037
  g_workObj.drunkXFlg = false;
11972
12038
  g_workObj.drunkYFlg = false;
12039
+ g_workObj.drunkAxisFlg = false;
12040
+ g_workObj.drunkRotateFlg = false;
11973
12041
 
11974
12042
  // AppearanceFilterの可視範囲設定
11975
12043
  g_workObj.aprFilterCnt = 0;
@@ -13253,7 +13321,9 @@ const mainInit = () => {
13253
13321
  }
13254
13322
 
13255
13323
  // 画面揺れの設定
13256
- g_shakingFunc.get(g_stateObj.shaking)();
13324
+ if (g_scoreObj.baseFrame % 2 === 0) {
13325
+ g_shakingFunc.get(g_stateObj.shaking)();
13326
+ }
13257
13327
 
13258
13328
  // ユーザカスタムイベント(フレーム毎)
13259
13329
  g_customJsObj.mainEnterFrame.forEach(func => func());
@@ -13706,52 +13776,81 @@ const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) =
13706
13776
  };
13707
13777
 
13708
13778
  /**
13709
- * FrzReturnの追加処理
13710
- * @param {number} _rad 回転角度
13711
- * @param {number[]} _axis 回転軸
13779
+ * FrzReturnの開始条件
13712
13780
  */
13713
- const changeReturn = (_rad, _axis) => {
13781
+ const startFrzReturn = () => {
13782
+ if (!g_workObj.frzReturnFlg) {
13783
+ if (g_workObj.frzReturnTimerId) {
13784
+ clearTimeout(g_workObj.frzReturnTimerId);
13785
+ g_workObj.frzReturnTimerId = null;
13786
+ }
13787
+ const seqLen = g_workObj.frzReturnSeq.length;
13788
+ executeFrzReturn(
13789
+ g_workObj.frzReturnSeq[seqLen > 1 ? Math.floor(Math.random() * seqLen) : 0], 0,
13790
+ g_frzReturnFunc.get(g_stateObj.frzReturn)()
13791
+ );
13792
+ }
13793
+ };
13794
+
13795
+ /**
13796
+ * FrzReturnの実行
13797
+ * @param {number[]} _seq FrzReturnの移動配列
13798
+ * @param {number} _idx FrzReturnの移動配列のインディクス(transformの決定に利用)
13799
+ * @param {number[]} _axis 回転軸(X, Y, X-Yなど)
13800
+ */
13801
+ const executeFrzReturn = (_seq, _idx, _axis) => {
13802
+
13803
+ if (!_seq || _idx >= _seq.length) {
13804
+ // 移動終了時
13805
+ delTransform(`mainSprite`, `frzReturn`);
13806
+ g_workObj.frzReturnFlg = false;
13807
+ g_workObj.frzReturnTimerId = null;
13808
+ return;
13809
+ }
13810
+ const sprite = document.getElementById(`mainSprite`);
13811
+ if (sprite === null) {
13812
+ // 画面がプレイ画面から移動した場合
13813
+ g_workObj.frzReturnFlg = false;
13814
+ g_workObj.frzReturnTimerId = null;
13815
+ return;
13816
+ }
13817
+
13714
13818
  g_workObj.frzReturnFlg = true;
13819
+ const _rad = _seq[_idx];
13820
+
13715
13821
  let _transform = `rotate${_axis[0]}(${_rad}deg)`;
13716
13822
  if (_axis[1] !== undefined) {
13717
13823
  _transform += ` rotate${_axis[1]}(${_rad}deg)`;
13718
13824
  }
13719
- const sprite = document.getElementById(`mainSprite`);
13720
- if (sprite !== null) {
13721
- sprite.style.transformStyle = `preserve-3d`;
13722
- const rad360 = _rad % 360;
13723
13825
 
13724
- let isBack = false;
13826
+ sprite.style.transformStyle = `preserve-3d`;
13827
+ const rad360 = ((_rad % 360) + 360) % 360;
13725
13828
 
13726
- // 単軸回転
13727
- if (_axis.length === 1) {
13728
- const axis = _axis[0];
13729
- if (axis === 'Y' || axis === 'X') {
13730
- isBack = rad360 > 90 && rad360 < 270;
13731
- }
13732
- // Z軸は平面回転なので「裏側」は存在しない
13733
- }
13829
+ let isBack = false;
13734
13830
 
13735
- // 2軸回転(XZ / XY / YZ)
13736
- if (_axis.length === 2) {
13737
- // 2軸回転は「どちらかの軸が裏側なら裏側」とみなす
13738
- const [a1, a2] = _axis;
13739
- const back1 = (a1 === 'Y' || a1 === 'X') && (rad360 > 90 && rad360 < 270);
13740
- const back2 = (a2 === 'Y' || a2 === 'X') && (rad360 > 90 && rad360 < 270);
13741
- isBack = back1 || back2;
13831
+ // 単軸回転
13832
+ if (_axis.length === 1) {
13833
+ const axis = _axis[0];
13834
+ if (axis === 'Y' || axis === 'X') {
13835
+ isBack = rad360 > 90 && rad360 < 270;
13742
13836
  }
13743
- sprite.style.opacity = isBack ? 0.7 : 1;
13744
-
13745
- addTransform(`mainSprite`, `frzReturn`, _transform, g_transPriority.frzReturn);
13837
+ // Z軸は平面回転なので「裏側」は存在しない
13838
+ }
13746
13839
 
13747
- if (_rad < 360 && g_workObj.frzReturnFlg) {
13748
- setTimeout(() => changeReturn(_rad + 4, _axis), 20);
13749
- } else {
13750
- delTransform(`mainSprite`, `frzReturn`);
13751
- g_workObj.frzReturnFlg = false;
13752
- }
13840
+ // 2軸回転(XZ / XY / YZ)
13841
+ if (_axis.length === 2) {
13842
+ // 2軸回転は「どちらかの軸が裏側なら裏側」とみなす
13843
+ const [a1, a2] = _axis;
13844
+ const back1 = (a1 === 'Y' || a1 === 'X') && (rad360 > 90 && rad360 < 270);
13845
+ const back2 = (a2 === 'Y' || a2 === 'X') && (rad360 > 90 && rad360 < 270);
13846
+ isBack = back1 || back2;
13753
13847
  }
13754
- }
13848
+ sprite.style.opacity = isBack ? 0.7 : 1;
13849
+
13850
+ addTransform(`mainSprite`, `frzReturn`, _transform, g_transPriority.frzReturn);
13851
+
13852
+ g_workObj.frzReturnTimerId = setTimeout(() => executeFrzReturn(_seq, _idx + 1, _axis), 20);
13853
+ };
13755
13854
 
13756
13855
  /**
13757
13856
  * AutoRetryの設定
@@ -13943,9 +14042,7 @@ const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
13943
14042
 
13944
14043
  // FrzReturnの設定
13945
14044
  if (g_stateObj.frzReturn !== C_FLG_OFF) {
13946
- if (!g_workObj.frzReturnFlg) {
13947
- changeReturn(4, g_frzReturnFunc.get(g_stateObj.frzReturn)());
13948
- }
14045
+ startFrzReturn();
13949
14046
  }
13950
14047
  g_customJsObj[`judg_${_name}Hit`].forEach(func => func(_difFrame));
13951
14048
  };
@@ -13968,9 +14065,7 @@ const changeFailedFrz = (_j, _k) => {
13968
14065
 
13969
14066
  // FrzReturnの設定
13970
14067
  if (g_stateObj.frzReturn !== C_FLG_OFF) {
13971
- if (!g_workObj.frzReturnFlg) {
13972
- changeReturn(4, g_frzReturnFunc.get(g_stateObj.frzReturn)());
13973
- }
14068
+ startFrzReturn();
13974
14069
  }
13975
14070
  };
13976
14071
 
@@ -14189,10 +14284,8 @@ const judgeRecovery = (_name, _difFrame) => {
14189
14284
  lifeRecovery();
14190
14285
  finishViewing();
14191
14286
 
14192
- if (g_stateObj.freezeReturn !== C_FLG_OFF) {
14193
- if ((g_resultObj.ii + g_resultObj.shakin) % 100 === 0 && !g_workObj.frzReturnFlg) {
14194
- changeReturn(1, g_frzReturnFunc.get(g_stateObj.frzReturn)());
14195
- }
14287
+ if (g_stateObj.frzReturn !== C_FLG_OFF && (g_resultObj.ii + g_resultObj.shakin) % 100 === 0) {
14288
+ startFrzReturn();
14196
14289
  }
14197
14290
  if (_name === `shakin`) {
14198
14291
  quickRetry(`Shakin(Great)`);
@@ -15167,14 +15260,16 @@ const getSelectedSettingList = (_shuffleName) => {
15167
15260
  withOptions(g_stateObj.appearance, `Visible`) +
15168
15261
  ((g_appearanceRanges.includes(g_stateObj.appearance) && g_stateObj.filterLock === C_FLG_ON) ? `(${g_hidSudObj.filterPos}%)` : ``),
15169
15262
  withOptions(g_stateObj.gauge, g_settings.gauges[0]),
15170
- withOptions(g_stateObj.playWindow, `Default`),
15263
+ withOptions(g_stateObj.playWindow, `Default`,
15264
+ `${getStgDetailName(g_stateObj.playWindowType === `Reverse` ? `R-` : ``)}${getStgDetailName(g_stateObj.playWindow)}`),
15171
15265
  withOptions(g_stateObj.stepArea, `Default`),
15172
- withOptions(g_stateObj.frzReturn, C_FLG_OFF, `FR:${g_stateObj.frzReturn}`),
15266
+ withOptions(g_stateObj.frzReturn, C_FLG_OFF,
15267
+ `FR:${getStgDetailName(g_stateObj.frzReturn)}(${getStgDetailName(g_stateObj.frzReturnType)})`),
15173
15268
  withOptions(g_stateObj.shaking, C_FLG_OFF),
15174
15269
  withOptions(g_stateObj.effect, C_FLG_OFF),
15175
- withOptions(g_stateObj.camoufrage, C_FLG_OFF, `Cmf:${g_stateObj.camoufrage}`),
15176
- withOptions(g_stateObj.swapping, C_FLG_OFF, `Swap:${g_stateObj.swapping}`),
15177
- withOptions(g_stateObj.judgRange, `Normal`, `Judg:${g_stateObj.judgRange}`),
15270
+ withOptions(g_stateObj.camoufrage, C_FLG_OFF, `Cmf:${getStgDetailName(g_stateObj.camoufrage)}`),
15271
+ withOptions(g_stateObj.swapping, C_FLG_OFF, `Swap:${getStgDetailName(g_stateObj.swapping)}`),
15272
+ withOptions(g_stateObj.judgRange, `Normal`, `Judg:${getStgDetailName(g_stateObj.judgRange)}`),
15178
15273
  ].filter(value => value !== ``).join(`, `);
15179
15274
 
15180
15275
  // Display設定の組み立て処理 (Ex: Step : FlatBar, Judge, Life : OFF)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/03/01 (v45.3.0)
8
+ * Revised : 2026/03/04 (v45.4.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -51,6 +51,9 @@ const g_limitObj = {
51
51
  setLblHeight: 22,
52
52
  setLblSiz: 17,
53
53
 
54
+ setLblLeftShort: 250,
55
+ setLblWidthShort: 120,
56
+
54
57
  // 設定画面の左右移動ボタンの幅、フォントサイズ
55
58
  setMiniWidth: 40,
56
59
  setMiniSiz: 18,
@@ -1164,8 +1167,10 @@ const g_stateObj = {
1164
1167
  opacity: 100,
1165
1168
 
1166
1169
  playWindow: `Default`,
1170
+ playWindowType: `---`,
1167
1171
  stepArea: `Default`,
1168
1172
  frzReturn: C_FLG_OFF,
1173
+ frzReturnType: `360deg`,
1169
1174
  shaking: C_FLG_OFF,
1170
1175
  effect: C_FLG_OFF,
1171
1176
  camoufrage: C_FLG_OFF,
@@ -1330,9 +1335,12 @@ const g_settings = {
1330
1335
  special: 0,
1331
1336
  },
1332
1337
 
1333
- playWindows: [`Default`, `Stairs`, `R-Stairs`, `Slope`, `R-Slope`, `Distorted`, `R-Distorted`, `SideScroll`, `R-SideScroll`],
1338
+ playWindows: [`Default`, `Stairs`, `Slope`, `Distorted`, `SideScroll`],
1334
1339
  playWindowNum: 0,
1335
1340
 
1341
+ playWindowTypes: [`---`, `Reverse`],
1342
+ playWindowTypeNum: 0,
1343
+
1336
1344
  stepAreas: [`Default`, `Halfway`, `2Step`, `Mismatched`, `R-Mismatched`, `X-Flower`, `Alt-Crossing`],
1337
1345
  stepAreaLayers: [`2Step`, `Mismatched`, `R-Mismatched`, `X-Flower`, `Alt-Crossing`],
1338
1346
  stepAreaNum: 0,
@@ -1340,7 +1348,10 @@ const g_settings = {
1340
1348
  frzReturns: [C_FLG_OFF, `X-Axis`, `Y-Axis`, `Z-Axis`, `Random`, `XY-Axis`, `XZ-Axis`, `YZ-Axis`, `Random+`],
1341
1349
  frzReturnNum: 0,
1342
1350
 
1343
- shakings: [C_FLG_OFF, `Horizontal`, `Vertical`, `X-Horizontal`, `X-Vertical`, `Drunk`, `S-Drunk`],
1351
+ frzReturnTypes: [`360deg`, `120deg`, `60deg`, `±360deg`, `±120deg`, `Pendulum`],
1352
+ frzReturnTypeNum: 0,
1353
+
1354
+ shakings: [C_FLG_OFF, `Horizontal`, `Vertical`, `X-Horizontal`, `X-Vertical`, `Drunk`, `S-Drunk`, `H-Drunk`],
1344
1355
  shakingNum: 0,
1345
1356
 
1346
1357
  effects: [C_FLG_OFF, `Dizzy`, `Spin`, `Wave`, `Storm`, `Blinking`, `Squids`],
@@ -1394,7 +1405,9 @@ const g_transPriority = {
1394
1405
  playWindow: 100,
1395
1406
  stepArea: 110,
1396
1407
  frzReturn: 120,
1397
- shaking: 130,
1408
+ shakingR: 130,
1409
+ shakingX: 140,
1410
+ shakingY: 150,
1398
1411
  scale: 200,
1399
1412
  };
1400
1413
 
@@ -1589,6 +1602,7 @@ const resetXY = () => {
1589
1602
 
1590
1603
  /**
1591
1604
  * データ消去用管理関数
1605
+ * - 対応するキー名: g_settings.dataMgtNum で定義したキー
1592
1606
  */
1593
1607
  const g_resetFunc = new Map([
1594
1608
  ['highscores', () => {
@@ -1638,6 +1652,7 @@ const g_storageFunc = new Map([
1638
1652
 
1639
1653
  /**
1640
1654
  * シャッフル適用関数
1655
+ * - 対応するキー名: g_settings.shuffles
1641
1656
  * @param {number} keyNum
1642
1657
  * @param {array} shuffleGroup
1643
1658
  */
@@ -1662,6 +1677,7 @@ const g_shuffleFunc = new Map([
1662
1677
 
1663
1678
  /**
1664
1679
  * モーション適用関数
1680
+ * - 対応するキー名: g_settings.motions
1665
1681
  * @param {array} frms フレーム別の速度設定用配列。配列の15がステップゾーン上、0~14は矢印の枠外管理用
1666
1682
  */
1667
1683
  const g_motionFunc = new Map([
@@ -1676,6 +1692,7 @@ const g_motionFunc = new Map([
1676
1692
 
1677
1693
  /**
1678
1694
  * モーション適用中のアルファ値制御関数
1695
+ * - 対応するキー名: g_settings.motions
1679
1696
  * @param {object} _obj 対象オブジェクト
1680
1697
  * @param {object} _property 対象オブジェクトのプロパティ情報 (g_attrObj[オブジェクト名])
1681
1698
  */
@@ -1700,24 +1717,23 @@ const motionAlphaToggle = (_obj, _property) => {
1700
1717
 
1701
1718
  /**
1702
1719
  * PlayWindow適用関数
1720
+ * - 対応するキー名: g_settings.playWindows
1703
1721
  */
1704
- const g_changeStairs = (_rad) => `rotate(${_rad}deg)`;
1705
- const g_changeSkew = (_rad) => `Skew(${_rad}deg, ${_rad}deg) scaleY(0.9)`;
1722
+ const g_playWindowDir = () => g_stateObj.playWindowType === `Reverse` ? 1 : -1;
1723
+ const g_changeStairs = (_rad) => `rotate(${_rad * g_playWindowDir()}deg)`;
1724
+ const g_changeSkew = (_rad) => `Skew(${_rad * g_playWindowDir()}deg, ${_rad * g_playWindowDir()}deg) scaleY(0.9)`;
1706
1725
 
1707
1726
  const g_playWindowFunc = new Map([
1708
1727
  ['Default', () => ``],
1709
- ['Stairs', () => g_changeStairs(-8)],
1710
- ['R-Stairs', () => g_changeStairs(8)],
1711
- ['Slope', () => g_changeStairs(-g_slopeAngle())],
1712
- ['R-Slope', () => g_changeStairs(g_slopeAngle())],
1713
- ['Distorted', () => g_changeSkew(-15)],
1714
- ['R-Distorted', () => g_changeSkew(15)],
1715
- ['SideScroll', () => g_changeStairs(-90)],
1716
- ['R-SideScroll', () => g_changeStairs(90)],
1728
+ ['Stairs', () => g_changeStairs(8)],
1729
+ ['Slope', () => g_changeStairs(g_slopeAngle())],
1730
+ ['Distorted', () => g_changeSkew(15)],
1731
+ ['SideScroll', () => g_changeStairs(90)],
1717
1732
  ]);
1718
1733
 
1719
1734
  /**
1720
1735
  * StepArea適用関数
1736
+ * - 対応するキー名: g_settings.stepAreas
1721
1737
  */
1722
1738
  const g_arrowGroupSprite = [`stepSprite`, `arrowSprite`, `frzHitSprite`];
1723
1739
  const halfwayOffset = _j => (_j % 2 === 0 ? 1 : -1) * (g_headerObj.playingHeight / 2 - g_posObj.stepY + (g_posObj.stepYR - C_ARW_WIDTH) / 2);
@@ -1777,50 +1793,87 @@ const g_stepAreaFunc = new Map([
1777
1793
 
1778
1794
  /**
1779
1795
  * Shaking適用関数
1796
+ * - 対応するキー名: g_settings.shakings
1797
+ * - Drunk系は補正座標が0になったときに判定を行い、移動方向や回転を切り替える
1780
1798
  */
1781
1799
  const getShakingDist = () => (Math.abs((g_scoreObj.baseFrame / 2) % 100 - 50) - 25);
1782
1800
  const g_shakingFunc = new Map([
1783
1801
  ['OFF', () => true],
1784
- ['Horizontal', () => addTransform(`mainSprite`, `shakingX`, `translateX(${getShakingDist()}px)`, g_transPriority.shaking)],
1785
- ['Vertical', () => addTransform(`mainSprite`, `shakingY`, `translateY(${getShakingDist() / 2}px)`, g_transPriority.shaking)],
1786
- ['X-Horizontal', () => {
1802
+ ['Horizontal', (_multi = 1) => {
1803
+ addTransform(`mainSprite`, `shakingX_base`, `translateX(${getShakingDist() * _multi}px)`, g_transPriority.shakingX)
1804
+ }],
1805
+ ['Vertical', (_multi = 1) => {
1806
+ addTransform(`mainSprite`, `shakingY_base`, `translateY(${getShakingDist() / 2 * _multi}px)`, g_transPriority.shakingY)
1807
+ }],
1808
+ ['X-Horizontal', (_multi = 1) => {
1787
1809
  for (let j = 0; j < g_stateObj.layerNum; j++) {
1788
- addTransform(`mainSprite${j}`, `shakingX`, `translateX(${getDirFromLayer(j) * (4 / 3) * getShakingDist()}px)`, g_transPriority.shaking);
1810
+ addTransform(`mainSprite${j}`, `shakingX_layer`, `translateX(${getDirFromLayer(j) * (4 / 3) * getShakingDist() * _multi}px)`, g_transPriority.shakingX);
1789
1811
  }
1790
1812
  }],
1791
- ['X-Vertical', () => {
1813
+ ['X-Vertical', (_multi = 1) => {
1792
1814
  for (let j = 0; j < g_stateObj.layerNum; j++) {
1793
- addTransform(`mainSprite${j}`, `shakingY`, `translateY(${getDirFromLayer(j) * getShakingDist()}px)`, g_transPriority.shaking);
1815
+ addTransform(`mainSprite${j}`, `shakingY_layer`, `translateY(${getDirFromLayer(j) * getShakingDist() * _multi}px)`, g_transPriority.shakingY);
1794
1816
  }
1795
1817
  }],
1796
- ['Drunk', () => {
1797
- // Drunkは揺れの軸が途中で変わるため、基準位置取得のためにmainSpriteのみaddX, addYを使用
1798
- const shakeX = g_posXs.mainSprite?.get(`shakingX`) ?? 0;
1799
- const shakeY = g_posYs.mainSprite?.get(`shakingY`) ?? 0;
1800
- if (shakeX === 0 && shakeY === 0) {
1818
+ ['Drunk', (_multi = 1) => {
1819
+ const dist = getShakingDist();
1820
+ if (g_workObj.drunkXFlg) {
1821
+ const deltaX = dist * _multi;
1822
+ addTransform(`mainSprite`, `shakingX_drunk`, `translateX(${deltaX}px)`, g_transPriority.shakingX);
1823
+ addTransform(`infoSprite`, `shakingX_drunk`, `translateX(${deltaX}px)`, g_transPriority.shakingX);
1824
+ addTransform(`judgeSprite`, `shakingX_drunk`, `translateX(${deltaX}px)`, g_transPriority.shakingX);
1825
+ }
1826
+ if (g_workObj.drunkYFlg) {
1827
+ const deltaY = dist / 2 * _multi;
1828
+ addTransform(`mainSprite`, `shakingY_drunk`, `translateY(${deltaY}px)`, g_transPriority.shakingY);
1829
+ addTransform(`infoSprite`, `shakingY_drunk`, `translateY(${deltaY}px)`, g_transPriority.shakingY);
1830
+ addTransform(`judgeSprite`, `shakingY_drunk`, `translateY(${deltaY}px)`, g_transPriority.shakingY);
1831
+ }
1832
+ // 補正がゼロになったときに軸の移動方法をランダムで決定
1833
+ if (dist === 0) {
1801
1834
  g_workObj.drunkXFlg = Math.random() < 0.5;
1802
1835
  g_workObj.drunkYFlg = Math.random() < 0.5;
1836
+
1837
+ if (!g_workObj.drunkXFlg && !g_workObj.drunkYFlg) {
1838
+ g_workObj.drunkYFlg = true;
1839
+ }
1803
1840
  }
1841
+ }],
1842
+ ['S-Drunk', () => {
1843
+ // Drunkとはあえて異なる軸の補正を掛ける
1804
1844
  if (g_workObj.drunkXFlg) {
1805
- const deltaX = getShakingDist();
1806
- addX(`mainSprite`, `shakingX`, deltaX, { priority: g_transPriority.shaking });
1807
- addTransform(`infoSprite`, `shakingX`, `translateX(${deltaX}px)`, g_transPriority.shaking);
1808
- addTransform(`judgeSprite`, `shakingX`, `translateX(${deltaX}px)`, g_transPriority.shaking);
1845
+ g_shakingFunc.get(`X-Vertical`)(2);
1809
1846
  }
1810
1847
  if (g_workObj.drunkYFlg) {
1811
- const deltaY = getShakingDist() / 2;
1812
- addY(`mainSprite`, `shakingY`, deltaY, { priority: g_transPriority.shaking });
1813
- addTransform(`infoSprite`, `shakingY`, `translateY(${deltaY}px)`, g_transPriority.shaking);
1814
- addTransform(`judgeSprite`, `shakingY`, `translateY(${deltaY}px)`, g_transPriority.shaking);
1848
+ g_shakingFunc.get(`X-Horizontal`)(2);
1815
1849
  }
1850
+ g_shakingFunc.get(`Drunk`)(2);
1816
1851
  }],
1817
- ['S-Drunk', () => {
1818
- g_shakingFunc.get(`Drunk`)();
1852
+ ['H-Drunk', () => {
1853
+ const dist = getShakingDist();
1854
+
1855
+ // X方向、Y方向の移動方法。S-Drunkと同様、Drunkとあえて異なる軸の補正を掛ける
1856
+ // 本来は適用するtransform先が異なるためdelTransformを行う必要があるが、補正ゼロ時に切り替えるため問題なし
1819
1857
  if (g_workObj.drunkXFlg) {
1820
- g_shakingFunc.get(`X-Vertical`)();
1858
+ g_shakingFunc.get((g_workObj.drunkAxisFlg ? `X-` : ``) + `Vertical`)(3);
1821
1859
  }
1822
1860
  if (g_workObj.drunkYFlg) {
1823
- g_shakingFunc.get(`X-Horizontal`)();
1861
+ g_shakingFunc.get((g_workObj.drunkAxisFlg ? `X-` : ``) + `Horizontal`)(3);
1862
+ }
1863
+ // 軸回転の設定(判定・メイン部分は常時回転、メイン内の各層は条件式により回転するかどうかを決定)
1864
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1865
+ g_workObj.drunkRotateFlg
1866
+ ? addTransform(`mainSprite${j}`, `shakingR_layer`, `rotate(${getDirFromLayer(j) * dist}deg)`, g_transPriority.shakingR)
1867
+ : delTransform(`mainSprite${j}`, `shakingR_layer`);
1868
+ }
1869
+ addTransform(`mainSprite`, `shakingR_base`, `rotate(${dist / 2}deg)`, g_transPriority.shakingR);
1870
+ addTransform(`infoSprite`, `shakingR_base`, `rotate(${dist / 2}deg)`, g_transPriority.shakingR);
1871
+
1872
+ g_shakingFunc.get(`Drunk`)(2);
1873
+ if (dist === 0) {
1874
+ // 補正がゼロになったときに軸の移動方法と回転方法をランダムで決定
1875
+ g_workObj.drunkAxisFlg = Math.random() >= 0.33;
1876
+ g_workObj.drunkRotateFlg = Math.random() >= 0.66;
1824
1877
  }
1825
1878
  }],
1826
1879
  ]);
@@ -1846,6 +1899,7 @@ const g_getSecondaryAxis = (_primaryAxis) => {
1846
1899
 
1847
1900
  /**
1848
1901
  * FrzReturn適用関数
1902
+ * - 対応するキー名: g_settings.frzReturns
1849
1903
  */
1850
1904
  const g_frzReturnFunc = new Map([
1851
1905
  ['OFF', () => true],
@@ -1863,6 +1917,91 @@ const g_frzReturnFunc = new Map([
1863
1917
  }],
1864
1918
  ]);
1865
1919
 
1920
+ /**
1921
+ * FrzReturnの種別ごとの移動配列を作成
1922
+ * - 対応するキー名: g_settings.frzReturnTypes
1923
+ * - キー: FrzReturn種別 (例: "60deg", "±120deg")
1924
+ * - 値: 移動配列を返す関数 (オプション引数 _dir で方向指定、デフォルト 1)
1925
+ * @type {Map<string, (dir?: number) => number[][]>}
1926
+ */
1927
+ const g_frzReturnSeqFunc = new Map([
1928
+ [`60deg`, (_dir = 1) => {
1929
+ const steps = 25;
1930
+ return [
1931
+ [
1932
+ ...makeEaseSequence(0, 60 * _dir, steps, easeInOutQuad),
1933
+ ...makeEaseSequence(60 * _dir, 0, steps, easeInOutQuad),
1934
+ ],
1935
+ ];
1936
+ }],
1937
+ [`120deg`, (_dir = 1) => {
1938
+ const steps = 40;
1939
+ return [
1940
+ [
1941
+ ...makeEaseSequence(0, 120 * _dir, steps, easeInOutQuad),
1942
+ ...makeEaseSequence(120 * _dir, 0, steps, easeInOutQuad),
1943
+ ],
1944
+ ];
1945
+ }],
1946
+ [`360deg`, (_dir = 1) => {
1947
+ return [
1948
+ Array.from({ length: 91 }, (_, i) => i * 4 * _dir)
1949
+ ];
1950
+ }],
1951
+ [`Pendulum`, (_dir = 1) => {
1952
+ const steps = 25;
1953
+ return [
1954
+ [
1955
+ ...makeEaseSequence(0, -60 * _dir, steps, easeInOutQuad),
1956
+ ...makeEaseSequence(-60 * _dir, 60 * _dir, steps * 2, easeInOutQuad),
1957
+ ...makeEaseSequence(60 * _dir, 0, steps, easeInOutQuad),
1958
+ ],
1959
+ [
1960
+ ...makeEaseSequence(0, -70 * _dir, steps, easeInOutQuad),
1961
+ ...makeEaseSequence(-70 * _dir, 70 * _dir, steps * 2, easeInOutQuad),
1962
+ ...makeEaseSequence(70 * _dir, 0, steps, easeInOutQuad),
1963
+ ],
1964
+ [
1965
+ ...makeEaseSequence(0, -80 * _dir, steps, easeInOutQuad),
1966
+ ...makeEaseSequence(-80 * _dir, 80 * _dir, steps * 2, easeInOutQuad),
1967
+ ...makeEaseSequence(80 * _dir, 0, steps, easeInOutQuad),
1968
+ ],
1969
+ ];
1970
+ }],
1971
+ [`±120deg`, () => g_frzReturnSeqFunc.get(`120deg`)().concat(g_frzReturnSeqFunc.get(`120deg`)(-1))],
1972
+ [`±360deg`, () => g_frzReturnSeqFunc.get(`360deg`)().concat(g_frzReturnSeqFunc.get(`360deg`)(-1))],
1973
+ ]);
1974
+
1975
+ /**
1976
+ * イージング作成関数
1977
+ * @param {(t: number) => number} _t
1978
+ * @returns {number}
1979
+ */
1980
+ const easeInOutQuad = _t => _t < 0.5
1981
+ ? 2 * _t * _t
1982
+ : 1 - Math.pow(-2 * _t + 2, 2) / 2;
1983
+
1984
+ /**
1985
+ * イージング用の移動配列の作成
1986
+ * @param {number} _start
1987
+ * @param {number} _end
1988
+ * @param {number} _steps
1989
+ * @param {number} _easing
1990
+ * @returns {number[]}
1991
+ */
1992
+ const makeEaseSequence = (_start, _end, _steps, _easing) => {
1993
+ if (_steps <= 0) {
1994
+ return [_start];
1995
+ }
1996
+ const seq = [];
1997
+ for (let i = 0; i <= _steps; i++) {
1998
+ const t = i / _steps;
1999
+ const e = _easing(t);
2000
+ seq.push(_start + (_end - _start) * e);
2001
+ }
2002
+ return seq;
2003
+ };
2004
+
1866
2005
  /**
1867
2006
  * Effect適用関数
1868
2007
  * @param {string} _arrowEffect
@@ -1881,6 +2020,10 @@ const g_setEffect = (_arrowEffect, _frzEffect = ``, _frzArrowEffect = _arrowEffe
1881
2020
  }
1882
2021
  }
1883
2022
  };
2023
+ /**
2024
+ * Effect定義関数
2025
+ * - 対応するキー名: g_settings.effects
2026
+ */
1884
2027
  const g_effectFunc = new Map([
1885
2028
  ['OFF', () => true],
1886
2029
  ['Dizzy', () => g_setEffect(`effects-dizzy`)],
@@ -2361,6 +2504,7 @@ const g_shortcutObj = {
2361
2504
  Numpad0: { id: `btnPrecond9` },
2362
2505
  Escape: { id: `btnBack` },
2363
2506
  ShiftLeft_Tab: { id: `btnBack` },
2507
+ ShiftRight_Tab: { id: `btnBack` },
2364
2508
  },
2365
2509
  option: {
2366
2510
  ShiftLeft_KeyD: { id: `lnkDifficultyL` },
@@ -2610,18 +2754,29 @@ const g_shortcutObj = {
2610
2754
  },
2611
2755
  exSetting: {
2612
2756
  ShiftLeft_KeyP: { id: `lnkPlayWindowL` },
2757
+ ShiftRight_KeyP: { id: `lnkPlayWindowL` },
2613
2758
  ShiftLeft_KeyS: { id: `lnkStepAreaL` },
2759
+ ShiftRight_KeyS: { id: `lnkStepAreaL` },
2614
2760
  ShiftLeft_KeyF: { id: `lnkFrzReturnL` },
2761
+ ShiftRight_KeyF: { id: `lnkFrzReturnL` },
2615
2762
  ShiftLeft_KeyH: { id: `lnkShakingL` },
2763
+ ShiftRight_KeyH: { id: `lnkShakingL` },
2616
2764
  ShiftLeft_KeyE: { id: `lnkEffectL` },
2765
+ ShiftRight_KeyE: { id: `lnkEffectL` },
2617
2766
  ShiftLeft_KeyC: { id: `lnkCamoufrageL` },
2767
+ ShiftRight_KeyC: { id: `lnkCamoufrageL` },
2618
2768
  ShiftLeft_KeyW: { id: `lnkSwappingL` },
2769
+ ShiftRight_KeyW: { id: `lnkSwappingL` },
2619
2770
  ShiftLeft_KeyJ: { id: `lnkJudgRangeL` },
2771
+ ShiftRight_KeyJ: { id: `lnkJudgRangeL` },
2620
2772
  ShiftLeft_KeyA: { id: `lnkAutoRetryL` },
2773
+ ShiftRight_KeyA: { id: `lnkAutoRetryL` },
2621
2774
 
2622
2775
  KeyP: { id: `lnkPlayWindowR` },
2776
+ KeyR: { id: `lnkPlayWindowType` },
2623
2777
  KeyS: { id: `lnkStepAreaR` },
2624
2778
  KeyF: { id: `lnkFrzReturnR` },
2779
+ KeyD: { id: `lnkFrzReturnType` },
2625
2780
  KeyH: { id: `lnkShakingR` },
2626
2781
  KeyE: { id: `lnkEffectR` },
2627
2782
  KeyC: { id: `lnkCamoufrageR` },
@@ -3799,9 +3954,10 @@ const g_dataMinObj = {
3799
3954
  */
3800
3955
  const g_dataSetObj = {
3801
3956
  2: [`speedData`, `boostData`],
3802
- 4: [`colorData`, `arrowCssMotionData`, `frzCssMotionData`,
3803
- `dummyArrowCssMotionData`, `dummyFrzCssMotionData`],
3957
+ 4: [`colorData`],
3804
3958
  5: [`ncolorData`, `scrollchData`],
3959
+ 6: [`arrowCssMotionData`, `frzCssMotionData`,
3960
+ `dummyArrowCssMotionData`, `dummyFrzCssMotionData`],
3805
3961
  }
3806
3962
 
3807
3963
  const g_dfColorObj = {
@@ -4197,6 +4353,7 @@ const g_lblNameObj = {
4197
4353
  'u_Asymmetry': `Asymmetry`,
4198
4354
  'u_Flat': `Flat`,
4199
4355
  'u_R-': `R-`,
4356
+ 'u_---': `---`,
4200
4357
  'u_Reverse': `Reverse`,
4201
4358
 
4202
4359
  'u_Mirror': `Mirror`,
@@ -4237,13 +4394,9 @@ const g_lblNameObj = {
4237
4394
  'u_Hid&Sud+': `Hid&Sud+`,
4238
4395
 
4239
4396
  'u_Stairs': `Stairs`,
4240
- 'u_R-Stairs': `R-Stairs`,
4241
4397
  'u_Slope': `Slope`,
4242
- 'u_R-Slope': `R-Slope`,
4243
4398
  'u_Distorted': `Distorted`,
4244
- 'u_R-Distorted': `R-Distorted`,
4245
4399
  'u_SideScroll': `SideScroll`,
4246
- 'u_R-SideScroll': `R-SideScroll`,
4247
4400
 
4248
4401
  'u_Halfway': `Halfway`,
4249
4402
  'u_2Step': `2Step`,
@@ -4265,6 +4418,7 @@ const g_lblNameObj = {
4265
4418
  'u_X-Vertical': `X-Vertical`,
4266
4419
  'u_Drunk': `Drunk`,
4267
4420
  'u_S-Drunk': `S-Drunk`,
4421
+ 'u_H-Drunk': `H-Drunk`,
4268
4422
 
4269
4423
  'u_Dizzy': `Dizzy`,
4270
4424
  'u_Spin': `Spin`,
@@ -4377,6 +4531,13 @@ const g_lang_lblNameObj = {
4377
4531
  s_printTitle: `Dancing☆Onigiri レベル計算ツール+++`,
4378
4532
  s_printHeader: `難易度\t同時\t縦連\t総数\t矢印\t氷矢印\tAPM\t時間`,
4379
4533
 
4534
+ 'u_60deg': `60°`,
4535
+ 'u_120deg': `120°`,
4536
+ 'u_360deg': `360°`,
4537
+ 'u_Pendulum': `Pendulum`,
4538
+ 'u_±120deg': `±120°`,
4539
+ 'u_±360deg': `±360°`,
4540
+
4380
4541
  j_ii: "(・∀・)イイ!!",
4381
4542
  j_shakin: "(`・ω・)シャキン",
4382
4543
  j_matari: "( ´∀`)マターリ",
@@ -4421,6 +4582,13 @@ const g_lang_lblNameObj = {
4421
4582
  s_printTitle: `Dancing☆Onigiri Level Calculator+++`,
4422
4583
  s_printHeader: `Level\tChords\tJack\tAll\tArrow\tFrz\tAPM\tTime`,
4423
4584
 
4585
+ 'u_60deg': `60deg`,
4586
+ 'u_120deg': `120deg`,
4587
+ 'u_360deg': `360deg`,
4588
+ 'u_Pendulum': `Pendulum`,
4589
+ 'u_±120deg': `±120deg`,
4590
+ 'u_±360deg': `±360deg`,
4591
+
4424
4592
  j_ii: ":D Perfect!!",
4425
4593
  j_shakin: ":) Great!",
4426
4594
  j_matari: ":| Good",
@@ -4508,13 +4676,16 @@ const g_lang_msgObj = {
4508
4676
 
4509
4677
  playWindow: `ステップゾーン及び矢印の位置を全体的に回転する等の設定です。\n[Stairs/Slope] ステップゾーンを階段状にします\n[Distorted] 画面を歪ませます\n` +
4510
4678
  `[SideScroll] 横スクロールモードになります`,
4679
+ playWindowType: `[Reverse] ステップゾーン及び矢印の位置について逆方向の回転が掛かります`,
4511
4680
  stepArea: `ステップゾーンの位置を変更します。\n[Halfway] ステップゾーンが中央に表示されます\n[2Step] ステップゾーンが2段に分かれて流れてきます\n` +
4512
4681
  `[Mismatched/R-Mismatched] スクロールの向きが上下で異なる方向に流れます\n` +
4513
4682
  `[X-Flower] レーンが花びらのように広がります\n[Alt-Crossing] レーンが交互に違う方向から流れます`,
4514
4683
  frzReturn: `フリーズアロー到達時及び矢印の回復判定が100の倍数に達するごとに、X/Y/Z軸のいずれかに回転します`,
4684
+ frzReturnType: `[360°/120°/60°] 指定の角度まで回転します\n[±360°/±120°] 360°/120°に加えて逆回転が掛かることがあります\n[Pendulum] 振り子のように左右に動きます`,
4515
4685
  shaking: `ステップゾーン及び矢印を揺らす設定です。\n[Horizontal] 横方向に揺らします\n[Vertical] 縦方向に揺らします\n` +
4516
4686
  `[X-Horizontal] レイヤーごとに左右交互の向きで横に揺らします\n[X-Vertical] レイヤーごとに上下交互の向きで縦に揺らします\n[Drunk] 画面全体を上下左右ランダムに揺らします。画面酔いに注意してください\n` +
4517
- `[S-Drunk] 画面全体を上下左右ランダムに揺らし、さらにレイヤーごとに上下左右に揺らします`,
4687
+ `[S-Drunk] 画面全体を上下左右ランダムに揺らし、さらにレイヤーごとに上下左右に揺らします\n` +
4688
+ `[H-Drunk] S-Drunkより大きく上下に揺らし、さらに回転が掛かります`,
4518
4689
  effect: `矢印・フリーズアローにエフェクトをかけます。\n[Dizzy/Spin] 矢印が回転します\n[Wave/Storm] 矢印の軌道が左右に揺れます\n[Blinking] 矢印が点滅します\n[Squids] 矢印が伸び縮みします`,
4519
4690
  camoufrage: `ステップの見た目が配置は同じでランダムに変わります。`,
4520
4691
  swapping: `ステップゾーンの位置をグループ単位で入れ替えます。`,
@@ -4601,14 +4772,17 @@ const g_lang_msgObj = {
4601
4772
 
4602
4773
  playWindow: `This is the setting for overall rotation of the step zone and arrow position, etc.\n[Stairs/Slope] The step zone is in a staircase shape.\n[Distorted] Distorts the screen.\n` +
4603
4774
  `[SideScroll] It becomes a side scroll mode.`,
4775
+ playWindowType: `[Reverse] Applies reverse rotation to the step zone and arrow positions.`,
4604
4776
  stepArea: `Change the position of the step zone.\n[Halfway] Step zones are centered.\n[2Step] Step zones are divided into two layers.\n` +
4605
4777
  `[Mismatched/R-Mismatched] Scroll direction flows in different directions up and down.\n` +
4606
4778
  `[X-Flower] Lanes spread out like flower petals.\n[Alt-Crossing] Lanes flow from different directions alternately.`,
4607
4779
  frzReturn: `When the Freeze Arrow is reached, and every time the arrow's recovery judgment \nreaches a multiple of 100, it will rotate on either the X, Y, or Z axis.`,
4780
+ frzReturnType: `[360deg/120deg/60deg] Rotates to the specified angle.\n[±360deg/±120deg] May rotate in the opposite direction in addition to 360deg/120deg.\n[Pendulum] Moves back and forth like a pendulum.`,
4608
4781
  shaking: `This sets shaking for the step zone and arrows.\n[Horizontal] Shakes horizontally.\n[Vertical] Shakes vertically.\n` +
4609
4782
  `[X-Horizontal] Per-layer shaking with alternating left/right direction by layer.\n[X-Vertical] Per-layer shaking with alternating up/down direction by layer.\n` +
4610
4783
  `[Drunk] Shakes the entire screen randomly in all directions (may cause motion sickness).\n` +
4611
- `[S-Drunk] Shakes the entire screen randomly in all directions, and also shakes each layer randomly in all directions.`,
4784
+ `[S-Drunk] Shakes the entire screen randomly in all directions, and also shakes each layer randomly in all directions.\n` +
4785
+ `[H-Drunk] Adds stronger vertical movement than S-Drunk and adds rotation.`,
4612
4786
  effect: `Applies effects to the arrows and freeze arrows.\n[Dizzy/Spin] Arrows rotate.\n[Wave/Storm] Swing from left to right.\n[Blinking] Arrows blink.\n[Squids] Arrows stretch and shrink.`,
4613
4787
  camoufrage: `The appearance of the steps changes randomly with the same placement.`,
4614
4788
  swapping: `Replaces the position of step zones on a group-by-group basis.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "45.3.0",
3
+ "version": "45.4.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "scripts": {