danoniplus 39.0.0 → 39.2.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 : 2025/02/01
7
+ * Revised : 2025/02/08
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 39.0.0`;
12
- const g_revisedDate = `2025/02/01`;
11
+ const g_version = `Ver 39.2.0`;
12
+ const g_revisedDate = `2025/02/08`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -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`);
@@ -3916,6 +3917,7 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3916
3917
 
3917
3918
  const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
3918
3919
  const toString = _str => _str;
3920
+ const toInt = _num => isNaN(parseInt(_num)) ? _num : parseInt(_num);
3919
3921
  const toFloat = _num => isNaN(parseFloat(_num)) ? _num : parseFloat(_num);
3920
3922
  const toKeyCtrlArray = _str =>
3921
3923
  makeBaseArray(_str.split(`/`).map(n => getKeyCtrlVal(n)), g_keyObj.minKeyCtrlNum, 0);
@@ -4270,6 +4272,19 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
4270
4272
  // |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
4271
4273
  newKeyPairParam(newKey, `assist`, `assistPos`);
4272
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
+
4273
4288
  // keyRetry, keyTitleBackのキー名をキーコードに変換
4274
4289
  const keyTypePatterns = Object.keys(g_keyObj).filter(val => val.startsWith(`keyRetry${newKey}`) || val.startsWith(`keyTitleBack${newKey}`));
4275
4290
  keyTypePatterns.forEach(name => g_keyObj[name] = getKeyCtrlVal(g_keyObj[name]));
@@ -6790,7 +6805,7 @@ const keyConfigInit = (_kcType = g_kcType) => {
6790
6805
  [tkObj.keyCtrlPtn, tkObj.keyNum, tkObj.posMax, tkObj.divideCnt];
6791
6806
 
6792
6807
  g_keyCopyLists.simpleDef.forEach(header => updateKeyInfo(header, keyCtrlPtn));
6793
- keyconSprite.style.transform = `scale(${g_keyObj.scale})`;
6808
+ addTransform(`keyconSprite`, `root`, `scale(${g_keyObj.scale})`)
6794
6809
  keyconSprite.style.height = `${parseFloat(keyconSprite.style.height) / ((1 + g_keyObj.scale) / 2)}px`;
6795
6810
  const kWidth = parseInt(keyconSprite.style.width);
6796
6811
  changeSetColor();
@@ -8497,15 +8512,10 @@ const scoreConvert = (_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
8497
8512
  const frame = calcFrame(tmpScrollchData[0]);
8498
8513
  const arrowNum = parseFloat(tmpScrollchData[1]);
8499
8514
  const scrollDir = parseFloat(tmpScrollchData[2] ?? `1`);
8515
+ const layerGroup = parseFloat(tmpScrollchData[3] ?? `-1`);
8500
8516
 
8501
- scrollchData.push([frame, arrowNum, frame, scrollDir]);
8517
+ scrollchData.push([frame, arrowNum, frame, scrollDir, layerGroup]);
8502
8518
  });
8503
-
8504
- // 個別のスクロール変化が存在する場合、StepAreaを自動リセット
8505
- if (scrollchData.length > 0) {
8506
- g_stateObj.stepArea = `Default`;
8507
- g_settings.stepAreaNum = 0;
8508
- }
8509
8519
  return scrollchData.sort((_a, _b) => _a[0] - _b[0]).flat();
8510
8520
  }
8511
8521
  return [];
