danoniplus 25.5.6 → 26.3.1

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 : 2022/02/20
7
+ * Revised : 2022/02/23
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 25.5.6`;
12
- const g_revisedDate = `2022/02/20`;
11
+ const g_version = `Ver 26.3.1`;
12
+ const g_revisedDate = `2022/02/23`;
13
13
  const g_alphaVersion = ``;
14
14
 
15
15
  // カスタム用バージョン (danoni_custom.js 等で指定可)
@@ -49,19 +49,16 @@ const current = _ => {
49
49
  const g_rootPath = current().match(/(^.*\/)/)[0];
50
50
  const g_remoteFlg = g_rootPath.match(`^https://cwtickle.github.io/danoniplus/`) !== null;
51
51
 
52
- window.onload = _ => {
52
+ window.onload = async () => {
53
53
  g_loadObj.main = true;
54
54
  g_currentPage = `initial`;
55
55
 
56
56
  // ロード直後に定数・初期化ファイル、旧バージョン定義関数を読込
57
57
  const randTime = new Date().getTime();
58
- loadScript(`${g_rootPath}../js/lib/danoni_localbinary.js?${randTime}`, _ => {
59
- loadScript(`${g_rootPath}../js/lib/danoni_constants.js?${randTime}`, _ => {
60
- loadScript(`${g_rootPath}../js/lib/danoni_legacy_function.js?${randTime}`, _ => {
61
- initialControl();
62
- }, false);
63
- });
64
- }, false);
58
+ await loadScript2(`${g_rootPath}../js/lib/danoni_localbinary.js?${randTime}`, false);
59
+ await loadScript2(`${g_rootPath}../js/lib/danoni_constants.js?${randTime}`);
60
+ await loadScript2(`${g_rootPath}../js/lib/danoni_legacy_function.js?${randTime}`, false);
61
+ initialControl();
65
62
  };
66
63
 
67
64
  /*-----------------------------------------------------------*/
@@ -113,6 +110,7 @@ let g_finishFlg = true;
113
110
  /** 共通オブジェクト */
114
111
  const g_loadObj = {};
115
112
  const g_rootObj = {};
113
+ const g_presetObj = {};
116
114
  let g_headerObj = {};
117
115
  let g_scoreObj = {};
118
116
  let g_attrObj = {};
@@ -125,7 +123,14 @@ const g_detailObj = {
125
123
  arrowCnt: [],
126
124
  frzCnt: [],
127
125
  maxDensity: [],
126
+ maxDensity2Push: [],
127
+ maxDensity3Push: [],
128
128
  densityData: [],
129
+ density2PushData: [],
130
+ density3PushData: [],
131
+ densityDiff: [],
132
+ density2PushDiff: [],
133
+ density3PushDiff: [],
129
134
  startFrame: [],
130
135
  playingFrame: [],
131
136
  playingFrameWithBlank: [],
@@ -234,11 +239,11 @@ const hasArrayList = (_data, _length = 1) => _data !== undefined && _data.length
234
239
  /**
235
240
  * 重複を排除した配列の生成
236
241
  * @param {array} _array1
237
- * @param {array} _array2
242
+ * @param {...any} _arrays
238
243
  * @returns
239
244
  */
240
- const makeDedupliArray = (_array1, _array2) =>
241
- Array.from((new Set([..._array1, ..._array2])).values());
245
+ const makeDedupliArray = (_array1, ..._arrays) =>
246
+ Array.from((new Set([..._array1, ..._arrays.flat()])).values());
242
247
 
243
248
  /**
244
249
  * 部分一致検索(リストのいずれかに合致、大小文字問わず)
@@ -517,8 +522,9 @@ function preloadFile(_as, _href, _type = ``, _crossOrigin = `anonymous`) {
517
522
  }
518
523
 
519
524
  /**
520
- * CSSファイルの読み込み(danoni_main.css以外)
525
+ * CSSファイルの読み込み (callback)
521
526
  * デフォルトは danoni_skin_default.css を読み込む
527
+ * @deprecated v27以降非推奨予定
522
528
  * @param {url} _href
523
529
  * @param {function} _func
524
530
  */
@@ -539,6 +545,31 @@ function importCssFile(_href, _func) {
539
545
  document.head.appendChild(link);
540
546
  }
541
547
 
548
+ /**
549
+ * CSSファイルの読み込み (Promise)
550
+ * デフォルトは danoni_skin_default.css を読み込む
551
+ * @param {url} _href
552
+ */
553
+ function importCssFile2(_href) {
554
+ const baseUrl = _href.split(`?`)[0];
555
+ g_loadObj[baseUrl] = false;
556
+
557
+ return new Promise(resolve => {
558
+ const link = document.createElement(`link`);
559
+ link.rel = `stylesheet`;
560
+ link.href = _href;
561
+ link.onload = _ => {
562
+ g_loadObj[baseUrl] = true;
563
+ resolve(link);
564
+ };
565
+ link.onerror = _ => {
566
+ makeWarningWindow(g_msgInfoObj.E_0041.split(`{0}`).join(baseUrl), { resetFlg: `title` });
567
+ resolve(link);
568
+ };
569
+ document.head.appendChild(link);
570
+ });
571
+ }
572
+
542
573
  /**
543
574
  * 画面共通のフォント設定
544
575
  * @param {string} _priorityFont
@@ -713,7 +744,7 @@ function createColorObject2(_id,
713
744
  style.webkitMaskImage = `url("${g_imgObj[charaStyle]}")`;
714
745
  style.webkitMaskSize = `contain`;
715
746
  Object.keys(rest).forEach(property => style[property] = rest[property]);
716
- setAttrs(div, { color: rest.background || ``, type: charaStyle, cnt: 0, });
747
+ setAttrs(div, { color: rest.background ?? ``, type: charaStyle, cnt: 0, });
717
748
 
718
749
  return div;
719
750
  }
@@ -803,7 +834,7 @@ function createCss2Button(_id, _text, _func = _ => true, { x = 0, y = g_sHeight
803
834
  if (g_initialFlg && g_btnWaitFrame[groupName].initial) {
804
835
  } else {
805
836
  style.pointerEvents = C_DIS_NONE;
806
- setTimeout(_ => style.pointerEvents = setVal(rest.pointerEvents, `auto`, C_TYP_STRING),
837
+ setTimeout(_ => style.pointerEvents = rest.pointerEvents ?? `auto`,
807
838
  g_btnWaitFrame[groupName].b_frame * 1000 / g_fps);
808
839
  }
809
840
  }
@@ -945,8 +976,9 @@ function clearWindow(_redrawFlg = false, _customDisplayName = ``) {
945
976
  }
946
977
 
947
978
  /**
948
- * 外部jsファイルの読込
979
+ * 外部jsファイルの読込 (callback)
949
980
  * 読込可否を g_loadObj[ファイル名] で管理 (true: 読込成功, false: 読込失敗)
981
+ * @deprecated v27以降非推奨予定
950
982
  * @param {string} _url
951
983
  * @param {function} _callback
952
984
  * @param {boolean} _requiredFlg (default : true / 読込必須)
@@ -973,10 +1005,42 @@ function loadScript(_url, _callback, _requiredFlg = true, _charset = `UTF-8`) {
973
1005
  document.querySelector(`head`).appendChild(script);
974
1006
  }
975
1007
 
1008
+ /**
1009
+ * 外部jsファイルの読込 (Promise)
1010
+ * 読込可否を g_loadObj[ファイル名] で管理 (true: 読込成功, false: 読込失敗)
1011
+ * @param {string} _url
1012
+ * @param {boolean} _requiredFlg (default : true / 読込必須)
1013
+ * @param {string} _charset (default : UTF-8)
1014
+ */
1015
+ function loadScript2(_url, _requiredFlg = true, _charset = `UTF-8`) {
1016
+ const baseUrl = _url.split(`?`)[0];
1017
+ g_loadObj[baseUrl] = false;
1018
+
1019
+ return new Promise((resolve, reject) => {
1020
+ const script = document.createElement(`script`);
1021
+ script.type = `text/javascript`;
1022
+ script.src = _url;
1023
+ script.charset = _charset;
1024
+ script.onload = _ => {
1025
+ g_loadObj[baseUrl] = true;
1026
+ resolve(script);
1027
+ };
1028
+ script.onerror = _err => {
1029
+ if (_requiredFlg) {
1030
+ makeWarningWindow(g_msgInfoObj.E_0041.split(`{0}`).join(_url.split(`?`)[0]));
1031
+ reject(_err);
1032
+ } else {
1033
+ resolve(script);
1034
+ }
1035
+ };
1036
+ document.querySelector(`head`).appendChild(script);
1037
+ });
1038
+ }
1039
+
976
1040
  // WebAudioAPIでAudio要素風に再生するクラス
977
1041
  class AudioPlayer {
978
1042
  constructor() {
979
- const AudioContext = window.AudioContext || window.webkitAudioContext;
1043
+ const AudioContext = window.AudioContext ?? window.webkitAudioContext;
980
1044
  this._context = new AudioContext();
981
1045
  this._gain = this._context.createGain();
982
1046
  this._gain.connect(this._context.destination);
@@ -1148,12 +1212,12 @@ function makeSpriteData(_data, _calcFrame = _frame => _frame) {
1148
1212
  }
1149
1213
 
1150
1214
  const tmpObj = {
1151
- path: escapeHtml(setVal(tmpSpriteData[2], ``, C_TYP_STRING), g_escapeStr.escapeCode), // 画像パス or テキスト
1152
- class: escapeHtml(setVal(tmpSpriteData[3], ``, C_TYP_STRING)), // CSSクラス
1215
+ path: escapeHtml(tmpSpriteData[2] ?? ``, g_escapeStr.escapeCode), // 画像パス or テキスト
1216
+ class: escapeHtml(tmpSpriteData[3] ?? ``), // CSSクラス
1153
1217
  left: setVal(tmpSpriteData[4], 0, C_TYP_CALC), // X座標
1154
1218
  top: setVal(tmpSpriteData[5], 0, C_TYP_CALC), // Y座標
1155
1219
  width: setVal(tmpSpriteData[6], 0, C_TYP_NUMBER), // spanタグの場合は font-size
1156
- height: escapeHtml(setVal(tmpSpriteData[7], ``, C_TYP_STRING)), // spanタグの場合は color(文字列可)
1220
+ height: escapeHtml(tmpSpriteData[7] ?? ``), // spanタグの場合は color(文字列可)
1157
1221
  opacity: setVal(tmpSpriteData[8], 1, C_TYP_FLOAT),
1158
1222
  animationName: escapeHtml(setVal(tmpSpriteData[9], C_DIS_NONE, C_TYP_STRING)),
1159
1223
  animationDuration: setVal(tmpSpriteData[10], 0, C_TYP_NUMBER) / g_fps,
@@ -1282,7 +1346,120 @@ function initialControl() {
1282
1346
  loadLocalStorage();
1283
1347
 
1284
1348
  // 譜面データの読み込み
1285
- loadDos(_ => loadSettingJs(), 0);
1349
+ loadDos(_ => loadBaseFiles(), 0);
1350
+ }
1351
+
1352
+ /**
1353
+ * 共通設定ファイル、スキンファイル、カスタムファイルの読込
1354
+ */
1355
+ async function loadBaseFiles() {
1356
+
1357
+ // 共通設定ファイルの指定
1358
+ let [settingType, settingRoot] = getFilePath(g_rootObj.settingType ?? ``, C_DIR_JS);
1359
+ if (settingType !== ``) {
1360
+ settingType = `_${settingType}`;
1361
+ }
1362
+
1363
+ // 共通設定ファイルの読込
1364
+ const randTime = new Date().getTime();
1365
+ await loadScript2(`${settingRoot}danoni_setting${settingType}.js?${randTime}`, false);
1366
+ loadLegacySettingFunc();
1367
+ if (document.querySelector(`#lblLoading`) !== null) {
1368
+ divRoot.removeChild(document.querySelector(`#lblLoading`));
1369
+ }
1370
+
1371
+ // クエリで譜面番号が指定されていればセット
1372
+ g_stateObj.scoreId = setVal(getQueryParamVal(`scoreId`), 0, C_TYP_NUMBER);
1373
+
1374
+ // 譜面ヘッダーの読込
1375
+ Object.assign(g_headerObj, preheaderConvert(g_rootObj));
1376
+
1377
+ // CSSファイル内のbackgroundを取得するために再描画
1378
+ if (document.querySelector(`#layer0`) === null) {
1379
+ divRoot.removeChild(document.querySelector(`#divBack`));
1380
+ createEmptySprite(divRoot, `divBack`);
1381
+ } else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
1382
+ createEmptySprite(divRoot, `divBack`);
1383
+ }
1384
+
1385
+ // CSSファイルの読み込み
1386
+ const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
1387
+ await loadMultipleFiles2(skinList, `css`);
1388
+
1389
+ // JSファイルの読み込み
1390
+ await loadMultipleFiles2(g_headerObj.jsData, `js`);
1391
+ loadLegacyCustomFunc();
1392
+
1393
+ // 譜面ヘッダー、特殊キー情報の読込
1394
+ Object.assign(g_headerObj, headerConvert(g_rootObj));
1395
+ if (g_presetObj.keysData !== undefined) {
1396
+ keysConvert(dosConvert(g_presetObj.keysData));
1397
+ g_headerObj.undefinedKeyLists = g_headerObj.undefinedKeyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
1398
+ }
1399
+ g_headerObj.keyExtraList = keysConvert(g_rootObj, {
1400
+ keyExtraList: (g_rootObj.keyExtraList !== undefined ?
1401
+ makeDedupliArray(g_rootObj.keyExtraList.split(`,`), g_headerObj.undefinedKeyLists) : g_headerObj.undefinedKeyLists),
1402
+ });
1403
+
1404
+ // キー数情報を初期化
1405
+ g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
1406
+ g_keyObj.currentPtn = 0;
1407
+
1408
+ // 画像ファイルの読み込み
1409
+ g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
1410
+
1411
+ // その他の画像ファイルの読み込み
1412
+ g_headerObj.preloadImages.filter(image => hasVal(image)).forEach(preloadImage => {
1413
+
1414
+ // Pattern A: |preloadImages=file.png|
1415
+ // Pattern B: |preloadImages=file*.png@10| -> file01.png ~ file10.png
1416
+ // Pattern C: |preloadImages=file*.png@2-9| -> file2.png ~ file9.png
1417
+ // Pattern D: |preloadImages=file*.png@003-018| -> file003.png ~ file018.png
1418
+
1419
+ const tmpPreloadImages = preloadImage.split(`@`);
1420
+ if (tmpPreloadImages.length === 1) {
1421
+ // Pattern Aの場合
1422
+ preloadFile(`image`, preloadImage);
1423
+ } else {
1424
+ const termRoopCnts = tmpPreloadImages[1].split(`-`);
1425
+ let startCnt = 1;
1426
+ let lastCnt;
1427
+ let paddingLen;
1428
+
1429
+ if (termRoopCnts.length === 1) {
1430
+ // Pattern Bの場合
1431
+ lastCnt = setVal(tmpPreloadImages[1], 1, C_TYP_NUMBER);
1432
+ paddingLen = String(setVal(tmpPreloadImages[1], 1, C_TYP_STRING)).length;
1433
+ } else {
1434
+ // Pattern C, Dの場合
1435
+ startCnt = setVal(termRoopCnts[0], 1, C_TYP_NUMBER);
1436
+ lastCnt = setVal(termRoopCnts[1], 1, C_TYP_NUMBER);
1437
+ paddingLen = String(setVal(termRoopCnts[1], 1, C_TYP_STRING)).length;
1438
+ }
1439
+ for (let k = startCnt; k <= lastCnt; k++) {
1440
+ preloadFile(`image`, tmpPreloadImages[0].replace(/\*/g, String(k).padStart(paddingLen, `0`)));
1441
+ }
1442
+ }
1443
+ });
1444
+
1445
+ // ローカルファイル起動時に各種警告文を表示
1446
+ if (g_isFile) {
1447
+ makeWarningWindow(g_msgInfoObj.W_0011);
1448
+ if (!listMatching(getMusicUrl(g_stateObj.scoreId), [`.js`, `.txt`], { suffix: `$` })) {
1449
+ if (g_userAgent.indexOf(`firefox`) !== -1) {
1450
+ makeWarningWindow(g_msgInfoObj.W_0001);
1451
+ }
1452
+ makeWarningWindow(g_msgInfoObj.W_0012);
1453
+ }
1454
+ }
1455
+
1456
+ if (g_loadObj.main) {
1457
+ // 譜面詳細情報取得のために譜面をロード
1458
+ loadDos(_ => getScoreDetailData(0), 0, true);
1459
+ } else {
1460
+ getScoreDetailData(0);
1461
+ reloadDos(0);
1462
+ }
1286
1463
  }
1287
1464
 
1288
1465
  /**
@@ -1317,7 +1494,7 @@ function loadLocalStorage() {
1317
1494
  g_localeObj.val = g_langStorage.locale;
1318
1495
  g_localeObj.num = g_localeObj.list.findIndex(val => val === g_localeObj.val);
1319
1496
  }
1320
- Object.keys(g_lang_msgInfoObj[g_localeObj.val]).forEach(property => g_msgInfoObj[property] = g_lang_msgInfoObj[g_localeObj.val][property]);
1497
+ Object.assign(g_msgInfoObj, g_lang_msgInfoObj[g_localeObj.val]);
1321
1498
 
1322
1499
  // 作品別ローカルストレージの読込
1323
1500
  const checkStorage = localStorage.getItem(g_localStorageUrl);
@@ -1350,7 +1527,7 @@ function loadLocalStorage() {
1350
1527
  * @param {number} _scoreId 譜面番号
1351
1528
  * @param {boolean} _cyclicFlg 再読込フラグ(譜面詳細情報取得用、再帰的にloadDosを呼び出す)
1352
1529
  */
1353
- function loadDos(_afterFunc, _scoreId = g_stateObj.scoreId, _cyclicFlg = false) {
1530
+ async function loadDos(_afterFunc, _scoreId = g_stateObj.scoreId, _cyclicFlg = false) {
1354
1531
 
1355
1532
  const dosInput = document.querySelector(`#dos`);
1356
1533
  const externalDosInput = document.querySelector(`#externalDos`);
@@ -1403,37 +1580,36 @@ function loadDos(_afterFunc, _scoreId = g_stateObj.scoreId, _cyclicFlg = false)
1403
1580
  `${filenameCommon}${setScoreIdHeader(_scoreId)}.${filenameExtension}`);
1404
1581
 
1405
1582
  const randTime = new Date().getTime();
1406
- loadScript(`${filename}?${randTime}`, _ => {
1407
- if (typeof externalDosInit === C_TYP_FUNCTION) {
1408
- if (document.querySelector(`#lblLoading`) !== null) {
1409
- divRoot.removeChild(document.querySelector(`#lblLoading`));
1410
- }
1411
-
1412
- // 外部データを読込(ファイルが見つからなかった場合は譜面追記をスキップ)
1413
- externalDosInit();
1414
- if (g_loadObj[filename]) {
1415
- Object.assign(g_rootObj, dosConvert(g_externalDos));
1416
- }
1583
+ await loadScript2(`${filename}?${randTime}`, false, charset);
1584
+ if (typeof externalDosInit === C_TYP_FUNCTION) {
1585
+ if (document.querySelector(`#lblLoading`) !== null) {
1586
+ divRoot.removeChild(document.querySelector(`#lblLoading`));
1587
+ }
1417
1588
 
1418
- } else {
1419
- makeWarningWindow(g_msgInfoObj.E_0022);
1589
+ // 外部データを読込(ファイルが見つからなかった場合は譜面追記をスキップ)
1590
+ externalDosInit();
1591
+ if (g_loadObj[filename]) {
1592
+ Object.assign(g_rootObj, dosConvert(g_externalDos));
1420
1593
  }
1421
- _afterFunc();
1422
- if (_cyclicFlg) {
1423
- if (g_stateObj.dosDivideFlg && _scoreId > 0) {
1424
- // 初期矢印・フリーズアロー色の再定義
1425
- if (g_stateObj.scoreLockFlg) {
1426
- Object.assign(g_rootObj, copySetColor(g_rootObj, _scoreId));
1427
- }
1428
- Object.assign(g_headerObj, resetBaseColorList(g_headerObj, g_rootObj, { scoreId: _scoreId }));
1429
1594
 
1430
- // ライフ設定のカスタム部分再取得(譜面ヘッダー加味)
1431
- Object.assign(g_gaugeOptionObj, resetCustomGauge(g_rootObj, { scoreId: _scoreId }));
1432
- Object.keys(g_gaugeOptionObj.customFulls).forEach(gaugePtn => getGaugeSetting(g_rootObj, gaugePtn, g_headerObj.difLabels.length, { scoreId: _scoreId }));
1595
+ } else {
1596
+ makeWarningWindow(g_msgInfoObj.E_0022);
1597
+ }
1598
+ _afterFunc();
1599
+ if (_cyclicFlg) {
1600
+ if (g_stateObj.dosDivideFlg && _scoreId > 0) {
1601
+ // 初期矢印・フリーズアロー色の再定義
1602
+ if (g_stateObj.scoreLockFlg) {
1603
+ Object.assign(g_rootObj, copySetColor(g_rootObj, _scoreId));
1433
1604
  }
1434
- reloadDos(_scoreId);
1605
+ Object.assign(g_headerObj, resetBaseColorList(g_headerObj, g_rootObj, { scoreId: _scoreId }));
1606
+
1607
+ // ライフ設定のカスタム部分再取得(譜面ヘッダー加味)
1608
+ Object.assign(g_gaugeOptionObj, resetCustomGauge(g_rootObj, { scoreId: _scoreId }));
1609
+ Object.keys(g_gaugeOptionObj.customFulls).forEach(gaugePtn => getGaugeSetting(g_rootObj, gaugePtn, g_headerObj.difLabels.length, { scoreId: _scoreId }));
1435
1610
  }
1436
- }, false, charset);
1611
+ reloadDos(_scoreId);
1612
+ }
1437
1613
  }
1438
1614
  }
1439
1615
 
@@ -1471,103 +1647,6 @@ function copySetColor(_baseObj, _scoreId) {
1471
1647
  return obj;
1472
1648
  }
1473
1649
 
1474
- /**
1475
- * 初回読込後に画像プリロードを設定する処理
1476
- */
1477
- function initAfterDosLoaded() {
1478
-
1479
- // クエリで譜面番号が指定されていればセット
1480
- g_stateObj.scoreId = setVal(getQueryParamVal(`scoreId`), 0, C_TYP_NUMBER);
1481
-
1482
- // 譜面ヘッダーの読込
1483
- Object.assign(g_headerObj, preheaderConvert(g_rootObj));
1484
-
1485
- // CSSファイル内のbackgroundを取得するために再描画
1486
- if (document.querySelector(`#layer0`) === null) {
1487
- divRoot.removeChild(document.querySelector(`#divBack`));
1488
- createEmptySprite(divRoot, `divBack`);
1489
- } else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
1490
- createEmptySprite(divRoot, `divBack`);
1491
- }
1492
-
1493
- // CSSファイルの読み込み
1494
- const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
1495
- loadMultipleFiles(0, skinList, `css`, _ => initAfterCssLoaded());
1496
-
1497
- /**
1498
- * スキンCSSファイルを読み込んだ後の処理
1499
- */
1500
- function initAfterCssLoaded() {
1501
-
1502
- // 譜面ヘッダー、特殊キー情報の読込
1503
- Object.assign(g_headerObj, headerConvert(g_rootObj));
1504
- keysConvert(g_rootObj);
1505
-
1506
- // キー数情報を初期化
1507
- g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
1508
- g_keyObj.currentPtn = 0;
1509
-
1510
- // 画像ファイルの読み込み
1511
- g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
1512
-
1513
- // その他の画像ファイルの読み込み
1514
- g_headerObj.preloadImages.filter(image => hasVal(image)).forEach(preloadImage => {
1515
-
1516
- // Pattern A: |preloadImages=file.png|
1517
- // Pattern B: |preloadImages=file*.png@10| -> file01.png ~ file10.png
1518
- // Pattern C: |preloadImages=file*.png@2-9| -> file2.png ~ file9.png
1519
- // Pattern D: |preloadImages=file*.png@003-018| -> file003.png ~ file018.png
1520
-
1521
- const tmpPreloadImages = preloadImage.split(`@`);
1522
- if (tmpPreloadImages.length === 1) {
1523
- // Pattern Aの場合
1524
- preloadFile(`image`, preloadImage);
1525
- } else {
1526
- const termRoopCnts = tmpPreloadImages[1].split(`-`);
1527
- let startCnt = 1;
1528
- let lastCnt;
1529
- let paddingLen;
1530
-
1531
- if (termRoopCnts.length === 1) {
1532
- // Pattern Bの場合
1533
- lastCnt = setVal(tmpPreloadImages[1], 1, C_TYP_NUMBER);
1534
- paddingLen = String(setVal(tmpPreloadImages[1], 1, C_TYP_STRING)).length;
1535
- } else {
1536
- // Pattern C, Dの場合
1537
- startCnt = setVal(termRoopCnts[0], 1, C_TYP_NUMBER);
1538
- lastCnt = setVal(termRoopCnts[1], 1, C_TYP_NUMBER);
1539
- paddingLen = String(setVal(termRoopCnts[1], 1, C_TYP_STRING)).length;
1540
- }
1541
- for (let k = startCnt; k <= lastCnt; k++) {
1542
- preloadFile(`image`, tmpPreloadImages[0].replace(/\*/g, String(k).padStart(paddingLen, `0`)));
1543
- }
1544
- }
1545
- });
1546
-
1547
- // ローカルファイル起動時に各種警告文を表示
1548
- if (g_isFile) {
1549
- makeWarningWindow(g_msgInfoObj.W_0011);
1550
- if (!listMatching(getMusicUrl(g_stateObj.scoreId), [`.js`, `.txt`], { suffix: `$` })) {
1551
- if (g_userAgent.indexOf(`firefox`) !== -1) {
1552
- makeWarningWindow(g_msgInfoObj.W_0001);
1553
- }
1554
- makeWarningWindow(g_msgInfoObj.W_0012);
1555
- }
1556
- }
1557
-
1558
- if (g_loadObj.main) {
1559
- // customjsの読み込み後、譜面詳細情報取得のために譜面をロード
1560
- loadMultipleFiles(0, g_headerObj.jsData, `js`, _ => {
1561
- loadLegacyCustomFunc();
1562
- loadDos(_ => getScoreDetailData(0), 0, true);
1563
- });
1564
- } else {
1565
- getScoreDetailData(0);
1566
- reloadDos(0);
1567
- }
1568
- }
1569
- }
1570
-
1571
1650
  /**
1572
1651
  * MusicUrlの基本情報を取得
1573
1652
  * @param {number} _scoreId
@@ -1575,7 +1654,7 @@ function initAfterDosLoaded() {
1575
1654
  */
1576
1655
  function getMusicUrl(_scoreId) {
1577
1656
  return g_headerObj.musicUrls !== undefined ?
1578
- g_headerObj.musicUrls[g_headerObj.musicNos[_scoreId]] ||
1657
+ g_headerObj.musicUrls[g_headerObj.musicNos[_scoreId]] ??
1579
1658
  g_headerObj.musicUrls[0] : `nosound.mp3`;
1580
1659
  }
1581
1660
 
@@ -1607,6 +1686,7 @@ function storeBaseData(_scoreId, _scoreObj, _keyCtrlPtn) {
1607
1686
  let allData = 0;
1608
1687
 
1609
1688
  const types = [`arrow`, `frz`];
1689
+ let fullData = [];
1610
1690
  for (let j = 0; j < keyNum; j++) {
1611
1691
  noteCnt.arrow[j] = 0;
1612
1692
  noteCnt.frz[j] = 0;
@@ -1625,17 +1705,53 @@ function storeBaseData(_scoreId, _scoreObj, _keyCtrlPtn) {
1625
1705
  }
1626
1706
  })
1627
1707
  });
1708
+ fullData = fullData.concat(..._scoreObj.arrowData[j], ...tmpFrzData);
1628
1709
  }
1629
1710
 
1711
+ fullData = fullData.filter(val => !isNaN(parseFloat(val))).sort((a, b) => a - b);
1712
+ let pushCnt = 0;
1713
+ const density2PushData = [...Array(C_LEN_DENSITY_DIVISION)].fill(0);
1714
+ const density3PushData = [...Array(C_LEN_DENSITY_DIVISION)].fill(0);
1715
+ fullData.forEach((note, j) => {
1716
+ if (fullData[j] === fullData[j + 1]) {
1717
+ pushCnt++;
1718
+ } else {
1719
+ const point = Math.floor((note - firstArrowFrame) / playingFrame * C_LEN_DENSITY_DIVISION);
1720
+ if (point >= 0) {
1721
+ if (pushCnt > 2) {
1722
+ density3PushData[point] += pushCnt;
1723
+ }
1724
+ density2PushData[point] += pushCnt;
1725
+ }
1726
+ pushCnt = 0;
1727
+ }
1728
+ });
1729
+
1630
1730
  g_detailObj.toolDif[_scoreId] = calcLevel(_scoreObj);
1631
1731
  g_detailObj.speedData[_scoreId] = _scoreObj.speedData.concat();
1632
1732
  g_detailObj.boostData[_scoreId] = _scoreObj.boostData.concat();
1633
1733
 
1634
- g_detailObj.maxDensity[_scoreId] = densityData.indexOf(Math.max.apply(null, densityData));
1635
- g_detailObj.densityData[_scoreId] = [];
1636
- for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
1637
- g_detailObj.densityData[_scoreId].push(Math.round(densityData[j] / allData * C_LEN_DENSITY_DIVISION * 10000) / 100);
1734
+ const storeDensity = _densityData => {
1735
+ const dataList = [];
1736
+ for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
1737
+ dataList.push(allData === 0 ? 0 : Math.round(_densityData[j] / allData * C_LEN_DENSITY_DIVISION * 10000) / 100);
1738
+ }
1739
+ return dataList;
1638
1740
  }
1741
+ const diffArray = (_array1, _array2) => {
1742
+ const list = [];
1743
+ _array1.forEach((val, j) => list.push(_array1[j] - _array2[j]));
1744
+ return list;
1745
+ };
1746
+ g_detailObj.densityData[_scoreId] = storeDensity(densityData);
1747
+ g_detailObj.density2PushData[_scoreId] = storeDensity(density2PushData);
1748
+ g_detailObj.density3PushData[_scoreId] = storeDensity(density3PushData);
1749
+
1750
+ g_detailObj.densityDiff[_scoreId] = diffArray(g_detailObj.densityData[_scoreId], g_detailObj.density2PushData[_scoreId]);
1751
+ g_detailObj.density2PushDiff[_scoreId] = diffArray(g_detailObj.density2PushData[_scoreId], g_detailObj.density3PushData[_scoreId]);
1752
+ g_detailObj.density3PushDiff[_scoreId] = g_detailObj.density3PushData[_scoreId].concat();
1753
+
1754
+ g_detailObj.maxDensity[_scoreId] = densityData.indexOf(Math.max.apply(null, densityData));
1639
1755
 
1640
1756
  g_detailObj.arrowCnt[_scoreId] = noteCnt.arrow.concat();
1641
1757
  g_detailObj.frzCnt[_scoreId] = noteCnt.frz.concat();
@@ -1810,7 +1926,8 @@ function calcLevel(_scoreObj) {
1810
1926
  }
1811
1927
 
1812
1928
  /**
1813
- * jsファイルの連続読込
1929
+ * js, cssファイルの連続読込 (callback)
1930
+ * @deprecated v27以降非推奨予定
1814
1931
  * @param {number} _j
1815
1932
  * @param {array} _fileData
1816
1933
  * @param {string} _loadType
@@ -1837,6 +1954,28 @@ function loadMultipleFiles(_j, _fileData, _loadType, _afterFunc = _ => true) {
1837
1954
  }
1838
1955
  }
1839
1956
 
1957
+ /**
1958
+ * js, cssファイルの連続読込 (async function)
1959
+ * @param {array} _fileData
1960
+ * @param {string} _loadType
1961
+ */
1962
+ async function loadMultipleFiles2(_fileData, _loadType) {
1963
+ await Promise.all(_fileData.map(async filePart => {
1964
+ const filePath = `${filePart[1]}${filePart[0]}?${new Date().getTime()}`;
1965
+ if (filePart[0].endsWith(`.css`)) {
1966
+ _loadType = `css`;
1967
+ }
1968
+
1969
+ // jsファイル、cssファイルにより呼び出す関数を切替
1970
+ if (_loadType === `js`) {
1971
+ await loadScript2(filePath, false);
1972
+ } else if (_loadType === `css`) {
1973
+ const cssPath = filePath.split(`.js`).join(`.css`);
1974
+ await importCssFile2(cssPath);
1975
+ }
1976
+ }));
1977
+ }
1978
+
1840
1979
  /**
1841
1980
  * 入力されたパスを、ディレクトリとそれ以外に分割
1842
1981
  * 返却値:[ファイルキーワード, ルートディレクトリ]
@@ -1865,26 +2004,6 @@ const getFilePath = (_fileName, _directory = ``) => {
1865
2004
  }
1866
2005
  };
1867
2006
 
1868
- /**
1869
- * danoni_setting.jsの読込
1870
- */
1871
- function loadSettingJs() {
1872
-
1873
- // 共通設定ファイルの指定
1874
- let [settingType, settingRoot] = getFilePath(g_rootObj.settingType || ``, C_DIR_JS);
1875
- if (settingType !== ``) {
1876
- settingType = `_${settingType}`;
1877
- }
1878
-
1879
- const randTime = new Date().getTime();
1880
- loadScript(`${settingRoot}danoni_setting${settingType}.js?${randTime}`, _ => {
1881
- if (document.querySelector(`#lblLoading`) !== null) {
1882
- divRoot.removeChild(document.querySelector(`#lblLoading`));
1883
- }
1884
- initAfterDosLoaded();
1885
- }, false);
1886
- }
1887
-
1888
2007
  function loadMusic() {
1889
2008
 
1890
2009
  clearWindow(true);
@@ -2284,7 +2403,7 @@ const createScText = (_obj, _settingLabel, { displayName = `option`, dfLabel = `
2284
2403
  if (scKey.length > 0) {
2285
2404
  multiAppend(_obj,
2286
2405
  createDivCss2Label(`sc${_settingLabel}`,
2287
- g_scViewObj.format.split(`{0}`).join(dfLabel !== `` ? `${dfLabel}` : `${setVal(g_kCd[g_kCdN.findIndex(kCd => kCd === scKey[0])], ``, C_TYP_STRING)}`), {
2406
+ g_scViewObj.format.split(`{0}`).join(dfLabel !== `` ? `${dfLabel}` : `${g_kCd[g_kCdN.findIndex(kCd => kCd === scKey[0])] ?? ''}`), {
2288
2407
  x, y, w, siz, fontWeight: `bold`, opacity: 0.75, pointerEvents: C_DIS_NONE,
2289
2408
  })
2290
2409
  );
@@ -2300,8 +2419,8 @@ const createScTextCommon = _displayName => {
2300
2419
  .forEach(target =>
2301
2420
  createScText(document.getElementById(`btn${target}`), target, {
2302
2421
  displayName: _displayName, targetLabel: `btn${target}`,
2303
- dfLabel: setVal(g_lblNameObj[`sc_${_displayName}${target}`], ``, C_TYP_STRING),
2304
- x: g_btnPatterns[_displayName][target]
2422
+ dfLabel: g_lblNameObj[`sc_${_displayName}${target}`] ?? ``,
2423
+ x: g_btnPatterns[_displayName][target],
2305
2424
  }));
2306
2425
  }
2307
2426
 
@@ -2448,7 +2567,7 @@ function titleInit() {
2448
2567
  -webkit-text-fill-color: rgba(255,255,255,0.0);
2449
2568
  ${txtAnimations[1]}
2450
2569
  " class="${g_headerObj.titleAnimationClass[1]}">
2451
- ${setVal(g_headerObj.musicTitleForView[1], ``, C_TYP_STRING)}
2570
+ ${g_headerObj.musicTitleForView[1] ?? ``}
2452
2571
  </div>
2453
2572
  `,
2454
2573
  {
@@ -2562,15 +2681,23 @@ function titleInit() {
2562
2681
 
2563
2682
  // コメントエリア作成
2564
2683
  if (g_headerObj.commentVal !== ``) {
2684
+
2685
+ // コメント文の加工
2686
+ const comments = g_headerObj.commentVal.split(`}`).join(`{`).split(`{`);
2687
+ let convCommentVal = ``;
2688
+ for (let j = 0; j < comments.length; j += 2) {
2689
+ convCommentVal += escapeHtmlForEnabledTag(comments[j]);
2690
+ convCommentVal += setVal(comments[j + 1], ``, C_TYP_CALC);
2691
+ }
2692
+
2565
2693
  if (g_headerObj.commentExternal) {
2566
2694
  if (document.querySelector(`#commentArea`) !== null) {
2567
- commentArea.innerHTML = g_headerObj.commentVal;
2695
+ commentArea.innerHTML = convCommentVal;
2568
2696
  }
2569
2697
  } else {
2570
- let tmpComment = g_headerObj.commentVal;
2571
2698
  multiAppend(divRoot,
2572
2699
 
2573
- createDivCss2Label(`lblComment`, tmpComment, {
2700
+ createDivCss2Label(`lblComment`, convCommentVal, {
2574
2701
  x: 0, y: 70, w: g_sWidth, h: g_sHeight - 180, siz: C_SIZ_DIFSELECTOR, align: C_ALIGN_LEFT,
2575
2702
  overflow: `auto`, background: `#222222`, color: `#cccccc`, display: C_DIS_NONE,
2576
2703
  }),
@@ -2579,10 +2706,11 @@ function titleInit() {
2579
2706
  const lblCommentDef = lblComment.style.display;
2580
2707
  lblComment.style.display = (lblCommentDef === C_DIS_NONE ? C_DIS_INHERIT : C_DIS_NONE);
2581
2708
  }, {
2582
- x: g_sWidth - 180, y: (g_sHeight / 2) + 150, w: 150, h: 50, siz: 20, border: `solid 1px #999999`,
2709
+ x: g_sWidth - 160, y: (g_sHeight / 2) + 150, w: 140, h: 50, siz: 20, border: `solid 1px #999999`,
2583
2710
  }, g_cssObj.button_Default),
2584
2711
 
2585
2712
  );
2713
+ setUserSelect(lblComment.style, `text`);
2586
2714
  }
2587
2715
  }
2588
2716
 
@@ -2766,30 +2894,28 @@ function preheaderConvert(_dosObj) {
2766
2894
  };
2767
2895
 
2768
2896
  // 外部スキンファイルの指定
2769
- const tmpSkinType = _dosObj.skinType || (typeof g_presetSkinType === C_TYP_STRING ? g_presetSkinType : `default`);
2897
+ const tmpSkinType = _dosObj.skinType ?? g_presetObj.skinType ?? `default`;
2770
2898
  const tmpSkinTypes = tmpSkinType.split(`,`);
2771
2899
  obj.defaultSkinFlg = tmpSkinTypes.includes(`default`);
2772
2900
  setJsFiles(tmpSkinTypes, C_DIR_SKIN, `skin`);
2773
2901
 
2774
2902
  // 外部jsファイルの指定
2775
- const tmpCustomjs = _dosObj.customjs || (typeof g_presetCustomJs === C_TYP_STRING ? g_presetCustomJs : C_JSF_CUSTOM);
2903
+ const tmpCustomjs = _dosObj.customjs ?? g_presetObj.customJs ?? C_JSF_CUSTOM;
2776
2904
  setJsFiles(tmpCustomjs.split(`,`), C_DIR_JS);
2777
2905
 
2778
2906
  // 外部cssファイルの指定
2779
- const tmpCustomcss = _dosObj.customcss || (typeof g_presetCustomCss === C_TYP_STRING ? g_presetCustomCss : ``);
2907
+ const tmpCustomcss = _dosObj.customcss ?? g_presetObj.customCss ?? ``;
2780
2908
  setJsFiles(tmpCustomcss.split(`,`), C_DIR_CSS);
2781
2909
 
2782
2910
  // デフォルト曲名表示、背景、Ready表示の利用有無
2783
2911
  g_titleLists.init.forEach(objName => {
2784
2912
  const objUpper = toCapitalize(objName);
2785
- obj[`custom${objUpper}Use`] = setVal(_dosObj[`custom${objUpper}Use`],
2786
- (typeof g_presetCustomDesignUse === C_TYP_OBJECT && (objName in g_presetCustomDesignUse) ?
2787
- setVal(g_presetCustomDesignUse[objName], false, C_TYP_BOOLEAN) : false), C_TYP_BOOLEAN);
2913
+ obj[`custom${objUpper}Use`] =
2914
+ setVal(_dosObj[`custom${objUpper}Use`] ?? g_presetObj.customDesignUse?.[objName], false, C_TYP_BOOLEAN);
2788
2915
  });
2789
2916
 
2790
2917
  // 背景・マスクモーションのパス指定方法を他の設定に合わせる設定
2791
- const tmpSyncBackPath = (typeof g_presetSyncBackPath === C_TYP_BOOLEAN ? g_presetSyncBackPath : false);
2792
- obj.syncBackPath = setVal(_dosObj.syncBackPath, tmpSyncBackPath, C_TYP_BOOLEAN);
2918
+ obj.syncBackPath = setVal(_dosObj.syncBackPath ?? g_presetObj.syncBackPath, false, C_TYP_BOOLEAN);
2793
2919
 
2794
2920
  return obj;
2795
2921
  }
@@ -2802,26 +2928,14 @@ function updateImgType(_imgType) {
2802
2928
  resetImgs(_imgType.name, _imgType.extension);
2803
2929
  reloadImgObj();
2804
2930
  Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_rootPath}${g_imgObj[key]}`);
2805
- if (_imgType[1] === undefined && typeof g_presetOverrideExtension === C_TYP_STRING) {
2806
- Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_imgObj[key].slice(0, -3)}${g_presetOverrideExtension}`);
2931
+ if (_imgType[1] === undefined && g_presetObj.overrideExtension !== undefined) {
2932
+ Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_imgObj[key].slice(0, -3)}${g_presetObj.overrideExtension}`);
2807
2933
  }
2808
2934
  if (!g_isFile) {
2809
2935
  g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
2810
2936
  }
2811
2937
  }
2812
2938
 
2813
- /**
2814
- * 独自で設定したラベルテキスト、オンマウステキスト、確認メッセージ定義を上書き
2815
- */
2816
- function updateLocalDesc() {
2817
- if (typeof g_local_lblNameObj === C_TYP_OBJECT && g_local_lblNameObj[g_localeObj.val] !== undefined) {
2818
- Object.keys(g_local_lblNameObj[g_localeObj.val]).forEach(property => g_lblNameObj[property] = g_local_lblNameObj[g_localeObj.val][property]);
2819
- }
2820
- if (typeof g_local_msgObj === C_TYP_OBJECT && g_local_msgObj[g_localeObj.val] !== undefined) {
2821
- Object.keys(g_local_msgObj[g_localeObj.val]).forEach(property => g_msgObj[property] = g_local_msgObj[g_localeObj.val][property]);
2822
- }
2823
- }
2824
-
2825
2939
  /**
2826
2940
  * 譜面ヘッダーの分解(その他の設定)
2827
2941
  * @param {object} _dosObj 譜面データオブジェクト
@@ -2832,7 +2946,7 @@ function headerConvert(_dosObj) {
2832
2946
  const obj = {};
2833
2947
 
2834
2948
  // フォントの設定
2835
- obj.customFont = setVal(_dosObj.customFont, ``, C_TYP_STRING);
2949
+ obj.customFont = _dosObj.customFont ?? ``;
2836
2950
  g_headerObj.customFont = obj.customFont;
2837
2951
 
2838
2952
  // 画像ルートパス、拡張子の設定 (サーバ上のみ)
@@ -2841,8 +2955,8 @@ function headerConvert(_dosObj) {
2841
2955
  let tmpImgTypes = [];
2842
2956
  if (hasVal(_dosObj.imgType)) {
2843
2957
  tmpImgTypes = _dosObj.imgType.split(`$`);
2844
- } else if (typeof g_presetImageSets === C_TYP_OBJECT) {
2845
- tmpImgTypes = g_presetImageSets.concat();
2958
+ } else if (g_presetObj.imageSets !== undefined) {
2959
+ tmpImgTypes = g_presetObj.imageSets.concat();
2846
2960
  }
2847
2961
  if (tmpImgTypes.length > 0) {
2848
2962
  tmpImgTypes.forEach((tmpImgType, j) => {
@@ -2873,9 +2987,8 @@ function headerConvert(_dosObj) {
2873
2987
  }
2874
2988
 
2875
2989
  // ラベルテキスト、オンマウステキスト、確認メッセージ定義の上書き設定
2876
- Object.keys(g_lang_lblNameObj[g_localeObj.val]).forEach(property => g_lblNameObj[property] = g_lang_lblNameObj[g_localeObj.val][property]);
2877
- Object.keys(g_lang_msgObj[g_localeObj.val]).forEach(property => g_msgObj[property] = g_lang_msgObj[g_localeObj.val][property]);
2878
- updateLocalDesc();
2990
+ Object.assign(g_lblNameObj, g_lang_lblNameObj[g_localeObj.val], g_presetObj.lblName?.[g_localeObj.val]);
2991
+ Object.assign(g_msgObj, g_lang_msgObj[g_localeObj.val], g_presetObj.msg?.[g_localeObj.val]);
2879
2992
 
2880
2993
  // 曲名
2881
2994
  obj.musicTitles = [];
@@ -2896,18 +3009,18 @@ function headerConvert(_dosObj) {
2896
3009
  if (obj.musicNos.length >= j) {
2897
3010
  obj.musicTitles[j] = escapeHtml(getMusicNameSimple(musics[0]));
2898
3011
  obj.musicTitlesForView[j] = escapeHtmlForArray(getMusicNameMultiLine(musics[0]));
2899
- obj.artistNames[j] = escapeHtml(setVal(musics[1], ``, C_TYP_STRING));
3012
+ obj.artistNames[j] = escapeHtml(musics[1] ?? ``);
2900
3013
  }
2901
3014
  }
2902
3015
  const musics = musicData[0].split(`,`);
2903
3016
  obj.musicTitle = obj.musicTitles[0];
2904
3017
  obj.musicTitleForView = obj.musicTitlesForView[0];
2905
- obj.artistName = obj.artistNames[0] || ``;
3018
+ obj.artistName = obj.artistNames[0] ?? ``;
2906
3019
  if (obj.artistName === ``) {
2907
3020
  makeWarningWindow(g_msgInfoObj.E_0011);
2908
3021
  obj.artistName = `artistName`;
2909
3022
  }
2910
- obj.artistUrl = musics[2] || ``;
3023
+ obj.artistUrl = musics[2] ?? ``;
2911
3024
  if (musics[3] !== undefined) {
2912
3025
  obj.musicTitles[0] = escapeHtml(getMusicNameSimple(musics[3]));
2913
3026
  obj.musicTitlesForView[0] = escapeHtmlForArray(getMusicNameMultiLine(musics[3]));
@@ -2943,10 +3056,10 @@ function headerConvert(_dosObj) {
2943
3056
  if (hasVal(_dosObj.tuning)) {
2944
3057
  const tunings = _dosObj.tuning.split(`,`);
2945
3058
  obj.tuning = escapeHtmlForEnabledTag(tunings[0]);
2946
- obj.creatorUrl = (tunings.length > 1 ? tunings[1] : (typeof g_presetTuningUrl === C_TYP_STRING ? g_presetTuningUrl : ``));
3059
+ obj.creatorUrl = (tunings.length > 1 ? tunings[1] : (g_presetObj.tuningUrl ?? ``));
2947
3060
  } else {
2948
- obj.tuning = (typeof g_presetTuning === C_TYP_STRING ? escapeHtmlForEnabledTag(g_presetTuning) : `name`);
2949
- obj.creatorUrl = (typeof g_presetTuningUrl === C_TYP_STRING ? g_presetTuningUrl : ``);
3061
+ obj.tuning = escapeHtmlForEnabledTag(g_presetObj.tuning ?? `name`);
3062
+ obj.creatorUrl = g_presetObj.tuningUrl ?? ``;
2950
3063
  }
2951
3064
  obj.tuningInit = obj.tuning;
2952
3065
 
@@ -2954,7 +3067,7 @@ function headerConvert(_dosObj) {
2954
3067
  if (hasVal(_dosObj.difData)) {
2955
3068
  const difs = _dosObj.difData.split(`$`);
2956
3069
  const difpos = {
2957
- key: 0, name: 1, speed: 2, border: 3, recovery: 4, damage: 5, init: 6,
3070
+ Key: 0, Name: 1, Speed: 2, Border: 3, Recovery: 4, Damage: 5, Init: 6,
2958
3071
  };
2959
3072
  obj.keyLabels = [];
2960
3073
  obj.difLabels = [];
@@ -2966,34 +3079,25 @@ function headerConvert(_dosObj) {
2966
3079
  obj.creatorNames = [];
2967
3080
  g_stateObj.scoreId = (g_stateObj.scoreId < difs.length ? g_stateObj.scoreId : 0);
2968
3081
 
2969
- const lifeData = (_name, _preData, _default) => {
2970
- const data = (_preData) ? _preData :
2971
- (typeof g_presetGauge === C_TYP_OBJECT && (_name in g_presetGauge) ?
2972
- g_presetGauge[_name] : _default);
2973
- return setVal(data, _default, C_TYP_FLOAT);
2974
- };
2975
-
2976
3082
  difs.forEach(dif => {
2977
3083
  const difDetails = dif.split(`,`);
3084
+ const lifeData = (_type, _default) =>
3085
+ setVal(difDetails[difpos[_type]] || g_presetObj.gauge?.[_type], _default, C_TYP_FLOAT);
2978
3086
 
2979
3087
  // ライフ:ノルマ、回復量、ダメージ量、初期値の設定
2980
- const border = (difDetails[difpos.border]) ? difDetails[difpos.border] :
2981
- (typeof g_presetGauge === C_TYP_OBJECT && (`Border` in g_presetGauge) ?
2982
- g_presetGauge.Border : `x`);
2983
-
2984
- obj.lifeBorders.push(border === `x` ? `x` : setVal(border, 70, C_TYP_FLOAT));
2985
- obj.lifeRecoverys.push(lifeData(`Recovery`, difDetails[difpos.recovery], 6));
2986
- obj.lifeDamages.push(lifeData(`Damage`, difDetails[difpos.damage], 40));
2987
- obj.lifeInits.push(lifeData(`Init`, difDetails[difpos.init], 25));
3088
+ obj.lifeBorders.push(lifeData(`Border`, `x`));
3089
+ obj.lifeRecoverys.push(lifeData(`Recovery`, 6));
3090
+ obj.lifeDamages.push(lifeData(`Damage`, 40));
3091
+ obj.lifeInits.push(lifeData(`Init`, 25));
2988
3092
 
2989
3093
  // キー数
2990
- const keyLabel = setVal(difDetails[difpos.key], `7`, C_TYP_STRING);
2991
- obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] || keyLabel);
3094
+ const keyLabel = difDetails[difpos.Key] ?? `7`;
3095
+ obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] ?? keyLabel);
2992
3096
 
2993
3097
  // 譜面名、制作者名
2994
- if (hasVal(difDetails[difpos.name])) {
2995
- const difNameInfo = difDetails[difpos.name].split(`::`);
2996
- obj.difLabels.push(escapeHtml(setVal(difNameInfo[0], `Normal`, C_TYP_STRING)));
3098
+ if (hasVal(difDetails[difpos.Name])) {
3099
+ const difNameInfo = difDetails[difpos.Name].split(`::`);
3100
+ obj.difLabels.push(escapeHtml(difNameInfo[0] ?? `Normal`));
2997
3101
  obj.creatorNames.push(difNameInfo.length > 1 ? escapeHtml(difNameInfo[1]) : obj.tuning);
2998
3102
  } else {
2999
3103
  obj.difLabels.push(`Normal`);
@@ -3001,7 +3105,7 @@ function headerConvert(_dosObj) {
3001
3105
  }
3002
3106
 
3003
3107
  // 初期速度
3004
- obj.initSpeeds.push(setVal(difDetails[difpos.speed], 3.5, C_TYP_FLOAT));
3108
+ obj.initSpeeds.push(setVal(difDetails[difpos.Speed], 3.5, C_TYP_FLOAT));
3005
3109
  });
3006
3110
  } else {
3007
3111
  makeWarningWindow(g_msgInfoObj.E_0021);
@@ -3014,8 +3118,9 @@ function headerConvert(_dosObj) {
3014
3118
  obj.lifeInits = [25];
3015
3119
  obj.creatorNames = [obj.tuning];
3016
3120
  }
3017
- const keyLists = obj.keyLabels.filter((x, j, self) => self.indexOf(x) === j);
3121
+ const keyLists = makeDedupliArray(obj.keyLabels);
3018
3122
  obj.keyLists = keyLists.sort((a, b) => parseInt(a) - parseInt(b));
3123
+ obj.undefinedKeyLists = obj.keyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
3019
3124
 
3020
3125
  // 譜面変更セレクターの利用有無
3021
3126
  obj.difSelectorUse = (setVal(_dosObj.difSelectorUse, obj.keyLabels.length > 5, C_TYP_BOOLEAN));
@@ -3034,7 +3139,7 @@ function headerConvert(_dosObj) {
3034
3139
  if (hasVal(_dosObj.defaultColorgrd)) {
3035
3140
  obj.defaultColorgrd = _dosObj.defaultColorgrd.split(`,`);
3036
3141
  obj.defaultColorgrd[0] = setVal(obj.defaultColorgrd[0], false, C_TYP_BOOLEAN);
3037
- obj.defaultColorgrd[1] = setVal(obj.defaultColorgrd[1], intermediateColor, C_TYP_STRING);
3142
+ obj.defaultColorgrd[1] = obj.defaultColorgrd[1] ?? intermediateColor;
3038
3143
  }
3039
3144
  g_rankObj.rankColorAllPerfect = intermediateColor;
3040
3145
 
@@ -3055,13 +3160,7 @@ function headerConvert(_dosObj) {
3055
3160
  });
3056
3161
 
3057
3162
  // フリーズアローのデフォルト色セットの利用有無 (true: 使用, false: 矢印色を優先してセット)
3058
- if (hasVal(_dosObj.defaultFrzColorUse)) {
3059
- obj.defaultFrzColorUse = setVal(_dosObj.defaultFrzColorUse, true, C_TYP_BOOLEAN);
3060
- } else if (typeof g_presetFrzColors === C_TYP_BOOLEAN) {
3061
- obj.defaultFrzColorUse = g_presetFrzColors;
3062
- } else {
3063
- obj.defaultFrzColorUse = true;
3064
- }
3163
+ obj.defaultFrzColorUse = setVal(_dosObj.defaultFrzColorUse ?? g_presetObj.frzColors, true, C_TYP_BOOLEAN);
3065
3164
 
3066
3165
  // 矢印色変化に対応してフリーズアロー色を追随する範囲の設定
3067
3166
  // (defaultFrzColorUse=false時のみ)
@@ -3072,8 +3171,8 @@ function headerConvert(_dosObj) {
3072
3171
 
3073
3172
  if (hasVal(_dosObj.frzScopeFromAC)) {
3074
3173
  tmpFrzScope.push(..._dosObj.frzScopeFromAC.split(`,`));
3075
- } else if (typeof g_presetFrzScopeFromAC === C_TYP_OBJECT) {
3076
- tmpFrzScope.push(...g_presetFrzScopeFromAC);
3174
+ } else if (g_presetObj.frzScopeFromAC !== undefined) {
3175
+ tmpFrzScope.push(...g_presetObj.frzScopeFromAC);
3077
3176
  }
3078
3177
  tmpFrzScope.filter(type => [`Normal`, `Hit`].includes(type))
3079
3178
  .forEach(data => obj.frzScopeFromArrowColors.push(data));
@@ -3097,10 +3196,10 @@ function headerConvert(_dosObj) {
3097
3196
  addGaugeFulls(g_gaugeOptionObj.survival);
3098
3197
  addGaugeFulls(g_gaugeOptionObj.border);
3099
3198
 
3100
- if (typeof g_presetGaugeList === C_TYP_OBJECT) {
3101
- Object.keys(g_presetGaugeList).forEach(key => {
3199
+ if (g_presetObj.gaugeList !== undefined) {
3200
+ Object.keys(g_presetObj.gaugeList).forEach(key => {
3102
3201
  g_gaugeOptionObj.customDefault.push(key);
3103
- g_gaugeOptionObj.varCustomDefault.push((g_presetGaugeList[key] !== `V` ? C_FLG_OFF : C_FLG_ON));
3202
+ g_gaugeOptionObj.varCustomDefault.push((g_presetObj.gaugeList[key] !== `V` ? C_FLG_OFF : C_FLG_ON));
3104
3203
  });
3105
3204
  g_gaugeOptionObj.custom = g_gaugeOptionObj.customDefault.concat();
3106
3205
  g_gaugeOptionObj.varCustom = g_gaugeOptionObj.varCustomDefault.concat();
@@ -3173,7 +3272,7 @@ function headerConvert(_dosObj) {
3173
3272
  g_diffObj.frzJdgY = (isNaN(parseFloat(_dosObj.frzJdgY)) ? 0 : parseFloat(_dosObj.frzJdgY));
3174
3273
 
3175
3274
  // musicフォルダ設定
3176
- obj.musicFolder = setVal(_dosObj.musicFolder, (g_remoteFlg ? `(..)../music` : `music`), C_TYP_STRING);
3275
+ obj.musicFolder = _dosObj.musicFolder ?? (g_remoteFlg ? `(..)../music` : `music`);
3177
3276
 
3178
3277
  // 楽曲URL
3179
3278
  if (hasVal(_dosObj.musicUrl)) {
@@ -3198,10 +3297,10 @@ function headerConvert(_dosObj) {
3198
3297
  }
3199
3298
 
3200
3299
  // 最終演出表示有無(noneで無効化)
3201
- obj.finishView = setVal(_dosObj.finishView, ``, C_TYP_STRING);
3300
+ obj.finishView = _dosObj.finishView ?? ``;
3202
3301
 
3203
3302
  // 更新日
3204
- obj.releaseDate = setVal(_dosObj.releaseDate, ``, C_TYP_STRING);
3303
+ obj.releaseDate = _dosObj.releaseDate ?? ``;
3205
3304
 
3206
3305
  // デフォルトReady/リザルト表示の遅延時間設定
3207
3306
  [`ready`, `result`].forEach(objName => {
@@ -3212,16 +3311,16 @@ function headerConvert(_dosObj) {
3212
3311
  obj.readyAnimationFrame = setVal(_dosObj.readyAnimationFrame, 150, C_TYP_NUMBER);
3213
3312
 
3214
3313
  // デフォルトReady表示のアニメーション名
3215
- obj.readyAnimationName = setVal(_dosObj.readyAnimationName, `leftToRightFade`, C_TYP_STRING);
3314
+ obj.readyAnimationName = _dosObj.readyAnimationName ?? `leftToRightFade`;
3216
3315
 
3217
3316
  // デフォルトReady表示の先頭文字色
3218
- obj.readyColor = setVal(_dosObj.readyColor, ``, C_TYP_STRING);
3317
+ obj.readyColor = _dosObj.readyColor ?? ``;
3219
3318
 
3220
3319
  // デフォルトReady表示を上書きするテキスト
3221
- obj.readyHtml = setVal(_dosObj.readyHtml, ``, C_TYP_STRING);
3320
+ obj.readyHtml = _dosObj.readyHtml ?? ``;
3222
3321
 
3223
3322
  // デフォルト曲名表示のフォントサイズ
3224
- obj.titlesize = setVal(_dosObj.titlesize, ``, C_TYP_STRING);
3323
+ obj.titlesize = _dosObj.titlesize ?? ``;
3225
3324
 
3226
3325
  // デフォルト曲名表示のフォント名
3227
3326
  // (使用例: |titlefont=Century,Meiryo UI|)
@@ -3241,7 +3340,7 @@ function headerConvert(_dosObj) {
3241
3340
  if (hasVal(_dosObj[_name])) {
3242
3341
  const tmpTitlegrd = _dosObj[_name].replace(/,/g, `:`);
3243
3342
  obj[`${_name}s`] = tmpTitlegrd.split(`$`);
3244
- obj[`${_name}`] = setVal(obj[`${_name}s`][0], ``, C_TYP_STRING);
3343
+ obj[`${_name}`] = obj[`${_name}s`][0] ?? ``;
3245
3344
  }
3246
3345
  });
3247
3346
 
@@ -3270,7 +3369,7 @@ function headerConvert(_dosObj) {
3270
3369
  }
3271
3370
  if (hasVal(_dosObj.titleanimationclass)) {
3272
3371
  _dosObj.titleanimationclass.split(`$`).forEach((animationClass, j) => {
3273
- obj.titleAnimationClass[j] = setVal(animationClass, ``, C_TYP_STRING);
3372
+ obj.titleAnimationClass[j] = animationClass ?? ``;
3274
3373
  });
3275
3374
  }
3276
3375
  if (obj.titleAnimationName.length === 1) {
@@ -3286,8 +3385,7 @@ function headerConvert(_dosObj) {
3286
3385
  obj.titlelineheight = setVal(_dosObj.titlelineheight, ``, C_TYP_NUMBER);
3287
3386
 
3288
3387
  // フリーズアローの始点で通常矢印の判定を行うか(dotさんソース方式)
3289
- obj.frzStartjdgUse = setVal(_dosObj.frzStartjdgUse,
3290
- (typeof g_presetFrzStartjdgUse === C_TYP_STRING ? setVal(g_presetFrzStartjdgUse, false, C_TYP_BOOLEAN) : false), C_TYP_BOOLEAN);
3388
+ obj.frzStartjdgUse = setVal(_dosObj.frzStartjdgUse ?? g_presetObj.frzStartjdgUse, false, C_TYP_BOOLEAN);
3291
3389
 
3292
3390
  // 譜面名に制作者名を付加するかどうかのフラグ
3293
3391
  obj.makerView = setVal(_dosObj.makerView, false, C_TYP_BOOLEAN);
@@ -3300,25 +3398,21 @@ function headerConvert(_dosObj) {
3300
3398
 
3301
3399
  // オプション利用可否設定
3302
3400
  g_canDisabledSettings.forEach(option => {
3303
- obj[`${option}Use`] = setVal(_dosObj[`${option}Use`],
3304
- (typeof g_presetSettingUse === C_TYP_OBJECT ?
3305
- setVal(g_presetSettingUse[option], true, C_TYP_BOOLEAN) : true), C_TYP_BOOLEAN);
3401
+ obj[`${option}Use`] = setVal(_dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option], true, C_TYP_BOOLEAN);
3306
3402
  });
3307
3403
 
3308
3404
  let interlockingErrorFlg = false;
3309
3405
  g_displays.forEach((option, j) => {
3310
3406
 
3311
3407
  // Display使用可否設定を分解 |displayUse=false,ON|
3312
- const displayTempUse = setVal(_dosObj[`${option}Use`],
3313
- (typeof g_presetSettingUse === C_TYP_OBJECT ?
3314
- g_presetSettingUse[option] : `true`), C_TYP_STRING);
3408
+ const displayTempUse = _dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option] ?? `true`;
3315
3409
  const displayUse = (displayTempUse !== undefined ? displayTempUse.split(`,`) : [true, C_FLG_ON]);
3316
3410
 
3317
3411
  // displayUse -> ボタンの有効/無効, displaySet -> ボタンの初期値(ON/OFF)
3318
3412
  obj[`${option}Use`] = setVal(displayUse[0], true, C_TYP_BOOLEAN);
3319
3413
  obj[`${option}Set`] = setVal(displayUse.length > 1 ? displayUse[1] :
3320
3414
  (obj[`${option}Use`] ? C_FLG_ON : C_FLG_OFF), ``, C_TYP_SWITCH);
3321
- g_stateObj[`d_${option.toLowerCase()}`] = (obj[`${option}Set`] !== `` ? obj[`${option}Set`] : C_FLG_ON);
3415
+ g_stateObj[`d_${option.toLowerCase()}`] = setVal(obj[`${option}Set`], C_FLG_ON, C_TYP_SWITCH);
3322
3416
  obj[`${option}ChainOFF`] = (_dosObj[`${option}ChainOFF`] !== undefined ? _dosObj[`${option}ChainOFF`].split(`,`) : []);
3323
3417
 
3324
3418
  // Displayのデフォルト設定で、双方向に設定されている場合は設定をブロック
@@ -3381,7 +3475,7 @@ function headerConvert(_dosObj) {
3381
3475
  obj.maskresultButton = setVal(_dosObj.maskresultButton, false, C_TYP_BOOLEAN);
3382
3476
 
3383
3477
  // color_dataの過去バージョン互換設定
3384
- obj.colorDataType = setVal(_dosObj.colorDataType, ``, C_TYP_STRING);
3478
+ obj.colorDataType = _dosObj.colorDataType ?? ``;
3385
3479
 
3386
3480
  // リザルトモーションをDisplay:BackgroundのON/OFFと連動させるかどうかの設定
3387
3481
  obj.resultMotionSet = setVal(_dosObj.resultMotionSet, true, C_TYP_BOOLEAN);
@@ -3394,9 +3488,8 @@ function headerConvert(_dosObj) {
3394
3488
 
3395
3489
  // タイトル表示用コメント
3396
3490
  const newlineTag = setVal(_dosObj.commentAutoBr, true, C_TYP_BOOLEAN) ? `<br>` : ``;
3397
- let tmpComment = setVal(_dosObj[`commentVal${g_localeObj.val}`] || _dosObj.commentVal, ``, C_TYP_STRING);
3398
- tmpComment = tmpComment.split(`\r\n`).join(`\n`);
3399
- obj.commentVal = escapeHtmlForEnabledTag(tmpComment.split(`\n`).join(newlineTag));
3491
+ const tmpComment = (_dosObj[`commentVal${g_localeObj.val}`] ?? _dosObj.commentVal ?? ``).split(`\r\n`).join(`\n`);
3492
+ obj.commentVal = tmpComment.split(`\n`).join(newlineTag);
3400
3493
 
3401
3494
  // クレジット表示
3402
3495
  if (document.querySelector(`#webMusicTitle`) !== null) {
@@ -3409,8 +3502,7 @@ function headerConvert(_dosObj) {
3409
3502
  obj.commentExternal = setVal(_dosObj.commentExternal, false, C_TYP_BOOLEAN);
3410
3503
 
3411
3504
  // Reverse時の歌詞の自動反転制御
3412
- obj.wordAutoReverse = setVal(_dosObj.wordAutoReverse,
3413
- (typeof g_presetWordAutoReverse === C_TYP_STRING ? setVal(g_presetWordAutoReverse, `auto`, C_TYP_STRING) : `auto`), C_TYP_STRING);
3505
+ obj.wordAutoReverse = _dosObj.wordAutoReverse ?? g_presetObj.wordAutoReverse ?? `auto`;
3414
3506
 
3415
3507
  // プレイサイズ(X方向)
3416
3508
  obj.playingWidth = setVal(_dosObj.playingWidth, g_sWidth, C_TYP_NUMBER);
@@ -3426,19 +3518,18 @@ function headerConvert(_dosObj) {
3426
3518
 
3427
3519
  // リザルトデータのカスタマイズ
3428
3520
  const resultFormatDefault = `【#danoni[hashTag]】[musicTitle]([keyLabel]) /[maker] /Rank:[rank]/Score:[score]/Playstyle:[playStyle]/[arrowJdg]/[frzJdg]/[maxCombo] [url]`;
3429
- obj.resultFormat = escapeHtmlForEnabledTag(setVal(_dosObj.resultFormat, (typeof g_presetResultFormat === C_TYP_STRING ?
3430
- setVal(g_presetResultFormat, resultFormatDefault, C_TYP_STRING) : resultFormatDefault), C_TYP_STRING));
3521
+ obj.resultFormat = escapeHtmlForEnabledTag(_dosObj.resultFormat ?? g_presetObj.resultFormat ?? resultFormatDefault);
3431
3522
 
3432
3523
  // フェードイン時にそれ以前のデータを蓄積しない種別(word, back, mask)を指定
3433
- obj.unStockCategories = setVal(_dosObj.unStockCategory, ``, C_TYP_STRING).split(`,`);
3434
- if (typeof g_presetUnStockCategories === C_TYP_OBJECT) {
3435
- obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetUnStockCategories);
3524
+ obj.unStockCategories = (_dosObj.unStockCategory ?? ``).split(`,`);
3525
+ if (g_presetObj.unStockCategories !== undefined) {
3526
+ obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetObj.unStockCategories);
3436
3527
  }
3437
3528
  g_fadeinStockList = g_fadeinStockList.filter(cg => obj.unStockCategories.indexOf(cg) === -1);
3438
3529
 
3439
3530
  // フェードイン時にそれ以前のデータを蓄積しないパターンを指定
3440
- if (typeof g_presetStockForceDelList === C_TYP_OBJECT) {
3441
- Object.assign(g_stockForceDelList, g_presetStockForceDelList);
3531
+ if (g_presetObj.stockForceDelList !== undefined) {
3532
+ Object.assign(g_stockForceDelList, g_presetObj.stockForceDelList);
3442
3533
  }
3443
3534
  g_fadeinStockList.forEach(type => {
3444
3535
  if (hasVal(_dosObj[`${type}StockForceDel`])) {
@@ -3715,11 +3806,11 @@ function getGaugeSetting(_dosObj, _name, _difLength, { scoreId = 0 } = {}) {
3715
3806
  }
3716
3807
  }
3717
3808
 
3718
- } else if (typeof g_presetGaugeCustom === C_TYP_OBJECT && g_presetGaugeCustom[_name]) {
3809
+ } else if (g_presetObj.gaugeCustom?.[_name] !== undefined) {
3719
3810
 
3720
3811
  const gaugeDetails = [
3721
- g_presetGaugeCustom[_name].Border, g_presetGaugeCustom[_name].Recovery,
3722
- g_presetGaugeCustom[_name].Damage, g_presetGaugeCustom[_name].Init,
3812
+ g_presetObj.gaugeCustom[_name].Border, g_presetObj.gaugeCustom[_name].Recovery,
3813
+ g_presetObj.gaugeCustom[_name].Damage, g_presetObj.gaugeCustom[_name].Init,
3723
3814
  ]
3724
3815
  if (gaugeUpdateFlg) {
3725
3816
  gaugeCreateFlg = setGaugeDetails(scoreId, gaugeDetails);
@@ -3745,12 +3836,11 @@ const getKeyName = _key => hasVal(g_keyObj[`keyName${_key}`]) ? g_keyObj[`keyNam
3745
3836
  * 一時的な追加キーの設定
3746
3837
  * @param {object} _dosObj
3747
3838
  */
3748
- function keysConvert(_dosObj) {
3839
+ function keysConvert(_dosObj, { keyExtraList = _dosObj.keyExtraList.split(`,`) } = {}) {
3749
3840
 
3750
- if (_dosObj.keyExtraList === undefined) {
3751
- return;
3841
+ if (keyExtraList === undefined) {
3842
+ return [];
3752
3843
  }
3753
- const keyExtraList = _dosObj.keyExtraList.split(`,`);
3754
3844
 
3755
3845
  const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
3756
3846
  const toString = _str => _str;
@@ -3854,7 +3944,7 @@ function keysConvert(_dosObj) {
3854
3944
  let tmpMinPatterns = 1;
3855
3945
 
3856
3946
  // キーの名前 (keyNameX)
3857
- g_keyObj[`keyName${newKey}`] = setVal(_dosObj[`keyName${newKey}`], newKey, C_TYP_STRING);
3947
+ g_keyObj[`keyName${newKey}`] = _dosObj[`keyName${newKey}`] ?? newKey;
3858
3948
 
3859
3949
  // 矢印色パターン (colorX_Y)
3860
3950
  tmpMinPatterns = newKeyMultiParam(newKey, `color`, toNumber, {
@@ -3943,6 +4033,8 @@ function keysConvert(_dosObj) {
3943
4033
  // |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
3944
4034
  newKeyPairParam(newKey, `assist`, `assistPos`);
3945
4035
  });
4036
+
4037
+ return keyExtraList;
3946
4038
  }
3947
4039
 
3948
4040
 
@@ -4441,13 +4533,30 @@ function createOptionWindow(_sprite) {
4441
4533
  drawBaseLine(context);
4442
4534
  for (let j = 0; j < C_LEN_DENSITY_DIVISION; j++) {
4443
4535
  context.beginPath();
4444
- context.fillStyle = (j === g_detailObj.maxDensity[_scoreId] ? C_CLR_DENSITY_MAX : C_CLR_DENSITY_DEFAULT);
4445
- context.fillRect(16 * j * 16 / C_LEN_DENSITY_DIVISION + 30, 195 - 9 * g_detailObj.densityData[_scoreId][j] / 10,
4446
- 15.5 * 16 / C_LEN_DENSITY_DIVISION, 9 * g_detailObj.densityData[_scoreId][j] / 10
4447
- );
4536
+ [``, `2Push`, `3Push`].forEach(val => {
4537
+ context.fillStyle = (j === g_detailObj.maxDensity[_scoreId] ? g_graphColorObj[`max${val}`] : g_graphColorObj[`default${val}`]);
4538
+ context.fillRect(16 * j * 16 / C_LEN_DENSITY_DIVISION + 30, 195 - 9 * g_detailObj[`density${val}Data`][_scoreId][j] / 10,
4539
+ 15.5 * 16 / C_LEN_DENSITY_DIVISION, 9 * g_detailObj[`density${val}Diff`][_scoreId][j] / 10
4540
+ );
4541
+ });
4448
4542
  context.stroke();
4449
4543
  }
4450
4544
 
4545
+ const lineNames = [`1Push`, `2Push`, `3Push+`];
4546
+ Object.keys(g_graphColorObj).filter(val => val.indexOf(`max`) !== -1).forEach((val, j) => {
4547
+ const lineX = 70 + j * 70;
4548
+
4549
+ context.beginPath();
4550
+ context.lineWidth = 3;
4551
+ context.fillStyle = g_rankObj.rankColorAllPerfect;
4552
+ context.strokeStyle = g_graphColorObj[val];
4553
+ context.moveTo(lineX, 215);
4554
+ context.lineTo(lineX + 20, 215);
4555
+ context.stroke();
4556
+ context.font = `${C_SIZ_DIFSELECTOR}px ${getBasicFont()}`;
4557
+ context.fillText(lineNames[j], lineX + 20, 218);
4558
+ });
4559
+
4451
4560
  const obj = getScoreBaseData(_scoreId);
4452
4561
  updateScoreDetailLabel(`Density`, g_lblNameObj.s_apm, obj.apm, 0);
4453
4562
  updateScoreDetailLabel(`Density`, g_lblNameObj.s_time, obj.playingTime, 1);
@@ -4911,8 +5020,6 @@ function createOptionWindow(_sprite) {
4911
5020
  // ---------------------------------------------------
4912
5021
  // 1. キーコンフィグ設定 (KeyConfig)
4913
5022
 
4914
- // 特殊キーフラグ
4915
- g_stateObj.extraKeyFlg = false;
4916
5023
 
4917
5024
  g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
4918
5025
  const isNotSameKey = (g_keyObj.prevKey !== g_keyObj.currentKey);
@@ -4920,15 +5027,8 @@ function createOptionWindow(_sprite) {
4920
5027
  if (g_headerObj.dummyScoreNos !== undefined) {
4921
5028
  g_stateObj.dummyId = setVal(g_headerObj.dummyScoreNos[g_stateObj.scoreId], ``, C_TYP_NUMBER);
4922
5029
  }
4923
-
4924
- if (g_rootObj.keyExtraList !== undefined) {
4925
- g_rootObj.keyExtraList.split(`,`).some(extraKey => {
4926
- if (g_keyObj.currentKey === extraKey) {
4927
- g_stateObj.extraKeyFlg = true;
4928
- return true;
4929
- }
4930
- });
4931
- }
5030
+ // 特殊キーフラグ
5031
+ g_stateObj.extraKeyFlg = g_headerObj.keyExtraList.includes(g_keyObj.currentKey);
4932
5032
 
4933
5033
  // ---------------------------------------------------
4934
5034
  // 2. 初期化設定
@@ -5166,8 +5266,8 @@ function createLblSetting(_settingName, _adjY = 0, _settingLabel = _settingName)
5166
5266
  * @param {string} _name
5167
5267
  */
5168
5268
  function getStgDetailName(_name) {
5169
- return g_lblNameObj[`u_${_name}`] !== undefined && (typeof g_lblRenames !== C_TYP_OBJECT ||
5170
- (typeof g_lblRenames === C_TYP_OBJECT && g_lblRenames[g_currentPage])) ? g_lblNameObj[`u_${_name}`] : _name;
5269
+ return g_lblNameObj[`u_${_name}`] !== undefined &&
5270
+ (g_presetObj.lblRenames === undefined || g_presetObj.lblRenames[g_currentPage]) ? g_lblNameObj[`u_${_name}`] : _name;
5171
5271
  }
5172
5272
 
5173
5273
  /**
@@ -5221,7 +5321,7 @@ function makeDisabledLabel(_id, _heightPos, _defaultStr) {
5221
5321
  */
5222
5322
  function getKeyReverse(_localStorage, _extraKeyName = ``) {
5223
5323
  if (_localStorage[`reverse${_extraKeyName}`] !== undefined) {
5224
- g_stateObj.reverse = setVal(_localStorage[`reverse${_extraKeyName}`], C_FLG_OFF, C_TYP_STRING);
5324
+ g_stateObj.reverse = _localStorage[`reverse${_extraKeyName}`] ?? C_FLG_OFF;
5225
5325
  g_settings.reverseNum = roundZero(g_settings.reverses.findIndex(reverse => reverse === g_stateObj.reverse));
5226
5326
  } else {
5227
5327
  g_stateObj.reverse = C_FLG_OFF;
@@ -6025,7 +6125,7 @@ function keyConfigInit(_kcType = g_kcType) {
6025
6125
 
6026
6126
  // キーパターン表示
6027
6127
  const lblTransKey = hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ?
6028
- '(' + setVal(g_keyObj[`transKey${keyCtrlPtn}`], ``, C_TYP_STRING) + ')' : ``;
6128
+ `(${g_keyObj[`transKey${keyCtrlPtn}`] ?? ''})` : ``;
6029
6129
 
6030
6130
  // パターン検索
6031
6131
  const searchPattern = (_tempPtn, _sign, _transKeyUse = false, _keyCheck = `keyCtrl`) => {
@@ -6630,20 +6730,27 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6630
6730
  obj.speedData = setSpeedData(`speed`, scoreIdHeader, speedFooter);
6631
6731
 
6632
6732
  // 色変化(個別・全体)の分解 (3つで1セット, セット毎の改行区切り可)
6633
- g_typeLists.color.forEach(sprite =>
6634
- obj[`${sprite}Data`] = setColorData(sprite, scoreIdHeader));
6733
+ g_typeLists.color.forEach(sprite => {
6734
+ obj[`${sprite}Data`] = setColorData(sprite, scoreIdHeader);
6735
+ if (g_stateObj.dummyId !== ``) {
6736
+ obj[`${sprite}DummyData`] = setColorData(sprite, _dummyNo);
6737
+ }
6738
+ });
6635
6739
 
6636
6740
  if (_scoreAnalyzeFlg) {
6637
6741
  return obj;
6638
6742
  }
6639
6743
 
6640
6744
  obj.colorData = mergeColorData();
6745
+ obj.dummyColorData = mergeColorData(`Dummy`);
6641
6746
 
6642
6747
  // 矢印モーション(個別)データの分解(3~4つで1セット, セット毎の改行区切り)
6643
6748
  obj.arrowCssMotionData = setCssMotionData(`arrow`, scoreIdHeader);
6644
6749
  obj.frzCssMotionData = setCssMotionData(`frz`, scoreIdHeader);
6645
- obj.dummyArrowCssMotionData = setCssMotionData(`arrow`, _dummyNo);
6646
- obj.dummyFrzCssMotionData = setCssMotionData(`frz`, _dummyNo);
6750
+ if (g_stateObj.dummyId !== ``) {
6751
+ obj.dummyArrowCssMotionData = setCssMotionData(`arrow`, _dummyNo);
6752
+ obj.dummyFrzCssMotionData = setCssMotionData(`frz`, _dummyNo);
6753
+ }
6647
6754
 
6648
6755
  // 歌詞データの分解 (3つで1セット, セット毎の改行区切り可)
6649
6756
  obj.wordData = [];
@@ -6719,8 +6826,9 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6719
6826
  * @param {string} _header
6720
6827
  * @returns
6721
6828
  */
6722
- function mergeColorData(_header = `color`) {
6723
- const tmpArr = obj[`${_header}Data`].concat(obj[`a${_header}Data`]);
6829
+ function mergeColorData(_header = ``) {
6830
+ if (obj[`color${_header}Data`] === undefined) return [];
6831
+ const tmpArr = obj[`color${_header}Data`].concat(obj[`acolor${_header}Data`]);
6724
6832
  return tmpArr.sort((_a, _b) => _a[0] - _b[0]).flat();
6725
6833
  }
6726
6834
 
@@ -6871,7 +6979,7 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6871
6979
  break;
6872
6980
  } else {
6873
6981
  wordData[tmpWordData[k]][addFrame].push(tmpWordData[k + 1],
6874
- escapeHtmlForEnabledTag(setVal(tmpWordData[k + 2], ``, C_TYP_STRING)));
6982
+ escapeHtmlForEnabledTag(tmpWordData[k + 2] ?? ``));
6875
6983
  }
6876
6984
  }
6877
6985
  });
@@ -7312,10 +7420,11 @@ function pushArrows(_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
7312
7420
  }
7313
7421
 
7314
7422
  // 個別・全体色変化、モーションデータのタイミング更新
7315
- calcDataTiming(`color`, ``, pushColors, { _colorFlg: true });
7423
+ [``, `dummy`].forEach(type =>
7424
+ calcDataTiming(`color`, type, pushColors, { _colorFlg: true }));
7316
7425
 
7317
7426
  g_typeLists.arrow.forEach(header =>
7318
- calcDataTiming(`CssMotion`, header, pushCssMotions, { _calcFrameFlg: true }));
7427
+ calcDataTiming(`cssMotion`, header, pushCssMotions, { _calcFrameFlg: true }));
7319
7428
 
7320
7429
  /**
7321
7430
  * 色変化・モーションデータのタイミング更新
@@ -7327,7 +7436,9 @@ function pushArrows(_dataObj, _speedOnFrame, _motionOnFrame, _firstArrivalFrame)
7327
7436
  */
7328
7437
  function calcDataTiming(_type, _header, _setFunc = _ => true,
7329
7438
  { _term = 4, _colorFlg = false, _calcFrameFlg = false } = {}) {
7330
- const baseData = _dataObj[`${_header}${_type}Data`];
7439
+
7440
+ const camelHeader = _header === `` ? _type : `${_header}${toCapitalize(_type)}`;
7441
+ const baseData = _dataObj[`${camelHeader}Data`];
7331
7442
 
7332
7443
  if (!hasArrayList(baseData, _term)) {
7333
7444
  return;
@@ -7566,7 +7677,7 @@ function pushColors(_header, _frame, _val, _colorCd, _allFlg) {
7566
7677
 
7567
7678
  // フリーズアロー色の追随設定がある場合、対象を追加
7568
7679
  g_headerObj.frzScopeFromArrowColors.forEach(type => {
7569
- baseHeaders.push(`mkF${_header}Color${type}`, `mkF${_header}Color${type}Bar`);
7680
+ baseHeaders.push(`mk${_header}FColor${type}`, `mk${_header}FColor${type}Bar`);
7570
7681
  });
7571
7682
  if (g_headerObj.frzScopeFromArrowColors.length > 0) {
7572
7683
  allUseTypes.push(`Frz`);
@@ -7589,7 +7700,7 @@ function pushColors(_header, _frame, _val, _colorCd, _allFlg) {
7589
7700
  });
7590
7701
 
7591
7702
  } else {
7592
- const baseHeader = `mkF${_header}Color`;
7703
+ const baseHeader = `mk${_header}FColor`;
7593
7704
  allUseTypes.push(`Frz`);
7594
7705
 
7595
7706
  // フリーズアローの色変化
@@ -7856,6 +7967,9 @@ function MainInit() {
7856
7967
  // マスクスプライトを作成 (最上位)
7857
7968
  createMultipleSprite(`maskSprite`, g_scoreObj.maskMaxDepth);
7858
7969
 
7970
+ // カラー・モーションを適用するオブジェクトの種類
7971
+ const objList = (g_stateObj.dummyId === `` ? [``] : [`dummy`, ``]);
7972
+
7859
7973
  // 背景・マスクモーション(0フレーム指定)
7860
7974
  if (g_scoreObj.frameNum === 0) {
7861
7975
  g_animationData.forEach(sprite => {
@@ -8348,56 +8462,70 @@ function MainInit() {
8348
8462
  }
8349
8463
 
8350
8464
  /**
8351
- * 全体色変化
8352
- *
8353
- * @param _j 矢印位置
8354
- * @param _k 矢印の表示順
8355
- * @param _state フリーズアローの色変化対象 (Normal: 通常時、Hit: ヒット時)
8465
+ * 全体色変化(矢印)
8466
+ * @param {number} _j
8467
+ * @param {number} _k
8468
+ * @param {string} _name
8356
8469
  */
8357
- const changeColorFunc = {
8470
+ const changeArrowColor = (_j, _k, _name) => {
8471
+ if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`][g_scoreObj.frameNum]) {
8472
+ const colorSelf = g_workObj[`${_name}Colors`][_j];
8473
+ const colorAll = g_workObj[`${_name}ColorsAll`][_j];
8474
+ const arrowTop = document.querySelector(`#${_name}Top${_j}_${_k}`);
8358
8475
 
8359
- // TODO: この部分を矢印塗りつぶし部分についても適用できるように対応
8360
- arrow: (_j, _k) => {
8361
- const arrowTop = document.querySelector(`#arrowTop${_j}_${_k}`);
8362
- if (g_workObj.mkArrowColorChangeAll[g_scoreObj.frameNum]) {
8363
- if (arrowTop.getAttribute(`color`) !== g_workObj.arrowColors[_j] &&
8364
- g_workObj.arrowColors[_j] === g_workObj.arrowColorsAll[_j]) {
8365
- arrowTop.style.background = g_workObj.arrowColorsAll[_j];
8366
- arrowTop.setAttribute(`color`, g_workObj.arrowColorsAll[_j]);
8367
- }
8476
+ if (arrowTop.getAttribute(`color`) !== colorSelf && colorAll === colorSelf) {
8477
+ arrowTop.style.background = colorAll;
8478
+ arrowTop.setAttribute(`color`, colorAll);
8368
8479
  }
8369
- },
8370
-
8371
- dummyArrow: (_j, _k) => { },
8372
-
8373
- // TODO: この部分を矢印塗りつぶし部分についても適用できるように対応
8374
- frz: (_j, _k, _state) => {
8375
- const frzTop = document.querySelector(`#frzTop${_j}_${_k}`);
8376
- const frzBar = document.querySelector(`#frzBar${_j}_${_k}`);
8377
- const frzBtm = document.querySelector(`#frzBtm${_j}_${_k}`);
8480
+ }
8481
+ };
8378
8482
 
8379
- if (g_workObj.mkFrzColorChangeAll[g_scoreObj.frameNum]) {
8380
- if (frzBtm.getAttribute(`color`) !== g_workObj[`frz${_state}Colors`][_j]) {
8381
- const toColorCode = g_workObj[`frz${_state}ColorsAll`][_j];
8382
- if (g_workObj[`frz${_state}Colors`][_j] === toColorCode) {
8383
- if (_state === `Normal`) {
8384
- frzTop.style.background = toColorCode;
8385
- }
8386
- frzBtm.style.background = toColorCode;
8387
- frzBtm.setAttribute(`color`, toColorCode);
8483
+ /**
8484
+ * 全体色変化(フリーズアロー)
8485
+ * @param {number} _j 矢印位置
8486
+ * @param {number} _k 矢印の表示順
8487
+ * @param {string} _name 通常, ダミー
8488
+ * @param {string} _state フリーズアローの色変化対象 (Normal: 通常時、Hit: ヒット時)
8489
+ */
8490
+ const changeFrzColor = (_j, _k, _name, _state) => {
8491
+
8492
+ if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`][g_scoreObj.frameNum]) {
8493
+ const frzTop = document.querySelector(`#${_name}Top${_j}_${_k}`);
8494
+ const frzBar = document.querySelector(`#${_name}Bar${_j}_${_k}`);
8495
+ const frzBtm = document.querySelector(`#${_name}Btm${_j}_${_k}`);
8496
+ const frzName = `${_name}${_state}`;
8497
+
8498
+ // 矢印部分の色変化
8499
+ if (frzBtm.getAttribute(`color`) !== g_workObj[`${frzName}Colors`][_j]) {
8500
+ const toColorCode = g_workObj[`${frzName}ColorsAll`][_j];
8501
+ if (g_workObj[`${frzName}Colors`][_j] === toColorCode) {
8502
+ if (_state === `Normal`) {
8503
+ frzTop.style.background = toColorCode;
8388
8504
  }
8505
+ frzBtm.style.background = toColorCode;
8506
+ frzBtm.setAttribute(`color`, toColorCode);
8389
8507
  }
8390
- if (frzBar.getAttribute(`color`) !== g_workObj[`frz${_state}BarColors`][_j]) {
8391
- const toBarColorCode = g_workObj[`frz${_state}BarColorsAll`][_j];
8392
- if (g_workObj[`frz${_state}BarColors`][_j] === toBarColorCode) {
8393
- frzBar.style.background = toBarColorCode;
8394
- frzBar.setAttribute(`color`, toBarColorCode);
8395
- }
8508
+ }
8509
+ // 帯部分の色変化
8510
+ if (frzBar.getAttribute(`color`) !== g_workObj[`${frzName}BarColors`][_j]) {
8511
+ const toBarColorCode = g_workObj[`${frzName}BarColorsAll`][_j];
8512
+ if (g_workObj[`${frzName}BarColors`][_j] === toBarColorCode) {
8513
+ frzBar.style.background = toBarColorCode;
8514
+ frzBar.setAttribute(`color`, toBarColorCode);
8396
8515
  }
8397
8516
  }
8398
- },
8517
+ }
8518
+ };
8399
8519
 
8400
- dummyFrz: (_j, _k, _state) => { },
8520
+
8521
+ /**
8522
+ * 全体色変化
8523
+ */
8524
+ const changeColorFunc = {
8525
+ arrow: (_j, _k) => changeArrowColor(_j, _k, `arrow`),
8526
+ dummyArrow: (_j, _k) => changeArrowColor(_j, _k, `dummyArrow`),
8527
+ frz: (_j, _k, _state) => changeFrzColor(_j, _k, `frz`, _state),
8528
+ dummyFrz: (_j, _k, _state) => changeFrzColor(_j, _k, `dummyFrz`, _state),
8401
8529
  };
8402
8530
 
8403
8531
  /**
@@ -8870,29 +8998,30 @@ function MainInit() {
8870
8998
  boostCnts += 2;
8871
8999
  }
8872
9000
 
8873
- // 個別・全体色変化 (矢印)
8874
- changeColors(g_workObj.mkColor[currentFrame], g_workObj.mkColorCd[currentFrame]);
9001
+ objList.forEach(header => {
9002
+ const headerU = toCapitalize(header);
8875
9003
 
8876
- // 個別・全体色変化(フリーズアロー)
8877
- g_typeLists.frzColor.forEach(ctype =>
8878
- changeColors(g_workObj[`mkFColor${ctype}`][currentFrame], g_workObj[`mkFColor${ctype}Cd`][currentFrame], `frz${ctype}`));
9004
+ // 個別・全体色変化 (矢印)
9005
+ changeColors(g_workObj[`mk${headerU}Color`][currentFrame],
9006
+ g_workObj[`mk${headerU}ColorCd`][currentFrame], header, `arrow`);
8879
9007
 
8880
- // 矢印モーション
8881
- changeCssMotions(g_workObj.mkArrowCssMotion[currentFrame], g_workObj.mkArrowCssMotionName[currentFrame], `arrow`);
9008
+ // 個別・全体色変化(フリーズアロー)
9009
+ g_typeLists.frzColor.forEach(ctype =>
9010
+ changeColors(g_workObj[`mk${headerU}FColor${ctype}`][currentFrame],
9011
+ g_workObj[`mk${headerU}FColor${ctype}Cd`][currentFrame], header, `frz${ctype}`));
8882
9012
 
8883
- // フリーズアローモーション
8884
- changeCssMotions(g_workObj.mkFrzCssMotion[currentFrame], g_workObj.mkFrzCssMotionName[currentFrame], `frz`);
9013
+ // 矢印モーション
9014
+ changeCssMotions(header, `arrow`, currentFrame);
8885
9015
 
8886
- // ダミー矢印モーション
8887
- changeCssMotions(g_workObj.mkDummyArrowCssMotion[currentFrame], g_workObj.mkDummyArrowCssMotionName[currentFrame], `dummyArrow`);
9016
+ // フリーズアローモーション
9017
+ changeCssMotions(header, `frz`, currentFrame);
8888
9018
 
8889
- // ダミーフリーズアローモーション
8890
- changeCssMotions(g_workObj.mkDummyFrzCssMotion[currentFrame], g_workObj.mkDummyFrzCssMotionName[currentFrame], `dummyFrz`);
9019
+ });
8891
9020
 
8892
9021
  // ダミー矢印生成(背面に表示するため先に処理)
8893
9022
  if (g_workObj.mkDummyArrow[currentFrame] !== undefined) {
8894
9023
  g_workObj.mkDummyArrow[currentFrame].forEach(data =>
8895
- makeArrow(data, ++dummyArrowCnts[data], `dummyArrow`, C_CLR_DUMMY));
9024
+ makeArrow(data, ++dummyArrowCnts[data], `dummyArrow`, g_workObj.dummyArrowColors[data]));
8896
9025
  }
8897
9026
 
8898
9027
  // 矢印生成
@@ -8904,7 +9033,7 @@ function MainInit() {
8904
9033
  // ダミーフリーズアロー生成
8905
9034
  if (g_workObj.mkDummyFrzArrow[currentFrame] !== undefined) {
8906
9035
  g_workObj.mkDummyFrzArrow[currentFrame].forEach(data =>
8907
- makeFrzArrow(data, ++dummyFrzCnts[data], `dummyFrz`, C_CLR_DUMMY, `#888888`));
9036
+ makeFrzArrow(data, ++dummyFrzCnts[data], `dummyFrz`, g_workObj.dummyFrzNormalColors[data], g_workObj.dummyFrzNormalBarColors[data]));
8908
9037
  }
8909
9038
 
8910
9039
  // フリーズアロー生成
@@ -9123,19 +9252,21 @@ function makeCounterSymbol(_id, _x, _class, _heightPos, _text, _display = C_DIS_
9123
9252
  * 個別・全体色変化
9124
9253
  * @param {array} _mkColor
9125
9254
  * @param {array} _mkColorCd
9126
- * @param {string} _objType
9255
+ * @param {string} _header
9256
+ * @param {string} _name
9127
9257
  */
9128
- function changeColors(_mkColor, _mkColorCd, _objType = `arrow`) {
9258
+ function changeColors(_mkColor, _mkColorCd, _header, _name) {
9129
9259
 
9130
9260
  if (_mkColor === undefined) {
9131
9261
  return;
9132
9262
  }
9263
+ const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
9133
9264
  _mkColor.forEach((tempj, j) => {
9134
9265
  const targetj = tempj % 1000;
9135
- g_workObj[`${_objType}Colors`][targetj] = _mkColorCd[j];
9266
+ g_workObj[`${camelHeader}Colors`][targetj] = _mkColorCd[j];
9136
9267
  if (tempj >= 1000) {
9137
- g_workObj[`${_objType}ColorsAll`][targetj] = _mkColorCd[j];
9138
- if (_objType.indexOf(`HitBar`) !== -1 && isNaN(Number(g_workObj.arrowRtn[targetj]))) {
9268
+ g_workObj[`${camelHeader}ColorsAll`][targetj] = _mkColorCd[j];
9269
+ if (camelHeader.indexOf(`frzHitBar`) !== -1 && isNaN(Number(g_workObj.arrowRtn[targetj]))) {
9139
9270
  $id(`frzHitTop${targetj}`).background = _mkColorCd[j];
9140
9271
  }
9141
9272
  }
@@ -9144,16 +9275,20 @@ function changeColors(_mkColor, _mkColorCd, _objType = `arrow`) {
9144
9275
 
9145
9276
  /**
9146
9277
  * 個別モーション
9147
- * @param {array} _mkCssMotion
9148
- * @param {array} _mkCssMotionName
9278
+ * @param {string} _header
9149
9279
  * @param {string} _name
9280
+ * @param {number} _frameNum
9150
9281
  */
9151
- function changeCssMotions(_mkCssMotion, _mkCssMotionName, _name) {
9282
+ function changeCssMotions(_header, _name, _frameNum) {
9283
+
9284
+ const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
9285
+ const frameData = g_workObj[`mk${toCapitalize(camelHeader)}CssMotion`][_frameNum];
9152
9286
 
9153
- if (_mkCssMotion !== undefined) {
9154
- for (let j = 0; j < _mkCssMotion.length; j++) {
9155
- const targetj = _mkCssMotion[j];
9156
- g_workObj[`${_name}CssMotions`][targetj] = _mkCssMotionName[2 * j + g_workObj.dividePos[targetj]];
9287
+ if (frameData !== undefined) {
9288
+ for (let j = 0; j < frameData.length; j++) {
9289
+ const targetj = frameData[j];
9290
+ g_workObj[`${camelHeader}CssMotions`][targetj] =
9291
+ g_workObj[`mk${toCapitalize(camelHeader)}CssMotionName`][_frameNum][2 * j + g_workObj.dividePos[targetj]];
9157
9292
  }
9158
9293
  }
9159
9294
  }
@@ -9601,8 +9736,16 @@ function resultInit() {
9601
9736
  // diffListから適正Adjを算出(20個以下の場合は算出しない)
9602
9737
  const getSign = _val => (_val > 0 ? `+` : ``);
9603
9738
  const getDiffFrame = _val => `${getSign(_val)}${_val}${g_lblNameObj.frame}`;
9604
- const estimatedAdj = (g_workObj.diffList.length <= 20 ?
9605
- `` : Math.round((g_stateObj.adjustment - g_workObj.diffList.reduce((x, y) => x + y, 0) / g_workObj.diffList.length) * 10) / 10);
9739
+ const diffLength = g_workObj.diffList.length;
9740
+ const bayesFunc = (_offset, _length) => {
9741
+ let result = 0;
9742
+ for (let j = _offset; j < _length; j++) {
9743
+ result += (_length - j) * (j + 1) * g_workObj.diffList[j];
9744
+ }
9745
+ return result;
9746
+ };
9747
+ const bayesExVal = 6 * bayesFunc(0, diffLength) / (diffLength * (diffLength + 1) * (diffLength + 2));
9748
+ const estimatedAdj = (diffLength <= 20 ? `` : Math.round((g_stateObj.adjustment - bayesExVal) * 10) / 10);
9606
9749
 
9607
9750
  // 背景スプライトを作成
9608
9751
  createMultipleSprite(`backResultSprite`, g_headerObj.backResultMaxDepth);
@@ -9922,9 +10065,9 @@ function resultInit() {
9922
10065
  .split(`[maxCombo]`).join(tweetMaxCombo)
9923
10066
  .split(`[url]`).join(`${twiturl.toString()}`.replace(/[\t\n]/g, ``));
9924
10067
 
9925
- if (typeof g_presetResultVals === C_TYP_OBJECT) {
9926
- Object.keys(g_presetResultVals).forEach(key => {
9927
- tweetResultTmp = tweetResultTmp.split(`[${key}]`).join(g_resultObj[g_presetResultVals[key]]);
10068
+ if (g_presetObj.resultVals !== undefined) {
10069
+ Object.keys(g_presetObj.resultVals).forEach(key => {
10070
+ tweetResultTmp = tweetResultTmp.split(`[${key}]`).join(g_resultObj[g_presetObj.resultVals[key]]);
9928
10071
  });
9929
10072
  }
9930
10073
  const resultText = `${unEscapeHtml(tweetResultTmp)}`;