danoniplus 45.3.1 → 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/02
7
+ * Revised : 2026/03/04
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 45.3.1`;
12
- const g_revisedDate = `2026/03/02`;
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 = ``;
@@ -8692,9 +8692,67 @@ const exSettingInit = () => {
8692
8692
  createEmptySprite(divRoot, `optionsprite`, g_windowObj.optionSprite);
8693
8693
  const spriteList = setSpriteList(g_settingPos.exSetting);
8694
8694
 
8695
- 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
+
8696
8748
  createGeneralSetting(spriteList.stepArea, `stepArea`);
8697
- 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
+
8698
8756
  createGeneralSetting(spriteList.shaking, `shaking`);
8699
8757
  createGeneralSetting(spriteList.effect, `effect`, {
8700
8758
  addRFunc: () => {
@@ -11695,7 +11753,7 @@ const getArrowSettings = () => {
11695
11753
 
11696
11754
  if (g_stateObj.playWindow.endsWith(`SideScroll`)) {
11697
11755
  if (g_stateObj.rotateEnabled) {
11698
- const sign = g_stateObj.playWindow === `SideScroll` ? 1 : -1;
11756
+ const sign = g_stateObj.playWindowType === `Reverse` ? -1 : 1;
11699
11757
  changeStepRtn(`stepRtn`, 90 * sign);
11700
11758
  changeStepRtn(`stepHitRtn`, 90 * sign);
11701
11759
  changeStepRtn(`arrowRtn`, 90 * sign);
@@ -11898,6 +11956,11 @@ const getArrowSettings = () => {
11898
11956
 
11899
11957
  // FrzReturnの初期化
11900
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
+ }
11901
11964
 
11902
11965
  // AutoRetryの初期化
11903
11966
  g_workObj.autoRetryFlg = false;
@@ -11970,9 +12033,11 @@ const getArrowSettings = () => {
11970
12033
  }
11971
12034
  }
11972
12035
 
11973
- // Shaking: Drunkでの画面揺れ設定 (X方向、Y方向)
12036
+ // Shaking: Drunkでの画面揺れ設定 (X方向、Y方向、移動軸条件、回転軸条件)
11974
12037
  g_workObj.drunkXFlg = false;
11975
12038
  g_workObj.drunkYFlg = false;
12039
+ g_workObj.drunkAxisFlg = false;
12040
+ g_workObj.drunkRotateFlg = false;
11976
12041
 
11977
12042
  // AppearanceFilterの可視範囲設定
11978
12043
  g_workObj.aprFilterCnt = 0;
@@ -13256,7 +13321,9 @@ const mainInit = () => {
13256
13321
  }
13257
13322
 
13258
13323
  // 画面揺れの設定
13259
- g_shakingFunc.get(g_stateObj.shaking)();
13324
+ if (g_scoreObj.baseFrame % 2 === 0) {
13325
+ g_shakingFunc.get(g_stateObj.shaking)();
13326
+ }
13260
13327
 
13261
13328
  // ユーザカスタムイベント(フレーム毎)
13262
13329
  g_customJsObj.mainEnterFrame.forEach(func => func());
@@ -13709,52 +13776,81 @@ const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) =
13709
13776
  };
13710
13777
 
13711
13778
  /**
13712
- * FrzReturnの追加処理
13713
- * @param {number} _rad 回転角度
13714
- * @param {number[]} _axis 回転軸
13779
+ * FrzReturnの開始条件
13780
+ */
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など)
13715
13800
  */
13716
- const changeReturn = (_rad, _axis) => {
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
+
13717
13818
  g_workObj.frzReturnFlg = true;
13819
+ const _rad = _seq[_idx];
13820
+
13718
13821
  let _transform = `rotate${_axis[0]}(${_rad}deg)`;
13719
13822
  if (_axis[1] !== undefined) {
13720
13823
  _transform += ` rotate${_axis[1]}(${_rad}deg)`;
13721
13824
  }
13722
- const sprite = document.getElementById(`mainSprite`);
13723
- if (sprite !== null) {
13724
- sprite.style.transformStyle = `preserve-3d`;
13725
- const rad360 = _rad % 360;
13726
13825
 
13727
- let isBack = false;
13826
+ sprite.style.transformStyle = `preserve-3d`;
13827
+ const rad360 = ((_rad % 360) + 360) % 360;
13728
13828
 
13729
- // 単軸回転
13730
- if (_axis.length === 1) {
13731
- const axis = _axis[0];
13732
- if (axis === 'Y' || axis === 'X') {
13733
- isBack = rad360 > 90 && rad360 < 270;
13734
- }
13735
- // Z軸は平面回転なので「裏側」は存在しない
13736
- }
13829
+ let isBack = false;
13737
13830
 
13738
- // 2軸回転(XZ / XY / YZ)
13739
- if (_axis.length === 2) {
13740
- // 2軸回転は「どちらかの軸が裏側なら裏側」とみなす
13741
- const [a1, a2] = _axis;
13742
- const back1 = (a1 === 'Y' || a1 === 'X') && (rad360 > 90 && rad360 < 270);
13743
- const back2 = (a2 === 'Y' || a2 === 'X') && (rad360 > 90 && rad360 < 270);
13744
- 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;
13745
13836
  }
13746
- sprite.style.opacity = isBack ? 0.7 : 1;
13747
-
13748
- addTransform(`mainSprite`, `frzReturn`, _transform, g_transPriority.frzReturn);
13837
+ // Z軸は平面回転なので「裏側」は存在しない
13838
+ }
13749
13839
 
13750
- if (_rad < 360 && g_workObj.frzReturnFlg) {
13751
- setTimeout(() => changeReturn(_rad + 4, _axis), 20);
13752
- } else {
13753
- delTransform(`mainSprite`, `frzReturn`);
13754
- g_workObj.frzReturnFlg = false;
13755
- }
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;
13756
13847
  }
13757
- }
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
+ };
13758
13854
 
13759
13855
  /**
13760
13856
  * AutoRetryの設定
@@ -13946,9 +14042,7 @@ const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
13946
14042
 
13947
14043
  // FrzReturnの設定
13948
14044
  if (g_stateObj.frzReturn !== C_FLG_OFF) {
13949
- if (!g_workObj.frzReturnFlg) {
13950
- changeReturn(4, g_frzReturnFunc.get(g_stateObj.frzReturn)());
13951
- }
14045
+ startFrzReturn();
13952
14046
  }
13953
14047
  g_customJsObj[`judg_${_name}Hit`].forEach(func => func(_difFrame));
13954
14048
  };
@@ -13971,9 +14065,7 @@ const changeFailedFrz = (_j, _k) => {
13971
14065
 
13972
14066
  // FrzReturnの設定
13973
14067
  if (g_stateObj.frzReturn !== C_FLG_OFF) {
13974
- if (!g_workObj.frzReturnFlg) {
13975
- changeReturn(4, g_frzReturnFunc.get(g_stateObj.frzReturn)());
13976
- }
14068
+ startFrzReturn();
13977
14069
  }
13978
14070
  };
13979
14071
 
@@ -14192,10 +14284,8 @@ const judgeRecovery = (_name, _difFrame) => {
14192
14284
  lifeRecovery();
14193
14285
  finishViewing();
14194
14286
 
14195
- if (g_stateObj.freezeReturn !== C_FLG_OFF) {
14196
- if ((g_resultObj.ii + g_resultObj.shakin) % 100 === 0 && !g_workObj.frzReturnFlg) {
14197
- changeReturn(1, g_frzReturnFunc.get(g_stateObj.frzReturn)());
14198
- }
14287
+ if (g_stateObj.frzReturn !== C_FLG_OFF && (g_resultObj.ii + g_resultObj.shakin) % 100 === 0) {
14288
+ startFrzReturn();
14199
14289
  }
14200
14290
  if (_name === `shakin`) {
14201
14291
  quickRetry(`Shakin(Great)`);
@@ -15170,14 +15260,16 @@ const getSelectedSettingList = (_shuffleName) => {
15170
15260
  withOptions(g_stateObj.appearance, `Visible`) +
15171
15261
  ((g_appearanceRanges.includes(g_stateObj.appearance) && g_stateObj.filterLock === C_FLG_ON) ? `(${g_hidSudObj.filterPos}%)` : ``),
15172
15262
  withOptions(g_stateObj.gauge, g_settings.gauges[0]),
15173
- withOptions(g_stateObj.playWindow, `Default`),
15263
+ withOptions(g_stateObj.playWindow, `Default`,
15264
+ `${getStgDetailName(g_stateObj.playWindowType === `Reverse` ? `R-` : ``)}${getStgDetailName(g_stateObj.playWindow)}`),
15174
15265
  withOptions(g_stateObj.stepArea, `Default`),
15175
- 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)})`),
15176
15268
  withOptions(g_stateObj.shaking, C_FLG_OFF),