@@ -9289,7 +9299,7 @@ const pushArrows = (_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
9289
9299
  g_typeLists.arrow.forEach(header =>
9290
9300
  calcDataTiming(`cssMotion`, header, pushCssMotions, { _calcFrameFlg: true }));
9291
9301
 
9292
- calcDataTiming(`scrollch`, ``, pushScrollchs, { _calcFrameFlg: true });
9302
+ calcDataTiming(`scrollch`, ``, pushScrollchs, { _term: 5, _calcFrameFlg: true });
9293
9303
 
9294
9304
  g_fadeinStockList.forEach(type =>
9295
9305
  _dataObj[`${type}Data`] = calcAnimationData(type, _dataObj[`${type}Data`]));
@@ -9555,29 +9565,32 @@ const pushCssMotions = (_header, _frame, _val, _styleName, _styleNameRev) => {
9555
9565
  * @param {number} _frameStep
9556
9566
  * @param {number} _scrollDir
9557
9567
  */
9558
- const pushScrollchs = (_header, _frameArrow, _val, _frameStep, _scrollDir) => {
9568
+ const pushScrollchs = (_header, _frameArrow, _val, _frameStep, _scrollDir, _layerGroup) => {
9559
9569
  const tkObj = getKeyInfo();
9570
+ g_stateObj.layerNum = Math.max(g_stateObj.layerNum, (_layerGroup + 1) * 2);
9560
9571
 
9561
9572
  const frameArrow = Math.max(_frameArrow, g_scoreObj.frameNum);
9562
9573
  const frameStep = Math.max(_frameStep, g_scoreObj.frameNum);
9563
9574
  const pushData = (_pattern, _frame, _val) =>
9564
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
+ };
9565
9584
 
9566
9585
  if (_val < 20 || _val >= 1000) {
9567
9586
  const realVal = g_workObj.replaceNums[_val % 1000];
9568
- pushData(`Arrow`, frameArrow, realVal);
9569
- pushData(`ArrowDir`, frameArrow, _scrollDir);
9570
- pushData(`Step`, frameStep, realVal);
9571
- pushData(`StepDir`, frameStep, _scrollDir);
9587
+ pushScrollData(realVal);
9572
9588
 
9573
9589
  } else {
9574
9590
  const colorNum = _val - 20;
9575
9591
  for (let j = 0; j < tkObj.keyNum; j++) {
9576
9592
  if (g_keyObj[`color${tkObj.keyCtrlPtn}`][j] === colorNum) {
9577
- pushData(`Arrow`, frameArrow, j);
9578
- pushData(`ArrowDir`, frameArrow, _scrollDir);
9579
- pushData(`Step`, frameStep, j);
9580
- pushData(`StepDir`, frameStep, _scrollDir);
9593
+ pushScrollData(j);
9581
9594
  }
9582
9595
  }
9583
9596
  }
@@ -9657,7 +9670,8 @@ const getArrowSettings = () => {
9657
9670
  const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
9658
9671
 
9659
9672
  g_workObj.stepX[j] = g_keyObj.blank * stdPos + (g_headerObj.playingWidth - C_ARW_WIDTH) / 2;
9660
- 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;
9661
9675
  if (g_stateObj.stepArea === `X-Flower`) {
9662
9676
  g_workObj.dividePos[j] = (g_workObj.stepX[j] < (g_headerObj.playingWidth - C_ARW_WIDTH) / 2 ? 0 : 1) * 2 + g_workObj.dividePos[j] % 2;
9663
9677
  }
@@ -9679,7 +9693,8 @@ const getArrowSettings = () => {
9679
9693
  });
9680
9694
  }
9681
9695
  g_workObj.scrollDirDefault = g_workObj.scrollDir.concat();
9682
- g_stateObj.layerNum = Math.ceil((Math.max(...g_workObj.dividePos) + 1) / 2) * 2;
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);
9683
9698
 
9684
9699
  Object.keys(g_resultObj).forEach(judgeCnt => g_resultObj[judgeCnt] = 0);
9685
9700
  g_resultObj.spState = ``;
@@ -9799,6 +9814,9 @@ const getArrowSettings = () => {
9799
9814
  g_workObj.drunkXFlg = false;
9800
9815
  g_workObj.drunkYFlg = false;
9801
9816
 
9817
+ // AppearanceFilterの可視範囲設定
9818
+ g_workObj.aprFilterCnt = 0;
9819
+
9802
9820
  if (g_stateObj.dataSaveFlg) {
9803
9821
  // ローカルストレージへAdjustment, HitPosition, Volume設定を保存
9804
9822
  g_storeSettings.forEach(setting => g_localStorage[setting] = g_stateObj[setting]);
@@ -9920,8 +9938,8 @@ const mainInit = () => {
9920
9938
  // ステップゾーン、矢印のメインスプライトを作成
9921
9939
  const mainSprite = createEmptySprite(divRoot, `mainSprite`, {
9922
9940
  x: g_workObj.playingX, y: g_posObj.stepY - C_STEP_Y + g_headerObj.playingY, w: g_headerObj.playingWidth, h: g_headerObj.playingHeight,
9923
- transform: `scale(${g_keyObj.scale})`,
9924
9941
  });
9942
+ addTransform(`mainSprite`, `root`, `scale(${g_keyObj.scale})`);
9925
9943
 
9926
9944
  // 曲情報・判定カウント用スプライトを作成(メインスプライトより上位)
9927
9945
  const infoSprite = createEmptySprite(divRoot, `infoSprite`, { x: g_workObj.playingX, y: g_headerObj.playingY, w: g_headerObj.playingWidth, h: g_headerObj.playingHeight });
@@ -9955,82 +9973,54 @@ const mainInit = () => {
9955
9973
  let boostCnts = 0;
9956
9974
  let keychCnts = 0;
9957
9975
 
9958
- const flatMode = g_stateObj.d_stepzone === `FlatBar` ||
9976
+ g_workObj.flatMode = g_stateObj.d_stepzone === `FlatBar` ||
9959
9977
  g_stateObj.scroll.endsWith(`Flat`) ||
9960
9978
  g_keyObj[`flatMode${keyCtrlPtn}`] ||
9961
9979
  (g_stateObj.stepArea === `Halfway` &&
9962
9980
  g_keyObj[`div${keyCtrlPtn}`] < g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length);
9963
- const stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
9964
-
9965
- // Hidden+, Sudden+用のライン、パーセント表示
9966
- const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
9967
- [`filterBar0`, `filterBar1`, `borderBar0`, `borderBar1`].forEach(obj =>
9968
- mainSprite.appendChild(createColorObject2(obj, g_lblPosObj.filterBar, filterCss)));
9969
- borderBar0.style.top = wUnit(g_posObj.stepDiffY + g_stateObj.hitPosition);
9970
- borderBar1.style.top = wUnit(g_posObj.stepDiffY + g_posObj.arrowHeight - g_stateObj.hitPosition);
9971
-
9972
- if (g_appearanceRanges.includes(g_stateObj.appearance)) {
9973
- mainSprite.appendChild(createDivCss2Label(`filterView`, ``, g_lblPosObj.filterView));
9974
- if (g_stateObj.d_filterline === C_FLG_ON) {
9975
- $id(`filterView`).opacity = g_stateObj.opacity / 100;
9976
- $id(`filterBar0`).opacity = g_stateObj.opacity / 100;
9977
- $id(`filterBar1`).opacity = g_stateObj.opacity / 100;
9978
- }
9979
- }
9981
+ g_workObj.stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || g_workObj.flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
9980
9982
 
9981
9983
  // mainSprite配下に層別のスプライトを作成し、ステップゾーン・矢印本体・フリーズアローヒット部分に分ける
9982
9984
  const mainSpriteN = [], stepSprite = [], arrowSprite = [], frzHitSprite = [];
9983
9985
  const mainCommonPos = { w: g_headerObj.playingWidth, h: g_posObj.arrowHeight };
9986
+
9987
+ // Hidden+, Sudden+用のライン、パーセント表示
9988
+ const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
9989
+ const doubleFilterFlg = ![`Default`, `Halfway`].includes(g_stateObj.stepArea);
9990
+
9984
9991
  for (let j = 0; j < g_stateObj.layerNum; j++) {
9985
9992
  const mainSpriteJ = createEmptySprite(mainSprite, `mainSprite${j}`, mainCommonPos);
9986
9993
  mainSpriteN.push(mainSpriteJ);
9994
+ mainSpriteJ.appendChild(createColorObject2(`filterBar${j}`, g_lblPosObj.filterBar, filterCss));
9995
+ if (doubleFilterFlg) {
9996
+ mainSpriteJ.appendChild(createColorObject2(`filterBar${j % 2 == 0 ? j + 1 : j - 1}_HS`, g_lblPosObj.filterBar, filterCss));
9997
+ }
9998
+ addTransform(`mainSprite${j}`, `mainSprite${j}`,
9999
+ g_keyObj[`layerTrans${keyCtrlPtn}`]?.[0]?.[Math.floor(j / 2) + (j + Number(g_stateObj.reverse === C_FLG_ON)) % 2]);
10000
+
9987
10001
  stepSprite.push(createEmptySprite(mainSpriteJ, `stepSprite${j}`, mainCommonPos));
9988
10002
  arrowSprite.push(createEmptySprite(mainSpriteJ, `arrowSprite${j}`, Object.assign({ y: g_workObj.hitPosition * (j % 2 === 0 ? 1 : -1) }, mainCommonPos)));
9989
10003
  frzHitSprite.push(createEmptySprite(mainSpriteJ, `frzHitSprite${j}`, mainCommonPos));
9990
10004
  }
9991
10005
 
9992
- for (let j = 0; j < keyNum; j++) {
9993
- const colorPos = g_keyObj[`color${keyCtrlPtn}`][j];
9994
-
9995
- // ステップゾーンルート
9996
- const stepRoot = createEmptySprite(stepSprite[g_workObj.dividePos[j]], `stepRoot${j}`, {
9997
- x: g_workObj.stepX[j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[j] % 2),
9998
- w: C_ARW_WIDTH, h: C_ARW_WIDTH,
9999
- });
10000
-
10001
- // 矢印の内側を塗りつぶすか否か
10002
- if (g_headerObj.setShadowColor[colorPos] !== ``) {
10003
- stepRoot.appendChild(
10004
- createColorObject2(`stepShadow${j}`, {
10005
- rotate: g_workObj.stepRtn[j], styleName: `ShadowStep`,
10006
- opacity: 0.7, display: stepZoneDisp,
10007
- }, g_cssObj.main_objStepShadow)
10008
- );
10006
+ if (g_appearanceRanges.includes(g_stateObj.appearance)) {
10007
+ mainSprite.appendChild(createDivCss2Label(`filterView`, ``, g_lblPosObj.filterView));
10008
+ if (g_stateObj.d_filterline === C_FLG_ON) {
10009
+ $id(`filterView`).opacity = g_stateObj.opacity / 100;
10010
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
10011
+ $id(`filterBar${j}`).opacity = g_stateObj.opacity / 100;
10012
+ if (doubleFilterFlg) {
10013
+ $id(`filterBar${j}_HS`).opacity = g_stateObj.opacity / 100;
10014
+ }
10015
+ }
10009
10016
  }
10017
+ }
10010
10018
 
10011
- appearStepZone(j, C_DIS_NONE);
10012
-
10013
- // ステップゾーン
10014
- multiAppend(stepRoot,
10015
-
10016
- // 本体
10017
- createColorObject2(`step${j}`, {
10018
- rotate: g_workObj.stepRtn[j], styleName: `Step`, display: stepZoneDisp,
10019
- }, g_cssObj.main_stepDefault),
10020
-
10021
- // 空押し
10022
- createColorObject2(`stepDiv${j}`, {
10023
- rotate: g_workObj.stepRtn[j], styleName: `Step`, display: C_DIS_NONE,
10024
- }, g_cssObj.main_stepKeyDown),
10025
-
10026
- // ヒット時モーション
10027
- createColorObject2(`stepHit${j}`, Object.assign(g_lblPosObj.stepHit, {
10028
- rotate: g_workObj.stepHitRtn[j], styleName: `StepHit`, opacity: 0,
10029
- }), g_cssObj.main_stepDefault),
10030
-
10031
- );
10019
+ // ステップゾーン、フリーズアローヒット部分の生成
10020
+ for (let j = 0; j < keyNum; j++) {
10021
+ makeStepZone(j, keyCtrlPtn);
10032
10022
  }
10033
- if (flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
10023
+ if (g_workObj.flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
10034
10024
 
10035
10025
  // スクロール名に`R-`が含まれていればリバースと見做す
10036
10026
  const reverseFlg = g_stateObj.reverse === C_FLG_ON || g_stateObj.scroll.startsWith(`R-`);
@@ -10054,37 +10044,12 @@ const mainInit = () => {
10054
10044
  }
10055
10045
  }
10056
10046
 
10057
- for (let j = 0; j < keyNum; j++) {
10058
-
10059
- // フリーズアローヒット部分
10060
- const frzHit = createEmptySprite(frzHitSprite[g_workObj.dividePos[j]], `frzHit${j}`, {
10061
- x: g_workObj.stepX[j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[j] % 2),
10062
- w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
10063
- });
10064
- if (isNaN(parseFloat(g_workObj.arrowRtn[j]))) {
10065
- multiAppend(frzHit,
10066
- createColorObject2(`frzHitShadow${j}`, {
10067
- rotate: g_workObj.arrowRtn[j], styleName: `Shadow`,
10068
- }, g_cssObj.main_objShadow),
10069
- createColorObject2(`frzHitTop${j}`, {
10070
- background: g_workObj.frzHitColors[j], rotate: g_workObj.arrowRtn[j],
10071
- })
10072
- );
10073
- } else {
10074
- frzHit.appendChild(
10075
- createColorObject2(`frzHitTop${j}`, Object.assign(g_lblPosObj.frzHitTop, {
10076
- rotate: g_workObj.arrowRtn[j], styleName: `Shadow`,
10077
- }), g_cssObj.main_frzHitTop)
10078
- );
10079
- }
10080
- }
10081
-
10082
10047
  // StepArea処理
10083
10048
  g_stepAreaFunc[g_stateObj.stepArea]();
10084
10049
 
10085
10050
  // Appearanceのオプション適用時は一部描画を隠す
10086
10051
  changeAppearanceFilter(g_appearanceRanges.includes(g_stateObj.appearance) ?
10087
- g_hidSudObj.filterPos : g_hidSudObj.filterPosDefault[g_stateObj.appearance]);
10052
+ g_hidSudObj.filterPos : g_hidSudObj.filterPosDefault[g_stateObj.appearance], true);
10088
10053
 
10089
10054
  // 現在の矢印・フリーズアローの速度、個別加算速度の初期化 (速度変化時に直す)
10090
10055
  g_workObj.currentSpeed = 2;
@@ -10345,9 +10310,7 @@ const mainInit = () => {
10345
10310
  g_customJsObj.main.forEach(func => func());
10346
10311
 
10347
10312
  // mainSpriteのtransform追加処理
10348
- g_workObj.transform = mainSprite.style.transform || ``;
10349
- g_workObj.transform += g_playWindowFunc[g_stateObj.playWindow]();
10350
- mainSprite.style.transform = g_workObj.transform;
10313
+ addTransform(`mainSprite`, `playWindow`, g_playWindowFunc[g_stateObj.playWindow]());
10351
10314
 
10352
10315
  // EffectのArrowEffect追加処理
10353
10316
  g_effectFunc[g_stateObj.effect]();
@@ -11291,11 +11254,84 @@ const mainInit = () => {
11291
11254
  g_timeoutEvtId = setTimeout(flowTimeline, 1000 / g_fps);
11292
11255
  };
11293
11256
 
11257
+ /**
11258
+ * ステップゾーン、フリーズアローヒット部分の生成
11259
+ * @param {number} _j
11260
+ * @param {string} _keyCtrlPtn
11261
+ */
11262
+ const makeStepZone = (_j, _keyCtrlPtn) => {
11263
+
11264
+ const colorPos = g_keyObj[`color${_keyCtrlPtn}`][_j];
11265
+ const stepSpriteJ = document.getElementById(`stepSprite${g_workObj.dividePos[_j]}`);
11266
+ const frzHitSpriteJ = document.getElementById(`frzHitSprite${g_workObj.dividePos[_j]}`);
11267
+
11268
+ // ステップゾーンルート
11269
+ const stepRoot = createEmptySprite(stepSpriteJ, `stepRoot${_j}`, {
11270
+ x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
11271
+ w: C_ARW_WIDTH, h: C_ARW_WIDTH,
11272
+ });
11273
+
11274
+ // 矢印の内側を塗りつぶすか否か
11275
+ if (g_headerObj.setShadowColor[colorPos] !== ``) {
11276
+ stepRoot.appendChild(
11277
+ createColorObject2(`stepShadow${_j}`, {
11278
+ rotate: g_workObj.stepRtn[_j], styleName: `ShadowStep`,
11279
+ opacity: 0.7, display: g_workObj.stepZoneDisp,
11280
+ }, g_cssObj.main_objStepShadow)
11281
+ );
11282
+ }
11283
+
11284
+ appearStepZone(_j, C_DIS_NONE);
11285
+
11286
+ // ステップゾーン
11287
+ multiAppend(stepRoot,
11288
+
11289
+ // 本体
11290
+ createColorObject2(`step${_j}`, {
11291
+ rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: g_workObj.stepZoneDisp,
11292
+ }, g_cssObj.main_stepDefault),
11293
+
11294
+ // 空押し
11295
+ createColorObject2(`stepDiv${_j}`, {
11296
+ rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: C_DIS_NONE,
11297
+ }, g_cssObj.main_stepKeyDown),
11298
+
11299
+ // ヒット時モーション
11300
+ createColorObject2(`stepHit${_j}`, Object.assign(g_lblPosObj.stepHit, {
11301
+ rotate: g_workObj.stepHitRtn[_j], styleName: `StepHit`, opacity: 0,
11302
+ }), g_cssObj.main_stepDefault),
11303
+
11304
+ );
11305
+
11306
+ // フリーズアローヒット部分
11307
+ const frzHit = createEmptySprite(frzHitSpriteJ, `frzHit${_j}`, {
11308
+ x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
11309
+ w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
11310
+ });
11311
+ if (isNaN(parseFloat(g_workObj.arrowRtn[_j]))) {
11312
+ multiAppend(frzHit,
11313
+ createColorObject2(`frzHitShadow${_j}`, {
11314
+ rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
11315
+ }, g_cssObj.main_objShadow),
11316
+ createColorObject2(`frzHitTop${_j}`, {
11317
+ background: g_workObj.frzHitColors[_j], rotate: g_workObj.arrowRtn[_j],
11318
+ })
11319
+ );
11320
+ } else {
11321
+ frzHit.appendChild(
11322
+ createColorObject2(`frzHitTop${_j}`, Object.assign(g_lblPosObj.frzHitTop, {
11323
+ rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
11324
+ }), g_cssObj.main_frzHitTop)
11325
+ );
11326
+ }
11327
+ };
11328
+
11294
11329
  /**
11295
11330
  * アルファマスクの再描画 (Appearance: Hidden+, Sudden+ 用)
11296
11331
  * @param {number} _num
11332
+ * @param {boolean} _shiftFlg シフトキーを押したかどうかのフラグ
11297
11333
  */
11298
- const changeAppearanceFilter = (_num = 10) => {
11334
+ const changeAppearanceFilter = (_num = 10, _shiftFlg = keyIsShift()) => {
11299
11335
  const MAX_FILTER_POS = 100;
11300
11336
  const topNum = g_hidSudObj[g_stateObj.appearance];
11301
11337
  const bottomNum = (g_hidSudObj[g_stateObj.appearance] + 1) % 2;
@@ -11306,16 +11342,39 @@ const changeAppearanceFilter = (_num = 10) => {
11306
11342
  const numPlus = (g_stateObj.appearance === `Hid&Sud+` ? _num : 0);
11307
11343
  const topShape = `inset(${_num}% 0% ${numPlus}% 0%)`;
11308
11344
  const bottomShape = `inset(${numPlus}% 0% ${_num}% 0%)`;
11345
+ const appearPers = [_num, MAX_FILTER_POS - _num];
11309
11346
 
11310
11347
  for (let j = 0; j < g_stateObj.layerNum; j += 2) {
11311
11348
  $id(`arrowSprite${topNum + j}`).clipPath = topShape;
11312
11349
  $id(`arrowSprite${bottomNum + j}`).clipPath = bottomShape;
11350
+
11351
+ $id(`filterBar${topNum + j}`).top = wUnit(parseFloat($id(`arrowSprite${j}`).top) + g_posObj.arrowHeight * appearPers[topNum] / MAX_FILTER_POS);
11352
+ $id(`filterBar${bottomNum + j}`).top = wUnit(parseFloat($id(`arrowSprite${j + 1}`).top) + g_posObj.arrowHeight * appearPers[bottomNum] / MAX_FILTER_POS);
11353
+
11354
+ if (![`Default`, `Halfway`].includes(g_stateObj.stepArea)) {
11355
+ $id(`filterBar${bottomNum + j}_HS`).top = wUnit(parseFloat($id(`arrowSprite${j}`).top) + g_posObj.arrowHeight * appearPers[bottomNum] / MAX_FILTER_POS);
11356
+ $id(`filterBar${topNum + j}_HS`).top = wUnit(parseFloat($id(`arrowSprite${j + 1}`).top) + g_posObj.arrowHeight * appearPers[topNum] / MAX_FILTER_POS);
11357
+ }
11358
+
11359
+ // 階層が多い場合はShift+pgUp/pgDownで表示する階層グループを切り替え
11360
+ if (_shiftFlg && g_stateObj.d_filterline === C_FLG_ON) {
11361
+ [`${topNum + j}`, `${bottomNum + j}`].forEach(type => {
11362
+ $id(`filterBar${type}`).display = (j === g_workObj.aprFilterCnt ? C_DIS_INHERIT : C_DIS_NONE);
11363
+
11364
+ if (![`Default`, `Halfway`].includes(g_stateObj.stepArea)) {
11365
+ $id(`filterBar${type}_HS`).display = (j === g_workObj.aprFilterCnt ? C_DIS_INHERIT : C_DIS_NONE);
11366
+ }
11367
+ });
11368
+ }
11313
11369
  }
11314
- $id(`filterBar0`).top = wUnit(parseFloat($id(`arrowSprite${topNum}`).top) + g_posObj.arrowHeight * _num / MAX_FILTER_POS);
11315
- $id(`filterBar1`).top = wUnit(parseFloat($id(`arrowSprite${bottomNum}`).top) + g_posObj.arrowHeight * (MAX_FILTER_POS - _num) / MAX_FILTER_POS);
11370
+
11371
+ if (_shiftFlg) {
11372
+ g_workObj.aprFilterCnt = nextPos(g_workObj.aprFilterCnt, 2, g_stateObj.layerNum);
11373
+ }
11374
+
11316
11375
  if (g_appearanceRanges.includes(g_stateObj.appearance)) {
11317
11376
  $id(`filterView`).top =
11318
- $id(`filterBar${g_hidSudObj.std[g_stateObj.appearance][g_stateObj.reverse]}`).top;
11377
+ $id(`filterBar${(g_hidSudObj.std[g_stateObj.appearance][g_stateObj.reverse]) % 2}`).top;
11319
11378
  filterView.textContent = `${_num}%`;
11320
11379
 
11321
11380
  if (g_stateObj.appearance !== `Hid&Sud+` && g_workObj.dividePos.every(v => v === g_workObj.dividePos[0])) {
@@ -11376,17 +11435,17 @@ const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) =
11376
11435
  */
11377
11436
  const changeReturn = (_rad, _axis) => {
11378
11437
  g_workObj.frzReturnFlg = true;
11379
- let _transform = g_workObj.transform;
11380
- _transform += ` rotate${_axis[0]}(${_rad}deg)`;
11438
+ let _transform = `rotate${_axis[0]}(${_rad}deg)`;
11381
11439
  if (_axis[1] !== undefined) {
11382
11440
  _transform += ` rotate${_axis[1]}(${_rad}deg)`;
11383
11441
  }
11384
11442
  if (document.getElementById(`mainSprite`) !== null) {
11385
- mainSprite.style.transform = _transform;
11443
+ addTransform(`mainSprite`, `frzReturn`, _transform);
11386
11444
 
11387
11445
  if (_rad < 360 && g_workObj.frzReturnFlg) {
11388
11446
  setTimeout(() => changeReturn(_rad + 4, _axis), 20);
11389
11447
  } else {
11448
+ addTransform(`mainSprite`, `frzReturn`, ``);
11390
11449
  g_workObj.frzReturnFlg = false;
11391
11450
  }
11392
11451
  }
@@ -11453,8 +11512,9 @@ const changeCssMotions = (_header, _name, _frameNum) => {
11453
11512
  const changeScrollArrowDirs = (_frameNum) =>
11454
11513
  g_workObj.mkScrollchArrow[_frameNum]?.forEach((targetj, j) => {
11455
11514
  g_workObj.scrollDir[targetj] = g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchArrowDir[_frameNum][j];
11456
- const baseLayer = Math.floor(g_workObj.dividePos[targetj] / 2) * 2;
11457
- g_workObj.dividePos[targetj] = baseLayer + (g_workObj.scrollDir[targetj] === 1 ? 0 : 1);
11515
+ const baseLayer = g_workObj.mkScrollchArrowLayer[_frameNum][j] === -1 ?
11516
+ Math.floor(g_workObj.dividePosDefault[targetj] / 2) : g_workObj.mkScrollchArrowLayer[_frameNum][j];
11517
+ g_workObj.dividePos[targetj] = baseLayer * 2 + (g_workObj.scrollDir[targetj] === 1 ? 0 : 1);
11458
11518
  });
11459
11519
 
11460
11520
  /**
@@ -11464,9 +11524,21 @@ const changeScrollArrowDirs = (_frameNum) =>
11464
11524
  const changeStepY = (_frameNum) =>
11465
11525
  g_workObj.mkScrollchStep[_frameNum]?.forEach((targetj, j) => {
11466
11526
  const dividePos = (g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchStepDir[_frameNum][j] === 1 ? 0 : 1);
11467
- const baseY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
11468
- $id(`stepRoot${targetj}`).top = wUnit(baseY);
11469
- $id(`frzHit${targetj}`).top = wUnit(baseY);
11527
+
11528
+ // 移動元のステップゾーンの不透明度、表示・非表示を退避
11529
+ const _stepOpacity = $id(`stepRoot${targetj}`).opacity;
11530
+ const _stepDisplay = $id(`stepRoot${targetj}`).display;
11531
+
11532
+ // 移動元のステップゾーンを消去
11533
+ document.getElementById(`stepRoot${targetj}`).remove();
11534
+ document.getElementById(`frzHit${targetj}`).remove();
11535
+
11536
+ // レイヤーを変更しステップゾーンを再生成。移動元の不透明度、表示・非表示を反映
11537
+ const baseLayer = g_workObj.mkScrollchStepLayer[_frameNum][j] === -1 ?
11538
+ Math.floor(g_workObj.dividePosDefault[targetj] / 2) : g_workObj.mkScrollchStepLayer[_frameNum][j];
11539
+ g_workObj.dividePos[targetj] = baseLayer * 2 + dividePos;
11540
+ makeStepZone(targetj, `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`);
11541
+ appearStepZone(targetj, _stepDisplay, _stepOpacity);
11470
11542
  });
11471
11543
 
11472
11544
  /**
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/02/01 (v39.0.0)
8
+ * Revised : 2025/02/08 (v39.2.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -650,7 +650,8 @@ const g_typeLists = {
650
650
  frzColor: [`Normal`, `NormalBar`, `Hit`, `HitBar`, `NormalShadow`, `HitShadow`],
651
651
  dataList: [
652
652
  `Arrow`, `FrzArrow`, `FrzLength`,
653
- `Color`, `ColorCd`, `ColorShadow`, `ColorShadowCd`, `ScrollchArrow`, `ScrollchStep`, `ScrollchArrowDir`, `ScrollchStepDir`,
653
+ `Color`, `ColorCd`, `ColorShadow`, `ColorShadowCd`,
654
+ `ScrollchArrow`, `ScrollchStep`, `ScrollchArrowDir`, `ScrollchStepDir`, `ScrollchArrowLayer`, `ScrollchStepLayer`,
654
655
  `FColorNormal`, `FColorNormalCd`, `FColorNormalBar`, `FColorNormalBarCd`,
655
656
  `FColorNormalShadow`, `FColorNormalShadowCd`,
656
657
  `FColorHit`, `FColorHitCd`, `FColorHitBar`, `FColorHitBarCd`,
@@ -1108,6 +1109,54 @@ const g_moveSettingWindow = (_changePageFlg = true, _direction = 1) => {
1108
1109
  g_settings.settingWindows[g_settings.settingWindowNum]();
1109
1110
  };
1110
1111
 
1112
+ /**
1113
+ * transform管理
1114
+ */
1115
+ const g_transforms = {};
1116
+
1117
+ /**
1118
+ * idごとのtransformを追加・変更
1119
+ * - _transformIdごとに transform情報を管理
1120
+ * @param {string} _id
1121
+ * @param {string} _transformId
1122
+ * @param {string} _transform
1123
+ */
1124
+ const addTransform = (_id, _transformId, _transform) => {
1125
+ if (g_transforms[_id] === undefined) {
1126
+ g_transforms[_id] = {};
1127
+ }
1128
+ g_transforms[_id][_transformId] = _transform;
1129
+ const _transforms = [];
1130
+ Object.keys(g_transforms[_id]).forEach(transformId => _transforms.push(g_transforms[_id][transformId]));
1131
+ $id(_id).transform = _transforms.join(` `);
1132
+ };
1133
+
1134
+ /**
1135
+ * idごとのtransformを追加(一時)
1136
+ * @param {string} _id
1137
+ * @param {string} _transform
1138
+ */
1139
+ const addTempTransform = (_id, _transform) => {
1140
+ $id(_id).transform = ($id(_id).transform || ``) + ` ` + _transform;
1141
+ };
1142
+
1143
+ /**
1144
+ * transformの初期化
1145
+ */
1146
+ const resetTransform = () => {
1147
+ Object.keys(g_transforms).forEach(_id => g_transforms[_id] = {});
1148
+ };
1149
+
1150
+ /**
1151
+ * id, transformIdに合致するtransform情報の取得
1152
+ * @param {string} _id
1153
+ * @param {string} _transformId
1154
+ * @returns
1155
+ */
1156
+ const getTransform = (_id, _transformId) => {
1157
+ return g_transforms[_id]?.[_transformId] || ``;
1158
+ };
1159
+
1111
1160
  /**
1112
1161
  * シャッフル適用関数
1113
1162
  * @param {number} keyNum
@@ -1154,8 +1203,8 @@ const g_motionFunc = {
1154
1203
  /**
1155
1204
  * PlayWindow適用関数
1156
1205
  */
1157
- const g_changeStairs = (_rad) => ` rotate(${_rad}deg)`;
1158
- const g_changeSkew = (_rad) => ` Skew(${_rad}deg, ${_rad}deg) scaleY(0.9)`;
1206
+ const g_changeStairs = (_rad) => `rotate(${_rad}deg)`;
1207
+ const g_changeSkew = (_rad) => `Skew(${_rad}deg, ${_rad}deg) scaleY(0.9)`;
1159
1208
 
1160
1209
  const g_playWindowFunc = {
1161
1210
  'Default': () => ``,
@@ -1173,29 +1222,25 @@ const g_stepAreaFunc = {
1173
1222
  'Default': () => ``,
1174
1223
  'Halfway': () => {
1175
1224
  [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1176
- $id(`${sprite}0`).top = `${g_headerObj.playingHeight / 2 - g_posObj.stepY + (g_posObj.stepYR - C_ARW_WIDTH) / 2}px`;
1177
- $id(`${sprite}1`).top = `-${g_headerObj.playingHeight / 2 - g_posObj.stepY + (g_posObj.stepYR - C_ARW_WIDTH) / 2}px`;
1225
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1226
+ $id(`${sprite}${j}`).top = `${(j % 2 === 0 ? 1 : -1) * (g_headerObj.playingHeight / 2 - g_posObj.stepY + (g_posObj.stepYR - C_ARW_WIDTH) / 2)}px`;
1227
+ }
1178
1228
  });
1179
1229
  },
1180
1230
  'Mismatched': () => {
1181
- [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1182
- $id(`${sprite}0`).transform = `rotate(-15deg)`;
1183
- $id(`${sprite}1`).transform = `rotate(15deg)`;
1184
- });
1231
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1232
+ addTransform(`mainSprite${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * -15}deg)`);
1233
+ }
1185
1234
  },
1186
1235
  'R-Mismatched': () => {
1187
- [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1188
- $id(`${sprite}0`).transform = `rotate(15deg)`;
1189
- $id(`${sprite}1`).transform = `rotate(-15deg)`;
1190
- });
1236
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1237
+ addTransform(`mainSprite${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * 15}deg)`);
1238
+ }
1191
1239
  },
1192
1240
  'X-Flower': () => {
1193
- [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1194
- $id(`${sprite}0`).transform = `rotate(-15deg)`;
1195
- $id(`${sprite}1`).transform = `rotate(15deg)`;
1196
- $id(`${sprite}2`).transform = `rotate(15deg)`;
1197
- $id(`${sprite}3`).transform = `rotate(-15deg)`;
1198
- });
1241
+ for (let j = 0; j < Math.min(g_stateObj.layerNum, 4); j++) {
1242
+ addTransform(`mainSprite${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * (j % 4 < 2 ? 1 : -1) * -15}deg)`);
1243
+ }
1199
1244
  },
1200
1245
  };
1201
1246
 
@@ -2813,7 +2858,7 @@ g_keycons.groups.forEach(type => {
2813
2858
  const g_keyCopyLists = {
2814
2859
  simpleDef: [`blank`, `scale`],
2815
2860
  simple: [`div`, `divMax`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
2816
- multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroup`, `keyGroupOrder`],
2861
+ multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroup`, `keyGroupOrder`, `layerGroup`, `layerTrans`],
2817
2862
  };
2818
2863
 
2819
2864
  // タイトル画面関連のリスト群
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "39.0.0",
3
+ "version": "39.2.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {