danoniplus 24.6.5 → 26.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
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 24.6.5`;
11
+ const g_version = `Ver 26.2.0`;
12
12
  const g_revisedDate = `2022/02/20`;
13
13
  const g_alphaVersion = ``;
14
14
 
@@ -125,7 +125,14 @@ const g_detailObj = {
125
125
  arrowCnt: [],
126
126
  frzCnt: [],
127
127
  maxDensity: [],
128
+ maxDensity2Push: [],
129
+ maxDensity3Push: [],
128
130
  densityData: [],
131
+ density2PushData: [],
132
+ density3PushData: [],
133
+ densityDiff: [],
134
+ density2PushDiff: [],
135
+ density3PushDiff: [],
129
136
  startFrame: [],
130
137
  playingFrame: [],
131
138
  playingFrameWithBlank: [],
@@ -231,6 +238,15 @@ const hasValInArray = (_val, _array, _pos = 0) =>
231
238
  */
232
239
  const hasArrayList = (_data, _length = 1) => _data !== undefined && _data.length >= _length;
233
240
 
241
+ /**
242
+ * 重複を排除した配列の生成
243
+ * @param {array} _array1
244
+ * @param {...any} _arrays
245
+ * @returns
246
+ */
247
+ const makeDedupliArray = (_array1, ..._arrays) =>
248
+ Array.from((new Set([..._array1, ..._arrays.flat()])).values());
249
+
234
250
  /**
235
251
  * 部分一致検索(リストのいずれかに合致、大小文字問わず)
236
252
  * @param {string} _str 検索文字
@@ -569,28 +585,34 @@ function getFontSize(_str, _maxWidth, _font = getBasicFont(), _maxFontsize = 64,
569
585
 
570
586
  /**
571
587
  * クリップボードコピー関数
572
- * 入力値をクリップボードへコピーする
588
+ * 入力値をクリップボードへコピーし、メッセージを表示
573
589
  * @param {string} _textVal 入力値
590
+ * @param {string} _msg
574
591
  */
575
- function copyTextToClipboard(_textVal) {
576
- // テキストエリアを用意する
577
- const copyFrom = document.createElement(`textarea`);
578
- // テキストエリアへ値をセット
579
- copyFrom.textContent = _textVal;
592
+ async function copyTextToClipboard(_textVal, _msg) {
593
+ try {
594
+ await navigator.clipboard.writeText(_textVal);
595
+
596
+ } catch (error) {
597
+ // http環境では navigator.clipboard が使えないため、従来の方法を実行
598
+ // テキストエリアを用意し、値をセット
599
+ const copyFrom = document.createElement(`textarea`);
600
+ copyFrom.textContent = _textVal;
601
+
602
+ // bodyタグの要素を取得
603
+ const bodyElm = document.getElementsByTagName(`body`)[0];
604
+ // 子要素にテキストエリアを配置
605
+ bodyElm.appendChild(copyFrom);
580
606
 
581
- // bodyタグの要素を取得
582
- const bodyElm = document.getElementsByTagName(`body`)[0];
583
- // 子要素にテキストエリアを配置
584
- bodyElm.appendChild(copyFrom);
607
+ // テキストエリアの値を選択し、コピーコマンド発行
608
+ copyFrom.select();
609
+ document.execCommand(`copy`);
610
+ // 追加テキストエリアを削除
611
+ bodyElm.removeChild(copyFrom);
585
612
 
586
- // テキストエリアの値を選択
587
- copyFrom.select();
588
- // コピーコマンド発行
589
- const retVal = document.execCommand(`copy`);
590
- // 追加テキストエリアを削除
591
- bodyElm.removeChild(copyFrom);
592
- // 処理結果を返却
593
- return retVal;
613
+ } finally {
614
+ makeInfoWindow(_msg, `leftToRightFade`);
615
+ }
594
616
  }
595
617
 
596
618
  /**
@@ -1145,6 +1167,10 @@ function makeSpriteData(_data, _calcFrame = _frame => _frame) {
1145
1167
  };
1146
1168
  if (g_headerObj.autoPreload) {
1147
1169
  if (checkImage(tmpObj.path)) {
1170
+ if (g_headerObj.syncBackPath) {
1171
+ const [file, dir] = getFilePath(tmpObj.path, `./`);
1172
+ tmpObj.path = `${dir}${file}`;
1173
+ }
1148
1174
  preloadFile(`image`, tmpObj.path);
1149
1175
  }
1150
1176
  }
@@ -1159,6 +1185,7 @@ function makeSpriteData(_data, _calcFrame = _frame => _frame) {
1159
1185
  command: tmpObj.path,
1160
1186
  jumpFrame: tmpObj.class,
1161
1187
  maxLoop: tmpObj.left,
1188
+ animationName: tmpObj.animationName,
1162
1189
  htmlText: emptyPatterns.includes(tmpObj.path) ?
1163
1190
  `` : (checkImage(tmpObj.path) ? makeSpriteImage(tmpObj) : makeSpriteText(tmpObj)),
1164
1191
  };
@@ -1466,19 +1493,13 @@ function initAfterDosLoaded() {
1466
1493
  if (document.querySelector(`#layer0`) === null) {
1467
1494
  divRoot.removeChild(document.querySelector(`#divBack`));
1468
1495
  createEmptySprite(divRoot, `divBack`);
1469
- } else if (g_headerObj.skinType !== `default` && !g_headerObj.customBackUse) {
1496
+ } else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
1470
1497
  createEmptySprite(divRoot, `divBack`);
1471
1498
  }
1472
1499
 
1473
1500
  // CSSファイルの読み込み
1474
- const randTime = new Date().getTime();
1475
- importCssFile(`${g_headerObj.skinRoot}danoni_skin_${g_headerObj.skinType}.css?${randTime}`, _ => {
1476
- if (g_headerObj.skinType2 !== ``) {
1477
- importCssFile(`${g_headerObj.skinRoot2}danoni_skin_${g_headerObj.skinType2}.css?${randTime}`, _ => initAfterCssLoaded());
1478
- } else {
1479
- initAfterCssLoaded();
1480
- }
1481
- });
1501
+ const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
1502
+ loadMultipleFiles(0, skinList, `css`, _ => initAfterCssLoaded());
1482
1503
 
1483
1504
  /**
1484
1505
  * スキンCSSファイルを読み込んだ後の処理
@@ -1487,7 +1508,14 @@ function initAfterDosLoaded() {
1487
1508
 
1488
1509
  // 譜面ヘッダー、特殊キー情報の読込
1489
1510
  Object.assign(g_headerObj, headerConvert(g_rootObj));
1490
- keysConvert(g_rootObj);
1511
+ if (typeof g_presetKeysData === C_TYP_STRING) {
1512
+ keysConvert(dosConvert(g_presetKeysData));
1513
+ g_headerObj.undefinedKeyLists = g_headerObj.undefinedKeyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
1514
+ }
1515
+ g_headerObj.keyExtraList = keysConvert(g_rootObj, {
1516
+ keyExtraList: (g_rootObj.keyExtraList !== undefined ?
1517
+ makeDedupliArray(g_rootObj.keyExtraList.split(`,`), g_headerObj.undefinedKeyLists) : g_headerObj.undefinedKeyLists),
1518
+ });
1491
1519
 
1492
1520
  // キー数情報を初期化
1493
1521
  g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
@@ -1543,10 +1571,9 @@ function initAfterDosLoaded() {
1543
1571
 
1544
1572
  if (g_loadObj.main) {
1545
1573
  // customjsの読み込み後、譜面詳細情報取得のために譜面をロード
1546
- loadCustomjs(_ => {
1547
- loadDos(_ => {
1548
- getScoreDetailData(0);
1549
- }, 0, true);
1574
+ loadMultipleFiles(0, g_headerObj.jsData, `js`, _ => {
1575
+ loadLegacyCustomFunc();
1576
+ loadDos(_ => getScoreDetailData(0), 0, true);
1550
1577
  });
1551
1578
  } else {
1552
1579
  getScoreDetailData(0);
@@ -1594,6 +1621,7 @@ function storeBaseData(_scoreId, _scoreObj, _keyCtrlPtn) {
1594
1621
  let allData = 0;
1595
1622
 
1596
1623
  const types = [`arrow`, `frz`];
1624
+ let fullData = [];
1597
1625
  for (let j = 0; j < keyNum; j++) {
1598
1626
  noteCnt.arrow[j] = 0;
1599
1627
  noteCnt.frz[j] = 0;
@@ -1612,17 +1640,53 @@ function storeBaseData(_scoreId, _scoreObj, _keyCtrlPtn) {
1612
1640
  }
1613
1641
  })
1614
1642
  });
1643
+ fullData = fullData.concat(..._scoreObj.arrowData[j], ...tmpFrzData);
1615
1644
  }
1616
1645
 
1646
+ fullData = fullData.filter(val => !isNaN(parseFloat(val))).sort((a, b) => a - b);
1647
+ let pushCnt = 0;
1648
+ const density2PushData = [...Array(C_LEN_DENSITY_DIVISION)].fill(0);
1649
+ const density3PushData = [...Array(C_LEN_DENSITY_DIVISION)].fill(0);
1650
+ fullData.forEach((note, j) => {
1651
+ if (fullData[j] === fullData[j + 1]) {
1652
+ pushCnt++;
1653
+ } else {
1654
+ const point = Math.floor((note - firstArrowFrame) / playingFrame * C_LEN_DENSITY_DIVISION);
1655
+ if (point >= 0) {
1656
+ if (pushCnt > 2) {
1657
+ density3PushData[point] += pushCnt;
1658
+ }
1659
+ density2PushData[point] += pushCnt;
1660
+ }
1661
+ pushCnt = 0;
1662
+ }
1663
+ });
1664
+
1617
1665
  g_detailObj.toolDif[_scoreId] = calcLevel(_scoreObj);
1618
1666
  g_detailObj.speedData[_scoreId] = _scoreObj.speedData.concat();
1619
1667
  g_detailObj.boostData[_scoreId] = _scoreObj.boostData.concat();
1620
1668
 
1621
- g_detailObj.maxDensity[_scoreId] = densityData.indexOf(Math.max.apply(null, densityData));
1622
- g_detailObj.densityData[_scoreId] = [];
1623
- for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
1624
- g_detailObj.densityData[_scoreId].push(Math.round(densityData[j] / allData * C_LEN_DENSITY_DIVISION * 10000) / 100);
1669
+ const storeDensity = _densityData => {
1670
+ const dataList = [];
1671
+ for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
1672
+ dataList.push(allData === 0 ? 0 : Math.round(_densityData[j] / allData * C_LEN_DENSITY_DIVISION * 10000) / 100);
1673
+ }
1674
+ return dataList;
1625
1675
  }
1676
+ const diffArray = (_array1, _array2) => {
1677
+ const list = [];
1678
+ _array1.forEach((val, j) => list.push(_array1[j] - _array2[j]));
1679
+ return list;
1680
+ };
1681
+ g_detailObj.densityData[_scoreId] = storeDensity(densityData);
1682
+ g_detailObj.density2PushData[_scoreId] = storeDensity(density2PushData);
1683
+ g_detailObj.density3PushData[_scoreId] = storeDensity(density3PushData);
1684
+
1685
+ g_detailObj.densityDiff[_scoreId] = diffArray(g_detailObj.densityData[_scoreId], g_detailObj.density2PushData[_scoreId]);
1686
+ g_detailObj.density2PushDiff[_scoreId] = diffArray(g_detailObj.density2PushData[_scoreId], g_detailObj.density3PushData[_scoreId]);
1687
+ g_detailObj.density3PushDiff[_scoreId] = g_detailObj.density3PushData[_scoreId].concat();
1688
+
1689
+ g_detailObj.maxDensity[_scoreId] = densityData.indexOf(Math.max.apply(null, densityData));
1626
1690
 
1627
1691
  g_detailObj.arrowCnt[_scoreId] = noteCnt.arrow.concat();
1628
1692
  g_detailObj.frzCnt[_scoreId] = noteCnt.frz.concat();
@@ -1797,20 +1861,31 @@ function calcLevel(_scoreObj) {
1797
1861
  }
1798
1862
 
1799
1863
  /**
1800
- * customjsの読込
1864
+ * jsファイルの連続読込
1865
+ * @param {number} _j
1866
+ * @param {array} _fileData
1867
+ * @param {string} _loadType
1801
1868
  * @param {function} _afterFunc
1802
1869
  */
