danoniplus 50.4.0 → 50.5.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 +479 -16549
- package/js/lib/danoni_constants.js +2 -1
- package/js/lib/dataLoader.js +2837 -0
- package/js/lib/dosConverter.js +3093 -0
- package/js/lib/keyconfig.js +1932 -0
- package/js/lib/mainWindow.js +2626 -0
- package/js/lib/result.js +979 -0
- package/js/lib/settings.js +3426 -0
- package/js/lib/title.js +1274 -0
- package/package.json +1 -1
|
@@ -0,0 +1,3093 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dancing☆Onigiri (CW Edition)
|
|
3
|
+
* 譜面データを分割してグローバル変数に格納する処理群
|
|
4
|
+
* - ページ: initial
|
|
5
|
+
*
|
|
6
|
+
* Source by tickle
|
|
7
|
+
* Created : 2026/09/13
|
|
8
|
+
* Revised :
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/cwtickle/danoniplus
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/*-----------------------------------------------------------*/
|
|
14
|
+
/* Scene : INITIALIZE [peach] */
|
|
15
|
+
/*-----------------------------------------------------------*/
|
|
16
|
+
|
|
17
|
+
const initialControl = async () => {
|
|
18
|
+
|
|
19
|
+
const stage = document.getElementById(`canvas-frame`);
|
|
20
|
+
const divRoot = createEmptySprite(stage, `divRoot`, g_windowObj.divRoot);
|
|
21
|
+
g_workPath = validatePath(document.getElementById(`jsRootUrl`)?.value,
|
|
22
|
+
new URL(location.href).href.match(/(^.*\/)/)[0]);
|
|
23
|
+
|
|
24
|
+
// 背景の表示
|
|
25
|
+
if (document.getElementById(`layer0`) !== null) {
|
|
26
|
+
const layer0 = document.getElementById(`layer0`);
|
|
27
|
+
makeBgCanvas(layer0.getContext(`2d`));
|
|
28
|
+
} else {
|
|
29
|
+
createEmptySprite(divRoot, `divBack`, g_windowObj.divBack);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Now Loadingを表示
|
|
33
|
+
divRoot.appendChild(getLoadingLabel());
|
|
34
|
+
|
|
35
|
+
// 譜面初期情報ロード許可フラグ
|
|
36
|
+
g_canLoadDifInfoFlg = true;
|
|
37
|
+
|
|
38
|
+
// 譜面データの読み込みオプション
|
|
39
|
+
g_enableAmpersandSplit = setBoolVal(document.getElementById(`enableAmpersandSplit`)?.value, true);
|
|
40
|
+
g_enableDecodeURI = setBoolVal(document.getElementById(`enableDecodeURI`)?.value);
|
|
41
|
+
|
|
42
|
+
// 作品別ローカルストレージの読み込み
|
|
43
|
+
loadLocalStorage();
|
|
44
|
+
|
|
45
|
+
// 譜面データの読み込み(1ファイル目)
|
|
46
|
+
await loadChartFile(0);
|
|
47
|
+
|
|
48
|
+
// 共通設定ファイルの指定
|
|
49
|
+
let tmpSettingType = g_rootObj.settingType ?? ``;
|
|
50
|
+
if (g_remoteFlg && !tmpSettingType.includes(C_MRK_CURRENT_DIRECTORY)) {
|
|
51
|
+
tmpSettingType = `${C_MRK_CURRENT_DIRECTORY}../js/${tmpSettingType}`;
|
|
52
|
+
};
|
|
53
|
+
let [settingType, settingRoot] = getFilePath(tmpSettingType);
|
|
54
|
+
if (settingType !== ``) {
|
|
55
|
+
settingType = `_${settingType}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 共通設定ファイルの読込
|
|
59
|
+
await loadScript2(`${settingRoot}danoni_setting${settingType}.js?${g_randTime}`, false);
|
|
60
|
+
loadLegacySettingFunc();
|
|
61
|
+
deleteDiv(divRoot, `lblLoading`);
|
|
62
|
+
|
|
63
|
+
// クエリで譜面番号が指定されていればセット
|
|
64
|
+
g_stateObj.scoreId = setIntVal(getQueryParamVal(`scoreId`));
|
|
65
|
+
|
|
66
|
+
// 譜面ヘッダーの読込
|
|
67
|
+
Object.assign(g_headerObj, preheaderConvert(g_rootObj));
|
|
68
|
+
|
|
69
|
+
// CSSファイル内のbackgroundを取得するために再描画
|
|
70
|
+
if (document.getElementById(`layer0`) === null) {
|
|
71
|
+
deleteDiv(divRoot, `divBack`);
|
|
72
|
+
createEmptySprite(divRoot, `divBack`);
|
|
73
|
+
} else if (!g_headerObj.defaultSkinFlg && !g_headerObj.customBackUse) {
|
|
74
|
+
createEmptySprite(divRoot, `divBack`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// CSSファイルの読み込み
|
|
78
|
+
const skinList = g_headerObj.jsData.filter(file => file[0].indexOf(`danoni_skin`) !== -1);
|
|
79
|
+
await loadMultipleFiles2(skinList, `css`);
|
|
80
|
+
|
|
81
|
+
// JSファイルの読み込み
|
|
82
|
+
await loadMultipleFiles2(g_headerObj.jsData, `js`);
|
|
83
|
+
loadLegacyCustomFunc();
|
|
84
|
+
|
|
85
|
+
// 譜面ヘッダー、特殊キー情報の読込
|
|
86
|
+
Object.assign(g_headerObj, headerConvert(g_rootObj));
|
|
87
|
+
g_headerObj.undefinedKeyListFinal = [];
|
|
88
|
+
const importKeysData = _data => {
|
|
89
|
+
keysConvert(dosConvert(_data));
|
|
90
|
+
g_headerObj.undefinedKeyLists = g_headerObj.undefinedKeyLists.filter(key => g_keyObj[`${g_keyObj.defaultProp}${key}_0`] === undefined);
|
|
91
|
+
};
|
|
92
|
+
g_presetObj.keysDataLib.forEach(list => importKeysData(list));
|
|
93
|
+
if (g_presetObj.keysData !== undefined) {
|
|
94
|
+
g_presetObj.keysDataLocal.unshift(g_presetObj.keysData);
|
|
95
|
+
}
|
|
96
|
+
g_presetObj.keysDataLocal.forEach(list => importKeysData(list));
|
|
97
|
+
g_headerObj.keyExtraList = keysConvert(g_rootObj, {
|
|
98
|
+
keyExtraList: makeDedupliArray(g_headerObj.undefinedKeyLists, g_rootObj.keyExtraList?.split(`,`)),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// キー定義でエラーになる場合は強制的にデフォルトキーへ変更して続行
|
|
102
|
+
let hasUndefinedKey = false;
|
|
103
|
+
for (let j = 0; j < g_headerObj.keyLabels.length; j++) {
|
|
104
|
+
if (g_headerObj.undefinedKeyListFinal.includes(g_headerObj.keyLabels[j])) {
|
|
105
|
+
g_headerObj.keyLists = g_headerObj.keyLists.filter(key => key !== g_headerObj.keyLabels[j]);
|
|
106
|
+
g_headerObj.keyLabels[j] = g_keyObj.initKeyLabel;
|
|
107
|
+
hasUndefinedKey = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (hasUndefinedKey) {
|
|
111
|
+
g_headerObj.keyLists = makeDedupliArray(g_headerObj.keyLists, [g_keyObj.initKeyLabel])
|
|
112
|
+
.sort((a, b) => parseInt(a) - parseInt(b));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ラベルテキスト、オンマウステキスト、確認メッセージ定義の上書き設定
|
|
116
|
+
Object.assign(g_lblNameObj, g_lang_lblNameObj[g_localeObj.val], g_presetObj.lblName?.[g_localeObj.val]);
|
|
117
|
+
Object.assign(g_msgObj, g_lang_msgObj[g_localeObj.val], g_presetObj.msg?.[g_localeObj.val]);
|
|
118
|
+
|
|
119
|
+
// デフォルトのカラー・シャッフルグループ設定を退避
|
|
120
|
+
g_keycons.groups.forEach(type =>
|
|
121
|
+
Object.keys(g_keyObj).filter(val => val.startsWith(type))
|
|
122
|
+
.forEach(property => g_keyObj[`${property}d`] = structuredClone(g_keyObj[property])));
|
|
123
|
+
|
|
124
|
+
// 自動横幅拡張設定
|
|
125
|
+
if (g_headerObj.autoSpread) {
|
|
126
|
+
g_sWidth = Math.max(g_sWidth, g_presetObj.autoMinWidth ?? g_keyObj.minWidth);
|
|
127
|
+
g_headerObj.keyLists.forEach(key => {
|
|
128
|
+
g_sWidth = Math.max(g_sWidth, g_keyObj[`minWidth${key}`] ?? g_keyObj.minWidthDefault);
|
|
129
|
+
|
|
130
|
+
// 別キーモード有効時は、別キーモード毎の横幅を拡張対象へ追加
|
|
131
|
+
if (g_headerObj.transKeyUse) {
|
|
132
|
+
for (let k = 1; hasVal(g_keyObj[`keyCtrl${key}_${k}`]); k++) {
|
|
133
|
+
const anotherKey = g_keyObj[`transKey${key}_${k}`] ?? ``;
|
|
134
|
+
if (anotherKey !== ``) {
|
|
135
|
+
g_sWidth = Math.max(g_sWidth, g_keyObj[`minWidth${anotherKey}`] ?? g_keyObj.minWidthDefault);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
$id(`canvas-frame`).width = wUnit(g_sWidth);
|
|
142
|
+
$id(`divRoot`).width = wUnit(g_sWidth);
|
|
143
|
+
}
|
|
144
|
+
if (g_headerObj.playingWidth === `default`) {
|
|
145
|
+
g_headerObj.playingWidth = g_sWidth;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 可変ウィンドウサイズを更新
|
|
149
|
+
updateWindowSiz();
|
|
150
|
+
|
|
151
|
+
// キー数情報を初期化
|
|
152
|
+
g_keyObj.currentKey = g_headerObj.keyLabels[g_stateObj.scoreId];
|
|
153
|
+
g_keyObj.currentPtn = 0;
|
|
154
|
+
|
|
155
|
+
// 画像ファイルの読み込み
|
|
156
|
+
g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
|
|
157
|
+
|
|
158
|
+
// その他の画像ファイルの読み込み
|
|
159
|
+
g_headerObj.preloadImages.filter(image => hasVal(image)).forEach(preloadImage => {
|
|
160
|
+
|
|
161
|
+
// Pattern A: |preloadImages=file.png|
|
|
162
|
+
// Pattern B: |preloadImages=file*.png@10| -> file01.png ~ file10.png
|
|
163
|
+
// Pattern C: |preloadImages=file*.png@2-9| -> file2.png ~ file9.png
|
|
164
|
+
// Pattern D: |preloadImages=file*.png@003-018| -> file003.png ~ file018.png
|
|
165
|
+
|
|
166
|
+
const tmpPreloadImages = preloadImage.split(`@`);
|
|
167
|
+
if (tmpPreloadImages.length === 1) {
|
|
168
|
+
// Pattern Aの場合
|
|
169
|
+
preloadFile(`image`, preloadImage);
|
|
170
|
+
} else {
|
|
171
|
+
const termRoopCnts = tmpPreloadImages[1].split(`-`);
|
|
172
|
+
let startCnt = 1;
|
|
173
|
+
let lastCnt;
|
|
174
|
+
let paddingLen;
|
|
175
|
+
|
|
176
|
+
if (termRoopCnts.length === 1) {
|
|
177
|
+
// Pattern Bの場合
|
|
178
|
+
lastCnt = setIntVal(tmpPreloadImages[1], 1);
|
|
179
|
+
paddingLen = String(setVal(tmpPreloadImages[1], 1)).length;
|
|
180
|
+
} else {
|
|
181
|
+
// Pattern C, Dの場合
|
|
182
|
+
startCnt = setIntVal(termRoopCnts[0], 1);
|
|
183
|
+
lastCnt = setIntVal(termRoopCnts[1], 1);
|
|
184
|
+
paddingLen = String(setVal(termRoopCnts[1], 1)).length;
|
|
185
|
+
}
|
|
186
|
+
for (let k = startCnt; k <= lastCnt; k++) {
|
|
187
|
+
preloadFile(`image`, tmpPreloadImages[0].replaceAll(`*`, String(k).padStart(paddingLen, `0`)));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// ローカルファイル起動時に各種警告文を表示
|
|
193
|
+
if (g_isFile) {
|
|
194
|
+
makeWarningWindow(g_msgInfoObj.W_0011);
|
|
195
|
+
if (!listMatching(getMusicUrl(g_stateObj.scoreId), [`.js`, `.txt`], { suffix: `$` })) {
|
|
196
|
+
if (g_userAgent.indexOf(`firefox`) !== -1) {
|
|
197
|
+
makeWarningWindow(g_msgInfoObj.W_0001);
|
|
198
|
+
}
|
|
199
|
+
makeWarningWindow(g_msgInfoObj.W_0012);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (g_loadObj.main) {
|
|
204
|
+
|
|
205
|
+
// 譜面分割、譜面番号固定かどうかをチェック
|
|
206
|
+
g_stateObj.dosDivideFlg = setBoolVal(document.getElementById(`externalDosDivide`)?.value ?? getQueryParamVal(`dosDivide`));
|
|
207
|
+
g_stateObj.scoreLockFlg = setBoolVal(document.getElementById(`externalDosLock`)?.value ?? getQueryParamVal(`dosLock`));
|
|
208
|
+
|
|
209
|
+
// 非分割時は resetGaugeSetting が全難易度を一括構築するため、初回のみで十分
|
|
210
|
+
const loopCount = g_stateObj.dosDivideFlg ? g_headerObj.keyLabels.length : 1;
|
|
211
|
+
|
|
212
|
+
for (let j = 0; j < g_headerObj.keyLabels.length; j++) {
|
|
213
|
+
|
|
214
|
+
// 譜面ファイルが分割されている場合、譜面詳細情報取得のために譜面をロード
|
|
215
|
+
if (g_stateObj.dosDivideFlg) {
|
|
216
|
+
await loadChartFile(j);
|
|
217
|
+
resetColorSetting(j);
|
|
218
|
+
}
|
|
219
|
+
getScoreDetailData(j);
|
|
220
|
+
if (j < loopCount) {
|
|
221
|
+
// 分割時は各譜面ごとに上書き・補完、非分割時は初回のみ実行
|
|
222
|
+
resetGaugeSetting(j);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
safeExecuteCustomHooks(`g_customJsObj.preTitle`, g_customJsObj.preTitle);
|
|
227
|
+
const queryMusicId = getQueryParamVal(`musicId`);
|
|
228
|
+
g_settings.musicIdxNum = queryMusicId !== null ? Number(queryMusicId) :
|
|
229
|
+
g_headerObj.musicGroups?.[g_headerObj.musicNos[g_stateObj.scoreId]] ??
|
|
230
|
+
g_headerObj.musicNos[g_stateObj.scoreId] ?? g_headerObj.musicNos[0];
|
|
231
|
+
titleInit(true);
|
|
232
|
+
|
|
233
|
+
// 未使用のg_keyObjプロパティを削除
|
|
234
|
+
const keyProp = g_keyCopyLists.simple.concat(
|
|
235
|
+
g_keyCopyLists.multiple,
|
|
236
|
+
`keyCtrl`, `keyName`, `minWidth`, `movLock`, `initManual`, `ptchara`
|
|
237
|
+
);
|
|
238
|
+
const delKeyPropList = [`ptchara7`, `dfPtnNum`, `minKeyCtrlNum`, `minPatterns`];
|
|
239
|
+
Object.keys(g_keyObj).forEach(key => {
|
|
240
|
+
const type = keyProp.find(prop => key.startsWith(prop)) || ``;
|
|
241
|
+
if (type !== ``) {
|
|
242
|
+
const keyName = String(key.split(`_`)[0].slice(type.length));
|
|
243
|
+
if (!g_headerObj.keyLists.includes(keyName) && keyName !== `` && keyName !== `Default`) {
|
|
244
|
+
delete g_keyObj[key];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (key.match(/^chara7_[a-z]/) || delKeyPropList.includes(key) || g_keyObj[key] === undefined) {
|
|
248
|
+
delete g_keyObj[key];
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
g_stateObj.keyInitial = true;
|
|
253
|
+
|
|
254
|
+
// エディター用のフォーマッター作成
|
|
255
|
+
const customKeyList = g_headerObj.keyLists.filter(val =>
|
|
256
|
+
g_keyObj.defaultKeyList.findIndex(key => key === val) < 0);
|
|
257
|
+
|
|
258
|
+
if (customKeyList.length === 0) {
|
|
259
|
+
g_settings.preconditions = g_settings.preconditions.filter(val => !val.includes(`g_editorTmp`));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const addNewOrderGroup = (_orgList, _sortRule) => {
|
|
263
|
+
// インデックスを保持した配列を作成、ルールに従ってソート
|
|
264
|
+
const indexedList = _orgList.map((value, idx) => ({ value, idx }));
|
|
265
|
+
const sortedList = [...indexedList].sort(_sortRule);
|
|
266
|
+
// ソート後の配列のインデックスに基づいて、元のインデックスを取得
|
|
267
|
+
const newIdxs = sortedList.map(({ idx }) => indexedList.findIndex(({ idx: originalIdx }) => originalIdx === idx));
|
|
268
|
+
return !newIdxs.every((val, j) => val === j) ? newIdxs : undefined;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
customKeyList.forEach(key => {
|
|
272
|
+
const keyBase = `${key}_0`;
|
|
273
|
+
const keyCtrlPtn = `${g_keyObj.defaultProp}${keyBase}`;
|
|
274
|
+
const keyGroup = g_keyObj[`keyGroup${keyBase}`];
|
|
275
|
+
const keyGroupList = makeDedupliArray(keyGroup.flat());
|
|
276
|
+
const orgKeyNum = g_keyObj[keyCtrlPtn].length;
|
|
277
|
+
const baseX = Math.floor(Math.random() * (100 - keyGroupList.length));
|
|
278
|
+
|
|
279
|
+
const divPos = g_keyObj[`div${keyBase}`];
|
|
280
|
+
const divMaxPos = g_keyObj[`divMax${keyBase}`] ?? Math.max(...g_keyObj[`pos${keyBase}`]) + 1;
|
|
281
|
+
const stdPos = Math.max(divPos, divMaxPos - divPos);
|
|
282
|
+
const [deltaXAbove, deltaXBelow] = [(divPos - stdPos) / 2, (divMaxPos - divPos - stdPos) / 2];
|
|
283
|
+
|
|
284
|
+
keyGroupList.forEach((keyGroupNo, j) => {
|
|
285
|
+
const keyN = keyGroupNo === `0` ? key : `${key}_${j + 1}`;
|
|
286
|
+
const filterCond = (r) => keyGroup[r].findIndex(val => val === keyGroupNo) >= 0;
|
|
287
|
+
const keyCtrlList = g_keyObj[keyCtrlPtn].filter((val, r) => filterCond(r));
|
|
288
|
+
const charaList = g_keyObj[`chara${keyBase}`].filter((val, r) => filterCond(r));
|
|
289
|
+
const colorList = g_keyObj[`color${keyBase}_0`].filter((val, r) => filterCond(r));
|
|
290
|
+
const stepRtnList = g_keyObj[`stepRtn${keyBase}_0`].filter((val, r) => filterCond(r));
|
|
291
|
+
const keyNum = g_keyObj[keyCtrlPtn].filter((val, r) => filterCond(r)).length;
|
|
292
|
+
|
|
293
|
+
// ---- Dancing☆Onigiri (CW Edition対応)のフォーマット
|
|
294
|
+
g_editorTmp[keyN] = {};
|
|
295
|
+
g_editorTmp[keyN].id = orgKeyNum * 100 + baseX + j;
|
|
296
|
+
g_editorTmp[keyN].num = keyNum;
|
|
297
|
+
g_editorTmp[keyN].chars = keyCtrlList.map(val => g_kCd[val[0]]);
|
|
298
|
+
g_editorTmp[keyN].keys = keyCtrlList.map(val => g_kCdN[val[0]]).map(val => replaceStr(val, g_escapeStr.editorKey));
|
|
299
|
+
g_editorTmp[keyN].alternativeKeys = keyCtrlList.map(val => val[1] === 0 ? `` : g_kCdN[val[1]]).map(val => replaceStr(val, g_escapeStr.editorKey));
|
|
300
|
+
g_editorTmp[keyN].noteNames = charaList.map(val => `${val}_data`);
|
|
301
|
+
g_editorTmp[keyN].freezeNames = charaList.map(val => {
|
|
302
|
+
let frzName = replaceStr(val, g_escapeStr.frzName);
|
|
303
|
+
if (frzName.indexOf(`frz`) === -1 && frzName.indexOf(`foni`) === -1) {
|
|
304
|
+
frzName = frzName.replaceAll(frzName, `frz${toCapitalize(frzName)}`);
|
|
305
|
+
}
|
|
306
|
+
return `${frzName}_data`;
|
|
307
|
+
});
|
|
308
|
+
g_editorTmp[keyN].colorGroup = colorList.map(val => val % 3);
|
|
309
|
+
|
|
310
|
+
// orderGroupsのカスタマイズ
|
|
311
|
+
if (divMaxPos > divPos) {
|
|
312
|
+
|
|
313
|
+
// posXの実際の相対位置を計算
|
|
314
|
+
const orgPosList = g_keyObj[`pos${keyBase}`].filter((val, r) => filterCond(r));
|
|
315
|
+
const posList = orgPosList.map(val => val < divPos ? val - deltaXAbove : val - divPos - deltaXBelow);
|
|
316
|
+
|
|
317
|
+
g_editorTmp[keyN].orderGroups = [];
|
|
318
|
+
|
|
319
|
+
// パターン1: 上下グループ分けして各グループ内で位置順にソート(上下反転)
|
|
320
|
+
const upDownIdxs = addNewOrderGroup(orgPosList, (a, b) => {
|
|
321
|
+
const aAbove = a.value < divPos;
|
|
322
|
+
const bAbove = b.value < divPos;
|
|
323
|
+
if (aAbove !== bAbove) return Number(aAbove) - Number(bAbove);
|
|
324
|
+
return a.value - b.value;
|
|
325
|
+
});
|
|
326
|
+
if (upDownIdxs !== undefined) {
|
|
327
|
+
g_editorTmp[keyN].orderGroups.push(upDownIdxs);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// パターン2: 単純にステップゾーンのX座標が小さい順にソート
|
|
331
|
+
const sortedIdxs = addNewOrderGroup(posList, (a, b) => a.value - b.value);
|
|
332
|
+
if (sortedIdxs !== undefined) {
|
|
333
|
+
g_editorTmp[keyN].orderGroups.push(sortedIdxs);
|
|
334
|
+
}
|
|
335
|
+
if (g_editorTmp[keyN].orderGroups.length === 0) {
|
|
336
|
+
delete g_editorTmp[keyN].orderGroups;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ---- ダンおに譜面作成エディタ ver3フォーマット
|
|
341
|
+
|
|
342
|
+
// 既存のシャッフルグループからミラー配列を自動生成
|
|
343
|
+
let k = 0, n = 0, convTxt = ``;
|
|
344
|
+
let prevMirrorList = [];
|
|
345
|
+
while (g_keyObj[`shuffle${keyBase}_${k}`] !== undefined) {
|
|
346
|
+
|
|
347
|
+
const orgTmpList = []
|
|
348
|
+
const mirrorTmpList = [];
|
|
349
|
+
const mirrorList = [];
|
|
350
|
+
g_keyObj[`shuffle${keyBase}_${k}`].filter((val, m) => filterCond(m))
|
|
351
|
+
.forEach((_val, _i) => orgTmpList[_val]?.push(_i) || (orgTmpList[_val] = [_i]));
|
|
352
|
+
orgTmpList.forEach((list, idx) => mirrorTmpList[idx] = list.toReversed());
|
|
353
|
+
orgTmpList?.forEach((list, a) => list?.forEach((val, b) => mirrorList[orgTmpList[a][b]] = mirrorTmpList[a][b]));
|
|
354
|
+
if (!mirrorList.every((val, p) => val === prevMirrorList[p])) {
|
|
355
|
+
convTxt += `\$conv${n + 1}=Mirror${n + 1},${mirrorList.join(',')}<br>`;
|
|
356
|
+
prevMirrorList = mirrorList.concat();
|
|
357
|
+
n++;
|
|
358
|
+
}
|
|
359
|
+
k++;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 矢印・フリーズアローのヘッダー情報を定義
|
|
363
|
+
const noteTxt = g_editorTmp[keyN].noteNames.map((val, r) =>
|
|
364
|
+
`|${val.slice(0, -(`_data`.length))}[i]_data=[a${String(r).padStart(2, `0`)}]|[E]<br>`).join(``);
|
|
365
|
+
|
|
366
|
+
const freezeTxt = g_editorTmp[keyN].freezeNames.map((val, r) =>
|
|
367
|
+
`|${val.slice(0, -(`_data`.length))}[i]_data=[f${String(r).padStart(2, `0`)}]|[E]<br>`).join(``);
|
|
368
|
+
|
|
369
|
+
g_editorTmp2 += g_editorTmp2Template
|
|
370
|
+
.replace(`[__KEY__]`, keyN)
|
|
371
|
+
.replace(`[__MAP__]`, colorList.map(val => val < 3 ? (val + 1) % 3 : val % 7).join(','))
|
|
372
|
+
.replace(`[__POS__]`, fillArray(keyNum).map((val, r) =>
|
|
373
|
+
isNaN(parseFloat(stepRtnList[r])) ? 28 : 24).join(`,`))
|
|
374
|
+
.replace(`[__TXT__]`, g_editorTmp[keyN].chars.map(val => val.replace(`, `, ``)).join(`,`))
|
|
375
|
+
.replace(`[__CONV__]`, convTxt)
|
|
376
|
+
.replace(`[__NOTE__]`, noteTxt)
|
|
377
|
+
.replace(`[__FREEZE__]`, freezeTxt)
|
|
378
|
+
.replaceAll(`\n`, ``);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* 作品別ローカルストレージの読み込み・初期設定
|
|
385
|
+
* @param {string} _musicId 楽曲ID
|
|
386
|
+
*/
|
|
387
|
+
const loadLocalStorage = (_musicId = ``) => {
|
|
388
|
+
|
|
389
|
+
// 作品別ローカルストレージのキー(URL)取得のため、
|
|
390
|
+
// scoreId, h, debug, musicIdを削除
|
|
391
|
+
// 選択中の楽曲ID(_musicId)がある場合は、キーとして区別するため追加
|
|
392
|
+
const url = new URL(location.href);
|
|
393
|
+
url.searchParams.delete(`scoreId`);
|
|
394
|
+
url.searchParams.delete(`h`);
|
|
395
|
+
url.searchParams.delete(`debug`);
|
|
396
|
+
url.searchParams.delete(`musicId`);
|
|
397
|
+
g_localStorageUrl = url.toString();
|
|
398
|
+
|
|
399
|
+
// リザルト表示用のURL組み立てのため、_musicIdのないURLを保存
|
|
400
|
+
g_localStorageUrlOrg = g_localStorageUrl;
|
|
401
|
+
|
|
402
|
+
if (_musicId !== ``) {
|
|
403
|
+
url.searchParams.append(`musicId`, _musicId);
|
|
404
|
+
g_localStorageUrl = url.toString();
|
|
405
|
+
if (g_langStorage.safeMode === C_FLG_ON) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* ローカルストレージの初期値設定
|
|
412
|
+
* @param {string} _name
|
|
413
|
+
* @param {string} _type
|
|
414
|
+
* @param {number} _defaultPos
|
|
415
|
+
*/
|
|
416
|
+
const checkLocalParam = (_name, _type = C_TYP_STRING, _defaultPos = 0) => {
|
|
417
|
+
const defaultVal = g_settings[`${_name}s`][_defaultPos];
|
|
418
|
+
if (g_localStorage[_name] !== undefined) {
|
|
419
|
+
g_stateObj[_name] = setVal(g_localStorage[_name], defaultVal, _type);
|
|
420
|
+
g_settings[`${_name}Num`] = roundZero(g_settings[`${_name}s`].findIndex(val => val === g_stateObj[_name]), defaultVal);
|
|
421
|
+
} else {
|
|
422
|
+
g_localStorage[_name] = defaultVal;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// ロケールの読込、警告メッセージの入替
|
|
427
|
+
g_langStorage = parseStorageData(`danoni-locale`);
|
|
428
|
+
if (g_langStorage.locale !== undefined) {
|
|
429
|
+
g_localeObj.val = g_langStorage.locale;
|
|
430
|
+
g_localeObj.num = g_localeObj.list.findIndex(val => val === g_localeObj.val);
|
|
431
|
+
}
|
|
432
|
+
if (g_langStorage.safeMode === undefined) {
|
|
433
|
+
g_langStorage.safeMode = C_FLG_OFF;
|
|
434
|
+
}
|
|
435
|
+
if (g_langStorage.bgmVolume === undefined) {
|
|
436
|
+
g_langStorage.bgmVolume = 50;
|
|
437
|
+
}
|
|
438
|
+
g_stateObj.bgmVolume = g_langStorage.bgmVolume;
|
|
439
|
+
g_settings.bgmVolumeNum = g_settings.volumes.findIndex(val => val === g_stateObj.bgmVolume);
|
|
440
|
+
Object.assign(g_msgInfoObj, g_lang_msgInfoObj[g_localeObj.val]);
|
|
441
|
+
Object.assign(g_kCd, g_lang_kCd[g_localeObj.val]);
|
|
442
|
+
|
|
443
|
+
// 作品別ローカルストレージの読込
|
|
444
|
+
if (g_langStorage.safeMode === C_FLG_OFF) {
|
|
445
|
+
g_localStorage = parseStorageData(g_localStorageUrl, {
|
|
446
|
+
adjustment: 0, hitPosition: 0, volume: 100, highscores: {},
|
|
447
|
+
});
|
|
448
|
+
} else {
|
|
449
|
+
g_localStorage = {};
|
|
450
|
+
g_stateObj.dataSaveFlg = false;
|
|
451
|
+
makeWarningWindow(g_msgInfoObj.W_0031);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Adjustment, Volume, Appearance, Opacity, HitPosition初期値設定
|
|
455
|
+
checkLocalParam(`adjustment`, C_TYP_FLOAT, g_settings.adjustmentNum);
|
|
456
|
+
checkLocalParam(`volume`, C_TYP_NUMBER, g_settings.volumes.length - 1);
|
|
457
|
+
checkLocalParam(`appearance`);
|
|
458
|
+
checkLocalParam(`opacity`, C_TYP_NUMBER, g_settings.opacitys.length - 1);
|
|
459
|
+
checkLocalParam(`hitPosition`, C_TYP_FLOAT, g_settings.hitPositionNum);
|
|
460
|
+
|
|
461
|
+
// ハイスコア取得準備
|
|
462
|
+
if (g_localStorage.highscores === undefined) {
|
|
463
|
+
g_localStorage.highscores = {};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// 廃棄済みリストからデータを消去
|
|
467
|
+
g_storeSettingsEx.filter(val => g_localStorage[val] !== undefined)
|
|
468
|
+
.forEach(val => delete g_localStorage[val]);
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* 譜面データを分割して値を取得
|
|
473
|
+
* @param {string} _dos 譜面データ
|
|
474
|
+
* @returns
|
|
475
|
+
*/
|
|
476
|
+
const dosConvert = (_dos = ``) => {
|
|
477
|
+
|
|
478
|
+
const obj = {};
|
|
479
|
+
const paramsTmp = g_enableAmpersandSplit ? _dos.split(`&`).join(`|`) : _dos;
|
|
480
|
+
paramsTmp.split(`|`).filter(param => param.indexOf(`=`) > 0).forEach(param => {
|
|
481
|
+
const pos = param.indexOf(`=`);
|
|
482
|
+
const pKey = param.substring(0, pos);
|
|
483
|
+
const pValue = param.substring(pos + 1);
|
|
484
|
+
|
|
485
|
+
if (pKey !== undefined) {
|
|
486
|
+
obj[pKey] = g_enableDecodeURI ? decodeURIComponent(pValue) : pValue;
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
return obj;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 譜面読込
|
|
494
|
+
* @param {number} _scoreId 譜面番号
|
|
495
|
+
*/
|
|
496
|
+
const loadChartFile = async (_scoreId = g_stateObj.scoreId) => {
|
|
497
|
+
|
|
498
|
+
const dosInput = document.getElementById(`dos`);
|
|
499
|
+
const divRoot = document.getElementById(`divRoot`);
|
|
500
|
+
const queryDos = getQueryParamVal(`dos`) !== null ?
|
|
501
|
+
`dos/${getQueryParamVal('dos')}.txt` : encodeURI(document.getElementById(`externalDos`)?.value ?? ``);
|
|
502
|
+
|
|
503
|
+
if (dosInput === null && queryDos === ``) {
|
|
504
|
+
makeWarningWindow(g_msgInfoObj.E_0023);
|
|
505
|
+
g_loadObj.main = false;
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// 譜面分割あり、譜面番号固定時のみ譜面データを一時クリア
|
|
510
|
+
if (queryDos !== `` && g_stateObj.dosDivideFlg && g_stateObj.scoreLockFlg) {
|
|
511
|
+
Object.keys(g_rootObj).filter(data => fuzzyListMatching(data, g_checkStr.resetDosHeader, g_checkStr.resetDosFooter))
|
|
512
|
+
.forEach(scoredata => g_rootObj[scoredata] = ``);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// HTML埋め込みdos
|
|
516
|
+
if (dosInput !== null && _scoreId === 0) {
|
|
517
|
+
Object.assign(g_rootObj, dosConvert(dosInput.value));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// 外部dos読み込み
|
|
521
|
+
if (queryDos !== ``) {
|
|
522
|
+
const charset = document.getElementById(`externalDosCharset`)?.value ?? document.characterSet;
|
|
523
|
+
const fileBase = queryDos.match(/.+\..*/)[0];
|
|
524
|
+
const fileExtension = fileBase.split(`.`).pop();
|
|
525
|
+
const fileCommon = fileBase.split(`.${fileExtension}`)[0];
|
|
526
|
+
const filename = `${fileCommon}${g_stateObj.dosDivideFlg ?
|
|
527
|
+
setDosIdHeader(_scoreId, g_stateObj.scoreLockFlg) : ''}.${fileExtension}`;
|
|
528
|
+
|
|
529
|
+
await loadScript2(`${filename}?${Date.now()}`, false, charset);
|
|
530
|
+
if (typeof externalDosInit === C_TYP_FUNCTION) {
|
|
531
|
+
|
|
532
|
+
// 外部データを読込(ファイルが見つからなかった場合は譜面追記をスキップ)
|
|
533
|
+
externalDosInit();
|
|
534
|
+
if (g_loadObj[filename]) {
|
|
535
|
+
Object.assign(g_rootObj, dosConvert(g_externalDos));
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
} else {
|
|
539
|
+
makeWarningWindow(g_msgInfoObj.E_0022);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* 譜面をファイルで分割している場合に初期色を追加取得
|
|
546
|
+
* @param {string} _scoreId
|
|
547
|
+
*/
|
|
548
|
+
const resetColorSetting = _scoreId => {
|
|
549
|
+
// 初期矢印・フリーズアロー色の再定義
|
|
550
|
+
if (g_stateObj.scoreLockFlg) {
|
|
551
|
+
Object.assign(g_rootObj, copySetColor(g_rootObj, _scoreId));
|
|
552
|
+
|
|
553
|
+
// 分割先のファイルで初期色が未定義の場合はデフォルト値を適用
|
|
554
|
+
[``, `Shadow`].forEach(pattern =>
|
|
555
|
+
[`set`, `frz`].forEach(arrow => {
|
|
556
|
+
// frzShadowColorStrのみ、空で構成された初期配列があるためその条件を追加して除外条件とする
|
|
557
|
+
if (!hasVal(g_rootObj[`${arrow}${pattern}Color${_scoreId + 1}`])
|
|
558
|
+
&& g_headerObj[`${arrow}${pattern}ColorStr`]?.flat()?.some(val => hasVal(val))) {
|
|
559
|
+
g_rootObj[`${arrow}${pattern}Color`] = g_headerObj[`${arrow}${pattern}ColorStr`].join(`,`);
|
|
560
|
+
}
|
|
561
|
+
})
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
Object.assign(g_headerObj, resetBaseColorList(g_headerObj, g_rootObj, { scoreId: _scoreId, scoreLockFlg: false }));
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* 譜面をファイルで分割している場合にゲージ情報を追加取得
|
|
569
|
+
* @param {string} _scoreId
|
|
570
|
+
*/
|
|
571
|
+
const resetGaugeSetting = _scoreId => {
|
|
572
|
+
// ライフ設定のカスタム部分再取得(譜面ヘッダー加味)
|
|
573
|
+
Object.assign(g_gaugeOptionObj, resetCustomGauge(g_rootObj, { scoreId: _scoreId }));
|
|
574
|
+
Object.keys(g_gaugeOptionObj.customFulls).forEach(gaugePtn => getGaugeSetting(g_rootObj, gaugePtn, g_headerObj.difLabels.length, { scoreId: _scoreId }));
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* 譜面番号固定かつ譜面ファイル分割時に初期色情報を他譜面へコピー
|
|
579
|
+
* @param {object} _baseObj
|
|
580
|
+
* @param {number} _scoreId
|
|
581
|
+
* @returns
|
|
582
|
+
*/
|
|
583
|
+
const copySetColor = (_baseObj, _scoreId) => {
|
|
584
|
+
const obj = {};
|
|
585
|
+
// Todo: dosIdを引数にして、dosIdと一致するscoreIdを算出
|
|
586
|
+
// 算出したscoreIdすべてに対して下記処理を実行
|
|
587
|
+
const srcIdHeader = setScoreIdHeader(_scoreId, g_stateObj.scoreLockFlg, true);
|
|
588
|
+
const targetIdHeader = setScoreIdHeader(_scoreId, false, true);
|
|
589
|
+
[``, `Shadow`].forEach(pattern =>
|
|
590
|
+
[`set`, `frz`].filter(arrow => hasVal(_baseObj[`${arrow}${pattern}Color${srcIdHeader}`] || _baseObj[`${arrow}${pattern}Color`]))
|
|
591
|
+
.forEach(arrow => obj[`${arrow}${pattern}Color${targetIdHeader}`] =
|
|
592
|
+
_baseObj[`${arrow}${pattern}Color${srcIdHeader}`] || _baseObj[`${arrow}${pattern}Color`]));
|
|
593
|
+
return obj;
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* MusicUrlの基本情報を取得
|
|
598
|
+
* @param {number} _scoreId
|
|
599
|
+
* @returns {string}
|
|
600
|
+
*/
|
|
601
|
+
const getMusicUrl = _scoreId =>
|
|
602
|
+
g_headerObj.musicUrls?.[g_headerObj.musicNos[_scoreId]] ?? g_headerObj.musicUrls?.[0] ?? `nosound.mp3`;
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* 音源データの実際のパスを取得
|
|
606
|
+
* @param {string} _musicUrl
|
|
607
|
+
* @returns {string}
|
|
608
|
+
*/
|
|
609
|
+
const getFullMusicUrl = (_musicUrl = ``) => {
|
|
610
|
+
let baseMusicUrl = _musicUrl;
|
|
611
|
+
let baseDir = `../${g_headerObj.musicFolder}/`;
|
|
612
|
+
|
|
613
|
+
if (_musicUrl.includes(C_MRK_CURRENT_DIRECTORY)) {
|
|
614
|
+
// musicUrl, musicFolder両方にカレントパス指定がある場合は、musicUrlの値を優先
|
|
615
|
+
|
|
616
|
+
} else if (g_headerObj.musicFolder.includes(C_MRK_CURRENT_DIRECTORY)) {
|
|
617
|
+
// musicFolderにカレントパス指定がある場合は、ファイル名にmusicFolderの値も含める
|
|
618
|
+
baseMusicUrl = `${g_headerObj.musicFolder}/${_musicUrl}`;
|
|
619
|
+
}
|
|
620
|
+
if (g_headerObj.musicFolder.includes(C_MRK_CURRENT_DIRECTORY)) {
|
|
621
|
+
// musicFolderにカレントパス指定がある場合は、ディレクトリは指定しない
|
|
622
|
+
baseDir = ``;
|
|
623
|
+
}
|
|
624
|
+
const [musicFile, musicPath] = getFilePath(baseMusicUrl, baseDir);
|
|
625
|
+
return `${musicPath}${musicFile}`;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* 譜面ファイル読込後処理(譜面詳細情報取得用)
|
|
630
|
+
* @param {number} _scoreId
|
|
631
|
+
*/
|
|
632
|
+
const getScoreDetailData = _scoreId => {
|
|
633
|
+
const keyCtrlPtn = `${g_headerObj.keyLabels[_scoreId]}_0`;
|
|
634
|
+
storeBaseData(_scoreId, scoreConvert(g_rootObj, _scoreId, 0, ``, keyCtrlPtn, true), keyCtrlPtn);
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* 譜面詳細データの格納
|
|
639
|
+
* @param {number} _scoreId
|
|
640
|
+
* @param {object} _scoreObj
|
|
641
|
+
* @param {number} _keyCtrlPtn
|
|
642
|
+
*/
|
|
643
|
+
const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
|
|
644
|
+
const lastFrame = getLastFrame(_scoreObj, _keyCtrlPtn) + 1;
|
|
645
|
+
const startFrame = getStartFrame(lastFrame, 0, _scoreId);
|
|
646
|
+
const firstArrowFrame = getFirstArrowFrame(_scoreObj, _keyCtrlPtn);
|
|
647
|
+
const playingFrame = lastFrame - firstArrowFrame;
|
|
648
|
+
const keyNum = g_keyObj[`${g_keyObj.defaultProp}${_keyCtrlPtn}`].length;
|
|
649
|
+
|
|
650
|
+
// 譜面密度グラフ用のデータ作成
|
|
651
|
+
const noteCnt = { arrow: [], frz: [] };
|
|
652
|
+
const densityData = fillArray(g_limitObj.densityDivision);
|
|
653
|
+
let allData = 0;
|
|
654
|
+
|
|
655
|
+
const types = [`arrow`, `frz`];
|
|
656
|
+
let fullData = [];
|
|
657
|
+
for (let j = 0; j < keyNum; j++) {
|
|
658
|
+
noteCnt.arrow[j] = 0;
|
|
659
|
+
noteCnt.frz[j] = 0;
|
|
660
|
+
|
|
661
|
+
const tmpFrzData = _scoreObj.frzData[j].filter((data, k) => k % 2 === 0);
|
|
662
|
+
[_scoreObj.arrowData[j], tmpFrzData].forEach((typeData, m) =>
|
|
663
|
+
typeData.forEach(note => {
|
|
664
|
+
if (isNaN(parseFloat(note))) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const point = Math.floor((note - firstArrowFrame) / playingFrame * g_limitObj.densityDivision);
|
|
668
|
+
if (point >= 0) {
|
|
669
|
+
densityData[point]++;
|
|
670
|
+
noteCnt[types[m]][j]++;
|
|
671
|
+
allData++;
|
|
672
|
+
}
|
|
673
|
+
}));
|
|
674
|
+
fullData = fullData.concat(..._scoreObj.arrowData[j], ...tmpFrzData);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
fullData = fullData.filter(val => !isNaN(parseFloat(val))).sort((a, b) => a - b);
|
|
678
|
+
let pushCnt = 1;
|
|
679
|
+
const density2PushData = fillArray(g_limitObj.densityDivision);
|
|
680
|
+
const density3PushData = fillArray(g_limitObj.densityDivision);
|
|
681
|
+
fullData.forEach((note, j) => {
|
|
682
|
+
if (fullData[j] === fullData[j + 1]) {
|
|
683
|
+
pushCnt++;
|
|
684
|
+
} else {
|
|
685
|
+
const point = Math.floor((note - firstArrowFrame) / playingFrame * g_limitObj.densityDivision);
|
|
686
|
+
if (point >= 0) {
|
|
687
|
+
if (pushCnt >= 2) {
|
|
688
|
+
density2PushData[point] += pushCnt;
|
|
689
|
+
if (pushCnt >= 3) {
|
|
690
|
+
density3PushData[point] += pushCnt;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
pushCnt = 1;
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
g_detailObj.toolDif[_scoreId] = calcLevel(_scoreObj);
|
|
699
|
+
g_detailObj.speedData[_scoreId] = _scoreObj.speedData.concat();
|
|
700
|
+
g_detailObj.boostData[_scoreId] = _scoreObj.boostData.concat();
|
|
701
|
+
|
|
702
|
+
const storeDensity = _densityData => {
|
|
703
|
+
const dataList = [];
|
|
704
|
+
for (let j = 0; j < g_limitObj.densityDivision; j++) {
|
|
705
|
+
dataList.push(allData === 0 ? 0 : Math.round(_densityData[j] / allData * g_limitObj.densityDivision * 10000) / 100);
|
|
706
|
+
}
|
|
707
|
+
return dataList;
|
|
708
|
+
};
|
|
709
|
+
const diffArray = (_array1, _array2) => {
|
|
710
|
+
const list = [];
|
|
711
|
+
_array1.forEach((val, j) => list.push(_array1[j] - _array2[j]));
|
|
712
|
+
return list;
|
|
713
|
+
};
|
|
714
|
+
g_detailObj.densityData[_scoreId] = storeDensity(densityData);
|
|
715
|
+
g_detailObj.density2PushData[_scoreId] = storeDensity(density2PushData);
|
|
716
|
+
g_detailObj.density3PushData[_scoreId] = storeDensity(density3PushData);
|
|
717
|
+
|
|
718
|
+
g_detailObj.densityDiff[_scoreId] = diffArray(g_detailObj.densityData[_scoreId], g_detailObj.density2PushData[_scoreId]);
|
|
719
|
+
g_detailObj.density2PushDiff[_scoreId] = diffArray(g_detailObj.density2PushData[_scoreId], g_detailObj.density3PushData[_scoreId]);
|
|
720
|
+
g_detailObj.density3PushDiff[_scoreId] = g_detailObj.density3PushData[_scoreId].concat();
|
|
721
|
+
|
|
722
|
+
g_detailObj.maxDensity[_scoreId] = getMaxValIdxs(densityData, g_limitObj.densityMaxVals).flat();
|
|
723
|
+
|
|
724
|
+
g_detailObj.arrowCnt[_scoreId] = noteCnt.arrow.concat();
|
|
725
|
+
g_detailObj.frzCnt[_scoreId] = noteCnt.frz.map((val, k) => _scoreObj.frzData[k].length % 2 === 0 ? val : val - 0.5);
|
|
726
|
+
g_detailObj.startFrame[_scoreId] = startFrame;
|
|
727
|
+
g_detailObj.playingFrame[_scoreId] = playingFrame;
|
|
728
|
+
g_detailObj.playingFrameWithBlank[_scoreId] = lastFrame - startFrame;
|
|
729
|
+
|
|
730
|
+
// --- ミニマップ設定 ---
|
|
731
|
+
g_detailObj.miniMapParams[_scoreId] = {
|
|
732
|
+
_scoreId, _scoreObj, _keyNum: keyNum,
|
|
733
|
+
_playingFrame: playingFrame,
|
|
734
|
+
_firstArrowFrame: firstArrowFrame,
|
|
735
|
+
_keyCtrlPtn,
|
|
736
|
+
config: {
|
|
737
|
+
scale: 1.5,
|
|
738
|
+
timeMargin: 35,
|
|
739
|
+
mmWidthBase: (g_sWidth - 500) / 2 + 290,
|
|
740
|
+
mmMarginY: 2,
|
|
741
|
+
get laneWidth() {
|
|
742
|
+
return Math.min((this.mmWidthBase - this.timeMargin) / keyNum, 40);
|
|
743
|
+
},
|
|
744
|
+
get logicalWidth() {
|
|
745
|
+
const logicalWidth = this.timeMargin + (this.laneWidth * keyNum);
|
|
746
|
+
return Math.ceil(logicalWidth * g_dpr) / g_dpr;
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// Canvas保存用配列を空で初期化
|
|
752
|
+
g_detailObj.scoreMinimap[_scoreId] = null;
|
|
753
|
+
g_detailObj.scoreMinimapReverse[_scoreId] = null;
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* ツール計算
|
|
758
|
+
* @param {object} _scoreObj
|
|
759
|
+
* @param {number[][]} _scoreObj.arrowData 矢印データ
|
|
760
|
+
* @param {number[][]} _scoreObj.frzData フリーズデータ
|
|
761
|
+
* @returns {{tool: string, tate: number, douji: number, push3Cnt: number, push3: number[]}}
|
|
762
|
+
*/
|
|
763
|
+
const calcLevel = _scoreObj => {
|
|
764
|
+
//--------------------------------------------------------------
|
|
765
|
+
//<フリーズデータ分解>
|
|
766
|
+
// フリーズデータを分解し、矢印データに組み込む
|
|
767
|
+
//
|
|
768
|
+
// (イメージ)
|
|
769
|
+
// &left_data=400,500,700&
|
|
770
|
+
// &frzLeft_data=550,650&
|
|
771
|
+
// ⇒
|
|
772
|
+
// left_data=[400,500,550,700]; // フリーズの始点を組込
|
|
773
|
+
// frzStartData=[550]; // フリーズ始点
|
|
774
|
+
// frzEndData =[650]; // フリーズ終点
|
|
775
|
+
//--------------------------------------------------------------
|
|
776
|
+
const frzStartData = [];
|
|
777
|
+
const frzEndData = [];
|
|
778
|
+
|
|
779
|
+
_scoreObj.frzData.forEach((frzs, j) => {
|
|
780
|
+
if (frzs.length > 1) {
|
|
781
|
+
for (let k = 0; k < frzs.length; k += 2) {
|
|
782
|
+
_scoreObj.arrowData[j].push(frzs[k]);
|
|
783
|
+
frzStartData.push(frzs[k]);
|
|
784
|
+
frzEndData.push(frzs[k + 1]);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
_scoreObj.arrowData[j] = _scoreObj.arrowData[j].sort((a, b) => a - b)
|
|
788
|
+
.filter((x, i, self) => self.indexOf(x) === i && !isNaN(parseFloat(x)));
|
|
789
|
+
})
|
|
790
|
+
|
|
791
|
+
frzStartData.sort((a, b) => a - b);
|
|
792
|
+
frzEndData.sort((a, b) => a - b);
|
|
793
|
+
|
|
794
|
+
//--------------------------------------------------------------
|
|
795
|
+
//<データ結合・整理>
|
|
796
|
+
// 矢印データを連結してソートする。
|
|
797
|
+
//
|
|
798
|
+
// 重複は後の同時押し補正で使用する。
|
|
799
|
+
// 後の同時押し補正の都合上、firstFrame-100, lastFrame+100 のデータを末尾に追加。
|
|
800
|
+
//
|
|
801
|
+
// (イメージ)
|
|
802
|
+
// |left_data=300,400,550| // フリーズデータ(始点)を含む
|
|
803
|
+
// |down_data=500|
|
|
804
|
+
// |up_data=600|
|
|
805
|
+
// |right_data=700,800|
|
|
806
|
+
// |space_data=200,300,1000|
|
|
807
|
+
// frzEndData = [650]; // フリーズデータ(終点) ※allScorebook対象外
|
|
808
|
+
// ⇒
|
|
809
|
+
// allScorebook = [100,200,300,300,400,500,550,600,700,800,1000,1100];
|
|
810
|
+
//
|
|
811
|
+
//--------------------------------------------------------------
|
|
812
|
+
let allScorebook = [];
|
|
813
|
+
_scoreObj.arrowData.forEach(data => allScorebook = allScorebook.concat(data));
|
|
814
|
+
|
|
815
|
+
allScorebook.sort((a, b) => a - b);
|
|
816
|
+
allScorebook.unshift(allScorebook[0] - 100);
|
|
817
|
+
allScorebook.push(allScorebook.at(-1) + 100);
|
|
818
|
+
const allCnt = allScorebook.length;
|
|
819
|
+
|
|
820
|
+
frzEndData.push(allScorebook.at(-1));
|
|
821
|
+
|
|
822
|
+
//--------------------------------------------------------------
|
|
823
|
+
//<間隔フレーム数の調和平均計算+いろいろ補正>
|
|
824
|
+
// レベル計算メイン。
|
|
825
|
+
//
|
|
826
|
+
// [レベル計算ツール++ ver1.18] 3つ押し以上でも同時押し補正ができるよう調整
|
|
827
|
+
//--------------------------------------------------------------
|
|
828
|
+
let levelcount = 0; // 難易度レベル
|
|
829
|
+
let freezenum = 0; // フリーズアロー数
|
|
830
|
+
let pushCnt = 1; // 同時押し数カウント
|
|
831
|
+
let twoPushCount = 0; // 同時押し補正値
|
|
832
|
+
const push3List = []; // 3つ押し判定数
|
|
833
|
+
|
|
834
|
+
for (let i = 1; i < allCnt - 2; i++) {
|
|
835
|
+
// フリーズ始点の検索
|
|
836
|
+
while (frzStartData[0] === allScorebook[i]) {
|
|
837
|
+
// 同時押しの場合
|
|
838
|
+
if (allScorebook[i] === allScorebook[i + 1]) {
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// 現フレームに存在するフリーズ数を1増やす
|
|
843
|
+
// (フリーズアローの同時チェック開始)
|
|
844
|
+
frzStartData.shift();
|
|
845
|
+
freezenum++;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// フリーズ終点の検索
|
|
849
|
+
while (frzEndData[0] < allScorebook[i + 1]) {
|
|
850
|
+
// 現フレームに存在するフリーズ数を1減らす
|
|
851
|
+
frzEndData.shift();
|
|
852
|
+
freezenum--;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// 同時押し補正処理(フリーズアローが絡まない場合)
|
|
856
|
+
if (allScorebook[i + 1] === allScorebook[i] && !freezenum) {
|
|
857
|
+
|
|
858
|
+
const chk = (allScorebook[i + 2] - allScorebook[i + 1]) * (allScorebook[i] - allScorebook[i - pushCnt]);
|
|
859
|
+
if (chk !== 0) {
|
|
860
|
+
twoPushCount += 40 / chk;
|
|
861
|
+
} else {
|
|
862
|
+
// 3つ押しが絡んだ場合は加算しない
|
|
863
|
+
push3List.push(allScorebook[i]);
|
|
864
|
+
}
|
|
865
|
+
pushCnt++;
|
|
866
|
+
|
|
867
|
+
} else {
|
|
868
|
+
// 単押し+フリーズアローの補正処理(フリーズアロー中の矢印)
|
|
869
|
+
pushCnt = 1;
|
|
870
|
+
const chk2 = (2 - freezenum) * (allScorebook[i + 1] - allScorebook[i]);
|
|
871
|
+
if (chk2 > 0) {
|
|
872
|
+
levelcount += 2 / chk2;
|
|
873
|
+
} else {
|
|
874
|
+
// 3つ押しが絡んだ場合は加算しない
|
|
875
|
+
push3List.push(allScorebook[i]);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
levelcount += twoPushCount;
|
|
880
|
+
const leveltmp = levelcount;
|
|
881
|
+
|
|
882
|
+
//--------------------------------------------------------------
|
|
883
|
+
//<同方向連打補正>
|
|
884
|
+
// 同方向矢印(フリーズアロー)の隣接間隔が10フレーム未満の場合に加算する。
|
|
885
|
+
//--------------------------------------------------------------
|
|
886
|
+
_scoreObj.arrowData.forEach(arrows =>
|
|
887
|
+
arrows.forEach((val, k) => {
|
|
888
|
+
if (arrows[k + 1] - arrows[k] < 10) {
|
|
889
|
+
levelcount += 10 / Math.pow(arrows[k + 1] - arrows[k], 2) - 1 / 10;
|
|
890
|
+
}
|
|
891
|
+
}));
|
|
892
|
+
|
|
893
|
+
//--------------------------------------------------------------
|
|
894
|
+
//<表示>
|
|
895
|
+
// 曲長、3つ押し補正を行い、最終的な難易度レベル値を表示する。
|
|
896
|
+
//--------------------------------------------------------------
|
|
897
|
+
const push3Cnt = push3List.length;
|
|
898
|
+
const calcArrowCnt = allCnt - push3Cnt - 3;
|
|
899
|
+
const toDecimal2 = num => Math.round(num * 100) / 100;
|
|
900
|
+
const calcDifLevel = num => calcArrowCnt > 0 ? toDecimal2(num / Math.sqrt(calcArrowCnt) * 4) : 0;
|
|
901
|
+
|
|
902
|
+
const baseDifLevel = calcDifLevel(levelcount);
|
|
903
|
+
const difLevel = toDecimal2(baseDifLevel * (allCnt - 3) / calcArrowCnt);
|
|
904
|
+
|
|
905
|
+
//--------------------------------------------------------------
|
|
906
|
+
//<計算結果を格納>
|
|
907
|
+
//--------------------------------------------------------------
|
|
908
|
+
return {
|
|
909
|
+
// 難易度レベル
|
|
910
|
+
tool: (allCnt === 3 ? `0.01` : `${difLevel.toFixed(2)}${(push3Cnt > 0 ? "*" : "")}`),
|
|
911
|
+
// 縦連打補正
|
|
912
|
+
tate: toDecimal2(baseDifLevel - calcDifLevel(leveltmp)),
|
|
913
|
+
// 同時押し補正
|
|
914
|
+
douji: calcDifLevel(twoPushCount),
|
|
915
|
+
// 3つ押し数
|
|
916
|
+
push3cnt: push3Cnt,
|
|
917
|
+
// 3つ押しリスト
|
|
918
|
+
push3: makeDedupliArray(push3List),
|
|
919
|
+
};
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* ロケールを含んだヘッダーの優先度設定
|
|
924
|
+
* @param {object} _obj
|
|
925
|
+
* @param {...any} [_params]
|
|
926
|
+
* @returns {string}
|
|
927
|
+
*/
|
|
928
|
+
const getHeader = (_obj, ..._params) => {
|
|
929
|
+
let headerLocale, headerDf;
|
|
930
|
+
Object.keys(_params).forEach(j => {
|
|
931
|
+
headerLocale ??= _obj[`${_params[j]}${g_localeObj.val}`];
|
|
932
|
+
headerDf ??= _obj[_params[j]];
|
|
933
|
+
});
|
|
934
|
+
return headerLocale ?? headerDf;
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* ヘッダー名の互換設定
|
|
939
|
+
* @param {string} _param
|
|
940
|
+
* @returns {string[]}
|
|
941
|
+
*/
|
|
942
|
+
const getHname = _param => [_param, _param.toLowerCase()];
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* 譜面ヘッダーの分解(スキン、jsファイルなどの設定)
|
|
946
|
+
* @param {object} _dosObj
|
|
947
|
+
* @returns {object}
|
|
948
|
+
*/
|
|
949
|
+
const preheaderConvert = _dosObj => {
|
|
950
|
+
|
|
951
|
+
// ヘッダー群の格納先
|
|
952
|
+
const obj = {};
|
|
953
|
+
|
|
954
|
+
// ウィンドウ位置の設定
|
|
955
|
+
const align = _dosObj.windowAlign ?? g_presetObj.windowAlign;
|
|
956
|
+
if (align !== undefined) {
|
|
957
|
+
g_windowAlign[align]();
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
obj.jsData = [];
|
|
961
|
+
obj.stepRtnUse = true;
|
|
962
|
+
|
|
963
|
+
const setJsFiles = (_files, _defaultDir, _type = `custom`) =>
|
|
964
|
+
_files.filter(file => hasVal(file)).forEach(file => {
|
|
965
|
+
const [jsFile, jsDir] = getFilePath(file, _defaultDir);
|
|
966
|
+
obj.jsData.push([_type === `skin` ? `danoni_skin_${jsFile}.js` : jsFile, jsDir]);
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
const convLocalPath = (_file, _type) =>
|
|
970
|
+
g_remoteFlg && hasVal(_file) && !_file.includes(C_MRK_CURRENT_DIRECTORY) && !hasRemoteDomain(_file)
|
|
971
|
+
? `${C_MRK_CURRENT_DIRECTORY}../${_type}/${_file}`
|
|
972
|
+
: _file;
|
|
973
|
+
|
|
974
|
+
// 外部スキンファイルの指定
|
|
975
|
+
const tmpSkinType = _dosObj.skinType ?? g_presetObj.skinType ?? `default`;
|
|
976
|
+
const tmpSkinTypes = tmpSkinType.split(`,`).map(file => {
|
|
977
|
+
|
|
978
|
+
// スキンタイプを取得(ディレクトリパス、カレント指定(..)を除去)
|
|
979
|
+
const match = file.match(/.*\/(.+)|\(\.\.\)([^/]+)|(.+)/);
|
|
980
|
+
const skinName = match[1] || match[2] || match[3];
|
|
981
|
+
|
|
982
|
+
// デフォルトセット以外はリモート先のデータを使用しない
|
|
983
|
+
return g_defaultSets.skinType.findIndex(val => val === skinName) < 0 ?
|
|
984
|
+
convLocalPath(file, `skin`) : file;
|
|
985
|
+
});
|
|
986
|
+
obj.defaultSkinFlg = tmpSkinTypes.includes(`default`) && setBoolVal(_dosObj.bgCanvasUse ?? g_presetObj.bgCanvasUse, true);
|
|
987
|
+
setJsFiles(tmpSkinTypes, C_DIR_SKIN, `skin`);
|
|
988
|
+
|
|
989
|
+
// 外部jsファイルの指定
|
|
990
|
+
const tmpCustomjs = getHeader(_dosObj, ...getHname(`customJs`)) ?? g_presetObj.customJs ?? C_JSF_CUSTOM;
|
|
991
|
+
setJsFiles(tmpCustomjs.replaceAll(`*`, g_presetObj.customJs).split(`,`)
|
|
992
|
+
.map(file => convLocalPath(file, `js`)), C_DIR_JS);
|
|
993
|
+
|
|
994
|
+
// 外部cssファイルの指定
|
|
995
|
+
const tmpCustomcss = getHeader(_dosObj, ...getHname(`customCss`)) ?? g_presetObj.customCss ?? ``;
|
|
996
|
+
setJsFiles(tmpCustomcss.replaceAll(`*`, g_presetObj.customCss).split(`,`)
|
|
997
|
+
.map(file => convLocalPath(file, `css`)), C_DIR_CSS);
|
|
998
|
+
|
|
999
|
+
// デフォルト曲名表示、背景、Ready表示の利用有無
|
|
1000
|
+
g_titleLists.init.forEach(objName => {
|
|
1001
|
+
const objUpper = toCapitalize(objName);
|
|
1002
|
+
obj[`custom${objUpper}Use`] =
|
|
1003
|
+
setBoolVal(_dosObj[`custom${objUpper}Use`] ?? g_presetObj.customDesignUse?.[objName]);
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
// 背景・マスクモーションのパス指定方法を他の設定に合わせる設定
|
|
1007
|
+
obj.syncBackPath = setBoolVal(_dosObj.syncBackPath ?? g_presetObj.syncBackPath);
|
|
1008
|
+
|
|
1009
|
+
return obj;
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* 譜面ヘッダーの分解(その他の設定)
|
|
1014
|
+
* @param {object} _dosObj 譜面データオブジェクト
|
|
1015
|
+
* @returns {object}
|
|
1016
|
+
*/
|
|
1017
|
+
const headerConvert = _dosObj => {
|
|
1018
|
+
|
|
1019
|
+
// ヘッダー群の格納先
|
|
1020
|
+
const obj = {};
|
|
1021
|
+
|
|
1022
|
+
// 自動プリロードの設定
|
|
1023
|
+
obj.autoPreload = setBoolVal(_dosObj.autoPreload, true);
|
|
1024
|
+
g_headerObj.autoPreload = obj.autoPreload;
|
|
1025
|
+
|
|
1026
|
+
// デフォルトスタイルのバックアップ
|
|
1027
|
+
getCssCustomProperties();
|
|
1028
|
+
|
|
1029
|
+
// 初期で変更するカスタムプロパティを設定
|
|
1030
|
+
Object.keys(_dosObj).filter(val => val.startsWith(`--`) && hasVal(_dosObj[val])).forEach(prop => {
|
|
1031
|
+
g_cssBkProperties[prop] = getCssCustomProperty(prop, _dosObj[prop]);
|
|
1032
|
+
document.documentElement.style.setProperty(prop, g_cssBkProperties[prop]);
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
// フォントの設定
|
|
1036
|
+
obj.customFont = _dosObj.customFont ?? ``;
|
|
1037
|
+
g_headerObj.customFont = obj.customFont;
|
|
1038
|
+
|
|
1039
|
+
// 画像ルートパス、拡張子の設定 (サーバ上のみ)
|
|
1040
|
+
obj.imgType = [];
|
|
1041
|
+
if (!g_isFile) {
|
|
1042
|
+
let tmpImgTypes = [];
|
|
1043
|
+
if (hasVal(_dosObj.imgType)) {
|
|
1044
|
+
tmpImgTypes = splitLF2(_dosObj.imgType);
|
|
1045
|
+
} else if (g_presetObj.imageSets !== undefined) {
|
|
1046
|
+
tmpImgTypes = g_presetObj.imageSets.concat();
|
|
1047
|
+
}
|
|
1048
|
+
tmpImgTypes.forEach((tmpImgType, j) => {
|
|
1049
|
+
const imgTypes = tmpImgType.split(`,`);
|
|
1050
|
+
obj.imgType[j] = {
|
|
1051
|
+
name: imgTypes[0],
|
|
1052
|
+
extension: imgTypes[1] || `svg`,
|
|
1053
|
+
rotateEnabled: setBoolVal(imgTypes[2], true),
|
|
1054
|
+
flatStepHeight: setVal(imgTypes[3], C_ARW_WIDTH, C_TYP_FLOAT),
|
|
1055
|
+
remoteDir: imgTypes[4] || ``,
|
|
1056
|
+
};
|
|
1057
|
+
g_keycons.imgTypes[j] = (imgTypes[0] === `` ? `Original` : imgTypes[0]);
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// 末尾にデフォルト画像セットが入るよう追加
|
|
1062
|
+
if (obj.imgType.findIndex(imgSets => imgSets.name === ``) === -1) {
|
|
1063
|
+
obj.imgType.push({ name: ``, extension: `svg`, rotateEnabled: true, flatStepHeight: C_ARW_WIDTH, remoteDir: `` });
|
|
1064
|
+
g_keycons.imgTypes.push(`Original`);
|
|
1065
|
+
}
|
|
1066
|
+
g_imgType = g_keycons.imgTypes[0];
|
|
1067
|
+
g_stateObj.rotateEnabled = obj.imgType[0].rotateEnabled;
|
|
1068
|
+
g_stateObj.flatStepHeight = obj.imgType[0].flatStepHeight;
|
|
1069
|
+
changeSettingListsForImg();
|
|
1070
|
+
|
|
1071
|
+
const [titleArrowName, titleArrowRotate] = padArray(_dosObj.titleArrowName?.split(`:`), [`Original`, 180]);
|
|
1072
|
+
obj.titleArrowNo = roundZero(g_keycons.imgTypes.findIndex(imgType => imgType === titleArrowName));
|
|
1073
|
+
obj.titleArrowRotate = titleArrowRotate;
|
|
1074
|
+
|
|
1075
|
+
// サーバ上の場合、画像セットを再読込(ローカルファイル時は読込済みのためスキップ)
|
|
1076
|
+
if (!g_isFile) {
|
|
1077
|
+
updateImgType(obj.imgType[obj.titleArrowNo], true);
|
|
1078
|
+
updateImgType(obj.imgType[0]);
|
|
1079
|
+
} else {
|
|
1080
|
+
g_imgObj.titleArrow = C_IMG_ARROW;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// 自動横幅拡張設定
|
|
1084
|
+
obj.autoSpread = setBoolVal(_dosObj.autoSpread, g_presetObj.autoSpread ?? true);
|
|
1085
|
+
|
|
1086
|
+
// 横幅設定
|
|
1087
|
+
if (hasVal(_dosObj.windowWidth)) {
|
|
1088
|
+
g_sWidth = Math.max(setIntVal(_dosObj.windowWidth, g_sWidth), g_sWidth);
|
|
1089
|
+
$id(`canvas-frame`).width = wUnit(g_sWidth);
|
|
1090
|
+
}
|
|
1091
|
+
// 高さ設定
|
|
1092
|
+
obj.heightVariable = getQueryParamVal(`h`) !== null && (_dosObj.heightVariable || g_presetObj.heightVariable || false);
|
|
1093
|
+
if (hasVal(_dosObj.windowHeight || g_presetObj.autoMinHeight) || obj.heightVariable) {
|
|
1094
|
+
g_sHeight = Math.max(setIntVal(_dosObj.windowHeight, g_presetObj.autoMinHeight ?? g_sHeight),
|
|
1095
|
+
setIntVal(getQueryParamVal(`h`), g_sHeight), g_sHeight);
|
|
1096
|
+
$id(`canvas-frame`).height = wUnit(g_sHeight);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// 曲名
|
|
1100
|
+
obj.musicTitles = [`musicName`];
|
|
1101
|
+
obj.musicTitlesForView = [[`musicName`]];
|
|
1102
|
+
obj.artistNames = [``];
|
|
1103
|
+
obj.artistUrls = [``];
|
|
1104
|
+
obj.bpms = [`----`];
|
|
1105
|
+
obj.musicNos = hasVal(_dosObj.musicNo)
|
|
1106
|
+
? splitLF2(_dosObj.musicNo).map(Number).map(val => isNaN(val) ? 0 : val)
|
|
1107
|
+
: fillArray(_dosObj.difData?.split(`$`).length ?? 1);
|
|
1108
|
+
|
|
1109
|
+
const dosMusicTitle = getHeader(_dosObj, `musicTitle`);
|
|
1110
|
+
let alternativeTitle;
|
|
1111
|
+
if (hasVal(dosMusicTitle)) {
|
|
1112
|
+
const musicData = splitLF2(dosMusicTitle);
|
|
1113
|
+
|
|
1114
|
+
const lastIdx = Math.max(...obj.musicNos, musicData.length - 1);
|
|
1115
|
+
for (let j = 0; j <= lastIdx; j++) {
|
|
1116
|
+
const tmpMusicData = musicData[j] ?? ``;
|
|
1117
|
+
const musics = splitComma(tmpMusicData);
|
|
1118
|
+
|
|
1119
|
+
obj.musicTitles[j] = hasVal(musics[0])
|
|
1120
|
+
? escapeHtml(getMusicNameSimple(musics[0]))
|
|
1121
|
+
: obj.musicTitles[0];
|
|
1122
|
+
obj.musicTitlesForView[j] = hasVal(musics[0])
|
|
1123
|
+
? escapeHtmlForArray(getMusicNameMultiLine(musics[0]))
|
|
1124
|
+
: obj.musicTitlesForView[0];
|
|
1125
|
+
obj.artistNames[j] = hasVal(musics[1])
|
|
1126
|
+
? escapeHtml(musics[1])
|
|
1127
|
+
: obj.artistNames[0];
|
|
1128
|
+
obj.artistUrls[j] = musics[2] || obj.artistUrls[0];
|
|
1129
|
+
obj.bpms[j] = musics[4] || obj.bpms[0];
|
|
1130
|
+
|
|
1131
|
+
// 代替タイトル名
|
|
1132
|
+
if (j === 0 && hasVal(_dosObj.musicNo)) {
|
|
1133
|
+
alternativeTitle = musics[3];
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
} else {
|
|
1138
|
+
makeWarningWindow(g_msgInfoObj.E_0012);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// 単一作品用の項目としての管理変数
|
|
1142
|
+
obj.musicTitle = obj.musicTitles[0];
|
|
1143
|
+
obj.musicTitleForView = obj.musicTitlesForView[0];
|
|
1144
|
+
obj.artistName = obj.artistNames[0];
|
|
1145
|
+
if (obj.artistName === ``) {
|
|
1146
|
+
makeWarningWindow(g_msgInfoObj.E_0011);
|
|
1147
|
+
obj.artistName = `artistName`;
|
|
1148
|
+
}
|
|
1149
|
+
obj.artistUrl = obj.artistUrls[0];
|
|
1150
|
+
|
|
1151
|
+
// 代替タイトル名は曲名定義の後に設定する(複数曲を束ねる名前であり、曲名ではないため)
|
|
1152
|
+
if (hasVal(alternativeTitle)) {
|
|
1153
|
+
obj.musicTitles[0] = escapeHtml(getMusicNameSimple(alternativeTitle));
|
|
1154
|
+
obj.musicTitlesForView[0] = escapeHtmlForArray(getMusicNameMultiLine(alternativeTitle));
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// 選曲機能の利用有無(最後のカンマ後の文字をBGM利用フラグとして利用)
|
|
1158
|
+
const rawPackageName = _dosObj.packageName || ``;
|
|
1159
|
+
const packageNameParts = rawPackageName.split(`,`);
|
|
1160
|
+
const bgmUseSwitch = setVal(trimStr(packageNameParts.at(-1)), ``, C_TYP_SWITCH);
|
|
1161
|
+
const packageName = bgmUseSwitch === ``
|
|
1162
|
+
? rawPackageName
|
|
1163
|
+
: packageNameParts.slice(0, -1).join(`,`);
|
|
1164
|
+
obj.packageNames = (packageName || ``).split(`<br>`);
|
|
1165
|
+
obj.musicSelectUse = _dosObj.packageName !== undefined;
|
|
1166
|
+
obj.bgmUseFlg = bgmUseSwitch === C_FLG_ON;
|
|
1167
|
+
|
|
1168
|
+
if (!obj.bgmUseFlg) {
|
|
1169
|
+
g_stateObj.bgmMuteFlg = true;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// 最小・最大速度の設定
|
|
1173
|
+
obj.minSpeed = Math.round(setVal(_dosObj.minSpeed, C_MIN_SPEED, C_TYP_FLOAT) * 4) / 4;
|
|
1174
|
+
obj.maxSpeed = Math.round(setVal(_dosObj.maxSpeed, C_MAX_SPEED, C_TYP_FLOAT) * 4) / 4;
|
|
1175
|
+
if (obj.minSpeed > obj.maxSpeed || obj.minSpeed < 0.5 || obj.maxSpeed < 0.5) {
|
|
1176
|
+
obj.minSpeed = C_MIN_SPEED;
|
|
1177
|
+
obj.maxSpeed = C_MAX_SPEED;
|
|
1178
|
+
}
|
|
1179
|
+
g_settings.speeds = makeSpeedList(obj.minSpeed, obj.maxSpeed);
|
|
1180
|
+
|
|
1181
|
+
// プレイ中のショートカットキー
|
|
1182
|
+
obj.keyRetry = setIntVal(getKeyCtrlVal(_dosObj.keyRetry), C_KEY_RETRY);
|
|
1183
|
+
obj.keyRetryDef = obj.keyRetry;
|
|
1184
|
+
obj.keyRetryDef2 = obj.keyRetry;
|
|
1185
|
+
obj.keyTitleBack = setIntVal(getKeyCtrlVal(_dosObj.keyTitleBack), C_KEY_TITLEBACK);
|
|
1186
|
+
obj.keyTitleBackDef = obj.keyTitleBack;
|
|
1187
|
+
obj.keyTitleBackDef2 = obj.keyTitleBack;
|
|
1188
|
+
obj.keyPause = setIntVal(getKeyCtrlVal(_dosObj.keyPause), C_KEY_PAUSE);
|
|
1189
|
+
obj.keyPauseDef = obj.keyPause;
|
|
1190
|
+
obj.keyPauseDef2 = obj.keyPause;
|
|
1191
|
+
|
|
1192
|
+
// フリーズアローの許容フレーム数設定
|
|
1193
|
+
obj.frzAttempt = setIntVal(_dosObj.frzAttempt, C_FRM_FRZATTEMPT);
|
|
1194
|
+
|
|
1195
|
+
// 製作者表示
|
|
1196
|
+
const dosTuning = getHeader(_dosObj, `tuning`);
|
|
1197
|
+
obj.tuningNames = [];
|
|
1198
|
+
obj.tuningUrls = [];
|
|
1199
|
+
if (hasVal(dosTuning)) {
|
|
1200
|
+
splitLF2(dosTuning).forEach(tuning => {
|
|
1201
|
+
const tuningData = tuning.split(`,`);
|
|
1202
|
+
obj.tuningNames.push(escapeHtmlForEnabledTag(tuningData[0]));
|
|
1203
|
+
obj.tuningUrls.push(tuningData[1] ||
|
|
1204
|
+
(getHeader(g_presetObj, `tuning`) === tuningData[0] ? g_presetObj.tuningUrl : ``));
|
|
1205
|
+
});
|
|
1206
|
+
obj.tuning = obj.tuningNames[0];
|
|
1207
|
+
obj.creatorUrl = obj.tuningUrls[0] || g_presetObj.tuningUrl || ``;
|
|
1208
|
+
} else {
|
|
1209
|
+
obj.tuning = escapeHtmlForEnabledTag(getHeader(g_presetObj, `tuning`) ?? `name`);
|
|
1210
|
+
obj.creatorUrl = g_presetObj.tuningUrl ?? ``;
|
|
1211
|
+
}
|
|
1212
|
+
obj.tuningInit = obj.tuning;
|
|
1213
|
+
|
|
1214
|
+
obj.dosNos = [];
|
|
1215
|
+
obj.scoreNos = [];
|
|
1216
|
+
if (hasVal(_dosObj.dosNo)) {
|
|
1217
|
+
splitLF2(_dosObj.dosNo).map((val, j) => [obj.dosNos[j], obj.scoreNos[j]] = val.split(`,`));
|
|
1218
|
+
const dosNoCnt = {};
|
|
1219
|
+
obj.dosNos.forEach((val, j) => {
|
|
1220
|
+
if (dosNoCnt[val] === undefined) {
|
|
1221
|
+
dosNoCnt[val] = 0;
|
|
1222
|
+
}
|
|
1223
|
+
if (obj.scoreNos[j] === undefined) {
|
|
1224
|
+
dosNoCnt[val]++;
|
|
1225
|
+
obj.scoreNos[j] = dosNoCnt[val];
|
|
1226
|
+
} else {
|
|
1227
|
+
dosNoCnt[val] = Number(obj.scoreNos[j]);
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// 譜面情報
|
|
1233
|
+
if (hasVal(_dosObj.difData)) {
|
|
1234
|
+
const difs = splitLF2(_dosObj.difData);
|
|
1235
|
+
const difpos = {
|
|
1236
|
+
Key: 0, Name: 1, Speed: 2, Border: 3, Recovery: 4, Damage: 5, Init: 6,
|
|
1237
|
+
};
|
|
1238
|
+
obj.keyLabels = [];
|
|
1239
|
+
obj.difLabels = [];
|
|
1240
|
+
obj.initSpeeds = [];
|
|
1241
|
+
obj.lifeBorders = [];
|
|
1242
|
+
obj.lifeRecoverys = [];
|
|
1243
|
+
obj.lifeDamages = [];
|
|
1244
|
+
obj.lifeInits = [];
|
|
1245
|
+
obj.creatorNames = [];
|
|
1246
|
+
obj.difficulties = [];
|
|
1247
|
+
g_stateObj.scoreId = (g_stateObj.scoreId < difs.length ? g_stateObj.scoreId : 0);
|
|
1248
|
+
|
|
1249
|
+
difs.forEach(dif => {
|
|
1250
|
+
const difDetails = dif.split(`,`);
|
|
1251
|
+
const lifeData = (_type, _default) =>
|
|
1252
|
+
difDetails[difpos[_type]] || g_presetObj.gauge?.[_type] || _default;
|
|
1253
|
+
|
|
1254
|
+
// ライフ:ノルマ、回復量、ダメージ量、初期値の設定
|
|
1255
|
+
obj.lifeBorders.push(lifeData(`Border`, `x`));
|
|
1256
|
+
obj.lifeRecoverys.push(lifeData(`Recovery`, 6));
|
|
1257
|
+
obj.lifeDamages.push(lifeData(`Damage`, 40));
|
|
1258
|
+
obj.lifeInits.push(lifeData(`Init`, 25));
|
|
1259
|
+
|
|
1260
|
+
// キー数
|
|
1261
|
+
const keyLabel = difDetails[difpos.Key] || g_keyObj.initKeyLabel;
|
|
1262
|
+
obj.keyLabels.push(g_keyObj.keyTransPattern[keyLabel] ?? keyLabel);
|
|
1263
|
+
|
|
1264
|
+
// 譜面名、制作者名
|
|
1265
|
+
if (hasVal(difDetails[difpos.Name])) {
|
|
1266
|
+
const difNameInfo = difDetails[difpos.Name].split(`::`);
|
|
1267
|
+
obj.difLabels.push(escapeHtml(difNameInfo[0] ?? `Normal`));
|
|
1268
|
+
obj.creatorNames.push(setVal(escapeHtml(difNameInfo[1]), obj.tuning));
|
|
1269
|
+
obj.difficulties.push(setIntVal(difNameInfo[2], 0));
|
|
1270
|
+
} else {
|
|
1271
|
+
obj.difLabels.push(`Normal`);
|
|
1272
|
+
obj.creatorNames.push(obj.tuning);
|
|
1273
|
+
obj.difficulties.push(0);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// 初期速度
|
|
1277
|
+
obj.initSpeeds.push(setVal(difDetails[difpos.Speed], 3.5, C_TYP_FLOAT));
|
|
1278
|
+
});
|
|
1279
|
+
} else {
|
|
1280
|
+
makeWarningWindow(g_msgInfoObj.E_0021);
|
|
1281
|
+
obj.keyLabels = [g_keyObj.initKeyLabel];
|
|
1282
|
+
obj.difLabels = [`Normal`];
|
|
1283
|
+
obj.initSpeeds = [3.5];
|
|
1284
|
+
obj.lifeBorders = [`x`];
|
|
1285
|
+
obj.lifeRecoverys = [6];
|
|
1286
|
+
obj.lifeDamages = [40];
|
|
1287
|
+
obj.lifeInits = [25];
|
|
1288
|
+
obj.creatorNames = [obj.tuning];
|
|
1289
|
+
obj.difficulties = [0];
|
|
1290
|
+
}
|
|
1291
|
+
const keyLists = makeDedupliArray(obj.keyLabels);
|
|
1292
|
+
obj.viewLists = [...Array(obj.keyLabels.length).keys()];
|
|
1293
|
+
obj.keyLists = keyLists.sort((a, b) => parseInt(a) - parseInt(b));
|
|
1294
|
+
obj.undefinedKeyLists = obj.keyLists.filter(key => g_keyObj[`${g_keyObj.defaultProp}${key}_0`] === undefined);
|
|
1295
|
+
|
|
1296
|
+
// 楽曲別のグループ化設定(選曲モードのみ)
|
|
1297
|
+
if (hasVal(_dosObj.musicGroup)) {
|
|
1298
|
+
obj.musicGroups = _dosObj.musicGroup.split(`,`)
|
|
1299
|
+
.map((val, j) => setVal(val, j, C_TYP_NUMBER))
|
|
1300
|
+
.map((val, j) => val < 0 ? j + val : val);
|
|
1301
|
+
for (let k = obj.musicGroups.length; k <= Math.max(...obj.musicNos); k++) {
|
|
1302
|
+
obj.musicGroups[k] = k;
|
|
1303
|
+
}
|
|
1304
|
+
obj.musicIdxList = makeDedupliArray(obj.musicGroups);
|
|
1305
|
+
} else {
|
|
1306
|
+
obj.musicIdxList = [...Array(Math.max(...obj.musicNos) + 1).keys()];
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// 難易度配色の設定(選曲画面でのみ使用)
|
|
1310
|
+
const normalizeCssColor = _color => {
|
|
1311
|
+
const tmp = document.createElement(`span`);
|
|
1312
|
+
tmp.style.color = ``;
|
|
1313
|
+
tmp.style.color = trimStr(_color ?? ``);
|
|
1314
|
+
return tmp.style.color;
|
|
1315
|
+
};
|
|
1316
|
+
obj.difColorList = [
|
|
1317
|
+
{ threshold: Infinity, color: `` }
|
|
1318
|
+
];
|
|
1319
|
+
if (hasVal(_dosObj.difColor)) {
|
|
1320
|
+
_dosObj.difColor.split(`,`).forEach(val => {
|
|
1321
|
+
const difColorSet = val.split(`/`);
|
|
1322
|
+
obj.difColorList.push({
|
|
1323
|
+
threshold: setIntVal(difColorSet[0]),
|
|
1324
|
+
color: hasVal(difColorSet[1]) ? normalizeCssColor(difColorSet[1]) : ``
|
|
1325
|
+
});
|
|
1326
|
+
})
|
|
1327
|
+
}
|
|
1328
|
+
obj.difColorList.sort((a, b) => a.threshold - b.threshold);
|
|
1329
|
+
|
|
1330
|
+
const sanitizeCustomLink = _link => {
|
|
1331
|
+
try {
|
|
1332
|
+
const raw = trimStr(_link);
|
|
1333
|
+
if (!hasVal(raw)) return undefined;
|
|
1334
|
+
const url = new URL(raw, location.href); // allows relative inputs
|
|
1335
|
+
const allowed = g_isFile ? [`http:`, `https:`, `file:`] : [`http:`, `https:`];
|
|
1336
|
+
return allowed.includes(url.protocol) ? url.href : undefined;
|
|
1337
|
+
} catch {
|
|
1338
|
+
return undefined;
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
obj.difCustomLink = [];
|
|
1342
|
+
if (hasVal(_dosObj.difCustomLink)) {
|
|
1343
|
+
splitLF2(_dosObj.difCustomLink).forEach(val => {
|
|
1344
|
+
const commaPos = val.indexOf(`,`);
|
|
1345
|
+
if (commaPos < 0) return;
|
|
1346
|
+
const idxStr = trimStr(val.slice(0, commaPos));
|
|
1347
|
+
const linkStr = val.slice(commaPos + 1);
|
|
1348
|
+
const idx = setIntVal(idxStr, -1);
|
|
1349
|
+
if (!Number.isFinite(idx) || idx < 0 || idx >= obj.difLabels.length) return;
|
|
1350
|
+
const safeHref = sanitizeCustomLink(linkStr);
|
|
1351
|
+
if (safeHref !== undefined) {
|
|
1352
|
+
obj.difCustomLink[idx] = safeHref;
|
|
1353
|
+
}
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// 譜面変更セレクターの利用有無
|
|
1358
|
+
obj.difSelectorUse = getDifSelectorUse(_dosObj.difSelectorUse, obj.viewLists);
|
|
1359
|
+
|
|
1360
|
+
// 初期速度の設定
|
|
1361
|
+
g_stateObj.speed = obj.initSpeeds[g_stateObj.scoreId];
|
|
1362
|
+
g_settings.speedNum = roundZero(g_settings.speeds.findIndex(speed => speed === g_stateObj.speed));
|
|
1363
|
+
|
|
1364
|
+
// グラデーションのデフォルト中間色を設定
|
|
1365
|
+
divRoot.appendChild(createDivCss2Label(`dummyLabel`, ``));
|
|
1366
|
+
obj.baseBrightFlg = setBoolVal(_dosObj.baseBright, checkLightOrDark(colorNameToCode(window.getComputedStyle(dummyLabel, ``).color)));
|
|
1367
|
+
const intermediateColor = obj.baseBrightFlg ? `#111111` : `#eeeeee`;
|
|
1368
|
+
|
|
1369
|
+
// 矢印の色変化を常時グラデーションさせる設定
|
|
1370
|
+
obj.defaultColorgrd = [false, intermediateColor];
|
|
1371
|
+
if (hasVal(_dosObj.defaultColorgrd)) {
|
|
1372
|
+
obj.defaultColorgrd = _dosObj.defaultColorgrd.split(`,`);
|
|
1373
|
+
obj.defaultColorgrd[0] = setBoolVal(obj.defaultColorgrd[0]);
|
|
1374
|
+
obj.defaultColorgrd[1] = obj.defaultColorgrd[1] ?? intermediateColor;
|
|
1375
|
+
}
|
|
1376
|
+
g_rankObj.rankColorAllPerfect = intermediateColor;
|
|
1377
|
+
|
|
1378
|
+
// カラーコードのゼロパディング有無設定
|
|
1379
|
+
obj.colorCdPaddingUse = setBoolVal(_dosObj.colorCdPaddingUse);
|
|
1380
|
+
|
|
1381
|
+
// 最大ライフ
|
|
1382
|
+
obj.maxLifeVal = setVal(_dosObj.maxLifeVal, C_VAL_MAXLIFE, C_TYP_FLOAT);
|
|
1383
|
+
if (obj.maxLifeVal <= 0) {
|
|
1384
|
+
obj.maxLifeVal = C_VAL_MAXLIFE;
|
|
1385
|
+
makeWarningWindow(g_msgInfoObj.E_0042.split(`{0}`).join(`maxLifeVal`));
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// ゲージ初期設定(最大ライフ反映)
|
|
1389
|
+
g_gaugeOptionObj.defaultList.forEach(type => {
|
|
1390
|
+
const pos = g_gaugeOptionObj[`dmg${toCapitalize(type)}`].findIndex(val => val === C_LFE_MAXLIFE);
|
|
1391
|
+
g_gaugeOptionObj[`dmg${toCapitalize(type)}`][pos] = obj.maxLifeVal;
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
// フリーズアローのデフォルト色セットの利用有無 (true: 使用, false: 矢印色を優先してセット)
|
|
1395
|
+
obj.defaultFrzColorUse = setBoolVal(_dosObj.defaultFrzColorUse ?? g_presetObj.frzColors, true);
|
|
1396
|
+
|
|
1397
|
+
// 矢印色変化に対応してフリーズアロー色を追随する範囲の設定
|
|
1398
|
+
// (defaultFrzColorUse=false時のみ)
|
|
1399
|
+
obj.frzScopeFromArrowColors = [];
|
|
1400
|
+
|
|
1401
|
+
if (!obj.defaultFrzColorUse) {
|
|
1402
|
+
const tmpFrzScope = [];
|
|
1403
|
+
|
|
1404
|
+
if (hasVal(_dosObj.frzScopeFromAC)) {
|
|
1405
|
+
tmpFrzScope.push(..._dosObj.frzScopeFromAC.split(`,`));
|
|
1406
|
+
} else if (g_presetObj.frzScopeFromAC !== undefined) {
|
|
1407
|
+
tmpFrzScope.push(...g_presetObj.frzScopeFromAC);
|
|
1408
|
+
}
|
|
1409
|
+
tmpFrzScope.filter(type => [`Normal`, `Hit`].includes(type))
|
|
1410
|
+
.forEach(data => obj.frzScopeFromArrowColors.push(data));
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// 初期色情報
|
|
1414
|
+
const baseColor = (obj.baseBrightFlg ? `light` : `dark`);
|
|
1415
|
+
Object.assign(g_dfColorObj, g_dfColorBaseObj[baseColor]);
|
|
1416
|
+
Object.keys(g_dfColorObj).forEach(key => obj[key] = g_dfColorObj[key].concat());
|
|
1417
|
+
obj.frzColorDefault = [];
|
|
1418
|
+
|
|
1419
|
+
// ダミー用初期矢印色
|
|
1420
|
+
obj.setDummyColor = [`#777777`, `#444444`, `#777777`, `#444444`, `#777777`];
|
|
1421
|
+
obj.dfColorgrdSet = {
|
|
1422
|
+
'': obj.defaultColorgrd,
|
|
1423
|
+
'Type0': [!obj.defaultColorgrd[0], obj.defaultColorgrd[1]],
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
// カスタムゲージ設定(共通設定ファイル)
|
|
1427
|
+
addGaugeFulls(g_gaugeOptionObj.survival);
|
|
1428
|
+
addGaugeFulls(g_gaugeOptionObj.border);
|
|
1429
|
+
|
|
1430
|
+
if (g_presetObj.gaugeList !== undefined) {
|
|
1431
|
+
Object.keys(g_presetObj.gaugeList).forEach(key => {
|
|
1432
|
+
g_gaugeOptionObj.customDefault.push(key);
|
|
1433
|
+
g_gaugeOptionObj.varCustomDefault.push(boolToSwitch(g_presetObj.gaugeList[key] === `V`));
|
|
1434
|
+
});
|
|
1435
|
+
g_gaugeOptionObj.custom = g_gaugeOptionObj.customDefault.concat();
|
|
1436
|
+
g_gaugeOptionObj.varCustom = g_gaugeOptionObj.varCustomDefault.concat();
|
|
1437
|
+
addGaugeFulls(g_gaugeOptionObj.customDefault);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// カスタムゲージ設定、初期色設定(譜面ヘッダー)の譜面別設定
|
|
1441
|
+
Object.assign(obj, resetBaseColorList(obj, _dosObj));
|
|
1442
|
+
for (let j = 0; j < obj.difLabels.length; j++) {
|
|
1443
|
+
Object.assign(g_gaugeOptionObj, resetCustomGauge(_dosObj, { scoreId: j }));
|
|
1444
|
+
Object.assign(obj, resetBaseColorList(obj, _dosObj, { scoreId: j }));
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// ダミー譜面の設定
|
|
1448
|
+
if (hasVal(_dosObj.dummyId)) {
|
|
1449
|
+
obj.dummyScoreNos = _dosObj.dummyId.split(`$`);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// 無音のフレーム数
|
|
1453
|
+
obj.blankFrameDefs = [200];
|
|
1454
|
+
if (isNaN(parseFloat(_dosObj.blankFrame))) {
|
|
1455
|
+
} else {
|
|
1456
|
+
obj.blankFrameDefs = splitLF2(_dosObj.blankFrame).map(val => parseInt(val));
|
|
1457
|
+
}
|
|
1458
|
+
obj.blankFrame = obj.blankFrameDefs[0];
|
|
1459
|
+
obj.blankFrameDef = obj.blankFrameDefs[0];
|
|
1460
|
+
|
|
1461
|
+
// 開始フレーム数(0以外の場合はフェードインスタート)、終了フレーム数
|
|
1462
|
+
[`startFrame`, `endFrame`].filter(tmpParam => hasVal(_dosObj[tmpParam]))
|
|
1463
|
+
.forEach(param => obj[param] = splitLF2(_dosObj[param]).map(frame => transTimerToFrame(frame)));
|
|
1464
|
+
|
|
1465
|
+
// フェードアウトフレーム数(譜面別)
|
|
1466
|
+
if (hasVal(_dosObj.fadeFrame)) {
|
|
1467
|
+
const fadeFrames = splitLF2(_dosObj.fadeFrame);
|
|
1468
|
+
obj.fadeFrame = [];
|
|
1469
|
+
fadeFrames.forEach((fadeInfo, j) => {
|
|
1470
|
+
obj.fadeFrame[j] = fadeInfo.split(`,`);
|
|
1471
|
+
obj.fadeFrame[j][0] = transTimerToFrame(obj.fadeFrame[j][0]);
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// タイミング調整
|
|
1476
|
+
obj.adjustment = (hasVal(_dosObj.adjustment) ? _dosObj.adjustment.split(`$`) : [0]);
|
|
1477
|
+
|
|
1478
|
+
// 再生速度
|
|
1479
|
+
obj.playbackRate = setVal(_dosObj.playbackRate, 1, C_TYP_FLOAT);
|
|
1480
|
+
if (obj.playbackRate <= 0) {
|
|
1481
|
+
obj.playbackRate = 1;
|
|
1482
|
+
makeWarningWindow(g_msgInfoObj.E_0042.split(`{0}`).join(`playbackRate`));
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// プレイサイズ(X方向, Y方向)
|
|
1486
|
+
obj.playingWidth = setIntVal(_dosObj.playingWidth, g_presetObj.playingWidth ?? `default`);
|
|
1487
|
+
const tmpPlayingHeight = setIntVal(_dosObj.playingHeight, g_presetObj.playingHeight ?? g_sHeight);
|
|
1488
|
+
obj.playingHeight = Math.max(obj.heightVariable ?
|
|
1489
|
+
setIntVal(getQueryParamVal(`h`) - (g_sHeight - tmpPlayingHeight), tmpPlayingHeight) : tmpPlayingHeight, 400);
|
|
1490
|
+
|
|
1491
|
+
// プレイ左上位置(X座標, Y座標)
|
|
1492
|
+
obj.playingX = setIntVal(_dosObj.playingX, g_presetObj.playingX ?? 0);
|
|
1493
|
+
obj.playingY = setIntVal(_dosObj.playingY, g_presetObj.playingY ?? 0);
|
|
1494
|
+
|
|
1495
|
+
// ステップゾーン位置
|
|
1496
|
+
g_posObj.stepY = setVal(_dosObj.stepY, C_STEP_Y, C_TYP_FLOAT);
|
|
1497
|
+
g_posObj.stepYR = setVal(_dosObj.stepYR, C_STEP_YR, C_TYP_FLOAT);
|
|
1498
|
+
g_posObj.stepDiffY = g_posObj.stepY - C_STEP_Y;
|
|
1499
|
+
g_posObj.distY = obj.playingHeight - C_STEP_Y + g_posObj.stepYR;
|
|
1500
|
+
g_posObj.reverseStepY = g_posObj.distY - g_posObj.stepY - g_posObj.stepDiffY - C_ARW_WIDTH;
|
|
1501
|
+
g_posObj.arrowHeight = obj.playingHeight + g_posObj.stepYR - g_posObj.stepDiffY * 2;
|
|
1502
|
+
obj.bottomWordSetFlg = setBoolVal(_dosObj.bottomWordSet);
|
|
1503
|
+
|
|
1504
|
+
// ウィンドウサイズ(高さ)とステップゾーン位置の組み合わせで基準速度を変更
|
|
1505
|
+
obj.baseSpeed = 1 + ((g_posObj.distY - (g_posObj.stepY - C_STEP_Y) * 2) / (500 - C_STEP_Y) - 1) * 0.85;
|
|
1506
|
+
|
|
1507
|
+
// 矢印・フリーズアロー判定位置補正
|
|
1508
|
+
g_diffObj.arrowJdgX = setVal(_dosObj.arrowJdgX, 0, C_TYP_FLOAT);
|
|
1509
|
+
g_diffObj.arrowJdgY = setVal(_dosObj.arrowJdgY, 0, C_TYP_FLOAT);
|
|
1510
|
+
g_diffObj.frzJdgX = setVal(_dosObj.frzJdgX, 0, C_TYP_FLOAT);
|
|
1511
|
+
g_diffObj.frzJdgY = setVal(_dosObj.frzJdgY, 0, C_TYP_FLOAT);
|
|
1512
|
+
g_diffInitObj.arrowJdgX = g_diffObj.arrowJdgX;
|
|
1513
|
+
g_diffInitObj.arrowJdgY = g_diffObj.arrowJdgY;
|
|
1514
|
+
g_diffInitObj.frzJdgX = g_diffObj.frzJdgX;
|
|
1515
|
+
g_diffInitObj.frzJdgY = g_diffObj.frzJdgY;
|
|
1516
|
+
|
|
1517
|
+
// ショートカット表示位置補正
|
|
1518
|
+
g_diffObj.shortcutX = setVal(_dosObj.shortcutX, 0, C_TYP_FLOAT);
|
|
1519
|
+
g_diffObj.shortcutY = setVal(_dosObj.shortcutY, 0, C_TYP_FLOAT);
|
|
1520
|
+
g_diffInitObj.shortcutX = g_diffObj.shortcutX;
|
|
1521
|
+
g_diffInitObj.shortcutY = g_diffObj.shortcutY;
|
|
1522
|
+
|
|
1523
|
+
if (Object.keys(g_diffObj).some(key => g_localStorage[key] !== undefined)) {
|
|
1524
|
+
Object.keys(g_diffObj).forEach(key =>
|
|
1525
|
+
g_diffObj[key] = setIntVal(g_localStorage[key], g_diffObj[key])
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// musicフォルダ設定
|
|
1530
|
+
obj.musicFolder = _dosObj.musicFolder ?? (g_remoteFlg ? `${C_MRK_CURRENT_DIRECTORY}../music` : `music`);
|
|
1531
|
+
|
|
1532
|
+
// 楽曲URL
|
|
1533
|
+
if (hasVal(_dosObj.musicUrl)) {
|
|
1534
|
+
const musicUrls = splitLF2(_dosObj.musicUrl);
|
|
1535
|
+
obj.musicUrls = [], obj.musicStarts = [], obj.musicEnds = [];
|
|
1536
|
+
musicUrls.forEach((val, j) => {
|
|
1537
|
+
const musicUrlPair = val.split(`,`);
|
|
1538
|
+
obj.musicUrls[j] = musicUrlPair[0] || ``;
|
|
1539
|
+
if (musicUrlPair[1] !== undefined) {
|
|
1540
|
+
const musicBGMTime = musicUrlPair[1].split(`-`).map(str => str.trim());
|
|
1541
|
+
obj.musicStarts[j] = Math.floor(transTimerToFrame(musicBGMTime[0] ?? 0) / g_fps);
|
|
1542
|
+
obj.musicEnds[j] = musicBGMTime[1] !== undefined ?
|
|
1543
|
+
Math.floor((transTimerToFrame(musicBGMTime[1] ?? 0)) / g_fps) :
|
|
1544
|
+
Math.floor((transTimerToFrame(musicBGMTime[0] ?? 0) + transTimerToFrame(`0:20`)) / g_fps);
|
|
1545
|
+
} else {
|
|
1546
|
+
obj.musicStarts[j] = 0;
|
|
1547
|
+
obj.musicEnds[j] = 20;
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
} else {
|
|
1551
|
+
makeWarningWindow(g_msgInfoObj.E_0031);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// ハッシュタグ
|
|
1555
|
+
obj.hashTag = _dosObj.hashTag ?? ``;
|
|
1556
|
+
|
|
1557
|
+
// 読込対象の画像を指定(rel:preload)と同じ
|
|
1558
|
+
obj.preloadImages = [];
|
|
1559
|
+
if (hasVal(_dosObj.preloadImages)) {
|
|
1560
|
+
obj.preloadImages = _dosObj.preloadImages.split(`,`).filter(image => hasVal(image)).map(preloadImage => preloadImage);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// 初期表示する部分キーの設定
|
|
1564
|
+
obj.keyGroupOrder = [];
|
|
1565
|
+
_dosObj.keyGroupOrder?.split(`$`).forEach((val, j) => {
|
|
1566
|
+
if (val !== ``) {
|
|
1567
|
+
obj.keyGroupOrder[j] = val.split(`,`);
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
// 縦伸縮率の設定
|
|
1572
|
+
const stretchYRate = [];
|
|
1573
|
+
_dosObj.stretchYRate?.split(`$`).forEach((val, j) => {
|
|
1574
|
+
stretchYRate[j] = hasVal(val) ? setVal(val, 1, C_TYP_FLOAT) : 1;
|
|
1575
|
+
});
|
|
1576
|
+
obj.stretchYRate = makeBaseArray(stretchYRate, obj.difLabels.length, 1);
|
|
1577
|
+
// 最終演出表示有無(noneで無効化)
|
|
1578
|
+
obj.finishView = _dosObj.finishView ?? ``;
|
|
1579
|
+
|
|
1580
|
+
// 更新日
|
|
1581
|
+
obj.releaseDate = _dosObj.releaseDate ?? ``;
|
|
1582
|
+
|
|
1583
|
+
// デフォルトReady/リザルト表示の遅延時間設定
|
|
1584
|
+
[`ready`, `result`].forEach(objName =>
|
|
1585
|
+
obj[`${objName}DelayFrame`] = setIntVal(_dosObj[`${objName}DelayFrame`]));
|
|
1586
|
+
|
|
1587
|
+
// デフォルトReady表示のアニメーション時間設定
|
|
1588
|
+
obj.readyAnimationFrame = setIntVal(_dosObj.readyAnimationFrame, 150);
|
|
1589
|
+
|
|
1590
|
+
// デフォルトReady表示のアニメーション名
|
|
1591
|
+
obj.readyAnimationName = _dosObj.readyAnimationName ?? `leftToRightFade`;
|
|
1592
|
+
|
|
1593
|
+
// デフォルトReady表示の先頭文字色
|
|
1594
|
+
obj.readyColor = _dosObj.readyColor ?? ``;
|
|
1595
|
+
|
|
1596
|
+
// デフォルトReady表示を上書きするテキスト
|
|
1597
|
+
obj.readyHtml = _dosObj.readyHtml ?? ``;
|
|
1598
|
+
|
|
1599
|
+
// デフォルト曲名表示のフォントサイズ
|
|
1600
|
+
obj.titlesize = getHeader(_dosObj, ...getHname(`titleSize`)) ?? ``;
|
|
1601
|
+
|
|
1602
|
+
// デフォルト曲名表示のフォント名
|
|
1603
|
+
// (使用例: |titlefont=Century,Meiryo UI|)
|
|
1604
|
+
obj.titlefonts = g_titleLists.defaultFonts.concat();
|
|
1605
|
+
getHeader(_dosObj, ...getHname(`titleFont`))?.split(`$`).forEach((font, j) => obj.titlefonts[j] = `'${(font.replaceAll(`,`, `', '`))}'`);
|
|
1606
|
+
if (obj.titlefonts[1] === undefined) {
|
|
1607
|
+
obj.titlefonts[1] = obj.titlefonts[0];
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// デフォルト曲名表示, 背景矢印のグラデーション指定css
|
|
1611
|
+
[`titlegrd`, `titleArrowgrd`].forEach(_name => {
|
|
1612
|
+
const objName = `${_name.toLowerCase()}`;
|
|
1613
|
+
obj[`${objName}s`] = [];
|
|
1614
|
+
const tmpTitlegrd = getHeader(_dosObj, ...getHname(_name))?.replaceAll(`,`, `:`);
|
|
1615
|
+
if (hasVal(tmpTitlegrd)) {
|
|
1616
|
+
obj[`${objName}s`] = tmpTitlegrd.split(`$`);
|
|
1617
|
+
obj[`${objName}`] = obj[`${objName}s`][0] ?? ``;
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
// デフォルト曲名表示の表示位置調整
|
|
1622
|
+
obj.titlepos = [[0, 0], [0, 0]];
|
|
1623
|
+
getHeader(_dosObj, ...getHname(`titlePos`))?.split(`$`).forEach((pos, j) => obj.titlepos[j] = pos.split(`,`).map(x => parseFloat(x)));
|
|
1624
|
+
|
|
1625
|
+
// タイトル文字のアニメーション設定
|
|
1626
|
+
obj.titleAnimationName = [`leftToRight`];
|
|
1627
|
+
obj.titleAnimationDuration = [1.5];
|
|
1628
|
+
obj.titleAnimationDelay = [0];
|
|
1629
|
+
obj.titleAnimationTimingFunction = [`ease`];
|
|
1630
|
+
obj.titleAnimationClass = [``];
|
|
1631
|
+
|
|
1632
|
+
getHeader(_dosObj, ...getHname(`titleAnimation`))?.split(`$`).forEach((pos, j) => {
|
|
1633
|
+
const titleAnimation = pos.split(`,`);
|
|
1634
|
+
obj.titleAnimationName[j] = setVal(titleAnimation[0], obj.titleAnimationName[0]);
|
|
1635
|
+
obj.titleAnimationDuration[j] = setVal(titleAnimation[1] / g_fps, obj.titleAnimationDuration[0], C_TYP_FLOAT);
|
|
1636
|
+
obj.titleAnimationDelay[j] = setVal(titleAnimation[2] / g_fps, obj.titleAnimationDelay[0], C_TYP_FLOAT);
|
|
1637
|
+
obj.titleAnimationTimingFunction[j] = setVal(titleAnimation[3], obj.titleAnimationName[3]);
|
|
1638
|
+
});
|
|
1639
|
+
getHeader(_dosObj, ...getHname(`titleAnimationClass`))?.split(`$`).forEach((animationClass, j) =>
|
|
1640
|
+
obj.titleAnimationClass[j] = animationClass ?? ``);
|
|
1641
|
+
|
|
1642
|
+
if (obj.titleAnimationName.length === 1) {
|
|
1643
|
+
g_titleLists.animation.forEach(pattern =>
|
|
1644
|
+
obj[`titleAnimation${pattern}`][1] = obj[`titleAnimation${pattern}`][0]);
|
|
1645
|
+
}
|
|
1646
|
+
if (obj.titleAnimationClass.length === 1) {
|
|
1647
|
+
obj.titleAnimationClass[1] = obj.titleAnimationClass[0];
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// デフォルト曲名表示の複数行時の縦間隔
|
|
1651
|
+
obj.titlelineheight = setIntVal(getHeader(_dosObj, ...getHname(`titleLineHeight`)), ``);
|
|
1652
|
+
|
|
1653
|
+
// フリーズアローの始点で通常矢印の判定を行うか(dotさんソース方式)
|
|
1654
|
+
obj.frzStartjdgUse = setBoolVal(_dosObj.frzStartjdgUse ?? g_presetObj.frzStartjdgUse);
|
|
1655
|
+
|
|
1656
|
+
// 空押し判定の設定
|
|
1657
|
+
// excessiveUses : 譜面毎の空押し有効化設定
|
|
1658
|
+
// excessiveJdgUses: 譜面毎の空押し初期設定
|
|
1659
|
+
obj.excessiveUses = [];
|
|
1660
|
+
obj.excessiveJdgUses = [];
|
|
1661
|
+
splitLF2(_dosObj.excessiveUse)?.forEach(val => {
|
|
1662
|
+
const tmpVal = val.split(`,`);
|
|
1663
|
+
obj.excessiveUses.push(setBoolVal(tmpVal[0]));
|
|
1664
|
+
obj.excessiveJdgUses.push(setVal(tmpVal[1], C_FLG_OFF, C_TYP_SWITCH) === C_FLG_ON);
|
|
1665
|
+
});
|
|
1666
|
+
if ((obj.excessiveUses?.length || 0) < obj.difLabels.length) {
|
|
1667
|
+
obj.excessiveUses = makeBaseArray(obj.excessiveUses, obj.difLabels.length,
|
|
1668
|
+
setBoolVal(obj.excessiveUses?.[0] ?? _dosObj.excessiveUse ?? g_presetObj.excessiveUse, true));
|
|
1669
|
+
obj.excessiveJdgUses = makeBaseArray(obj.excessiveJdgUses, obj.difLabels.length,
|
|
1670
|
+
setBoolVal(obj.excessiveJdgUses?.[0] ?? g_presetObj.excessiveJdgUse ?? false));
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// excessiveJdgUseが有効な場合は全譜面に対して強制的に上書き
|
|
1674
|
+
if (_dosObj.excessiveJdgUse !== undefined) {
|
|
1675
|
+
const excessiveJdg = setBoolVal(_dosObj.excessiveJdgUse);
|
|
1676
|
+
if (excessiveJdg) {
|
|
1677
|
+
obj.excessiveJdgUses = obj.excessiveJdgUses.map(val => true);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
obj.excessiveJdgUse = obj.excessiveJdgUses[0];
|
|
1681
|
+
g_stateObj.excessive = boolToSwitch(obj.excessiveJdgUse);
|
|
1682
|
+
g_settings.excessiveNum = Number(obj.excessiveJdgUse);
|
|
1683
|
+
|
|
1684
|
+
// 譜面名に制作者名を付加するかどうかのフラグ(選曲用に初期値を退避)
|
|
1685
|
+
obj.makerView = setBoolVal(_dosObj.makerView);
|
|
1686
|
+
obj.makerViewOrg = obj.makerView;
|
|
1687
|
+
|
|
1688
|
+
// shuffleUse=group 時のみshuffle用配列を組み替える
|
|
1689
|
+
if (_dosObj.shuffleUse === `group`) {
|
|
1690
|
+
_dosObj.shuffleUse = true;
|
|
1691
|
+
g_settings.shuffles = g_settings.shuffles.filter(val => !val.endsWith(`+`));
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
// オプション利用可否設定
|
|
1695
|
+
g_canDisabledSettings.forEach(option =>
|
|
1696
|
+
obj[`${option}Use`] = setBoolVal(_dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option], true));
|
|
1697
|
+
|
|
1698
|
+
let interlockingErrorFlg = false;
|
|
1699
|
+
g_displays.forEach((option, j) => {
|
|
1700
|
+
|
|
1701
|
+
// Display使用可否設定を分解 |displayUse=false,ON|
|
|
1702
|
+
const displayTempUse = _dosObj[`${option}Use`] ?? g_presetObj.settingUse?.[option] ?? `true`;
|
|
1703
|
+
const displayUse = displayTempUse?.split(`,`) ?? [true, C_FLG_ON];
|
|
1704
|
+
|
|
1705
|
+
// displayUse -> ボタンの有効/無効, displaySet -> ボタンの初期値(ON/OFF)
|
|
1706
|
+
obj[`${option}Use`] = setBoolVal(displayUse[0], true);
|
|
1707
|
+
obj[`${option}Set`] = setVal(displayUse.length > 1 ? displayUse[1] :
|
|
1708
|
+
boolToSwitch(obj[`${option}Use`]), ``, C_TYP_SWITCH);
|
|
1709
|
+
g_stateObj[`d_${option.toLowerCase()}`] = setVal(obj[`${option}Set`], C_FLG_ON, C_TYP_SWITCH);
|
|
1710
|
+
obj[`${option}ChainOFF`] = _dosObj[`${option}ChainOFF`]?.split(`,`) ?? [];
|
|
1711
|
+
|
|
1712
|
+
// Displayのデフォルト設定で、双方向に設定されている場合は設定をブロック
|
|
1713
|
+
g_displays.filter((option2, k) =>
|
|
1714
|
+
j > k && (obj[`${option}ChainOFF`].includes(option2) && obj[`${option2}ChainOFF`].includes(option)))
|
|
1715
|
+
.forEach(() => {
|
|
1716
|
+
interlockingErrorFlg = true;
|
|
1717
|
+
makeWarningWindow(g_msgInfoObj.E_0051);
|
|
1718
|
+
});
|
|
1719
|
+
if (!interlockingErrorFlg && obj[`${option}ChainOFF`].includes(option)) {
|
|
1720
|
+
interlockingErrorFlg = true;
|
|
1721
|
+
makeWarningWindow(g_msgInfoObj.E_0051);
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
if (!interlockingErrorFlg) {
|
|
1726
|
+
g_displays.forEach(option =>
|
|
1727
|
+
obj[`${option}ChainOFF`].forEach(defaultOption => {
|
|
1728
|
+
g_stateObj[`d_${defaultOption.toLowerCase()}`] = C_FLG_OFF;
|
|
1729
|
+
interlockingButton(obj, defaultOption, C_FLG_OFF, C_FLG_ON);
|
|
1730
|
+
}));
|
|
1731
|
+
}
|
|
1732
|
+
obj.arrowEffectUseOrg = obj.arrowEffectUse;
|
|
1733
|
+
obj.arrowEffectSetFlg = obj.arrowEffectSet === C_FLG_ON;
|
|
1734
|
+
|
|
1735
|
+
// ローカルストレージに保存済みのColorType設定からDisplayのColor設定を反映
|
|
1736
|
+
if (g_localStorage.colorType !== undefined) {
|
|
1737
|
+
g_colorType = g_keycons.colorTypes.concat(g_keycons.colorSelf).includes(g_localStorage.colorType)
|
|
1738
|
+
? g_localStorage.colorType : `Default`;
|
|
1739
|
+
if (obj.colorUse) {
|
|
1740
|
+
g_stateObj.d_color = boolToSwitch(g_keycons.colorDefTypes.includes(g_colorType));
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// 別キーパターンの使用有無
|
|
1745
|
+
obj.transKeyUse = setBoolVal(_dosObj.transKeyUse, true);
|
|
1746
|
+
|
|
1747
|
+
// タイトル画面用・背景/マスクデータの分解 (下記すべてで1セット、改行区切り)
|
|
1748
|
+
// [フレーム数,階層,背景パス,class(CSSで別定義),X,Y,width,height,opacity,animationName,animationDuration]
|
|
1749
|
+
g_animationData.forEach(sprite => {
|
|
1750
|
+
obj[`${sprite}TitleData`] = [];
|
|
1751
|
+
obj[`${sprite}TitleMaxDepth`] = -1;
|
|
1752
|
+
|
|
1753
|
+
const dataList = [_dosObj[`${sprite}title${g_localeObj.val}_data`], _dosObj[`${sprite}title_data`]];
|
|
1754
|
+
const data = dataList.find((v) => v !== undefined);
|
|
1755
|
+
if (hasVal(data)) {
|
|
1756
|
+
[obj[`${sprite}TitleData`], obj[`${sprite}TitleMaxDepth`]] = g_animationFunc.make[sprite](data);
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
// 結果画面用のマスク透過設定
|
|
1761
|
+
obj.masktitleButton = setBoolVal(_dosObj.masktitleButton);
|
|
1762
|
+
|
|
1763
|
+
// 結果画面用のマスク透過設定
|
|
1764
|
+
obj.maskresultButton = setBoolVal(_dosObj.maskresultButton);
|
|
1765
|
+
|
|
1766
|
+
// リザルトモーションをDisplay:BackgroundのON/OFFと連動させるかどうかの設定
|
|
1767
|
+
obj.resultMotionSet = setBoolVal(_dosObj.resultMotionSet, true);
|
|
1768
|
+
|
|
1769
|
+
// 譜面明細の使用可否
|
|
1770
|
+
const tmpDetails = getHeader(_dosObj, `scoreDetailUse`, `chartDetailUse`)?.split(`,`).filter(val => hasVal(val) && val !== `false`)
|
|
1771
|
+
.map(val => replaceStr(val, g_settings.scoreDetailTrans));
|
|
1772
|
+
g_settings.scoreDetails = g_settings.scoreDetailDefs.filter(val => tmpDetails?.includes(val) || tmpDetails === undefined);
|
|
1773
|
+
|
|
1774
|
+
g_stateObj.scoreDetail = g_settings.scoreDetails[0] || ``;
|
|
1775
|
+
g_settings.scoreDetailCursors = g_settings.scoreDetails.map(val => `lnk${val}G`);
|
|
1776
|
+
g_settings.scoreDetailCursorsOrg = g_settings.scoreDetailCursors.concat();
|
|
1777
|
+
g_settings.scoreDetailCursors.push(`btnGraphB`);
|
|
1778
|
+
[`option`, `difSelector`, `scoreDetail`].forEach(page => g_shortcutObj[page].KeyQ.id = g_settings.scoreDetailCursors[0]);
|
|
1779
|
+
g_shortcutObj.scoreDetail.ArrowDown.id = g_settings.scoreDetailCursorsOrg[nextPos(0, 1, g_settings.scoreDetailCursorsOrg.length)];
|
|
1780
|
+
g_shortcutObj.scoreDetail.ArrowUp.id = g_settings.scoreDetailCursorsOrg[nextPos(0, -1, g_settings.scoreDetailCursorsOrg.length)];
|
|
1781
|
+
|
|
1782
|
+
// 判定位置をBackgroundのON/OFFと連動してリセットする設定
|
|
1783
|
+
obj.jdgPosReset = setBoolVal(_dosObj.jdgPosReset, true);
|
|
1784
|
+
|
|
1785
|
+
// タイトル表示用コメント
|
|
1786
|
+
const newlineTag = setBoolVal(_dosObj.commentAutoBr, true) ? `<br>` : ``;
|
|
1787
|
+
const tmpComment = (_dosObj[`commentVal${g_localeObj.val}`] ?? _dosObj.commentVal ?? ``).split(`\r\n`).join(`\n`);
|
|
1788
|
+
obj.commentVal = tmpComment.split(`\n`).join(newlineTag);
|
|
1789
|
+
|
|
1790
|
+
const maxMusicNo = Math.max(...obj.musicNos);
|
|
1791
|
+
for (let j = 0; j <= maxMusicNo; j++) {
|
|
1792
|
+
obj[`commentVal${j}`] = (_dosObj[`commentVal${j}`] || ``).split(`\n`)
|
|
1793
|
+
.filter((val, k) => k !== 0 || val !== ``).join(`<br>`);
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// コメントの外部化設定
|
|
1797
|
+
obj.commentExternal = setBoolVal(_dosObj.commentExternal);
|
|
1798
|
+
|
|
1799
|
+
// Reverse時の歌詞の自動反転制御
|
|
1800
|
+
obj.wordAutoReverse = _dosObj.wordAutoReverse ?? g_presetObj.wordAutoReverse ?? C_DIS_AUTO;
|
|
1801
|
+
|
|
1802
|
+
// プレイ中クレジットを表示しないエリアのサイズ(X方向)
|
|
1803
|
+
obj.customViewWidth = setVal(_dosObj.customViewWidth ?? _dosObj.customCreditWidth, 0, C_TYP_FLOAT);
|
|
1804
|
+
|
|
1805
|
+
// ショートカットキーが既定値ではない場合の左右の拡張エリアのサイズ
|
|
1806
|
+
if (hasVal(_dosObj.scArea)) {
|
|
1807
|
+
const tmp = _dosObj.scArea.split(`,`);
|
|
1808
|
+
obj.scAreaWidth = setVal(tmp[0], 0, C_TYP_FLOAT);
|
|
1809
|
+
obj.playingLayout = tmp[1] !== `left`;
|
|
1810
|
+
} else {
|
|
1811
|
+
obj.scAreaWidth = g_presetObj.scAreaWidth ?? 0;
|
|
1812
|
+
obj.playingLayout = g_presetObj.playingLayout ?? true;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// ジャストフレームの設定 (ローカル/デバッグ時: 0フレーム, 通常時: 1フレーム以内)
|
|
1816
|
+
obj.justFrames = g_isDebug ? 0 : 1;
|
|
1817
|
+
|
|
1818
|
+
// リザルトデータのカスタマイズ
|
|
1819
|
+
obj.resultFormat = escapeHtmlForEnabledTag(_dosObj.resultFormat ?? g_presetObj.resultFormat ?? g_templateObj.resultFormatDf);
|
|
1820
|
+
|
|
1821
|
+
// リザルト画像データのカスタム設定
|
|
1822
|
+
obj.resultValsView = _dosObj.resultValsView?.split(`,`) ?? g_presetObj.resultValsView ?? Array.from(Object.keys(g_presetObj.resultVals ?? {}));
|
|
1823
|
+
|
|
1824
|
+
// フェードイン時にそれ以前のデータを蓄積しない種別(word, back, mask)を指定
|
|
1825
|
+
obj.unStockCategories = (_dosObj.unStockCategory ?? ``).split(`,`);
|
|
1826
|
+
if (g_presetObj.unStockCategories !== undefined) {
|
|
1827
|
+
obj.unStockCategories = makeDedupliArray(obj.unStockCategories, g_presetObj.unStockCategories);
|
|
1828
|
+
}
|
|
1829
|
+
g_fadeinStockList = g_fadeinStockList.filter(cg => obj.unStockCategories.indexOf(cg) === -1);
|
|
1830
|
+
|
|
1831
|
+
// フェードイン時にそれ以前のデータを蓄積しないパターンを指定
|
|
1832
|
+
if (g_presetObj.stockForceDelList !== undefined) {
|
|
1833
|
+
Object.assign(g_stockForceDelList, g_presetObj.stockForceDelList);
|
|
1834
|
+
}
|
|
1835
|
+
g_fadeinStockList.filter(type => hasVal(_dosObj[`${type}StockForceDel`]))
|
|
1836
|
+
.forEach(type => g_stockForceDelList[type] = makeDedupliArray(g_stockForceDelList[type], _dosObj[`${type}StockForceDel`].split(`,`)));
|
|
1837
|
+
|
|
1838
|
+
return obj;
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
/**
|
|
1842
|
+
* 譜面リスト作成有無の状態を取得
|
|
1843
|
+
* @param {boolean} _headerFlg
|
|
1844
|
+
* @param {number[]} _viewLists
|
|
1845
|
+
* @returns {boolean}
|
|
1846
|
+
*/
|
|
1847
|
+
const getDifSelectorUse = (_headerFlg, _viewLists = g_headerObj.viewLists) => setBoolVal(_headerFlg, _viewLists.length > 5);
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* カラーセットの格納
|
|
1851
|
+
* @param {string} object._from コピー元矢印カラーセット(の譜面番号)
|
|
1852
|
+
* @param {string} object._to コピー先矢印のカラーセット(の譜面番号)
|
|
1853
|
+
* @param {object} object._fromObj コピー元オブジェクト
|
|
1854
|
+
* @param {object} object._toObj コピー先オブジェクト
|
|
1855
|
+
*/
|
|
1856
|
+
const resetColorType = ({ _from = ``, _to = ``, _fromObj = g_headerObj, _toObj = g_headerObj } = {}) => {
|
|
1857
|
+
_toObj[`setColor${_to}`] = structuredClone(_fromObj[`setColor${_from}`]);
|
|
1858
|
+
_toObj[`setShadowColor${_to}`] = structuredClone(_fromObj[`setShadowColor${_from}`]);
|
|
1859
|
+
_toObj[`frzColor${_to}`] = structuredClone(_fromObj[`frzColor${_from}`]);
|
|
1860
|
+
_toObj[`frzShadowColor${_to}`] = structuredClone(_fromObj[`frzShadowColor${_from}`]);
|
|
1861
|
+
};
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* 配列に対象がいない場合、配列の先頭にその対象を追加
|
|
1865
|
+
* @param {string[]|number[]} _arr 検索対象の配列
|
|
1866
|
+
* @param {string|number} _target 検索対象
|
|
1867
|
+
* @returns {string[]|number[]}
|
|
1868
|
+
*/
|
|
1869
|
+
const addValtoArray = (_arr, _target) => {
|
|
1870
|
+
if (!_arr.includes(_target)) {
|
|
1871
|
+
_arr.unshift(_target);
|
|
1872
|
+
}
|
|
1873
|
+
return _arr;
|
|
1874
|
+
};
|
|
1875
|
+
|
|
1876
|
+
/**
|
|
1877
|
+
* 曲名(1行)の取得
|
|
1878
|
+
* @param {string} _musicName
|
|
1879
|
+
* @returns {string}
|
|
1880
|
+
*/
|
|
1881
|
+
const getMusicNameSimple = _musicName => replaceStr(_musicName, g_escapeStr.musicNameSimple);
|
|
1882
|
+
|
|
1883
|
+
/**
|
|
1884
|
+
* 曲名(複数行)の取得
|
|
1885
|
+
* @param {string} _musicName
|
|
1886
|
+
* @returns {string[]}
|
|
1887
|
+
*/
|
|
1888
|
+
const getMusicNameMultiLine = _musicName => {
|
|
1889
|
+
const tmpName = replaceStr(_musicName, g_escapeStr.musicNameMultiLine).split(`<br>`);
|
|
1890
|
+
return tmpName.length === 1 ? [tmpName[0], ``] : tmpName;
|
|
1891
|
+
};
|
|
1892
|
+
|
|
1893
|
+
/**
|
|
1894
|
+
* 画像セットの入れ替え処理
|
|
1895
|
+
* @param {object} _imgType
|
|
1896
|
+
* @param {string} _imgType.name
|
|
1897
|
+
* @param {string} _imgType.extension
|
|
1898
|
+
* @param {string} _imgType.remoteDir
|
|
1899
|
+
* @param {boolean} _initFlg
|
|
1900
|
+
*/
|
|
1901
|
+
const updateImgType = (_imgType, _initFlg = false) => {
|
|
1902
|
+
if (_initFlg) {
|
|
1903
|
+
const baseDir = (_imgType.name === `` ? `` : `${_imgType.name}/`);
|
|
1904
|
+
C_IMG_TITLE_ARROW = `../img/${baseDir}arrow.${_imgType.extension}`;
|
|
1905
|
+
}
|
|
1906
|
+
resetImgs(_imgType.name, _imgType.extension);
|
|
1907
|
+
reloadImgObj();
|
|
1908
|
+
const orgImgObj = structuredClone(g_imgObj);
|
|
1909
|
+
Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_rootPath}${orgImgObj[key]}`);
|
|
1910
|
+
|
|
1911
|
+
// リモート時は作品ページ側にある画像を優先し、リモートに存在するもののみリモートから取得する
|
|
1912
|
+
// titleArrowについては他のImgTypeから取得するため、remoteDir属性には依存させない
|
|
1913
|
+
if (g_remoteFlg) {
|
|
1914
|
+
Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_workPath}${orgImgObj[key]}`);
|
|
1915
|
+
if (_imgType.remoteDir !== `` && hasRemoteDomain(_imgType.remoteDir)) {
|
|
1916
|
+
g_defaultSets.imgList.filter(val => val !== `titleArrow`)
|
|
1917
|
+
.forEach(key => g_imgObj[key] = `${_imgType.remoteDir}img/${orgImgObj[key]}`);
|
|
1918
|
+
} else if (g_defaultSets.imgType.findIndex(val => val === _imgType.name) >= 0) {
|
|
1919
|
+
g_defaultSets.imgList.forEach(key => g_imgObj[key] = `${g_rootPath}${orgImgObj[key]}`);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
if (_imgType.extension === undefined && g_presetObj.overrideExtension !== undefined) {
|
|
1923
|
+
Object.keys(g_imgObj).forEach(key => g_imgObj[key] = `${g_imgObj[key].slice(0, -3)}${g_presetObj.overrideExtension}`);
|
|
1924
|
+
}
|
|
1925
|
+
if (!g_isFile) {
|
|
1926
|
+
g_imgInitList.forEach(img => preloadFile(`image`, g_imgObj[img]));
|
|
1927
|
+
}
|
|
1928
|
+
};
|
|
1929
|
+
|
|
1930
|
+
/**
|
|
1931
|
+
* ゲージ設定リストへの追加
|
|
1932
|
+
* @param {object} _obj
|
|
1933
|
+
*/
|
|
1934
|
+
const addGaugeFulls = _obj => _obj.map(key => g_gaugeOptionObj.customFulls[key] = false);
|
|
1935
|
+
|
|
1936
|
+
/**
|
|
1937
|
+
* 矢印・フリーズアロー色のデータ変換
|
|
1938
|
+
* @param {object} _baseObj
|
|
1939
|
+
* @param {object} _dosObj
|
|
1940
|
+
* @param {string} [object.scoreId='']
|
|
1941
|
+
* @param {boolean} [object.scoreLockFlg=g_stateObj.scoreLockFlg]
|
|
1942
|
+
* @returns {object} ※Object.assign(obj, resetBaseColorList(...))の形で呼び出しが必要
|
|
1943
|
+
*/
|
|
1944
|
+
const resetBaseColorList = (_baseObj, _dosObj, { scoreId = ``, scoreLockFlg = g_stateObj.scoreLockFlg } = {}) => {
|
|
1945
|
+
|
|
1946
|
+
const obj = {};
|
|
1947
|
+
const idHeader = setScoreIdHeader(scoreId, scoreLockFlg, scoreId !== ``);
|
|
1948
|
+
const getRefData = (_header, _dataName) => {
|
|
1949
|
+
const data = _dosObj[`${_header}${_dataName}`];
|
|
1950
|
+
return data?.startsWith(_header) ? _dosObj[data] : data;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
[``, `Shadow`].forEach(pattern => {
|
|
1954
|
+
const _arrowCommon = `set${pattern}Color`;
|
|
1955
|
+
const _frzCommon = `frz${pattern}Color`;
|
|
1956
|
+
|
|
1957
|
+
const _name = `${_arrowCommon}${idHeader}`;
|
|
1958
|
+
const _frzName = `${_frzCommon}${idHeader}`;
|
|
1959
|
+
const _arrowInit = `${_arrowCommon}Init`;
|
|
1960
|
+
const _frzInit = `${_frzCommon}Init`;
|
|
1961
|
+
|
|
1962
|
+
const arrowColorTxt = getRefData(_arrowCommon, idHeader) || _dosObj[_arrowCommon];
|
|
1963
|
+
const frzColorTxt = getRefData(_frzCommon, idHeader) || _dosObj[_frzCommon];
|
|
1964
|
+
|
|
1965
|
+
// 矢印色
|
|
1966
|
+
Object.keys(_baseObj.dfColorgrdSet).forEach(type => {
|
|
1967
|
+
[obj[`${_name}${type}`], obj[`${_name}Str${type}`], obj[`${_name}Org${type}`]] =
|
|
1968
|
+
setColorList(arrowColorTxt, _baseObj[_arrowInit], _baseObj[_arrowInit].length, {
|
|
1969
|
+
_defaultColorgrd: _baseObj.dfColorgrdSet[type],
|
|
1970
|
+
_colorCdPaddingUse: _baseObj.colorCdPaddingUse,
|
|
1971
|
+
_shadowFlg: pattern === `Shadow`,
|
|
1972
|
+
});
|
|
1973
|
+
|
|
1974
|
+
obj[`${_frzName}${type}`] = [];
|
|
1975
|
+
obj[`${_frzName}Str${type}`] = [];
|
|
1976
|
+
obj[`${_frzName}Org${type}`] = [];
|
|
1977
|
+
});
|
|
1978
|
+
|
|
1979
|
+
// フリーズアロー色
|
|
1980
|
+
const tmpFrzColors = (frzColorTxt !== undefined ? splitLF2(frzColorTxt) : []);
|
|
1981
|
+
const firstFrzColors = tmpFrzColors[0]?.split(`,`) ?? [];
|
|
1982
|
+
|
|
1983
|
+
for (let j = 0; j < _baseObj.setColorInit.length; j++) {
|
|
1984
|
+
|
|
1985
|
+
// デフォルト配列の作成(1番目の要素をベースに、フリーズアロー初期セット or 矢印色からデータを補完)
|
|
1986
|
+
const currentFrzColors = [];
|
|
1987
|
+
const baseLength = firstFrzColors.length === 0 || _baseObj.defaultFrzColorUse ?
|
|
1988
|
+
_baseObj[_frzInit].length : firstFrzColors.length;
|
|
1989
|
+
for (let k = 0; k < baseLength; k++) {
|
|
1990
|
+
currentFrzColors[k] = setVal(firstFrzColors[k],
|
|
1991
|
+
_baseObj.defaultFrzColorUse ? _baseObj[_frzInit][k] : obj[`${_name}Str`][j]);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
Object.keys(_baseObj.dfColorgrdSet).forEach(type =>
|
|
1995
|
+
[obj[`${_frzName}${type}`][j], obj[`${_frzName}Str${type}`][j], obj[`${_frzName}Org${type}`][j]] =
|
|
1996
|
+
setColorList(tmpFrzColors[j], currentFrzColors, _baseObj[_frzInit].length, {
|
|
1997
|
+
_defaultColorgrd: _baseObj.dfColorgrdSet[type],
|
|
1998
|
+
_colorCdPaddingUse: _baseObj.colorCdPaddingUse,
|
|
1999
|
+
_defaultFrzColorUse: _baseObj.defaultFrzColorUse,
|
|
2000
|
+
_objType: `frz`,
|
|
2001
|
+
_shadowFlg: pattern === `Shadow`,
|
|
2002
|
+
}));
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
obj[`${_name}Default`] = obj[_name].concat();
|
|
2006
|
+
obj[`${_frzName}Default`] = obj[_frzName].concat();
|
|
2007
|
+
});
|
|
2008
|
+
|
|
2009
|
+
return obj;
|
|
2010
|
+
};
|
|
2011
|
+
|
|
2012
|
+
/**
|
|
2013
|
+
* 矢印・フリーズアロー色のデータ展開
|
|
2014
|
+
* @param {string} _data
|
|
2015
|
+
* @param {string[]} _colorInit
|
|
2016
|
+
* @param {number} _colorInitLength
|
|
2017
|
+
* @param {string[]} [object._defaultColorgrd=g_headerObj.defaultColorgrd]
|
|
2018
|
+
* @param {boolean} [object._colorCdPaddingUse=false]
|
|
2019
|
+
* @param {boolean} [object._defaultFrzColorUse=true]
|
|
2020
|
+
* @param {string} [object._objType='normal']
|
|
2021
|
+
* @param {boolean} [object._shadowFlg=false]
|
|
2022
|
+
* @returns {string[][]}
|
|
2023
|
+
*/
|
|
2024
|
+
const setColorList = (_data, _colorInit, _colorInitLength,
|
|
2025
|
+
{ _defaultColorgrd = g_headerObj.defaultColorgrd, _colorCdPaddingUse = false,
|
|
2026
|
+
_defaultFrzColorUse = true, _objType = `normal`, _shadowFlg = false } = {}) => {
|
|
2027
|
+
|
|
2028
|
+
// グラデーション文字列 #ffff99:#9999ff@linear-gradient
|
|
2029
|
+
let colorStr = [];
|
|
2030
|
+
|
|
2031
|
+
// カラーコード抽出用 #ffff99 - Ready文字、背景矢印のデフォルト色で使用
|
|
2032
|
+
let colorOrg = [];
|
|
2033
|
+
|
|
2034
|
+
// グラデーション適用後文字列 linear-gradient(to right, #ffff99, #9999ff)
|
|
2035
|
+
let colorList = [];
|
|
2036
|
+
|
|
2037
|
+
// 譜面側で指定されているデータを配列に変換
|
|
2038
|
+
if (hasVal(_data)) {
|
|
2039
|
+
colorList = _data.split(`,`);
|
|
2040
|
+
colorStr = colorList.concat();
|
|
2041
|
+
|
|
2042
|
+
// データ補完処理
|
|
2043
|
+
const defaultLength = colorStr.length;
|
|
2044
|
+
if (_objType === `frz` && _defaultFrzColorUse) {
|
|
2045
|
+
// デフォルト配列に満たない・足りない部分はデフォルト配列で穴埋め
|
|
2046
|
+
for (let j = 0; j < _colorInitLength; j++) {
|
|
2047
|
+
if (!hasVal(colorStr[j])) {
|
|
2048
|
+
colorStr[j] = _colorInit[j];
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
} else {
|
|
2052
|
+
// デフォルト配列長をループさせて格納
|
|
2053
|
+
for (let j = 0; j < _colorInitLength; j++) {
|
|
2054
|
+
colorStr[j] = colorStr[j % defaultLength];
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
colorList = colorStr.concat();
|
|
2058
|
+
|
|
2059
|
+
for (let j = 0; j < colorList.length; j++) {
|
|
2060
|
+
const tmpSetColorOrg = colorStr[j].replaceAll(`0x`, `#`).split(`:`);
|
|
2061
|
+
const hasColor = tmpSetColorOrg.some(tmpColorOrg => {
|
|
2062
|
+
if (hasVal(tmpColorOrg) && (isColorCd(tmpColorOrg) || !hasAnglePointInfo(tmpColorOrg) || tmpColorOrg === `Default`)) {
|
|
2063
|
+
colorOrg[j] = colorCdPadding(_colorCdPaddingUse, colorToHex(tmpColorOrg));
|
|
2064
|
+
return true;
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2067
|
+
if (!hasColor) {
|
|
2068
|
+
colorOrg[j] = _colorInit[j];
|
|
2069
|
+
}
|
|
2070
|
+
colorList[j] = makeColorGradation(colorStr[j] === `` ? _colorInit[j] : colorStr[j], {
|
|
2071
|
+
_defaultColorgrd, _colorCdPaddingUse, _objType, _shadowFlg,
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
} else {
|
|
2076
|
+
|
|
2077
|
+
// 未定義の場合は指定されたデフォルト配列(_colorInit)で再定義
|
|
2078
|
+
colorStr = _colorInit.concat();
|
|
2079
|
+
colorOrg = _colorInit.concat();
|
|
2080
|
+
colorList = _colorInit.map(colorStr => makeColorGradation(colorStr, {
|
|
2081
|
+
_defaultColorgrd, _colorCdPaddingUse, _shadowFlg,
|
|
2082
|
+
}));
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
return [colorList, colorStr, colorOrg];
|
|
2086
|
+
};
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* 複合カスタムゲージの定義設定
|
|
2090
|
+
* |customGauge=_Original::F::Original,_Normal::V::Normal,Escape::V|
|
|
2091
|
+
* @param {object} _dosObj
|
|
2092
|
+
* @param {string} [object.scoreId=0]
|
|
2093
|
+
* @returns {object} ※Object.assign(obj, resetCustomGauge(...))の形で呼び出しが必要
|
|
2094
|
+
*/
|
|
2095
|
+
const resetCustomGauge = (_dosObj, { scoreId = 0 } = {}) => {
|
|
2096
|
+
|
|
2097
|
+
const obj = {};
|
|
2098
|
+
const scoreIdHeader = setScoreIdHeader(scoreId, g_stateObj.scoreLockFlg, false);
|
|
2099
|
+
const dosCustomGauge = _dosObj[`customGauge${scoreIdHeader}`];
|
|
2100
|
+
if (hasVal(dosCustomGauge)) {
|
|
2101
|
+
if (g_gaugeOptionObj.defaultPlusList.includes(dosCustomGauge)) {
|
|
2102
|
+
obj[`custom${scoreId}`] = g_gaugeOptionObj[dosCustomGauge].concat();
|
|
2103
|
+
obj[`varCustom${scoreId}`] = g_gaugeOptionObj[`var${toCapitalize(dosCustomGauge)}`].concat();
|
|
2104
|
+
if (g_gaugeOptionObj.defaultList.includes(dosCustomGauge)) {
|
|
2105
|
+
obj[`defaultGauge${scoreId}`] = dosCustomGauge;
|
|
2106
|
+
obj[`typeCustom${scoreId}`] = g_gaugeOptionObj[`type${toCapitalize(dosCustomGauge)}`].concat();
|
|
2107
|
+
}
|
|
2108
|
+
} else {
|
|
2109
|
+
const customGauges = dosCustomGauge.split(`,`);
|
|
2110
|
+
|
|
2111
|
+
obj[`custom${scoreId}`] = [];
|
|
2112
|
+
obj[`varCustom${scoreId}`] = [];
|
|
2113
|
+
|
|
2114
|
+
for (let j = 0; j < customGauges.length; j++) {
|
|
2115
|
+
const customGaugeSets = customGauges[j].split(`::`);
|
|
2116
|
+
obj[`custom${scoreId}`][j] = customGaugeSets[0];
|
|
2117
|
+
obj[`varCustom${scoreId}`][j] = boolToSwitch(customGaugeSets[1] === `V`);
|
|
2118
|
+
if (hasVal(customGaugeSets[2])) {
|
|
2119
|
+
g_lblNameObj[`u_${customGaugeSets[0]}`] = customGaugeSets[2];
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
if (scoreId === 0) {
|
|
2123
|
+
obj.custom = obj.custom0.concat();
|
|
2124
|
+
obj.varCustom = obj.varCustom0.concat();
|
|
2125
|
+
}
|
|
2126
|
+
addGaugeFulls(obj[`custom${scoreId}`]);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
return obj;
|
|
2130
|
+
};
|
|
2131
|
+
|
|
2132
|
+
/**
|
|
2133
|
+
* ゲージ別個別設定の取得
|
|
2134
|
+
* @param {object} _dosObj
|
|
2135
|
+
* @param {string} _name
|
|
2136
|
+
* @param {number} _difLength
|
|
2137
|
+
* @param {string} [object.scoreId=0]
|
|
2138
|
+
*/
|
|
2139
|
+
const getGaugeSetting = (_dosObj, _name, _difLength, { scoreId = 0 } = {}) => {
|
|
2140
|
+
|
|
2141
|
+
const obj = {
|
|
2142
|
+
lifeBorders: [],
|
|
2143
|
+
lifeRecoverys: [],
|
|
2144
|
+
lifeDamages: [],
|
|
2145
|
+
lifeInits: []
|
|
2146
|
+
};
|
|
2147
|
+
/** ゲージ設定再作成フラグ */
|
|
2148
|
+
let gaugeCreateFlg = false;
|
|
2149
|
+
|
|
2150
|
+
/** ゲージ設定上書きフラグ */
|
|
2151
|
+
const gaugeUpdateFlg = g_stateObj.scoreLockFlg && scoreId > 0;
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* ゲージ別個別配列への値格納
|
|
2155
|
+
* この時点では各種ゲージ設定は文字列のまま。setGauge関数にて数式に変換される
|
|
2156
|
+
* @param {number} _scoreId
|
|
2157
|
+
* @param {string[]} _gaugeDetails
|
|
2158
|
+
* @returns {boolean}
|
|
2159
|
+
*/
|
|
2160
|
+
const setGaugeDetails = (_scoreId, _gaugeDetails) => {
|
|
2161
|
+
|
|
2162
|
+
obj.lifeBorders[_scoreId] = _gaugeDetails[0] === `x` ? `x` : _gaugeDetails[0];
|
|
2163
|
+
obj.lifeRecoverys[_scoreId] = _gaugeDetails[1];
|
|
2164
|
+
obj.lifeDamages[_scoreId] = _gaugeDetails[2];
|
|
2165
|
+
obj.lifeInits[_scoreId] = _gaugeDetails[3];
|
|
2166
|
+
|
|
2167
|
+
if (gaugeUpdateFlg && hasVal(g_gaugeOptionObj[`gauge${_name}s`])) {
|
|
2168
|
+
// ゲージ上書き時は_gaugeDetails(obj)の値を優先し、デフォルト値で穴埋めする
|
|
2169
|
+
Object.keys(obj).forEach(key => g_gaugeOptionObj[`gauge${_name}s`][key] =
|
|
2170
|
+
fillMissingArrayElem(g_gaugeOptionObj[`gauge${_name}s`][key] || [], obj[key]));
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
return true;
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
/**
|
|
2177
|
+
* gaugeNormal2, gaugeEasy2などの個別設定があった場合にその値から配列を作成
|
|
2178
|
+
* @param {number} _scoreId
|
|
2179
|
+
* @param {number[]} _defaultGaugeList
|
|
2180
|
+
* @returns {number[]}
|
|
2181
|
+
*/
|
|
2182
|
+
const getGaugeDetailList = (_scoreId, _defaultGaugeList) => {
|
|
2183
|
+
if (_scoreId > 0) {
|
|
2184
|
+
const idHeader = setScoreIdHeader(_scoreId, g_stateObj.scoreLockFlg, false);
|
|
2185
|
+
const dosId = (idHeader || 0) - 1;
|
|
2186
|
+
const headerName = `gauge${_name}${idHeader}`;
|
|
2187
|
+
if (hasVal(_dosObj[headerName])) {
|
|
2188
|
+
const gauges = splitLF2(_dosObj[headerName]);
|
|
2189
|
+
return (gauges[dosId] || gauges[0])?.split(`,`);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
return _defaultGaugeList;
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
if (hasVal(_dosObj[`gauge${_name}`])) {
|
|
2196
|
+
|
|
2197
|
+
const gauges = splitLF2(_dosObj[`gauge${_name}`]);
|
|
2198
|
+
if (gaugeUpdateFlg) {
|
|
2199
|
+
gaugeCreateFlg = setGaugeDetails(scoreId, (gauges[scoreId] || gauges[0])?.split(`,`));
|
|
2200
|
+
} else {
|
|
2201
|
+
for (let j = 0; j < _difLength; j++) {
|
|
2202
|
+
gaugeCreateFlg = setGaugeDetails(j, getGaugeDetailList(j, (gauges[j] || gauges[0]).split(`,`)));
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
} else if (g_presetObj.gaugeCustom?.[_name] !== undefined) {
|
|
2207
|
+
|
|
2208
|
+
const gaugeDetails = [
|
|
2209
|
+
g_presetObj.gaugeCustom[_name].Border, g_presetObj.gaugeCustom[_name].Recovery,
|
|
2210
|
+
g_presetObj.gaugeCustom[_name].Damage, g_presetObj.gaugeCustom[_name].Init,
|
|
2211
|
+
];
|
|
2212
|
+
if (gaugeUpdateFlg) {
|
|
2213
|
+
gaugeCreateFlg = setGaugeDetails(scoreId, gaugeDetails);
|
|
2214
|
+
} else {
|
|
2215
|
+
for (let j = 0; j < _difLength; j++) {
|
|
2216
|
+
gaugeCreateFlg = setGaugeDetails(j, getGaugeDetailList(j, gaugeDetails));
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
if (gaugeCreateFlg) {
|
|
2221
|
+
g_gaugeOptionObj[`gauge${_name}s`] = obj;
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
|
|
2225
|
+
/**
|
|
2226
|
+
* キー名の取得
|
|
2227
|
+
* @param {string} _key
|
|
2228
|
+
* @returns {string} キー名
|
|
2229
|
+
*/
|
|
2230
|
+
const getKeyName = _key => unEscapeHtml(escapeHtml(g_keyObj[`keyName${_key}`]?.[0] ?? _key));
|
|
2231
|
+
|
|
2232
|
+
/**
|
|
2233
|
+
* キー単位名の取得
|
|
2234
|
+
* @param {string} _key
|
|
2235
|
+
* @returns {string} キー単位名(デフォルト: key)
|
|
2236
|
+
*/
|
|
2237
|
+
const getKeyUnitName = _key => unEscapeHtml(escapeHtml(g_keyObj[`keyName${_key}`]?.[1] ?? `key`));
|
|
2238
|
+
|
|
2239
|
+
/**
|
|
2240
|
+
* シャッフル名の取得
|
|
2241
|
+
* @returns {string}
|
|
2242
|
+
*/
|
|
2243
|
+
const getShuffleName = () => {
|
|
2244
|
+
const orgShuffleFlg = getOrgShuffleFlg();
|
|
2245
|
+
return `${getStgDetailName(g_stateObj.shuffle)}${!orgShuffleFlg && !g_stateObj.shuffle.endsWith(`+`) ? getStgDetailName('(S)') : ''}`;
|
|
2246
|
+
};
|
|
2247
|
+
|
|
2248
|
+
/**
|
|
2249
|
+
* シャッフルカスタムフラグの取得
|
|
2250
|
+
* @returns {boolean}
|
|
2251
|
+
*/
|
|
2252
|
+
const getOrgShuffleFlg = () => {
|
|
2253
|
+
const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
2254
|
+
return g_keyObj[`shuffle${keyCtrlPtn}`].filter((shuffleGr, j) => shuffleGr !== g_keyObj[`shuffle${keyCtrlPtn}_0d`][j]).length === 0;
|
|
2255
|
+
};
|
|
2256
|
+
|
|
2257
|
+
/**
|
|
2258
|
+
* 別キーモード時の表示名の取得
|
|
2259
|
+
* @param {boolean} _spaceFlg
|
|
2260
|
+
* @returns {string} 別キー名
|
|
2261
|
+
*/
|
|
2262
|
+
const getTransKeyName = (_spaceFlg = false) => hasVal(g_keyObj[`transKey${g_keyObj.currentKey}_${g_keyObj.currentPtn}`])
|
|
2263
|
+
? (_spaceFlg ? ` ` : ``) + `(${g_keyObj[`transKey${g_keyObj.currentKey}_${g_keyObj.currentPtn}`]})` : ``;
|
|
2264
|
+
|
|
2265
|
+
/**
|
|
2266
|
+
* ハイスコア定義を行う際のストレージキー名の取得
|
|
2267
|
+
* @param {string} _key
|
|
2268
|
+
* @param {string} _transName
|
|
2269
|
+
* @param {string} _assistFlg
|
|
2270
|
+
* @param {string} _mirrorName
|
|
2271
|
+
* @param {string} _scoreId
|
|
2272
|
+
* @returns {string}
|
|
2273
|
+
*/
|
|
2274
|
+
const getStorageKeyName = (_key, _transName, _assistFlg, _mirrorName, _scoreId) => {
|
|
2275
|
+
let scoreName = `${_key}${_transName}${getStgDetailName('k-')}${g_headerObj.difLabels[_scoreId]}${_assistFlg}${_mirrorName}`;
|
|
2276
|
+
if (g_headerObj.makerView) {
|
|
2277
|
+
scoreName += `-${g_headerObj.creatorNames[_scoreId]}`;
|
|
2278
|
+
}
|
|
2279
|
+
return scoreName;
|
|
2280
|
+
};
|
|
2281
|
+
|
|
2282
|
+
/**
|
|
2283
|
+
* KeyBoardEvent.code の値をCW Edition用のキーコードに変換
|
|
2284
|
+
* 簡略指定ができるように、以下の記述を許容
|
|
2285
|
+
* 例) KeyD -> D, ArrowDown -> Down, AltLeft -> Alt
|
|
2286
|
+
* @param {string} _kCdN
|
|
2287
|
+
* @returns {number}
|
|
2288
|
+
*/
|
|
2289
|
+
const getKeyCtrlVal = _kCdN => {
|
|
2290
|
+
const convVal = Object.keys(g_kCdN).findIndex(val =>
|
|
2291
|
+
[_kCdN, `Key${_kCdN}`, `Arrow${_kCdN}`].includes(g_kCdN[val]) || _kCdN === replaceStr(g_kCdN[val], g_escapeStr.keyCtrlName));
|
|
2292
|
+
return convVal !== -1 ? convVal : parseInt(_kCdN, 10);
|
|
2293
|
+
};
|
|
2294
|
+
|
|
2295
|
+
/**
|
|
2296
|
+
* 一時的な追加キーの設定
|
|
2297
|
+
* - keyExtraListの指定がない場合は、_dosObj.keyCtrlXに合致するXを追加キーとして追加
|
|
2298
|
+
* @param {object} _dosObj
|
|
2299
|
+
* @param {string[]} object.keyExtraList
|
|
2300
|
+
* @returns {string[]}
|
|
2301
|
+
*/
|
|
2302
|
+
const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`) } = {}) => {
|
|
2303
|
+
|
|
2304
|
+
if (keyExtraList === undefined) {
|
|
2305
|
+
keyExtraList = [];
|
|
2306
|
+
Object.keys(_dosObj).filter(val => val.startsWith(g_keyObj.defaultProp))
|
|
2307
|
+
.forEach(keyName => keyExtraList.push(keyName.slice(g_keyObj.defaultProp.length)));
|
|
2308
|
+
|
|
2309
|
+
if (keyExtraList.length === 0) {
|
|
2310
|
+
return [];
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
const existParam = (_data, _paramName) => !hasVal(_data) && g_keyObj[_paramName] !== undefined;
|
|
2315
|
+
const toString = _str => _str;
|
|
2316
|
+
const toInt = _num => isNaN(parseInt(_num)) ? _num : parseInt(_num);
|
|
2317
|
+
const toFloat = _num => isNaN(parseFloat(_num)) ? _num : parseFloat(_num);
|
|
2318
|
+
const toKeyCtrlArray = _str =>
|
|
2319
|
+
makeBaseArray(_str.split(`/`).map(n => getKeyCtrlVal(n)), g_keyObj.minKeyCtrlNum, 0);
|
|
2320
|
+
const toSplitArrayStr = _str => _str.split(`/`).map(n => n);
|
|
2321
|
+
|
|
2322
|
+
// 略記記法を元の文字列に復元後、配列に変換 (1...3,5...7 -> 1,2,3,5,6,7)
|
|
2323
|
+
const toOriginalArray = (_val, _func) => _val?.split(`,`).map(n => _func(n)).join(`,`).split(`,`);
|
|
2324
|
+
|
|
2325
|
+
/**
|
|
2326
|
+
* 略記記法を元の文字列に変換 (1...5 -> 1,2,3,4,5 / 3...+4 -> 3,4,5,6,7)
|
|
2327
|
+
* @param {string} _str
|
|
2328
|
+
* @returns {string}
|
|
2329
|
+
*/
|
|
2330
|
+
const toFloatStr = _str => {
|
|
2331
|
+
const nums = _str?.split(`...`);
|
|
2332
|
+
const bottomMark = nums[0].startsWith(`b`) ? `b` : ``;
|
|
2333
|
+
const [startN, endN] = [parseFloat(bottomMark === `b` ? nums[0].slice(1) : nums[0]), parseFloat(nums[1])];
|
|
2334
|
+
|
|
2335
|
+
if (nums.length === 2 && !isNaN(startN) && !isNaN(endN)) {
|
|
2336
|
+
const endN2 = nums[1].startsWith(`+`) ? startN + endN : endN;
|
|
2337
|
+
const arr = [];
|
|
2338
|
+
for (let k = startN; k <= endN2; k++) {
|
|
2339
|
+
arr.push(`${bottomMark}${k}`);
|
|
2340
|
+
}
|
|
2341
|
+
return arr.join(`,`);
|
|
2342
|
+
} else {
|
|
2343
|
+
return _str;
|
|
2344
|
+
}
|
|
2345
|
+
};
|
|
2346
|
+
|
|
2347
|
+
/**
|
|
2348
|
+
* 略記記法を元の文字列に変換 (1@:5 -> 1,1,1,1,1 / onigiri!giko!c@:2 -> onigiri,giko,c,onigiri,giko,c)
|
|
2349
|
+
* @param {string} _str
|
|
2350
|
+
* @returns {string}
|
|
2351
|
+
*/
|
|
2352
|
+
const toSameValStr = _str => {
|
|
2353
|
+
const nums = _str?.split(`@:`);
|
|
2354
|
+
const groupStr = toFloatStr(nums[0]).split(`!`).join(`,`);
|
|
2355
|
+
return nums.length === 2 && !isNaN(parseInt(nums[1])) ?
|
|
2356
|
+
fillArray(Math.floor(parseInt(nums[1])), groupStr).join(`,`) : groupStr;
|
|
2357
|
+
};
|
|
2358
|
+
|
|
2359
|
+
/**
|
|
2360
|
+
* キーパターン(相対パターン)をキーパターン(実際のパターン番号)に変換
|
|
2361
|
+
* 例) 12_(0) -> 12_4
|
|
2362
|
+
* それ以外の文字列が来た場合は、そのままの値を戻す
|
|
2363
|
+
* @param {string} _str
|
|
2364
|
+
* @returns {string}
|
|
2365
|
+
*/
|
|
2366
|
+
const getKeyPtnName = _str => {
|
|
2367
|
+
const regex = /\((\d+)\)/;
|
|
2368
|
+
const checkStr = _str.match(regex);
|
|
2369
|
+
if (checkStr !== null) {
|
|
2370
|
+
return _str.replace(regex, (match, p) => `${parseInt(p, 10) + setIntVal(g_keyObj.dfPtnNum)}`);
|
|
2371
|
+
}
|
|
2372
|
+
return _str;
|
|
2373
|
+
};
|
|
2374
|
+
|
|
2375
|
+
/**
|
|
2376
|
+
* divMaxX, posXの下段補完処理
|
|
2377
|
+
* ・divXの1番目の指定があるとき、その値を元に下段の位置を補完
|
|
2378
|
+
* 例) |div11x=7,b6|pos11x=0,1,2,3,4,5,6,b0,b1,b5,b6|
|
|
2379
|
+
* -> |div11x=7,13|pos11x=0,1,2,3,4,5,6,7,8,12,13|
|
|
2380
|
+
* @param {number} _num
|
|
2381
|
+
* @param {number} _divNum
|
|
2382
|
+
* @returns {number}
|
|
2383
|
+
*/
|
|
2384
|
+
const getKeyPosNum = (_num, _divNum = 0) => {
|
|
2385
|
+
if (!hasVal(_num) || (!_num.startsWith(`b`) && isNaN(parseFloat(_num)))) {
|
|
2386
|
+
return _num;
|
|
2387
|
+
}
|
|
2388
|
+
return _num.startsWith(`b`) ? parseFloat(_num.slice(1)) + _divNum : parseFloat(_num);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
/**
|
|
2392
|
+
* キーパターンの略名から実際のデータへ展開
|
|
2393
|
+
* - charaX の場合に限り、a>5_0 の形式を aleft, adown, aup, aright, aspace に変換する
|
|
2394
|
+
* @param {string} _str
|
|
2395
|
+
* @param {string} _name
|
|
2396
|
+
* @param {Function} _convFunc
|
|
2397
|
+
* @returns {string[]|number[]}
|
|
2398
|
+
*/
|
|
2399
|
+
const expandKeyPtn = (_str, _name, _convFunc) => {
|
|
2400
|
+
const pos = _str.indexOf(`>`);
|
|
2401
|
+
const expandData = _ptnstr => structuredClone(g_keyObj[`${_name}${getKeyPtnName(_ptnstr)}`]) ?? [_convFunc(_ptnstr)];
|
|
2402
|
+
|
|
2403
|
+
if (pos > 0 && _name === `chara`) {
|
|
2404
|
+
const [header, ptn] = [_str.substring(0, pos), _str.substring(pos + 1)];
|
|
2405
|
+
return expandData(ptn)?.map(n => `${header}${n}`);
|
|
2406
|
+
} else {
|
|
2407
|
+
return expandData(_str);
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
2410
|
+
|
|
2411
|
+
/**
|
|
2412
|
+
* 新キー用複合パラメータ
|
|
2413
|
+
* @param {string} _key キー数
|
|
2414
|
+
* @param {string} _name 名前
|
|
2415
|
+
* @param {Function} _convFunc マッピング関数
|
|
2416
|
+
* @param {string} object.errCd エラーコード
|
|
2417
|
+
* @param {boolean} object.baseCopyFlg コピー配列の準備可否
|
|
2418
|
+
* @param {Function} object.loopFunc パターン別に処理する個別関数
|
|
2419
|
+
* @returns {number} 最小パターン数
|
|
2420
|
+
*/
|
|
2421
|
+
const newKeyMultiParam = (_key, _name, _convFunc, { errCd = ``, baseCopyFlg = false, loopFunc = () => true } = {}) => {
|
|
2422
|
+
let tmpMinPatterns = 1;
|
|
2423
|
+
const keyheader = _name + _key;
|
|
2424
|
+
const dfPtn = setIntVal(g_keyObj.dfPtnNum);
|
|
2425
|
+
|
|
2426
|
+
if (hasVal(_dosObj[keyheader])) {
|
|
2427
|
+
const tmpArray = splitLF2(_dosObj[keyheader]);
|
|
2428
|
+
tmpMinPatterns = tmpArray.length;
|
|
2429
|
+
for (let k = 0; k < tmpMinPatterns; k++) {
|
|
2430
|
+
if (existParam(tmpArray[k], `${keyheader}_${k + dfPtn}`)) {
|
|
2431
|
+
continue;
|
|
2432
|
+
}
|
|
2433
|
+
// |keyCtrl9j=Tab,7_0,Enter| -> |keyCtrl9j=Tab,S,D,F,Space,J,K,L,Enter| のように補完
|
|
2434
|
+
// |pos9j=0..4,6..9| -> |pos9j=0,1,2,3,4,6,7,8,9|
|
|
2435
|
+
g_keyObj[`${keyheader}_${k + dfPtn}`] =
|
|
2436
|
+
toOriginalArray(tmpArray[k], toSameValStr).map(n => expandKeyPtn(n, _name, _convFunc)).flat();
|
|
2437
|
+
if (baseCopyFlg) {
|
|
2438
|
+
g_keyObj[`${keyheader}_${k + dfPtn}d`] = structuredClone(g_keyObj[`${keyheader}_${k + dfPtn}`]);
|
|
2439
|
+
}
|
|
2440
|
+
loopFunc(k, keyheader);
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
} else if (errCd !== `` && g_keyObj[`${keyheader}_0`] === undefined) {
|
|
2444
|
+
makeWarningWindow(g_msgInfoObj[errCd].split(`{0}`).join(_key));
|
|
2445
|
+
}
|
|
2446
|
+
return tmpMinPatterns;
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
/**
|
|
2450
|
+
* 新キー用複合パラメータ(特殊)
|
|
2451
|
+
* @param {string} _key キー数
|
|
2452
|
+
* @param {string} _name 名前
|
|
2453
|
+
*/
|
|
2454
|
+
const newKeyTripleParam = (_key, _name) => {
|
|
2455
|
+
const keyheader = _name + _key;
|
|
2456
|
+
const dfPtn = setIntVal(g_keyObj.dfPtnNum);
|
|
2457
|
+
|
|
2458
|
+
if (hasVal(_dosObj[keyheader])) {
|
|
2459
|
+
splitLF2(_dosObj[keyheader])?.forEach((tmpParam, k) => {
|
|
2460
|
+
if (existParam(tmpParam, `${keyheader}_${k + dfPtn}`)) {
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
let ptnCnt = 0;
|
|
2465
|
+
tmpParam.split(`/`).forEach(list => {
|
|
2466
|
+
|
|
2467
|
+
const keyPtn = getKeyPtnName(list);
|
|
2468
|
+
if (list === ``) {
|
|
2469
|
+
// 空指定の場合は一律同じグループへ割り当て
|
|
2470
|
+
g_keyObj[`${keyheader}_${k + dfPtn}_${ptnCnt}`] = fillArray(g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length);
|
|
2471
|
+
|
|
2472
|
+
} else if (g_keyObj[`${_name}${keyPtn}_0`] !== undefined) {
|
|
2473
|
+
// 他のキーパターン (例: |shuffle8i=8_0| ) を直接指定した場合、該当があれば既存パターンからコピー
|
|
2474
|
+
// 既存パターンが複数ある場合、全てコピーする
|
|
2475
|
+
let m = 0;
|
|
2476
|
+
while (g_keyObj[`${_name}${keyPtn}_${m}`] !== undefined) {
|
|
2477
|
+
g_keyObj[`${keyheader}_${k + dfPtn}_${ptnCnt}`] = structuredClone(g_keyObj[`${_name}${keyPtn}_${m}`]);
|
|
2478
|
+
m++;
|
|
2479
|
+
ptnCnt++;
|
|
2480
|
+
}
|
|
2481
|
+
} else {
|
|
2482
|
+
// 通常の指定方法 (例: |shuffle8i=1,1,1,2,0,0,0,0/1,1,1,1,0,0,0,0| )の場合の取り込み
|
|
2483
|
+
// 部分的にキーパターン指定があった場合は既存パターンを展開 (例: |shuffle9j=2,7_0_0,2|)
|
|
2484
|
+
g_keyObj[`${keyheader}_${k + dfPtn}_${ptnCnt}`] =
|
|
2485
|
+
makeBaseArray(toOriginalArray(list, toSameValStr).map(n =>
|
|
2486
|
+
expandKeyPtn(n, _name, _str => isNaN(parseInt(_str)) ? _str : parseInt(_str, 10))
|
|
2487
|
+
).flat(), g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length, 0);
|
|
2488
|
+
ptnCnt++;
|
|
2489
|
+
}
|
|
2490
|
+
});
|
|
2491
|
+
g_keyObj[`${keyheader}_${k + dfPtn}`] = structuredClone(g_keyObj[`${keyheader}_${k + dfPtn}_0`]);
|
|
2492
|
+
});
|
|
2493
|
+
|
|
2494
|
+
} else if (g_keyObj[`${keyheader}_${dfPtn}_0`] === undefined) {
|
|
2495
|
+
// 特に指定が無い場合はkeyCtrlX_Yの配列長で決定
|
|
2496
|
+
for (let k = 0; k < g_keyObj.minPatterns; k++) {
|
|
2497
|
+
const ptnName = `${_key}_${k + dfPtn}`;
|
|
2498
|
+
g_keyObj[`${_name}${ptnName}_0`] = fillArray(g_keyObj[`${g_keyObj.defaultProp}${ptnName}`].length);
|
|
2499
|
+
g_keyObj[`${_name}${ptnName}`] = structuredClone(g_keyObj[`${_name}${ptnName}_0`]);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* 新キー用単一パラメータ
|
|
2506
|
+
* @param {string} _key キー数
|
|
2507
|
+
* @param {string} _name 名前
|
|
2508
|
+
* @param {string} _type float, number, string, boolean
|
|
2509
|
+
* @param {string} _defaultVal
|
|
2510
|
+
*/
|
|
2511
|
+
const newKeySingleParam = (_key, _name, _type, _defaultVal) => {
|
|
2512
|
+
const keyheader = _name + _key;
|
|
2513
|
+
const dfPtn = setIntVal(g_keyObj.dfPtnNum);
|
|
2514
|
+
if (_dosObj[keyheader] !== undefined) {
|
|
2515
|
+
const tmps = _dosObj[keyheader].split(`$`);
|
|
2516
|
+
for (let k = 0; k < tmps.length; k++) {
|
|
2517
|
+
g_keyObj[`${keyheader}_${k + dfPtn}`] = setVal(g_keyObj[`${_name}${getKeyPtnName(tmps[k])}`],
|
|
2518
|
+
tmps[k].indexOf(`_`) !== -1 ? _defaultVal : setVal(tmps[k], ``, _type));
|
|
2519
|
+
}
|
|
2520
|
+
for (let k = tmps.length; k < g_keyObj.minPatterns; k++) {
|
|
2521
|
+
g_keyObj[`${keyheader}_${k + dfPtn}`] = g_keyObj[`${keyheader}_0`];
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
|
|
2526
|
+
/**
|
|
2527
|
+
* 新キー用複合パラメータ(パターン設定用)
|
|
2528
|
+
* @param {string} _key キー数
|
|
2529
|
+
* @param {string} _name 名前
|
|
2530
|
+
* @param {string} _pairName 詳細設定する変数名
|
|
2531
|
+
* @param {string} _defaultName パラメータの初期値
|
|
2532
|
+
* @param {number} _defaultVal パラメータの初期値の場合の一律設定値(colorX_Yの配列幅に対して設定値で埋める)
|
|
2533
|
+
*/
|
|
2534
|
+
const newKeyPairParam = (_key, _name, _pairName, _defaultName = ``, _defaultVal = 0) => {
|
|
2535
|
+
const keyheader = _name + _key;
|
|
2536
|
+
const dfPtn = setIntVal(g_keyObj.dfPtnNum);
|
|
2537
|
+
|
|
2538
|
+
splitLF2(_dosObj[keyheader])?.forEach((tmpParam, k) => {
|
|
2539
|
+
const pairName = `${_pairName}${_key}_${k + dfPtn}`;
|
|
2540
|
+
if (!hasVal(tmpParam)) {
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
g_keyObj[pairName] = {};
|
|
2544
|
+
|
|
2545
|
+
// デフォルト項目がある場合は先に定義
|
|
2546
|
+
if (_defaultName !== ``) {
|
|
2547
|
+
g_keyObj[pairName][_defaultName] = fillArray(g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length, _defaultVal);
|
|
2548
|
+
}
|
|
2549
|
+
tmpParam.split(`/`).forEach(pairs => {
|
|
2550
|
+
const keyPtn = getKeyPtnName(pairs);
|
|
2551
|
+
if (pairs === ``) {
|
|
2552
|
+
} else if (g_keyObj[`${_pairName}${keyPtn}`] !== undefined) {
|
|
2553
|
+
// 他のキーパターン指定時、該当があればプロパティを全コピー
|
|
2554
|
+
Object.assign(g_keyObj[pairName], g_keyObj[`${_pairName}${keyPtn}`]);
|
|
2555
|
+
} else {
|
|
2556
|
+
// 通常の指定方法(例:|scroll8i=Cross::1,1,1,-,-,-,1,1/Split::1,1,1,1,-,-,-,-|)から取り込み
|
|
2557
|
+
// 部分的にキーパターン指定があった場合は既存パターンを展開 (例: |scroll9j=Cross::1,7_0,1|)
|
|
2558
|
+
const tmpParamPair = pairs.split(`::`);
|
|
2559
|
+
g_keyObj[pairName][tmpParamPair[0]] =
|
|
2560
|
+
makeBaseArray(toOriginalArray(tmpParamPair[1], toSameValStr)?.map(n =>
|
|
2561
|
+
structuredClone(g_keyObj[`${_pairName}${getKeyPtnName(n)}`]?.[tmpParamPair[0]]) ??
|
|
2562
|
+
[n === `-` ? -1 : parseInt(n, 10)]
|
|
2563
|
+
).flat(), g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length, _defaultVal);
|
|
2564
|
+
}
|
|
2565
|
+
});
|
|
2566
|
+
});
|
|
2567
|
+
};
|
|
2568
|
+
|
|
2569
|
+
// 対象キー毎に処理
|
|
2570
|
+
keyExtraList.forEach(newKey => {
|
|
2571
|
+
g_keyObj.minPatterns = 1;
|
|
2572
|
+
g_keyObj.dfPtnNum = 0;
|
|
2573
|
+
|
|
2574
|
+
try {
|
|
2575
|
+
|
|
2576
|
+
// キーパターンの追記 (appendX)
|
|
2577
|
+
if (setBoolVal(_dosObj[`append${newKey}`])) {
|
|
2578
|
+
for (let j = 0; ; j++) {
|
|
2579
|
+
if (g_keyObj[`${g_keyObj.defaultProp}${newKey}_${j}`] === undefined) {
|
|
2580
|
+
break;
|
|
2581
|
+
}
|
|
2582
|
+
g_keyObj.dfPtnNum++;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
const dfPtnNum = g_keyObj.dfPtnNum;
|
|
2586
|
+
|
|
2587
|
+
// キーの名前 (keyNameX)
|
|
2588
|
+
g_keyObj[`keyName${newKey}`] = _dosObj[`keyName${newKey}`]?.split(`,`) ?? [newKey, `key`];
|
|
2589
|
+
|
|
2590
|
+
// キーの最小横幅 (minWidthX)
|
|
2591
|
+
g_keyObj[`minWidth${newKey}`] = _dosObj[`minWidth${newKey}`] ?? g_keyObj[`minWidth${newKey}`] ?? g_keyObj.minWidthDefault;
|
|
2592
|
+
|
|
2593
|
+
// 移動ロック (movLockX)
|
|
2594
|
+
g_keyObj[`movLock${newKey}`] = setBoolVal(_dosObj[`movLock${newKey}`] ?? g_keyObj[`movLock${newKey}`], false);
|
|
2595
|
+
|
|
2596
|
+
// 位置マニュアル化 (initManualX)
|
|
2597
|
+
g_keyObj[`initManual${newKey}`] = setBoolVal(_dosObj[`initManual${newKey}`] ?? g_keyObj[`initManual${newKey}`], false);
|
|
2598
|
+
|
|
2599
|
+
// カスタムキーの説明ページ(keyHelpJaX / keyHelpEnX)
|
|
2600
|
+
Object.keys(g_lang_lblNameObj).forEach(lang =>
|
|
2601
|
+
g_lang_lblNameObj[lang][`keyHelp${newKey}`] = _dosObj[`keyHelp${lang}${newKey}`] ?? _dosObj[`keyHelp${newKey}`] ?? ``);
|
|
2602
|
+
|
|
2603
|
+
// キーコンフィグ (keyCtrlX_Y)
|
|
2604
|
+
g_keyObj.minPatterns = newKeyMultiParam(newKey, `keyCtrl`, toKeyCtrlArray, {
|
|
2605
|
+
errCd: `E_0104`, baseCopyFlg: true,
|
|
2606
|
+
});
|
|
2607
|
+
|
|
2608
|
+
// 読込変数の接頭辞 (charaX_Y)
|
|
2609
|
+
newKeyMultiParam(newKey, `chara`, toString);
|
|
2610
|
+
|
|
2611
|
+
// 矢印色パターン (colorX_Y)
|
|
2612
|
+
newKeyTripleParam(newKey, `color`);
|
|
2613
|
+
|
|
2614
|
+
// 矢印の回転量指定、キャラクタパターン (stepRtnX_Y)
|
|
2615
|
+
newKeyTripleParam(newKey, `stepRtn`);
|
|
2616
|
+
|
|
2617
|
+
// 各キーの区切り位置 (divX_Y)
|
|
2618
|
+
_dosObj[`div${newKey}`]?.split(`$`).forEach((tmpDiv, k) => {
|
|
2619
|
+
const tmpDivPtn = tmpDiv.split(`,`);
|
|
2620
|
+
const ptnName = `${newKey}_${k + dfPtnNum}`;
|
|
2621
|
+
|
|
2622
|
+
if (g_keyObj[`div${tmpDivPtn[0]}`] !== undefined) {
|
|
2623
|
+
// 既定キーパターンが指定された場合、存在すればその値を適用
|
|
2624
|
+
g_keyObj[`div${ptnName}`] = g_keyObj[`div${tmpDivPtn[0]}`];
|
|
2625
|
+
g_keyObj[`divMax${ptnName}`] = setVal(g_keyObj[`divMax${tmpDivPtn[0]}`], undefined, C_TYP_FLOAT);
|
|
2626
|
+
} else if (!hasVal(tmpDivPtn[0]) && setIntVal(g_keyObj[`div${ptnName}`], -1) !== -1) {
|
|
2627
|
+
// カスタムキー側のdivXが未定義だが、すでに初期設定で定義済みの場合はスキップ
|
|
2628
|
+
return;
|
|
2629
|
+
} else {
|
|
2630
|
+
// それ以外の場合は指定された値を適用(未指定時はその後で指定)
|
|
2631
|
+
g_keyObj[`div${ptnName}`] = setVal(tmpDivPtn[0], undefined, C_TYP_NUMBER);
|
|
2632
|
+
g_keyObj[`divMax${ptnName}`] = setVal(getKeyPosNum(tmpDivPtn[1], g_keyObj[`div${ptnName}`]), undefined, C_TYP_FLOAT);
|
|
2633
|
+
}
|
|
2634
|
+
});
|
|
2635
|
+
|
|
2636
|
+
// ステップゾーン位置 (posX_Y)
|
|
2637
|
+
newKeyMultiParam(newKey, `pos`, toFloat, {
|
|
2638
|
+
loopFunc: (k, keyheader) => {
|
|
2639
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`].forEach((val, j) =>
|
|
2640
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`][j] = getKeyPosNum(String(val), g_keyObj[`div${newKey}_${k + dfPtnNum}`]));
|
|
2641
|
+
},
|
|
2642
|
+
});
|
|
2643
|
+
|
|
2644
|
+
// charaX_Y, posX_Y, keyGroupX_Y, divX_Y, divMaxX_Yが未指定の場合はkeyCtrlX_Yを元に適用
|
|
2645
|
+
for (let k = 0; k < g_keyObj.minPatterns; k++) {
|
|
2646
|
+
setKeyDfVal(`${newKey}_${k + dfPtnNum}`);
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
// ステップゾーン間隔 (blankX_Y)
|
|
2650
|
+
newKeySingleParam(newKey, `blank`, C_TYP_FLOAT, g_keyObj.blank_def);
|
|
2651
|
+
|
|
2652
|
+
// 矢印群の倍率 (scaleX_Y)
|
|
2653
|
+
newKeySingleParam(newKey, `scale`, C_TYP_FLOAT, g_keyObj.scale_def);
|
|
2654
|
+
|
|
2655
|
+
// プレイ中ショートカット:リトライ (keyRetryX_Y)
|
|
2656
|
+
newKeySingleParam(newKey, `keyRetry`, C_TYP_STRING, C_KEY_RETRY);
|
|
2657
|
+
|
|
2658
|
+
// プレイ中ショートカット:タイトルバック (keyTitleBackX_Y)
|
|
2659
|
+
newKeySingleParam(newKey, `keyTitleBack`, C_TYP_STRING, C_KEY_TITLEBACK);
|
|
2660
|
+
|
|
2661
|
+
// プレイ中ショートカット:タイトルバック (keyPauseX_Y)
|
|
2662
|
+
newKeySingleParam(newKey, `keyPause`, C_TYP_STRING, C_KEY_PAUSE);
|
|
2663
|
+
|
|
2664
|
+
// 別キーフラグ (transKeyX_Y)
|
|
2665
|
+
newKeySingleParam(newKey, `transKey`, C_TYP_STRING, ``);
|
|
2666
|
+
|
|
2667
|
+
// フラットモード (flatModeX_Y)
|
|
2668
|
+
newKeySingleParam(newKey, `flatMode`, C_TYP_BOOLEAN, false);
|
|
2669
|
+
|
|
2670
|
+
// シャッフルグループ (shuffleX_Y)
|
|
2671
|
+
newKeyTripleParam(newKey, `shuffle`);
|
|
2672
|
+
|
|
2673
|
+
// キーグループ (keyGroupX_Y)
|
|
2674
|
+
newKeyMultiParam(newKey, `keyGroup`, toSplitArrayStr);
|
|
2675
|
+
|
|
2676
|
+
// キーグループの表示制御 (keyGroupOrderX_Y)
|
|
2677
|
+
newKeyMultiParam(newKey, `keyGroupOrder`, toString);
|
|
2678
|
+
|
|
2679
|
+
// スクロールパターン (scrollX_Y)
|
|
2680
|
+
// |scroll(newKey)=Cross::1,1,-1,-1,-1,1,1/Split::1,1,1,-1,-1,-1,-1$...|
|
|
2681
|
+
newKeyPairParam(newKey, `scroll`, `scrollDir`, C_FLG_HYPHEN, 1);
|
|
2682
|
+
|
|
2683
|
+
// アシストパターン (assistX_Y)
|
|
2684
|
+
// |assist(newKey)=Onigiri::0,0,0,0,0,1/AA::0,0,0,1,1,1$...|
|
|
2685
|
+
newKeyPairParam(newKey, `assist`, `assistPos`);
|
|
2686
|
+
|
|
2687
|
+
// レーンごとの割当レイヤーグループ (layerGroupX_Y)
|
|
2688
|
+
newKeyMultiParam(newKey, `layerGroup`, toInt);
|
|
2689
|
+
|
|
2690
|
+
// レイヤーごとのアニメーション情報 (layerTransX_Y)
|
|
2691
|
+
if (hasVal(_dosObj[`layerTrans${newKey}`])) {
|
|
2692
|
+
_dosObj[`layerTrans${newKey}`] = _dosObj[`layerTrans${newKey}`]?.replaceAll(`,`, `___`);
|
|
2693
|
+
newKeyMultiParam(newKey, `layerTrans`, toSplitArrayStr, {
|
|
2694
|
+
loopFunc: (k, keyheader) => {
|
|
2695
|
+
g_keyObj[`${keyheader}_${k + dfPtnNum}`][0] = g_keyObj[`${keyheader}_${k + dfPtnNum}`]?.[0]?.map(val => val.replaceAll(`___`, `,`));
|
|
2696
|
+
},
|
|
2697
|
+
});
|
|
2698
|
+
}
|
|
2699
|
+
// カスタムキーで定義されたtransKeyPtnを補完
|
|
2700
|
+
completeTransKeyPtn([newKey]);
|
|
2701
|
+
|
|
2702
|
+
// keyRetry, keyTitleBack, keyPauseのキー名をキーコードに変換
|
|
2703
|
+
const keyTypePatterns = Object.keys(g_keyObj).filter(val =>
|
|
2704
|
+
val.startsWith(`keyRetry${newKey}`) || val.startsWith(`keyTitleBack${newKey}`) || val.startsWith(`keyPause${newKey}`));
|
|
2705
|
+
keyTypePatterns.forEach(name => g_keyObj[name] = getKeyCtrlVal(g_keyObj[name]));
|
|
2706
|
+
} catch (e) {
|
|
2707
|
+
g_headerObj.undefinedKeyListFinal.push(newKey);
|
|
2708
|
+
console.warn(`Error in key pattern conversion: ${newKey}`, e);
|
|
2709
|
+
}
|
|
2710
|
+
});
|
|
2711
|
+
|
|
2712
|
+
return keyExtraList;
|
|
2713
|
+
};
|
|
2714
|
+
|
|
2715
|
+
/**
|
|
2716
|
+
* キーパターンのデフォルト値設定
|
|
2717
|
+
* @param {string} _ptnName
|
|
2718
|
+
*/
|
|
2719
|
+
const setKeyDfVal = _ptnName => {
|
|
2720
|
+
const baseLength = g_keyObj[`${g_keyObj.defaultProp}${_ptnName}`].length;
|
|
2721
|
+
g_keyObj[`chara${_ptnName}`] = padArray(g_keyObj[`chara${_ptnName}`], [...Array(baseLength).keys()].map(i => `${i + 1}a`));
|
|
2722
|
+
g_keyObj[`pos${_ptnName}`] = padArray(g_keyObj[`pos${_ptnName}`], [...Array(baseLength).keys()].map(i => i));
|
|
2723
|
+
g_keyObj[`keyGroup${_ptnName}`] = padArray(g_keyObj[`keyGroup${_ptnName}`], fillArray(baseLength, [`0`]));
|
|
2724
|
+
|
|
2725
|
+
if (g_keyObj[`div${_ptnName}`] === undefined) {
|
|
2726
|
+
g_keyObj[`div${_ptnName}`] = Math.max(...g_keyObj[`pos${_ptnName}`]) + 1;
|
|
2727
|
+
}
|
|
2728
|
+
if (g_keyObj[`divMax${_ptnName}`] === undefined) {
|
|
2729
|
+
g_keyObj[`divMax${_ptnName}`] = Math.max(...g_keyObj[`pos${_ptnName}`]) + 1;
|
|
2730
|
+
}
|
|
2731
|
+
};
|
|
2732
|
+
|
|
2733
|
+
/**
|
|
2734
|
+
* 背景・マスク用画像の描画
|
|
2735
|
+
* @param {object} _obj
|
|
2736
|
+
* @param {string} _obj.path 画像のパス
|
|
2737
|
+
* @param {string} _obj.class 画像を装飾するCSSクラス名
|
|
2738
|
+
* @param {string} _obj.left 画像の位置(x座標)
|
|
2739
|
+
* @param {string} _obj.top 画像の位置(y座標)
|
|
2740
|
+
* @param {number} _obj.width 画像の幅
|
|
2741
|
+
* @param {string} _obj.height 画像の高さ (他との共用項目のため、stringで受ける)
|
|
2742
|
+
* @param {string} _obj.animationName アニメーション名
|
|
2743
|
+
* @param {string} _obj.animationDuration アニメーションを動かす間隔(秒)
|
|
2744
|
+
* @param {number} _obj.opacity 画像の不透明度
|
|
2745
|
+
* @returns {string}
|
|
2746
|
+
*/
|
|
2747
|
+
const makeSpriteImage = _obj => {
|
|
2748
|
+
let tmpInnerHTML = `<img src=${_obj.path} class="${_obj.class}" style="position:absolute;left:${wUnit(_obj.left)};top:${wUnit(_obj.top)}`;
|
|
2749
|
+
if (_obj.width > 0) {
|
|
2750
|
+
tmpInnerHTML += `;width:${wUnit(_obj.width)}`;
|
|
2751
|
+
}
|
|
2752
|
+
if (setIntVal(_obj.height) > 0) {
|
|
2753
|
+
tmpInnerHTML += `;height:${wUnit(_obj.height)}`;
|
|
2754
|
+
}
|
|
2755
|
+
tmpInnerHTML += `;animation-name:${_obj.animationName};animation-duration:${_obj.animationDuration}s;opacity:${_obj.opacity}">`;
|
|
2756
|
+
return tmpInnerHTML;
|
|
2757
|
+
};
|
|
2758
|
+
|
|
2759
|
+
/**
|
|
2760
|
+
* 背景・マスク用テキストの描画
|
|
2761
|
+
* @param {object} _obj
|
|
2762
|
+
* @param {string} _obj.path テキスト本体
|
|
2763
|
+
* @param {string} _obj.class テキストを装飾するCSSクラス名
|
|
2764
|
+
* @param {string} _obj.left テキストの位置(x座標)
|
|
2765
|
+
* @param {string} _obj.top テキストの位置(y座標)
|
|
2766
|
+
* @param {number} _obj.width テキストのフォントサイズ (font-size)
|
|
2767
|
+
* @param {string} _obj.height テキストの色 (color)
|
|
2768
|
+
* @param {string} _obj.animationName アニメーション名
|
|
2769
|
+
* @param {string} _obj.animationDuration アニメーションを動かす間隔(秒)
|
|
2770
|
+
* @param {number} _obj.opacity テキストの不透明度
|
|
2771
|
+
* @returns {string}
|
|
2772
|
+
*/
|
|
2773
|
+
const makeSpriteText = _obj => {
|
|
2774
|
+
let tmpInnerHTML = `<span class="${_obj.class}" style="display:inline-block;position:absolute;left:${wUnit(_obj.left)};top:${wUnit(_obj.top)}`;
|
|
2775
|
+
|
|
2776
|
+
// この場合のwidthは font-size と解釈する
|
|
2777
|
+
if (_obj.width > 0) {
|
|
2778
|
+
tmpInnerHTML += `;font-size:${wUnit(_obj.width)}`;
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
// この場合のheightは color と解釈する
|
|
2782
|
+
if (_obj.height !== ``) {
|
|
2783
|
+
tmpInnerHTML += `;color:${_obj.height}`;
|
|
2784
|
+
}
|
|
2785
|
+
tmpInnerHTML += `;animation-name:${_obj.animationName};animation-duration:${_obj.animationDuration}s;opacity:${_obj.opacity}">${_obj.path}</span>`;
|
|
2786
|
+
return tmpInnerHTML;
|
|
2787
|
+
};
|
|
2788
|
+
|
|
2789
|
+
/**
|
|
2790
|
+
* 多重配列の存在をチェックし、
|
|
2791
|
+
* 存在しない場合は作成、存在する場合は重複を避けて配列を新規作成
|
|
2792
|
+
* @param {any[][]} _obj
|
|
2793
|
+
* @returns [多重配列(初期化済),配列初期化済数]
|
|
2794
|
+
*/
|
|
2795
|
+
const checkDuplicatedObjects = _obj => {
|
|
2796
|
+
let dataCnts = 0;
|
|
2797
|
+
if (_obj === undefined) {
|
|
2798
|
+
_obj = [];
|
|
2799
|
+
_obj[0] = [];
|
|
2800
|
+
} else {
|
|
2801
|
+
for (let m = 1; ; m++) {
|
|
2802
|
+
if (_obj[m] === undefined) {
|
|
2803
|
+
_obj[m] = [];
|
|
2804
|
+
dataCnts = m;
|
|
2805
|
+
break;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
return [_obj, dataCnts];
|
|
2810
|
+
};
|
|
2811
|
+
|
|
2812
|
+
/**
|
|
2813
|
+
* 多層スプライトデータの作成処理
|
|
2814
|
+
* @param {string} _data
|
|
2815
|
+
* @param {Function} _calcFrame
|
|
2816
|
+
* @returns [多層スプライトデータ, 最大深度]
|
|
2817
|
+
*/
|
|
2818
|
+
const makeSpriteData = (_data, _calcFrame = _frame => _frame) => {
|
|
2819
|
+
|
|
2820
|
+
const spriteData = [];
|
|
2821
|
+
let maxDepth = -1;
|
|
2822
|
+
|
|
2823
|
+
splitLF(_data).filter(data => hasVal(data)).forEach(tmpData => {
|
|
2824
|
+
const tmpSpriteData = tmpData.split(`,`).map(val => trimStr(val));
|
|
2825
|
+
|
|
2826
|
+
// 深度が"-"の場合はスキップ
|
|
2827
|
+
if (tmpSpriteData[1] === undefined || tmpSpriteData[1] === `-` ||
|
|
2828
|
+
(tmpSpriteData[1] === `` && ![`[loop]`, `[jump]`].includes(tmpSpriteData[2]))) {
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
// 値チェックとエスケープ処理
|
|
2833
|
+
const tmpFrame = setIntVal(tmpSpriteData[0], -1) === 0 ? 0 :
|
|
2834
|
+
roundZero(_calcFrame(setVal(tmpSpriteData[0], 200, C_TYP_CALC)));
|
|
2835
|
+
const tmpDepth = (tmpSpriteData[1] === C_FLG_ALL ? C_FLG_ALL : setVal(tmpSpriteData[1], 0, C_TYP_CALC));
|
|
2836
|
+
if (tmpDepth !== C_FLG_ALL && tmpDepth > maxDepth) {
|
|
2837
|
+
maxDepth = tmpDepth;
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
const colorObjFlg = tmpSpriteData[2]?.startsWith(`[c]`) || false;
|
|
2841
|
+
const transformFlg = tmpSpriteData[2]?.startsWith(`[t]`) || false;
|
|
2842
|
+
const tmpObj = {
|
|
2843
|
+
path: escapeHtml(tmpSpriteData[2] ?? ``, g_escapeStr.escapeCode), // 画像パス or テキスト
|
|
2844
|
+
class: escapeHtml(tmpSpriteData[3] ?? ``), // CSSクラス
|
|
2845
|
+
left: transformFlg
|
|
2846
|
+
? setVal(tmpSpriteData[4], 1000, C_TYP_NUMBER) // [t]のみtransformのPriority
|
|
2847
|
+
: setVal(tmpSpriteData[4], `0`).includes(`{`)
|
|
2848
|
+
? `${setVal(tmpSpriteData[4], 0)}`
|
|
2849
|
+
: `{${setVal(tmpSpriteData[4], 0)}}`, // X座標
|
|
2850
|
+
top: setVal(tmpSpriteData[5], `0`).includes(`{`)
|
|
2851
|
+
? `${setVal(tmpSpriteData[5], 0)}`
|
|
2852
|
+
: `{${setVal(tmpSpriteData[5], 0)}}`, // Y座標
|
|
2853
|
+
width: `${setIntVal(tmpSpriteData[6])}`, // spanタグの場合は font-size
|
|
2854
|
+
height: `${escapeHtml(tmpSpriteData[7] ?? ``)}`, // spanタグの場合は color(文字列可)
|
|
2855
|
+
opacity: setVal(tmpSpriteData[8], 1, C_TYP_FLOAT),
|
|
2856
|
+
animationName: escapeHtml(setVal(tmpSpriteData[9], C_DIS_NONE)),
|
|
2857
|
+
animationDuration: setIntVal(tmpSpriteData[10]) / g_fps,
|
|
2858
|
+
};
|
|
2859
|
+
if (setVal(tmpSpriteData[11], g_presetObj.animationFillMode) !== undefined) {
|
|
2860
|
+
tmpObj.animationFillMode = setVal(tmpSpriteData[11], g_presetObj.animationFillMode);
|
|
2861
|
+
}
|
|
2862
|
+
tmpObj.path = preloadImgFile(tmpObj.path, { syncBackPath: g_headerObj.syncBackPath });
|
|
2863
|
+
|
|
2864
|
+
let dataCnts = 0;
|
|
2865
|
+
[spriteData[tmpFrame], dataCnts] =
|
|
2866
|
+
checkDuplicatedObjects(spriteData[tmpFrame]);
|
|
2867
|
+
|
|
2868
|
+
const emptyPatterns = [`[loop]`, `[jump]`];
|
|
2869
|
+
const spriteFrameData = spriteData[tmpFrame][dataCnts] = {
|
|
2870
|
+
depth: tmpDepth,
|
|
2871
|
+
};
|
|
2872
|
+
|
|
2873
|
+
if (colorObjFlg) {
|
|
2874
|
+
// [c]始まりの場合、カラーオブジェクト用の作成準備を行う
|
|
2875
|
+
const data = tmpObj.path.slice(`[c]`.length).split(`/`);
|
|
2876
|
+
let objPart = data[0];
|
|
2877
|
+
if (!isNaN(parseInt(data[0]))) {
|
|
2878
|
+
const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
2879
|
+
objPart = g_keyObj[`stepRtn${keyCtrlPtn}`][data[0]];
|
|
2880
|
+
spriteFrameData.transform = parseInt(data[0]);
|
|
2881
|
+
}
|
|
2882
|
+
spriteFrameData.colorObjInfo = {
|
|
2883
|
+
x: tmpObj.left, y: tmpObj.top, w: tmpObj.width, h: tmpObj.height,
|
|
2884
|
+
rotate: setVal(objPart, `0`), opacity: tmpObj.opacity,
|
|
2885
|
+
background: makeColorGradation(setVal(data[1], `#ffffff`), { _defaultColorgrd: false }),
|
|
2886
|
+
animationName: tmpObj.animationName,
|
|
2887
|
+
animationDuration: `${tmpObj.animationDuration}s`,
|
|
2888
|
+
};
|
|
2889
|
+
spriteFrameData.colorObjId = `${tmpFrame}_${dataCnts}`;
|
|
2890
|
+
spriteFrameData.colorObjClass = setVal(tmpObj.class, undefined);
|
|
2891
|
+
if (tmpObj.animationFillMode !== undefined) {
|
|
2892
|
+
spriteFrameData.colorObjInfo.animationFillMode = tmpObj.animationFillMode;
|
|
2893
|
+
}
|
|
2894
|
+
} else if (transformFlg) {
|
|
2895
|
+
// [t]始まりの場合、レイヤーに対してtransformを掛ける準備を行う
|
|
2896
|
+
const transformData = tmpObj.path.slice(`[t]`.length);
|
|
2897
|
+
spriteFrameData.transform = transformData || ``;
|
|
2898
|
+
spriteFrameData.transformId = tmpObj.class;
|
|
2899
|
+
spriteFrameData.transPriority = tmpObj.left;
|
|
2900
|
+
|
|
2901
|
+
} else if (tmpObj.path === ``) {
|
|
2902
|
+
spriteFrameData.command = ``;
|
|
2903
|
+
} else if (emptyPatterns.includes(tmpObj.path)) {
|
|
2904
|
+
// ループ、フレームジャンプの場合の処理
|
|
2905
|
+
spriteFrameData.command = tmpObj.path;
|
|
2906
|
+
spriteFrameData.jumpFrame = tmpObj.class;
|
|
2907
|
+
spriteFrameData.maxLoop = tmpObj.left;
|
|
2908
|
+
spriteFrameData.htmlText = ``;
|
|
2909
|
+
} else {
|
|
2910
|
+
// それ以外の画像、テキストの場合
|
|
2911
|
+
spriteFrameData.animationName = tmpObj.animationName;
|
|
2912
|
+
spriteFrameData.htmlText = (checkImage(tmpObj.path) ? makeSpriteImage(tmpObj) : makeSpriteText(tmpObj));
|
|
2913
|
+
}
|
|
2914
|
+
});
|
|
2915
|
+
|
|
2916
|
+
return [spriteData, maxDepth];
|
|
2917
|
+
};
|
|
2918
|
+
|
|
2919
|
+
/**
|
|
2920
|
+
* スタイル変更データの作成処理
|
|
2921
|
+
* @param {string} _data
|
|
2922
|
+
* @param {Function} _calcFrame
|
|
2923
|
+
* @returns [多層スプライトデータ, 1(固定)]
|
|
2924
|
+
*/
|
|
2925
|
+
const makeStyleData = (_data, _calcFrame = _frame => _frame) => {
|
|
2926
|
+
const spriteData = [];
|
|
2927
|
+
splitLF(_data).filter(data => hasVal(data)).forEach(tmpData => {
|
|
2928
|
+
const tmpSpriteData = tmpData.split(`,`).map(val => trimStr(val));
|
|
2929
|
+
|
|
2930
|
+
// カスタムプロパティの名称(--始まり)で無い場合はコメントと見做してスキップ
|
|
2931
|
+
if (tmpSpriteData.length <= 1 || !tmpSpriteData[1].startsWith(`--`)) {
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
const tmpFrame = setIntVal(tmpSpriteData[0], -1) === 0 ? 0 :
|
|
2935
|
+
roundZero(_calcFrame(setVal(tmpSpriteData[0], 200, C_TYP_CALC)));
|
|
2936
|
+
|
|
2937
|
+
let dataCnts = 0;
|
|
2938
|
+
[spriteData[tmpFrame], dataCnts] = checkDuplicatedObjects(spriteData[tmpFrame]);
|
|
2939
|
+
spriteData[tmpFrame][dataCnts] = {
|
|
2940
|
+
depth: tmpSpriteData[1],
|
|
2941
|
+
styleData: getCssCustomProperty(tmpSpriteData[1], tmpSpriteData[2]),
|
|
2942
|
+
};
|
|
2943
|
+
});
|
|
2944
|
+
return [spriteData, 1];
|
|
2945
|
+
};
|
|
2946
|
+
|
|
2947
|
+
/**
|
|
2948
|
+
* 画像ファイルかどうかをチェック
|
|
2949
|
+
* @param {string} _str
|
|
2950
|
+
* @returns {boolean}
|
|
2951
|
+
*/
|
|
2952
|
+
const checkImage = _str => listMatching(_str, g_imgExtensions, { prefix: `[.]`, suffix: `$` });
|
|
2953
|
+
|
|
2954
|
+
/**
|
|
2955
|
+
* back/masktitle(result)において、ジャンプ先のフレーム数を取得
|
|
2956
|
+
* @param {string} _frames ジャンプ先のフレーム数情報。コロン指定でジャンプ先を確率で分岐 (ex. 300:1500:1500)
|
|
2957
|
+
* @returns {number}
|
|
2958
|
+
*/
|
|
2959
|
+
const getSpriteJumpFrame = _frames => {
|
|
2960
|
+
const jumpFrames = _frames.split(`:`);
|
|
2961
|
+
const jumpCnt = Math.floor(Math.random() * jumpFrames.length);
|
|
2962
|
+
return setIntVal(Number(jumpFrames[jumpCnt]) - 1);
|
|
2963
|
+
};
|
|
2964
|
+
|
|
2965
|
+
/**
|
|
2966
|
+
* 背景・マスクモーションの表示(共通処理)
|
|
2967
|
+
* @param {object} _spriteData
|
|
2968
|
+
* @param {string} _name
|
|
2969
|
+
* @param {boolean} [_condition=true]
|
|
2970
|
+
*/
|
|
2971
|
+
const drawBaseSpriteData = (_spriteData, _name, _condition = true) => {
|
|
2972
|
+
const baseSprite = document.getElementById(`${_name}Sprite${_spriteData.depth}`);
|
|
2973
|
+
if (_spriteData.command === ``) {
|
|
2974
|
+
if (_spriteData.depth === C_FLG_ALL) {
|
|
2975
|
+
for (let j = 0; j <= g_scoreObj[`${_name}MaxDepth`]; j++) {
|
|
2976
|
+
document.getElementById(`${_name}Sprite${j}`).textContent = ``;
|
|
2977
|
+
}
|
|
2978
|
+
} else {
|
|
2979
|
+
baseSprite.textContent = ``;
|
|
2980
|
+
}
|
|
2981
|
+
} else {
|
|
2982
|
+
if (_condition) {
|
|
2983
|
+
if (_spriteData.colorObjInfo === undefined && _spriteData.transform === undefined) {
|
|
2984
|
+
baseSprite.innerHTML = convertStrToVal(_spriteData.htmlText);
|
|
2985
|
+
return;
|
|
2986
|
+
}
|
|
2987
|
+
if (_spriteData.colorObjInfo !== undefined) {
|
|
2988
|
+
const colorObjClass = _spriteData.colorObjClass?.split(`/`) ?? [];
|
|
2989
|
+
const id = `${_name}${_spriteData.depth}${_spriteData.colorObjId}`;
|
|
2990
|
+
[`x`, `y`, `w`, `h`].forEach(val => _spriteData.colorObjInfo[val] = convertStrToVal(_spriteData.colorObjInfo[val]));
|
|
2991
|
+
baseSprite.appendChild(
|
|
2992
|
+
createColorObject2(id, _spriteData.colorObjInfo, ...colorObjClass)
|
|
2993
|
+
);
|
|
2994
|
+
}
|
|
2995
|
+
if (_spriteData.transform !== undefined) {
|
|
2996
|
+
const targetId = `${_name}Sprite${_spriteData.depth}`;
|
|
2997
|
+
|
|
2998
|
+
if (!isNaN(parseInt(_spriteData.transform))) {
|
|
2999
|
+
// PlayWindow由来のtransformを継承(別transformId)
|
|
3000
|
+
const transformId = `${_name}${_spriteData.depth}PlayWindow`;
|
|
3001
|
+
const transformData = getTransform(`mainSprite`, `playWindow`);
|
|
3002
|
+
|
|
3003
|
+
if (hasVal(transformData)) {
|
|
3004
|
+
if (transformData !== getTransform(targetId, transformId)) {
|
|
3005
|
+
addTransform(targetId, transformId, transformData, g_transPriority.playWindow);
|
|
3006
|
+
}
|
|
3007
|
+
} else {
|
|
3008
|
+
delTransform(targetId, transformId);
|
|
3009
|
+
}
|
|
3010
|
+
} else {
|
|
3011
|
+
// 明示指定のtransformを適用
|
|
3012
|
+
const transformId = _spriteData.transformId || `${_name}${_spriteData.depth}`;
|
|
3013
|
+
|
|
3014
|
+
if (hasVal(_spriteData.transform)) {
|
|
3015
|
+
addTransform(targetId, transformId, _spriteData.transform, _spriteData.transPriority);
|
|
3016
|
+
} else {
|
|
3017
|
+
delTransform(targetId, transformId);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
};
|
|
3024
|
+
|
|
3025
|
+
/**
|
|
3026
|
+
* 背景・マスクモーションの表示(タイトル・リザルト用)
|
|
3027
|
+
* @param {number} _frame
|
|
3028
|
+
* @param {string} _displayName title / result
|
|
3029
|
+
* @param {string} _depthName back / mask
|
|
3030
|
+
* @returns {number}
|
|
3031
|
+
*/
|
|
3032
|
+
const drawSpriteData = (_frame, _displayName, _depthName) => {
|
|
3033
|
+
|
|
3034
|
+
const spriteName = `${_depthName}${toCapitalize(_displayName)}`;
|
|
3035
|
+
const tmpObjs = g_headerObj[`${spriteName}Data`][_frame];
|
|
3036
|
+
|
|
3037
|
+
for (let j = 0; j < tmpObjs.length; j++) {
|
|
3038
|
+
const tmpObj = tmpObjs[j];
|
|
3039
|
+
drawBaseSpriteData(tmpObj, spriteName, ![`[loop]`, `[jump]`].includes(tmpObj.command));
|
|
3040
|
+
if (tmpObj.command === `[loop]`) {
|
|
3041
|
+
// キーワード指定:ループ
|
|
3042
|
+
// 指定フレーム(class)へ移動する
|
|
3043
|
+
g_scoreObj[`${spriteName}LoopCount`]++;
|
|
3044
|
+
return getSpriteJumpFrame(tmpObj.jumpFrame);
|
|
3045
|
+
|
|
3046
|
+
} else if (tmpObj.command === `[jump]`) {
|
|
3047
|
+
// キーワード指定:フレームジャンプ
|
|
3048
|
+
// 指定回数以上のループ(maxLoop)があれば指定フレーム(jumpFrame)へ移動する
|
|
3049
|
+
if (g_scoreObj[`${spriteName}LoopCount`] >= Number(tmpObj.maxLoop)) {
|
|
3050
|
+
g_scoreObj[`${spriteName}LoopCount`] = 0;
|
|
3051
|
+
return getSpriteJumpFrame(tmpObj.jumpFrame);
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
return _frame;
|
|
3056
|
+
};
|
|
3057
|
+
|
|
3058
|
+
/**
|
|
3059
|
+
* 背景・マスクモーションの表示
|
|
3060
|
+
* @param {number} _frame
|
|
3061
|
+
* @param {string} _depthName
|
|
3062
|
+
*/
|
|
3063
|
+
const drawMainSpriteData = (_frame, _depthName) =>
|
|
3064
|
+
g_scoreObj[`${_depthName}Data`][_frame].forEach(tmpObj => drawBaseSpriteData(tmpObj, _depthName));
|
|
3065
|
+
|
|
3066
|
+
/**
|
|
3067
|
+
* スタイル切替
|
|
3068
|
+
* @param {number} _frame
|
|
3069
|
+
* @param {string} _displayName
|
|
3070
|
+
* @returns {number}
|
|
3071
|
+
*/
|
|
3072
|
+
const drawStyleData = (_frame, _displayName) => {
|
|
3073
|
+
g_headerObj[`style${toCapitalize(_displayName)}Data`][_frame].forEach(tmpObj =>
|
|
3074
|
+
document.documentElement.style.setProperty(tmpObj.depth, tmpObj.styleData));
|
|
3075
|
+
|
|
3076
|
+
return _frame;
|
|
3077
|
+
};
|
|
3078
|
+
|
|
3079
|
+
const drawMainStyleData = (_frame) =>
|
|
3080
|
+
g_scoreObj.styleData[_frame].forEach(tmpObj =>
|
|
3081
|
+
document.documentElement.style.setProperty(tmpObj.depth, tmpObj.styleData));
|
|
3082
|
+
|
|
3083
|
+
/**
|
|
3084
|
+
* タイトル・リザルトモーションの描画
|
|
3085
|
+
* @param {string} _displayName
|
|
3086
|
+
*/
|
|
3087
|
+
const drawTitleResultMotion = _displayName =>
|
|
3088
|
+
g_animationData.forEach(sprite => {
|
|
3089
|
+
const spriteName = `${sprite}${toCapitalize(_displayName)}`;
|
|
3090
|
+
if (g_headerObj[`${spriteName}Data`][g_scoreObj[`${spriteName}FrameNum`]] !== undefined) {
|
|
3091
|
+
g_scoreObj[`${spriteName}FrameNum`] = g_animationFunc.draw[sprite](g_scoreObj[`${spriteName}FrameNum`], _displayName, sprite);
|
|
3092
|
+
}
|
|
3093
|
+
});
|