danoniplus 39.0.0 → 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,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/04
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.1.0`;
12
+ const g_revisedDate = `2025/02/04`;
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 = ``;
@@ -9920,8 +9935,8 @@ const mainInit = () => {
9920
9935
  // ステップゾーン、矢印のメインスプライトを作成
9921
9936
  const mainSprite = createEmptySprite(divRoot, `mainSprite`, {
9922
9937
  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
9938
  });
9939
+ addTransform(`mainSprite`, `root`, `scale(${g_keyObj.scale})`);
9925
9940
 
9926
9941
  // 曲情報・判定カウント用スプライトを作成(メインスプライトより上位)
9927
9942
  const infoSprite = createEmptySprite(divRoot, `infoSprite`, { x: g_workObj.playingX, y: g_headerObj.playingY, w: g_headerObj.playingWidth, h: g_headerObj.playingHeight });
@@ -9955,12 +9970,12 @@ const mainInit = () => {
9955
9970
  let boostCnts = 0;
9956
9971
  let keychCnts = 0;
9957
9972
 
9958
- const flatMode = g_stateObj.d_stepzone === `FlatBar` ||
9973
+ g_workObj.flatMode = g_stateObj.d_stepzone === `FlatBar` ||
9959
9974
  g_stateObj.scroll.endsWith(`Flat`) ||
9960
9975
  g_keyObj[`flatMode${keyCtrlPtn}`] ||
9961
9976
  (g_stateObj.stepArea === `Halfway` &&
9962
9977
  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;
9978
+ g_workObj.stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || g_workObj.flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
9964
9979
 
9965
9980
  // Hidden+, Sudden+用のライン、パーセント表示
9966
9981
  const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
@@ -9984,53 +9999,18 @@ const mainInit = () => {
9984
9999
  for (let j = 0; j < g_stateObj.layerNum; j++) {
9985
10000
  const mainSpriteJ = createEmptySprite(mainSprite, `mainSprite${j}`, mainCommonPos);
9986
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]);
9987
10004
  stepSprite.push(createEmptySprite(mainSpriteJ, `stepSprite${j}`, mainCommonPos));
9988
10005
  arrowSprite.push(createEmptySprite(mainSpriteJ, `arrowSprite${j}`, Object.assign({ y: g_workObj.hitPosition * (j % 2 === 0 ? 1 : -1) }, mainCommonPos)));
9989
10006
  frzHitSprite.push(createEmptySprite(mainSpriteJ, `frzHitSprite${j}`, mainCommonPos));
9990
10007
  }
9991
10008
 
10009
+ // ステップゾーン、フリーズアローヒット部分の生成
9992
10010
  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
- );
10009
- }
10010
-
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
- );
10011
+ makeStepZone(j, keyCtrlPtn);
10032
10012
  }
10033
- if (flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
10013
+ if (g_workObj.flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
10034
10014
 
10035
10015
  // スクロール名に`R-`が含まれていればリバースと見做す
10036
10016
  const reverseFlg = g_stateObj.reverse === C_FLG_ON || g_stateObj.scroll.startsWith(`R-`);
@@ -10054,31 +10034,6 @@ const mainInit = () => {
10054
10034
  }
10055
10035
  }
10056
10036
 
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
10037
  // StepArea処理
10083
10038
  g_stepAreaFunc[g_stateObj.stepArea]();
10084
10039
 
@@ -10345,9 +10300,7 @@ const mainInit = () => {
10345
10300
  g_customJsObj.main.forEach(func => func());
10346
10301
 
10347
10302
  // 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;
10303
+ addTransform(`mainSprite`, `playWindow`, g_playWindowFunc[g_stateObj.playWindow]());
10351
10304
 
10352
10305
  // EffectのArrowEffect追加処理
10353
10306
  g_effectFunc[g_stateObj.effect]();
@@ -11291,6 +11244,78 @@ const mainInit = () => {
11291
11244
  g_timeoutEvtId = setTimeout(flowTimeline, 1000 / g_fps);
11292
11245
  };
11293
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
+
11294
11319
  /**
11295
11320
  * アルファマスクの再描画 (Appearance: Hidden+, Sudden+ 用)
11296
11321
  * @param {number} _num
@@ -11376,17 +11401,17 @@ const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) =
11376
11401
  */
11377
11402
  const changeReturn = (_rad, _axis) => {
11378
11403
  g_workObj.frzReturnFlg = true;
11379
- let _transform = g_workObj.transform;
11380
- _transform += ` rotate${_axis[0]}(${_rad}deg)`;
11404
+ let _transform = `rotate${_axis[0]}(${_rad}deg)`;
11381
11405
  if (_axis[1] !== undefined) {
11382
11406
  _transform += ` rotate${_axis[1]}(${_rad}deg)`;
11383
11407
  }
11384
11408
  if (document.getElementById(`mainSprite`) !== null) {
11385
- mainSprite.style.transform = _transform;
11409
+ addTransform(`mainSprite`, `frzReturn`, _transform);
11386
11410
 
11387
11411
  if (_rad < 360 && g_workObj.frzReturnFlg) {
11388
11412
  setTimeout(() => changeReturn(_rad + 4, _axis), 20);
11389
11413
  } else {
11414
+ addTransform(`mainSprite`, `frzReturn`, ``);
11390
11415
  g_workObj.frzReturnFlg = false;
11391
11416
  }
11392
11417
  }
@@ -11453,8 +11478,9 @@ const changeCssMotions = (_header, _name, _frameNum) => {
11453
11478
  const changeScrollArrowDirs = (_frameNum) =>
11454
11479
  g_workObj.mkScrollchArrow[_frameNum]?.forEach((targetj, j) => {
11455
11480
  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);
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);
11458
11484
  });
11459
11485
 
11460
11486
  /**
@@ -11464,9 +11490,21 @@ const changeScrollArrowDirs = (_frameNum) =>
11464
11490
  const changeStepY = (_frameNum) =>
11465
11491
  g_workObj.mkScrollchStep[_frameNum]?.forEach((targetj, j) => {
11466
11492
  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);
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);
11470
11508
  });
11471
11509
 
11472
11510
  /**
@@ -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/04 (v39.1.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,28 +1222,30 @@ 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
1231
  [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1182
- $id(`${sprite}0`).transform = `rotate(-15deg)`;
1183
- $id(`${sprite}1`).transform = `rotate(15deg)`;
1232
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1233
+ addTransform(`${sprite}${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * -15}deg)`);
1234
+ }
1184
1235
  });
1185
1236
  },
1186
1237
  'R-Mismatched': () => {
1187
1238
  [`stepSprite`, `arrowSprite`, `frzHitSprite`].forEach(sprite => {
1188
- $id(`${sprite}0`).transform = `rotate(15deg)`;
1189
- $id(`${sprite}1`).transform = `rotate(-15deg)`;
1239
+ for (let j = 0; j < g_stateObj.layerNum; j++) {
1240
+ addTransform(`${sprite}${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * 15}deg)`);
1241
+ }
1190
1242
  });
1191
1243
  },
1192
1244
  'X-Flower': () => {
1193
1245
  [`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)`;
1246
+ for (let j = 0; j < Math.min(g_stateObj.layerNum, 4); j++) {
1247
+ addTransform(`${sprite}${j}`, `stepArea`, `rotate(${(j % 2 === 0 ? 1 : -1) * (j % 4 < 2 ? 1 : -1) * -15}deg)`);
1248
+ }
1198
1249
  });
1199
1250
  },
1200
1251
  };
@@ -2813,7 +2864,7 @@ g_keycons.groups.forEach(type => {
2813
2864
  const g_keyCopyLists = {
2814
2865
  simpleDef: [`blank`, `scale`],
2815
2866
  simple: [`div`, `divMax`, `blank`, `scale`, `keyRetry`, `keyTitleBack`, `transKey`, `scrollDir`, `assistPos`, `flatMode`],
2816
- multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroup`, `keyGroupOrder`],
2867
+ multiple: [`chara`, `color`, `stepRtn`, `pos`, `shuffle`, `keyGroup`, `keyGroupOrder`, `layerGroup`, `layerTrans`],
2817
2868
  };
2818
2869
 
2819
2870
  // タイトル画面関連のリスト群
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "39.0.0",
3
+ "version": "39.1.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {