danoniplus 38.3.2 → 39.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/danoni_main.js CHANGED
@@ -4,19 +4,19 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2025/02/01
7
+ * Revised : 2025/02/04
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 38.3.2`;
12
- const g_revisedDate = `2025/02/01`;
11
+ const g_version = `Ver 39.1.0`;
12
+ const g_revisedDate = `2025/02/04`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
16
16
  let g_localVersion2 = ``;
17
17
 
18
18
  // ショートカット用文字列(↓の文字列を検索することで対象箇所へジャンプできます)
19
- // 共通:water 初期化:peach タイトル:melon 設定:lime ディスプレイ:lemon キーコンフィグ:orange 譜面読込:strawberry メイン:banana 結果:grape
19
+ // 共通:water 初期化:peach タイトル:melon 設定:lime ディスプレイ:lemon 拡張設定:apple キーコンフィグ:orange 譜面読込:strawberry メイン:banana 結果:grape
20
20
  // シーンジャンプ:Scene
21
21
 
22
22
  /**
@@ -100,7 +100,6 @@ let g_currentPage = ``;
100
100
  let g_kcType = `Main`;
101
101
  let g_colorType = `Default`;
102
102
  let g_imgType = `Original`;
103
- let g_baseDisp = `Settings`;
104
103
 
105
104
  // ライフ・ゲームオーバー・曲終了管理
106
105
  let g_maxScore = 1000000;
@@ -1232,7 +1231,8 @@ const createColorPicker = (_parentObj, _id, _func, { x = 0, y = 0 } = {}) => {
1232
1231
  * @returns {HTMLDivElement}
1233
1232
  */
1234
1233
  const createColorObject2 = (_id,
1235
- { x = 0, y = 0, w = C_ARW_WIDTH, h = C_ARW_WIDTH, rotate = ``, styleName = ``, ...rest } = {}, ..._classes) => {
1234
+ { x = 0, y = 0, w = C_ARW_WIDTH, h = C_ARW_WIDTH, rotate = ``, styleName = ``,
1235
+ rotateEnabled = g_stateObj.rotateEnabled, ...rest } = {}, ..._classes) => {
1236
1236
 
1237
1237
  const div = createDiv(_id, x, y, w, h, _classes);
1238
1238
  const style = div.style;
@@ -1244,7 +1244,7 @@ const createColorObject2 = (_id,
1244
1244
  rotate = setVal(objData[1], 0, C_TYP_FLOAT);
1245
1245
  charaStyle = `${objData[0]}${styleName}`;
1246
1246
  }
1247
- if (g_stateObj.rotateEnabled) {
1247
+ if (rotateEnabled) {
1248
1248
  style.transform = `rotate(${rotate}deg)`;
1249
1249
  }
1250
1250
 
@@ -1537,6 +1537,7 @@ const makeBgCanvas = (_ctx, { w = g_sWidth, h = g_sHeight } = {}) => {
1537
1537
  */
1538
1538
  const clearWindow = (_redrawFlg = false, _customDisplayName = ``) => {
1539
1539
  resetKeyControl();
1540
+ resetTransform();
1540
1541
 
1541
1542
  // ボタン、オブジェクトをクリア (divRoot配下のもの)
1542
1543
  deleteChildspriteAll(`divRoot`);
@@ -2931,6 +2932,10 @@ const headerConvert = _dosObj => {
2931
2932
  setIntVal(getQueryParamVal(`h`), g_sHeight), g_sHeight);
2932
2933
  $id(`canvas-frame`).height = wUnit(g_sHeight);
2933
2934
  }
2935
+ if (!(_dosObj.heightVariable || g_presetObj.heightVariable || false)) {
2936
+ obj.heightLockFlg = true;
2937
+ g_settings.playWindows = g_settings.playWindows.filter(val => !val.endsWith(`Slope`) && !val.endsWith(`SideScroll`));
2938
+ }
2934
2939
 
2935
2940
  // 曲名
2936
2941
  obj.musicTitles = [];
@@ -3398,6 +3403,8 @@ const headerConvert = _dosObj => {
3398
3403
  interlockingButton(obj, defaultOption, C_FLG_OFF, C_FLG_ON);
3399
3404
  }));
3400
3405
  }
3406
+ obj.arrowEffectUseOrg = obj.arrowEffectUse;
3407
+ obj.arrowEffectSetFlg = obj.arrowEffectSet === C_FLG_ON;
3401
3408
 
3402
3409
  // ローカルストレージに保存済みのColorType設定からDisplayのColor設定を反映
3403
3410
  if (g_localStorage.colorType !== undefined) {
@@ -3910,6 +3917,7 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3910
3917
 
3911
3918
  const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
3912
3919
  const toString = _str => _str;
3920
+ const toInt = _num => isNaN(parseInt(_num)) ? _num : parseInt(_num);
3913
3921
  const toFloat = _num => isNaN(parseFloat(_num)) ? _num : parseFloat(_num);
3914
3922
  const toKeyCtrlArray = _str =>
3915
3923
  makeBaseArray(_str.split(`/`).map(n => getKeyCtrlVal(n)), g_keyObj.minKeyCtrlNum, 0);
@@ -4264,6 +4272,19 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
4264
4272
  // |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
4265
4273
  newKeyPairParam(newKey, `assist`, `assistPos`);
4266
4274
 
4275
+ // レーンごとの割当レイヤーグループ (layerGroupX_Y)
4276
+ newKeyMultiParam(newKey, `layerGroup`, toInt);
4277
+
4278
+ // レイヤーごとのアニメーション情報 (layerTransX_Y)
4279
+ if (hasVal(_dosObj[`layerTrans${newKey}`])) {
4280
+ _dosObj[`layerTrans${newKey}`] = _dosObj[`layerTrans${newKey}`]?.replaceAll(`,`, `___`);
4281
+ newKeyMultiParam(newKey, `layerTrans`, toSplitArrayStr, {
4282
+ loopFunc: (k, keyheader) => {
4283
+ g_keyObj[`${keyheader}_${k + dfPtnNum}`][0] = g_keyObj[`${keyheader}_${k + dfPtnNum}`]?.[0]?.map(val => val.replaceAll(`___`, `,`));
4284
+ },
4285
+ });
4286
+ }
4287
+
4267
4288
  // keyRetry, keyTitleBackのキー名をキーコードに変換
4268
4289
  const keyTypePatterns = Object.keys(g_keyObj).filter(val => val.startsWith(`keyRetry${newKey}`) || val.startsWith(`keyTitleBack${newKey}`));
4269
4290
  keyTypePatterns.forEach(name => g_keyObj[name] = getKeyCtrlVal(g_keyObj[name]));
@@ -4305,6 +4326,9 @@ const titleInit = () => {
4305
4326
  // タイトル用フレーム初期化
4306
4327
  g_scoreObj.titleFrameNum = 0;
4307
4328
 
4329
+ // 設定画面位置初期化
4330
+ g_settings.settingWindowNum = 0;
4331
+
4308
4332
  // タイトルアニメーション用フレーム初期化、ループカウンター設定
4309
4333
  g_animationData.forEach(sprite => {
4310
4334
  g_scoreObj[`${sprite}TitleFrameNum`] = 0;
@@ -4331,7 +4355,7 @@ const titleInit = () => {
4331
4355
  divRoot.appendChild(
4332
4356
  createColorObject2(`lblArrow`, {
4333
4357
  x: (g_sWidth - 500) / 2, y: -15 + (g_sHeight - 500) / 2,
4334
- w: 500, h: 500,
4358
+ w: 500, h: 500, rotateEnabled: true,
4335
4359
  background: makeColorGradation(g_headerObj.titlearrowgrds[0] || g_headerObj.setColorOrg[0], {
4336
4360
  _defaultColorgrd: [false, `#eeeeee`],
4337
4361
  _objType: `titleArrow`,
@@ -4699,7 +4723,8 @@ const commonSettingBtn = _labelName => {
4699
4723
  // Display設定へ移動
4700
4724
  createCss2Button(`btn${_labelName}`, `>`, () => true,
4701
4725
  Object.assign(g_lblPosObj.btnSwitchSetting, {
4702
- title: g_msgObj[`to${_labelName}`], resetFunc: () => g_jumpSettingWindow[g_currentPage](),
4726
+ title: g_msgObj[`to${_labelName}`], resetFunc: () => g_moveSettingWindow(),
4727
+ cxtFunc: () => g_moveSettingWindow(true, -1),
4703
4728
  }), g_cssObj.button_Mini),
4704
4729
 
4705
4730
  // データセーブフラグの切替
@@ -4727,7 +4752,6 @@ const optionInit = () => {
4727
4752
 
4728
4753
  clearWindow(true);
4729
4754
  const divRoot = document.getElementById(`divRoot`);
4730
- g_baseDisp = `Settings`;
4731
4755
  g_currentPage = `option`;
4732
4756
  g_stateObj.filterKeys = ``;
4733
4757
 
@@ -6002,7 +6026,7 @@ const createGeneralSetting = (_obj, _settingName, { unitName = ``,
6002
6026
  */
6003
6027
  const createLblSetting = (_settingName, _adjY = 0, _settingLabel = _settingName) => {
6004
6028
  const lbl = createDivCss2Label(`lbl${_settingName}`, g_lblNameObj[_settingLabel], {
6005
- x: 0, y: _adjY, w: 100,
6029
+ x: -5, y: _adjY, w: 110,
6006
6030
  }, `settings_${_settingName}`);
6007
6031
  lbl.title = g_msgObj[`${_settingName.charAt(0).toLowerCase()}${_settingName.slice(1)}`];
6008
6032
  return lbl;
@@ -6452,7 +6476,6 @@ const settingsDisplayInit = () => {
6452
6476
 
6453
6477
  clearWindow(true);
6454
6478
  const divRoot = document.getElementById(`divRoot`);
6455
- g_baseDisp = `Display`;
6456
6479
  g_currentPage = `settingsDisplay`;
6457
6480
 
6458
6481
  // 譜面初期情報ロード許可フラグ
@@ -6669,6 +6692,80 @@ const interlockingButton = (_headerObj, _name, _current, _next, _buttonFlg = fal
6669
6692
  }
6670
6693
  };
6671
6694
 
6695
+ /*-----------------------------------------------------------*/
6696
+ /* Scene : EX-SETTINGS [apple] */
6697
+ /*-----------------------------------------------------------*/
6698
+
6699
+ const exSettingInit = () => {
6700
+ clearWindow(true);
6701
+ g_currentPage = `exSetting`;
6702
+
6703
+ multiAppend(divRoot,
6704
+
6705
+ // 画面タイトル
6706
+ getTitleDivLabel(`lblTitle`,
6707
+ `<div class="settings_Title">EX-</div><div class="settings_Title2">SETTINGS</div>`
6708
+ .replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
6709
+
6710
+ );
6711
+
6712
+ // 各ボタン用のスプライトを作成
6713
+ createEmptySprite(divRoot, `optionsprite`, g_windowObj.optionSprite);
6714
+ const spriteList = setSpriteList(g_settingPos.exSetting);
6715
+
6716
+ createGeneralSetting(spriteList.playWindow, `playWindow`);
6717
+ lblPlayWindow.title += g_headerObj.heightLockFlg ? g_msgObj.sideScrollDisable : g_msgObj.sideScrollMsg;
6718
+
6719
+ createGeneralSetting(spriteList.stepArea, `stepArea`);
6720
+ createGeneralSetting(spriteList.frzReturn, `frzReturn`);
6721
+ createGeneralSetting(spriteList.shaking, `shaking`);
6722
+ createGeneralSetting(spriteList.effect, `effect`, {
6723
+ addRFunc: () => {
6724
+ g_stateObj.d_arroweffect = boolToSwitch(g_stateObj.effect !== C_FLG_OFF || g_headerObj.arrowEffectSetFlg);
6725
+ g_headerObj.arrowEffectUse = g_stateObj.effect === C_FLG_OFF && g_headerObj.arrowEffectUseOrg;
6726
+ g_headerObj.arrowEffectSet = g_stateObj.d_arroweffect;
6727
+ },
6728
+ });
6729
+ createGeneralSetting(spriteList.camoufrage, `camoufrage`);
6730
+ createGeneralSetting(spriteList.swapping, `swapping`);
6731
+ createGeneralSetting(spriteList.judgRange, `judgRange`, {
6732
+ addRFunc: () => {
6733
+ [g_judgObj.arrowJ, g_judgObj.frzJ] = g_judgRanges[g_stateObj.judgRange];
6734
+ lblJudgRangeView.innerHTML = getJudgRangeView();
6735
+ }
6736
+ });
6737
+ createGeneralSetting(spriteList.autoRetry, `autoRetry`);
6738
+
6739
+ // 判定範囲の設定を表示
6740
+ const getJudgRangeView = () => `| ` +
6741
+ `<span class="common_ii">${g_lblNameObj.j_ii}</span>: ≦ <b>±${g_judgObj.arrowJ[0]} f</b> | ` +
6742
+ `<span class="common_shakin">${g_lblNameObj.j_shakin}</span>: ≦ <b>±${g_judgObj.arrowJ[1]} f</b> | ` +
6743
+ `<span class="common_matari">${g_lblNameObj.j_matari}</span>: ≦ <b>±${g_judgObj.arrowJ[2]} f</b> | <br>| ` +
6744
+ `<span class="common_shobon">${g_lblNameObj.j_shobon}</span>: ≦ <b>±${g_judgObj.arrowJ[3]} f</b> | ` +
6745
+ `<span class="common_uwan">${g_lblNameObj.j_uwan}</span>: > <b>±${g_judgObj.arrowJ[3]} f</b> | <br>| ` +
6746
+ `<span class="common_kita">${g_lblNameObj.j_kita}</span>: ≦ <b>±${g_judgObj.frzJ[1]} f</b> | ` +
6747
+ `<span class="common_iknai">${g_lblNameObj.j_iknai}</span>: > <b>±${g_judgObj.frzJ[1]} f</b> |`;
6748
+
6749
+ multiAppend(judgRangeSprite,
6750
+ createDivCss2Label(`lblJudgRangeView`, getJudgRangeView(), {
6751
+ x: parseFloat($id(`lblJudgRange`).left) + 10, y: parseFloat($id(`lblJudgRange`).top) + 25, w: 300, h: 30, siz: 13,
6752
+ align: C_ALIGN_LEFT,
6753
+ }),
6754
+ );
6755
+
6756
+ // ユーザカスタムイベント(初期)
6757
+ g_customJsObj.exSetting.forEach(func => func());
6758
+
6759
+ // 設定系のボタン群をまとめて作成(Data Save, Display切替, Back, KeyConfig, Playボタン)
6760
+ commonSettingBtn(g_currentPage);
6761
+
6762
+ // キー操作イベント(デフォルト)
6763
+ setShortcutEvent(g_currentPage, () => true, { dfEvtFlg: true });
6764
+ document.oncontextmenu = () => true;
6765
+
6766
+ g_skinJsObj.exSetting.forEach(func => func());
6767
+ };
6768
+
6672
6769
  /*-----------------------------------------------------------*/
6673
6770
  /* Scene : KEYCONFIG [orange] */
6674
6771
  /*-----------------------------------------------------------*/
@@ -6708,7 +6805,7 @@ const keyConfigInit = (_kcType = g_kcType) => {
6708
6805
  [tkObj.keyCtrlPtn, tkObj.keyNum, tkObj.posMax, tkObj.divideCnt];
6709
6806
 
6710
6807
  g_keyCopyLists.simpleDef.forEach(header => updateKeyInfo(header, keyCtrlPtn));
6711
- keyconSprite.style.transform = `scale(${g_keyObj.scale})`;
6808
+ addTransform(`keyconSprite`, `root`, `scale(${g_keyObj.scale})`)
6712
6809
  keyconSprite.style.height = `${parseFloat(keyconSprite.style.height) / ((1 + g_keyObj.scale) / 2)}px`;
6713
6810
  const kWidth = parseInt(keyconSprite.style.width);
6714
6811
  changeSetColor();
@@ -7422,7 +7519,7 @@ const keyConfigInit = (_kcType = g_kcType) => {
7422
7519
  g_currentk = 0;
7423
7520
  g_prevKey = 0;
7424
7521
  }, Object.assign(g_lblPosObj.btnKcBack, {
7425
- resetFunc: () => (g_baseDisp === `Settings` ? optionInit() : settingsDisplayInit()),
7522
+ resetFunc: () => g_moveSettingWindow(false),
7426
7523
  }), g_cssObj.button_Back),
7427
7524
 
7428
7525
  createDivCss2Label(`lblPattern`, `${g_lblNameObj.KeyPattern}: ${g_keyObj.currentPtn === -1 ?
@@ -7883,12 +7980,12 @@ const loadingScoreInit = async () => {
7883
7980
 
7884
7981
  // シャッフルグループを扱いやすくする
7885
7982
  // [0, 0, 0, 1, 0, 0, 0] -> [[0, 1, 2, 4, 5, 6], [3]]
7886
- const shuffleGroupMap = {};
7983
+ g_workObj.shuffleGroupMap = {};
7887
7984
  g_keyObj[`shuffle${keyCtrlPtn}`].forEach((_val, _i) =>
7888
- shuffleGroupMap[_val]?.push(_i) || (shuffleGroupMap[_val] = [_i]));
7985
+ g_workObj.shuffleGroupMap[_val]?.push(_i) || (g_workObj.shuffleGroupMap[_val] = [_i]));
7889
7986
 
7890
7987
  // Mirror,Random,S-Randomの適用
7891
- g_shuffleFunc[g_stateObj.shuffle](keyNum, Object.values(shuffleGroupMap));
7988
+ g_shuffleFunc[g_stateObj.shuffle](keyNum, Object.values(g_workObj.shuffleGroupMap));
7892
7989
 
7893
7990
  // アシスト用の配列があれば、ダミーデータで上書き
7894
7991
  if (typeof g_keyObj[`assistPos${keyCtrlPtn}`] === C_TYP_OBJECT &&
@@ -7989,6 +8086,26 @@ const applyShuffle = (_keyNum, _shuffleGroup, _style) => {
7989
8086
  });
7990
8087
  };
7991
8088
 
8089
+ /**
8090
+ * X-Mirror作成用の入れ替え関数
8091
+ * グループが4の倍数のとき、4n+1, 4n+2のみ入れ替える
8092
+ * @param {number[][]} _style
8093
+ * @param {number[]} _group
8094
+ * @param {number} _i
8095
+ * @param {number} _divideNum
8096
+ * @returns
8097
+ */
8098
+ const swapGroupNums = (_style, _group, _i, _divideNum) => {
8099
+ if (_group.length % _divideNum === 0) {
8100
+ for (let k = 0; k < _group.length / _divideNum; k++) {
8101
+ const swap1 = Math.floor(_divideNum * (k + 1 / 2) - 1);
8102
+ const swap2 = Math.ceil(_divideNum * (k + 1 / 2));
8103
+ [_style[_i][swap1], _style[_i][swap2]] = [_style[_i][swap2], _style[_i][swap1]];
8104
+ }
8105
+ }
8106
+ return _style;
8107
+ };
8108
+
7992
8109
  /**
7993
8110
  * Mirrorの適用
7994
8111
  * @param {number} _keyNum
@@ -7999,23 +8116,19 @@ const applyMirror = (_keyNum, _shuffleGroup, _swapFlg = false) => {
7999
8116
 
8000
8117
  // シャッフルグループごとにミラー
8001
8118
  const style = structuredClone(_shuffleGroup).map(_group => _group.reverse());
8002
- let swapUseFlg = false;
8003
-
8004
- // X-Mirror作成用の入れ替え関数
8005
- // グループが4の倍数のとき、4n+1, 4n+2のみ入れ替える
8006
- const swapGroupNums = (_group, _i, _divideNum) => {
8007
- if (_group.length % _divideNum === 0) {
8008
- swapUseFlg = true;
8009
- for (let k = 0; k < _group.length / _divideNum; k++) {
8010
- const swap1 = Math.floor(_divideNum * (k + 1 / 2) - 1);
8011
- const swap2 = Math.ceil(_divideNum * (k + 1 / 2));
8012
- [style[_i][swap1], style[_i][swap2]] = [style[_i][swap2], style[_i][swap1]];
8013
- }
8014
- }
8015
- };
8119
+ const mirStyle = structuredClone(style);
8016
8120
 
8017
8121
  if (_swapFlg) {
8018
- style.forEach((group, i) => g_settings.swapPattern.forEach(val => swapGroupNums(group, i, val)));
8122
+ style.forEach((group, i) => g_settings.swapPattern.forEach(val => swapGroupNums(style, group, i, val)));
8123
+ let swapUseFlg = false;
8124
+ style.forEach((_group, j) => {
8125
+ _group.forEach((val, k) => {
8126
+ if (style[j][k] !== mirStyle[j][k]) {
8127
+ swapUseFlg = true;
8128
+ return;
8129
+ }
8130
+ });
8131
+ });
8019
8132
  if (!swapUseFlg) {
8020
8133
  g_stateObj.shuffle = `Mirror`;
8021
8134
  }
@@ -8370,6 +8483,12 @@ const scoreConvert = (_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
8370
8483
 
8371
8484
  cssMotionData.push([frame, arrowNum, styleUp, styleDown]);
8372
8485
  });
8486
+
8487
+ // 個別のモーションデータが存在する場合、Effect設定を自動リセット
8488
+ if (cssMotionData.length > 0) {
8489
+ g_stateObj.effect = C_FLG_OFF;
8490
+ g_settings.effectNum = 0;
8491
+ }
8373
8492
  return cssMotionData.sort((_a, _b) => _a[0] - _b[0]).flat();
8374
8493
  }
8375
8494
  return [];
@@ -8393,8 +8512,9 @@ const scoreConvert = (_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
8393
8512
  const frame = calcFrame(tmpScrollchData[0]);
8394
8513
  const arrowNum = parseFloat(tmpScrollchData[1]);
8395
8514
  const scrollDir = parseFloat(tmpScrollchData[2] ?? `1`);
8515
+ const layerGroup = parseFloat(tmpScrollchData[3] ?? `-1`);
8396
8516
 
8397
- scrollchData.push([frame, arrowNum, frame, scrollDir]);
8517
+ scrollchData.push([frame, arrowNum, frame, scrollDir, layerGroup]);
8398
8518
  });
8399
8519
  return scrollchData.sort((_a, _b) => _a[0] - _b[0]).flat();
8400
8520
  }
@@ -9179,7 +9299,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9179
9299
  g_typeLists.arrow.forEach(header =>
9180
9300
  calcDataTiming(`cssMotion`, header, pushCssMotions, { _calcFrameFlg: true }));
9181
9301
 
9182
- calcDataTiming(`scrollch`, ``, pushScrollchs, { _calcFrameFlg: true });
9302
+ calcDataTiming(`scrollch`, ``, pushScrollchs, { _term: 5, _calcFrameFlg: true });
9183
9303
 
9184
9304
  g_fadeinStockList.forEach(type =>
9185
9305
  _dataObj[`${type}Data`] = calcAnimationData(type, _dataObj[`${type}Data`]));
@@ -9445,29 +9565,32 @@ const pushCssMotions = (_header, _frame, _val, _styleName, _styleNameRev) => {
9445
9565
  * @param {number} _frameStep
9446
9566
  * @param {number} _scrollDir
9447
9567
  */
9448
- const pushScrollchs = (_header, _frameArrow, _val, _frameStep, _scrollDir) => {
9568
+ const pushScrollchs = (_header, _frameArrow, _val, _frameStep, _scrollDir, _layerGroup) => {
9449
9569
  const tkObj = getKeyInfo();
9570
+ g_stateObj.layerNum = Math.max(g_stateObj.layerNum, (_layerGroup + 1) * 2);
9450
9571
 
9451
9572
  const frameArrow = Math.max(_frameArrow, g_scoreObj.frameNum);
9452
9573
  const frameStep = Math.max(_frameStep, g_scoreObj.frameNum);
9453
9574
  const pushData = (_pattern, _frame, _val) =>
9454
9575
  g_workObj[`mkScrollch${_pattern}`][_frame]?.push(_val) || (g_workObj[`mkScrollch${_pattern}`][_frame] = [_val]);
9576
+ const pushScrollData = _j => {
9577
+ pushData(`Arrow`, frameArrow, _j);
9578
+ pushData(`ArrowDir`, frameArrow, _scrollDir);
9579
+ pushData(`ArrowLayer`, frameArrow, _layerGroup);
9580
+ pushData(`Step`, frameStep, _j);
9581
+ pushData(`StepDir`, frameStep, _scrollDir);
9582
+ pushData(`StepLayer`, frameStep, _layerGroup);
9583
+ };
9455
9584
 
9456
9585
  if (_val < 20 || _val >= 1000) {
9457
9586
  const realVal = g_workObj.replaceNums[_val % 1000];
9458
- pushData(`Arrow`, frameArrow, realVal);
9459
- pushData(`ArrowDir`, frameArrow, _scrollDir);
9460
- pushData(`Step`, frameStep, realVal);
9461
- pushData(`StepDir`, frameStep, _scrollDir);
9587
+ pushScrollData(realVal);
9462
9588
 
9463
9589
  } else {
9464
9590
  const colorNum = _val - 20;
9465
9591
  for (let j = 0; j < tkObj.keyNum; j++) {
9466
9592
  if (g_keyObj[`color${tkObj.keyCtrlPtn}`][j] === colorNum) {
9467
- pushData(`Arrow`, frameArrow, j);
9468
- pushData(`ArrowDir`, frameArrow, _scrollDir);
9469
- pushData(`Step`, frameStep, j);
9470
- pushData(`StepDir`, frameStep, _scrollDir);
9593
+ pushScrollData(j);
9471
9594
  }
9472
9595
  }
9473
9596
  }
@@ -9531,6 +9654,8 @@ const getArrowSettings = () => {
9531
9654
 
9532
9655
  // モーション管理
9533
9656
  g_typeLists.arrow.forEach(type => g_workObj[`${type}CssMotions`] = fillArray(keyNum, ``));
9657
+ g_workObj.frzArrowCssMotions = fillArray(keyNum, ``);
9658
+ g_workObj.dummyFrzArrowCssMotions = fillArray(keyNum, ``);
9534
9659
 
9535
9660
  const scrollDirOptions = g_keyObj[`scrollDir${keyCtrlPtn}`]?.[g_stateObj.scroll] ?? fillArray(keyNum, 1);
9536
9661
 
@@ -9545,7 +9670,11 @@ const getArrowSettings = () => {
9545
9670
  const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
9546
9671
 
9547
9672
  g_workObj.stepX[j] = g_keyObj.blank * stdPos + (g_headerObj.playingWidth - C_ARW_WIDTH) / 2;
9548
- g_workObj.dividePos[j] = ((posj <= divideCnt ? 0 : 1) + (scrollDirOptions[j] === 1 ? 0 : 1) + (g_stateObj.reverse === C_FLG_OFF ? 0 : 1)) % 2;
9673
+ const baseLayer = g_keyObj[`layerGroup${keyCtrlPtn}`]?.[j] || 0;
9674
+ g_workObj.dividePos[j] = baseLayer * 2 + ((posj <= divideCnt ? 0 : 1) + (scrollDirOptions[j] === 1 ? 0 : 1) + (g_stateObj.reverse === C_FLG_OFF ? 0 : 1)) % 2;
9675
+ if (g_stateObj.stepArea === `X-Flower`) {
9676
+ g_workObj.dividePos[j] = (g_workObj.stepX[j] < (g_headerObj.playingWidth - C_ARW_WIDTH) / 2 ? 0 : 1) * 2 + g_workObj.dividePos[j] % 2;
9677
+ }
9549
9678
  g_workObj.scrollDir[j] = (posj <= divideCnt ? 1 : -1) * scrollDirOptions[j] * (g_stateObj.reverse === C_FLG_OFF ? 1 : -1);
9550
9679
 
9551
9680
  eachOrAll.forEach(type => {
@@ -9564,6 +9693,8 @@ const getArrowSettings = () => {
9564
9693
  });
9565
9694
  }
9566
9695
  g_workObj.scrollDirDefault = g_workObj.scrollDir.concat();
9696
+ g_workObj.dividePosDefault = g_workObj.dividePos.concat();
9697
+ g_stateObj.layerNum = Math.max(g_stateObj.layerNum, Math.ceil((Math.max(...g_workObj.dividePos) + 1) / 2) * 2);
9567
9698
 
9568
9699
  Object.keys(g_resultObj).forEach(judgeCnt => g_resultObj[judgeCnt] = 0);
9569
9700
  g_resultObj.spState = ``;
@@ -9584,6 +9715,105 @@ const getArrowSettings = () => {
9584
9715
  g_workObj.backX = (g_workObj.nonDefaultSc && g_headerObj.playingLayout ? g_headerObj.scAreaWidth : 0);
9585
9716
  g_workObj.playingX = g_headerObj.playingX + g_workObj.backX;
9586
9717
 
9718
+ // Swapping設定に応じたステップゾーンの入れ替え
9719
+ if (g_stateObj.swapping.includes(`Mirror`)) {
9720
+
9721
+ let _style = structuredClone(Object.values(g_workObj.shuffleGroupMap));
9722
+ if (g_stateObj.swapping === `Mirror`) {
9723
+ _style.map(_group => _group.reverse());
9724
+
9725
+ } else if (g_stateObj.swapping === `X-Mirror`) {
9726
+ // X-Mirrorの場合、グループの内側だけ入れ替える
9727
+ _style.forEach((group, i) => g_settings.swapPattern.forEach(val => swapGroupNums(_style, group, i, val)));
9728
+ }
9729
+
9730
+ // 入れ替えた結果に合わせてX座標位置を入れ替える
9731
+ g_workObj.stepX_df = structuredClone(g_workObj.stepX);
9732
+ _style.forEach((_group, _i) => {
9733
+ _group.forEach((_val, _j) => {
9734
+ g_workObj.stepX[_group[_j]] = g_workObj.stepX_df[g_workObj.shuffleGroupMap[_i][_j]];
9735
+ });
9736
+ });
9737
+ }
9738
+
9739
+ // FrzReturnの初期化
9740
+ g_workObj.frzReturnFlg = false;
9741
+
9742
+ // AutoRetryの初期化
9743
+ g_workObj.autoRetryFlg = false;
9744
+
9745
+ // Camoufrageの設定
9746
+ if (!g_stateObj.rotateEnabled) {
9747
+
9748
+ // 矢印の回転が無効の場合は、設定を変える
9749
+ if (g_stateObj.camoufrage === `Arrow`) {
9750
+ g_stateObj.camoufrage = C_FLG_OFF;
9751
+ } else if (g_stateObj.camoufrage === C_FLG_ALL) {
9752
+ g_stateObj.camoufrage = `Color`;
9753
+ }
9754
+ g_settings.camoufrageNum = g_settings.camoufrages.findIndex(val => val === g_stateObj.camoufrage);
9755
+ }
9756
+ if (g_stateObj.camoufrage !== C_FLG_OFF) {
9757
+ const eachOrAll = [``, `All`];
9758
+ const keyNum = g_keyObj[`chara${g_keyObj.currentKey}_${g_keyObj.currentPtn}`].length;
9759
+
9760
+ // 位置変更用の配列を作成
9761
+ const randArray = [...Array(keyNum).keys()].map(_i => _i);
9762
+ let _i = randArray.length;
9763
+ while (_i) {
9764
+ const _j = Math.floor(Math.random() * _i--);
9765
+ [randArray[_i], randArray[_j]] = [randArray[_j], randArray[_i]];
9766
+ }
9767
+
9768
+ // 位置変更用の配列に従い、初期矢印・初期色の位置変更
9769
+ const getSwapArray = (_array) => {
9770
+ const _copiedArray = structuredClone(_array);
9771
+ return _array.map((_val, _i) => _array[_i] = _copiedArray[randArray[_i]]);
9772
+ };
9773
+ if (g_stateObj.camoufrage === `Arrow` || g_stateObj.camoufrage === C_FLG_ALL) {
9774
+
9775
+ // 矢印ヒット時に元の矢印がわかるようにするため、あえて g_workObj.stepHitRtn はそのままにする
9776
+ g_workObj.stepRtn = getSwapArray(g_workObj.stepRtn);
9777
+ g_workObj.arrowRtn = getSwapArray(g_workObj.arrowRtn);
9778
+ }
9779
+ eachOrAll.forEach(type => {
9780
+ if (g_stateObj.camoufrage === `Color` || g_stateObj.camoufrage === C_FLG_ALL) {
9781
+
9782
+ // ダミー矢印は対象外
9783
+ g_workObj[`arrowColors${type}`] = getSwapArray(g_workObj[`arrowColors${type}`]);
9784
+ g_workObj[`arrowShadowColors${type}`] = getSwapArray(g_workObj[`arrowShadowColors${type}`]);
9785
+
9786
+ g_typeLists.frzColor.forEach(frzType => {
9787
+ g_workObj[`frz${frzType}Colors${type}`] = getSwapArray(g_workObj[`frz${frzType}Colors${type}`]);
9788
+ });
9789
+ g_workObj[`frzNormalShadowColors${type}`] = getSwapArray(g_workObj[`frzNormalShadowColors${type}`]);
9790
+ g_workObj[`frzHitShadowColors${type}`] = getSwapArray(g_workObj[`frzHitShadowColors${type}`]);
9791
+ }
9792
+ });
9793
+
9794
+ // 位置変更用の配列に従い、個別・全体色変化の位置変更
9795
+ if (g_stateObj.camoufrage === `Color` || g_stateObj.camoufrage === C_FLG_ALL) {
9796
+ const getSwapList = (_array) => {
9797
+ const _copiedArray = structuredClone(_array);
9798
+ return _array.map((_val, _i) => _array[_i] = randArray[_copiedArray[_i]]);
9799
+ };
9800
+ [`mkColor`, `mkColorShadow`, `mkFColor`, `mkFColorShadow`].forEach(type => {
9801
+ if (g_workObj[type] !== undefined) {
9802
+ for (let j = 0; j < g_workObj[type].length; j++) {
9803
+ if (g_workObj[type][j] === undefined) {
9804
+ continue;
9805
+ }
9806
+ g_workObj[type][j] = getSwapList(g_workObj[type][j]);
9807
+ }
9808
+ }
9809
+ });
9810
+ }
9811
+ }
9812
+
9813
+ // Shaking: Drunkでの画面揺れ設定 (X方向、Y方向)
9814
+ g_workObj.drunkXFlg = false;
9815
+ g_workObj.drunkYFlg = false;
9816
+
9587
9817
  if (g_stateObj.dataSaveFlg) {
9588
9818
  // ローカルストレージへAdjustment, HitPosition, Volume設定を保存
9589
9819
  g_storeSettings.forEach(setting => g_localStorage[setting] = g_stateObj[setting]);
@@ -9705,8 +9935,8 @@ const mainInit = () => {
9705
9935
  // ステップゾーン、矢印のメインスプライトを作成
9706
9936
  const mainSprite = createEmptySprite(divRoot, `mainSprite`, {
9707
9937
  x: g_workObj.playingX, y: g_posObj.stepY - C_STEP_Y + g_headerObj.playingY, w: g_headerObj.playingWidth, h: g_headerObj.playingHeight,
9708
- transform: `scale(${g_keyObj.scale})`,
9709
9938
  });
9939
+ addTransform(`mainSprite`, `root`, `scale(${g_keyObj.scale})`);
9710
9940
 
9711
9941
  // 曲情報・判定カウント用スプライトを作成(メインスプライトより上位)
9712
9942
  const infoSprite = createEmptySprite(divRoot, `infoSprite`, { x: g_workObj.playingX, y: g_headerObj.playingY, w: g_headerObj.playingWidth, h: g_headerObj.playingHeight });
@@ -9739,51 +9969,48 @@ const mainInit = () => {
9739
9969
  let speedCnts = 0;
9740
9970
  let boostCnts = 0;
9741
9971
  let keychCnts = 0;
9742
- const flatMode = g_stateObj.d_stepzone === `FlatBar` || g_stateObj.scroll.endsWith(`Flat`) || g_keyObj[`flatMode${keyCtrlPtn}`];
9743
- const stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
9744
9972
 
9745
- for (let j = 0; j < keyNum; j++) {
9746
- const colorPos = g_keyObj[`color${keyCtrlPtn}`][j];
9973
+ g_workObj.flatMode = g_stateObj.d_stepzone === `FlatBar` ||
9974
+ g_stateObj.scroll.endsWith(`Flat`) ||
9975
+ g_keyObj[`flatMode${keyCtrlPtn}`] ||
9976
+ (g_stateObj.stepArea === `Halfway` &&
9977
+ g_keyObj[`div${keyCtrlPtn}`] < g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length);
9978
+ g_workObj.stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || g_workObj.flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
9747
9979
 
9748
- // ステップゾーンルート
9749
- const stepRoot = createEmptySprite(mainSprite, `stepRoot${j}`, {
9750
- x: g_workObj.stepX[j], y: C_STEP_Y + g_posObj.reverseStepY * g_workObj.dividePos[j],
9751
- w: C_ARW_WIDTH, h: C_ARW_WIDTH,
9752
- });
9980
+ // Hidden+, Sudden+用のライン、パーセント表示
9981
+ const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
9982
+ [`filterBar0`, `filterBar1`, `borderBar0`, `borderBar1`].forEach(obj =>
9983
+ mainSprite.appendChild(createColorObject2(obj, g_lblPosObj.filterBar, filterCss)));
9984
+ borderBar0.style.top = wUnit(g_posObj.stepDiffY + g_stateObj.hitPosition);
9985
+ borderBar1.style.top = wUnit(g_posObj.stepDiffY + g_posObj.arrowHeight - g_stateObj.hitPosition);
9753
9986
 
9754
- // 矢印の内側を塗りつぶすか否か
9755
- if (g_headerObj.setShadowColor[colorPos] !== ``) {
9756
- stepRoot.appendChild(
9757
- createColorObject2(`stepShadow${j}`, {
9758
- rotate: g_workObj.stepRtn[j], styleName: `ShadowStep`,
9759
- opacity: 0.7, display: stepZoneDisp,
9760
- }, g_cssObj.main_objStepShadow)
9761
- );
9987
+ if (g_appearanceRanges.includes(g_stateObj.appearance)) {
9988
+ mainSprite.appendChild(createDivCss2Label(`filterView`, ``, g_lblPosObj.filterView));
9989
+ if (g_stateObj.d_filterline === C_FLG_ON) {
9990
+ $id(`filterView`).opacity = g_stateObj.opacity / 100;
9991
+ $id(`filterBar0`).opacity = g_stateObj.opacity / 100;
9992
+ $id(`filterBar1`).opacity = g_stateObj.opacity / 100;
9762
9993
  }
9994
+ }
9763
9995
 
9764
- appearStepZone(j, C_DIS_NONE);
9765
-
9766
- // ステップゾーン
9767
- multiAppend(stepRoot,
9768
-
9769
- // 本体
9770
- createColorObject2(`step${j}`, {
9771
- rotate: g_workObj.stepRtn[j], styleName: `Step`, display: stepZoneDisp,
9772
- }, g_cssObj.main_stepDefault),
9773
-
9774
- // 空押し
9775
- createColorObject2(`stepDiv${j}`, {
9776
- rotate: g_workObj.stepRtn[j], styleName: `Step`, display: C_DIS_NONE,
9777
- }, g_cssObj.main_stepKeyDown),
9778
-
9779
- // ヒット時モーション
9780
- createColorObject2(`stepHit${j}`, Object.assign(g_lblPosObj.stepHit, {
9781
- rotate: g_workObj.stepHitRtn[j], styleName: `StepHit`, opacity: 0,
9782
- }), g_cssObj.main_stepDefault),
9996
+ // mainSprite配下に層別のスプライトを作成し、ステップゾーン・矢印本体・フリーズアローヒット部分に分ける
9997
+ const mainSpriteN = [], stepSprite = [], arrowSprite = [], frzHitSprite = [];
9998
+ const mainCommonPos = { w: g_headerObj.playingWidth, h: g_posObj.arrowHeight };
9999
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
10000
+ const mainSpriteJ = createEmptySprite(mainSprite, `mainSprite${j}`, mainCommonPos);
10001
+ mainSpriteN.push(mainSpriteJ);
10002
+ addTransform(`mainSprite${j}`, `mainSprite${j}`,
10003
+ g_keyObj[`layerTrans${keyCtrlPtn}`]?.[0]?.[Math.floor(j / 2) + (j + Number(g_stateObj.reverse === C_FLG_ON)) % 2]);
10004
+ stepSprite.push(createEmptySprite(mainSpriteJ, `stepSprite${j}`, mainCommonPos));
10005
+ arrowSprite.push(createEmptySprite(mainSpriteJ, `arrowSprite${j}`, Object.assign({ y: g_workObj.hitPosition * (j % 2 === 0 ? 1 : -1) }, mainCommonPos)));
10006
+ frzHitSprite.push(createEmptySprite(mainSpriteJ, `frzHitSprite${j}`, mainCommonPos));
10007
+ }
9783
10008
 
9784
- );
10009
+ // ステップゾーン、フリーズアローヒット部分の生成
10010
+ for (let j = 0; j < keyNum; j++) {
10011
+ makeStepZone(j, keyCtrlPtn);
9785
10012
  }
9786
- if (flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
10013
+ if (g_workObj.flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
9787
10014
 
9788
10015
  // スクロール名に`R-`が含まれていればリバースと見做す
9789
10016
  const reverseFlg = g_stateObj.reverse === C_FLG_ON || g_stateObj.scroll.startsWith(`R-`);
@@ -9795,66 +10022,25 @@ const mainInit = () => {
9795
10022
  lineY.push(lineY[0], lineY[1]);
9796
10023
  reverses.push(!reverses[0], !reverses[1]);
9797
10024
  }
9798
- lineY.forEach((y, j) => {
9799
- mainSprite.appendChild(
9800
- createColorObject2(`stepBar${j}`, {
9801
- x: 0, y: C_STEP_Y + g_posObj.reverseStepY * Number(reverses[j]) + y,
9802
- w: g_headerObj.playingWidth - 50, h: 1, styleName: `lifeBar`,
9803
- }, g_cssObj.life_Failed)
9804
- );
9805
- });
9806
-
9807
- }
9808
-
9809
- // Hidden+, Sudden+用のライン、パーセント表示
9810
- const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
9811
- [`filterBar0`, `filterBar1`, `borderBar0`, `borderBar1`].forEach(obj =>
9812
- mainSprite.appendChild(createColorObject2(obj, g_lblPosObj.filterBar, filterCss)));
9813
- borderBar0.style.top = wUnit(g_posObj.stepDiffY + g_workObj.hitPosition);
9814
- borderBar1.style.top = wUnit(g_posObj.stepDiffY + g_posObj.arrowHeight - g_workObj.hitPosition);
9815
-
9816
- if (g_appearanceRanges.includes(g_stateObj.appearance)) {
9817
- mainSprite.appendChild(createDivCss2Label(`filterView`, ``, g_lblPosObj.filterView));
9818
- if (g_stateObj.d_filterline === C_FLG_ON) {
9819
- [`filterBar0`, `filterBar1`, `filterView`].forEach(obj => $id(obj).opacity = g_stateObj.opacity / 100);
10025
+ for (let k = 0; k < g_stateObj.layerNum; k += 2) {
10026
+ lineY.forEach((y, j) => {
10027
+ stepSprite[Number(reverses[j]) + k].appendChild(
10028
+ createColorObject2(`stepBar${j + k}`, {
10029
+ x: 0, y: C_STEP_Y + g_posObj.reverseStepY * Number(reverses[j]) + y,
10030
+ w: g_headerObj.playingWidth - 50, h: 1, styleName: `lifeBar`,
10031
+ }, g_cssObj.life_Failed)
10032
+ );
10033
+ });
9820
10034
  }
9821
10035
  }
9822
10036
 
9823
- // 矢印・フリーズアロー描画スプライト(ステップゾーンの上に配置)
9824
- const arrowSprite = [
9825
- createEmptySprite(mainSprite, `arrowSprite0`, { y: g_workObj.hitPosition, w: g_headerObj.playingWidth, h: g_posObj.arrowHeight }),
9826
- createEmptySprite(mainSprite, `arrowSprite1`, { y: -g_workObj.hitPosition, w: g_headerObj.playingWidth, h: g_posObj.arrowHeight }),
9827
- ];
10037
+ // StepArea処理
10038
+ g_stepAreaFunc[g_stateObj.stepArea]();
9828
10039
 
9829
10040
  // Appearanceのオプション適用時は一部描画を隠す
9830
10041
  changeAppearanceFilter(g_appearanceRanges.includes(g_stateObj.appearance) ?
9831
10042
  g_hidSudObj.filterPos : g_hidSudObj.filterPosDefault[g_stateObj.appearance]);
9832
10043
 
9833
- for (let j = 0; j < keyNum; j++) {
9834
-
9835
- // フリーズアローヒット部分
9836
- const frzHit = createEmptySprite(mainSprite, `frzHit${j}`, {
9837
- x: g_workObj.stepX[j], y: C_STEP_Y + g_posObj.reverseStepY * g_workObj.dividePos[j],
9838
- w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
9839
- });
9840
- if (isNaN(parseFloat(g_workObj.arrowRtn[j]))) {
9841
- multiAppend(frzHit,
9842
- createColorObject2(`frzHitShadow${j}`, {
9843
- rotate: g_workObj.arrowRtn[j], styleName: `Shadow`,
9844
- }, g_cssObj.main_objShadow),
9845
- createColorObject2(`frzHitTop${j}`, {
9846
- background: g_workObj.frzHitColors[j], rotate: g_workObj.arrowRtn[j],
9847
- })
9848
- );
9849
- } else {
9850
- frzHit.appendChild(
9851
- createColorObject2(`frzHitTop${j}`, Object.assign(g_lblPosObj.frzHitTop, {
9852
- rotate: g_workObj.arrowRtn[j], styleName: `Shadow`,
9853
- }), g_cssObj.main_frzHitTop)
9854
- );
9855
- }
9856
- }
9857
-
9858
10044
  // 現在の矢印・フリーズアローの速度、個別加算速度の初期化 (速度変化時に直す)
9859
10045
  g_workObj.currentSpeed = 2;
9860
10046
  g_workObj.boostSpd = 1;
@@ -10113,6 +10299,12 @@ const mainInit = () => {
10113
10299
  // ユーザカスタムイベント(初期)
10114
10300
  g_customJsObj.main.forEach(func => func());
10115
10301
 
10302
+ // mainSpriteのtransform追加処理
10303
+ addTransform(`mainSprite`, `playWindow`, g_playWindowFunc[g_stateObj.playWindow]());
10304
+
10305
+ // EffectのArrowEffect追加処理
10306
+ g_effectFunc[g_stateObj.effect]();
10307
+
10116
10308
  /**
10117
10309
  * キーを押したときの処理
10118
10310
  */
@@ -10518,7 +10710,7 @@ const mainInit = () => {
10518
10710
  */
10519
10711
  const makeArrow = (_attrs, _arrowCnt, _name, _color, _shadowColor) => {
10520
10712
  const _j = _attrs.pos;
10521
- const dividePos = g_workObj.dividePos[_j];
10713
+ const dividePos = g_workObj.dividePos[_j] % 2;
10522
10714
  const colorPos = g_keyObj[`color${keyCtrlPtn}`][_j];
10523
10715
 
10524
10716
  const arrowName = `${_name}${_j}_${_arrowCnt}`;
@@ -10526,7 +10718,7 @@ const mainInit = () => {
10526
10718
  (_attrs.initY * g_workObj.boostSpd +
10527
10719
  _attrs.initBoostY * g_workObj.boostDir) * g_workObj.scrollDir[_j];
10528
10720
 
10529
- const stepRoot = createEmptySprite(arrowSprite[dividePos], arrowName, {
10721
+ const stepRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], arrowName, {
10530
10722
  x: g_workObj.stepX[_j], y: firstPosY, w: C_ARW_WIDTH, h: C_ARW_WIDTH,
10531
10723
  });
10532
10724
  /**
@@ -10553,7 +10745,7 @@ const mainInit = () => {
10553
10745
  // 矢印色の設定
10554
10746
  // - 枠/塗りつぶし色: g_attrObj[arrowName].Arrow / ArrowShadow
10555
10747
  g_typeLists.arrowColor.forEach(val => g_attrObj[arrowName][`Arrow${val}`] = g_workObj[`${_name}${val}Colors`][_j]);
10556
- arrowSprite[dividePos].appendChild(stepRoot);
10748
+ arrowSprite[g_workObj.dividePos[_j]].appendChild(stepRoot);
10557
10749
 
10558
10750
  if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
10559
10751
  stepRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
@@ -10581,6 +10773,7 @@ const mainInit = () => {
10581
10773
  stepRoot.appendChild(createColorObject2(`${_name}Top${_j}_${_arrowCnt}`, {
10582
10774
  background: _color, rotate: g_workObj.arrowRtn[_j],
10583
10775
  }));
10776
+ g_customJsObj.makeArrow.forEach(func => func(_attrs, arrowName, _name, _arrowCnt));
10584
10777
  };
10585
10778
 
10586
10779
  /**
@@ -10621,7 +10814,7 @@ const mainInit = () => {
10621
10814
  */
10622
10815
  const makeFrzArrow = (_attrs, _arrowCnt, _name, _normalColor, _barColor, _shadowColor) => {
10623
10816
  const _j = _attrs.pos;
10624
- const dividePos = g_workObj.dividePos[_j];
10817
+ const dividePos = g_workObj.dividePos[_j] % 2;
10625
10818
  const frzNo = `${_j}_${_arrowCnt}`;
10626
10819
  const frzName = `${_name}${frzNo}`;
10627
10820
  const firstPosY = C_STEP_Y + g_posObj.reverseStepY * dividePos +
@@ -10629,7 +10822,7 @@ const mainInit = () => {
10629
10822
  _attrs.initBoostY * g_workObj.boostDir) * g_workObj.scrollDir[_j];
10630
10823
  const firstBarLength = g_workObj[`mk${toCapitalize(_name)}Length`][_j][(_arrowCnt - 1) * 2] * g_workObj.boostSpd;
10631
10824
 
10632
- const frzRoot = createEmptySprite(arrowSprite[dividePos], frzName, {
10825
+ const frzRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], frzName, {
10633
10826
  x: g_workObj.stepX[_j], y: firstPosY, w: C_ARW_WIDTH, h: C_ARW_WIDTH + firstBarLength,
10634
10827
  });
10635
10828
  /**
@@ -10667,12 +10860,7 @@ const mainInit = () => {
10667
10860
  // - 通常時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Normal / NormalShadow / NormalBar
10668
10861
  // - ヒット時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Hit / HitShadow / HitBar
10669
10862
  g_typeLists.frzColor.forEach(val => g_attrObj[frzName][val] = g_workObj[`${_name}${val}Colors`][_j]);
10670
- arrowSprite[dividePos].appendChild(frzRoot);
10671
-
10672
- if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
10673
- frzRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
10674
- frzRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
10675
- }
10863
+ arrowSprite[g_workObj.dividePos[_j]].appendChild(frzRoot);
10676
10864
  let shadowColor = _shadowColor === `Default` ? _normalColor : _shadowColor;
10677
10865
 
10678
10866
  /**
@@ -10686,30 +10874,49 @@ const mainInit = () => {
10686
10874
  x: 5, y: g_attrObj[frzName].barY, w: C_ARW_WIDTH - 10, h: firstBarLength, background: _barColor, styleName: `frzBar`,
10687
10875
  opacity: 0.75,
10688
10876
  }),
10877
+ );
10878
+ const frzTopRoot = createEmptySprite(frzRoot, `${_name}TopRoot${frzNo}`,
10879
+ { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
10880
+ const frzBtmRoot = createEmptySprite(frzRoot, `${_name}BtmRoot${frzNo}`,
10881
+ { x: 0, y: g_attrObj[frzName].btmY, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
10882
+
10883
+ multiAppend(frzTopRoot,
10689
10884
 
10690
- // 開始矢印の塗り部分。ヒット時は前面に出て光る。
10885
+ // 開始矢印の塗り部分。ヒット時は前面に表示
10691
10886
  createColorObject2(`${_name}TopShadow${frzNo}`, {
10692
10887
  background: shadowColor, rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
10693
10888
  }, g_cssObj.main_objShadow),
10694
10889
 
10695
- // 開始矢印。ヒット時は隠れる。
10890
+ // 開始矢印。ヒット時は非表示
10696
10891
  createColorObject2(`${_name}Top${frzNo}`, {
10697
10892
  background: _normalColor, rotate: g_workObj.arrowRtn[_j],
10698
10893
  }),
10894
+ );
10895
+
10896
+ multiAppend(frzBtmRoot,
10699
10897
 
10700
10898
  // 後発矢印の塗り部分
10701
10899
  createColorObject2(`${_name}BtmShadow${frzNo}`, {
10702
- x: 0, y: g_attrObj[frzName].btmY,
10703
10900
  background: shadowColor, rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
10704
10901
  }, g_cssObj.main_objShadow),
10705
10902
 
10706
10903
  // 後発矢印
10707
10904
  createColorObject2(`${_name}Btm${frzNo}`, {
10708
- x: 0, y: g_attrObj[frzName].btmY,
10709
10905
  background: _normalColor, rotate: g_workObj.arrowRtn[_j],
10710
10906
  }),
10711
10907
 
10712
10908
  );
10909
+ if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
10910
+ frzRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
10911
+ frzRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
10912
+ }
10913
+ if (g_workObj[`${_name}ArrowCssMotions`][_j] !== ``) {
10914
+ [frzTopRoot, frzBtmRoot].forEach(obj => {
10915
+ obj.classList.add(g_workObj[`${_name}ArrowCssMotions`][_j]);
10916
+ obj.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
10917
+ });
10918
+ }
10919
+ g_customJsObj.makeFrzArrow.forEach(func => func(_attrs, frzName, _name, _arrowCnt));
10713
10920
  };
10714
10921
 
10715
10922
  /**
@@ -10755,8 +10962,7 @@ const mainInit = () => {
10755
10962
 
10756
10963
  $id(`${_name}Bar${frzNo}`).height = wUnit(currentFrz.frzBarLength);
10757
10964
  $id(`${_name}Bar${frzNo}`).top = wUnit(currentFrz.barY);
10758
- $id(`${_name}Btm${frzNo}`).top = wUnit(currentFrz.btmY);
10759
- $id(`${_name}BtmShadow${frzNo}`).top = wUnit(currentFrz.btmY);
10965
+ $id(`${_name}BtmRoot${frzNo}`).top = wUnit(currentFrz.btmY);
10760
10966
 
10761
10967
  if (!checkKeyUpFunc[`${_name}${g_stateObj.autoAll}`](_j)) {
10762
10968
  currentFrz.keyUpFrame++;
@@ -10821,6 +11027,9 @@ const mainInit = () => {
10821
11027
  g_audio.volume = Math.max((g_audio.volume - (3 * g_stateObj.volume / 100 * C_FRM_AFTERFADE / g_scoreObj.fadeOutTerm) / 1000), 0);
10822
11028
  }
10823
11029
 
11030
+ // 画面揺れの設定
11031
+ g_shakingFunc[g_stateObj.shaking]();
11032
+
10824
11033
  // ユーザカスタムイベント(フレーム毎)
10825
11034
  g_customJsObj.mainEnterFrame.forEach(func => func());
10826
11035
 
@@ -11035,6 +11244,78 @@ const mainInit = () => {
11035
11244
  g_timeoutEvtId = setTimeout(flowTimeline, 1000 / g_fps);
11036
11245
  };
11037
11246
 
11247
+ /**
11248
+ * ステップゾーン、フリーズアローヒット部分の生成
11249
+ * @param {number} _j
11250
+ * @param {string} _keyCtrlPtn
11251
+ */
11252
+ const makeStepZone = (_j, _keyCtrlPtn) => {
11253
+
11254
+ const colorPos = g_keyObj[`color${_keyCtrlPtn}`][_j];
11255
+ const stepSpriteJ = document.getElementById(`stepSprite${g_workObj.dividePos[_j]}`);
11256
+ const frzHitSpriteJ = document.getElementById(`frzHitSprite${g_workObj.dividePos[_j]}`);
11257
+
11258
+ // ステップゾーンルート
11259
+ const stepRoot = createEmptySprite(stepSpriteJ, `stepRoot${_j}`, {
11260
+ x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
11261
+ w: C_ARW_WIDTH, h: C_ARW_WIDTH,
11262
+ });
11263
+
11264
+ // 矢印の内側を塗りつぶすか否か
11265
+ if (g_headerObj.setShadowColor[colorPos] !== ``) {
11266
+ stepRoot.appendChild(
11267
+ createColorObject2(`stepShadow${_j}`, {
11268
+ rotate: g_workObj.stepRtn[_j], styleName: `ShadowStep`,
11269
+ opacity: 0.7, display: g_workObj.stepZoneDisp,
11270
+ }, g_cssObj.main_objStepShadow)
11271
+ );
11272
+ }
11273
+
11274
+ appearStepZone(_j, C_DIS_NONE);
11275
+
11276
+ // ステップゾーン
11277
+ multiAppend(stepRoot,
11278
+
11279
+ // 本体
11280
+ createColorObject2(`step${_j}`, {
11281
+ rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: g_workObj.stepZoneDisp,
11282
+ }, g_cssObj.main_stepDefault),
11283
+
11284
+ // 空押し
11285
+ createColorObject2(`stepDiv${_j}`, {
11286
+ rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: C_DIS_NONE,
11287
+ }, g_cssObj.main_stepKeyDown),
11288
+
11289
+ // ヒット時モーション
11290
+ createColorObject2(`stepHit${_j}`, Object.assign(g_lblPosObj.stepHit, {
11291
+ rotate: g_workObj.stepHitRtn[_j], styleName: `StepHit`, opacity: 0,
11292
+ }), g_cssObj.main_stepDefault),
11293
+
11294
+ );
11295
+
11296
+ // フリーズアローヒット部分
11297
+ const frzHit = createEmptySprite(frzHitSpriteJ, `frzHit${_j}`, {
11298
+ x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
11299
+ w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
11300
+ });
11301
+ if (isNaN(parseFloat(g_workObj.arrowRtn[_j]))) {
11302
+ multiAppend(frzHit,
11303
+ createColorObject2(`frzHitShadow${_j}`, {
11304
+ rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
11305
+ }, g_cssObj.main_objShadow),
11306
+ createColorObject2(`frzHitTop${_j}`, {
11307
+ background: g_workObj.frzHitColors[_j], rotate: g_workObj.arrowRtn[_j],
11308
+ })
11309
+ );
11310
+ } else {
11311
+ frzHit.appendChild(
11312
+ createColorObject2(`frzHitTop${_j}`, Object.assign(g_lblPosObj.frzHitTop, {
11313
+ rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
11314
+ }), g_cssObj.main_frzHitTop)
11315
+ );
11316
+ }
11317
+ };
11318
+
11038
11319
  /**
11039
11320
  * アルファマスクの再描画 (Appearance: Hidden+, Sudden+ 用)
11040
11321
  * @param {number} _num
@@ -11051,12 +11332,12 @@ const changeAppearanceFilter = (_num = 10) => {
11051
11332
  const topShape = `inset(${_num}% 0% ${numPlus}% 0%)`;
11052
11333
  const bottomShape = `inset(${numPlus}% 0% ${_num}% 0%)`;
11053
11334
 
11054
- $id(`arrowSprite${topNum}`).clipPath = topShape;
11055
- $id(`arrowSprite${bottomNum}`).clipPath = bottomShape;
11056
-
11057
- $id(`filterBar0`).top = wUnit(g_posObj.arrowHeight * _num / MAX_FILTER_POS - g_stateObj.hitPosition);
11058
- $id(`filterBar1`).top = wUnit(g_posObj.arrowHeight * (MAX_FILTER_POS - _num) / MAX_FILTER_POS + g_stateObj.hitPosition);
11059
-
11335
+ for (let j = 0; j < g_stateObj.layerNum; j += 2) {
11336
+ $id(`arrowSprite${topNum + j}`).clipPath = topShape;
11337
+ $id(`arrowSprite${bottomNum + j}`).clipPath = bottomShape;
11338
+ }
11339
+ $id(`filterBar0`).top = wUnit(parseFloat($id(`arrowSprite${topNum}`).top) + g_posObj.arrowHeight * _num / MAX_FILTER_POS);
11340
+ $id(`filterBar1`).top = wUnit(parseFloat($id(`arrowSprite${bottomNum}`).top) + g_posObj.arrowHeight * (MAX_FILTER_POS - _num) / MAX_FILTER_POS);
11060
11341
  if (g_appearanceRanges.includes(g_stateObj.appearance)) {
11061
11342
  $id(`filterView`).top =
11062
11343
  $id(`filterBar${g_hidSudObj.std[g_stateObj.appearance][g_stateObj.reverse]}`).top;
@@ -11113,6 +11394,45 @@ const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) =
11113
11394
  });
11114
11395
  };
11115
11396
 
11397
+ /**
11398
+ * FrzReturnの追加処理
11399
+ * @param {number} _rad 回転角度
11400
+ * @param {number[]} _axis 回転軸
11401
+ */
11402
+ const changeReturn = (_rad, _axis) => {
11403
+ g_workObj.frzReturnFlg = true;
11404
+ let _transform = `rotate${_axis[0]}(${_rad}deg)`;
11405
+ if (_axis[1] !== undefined) {
11406
+ _transform += ` rotate${_axis[1]}(${_rad}deg)`;
11407
+ }
11408
+ if (document.getElementById(`mainSprite`) !== null) {
11409
+ addTransform(`mainSprite`, `frzReturn`, _transform);
11410
+
11411
+ if (_rad < 360 && g_workObj.frzReturnFlg) {
11412
+ setTimeout(() => changeReturn(_rad + 4, _axis), 20);
11413
+ } else {
11414
+ addTransform(`mainSprite`, `frzReturn`, ``);
11415
+ g_workObj.frzReturnFlg = false;
11416
+ }
11417
+ }
11418
+ }
11419
+
11420
+ /**
11421
+ * AutoRetryの設定
11422
+ * @param {number} _retryNum AutoRetryの設定位置(g_settings.autoRetryNum)
11423
+ */
11424
+ const quickRetry = (_retryNum) => {
11425
+ if (g_settings.autoRetryNum >= _retryNum && !g_workObj.autoRetryFlg) {
11426
+ g_workObj.autoRetryFlg = true;
11427
+ setTimeout(() => {
11428
+ g_audio.pause();
11429
+ clearTimeout(g_timeoutEvtId);
11430
+ clearWindow();
11431
+ musicAfterLoaded();
11432
+ }, 16);
11433
+ }
11434
+ };
11435
+
11116
11436
  /**
11117
11437
  * 個別・全体色変化
11118
11438
  * @param {number[]} _mkColor
@@ -11148,7 +11468,7 @@ const changeCssMotions = (_header, _name, _frameNum) => {
11148
11468
  const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
11149
11469
  g_workObj[`mk${toCapitalize(camelHeader)}CssMotion`][_frameNum]?.forEach((targetj, j) =>
11150
11470
  g_workObj[`${camelHeader}CssMotions`][targetj] =
11151
- g_workObj[`mk${toCapitalize(camelHeader)}CssMotionName`][_frameNum][2 * j + g_workObj.dividePos[targetj]]);
11471
+ g_workObj[`mk${toCapitalize(camelHeader)}CssMotionName`][_frameNum][2 * j + (g_workObj.dividePos[targetj] % 2)]);
11152
11472
  };
11153
11473
 
11154
11474
  /**
@@ -11158,7 +11478,9 @@ const changeCssMotions = (_header, _name, _frameNum) => {
11158
11478
  const changeScrollArrowDirs = (_frameNum) =>
11159
11479
  g_workObj.mkScrollchArrow[_frameNum]?.forEach((targetj, j) => {
11160
11480
  g_workObj.scrollDir[targetj] = g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchArrowDir[_frameNum][j];
11161
- g_workObj.dividePos[targetj] = (g_workObj.scrollDir[targetj] === 1 ? 0 : 1);
11481
+ const baseLayer = g_workObj.mkScrollchArrowLayer[_frameNum][j] === -1 ?
11482
+ Math.floor(g_workObj.dividePosDefault[targetj] / 2) : g_workObj.mkScrollchArrowLayer[_frameNum][j];
11483
+ g_workObj.dividePos[targetj] = baseLayer * 2 + (g_workObj.scrollDir[targetj] === 1 ? 0 : 1);
11162
11484
  });
11163
11485
 
11164
11486
  /**
@@ -11168,9 +11490,21 @@ const changeScrollArrowDirs = (_frameNum) =>
11168
11490
  const changeStepY = (_frameNum) =>
11169
11491
  g_workObj.mkScrollchStep[_frameNum]?.forEach((targetj, j) => {
11170
11492
  const dividePos = (g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchStepDir[_frameNum][j] === 1 ? 0 : 1);
11171
- const baseY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
11172
- $id(`stepRoot${targetj}`).top = wUnit(baseY);
11173
- $id(`frzHit${targetj}`).top = wUnit(baseY);
11493
+
11494
+ // 移動元のステップゾーンの不透明度、表示・非表示を退避
11495
+ const _stepOpacity = $id(`stepRoot${targetj}`).opacity;
11496
+ const _stepDisplay = $id(`stepRoot${targetj}`).display;
11497
+
11498
+ // 移動元のステップゾーンを消去
11499
+ document.getElementById(`stepRoot${targetj}`).remove();
11500
+ document.getElementById(`frzHit${targetj}`).remove();
11501
+
11502
+ // レイヤーを変更しステップゾーンを再生成。移動元の不透明度、表示・非表示を反映
11503
+ const baseLayer = g_workObj.mkScrollchStepLayer[_frameNum][j] === -1 ?
11504
+ Math.floor(g_workObj.dividePosDefault[targetj] / 2) : g_workObj.mkScrollchStepLayer[_frameNum][j];
11505
+ g_workObj.dividePos[targetj] = baseLayer * 2 + dividePos;
11506
+ makeStepZone(targetj, `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`);
11507
+ appearStepZone(targetj, _stepDisplay, _stepOpacity);
11174
11508
  });
11175
11509
 
11176
11510
  /**
@@ -11190,9 +11524,10 @@ const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
11190
11524
  }
11191
11525
 
11192
11526
  const styfrzBar = $id(`${_name}Bar${frzNo}`);
11527
+ const styfrzBtmRoot = $id(`${_name}BtmRoot${frzNo}`);
11193
11528
  const styfrzBtm = $id(`${_name}Btm${frzNo}`);
11529
+ const styfrzTopRoot = $id(`${_name}TopRoot${frzNo}`);
11194
11530
  const styfrzTop = $id(`${_name}Top${frzNo}`);
11195
- const styfrzTopShadow = $id(`${_name}TopShadow${frzNo}`);
11196
11531
  const styfrzBtmShadow = $id(`${_name}BtmShadow${frzNo}`);
11197
11532
 
11198
11533
  // フリーズアロー位置の修正(ステップゾーン上に来るように)
@@ -11227,11 +11562,9 @@ const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
11227
11562
  styfrzBar.top = wUnit(currentFrz.barY);
11228
11563
  styfrzBar.height = wUnit(currentFrz.frzBarLength);
11229
11564
  styfrzBar.background = getColor(`HitBar`);
11230
- styfrzBtm.top = wUnit(currentFrz.btmY);
11565
+ styfrzBtmRoot.top = wUnit(currentFrz.btmY);
11231
11566
  styfrzBtm.background = tmpHitColor;
11232
- styfrzTop.top = wUnit(- hitPos);
11233
- styfrzTopShadow.top = styfrzTop.top;
11234
- styfrzBtmShadow.top = styfrzBtm.top;
11567
+ styfrzTopRoot.top = wUnit(- hitPos);
11235
11568
  if (_name === `frz`) {
11236
11569
  const tmpShadowColor = getColor(`HitShadow`);
11237
11570
  styfrzBtmShadow.background = tmpShadowColor === `Default` ? tmpHitColor : tmpShadowColor;
@@ -11242,6 +11575,12 @@ const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
11242
11575
  }
11243
11576
  }
11244
11577
 
11578
+ // FrzReturnの設定
11579
+ if (g_stateObj.frzReturn !== C_FLG_OFF) {
11580
+ if (!g_workObj.frzReturnFlg) {
11581
+ changeReturn(4, g_frzReturnFunc[g_stateObj.frzReturn]());
11582
+ }
11583
+ }
11245
11584
  g_customJsObj[`judg_${_name}Hit`].forEach(func => func(_difFrame));
11246
11585
  };
11247
11586
 
@@ -11260,6 +11599,13 @@ const changeFailedFrz = (_j, _k) => {
11260
11599
  $id(`frzBar${frzNo}`).background = `#999999`;
11261
11600
  $id(`frzBar${frzNo}`).opacity = 1;
11262
11601
  $id(`frzBtm${frzNo}`).background = `#cccccc`;
11602
+
11603
+ // FrzReturnの設定
11604
+ if (g_stateObj.frzReturn !== C_FLG_OFF) {
11605
+ if (!g_workObj.frzReturnFlg) {
11606
+ changeReturn(4, g_frzReturnFunc[g_stateObj.frzReturn]());
11607
+ }
11608
+ }
11263
11609
  };
11264
11610
 
11265
11611
  /**
@@ -11379,9 +11725,11 @@ const displayDiff = (_difFrame, _fjdg = ``, _justFrames = g_headerObj.justFrames
11379
11725
  } else if (_difFrame > _justFrames) {
11380
11726
  diffJDisp = `<span class="common_diffFast">Fast ${difCnt} Frames</span>`;
11381
11727
  g_resultObj.fast++;
11728
+ quickRetry(4);
11382
11729
  } else if (_difFrame < _justFrames * (-1)) {
11383
11730
  diffJDisp = `<span class="common_diffSlow">Slow ${difCnt} Frames</span>`;
11384
11731
  g_resultObj.slow++;
11732
+ quickRetry(4);
11385
11733
  }
11386
11734
  document.getElementById(`diff${_fjdg}J`).innerHTML = diffJDisp;
11387
11735
  };
@@ -11427,6 +11775,7 @@ const lifeRecovery = () => {
11427
11775
  */
11428
11776
  const lifeDamage = (_excessive = false) => {
11429
11777
  g_workObj.lifeVal -= g_workObj.lifeDmg * (_excessive ? 0.25 : 1);
11778
+ quickRetry(1);
11430
11779
 
11431
11780
  if (g_workObj.lifeVal <= 0) {
11432
11781
  g_workObj.lifeVal = 0;
@@ -11472,6 +11821,14 @@ const judgeRecovery = (_name, _difFrame) => {
11472
11821
  lifeRecovery();
11473
11822
  finishViewing();
11474
11823
 
11824
+ if (g_stateObj.freezeReturn !== C_FLG_OFF) {
11825
+ if ((g_resultObj.ii + g_resultObj.shakin) % 100 === 0 && !g_workObj.frzReturnFlg) {
11826
+ changeReturn(1, g_frzReturnFunc[g_stateObj.frzReturn]());
11827
+ }
11828
+ }
11829
+ if (_name === `shakin`) {
11830
+ quickRetry(3);
11831
+ }
11475
11832
  g_customJsObj[`judg_${_name}`].forEach(func => func(_difFrame));
11476
11833
  };
11477
11834
 
@@ -11509,6 +11866,7 @@ const judgeMatari = _difFrame => {
11509
11866
  changeJudgeCharacter(`matari`, g_lblNameObj.j_matari);
11510
11867
  comboJ.textContent = ``;
11511
11868
  finishViewing();
11869
+ quickRetry(2);
11512
11870
 
11513
11871
  g_customJsObj.judg_matari.forEach(func => func(_difFrame));
11514
11872
  };
@@ -11743,11 +12101,19 @@ const resultInit = () => {
11743
12101
  // 設定の組み立て処理 (Ex: 4x, Brake, Reverse, Sudden+, NoRecovery)
11744
12102
  let playStyleData = [
11745
12103
  `${g_stateObj.speed}${g_lblNameObj.multi}`,
11746
- `${withOptions(g_stateObj.motion, C_FLG_OFF)}`,
12104
+ withOptions(g_stateObj.motion, C_FLG_OFF),
11747
12105
  `${withOptions(g_stateObj.reverse, C_FLG_OFF,
11748
12106
  getStgDetailName(g_stateObj.scroll !== '---' ? 'R-' : 'Reverse'))}${withOptions(g_stateObj.scroll, '---')}`,
11749
- `${withOptions(g_stateObj.appearance, `Visible`)}`,
11750
- `${withOptions(g_stateObj.gauge, g_settings.gauges[0])}`
12107
+ withOptions(g_stateObj.appearance, `Visible`),
12108
+ withOptions(g_stateObj.gauge, g_settings.gauges[0]),
12109
+ withOptions(g_stateObj.playWindow, `Default`),
12110
+ withOptions(g_stateObj.stepArea, `Default`),
12111
+ withOptions(g_stateObj.frzReturn, C_FLG_OFF, `FR:${g_stateObj.frzReturn}`),
12112
+ withOptions(g_stateObj.shaking, C_FLG_OFF),
12113
+ withOptions(g_stateObj.effect, C_FLG_OFF),
12114
+ withOptions(g_stateObj.camoufrage, C_FLG_OFF, `Cmf:${g_stateObj.camoufrage}`),
12115
+ withOptions(g_stateObj.swapping, C_FLG_OFF, `Swap:${g_stateObj.swapping}`),
12116
+ withOptions(g_stateObj.judgRange, `Normal`, `Judg:${g_stateObj.judgRange}`),
11751
12117
  ].filter(value => value !== ``).join(`, `);
11752
12118
 
11753
12119
  // Display設定の組み立て処理 (Ex: Step : FlatBar, Judge, Life : OFF)
@@ -11796,6 +12162,23 @@ const resultInit = () => {
11796
12162
  makeCssResultPlayData(`lblDisplay2Data`, dataRX, g_cssObj.result_style, 5, display2Data),
11797
12163
  );
11798
12164
 
12165
+ // 設定項目が多い場合に2行に分解して表示する処理
12166
+ let playStyleBreakNum = lblStyleData.textContent.length;
12167
+ if (lblStyleData.textContent.length > 60) {
12168
+ for (let j = Math.floor(lblStyleData.textContent.length / 2); j > 0; j--) {
12169
+ if (lblStyleData.textContent[j] === `,`) {
12170
+ playStyleBreakNum = j + 2;
12171
+ break;
12172
+ }
12173
+ }
12174
+ lblStyleData.style.top = `${parseFloat(lblStyleData.style.top) - 3}px`;
12175
+ lblStyleData.innerHTML = `${lblStyleData.textContent.slice(0, playStyleBreakNum)}<br>` +
12176
+ `${lblStyleData.textContent.slice(playStyleBreakNum)}`;
12177
+ lblStyleData.style.fontSize = `${getFontSize(lblStyleData.textContent.slice(0, playStyleBreakNum), 350, getBasicFont(), 10)}px`;
12178
+ } else {
12179
+ lblStyleData.style.fontSize = `${getFontSize(lblStyleData.textContent, 350, getBasicFont(), 14)}px`;
12180
+ }
12181
+
11799
12182
  /**
11800
12183
  * キャラクタ、スコア描画のID共通部、色CSS名、スコア変数名
11801
12184
  * @property {number} pos 表示位置(縦)
@@ -12065,8 +12448,13 @@ const resultInit = () => {
12065
12448
  drawText(unEscapeHtml(mTitleForView[1]), { hy: 2 });
12066
12449
  drawText(`📝 ${unEscapeHtml(g_headerObj.tuning)} / 🎵 ${unEscapeHtml(artistName)}`, { hy: mTitleForView[1] !== `` ? 3 : 2, siz: 12 });
12067
12450
  drawText(unEscapeHtml(difDataForImage), { hy: 4 });
12068
- drawText(playStyleData, { hy: 5 });
12069
12451
 
12452
+ if (playStyleData.length > 60) {
12453
+ drawText(playStyleData.slice(0, playStyleBreakNum), { hy: 5, siz: getFontSize(playStyleData.slice(0, playStyleBreakNum), 370, getBasicFont(), 14) });
12454
+ drawText(playStyleData.slice(playStyleBreakNum), { hy: 6, siz: getFontSize(playStyleData.slice(playStyleBreakNum), 370, getBasicFont(), 14) });
12455
+ } else {
12456
+ drawText(playStyleData, { hy: 5, siz: getFontSize(lblStyleData.textContent, 370, getBasicFont(), 15) });
12457
+ }
12070
12458
  Object.keys(jdgScoreObj).forEach(score => {
12071
12459
  drawText(g_lblNameObj[`j_${score}`], { hy: 7 + jdgScoreObj[score].pos, color: jdgScoreObj[score].dfColor });
12072
12460
  drawText(g_resultObj[score], { x: 200, hy: 7 + jdgScoreObj[score].pos, align: C_ALIGN_RIGHT });