danoniplus 26.1.2 → 26.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2022/02/16
7
+ * Revised : 2022/02/25
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 26.1.2`;
12
- const g_revisedDate = `2022/02/16`;
11
+ const g_version = `Ver 26.4.0`;
12
+ const g_revisedDate = `2022/02/25`;
13
13
  const g_alphaVersion = ``;
14
14
 
15
15
  // カスタム用バージョン (danoni_custom.js 等で指定可)
@@ -48,20 +48,17 @@ const current = _ => {
48
48
  };
49
49
  const g_rootPath = current().match(/(^.*\/)/)[0];
50
50
  const g_remoteFlg = g_rootPath.match(`^https://cwtickle.github.io/danoniplus/`) !== null;
51
+ const g_randTime = Date.now();
51
52
 
52
- window.onload = _ => {
53
+ window.onload = async () => {
53
54
  g_loadObj.main = true;
54
55
  g_currentPage = `initial`;
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?${g_randTime}`, false);
59
+ await loadScript2(`${g_rootPath}../js/lib/danoni_constants.js?${g_randTime}`);
60
+ await loadScript2(`${g_rootPath}../js/lib/danoni_legacy_function.js?${g_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 = {};
@@ -241,11 +239,11 @@ const hasArrayList = (_data, _length = 1) => _data !== undefined && _data.length
241
239
  /**
242
240
  * 重複を排除した配列の生成
243
241
  * @param {array} _array1
244
- * @param {array} _array2
242
+ * @param {...any} _arrays
245
243
  * @returns
246
244
  */
247
- const makeDedupliArray = (_array1, _array2) =>
248
- Array.from((new Set([..._array1, ..._array2])).values());
245
+ const makeDedupliArray = (_array1, ..._arrays) =>
246
+ Array.from((new Set([..._array1, ..._arrays.flat()])).values());
249
247
 
250
248
  /**
251
249
  * 部分一致検索(リストのいずれかに合致、大小文字問わず)
@@ -524,8 +522,9 @@ function preloadFile(_as, _href, _type = ``, _crossOrigin = `anonymous`) {
524
522
  }
525
523
 
526
524
  /**
527
- * CSSファイルの読み込み(danoni_main.css以外)
525
+ * CSSファイルの読み込み (callback)
528
526
  * デフォルトは danoni_skin_default.css を読み込む
527
+ * @deprecated v27以降非推奨予定
529
528
  * @param {url} _href
530
529
  * @param {function} _func
531
530
  */
@@ -546,6 +545,31 @@ function importCssFile(_href, _func) {
546
545
  document.head.appendChild(link);
547
546
  }
548
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
+
549
573
  /**
550
574
  * 画面共通のフォント設定
551
575
  * @param {string} _priorityFont
@@ -720,7 +744,7 @@ function createColorObject2(_id,
720
744
  style.webkitMaskImage = `url("${g_imgObj[charaStyle]}")`;
721
745
  style.webkitMaskSize = `contain`;
722
746
  Object.keys(rest).forEach(property => style[property] = rest[property]);
723
- setAttrs(div, { color: rest.background || ``, type: charaStyle, cnt: 0, });
747
+ setAttrs(div, { color: rest.background ?? ``, type: charaStyle, cnt: 0, });
724
748
 
725
749
  return div;
726
750
  }
@@ -810,7 +834,7 @@ function createCss2Button(_id, _text, _func = _ => true, { x = 0, y = g_sHeight
810
834
  if (g_initialFlg && g_btnWaitFrame[groupName].initial) {
811
835
  } else {
812
836
  style.pointerEvents = C_DIS_NONE;
813
- setTimeout(_ => style.pointerEvents = setVal(rest.pointerEvents, `auto`, C_TYP_STRING),
837
+ setTimeout(_ => style.pointerEvents = rest.pointerEvents ?? `auto`,
814
838
  g_btnWaitFrame[groupName].b_frame * 1000 / g_fps);
815
839
  }
816
840
  }
@@ -952,8 +976,9 @@ function clearWindow(_redrawFlg = false, _customDisplayName = ``) {
952
976
  }
953
977
 
954
978
  /**
955
- * 外部jsファイルの読込
979
+ * 外部jsファイルの読込 (callback)
956
980
  * 読込可否を g_loadObj[ファイル名] で管理 (true: 読込成功, false: 読込失敗)
981
+ * @deprecated v27以降非推奨予定
957
982
  * @param {string} _url
958
983
  * @param {function} _callback
959
984
  * @param {boolean} _requiredFlg (default : true / 読込必須)
@@ -980,10 +1005,42 @@ function loadScript(_url, _callback, _requiredFlg = true, _charset = `UTF-8`) {
980
1005
  document.querySelector(`head`).appendChild(script);
981
1006
  }
982
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
+
983
1040
  // WebAudioAPIでAudio要素風に再生するクラス
984
1041
  class AudioPlayer {
985
1042
  constructor() {
986
- const AudioContext = window.AudioContext || window.webkitAudioContext;
1043
+ const AudioContext = window.AudioContext ?? window.webkitAudioContext;
987
1044
  this._context = new AudioContext();
988
1045
  this._gain = this._context.createGain();
989
1046
  this._gain.connect(this._context.destination);
@@ -1155,12 +1212,12 @@ function makeSpriteData(_data, _calcFrame = _frame => _frame) {
1155
1212
  }
1156
1213
 
1157
1214
  const tmpObj = {
1158
- path: escapeHtml(setVal(tmpSpriteData[2], ``, C_TYP_STRING), g_escapeStr.escapeCode), // 画像パス or テキスト
1159
- class: escapeHtml(setVal(tmpSpriteData[3], ``, C_TYP_STRING)), // CSSクラス
1215
+ path: escapeHtml(tmpSpriteData[2] ?? ``, g_escapeStr.escapeCode), // 画像パス or テキスト
1216
+ class: escapeHtml(tmpSpriteData[3] ?? ``), // CSSクラス
1160
1217
  left: setVal(tmpSpriteData[4], 0, C_TYP_CALC), // X座標
1161
1218
  top: setVal(tmpSpriteData[5], 0, C_TYP_CALC), // Y座標
1162
1219
  width: setVal(tmpSpriteData[6], 0, C_TYP_NUMBER), // spanタグの場合は font-size
1163
- height: escapeHtml(setVal(tmpSpriteData[7], ``, C_TYP_STRING)), // spanタグの場合は color(文字列可)
1220
+ height: escapeHtml(tmpSpriteData[7] ?? ``), // spanタグの場合は color(文字列可)
1164
1221
  opacity: setVal(tmpSpriteData[8], 1, C_TYP_FLOAT),
1165
1222
  animationName: escapeHtml(setVal(tmpSpriteData[9], C_DIS_NONE, C_TYP_STRING)),
1166
1223
  animationDuration: setVal(tmpSpriteData[10], 0, C_TYP_NUMBER) / g_fps,
@@ -1246,7 +1303,7 @@ const transTimerToFrame = _str => {
1246
1303
  /* Scene : TITLE [melon] */
1247
1304
  /*-----------------------------------------------------------*/
1248
1305
 
1249
- function initialControl() {
1306
+ async function initialControl() {
1250
1307
 
1251
1308
  [g_sWidth, g_sHeight] = [
1252
1309
  setVal($id(`canvas-frame`).width, 600, C_TYP_FLOAT), setVal($id(`canvas-frame`).height, 500, C_TYP_FLOAT)
@@ -1288,8 +1345,126 @@ function initialControl() {
1288
1345
  // 作品別ローカルストレージの読み込み
1289
1346
  loadLocalStorage();
1290
1347
 
1291
- // 譜面データの読み込み
1292
- loadDos(_ => loadSettingJs(), 0);
1348
+ // 譜面データの読み込み(1ファイル目)
1349
+ await loadChartFile(0);
1350
+
1351
+ // 共通設定ファイルの指定
1352
+ let [settingType, settingRoot] = getFilePath(g_rootObj.settingType ?? ``, C_DIR_JS);
1353
+ if (settingType !== ``) {
1354
+ settingType = `_${settingType}`;
1355
+ }
1356
+
1357
+ // 共通設定ファイルの読込
1358
+ await loadScript2(`${settingRoot}danoni_setting${settingType}.js?${g_randTime}`, false);
1359
+ loadLegacySettingFunc();
1360
+ if (document.querySelector(`#lblLoading`) !== null) {
1361
+ divRoot.removeChild(document.querySelector(`#lblLoading`));
1362
+ }
1363
+
1364
+ // クエリで譜面番号が指定されていればセット
1365
+ g_stateObj.scoreId = setVal(getQueryParamVal(`scoreId`), 0, C_TYP_NUMBER);
1366
+
1367
+ // 譜面ヘッダーの読込
1368
+ Object.assign(g_headerObj, preheaderConvert(g_rootObj));
1369
+
1370
+ // CSSファイル内のbackgroundを取得するために再描画
1371
+ if (document.querySelector(`#layer0`) === null) {
1372
+ divRoot.removeChild(document.querySelector(`#divBack`));
1373
+ createEmptySprite(divRoot, `divBack`);
1374
+ } else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
1375
+ createEmptySprite(divRoot, `divBack`);
1376
+ }
1377
+
1378
+ // CSSファイルの読み込み
1379
+ const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
1380
+ await loadMultipleFiles2(skinList, `css`);
1381
+
1382
+ // JSファイルの読み込み
1383
+ await loadMultipleFiles2(g_headerObj.jsData, `js`);
1384
+ loadLegacyCustomFunc();
1385
+
1386
+ // 譜面ヘッダー、特殊キー情報の読込
1387
+ Object.assign(g_headerObj, headerConvert(g_rootObj));
1388
+ if (g_presetObj.keysData !== undefined) {
1389
+ keysConvert(dosConvert(g_presetObj.keysData));
1390
+ g_headerObj.undefinedKeyLists = g_headerObj.undefinedKeyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
1391
+ }
1392
+ g_headerObj.keyExtraList = keysConvert(g_rootObj, {
1393
+ keyExtraList: (g_rootObj.keyExtraList !== undefined ?
1394
+ makeDedupliArray(g_rootObj.keyExtraList.split(`,`), g_headerObj.undefinedKeyLists) : g_headerObj.undefinedKeyLists),
1395
+ });
1396
+
1397
+ // キー数情報を初期化
1398
+ g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
1399
+ g_keyObj.currentPtn = 0;
1400
+
1401
+ // 画像ファイルの読み込み
1402
+ g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
1403
+
1404
+ // その他の画像ファイルの読み込み
1405
+ g_headerObj.preloadImages.filter(image => hasVal(image)).forEach(preloadImage => {
1406
+
1407
+ // Pattern A: |preloadImages=file.png|
1408
+ // Pattern B: |preloadImages=file*.png@10| -> file01.png ~ file10.png
1409
+ // Pattern C: |preloadImages=file*.png@2-9| -> file2.png ~ file9.png
1410
+ // Pattern D: |preloadImages=file*.png@003-018| -> file003.png ~ file018.png
1411
+
1412
+ const tmpPreloadImages = preloadImage.split(`@`);
1413
+ if (tmpPreloadImages.length === 1) {
1414
+ // Pattern Aの場合
1415
+ preloadFile(`image`, preloadImage);
1416
+ } else {
1417
+ const termRoopCnts = tmpPreloadImages[1].split(`-`);
1418
+ let startCnt = 1;
1419
+ let lastCnt;
1420
+ let paddingLen;
1421
+
1422
+ if (termRoopCnts.length === 1) {
1423
+ // Pattern Bの場合
1424
+ lastCnt = setVal(tmpPreloadImages[1], 1, C_TYP_NUMBER);
1425
+ paddingLen = String(setVal(tmpPreloadImages[1], 1, C_TYP_STRING)).length;
1426
+ } else {
1427
+ // Pattern C, Dの場合
1428
+ startCnt = setVal(termRoopCnts[0], 1, C_TYP_NUMBER);
1429
+ lastCnt = setVal(termRoopCnts[1], 1, C_TYP_NUMBER);
1430
+ paddingLen = String(setVal(termRoopCnts[1], 1, C_TYP_STRING)).length;
1431
+ }
1432
+ for (let k = startCnt; k <= lastCnt; k++) {
1433
+ preloadFile(`image`, tmpPreloadImages[0].replace(/\*/g, String(k).padStart(paddingLen, `0`)));
1434
+ }
1435
+ }
1436
+ });
1437
+
1438
+ // ローカルファイル起動時に各種警告文を表示
1439
+ if (g_isFile) {
1440
+ makeWarningWindow(g_msgInfoObj.W_0011);
1441
+ if (!listMatching(getMusicUrl(g_stateObj.scoreId), [`.js`, `.txt`], { suffix: `$` })) {
1442
+ if (g_userAgent.indexOf(`firefox`) !== -1) {
1443
+ makeWarningWindow(g_msgInfoObj.W_0001);
1444
+ }
1445
+ makeWarningWindow(g_msgInfoObj.W_0012);
1446
+ }
1447
+ }
1448
+
1449
+ getScoreDetailData(0);
1450
+
1451
+ if (g_loadObj.main) {
1452
+
1453
+ // 譜面分割、譜面番号固定かどうかをチェック
1454
+ g_stateObj.dosDivideFlg = setVal(document.querySelector(`#externalDosDivide`)?.value ?? getQueryParamVal(`dosDivide`), false, C_TYP_BOOLEAN);
1455
+ g_stateObj.scoreLockFlg = setVal(document.querySelector(`#externalDosLock`)?.value ?? getQueryParamVal(`dosLock`), false, C_TYP_BOOLEAN);
1456
+
1457
+ for (let j = 1; j < g_headerObj.keyLabels.length; j++) {
1458
+
1459
+ // 譜面ファイルが分割されている場合、譜面詳細情報取得のために譜面をロード
1460
+ if (g_stateObj.dosDivideFlg) {
1461
+ await loadChartFile(j);
1462
+ resetColorAndGauge(j);
1463
+ }
1464
+ getScoreDetailData(j);
1465
+ }
1466
+ }
1467
+ titleInit();
1293
1468
  }
1294
1469
 
1295
1470
  /**
@@ -1324,7 +1499,7 @@ function loadLocalStorage() {
1324
1499
  g_localeObj.val = g_langStorage.locale;
1325
1500
  g_localeObj.num = g_localeObj.list.findIndex(val => val === g_localeObj.val);
1326
1501
  }
1327
- Object.keys(g_lang_msgInfoObj[g_localeObj.val]).forEach(property => g_msgInfoObj[property] = g_lang_msgInfoObj[g_localeObj.val][property]);
1502
+ Object.assign(g_msgInfoObj, g_lang_msgInfoObj[g_localeObj.val]);
1328
1503
 
1329
1504
  // 作品別ローカルストレージの読込
1330
1505
  const checkStorage = localStorage.getItem(g_localStorageUrl);
@@ -1353,30 +1528,21 @@ function loadLocalStorage() {
1353
1528
 
1354
1529
  /**
1355
1530
  * 譜面読込
1356
- * @param {function} _afterFunc 実行後の処理
1357
1531
  * @param {number} _scoreId 譜面番号
1358
- * @param {boolean} _cyclicFlg 再読込フラグ(譜面詳細情報取得用、再帰的にloadDosを呼び出す)
1359
1532
  */
1360
- function loadDos(_afterFunc, _scoreId = g_stateObj.scoreId, _cyclicFlg = false) {
1533
+ async function loadChartFile(_scoreId = g_stateObj.scoreId) {
1361
1534
 
1362
1535
  const dosInput = document.querySelector(`#dos`);
1363
- const externalDosInput = document.querySelector(`#externalDos`);
1364
1536
  const divRoot = document.querySelector(`#divRoot`);
1365
- const queryDos = getQueryParamVal(`dos`) !== null ? `dos/${getQueryParamVal('dos')}.txt` :
1366
- (externalDosInput !== null ? externalDosInput.value : ``);
1537
+ const queryDos = getQueryParamVal(`dos`) !== null ? `dos/${getQueryParamVal('dos')}.txt` : (document.querySelector(`#externalDos`)?.value ?? ``);
1367
1538
 
1368
1539
  if (dosInput === null && queryDos === ``) {
1369
1540
  makeWarningWindow(g_msgInfoObj.E_0023);
1370
1541
  g_loadObj.main = false;
1371
- _afterFunc();
1372
1542
  return;
1373
1543
  }
1374
1544
 
1375
1545
  // 譜面分割あり、譜面番号固定時のみ譜面データを一時クリア
1376
- const dosDivideInput = document.querySelector(`#externalDosDivide`);
1377
- const dosLockInput = document.querySelector(`#externalDosLock`);
1378
- g_stateObj.dosDivideFlg = setVal(dosDivideInput !== null ? dosDivideInput.value : getQueryParamVal(`dosDivide`), false, C_TYP_BOOLEAN);
1379
- g_stateObj.scoreLockFlg = setVal(dosLockInput !== null ? dosLockInput.value : getQueryParamVal(`dosLock`), false, C_TYP_BOOLEAN);
1380
1546
  if (queryDos !== `` && g_stateObj.dosDivideFlg && g_stateObj.scoreLockFlg) {
1381
1547
  const scoreList = Object.keys(g_rootObj).filter(data => {
1382
1548
  return fuzzyListMatching(data, g_checkStr.resetDosHeader, g_checkStr.resetDosFooter);
@@ -1385,78 +1551,50 @@ function loadDos(_afterFunc, _scoreId = g_stateObj.scoreId, _cyclicFlg = false)
1385
1551
  }
1386
1552
 
1387
1553
  // HTML埋め込みdos
1388
- if (dosInput !== null) {
1554
+ if (dosInput !== null && _scoreId === 0) {
1389
1555
  Object.assign(g_rootObj, dosConvert(dosInput.value));
1390
- if (queryDos === ``) {
1391
- _afterFunc();
1392
- if (_cyclicFlg) {
1393
- reloadDos(_scoreId);
1394
- }
1395
- }
1396
1556
  }
1397
1557
 
1398
1558
  // 外部dos読み込み
1399
1559
  if (queryDos !== ``) {
1400
- let charset = document.characterSet;
1401
- const charsetInput = document.querySelector(`#externalDosCharset`);
1402
- if (charsetInput !== null) {
1403
- charset = charsetInput.value;
1404
- }
1405
- const filenameBase = queryDos.match(/.+\..*/)[0];
1406
- const filenameExtension = filenameBase.split(`.`).pop();
1407
- const filenameCommon = filenameBase.split(`.${filenameExtension}`)[0];
1408
- const filename = (!g_stateObj.dosDivideFlg ?
1409
- `${filenameCommon}.${filenameExtension}` :
1410
- `${filenameCommon}${setScoreIdHeader(_scoreId)}.${filenameExtension}`);
1411
-
1412
- const randTime = new Date().getTime();
1413
- loadScript(`${filename}?${randTime}`, _ => {
1414
- if (typeof externalDosInit === C_TYP_FUNCTION) {
1415
- if (document.querySelector(`#lblLoading`) !== null) {
1416
- divRoot.removeChild(document.querySelector(`#lblLoading`));
1417
- }
1418
-
1419
- // 外部データを読込(ファイルが見つからなかった場合は譜面追記をスキップ)
1420
- externalDosInit();
1421
- if (g_loadObj[filename]) {
1422
- Object.assign(g_rootObj, dosConvert(g_externalDos));
1423
- }
1560
+ const charset = document.querySelector(`#externalDosCharset`)?.value ?? document.characterSet;
1561
+ const fileBase = queryDos.match(/.+\..*/)[0];
1562
+ const fileExtension = fileBase.split(`.`).pop();
1563
+ const fileCommon = fileBase.split(`.${fileExtension}`)[0];
1564
+ const filename = `${fileCommon}${g_stateObj.dosDivideFlg ? setScoreIdHeader(_scoreId) : ''}.${fileExtension}`;
1424
1565
 
1425
- } else {
1426
- makeWarningWindow(g_msgInfoObj.E_0022);
1427
- }
1428
- _afterFunc();
1429
- if (_cyclicFlg) {
1430
- if (g_stateObj.dosDivideFlg && _scoreId > 0) {
1431
- // 初期矢印・フリーズアロー色の再定義
1432
- if (g_stateObj.scoreLockFlg) {
1433
- Object.assign(g_rootObj, copySetColor(g_rootObj, _scoreId));
1434
- }
1435
- Object.assign(g_headerObj, resetBaseColorList(g_headerObj, g_rootObj, { scoreId: _scoreId }));
1566
+ await loadScript2(`${filename}?${Date.now()}`, false, charset);
1567
+ if (typeof externalDosInit === C_TYP_FUNCTION) {
1568
+ if (document.querySelector(`#lblLoading`) !== null) {
1569
+ divRoot.removeChild(document.querySelector(`#lblLoading`));
1570
+ }
1436
1571
 
1437
- // ライフ設定のカスタム部分再取得(譜面ヘッダー加味)
1438
- Object.assign(g_gaugeOptionObj, resetCustomGauge(g_rootObj, { scoreId: _scoreId }));
1439
- Object.keys(g_gaugeOptionObj.customFulls).forEach(gaugePtn => getGaugeSetting(g_rootObj, gaugePtn, g_headerObj.difLabels.length, { scoreId: _scoreId }));
1440
- }
1441
- reloadDos(_scoreId);
1572
+ // 外部データを読込(ファイルが見つからなかった場合は譜面追記をスキップ)
1573
+ externalDosInit();
1574
+ if (g_loadObj[filename]) {
1575
+ Object.assign(g_rootObj, dosConvert(g_externalDos));
1442
1576
  }
1443
- }, false, charset);
1577
+
1578
+ } else {
1579
+ makeWarningWindow(g_msgInfoObj.E_0022);
1580
+ }
1444
1581
  }
1445
1582
  }
1446
1583
 
1447
1584
  /**
1448
- * 譜面情報の再取得を行う(譜面詳細情報取得用)
1449
- * @param {number} _scoreId
1585
+ * 譜面をファイルで分割している場合に初期色やゲージ情報を追加取得
1586
+ * @param {string} _scoreId
1450
1587
  */
1451
- function reloadDos(_scoreId) {
1452
- _scoreId++;
1453
- if (g_headerObj.keyLabels !== undefined && _scoreId < g_headerObj.keyLabels.length) {
1454
- loadDos(_ => {
1455
- getScoreDetailData(_scoreId);
1456
- }, _scoreId, true);
1457
- } else {
1458
- titleInit();
1588
+ function resetColorAndGauge(_scoreId) {
1589
+ // 初期矢印・フリーズアロー色の再定義
1590
+ if (g_stateObj.scoreLockFlg) {
1591
+ Object.assign(g_rootObj, copySetColor(g_rootObj, _scoreId));
1459
1592
  }
1593
+ Object.assign(g_headerObj, resetBaseColorList(g_headerObj, g_rootObj, { scoreId: _scoreId }));
1594
+
1595
+ // ライフ設定のカスタム部分再取得(譜面ヘッダー加味)
1596
+ Object.assign(g_gaugeOptionObj, resetCustomGauge(g_rootObj, { scoreId: _scoreId }));
1597
+ Object.keys(g_gaugeOptionObj.customFulls).forEach(gaugePtn => getGaugeSetting(g_rootObj, gaugePtn, g_headerObj.difLabels.length, { scoreId: _scoreId }));
1460
1598
  }
1461
1599
 
1462
1600
  /**
@@ -1478,103 +1616,6 @@ function copySetColor(_baseObj, _scoreId) {
1478
1616
  return obj;
1479
1617
  }
1480
1618
 
1481
- /**
1482
- * 初回読込後に画像プリロードを設定する処理
1483
- */
1484
- function initAfterDosLoaded() {
1485
-
1486
- // クエリで譜面番号が指定されていればセット
1487
- g_stateObj.scoreId = setVal(getQueryParamVal(`scoreId`), 0, C_TYP_NUMBER);
1488
-
1489
- // 譜面ヘッダーの読込
1490
- Object.assign(g_headerObj, preheaderConvert(g_rootObj));
1491
-
1492
- // CSSファイル内のbackgroundを取得するために再描画
1493
- if (document.querySelector(`#layer0`) === null) {
1494
- divRoot.removeChild(document.querySelector(`#divBack`));
1495
- createEmptySprite(divRoot, `divBack`);
1496
- } else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
1497
- createEmptySprite(divRoot, `divBack`);
1498
- }
1499
-
1500
- // CSSファイルの読み込み
1501
- const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
1502
- loadMultipleFiles(0, skinList, `css`, _ => initAfterCssLoaded());
1503
-
1504
- /**
1505
- * スキンCSSファイルを読み込んだ後の処理
1506
- */
1507
- function initAfterCssLoaded() {
1508
-
1509
- // 譜面ヘッダー、特殊キー情報の読込
1510
- Object.assign(g_headerObj, headerConvert(g_rootObj));
1511
- keysConvert(g_rootObj);
1512
-
1513
- // キー数情報を初期化
1514
- g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
1515
- g_keyObj.currentPtn = 0;
1516
-
1517
- // 画像ファイルの読み込み
1518
- g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
1519
-
1520
- // その他の画像ファイルの読み込み
1521
- g_headerObj.preloadImages.filter(image => hasVal(image)).forEach(preloadImage => {
1522
-
1523
- // Pattern A: |preloadImages=file.png|
1524
- // Pattern B: |preloadImages=file*.png@10| -> file01.png ~ file10.png
1525
- // Pattern C: |preloadImages=file*.png@2-9| -> file2.png ~ file9.png
1526
- // Pattern D: |preloadImages=file*.png@003-018| -> file003.png ~ file018.png
1527
-
1528
- const tmpPreloadImages = preloadImage.split(`@`);
1529
- if (tmpPreloadImages.length === 1) {
1530
- // Pattern Aの場合
1531
- preloadFile(`image`, preloadImage);
1532
- } else {
1533
- const termRoopCnts = tmpPreloadImages[1].split(`-`);
1534
- let startCnt = 1;
1535
- let lastCnt;
1536
- let paddingLen;
1537
-
1538
- if (termRoopCnts.length === 1) {
1539
- // Pattern Bの場合
1540
- lastCnt = setVal(tmpPreloadImages[1], 1, C_TYP_NUMBER);
1541
- paddingLen = String(setVal(tmpPreloadImages[1], 1, C_TYP_STRING)).length;
1542
- } else {
1543
- // Pattern C, Dの場合
1544
- startCnt = setVal(termRoopCnts[0], 1, C_TYP_NUMBER);
1545
- lastCnt = setVal(termRoopCnts[1], 1, C_TYP_NUMBER);
1546
- paddingLen = String(setVal(termRoopCnts[1], 1, C_TYP_STRING)).length;
1547
- }
1548
- for (let k = startCnt; k <= lastCnt; k++) {
1549
- preloadFile(`image`, tmpPreloadImages[0].replace(/\*/g, String(k).padStart(paddingLen, `0`)));
1550
- }
1551
- }
1552
- });
1553
-
1554
- // ローカルファイル起動時に各種警告文を表示
1555
- if (g_isFile) {
1556
- makeWarningWindow(g_msgInfoObj.W_0011);
1557
- if (!listMatching(getMusicUrl(g_stateObj.scoreId), [`.js`, `.txt`], { suffix: `$` })) {
1558
- if (g_userAgent.indexOf(`firefox`) !== -1) {
1559
- makeWarningWindow(g_msgInfoObj.W_0001);
1560
- }
1561
- makeWarningWindow(g_msgInfoObj.W_0012);
1562
- }
1563
- }
1564
-
1565
- if (g_loadObj.main) {
1566
- // customjsの読み込み後、譜面詳細情報取得のために譜面をロード
1567
- loadMultipleFiles(0, g_headerObj.jsData, `js`, _ => {
1568
- loadLegacyCustomFunc();
1569
- loadDos(_ => getScoreDetailData(0), 0, true);
1570
- });
1571
- } else {
1572
- getScoreDetailData(0);
1573
- reloadDos(0);
1574
- }
1575
- }
1576
- }
1577
-
1578
1619
  /**
1579
1620
  * MusicUrlの基本情報を取得
1580
1621
  * @param {number} _scoreId
@@ -1582,7 +1623,7 @@ function initAfterDosLoaded() {
1582
1623
  */
1583
1624
  function getMusicUrl(_scoreId) {
1584
1625
  return g_headerObj.musicUrls !== undefined ?
1585
- g_headerObj.musicUrls[g_headerObj.musicNos[_scoreId]] ||
1626
+ g_headerObj.musicUrls[g_headerObj.musicNos[_scoreId]] ??
1586
1627
  g_headerObj.musicUrls[0] : `nosound.mp3`;
1587
1628
  }
1588
1629
 
@@ -1854,7 +1895,8 @@ function calcLevel(_scoreObj) {
1854
1895
  }
1855
1896
 
1856
1897
  /**
1857
- * jsファイルの連続読込
1898
+ * js, cssファイルの連続読込 (callback)
1899
+ * @deprecated v27以降非推奨予定
1858
1900
  * @param {number} _j
1859
1901
  * @param {array} _fileData
1860
1902
  * @param {string} _loadType
@@ -1881,6 +1923,28 @@ function loadMultipleFiles(_j, _fileData, _loadType, _afterFunc = _ => true) {
1881
1923
  }
1882
1924
  }
1883
1925
 
1926
+ /**
1927
+ * js, cssファイルの連続読込 (async function)
1928
+ * @param {array} _fileData
1929
+ * @param {string} _loadType
1930
+ */
1931
+ async function loadMultipleFiles2(_fileData, _loadType) {
1932
+ await Promise.all(_fileData.map(async filePart => {
1933
+ const filePath = `${filePart[1]}${filePart[0]}?${g_randTime}`;
1934
+ if (filePart[0].endsWith(`.css`)) {
1935
+ _loadType = `css`;
1936
+ }
1937
+
1938
+ // jsファイル、cssファイルにより呼び出す関数を切替
1939
+ if (_loadType === `js`) {
1940
+ await loadScript2(filePath, false);
1941
+ } else if (_loadType === `css`) {
1942
+ const cssPath = filePath.split(`.js`).join(`.css`);
1943
+ await importCssFile2(cssPath);
1944
+ }
1945
+ }));
1946
+ }
1947
+
1884
1948
  /**
1885
1949
  * 入力されたパスを、ディレクトリとそれ以外に分割
1886
1950
  * 返却値:[ファイルキーワード, ルートディレクトリ]
@@ -1909,26 +1973,6 @@ const getFilePath = (_fileName, _directory = ``) => {
1909
1973
  }
1910
1974
  };
1911
1975
 
1912
- /**
1913
- * danoni_setting.jsの読込
1914
- */
1915
- function loadSettingJs() {
1916
-
1917
- // 共通設定ファイルの指定
1918
- let [settingType, settingRoot] = getFilePath(g_rootObj.settingType || ``, C_DIR_JS);
1919
- if (settingType !== ``) {
1920
- settingType = `_${settingType}`;
1921
- }
1922
-
1923
- const randTime = new Date().getTime();
1924
- loadScript(`${settingRoot}danoni_setting${settingType}.js?${randTime}`, _ => {
1925
- if (document.querySelector(`#lblLoading`) !== null) {
1926
- divRoot.removeChild(document.querySelector(`#lblLoading`));
1927
- }
1928
- initAfterDosLoaded();
1929
- }, false);
1930
- }
1931
-
1932
1976
  function loadMusic() {
1933
1977
 
1934
1978
  clearWindow(true);
@@ -2028,7 +2072,7 @@ function makePlayButton(_func) {
2028
2072
  * iOSの場合はAudioタグによる再生
2029
2073
  * @param {string} _url
2030
2074
  */
2031
- function setAudio(_url) {
2075
+ async function setAudio(_url) {
2032
2076
 
2033
2077
  const loadMp3 = _ => {
2034
2078
  if (g_isFile) {
@@ -2056,16 +2100,14 @@ function setAudio(_url) {
2056
2100
  };
2057
2101
 
2058
2102
  if (g_musicEncodedFlg) {
2059
- loadScript(_url, _ => {
2060
- if (typeof musicInit === C_TYP_FUNCTION) {
2061
- musicInit();
2062
- readyToStart(_ => initWebAudioAPIfromBase64(g_musicdata));
2063
- } else {
2064
- makeWarningWindow(g_msgInfoObj.E_0031);
2065
- musicAfterLoaded();
2066
- }
2067
- });
2068
-
2103
+ await loadScript2(_url);
2104
+ if (typeof musicInit === C_TYP_FUNCTION) {
2105
+ musicInit();
2106
+ readyToStart(_ => initWebAudioAPIfromBase64(g_musicdata));
2107
+ } else {
2108
+ makeWarningWindow(g_msgInfoObj.E_0031);
2109
+ musicAfterLoaded();
2110
+ }
2069
2111
  } else {
2070
2112
  readyToStart(_ => loadMp3());
2071
2113
  }
@@ -2328,7 +2370,7 @@ const createScText = (_obj, _settingLabel, { displayName = `option`, dfLabel = `
2328
2370
  if (scKey.length > 0) {
2329
2371
  multiAppend(_obj,
2330
2372
  createDivCss2Label(`sc${_settingLabel}`,
2331
- g_scViewObj.format.split(`{0}`).join(dfLabel !== `` ? `${dfLabel}` : `${setVal(g_kCd[g_kCdN.findIndex(kCd => kCd === scKey[0])], ``, C_TYP_STRING)}`), {
2373
+ g_scViewObj.format.split(`{0}`).join(dfLabel !== `` ? `${dfLabel}` : `${g_kCd[g_kCdN.findIndex(kCd => kCd === scKey[0])] ?? ''}`), {
2332
2374
  x, y, w, siz, fontWeight: `bold`, opacity: 0.75, pointerEvents: C_DIS_NONE,
2333
2375
  })
2334
2376
  );
@@ -2344,8 +2386,8 @@ const createScTextCommon = _displayName => {
2344
2386
  .forEach(target =>
2345
2387
  createScText(document.getElementById(`btn${target}`), target, {
2346
2388
  displayName: _displayName, targetLabel: `btn${target}`,
2347
- dfLabel: setVal(g_lblNameObj[`sc_${_displayName}${target}`], ``, C_TYP_STRING),
2348
- x: g_btnPatterns[_displayName][target]
2389
+ dfLabel: g_lblNameObj[`sc_${_displayName}${target}`] ?? ``,
2390
+ x: g_btnPatterns[_displayName][target],
2349
2391
  }));
2350
2392
  }
2351
2393
 
@@ -2492,7 +2534,7 @@ function titleInit() {
2492
2534
  -webkit-text-fill-color: rgba(255,255,255,0.0);
2493
2535
  ${txtAnimations[1]}
2494
2536
  " class="${g_headerObj.titleAnimationClass[1]}">
2495
- ${setVal(g_headerObj.musicTitleForView[1], ``, C_TYP_STRING)}
2537
+ ${g_headerObj.musicTitleForView[1] ?? ``}
2496
2538
  </div>
2497
2539
  `,
2498
2540
  {
@@ -2819,30 +2861,28 @@ function preheaderConvert(_dosObj) {
2819
2861
  };
2820
2862
 
2821
2863
  // 外部スキンファイルの指定
2822
- const tmpSkinType = _dosObj.skinType || (typeof g_presetSkinType === C_TYP_STRING ? g_presetSkinType : `default`);
2864
+ const tmpSkinType = _dosObj.skinType ?? g_presetObj.skinType ?? `default`;
2823
2865
  const tmpSkinTypes = tmpSkinType.split(`,`);
2824
2866
  obj.defaultSkinFlg = tmpSkinTypes.includes(`default`);
2825
2867
  setJsFiles(tmpSkinTypes, C_DIR_SKIN, `skin`);
2826
2868
 
2827
2869
  // 外部jsファイルの指定
2828
- const tmpCustomjs = _dosObj.customjs || (typeof g_presetCustomJs === C_TYP_STRING ? g_presetCustomJs : C_JSF_CUSTOM);
2870
+ const tmpCustomjs = _dosObj.customjs ?? g_presetObj.customJs ?? C_JSF_CUSTOM;
2829
2871
  setJsFiles(tmpCustomjs.split(`,`), C_DIR_JS);
2830
2872
 
2831
2873
  // 外部cssファイルの指定
2832
- const tmpCustomcss = _dosObj.customcss || (typeof g_presetCustomCss === C_TYP_STRING ? g_presetCustomCss : ``);
2874
+ const tmpCustomcss = _dosObj.customcss ?? g_presetObj.customCss ?? ``;
2833
2875
  setJsFiles(tmpCustomcss.split(`,`), C_DIR_CSS);
2834
2876
 
2835
2877
  // デフォルト曲名表示、背景、Ready表示の利用有無
2836
2878
  g_titleLists.init.forEach(objName => {
2837
2879
  const objUpper = toCapitalize(objName);
2838
- obj[`custom${objUpper}Use`] = setVal(_dosObj[`custom${objUpper}Use`],
2839
- (typeof g_presetCustomDesignUse === C_TYP_OBJECT && (objName in g_presetCustomDesignUse) ?
2840
- setVal(g_presetCustomDesignUse[objName], false, C_TYP_BOOLEAN) : false), C_TYP_BOOLEAN);
2880
+ obj[`custom${objUpper}Use`] =
2881
+ setVal(_dosObj[`custom${objUpper}Use`] ?? g_presetObj.customDesignUse?.[objName], false, C_TYP_BOOLEAN);
2841
2882
  });
2842
2883
 
2843
2884
  // 背景・マスクモーションのパス指定方法を他の設定に合わせる設定
2844
- const tmpSyncBackPath = (typeof g_presetSyncBackPath === C_TYP_BOOLEAN ? g_presetSyncBackPath : false);
2845
- obj.syncBackPath = setVal(_dosObj.syncBackPath, tmpSyncBackPath, C_TYP_BOOLEAN);
2885
+ obj.syncBackPath = setVal(_dosObj.syncBackPath ?? g_presetObj.syncBackPath, false, C_TYP_BOOLEAN);
2846
2886
 
2847
2887
  return obj;
2848
2888
  }
@@ -2855,26 +2895,14 @@ function updateImgType(_imgType) {
2855
2895
  resetImgs(_imgType.name, _imgType.extension);
2856
2896
  reloadImgObj();
2857
2897
  Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_rootPath}${g_imgObj[key]}`);
2858
- if (_imgType[1] === undefined && typeof g_presetOverrideExtension === C_TYP_STRING) {
2859
- Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_imgObj[key].slice(0, -3)}${g_presetOverrideExtension}`);
2898
+ if (_imgType[1] === undefined && g_presetObj.overrideExtension !== undefined) {
2899
+ Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_imgObj[key].slice(0, -3)}${g_presetObj.overrideExtension}`);
2860
2900
  }
2861
2901
  if (!g_isFile) {
2862
2902
  g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
2863
2903
  }
2864
2904
  }
2865
2905
 
2866
- /**
2867
- * 独自で設定したラベルテキスト、オンマウステキスト、確認メッセージ定義を上書き
2868
- */
2869
- function updateLocalDesc() {
2870
- if (typeof g_local_lblNameObj === C_TYP_OBJECT && g_local_lblNameObj[g_localeObj.val] !== undefined) {
2871
- Object.keys(g_local_lblNameObj[g_localeObj.val]).forEach(property => g_lblNameObj[property] = g_local_lblNameObj[g_localeObj.val][property]);
2872
- }
2873
- if (typeof g_local_msgObj === C_TYP_OBJECT && g_local_msgObj[g_localeObj.val] !== undefined) {
2874
- Object.keys(g_local_msgObj[g_localeObj.val]).forEach(property => g_msgObj[property] = g_local_msgObj[g_localeObj.val][property]);
2875
- }
2876
- }
2877
-
2878
2906
  /**
2879
2907
  * 譜面ヘッダーの分解(その他の設定)
2880
2908
  * @param {object} _dosObj 譜面データオブジェクト
@@ -2885,7 +2913,7 @@ function headerConvert(_dosObj) {
2885
2913
  const obj = {};
2886
2914
 
2887
2915
  // フォントの設定
2888
- obj.customFont = setVal(_dosObj.customFont, ``, C_TYP_STRING);
2916
+ obj.customFont = _dosObj.customFont ?? ``;
2889
2917
  g_headerObj.customFont = obj.customFont;
2890
2918
 
2891
2919
  // 画像ルートパス、拡張子の設定 (サーバ上のみ)
@@ -2894,8 +2922,8 @@ function headerConvert(_dosObj) {
2894
2922
  let tmpImgTypes = [];
2895
2923
  if (hasVal(_dosObj.imgType)) {
2896
2924
  tmpImgTypes = _dosObj.imgType.split(`$`);
2897
- } else if (typeof g_presetImageSets === C_TYP_OBJECT) {
2898
- tmpImgTypes = g_presetImageSets.concat();
2925
+ } else if (g_presetObj.imageSets !== undefined) {
2926
+ tmpImgTypes = g_presetObj.imageSets.concat();
2899
2927
  }
2900
2928
  if (tmpImgTypes.length > 0) {
2901
2929
  tmpImgTypes.forEach((tmpImgType, j) => {
@@ -2926,9 +2954,8 @@ function headerConvert(_dosObj) {
2926
2954
  }
2927
2955
 
2928
2956
  // ラベルテキスト、オンマウステキスト、確認メッセージ定義の上書き設定
2929
- Object.keys(g_lang_lblNameObj[g_localeObj.val]).forEach(property => g_lblNameObj[property] = g_lang_lblNameObj[g_localeObj.val][property]);
2930
- Object.keys(g_lang_msgObj[g_localeObj.val]).forEach(property => g_msgObj[property] = g_lang_msgObj[g_localeObj.val][property]);
2931
- updateLocalDesc();
2957
+ Object.assign(g_lblNameObj, g_lang_lblNameObj[g_localeObj.val], g_presetObj.lblName?.[g_localeObj.val]);
2958
+ Object.assign(g_msgObj, g_lang_msgObj[g_localeObj.val], g_presetObj.msg?.[g_localeObj.val]);
2932
2959
 
2933
2960
  // 曲名
2934
2961
  obj.musicTitles = [];
@@ -2949,18 +2976,18 @@ function headerConvert(_dosObj) {
2949
2976
  if (obj.musicNos.length >= j) {
2950
2977
  obj.musicTitles[j] = escapeHtml(getMusicNameSimple(musics[0]));
2951
2978
  obj.musicTitlesForView[j] = escapeHtmlForArray(getMusicNameMultiLine(musics[0]));
2952
- obj.artistNames[j] = escapeHtml(setVal(musics[1], ``, C_TYP_STRING));
2979
+ obj.artistNames[j] = escapeHtml(musics[1] ?? ``);
2953
2980
  }
2954
2981
  }
2955
2982
  const musics = musicData[0].split(`,`);
2956
2983
  obj.musicTitle = obj.musicTitles[0];
2957
2984
  obj.musicTitleForView = obj.musicTitlesForView[0];
2958
- obj.artistName = obj.artistNames[0] || ``;
2985
+ obj.artistName = obj.artistNames[0] ?? ``;
2959
2986
  if (obj.artistName === ``) {
2960
2987
  makeWarningWindow(g_msgInfoObj.E_0011);
2961
2988
  obj.artistName = `artistName`;
2962
2989
  }
2963
- obj.artistUrl = musics[2] || ``;
2990
+ obj.artistUrl = musics[2] ?? ``;
2964
2991
  if (musics[3] !== undefined) {
2965
2992
  obj.musicTitles[0] = escapeHtml(getMusicNameSimple(musics[3]));
2966
2993
  obj.musicTitlesForView[0] = escapeHtmlForArray(getMusicNameMultiLine(musics[3]));
@@ -2996,10 +3023,10 @@ function headerConvert(_dosObj) {
2996
3023
  if (hasVal(_dosObj.tuning)) {
2997
3024
  const tunings = _dosObj.tuning.split(`,`);
2998
3025
  obj.tuning = escapeHtmlForEnabledTag(tunings[0]);
2999
- obj.creatorUrl = (tunings.length > 1 ? tunings[1] : (typeof g_presetTuningUrl === C_TYP_STRING ? g_presetTuningUrl : ``));
3026
+ obj.creatorUrl = (tunings.length > 1 ? tunings[1] : (g_presetObj.tuningUrl ?? ``));
3000
3027
  } else {
3001
- obj.tuning = (typeof g_presetTuning === C_TYP_STRING ? escapeHtmlForEnabledTag(g_presetTuning) : `name`);
3002
- obj.creatorUrl = (typeof g_presetTuningUrl === C_TYP_STRING ? g_presetTuningUrl : ``);
3028
+ obj.tuning = escapeHtmlForEnabledTag(g_presetObj.tuning ?? `name`);
3029
+ obj.creatorUrl = g_presetObj.tuningUrl ?? ``;
3003
3030
  }
3004
3031
  obj.tuningInit = obj.tuning;
3005
3032
 
@@ -3007,7 +3034,7 @@ function headerConvert(_dosObj) {
3007
3034
  if (hasVal(_dosObj.difData)) {
3008
3035
  const difs = _dosObj.difData.split(`$`);
3009
3036
  const difpos = {
3010
- key: 0, name: 1, speed: 2, border: 3, recovery: 4, damage: 5, init: 6,
3037
+ Key: 0, Name: 1, Speed: 2, Border: 3, Recovery: 4, Damage: 5, Init: 6,
3011
3038
  };
3012
3039
  obj.keyLabels = [];
3013
3040
  obj.difLabels = [];
@@ -3019,34 +3046,25 @@ function headerConvert(_dosObj) {
3019
3046
  obj.creatorNames = [];
3020
3047
  g_stateObj.scoreId = (g_stateObj.scoreId < difs.length ? g_stateObj.scoreId : 0);
3021
3048
 
3022
- const lifeData = (_name, _preData, _default) => {
3023
- const data = (_preData) ? _preData :
3024
- (typeof g_presetGauge === C_TYP_OBJECT && (_name in g_presetGauge) ?
3025
- g_presetGauge[_name] : _default);
3026
- return setVal(data, _default, C_TYP_FLOAT);
3027
- };
3028
-
3029
3049
  difs.forEach(dif => {
3030
3050
  const difDetails = dif.split(`,`);
3051
+ const lifeData = (_type, _default) =>
3052
+ setVal(difDetails[difpos[_type]] || g_presetObj.gauge?.[_type], _default, C_TYP_FLOAT);
3031
3053
 
3032
3054
  // ライフ:ノルマ、回復量、ダメージ量、初期値の設定
3033
- const border = (difDetails[difpos.border]) ? difDetails[difpos.border] :
3034
- (typeof g_presetGauge === C_TYP_OBJECT && (`Border` in g_presetGauge) ?
3035
- g_presetGauge.Border : `x`);
3036
-
3037
- obj.lifeBorders.push(border === `x` ? `x` : setVal(border, 70, C_TYP_FLOAT));
3038
- obj.lifeRecoverys.push(lifeData(`Recovery`, difDetails[difpos.recovery], 6));
3039
- obj.lifeDamages.push(lifeData(`Damage`, difDetails[difpos.damage], 40));
3040
- obj.lifeInits.push(lifeData(`Init`, difDetails[difpos.init], 25));
3055
+ obj.lifeBorders.push(lifeData(`Border`, `x`));
3056
+ obj.lifeRecoverys.push(lifeData(`Recovery`, 6));
3057
+ obj.lifeDamages.push(lifeData(`Damage`, 40));
3058
+ obj.lifeInits.push(lifeData(`Init`, 25));
3041
3059
 
3042
3060
  // キー数
3043
- const keyLabel = setVal(difDetails[difpos.key], `7`, C_TYP_STRING);
3044
- obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] || keyLabel);
3061
+ const keyLabel = difDetails[difpos.Key] ?? `7`;
3062
+ obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] ?? keyLabel);
3045
3063
 
3046
3064
  // 譜面名、制作者名
3047
- if (hasVal(difDetails[difpos.name])) {
3048
- const difNameInfo = difDetails[difpos.name].split(`::`);
3049
- obj.difLabels.push(escapeHtml(setVal(difNameInfo[0], `Normal`, C_TYP_STRING)));
3065
+ if (hasVal(difDetails[difpos.Name])) {
3066
+ const difNameInfo = difDetails[difpos.Name].split(`::`);
3067
+ obj.difLabels.push(escapeHtml(difNameInfo[0] ?? `Normal`));
3050
3068
  obj.creatorNames.push(difNameInfo.length > 1 ? escapeHtml(difNameInfo[1]) : obj.tuning);
3051
3069
  } else {
3052
3070
  obj.difLabels.push(`Normal`);
@@ -3054,7 +3072,7 @@ function headerConvert(_dosObj) {
3054
3072
  }
3055
3073
 
3056
3074
  // 初期速度
3057
- obj.initSpeeds.push(setVal(difDetails[difpos.speed], 3.5, C_TYP_FLOAT));
3075
+ obj.initSpeeds.push(setVal(difDetails[difpos.Speed], 3.5, C_TYP_FLOAT));
3058
3076
  });
3059
3077
  } else {
3060
3078
  makeWarningWindow(g_msgInfoObj.E_0021);
@@ -3067,8 +3085,9 @@ function headerConvert(_dosObj) {
3067
3085
  obj.lifeInits = [25];
3068
3086
  obj.creatorNames = [obj.tuning];
3069
3087
  }
3070
- const keyLists = obj.keyLabels.filter((x, j, self) => self.indexOf(x) === j);
3088
+ const keyLists = makeDedupliArray(obj.keyLabels);
3071
3089
  obj.keyLists = keyLists.sort((a, b) => parseInt(a) - parseInt(b));
3090
+ obj.undefinedKeyLists = obj.keyLists.filter(key => g_keyObj[`chara${key}_0`] === undefined);
3072
3091
 
3073
3092
  // 譜面変更セレクターの利用有無
3074
3093
  obj.difSelectorUse = (setVal(_dosObj.difSelectorUse, obj.keyLabels.length > 5, C_TYP_BOOLEAN));
@@ -3087,7 +3106,7 @@ function headerConvert(_dosObj) {
3087
3106
  if (hasVal(_dosObj.defaultColorgrd)) {
3088
3107
  obj.defaultColorgrd = _dosObj.defaultColorgrd.split(`,`);
3089
3108
  obj.defaultColorgrd[0] = setVal(obj.defaultColorgrd[0], false, C_TYP_BOOLEAN);
3090
- obj.defaultColorgrd[1] = setVal(obj.defaultColorgrd[1], intermediateColor, C_TYP_STRING);
3109
+ obj.defaultColorgrd[1] = obj.defaultColorgrd[1] ?? intermediateColor;
3091
3110
  }
3092
3111
  g_rankObj.rankColorAllPerfect = intermediateColor;
3093
3112
 
@@ -3108,13 +3127,7 @@ function headerConvert(_dosObj) {
3108
3127
  });
3109
3128
 
3110
3129
  // フリーズアローのデフォルト色セットの利用有無 (true: 使用, false: 矢印色を優先してセット)
3111
- if (hasVal(_dosObj.defaultFrzColorUse)) {
3112
- obj.defaultFrzColorUse = setVal(_dosObj.defaultFrzColorUse, true, C_TYP_BOOLEAN);
3113
- } else if (typeof g_presetFrzColors === C_TYP_BOOLEAN) {
3114
- obj.defaultFrzColorUse = g_presetFrzColors;
3115
- } else {
3116
- obj.defaultFrzColorUse = true;
3117
- }
3130
+ obj.defaultFrzColorUse = setVal(_dosObj.defaultFrzColorUse ?? g_presetObj.frzColors, true, C_TYP_BOOLEAN);
3118
3131
 
3119
3132
  // 矢印色変化に対応してフリーズアロー色を追随する範囲の設定
3120
3133
  // (defaultFrzColorUse=false時のみ)
@@ -3125,8 +3138,8 @@ function headerConvert(_dosObj) {
3125
3138
 
3126
3139
  if (hasVal(_dosObj.frzScopeFromAC)) {
3127
3140
  tmpFrzScope.push(..._dosObj.frzScopeFromAC.split(`,`));
3128
- } else if (typeof g_presetFrzScopeFromAC === C_TYP_OBJECT) {
3129
- tmpFrzScope.push(...g_presetFrzScopeFromAC);
3141
+ } else if (g_presetObj.frzScopeFromAC !== undefined) {
3142
+ tmpFrzScope.push(...g_presetObj.frzScopeFromAC);
3130
3143
  }
3131
3144
  tmpFrzScope.filter(type => [`Normal`, `Hit`].includes(type))
3132
3145
  .forEach(data => obj.frzScopeFromArrowColors.push(data));
@@ -3150,10 +3163,10 @@ function headerConvert(_dosObj) {
3150
3163
  addGaugeFulls(g_gaugeOptionObj.survival);
3151
3164
  addGaugeFulls(g_gaugeOptionObj.border);
3152
3165
 
3153
- if (typeof g_presetGaugeList === C_TYP_OBJECT) {
3154
- Object.keys(g_presetGaugeList).forEach(key => {
3166
+ if (g_presetObj.gaugeList !== undefined) {
3167
+ Object.keys(g_presetObj.gaugeList).forEach(key => {
3155
3168
  g_gaugeOptionObj.customDefault.push(key);
3156
- g_gaugeOptionObj.varCustomDefault.push((g_presetGaugeList[key] !== `V` ? C_FLG_OFF : C_FLG_ON));
3169
+ g_gaugeOptionObj.varCustomDefault.push((g_presetObj.gaugeList[key] !== `V` ? C_FLG_OFF : C_FLG_ON));
3157
3170
  });
3158
3171
  g_gaugeOptionObj.custom = g_gaugeOptionObj.customDefault.concat();
3159
3172
  g_gaugeOptionObj.varCustom = g_gaugeOptionObj.varCustomDefault.concat();
@@ -3199,11 +3212,7 @@ function headerConvert(_dosObj) {
3199
3212
  }
3200
3213
 
3201
3214
  // タイミング調整
3202
- if (hasVal(_dosObj.adjustment)) {
3203
- obj.adjustment = _dosObj.adjustment.split(`$`);
3204
- } else {
3205
- obj.adjustment = [0];
3206
- }
3215
+ obj.adjustment = (hasVal(_dosObj.adjustment) ? _dosObj.adjustment.split(`$`) : [0]);
3207
3216
 
3208
3217
  // 再生速度
3209
3218
  obj.playbackRate = setVal(_dosObj.playbackRate, 1, C_TYP_FLOAT);
@@ -3226,7 +3235,7 @@ function headerConvert(_dosObj) {
3226
3235
  g_diffObj.frzJdgY = (isNaN(parseFloat(_dosObj.frzJdgY)) ? 0 : parseFloat(_dosObj.frzJdgY));
3227
3236
 
3228
3237
  // musicフォルダ設定
3229
- obj.musicFolder = setVal(_dosObj.musicFolder, (g_remoteFlg ? `(..)../music` : `music`), C_TYP_STRING);
3238
+ obj.musicFolder = _dosObj.musicFolder ?? (g_remoteFlg ? `(..)../music` : `music`);
3230
3239
 
3231
3240
  // 楽曲URL
3232
3241
  if (hasVal(_dosObj.musicUrl)) {
@@ -3251,10 +3260,10 @@ function headerConvert(_dosObj) {
3251
3260
  }
3252
3261
 
3253
3262
  // 最終演出表示有無(noneで無効化)
3254
- obj.finishView = setVal(_dosObj.finishView, ``, C_TYP_STRING);
3263
+ obj.finishView = _dosObj.finishView ?? ``;
3255
3264
 
3256
3265
  // 更新日
3257
- obj.releaseDate = setVal(_dosObj.releaseDate, ``, C_TYP_STRING);
3266
+ obj.releaseDate = _dosObj.releaseDate ?? ``;
3258
3267
 
3259
3268
  // デフォルトReady/リザルト表示の遅延時間設定
3260
3269
  [`ready`, `result`].forEach(objName => {
@@ -3265,16 +3274,16 @@ function headerConvert(_dosObj) {
3265
3274
  obj.readyAnimationFrame = setVal(_dosObj.readyAnimationFrame, 150, C_TYP_NUMBER);
3266
3275
 
3267
3276
  // デフォルトReady表示のアニメーション名
3268
- obj.readyAnimationName = setVal(_dosObj.readyAnimationName, `leftToRightFade`, C_TYP_STRING);
3277
+ obj.readyAnimationName = _dosObj.readyAnimationName ?? `leftToRightFade`;
3269
3278
 
3270
3279
  // デフォルトReady表示の先頭文字色
3271
- obj.readyColor = setVal(_dosObj.readyColor, ``, C_TYP_STRING);
3280
+ obj.readyColor = _dosObj.readyColor ?? ``;
3272
3281
 
3273
3282
  // デフォルトReady表示を上書きするテキスト
3274
- obj.readyHtml = setVal(_dosObj.readyHtml, ``, C_TYP_STRING);
3283
+ obj.readyHtml = _dosObj.readyHtml ?? ``;
3275
3284
 
3276
3285
  // デフォルト曲名表示のフォントサイズ
3277
- obj.titlesize = setVal(_dosObj.titlesize, ``, C_TYP_STRING);
3286
+ obj.titlesize = _dosObj.titlesize ?? ``;
3278
3287
 
3279
3288
  // デフォルト曲名表示のフォント名
3280
3289
  // (使用例: |titlefont=Century,Meiryo UI|)
@@ -3294,7 +3303,7 @@ function headerConvert(_dosObj) {
3294
3303
  if (hasVal(_dosObj[_name])) {
3295
3304
  const tmpTitlegrd = _dosObj[_name].replace(/,/g, `:`);
3296
3305
  obj[`${_name}s`] = tmpTitlegrd.split(`$`);
3297
- obj[`${_name}`] = setVal(obj[`${_name}s`][0], ``, C_TYP_STRING);
3306
+ obj[`${_name}`] = obj[`${_name}s`][0] ?? ``;
3298
3307
  }
3299
3308
  });
3300
3309
 
@@ -3323,7 +3332,7 @@ function headerConvert(_dosObj) {
3323
3332
  }
3324
3333
  if (hasVal(_dosObj.titleanimationclass)) {
3325
3334
  _dosObj.titleanimationclass.split(`$`).forEach((animationClass, j) => {
3326
- obj.titleAnimationClass[j] = setVal(animationClass, ``, C_TYP_STRING);
3335
+ obj.titleAnimationClass[j] = animationClass ?? ``;
3327
3336
  });
3328
3337
  }
3329
3338
  if (obj.titleAnimationName.length === 1) {
@@ -3339,8 +3348,7 @@ function headerConvert(_dosObj) {
3339
3348
  obj.titlelineheight = setVal(_dosObj.titlelineheight, ``, C_TYP_NUMBER);
3340
3349
 
3341
3350
  // フリーズアローの始点で通常矢印の判定を行うか(dotさんソース方式)
3342
- obj.frzStartjdgUse = setVal(_dosObj.frzStartjdgUse,
3343
- (typeof g_presetFrzStartjdgUse === C_TYP_STRING ? setVal(g_presetFrzStartjdgUse, false, C_TYP_BOOLEAN) : false), C_TYP_BOOLEAN);
3351
+ obj.frzStartjdgUse = setVal(_dosObj.frzStartjdgUse ?? g_presetObj.frzStartjdgUse, false, C_TYP_BOOLEAN);
3344
3352
 
3345
3353
  // 譜面名に制作者名を付加するかどうかのフラグ
3346
3354
  obj.makerView = setVal(_dosObj.makerView, false, C_TYP_BOOLEAN);
@@ -3353,25 +3361,21 @@ function headerConvert(_dosObj) {
3353
3361
 
3354
3362
  // オプション利用可否設定
3355
3363
  g_canDisabledSettings.forEach(option => {
3356
- obj[`${option}Use`] = setVal(_dosObj[`${option}Use`],
3357
- (typeof g_presetSettingUse === C_TYP_OBJECT ?
3358
- setVal(g_presetSettingUse[option], true, C_TYP_BOOLEAN) : true), C_TYP_BOOLEAN);
3364
+ obj[`${option}Use`] = setVal(_dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option], true, C_TYP_BOOLEAN);
3359
3365
  });
3360
3366
 
3361
3367
  let interlockingErrorFlg = false;
3362
3368
  g_displays.forEach((option, j) => {
3363
3369
 
3364
3370
  // Display使用可否設定を分解 |displayUse=false,ON|
3365
- const displayTempUse = setVal(_dosObj[`${option}Use`],
3366
- (typeof g_presetSettingUse === C_TYP_OBJECT ?
3367
- g_presetSettingUse[option] : `true`), C_TYP_STRING);
3371
+ const displayTempUse = _dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option] ?? `true`;
3368
3372
  const displayUse = (displayTempUse !== undefined ? displayTempUse.split(`,`) : [true, C_FLG_ON]);
3369
3373
 
3370
3374
  // displayUse -> ボタンの有効/無効, displaySet -> ボタンの初期値(ON/OFF)
3371
3375
  obj[`${option}Use`] = setVal(displayUse[0], true, C_TYP_BOOLEAN);
3372
3376
  obj[`${option}Set`] = setVal(displayUse.length > 1 ? displayUse[1] :
3373
3377
  (obj[`${option}Use`] ? C_FLG_ON : C_FLG_OFF), ``, C_TYP_SWITCH);
3374
- g_stateObj[`d_${option.toLowerCase()}`] = (obj[`${option}Set`] !== `` ? obj[`${option}Set`] : C_FLG_ON);
3378
+ g_stateObj[`d_${option.toLowerCase()}`] = setVal(obj[`${option}Set`], C_FLG_ON, C_TYP_SWITCH);
3375
3379
  obj[`${option}ChainOFF`] = (_dosObj[`${option}ChainOFF`] !== undefined ? _dosObj[`${option}ChainOFF`].split(`,`) : []);
3376
3380
 
3377
3381
  // Displayのデフォルト設定で、双方向に設定されている場合は設定をブロック
@@ -3434,7 +3438,7 @@ function headerConvert(_dosObj) {
3434
3438
  obj.maskresultButton = setVal(_dosObj.maskresultButton, false, C_TYP_BOOLEAN);
3435
3439
 
3436
3440
  // color_dataの過去バージョン互換設定
3437
- obj.colorDataType = setVal(_dosObj.colorDataType, ``, C_TYP_STRING);
3441
+ obj.colorDataType = _dosObj.colorDataType ?? ``;
3438
3442
 
3439
3443
  // リザルトモーションをDisplay:BackgroundのON/OFFと連動させるかどうかの設定
3440
3444
  obj.resultMotionSet = setVal(_dosObj.resultMotionSet, true, C_TYP_BOOLEAN);
@@ -3447,8 +3451,7 @@ function headerConvert(_dosObj) {
3447
3451
 
3448
3452
  // タイトル表示用コメント
3449
3453
  const newlineTag = setVal(_dosObj.commentAutoBr, true, C_TYP_BOOLEAN) ? `<br>` : ``;
3450
- let tmpComment = setVal(_dosObj[`commentVal${g_localeObj.val}`] || _dosObj.commentVal, ``, C_TYP_STRING);
3451
- tmpComment = tmpComment.split(`\r\n`).join(`\n`);
3454
+ const tmpComment = (_dosObj[`commentVal${g_localeObj.val}`] ?? _dosObj.commentVal ?? ``).split(`\r\n`).join(`\n`);
3452
3455
  obj.commentVal = tmpComment.split(`\n`).join(newlineTag);
3453
3456
 
3454
3457
  // クレジット表示
@@ -3462,8 +3465,7 @@ function headerConvert(_dosObj) {
3462
3465
  obj.commentExternal = setVal(_dosObj.commentExternal, false, C_TYP_BOOLEAN);
3463
3466
 
3464
3467
  // Reverse時の歌詞の自動反転制御
3465
- obj.wordAutoReverse = setVal(_dosObj.wordAutoReverse,
3466
- (typeof g_presetWordAutoReverse === C_TYP_STRING ? setVal(g_presetWordAutoReverse, `auto`, C_TYP_STRING) : `auto`), C_TYP_STRING);
3468
+ obj.wordAutoReverse = _dosObj.wordAutoReverse ?? g_presetObj.wordAutoReverse ?? `auto`;
3467
3469
 
3468
3470
  // プレイサイズ(X方向)
3469
3471
  obj.playingWidth = setVal(_dosObj.playingWidth, g_sWidth, C_TYP_NUMBER);
@@ -3479,19 +3481,18 @@ function headerConvert(_dosObj) {
3479
3481
 
3480
3482
  // リザルトデータのカスタマイズ
3481
3483
  const resultFormatDefault = `【#danoni[hashTag]】[musicTitle]([keyLabel]) /[maker] /Rank:[rank]/Score:[score]/Playstyle:[playStyle]/[arrowJdg]/[frzJdg]/[maxCombo] [url]`;
3482
- obj.resultFormat = escapeHtmlForEnabledTag(setVal(_dosObj.resultFormat, (typeof g_presetResultFormat === C_TYP_STRING ?
3483
- setVal(g_presetResultFormat, resultFormatDefault, C_TYP_STRING) : resultFormatDefault), C_TYP_STRING));
3484
+ obj.resultFormat = escapeHtmlForEnabledTag(_dosObj.resultFormat ?? g_presetObj.resultFormat ?? resultFormatDefault);
3484
3485
 
3485
3486
  // フェードイン時にそれ以前のデータを蓄積しない種別(word, back, mask)を指定
3486
- obj.unStockCategories = setVal(_dosObj.unStockCategory, ``, C_TYP_STRING).split(`,`);
3487
- if (typeof g_presetUnStockCategories === C_TYP_OBJECT) {
3488
- obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetUnStockCategories);
3487
+ obj.unStockCategories = (_dosObj.unStockCategory ?? ``).split(`,`);
3488
+ if (g_presetObj.unStockCategories !== undefined) {
3489
+ obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetObj.unStockCategories);
3489
3490
  }
3490
3491
  g_fadeinStockList = g_fadeinStockList.filter(cg => obj.unStockCategories.indexOf(cg) === -1);
3491
3492
 
3492
3493
  // フェードイン時にそれ以前のデータを蓄積しないパターンを指定
3493
- if (typeof g_presetStockForceDelList === C_TYP_OBJECT) {
3494
- Object.assign(g_stockForceDelList, g_presetStockForceDelList);
3494
+ if (g_presetObj.stockForceDelList !== undefined) {
3495
+ Object.assign(g_stockForceDelList, g_presetObj.stockForceDelList);
3495
3496
  }
3496
3497
  g_fadeinStockList.forEach(type => {
3497
3498
  if (hasVal(_dosObj[`${type}StockForceDel`])) {
@@ -3552,7 +3553,7 @@ function resetBaseColorList(_baseObj, _dosObj, { scoreId = `` } = {}) {
3552
3553
  for (let j = 0; j < _baseObj.setColorInit.length; j++) {
3553
3554
 
3554
3555
  // デフォルト配列の作成(1番目の要素をベースに、フリーズアロー初期セット or 矢印色からデータを補完)
3555
- let currentFrzColors = [];
3556
+ const currentFrzColors = [];
3556
3557
  const baseLength = firstFrzColors.length === 0 || _baseObj.defaultFrzColorUse ?
3557
3558
  _baseObj[_frzInit].length : firstFrzColors.length;
3558
3559
  for (let k = 0; k < baseLength; k++) {
@@ -3768,11 +3769,11 @@ function getGaugeSetting(_dosObj, _name, _difLength, { scoreId = 0 } = {}) {
3768
3769
  }
3769
3770
  }
3770
3771
 
3771
- } else if (typeof g_presetGaugeCustom === C_TYP_OBJECT && g_presetGaugeCustom[_name]) {
3772
+ } else if (g_presetObj.gaugeCustom?.[_name] !== undefined) {
3772
3773
 
3773
3774
  const gaugeDetails = [
3774
- g_presetGaugeCustom[_name].Border, g_presetGaugeCustom[_name].Recovery,
3775
- g_presetGaugeCustom[_name].Damage, g_presetGaugeCustom[_name].Init,
3775
+ g_presetObj.gaugeCustom[_name].Border, g_presetObj.gaugeCustom[_name].Recovery,
3776
+ g_presetObj.gaugeCustom[_name].Damage, g_presetObj.gaugeCustom[_name].Init,
3776
3777
  ]
3777
3778
  if (gaugeUpdateFlg) {
3778
3779
  gaugeCreateFlg = setGaugeDetails(scoreId, gaugeDetails);
@@ -3798,12 +3799,11 @@ const getKeyName = _key => hasVal(g_keyObj[`keyName${_key}`]) ? g_keyObj[`keyNam
3798
3799
  * 一時的な追加キーの設定
3799
3800
  * @param {object} _dosObj
3800
3801
  */
3801
- function keysConvert(_dosObj) {
3802
+ function keysConvert(_dosObj, { keyExtraList = _dosObj.keyExtraList.split(`,`) } = {}) {
3802
3803
 
3803
- if (_dosObj.keyExtraList === undefined) {
3804
- return;
3804
+ if (keyExtraList === undefined) {
3805
+ return [];
3805
3806
  }
3806
- const keyExtraList = _dosObj.keyExtraList.split(`,`);
3807
3807
 
3808
3808
  const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
3809
3809
  const toString = _str => _str;
@@ -3907,7 +3907,7 @@ function keysConvert(_dosObj) {
3907
3907
  let tmpMinPatterns = 1;
3908
3908
 
3909
3909
  // キーの名前 (keyNameX)
3910
- g_keyObj[`keyName${newKey}`] = setVal(_dosObj[`keyName${newKey}`], newKey, C_TYP_STRING);
3910
+ g_keyObj[`keyName${newKey}`] = _dosObj[`keyName${newKey}`] ?? newKey;
3911
3911
 
3912
3912
  // 矢印色パターン (colorX_Y)
3913
3913
  tmpMinPatterns = newKeyMultiParam(newKey, `color`, toNumber, {
@@ -3996,6 +3996,8 @@ function keysConvert(_dosObj) {
3996
3996
  // |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
3997
3997
  newKeyPairParam(newKey, `assist`, `assistPos`);
3998
3998
  });
3999
+
4000
+ return keyExtraList;
3999
4001
  }
4000
4002
 
4001
4003
 
@@ -4981,8 +4983,6 @@ function createOptionWindow(_sprite) {
4981
4983
  // ---------------------------------------------------
4982
4984
  // 1. キーコンフィグ設定 (KeyConfig)
4983
4985
 
4984
- // 特殊キーフラグ
4985
- g_stateObj.extraKeyFlg = false;
4986
4986
 
4987
4987
  g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
4988
4988
  const isNotSameKey = (g_keyObj.prevKey !== g_keyObj.currentKey);
@@ -4990,15 +4990,8 @@ function createOptionWindow(_sprite) {
4990
4990
  if (g_headerObj.dummyScoreNos !== undefined) {
4991
4991
  g_stateObj.dummyId = setVal(g_headerObj.dummyScoreNos[g_stateObj.scoreId], ``, C_TYP_NUMBER);
4992
4992
  }
4993
-
4994
- if (g_rootObj.keyExtraList !== undefined) {
4995
- g_rootObj.keyExtraList.split(`,`).some(extraKey => {
4996
- if (g_keyObj.currentKey === extraKey) {
4997
- g_stateObj.extraKeyFlg = true;
4998
- return true;
4999
- }
5000
- });
5001
- }
4993
+ // 特殊キーフラグ
4994
+ g_stateObj.extraKeyFlg = g_headerObj.keyExtraList.includes(g_keyObj.currentKey);
5002
4995
 
5003
4996
  // ---------------------------------------------------
5004
4997
  // 2. 初期化設定
@@ -5236,8 +5229,8 @@ function createLblSetting(_settingName, _adjY = 0, _settingLabel = _settingName)
5236
5229
  * @param {string} _name
5237
5230
  */
5238
5231
  function getStgDetailName(_name) {
5239
- return g_lblNameObj[`u_${_name}`] === undefined || typeof g_lblRenames !== C_TYP_OBJECT || !g_lblRenames[g_currentPage] ?
5240
- _name : g_lblNameObj[`u_${_name}`];
5232
+ return g_lblNameObj[`u_${_name}`] !== undefined &&
5233
+ (g_presetObj.lblRenames === undefined || g_presetObj.lblRenames[g_currentPage]) ? g_lblNameObj[`u_${_name}`] : _name;
5241
5234
  }
5242
5235
 
5243
5236
  /**
@@ -5291,7 +5284,7 @@ function makeDisabledLabel(_id, _heightPos, _defaultStr) {
5291
5284
  */
5292
5285
  function getKeyReverse(_localStorage, _extraKeyName = ``) {
5293
5286
  if (_localStorage[`reverse${_extraKeyName}`] !== undefined) {
5294
- g_stateObj.reverse = setVal(_localStorage[`reverse${_extraKeyName}`], C_FLG_OFF, C_TYP_STRING);
5287
+ g_stateObj.reverse = _localStorage[`reverse${_extraKeyName}`] ?? C_FLG_OFF;
5295
5288
  g_settings.reverseNum = roundZero(g_settings.reverses.findIndex(reverse => reverse === g_stateObj.reverse));
5296
5289
  } else {
5297
5290
  g_stateObj.reverse = C_FLG_OFF;
@@ -6095,7 +6088,7 @@ function keyConfigInit(_kcType = g_kcType) {
6095
6088
 
6096
6089
  // キーパターン表示
6097
6090
  const lblTransKey = hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ?
6098
- '(' + setVal(g_keyObj[`transKey${keyCtrlPtn}`], ``, C_TYP_STRING) + ')' : ``;
6091
+ `(${g_keyObj[`transKey${keyCtrlPtn}`] ?? ''})` : ``;
6099
6092
 
6100
6093
  // パターン検索
6101
6094
  const searchPattern = (_tempPtn, _sign, _transKeyUse = false, _keyCheck = `keyCtrl`) => {
@@ -6307,164 +6300,164 @@ function changeSetColor() {
6307
6300
  /**
6308
6301
  * 読込画面初期化
6309
6302
  */
6310
- function loadingScoreInit() {
6303
+ async function loadingScoreInit() {
6304
+
6311
6305
  // 譜面データの読み込み
6312
- loadDos(_ => {
6313
- const tkObj = getKeyInfo();
6314
- const [keyCtrlPtn, keyNum] = [tkObj.keyCtrlPtn, tkObj.keyNum];
6315
- g_headerObj.blankFrame = g_headerObj.blankFrameDef;
6306
+ await loadChartFile();
6307
+ const tkObj = getKeyInfo();
6308
+ const [keyCtrlPtn, keyNum] = [tkObj.keyCtrlPtn, tkObj.keyNum];
6309
+ g_headerObj.blankFrame = g_headerObj.blankFrameDef;
6316
6310
 
6317
- // ユーザカスタムイベント
6318
- g_customJsObj.preloading.forEach(func => func());
6319
- g_skinJsObj.preloading.forEach(func => func());
6311
+ // ユーザカスタムイベント
6312
+ g_customJsObj.preloading.forEach(func => func());
6313
+ g_skinJsObj.preloading.forEach(func => func());
6320
6314
 
6321
- let dummyIdHeader = ``;
6322
- if (g_stateObj.dummyId !== ``) {
6323
- if (g_stateObj.dummyId === 0 || g_stateObj.dummyId === 1) {
6324
- dummyIdHeader = ``;
6325
- } else {
6326
- dummyIdHeader = g_stateObj.dummyId;
6327
- }
6315
+ let dummyIdHeader = ``;
6316
+ if (g_stateObj.dummyId !== ``) {
6317
+ if (g_stateObj.dummyId === 0 || g_stateObj.dummyId === 1) {
6318
+ dummyIdHeader = ``;
6319
+ } else {
6320
+ dummyIdHeader = g_stateObj.dummyId;
6328
6321
  }
6329
- g_scoreObj = scoreConvert(g_rootObj, g_stateObj.scoreId, 0, dummyIdHeader);
6330
-
6331
- // 最終フレーム数の取得
6332
- let lastFrame = getLastFrame(g_scoreObj) + g_headerObj.blankFrame;
6333
-
6334
- // 最初の矢印データがあるフレーム数を取得
6335
- let firstArrowFrame = getFirstArrowFrame(g_scoreObj);
6322
+ }
6323
+ g_scoreObj = scoreConvert(g_rootObj, g_stateObj.scoreId, 0, dummyIdHeader);
6336
6324
 
6337
- // 開始フレーム数の取得(フェードイン加味)
6338
- g_scoreObj.frameNum = getStartFrame(lastFrame, g_stateObj.fadein);
6339
- g_scoreObj.baseFrame = g_scoreObj.frameNum - g_stateObj.intAdjustment;
6325
+ // 最終フレーム数の取得
6326
+ let lastFrame = getLastFrame(g_scoreObj) + g_headerObj.blankFrame;
6340
6327
 
6341
- // フレームごとの速度を取得(配列形式)
6342
- let speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
6328
+ // 最初の矢印データがあるフレーム数を取得
6329
+ let firstArrowFrame = getFirstArrowFrame(g_scoreObj);
6343
6330
 
6344
- // Motionオプション適用時の矢印別の速度を取得(配列形式)
6345
- const motionOnFrame = setMotionOnFrame();
6346
- g_workObj.motionOnFrames = copyArray2d(motionOnFrame);
6331
+ // 開始フレーム数の取得(フェードイン加味)
6332
+ g_scoreObj.frameNum = getStartFrame(lastFrame, g_stateObj.fadein);
6333
+ g_scoreObj.baseFrame = g_scoreObj.frameNum - g_stateObj.intAdjustment;
6347
6334
 
6348
- // 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
6349
- const firstFrame = (g_scoreObj.frameNum === 0 ? 0 : g_scoreObj.frameNum + g_headerObj.blankFrame);
6350
- let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
6335
+ // フレームごとの速度を取得(配列形式)
6336
+ let speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
6351
6337
 
6352
- // キーパターン(デフォルト)に対応する矢印番号を格納
6353
- convertreplaceNums();
6338
+ // Motionオプション適用時の矢印別の速度を取得(配列形式)
6339
+ const motionOnFrame = setMotionOnFrame();
6340
+ g_workObj.motionOnFrames = copyArray2d(motionOnFrame);
6354
6341
 
6355
- const setData = (_data, _minLength = 1) => {
6356
- return (hasArrayList(_data, _minLength) ? _data.concat() : []);
6357
- }
6342
+ // 最初のフレームで出現する矢印が、ステップゾーンに到達するまでのフレーム数を取得
6343
+ const firstFrame = (g_scoreObj.frameNum === 0 ? 0 : g_scoreObj.frameNum + g_headerObj.blankFrame);
6344
+ let arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
6358
6345
 
6359
- // フレーム・曲開始位置調整
6360
- let preblankFrame = 0;
6361
- if (g_scoreObj.frameNum === 0) {
6362
- if (firstArrowFrame - C_MAX_ADJUSTMENT < arrivalFrame) {
6363
- preblankFrame = arrivalFrame - firstArrowFrame + C_MAX_ADJUSTMENT;
6346
+ // キーパターン(デフォルト)に対応する矢印番号を格納
6347
+ convertreplaceNums();
6364
6348
 
6365
- // 譜面データの再読み込み
6366
- const noteExistObj = {
6367
- arrow: true,
6368
- frz: true,
6369
- dummyArrow: g_stateObj.shuffle === C_FLG_OFF,
6370
- dummyFrz: g_stateObj.shuffle === C_FLG_OFF,
6371
- };
6372
- const tmpObj = scoreConvert(g_rootObj, g_stateObj.scoreId, preblankFrame, dummyIdHeader);
6373
- for (let j = 0; j < keyNum; j++) {
6374
- Object.keys(noteExistObj).forEach(name => {
6375
- if (tmpObj[`${name}Data`][j] !== undefined && noteExistObj[name]) {
6376
- g_scoreObj[`${name}Data`][j] = copyArray2d(tmpObj[`${name}Data`][j]);
6377
- }
6378
- });
6379
- }
6349
+ const setData = (_data, _minLength = 1) => {
6350
+ return (hasArrayList(_data, _minLength) ? _data.concat() : []);
6351
+ }
6380
6352
 
6381
- Object.keys(g_dataMinObj).forEach(dataType => {
6382
- g_scoreObj[`${dataType}Data`] = setData(tmpObj[`${dataType}Data`], g_dataMinObj[dataType]);
6353
+ // フレーム・曲開始位置調整
6354
+ let preblankFrame = 0;
6355
+ if (g_scoreObj.frameNum === 0) {
6356
+ if (firstArrowFrame - C_MAX_ADJUSTMENT < arrivalFrame) {
6357
+ preblankFrame = arrivalFrame - firstArrowFrame + C_MAX_ADJUSTMENT;
6358
+
6359
+ // 譜面データの再読み込み
6360
+ const noteExistObj = {
6361
+ arrow: true,
6362
+ frz: true,
6363
+ dummyArrow: g_stateObj.shuffle === C_FLG_OFF,
6364
+ dummyFrz: g_stateObj.shuffle === C_FLG_OFF,
6365
+ };
6366
+ const tmpObj = scoreConvert(g_rootObj, g_stateObj.scoreId, preblankFrame, dummyIdHeader);
6367
+ for (let j = 0; j < keyNum; j++) {
6368
+ Object.keys(noteExistObj).forEach(name => {
6369
+ if (tmpObj[`${name}Data`][j] !== undefined && noteExistObj[name]) {
6370
+ g_scoreObj[`${name}Data`][j] = copyArray2d(tmpObj[`${name}Data`][j]);
6371
+ }
6383
6372
  });
6384
-
6385
- lastFrame += preblankFrame;
6386
- firstArrowFrame += preblankFrame;
6387
- speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
6388
- arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
6389
- g_headerObj.blankFrame += preblankFrame;
6390
6373
  }
6391
- }
6392
6374
 
6393
- // シャッフルグループ未定義の場合
6394
- if (g_keyObj[`shuffle${keyCtrlPtn}`] === undefined) {
6395
- g_keyObj[`shuffle${keyCtrlPtn}`] = [...Array(keyNum)].fill(0);
6375
+ Object.keys(g_dataMinObj).forEach(dataType => {
6376
+ g_scoreObj[`${dataType}Data`] = setData(tmpObj[`${dataType}Data`], g_dataMinObj[dataType]);
6377
+ });
6378
+
6379
+ lastFrame += preblankFrame;
6380
+ firstArrowFrame += preblankFrame;
6381
+ speedOnFrame = setSpeedOnFrame(g_scoreObj.speedData, lastFrame);
6382
+ arrivalFrame = getFirstArrivalFrame(firstFrame, speedOnFrame, motionOnFrame);
6383
+ g_headerObj.blankFrame += preblankFrame;
6396
6384
  }
6385
+ }
6397
6386
 
6398
- // シャッフルグループを扱いやすくする
6399
- // [0, 0, 0, 1, 0, 0, 0] -> [[0, 1, 2, 4, 5, 6], [3]]
6400
- const shuffleGroupMap = {};
6401
- g_keyObj[`shuffle${keyCtrlPtn}`].forEach((_val, _i) => {
6402
- if (shuffleGroupMap[_val] === undefined) {
6403
- shuffleGroupMap[_val] = [];
6404
- };
6405
- shuffleGroupMap[_val].push(_i);
6406
- });
6387
+ // シャッフルグループ未定義の場合
6388
+ if (g_keyObj[`shuffle${keyCtrlPtn}`] === undefined) {
6389
+ g_keyObj[`shuffle${keyCtrlPtn}`] = [...Array(keyNum)].fill(0);
6390
+ }
6407
6391
 
6408
- // Mirror,Random,S-Randomの適用
6409
- g_shuffleFunc[g_stateObj.shuffle](keyNum, Object.values(shuffleGroupMap));
6392
+ // シャッフルグループを扱いやすくする
6393
+ // [0, 0, 0, 1, 0, 0, 0] -> [[0, 1, 2, 4, 5, 6], [3]]
6394
+ const shuffleGroupMap = {};
6395
+ g_keyObj[`shuffle${keyCtrlPtn}`].forEach((_val, _i) => {
6396
+ if (shuffleGroupMap[_val] === undefined) {
6397
+ shuffleGroupMap[_val] = [];
6398
+ };
6399
+ shuffleGroupMap[_val].push(_i);
6400
+ });
6410
6401
 
6411
- // アシスト用の配列があれば、ダミーデータで上書き
6412
- if (typeof g_keyObj[`assistPos${keyCtrlPtn}`] === C_TYP_OBJECT &&
6413
- !g_autoPlaysBase.includes(g_stateObj.autoPlay)) {
6414
- const assistArray = g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay];
6415
- for (let j = 0; j < keyNum; j++) {
6416
- if (assistArray[j] === 1) {
6417
- g_scoreObj.dummyArrowData[j] = g_scoreObj.arrowData[j].concat();
6418
- g_scoreObj.arrowData[j] = [];
6419
- g_scoreObj.dummyFrzData[j] = g_scoreObj.frzData[j].concat();
6420
- g_scoreObj.frzData[j] = [];
6421
- } else {
6422
- g_scoreObj.dummyArrowData[j] = [];
6423
- g_scoreObj.dummyFrzData[j] = [];
6424
- }
6402
+ // Mirror,Random,S-Randomの適用
6403
+ g_shuffleFunc[g_stateObj.shuffle](keyNum, Object.values(shuffleGroupMap));
6404
+
6405
+ // アシスト用の配列があれば、ダミーデータで上書き
6406
+ if (typeof g_keyObj[`assistPos${keyCtrlPtn}`] === C_TYP_OBJECT &&
6407
+ !g_autoPlaysBase.includes(g_stateObj.autoPlay)) {
6408
+ const assistArray = g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay];
6409
+ for (let j = 0; j < keyNum; j++) {
6410
+ if (assistArray[j] === 1) {
6411
+ g_scoreObj.dummyArrowData[j] = g_scoreObj.arrowData[j].concat();
6412
+ g_scoreObj.arrowData[j] = [];
6413
+ g_scoreObj.dummyFrzData[j] = g_scoreObj.frzData[j].concat();
6414
+ g_scoreObj.frzData[j] = [];
6415
+ } else {
6416
+ g_scoreObj.dummyArrowData[j] = [];
6417
+ g_scoreObj.dummyFrzData[j] = [];
6425
6418
  }
6426
6419
  }
6420
+ }
6427
6421
 
6428
- // 矢印・フリーズアロー数をカウント
6429
- g_allArrow = 0;
6430
- g_allFrz = 0;
6431
- g_scoreObj.arrowData.forEach(data => g_allArrow += data.length);
6432
- g_scoreObj.frzData.forEach(data => g_allFrz += data.length);
6422
+ // 矢印・フリーズアロー数をカウント
6423
+ g_allArrow = 0;
6424
+ g_allFrz = 0;
6425
+ g_scoreObj.arrowData.forEach(data => g_allArrow += data.length);
6426
+ g_scoreObj.frzData.forEach(data => g_allFrz += data.length);
6433
6427
 
6434
- // ライフ回復・ダメージ量の計算
6435
- // フリーズ始点でも通常判定させる場合は総矢印数を水増しする
6436
- if (g_headerObj.frzStartjdgUse) {
6437
- g_allArrow += g_allFrz / 2;
6438
- }
6439
- g_fullArrows = g_allArrow + g_allFrz / 2;
6428
+ // ライフ回復・ダメージ量の計算
6429
+ // フリーズ始点でも通常判定させる場合は総矢印数を水増しする
6430
+ if (g_headerObj.frzStartjdgUse) {
6431
+ g_allArrow += g_allFrz / 2;
6432
+ }
6433
+ g_fullArrows = g_allArrow + g_allFrz / 2;
6440
6434
 
6441
- calcLifeVals(g_fullArrows);
6435
+ calcLifeVals(g_fullArrows);
6442
6436
 
6443
- // 矢印・フリーズアロー・速度/色変化格納処理
6444
- pushArrows(g_scoreObj, speedOnFrame, motionOnFrame, arrivalFrame);
6437
+ // 矢印・フリーズアロー・速度/色変化格納処理
6438
+ pushArrows(g_scoreObj, speedOnFrame, motionOnFrame, arrivalFrame);
6445
6439
 
6446
- // メインに入る前の最終初期化処理
6447
- getArrowSettings();
6440
+ // メインに入る前の最終初期化処理
6441
+ getArrowSettings();
6448
6442
 
6449
- // ユーザカスタムイベント
6450
- g_customJsObj.loading.forEach(func => func());
6443
+ // ユーザカスタムイベント
6444
+ g_customJsObj.loading.forEach(func => func());
6451
6445
 
6452
- const tempId = setInterval(() => {
6453
- const executeMain = _ => {
6454
- clearInterval(tempId);
6455
- MainInit();
6456
- }
6457
- if (g_audio.duration !== undefined) {
6458
- if (g_userAgent.indexOf(`firefox`) !== -1) {
6459
- if (g_preloadFiles.image.every(v => g_loadObj[v] === true)) {
6460
- executeMain();
6461
- }
6462
- } else {
6446
+ const tempId = setInterval(() => {
6447
+ const executeMain = _ => {
6448
+ clearInterval(tempId);
6449
+ MainInit();
6450
+ }
6451
+ if (g_audio.duration !== undefined) {
6452
+ if (g_userAgent.indexOf(`firefox`) !== -1) {
6453
+ if (g_preloadFiles.image.every(v => g_loadObj[v] === true)) {
6463
6454
  executeMain();
6464
6455
  }
6456
+ } else {
6457
+ executeMain();
6465
6458
  }
6466
- }, 100);
6467
- });
6459
+ }
6460
+ }, 100);
6468
6461
  }
6469
6462
 
6470
6463
  function setScoreIdHeader(_scoreId = 0, _scoreLockFlg = false) {
@@ -6949,7 +6942,7 @@ function scoreConvert(_dosObj, _scoreId, _preblankFrame, _dummyNo = ``,
6949
6942
  break;
6950
6943
  } else {
6951
6944
  wordData[tmpWordData[k]][addFrame].push(tmpWordData[k + 1],
6952
- escapeHtmlForEnabledTag(setVal(tmpWordData[k + 2], ``, C_TYP_STRING)));
6945
+ escapeHtmlForEnabledTag(tmpWordData[k + 2] ?? ``));
6953
6946
  }
6954
6947
  }
6955
6948
  });
@@ -10035,9 +10028,9 @@ function resultInit() {
10035
10028
  .split(`[maxCombo]`).join(tweetMaxCombo)
10036
10029
  .split(`[url]`).join(`${twiturl.toString()}`.replace(/[\t\n]/g, ``));
10037
10030
 
10038
- if (typeof g_presetResultVals === C_TYP_OBJECT) {
10039
- Object.keys(g_presetResultVals).forEach(key => {
10040
- tweetResultTmp = tweetResultTmp.split(`[${key}]`).join(g_resultObj[g_presetResultVals[key]]);
10031
+ if (g_presetObj.resultVals !== undefined) {
10032
+ Object.keys(g_presetObj.resultVals).forEach(key => {
10033
+ tweetResultTmp = tweetResultTmp.split(`[${key}]`).join(g_resultObj[g_presetObj.resultVals[key]]);
10041
10034
  });
10042
10035
  }
10043
10036
  const resultText = `${unEscapeHtml(tweetResultTmp)}`;