15177
15269
  withOptions(g_stateObj.effect, C_FLG_OFF),
15178
- withOptions(g_stateObj.camoufrage, C_FLG_OFF, `Cmf:${g_stateObj.camoufrage}`),
15179
- withOptions(g_stateObj.swapping, C_FLG_OFF, `Swap:${g_stateObj.swapping}`),
15180
- 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)}`),
15181
15273
  ].filter(value => value !== ``).join(`, `);
15182
15274
 
15183
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/02 (v45.3.1)
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,62 +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', () => {
1785
- if (g_scoreObj.baseFrame % 2 === 0)
1786
- addTransform(`mainSprite`, `shakingX`, `translateX(${getShakingDist()}px)`, g_transPriority.shaking)
1802
+ ['Horizontal', (_multi = 1) => {
1803
+ addTransform(`mainSprite`, `shakingX_base`, `translateX(${getShakingDist() * _multi}px)`, g_transPriority.shakingX)
1787
1804
  }],
1788
- ['Vertical', () => {
1789
- if (g_scoreObj.baseFrame % 2 === 0)
1790
- addTransform(`mainSprite`, `shakingY`, `translateY(${getShakingDist() / 2}px)`, g_transPriority.shaking)
1805
+ ['Vertical', (_multi = 1) => {
1806
+ addTransform(`mainSprite`, `shakingY_base`, `translateY(${getShakingDist() / 2 * _multi}px)`, g_transPriority.shakingY)
1791
1807
  }],
1792
- ['X-Horizontal', () => {
1793
- if (g_scoreObj.baseFrame % 2 === 0)
1794
- for (let j = 0; j < g_stateObj.layerNum; j++) {
1795
- addTransform(`mainSprite${j}`, `shakingX`, `translateX(${getDirFromLayer(j) * (4 / 3) * getShakingDist()}px)`, g_transPriority.shaking);
1796
- }
1808
+ ['X-Horizontal', (_multi = 1) => {
1809
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1810
+ addTransform(`mainSprite${j}`, `shakingX_layer`, `translateX(${getDirFromLayer(j) * (4 / 3) * getShakingDist() * _multi}px)`, g_transPriority.shakingX);
1811
+ }
1797
1812
  }],
1798
- ['X-Vertical', () => {
1799
- if (g_scoreObj.baseFrame % 2 === 0)
1800
- for (let j = 0; j < g_stateObj.layerNum; j++) {
1801
- addTransform(`mainSprite${j}`, `shakingY`, `translateY(${getDirFromLayer(j) * getShakingDist()}px)`, g_transPriority.shaking);
1802
- }
1813
+ ['X-Vertical', (_multi = 1) => {
1814
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1815
+ addTransform(`mainSprite${j}`, `shakingY_layer`, `translateY(${getDirFromLayer(j) * getShakingDist() * _multi}px)`, g_transPriority.shakingY);
1816
+ }
1803
1817
  }],
1804
- ['Drunk', () => {
1805
- if (g_scoreObj.baseFrame % 2 === 0) {
1806
- // Drunkは揺れの軸が途中で変わるため、基準位置取得のためにmainSpriteのみaddX, addYを使用
1807
- const shakeX = g_posXs.mainSprite?.get(`shakingX`) ?? 0;
1808
- const shakeY = g_posYs.mainSprite?.get(`shakingY`) ?? 0;
1809
- if (shakeX === 0 && shakeY === 0) {
1810
- g_workObj.drunkXFlg = Math.random() < 0.5;
1811
- g_workObj.drunkYFlg = Math.random() < 0.5;
1812
- }
1813
- if (g_workObj.drunkXFlg) {
1814
- const deltaX = getShakingDist();
1815
- addX(`mainSprite`, `shakingX`, deltaX, { priority: g_transPriority.shaking });
1816
- addTransform(`infoSprite`, `shakingX`, `translateX(${deltaX}px)`, g_transPriority.shaking);
1817
- addTransform(`judgeSprite`, `shakingX`, `translateX(${deltaX}px)`, g_transPriority.shaking);
1818
- }
1819
- if (g_workObj.drunkYFlg) {
1820
- const deltaY = getShakingDist() / 2;
1821
- addY(`mainSprite`, `shakingY`, deltaY, { priority: g_transPriority.shaking });
1822
- addTransform(`infoSprite`, `shakingY`, `translateY(${deltaY}px)`, g_transPriority.shaking);
1823
- addTransform(`judgeSprite`, `shakingY`, `translateY(${deltaY}px)`, g_transPriority.shaking);
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) {
1834
+ g_workObj.drunkXFlg = Math.random() < 0.5;
1835
+ g_workObj.drunkYFlg = Math.random() < 0.5;
1836
+
1837
+ if (!g_workObj.drunkXFlg && !g_workObj.drunkYFlg) {
1838
+ g_workObj.drunkYFlg = true;
1824
1839
  }
1825
1840
  }
1826
1841
  }],
1827
1842
  ['S-Drunk', () => {
1828
- if (g_scoreObj.baseFrame % 2 === 0) {
1829
- g_shakingFunc.get(`Drunk`)();
1830
- if (g_workObj.drunkXFlg) {
1831
- g_shakingFunc.get(`X-Vertical`)();
1832
- }
1833
- if (g_workObj.drunkYFlg) {
1834
- g_shakingFunc.get(`X-Horizontal`)();
1835
- }
1843
+ // Drunkとはあえて異なる軸の補正を掛ける
1844
+ if (g_workObj.drunkXFlg) {
1845
+ g_shakingFunc.get(`X-Vertical`)(2);
1846
+ }
1847
+ if (g_workObj.drunkYFlg) {
1848
+ g_shakingFunc.get(`X-Horizontal`)(2);
1849
+ }
1850
+ g_shakingFunc.get(`Drunk`)(2);
1851
+ }],
1852
+ ['H-Drunk', () => {
1853
+ const dist = getShakingDist();
1854
+
1855
+ // X方向、Y方向の移動方法。S-Drunkと同様、Drunkとあえて異なる軸の補正を掛ける
1856
+ // 本来は適用するtransform先が異なるためdelTransformを行う必要があるが、補正ゼロ時に切り替えるため問題なし
1857
+ if (g_workObj.drunkXFlg) {
1858
+ g_shakingFunc.get((g_workObj.drunkAxisFlg ? `X-` : ``) + `Vertical`)(3);
1859
+ }
1860
+ if (g_workObj.drunkYFlg) {
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;
1836
1877
  }
1837
1878
  }],
1838
1879
  ]);
@@ -1858,6 +1899,7 @@ const g_getSecondaryAxis = (_primaryAxis) => {
1858
1899
 
1859
1900
  /**
1860
1901
  * FrzReturn適用関数
1902
+ * - 対応するキー名: g_settings.frzReturns
1861
1903
  */
1862
1904
  const g_frzReturnFunc = new Map([
1863
1905
  ['OFF', () => true],
@@ -1875,6 +1917,91 @@ const g_frzReturnFunc = new Map([
1875
1917
  }],
1876
1918
  ]);
1877
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
+
1878
2005
  /**
1879
2006
  * Effect適用関数
1880
2007
  * @param {string} _arrowEffect
@@ -1893,6 +2020,10 @@ const g_setEffect = (_arrowEffect, _frzEffect = ``, _frzArrowEffect = _arrowEffe
1893
2020
  }
1894
2021
  }
1895
2022
  };
2023
+ /**
2024
+ * Effect定義関数
2025
+ * - 対応するキー名: g_settings.effects
2026
+ */
1896
2027
  const g_effectFunc = new Map([
1897
2028
  ['OFF', () => true],
1898
2029
  ['Dizzy', () => g_setEffect(`effects-dizzy`)],
@@ -2373,6 +2504,7 @@ const g_shortcutObj = {
2373
2504
  Numpad0: { id: `btnPrecond9` },
2374
2505
  Escape: { id: `btnBack` },
2375
2506
  ShiftLeft_Tab: { id: `btnBack` },
2507
+ ShiftRight_Tab: { id: `btnBack` },
2376
2508
  },
2377
2509
  option: {
2378
2510
  ShiftLeft_KeyD: { id: `lnkDifficultyL` },
@@ -2622,18 +2754,29 @@ const g_shortcutObj = {
2622
2754
  },
2623
2755
  exSetting: {
2624
2756
  ShiftLeft_KeyP: { id: `lnkPlayWindowL` },
2757
+ ShiftRight_KeyP: { id: `lnkPlayWindowL` },
2625
2758
  ShiftLeft_KeyS: { id: `lnkStepAreaL` },
2759
+ ShiftRight_KeyS: { id: `lnkStepAreaL` },
2626
2760
  ShiftLeft_KeyF: { id: `lnkFrzReturnL` },
2761
+ ShiftRight_KeyF: { id: `lnkFrzReturnL` },
2627
2762
  ShiftLeft_KeyH: { id: `lnkShakingL` },
2763
+ ShiftRight_KeyH: { id: `lnkShakingL` },
2628
2764
  ShiftLeft_KeyE: { id: `lnkEffectL` },
2765
+ ShiftRight_KeyE: { id: `lnkEffectL` },
2629
2766
  ShiftLeft_KeyC: { id: `lnkCamoufrageL` },
2767
+ ShiftRight_KeyC: { id: `lnkCamoufrageL` },
2630
2768
  ShiftLeft_KeyW: { id: `lnkSwappingL` },
2769
+ ShiftRight_KeyW: { id: `lnkSwappingL` },
2631
2770
  ShiftLeft_KeyJ: { id: `lnkJudgRangeL` },
2771
+ ShiftRight_KeyJ: { id: `lnkJudgRangeL` },
2632
2772
  ShiftLeft_KeyA: { id: `lnkAutoRetryL` },
2773
+ ShiftRight_KeyA: { id: `lnkAutoRetryL` },
2633
2774
 
2634
2775
  KeyP: { id: `lnkPlayWindowR` },
2776
+ KeyR: { id: `lnkPlayWindowType` },
2635
2777
  KeyS: { id: `lnkStepAreaR` },
2636
2778
  KeyF: { id: `lnkFrzReturnR` },
2779
+ KeyD: { id: `lnkFrzReturnType` },
2637
2780
  KeyH: { id: `lnkShakingR` },
2638
2781
  KeyE: { id: `lnkEffectR` },
2639
2782
  KeyC: { id: `lnkCamoufrageR` },
@@ -4210,6 +4353,7 @@ const g_lblNameObj = {
4210
4353
  'u_Asymmetry': `Asymmetry`,
4211
4354
  'u_Flat': `Flat`,
4212
4355
  'u_R-': `R-`,
4356
+ 'u_---': `---`,
4213
4357
  'u_Reverse': `Reverse`,
4214
4358
 
4215
4359
  'u_Mirror': `Mirror`,
@@ -4250,13 +4394,9 @@ const g_lblNameObj = {
4250
4394
  'u_Hid&Sud+': `Hid&Sud+`,
4251
4395
 
4252
4396
  'u_Stairs': `Stairs`,
4253
- 'u_R-Stairs': `R-Stairs`,
4254
4397
  'u_Slope': `Slope`,
4255
- 'u_R-Slope': `R-Slope`,
4256
4398
  'u_Distorted': `Distorted`,
4257
- 'u_R-Distorted': `R-Distorted`,
4258
4399
  'u_SideScroll': `SideScroll`,
4259
- 'u_R-SideScroll': `R-SideScroll`,
4260
4400
 
4261
4401
  'u_Halfway': `Halfway`,
4262
4402
  'u_2Step': `2Step`,
@@ -4278,6 +4418,7 @@ const g_lblNameObj = {
4278
4418
  'u_X-Vertical': `X-Vertical`,
4279
4419
  'u_Drunk': `Drunk`,
4280
4420
  'u_S-Drunk': `S-Drunk`,
4421
+ 'u_H-Drunk': `H-Drunk`,
4281
4422
 
4282
4423
  'u_Dizzy': `Dizzy`,
4283
4424
  'u_Spin': `Spin`,
@@ -4390,6 +4531,13 @@ const g_lang_lblNameObj = {
4390
4531
  s_printTitle: `Dancing☆Onigiri レベル計算ツール+++`,
4391
4532
  s_printHeader: `難易度\t同時\t縦連\t総数\t矢印\t氷矢印\tAPM\t時間`,
4392
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
+
4393
4541
  j_ii: "(・∀・)イイ!!",
4394
4542
  j_shakin: "(`・ω・)シャキン",