1803
- function loadCustomjs(_afterFunc) {
1804
- const randTime = new Date().getTime();
1805
- loadScript(`${g_headerObj.customjsRoot}${g_headerObj.customjs}?${randTime}`, _ => {
1806
- loadScript(`${g_headerObj.customjs2Root}${g_headerObj.customjs2}?${randTime}`, _ => {
1807
- loadScript(`${g_headerObj.skinRoot}danoni_skin_${g_headerObj.skinType}.js?${randTime}`, _ => {
1808
- loadScript(`${g_headerObj.skinRoot2}danoni_skin_${g_headerObj.skinType2}.js?${randTime}`, _ => {
1809
- _afterFunc();
1810
- }, false);
1811
- }, false);
1812
- }, false);
1813
- }, false);
1870
+ function loadMultipleFiles(_j, _fileData, _loadType, _afterFunc = _ => true) {
1871
+ if (_j < _fileData.length) {
1872
+ const filePath = `${_fileData[_j][1]}${_fileData[_j][0]}?${new Date().getTime()}`;
1873
+ if (_fileData[_j][0].endsWith(`.css`)) {
1874
+ _loadType = `css`;
1875
+ }
1876
+
1877
+ // jsファイル、cssファイルにより呼び出す関数を切替
1878
+ if (_loadType === `js`) {
1879
+ loadScript(filePath, _ =>
1880
+ loadMultipleFiles(_j + 1, _fileData, _loadType, _afterFunc), false);
1881
+ } else if (_loadType === `css`) {
1882
+ const cssPath = filePath.split(`.js`).join(`.css`);
1883
+ importCssFile(cssPath, _ =>
1884
+ loadMultipleFiles(_j + 1, _fileData, _loadType, _afterFunc));
1885
+ }
1886
+ } else {
1887
+ _afterFunc();
1888
+ }
1814
1889
  }
1815
1890
 
1816
1891
  /**
@@ -1916,12 +1991,7 @@ function loadMusic() {
1916
1991
  lblLoading.textContent = `${g_lblNameObj.nowLoading} ${_event.loaded}Bytes`;
1917
1992
  }
1918
1993
  // ユーザカスタムイベント
1919
- if (typeof customLoadingProgress === C_TYP_FUNCTION) {
1920
- customLoadingProgress(_event);
1921
- if (typeof customLoadingProgress2 === C_TYP_FUNCTION) {
1922
- customLoadingProgress2(_event);
1923
- }
1924
- }
1994
+ g_customJsObj.progress.forEach(func => func(_event));
1925
1995
  });
1926
1996
 
1927
1997
  // エラー処理
@@ -2032,7 +2102,7 @@ function drawDefaultBackImage(_key) {
2032
2102
  l0ctx.fillStyle = grd;
2033
2103
  l0ctx.fillRect(0, 0, g_sWidth, g_sHeight);
2034
2104
 
2035
- if (g_headerObj.skinType !== `default`) {
2105
+ if (!g_headerObj.defaultSkinFlg) {
2036
2106
  createEmptySprite(divRoot, `divBack`);
2037
2107
  }
2038
2108
  }
@@ -2257,7 +2327,7 @@ function drawTitleResultMotion(_displayName) {
2257
2327
  * ショートカットキー表示
2258
2328
  * @param {object} _obj
2259
2329
  * @param {string} _settingLabel
2260
- * @param {object} objectList
2330
+ * @param {object} objectList
2261
2331
  */
2262
2332
  const createScText = (_obj, _settingLabel, { displayName = `option`, dfLabel = ``, targetLabel = `lnk${_settingLabel}R`,
2263
2333
  x = g_scViewObj.x, y = g_scViewObj.y, w = g_scViewObj.w, siz = g_scViewObj.siz } = {}) => {
@@ -2446,12 +2516,7 @@ function titleInit() {
2446
2516
  }
2447
2517
 
2448
2518
  // ユーザカスタムイベント(初期)
2449
- if (typeof customTitleInit === C_TYP_FUNCTION) {
2450
- customTitleInit();
2451
- if (typeof customTitleInit2 === C_TYP_FUNCTION) {
2452
- customTitleInit2();
2453
- }
2454
- }
2519
+ g_customJsObj.title.forEach(func => func());
2455
2520
 
2456
2521
  // バージョン情報取得
2457
2522
  let customVersion = ``;
@@ -2548,15 +2613,23 @@ function titleInit() {
2548
2613
 
2549
2614
  // コメントエリア作成
2550
2615
  if (g_headerObj.commentVal !== ``) {
2616
+
2617
+ // コメント文の加工
2618
+ const comments = g_headerObj.commentVal.split(`}`).join(`{`).split(`{`);
2619
+ let convCommentVal = ``;
2620
+ for (let j = 0; j < comments.length; j += 2) {
2621
+ convCommentVal += escapeHtmlForEnabledTag(comments[j]);
2622
+ convCommentVal += setVal(comments[j + 1], ``, C_TYP_CALC);
2623
+ }
2624
+
2551
2625
  if (g_headerObj.commentExternal) {
2552
2626
  if (document.querySelector(`#commentArea`) !== null) {
2553
- commentArea.innerHTML = g_headerObj.commentVal;
2627
+ commentArea.innerHTML = convCommentVal;
2554
2628
  }
2555
2629
  } else {
2556
- let tmpComment = g_headerObj.commentVal;
2557
2630
  multiAppend(divRoot,
2558
2631
 
2559
- createDivCss2Label(`lblComment`, tmpComment, {
2632
+ createDivCss2Label(`lblComment`, convCommentVal, {
2560
2633
  x: 0, y: 70, w: g_sWidth, h: g_sHeight - 180, siz: C_SIZ_DIFSELECTOR, align: C_ALIGN_LEFT,
2561
2634
  overflow: `auto`, background: `#222222`, color: `#cccccc`, display: C_DIS_NONE,
2562
2635
  }),
@@ -2565,10 +2638,11 @@ function titleInit() {
2565
2638
  const lblCommentDef = lblComment.style.display;
2566
2639
  lblComment.style.display = (lblCommentDef === C_DIS_NONE ? C_DIS_INHERIT : C_DIS_NONE);
2567
2640
  }, {
2568
- x: g_sWidth - 180, y: (g_sHeight / 2) + 150, w: 150, h: 50, siz: 20, border: `solid 1px #999999`,
2641
+ x: g_sWidth - 160, y: (g_sHeight / 2) + 150, w: 140, h: 50, siz: 20, border: `solid 1px #999999`,
2569
2642
  }, g_cssObj.button_Default),
2570
2643
 
2571
2644
  );
2645
+ setUserSelect(lblComment.style, `text`);
2572
2646
  }
2573
2647
  }
2574
2648
 
@@ -2584,12 +2658,7 @@ function titleInit() {
2584
2658
  function flowTitleTimeline() {
2585
2659
 
2586
2660
  // ユーザカスタムイベント(フレーム毎)
2587
- if (typeof customTitleEnterFrame === C_TYP_FUNCTION) {
2588
- customTitleEnterFrame();
2589
- if (typeof customTitleEnterFrame2 === C_TYP_FUNCTION) {
2590
- customTitleEnterFrame2();
2591
- }
2592
- }
2661
+ g_customJsObj.titleEnterFrame.forEach(func => func());
2593
2662
 
2594
2663
  // 背景・マスクモーション
2595
2664
  drawTitleResultMotion(g_currentPage);
@@ -2611,12 +2680,7 @@ function titleInit() {
2611
2680
  document.oncontextmenu = _ => true;
2612
2681
  divRoot.oncontextmenu = _ => false;
2613
2682
 
2614
- if (typeof skinTitleInit === C_TYP_FUNCTION) {
2615
- skinTitleInit();
2616
- if (typeof skinTitleInit2 === C_TYP_FUNCTION) {
2617
- skinTitleInit2();
2618
- }
2619
- }
2683
+ g_skinJsObj.title.forEach(func => func());
2620
2684
  }
2621
2685
 
2622
2686
  /**
@@ -2649,8 +2713,8 @@ function makeWarningWindow(_text = ``, { resetFlg = false, backBtnUse = false }
2649
2713
  * お知らせウィンドウ(汎用)を表示
2650
2714
  * @param {string} _text
2651
2715
  */
2652
- function makeInfoWindow(_text, _animationName = ``) {
2653
- const lblWarning = setWindowStyle(`<p>${_text}</p>`, `#ccccff`, `#000066`, C_ALIGN_CENTER);
2716
+ function makeInfoWindow(_text, _animationName = ``, _backColor = `#ccccff`) {
2717
+ const lblWarning = setWindowStyle(`<p>${_text}</p>`, _backColor, `#000066`, C_ALIGN_CENTER);
2654
2718
  lblWarning.style.pointerEvents = C_DIS_NONE;
2655
2719
 
2656
2720
  if (_animationName !== ``) {
@@ -2664,7 +2728,7 @@ function makeInfoWindow(_text, _animationName = ``) {
2664
2728
 
2665
2729
  /**
2666
2730
  * 警告ウィンドウのスタイル設定
2667
- * @param {string} _text
2731
+ * @param {string} _text
2668
2732
  * @param {string} _bkColor
2669
2733
  * @param {string} _textColor
2670
2734
  * @param {string} _align
@@ -2750,17 +2814,30 @@ function preheaderConvert(_dosObj) {
2750
2814
  // ヘッダー群の格納先
2751
2815
  const obj = {};
2752
2816
 
2817
+ obj.jsData = [];
2818
+
2819
+ const setJsFiles = (_files, _defaultDir, _type = `custom`) => {
2820
+ _files.forEach(file => {
2821
+ if (hasVal(file)) {
2822
+ const [jsFile, jsDir] = getFilePath(file, _defaultDir);
2823
+ obj.jsData.push([_type === `skin` ? `danoni_skin_${jsFile}.js` : jsFile, jsDir]);
2824
+ }
2825
+ });
2826
+ };
2827
+
2753
2828
  // 外部スキンファイルの指定
2754
2829
  const tmpSkinType = _dosObj.skinType || (typeof g_presetSkinType === C_TYP_STRING ? g_presetSkinType : `default`);
2755
- const skinTypes = tmpSkinType.split(`,`);
2756
- [obj.skinType2, obj.skinRoot2] = getFilePath(skinTypes.length > 1 ? skinTypes[1] : `blank`, C_DIR_SKIN);
2757
- [obj.skinType, obj.skinRoot] = getFilePath(skinTypes[0], C_DIR_SKIN);
2830
+ const tmpSkinTypes = tmpSkinType.split(`,`);
2831
+ obj.defaultSkinFlg = tmpSkinTypes.includes(`default`);
2832
+ setJsFiles(tmpSkinTypes, C_DIR_SKIN, `skin`);
2758
2833
 
2759
2834
  // 外部jsファイルの指定
2760
2835
  const tmpCustomjs = _dosObj.customjs || (typeof g_presetCustomJs === C_TYP_STRING ? g_presetCustomJs : C_JSF_CUSTOM);
2761
- const customjss = tmpCustomjs.split(`,`);
2762
- [obj.customjs2, obj.customjs2Root] = getFilePath(customjss.length > 1 ? customjss[1] : C_JSF_BLANK, C_DIR_JS);
2763
- [obj.customjs, obj.customjsRoot] = getFilePath(customjss[0], C_DIR_JS);
2836
+ setJsFiles(tmpCustomjs.split(`,`), C_DIR_JS);
2837
+
2838
+ // 外部cssファイルの指定
2839
+ const tmpCustomcss = _dosObj.customcss || (typeof g_presetCustomCss === C_TYP_STRING ? g_presetCustomCss : ``);
2840
+ setJsFiles(tmpCustomcss.split(`,`), C_DIR_CSS);
2764
2841
 
2765
2842
  // デフォルト曲名表示、背景、Ready表示の利用有無
2766
2843
  g_titleLists.init.forEach(objName => {
@@ -2770,6 +2847,10 @@ function preheaderConvert(_dosObj) {
2770
2847
  setVal(g_presetCustomDesignUse[objName], false, C_TYP_BOOLEAN) : false), C_TYP_BOOLEAN);
2771
2848
  });
2772
2849
 
2850
+ // 背景・マスクモーションのパス指定方法を他の設定に合わせる設定
2851
+ const tmpSyncBackPath = (typeof g_presetSyncBackPath === C_TYP_BOOLEAN ? g_presetSyncBackPath : false);
2852
+ obj.syncBackPath = setVal(_dosObj.syncBackPath, tmpSyncBackPath, C_TYP_BOOLEAN);
2853
+
2773
2854
  return obj;
2774
2855
  }
2775
2856
 
@@ -2993,8 +3074,9 @@ function headerConvert(_dosObj) {
2993
3074
  obj.lifeInits = [25];
2994
3075
  obj.creatorNames = [obj.tuning];
2995
3076
  }
2996
- const keyLists = obj.keyLabels.filter((x, j, self) => self.indexOf(x) === j);
3077
+ const keyLists = makeDedupliArray(obj.keyLabels);
2997
3078
  obj.keyLists = keyLists.sort((a, b) => parseInt(a) - parseInt(b));
3079
+ obj.undefinedKeyLists = obj.keyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
2998
3080
 
2999
3081
  // 譜面変更セレクターの利用有無
3000
3082
  obj.difSelectorUse = (setVal(_dosObj.difSelectorUse, obj.keyLabels.length > 5, C_TYP_BOOLEAN));
@@ -3042,6 +3124,22 @@ function headerConvert(_dosObj) {
3042
3124
  obj.defaultFrzColorUse = true;
3043
3125
  }
3044
3126
 
3127
+ // 矢印色変化に対応してフリーズアロー色を追随する範囲の設定
3128
+ // (defaultFrzColorUse=false時のみ)
3129
+ obj.frzScopeFromArrowColors = [];
3130
+
3131
+ if (!obj.defaultFrzColorUse) {
3132
+ const tmpFrzScope = [];
3133
+
3134
+ if (hasVal(_dosObj.frzScopeFromAC)) {
3135
+ tmpFrzScope.push(..._dosObj.frzScopeFromAC.split(`,`));
3136
+ } else if (typeof g_presetFrzScopeFromAC === C_TYP_OBJECT) {
3137
+ tmpFrzScope.push(...g_presetFrzScopeFromAC);
3138
+ }
3139
+ tmpFrzScope.filter(type => [`Normal`, `Hit`].includes(type))
3140
+ .forEach(data => obj.frzScopeFromArrowColors.push(data));
3141
+ }
3142
+
3045
3143
  // 初期色情報
3046
3144
  Object.keys(g_dfColorObj).forEach(key => obj[key] = g_dfColorObj[key].concat());
3047
3145
  if (obj.baseBrightFlg) {
@@ -3359,7 +3457,7 @@ function headerConvert(_dosObj) {
3359
3457
  const newlineTag = setVal(_dosObj.commentAutoBr, true, C_TYP_BOOLEAN) ? `<br>` : ``;
3360
3458
  let tmpComment = setVal(_dosObj[`commentVal${g_localeObj.val}`] || _dosObj.commentVal, ``, C_TYP_STRING);
3361
3459
  tmpComment = tmpComment.split(`\r\n`).join(`\n`);
3362
- obj.commentVal = escapeHtmlForEnabledTag(tmpComment.split(`\n`).join(newlineTag));
3460
+ obj.commentVal = tmpComment.split(`\n`).join(newlineTag);
3363
3461
 
3364
3462
  // クレジット表示
3365
3463
  if (document.querySelector(`#webMusicTitle`) !== null) {
@@ -3392,6 +3490,23 @@ function headerConvert(_dosObj) {
3392
3490
  obj.resultFormat = escapeHtmlForEnabledTag(setVal(_dosObj.resultFormat, (typeof g_presetResultFormat === C_TYP_STRING ?
3393
3491
  setVal(g_presetResultFormat, resultFormatDefault, C_TYP_STRING) : resultFormatDefault), C_TYP_STRING));
3394
3492
 
3493
+ // フェードイン時にそれ以前のデータを蓄積しない種別(word, back, mask)を指定
3494
+ obj.unStockCategories = setVal(_dosObj.unStockCategory, ``, C_TYP_STRING).split(`,`);
3495
+ if (typeof g_presetUnStockCategories === C_TYP_OBJECT) {
3496
+ obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetUnStockCategories);
3497
+ }
3498
+ g_fadeinStockList = g_fadeinStockList.filter(cg => obj.unStockCategories.indexOf(cg) === -1);
3499
+
3500
+ // フェードイン時にそれ以前のデータを蓄積しないパターンを指定
3501
+ if (typeof g_presetStockForceDelList === C_TYP_OBJECT) {
3502
+ Object.assign(g_stockForceDelList, g_presetStockForceDelList);
3503
+ }
3504
+ g_fadeinStockList.forEach(type => {
3505
+ if (hasVal(_dosObj[`${type}StockForceDel`])) {
3506
+ g_stockForceDelList[type] = makeDedupliArray(g_stockForceDelList[type], _dosObj[`${type}StockForceDel`].split(`,`));
3507
+ }
3508
+ });
3509
+
3395
3510
  return obj;
3396
3511
  }
3397
3512
 
@@ -3476,8 +3591,8 @@ function resetBaseColorList(_baseObj, _dosObj, { scoreId = `` } = {}) {
3476
3591
  * 矢印・フリーズアロー色のデータ展開
3477
3592
  * @param {string} _data
3478
3593
  * @param {array} _colorInit
3479
- * @param {array} _colorInitLength
3480
- * @param {object} objectList
3594
+ * @param {number} _colorInitLength
3595
+ * @param {object} objectList
3481
3596
  */
3482
3597
  function setColorList(_data, _colorInit, _colorInitLength,
3483
3598
  { _defaultColorgrd = g_headerObj.defaultColorgrd, _colorCdPaddingUse = false,
@@ -3691,12 +3806,11 @@ const getKeyName = _key => hasVal(g_keyObj[`keyName${_key}`]) ? g_keyObj[`keyNam
3691
3806
  * 一時的な追加キーの設定
3692
3807
  * @param {object} _dosObj
3693
3808
  */
3694
- function keysConvert(_dosObj) {
3809
+ function keysConvert(_dosObj, { keyExtraList = _dosObj.keyExtraList.split(`,`) } = {}) {
3695
3810
 
3696
- if (_dosObj.keyExtraList === undefined) {
3697
- return;
3811
+ if (keyExtraList === undefined) {
3812
+ return [];
3698
3813
  }
3699
- const keyExtraList = _dosObj.keyExtraList.split(`,`);
3700
3814
 
3701
3815
  const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
3702
3816
  const toString = _str => _str;
@@ -3889,6 +4003,8 @@ function keysConvert(_dosObj) {
3889
4003
  // |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
3890
4004
  newKeyPairParam(newKey, `assist`, `assistPos`);
3891
4005
  });
4006
+
4007
+ return keyExtraList;
3892
4008
  }
3893
4009
 
3894
4010
 
@@ -3924,7 +4040,7 @@ const commonSettingBtn = _labelName => {
3924
4040
  createCss2Button(`btn${_labelName}`, `>`, _ => true, {
3925
4041
  x: g_sWidth / 2 + 175 - C_LEN_SETMINI_WIDTH / 2, y: 25,
3926
4042
  w: C_LEN_SETMINI_WIDTH, h: 40, title: g_msgObj[`to${_labelName}`],
3927
- resetFunc: _ => (_labelName === `Display` ? settingsDisplayInit() : optionInit()),
4043
+ resetFunc: _ => g_jumpSettingWindow[g_currentPage](),
3928
4044
  }, g_cssObj.button_Mini),
3929
4045
 
3930
4046
  // データセーブフラグの切替
@@ -3953,12 +4069,7 @@ function optionInit() {
3953
4069
  createOptionWindow(divRoot);
3954
4070
 
3955
4071
  // ユーザカスタムイベント(初期)
3956
- if (typeof customOptionInit === C_TYP_FUNCTION) {
3957
- customOptionInit();
3958
- if (typeof customOptionInit2 === C_TYP_FUNCTION) {
3959
- customOptionInit2();
3960
- }
3961
- }
4072
+ g_customJsObj.option.forEach(func => func());
3962
4073
 
3963
4074
  // ボタン描画
3964
4075
  commonSettingBtn(`Display`);
@@ -3968,12 +4079,7 @@ function optionInit() {
3968
4079
  document.oncontextmenu = _ => true;
3969
4080
  g_initialFlg = true;
3970
4081
 
3971
- if (typeof skinOptionInit === C_TYP_FUNCTION) {
3972
- skinOptionInit();
3973
- if (typeof skinOptionInit2 === C_TYP_FUNCTION) {
3974
- skinOptionInit2();
3975
- }
3976
- }
4082
+ g_skinJsObj.option.forEach(func => func());
3977
4083
  }
3978
4084
 
3979
4085
  function musicAfterLoaded() {
@@ -4022,6 +4128,18 @@ const createOptionSprite = _sprite => createEmptySprite(_sprite, `optionsprite`,
4022
4128
  x: (g_sWidth - 450) / 2, y: 65 + (g_sHeight - 500) / 2, w: 450, h: 325,
4023
4129
  });
4024
4130
 
4131
+ /**
4132
+ * スライダー共通処理
4133
+ * @param {object} _slider
4134
+ * @param {object} _link
4135
+ * @returns
4136
+ */
4137
+ const inputSlider = (_slider, _link) => {
4138
+ const value = parseInt(_slider.value);
4139
+ _link.textContent = `${value}${g_lblNameObj.percent}`;
4140
+ return value;
4141
+ }
4142
+
4025
4143
  /**
4026
4144
  * 設定・オプション画面のラベル・ボタン処理の描画
4027
4145
  * @param {Object} _sprite 基準とするスプライト(ここで指定する座標は、そのスプライトからの相対位置)
@@ -4210,7 +4328,7 @@ function createOptionWindow(_sprite) {
4210
4328
  // 縦位置: 2 短縮ショートカットあり
4211
4329
  createGeneralSetting(spriteList.speed, `speed`, {
4212
4330
  skipTerms: [20, 5, 1], hiddenBtn: true, scLabel: g_lblNameObj.sc_speed, roundNum: 5,
4213
- unitName: ` ${getStgDetailName(g_lblNameObj.multi)}`,
4331
+ unitName: ` ${g_lblNameObj.multi}`,
4214
4332
  });
4215
4333
 
4216
4334
  if (g_headerObj.scoreDetailUse) {
@@ -4385,13 +4503,30 @@ function createOptionWindow(_sprite) {
4385
4503
  drawBaseLine(context);
4386
4504
  for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
4387
4505
  context.beginPath();
4388
- context.fillStyle = (j === g_detailObj.maxDensity[_scoreId] ? C_CLR_DENSITY_MAX : C_CLR_DENSITY_DEFAULT);
4389
- context.fillRect(16 * j * 16 / C_LEN_DENSITY_DIVISION + 30, 195 - 9 * g_detailObj.densityData[_scoreId][j] / 10,
4390
- 15.5 * 16 / C_LEN_DENSITY_DIVISION, 9 * g_detailObj.densityData[_scoreId][j] / 10
4391
- );
4506
+ [``, `2Push`, `3Push`].forEach(val => {
4507
+ context.fillStyle = (j === g_detailObj.maxDensity[_scoreId] ? g_graphColorObj[`max${val}`] : g_graphColorObj[`default${val}`]);
4508
+ context.fillRect(16 * j * 16 / C_LEN_DENSITY_DIVISION + 30, 195 - 9 * g_detailObj[`density${val}Data`][_scoreId][j] / 10,
4509
+ 15.5 * 16 / C_LEN_DENSITY_DIVISION, 9 * g_detailObj[`density${val}Diff`][_scoreId][j] / 10
4510
+ );
4511
+ });
4392
4512
  context.stroke();
4393
4513
  }
4394
4514
 
4515
+ const lineNames = [`1Push`, `2Push`, `3Push+`];
4516
+ Object.keys(g_graphColorObj).filter(val => val.indexOf(`max`) !== -1).forEach((val, j) => {
4517
+ const lineX = 70 + j * 70;
4518
+
4519
+ context.beginPath();
4520
+ context.lineWidth = 3;
4521
+ context.fillStyle = g_rankObj.rankColorAllPerfect;
4522
+ context.strokeStyle = g_graphColorObj[val];
4523
+ context.moveTo(lineX, 215);
4524
+ context.lineTo(lineX + 20, 215);
4525
+ context.stroke();
4526
+ context.font = `${C_SIZ_DIFSELECTOR}px ${getBasicFont()}`;
4527
+ context.fillText(lineNames[j], lineX + 20, 218);
4528
+ });
4529
+
4395
4530
  const obj = getScoreBaseData(_scoreId);
4396
4531
  updateScoreDetailLabel(`Density`, g_lblNameObj.s_apm, obj.apm, 0);
4397
4532
  updateScoreDetailLabel(`Density`, g_lblNameObj.s_time, obj.playingTime, 1);
@@ -4521,9 +4656,8 @@ function createOptionWindow(_sprite) {
4521
4656
  makeSettingLblCssButton(`lnkDifInfo`, g_lblNameObj.s_print, 0, _ => {
4522
4657
  copyTextToClipboard(
4523
4658
  `****** ${g_lblNameObj.s_printTitle} [${g_version}] ******\r\n\r\n`
4524
- + `\t${g_lblNameObj.s_printHeader}\r\n\r\n${printData}`
4659
+ + `\t${g_lblNameObj.s_printHeader}\r\n\r\n${printData}`, g_msgInfoObj.I_0003
4525
4660
  );
4526
- makeInfoWindow(g_msgInfoObj.I_0003, `leftToRightFade`);
4527
4661
  }, {
4528
4662
  x: 10, y: 30, w: 100, borderStyle: `solid`
4529
4663
  }, g_cssObj.button_RevON),
@@ -4799,7 +4933,7 @@ function createOptionWindow(_sprite) {
4799
4933
  // 縦位置: 10 短縮ショートカットあり
4800
4934
  createGeneralSetting(spriteList.adjustment, `adjustment`, {
4801
4935
  skipTerms: [50, 10, 5], hiddenBtn: true, scLabel: g_lblNameObj.sc_adjustment, roundNum: 5,
4802
- unitName: `${getStgDetailName(g_lblNameObj.frame)}`,
4936
+ unitName: g_lblNameObj.frame,
4803
4937
  });
4804
4938
 
4805
4939
  // ---------------------------------------------------
@@ -4807,7 +4941,7 @@ function createOptionWindow(_sprite) {
4807
4941
  // 縦位置: 11 スライダーあり
4808
4942
  spriteList.fadein.appendChild(createLblSetting(`Fadein`));
4809
4943
 
4810
- const lnkFadein = createDivCss2Label(`lnkFadein`, `${g_stateObj.fadein}${getStgDetailName(g_lblNameObj.percent)}`, {
4944
+ const lnkFadein = createDivCss2Label(`lnkFadein`, `${g_stateObj.fadein}${g_lblNameObj.percent}`, {
4811
4945
  x: C_LEN_SETLBL_LEFT, y: 0,
4812
4946
  }, g_cssObj.settings_FadeinBar);
4813
4947
  spriteList.fadein.appendChild(lnkFadein);
@@ -4815,7 +4949,7 @@ function createOptionWindow(_sprite) {
4815
4949
  const setFadein = _sign => {
4816
4950
  g_stateObj.fadein = nextPos(g_stateObj.fadein, _sign, 100);
4817
4951
  fadeinSlider.value = g_stateObj.fadein;
4818
- lnkFadein.textContent = `${g_stateObj.fadein}${getStgDetailName(g_lblNameObj.percent)}`;
4952
+ lnkFadein.textContent = `${g_stateObj.fadein}${g_lblNameObj.percent}`;
4819
4953
  };
4820
4954
 
4821
4955
  multiAppend(spriteList.fadein,
@@ -4832,15 +4966,13 @@ function createOptionWindow(_sprite) {
4832
4966
  )
4833
4967
 
4834
4968
  const fadeinSlider = document.querySelector(`#fadeinSlider`);
4835
- fadeinSlider.addEventListener(`input`, _ => {
4836
- g_stateObj.fadein = parseInt(fadeinSlider.value);
4837
- lnkFadein.textContent = `${g_stateObj.fadein}${getStgDetailName(g_lblNameObj.percent)}`;
4838
- }, false);
4969
+ fadeinSlider.addEventListener(`input`, _ =>
4970
+ g_stateObj.fadein = inputSlider(fadeinSlider, lnkFadein), false);
4839
4971
 
4840
4972
  // ---------------------------------------------------
4841
4973
  // ボリューム (Volume)
4842
4974
  // 縦位置: 12
4843
- createGeneralSetting(spriteList.volume, `volume`, { unitName: getStgDetailName(g_lblNameObj.percent) });
4975
+ createGeneralSetting(spriteList.volume, `volume`, { unitName: g_lblNameObj.percent });
4844
4976
 
4845
4977
  /**
4846
4978
  * 譜面初期化処理
@@ -4858,8 +4990,6 @@ function createOptionWindow(_sprite) {
4858
4990
  // ---------------------------------------------------
4859
4991
  // 1. キーコンフィグ設定 (KeyConfig)
4860
4992
 
4861
- // 特殊キーフラグ
4862
- g_stateObj.extraKeyFlg = false;
4863
4993
 
4864
4994
  g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
4865
4995
  const isNotSameKey = (g_keyObj.prevKey !== g_keyObj.currentKey);
@@ -4867,15 +4997,8 @@ function createOptionWindow(_sprite) {
4867
4997
  if (g_headerObj.dummyScoreNos !== undefined) {
4868
4998
  g_stateObj.dummyId = setVal(g_headerObj.dummyScoreNos[g_stateObj.scoreId], ``, C_TYP_NUMBER);
4869
4999
  }
4870
-
4871
- if (g_rootObj.keyExtraList !== undefined) {
4872
- g_rootObj.keyExtraList.split(`,`).some(extraKey => {
4873
- if (g_keyObj.currentKey === extraKey) {
4874
- g_stateObj.extraKeyFlg = true;
4875
- return true;
4876
- }
4877
- });
4878
- }
5000
+ // 特殊キーフラグ
5001
+ g_stateObj.extraKeyFlg = g_headerObj.keyExtraList.includes(g_keyObj.currentKey);
4879
5002
 
4880
5003
  // ---------------------------------------------------
4881
5004
  // 2. 初期化設定
@@ -4961,7 +5084,7 @@ function createOptionWindow(_sprite) {
4961
5084
 
4962
5085
  // 譜面名設定 (Difficulty)
4963
5086
  const difWidth = parseFloat(lnkDifficulty.style.width);
4964
- const difNames = [`${getKeyName(g_keyObj.currentKey)} key / ${g_headerObj.difLabels[g_stateObj.scoreId]}`];
5087
+ const difNames = [`${getKeyName(g_keyObj.currentKey)} ${getStgDetailName('key')} / ${g_headerObj.difLabels[g_stateObj.scoreId]}`];
4965
5088
  lnkDifficulty.style.fontSize = `${getFontSize(difNames[0], difWidth, getBasicFont(), C_SIZ_SETLBL)}px`;
4966
5089
 
4967
5090
  if (g_headerObj.makerView) {
@@ -4974,7 +5097,7 @@ function createOptionWindow(_sprite) {
4974
5097
  lnkDifficulty.innerHTML = difNames.join(``);
4975
5098
 
4976
5099
  // 速度設定 (Speed)
4977
- setSetting(0, `speed`, ` ${getStgDetailName(g_lblNameObj.multi)}`);
5100
+ setSetting(0, `speed`, ` ${g_lblNameObj.multi}`);
4978
5101
  if (g_headerObj.scoreDetailUse) {
4979
5102
  drawSpeedGraph(g_stateObj.scoreId);
4980
5103
  drawDensityGraph(g_stateObj.scoreId);
@@ -5009,12 +5132,7 @@ function createOptionWindow(_sprite) {
5009
5132
  setGauge(0);
5010
5133
 
5011
5134
  // ユーザカスタムイベント(初期)
5012
- if (typeof customSetDifficulty === C_TYP_FUNCTION) {
5013
- customSetDifficulty(_initFlg, g_canLoadDifInfoFlg);
5014
- if (typeof customSetDifficulty2 === C_TYP_FUNCTION) {
5015
- customSetDifficulty2(_initFlg, g_canLoadDifInfoFlg);
5016
- }
5017
- }
5135
+ g_customJsObj.difficulty.forEach(func => func(_initFlg, g_canLoadDifInfoFlg));
5018
5136
 
5019
5137
  // ---------------------------------------------------
5020
5138
  // 4. 譜面初期情報ロード許可フラグの設定
@@ -5310,12 +5428,7 @@ function settingsDisplayInit() {
5310
5428
  );
5311
5429
 
5312
5430
  // ユーザカスタムイベント(初期)
5313
- if (typeof customSettingsDisplayInit === C_TYP_FUNCTION) {
5314
- customSettingsDisplayInit();
5315
- if (typeof customSettingsDisplayInit2 === C_TYP_FUNCTION) {
5316
- customSettingsDisplayInit2();
5317
- }
5318
- }
5431
+ g_customJsObj.settingsDisplay.forEach(func => func());
5319
5432
 
5320
5433
  // ボタン描画
5321
5434
  commonSettingBtn(`Settings`);
@@ -5324,12 +5437,7 @@ function settingsDisplayInit() {
5324
5437
  setShortcutEvent(g_currentPage);
5325
5438
  document.oncontextmenu = _ => true;
5326
5439
 
5327
- if (typeof skinSettingsDisplayInit === C_TYP_FUNCTION) {
5328
- skinSettingsDisplayInit();
5329
- if (typeof skinSettingsDisplayInit2 === C_TYP_FUNCTION) {
5330
- skinSettingsDisplayInit2();
5331
- }
5332
- }
5440
+ g_skinJsObj.settingsDisplay.forEach(func => func());
5333
5441
  }
5334
5442
 
5335
5443
  /**
@@ -5371,13 +5479,13 @@ function createSettingsDisplayWindow(_sprite) {
5371
5479
 
5372
5480
  // Hidden+/Sudden+初期値用スライダー、ロックボタン
5373
5481
  multiAppend(spriteList.appearance,
5374
- createDivCss2Label(`lblAppearancePos`, `${g_hidSudObj.filterPos}${getStgDetailName(g_lblNameObj.percent)}`, {
5482
+ createDivCss2Label(`lblAppearancePos`, `${g_hidSudObj.filterPos}${g_lblNameObj.percent}`, {
5375
5483
  x: C_LEN_SETLBL_LEFT, y: 20, siz: 12, align: C_ALIGN_CENTER,
5376
5484
  }),
5377
5485
  createDivCss2Label(`lblAppearanceBar`, `<input id="appearanceSlider" type="range" value="${g_hidSudObj.filterPos}" min="0" max="100" step="1">`, {
5378
5486
  x: C_LEN_SETLBL_LEFT, y: 15,
5379
5487
  }),
5380
- createCss2Button(`lnkLockBtn`, `${getStgDetailName(g_lblNameObj.filterLock)}`, evt => setLockView(evt.target), {
5488
+ createCss2Button(`lnkLockBtn`, g_lblNameObj.filterLock, evt => setLockView(evt.target), {
5381
5489
  x: C_LEN_SETLBL_LEFT + C_LEN_SETLBL_WIDTH - 40, y: 0, w: 40, h: C_LEN_SETLBL_HEIGHT, siz: 12,
5382
5490
  borderStyle: `solid`, cxtFunc: evt => setLockView(evt.target),
5383
5491
  }, g_cssObj.button_Default, g_cssObj[`button_Rev${g_stateObj.filterLock}`]),
@@ -5393,10 +5501,8 @@ function createSettingsDisplayWindow(_sprite) {
5393
5501
  }
5394
5502
 
5395
5503
  const appearanceSlider = document.querySelector(`#appearanceSlider`);
5396
- appearanceSlider.addEventListener(`input`, _ => {
5397
- g_hidSudObj.filterPos = parseInt(appearanceSlider.value);
5398
- lblAppearancePos.textContent = `${g_hidSudObj.filterPos}${getStgDetailName(g_lblNameObj.percent)}`;
5399
- }, false);
5504
+ appearanceSlider.addEventListener(`input`, _ =>
5505
+ g_hidSudObj.filterPos = inputSlider(appearanceSlider, lblAppearancePos), false);
5400
5506
 
5401
5507
  const dispAppearanceSlider = _ => {
5402
5508
  [`lblAppearancePos`, `lblAppearanceBar`, `lnkLockBtn`].forEach(obj =>
@@ -5409,7 +5515,7 @@ function createSettingsDisplayWindow(_sprite) {
5409
5515
  // ---------------------------------------------------
5410
5516
  // 判定表示系の不透明度 (Opacity)
5411
5517
  // 縦位置: 9
5412
- createGeneralSetting(spriteList.opacity, `opacity`, { unitName: getStgDetailName(g_lblNameObj.percent), displayName: g_currentPage });
5518
+ createGeneralSetting(spriteList.opacity, `opacity`, { unitName: g_lblNameObj.percent, displayName: g_currentPage });
5413
5519
 
5414
5520
  /**
5415
5521
  * Display表示/非表示ボタン
@@ -5544,7 +5650,7 @@ function keyConfigInit(_kcType = g_kcType) {
5544
5650
  );
5545
5651
 
5546
5652
  // キーの一覧を表示
5547
- const keyconSprite = createEmptySprite(divRoot, `keyconSprite`, { y: 100 + (g_sHeight - 500) / 2, h: 300 });
5653
+ const keyconSprite = createEmptySprite(divRoot, `keyconSprite`, { y: 88 + (g_sHeight - 500) / 2, h: g_sHeight, overflow: `auto` });
5548
5654
  const tkObj = getKeyInfo();
5549
5655
  const [keyCtrlPtn, keyNum, posMax, divideCnt] =
5550
5656
  [tkObj.keyCtrlPtn, tkObj.keyNum, tkObj.posMax, tkObj.divideCnt];
@@ -5554,6 +5660,19 @@ function keyConfigInit(_kcType = g_kcType) {
5554
5660
  const kWidth = parseInt(keyconSprite.style.width);
5555
5661
  changeSetColor();
5556
5662
 
5663
+ const maxLeftPos = Math.max(divideCnt, posMax - divideCnt - 2) / 2;
5664
+ const maxLeftX = Math.min(0, (kWidth - C_ARW_WIDTH) / 2 - maxLeftPos * g_keyObj.blank);
5665
+
5666
+ /**
5667
+ * keyconSpriteのスクロール位置調整
5668
+ * @param {number} _targetX
5669
+ */
5670
+ const adjustScrollPoint = _targetX => {
5671
+ if (maxLeftX !== 0) {
5672
+ keyconSprite.scrollLeft = Math.max(0, _targetX - g_sWidth / 2);
5673
+ }
5674
+ };
5675
+
5557
5676
  /**
5558
5677
  * キーコンフィグ用の矢印色を取得
5559
5678
  * @param {number} _colorPos
@@ -5619,6 +5738,8 @@ function keyConfigInit(_kcType = g_kcType) {
5619
5738
  const arrowColor = getKeyConfigColor(_j, g_keyObj[`color${keyCtrlPtn}`][_j]);
5620
5739
  $id(`arrow${_j}`).background = arrowColor;
5621
5740
  $id(`arrowShadow${_j}`).background = getShadowColor(g_keyObj[`color${keyCtrlPtn}`][_j], arrowColor);
5741
+
5742
+ adjustScrollPoint(parseFloat($id(`arrow${_j}`).left));
5622
5743
  };
5623
5744
 
5624
5745
  /**
@@ -5629,6 +5750,8 @@ function keyConfigInit(_kcType = g_kcType) {
5629
5750
  const changeTmpShuffleNum = (_j, _scrollNum = 1) => {
5630
5751
  const tmpShuffle = changeTmpData(`shuffle`, 10, _j, _scrollNum);
5631
5752
  document.getElementById(`sArrow${_j}`).textContent = tmpShuffle + 1;
5753
+
5754
+ adjustScrollPoint(parseFloat($id(`arrow${_j}`).left));
5632
5755
  };
5633
5756
 
5634
5757
  for (let j = 0; j < keyNum; j++) {
@@ -5636,8 +5759,8 @@ function keyConfigInit(_kcType = g_kcType) {
5636
5759
  const posj = g_keyObj[`pos${keyCtrlPtn}`][j];
5637
5760
  const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
5638
5761
 
5639
- const keyconX = g_keyObj.blank * stdPos + (kWidth - C_ARW_WIDTH) / 2;
5640
- const keyconY = C_KYC_HEIGHT * (Number(posj > divideCnt));
5762
+ const keyconX = g_keyObj.blank * stdPos + (kWidth - C_ARW_WIDTH) / 2 - maxLeftX;
5763
+ const keyconY = C_KYC_HEIGHT * (Number(posj > divideCnt)) + 12;
5641
5764
  const colorPos = g_keyObj[`color${keyCtrlPtn}`][j];
5642
5765
  const arrowColor = getKeyConfigColor(j, colorPos);
5643
5766
 
@@ -5697,7 +5820,7 @@ function keyConfigInit(_kcType = g_kcType) {
5697
5820
 
5698
5821
  // カーソルの作成
5699
5822
  const cursor = keyconSprite.appendChild(createImg(`cursor`, g_imgObj.cursor,
5700
- (kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * (posj - divideCnt / 2) - 10, 45, 15, 30));
5823
+ (kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * (posj - divideCnt / 2) - 10, 57, 15, 30));
5701
5824
  cursor.style.transitionDuration = `0.125s`;
5702
5825
 
5703
5826
  const viewGroupObj = {
@@ -5890,13 +6013,17 @@ function keyConfigInit(_kcType = g_kcType) {
5890
6013
  const posj = g_keyObj[`pos${keyCtrlPtn}`][g_currentj];
5891
6014
  const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
5892
6015
 
5893
- cursor.style.left = `${(kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * stdPos - 10}px`;
5894
- const baseY = C_KYC_HEIGHT * Number(posj > divideCnt) + 45;
6016
+ const nextLeft = (kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * stdPos - maxLeftX - 10;
6017
+ cursor.style.left = `${nextLeft}px`;
6018
+ const baseY = C_KYC_HEIGHT * Number(posj > divideCnt) + 57;
5895
6019
  cursor.style.top = `${baseY + C_KYC_REPHEIGHT * g_currentk}px`;
5896
6020
  if (g_currentk === 0 && g_kcType === `Replaced`) {
5897
6021
  g_kcType = C_FLG_ALL;
5898
6022
  lnkKcType.textContent = getStgDetailName(g_kcType);
5899
6023
  }
6024
+
6025
+ // 次の位置が見えなくなったらkeyconSpriteの位置を調整する
6026
+ adjustScrollPoint(nextLeft);
5900
6027
  };
5901
6028
 
5902
6029
  /**
@@ -5964,6 +6091,7 @@ function keyConfigInit(_kcType = g_kcType) {
5964
6091
  // ConfigType, ColorTypeの初期設定
5965
6092
  setConfigType(0);
5966
6093
  setColorType(0);
6094
+ keyconSprite.scrollLeft = - maxLeftX;
5967
6095
 
5968
6096
  // キーパターン表示
5969
6097
  const lblTransKey = hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ?
@@ -5982,12 +6110,7 @@ function keyConfigInit(_kcType = g_kcType) {
5982
6110
  };
5983
6111
 
5984
6112
  // ユーザカスタムイベント(初期)
5985
- if (typeof customKeyConfigInit === C_TYP_FUNCTION) {
5986
- customKeyConfigInit();
5987
- if (typeof customKeyConfigInit2 === C_TYP_FUNCTION) {
5988
- customKeyConfigInit2();
5989
- }
5990
- }
6113
+ g_customJsObj.keyconfig.forEach(func => func());
5991
6114
 
5992
6115
  // ラベル・ボタン描画
5993
6116
  multiAppend(divRoot,
@@ -6045,6 +6168,7 @@ function keyConfigInit(_kcType = g_kcType) {
6045
6168
  }
6046
6169
  }
6047
6170
  resetCursor(Number(g_kcType === `Replaced`));
6171
+ keyconSprite.scrollLeft = - maxLeftX;
6048
6172
  }
6049
6173
  }, {
6050
6174
  x: 0, y: g_sHeight - 75,
@@ -6111,15 +6235,8 @@ function keyConfigInit(_kcType = g_kcType) {
6111
6235
  }
6112
6236
  });
6113
6237
 
6114
- if (typeof skinKeyConfigInit === C_TYP_FUNCTION) {
6115
- skinKeyConfigInit();
6116
- if (typeof skinKeyConfigInit2 === C_TYP_FUNCTION) {
6117
- skinKeyConfigInit2();
6118
- }
6119
- }
6120
-
6238
+ g_skinJsObj.keyconfig.forEach(func => func());
6121
6239
  document.onkeyup = evt => commonKeyUp(evt);
6122
-
6123
6240
  document.oncontextmenu = _ => false;
6124
6241
  }
6125
6242
 
@@ -6198,18 +6315,8 @@ function loadingScoreInit() {
6198
6315
  g_headerObj.blankFrame = g_headerObj.blankFrameDef;
6199
6316
 
6200
6317
  // ユーザカスタムイベント
6201
- if (typeof customPreloadingInit === C_TYP_FUNCTION) {
6202
- customPreloadingInit();
6203
- if (typeof customPreloadingInit2 === C_TYP_FUNCTION) {
6204
- customPreloadingInit2();
6205
- }
6206
- }
6207
- if (typeof skinPreloadingInit === C_TYP_FUNCTION) {
6208
- skinPreloadingInit();
6209
- if (typeof skinPreloadingInit2 === C_TYP_FUNCTION) {
6210
- skinPreloadingInit2();
6211
- }
6212
- }
6318
+ g_customJsObj.preloading.forEach(func => func());
6319
+ g_skinJsObj.preloading.forEach(func => func());
6213
6320
 
6214
6321
  let dummyIdHeader = ``;
6215
6322
  if (g_stateObj.dummyId !== ``) {
@@ -6229,7 +6336,7 @@ function loadingScoreInit() {
6229
6336
 
6230
6337
  // 開始フレーム数の取得(フェードイン加味)
6231
6338
  g_scoreObj.frameNum = getStartFrame(lastFrame, g_stateObj.fadein);
6232
- g_scoreObj.baseFrame;
6339
+ g_scoreObj.baseFrame = g_scoreObj.frameNum - g_stateObj.intAdjustment;
6233
6340
 
6234
6341
  // フレームごとの速度を取得(配列形式)
6235
6342
  let speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
@@ -6340,12 +6447,7 @@ function loadingScoreInit() {
6340
6447
  getArrowSettings();
6341
6448
 
6342
6449
  // ユーザカスタムイベント
6343
- if (typeof customLoadingInit === C_TYP_FUNCTION) {
6344
- customLoadingInit();
6345
- if (typeof customLoadingInit2 === C_TYP_FUNCTION) {
6346
- customLoadingInit2();
6347
- }
6348
- }
6450
+ g_customJsObj.loading.forEach(func => func());
6349
6451
 
6350
6452
  const tempId = setInterval(() => {
6351
6453
  const executeMain = _ => {
@@ -6598,18 +6700,27 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6598
6700
  obj.speedData = setSpeedData(`speed`, scoreIdHeader, speedFooter);
6599
6701
 
6600
6702
  // 色変化(個別・全体)の分解 (3つで1セット, セット毎の改行区切り可)
6601
- g_typeLists.color.forEach(sprite =>
6602
- obj[`${sprite}Data`] = setColorData(sprite, scoreIdHeader));
6703
+ g_typeLists.color.forEach(sprite => {
6704
+ obj[`${sprite}Data`] = setColorData(sprite, scoreIdHeader);
6705
+ if (g_stateObj.dummyId !== ``) {
6706
+ obj[`${sprite}DummyData`] = setColorData(sprite, _dummyNo);
6707
+ }
6708
+ });
6603
6709
 
6604
6710
  if (_scoreAnalyzeFlg) {
6605
6711
  return obj;
6606
6712
  }
6607
6713
 
6714
+ obj.colorData = mergeColorData();
6715
+ obj.dummyColorData = mergeColorData(`Dummy`);
6716
+
6608
6717
  // 矢印モーション(個別)データの分解(3~4つで1セット, セット毎の改行区切り)
6609
6718
  obj.arrowCssMotionData = setCssMotionData(`arrow`, scoreIdHeader);
6610
6719
  obj.frzCssMotionData = setCssMotionData(`frz`, scoreIdHeader);
6611
- obj.dummyArrowCssMotionData = setCssMotionData(`arrow`, _dummyNo);
6612
- obj.dummyFrzCssMotionData = setCssMotionData(`frz`, _dummyNo);
6720
+ if (g_stateObj.dummyId !== ``) {
6721
+ obj.dummyArrowCssMotionData = setCssMotionData(`arrow`, _dummyNo);
6722
+ obj.dummyFrzCssMotionData = setCssMotionData(`frz`, _dummyNo);
6723
+ }
6613
6724
 
6614
6725
  // 歌詞データの分解 (3つで1セット, セット毎の改行区切り可)
6615
6726
  obj.wordData = [];
@@ -6680,13 +6791,26 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6680
6791
  return [];
6681
6792
  }
6682
6793
 
6794
+ /**
6795
+ * 個別・全体色変化データをマージして整列し、単純配列として返却
6796
+ * @param {string} _header
6797
+ * @returns
6798
+ */
6799
+ function mergeColorData(_header = ``) {
6800
+ if (obj[`color${_header}Data`] === undefined) return [];
6801
+ const tmpArr = obj[`color${_header}Data`].concat(obj[`acolor${_header}Data`]);
6802
+ return tmpArr.sort((_a, _b) => _a[0] - _b[0]).flat();
6803
+ }
6804
+
6683
6805
  /**
6684
6806
  * 色変化データの分解・格納(フレーム数, 矢印番号)
6807
+ * 後で個別・全体色変化をマージするため、二次元配列として返却
6685
6808
  * @param {string} _header
6686
6809
  * @param {number} _scoreNo
6687
6810
  */
6688
6811
  function setColorData(_header, _scoreNo) {
6689
6812
  const colorData = [];
6813
+ const allFlg = (_header.charAt(0) === `a`);
6690
6814
 
6691
6815
  if (hasVal(_dosObj[`${_header}${_scoreNo}_data`]) && g_stateObj.d_color === C_FLG_ON) {
6692
6816
  const tmpArrayData = splitLF(_dosObj[`${_header}${_scoreNo}_data`]);
@@ -6703,10 +6827,11 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6703
6827
  const colorNum = setVal(tmpColorData[k + 1], 0, C_TYP_CALC);
6704
6828
  const colorCd = tmpColorData[k + 2];
6705
6829
 
6706
- colorData.push([frame, colorNum, colorCd]);
6830
+ // フレーム数、色番号、カラーコード、全体色変化フラグをセットとして配列化
6831
+ colorData.push([frame, colorNum, colorCd, allFlg]);
6707
6832
  }
6708
6833
  });
6709
- return colorData.sort((_a, _b) => _a[0] - _b[0]).flat();
6834
+ return colorData.sort((_a, _b) => _a[0] - _b[0]);
6710
6835
  }
6711
6836
  return [];
6712
6837
  }
@@ -7265,33 +7390,32 @@ function pushArrows(_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
7265
7390
  }
7266
7391
 
7267
7392
  // 個別・全体色変化、モーションデータのタイミング更新
7268
- calcDataTiming(`color`, ``, 3, pushColors, { _colorFlg: true });
7269
- calcDataTiming(`color`, `a`, 3, pushColors);
7270
- calcDataTiming(`color`, `shadow`, 3, pushColors, { _colorFlg: true });
7271
- calcDataTiming(`color`, `ashadow`, 3, pushColors);
7393
+ [``, `dummy`].forEach(type =>
7394
+ calcDataTiming(`color`, type, pushColors, { _colorFlg: true }));
7272
7395
 
7273
- [`arrow`, `frz`, `dummyArrow`, `dummyFrz`].forEach(header =>
7274
- calcDataTiming(`CssMotion`, header, 4, pushCssMotions, { _calcFrameFlg: true }));
7396
+ g_typeLists.arrow.forEach(header =>
7397
+ calcDataTiming(`cssMotion`, header, pushCssMotions, { _calcFrameFlg: true }));
7275
7398
 
7276
7399
  /**
7277
7400
  * 色変化・モーションデータのタイミング更新
7278
7401
  * @param {string} _type
7279
7402
  * @param {string} _header
7280
- * @param {integer} _term
7281
7403
  * @param {function} _setFunc
7282
7404
  * @param {object} obj _colorFlg: 個別色変化フラグ, _calcFrameFlg: 逆算を無条件で行うかどうかの可否
7283
7405
  * @returns
7284
7406
  */
7285
- function calcDataTiming(_type, _header, _term, _setFunc = _ => true,
7286
- { _colorFlg = false, _calcFrameFlg = false } = {}) {
7287
- const baseData = _dataObj[`${_header}${_type}Data`];
7407
+ function calcDataTiming(_type, _header, _setFunc = _ => true,
7408
+ { _term = 4, _colorFlg = false, _calcFrameFlg = false } = {}) {
7409
+
7410
+ const camelHeader = _header === `` ? _type : `${_header}${toCapitalize(_type)}`;
7411
+ const baseData = _dataObj[`${camelHeader}Data`];
7288
7412
 
7289
7413
  if (!hasArrayList(baseData, _term)) {
7290
7414
  return;
7291
7415
  }
7292
7416
  const frontData = [];
7293
7417
  for (let k = baseData.length - _term; k >= 0; k -= _term) {
7294
- const calcFrameFlg = (_colorFlg && !isFrzHitColor(baseData[k + 1])) || _calcFrameFlg;
7418
+ const calcFrameFlg = (_colorFlg && !isFrzHitColor(baseData[k + 1]) && !baseData[k + 3]) || _calcFrameFlg;
7295
7419
 
7296
7420
  if (baseData[k] < g_scoreObj.frameNum) {
7297
7421
  if (!hasValInArray(baseData[k + 1], frontData)) {
@@ -7314,6 +7438,74 @@ function pushArrows(_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
7314
7438
  frontData.forEach(data => _setFunc(toCapitalize(_header), g_scoreObj.frameNum, ...data));
7315
7439
  }
7316
7440
 
7441
+ g_fadeinStockList.forEach(type =>
7442
+ _dataObj[`${type}Data`] = calcAnimationData(type, _dataObj[`${type}Data`]));
7443
+
7444
+ /**
7445
+ * 歌詞表示、背景・マスク表示のフェードイン時調整処理
7446
+ * @param {string} _type
7447
+ * @param {object} _data
7448
+ * @returns
7449
+ */
7450
+ function calcAnimationData(_type, _data) {
7451
+
7452
+ const startNum = g_scoreObj.frameNum;
7453
+ const cgArrays = [`word`];
7454
+
7455
+ const isSameDepth = (_j, _k) =>
7456
+ _data[startNum][_j] !== undefined &&
7457
+ _data[startNum][_k] !== undefined &&
7458
+ (cgArrays.includes(_type) ? _data[startNum][_j][0] === _data[startNum][_k][0] :
7459
+ _data[startNum][_j].depth === _data[startNum][_k].depth);
7460
+
7461
+ const fuzzyCheck = (_str, _list) => listMatching(_str, _list);
7462
+ const isExceptData = {
7463
+ word: (_exceptList, _j) => fuzzyCheck(_data[startNum][_j][1], _exceptList.word),
7464
+ back: (_exceptList, _j) => fuzzyCheck(_data[startNum][_j].animationName, _exceptList.back),
7465
+ mask: (_exceptList, _j) => fuzzyCheck(_data[startNum][_j].animationName, _exceptList.mask),
7466
+ };
7467
+
7468
+ const getLength = _list =>
7469
+ _list === undefined ? 0 :
7470
+ (cgArrays.includes(_type) ? _list.length : Object.keys(_list).length);
7471
+
7472
+ // フェードイン位置にそれ以前のデータを前追加
7473
+ if (startNum > 0 && _data[startNum] === undefined) {
7474
+ _data[startNum] = [];
7475
+ }
7476
+ for (let j = _data.length - 1; j >= 0; j--) {
7477
+ if (_data[j] !== undefined && j < g_scoreObj.frameNum) {
7478
+ _data[startNum].unshift(..._data[j]);
7479
+ _data[j] = undefined;
7480
+ }
7481
+ }
7482
+
7483
+ // 重複する深度をカット(後方優先)
7484
+ // ただし、除外リストにあるデータは残す
7485
+ for (let j = getLength(_data[startNum]) - 1; j >= 0; j--) {
7486
+ if (_data[startNum][j] !== undefined) {
7487
+ for (let k = j - 1; k >= 0; k--) {
7488
+ if (isSameDepth(j, k) && !isExceptData[_type](g_preloadExceptList, k)) {
7489
+ _data[startNum][k] = undefined;
7490
+ }
7491
+ }
7492
+ }
7493
+ }
7494
+ // g_stockForceDelList に合致する消去対象データを検索し、削除
7495
+ for (let j = getLength(_data[startNum]) - 1; j >= 0; j--) {
7496
+ if (_data[startNum][j] !== undefined && isExceptData[_type](g_stockForceDelList, j)) {
7497
+ _data[startNum][j] = undefined;
7498
+ }
7499
+ }
7500
+
7501
+ // カットした箇所をリストから削除
7502
+ if (getLength(_data[startNum], _type) > 0) {
7503
+ _data[startNum] = _data[startNum].filter(list => getLength(list) > 0);
7504
+ }
7505
+
7506
+ return _data;
7507
+ }
7508
+
7317
7509
  // 実際に処理させる途中変速配列を作成
7318
7510
  g_workObj.speedData = [];
7319
7511
  g_workObj.speedData.length = 0;
@@ -7408,54 +7600,108 @@ function convertreplaceNums() {
7408
7600
  * @param {number} _frame
7409
7601
  * @param {number} _val
7410
7602
  * @param {string} _colorCd
7603
+ * @param {string} _allFlg
7411
7604
  */
7412
- function pushColors(_header, _frame, _val, _colorCd) {
7605
+ function pushColors(_header, _frame, _val, _colorCd, _allFlg) {
7413
7606
 
7414
7607
  const tkObj = getKeyInfo();
7415
7608
  const grdFlg = (g_colorType === `Type0` ? !g_headerObj.defaultColorgrd[0] : g_headerObj.defaultColorgrd[0])
7416
7609
  const colorCd = makeColorGradation(_colorCd, { _defaultColorgrd: [grdFlg, g_headerObj.defaultColorgrd[1]] });
7610
+ const addAll = Number(_allFlg) * 1000;
7611
+ const allUseTypes = [];
7612
+
7613
+ /**
7614
+ * 色変化用配列(フレーム別)の初期化
7615
+ * @param {string} _baseStr
7616
+ */
7617
+ const initialize = (_baseStr) => {
7618
+ if (g_workObj[_baseStr][_frame] === undefined) {
7619
+ g_workObj[_baseStr][_frame] = [];
7620
+ g_workObj[`${_baseStr}Cd`][_frame] = [];
7621
+ }
7622
+ };
7623
+
7624
+ /**
7625
+ * 全体色変化の有効化(フレーム別)
7626
+ * @param {...any} _types
7627
+ */
7628
+ const enabledAll = (..._types) => {
7629
+ if (_allFlg) {
7630
+ _types.forEach(type => g_workObj[`mk${type}ColorChangeAll`][_frame] = true);
7631
+ }
7632
+ };
7633
+
7634
+ /**
7635
+ * 色変化用配列(フレーム別)へのデータ追加
7636
+ * @param {string} _baseStr
7637
+ * @param {number} _cVal
7638
+ */
7639
+ const pushColor = (_baseStr, _cVal) => {
7640
+ g_workObj[_baseStr][_frame].push(_cVal);
7641
+ g_workObj[`${_baseStr}Cd`][_frame].push(colorCd);
7642
+ };
7417
7643
 
7418
7644
  if (_val < 30 || _val >= 1000) {
7419
- // 矢印の色変化
7420
- if (g_workObj[`mk${_header}Color`][_frame] === undefined) {
7421
- g_workObj[`mk${_header}Color`][_frame] = [];
7422
- g_workObj[`mk${_header}ColorCd`][_frame] = [];
7423
- }
7424
- if (_val < 20 || _val >= 1000) {
7425
- const realVal = g_workObj.replaceNums[_val % 1000];
7426
- g_workObj[`mk${_header}Color`][_frame].push(realVal);
7427
- g_workObj[`mk${_header}ColorCd`][_frame].push(colorCd);
7428
- } else if (_val >= 20) {
7429
- const colorNum = _val - 20;
7430
- for (let j = 0; j < tkObj.keyNum; j++) {
7431
- if (g_keyObj[`color${tkObj.keyCtrlPtn}`][j] === colorNum) {
7432
- g_workObj[`mk${_header}Color`][_frame].push(j);
7433
- g_workObj[`mk${_header}ColorCd`][_frame].push(colorCd);
7645
+ const baseHeaders = [`mk${_header}Color`];
7646
+ allUseTypes.push(`Arrow`);
7647
+
7648
+ // フリーズアロー色の追随設定がある場合、対象を追加
7649
+ g_headerObj.frzScopeFromArrowColors.forEach(type => {
7650
+ baseHeaders.push(`mk${_header}FColor${type}`, `mk${_header}FColor${type}Bar`);
7651
+ });
7652
+ if (g_headerObj.frzScopeFromArrowColors.length > 0) {
7653
+ allUseTypes.push(`Frz`);
7654
+ }
7655
+
7656
+ // 矢印の色変化 (追随指定時はフリーズアローも色変化)
7657
+ baseHeaders.forEach(baseHeader => {
7658
+ initialize(baseHeader);
7659
+
7660
+ if (_val < 20 || _val >= 1000) {
7661
+ pushColor(baseHeader, g_workObj.replaceNums[_val % 1000] + addAll);
7662
+ } else if (_val >= 20) {
7663
+ const colorNum = _val - 20;
7664
+ for (let j = 0; j < tkObj.keyNum; j++) {
7665
+ if (g_keyObj[`color${tkObj.keyCtrlPtn}`][j] === colorNum) {
7666
+ pushColor(baseHeader, j + addAll);
7667
+ }
7434
7668
  }
7435
7669
  }
7436
- }
7670
+ });
7671
+
7437
7672
  } else {
7673
+ const baseHeader = `mk${_header}FColor`;
7674
+ allUseTypes.push(`Frz`);
7675
+
7438
7676
  // フリーズアローの色変化
7439
- if (g_workObj[`mkF${_header}Color`][_frame] === undefined) {
7440
- g_workObj[`mkF${_header}Color`][_frame] = [];
7441
- g_workObj[`mkF${_header}ColorCd`][_frame] = [];
7442
- }
7677
+ const tmpVals = [];
7443
7678
  if (_val < 50) {
7444
- g_workObj[`mkF${_header}Color`][_frame].push(_val % 30);
7445
- g_workObj[`mkF${_header}ColorCd`][_frame].push(colorCd);
7679
+ tmpVals.push(_val % 30);
7446
7680
  } else if (_val < 60) {
7447
- const tmpVal = (_val % 50) * 2;
7448
- g_workObj[`mkF${_header}Color`][_frame].push(tmpVal, tmpVal + 1);
7449
- g_workObj[`mkF${_header}ColorCd`][_frame].push(colorCd, colorCd);
7681
+ tmpVals.push((_val % 50) * 2, (_val % 50) * 2 + 1);
7450
7682
  } else {
7451
7683
  if (_val === 60) {
7452
- g_workObj[`mkF${_header}Color`][_frame].push(0, 1, 2, 3, 4, 5, 6, 7);
7684
+ tmpVals.push(...Array(8).keys());
7453
7685
  } else {
7454
- g_workObj[`mkF${_header}Color`][_frame].push(10, 11, 12, 13, 14, 15, 16, 17);
7686
+ tmpVals.push(...[...Array(8).keys()].map(j => j + 10));
7455
7687
  }
7456
- g_workObj[`mkF${_header}ColorCd`][_frame].push(colorCd, colorCd, colorCd, colorCd, colorCd, colorCd, colorCd, colorCd);
7457
7688
  }
7689
+ tmpVals.forEach(targetj => {
7690
+
7691
+ // targetj=0,2,4,6,8 ⇒ Arrow, 1,3,5,7,9 ⇒ Bar
7692
+ const ctype = (targetj >= 10 ? `Hit` : `Normal`) + (targetj % 2 === 0 ? `` : `Bar`);
7693
+ const colorPos = Math.ceil((targetj % 10 - 1) / 2);
7694
+
7695
+ g_keyObj[`color${tkObj.keyCtrlPtn}`].forEach((cpattern, k) => {
7696
+ if (colorPos === cpattern) {
7697
+ initialize(baseHeader + ctype);
7698
+ pushColor(baseHeader + ctype, k + addAll);
7699
+ }
7700
+ });
7701
+ });
7458
7702
  }
7703
+
7704
+ enabledAll(...allUseTypes);
7459
7705
  }
7460
7706
 
7461
7707
  /**
@@ -7512,6 +7758,7 @@ function getArrowSettings() {
7512
7758
  g_workObj.stepHitRtn = copyArray2d(g_keyObj[`stepRtn${keyCtrlPtn}`]);
7513
7759
  g_workObj.arrowRtn = copyArray2d(g_keyObj[`stepRtn${keyCtrlPtn}`]);
7514
7760
  g_workObj.keyCtrl = copyArray2d(g_keyObj[`keyCtrl${keyCtrlPtn}`]);
7761
+ g_workObj.diffList = [];
7515
7762
 
7516
7763
  const keyCtrlLen = g_workObj.keyCtrl.length;
7517
7764
  g_workObj.keyCtrlN = [...Array(keyCtrlLen)].map(_ => []);
@@ -7690,6 +7937,9 @@ function MainInit() {
7690
7937
  // マスクスプライトを作成 (最上位)
7691
7938
  createMultipleSprite(`maskSprite`, g_scoreObj.maskMaxDepth);
7692
7939
 
7940
+ // カラー・モーションを適用するオブジェクトの種類
7941
+ const objList = (g_stateObj.dummyId === `` ? [``] : [`dummy`, ``]);
7942
+
7693
7943
  // 背景・マスクモーション(0フレーム指定)
7694
7944
  if (g_scoreObj.frameNum === 0) {
7695
7945
  g_animationData.forEach(sprite => {
@@ -8083,13 +8333,7 @@ function MainInit() {
8083
8333
  }
8084
8334
 
8085
8335
  // ユーザカスタムイベント(初期)
8086
- if (typeof customMainInit === C_TYP_FUNCTION) {
8087
- g_scoreObj.baseFrame = g_scoreObj.frameNum - g_stateObj.intAdjustment;
8088
- customMainInit();
8089
- if (typeof customMainInit2 === C_TYP_FUNCTION) {
8090
- customMainInit2();
8091
- }
8092
- }
8336
+ g_customJsObj.main.forEach(func => func());
8093
8337
 
8094
8338
  /**
8095
8339
  * キーを押したときの処理
@@ -8188,57 +8432,70 @@ function MainInit() {
8188
8432
  }
8189
8433
 
8190
8434
  /**
8191
- * 全体色変化
8192
- *
8193
- * @param _j 矢印位置
8194
- * @param _k 矢印の表示順
8195
- * @param _state フリーズアローの色変化対象 (Normal: 通常時、Hit: ヒット時)
8435
+ * 全体色変化(矢印)
8436
+ * @param {number} _j
8437
+ * @param {number} _k
8438
+ * @param {string} _name
8196
8439
  */
8197
- const changeColorFunc = {
8440
+ const changeArrowColor = (_j, _k, _name) => {
8441
+ if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`][g_scoreObj.frameNum]) {
8442
+ const colorSelf = g_workObj[`${_name}Colors`][_j];
8443
+ const colorAll = g_workObj[`${_name}ColorsAll`][_j];
8444
+ const arrowTop = document.querySelector(`#${_name}Top${_j}_${_k}`);
8198
8445
 
8199
- // TODO: この部分を矢印塗りつぶし部分についても適用できるように対応
8200
- arrow: (_j, _k) => {
8201
- const arrowTop = document.querySelector(`#arrowTop${_j}_${_k}`);
8202
- if (g_workObj.mkAColor[g_scoreObj.frameNum] !== undefined) {
8203
- if (arrowTop.getAttribute(`color`) !== g_workObj.arrowColors[_j]) {
8204
- if (g_workObj.arrowColors[_j] === g_workObj.arrowColorsAll[_j]) {
8205
- arrowTop.style.background = g_workObj.arrowColorsAll[_j];
8206
- arrowTop.setAttribute(`color`, g_workObj.arrowColorsAll[_j]);
8207
- }
8208
- }
8446
+ if (arrowTop.getAttribute(`color`) !== colorSelf && colorAll === colorSelf) {
8447
+ arrowTop.style.background = colorAll;
8448
+ arrowTop.setAttribute(`color`, colorAll);
8209
8449
  }
8210
- },
8211
-
8212
- dummyArrow: (_j, _k) => { },
8213
-
8214
- // TODO: この部分を矢印塗りつぶし部分についても適用できるように対応
8215
- frz: (_j, _k, _state) => {
8216
- const frzTop = document.querySelector(`#frzTop${_j}_${_k}`);
8217
- const frzBar = document.querySelector(`#frzBar${_j}_${_k}`);
8218
- const frzBtm = document.querySelector(`#frzBtm${_j}_${_k}`);
8450
+ }
8451
+ };
8219
8452
 
8220
- if (g_workObj.mkFAColor[g_scoreObj.frameNum] !== undefined) {
8221
- if (frzBtm.getAttribute(`color`) !== g_workObj[`frz${_state}Colors`][_j]) {
8222
- const toColorCode = g_workObj[`frz${_state}ColorsAll`][_j];
8223
- if (g_workObj[`frz${_state}Colors`][_j] === toColorCode) {
8224
- if (_state === `Normal`) {
8225
- frzTop.style.background = toColorCode;
8226
- }
8227
- frzBtm.style.background = toColorCode;
8228
- frzBtm.setAttribute(`color`, toColorCode);
8453
+ /**
8454
+ * 全体色変化(フリーズアロー)
8455
+ * @param {number} _j 矢印位置
8456
+ * @param {number} _k 矢印の表示順
8457
+ * @param {string} _name 通常, ダミー
8458
+ * @param {string} _state フリーズアローの色変化対象 (Normal: 通常時、Hit: ヒット時)
8459
+ */
8460
+ const changeFrzColor = (_j, _k, _name, _state) => {
8461
+
8462
+ if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`][g_scoreObj.frameNum]) {
8463
+ const frzTop = document.querySelector(`#${_name}Top${_j}_${_k}`);
8464
+ const frzBar = document.querySelector(`#${_name}Bar${_j}_${_k}`);
8465
+ const frzBtm = document.querySelector(`#${_name}Btm${_j}_${_k}`);
8466
+ const frzName = `${_name}${_state}`;
8467
+
8468
+ // 矢印部分の色変化
8469
+ if (frzBtm.getAttribute(`color`) !== g_workObj[`${frzName}Colors`][_j]) {
8470
+ const toColorCode = g_workObj[`${frzName}ColorsAll`][_j];
8471
+ if (g_workObj[`${frzName}Colors`][_j] === toColorCode) {
8472
+ if (_state === `Normal`) {
8473
+ frzTop.style.background = toColorCode;
8229
8474
  }
8475
+ frzBtm.style.background = toColorCode;
8476
+ frzBtm.setAttribute(`color`, toColorCode);
8230
8477
  }
8231
- if (frzBar.getAttribute(`color`) !== g_workObj[`frz${_state}BarColors`][_j]) {
8232
- const toBarColorCode = g_workObj[`frz${_state}BarColorsAll`][_j];
8233
- if (g_workObj[`frz${_state}BarColors`][_j] === toBarColorCode) {
8234
- frzBar.style.background = toBarColorCode;
8235
- frzBar.setAttribute(`color`, toBarColorCode);
8236
- }
8478
+ }
8479
+ // 帯部分の色変化
8480
+ if (frzBar.getAttribute(`color`) !== g_workObj[`${frzName}BarColors`][_j]) {
8481
+ const toBarColorCode = g_workObj[`${frzName}BarColorsAll`][_j];
8482
+ if (g_workObj[`${frzName}BarColors`][_j] === toBarColorCode) {
8483
+ frzBar.style.background = toBarColorCode;
8484
+ frzBar.setAttribute(`color`, toBarColorCode);
8237
8485
  }
8238
8486
  }
8239
- },
8487
+ }
8488
+ };
8240
8489
 
8241
- dummyFrz: (_j, _k, _state) => { },
8490
+
8491
+ /**
8492
+ * 全体色変化
8493
+ */
8494
+ const changeColorFunc = {
8495
+ arrow: (_j, _k) => changeArrowColor(_j, _k, `arrow`),
8496
+ dummyArrow: (_j, _k) => changeArrowColor(_j, _k, `dummyArrow`),
8497
+ frz: (_j, _k, _state) => changeFrzColor(_j, _k, `frz`, _state),
8498
+ dummyFrz: (_j, _k, _state) => changeFrzColor(_j, _k, `dummyFrz`, _state),
8242
8499
  };
8243
8500
 
8244
8501
  /**
@@ -8294,12 +8551,7 @@ function MainInit() {
8294
8551
  if (_cnt === 0) {
8295
8552
  const stepDivHit = document.querySelector(`#stepHit${_j}`);
8296
8553
 
8297
- if (typeof customJudgeDummyArrow === C_TYP_FUNCTION) {
8298
- customJudgeDummyArrow(_cnt);
8299
- if (typeof customJudgeDummyArrow2 === C_TYP_FUNCTION) {
8300
- customJudgeDummyArrow2(_cnt);
8301
- }
8302
- }
8554
+ g_customJsObj.dummyArrow.forEach(func => func());
8303
8555
  stepDivHit.style.top = `-15px`;
8304
8556
  stepDivHit.style.opacity = 1;
8305
8557
  stepDivHit.classList.value = ``;
@@ -8319,12 +8571,7 @@ function MainInit() {
8319
8571
 
8320
8572
  // ダミーフリーズアロー(成功時)
8321
8573
  dummyFrzOK: (_j, _k, _frzName, _cnt) => {
8322
- if (typeof customJudgeDummyFrz === C_TYP_FUNCTION) {
8323
- customJudgeDummyFrz(_cnt);
8324
- if (typeof customJudgeDummyFrz2 === C_TYP_FUNCTION) {
8325
- customJudgeDummyFrz2(_cnt);
8326
- }
8327
- }
8574
+ g_customJsObj.dummyFrz.forEach(func => func());
8328
8575
  $id(`frzHit${_j}`).opacity = 0;
8329
8576
  g_attrObj[_frzName].judgEndFlg = true;
8330
8577
  judgeObjDelete.dummyFrz(_j, _frzName);
@@ -8478,7 +8725,7 @@ function MainInit() {
8478
8725
  if (g_headerObj.setShadowColor[colorPos] !== ``) {
8479
8726
  // 矢印の塗り部分
8480
8727
  const arrShadow = createColorObject2(`${_name}Shadow${_j}_${_arrowCnt}`, {
8481
- background: getShadowColor(colorPos, g_workObj.arrowColors[_j]), rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
8728
+ background: getShadowColor(colorPos, _color), rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
8482
8729
  });
8483
8730
  if (g_headerObj.setShadowColor[colorPos] === `Default`) {
8484
8731
  arrShadow.style.opacity = 0.5;
@@ -8706,11 +8953,8 @@ function MainInit() {
8706
8953
  }
8707
8954
 
8708
8955
  // ユーザカスタムイベント(フレーム毎)
8709
- if (typeof customMainEnterFrame === C_TYP_FUNCTION) {
8710
- customMainEnterFrame();
8711
- if (typeof customMainEnterFrame2 === C_TYP_FUNCTION) {
8712
- customMainEnterFrame2();
8713
- }
8956
+ g_customJsObj.mainEnterFrame.forEach(func => func());
8957
+ if (g_customJsObj.mainEnterFrame.length > 0) {
8714
8958
  g_scoreObj.baseFrame++;
8715
8959
  }
8716
8960
 
@@ -8724,36 +8968,30 @@ function MainInit() {
8724
8968
  boostCnts += 2;
8725
8969
  }
8726
8970
 
8727
- // 個別色変化 (矢印)
8728
- changeArrowColors(g_workObj.mkColor[currentFrame], g_workObj.mkColorCd[currentFrame]);
8729
-
8730
- // 個別色変化(フリーズアロー)
8731
- changeFrzColors(g_workObj.mkFColor[currentFrame], g_workObj.mkFColorCd[currentFrame],
8732
- g_keyObj[`color${keyCtrlPtn}`]);
8733
-
8734
- // 全体色変化 (矢印)
8735
- changeArrowColors(g_workObj.mkAColor[currentFrame], g_workObj.mkAColorCd[currentFrame], `A`);
8971
+ objList.forEach(header => {
8972
+ const headerU = toCapitalize(header);
8736
8973
 
8737
- // 全体色変化 (フリーズアロー)
8738
- changeFrzColors(g_workObj.mkFAColor[currentFrame], g_workObj.mkFAColorCd[currentFrame],
8739
- g_keyObj[`color${keyCtrlPtn}`], `A`);
8974
+ // 個別・全体色変化 (矢印)
8975
+ changeColors(g_workObj[`mk${headerU}Color`][currentFrame],
8976
+ g_workObj[`mk${headerU}ColorCd`][currentFrame], header, `arrow`);
8740
8977
 
8741
- // 矢印モーション
8742
- changeCssMotions(g_workObj.mkArrowCssMotion[currentFrame], g_workObj.mkArrowCssMotionName[currentFrame], `arrow`);
8978
+ // 個別・全体色変化(フリーズアロー)
8979
+ g_typeLists.frzColor.forEach(ctype =>
8980
+ changeColors(g_workObj[`mk${headerU}FColor${ctype}`][currentFrame],
8981
+ g_workObj[`mk${headerU}FColor${ctype}Cd`][currentFrame], header, `frz${ctype}`));
8743
8982
 
8744
- // フリーズアローモーション
8745
- changeCssMotions(g_workObj.mkFrzCssMotion[currentFrame], g_workObj.mkFrzCssMotionName[currentFrame], `frz`);
8983
+ // 矢印モーション
8984
+ changeCssMotions(header, `arrow`, currentFrame);
8746
8985
 
8747
- // ダミー矢印モーション
8748
- changeCssMotions(g_workObj.mkDummyArrowCssMotion[currentFrame], g_workObj.mkDummyArrowCssMotionName[currentFrame], `dummyArrow`);
8986
+ // フリーズアローモーション
8987
+ changeCssMotions(header, `frz`, currentFrame);
8749
8988
 
8750
- // ダミーフリーズアローモーション
8751
- changeCssMotions(g_workObj.mkDummyFrzCssMotion[currentFrame], g_workObj.mkDummyFrzCssMotionName[currentFrame], `dummyFrz`);
8989
+ });
8752
8990
 
8753
8991
  // ダミー矢印生成(背面に表示するため先に処理)
8754
8992
  if (g_workObj.mkDummyArrow[currentFrame] !== undefined) {
8755
8993
  g_workObj.mkDummyArrow[currentFrame].forEach(data =>
8756
- makeArrow(data, ++dummyArrowCnts[data], `dummyArrow`, C_CLR_DUMMY));
8994
+ makeArrow(data, ++dummyArrowCnts[data], `dummyArrow`, g_workObj.dummyArrowColors[data]));
8757
8995
  }
8758
8996
 
8759
8997
  // 矢印生成
@@ -8765,7 +9003,7 @@ function MainInit() {
8765
9003
  // ダミーフリーズアロー生成
8766
9004
  if (g_workObj.mkDummyFrzArrow[currentFrame] !== undefined) {
8767
9005
  g_workObj.mkDummyFrzArrow[currentFrame].forEach(data =>
8768
- makeFrzArrow(data, ++dummyFrzCnts[data], `dummyFrz`, C_CLR_DUMMY, `#888888`));
9006
+ makeFrzArrow(data, ++dummyFrzCnts[data], `dummyFrz`, g_workObj.dummyFrzNormalColors[data], g_workObj.dummyFrzNormalBarColors[data]));
8769
9007
  }
8770
9008
 
8771
9009
  // フリーズアロー生成
@@ -8911,12 +9149,7 @@ function MainInit() {
8911
9149
  g_timeoutEvtId = setTimeout(_ => flowTimeline(), 1000 / g_fps - buffTime);
8912
9150
  }
8913
9151
  }
8914
- if (typeof skinMainInit === C_TYP_FUNCTION) {
8915
- skinMainInit();
8916
- if (typeof skinMainInit2 === C_TYP_FUNCTION) {
8917
- skinMainInit2();
8918
- }
8919
- }
9152
+ g_skinJsObj.main.forEach(func => func());
8920
9153
 
8921
9154
  g_audio.currentTime = firstFrame / g_fps * g_headerObj.playbackRate;
8922
9155
  g_audio.playbackRate = g_headerObj.playbackRate;
@@ -8986,68 +9219,46 @@ function makeCounterSymbol(_id, _x, _class, _heightPos, _text, _display = C_DIS_
8986
9219
  // TODO: この部分を矢印塗りつぶし部分についても適用できるように関数を見直し
8987
9220
 
8988
9221
  /**
8989
- * 個別色変化 (矢印)
9222
+ * 個別・全体色変化
8990
9223
  * @param {array} _mkColor
8991
9224
  * @param {array} _mkColorCd
8992
- * @param {string} _allFlg
8993
- */
8994
- function changeArrowColors(_mkColor, _mkColorCd, _allFlg = ``) {
8995
-
8996
- if (_mkColor === undefined) {
8997
- return;
8998
- }
8999
- _mkColor.forEach((targetj, j) => {
9000
- g_workObj.arrowColors[targetj] = _mkColorCd[j];
9001
- if (_allFlg === `A`) {
9002
- g_workObj.arrowColorsAll[targetj] = _mkColorCd[j];
9003
- }
9004
- });
9005
- }
9006
-
9007
- /**
9008
- * 個別色変化 (フリーズアロー)
9009
- * @param {array} _mkColor
9010
- * @param {array} _mkColorCd
9011
- * @param {array} _colorPatterns
9012
- * @param {string} _allFlg
9225
+ * @param {string} _header
9226
+ * @param {string} _name
9013
9227
  */
9014
- function changeFrzColors(_mkColor, _mkColorCd, _colorPatterns, _allFlg = ``) {
9228
+ function changeColors(_mkColor, _mkColorCd, _header, _name) {
9015
9229
 
9016
9230
  if (_mkColor === undefined) {
9017
9231
  return;
9018
9232
  }
9019
- _mkColor.forEach((targetj, j) => {
9020
-
9021
- // targetj=0,2,4,6,8 Arrow, 1,3,5,7,9 ⇒ Bar
9022
- const ctype = (targetj >= 10 ? `Hit` : `Normal`) + (targetj % 2 === 0 ? `` : `Bar`);
9023
- const colorPos = Math.ceil((targetj % 10 - 1) / 2);
9024
-
9025
- _colorPatterns.forEach((cpattern, k) => {
9026
- if (colorPos === cpattern) {
9027
- g_workObj[`frz${ctype}Colors`][k] = _mkColorCd[j];
9028
- if (_allFlg === `A`) {
9029
- g_workObj[`frz${ctype}ColorsAll`][k] = _mkColorCd[j];
9030
- if (ctype === `HitBar` && isNaN(Number(g_workObj.arrowRtn[k]))) {
9031
- $id(`frzHitTop${k}`).background = _mkColorCd[j];
9032
- }
9033
- }
9233
+ const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
9234
+ _mkColor.forEach((tempj, j) => {
9235
+ const targetj = tempj % 1000;
9236
+ g_workObj[`${camelHeader}Colors`][targetj] = _mkColorCd[j];
9237
+ if (tempj >= 1000) {
9238
+ g_workObj[`${camelHeader}ColorsAll`][targetj] = _mkColorCd[j];
9239
+ if (camelHeader.indexOf(`frzHitBar`) !== -1 && isNaN(Number(g_workObj.arrowRtn[targetj]))) {
9240
+ $id(`frzHitTop${targetj}`).background = _mkColorCd[j];
9034
9241
  }
9035
- });
9242
+ }
9036
9243
  });
9037
9244
  }
9038
9245
 
9039
9246
  /**
9040
9247
  * 個別モーション
9041
- * @param {array} _mkCssMotion
9042
- * @param {array} _mkCssMotionName
9248
+ * @param {string} _header
9043
9249
  * @param {string} _name
9250
+ * @param {number} _frameNum
9044
9251
  */
9045
- function changeCssMotions(_mkCssMotion, _mkCssMotionName, _name) {
9252
+ function changeCssMotions(_header, _name, _frameNum) {
9046
9253
 
9047
- if (_mkCssMotion !== undefined) {
9048
- for (let j = 0; j < _mkCssMotion.length; j++) {
9049
- const targetj = _mkCssMotion[j];
9050
- g_workObj[`${_name}CssMotions`][targetj] = _mkCssMotionName[2 * j + g_workObj.dividePos[targetj]];
9254
+ const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
9255
+ const frameData = g_workObj[`mk${toCapitalize(camelHeader)}CssMotion`][_frameNum];
9256
+
9257
+ if (frameData !== undefined) {
9258
+ for (let j = 0; j < frameData.length; j++) {
9259
+ const targetj = frameData[j];
9260
+ g_workObj[`${camelHeader}CssMotions`][targetj] =
9261
+ g_workObj[`mk${toCapitalize(camelHeader)}CssMotionName`][_frameNum][2 * j + g_workObj.dividePos[targetj]];
9051
9262
  }
9052
9263
  }
9053
9264
  }
@@ -9212,6 +9423,7 @@ function judgeArrow(_j) {
9212
9423
  */
9213
9424
  function displayDiff(_difFrame, _justFrames = 0) {
9214
9425
  let diffJDisp = ``;
9426
+ g_workObj.diffList.push(_difFrame);
9215
9427
  const difCnt = Math.abs(_difFrame);
9216
9428
  if (_difFrame > _justFrames) {
9217
9429
  diffJDisp = `<span class="common_matari">Fast ${difCnt} Frames</span>`;
@@ -9303,24 +9515,42 @@ function updateCombo() {
9303
9515
  }
9304
9516
 
9305
9517
  /**
9306
- * 判定処理:イイ
9307
- * @param {number} difFrame
9518
+ * 回復判定の共通処理
9519
+ * @param {string} _name
9520
+ * @param {number} _difFrame
9308
9521
  */
9309
- function judgeIi(difFrame) {
9310
- changeJudgeCharacter(`ii`, g_lblNameObj.j_ii);
9522
+ function judgeRecovery(_name, _difFrame) {
9523
+ changeJudgeCharacter(_name, g_lblNameObj[`j_${_name}`]);
9311
9524
 
9312
9525
  updateCombo();
9313
- displayDiff(difFrame, g_headerObj.justFrames);
9526
+ displayDiff(_difFrame, g_headerObj.justFrames);
9314
9527
 
9315
9528
  lifeRecovery();
9316
9529
  finishViewing();
9317
9530
 
9318
- if (typeof customJudgeIi === C_TYP_FUNCTION) {
9319
- customJudgeIi(difFrame);
9320
- if (typeof customJudgeIi2 === C_TYP_FUNCTION) {
9321
- customJudgeIi2(difFrame);
9322
- }
9323
- }
9531
+ g_customJsObj[`judg_${_name}`].forEach(func => func(_difFrame));
9532
+ }
9533
+
9534
+ /**
9535
+ * ダメージ系共通処理
9536
+ * @param {string} _name
9537
+ * @param {number} _difFrame
9538
+ */
9539
+ function judgeDamage(_name, _difFrame) {
9540
+ changeJudgeCharacter(_name, g_lblNameObj[`j_${_name}`]);
9541
+ g_resultObj.combo = 0;
9542
+ comboJ.textContent = ``;
9543
+ diffJ.textContent = ``;
9544
+ lifeDamage();
9545
+ g_customJsObj[`judg_${_name}`].forEach(func => func(_difFrame));
9546
+ }
9547
+
9548
+ /**
9549
+ * 判定処理:イイ
9550
+ * @param {number} difFrame
9551
+ */
9552
+ function judgeIi(difFrame) {
9553
+ judgeRecovery(`ii`, difFrame);
9324
9554
  }
9325
9555
 
9326
9556
  /**
@@ -9328,20 +9558,7 @@ function judgeIi(difFrame) {
9328
9558
  * @param {number} difFrame
9329
9559
  */
9330
9560
  function judgeShakin(difFrame) {
9331
- changeJudgeCharacter(`shakin`, g_lblNameObj.j_shakin);
9332
-
9333
- updateCombo();
9334
- displayDiff(difFrame, g_headerObj.justFrames);
9335
-
9336
- lifeRecovery();
9337
- finishViewing();
9338
-
9339
- if (typeof customJudgeShakin === C_TYP_FUNCTION) {
9340
- customJudgeShakin(difFrame);
9341
- if (typeof customJudgeShakin2 === C_TYP_FUNCTION) {
9342
- customJudgeShakin2(difFrame);
9343
- }
9344
- }
9561
+ judgeRecovery(`shakin`, difFrame);
9345
9562
  }
9346
9563
 
9347
9564
  /**
@@ -9355,22 +9572,7 @@ function judgeMatari(difFrame) {
9355
9572
  displayDiff(difFrame, g_headerObj.justFrames);
9356
9573
  finishViewing();
9357
9574
 
9358
- if (typeof customJudgeMatari === C_TYP_FUNCTION) {
9359
- customJudgeMatari(difFrame);
9360
- if (typeof customJudgeMatari2 === C_TYP_FUNCTION) {
9361
- customJudgeMatari2(difFrame);
9362
- }
9363
- }
9364
- }
9365
-
9366
- /**
9367
- * ダメージ系共通処理
9368
- */
9369
- function judgeDamage() {
9370
- g_resultObj.combo = 0;
9371
- comboJ.textContent = ``;
9372
- diffJ.textContent = ``;
9373
- lifeDamage();
9575
+ g_customJsObj.judg_matari.forEach(func => func(difFrame));
9374
9576
  }
9375
9577
 
9376
9578
  /**
@@ -9378,15 +9580,7 @@ function judgeDamage() {
9378
9580
  * @param {number} difFrame
9379
9581
  */
9380
9582
  function judgeShobon(difFrame) {
9381
- changeJudgeCharacter(`shobon`, g_lblNameObj.j_shobon);
9382
- judgeDamage();
9383
-
9384
- if (typeof customJudgeShobon === C_TYP_FUNCTION) {
9385
- customJudgeShobon(difFrame);
9386
- if (typeof customJudgeShobon2 === C_TYP_FUNCTION) {
9387
- customJudgeShobon2(difFrame);
9388
- }
9389
- }
9583
+ judgeDamage(`shobon`, difFrame);
9390
9584
  }
9391
9585
 
9392
9586
  /**
@@ -9394,15 +9588,7 @@ function judgeShobon(difFrame) {
9394
9588
  * @param {number} difFrame
9395
9589
  */
9396
9590
  function judgeUwan(difFrame) {
9397
- changeJudgeCharacter(`uwan`, g_lblNameObj.j_uwan);
9398
- judgeDamage();
9399
-
9400
- if (typeof customJudgeUwan === C_TYP_FUNCTION) {
9401
- customJudgeUwan(difFrame);
9402
- if (typeof customJudgeUwan2 === C_TYP_FUNCTION) {
9403
- customJudgeUwan2(difFrame);
9404
- }
9405
- }
9591
+ judgeDamage(`uwan`, difFrame);
9406
9592
  }
9407
9593
 
9408
9594
  /**
@@ -9421,12 +9607,7 @@ function judgeKita(difFrame) {
9421
9607
  lifeRecovery();
9422
9608
  finishViewing();
9423
9609
 
9424
- if (typeof customJudgeKita === C_TYP_FUNCTION) {
9425
- customJudgeKita(difFrame);
9426
- if (typeof customJudgeKita2 === C_TYP_FUNCTION) {
9427
- customJudgeKita2(difFrame);
9428
- }
9429
- }
9610
+ g_customJsObj.judg_kita.forEach(func => func(difFrame));
9430
9611
  }
9431
9612
 
9432
9613
  /**
@@ -9440,12 +9621,7 @@ function judgeIknai(difFrame) {
9440
9621
 
9441
9622
  lifeDamage();
9442
9623
 
9443
- if (typeof customJudgeIknai === C_TYP_FUNCTION) {
9444
- customJudgeIknai(difFrame);
9445
- if (typeof customJudgeIknai2 === C_TYP_FUNCTION) {
9446
- customJudgeIknai2(difFrame);
9447
- }
9448
- }
9624
+ g_customJsObj.judg_iknai.forEach(func => func(difFrame));
9449
9625
  }
9450
9626
 
9451
9627
  // クリア表示
@@ -9527,6 +9703,20 @@ function resultInit() {
9527
9703
  }
9528
9704
  }
9529
9705
 
9706
+ // diffListから適正Adjを算出(20個以下の場合は算出しない)
9707
+ const getSign = _val => (_val > 0 ? `+` : ``);
9708
+ const getDiffFrame = _val => `${getSign(_val)}${_val}${g_lblNameObj.frame}`;
9709
+ const diffLength = g_workObj.diffList.length;
9710
+ const bayesFunc = (_offset, _length) => {
9711
+ let result = 0;
9712
+ for (let j = _offset; j < _length; j++) {
9713
+ result += (_length - j) * (j + 1) * g_workObj.diffList[j];
9714
+ }
9715
+ return result;
9716
+ };
9717
+ const bayesExVal = 6 * bayesFunc(0, diffLength) / (diffLength * (diffLength + 1) * (diffLength + 2));
9718
+ const estimatedAdj = (diffLength <= 20 ? `` : Math.round((g_stateObj.adjustment - bayesExVal) * 10) / 10);
9719
+
9530
9720
  // 背景スプライトを作成
9531
9721
  createMultipleSprite(`backResultSprite`, g_headerObj.backResultMaxDepth);
9532
9722
 
@@ -9591,14 +9781,14 @@ function resultInit() {
9591
9781
  }
9592
9782
 
9593
9783
  let difData = [
9594
- `${getKeyName(g_headerObj.keyLabels[g_stateObj.scoreId])}${transKeyData} key / ${g_headerObj.difLabels[g_stateObj.scoreId]}`,
9784
+ `${getKeyName(g_headerObj.keyLabels[g_stateObj.scoreId])}${transKeyData} ${getStgDetailName('key')} / ${g_headerObj.difLabels[g_stateObj.scoreId]}`,
9595
9785
  `${withOptions(g_autoPlaysBase.includes(g_stateObj.autoPlay), true, `-${getStgDetailName(g_stateObj.autoPlay)}${getStgDetailName('less')}`)}`,
9596
9786
  `${withOptions(g_headerObj.makerView, false, `(${g_headerObj.creatorNames[g_stateObj.scoreId]})`)}`,
9597
9787
  `${withOptions(g_stateObj.shuffle, C_FLG_OFF, `[${getShuffleName()}]`)}`
9598
9788
  ].filter(value => value !== ``).join(` `);
9599
9789
 
9600
9790
  let playStyleData = [
9601
- `${g_stateObj.speed}${getStgDetailName(g_lblNameObj.multi)}`,
9791
+ `${g_stateObj.speed}${g_lblNameObj.multi}`,
9602
9792
  `${withOptions(g_stateObj.motion, C_FLG_OFF)}`,
9603
9793
  `${withOptions(g_stateObj.reverse, C_FLG_OFF,
9604
9794
  getStgDetailName(g_stateObj.scroll !== '---' ? 'R-' : 'Reverse'))}${withOptions(g_stateObj.scroll, '---')}`,
@@ -9684,6 +9874,12 @@ function resultInit() {
9684
9874
  makeCssResultSymbol(`lblFastS`, 260, g_cssObj.score, 1, g_resultObj.fast, C_ALIGN_RIGHT),
9685
9875
  makeCssResultSymbol(`lblSlowS`, 260, g_cssObj.score, 3, g_resultObj.slow, C_ALIGN_RIGHT),
9686
9876
  );
9877
+ if (estimatedAdj !== ``) {
9878
+ multiAppend(resultWindow,
9879
+ makeCssResultSymbol(`lblAdj`, 350, g_cssObj.common_shakin, 4, g_lblNameObj.j_adj),
9880
+ makeCssResultSymbol(`lblAdjS`, 260, g_cssObj.score, 5, `${getDiffFrame(estimatedAdj)}`, C_ALIGN_RIGHT),
9881
+ );
9882
+ }
9687
9883
  }
9688
9884
 
9689
9885
  // ランク描画
@@ -9729,7 +9925,7 @@ function resultInit() {
9729
9925
 
9730
9926
  // ハイスコア差分計算
9731
9927
  const assistFlg = (g_autoPlaysBase.includes(g_stateObj.autoPlay) ? `` : `-${g_stateObj.autoPlay}less`);
9732
- let scoreName = `${g_headerObj.keyLabels[g_stateObj.scoreId]}k-${g_headerObj.difLabels[g_stateObj.scoreId]}${assistFlg}`;
9928
+ let scoreName = `${g_headerObj.keyLabels[g_stateObj.scoreId]}${getStgDetailName('k-')}${g_headerObj.difLabels[g_stateObj.scoreId]}${assistFlg}`;
9733
9929
  if (g_headerObj.makerView) {
9734
9930
  scoreName += `-${g_headerObj.creatorNames[g_stateObj.scoreId]}`;
9735
9931
  }
@@ -9757,18 +9953,13 @@ function resultInit() {
9757
9953
  });
9758
9954
 
9759
9955
  } else {
9760
- resultWindow.appendChild(makeCssResultSymbol(`lblAutoView`, 230, g_cssObj.result_noRecord, 4, `(No Record)`));
9956
+ resultWindow.appendChild(makeCssResultSymbol(`lblAutoView`, 215, g_cssObj.result_noRecord, 4, `(No Record)`));
9761
9957
  const lblAutoView = document.querySelector(`#lblAutoView`);
9762
- lblAutoView.style.fontSize = `24px`;
9958
+ lblAutoView.style.fontSize = `20px`;
9763
9959
  }
9764
9960
 
9765
9961
  // ユーザカスタムイベント(初期)
9766
- if (typeof customResultInit === C_TYP_FUNCTION) {
9767
- customResultInit();
9768
- if (typeof customResultInit2 === C_TYP_FUNCTION) {
9769
- customResultInit2();
9770
- }
9771
- }
9962
+ g_customJsObj.result.forEach(func => func());
9772
9963
 
9773
9964
  if (highscoreCondition) {
9774
9965
 
@@ -9818,7 +10009,7 @@ function resultInit() {
9818
10009
  // Twitter用リザルト
9819
10010
  // スコアを上塗りする可能性があるため、カスタムイベント後に配置
9820
10011
  const hashTag = (g_headerObj.hashTag !== undefined ? ` ${g_headerObj.hashTag}` : ``);
9821
- let tweetDifData = `${getKeyName(g_headerObj.keyLabels[g_stateObj.scoreId])}${transKeyData}k-${g_headerObj.difLabels[g_stateObj.scoreId]}${assistFlg}`;
10012
+ let tweetDifData = `${getKeyName(g_headerObj.keyLabels[g_stateObj.scoreId])}${transKeyData}${getStgDetailName('k-')}${g_headerObj.difLabels[g_stateObj.scoreId]}${assistFlg}`;
9822
10013
  if (g_stateObj.shuffle !== `OFF`) {
9823
10014
  tweetDifData += `:${getShuffleName()}`;
9824
10015
  }
@@ -9869,8 +10060,7 @@ function resultInit() {
9869
10060
 
9870
10061
  // リザルトデータをクリップボードへコピー
9871
10062
  createCss2Button(`btnCopy`, g_lblNameObj.b_copy, _ => {
9872
- copyTextToClipboard(resultText);
9873
- makeInfoWindow(g_msgInfoObj.I_0001, `leftToRightFade`);
10063
+ copyTextToClipboard(resultText, g_msgInfoObj.I_0001);
9874
10064
  }, {
9875
10065
  x: g_sWidth / 4,
9876
10066
  w: g_sWidth / 2,
@@ -9928,12 +10118,7 @@ function resultInit() {
9928
10118
  function flowResultTimeline() {
9929
10119
 
9930
10120
  // ユーザカスタムイベント(フレーム毎)
9931
- if (typeof customResultEnterFrame === C_TYP_FUNCTION) {
9932
- customResultEnterFrame();
9933
- if (typeof customResultEnterFrame2 === C_TYP_FUNCTION) {
9934
- customResultEnterFrame2();
9935
- }
9936
- }
10121
+ g_customJsObj.resultEnterFrame.forEach(func => func());
9937
10122
 
9938
10123
  // 背景・マスクモーション
9939
10124
  drawTitleResultMotion(g_currentPage);
@@ -9969,12 +10154,7 @@ function resultInit() {
9969
10154
  setShortcutEvent(g_currentPage);
9970
10155
  document.oncontextmenu = _ => true;
9971
10156
 
9972
- if (typeof skinResultInit === C_TYP_FUNCTION) {
9973
- skinResultInit();
9974
- if (typeof skinResultInit2 === C_TYP_FUNCTION) {
9975
- skinResultInit2();
9976
- }
9977
- }
10157
+ g_skinJsObj.result.forEach(func => func());
9978
10158
  }
9979
10159
 
9980
10160
  /**