4395
4543
  j_matari: "( ´∀`)マターリ",
@@ -4434,6 +4582,13 @@ const g_lang_lblNameObj = {
4434
4582
  s_printTitle: `Dancing☆Onigiri Level Calculator+++`,
4435
4583
  s_printHeader: `Level\tChords\tJack\tAll\tArrow\tFrz\tAPM\tTime`,
4436
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
+
4437
4592
  j_ii: ":D Perfect!!",
4438
4593
  j_shakin: ":) Great!",
4439
4594
  j_matari: ":| Good",
@@ -4521,13 +4676,16 @@ const g_lang_msgObj = {
4521
4676
 
4522
4677
  playWindow: `ステップゾーン及び矢印の位置を全体的に回転する等の設定です。\n[Stairs/Slope] ステップゾーンを階段状にします\n[Distorted] 画面を歪ませます\n` +
4523
4678
  `[SideScroll] 横スクロールモードになります`,
4679
+ playWindowType: `[Reverse] ステップゾーン及び矢印の位置について逆方向の回転が掛かります`,
4524
4680
  stepArea: `ステップゾーンの位置を変更します。\n[Halfway] ステップゾーンが中央に表示されます\n[2Step] ステップゾーンが2段に分かれて流れてきます\n` +
4525
4681
  `[Mismatched/R-Mismatched] スクロールの向きが上下で異なる方向に流れます\n` +
4526
4682
  `[X-Flower] レーンが花びらのように広がります\n[Alt-Crossing] レーンが交互に違う方向から流れます`,
4527
4683
  frzReturn: `フリーズアロー到達時及び矢印の回復判定が100の倍数に達するごとに、X/Y/Z軸のいずれかに回転します`,
4684
+ frzReturnType: `[360°/120°/60°] 指定の角度まで回転します\n[±360°/±120°] 360°/120°に加えて逆回転が掛かることがあります\n[Pendulum] 振り子のように左右に動きます`,
4528
4685
  shaking: `ステップゾーン及び矢印を揺らす設定です。\n[Horizontal] 横方向に揺らします\n[Vertical] 縦方向に揺らします\n` +
4529
4686
  `[X-Horizontal] レイヤーごとに左右交互の向きで横に揺らします\n[X-Vertical] レイヤーごとに上下交互の向きで縦に揺らします\n[Drunk] 画面全体を上下左右ランダムに揺らします。画面酔いに注意してください\n` +
4530
- `[S-Drunk] 画面全体を上下左右ランダムに揺らし、さらにレイヤーごとに上下左右に揺らします`,
4687
+ `[S-Drunk] 画面全体を上下左右ランダムに揺らし、さらにレイヤーごとに上下左右に揺らします\n` +
4688
+ `[H-Drunk] S-Drunkより大きく上下に揺らし、さらに回転が掛かります`,
4531
4689
  effect: `矢印・フリーズアローにエフェクトをかけます。\n[Dizzy/Spin] 矢印が回転します\n[Wave/Storm] 矢印の軌道が左右に揺れます\n[Blinking] 矢印が点滅します\n[Squids] 矢印が伸び縮みします`,
4532
4690
  camoufrage: `ステップの見た目が配置は同じでランダムに変わります。`,
4533
4691
  swapping: `ステップゾーンの位置をグループ単位で入れ替えます。`,
@@ -4614,14 +4772,17 @@ const g_lang_msgObj = {
4614
4772
 
4615
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` +
4616
4774
  `[SideScroll] It becomes a side scroll mode.`,
4775
+ playWindowType: `[Reverse] Applies reverse rotation to the step zone and arrow positions.`,
4617
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` +
4618
4777
  `[Mismatched/R-Mismatched] Scroll direction flows in different directions up and down.\n` +
4619
4778
  `[X-Flower] Lanes spread out like flower petals.\n[Alt-Crossing] Lanes flow from different directions alternately.`,
4620
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.`,
4621
4781
  shaking: `This sets shaking for the step zone and arrows.\n[Horizontal] Shakes horizontally.\n[Vertical] Shakes vertically.\n` +
4622
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` +
4623
4783
  `[Drunk] Shakes the entire screen randomly in all directions (may cause motion sickness).\n` +
4624
- `[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.`,
4625
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.`,
4626
4787
  camoufrage: `The appearance of the steps changes randomly with the same placement.`,
4627
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.1",
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": {