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,2626 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dancing☆Onigiri (CW Edition)
|
|
3
|
+
* プレイ画面
|
|
4
|
+
* - ページ: main
|
|
5
|
+
*
|
|
6
|
+
* Source by tickle
|
|
7
|
+
* Created : 2026/09/13
|
|
8
|
+
* Revised :
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/cwtickle/danoniplus
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/*-----------------------------------------------------------*/
|
|
14
|
+
/* Scene : MAIN [banana] */
|
|
15
|
+
/*-----------------------------------------------------------*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* メイン画面初期化
|
|
19
|
+
*/
|
|
20
|
+
const mainInit = () => {
|
|
21
|
+
clearWindow(`Main`);
|
|
22
|
+
const divRoot = document.getElementById(`divRoot`);
|
|
23
|
+
document.oncontextmenu = () => false;
|
|
24
|
+
g_currentPage = `main`;
|
|
25
|
+
|
|
26
|
+
g_currentArrows = 0;
|
|
27
|
+
const wordMaxLen = g_scoreObj.wordMaxDepth + 1;
|
|
28
|
+
g_workObj.fadeInNo = fillArray(wordMaxLen);
|
|
29
|
+
g_workObj.fadeOutNo = fillArray(wordMaxLen);
|
|
30
|
+
g_workObj.lastFadeFrame = fillArray(wordMaxLen);
|
|
31
|
+
g_workObj.wordFadeFrame = fillArray(wordMaxLen);
|
|
32
|
+
const mainCommonPos = { w: g_headerObj.playingWidth, h: g_posObj.arrowHeight };
|
|
33
|
+
const objOpacity = g_stateObj.opacity / 100;
|
|
34
|
+
|
|
35
|
+
// 背景スプライトを作成
|
|
36
|
+
createMultipleSprite(`backSprite`, g_scoreObj.backMaxDepth, { x: g_workObj.backX });
|
|
37
|
+
|
|
38
|
+
// ステップゾーン、矢印のメインスプライトを作成
|
|
39
|
+
const mainSprite = createEmptySprite(divRoot, `mainSprite`, mainCommonPos);
|
|
40
|
+
if (g_stateObj.frzReturn !== C_FLG_OFF) {
|
|
41
|
+
divRoot.style.perspective = `1400px`;
|
|
42
|
+
divRoot.style.perspectiveOrigin = `center 60%`;
|
|
43
|
+
mainSprite.style.transformOrigin = `center 55%`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
addTransform(`mainSprite`, `root`, `scale(${g_workObj.scale})`, g_transPriority.scale);
|
|
47
|
+
addTransform(`mainSprite`, `main`, `translateX(${wUnit(g_workObj.playingX)}) translateY(${wUnit(g_posObj.stepY - C_STEP_Y + g_headerObj.playingY)})`, g_transPriority.base);
|
|
48
|
+
|
|
49
|
+
// 曲情報・判定カウント用スプライトを作成(メインスプライトより上位)
|
|
50
|
+
const infoSprite = createEmptySprite(divRoot, `infoSprite`, mainCommonPos);
|
|
51
|
+
addTransform(`infoSprite`, `main`, `translateX(${wUnit(g_workObj.playingX)}) translateY(${wUnit(g_headerObj.playingY)})`, g_transPriority.base);
|
|
52
|
+
|
|
53
|
+
// 判定系スプライトを作成(メインスプライトより上位)
|
|
54
|
+
const judgeSprite = createEmptySprite(divRoot, `judgeSprite`, mainCommonPos);
|
|
55
|
+
addTransform(`judgeSprite`, `main`, `translateX(${wUnit(g_workObj.playingX)}) translateY(${wUnit(g_headerObj.playingY)})`, g_transPriority.base);
|
|
56
|
+
const tkObj = getKeyInfo();
|
|
57
|
+
const [keyCtrlPtn, keyNum] = [tkObj.keyCtrlPtn, tkObj.keyNum];
|
|
58
|
+
|
|
59
|
+
// マスクスプライトを作成 (最上位)
|
|
60
|
+
createMultipleSprite(`maskSprite`, g_scoreObj.maskMaxDepth, { x: g_workObj.backX });
|
|
61
|
+
|
|
62
|
+
// カラー・モーションを適用するオブジェクトの種類
|
|
63
|
+
const objList = (g_stateObj.dummyId === `` && g_autoPlaysBase.includes(g_stateObj.autoPlay)
|
|
64
|
+
? [``] : [`dummy`, ``]);
|
|
65
|
+
|
|
66
|
+
// 背景・マスクモーション、スキン変更(0フレーム指定)
|
|
67
|
+
if (g_scoreObj.frameNum === 0) {
|
|
68
|
+
g_animationData.filter(sprite => g_scoreObj[`${sprite}Data`][0] !== undefined).forEach(sprite => {
|
|
69
|
+
g_animationFunc.drawMain[sprite](0, sprite);
|
|
70
|
+
g_scoreObj[`${sprite}Data`][0] = undefined;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 矢印・フリーズアロー・速度変化 移動/判定/変化対象の初期化
|
|
75
|
+
const arrowCnts = fillArray(keyNum);
|
|
76
|
+
const frzCnts = fillArray(keyNum);
|
|
77
|
+
const dummyArrowCnts = fillArray(keyNum);
|
|
78
|
+
const dummyFrzCnts = fillArray(keyNum);
|
|
79
|
+
let speedCnts = 0;
|
|
80
|
+
let keychCnts = 0;
|
|
81
|
+
|
|
82
|
+
g_workObj.flatMode = g_stateObj.d_stepzone === `FlatBar` ||
|
|
83
|
+
g_stateObj.scroll.endsWith(`Flat`) ||
|
|
84
|
+
g_keyObj[`flatMode${keyCtrlPtn}`] ||
|
|
85
|
+
(g_stateObj.stepArea === `Halfway` &&
|
|
86
|
+
g_keyObj[`div${keyCtrlPtn}`] < g_keyObj[`${g_keyObj.defaultProp}${keyCtrlPtn}`].length);
|
|
87
|
+
g_workObj.stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || g_workObj.flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
|
|
88
|
+
|
|
89
|
+
// mainSprite配下に層別のスプライトを作成し、ステップゾーン・矢印本体・フリーズアローヒット部分に分ける
|
|
90
|
+
const mainSpriteN = [], stepSprite = [], arrowSprite = [], frzHitSprite = [];
|
|
91
|
+
|
|
92
|
+
// Hidden+, Sudden+用のライン、パーセント表示
|
|
93
|
+
const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
|
|
94
|
+
const doubleFilterFlg = getDoubleFilterFlg();
|
|
95
|
+
|
|
96
|
+
for (let j = 0; j < g_stateObj.layerNum; j++) {
|
|
97
|
+
const mainSpriteJ = createEmptySprite(mainSprite, `mainSprite${j}`, mainCommonPos);
|
|
98
|
+
mainSpriteN.push(mainSpriteJ);
|
|
99
|
+
mainSpriteJ.appendChild(createColorObject2(`filterBar${j}`, g_lblPosObj.filterBar, filterCss));
|
|
100
|
+
if (doubleFilterFlg) {
|
|
101
|
+
mainSpriteJ.appendChild(createColorObject2(`filterBar${j % 2 == 0 ? j + 1 : j - 1}_HS`, g_lblPosObj.filterBar, filterCss));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// レイヤーごとのTransition設定
|
|
105
|
+
// StepAreaオプションにより、レイヤーが倍化される場合があるため基準レイヤー数ごとに設定
|
|
106
|
+
const transj = j % g_stateObj.layerNumDf;
|
|
107
|
+
addTransform(`mainSprite${j}`, `mainSprite${j}`,
|
|
108
|
+
g_workObj.layerTrans[Math.floor(transj / 2) * 2 + (transj + Number(g_stateObj.reverse === C_FLG_ON)) % 2], g_transPriority.layer);
|
|
109
|
+
|
|
110
|
+
stepSprite.push(createEmptySprite(mainSpriteJ, `stepSprite${j}`, mainCommonPos));
|
|
111
|
+
arrowSprite.push(createEmptySprite(mainSpriteJ, `arrowSprite${j}`, { ...mainCommonPos, y: g_workObj.hitPosition * (j % 2 === 0 ? 1 : -1) }));
|
|
112
|
+
frzHitSprite.push(createEmptySprite(mainSpriteJ, `frzHitSprite${j}`, mainCommonPos));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (g_appearanceRanges.includes(g_stateObj.appearance)) {
|
|
116
|
+
mainSprite.appendChild(createDivCss2Label(`filterView`, ``, g_lblPosObj.filterView));
|
|
117
|
+
if (g_stateObj.d_filterline === C_FLG_ON) {
|
|
118
|
+
$id(`filterView`).opacity = 1;
|
|
119
|
+
for (let j = 0; j < g_stateObj.layerNum; j++) {
|
|
120
|
+
$id(`filterBar${j}`).opacity = 1;
|
|
121
|
+
if (doubleFilterFlg) {
|
|
122
|
+
$id(`filterBar${j}_HS`).opacity = 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ステップゾーン、フリーズアローヒット部分の生成
|
|
129
|
+
for (let j = 0; j < keyNum; j++) {
|
|
130
|
+
makeStepZone(j, keyCtrlPtn);
|
|
131
|
+
}
|
|
132
|
+
if (g_workObj.flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
|
|
133
|
+
|
|
134
|
+
// スクロール名に`R-`が含まれていればリバースと見做す
|
|
135
|
+
const reverseFlg = g_stateObj.reverse === C_FLG_ON || g_stateObj.scroll.startsWith(`R-`);
|
|
136
|
+
|
|
137
|
+
// ステップゾーンの代わり
|
|
138
|
+
const lineY = [(C_ARW_WIDTH - g_stateObj.flatStepHeight) / 2, (C_ARW_WIDTH + g_stateObj.flatStepHeight) / 2];
|
|
139
|
+
const reverses = [reverseFlg, reverseFlg];
|
|
140
|
+
if (makeDedupliArray(g_workObj.scrollDir).length > 1) {
|
|
141
|
+
lineY.push(lineY[0], lineY[1]);
|
|
142
|
+
reverses.push(!reverses[0], !reverses[1]);
|
|
143
|
+
}
|
|
144
|
+
for (let k = 0; k < g_stateObj.layerNum; k += 2) {
|
|
145
|
+
lineY.forEach((y, j) => {
|
|
146
|
+
stepSprite[Number(reverses[j]) + k].appendChild(
|
|
147
|
+
createColorObject2(`stepBar${j + k}`, {
|
|
148
|
+
x: 0, y: C_STEP_Y + g_posObj.reverseStepY * Number(reverses[j]) + y,
|
|
149
|
+
w: g_headerObj.playingWidth - 50, h: 1, styleName: `lifeBar`,
|
|
150
|
+
}, g_cssObj.life_Failed)
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Appearanceのオプション適用時は一部描画を隠す
|
|
157
|
+
changeAppearanceBar(g_appearanceRanges.includes(g_stateObj.appearance)
|
|
158
|
+
? g_hidSudObj.filterPos : g_hidSudObj.filterPosDefault[g_stateObj.appearance], 0);
|
|
159
|
+
|
|
160
|
+
// StepArea処理
|
|
161
|
+
g_stepAreaFunc.get(g_stateObj.stepArea)();
|
|
162
|
+
|
|
163
|
+
// mainSpriteのtransform追加処理
|
|
164
|
+
addTransform(`mainSprite`, `playWindow`, g_playWindowFunc.get(g_stateObj.playWindow)(), g_transPriority.playWindow);
|
|
165
|
+
|
|
166
|
+
// EffectのArrowEffect追加処理
|
|
167
|
+
g_effectFunc.get(g_stateObj.effect)();
|
|
168
|
+
|
|
169
|
+
// 現在の矢印・フリーズアローの速度の初期化 (速度変化時に直す)
|
|
170
|
+
g_workObj.currentSpeed = 2;
|
|
171
|
+
|
|
172
|
+
// 開始位置、楽曲再生位置の設定
|
|
173
|
+
const firstFrame = g_scoreObj.frameNum;
|
|
174
|
+
let musicStartFrame = firstFrame + g_headerObj.blankFrame;
|
|
175
|
+
const fadeFlgs = { fadein: [`In`, `Out`], fadeout: [`Out`, `In`] };
|
|
176
|
+
g_audio.volume = (firstFrame === 0 ? g_stateObj.volume / 100 : 0);
|
|
177
|
+
|
|
178
|
+
// 曲時間制御変数
|
|
179
|
+
let thisTime;
|
|
180
|
+
let buffTime;
|
|
181
|
+
let musicStartTime;
|
|
182
|
+
let musicStartCtxTime;
|
|
183
|
+
let musicStartFlg = false;
|
|
184
|
+
let isPaused = false; // 一時停止中かどうか(経路によらず共通のフラグ)
|
|
185
|
+
let manualPauseFlg = false; // 手動ポーズによる一時停止かどうか(true時はvisibilitychangeでの自動再開をスキップ)
|
|
186
|
+
let pausedElapsedTime = null; // [AudioPlayer/開始後のみ] 一時停止時点の再生位置(秒)
|
|
187
|
+
let pausedStartAdjustment = null; // [AudioPlayer/開始前のみ] 開始予定までの残り時間(秒)
|
|
188
|
+
let countdownTimeoutId = null; // 再開前カウントダウンのタイマーID。null=カウントダウン中でない
|
|
189
|
+
const mySessionId = ++g_timelineSessionId; // このmainInit()実行を識別するID
|
|
190
|
+
|
|
191
|
+
g_inputKeyBuffer = {};
|
|
192
|
+
|
|
193
|
+
// 終了時間の設定
|
|
194
|
+
let duration = g_audio.duration * g_fps;
|
|
195
|
+
g_scoreObj.fadeOutFrame = Infinity;
|
|
196
|
+
g_scoreObj.fadeOutTerm = C_FRM_AFTERFADE;
|
|
197
|
+
|
|
198
|
+
// フェードアウト時間指定の場合、その7秒(=420フレーム)後に終了する
|
|
199
|
+
let fadeNo = -1;
|
|
200
|
+
if (g_headerObj.fadeFrame?.length >= g_stateObj.scoreId + 1) {
|
|
201
|
+
fadeNo = (isNaN(parseInt(g_headerObj.fadeFrame[g_stateObj.scoreId][0])) ? -1 : g_stateObj.scoreId);
|
|
202
|
+
}
|
|
203
|
+
if (fadeNo !== -1) {
|
|
204
|
+
// フェードアウト指定の場合、曲長(フェードアウト開始まで)は FadeFrame - (本来のblankFrame)
|
|
205
|
+
duration = parseInt(g_headerObj.fadeFrame[fadeNo][0]) - g_headerObj.blankFrameDef;
|
|
206
|
+
g_scoreObj.fadeOutFrame = Math.ceil(duration / g_headerObj.playbackRate + g_headerObj.blankFrame + g_stateObj.adjustment);
|
|
207
|
+
|
|
208
|
+
if (g_headerObj.fadeFrame[fadeNo].length > 1) {
|
|
209
|
+
g_scoreObj.fadeOutTerm = Number(g_headerObj.fadeFrame[fadeNo][1]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 終了時間指定の場合、その値を適用する
|
|
214
|
+
let endFrameUseFlg = false;
|
|
215
|
+
const tmpEndFrame = g_headerObj.endFrame?.[g_stateObj.scoreId] || g_headerObj.endFrame?.[0];
|
|
216
|
+
if (!isNaN(parseInt(tmpEndFrame))) {
|
|
217
|
+
// 終了時間指定の場合、曲長は EndFrame - (本来のblankFrame)
|
|
218
|
+
duration = parseInt(tmpEndFrame) - g_headerObj.blankFrameDef;
|
|
219
|
+
endFrameUseFlg = true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let fullFrame = Math.ceil(duration / g_headerObj.playbackRate + g_headerObj.blankFrame + g_stateObj.adjustment);
|
|
223
|
+
if (g_scoreObj.fadeOutFrame !== Infinity && !endFrameUseFlg) {
|
|
224
|
+
fullFrame += g_scoreObj.fadeOutTerm;
|
|
225
|
+
}
|
|
226
|
+
g_scoreObj.fullFrame = fullFrame;
|
|
227
|
+
const fullTime = transFrameToTimer(fullFrame - g_stateObj.intAdjustment);
|
|
228
|
+
|
|
229
|
+
// フレーム数
|
|
230
|
+
divRoot.appendChild(createDivCss2Label(`lblframe`, g_scoreObj.baseFrame, { ...g_lblPosObj.lblframe, display: g_workObj.lifegaugeDisp }));
|
|
231
|
+
|
|
232
|
+
// ライフ(数字)部作成
|
|
233
|
+
const intLifeVal = Math.floor(g_workObj.lifeVal);
|
|
234
|
+
let lblInitColor = g_cssObj.life_Failed;
|
|
235
|
+
if (g_workObj.lifeVal === g_headerObj.maxLifeVal) {
|
|
236
|
+
lblInitColor = g_cssObj.life_Max;
|
|
237
|
+
} else if (g_workObj.lifeVal >= g_workObj.lifeBorder) {
|
|
238
|
+
lblInitColor = g_cssObj.life_Cleared;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 曲名・アーティスト名、譜面名表示
|
|
242
|
+
const playbackView = (g_headerObj.playbackRate === 1 ? `` : ` [Rate:${g_headerObj.playbackRate}]`);
|
|
243
|
+
const musicTitle = (g_headerObj.musicTitles[g_headerObj.musicNos[g_stateObj.scoreId]] || g_headerObj.musicTitle) + playbackView;
|
|
244
|
+
const artistName = g_headerObj.artistNames[g_headerObj.musicNos[g_stateObj.scoreId]] || g_headerObj.artistName;
|
|
245
|
+
const assistFlg = (g_autoPlaysBase.includes(g_stateObj.autoPlay) ? `` : `-${getStgDetailName(g_stateObj.autoPlay)}${getStgDetailName('less')}`);
|
|
246
|
+
const shuffleName = (g_stateObj.shuffle !== C_FLG_OFF ? `: ${getShuffleName()}` : ``);
|
|
247
|
+
|
|
248
|
+
// 曲名・アーティスト名、譜面名のサイズ調整
|
|
249
|
+
const checkMusicSiz = (_text, _siz) => getFontSize2(_text, g_headerObj.playingWidth - g_headerObj.customViewWidth - 125, { maxSiz: _siz });
|
|
250
|
+
|
|
251
|
+
const makerView = g_headerObj.makerView ? ` (${g_headerObj.creatorNames[g_stateObj.scoreId]})` : ``;
|
|
252
|
+
const transKeyName = getTransKeyName();
|
|
253
|
+
const autoAll = g_stateObj.autoAll === C_FLG_ON ? ` > AutoPlay` : ``;
|
|
254
|
+
let difName = `[${getKeyName(g_headerObj.keyLabels[g_stateObj.scoreId])}${transKeyName} / ${g_headerObj.difLabels[g_stateObj.scoreId]}${assistFlg}${shuffleName}${makerView}${autoAll}]`;
|
|
255
|
+
let creditName = `${musicTitle} / ${artistName}`;
|
|
256
|
+
if (checkMusicSiz(creditName, g_limitObj.musicTitleSiz) < 12) {
|
|
257
|
+
creditName = `${musicTitle}`;
|
|
258
|
+
difName = `/ ${artistName} ` + difName;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
multiAppend(infoSprite,
|
|
262
|
+
|
|
263
|
+
// ライフ(数字)
|
|
264
|
+
createDivCss2Label(`lblLife`, intLifeVal, {
|
|
265
|
+
x: 0, y: 30, w: 70, h: 20, siz: g_limitObj.jdgCntsSiz, display: g_workObj.lifegaugeDisp,
|
|
266
|
+
}, lblInitColor),
|
|
267
|
+
|
|
268
|
+
// ゲージ種類
|
|
269
|
+
createDivCss2Label(`lblGaugeMode`, g_stateObj.gauge, { ...g_lblPosObj.lblGaugeMode, display: g_workObj.musicinfoDisp }),
|
|
270
|
+
|
|
271
|
+
// ライフ背景
|
|
272
|
+
createColorObject2(`lifeBackObj`, { ...g_lblPosObj.lifeBackObj, display: g_workObj.lifegaugeDisp }, g_cssObj.life_Background),
|
|
273
|
+
|
|
274
|
+
// ライフ本体
|
|
275
|
+
createColorObject2(`lifeBar`, {
|
|
276
|
+
x: 5, y: 50 + (g_headerObj.playingHeight - 100) * (g_headerObj.maxLifeVal - intLifeVal) / g_headerObj.maxLifeVal,
|
|
277
|
+
w: 15, h: (g_headerObj.playingHeight - 100) * intLifeVal / g_headerObj.maxLifeVal, styleName: `lifeBar`,
|
|
278
|
+
display: g_workObj.lifegaugeDisp,
|
|
279
|
+
}, lblInitColor),
|
|
280
|
+
|
|
281
|
+
// ライフ:ボーダーライン
|
|
282
|
+
// この背景の画像は40x16で作成しているが、`padding-right:5px`があるためサイズを35x16で作成
|
|
283
|
+
createColorObject2(`lifeBorderObj`, {
|
|
284
|
+
x: 10, y: 42 + (g_headerObj.playingHeight - 100) * (g_headerObj.maxLifeVal - g_workObj.lifeBorder) / g_headerObj.maxLifeVal,
|
|
285
|
+
w: 35, h: 16, background: C_CLR_BORDER, styleName: `lifeBorder`,
|
|
286
|
+
fontFamily: getBasicFont(), display: g_workObj.lifegaugeDisp,
|
|
287
|
+
}, g_cssObj.life_Border, g_cssObj.life_BorderColor),
|
|
288
|
+
|
|
289
|
+
// 曲名・アーティスト名表示
|
|
290
|
+
createDivCss2Label(`lblCredit`, creditName, { ...g_lblPosObj.lblCredit, siz: checkMusicSiz(creditName, g_limitObj.musicTitleSiz) }),
|
|
291
|
+
|
|
292
|
+
// 譜面名表示
|
|
293
|
+
createDivCss2Label(`lblDifName`, difName, { ...g_lblPosObj.lblDifName, siz: checkMusicSiz(difName, 12) }),
|
|
294
|
+
|
|
295
|
+
// 曲時間表示:現在時間
|
|
296
|
+
createDivCss2Label(`lblTime1`, `-:--`, { ...g_lblPosObj.lblTime1, display: g_workObj.musicinfoDisp }),
|
|
297
|
+
|
|
298
|
+
// 曲時間表示:総時間
|
|
299
|
+
createDivCss2Label(`lblTime2`, `/ ${fullTime}`, { ...g_lblPosObj.lblTime2, display: g_workObj.musicinfoDisp }),
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
if (g_stateObj.frzReturn !== C_FLG_OFF) {
|
|
303
|
+
multiAppend(infoSprite,
|
|
304
|
+
// FrzReturnゲージ
|
|
305
|
+
createColorObject2(`lifeBackFrzObj`, { ...g_lblPosObj.lifeBackFrzObj, display: g_workObj.scoreDisp }, g_cssObj.life_Background),
|
|
306
|
+
createColorObject2(`lifeBarFrz`, { ...g_lblPosObj.lifeBarFrz, display: g_workObj.scoreDisp }, g_cssObj.life_frzNormal),
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (g_workObj.nonDefaultSc) {
|
|
311
|
+
const diffX = g_sWidth + g_headerObj.scAreaWidth - 85 + g_diffObj.shortcutX;
|
|
312
|
+
const diffY = g_headerObj.playingHeight + g_diffObj.shortcutY;
|
|
313
|
+
multiAppend(infoSprite,
|
|
314
|
+
createDivCss2Label(`lblRetry`, `[${g_lblNameObj.l_retry}]`, {
|
|
315
|
+
...g_lblPosObj.lblMainScHeader, x: diffX, y: diffY - 95,
|
|
316
|
+
}),
|
|
317
|
+
createDivCss2Label(`lblRetrySc`, g_kCd[g_headerObj.keyRetry], {
|
|
318
|
+
...g_lblPosObj.lblMainScKey, x: diffX, y: diffY - 80,
|
|
319
|
+
fontWeight: g_headerObj.keyRetry === C_KEY_RETRY ? `normal` : `bold`,
|
|
320
|
+
}),
|
|
321
|
+
createDivCss2Label(`lblTitleBack`, `[${g_lblNameObj.l_titleBack}]`, {
|
|
322
|
+
...g_lblPosObj.lblMainScHeader, x: diffX, y: diffY - 65,
|
|
323
|
+
}),
|
|
324
|
+
createDivCss2Label(`lblTitleBackSc`, g_isMac ? `Shift+${g_kCd[g_headerObj.keyRetry]}` : g_kCd[g_headerObj.keyTitleBack], {
|
|
325
|
+
...g_lblPosObj.lblMainScKey, x: diffX, y: diffY - 50,
|
|
326
|
+
fontWeight: g_headerObj.keyTitleBack === C_KEY_TITLEBACK ? `normal` : `bold`,
|
|
327
|
+
}),
|
|
328
|
+
createDivCss2Label(`lblPause`, `[${g_lblNameObj.l_pause}]`, {
|
|
329
|
+
...g_lblPosObj.lblMainScHeader, x: diffX, y: diffY - 35,
|
|
330
|
+
}),
|
|
331
|
+
createDivCss2Label(`lblPauseSc`, g_kCd[g_headerObj.keyPause], {
|
|
332
|
+
...g_lblPosObj.lblMainScKey, x: diffX, y: diffY - 20,
|
|
333
|
+
fontWeight: g_headerObj.keyPause === C_KEY_PAUSE ? `normal` : `bold`,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ボーダーライン表示
|
|
339
|
+
lifeBorderObj.textContent = g_workObj.lifeBorder;
|
|
340
|
+
if (g_stateObj.lifeBorder === 0 || g_workObj.lifeVal === g_headerObj.maxLifeVal) {
|
|
341
|
+
lifeBorderObj.style.display = C_DIS_NONE;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// 歌詞表示
|
|
345
|
+
const wordSprite = createEmptySprite(judgeSprite, `wordSprite`, { w: g_headerObj.playingWidth });
|
|
346
|
+
for (let j = 0; j <= g_scoreObj.wordMaxDepth; j++) {
|
|
347
|
+
const wordY = (j % 2 === 0 ? 10 : (g_headerObj.bottomWordSetFlg ? g_posObj.distY + 10 : g_headerObj.playingHeight - 60));
|
|
348
|
+
wordSprite.appendChild(createDivCss2Label(`lblword${j}`, ``, { ...g_lblPosObj.lblWord, y: wordY, fontFamily: getBasicFont() }));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const jdgGroups = [`J`, `FJ`];
|
|
352
|
+
const jdgX = [g_headerObj.playingWidth / 2 - 220, g_headerObj.playingWidth / 2 - 120];
|
|
353
|
+
const jdgY = [(g_headerObj.playingHeight + g_posObj.stepYR) / 2 - 60, (g_headerObj.playingHeight + g_posObj.stepYR) / 2 + 10];
|
|
354
|
+
if (g_stateObj.d_background === C_FLG_OFF && g_headerObj.jdgPosReset && g_diffObj.arrowJdgX === 0) {
|
|
355
|
+
// jdgPosResetオプションにより判定位置変更が阻害されることを防ぐため、
|
|
356
|
+
// X座標が変わった場合は判定位置変更が行われたと判断
|
|
357
|
+
} else {
|
|
358
|
+
jdgX[0] += g_diffObj.arrowJdgX;
|
|
359
|
+
jdgX[1] += g_diffObj.frzJdgX;
|
|
360
|
+
jdgY[0] += g_diffObj.arrowJdgY;
|
|
361
|
+
jdgY[1] += g_diffObj.frzJdgY;
|
|
362
|
+
}
|
|
363
|
+
if (g_stateObj.playWindow === `SideScroll`) {
|
|
364
|
+
jdgX[0] += 30;
|
|
365
|
+
jdgX[1] -= 60;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
jdgGroups.forEach((jdg, j) => {
|
|
369
|
+
// キャラクタ表示
|
|
370
|
+
const charaJ = createDivCss2Label(`chara${jdg}`, ``, {
|
|
371
|
+
x: jdgX[j], y: jdgY[j],
|
|
372
|
+
w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight, siz: g_limitObj.jdgCharaSiz,
|
|
373
|
+
opacity: objOpacity, display: g_workObj.judgmentDisp,
|
|
374
|
+
}, g_cssObj.common_ii);
|
|
375
|
+
charaJ.setAttribute(`cnt`, 0);
|
|
376
|
+
|
|
377
|
+
multiAppend(judgeSprite,
|
|
378
|
+
|
|
379
|
+
// キャラクタ表示
|
|
380
|
+
charaJ,
|
|
381
|
+
|
|
382
|
+
// コンボ表示
|
|
383
|
+
createDivCss2Label(`combo${jdg}`, ``, {
|
|
384
|
+
x: jdgX[j] + 170, y: jdgY[j],
|
|
385
|
+
w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight, siz: g_limitObj.jdgCharaSiz,
|
|
386
|
+
opacity: objOpacity, display: g_workObj.judgmentDisp,
|
|
387
|
+
}, g_cssObj[`common_combo${jdg}`]),
|
|
388
|
+
|
|
389
|
+
// Fast/Slow表示
|
|
390
|
+
createDivCss2Label(`diff${jdg}`, ``, {
|
|
391
|
+
x: jdgX[j] + 170, y: jdgY[j] + 25,
|
|
392
|
+
w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight, siz: g_limitObj.mainSiz,
|
|
393
|
+
opacity: objOpacity, display: g_workObj.fastslowDisp,
|
|
394
|
+
}, g_cssObj.common_combo),
|
|
395
|
+
|
|
396
|
+
);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// 判定カウンタ表示
|
|
400
|
+
const jdgMainScoreObj = {
|
|
401
|
+
Ii: [`ii`, 0], Shakin: [`shakin`, 1], Matari: [`matari`, 2], Shobon: [`shobon`, 3], Uwan: [`uwan`, 4],
|
|
402
|
+
MCombo: [`combo`, 5], Kita: [`kita`, 7], Iknai: [`iknai`, 8], FCombo: [`combo`, 9],
|
|
403
|
+
};
|
|
404
|
+
Object.keys(jdgMainScoreObj).forEach(jdgScore =>
|
|
405
|
+
infoSprite.appendChild(makeCounterSymbol(`lbl${jdgScore}`, g_headerObj.playingWidth - 110 + (g_workObj.nonDefaultSc ? g_headerObj.scAreaWidth : 0),
|
|
406
|
+
g_cssObj[`common_${jdgMainScoreObj[jdgScore][0]}`], jdgMainScoreObj[jdgScore][1] + 1, 0, g_workObj.scoreDisp)));
|
|
407
|
+
|
|
408
|
+
// パーフェクト演出
|
|
409
|
+
judgeSprite.appendChild(createDivCss2Label(`finishView`, ``, g_lblPosObj.finishView, g_cssObj.common_kita));
|
|
410
|
+
|
|
411
|
+
// 曲情報OFF
|
|
412
|
+
if (g_stateObj.d_musicinfo === C_FLG_OFF) {
|
|
413
|
+
[`lblCredit`, `lblDifName`].forEach(labelName => changeStyle(labelName, g_lblPosObj.musicInfoOFF));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// デバッグ時のみフレーム数を残す
|
|
417
|
+
if (!g_isDebug) {
|
|
418
|
+
lblframe.style.display = C_DIS_NONE;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Ready?表示
|
|
422
|
+
if (!g_headerObj.customReadyUse) {
|
|
423
|
+
const readyColor = g_headerObj.readyColor || g_headerObj.setColorOrg[0];
|
|
424
|
+
let readyDelayFrame = 0;
|
|
425
|
+
if (g_stateObj.fadein === 0 && g_headerObj.readyDelayFrame > 0 &&
|
|
426
|
+
g_headerObj.readyDelayFrame + g_stateObj.adjustment > 0) {
|
|
427
|
+
readyDelayFrame = g_headerObj.readyDelayFrame + g_stateObj.adjustment;
|
|
428
|
+
}
|
|
429
|
+
const readyHtml = g_headerObj.readyHtml ||
|
|
430
|
+
`<span style='color:${readyColor};font-size:${wUnit(60)};'>R</span>EADY<span style='font-size:${wUnit(50)};'>?</span>`;
|
|
431
|
+
|
|
432
|
+
divRoot.appendChild(
|
|
433
|
+
createDivCss2Label(`lblReady`, readyHtml, {
|
|
434
|
+
x: g_workObj.playingX + (g_headerObj.playingWidth - g_sWidth) / 2,
|
|
435
|
+
y: g_headerObj.playingY + (g_headerObj.playingHeight + g_posObj.stepYR) / 2 - 75,
|
|
436
|
+
w: g_sWidth, h: 50, siz: 40,
|
|
437
|
+
animationDuration: `${g_headerObj.readyAnimationFrame / g_fps}s`,
|
|
438
|
+
animationName: g_headerObj.readyAnimationName,
|
|
439
|
+
animationDelay: `${readyDelayFrame / g_fps}s`, opacity: 0,
|
|
440
|
+
})
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const msg = [];
|
|
445
|
+
if (getMusicUrl(g_stateObj.scoreId) === `nosound.mp3`) {
|
|
446
|
+
msg.push(g_msgInfoObj.I_0004);
|
|
447
|
+
}
|
|
448
|
+
if (g_stateObj.shuffle.indexOf(`Mirror`) !== -1 &&
|
|
449
|
+
g_stateObj.dataSaveFlg && g_stateObj.autoAll === C_FLG_OFF &&
|
|
450
|
+
g_keyObj[`shuffle${keyCtrlPtn}`].filter((shuffleGr, j) => shuffleGr !== g_keyObj[`shuffle${keyCtrlPtn}_0d`][j]).length > 0) {
|
|
451
|
+
msg.push(g_msgInfoObj.I_0005);
|
|
452
|
+
}
|
|
453
|
+
if (msg.length > 0) {
|
|
454
|
+
makeInfoWindow(msg.join(`<br>`), `leftToRightFade`, { _x: g_workObj.playingX, _y: g_headerObj.playingY });
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ユーザカスタムイベント(初期)
|
|
458
|
+
safeExecuteCustomHooks(`g_customJsObj.main`, g_customJsObj.main);
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* キーを押したときの処理
|
|
462
|
+
*/
|
|
463
|
+
const mainKeyDownActFunc = {
|
|
464
|
+
|
|
465
|
+
OFF: (_code) => {
|
|
466
|
+
const matchKeys = g_workObj.keyCtrlN;
|
|
467
|
+
|
|
468
|
+
for (let j = 0; j < keyNum; j++) {
|
|
469
|
+
matchKeys[j].filter((key, k) => _code === key && !g_workObj.keyHitFlg[j][k] && !g_judgObj.lockFlgs[j])
|
|
470
|
+
.forEach(() => {
|
|
471
|
+
g_judgObj.lockFlgs[j] = true;
|
|
472
|
+
judgeArrow(j);
|
|
473
|
+
g_judgObj.lockFlgs[j] = false;
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
ON: (_code) => { },
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// キー操作イベント
|
|
482
|
+
document.onkeydown = async evt => {
|
|
483
|
+
evt.preventDefault();
|
|
484
|
+
const setCode = transCode(evt);
|
|
485
|
+
|
|
486
|
+
if (evt.repeat && !g_mainRepeatObj.key.includes(setCode)) {
|
|
487
|
+
return blockCode(setCode);
|
|
488
|
+
}
|
|
489
|
+
if (setCode === g_kCdN[g_headerObj.keyPause]) {
|
|
490
|
+
isPaused ? resumeTimeline(true) : pauseTimeline(true);
|
|
491
|
+
return blockCode(setCode);
|
|
492
|
+
}
|
|
493
|
+
// ポーズ中でも押下状態バッファ自体は常に最新化しておく
|
|
494
|
+
g_inputKeyBuffer[setCode] = true;
|
|
495
|
+
if (isPaused) {
|
|
496
|
+
return blockCode(setCode);
|
|
497
|
+
}
|
|
498
|
+
mainKeyDownActFunc[g_stateObj.autoAll](setCode);
|
|
499
|
+
|
|
500
|
+
// 曲中リトライ、タイトルバック
|
|
501
|
+
if (setCode === g_kCdN[g_headerObj.keyRetry]) {
|
|
502
|
+
|
|
503
|
+
if (g_isMac && keyIsShift()) {
|
|
504
|
+
// Mac OS、IPad OSはDeleteキーが無いためShift+BSで代用
|
|
505
|
+
g_audio.pause();
|
|
506
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
507
|
+
titleInit();
|
|
508
|
+
|
|
509
|
+
} else {
|
|
510
|
+
// その他の環境では単にRetryに対応するキーのみで適用
|
|
511
|
+
await executeRetry(`Retry`);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
} else if (setCode === g_kCdN[g_headerObj.keyTitleBack]) {
|
|
515
|
+
g_audio.pause();
|
|
516
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
517
|
+
if (keyIsShift()) {
|
|
518
|
+
if (g_currentArrows !== g_fullArrows || g_stateObj.lifeMode === C_LFE_BORDER && g_workObj.lifeVal < g_workObj.lifeBorder) {
|
|
519
|
+
g_gameOverFlg = true;
|
|
520
|
+
g_finishFlg = false;
|
|
521
|
+
g_resultObj.gaugeTransition.push([g_scoreObj.baseFrame, 0]);
|
|
522
|
+
}
|
|
523
|
+
resultInit();
|
|
524
|
+
} else {
|
|
525
|
+
titleInit();
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
} else if (g_appearanceRanges.includes(g_stateObj.appearance) && g_stateObj.filterLock === C_FLG_OFF) {
|
|
529
|
+
const MAX_FILTER_POS = 100;
|
|
530
|
+
const MIN_FILTER_POS = 0;
|
|
531
|
+
|
|
532
|
+
if (setCode === g_hidSudObj.pgDown[g_stateObj.appearance][g_stateObj.reverse]) {
|
|
533
|
+
keyIsShift()
|
|
534
|
+
? changeAppearanceBar(g_hidSudObj.filterPos, 2)
|
|
535
|
+
: changeAppearanceFilter(Math.min(g_hidSudObj.filterPos + 1, MAX_FILTER_POS));
|
|
536
|
+
} else if (setCode === g_hidSudObj.pgUp[g_stateObj.appearance][g_stateObj.reverse]) {
|
|
537
|
+
keyIsShift()
|
|
538
|
+
? changeAppearanceBar(g_hidSudObj.filterPos, -2)
|
|
539
|
+
: changeAppearanceFilter(Math.max(g_hidSudObj.filterPos - 1, MIN_FILTER_POS));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return blockCode(setCode);
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* キーを離したときの処理
|
|
547
|
+
*/
|
|
548
|
+
const mainKeyUpActFunc = {
|
|
549
|
+
|
|
550
|
+
OFF: () => {
|
|
551
|
+
for (let j = 0; j < keyNum; j++) {
|
|
552
|
+
if (g_workObj.keyCtrlN[j].find(key => keyIsDown(key)) === undefined) {
|
|
553
|
+
$id(`stepDiv${j}`).display = C_DIS_NONE;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
ON: () => { },
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
document.onkeyup = evt => {
|
|
562
|
+
g_inputKeyBuffer[transCode(evt)] = false;
|
|
563
|
+
mainKeyUpActFunc[g_stateObj.autoAll]();
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* 全体色変化(矢印)
|
|
568
|
+
* @param {number} _j 矢印位置
|
|
569
|
+
* @param {number} _k 矢印の表示順
|
|
570
|
+
* @param {string} _name 通常, ダミー
|
|
571
|
+
*/
|
|
572
|
+
const changeArrowColor = (_j, _k, _name) => {
|
|
573
|
+
if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`]?.[g_scoreObj.frameNum]) {
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* 全体色の変更処理
|
|
577
|
+
* - 次の全体色変化対象の色と比較して一致した場合に色を変更
|
|
578
|
+
* @param {string} _type
|
|
579
|
+
* @param {element} _baseObj
|
|
580
|
+
*/
|
|
581
|
+
const changeColor = (_type, _baseObj) => {
|
|
582
|
+
const cArrowColor = g_workObj[`${_name}${_type}Colors`][_j];
|
|
583
|
+
const cArrowColorAll = g_workObj[`${_name}${_type}ColorsAll`][_j];
|
|
584
|
+
if (_baseObj.getAttribute(`color`) !== cArrowColor && cArrowColorAll === cArrowColor) {
|
|
585
|
+
_baseObj.style.background = cArrowColorAll;
|
|
586
|
+
_baseObj.setAttribute(`color`, cArrowColorAll);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
// 矢印枠の色変化
|
|
591
|
+
const arrowTop = document.getElementById(`${_name}Top${_j}_${_k}`);
|
|
592
|
+
changeColor(``, arrowTop);
|
|
593
|
+
|
|
594
|
+
// 矢印塗りつぶし部分の色変化
|
|
595
|
+
if (g_headerObj.setShadowColor[0] !== ``) {
|
|
596
|
+
const arrowShadow = document.getElementById(`${_name}Shadow${_j}_${_k}`);
|
|
597
|
+
changeColor(`Shadow`, arrowShadow);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* 全体色変化(フリーズアロー)
|
|
604
|
+
* @param {number} _j 矢印位置
|
|
605
|
+
* @param {number} _k 矢印の表示順
|
|
606
|
+
* @param {string} _name 通常, ダミー
|
|
607
|
+
* @param {string} _state フリーズアローの色変化対象 (Normal: 通常時、Hit: ヒット時)
|
|
608
|
+
*/
|
|
609
|
+
const changeFrzColor = (_j, _k, _name, _state) => {
|
|
610
|
+
|
|
611
|
+
if (g_workObj[`mk${toCapitalize(_name)}ColorChangeAll`]?.[g_scoreObj.frameNum]) {
|
|
612
|
+
const frzNo = `${_j}_${_k}`;
|
|
613
|
+
const frzTop = document.getElementById(`${_name}Top${frzNo}`);
|
|
614
|
+
const frzBar = document.getElementById(`${_name}Bar${frzNo}`);
|
|
615
|
+
const frzBtm = document.getElementById(`${_name}Btm${frzNo}`);
|
|
616
|
+
const frzTopShadow = document.getElementById(`${_name}TopShadow${frzNo}`);
|
|
617
|
+
const frzBtmShadow = document.getElementById(`${_name}BtmShadow${frzNo}`);
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* 全体色の変更処理
|
|
621
|
+
* @param {string} _type
|
|
622
|
+
* @param {element} _baseObj
|
|
623
|
+
* @param {element} _baseObj2
|
|
624
|
+
*/
|
|
625
|
+
const changeColor = (_type, _baseObj, _baseObj2) => {
|
|
626
|
+
const cFrzColor = g_workObj[`${_name}${_state}${_type}Colors`][_j];
|
|
627
|
+
const cFrzColorAll = g_workObj[`${_name}${_state}${_type}ColorsAll`][_j];
|
|
628
|
+
if (_baseObj.getAttribute(`color${_state}`) !== cFrzColor && cFrzColorAll === cFrzColor) {
|
|
629
|
+
if (_baseObj2 && _state === `Normal`) {
|
|
630
|
+
_baseObj2.style.background = cFrzColorAll;
|
|
631
|
+
}
|
|
632
|
+
_baseObj.style.background = cFrzColorAll;
|
|
633
|
+
_baseObj.setAttribute(`color${_state}`, cFrzColorAll);
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
// 矢印部分の色変化
|
|
638
|
+
changeColor(``, frzBtm, frzTop);
|
|
639
|
+
|
|
640
|
+
// 帯部分の色変化
|
|
641
|
+
changeColor(`Bar`, frzBar);
|
|
642
|
+
|
|
643
|
+
// 矢印塗りつぶし部分の色変化
|
|
644
|
+
changeColor(`Shadow`, frzBtmShadow, frzTopShadow);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* 全体色変化
|
|
651
|
+
*/
|
|
652
|
+
const changeColorFunc = {
|
|
653
|
+
arrow: (_j, _k) => changeArrowColor(_j, _k, `arrow`),
|
|
654
|
+
dummyArrow: (_j, _k) => changeArrowColor(_j, _k, `dummyArrow`),
|
|
655
|
+
frz: (_j, _k, _state) => changeFrzColor(_j, _k, `frz`, _state),
|
|
656
|
+
dummyFrz: (_j, _k, _state) => changeFrzColor(_j, _k, `dummyFrz`, _state),
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* 矢印・フリーズアロー消去
|
|
661
|
+
*
|
|
662
|
+
* @param {number} _j 矢印位置
|
|
663
|
+
* @param {string} _deleteName 削除オブジェクト名
|
|
664
|
+
*/
|
|
665
|
+
const judgeObjDelete = {};
|
|
666
|
+
g_typeLists.arrow.forEach(type =>
|
|
667
|
+
judgeObjDelete[type] = (_j, _deleteName) => {
|
|
668
|
+
delTransform(_deleteName, `root`);
|
|
669
|
+
g_workObj[`judg${toCapitalize(type)}Cnt`][_j]++;
|
|
670
|
+
document.getElementById(_deleteName).remove();
|
|
671
|
+
delete g_attrObj[_deleteName];
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* 自動判定
|
|
676
|
+
* ※mainInit内部で指定必須(arrowSprite指定)
|
|
677
|
+
*
|
|
678
|
+
* @param {number} _j 矢印位置
|
|
679
|
+
* @param {object} _arrow 矢印(オブジェクト)
|
|
680
|
+
*
|
|
681
|
+
* @param {number} _k 矢印の表示順
|
|
682
|
+
* @param {object} _frzRoot フリーズアロー(オブジェクト)
|
|
683
|
+
* @param {number} _cnt ステップゾーン到達までのフレーム数
|
|
684
|
+
* @param {number} _keyUpFrame キーを離したフレーム数
|
|
685
|
+
*/
|
|
686
|
+
const judgeMotionFunc = {
|
|
687
|
+
|
|
688
|
+
// 矢印(枠外判定、AutoPlay: OFF)
|
|
689
|
+
arrowOFF: (_j, _arrowName, _cnt) => {
|
|
690
|
+
if (_cnt < (-1) * g_judgObj.arrowJ[g_judgPosObj.shobon]) {
|
|
691
|
+
judgeUwan(_cnt, _j);
|
|
692
|
+
judgeObjDelete.arrow(_j, _arrowName);
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
|
|
696
|
+
// 矢印(オート、AutoPlay: ON)
|
|
697
|
+
arrowON: (_j, _arrowName, _cnt) => {
|
|
698
|
+
if (_cnt === 0) {
|
|
699
|
+
const stepDivHit = document.getElementById(`stepHit${_j}`);
|
|
700
|
+
|
|
701
|
+
judgeIi(_cnt, _j);
|
|
702
|
+
stepDivHit.style.opacity = 1;
|
|
703
|
+
stepDivHit.setAttribute(`cnt`, C_FRM_HITMOTION);
|
|
704
|
+
judgeObjDelete.arrow(_j, _arrowName);
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
|
|
708
|
+
// ダミー矢印(オート、AutoPlay: OFF)
|
|
709
|
+
dummyArrowOFF: (_j, _arrowName, _cnt) => {
|
|
710
|
+
if (_cnt === 0) {
|
|
711
|
+
const stepDivHit = document.getElementById(`stepHit${_j}`);
|
|
712
|
+
|
|
713
|
+
safeExecuteCustomHooks(`g_customJsObj.dummyArrow`, g_customJsObj.dummyArrow, _j);
|
|
714
|
+
stepDivHit.style.top = wUnit(-15);
|
|
715
|
+
stepDivHit.style.opacity = 1;
|
|
716
|
+
stepDivHit.classList.value = ``;
|
|
717
|
+
stepDivHit.classList.add(g_cssObj.main_stepDummy);
|
|
718
|
+
stepDivHit.setAttribute(`cnt`, C_FRM_HITMOTION);
|
|
719
|
+
judgeObjDelete.dummyArrow(_j, _arrowName);
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
|
|
723
|
+
get dummyArrowON() {
|
|
724
|
+
return this.dummyArrowOFF;
|
|
725
|
+
},
|
|
726
|
+
|
|
727
|
+
// フリーズアロー(成功時)
|
|
728
|
+
frzOK: (_j, _k, _frzName, _cnt) => {
|
|
729
|
+
judgeKita(_cnt, _j);
|
|
730
|
+
$id(`frzHit${_j}`).opacity = 0;
|
|
731
|
+
g_attrObj[_frzName].judgEndFlg = true;
|
|
732
|
+
judgeObjDelete.frz(_j, _frzName);
|
|
733
|
+
},
|
|
734
|
+
|
|
735
|
+
// ダミーフリーズアロー(成功時)
|
|
736
|
+
dummyFrzOK: (_j, _k, _frzName, _cnt) => {
|
|
737
|
+
safeExecuteCustomHooks(`g_customJsObj.dummyFrz`, g_customJsObj.dummyFrz, _j);
|
|
738
|
+
$id(`frzHit${_j}`).opacity = 0;
|
|
739
|
+
g_attrObj[_frzName].judgEndFlg = true;
|
|
740
|
+
judgeObjDelete.dummyFrz(_j, _frzName);
|
|
741
|
+
},
|
|
742
|
+
|
|
743
|
+
// フリーズアロー(枠外判定)
|
|
744
|
+
frzNG: (_j, _k, _frzName, _cnt) => {
|
|
745
|
+
if (_cnt < (-1) * g_judgObj.frzJ[g_judgPosObj.iknai]) {
|
|
746
|
+
judgeIknai(_cnt, _j);
|
|
747
|
+
g_attrObj[_frzName].judgEndFlg = true;
|
|
748
|
+
|
|
749
|
+
changeFailedFrz(_j, _k);
|
|
750
|
+
if (g_headerObj.frzStartjdgUse) {
|
|
751
|
+
judgeUwan(_cnt, _j);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
|
|
756
|
+
// ダミーフリーズアロー(枠外判定)
|
|
757
|
+
dummyFrzNG: (_j, _k, _frzName, _cnt) => { },
|
|
758
|
+
|
|
759
|
+
// フリーズアロー(キーを離したときの処理)
|
|
760
|
+
frzKeyUp: (_j, _k, _frzName, _cnt) => {
|
|
761
|
+
if (g_attrObj[_frzName].keyUpFrame > g_headerObj.frzAttempt) {
|
|
762
|
+
judgeIknai(_cnt, _j);
|
|
763
|
+
g_attrObj[_frzName].judgEndFlg = true;
|
|
764
|
+
changeFailedFrz(_j, _k);
|
|
765
|
+
}
|
|
766
|
+
},
|
|
767
|
+
|
|
768
|
+
// ダミーフリーズアロー(キーを離したときの処理)
|
|
769
|
+
// ※処理上通ることはないが、統一のために定義
|
|
770
|
+
get dummyFrzKeyUp() {
|
|
771
|
+
return this.dummyFrzNG;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* 次矢印・フリーズアローへ判定を移すかチェック
|
|
778
|
+
*
|
|
779
|
+
* - 判定対象の矢印/フリーズアローが未判定の状態で、現在の矢印/フリーズアローの判定領域が回復判定内に入った場合、
|
|
780
|
+
* 自身より前の判定をNG判定とした上で、判定対象の矢印/フリーズアローを強制的に削除
|
|
781
|
+
* - ただし、判定対象の矢印/フリーズアローがジャスト付近の場合は判定対象を優先する
|
|
782
|
+
* (フリーズアローの場合、ヒット中の場合も判定対象が優先される)
|
|
783
|
+
*
|
|
784
|
+
* @param {number} _j 矢印の位置
|
|
785
|
+
* @param {number} _k 矢印の表示順
|
|
786
|
+
* @param {number} _cnt ステップゾーン到達までのフレーム数
|
|
787
|
+
*/
|
|
788
|
+
const judgeNextFunc = {
|
|
789
|
+
|
|
790
|
+
arrowOFF: (_j, _k, _cnt) => {
|
|
791
|
+
|
|
792
|
+
// 直前のフリーズアローが未判定で、自身の判定範囲がキター(O.K.)の範囲内のとき判定対象を矢印側へ移す
|
|
793
|
+
// 本来はシャキン(Great)の範囲内としたいところだが、実装が複雑になるため上記条件とする
|
|
794
|
+
judgeNextFunc.frzOFF(_j, g_workObj.judgFrzCnt[_j] + 1, _cnt);
|
|
795
|
+
|
|
796
|
+
if (g_workObj.judgArrowCnt[_j] === _k - 1 && _cnt <= g_judgObj.arrowJ[g_judgPosObj.shakin]) {
|
|
797
|
+
const prevArrowName = `arrow${_j}_${g_workObj.judgArrowCnt[_j]}`;
|
|
798
|
+
const prevArrow = g_attrObj[prevArrowName];
|
|
799
|
+
|
|
800
|
+
if (prevArrow.cnt < (-1) * g_judgObj.arrowJ[g_judgPosObj.ii]) {
|
|
801
|
+
|
|
802
|
+
// 自身より前の矢印が未判定の場合、強制的に枠外判定を行い矢印を削除
|
|
803
|
+
if (prevArrow.cnt >= (-1) * g_judgObj.arrowJ[g_judgPosObj.uwan]) {
|
|
804
|
+
judgeUwan(prevArrow.cnt, _j);
|
|
805
|
+
judgeObjDelete.arrow(_j, prevArrowName);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
|
|
811
|
+
arrowON: (_j, _k, _cnt) => true,
|
|
812
|
+
get dummyArrowOFF() {
|
|
813
|
+
return this.arrowON;
|
|
814
|
+
},
|
|
815
|
+
get dummyArrowON() {
|
|
816
|
+
return this.arrowON;
|
|
817
|
+
},
|
|
818
|
+
|
|
819
|
+
frzOFF: (_j, _k, _cnt) => {
|
|
820
|
+
|
|
821
|
+
// 判定対象が自身より前のフリーズアローで、自身の判定範囲がキター(O.K.)の範囲内のとき
|
|
822
|
+
if (g_workObj.judgFrzCnt[_j] === _k - 1 && _cnt <= g_judgObj.frzJ[g_judgPosObj.sfsf]) {
|
|
823
|
+
const prevFrzName = `frz${_j}_${g_workObj.judgFrzCnt[_j]}`;
|
|
824
|
+
const prevFrz = g_attrObj[prevFrzName];
|
|
825
|
+
|
|
826
|
+
// 自身より前のフリーズアローが移動中かつキター(O.K.)の領域外のとき
|
|
827
|
+
if (prevFrz && prevFrz.isMoving && prevFrz.cnt < (-1) * g_judgObj.frzJ[g_judgPosObj.kita]) {
|
|
828
|
+
|
|
829
|
+
// 自身より前のフリーズアローが未判定の場合、強制的に枠外判定を行う
|
|
830
|
+
if (prevFrz.cnt >= (-1) * g_judgObj.frzJ[g_judgPosObj.iknai] && !prevFrz.judgEndFlg) {
|
|
831
|
+
judgeIknai(prevFrz.cnt, _j);
|
|
832
|
+
if (g_headerObj.frzStartjdgUse) {
|
|
833
|
+
judgeUwan(prevFrz.cnt, _j);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// 自身より前のフリーズアローを削除して判定対象を自身に変更 (g_workObj.judgFrzCnt[_j]をカウントアップ)
|
|
837
|
+
judgeObjDelete.frz(_j, prevFrzName);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
frzON: (_j, _k, _cnt) => {
|
|
843
|
+
|
|
844
|
+
if (_cnt === 0) {
|
|
845
|
+
changeHitFrz(_j, _k, `frz`);
|
|
846
|
+
if (g_headerObj.frzStartjdgUse) {
|
|
847
|
+
judgeIi(_cnt, _j);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
|
|
852
|
+
dummyFrzOFF: (_j, _k, _cnt) => {
|
|
853
|
+
if (_cnt === 0) {
|
|
854
|
+
changeHitFrz(_j, _k, `dummyFrz`);
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
get dummyFrzON() {
|
|
858
|
+
return this.dummyFrzOFF;
|
|
859
|
+
},
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* フリーズアローヒット中に手を離したかどうかをチェック
|
|
864
|
+
*
|
|
865
|
+
* @param _j 矢印の位置
|
|
866
|
+
*/
|
|
867
|
+
const checkKeyUpFunc = {
|
|
868
|
+
frzOFF: (_j) => g_workObj.keyHitFlg[_j].find(flg => flg),
|
|
869
|
+
frzON: (_j) => true,
|
|
870
|
+
dummyFrzOFF: (_j) => true,
|
|
871
|
+
dummyFrzON: (_j) => true,
|
|
872
|
+
};
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* 矢印生成
|
|
876
|
+
* @param {object} _attrs 矢印個別の属性
|
|
877
|
+
* (pos: 矢印種類, arrivalFrame: 到達フレーム数, initY: 初期表示位置,
|
|
878
|
+
* initBoostY: Motion有効時の初期表示位置加算, motionFrame: アニメーション有効フレーム数)
|
|
879
|
+
* @param {number} _arrowCnt 現在の判定矢印順
|
|
880
|
+
* @param {string} _name 矢印名
|
|
881
|
+
* @param {string} _color 矢印色
|
|
882
|
+
* @param {string} _shadowColor 矢印塗りつぶし部分の色
|
|
883
|
+
*/
|
|
884
|
+
const makeArrow = (_attrs, _arrowCnt, _name, _color, _shadowColor) => {
|
|
885
|
+
const _j = _attrs.pos;
|
|
886
|
+
const dividePos = g_workObj.dividePos[_j] % 2;
|
|
887
|
+
const colorPos = g_keyObj[`color${keyCtrlPtn}`][_j];
|
|
888
|
+
|
|
889
|
+
const arrowName = `${_name}${_j}_${_arrowCnt}`;
|
|
890
|
+
const stepY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
|
|
891
|
+
const firstPosY = stepY + (_attrs.initY * _attrs.boostSpd +
|
|
892
|
+
_attrs.initBoostY * _attrs.boostDir) * g_workObj.scrollDir[_j];
|
|
893
|
+
|
|
894
|
+
const arrowRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], arrowName, {
|
|
895
|
+
x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH,
|
|
896
|
+
});
|
|
897
|
+
/**
|
|
898
|
+
* 矢印毎の属性情報
|
|
899
|
+
*/
|
|
900
|
+
g_attrObj[arrowName] = {
|
|
901
|
+
// 生存フレーム数
|
|
902
|
+
cnt: _attrs.arrivalFrame + 1,
|
|
903
|
+
// 生存フレーム数 (ストップ分除去、個別加速/Motionオプション用)
|
|
904
|
+
boostCnt: _attrs.motionFrame,
|
|
905
|
+
// 個別加速量
|
|
906
|
+
boostSpd: _attrs.boostSpd,
|
|
907
|
+
// ステップゾーン位置 (0: デフォルト, 1: リバース)
|
|
908
|
+
dividePos: dividePos,
|
|
909
|
+
// スクロール方向 (1: デフォルト, -1: リバース)
|
|
910
|
+
dir: g_workObj.scrollDir[_j],
|
|
911
|
+
// 個別加速方向 (1: 順方向加速, -1: 逆方向加速)
|
|
912
|
+
boostDir: _attrs.boostDir,
|
|
913
|
+
// 前フレーム時の位置 (判定で使用)
|
|
914
|
+
prevY: firstPosY,
|
|
915
|
+
// 現フレーム時の位置
|
|
916
|
+
y: firstPosY,
|
|
917
|
+
// 移動ロックフラグ(矢印モーション設定後に再設定)
|
|
918
|
+
movLockFlg: false,
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
// 矢印色の設定
|
|
922
|
+
// - 枠/塗りつぶし色: g_attrObj[arrowName].Arrow / ArrowShadow
|
|
923
|
+
g_typeLists.arrowColor.forEach(val => g_attrObj[arrowName][`Arrow${val}`] = g_workObj[`${_name}${val}Colors`][_j]);
|
|
924
|
+
|
|
925
|
+
// g_attrObj定義後のカスタムイベント
|
|
926
|
+
safeExecuteCustomHooks(`g_customJsObj.preMakeArrow`, g_customJsObj.preMakeArrow, _attrs, arrowName, _name, _arrowCnt);
|
|
927
|
+
|
|
928
|
+
arrowSprite[g_workObj.dividePos[_j]].appendChild(arrowRoot);
|
|
929
|
+
const arrowSubRoot = createEmptySprite(arrowRoot, `sub${arrowName}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
|
|
930
|
+
|
|
931
|
+
if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
|
|
932
|
+
arrowSubRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
|
|
933
|
+
arrowSubRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
|
|
934
|
+
}
|
|
935
|
+
g_attrObj[arrowName].movLockFlg = g_workObj[`${_name}MovLock`][_j] || g_workObj.movLockEnabled;
|
|
936
|
+
const initManualFlg = g_workObj[`${_name}InitManual`][_j] || g_workObj.initManualEnabled;
|
|
937
|
+
const setArrowYCondition = `${String(g_attrObj[arrowName].movLockFlg)}_${String(initManualFlg)}`;
|
|
938
|
+
setArrowY.get(setArrowYCondition)(arrowName, firstPosY, stepY);
|
|
939
|
+
if (!initManualFlg) {
|
|
940
|
+
addTransform(arrowName, `rootX`, `translateX(${wUnit(g_workObj.stepX[_j])})`);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* 矢印オブジェクトの生成
|
|
945
|
+
* - 後で生成されたものが手前に表示されるため、塗りつぶし ⇒ 枠の順で作成
|
|
946
|
+
*/
|
|
947
|
+
// 矢印の内側を塗りつぶすか否か
|
|
948
|
+
if (g_headerObj.setShadowColor[colorPos] !== ``) {
|
|
949
|
+
// 矢印 (塗りつぶし)
|
|
950
|
+
const arrShadow = createColorObject2(`${_name}Shadow${_j}_${_arrowCnt}`, {
|
|
951
|
+
background: _shadowColor === `Default` ? _color : _shadowColor,
|
|
952
|
+
rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
|
|
953
|
+
});
|
|
954
|
+
if (_shadowColor === `Default`) {
|
|
955
|
+
arrShadow.style.opacity = 0.5;
|
|
956
|
+
}
|
|
957
|
+
arrowSubRoot.appendChild(arrShadow);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// 矢印 (枠)
|
|
961
|
+
arrowSubRoot.appendChild(createColorObject2(`${_name}Top${_j}_${_arrowCnt}`, {
|
|
962
|
+
background: _color, rotate: g_workObj.arrowRtn[_j],
|
|
963
|
+
}));
|
|
964
|
+
safeExecuteCustomHooks(`g_customJsObj.makeArrow`, g_customJsObj.makeArrow, _attrs, arrowName, _name, _arrowCnt);
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* 矢印移動メイン
|
|
969
|
+
* @param {number} _j
|
|
970
|
+
* @param {number} _k
|
|
971
|
+
* @param {string} _name
|
|
972
|
+
*/
|
|
973
|
+
const movArrow = (_j, _k, _name) => {
|
|
974
|
+
const arrowName = `${_name}${_j}_${_k}`;
|
|
975
|
+
const currentArrow = g_attrObj[arrowName];
|
|
976
|
+
|
|
977
|
+
// 全体色変化 (移動時)
|
|
978
|
+
changeColorFunc[_name](_j, _k);
|
|
979
|
+
|
|
980
|
+
// 移動
|
|
981
|
+
if (g_workObj.currentSpeed !== 0) {
|
|
982
|
+
const boostCnt = currentArrow.boostCnt;
|
|
983
|
+
currentArrow.prevY = currentArrow.y;
|
|
984
|
+
currentArrow.y -= (g_workObj.currentSpeed * currentArrow.boostSpd +
|
|
985
|
+
(g_workObj.motionOnFrames[boostCnt] || 0) * currentArrow.boostDir) * currentArrow.dir;
|
|
986
|
+
movArrowY.get(currentArrow.movLockFlg)(arrowName, currentArrow.y);
|
|
987
|
+
g_motionAlphaFunc.get(g_stateObj.motion)(arrowName, currentArrow);
|
|
988
|
+
currentArrow.boostCnt--;
|
|
989
|
+
}
|
|
990
|
+
judgeMotionFunc[`${_name}${g_stateObj.autoAll}`](_j, arrowName, --currentArrow.cnt);
|
|
991
|
+
judgeNextFunc[`${_name}${g_stateObj.autoAll}`](_j, _k, currentArrow.cnt);
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* フリーズアロー生成
|
|
996
|
+
* @param {object} _attrs フリーズアロー個別の属性
|
|
997
|
+
* (pos: 矢印種類, arrivalFrame: 到達フレーム数, initY: 初期表示位置,
|
|
998
|
+
* initBoostY: Motion有効時の初期表示位置加算, motionFrame: アニメーション有効フレーム数)
|
|
999
|
+
* @param {number} _arrowCnt 現在の判定フリーズアロー順
|
|
1000
|
+
* @param {string} _name フリーズアロー名
|
|
1001
|
+
* @param {string} _normalColor フリーズアロー(矢印)の色
|
|
1002
|
+
* @param {string} _barColor フリーズアロー(帯)の色
|
|
1003
|
+
* @param {string} _shadowColor フリーズアロー(塗りつぶし)の色
|
|
1004
|
+
*/
|
|
1005
|
+
const makeFrzArrow = (_attrs, _arrowCnt, _name, _normalColor, _barColor, _shadowColor) => {
|
|
1006
|
+
const _j = _attrs.pos;
|
|
1007
|
+
const dividePos = g_workObj.dividePos[_j] % 2;
|
|
1008
|
+
const frzNo = `${_j}_${_arrowCnt}`;
|
|
1009
|
+
const frzName = `${_name}${frzNo}`;
|
|
1010
|
+
const stepY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
|
|
1011
|
+
const firstPosY = stepY + (_attrs.initY * _attrs.boostSpd +
|
|
1012
|
+
_attrs.initBoostY * _attrs.boostDir) * g_workObj.scrollDir[_j];
|
|
1013
|
+
const firstBarLength = g_workObj[`mk${toCapitalize(_name)}Length`][_j][(_arrowCnt - 1) * 2] * _attrs.boostSpd;
|
|
1014
|
+
|
|
1015
|
+
const frzRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], frzName, {
|
|
1016
|
+
x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH + firstBarLength,
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
// CamoufrageType: FrzArrowの場合のみ、フリーズアローの帯を隠す
|
|
1020
|
+
if (g_stateObj.camoufrageType === `FrzArrow`) {
|
|
1021
|
+
_barColor = `#00000000`;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* フリーズアロー毎の属性情報
|
|
1026
|
+
*/
|
|
1027
|
+
g_attrObj[frzName] = {
|
|
1028
|
+
// 生存フレーム数
|
|
1029
|
+
cnt: _attrs.arrivalFrame + 1,
|
|
1030
|
+
// 生存フレーム数 (ストップ分除去、個別加速/Motionオプション用)
|
|
1031
|
+
boostCnt: _attrs.motionFrame,
|
|
1032
|
+
// 判定終了フラグ (false: 未判定, true: 判定済)
|
|
1033
|
+
judgEndFlg: false,
|
|
1034
|
+
// 移動中フラグ (false: 押しっぱなしの状態, true: 移動中)
|
|
1035
|
+
isMoving: true,
|
|
1036
|
+
// フリーズアローの長さ
|
|
1037
|
+
frzBarLength: firstBarLength,
|
|
1038
|
+
// キーを離していたフレーム数 (基準値超えでNG判定)
|
|
1039
|
+
keyUpFrame: 0,
|
|
1040
|
+
// 個別加速量
|
|
1041
|
+
boostSpd: _attrs.boostSpd,
|
|
1042
|
+
// ステップゾーン位置 (0: デフォルト, 1: リバース)
|
|
1043
|
+
dividePos: dividePos,
|
|
1044
|
+
// スクロール方向 (1: デフォルト, -1: リバース)
|
|
1045
|
+
dir: g_workObj.scrollDir[_j],
|
|
1046
|
+
// 個別加速方向 (1: 順方向加速, -1: 逆方向加速)
|
|
1047
|
+
boostDir: _attrs.boostDir,
|
|
1048
|
+
// 現フレーム時のフリーズアロー本体の位置
|
|
1049
|
+
y: firstPosY,
|
|
1050
|
+
// フリーズアロー(帯)の相対位置
|
|
1051
|
+
barY: C_ARW_WIDTH / 2 - firstBarLength * dividePos,
|
|
1052
|
+
// フリーズアロー(対矢印)の相対位置
|
|
1053
|
+
btmY: firstBarLength * g_workObj.scrollDir[_j],
|
|
1054
|
+
// 移動ロックフラグ(矢印モーション設定後に再設定)
|
|
1055
|
+
movLockFlg: false,
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
// フリーズアロー色の設定
|
|
1059
|
+
// - 通常時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Normal / NormalShadow / NormalBar
|
|
1060
|
+
// - ヒット時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Hit / HitShadow / HitBar
|
|
1061
|
+
// - ヒット時(矢印枠/矢印塗りつぶし/帯別の生成時全体色): g_attrObj[frzName].HitAll / HitShadowAll / HitBarAll
|
|
1062
|
+
g_typeLists.frzColor.forEach(val => {
|
|
1063
|
+
g_attrObj[frzName][val] = g_workObj[`${_name}${val}Colors`][_j];
|
|
1064
|
+
if (val.startsWith(`Hit`)) {
|
|
1065
|
+
g_attrObj[frzName][`${val}All`] = g_workObj[`${_name}${val}ColorsAll`][_j];
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
// g_attrObj定義後のカスタムイベント
|
|
1070
|
+
safeExecuteCustomHooks(`g_customJsObj.preMakeFrzArrow`, g_customJsObj.preMakeFrzArrow, _attrs, frzName, _name, _arrowCnt);
|
|
1071
|
+
|
|
1072
|
+
arrowSprite[g_workObj.dividePos[_j]].appendChild(frzRoot);
|
|
1073
|
+
let shadowColor = _shadowColor === `Default` ? _normalColor : _shadowColor;
|
|
1074
|
+
const frzSubRoot = createEmptySprite(frzRoot, `sub${frzName}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH + firstBarLength });
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* フリーズアローオブジェクトの生成
|
|
1078
|
+
* - 後で生成されたものが手前に表示されるため、以下の順で作成
|
|
1079
|
+
*/
|
|
1080
|
+
multiAppend(frzSubRoot,
|
|
1081
|
+
|
|
1082
|
+
// フリーズアロー帯(frzBar)
|
|
1083
|
+
createColorObject2(`${_name}Bar${frzNo}`, {
|
|
1084
|
+
x: 5, y: g_attrObj[frzName].barY, w: C_ARW_WIDTH - 10, h: firstBarLength, background: _barColor, styleName: `frzBar`,
|
|
1085
|
+
opacity: 0.75,
|
|
1086
|
+
}),
|
|
1087
|
+
);
|
|
1088
|
+
const frzTopRoot = createEmptySprite(frzSubRoot, `${_name}TopRoot${frzNo}`,
|
|
1089
|
+
{ x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
|
|
1090
|
+
const frzBtmRoot = createEmptySprite(frzSubRoot, `${_name}BtmRoot${frzNo}`,
|
|
1091
|
+
{ x: 0, y: g_attrObj[frzName].btmY, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
|
|
1092
|
+
|
|
1093
|
+
multiAppend(frzTopRoot,
|
|
1094
|
+
|
|
1095
|
+
// 開始矢印の塗り部分。ヒット時は前面に表示
|
|
1096
|
+
createColorObject2(`${_name}TopShadow${frzNo}`, {
|
|
1097
|
+
background: shadowColor, rotate: g_workObj.frzArrowInitRtn[_j], styleName: `Shadow`,
|
|
1098
|
+
}, g_cssObj.main_objShadow),
|
|
1099
|
+
|
|
1100
|
+
// 開始矢印。ヒット時は非表示
|
|
1101
|
+
createColorObject2(`${_name}Top${frzNo}`, {
|
|
1102
|
+
background: _normalColor, rotate: g_workObj.frzArrowInitRtn[_j],
|
|
1103
|
+
}),
|
|
1104
|
+
);
|
|
1105
|
+
|
|
1106
|
+
multiAppend(frzBtmRoot,
|
|
1107
|
+
|
|
1108
|
+
// 後発矢印の塗り部分
|
|
1109
|
+
createColorObject2(`${_name}BtmShadow${frzNo}`, {
|
|
1110
|
+
background: shadowColor, rotate: g_workObj.frzArrowInitRtn[_j], styleName: `Shadow`,
|
|
1111
|
+
}, g_cssObj.main_objShadow),
|
|
1112
|
+
|
|
1113
|
+
// 後発矢印
|
|
1114
|
+
createColorObject2(`${_name}Btm${frzNo}`, {
|
|
1115
|
+
background: _normalColor, rotate: g_workObj.frzArrowInitRtn[_j],
|
|
1116
|
+
}),
|
|
1117
|
+
|
|
1118
|
+
);
|
|
1119
|
+
if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
|
|
1120
|
+
frzSubRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
|
|
1121
|
+
frzSubRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
|
|
1122
|
+
}
|
|
1123
|
+
if (g_workObj[`${_name}ArrowCssMotions`][_j] !== ``) {
|
|
1124
|
+
[frzTopRoot, frzBtmRoot].forEach(obj => {
|
|
1125
|
+
obj.classList.add(g_workObj[`${_name}ArrowCssMotions`][_j]);
|
|
1126
|
+
obj.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
g_attrObj[frzName].movLockFlg = g_workObj[`${_name}MovLock`][_j] || g_workObj.movLockEnabled;
|
|
1130
|
+
const initManualFlg = g_workObj[`${_name}InitManual`][_j] || g_workObj.initManualEnabled;
|
|
1131
|
+
const setArrowYCondition = `${String(g_attrObj[frzName].movLockFlg)}_${String(initManualFlg)}`;
|
|
1132
|
+
setArrowY.get(setArrowYCondition)(frzName, firstPosY, stepY);
|
|
1133
|
+
if (!initManualFlg) {
|
|
1134
|
+
addTransform(frzName, `rootX`, `translateX(${wUnit(g_workObj.stepX[_j])})`);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
safeExecuteCustomHooks(`g_customJsObj.makeFrzArrow`, g_customJsObj.makeFrzArrow, _attrs, frzName, _name, _arrowCnt);
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* フリーズアロー処理メイン
|
|
1142
|
+
* @param {number} _j
|
|
1143
|
+
* @param {number} _k
|
|
1144
|
+
* @param {string} _name
|
|
1145
|
+
*/
|
|
1146
|
+
const movFrzArrow = (_j, _k, _name) => {
|
|
1147
|
+
const frzNo = `${_j}_${_k}`;
|
|
1148
|
+
const frzName = `${_name}${frzNo}`;
|
|
1149
|
+
const currentFrz = g_attrObj[frzName];
|
|
1150
|
+
const movY = g_workObj.currentSpeed * currentFrz.boostSpd * currentFrz.dir;
|
|
1151
|
+
|
|
1152
|
+
if (!currentFrz.judgEndFlg) {
|
|
1153
|
+
if (currentFrz.isMoving) {
|
|
1154
|
+
|
|
1155
|
+
// 全体色変化 (通常時)
|
|
1156
|
+
changeColorFunc[_name](_j, _k, `Normal`);
|
|
1157
|
+
|
|
1158
|
+
// 移動
|
|
1159
|
+
if (g_workObj.currentSpeed !== 0) {
|
|
1160
|
+
currentFrz.prevY = currentFrz.y;
|
|
1161
|
+
currentFrz.y -= movY + (g_workObj.motionOnFrames[currentFrz.boostCnt] || 0) * currentFrz.dir * currentFrz.boostDir;
|
|
1162
|
+
movArrowY.get(currentFrz.movLockFlg)(frzName, currentFrz.y);
|
|
1163
|
+
g_motionAlphaFunc.get(g_stateObj.motion)(frzName, currentFrz);
|
|
1164
|
+
currentFrz.boostCnt--;
|
|
1165
|
+
}
|
|
1166
|
+
currentFrz.cnt--;
|
|
1167
|
+
|
|
1168
|
+
// 次フリーズアローへ判定を移すかチェック
|
|
1169
|
+
judgeNextFunc[`${_name}${g_stateObj.autoAll}`](_j, _k, currentFrz.cnt);
|
|
1170
|
+
|
|
1171
|
+
} else {
|
|
1172
|
+
|
|
1173
|
+
// 全体色変化 (ヒット時)
|
|
1174
|
+
changeColorFunc[_name](_j, _k, `Hit`);
|
|
1175
|
+
|
|
1176
|
+
// フリーズアローがヒット中の処理
|
|
1177
|
+
if (currentFrz.frzBarLength > 0) {
|
|
1178
|
+
|
|
1179
|
+
currentFrz.frzBarLength -= movY * currentFrz.dir;
|
|
1180
|
+
currentFrz.barY -= movY * currentFrz.dividePos;
|
|
1181
|
+
currentFrz.btmY -= movY;
|
|
1182
|
+
|
|
1183
|
+
$id(`${_name}Bar${frzNo}`).height = wUnit(currentFrz.frzBarLength);
|
|
1184
|
+
$id(`${_name}Bar${frzNo}`).top = wUnit(currentFrz.barY);
|
|
1185
|
+
$id(`${_name}BtmRoot${frzNo}`).top = wUnit(currentFrz.btmY);
|
|
1186
|
+
|
|
1187
|
+
if (!checkKeyUpFunc[`${_name}${g_stateObj.autoAll}`](_j)) {
|
|
1188
|
+
currentFrz.keyUpFrame++;
|
|
1189
|
+
judgeMotionFunc[`${_name}KeyUp`](_j, _k, frzName, currentFrz.cnt);
|
|
1190
|
+
}
|
|
1191
|
+
} else {
|
|
1192
|
+
judgeMotionFunc[`${_name}OK`](_j, _k, frzName, currentFrz.cnt);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
// フリーズアローが枠外に出たときの処理
|
|
1196
|
+
judgeMotionFunc[`${_name}NG`](_j, _k, frzName, currentFrz.cnt);
|
|
1197
|
+
|
|
1198
|
+
} else {
|
|
1199
|
+
currentFrz.frzBarLength -= movY * currentFrz.dir;
|
|
1200
|
+
if (currentFrz.frzBarLength > 0) {
|
|
1201
|
+
currentFrz.y -= movY;
|
|
1202
|
+
movArrowY.get(currentFrz.movLockFlg)(frzName, currentFrz.y);
|
|
1203
|
+
} else {
|
|
1204
|
+
judgeObjDelete[_name](_j, frzName);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* フレーム処理(譜面台)
|
|
1211
|
+
*/
|
|
1212
|
+
const flowTimeline = () => {
|
|
1213
|
+
|
|
1214
|
+
const currentFrame = g_scoreObj.frameNum;
|
|
1215
|
+
lblframe.textContent = g_scoreObj.baseFrame;
|
|
1216
|
+
|
|
1217
|
+
// キーの押下状態を取得
|
|
1218
|
+
for (let j = 0; j < keyNum; j++) {
|
|
1219
|
+
for (let m = 0; m < g_workObj.keyCtrlN[j].length; m++) {
|
|
1220
|
+
g_workObj.keyHitFlg[j][m] = keyIsDown(g_workObj.keyCtrlN[j][m]);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
if (currentFrame === musicStartFrame) {
|
|
1225
|
+
musicStartFlg = true;
|
|
1226
|
+
|
|
1227
|
+
// ローカルかつBase64エンコード無し(WebAudioAPI使用不可)のときは従来通り再生
|
|
1228
|
+
if (!(g_audio instanceof AudioPlayer)) {
|
|
1229
|
+
musicStartTime = performance.now();
|
|
1230
|
+
g_audio.play();
|
|
1231
|
+
g_audio.dispatchEvent(new CustomEvent(`timeupdate`));
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// 背景・マスクモーション、スキン変更
|
|
1236
|
+
g_animationData.filter(sprite => g_scoreObj[`${sprite}Data`][currentFrame] !== undefined)
|
|
1237
|
+
.forEach(sprite => g_animationFunc.drawMain[sprite](currentFrame, sprite));
|
|
1238
|
+
|
|
1239
|
+
// フェードイン・アウト
|
|
1240
|
+
const isFadeOutArea = currentFrame >= g_scoreObj.fadeOutFrame && currentFrame < g_scoreObj.fadeOutFrame + g_scoreObj.fadeOutTerm;
|
|
1241
|
+
if (g_audio.volume >= g_stateObj.volume / 100) {
|
|
1242
|
+
musicStartFlg = false;
|
|
1243
|
+
}
|
|
1244
|
+
if (musicStartFlg) {
|
|
1245
|
+
g_audio.volume = Math.min((g_audio.volume + (3 * g_stateObj.volume / 100) / 1000), 1);
|
|
1246
|
+
} else if (isFadeOutArea) {
|
|
1247
|
+
g_audio.volume = Math.max((g_audio.volume - (3 * g_stateObj.volume / 100 * C_FRM_AFTERFADE / g_scoreObj.fadeOutTerm) / 1000), 0);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// 画面揺れの設定
|
|
1251
|
+
if (g_scoreObj.baseFrame % 2 === 0) {
|
|
1252
|
+
g_shakingFunc.get(g_stateObj.shaking)();
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// ユーザカスタムイベント(フレーム毎)
|
|
1256
|
+
safeExecuteCustomHooks(`g_customJsObj.mainEnterFrame`, g_customJsObj.mainEnterFrame);
|
|
1257
|
+
|
|
1258
|
+
// 速度変化 (途中変速, 個別加速)
|
|
1259
|
+
while (currentFrame >= g_workObj.speedData?.[speedCnts]) {
|
|
1260
|
+
g_workObj.currentSpeed = g_workObj.speedData[speedCnts + 1];
|
|
1261
|
+
speedCnts += 2;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
objList.forEach(header => {
|
|
1265
|
+
const headerU = toCapitalize(header);
|
|
1266
|
+
|
|
1267
|
+
// 個別・全体色変化 (矢印)
|
|
1268
|
+
g_typeLists.arrowColor.forEach(ctype =>
|
|
1269
|
+
changeColors(g_workObj[`mk${headerU}Color${ctype}`]?.[currentFrame],
|
|
1270
|
+
g_workObj[`mk${headerU}Color${ctype}Cd`]?.[currentFrame], header, `arrow${ctype}`));
|
|
1271
|
+
|
|
1272
|
+
// 個別・全体色変化(フリーズアロー)
|
|
1273
|
+
g_typeLists.frzColor.forEach(ctype =>
|
|
1274
|
+
changeColors(g_workObj[`mk${headerU}FColor${ctype}`]?.[currentFrame],
|
|
1275
|
+
g_workObj[`mk${headerU}FColor${ctype}Cd`]?.[currentFrame], header, `frz${ctype}`));
|
|
1276
|
+
|
|
1277
|
+
// 矢印モーション
|
|
1278
|
+
changeCssMotions(header, `arrow`, currentFrame);
|
|
1279
|
+
|
|
1280
|
+
// フリーズアローモーション
|
|
1281
|
+
changeCssMotions(header, `frz`, currentFrame);
|
|
1282
|
+
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
// キー変化
|
|
1286
|
+
while (currentFrame >= g_scoreObj.keychFrames[keychCnts]) {
|
|
1287
|
+
for (let j = 0; j < keyNum; j++) {
|
|
1288
|
+
appearKeyTypes(j, g_scoreObj.keychTarget[keychCnts], g_scoreObj.keychTargetAlpha[keychCnts]);
|
|
1289
|
+
}
|
|
1290
|
+
keychCnts++;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// スクロール変化
|
|
1294
|
+
changeScrollArrowDirs(currentFrame);
|
|
1295
|
+
changeStepY(currentFrame);
|
|
1296
|
+
|
|
1297
|
+
// ダミー矢印生成(背面に表示するため先に処理)
|
|
1298
|
+
g_workObj.mkDummyArrow?.[currentFrame]?.forEach(data =>
|
|
1299
|
+
makeArrow(data, ++dummyArrowCnts[data.pos], `dummyArrow`, g_workObj.dummyArrowColors[data.pos], g_workObj.dummyArrowShadowColors[data.pos]));
|
|
1300
|
+
|
|
1301
|
+
// 矢印生成
|
|
1302
|
+
g_workObj.mkArrow[currentFrame]?.forEach(data =>
|
|
1303
|
+
makeArrow(data, ++arrowCnts[data.pos], `arrow`, g_workObj.arrowColors[data.pos], g_workObj.arrowShadowColors[data.pos]));
|
|
1304
|
+
|
|
1305
|
+
// ダミーフリーズアロー生成
|
|
1306
|
+
g_workObj.mkDummyFrzArrow?.[currentFrame]?.forEach(data =>
|
|
1307
|
+
makeFrzArrow(data, ++dummyFrzCnts[data.pos], `dummyFrz`, g_workObj.dummyFrzNormalColors[data.pos],
|
|
1308
|
+
g_workObj.dummyFrzNormalBarColors[data.pos], g_workObj.dummyFrzNormalShadowColors[data.pos]));
|
|
1309
|
+
|
|
1310
|
+
// フリーズアロー生成
|
|
1311
|
+
g_workObj.mkFrzArrow[currentFrame]?.forEach(data =>
|
|
1312
|
+
makeFrzArrow(data, ++frzCnts[data.pos], `frz`, g_workObj.frzNormalColors[data.pos],
|
|
1313
|
+
g_workObj.frzNormalBarColors[data.pos], g_workObj.frzNormalShadowColors[data.pos]));
|
|
1314
|
+
|
|
1315
|
+
// 矢印・フリーズアロー移動&消去
|
|
1316
|
+
for (let j = 0; j < keyNum; j++) {
|
|
1317
|
+
const stepDivHit = document.getElementById(`stepHit${j}`);
|
|
1318
|
+
|
|
1319
|
+
// ダミー矢印
|
|
1320
|
+
for (let k = g_workObj.judgDummyArrowCnt[j]; k <= dummyArrowCnts[j]; k++) {
|
|
1321
|
+
movArrow(j, k, `dummyArrow`);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// 通常矢印
|
|
1325
|
+
for (let k = g_workObj.judgArrowCnt[j]; k <= arrowCnts[j]; k++) {
|
|
1326
|
+
movArrow(j, k, `arrow`);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// ダミーフリーズアロー移動
|
|
1330
|
+
for (let k = g_workObj.judgDummyFrzCnt[j]; k <= dummyFrzCnts[j]; k++) {
|
|
1331
|
+
movFrzArrow(j, k, `dummyFrz`);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// フリーズアロー移動
|
|
1335
|
+
for (let k = g_workObj.judgFrzCnt[j]; k <= frzCnts[j]; k++) {
|
|
1336
|
+
movFrzArrow(j, k, `frz`);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// ステップゾーンのヒット領域は一定時間で非表示化
|
|
1340
|
+
let hitCnt = stepDivHit.getAttribute(`cnt`);
|
|
1341
|
+
if (hitCnt > 0) {
|
|
1342
|
+
stepDivHit.setAttribute(`cnt`, --hitCnt);
|
|
1343
|
+
if (hitCnt === 0) {
|
|
1344
|
+
stepDivHit.style.opacity = 0;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// 歌詞表示
|
|
1350
|
+
g_scoreObj.wordData[currentFrame]?.forEach(tmpObj => {
|
|
1351
|
+
g_wordObj.wordDir = tmpObj[0];
|
|
1352
|
+
g_wordObj.wordDat = tmpObj[1];
|
|
1353
|
+
g_wordSprite = document.getElementById(`lblword${g_wordObj.wordDir}`);
|
|
1354
|
+
|
|
1355
|
+
const wordDepth = Number(g_wordObj.wordDir);
|
|
1356
|
+
if (g_wordObj.wordDat.substring(0, 5) === `[fade`) {
|
|
1357
|
+
|
|
1358
|
+
// フェードイン・アウト開始
|
|
1359
|
+
const fkey = fadeFlgs[Object.keys(fadeFlgs).find(flg => g_wordObj.wordDat === `[${flg}]`)];
|
|
1360
|
+
g_wordObj[`fade${fkey[0]}Flg${wordDepth}`] = true;
|
|
1361
|
+
g_wordObj[`fade${fkey[1]}Flg${wordDepth}`] = false;
|
|
1362
|
+
g_wordSprite.style.animationName =
|
|
1363
|
+
`fade${fkey[0]}${(++g_workObj[`fade${fkey[0]}No`][wordDepth] % 2)}`;
|
|
1364
|
+
|
|
1365
|
+
g_workObj.lastFadeFrame[wordDepth] = currentFrame;
|
|
1366
|
+
g_workObj.wordFadeFrame[wordDepth] = (tmpObj.length > 2 ?
|
|
1367
|
+
setIntVal(tmpObj[2], C_WOD_FRAME) : C_WOD_FRAME);
|
|
1368
|
+
|
|
1369
|
+
g_wordSprite.style.animationDuration = `${g_workObj.wordFadeFrame[wordDepth] / g_fps}s`;
|
|
1370
|
+
g_wordSprite.style.animationTimingFunction = `linear`;
|
|
1371
|
+
g_wordSprite.style.animationFillMode = `forwards`;
|
|
1372
|
+
|
|
1373
|
+
} else if ([`[center]`, `[left]`, `[right]`].includes(g_wordObj.wordDat)) {
|
|
1374
|
+
|
|
1375
|
+
// 歌詞位置変更
|
|
1376
|
+
g_wordSprite.style.textAlign = g_wordObj.wordDat.slice(1, -1);
|
|
1377
|
+
|
|
1378
|
+
} else if (/\[fontSize=\d+\]/.test(g_wordObj.wordDat)) {
|
|
1379
|
+
|
|
1380
|
+
// フォントサイズ変更
|
|
1381
|
+
const fontSize = setIntVal(g_wordObj.wordDat.match(/\d+/)[0], g_limitObj.mainSiz);
|
|
1382
|
+
g_wordSprite.style.fontSize = wUnit(fontSize);
|
|
1383
|
+
|
|
1384
|
+
} else {
|
|
1385
|
+
|
|
1386
|
+
// フェードイン・アウト処理後、表示する歌詞を表示
|
|
1387
|
+
const fadingFlg = currentFrame - g_workObj.lastFadeFrame[wordDepth] >= g_workObj.wordFadeFrame[wordDepth];
|
|
1388
|
+
[`Out`, `In`].filter(pattern => g_wordObj[`fade${pattern}Flg${g_wordObj.wordDir}`] && fadingFlg).forEach(pattern => {
|
|
1389
|
+
g_wordSprite.style.animationName = `none`;
|
|
1390
|
+
g_wordObj[`fade${pattern}Flg${g_wordObj.wordDir}`] = false;
|
|
1391
|
+
});
|
|
1392
|
+
g_workObj[`word${g_wordObj.wordDir}Data`] = g_wordObj.wordDat;
|
|
1393
|
+
g_wordSprite.innerHTML = g_wordObj.wordDat;
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
// 判定キャラクタ消去
|
|
1398
|
+
jdgGroups.forEach(jdg => {
|
|
1399
|
+
let charaJCnt = document.getElementById(`chara${jdg}`).getAttribute(`cnt`);
|
|
1400
|
+
if (charaJCnt > 0) {
|
|
1401
|
+
document.getElementById(`chara${jdg}`).setAttribute(`cnt`, --charaJCnt);
|
|
1402
|
+
if (charaJCnt === 0) {
|
|
1403
|
+
document.getElementById(`chara${jdg}`).textContent = ``;
|
|
1404
|
+
document.getElementById(`combo${jdg}`).textContent = ``;
|
|
1405
|
+
document.getElementById(`diff${jdg}`).textContent = ``;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
// ユーザカスタムイベント(フレーム毎、タイマー直前)
|
|
1411
|
+
safeExecuteCustomHooks(`g_customJsObj.mainBeforeFrameTimer`, g_customJsObj.mainBeforeFrameTimer, {
|
|
1412
|
+
arrowCnts, frzCnts, dummyArrowCnts, dummyFrzCnts,
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
// 曲終了判定
|
|
1416
|
+
if (currentFrame >= fullFrame) {
|
|
1417
|
+
if (g_stateObj.lifeMode === C_LFE_BORDER && g_workObj.lifeVal < g_workObj.lifeBorder) {
|
|
1418
|
+
g_gameOverFlg = true;
|
|
1419
|
+
}
|
|
1420
|
+
resetKeyControl();
|
|
1421
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
1422
|
+
g_workObj.mainEndTime = thisTime;
|
|
1423
|
+
resultInit();
|
|
1424
|
+
|
|
1425
|
+
} else if (g_workObj.lifeVal === 0 && g_workObj.lifeBorder === 0) {
|
|
1426
|
+
|
|
1427
|
+
// ライフ制&ライフ0の場合は途中終了
|
|
1428
|
+
g_audio.pause();
|
|
1429
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
1430
|
+
g_gameOverFlg = true;
|
|
1431
|
+
g_finishFlg = false;
|
|
1432
|
+
resultInit();
|
|
1433
|
+
|
|
1434
|
+
} else {
|
|
1435
|
+
|
|
1436
|
+
// タイマー
|
|
1437
|
+
if (Math.floor(g_scoreObj.baseFrame % g_fps) === 0) {
|
|
1438
|
+
if (g_scoreObj.baseFrame >= 0) {
|
|
1439
|
+
lblTime1.textContent = transFrameToTimer(g_scoreObj.baseFrame);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// 60fpsから遅延するため、その差分を取って次回のタイミングで遅れをリカバリする
|
|
1444
|
+
// - WebAudioAPI使用時は音源クロック(AudioContext.currentTime)を基準とする
|
|
1445
|
+
// performance.now()とAudioContextの時計は独立して進むため、後者を基準にしないと
|
|
1446
|
+
// 再生開始時のオフセットずれやsuspend/resumeによるずれを吸収できない
|
|
1447
|
+
thisTime = performance.now();
|
|
1448
|
+
buffTime = 0;
|
|
1449
|
+
let holdFrame = false;
|
|
1450
|
+
|
|
1451
|
+
if (g_audio instanceof AudioPlayer && g_audioClockSync && musicStartCtxTime !== undefined) {
|
|
1452
|
+
if (g_audio.contextState === `running`) {
|
|
1453
|
+
buffTime = (g_audio.contextTime - musicStartCtxTime) * 1000
|
|
1454
|
+
- (currentFrame - musicStartFrame) * 1000 / g_fps;
|
|
1455
|
+
} else {
|
|
1456
|
+
// AudioContext停止中は音源も止まっているため、フレーム進行も止めて復帰を待つ
|
|
1457
|
+
getSharedAudioContext(); // suspended時はresumeを試行
|
|
1458
|
+
holdFrame = true;
|
|
1459
|
+
}
|
|
1460
|
+
} else if (g_audio instanceof AudioPlayer || currentFrame >= musicStartFrame) {
|
|
1461
|
+
buffTime = (thisTime - musicStartTime - (currentFrame - musicStartFrame) * 1000 / g_fps);
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
if (!holdFrame) {
|
|
1465
|
+
g_scoreObj.frameNum++;
|
|
1466
|
+
g_scoreObj.baseFrame++;
|
|
1467
|
+
}
|
|
1468
|
+
g_timeoutEvtId = g_timerHandler.setTimeout(flowTimeline, holdFrame ? g_maxFrameWait :
|
|
1469
|
+
Math.min(Math.max(1000 / g_fps - buffTime, 0), g_maxFrameWait));
|
|
1470
|
+
}
|
|
1471
|
+
};
|
|
1472
|
+
|
|
1473
|
+
/*
|
|
1474
|
+
* タブのバックグラウンド化に伴う一時停止/再開
|
|
1475
|
+
* - 【既知の制限】movLock/initManual設定(movArrowYがCSS animation任せになるケース)では、
|
|
1476
|
+
* 矢印移動そのものがCSS animation駆動になるため、この一時停止機能はバックグラウンド中の
|
|
1477
|
+
* 一時停止を保証できない(演出効果と異なり判定位置に直結するため実プレイには不適)。
|
|
1478
|
+
* 対処は行わず、既知の制限として明記するに留める。
|
|
1479
|
+
*/
|
|
1480
|
+
const cancelResumeCountdown = () => {
|
|
1481
|
+
if (countdownTimeoutId !== null) {
|
|
1482
|
+
g_timerHandler.clearTimeout(countdownTimeoutId);
|
|
1483
|
+
countdownTimeoutId = null;
|
|
1484
|
+
}
|
|
1485
|
+
document.getElementById(`lblResumeCountdown`)?.remove();
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
let nativeAudioWasPlaying = false;
|
|
1489
|
+
|
|
1490
|
+
const pauseTimeline = (_manual = false) => {
|
|
1491
|
+
// カウントダウン中に再度バックグラウンド化した場合は、カウントダウンのみ中断する
|
|
1492
|
+
// (音源は既に停止済み・gamePausedも付与済みのため、以降の処理は不要)
|
|
1493
|
+
cancelResumeCountdown();
|
|
1494
|
+
if (isPaused) {
|
|
1495
|
+
if (_manual) {
|
|
1496
|
+
// カウントダウン中に手動ポーズキーが押された場合、手動扱いに切り替える
|
|
1497
|
+
manualPauseFlg = true;
|
|
1498
|
+
}
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
isPaused = true;
|
|
1502
|
+
manualPauseFlg = _manual;
|
|
1503
|
+
pausedElapsedTime = null;
|
|
1504
|
+
pausedStartAdjustment = null;
|
|
1505
|
+
if (document.getElementById(`lblPauseMark`) == null) {
|
|
1506
|
+
const countdownLabel = createDivCss2Label(`lblPauseMark`, `Pause`, {
|
|
1507
|
+
...g_lblPosObj.lblPauseMark, x: g_workObj.playingX,
|
|
1508
|
+
});
|
|
1509
|
+
divRoot.appendChild(countdownLabel);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
if (g_audio instanceof AudioPlayer) {
|
|
1513
|
+
if (g_audio.contextTime < g_audio.scheduledTime) {
|
|
1514
|
+
// 音源開始前は、再生位置ではなく開始予定時刻までの残り時間を保持する。
|
|
1515
|
+
// g_audio.play() は g_scheduleLead を加算するため、その分を除く。
|
|
1516
|
+
pausedStartAdjustment = g_audio.scheduledTime
|
|
1517
|
+
- g_audio.contextTime - g_scheduleLead;
|
|
1518
|
+
} else {
|
|
1519
|
+
// 音源開始後: 再生位置を保存する。
|
|
1520
|
+
pausedElapsedTime = g_audio.elapsedTime - g_scheduleLead;
|
|
1521
|
+
}
|
|
1522
|
+
} else {
|
|
1523
|
+
// `paused` が false の場合だけ、再開時に play() を呼ぶ
|
|
1524
|
+
nativeAudioWasPlaying = !g_audio.paused;
|
|
1525
|
+
}
|
|
1526
|
+
if (g_workObj.frzReturnTimerId) {
|
|
1527
|
+
// FrzReturn演出はflowTimelineと独立したタイマーで動いているため、
|
|
1528
|
+
// 一時停止時点で早期終了させる(位置復元はせず、通常終了時と同じ後片付けを行う)
|
|
1529
|
+
resetFrzReturn();
|
|
1530
|
+
}
|
|
1531
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
1532
|
+
g_audio.pause();
|
|
1533
|
+
|
|
1534
|
+
// 自動ポーズ(タブ非表示等)の場合のみ強制的に全キー「離した」状態に戻す
|
|
1535
|
+
if (!_manual) {
|
|
1536
|
+
g_inputKeyBuffer = {};
|
|
1537
|
+
g_workObj.keyHitFlg.forEach(lane => lane.fill(false));
|
|
1538
|
+
mainKeyUpActFunc[g_stateObj.autoAll]();
|
|
1539
|
+
}
|
|
1540
|
+
divRoot.classList.add(`gamePaused`);
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
const resumeTimeline = (_manual = false) => {
|
|
1544
|
+
if (!isPaused || countdownTimeoutId !== null) {
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
if (!_manual && manualPauseFlg) {
|
|
1548
|
+
// 手動ポーズ中は、タブ復帰による自動再開をスキップする
|
|
1549
|
+
if (document.getElementById(`lblPauseMark`) == null) {
|
|
1550
|
+
const countdownLabel = createDivCss2Label(`lblPauseMark`, `Pause`, {
|
|
1551
|
+
...g_lblPosObj.lblPauseMark, x: g_workObj.playingX,
|
|
1552
|
+
});
|
|
1553
|
+
divRoot.appendChild(countdownLabel);
|
|
1554
|
+
}
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
deleteDiv(divRoot, `lblPauseMark`);
|
|
1558
|
+
const countdownLabel = createDivCss2Label(`lblResumeCountdown`, ``, {
|
|
1559
|
+
...g_lblPosObj.lblPauseMark, x: g_workObj.playingX,
|
|
1560
|
+
});
|
|
1561
|
+
divRoot.appendChild(countdownLabel);
|
|
1562
|
+
|
|
1563
|
+
const finishResume = () => {
|
|
1564
|
+
countdownTimeoutId = null;
|
|
1565
|
+
countdownLabel.remove();
|
|
1566
|
+
|
|
1567
|
+
// カウントダウン中に曲中リトライ等でmainInit()が再実行されたりプレイ画面外に移動した場合、
|
|
1568
|
+
// 古いセッションのfinishResumeが後から発火して二重再生・二重ループを起こすのを防ぐ
|
|
1569
|
+
if (mySessionId !== g_timelineSessionId || g_currentPage !== `main`) {
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
if (g_audio instanceof AudioPlayer) {
|
|
1574
|
+
// バックグラウンド中にsuspendされていた場合に備え、先に明示的にresumeを試みる
|
|
1575
|
+
getSharedAudioContext();
|
|
1576
|
+
|
|
1577
|
+
if (pausedStartAdjustment !== null) {
|
|
1578
|
+
// 開始前: 音源と譜面の残り開始時間を両方維持する。
|
|
1579
|
+
g_audio.play(pausedStartAdjustment);
|
|
1580
|
+
musicStartCtxTime = g_audio.scheduledTime
|
|
1581
|
+
+ (g_audioLatencyCompensation ? g_audio.outputLatency : 0);
|
|
1582
|
+
// musicStartFrame は変更しない。
|
|
1583
|
+
} else {
|
|
1584
|
+
// 開始後: 再生位置から再開し、現在フレームを基準に再アンカーする。
|
|
1585
|
+
g_audio.currentTime = pausedElapsedTime;
|
|
1586
|
+
g_audio.play();
|
|
1587
|
+
musicStartCtxTime = g_audio.scheduledTime
|
|
1588
|
+
+ (g_audioLatencyCompensation ? g_audio.outputLatency : 0);
|
|
1589
|
+
musicStartFrame = g_scoreObj.frameNum;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
} else {
|
|
1593
|
+
if (nativeAudioWasPlaying) {
|
|
1594
|
+
g_audio.play();
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
// バックグラウンド経過時間をフレーム計算から除外する
|
|
1598
|
+
musicStartTime = performance.now() - (g_scoreObj.frameNum - musicStartFrame) * 1000 / g_fps;
|
|
1599
|
+
|
|
1600
|
+
divRoot.classList.remove(`gamePaused`);
|
|
1601
|
+
isPaused = false;
|
|
1602
|
+
manualPauseFlg = false;
|
|
1603
|
+
pausedElapsedTime = null;
|
|
1604
|
+
pausedStartAdjustment = null;
|
|
1605
|
+
g_timeoutEvtId = g_timerHandler.setTimeout(flowTimeline, 1000 / g_fps);
|
|
1606
|
+
};
|
|
1607
|
+
|
|
1608
|
+
const tick = _remaining => {
|
|
1609
|
+
if (_remaining <= 0) {
|
|
1610
|
+
finishResume();
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
countdownLabel.innerHTML = String(_remaining);
|
|
1614
|
+
countdownTimeoutId = g_timerHandler.setTimeout(() => tick(_remaining - 1), 1000);
|
|
1615
|
+
};
|
|
1616
|
+
tick(3);
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
g_timelineHooks.pause = pauseTimeline;
|
|
1620
|
+
g_timelineHooks.resume = resumeTimeline;
|
|
1621
|
+
safeExecuteCustomHooks(`g_skinJsObj.main`, g_skinJsObj.main);
|
|
1622
|
+
|
|
1623
|
+
g_audio.currentTime = firstFrame / g_fps * g_headerObj.playbackRate;
|
|
1624
|
+
g_audio.playbackRate = g_headerObj.playbackRate;
|
|
1625
|
+
|
|
1626
|
+
// WebAudioAPIが使用できる場合は小数フレーム分だけ音源位置を調整
|
|
1627
|
+
if (g_audio instanceof AudioPlayer) {
|
|
1628
|
+
const musicStartAdjustment = (g_headerObj.blankFrame - g_stateObj.decimalAdjustment + 1) / g_fps;
|
|
1629
|
+
musicStartTime = performance.now() + (musicStartAdjustment + g_scheduleLead) * 1000;
|
|
1630
|
+
g_audio.play(musicStartAdjustment);
|
|
1631
|
+
|
|
1632
|
+
// 音源クロック基準の開始時刻(フレーム進行の基準)
|
|
1633
|
+
// - g_audioLatencyCompensationが有効な場合は出力遅延分だけ表示を後ろへずらす
|
|
1634
|
+
musicStartCtxTime = g_audio.scheduledTime
|
|
1635
|
+
+ (g_audioLatencyCompensation ? g_audio.outputLatency : 0);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
if (document.hidden) {
|
|
1639
|
+
pauseTimeline();
|
|
1640
|
+
} else {
|
|
1641
|
+
g_timeoutEvtId = g_timerHandler.setTimeout(flowTimeline, 1000 / g_fps);
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
/**
|
|
1646
|
+
* 矢印・フリーズアローの初期位置
|
|
1647
|
+
* - true_true: スクロールなし/初期位置マニュアル
|
|
1648
|
+
* - true_false: スクロールなし/初期位置自動
|
|
1649
|
+
* - false_true: スクロールあり/初期位置マニュアル
|
|
1650
|
+
* - false_false: スクロールあり/初期位置自動
|
|
1651
|
+
*/
|
|
1652
|
+
const setArrowY = new Map([
|
|
1653
|
+
[`true_true`, (_name, _startY, _stepY) => { }],
|
|
1654
|
+
[`true_false`, (_name, _startY, _stepY) => addTransform(_name, `root`, `translateY(${wUnit(_stepY)})`)],
|
|
1655
|
+
[`false_true`, (_name, _startY, _stepY) => addTransform(_name, `root`, `translateY(${wUnit(_startY)})`)],
|
|
1656
|
+
[`false_false`, (_name, _startY, _stepY) => addTransform(_name, `root`, `translateY(${wUnit(_startY)})`)],
|
|
1657
|
+
]);
|
|
1658
|
+
|
|
1659
|
+
/**
|
|
1660
|
+
* 矢印・フリーズアローの移動処理
|
|
1661
|
+
*/
|
|
1662
|
+
const movArrowY = new Map([
|
|
1663
|
+
[true, (_name, _y) => { }],
|
|
1664
|
+
[false, (_name, _y) => addTransform(_name, `root`, `translateY(${wUnit(_y)})`)],
|
|
1665
|
+
]);
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* ステップゾーン、フリーズアローヒット部分の生成
|
|
1669
|
+
* @param {number} _j
|
|
1670
|
+
* @param {string} _keyCtrlPtn
|
|
1671
|
+
*/
|
|
1672
|
+
const makeStepZone = (_j, _keyCtrlPtn) => {
|
|
1673
|
+
|
|
1674
|
+
const colorPos = g_keyObj[`color${_keyCtrlPtn}`][_j];
|
|
1675
|
+
const stepSpriteJ = document.getElementById(`stepSprite${g_workObj.dividePos[_j]}`);
|
|
1676
|
+
const frzHitSpriteJ = document.getElementById(`frzHitSprite${g_workObj.dividePos[_j]}`);
|
|
1677
|
+
|
|
1678
|
+
// ステップゾーンルート
|
|
1679
|
+
const stepRoot = createEmptySprite(stepSpriteJ, `stepRoot${_j}`, {
|
|
1680
|
+
x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
|
|
1681
|
+
w: C_ARW_WIDTH, h: C_ARW_WIDTH,
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
// 矢印の内側を塗りつぶすか否か
|
|
1685
|
+
if (g_headerObj.setShadowColor[colorPos] !== ``) {
|
|
1686
|
+
stepRoot.appendChild(
|
|
1687
|
+
createColorObject2(`stepShadow${_j}`, {
|
|
1688
|
+
rotate: g_workObj.stepRtn[_j], styleName: `ShadowStep`,
|
|
1689
|
+
opacity: 0.7, display: g_workObj.stepZoneDisp,
|
|
1690
|
+
}, g_cssObj.main_objStepShadow)
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
appearStepZone(_j, C_DIS_NONE);
|
|
1695
|
+
|
|
1696
|
+
// ステップゾーン
|
|
1697
|
+
multiAppend(stepRoot,
|
|
1698
|
+
|
|
1699
|
+
// 本体
|
|
1700
|
+
createColorObject2(`step${_j}`, {
|
|
1701
|
+
rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: g_workObj.stepZoneDisp,
|
|
1702
|
+
}, g_cssObj[`main_step${g_workObj.stepX[_j] === g_workObj.stepX_df[_j] ? 'Default'
|
|
1703
|
+
: g_stateObj.swapping === 'Mirror+' ? 'Shobon' : 'Matari'}`]),
|
|
1704
|
+
|
|
1705
|
+
// 空押し
|
|
1706
|
+
createColorObject2(`stepDiv${_j}`, {
|
|
1707
|
+
rotate: g_workObj.stepRtn[_j], styleName: `Step`, display: C_DIS_NONE,
|
|
1708
|
+
}, g_cssObj.main_stepKeyDown),
|
|
1709
|
+
|
|
1710
|
+
// ヒット時モーション
|
|
1711
|
+
createColorObject2(`stepHit${_j}`, {
|
|
1712
|
+
...g_lblPosObj.stepHit, rotate: g_workObj.stepHitRtn[_j], styleName: `StepHit`, opacity: 0,
|
|
1713
|
+
}, g_cssObj.main_stepDefault),
|
|
1714
|
+
|
|
1715
|
+
);
|
|
1716
|
+
|
|
1717
|
+
// フリーズアローヒット部分
|
|
1718
|
+
const frzHit = createEmptySprite(frzHitSpriteJ, `frzHit${_j}`, {
|
|
1719
|
+
x: g_workObj.stepX[_j], y: C_STEP_Y + g_posObj.reverseStepY * (g_workObj.dividePos[_j] % 2),
|
|
1720
|
+
w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
|
|
1721
|
+
});
|
|
1722
|
+
if (isNaN(parseFloat(g_workObj.arrowRtn[_j]))) {
|
|
1723
|
+
multiAppend(frzHit,
|
|
1724
|
+
createColorObject2(`frzHitShadow${_j}`, {
|
|
1725
|
+
rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
|
|
1726
|
+
}, g_cssObj.main_objShadow),
|
|
1727
|
+
createColorObject2(`frzHitTop${_j}`, {
|
|
1728
|
+
background: g_workObj.frzHitColors[_j], rotate: g_workObj.arrowRtn[_j],
|
|
1729
|
+
})
|
|
1730
|
+
);
|
|
1731
|
+
} else {
|
|
1732
|
+
frzHit.appendChild(
|
|
1733
|
+
createColorObject2(`frzHitTop${_j}`, {
|
|
1734
|
+
...g_lblPosObj.frzHitTop, rotate: g_workObj.arrowRtn[_j], styleName: `Shadow`,
|
|
1735
|
+
}, g_cssObj.main_frzHitTop)
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
/**
|
|
1741
|
+
* フィルターバーが同一層で複数必要かを確認
|
|
1742
|
+
* @returns {boolean}
|
|
1743
|
+
*/
|
|
1744
|
+
const getDoubleFilterFlg = () =>
|
|
1745
|
+
g_settings.stepAreaLayers.includes(g_stateObj.stepArea) ||
|
|
1746
|
+
(g_stateObj.stepArea === `Halfway` && g_stateObj.appearance === `Hid&Sud+`);
|
|
1747
|
+
|
|
1748
|
+
/**
|
|
1749
|
+
* フィルターバーの対象表示変更
|
|
1750
|
+
* @param {number} _num
|
|
1751
|
+
* @param {number} _dirPlus
|
|
1752
|
+
*/
|
|
1753
|
+
const changeAppearanceBar = (_num = 10, _dirPlus = 2) => {
|
|
1754
|
+
if (_dirPlus !== 0) {
|
|
1755
|
+
const step = Math.trunc(_dirPlus / 2) * 2;
|
|
1756
|
+
g_workObj.aprFilterCnt = nextPos(g_workObj.aprFilterCnt, step, g_stateObj.layerNum);
|
|
1757
|
+
}
|
|
1758
|
+
const doubleFilterFlg = changeAppearanceFilter(_num);
|
|
1759
|
+
|
|
1760
|
+
// フィルターバーを使用するオプションのみ以下を適用
|
|
1761
|
+
if (g_appearanceRanges.includes(g_stateObj.appearance) && g_stateObj.d_filterline === C_FLG_ON) {
|
|
1762
|
+
|
|
1763
|
+
// 階層が多い場合はShift+pgUp/pgDownで表示する階層グループを切り替え
|
|
1764
|
+
const topNum = g_hidSudObj[g_stateObj.appearance];
|
|
1765
|
+
const bottomNum = (g_hidSudObj[g_stateObj.appearance] + 1) % 2;
|
|
1766
|
+
|
|
1767
|
+
for (let j = 0; j < g_stateObj.layerNum; j += 2) {
|
|
1768
|
+
[`${topNum + j}`, `${bottomNum + j}`].forEach(type => {
|
|
1769
|
+
const displayState = (j === g_workObj.aprFilterCnt ? C_DIS_INHERIT : C_DIS_NONE);
|
|
1770
|
+
$id(`filterBar${type}`).display = displayState;
|
|
1771
|
+
|
|
1772
|
+
if (doubleFilterFlg) {
|
|
1773
|
+
$id(`filterBar${type}_HS`).display = displayState;
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// フィルターバーの非表示条件
|
|
1779
|
+
const baseLayer = g_workObj.aprFilterCnt;
|
|
1780
|
+
const dividePosPart = g_workObj.dividePos.filter(v => Math.floor(v / 2) === g_workObj.aprFilterCnt / 2);
|
|
1781
|
+
const currentBarNum = g_hidSudObj.std[g_stateObj.appearance][
|
|
1782
|
+
dividePosPart.length > 0
|
|
1783
|
+
? dividePosPart[0] % 2 === 0 ? C_FLG_OFF : C_FLG_ON
|
|
1784
|
+
: g_stateObj.reverse
|
|
1785
|
+
];
|
|
1786
|
+
|
|
1787
|
+
if (dividePosPart.length > 0
|
|
1788
|
+
&& dividePosPart.every(v => v % 2 === dividePosPart[0] % 2)) {
|
|
1789
|
+
if (g_stateObj.appearance !== `Hid&Sud+` || (g_stateObj.appearance === `Hid&Sud+` && g_stateObj.stepArea === `Halfway`)) {
|
|
1790
|
+
// スクロールが1種類の場合、対面のフィルターバーは不要なため非表示にする
|
|
1791
|
+
$id(`filterBar${(currentBarNum + 1) % 2 + baseLayer}`).display = C_DIS_NONE;
|
|
1792
|
+
|
|
1793
|
+
if (g_settings.stepAreaLayers.includes(g_stateObj.stepArea)) {
|
|
1794
|
+
$id(`filterBar${(currentBarNum + 1) % 2 + baseLayer}_HS`).display = C_DIS_NONE;
|
|
1795
|
+
} else if (g_stateObj.appearance === `Hid&Sud+` && g_stateObj.stepArea === `Halfway`) {
|
|
1796
|
+
$id(`filterBar${(currentBarNum) % 2 + baseLayer}_HS`).display = C_DIS_NONE;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
};
|
|
1802
|
+
|
|
1803
|
+
/**
|
|
1804
|
+
* アルファマスクの再描画 (Appearance: Hidden+, Sudden+ 用)
|
|
1805
|
+
* @param {number} _num
|
|
1806
|
+
* @returns {boolean} フィルターバーを複数利用するかどうかのフラグ (changeAppearanceBarで利用)
|
|
1807
|
+
*/
|
|
1808
|
+
const changeAppearanceFilter = (_num = 10) => {
|
|
1809
|
+
const MAX_FILTER_POS = 100;
|
|
1810
|
+
const topNum = g_hidSudObj[g_stateObj.appearance];
|
|
1811
|
+
const bottomNum = (g_hidSudObj[g_stateObj.appearance] + 1) % 2;
|
|
1812
|
+
if (g_stateObj.appearance === `Hid&Sud+` && _num > MAX_FILTER_POS / 2) {
|
|
1813
|
+
_num = MAX_FILTER_POS / 2;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// アルファマスクの位置設定
|
|
1817
|
+
const numPlus = (g_stateObj.appearance === `Hid&Sud+` ? _num : 0);
|
|
1818
|
+
const topShape = `inset(${_num}% 0% ${numPlus}% 0%)`;
|
|
1819
|
+
const bottomShape = `inset(${numPlus}% 0% ${_num}% 0%)`;
|
|
1820
|
+
|
|
1821
|
+
// フィルターバーの位置設定
|
|
1822
|
+
const appearPers = [_num, MAX_FILTER_POS - _num];
|
|
1823
|
+
const topDist = g_posObj.arrowHeight * appearPers[topNum] / MAX_FILTER_POS;
|
|
1824
|
+
const bottomDist = g_posObj.arrowHeight * appearPers[bottomNum] / MAX_FILTER_POS;
|
|
1825
|
+
const doubleFilterFlg = getDoubleFilterFlg();
|
|
1826
|
+
|
|
1827
|
+
for (let j = 0; j < g_stateObj.layerNum; j += 2) {
|
|
1828
|
+
$id(`arrowSprite${topNum + j}`).clipPath = topShape;
|
|
1829
|
+
$id(`arrowSprite${bottomNum + j}`).clipPath = bottomShape;
|
|
1830
|
+
|
|
1831
|
+
addTransform(`filterBar${topNum + j}`, `appearance`, `translateY(${wUnit(parseFloat($id(`arrowSprite${j}`).top) + topDist)})`, g_transPriority.layer);
|
|
1832
|
+
addTransform(`filterBar${bottomNum + j}`, `appearance`, `translateY(${wUnit(parseFloat($id(`arrowSprite${j + 1}`).top) + bottomDist)})`, g_transPriority.layer);
|
|
1833
|
+
|
|
1834
|
+
if (doubleFilterFlg) {
|
|
1835
|
+
addTransform(`filterBar${bottomNum + j}_HS`, `appearance`, `translateY(${wUnit(parseFloat($id(`arrowSprite${j}`).top) + bottomDist)})`, g_transPriority.layer);
|
|
1836
|
+
addTransform(`filterBar${topNum + j}_HS`, `appearance`, `translateY(${wUnit(parseFloat($id(`arrowSprite${j + 1}`).top) + topDist)})`, g_transPriority.layer);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// フィルターバーのパーセント表示(フィルターバーが複数表示されるなど複雑なため、最初の階層グループの位置に追従)
|
|
1841
|
+
if (g_appearanceRanges.includes(g_stateObj.appearance)) {
|
|
1842
|
+
const currentBarNum = g_hidSudObj.std[g_stateObj.appearance][g_stateObj.reverse];
|
|
1843
|
+
addTransform(`filterView`, `appearance`, `translateY(${wUnit(parseFloat($id(`arrowSprite${currentBarNum % 2}`).top) +
|
|
1844
|
+
(currentBarNum % 2 === 0 ? bottomDist : topDist))})`, g_transPriority.layer);
|
|
1845
|
+
filterView.textContent = `${_num}%`;
|
|
1846
|
+
g_hidSudObj.filterPos = _num;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// ユーザカスタムイベント(アルファマスクの再描画)
|
|
1850
|
+
safeExecuteCustomHooks(`g_customJsObj.appearanceFilter`, g_customJsObj.appearanceFilter, topNum, bottomNum);
|
|
1851
|
+
|
|
1852
|
+
return doubleFilterFlg;
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* 判定カウンタ表示作成
|
|
1857
|
+
* @param {string} _id
|
|
1858
|
+
* @param {number} _x
|
|
1859
|
+
* @param {string} _class
|
|
1860
|
+
* @param {number} _heightPos
|
|
1861
|
+
* @param {string|number} _text
|
|
1862
|
+
* @param {string} [_display='inherit'] 表示有無 (inherit: 表示 / none: 非表示)
|
|
1863
|
+
* @returns {HTMLDivElement}
|
|
1864
|
+
*/
|
|
1865
|
+
const makeCounterSymbol = (_id, _x, _class, _heightPos, _text, _display = C_DIS_INHERIT) => {
|
|
1866
|
+
return createDivCss2Label(_id, _text, {
|
|
1867
|
+
x: _x, y: g_limitObj.jdgCntsHeight * _heightPos,
|
|
1868
|
+
w: g_limitObj.jdgCntsWidth, h: g_limitObj.jdgCntsHeight, siz: g_limitObj.jdgCntsSiz, align: C_ALIGN_RIGHT,
|
|
1869
|
+
display: _display,
|
|
1870
|
+
}, _class);
|
|
1871
|
+
};
|
|
1872
|
+
|
|
1873
|
+
/**
|
|
1874
|
+
* ステップゾーンの表示・非表示切替
|
|
1875
|
+
* @param {number} _j
|
|
1876
|
+
* @param {string} _display
|
|
1877
|
+
* @param {number} [_alpha=1]
|
|
1878
|
+
*/
|
|
1879
|
+
const appearStepZone = (_j, _display, _alpha = 1) => {
|
|
1880
|
+
$id(`stepRoot${_j}`).display = _display;
|
|
1881
|
+
$id(`stepRoot${_j}`).opacity = _alpha;
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
/**
|
|
1885
|
+
* 部分キーのステップゾーン出現処理
|
|
1886
|
+
* @param {number} _j
|
|
1887
|
+
* @param {string[]} _targets
|
|
1888
|
+
* @param {number[]} [_alphas] ステップゾーン毎の可視状況 (style.opacity の値)
|
|
1889
|
+
*/
|
|
1890
|
+
const appearKeyTypes = (_j, _targets, _alphas = fillArray(_targets.length, 1)) => {
|
|
1891
|
+
appearStepZone(_j, C_DIS_NONE);
|
|
1892
|
+
_targets.forEach((target, k) => {
|
|
1893
|
+
if (g_workObj.keyGroupMaps[_j].includes(target)) {
|
|
1894
|
+
appearStepZone(_j, C_DIS_INHERIT, _alphas[k]);
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
};
|
|
1898
|
+
|
|
1899
|
+
/**
|
|
1900
|
+
* FrzReturnの開始条件
|
|
1901
|
+
*/
|
|
1902
|
+
const startFrzReturn = () => {
|
|
1903
|
+
if (!g_workObj.frzReturnFlg) {
|
|
1904
|
+
if (g_workObj.frzReturnTimerId) {
|
|
1905
|
+
g_timerHandler.clearTimeout(g_workObj.frzReturnTimerId);
|
|
1906
|
+
g_workObj.frzReturnTimerId = null;
|
|
1907
|
+
}
|
|
1908
|
+
lifeBarFrz.classList.remove(g_cssObj.life_frzNormal, g_cssObj.life_frzActive);
|
|
1909
|
+
lifeBarFrz.classList.add(g_cssObj.life_frzActive);
|
|
1910
|
+
const seqLen = g_workObj.frzReturnSeq.length;
|
|
1911
|
+
executeFrzReturn(
|
|
1912
|
+
g_workObj.frzReturnSeq[seqLen > 1 ? Math.floor(Math.random() * seqLen) : 0], 0,
|
|
1913
|
+
g_frzReturnFunc.get(g_stateObj.frzReturn)()
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
|
|
1918
|
+
/**
|
|
1919
|
+
* FrzReturnの停止・後片付け(通常終了時/一時停止による中断時で共通)
|
|
1920
|
+
*/
|
|
1921
|
+
const resetFrzReturn = () => {
|
|
1922
|
+
if (g_workObj.frzReturnTimerId) {
|
|
1923
|
+
g_timerHandler.clearTimeout(g_workObj.frzReturnTimerId);
|
|
1924
|
+
}
|
|
1925
|
+
g_workObj.frzReturnTimerId = null;
|
|
1926
|
+
g_workObj.frzReturnFlg = false;
|
|
1927
|
+
delTransform(`mainSprite`, `frzReturn`);
|
|
1928
|
+
const mainSprite = document.getElementById(`mainSprite`);
|
|
1929
|
+
if (mainSprite) {
|
|
1930
|
+
mainSprite.style.opacity = 1;
|
|
1931
|
+
}
|
|
1932
|
+
const frzReturnGauge = document.getElementById(`lifeBarFrz`);
|
|
1933
|
+
if (frzReturnGauge) {
|
|
1934
|
+
frzReturnGauge.classList.remove(g_cssObj.life_frzNormal, g_cssObj.life_frzActive);
|
|
1935
|
+
frzReturnGauge.classList.add(g_cssObj.life_frzNormal);
|
|
1936
|
+
}
|
|
1937
|
+
};
|
|
1938
|
+
|
|
1939
|
+
/**
|
|
1940
|
+
* FrzReturnの実行
|
|
1941
|
+
* @param {number[]} _seq FrzReturnの移動配列
|
|
1942
|
+
* @param {number} _idx FrzReturnの移動配列のインディクス(transformの決定に利用)
|
|
1943
|
+
* @param {number[]} _axis 回転軸(X, Y, X-Yなど)
|
|
1944
|
+
*/
|
|
1945
|
+
const executeFrzReturn = (_seq, _idx, _axis) => {
|
|
1946
|
+
|
|
1947
|
+
const sprite = document.getElementById(`mainSprite`);
|
|
1948
|
+
if (sprite === null) {
|
|
1949
|
+
// 画面がプレイ画面から移動した場合
|
|
1950
|
+
g_workObj.frzReturnFlg = false;
|
|
1951
|
+
g_workObj.frzReturnTimerId = null;
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
if (!_seq || _idx >= _seq.length) {
|
|
1956
|
+
// 移動終了時
|
|
1957
|
+
resetFrzReturn();
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
g_workObj.frzReturnFlg = true;
|
|
1962
|
+
const _rad = _seq[_idx];
|
|
1963
|
+
|
|
1964
|
+
let _transform = `rotate${_axis[0]}(${_rad}deg)`;
|
|
1965
|
+
if (_axis[1] !== undefined) {
|
|
1966
|
+
_transform += ` rotate${_axis[1]}(${_rad}deg)`;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
sprite.style.transformStyle = `preserve-3d`;
|
|
1970
|
+
const rad360 = ((_rad % 360) + 360) % 360;
|
|
1971
|
+
|
|
1972
|
+
let isBack = false;
|
|
1973
|
+
|
|
1974
|
+
// 単軸回転
|
|
1975
|
+
if (_axis.length === 1) {
|
|
1976
|
+
const axis = _axis[0];
|
|
1977
|
+
if (axis === 'Y' || axis === 'X') {
|
|
1978
|
+
isBack = rad360 > 90 && rad360 < 270;
|
|
1979
|
+
}
|
|
1980
|
+
// Z軸は平面回転なので「裏側」は存在しない
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// 2軸回転(XZ / XY / YZ)
|
|
1984
|
+
if (_axis.length === 2) {
|
|
1985
|
+
// 2軸回転は「どちらかの軸が裏側なら裏側」とみなす
|
|
1986
|
+
const [a1, a2] = _axis;
|
|
1987
|
+
const back1 = (a1 === 'Y' || a1 === 'X') && (rad360 > 90 && rad360 < 270);
|
|
1988
|
+
const back2 = (a2 === 'Y' || a2 === 'X') && (rad360 > 90 && rad360 < 270);
|
|
1989
|
+
isBack = back1 || back2;
|
|
1990
|
+
}
|
|
1991
|
+
sprite.style.opacity = isBack ? 0.7 : 1;
|
|
1992
|
+
|
|
1993
|
+
addTransform(`mainSprite`, `frzReturn`, _transform, g_transPriority.frzReturn);
|
|
1994
|
+
|
|
1995
|
+
g_workObj.frzReturnTimerId = g_timerHandler.setTimeout(() => executeFrzReturn(_seq, _idx + 1, _axis), 20);
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
/**
|
|
1999
|
+
* 曲中リトライの共通処理
|
|
2000
|
+
* - 手動リトライ、AutoRetryの両方から呼ばれる
|
|
2001
|
+
* - g_retryInProgressによる多重実行防止、失敗時のログ出力・フラグ復帰を一括で行う
|
|
2002
|
+
* @param {string} [_logLabel='Retry'] エラーログに表示するラベル(手動/自動の区別用)
|
|
2003
|
+
*/
|
|
2004
|
+
const executeRetry = async (_logLabel = `Retry`) => {
|
|
2005
|
+
if (g_retryInProgress) {
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
g_retryInProgress = true;
|
|
2009
|
+
try {
|
|
2010
|
+
g_audio.pause();
|
|
2011
|
+
g_timerHandler.clearTimeout(g_timeoutEvtId);
|
|
2012
|
+
clearWindow(`Main`);
|
|
2013
|
+
await musicAfterLoaded();
|
|
2014
|
+
await loadChartFile();
|
|
2015
|
+
prepareScoreData();
|
|
2016
|
+
mainInit();
|
|
2017
|
+
} catch (e) {
|
|
2018
|
+
console.warn(`${_logLabel} audio load error: ${e}`);
|
|
2019
|
+
} finally {
|
|
2020
|
+
g_retryInProgress = false;
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
|
|
2024
|
+
/**
|
|
2025
|
+
* AutoRetryの設定
|
|
2026
|
+
* @param {string} _retryCondition リトライ基準となるAutoRetry名
|
|
2027
|
+
*/
|
|
2028
|
+
const quickRetry = (_retryCondition) => {
|
|
2029
|
+
const retryNum = g_settings.autoRetrys.findIndex(val => val === _retryCondition);
|
|
2030
|
+
if (retryNum < 0) {
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
if (g_settings.autoRetryNum >= retryNum && !g_retryInProgress) {
|
|
2034
|
+
g_timerHandler.setTimeout(async () => {
|
|
2035
|
+
await executeRetry(`AutoRetry`);
|
|
2036
|
+
}, 16);
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
/**
|
|
2041
|
+
* 個別・全体色変化
|
|
2042
|
+
* @param {number[]} _mkColor
|
|
2043
|
+
* @param {string[]} _mkColorCd
|
|
2044
|
+
* @param {string} _header
|
|
2045
|
+
* @param {string} _name
|
|
2046
|
+
*/
|
|
2047
|
+
const changeColors = (_mkColor, _mkColorCd, _header, _name) => {
|
|
2048
|
+
|
|
2049
|
+
if (_mkColor === undefined) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
|
|
2053
|
+
_mkColor.forEach((tempj, j) => {
|
|
2054
|
+
const targetj = tempj % 1000;
|
|
2055
|
+
g_workObj[`${camelHeader}Colors`][targetj] = _mkColorCd[j];
|
|
2056
|
+
if (tempj >= 1000) {
|
|
2057
|
+
g_workObj[`${camelHeader}ColorsAll`][targetj] = _mkColorCd[j];
|
|
2058
|
+
if (camelHeader.indexOf(`frzHitBar`) !== -1 && isNaN(Number(g_workObj.arrowRtn[targetj]))) {
|
|
2059
|
+
$id(`frzHitTop${targetj}`).background = _mkColorCd[j];
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
});
|
|
2063
|
+
};
|
|
2064
|
+
|
|
2065
|
+
/**
|
|
2066
|
+
* 個別モーション
|
|
2067
|
+
* @param {string} _header
|
|
2068
|
+
* @param {string} _name
|
|
2069
|
+
* @param {number} _frameNum
|
|
2070
|
+
*/
|
|
2071
|
+
const changeCssMotions = (_header, _name, _frameNum) => {
|
|
2072
|
+
const camelHeader = _header === `` ? _name : `${_header}${toCapitalize(_name)}`;
|
|
2073
|
+
g_workObj[`mk${toCapitalize(camelHeader)}CssMotion`]?.[_frameNum]?.forEach((targetj, j) => {
|
|
2074
|
+
g_workObj[`${camelHeader}CssMotions`][targetj] =
|
|
2075
|
+
g_workObj[`mk${toCapitalize(camelHeader)}CssMotionName`][_frameNum][2 * j + (g_workObj.dividePos[targetj] % 2)]
|
|
2076
|
+
g_workObj[`${camelHeader}MovLock`][targetj] = g_workObj[`mk${toCapitalize(camelHeader)}MovLock`][_frameNum][j];
|
|
2077
|
+
g_workObj[`${camelHeader}InitManual`][targetj] = g_workObj[`mk${toCapitalize(camelHeader)}InitManual`][_frameNum][j];
|
|
2078
|
+
});
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
/**
|
|
2082
|
+
* 基準となる階層グループの取得
|
|
2083
|
+
* @param {number} _layerGroup
|
|
2084
|
+
* @param {number} _j
|
|
2085
|
+
* @returns {number}
|
|
2086
|
+
*/
|
|
2087
|
+
const getBaseLayerGroup = (_layerGroup, _j) =>
|
|
2088
|
+
_layerGroup === -1
|
|
2089
|
+
? Math.floor(g_workObj.dividePosDefault[_j] / 2)
|
|
2090
|
+
: _layerGroup + (g_workObj.dividePosDefault[_j] > g_stateObj.layerNumDf ? g_stateObj.layerNumDf / 2 : 0);
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* スクロール方向、レイヤーの変更(矢印・フリーズアロー)
|
|
2094
|
+
* StepAreaがDefault/Halfway以外の場合はレイヤー数が倍化するため、その設定にも追従する
|
|
2095
|
+
* @param {number} _frameNum
|
|
2096
|
+
*/
|
|
2097
|
+
const changeScrollArrowDirs = (_frameNum) => {
|
|
2098
|
+
if (g_workObj.mkScrollchArrow?.[_frameNum] === undefined) {
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const tmpObj = new Map();
|
|
2102
|
+
g_workObj.mkScrollchArrow?.[_frameNum]?.forEach((targetj, j) => {
|
|
2103
|
+
g_workObj.scrollDir[targetj] = g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchArrowDir[_frameNum][j];
|
|
2104
|
+
|
|
2105
|
+
// レイヤー変更
|
|
2106
|
+
const baseLayer = getBaseLayerGroup(g_workObj.mkScrollchArrowLayerGroup[_frameNum][j], targetj);
|
|
2107
|
+
g_workObj.dividePos[targetj] = baseLayer * 2 + (g_workObj.scrollDir[targetj] === 1 ? 0 : 1);
|
|
2108
|
+
|
|
2109
|
+
// 対象の矢印が属するレイヤーに対するTransitionを設定
|
|
2110
|
+
// ステップゾーンの移動よりも矢印・フリーズアローの方が早く変わるため、この関数のみ適用
|
|
2111
|
+
if (g_workObj.mkScrollchArrowLayerTrans[_frameNum][j] !== ``) {
|
|
2112
|
+
tmpObj.set(g_workObj.dividePos[targetj], g_workObj.mkScrollchArrowLayerTrans[_frameNum][j]);
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
tmpObj.forEach((val, key, map) => addTransform(`mainSprite${key}`, `scrollch`, val, g_transPriority.layer));
|
|
2116
|
+
};
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* ステップゾーンの位置反転
|
|
2120
|
+
* @param {number} _frameNum
|
|
2121
|
+
*/
|
|
2122
|
+
const changeStepY = (_frameNum) =>
|
|
2123
|
+
g_workObj.mkScrollchStep?.[_frameNum]?.forEach((targetj, j) => {
|
|
2124
|
+
const dividePos = (g_workObj.scrollDirDefault[targetj] * g_workObj.mkScrollchStepDir[_frameNum][j] === 1 ? 0 : 1);
|
|
2125
|
+
|
|
2126
|
+
// 移動元のステップゾーンの不透明度、表示・非表示を退避
|
|
2127
|
+
const _stepOpacity = $id(`stepRoot${targetj}`).opacity;
|
|
2128
|
+
const _stepDisplay = $id(`stepRoot${targetj}`).display;
|
|
2129
|
+
|
|
2130
|
+
// 移動元のステップゾーンを消去
|
|
2131
|
+
document.getElementById(`stepRoot${targetj}`).remove();
|
|
2132
|
+
document.getElementById(`frzHit${targetj}`).remove();
|
|
2133
|
+
|
|
2134
|
+
// レイヤーを変更しステップゾーンを再生成。移動元の不透明度、表示・非表示を反映
|
|
2135
|
+
const baseLayer = getBaseLayerGroup(g_workObj.mkScrollchStepLayerGroup[_frameNum][j], targetj);
|
|
2136
|
+
g_workObj.dividePos[targetj] = baseLayer * 2 + dividePos;
|
|
2137
|
+
makeStepZone(targetj, `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`);
|
|
2138
|
+
appearStepZone(targetj, _stepDisplay, _stepOpacity);
|
|
2139
|
+
});
|
|
2140
|
+
|
|
2141
|
+
/**
|
|
2142
|
+
* フリーズアローヒット時の描画変更
|
|
2143
|
+
* @param {number} _j
|
|
2144
|
+
* @param {number} _k
|
|
2145
|
+
* @param {string} _name
|
|
2146
|
+
* @param {number} [_difFrame=0]
|
|
2147
|
+
*/
|
|
2148
|
+
const changeHitFrz = (_j, _k, _name, _difFrame = 0) => {
|
|
2149
|
+
const frzNo = `${_j}_${_k}`;
|
|
2150
|
+
const frzName = `${_name}${frzNo}`;
|
|
2151
|
+
const currentFrz = g_attrObj[frzName];
|
|
2152
|
+
|
|
2153
|
+
if (currentFrz.keyUpFrame !== 0) {
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
const styfrzBar = $id(`${_name}Bar${frzNo}`);
|
|
2158
|
+
const styfrzBtmRoot = $id(`${_name}BtmRoot${frzNo}`);
|
|
2159
|
+
const styfrzBtm = $id(`${_name}Btm${frzNo}`);
|
|
2160
|
+
const styfrzTopRoot = $id(`${_name}TopRoot${frzNo}`);
|
|
2161
|
+
const styfrzBtmShadow = $id(`${_name}BtmShadow${frzNo}`);
|
|
2162
|
+
|
|
2163
|
+
// フリーズアロー位置の修正(ステップゾーン上に来るように)
|
|
2164
|
+
const delFrzLength = parseFloat($id(`stepRoot${_j}`).top) - currentFrz.y;
|
|
2165
|
+
|
|
2166
|
+
// 早押ししたboostCnt分のフリーズアロー終端位置の修正
|
|
2167
|
+
const delFrzMotionLength = sumData(g_workObj.motionOnFrames.slice(0, currentFrz.boostCnt + 1));
|
|
2168
|
+
|
|
2169
|
+
// 判定位置調整分の補正
|
|
2170
|
+
const hitPos = g_workObj.hitPosition * g_workObj.scrollDir[_j];
|
|
2171
|
+
|
|
2172
|
+
currentFrz.frzBarLength -= (delFrzLength + delFrzMotionLength) * currentFrz.dir;
|
|
2173
|
+
currentFrz.barY -= (delFrzLength + delFrzMotionLength) * currentFrz.dividePos + hitPos;
|
|
2174
|
+
currentFrz.btmY -= delFrzLength + delFrzMotionLength + hitPos;
|
|
2175
|
+
currentFrz.y += delFrzLength;
|
|
2176
|
+
currentFrz.isMoving = false;
|
|
2177
|
+
movArrowY.get(currentFrz.movLockFlg)(frzName, currentFrz.y);
|
|
2178
|
+
|
|
2179
|
+
/**
|
|
2180
|
+
* フリーズアロー(ヒット時)の色変更
|
|
2181
|
+
* - 生成時以降で全体色変化がある場合はその値へ置き換える
|
|
2182
|
+
* @param {string} _type
|
|
2183
|
+
* @returns {string}
|
|
2184
|
+
*/
|
|
2185
|
+
const getColor = (_type) => {
|
|
2186
|
+
const cColorAll = g_workObj[`${_name}${_type}ColorsAll`][_j];
|
|
2187
|
+
return currentFrz[_type] !== cColorAll && currentFrz[`${_type}All`] !== cColorAll
|
|
2188
|
+
? cColorAll : currentFrz[_type];
|
|
2189
|
+
};
|
|
2190
|
+
|
|
2191
|
+
const tmpHitColor = getColor(`Hit`);
|
|
2192
|
+
styfrzBar.top = wUnit(currentFrz.barY);
|
|
2193
|
+
styfrzBar.height = wUnit(currentFrz.frzBarLength);
|
|
2194
|
+
styfrzBar.background = getColor(`HitBar`);
|
|
2195
|
+
styfrzBtmRoot.top = wUnit(currentFrz.btmY);
|
|
2196
|
+
styfrzBtm.background = tmpHitColor;
|
|
2197
|
+
styfrzTopRoot.top = wUnit(- hitPos);
|
|
2198
|
+
if (_name === `frz`) {
|
|
2199
|
+
const tmpShadowColor = getColor(`HitShadow`);
|
|
2200
|
+
styfrzBtmShadow.background = tmpShadowColor === `Default` ? tmpHitColor : tmpShadowColor;
|
|
2201
|
+
$id(`frzHit${_j}`).opacity = 0.9;
|
|
2202
|
+
$id(`frzTop${frzNo}`).display = C_DIS_NONE;
|
|
2203
|
+
if (isNaN(parseFloat(g_workObj.arrowRtn[_j]))) {
|
|
2204
|
+
$id(`frzHitTop${_j}`).background = tmpHitColor;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// FrzReturnの設定
|
|
2209
|
+
if (g_stateObj.frzReturn !== C_FLG_OFF) {
|
|
2210
|
+
startFrzReturn();
|
|
2211
|
+
}
|
|
2212
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_${_name}Hit`, g_customJsObj[`judg_${_name}Hit`], _difFrame, _j);
|
|
2213
|
+
};
|
|
2214
|
+
|
|
2215
|
+
/**
|
|
2216
|
+
* フリーズアロー失敗時の描画変更
|
|
2217
|
+
* @param {number} _j
|
|
2218
|
+
* @param {number} _k
|
|
2219
|
+
*/
|
|
2220
|
+
const changeFailedFrz = (_j, _k) => {
|
|
2221
|
+
const frzNo = `${_j}_${_k}`;
|
|
2222
|
+
$id(`frzHit${_j}`).opacity = 0;
|
|
2223
|
+
$id(`frzTop${frzNo}`).display = C_DIS_INHERIT;
|
|
2224
|
+
$id(`frzTop${frzNo}`).background = `#cccccc`;
|
|
2225
|
+
$id(`frzTopShadow${frzNo}`).background = `#333333`;
|
|
2226
|
+
$id(`frzBtmShadow${frzNo}`).background = `#333333`;
|
|
2227
|
+
$id(`frzBar${frzNo}`).background = `#999999`;
|
|
2228
|
+
$id(`frzBar${frzNo}`).opacity = 1;
|
|
2229
|
+
$id(`frzBtm${frzNo}`).background = `#cccccc`;
|
|
2230
|
+
|
|
2231
|
+
// FrzReturnの設定
|
|
2232
|
+
if (g_stateObj.frzReturn !== C_FLG_OFF) {
|
|
2233
|
+
startFrzReturn();
|
|
2234
|
+
}
|
|
2235
|
+
};
|
|
2236
|
+
|
|
2237
|
+
/**
|
|
2238
|
+
* キーを押したかどうかを判定
|
|
2239
|
+
* @param {number} _keyCode
|
|
2240
|
+
* @returns {boolean}
|
|
2241
|
+
*/
|
|
2242
|
+
const keyIsDown = _keyCode => g_inputKeyBuffer[_keyCode];
|
|
2243
|
+
|
|
2244
|
+
/**
|
|
2245
|
+
* 押したキーがシフトキーかどうかを判定
|
|
2246
|
+
* @returns {boolean}
|
|
2247
|
+
*/
|
|
2248
|
+
const keyIsShift = () => keyIsDown(g_kCdNameObj.shiftLKey) || keyIsDown(g_kCdNameObj.shiftRKey);
|
|
2249
|
+
|
|
2250
|
+
/**
|
|
2251
|
+
* 矢印・フリーズアロー判定
|
|
2252
|
+
* @param {number} _j 対象矢印・フリーズアロー
|
|
2253
|
+
*/
|
|
2254
|
+
const judgeArrow = _j => {
|
|
2255
|
+
|
|
2256
|
+
const currentNo = g_workObj.judgArrowCnt[_j];
|
|
2257
|
+
const arrowName = `arrow${_j}_${currentNo}`;
|
|
2258
|
+
const currentArrow = g_attrObj[arrowName];
|
|
2259
|
+
const existJudgArrow = document.getElementById(arrowName) !== null;
|
|
2260
|
+
|
|
2261
|
+
const fcurrentNo = g_workObj.judgFrzCnt[_j];
|
|
2262
|
+
const frzName = `frz${_j}_${fcurrentNo}`;
|
|
2263
|
+
const currentFrz = g_attrObj[frzName];
|
|
2264
|
+
const existJudgFrz = document.getElementById(frzName) !== null;
|
|
2265
|
+
|
|
2266
|
+
const judgeTargetArrow = _difFrame => {
|
|
2267
|
+
const _difCnt = Math.abs(_difFrame);
|
|
2268
|
+
const stepHitTargetArrow = _resultJdg => {
|
|
2269
|
+
const stepDivHit = document.getElementById(`stepHit${_j}`);
|
|
2270
|
+
stepDivHit.style.top = wUnit(currentArrow.prevY - parseFloat($id(`stepRoot${_j}`).top) - 15 + g_workObj.hitPosition * g_workObj.scrollDir[_j]);
|
|
2271
|
+
stepDivHit.style.opacity = 0.75;
|
|
2272
|
+
stepDivHit.classList.value = ``;
|
|
2273
|
+
stepDivHit.classList.add(g_cssObj[`main_step${_resultJdg}`]);
|
|
2274
|
+
stepDivHit.setAttribute(`cnt`, C_FRM_HITMOTION);
|
|
2275
|
+
};
|
|
2276
|
+
|
|
2277
|
+
if (g_stateObj.excessive === C_FLG_ON && _difFrame <= g_judgObj.arrowJ[g_judgPosObj.uwan] && _difFrame > g_judgObj.arrowJ[g_judgPosObj.shobon]) {
|
|
2278
|
+
// 空押し判定(有効かつ早押し時のみ)
|
|
2279
|
+
displayDiff(_difFrame);
|
|
2280
|
+
stepHitTargetArrow(`Excessive`);
|
|
2281
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_excessive`, g_customJsObj.judg_excessive, _difFrame, _j);
|
|
2282
|
+
return true;
|
|
2283
|
+
|
|
2284
|
+
} else if (_difCnt <= g_judgObj.arrowJ[g_judgPosObj.shobon]) {
|
|
2285
|
+
// 通常判定
|
|
2286
|
+
const [resultFunc, resultJdg] = checkJudgment(_difCnt);
|
|
2287
|
+
resultFunc(_difFrame, _j);
|
|
2288
|
+
displayDiff(_difFrame);
|
|
2289
|
+
stepHitTargetArrow(resultJdg);
|
|
2290
|
+
document.getElementById(arrowName).remove();
|
|
2291
|
+
g_workObj.judgArrowCnt[_j]++;
|
|
2292
|
+
return true;
|
|
2293
|
+
}
|
|
2294
|
+
return false;
|
|
2295
|
+
};
|
|
2296
|
+
|
|
2297
|
+
const judgeTargetFrzArrow = _difFrame => {
|
|
2298
|
+
const _difCnt = Math.abs(_difFrame);
|
|
2299
|
+
if (_difCnt <= g_judgObj.frzJ[g_judgPosObj.iknai] && !currentFrz.judgEndFlg
|
|
2300
|
+
&& g_workObj.judgFrzHitCnt[_j] <= fcurrentNo) {
|
|
2301
|
+
|
|
2302
|
+
if (g_headerObj.frzStartjdgUse) {
|
|
2303
|
+
const [resultFunc] = checkJudgment(_difCnt);
|
|
2304
|
+
resultFunc(_difFrame, _j);
|
|
2305
|
+
displayDiff(_difFrame);
|
|
2306
|
+
} else {
|
|
2307
|
+
displayDiff(_difFrame, `F`);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
if (_difCnt <= g_judgObj.frzJ[g_judgPosObj.sfsf]) {
|
|
2311
|
+
changeHitFrz(_j, fcurrentNo, `frz`, _difFrame);
|
|
2312
|
+
} else {
|
|
2313
|
+
changeFailedFrz(_j, fcurrentNo);
|
|
2314
|
+
if (g_headerObj.frzStartjdgUse) {
|
|
2315
|
+
judgeIknai(_difFrame, _j);
|
|
2316
|
+
currentFrz.judgEndFlg = true;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
g_workObj.judgFrzHitCnt[_j] = fcurrentNo + 1;
|
|
2320
|
+
return true;
|
|
2321
|
+
}
|
|
2322
|
+
return false;
|
|
2323
|
+
};
|
|
2324
|
+
|
|
2325
|
+
let judgeFlg = false;
|
|
2326
|
+
const difFrame = (existJudgArrow ? currentArrow.cnt : Infinity);
|
|
2327
|
+
const frzDifFrame = (existJudgFrz ? currentFrz.cnt : Infinity);
|
|
2328
|
+
if (difFrame < frzDifFrame) {
|
|
2329
|
+
judgeFlg = judgeTargetArrow(difFrame);
|
|
2330
|
+
} else if (difFrame > frzDifFrame) {
|
|
2331
|
+
judgeFlg = judgeTargetFrzArrow(frzDifFrame);
|
|
2332
|
+
}
|
|
2333
|
+
if (!judgeFlg) {
|
|
2334
|
+
$id(`stepDiv${_j}`).display = C_DIS_INHERIT;
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2337
|
+
|
|
2338
|
+
/**
|
|
2339
|
+
* タイミングズレを表示
|
|
2340
|
+
* @param {number} _difFrame
|
|
2341
|
+
* @param {string} _fjdg フリーズアロー判定有無 (フリーズアローのときは"F"が入る)
|
|
2342
|
+
* @param {number} _justFrames Fast/Slowの表示条件フレーム数
|
|
2343
|
+
*/
|
|
2344
|
+
const displayDiff = (_difFrame, _fjdg = ``, _justFrames = g_headerObj.justFrames) => {
|
|
2345
|
+
g_workObj.diffList.push(_difFrame);
|
|
2346
|
+
|
|
2347
|
+
const difCnt = Math.abs(_difFrame);
|
|
2348
|
+
const diffJ = document.getElementById(`diff${_fjdg}J`);
|
|
2349
|
+
|
|
2350
|
+
let text = ``;
|
|
2351
|
+
let activeClass = ``;
|
|
2352
|
+
|
|
2353
|
+
// 1. 各条件の処理
|
|
2354
|
+
if (_difFrame > g_judgObj.arrowJ[g_judgPosObj.shobon]) {
|
|
2355
|
+
text = `Excessive`;
|
|
2356
|
+
activeClass = g_cssObj.common_Excessive;
|
|
2357
|
+
g_resultObj.excessive++;
|
|
2358
|
+
lifeDamage(true);
|
|
2359
|
+
|
|
2360
|
+
} else if (_difFrame > _justFrames) {
|
|
2361
|
+
text = `Fast ${difCnt} Frames`;
|
|
2362
|
+
activeClass = g_cssObj.common_diffFast;
|
|
2363
|
+
g_resultObj.fast++;
|
|
2364
|
+
quickRetry(`Fast/Slow`);
|
|
2365
|
+
|
|
2366
|
+
} else if (_difFrame < _justFrames * -1) {
|
|
2367
|
+
text = `Slow ${difCnt} Frames`;
|
|
2368
|
+
activeClass = g_cssObj.common_diffSlow;
|
|
2369
|
+
g_resultObj.slow++;
|
|
2370
|
+
quickRetry(`Fast/Slow`);
|
|
2371
|
+
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
// 2. DOMへの反映
|
|
2375
|
+
diffJ.textContent = text;
|
|
2376
|
+
diffJ.classList.value = ``;
|
|
2377
|
+
if (activeClass) {
|
|
2378
|
+
diffJ.classList.add(activeClass);
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
|
|
2382
|
+
/**
|
|
2383
|
+
* ライフゲージバーの色、数値を変更
|
|
2384
|
+
* @param {string} [_state='']
|
|
2385
|
+
*/
|
|
2386
|
+
const changeLifeColor = (_state = ``) => {
|
|
2387
|
+
const lblLife = document.getElementById(`lblLife`);
|
|
2388
|
+
const lifeBar = document.getElementById(`lifeBar`);
|
|
2389
|
+
|
|
2390
|
+
if (_state !== `` && _state !== g_workObj.currentLifeState) {
|
|
2391
|
+
const lifeCss = g_cssObj[`life_${_state}`];
|
|
2392
|
+
lblLife.classList.remove(g_cssObj.life_Max, g_cssObj.life_Cleared, g_cssObj.life_Failed);
|
|
2393
|
+
lifeBar.classList.remove(g_cssObj.life_Max, g_cssObj.life_Cleared, g_cssObj.life_Failed);
|
|
2394
|
+
lblLife.classList.add(lifeCss);
|
|
2395
|
+
lifeBar.classList.add(lifeCss);
|
|
2396
|
+
|
|
2397
|
+
g_workObj.currentLifeState = _state;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
const intLifeVal = Math.floor(g_workObj.lifeVal);
|
|
2401
|
+
lblLife.textContent = intLifeVal;
|
|
2402
|
+
|
|
2403
|
+
const playableHeight = g_headerObj.playingHeight - 100;
|
|
2404
|
+
lifeBar.style.top = wUnit(50 + playableHeight * (g_headerObj.maxLifeVal - intLifeVal) / g_headerObj.maxLifeVal);
|
|
2405
|
+
lifeBar.style.height = wUnit(playableHeight * intLifeVal / g_headerObj.maxLifeVal);
|
|
2406
|
+
};
|
|
2407
|
+
|
|
2408
|
+
/**
|
|
2409
|
+
* ゲージ回復処理
|
|
2410
|
+
*/
|
|
2411
|
+
const lifeRecovery = () => {
|
|
2412
|
+
g_workObj.lifeVal += g_workObj.lifeRcv;
|
|
2413
|
+
|
|
2414
|
+
if (g_workObj.lifeVal >= g_headerObj.maxLifeVal) {
|
|
2415
|
+
g_workObj.lifeVal = g_headerObj.maxLifeVal;
|
|
2416
|
+
changeLifeColor(`Max`);
|
|
2417
|
+
} else {
|
|
2418
|
+
changeLifeColor(g_workObj.lifeVal >= g_workObj.lifeBorder ? `Cleared` : ``);
|
|
2419
|
+
}
|
|
2420
|
+
g_resultObj.gaugeTransition.push([g_scoreObj.baseFrame, g_workObj.lifeVal]);
|
|
2421
|
+
};
|
|
2422
|
+
|
|
2423
|
+
/**
|
|
2424
|
+
* ゲージダメージ処理
|
|
2425
|
+
* @param {boolean} [_excessive=false] 空押し判定有無
|
|
2426
|
+
*/
|
|
2427
|
+
const lifeDamage = (_excessive = false) => {
|
|
2428
|
+
g_workObj.lifeVal -= g_workObj.lifeDmg * (_excessive ? 0.25 : 1);
|
|
2429
|
+
quickRetry(`Miss`);
|
|
2430
|
+
|
|
2431
|
+
if (g_workObj.lifeVal <= 0) {
|
|
2432
|
+
g_workObj.lifeVal = 0;
|
|
2433
|
+
changeLifeColor();
|
|
2434
|
+
} else {
|
|
2435
|
+
changeLifeColor(g_workObj.lifeVal < g_workObj.lifeBorder ? `Failed` : `Cleared`);
|
|
2436
|
+
}
|
|
2437
|
+
g_resultObj.gaugeTransition.push([g_scoreObj.baseFrame, g_workObj.lifeVal]);
|
|
2438
|
+
};
|
|
2439
|
+
|
|
2440
|
+
/**
|
|
2441
|
+
* 判定キャラクタの表示、判定済矢印数・判定数のカウンタ
|
|
2442
|
+
* @param {string} _name
|
|
2443
|
+
* @param {string} _character
|
|
2444
|
+
* @param {string} [_fjdg='']
|
|
2445
|
+
*/
|
|
2446
|
+
const changeJudgeCharacter = (_name, _character, _fjdg = ``) => {
|
|
2447
|
+
g_resultObj[_name]++;
|
|
2448
|
+
g_currentArrows++;
|
|
2449
|
+
const jdgJ = document.getElementById(`chara${_fjdg}J`);
|
|
2450
|
+
jdgJ.classList.value = ``;
|
|
2451
|
+
jdgJ.classList.add(g_cssObj[`common_${_name}`]);
|
|
2452
|
+
jdgJ.textContent = _character;
|
|
2453
|
+
jdgJ.setAttribute(`cnt`, C_FRM_JDGMOTION);
|
|
2454
|
+
document.getElementById(`lbl${toCapitalize(_name)}`).textContent = g_resultObj[_name];
|
|
2455
|
+
};
|
|
2456
|
+
|
|
2457
|
+
/**
|
|
2458
|
+
* コンボの更新
|
|
2459
|
+
*/
|
|
2460
|
+
const updateCombo = () => {
|
|
2461
|
+
if (++g_resultObj.combo > g_resultObj.maxCombo) {
|
|
2462
|
+
g_resultObj.maxCombo = g_resultObj.combo;
|
|
2463
|
+
lblMCombo.textContent = g_resultObj.maxCombo;
|
|
2464
|
+
}
|
|
2465
|
+
comboJ.textContent = `${g_resultObj.combo} Combo!!`;
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
/**
|
|
2469
|
+
* 回復判定の共通処理
|
|
2470
|
+
* @param {string} _name
|
|
2471
|
+
* @param {number} _difFrame
|
|
2472
|
+
* @param {number} _j
|
|
2473
|
+
*/
|
|
2474
|
+
const judgeRecovery = (_name, _difFrame, _j) => {
|
|
2475
|
+
changeJudgeCharacter(_name, g_lblNameObj[`j_${_name}`]);
|
|
2476
|
+
updateCombo();
|
|
2477
|
+
lifeRecovery();
|
|
2478
|
+
finishViewing();
|
|
2479
|
+
|
|
2480
|
+
if (g_stateObj.frzReturn !== C_FLG_OFF) {
|
|
2481
|
+
g_workObj.arrowReturnVal = (g_resultObj.ii + g_resultObj.shakin) % 100;
|
|
2482
|
+
const playableHeight = g_headerObj.playingHeight - 100;
|
|
2483
|
+
$id(`lifeBarFrz`).top = wUnit(50 + playableHeight * (100 - g_workObj.arrowReturnVal) / 100);
|
|
2484
|
+
$id(`lifeBarFrz`).height = wUnit(playableHeight * g_workObj.arrowReturnVal / 100);
|
|
2485
|
+
if (g_workObj.arrowReturnVal === 0) {
|
|
2486
|
+
startFrzReturn();
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
if (_name === `shakin`) {
|
|
2490
|
+
quickRetry(`Shakin(Great)`);
|
|
2491
|
+
}
|
|
2492
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_${_name}`, g_customJsObj[`judg_${_name}`], _difFrame, _j);
|
|
2493
|
+
};
|
|
2494
|
+
|
|
2495
|
+
/**
|
|
2496
|
+
* ダメージ系共通処理
|
|
2497
|
+
* @param {string} _name
|
|
2498
|
+
* @param {number} _difFrame
|
|
2499
|
+
* @param {number} _j
|
|
2500
|
+
*/
|
|
2501
|
+
const judgeDamage = (_name, _difFrame, _j) => {
|
|
2502
|
+
changeJudgeCharacter(_name, g_lblNameObj[`j_${_name}`]);
|
|
2503
|
+
g_resultObj.combo = 0;
|
|
2504
|
+
comboJ.textContent = ``;
|
|
2505
|
+
diffJ.textContent = ``;
|
|
2506
|
+
lifeDamage();
|
|
2507
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_${_name}`, g_customJsObj[`judg_${_name}`], _difFrame, _j);
|
|
2508
|
+
};
|
|
2509
|
+
|
|
2510
|
+
/**
|
|
2511
|
+
* 判定処理:イイ
|
|
2512
|
+
* @param {number} _difFrame
|
|
2513
|
+
* @param {number} _j
|
|
2514
|
+
*/
|
|
2515
|
+
const judgeIi = (_difFrame, _j) => judgeRecovery(`ii`, _difFrame, _j);
|
|
2516
|
+
|
|
2517
|
+
/**
|
|
2518
|
+
* 判定処理:シャキン
|
|
2519
|
+
* @param {number} _difFrame
|
|
2520
|
+
* @param {number} _j
|
|
2521
|
+
*/
|
|
2522
|
+
const judgeShakin = (_difFrame, _j) => judgeRecovery(`shakin`, _difFrame, _j);
|
|
2523
|
+
|
|
2524
|
+
/**
|
|
2525
|
+
* 判定処理:マターリ
|
|
2526
|
+
* @param {number} _difFrame
|
|
2527
|
+
* @param {number} _j
|
|
2528
|
+
*/
|
|
2529
|
+
const judgeMatari = (_difFrame, _j) => {
|
|
2530
|
+
changeJudgeCharacter(`matari`, g_lblNameObj.j_matari);
|
|
2531
|
+
comboJ.textContent = ``;
|
|
2532
|
+
finishViewing();
|
|
2533
|
+
quickRetry(`Matari(Good)`);
|
|
2534
|
+
|
|
2535
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_matari`, g_customJsObj.judg_matari, _difFrame, _j);
|
|
2536
|
+
};
|
|
2537
|
+
|
|
2538
|
+
/**
|
|
2539
|
+
* 判定処理:ショボーン
|
|
2540
|
+
* @param {number} _difFrame
|
|
2541
|
+
* @param {number} _j
|
|
2542
|
+
*/
|
|
2543
|
+
const judgeShobon = (_difFrame, _j) => judgeDamage(`shobon`, _difFrame, _j);
|
|
2544
|
+
|
|
2545
|
+
/**
|
|
2546
|
+
* 判定処理:ウワァン
|
|
2547
|
+
* @param {number} _difFrame
|
|
2548
|
+
* @param {number} _j
|
|
2549
|
+
*/
|
|
2550
|
+
const judgeUwan = (_difFrame, _j) => judgeDamage(`uwan`, _difFrame, _j);
|
|
2551
|
+
|
|
2552
|
+
/**
|
|
2553
|
+
* 判定処理:キター
|
|
2554
|
+
* @param {number} _difFrame
|
|
2555
|
+
* @param {number} _j
|
|
2556
|
+
*/
|
|
2557
|
+
const judgeKita = (_difFrame, _j) => {
|
|
2558
|
+
changeJudgeCharacter(`kita`, g_lblNameObj.j_kita, `F`);
|
|
2559
|
+
|
|
2560
|
+
if (++g_resultObj.fCombo > g_resultObj.fmaxCombo) {
|
|
2561
|
+
g_resultObj.fmaxCombo = g_resultObj.fCombo;
|
|
2562
|
+
lblFCombo.textContent = g_resultObj.fmaxCombo;
|
|
2563
|
+
}
|
|
2564
|
+
comboFJ.textContent = `${g_resultObj.fCombo} Combo!!`;
|
|
2565
|
+
|
|
2566
|
+
lifeRecovery();
|
|
2567
|
+
finishViewing();
|
|
2568
|
+
|
|
2569
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_kita`, g_customJsObj.judg_kita, _difFrame, _j);
|
|
2570
|
+
};
|
|
2571
|
+
|
|
2572
|
+
/**
|
|
2573
|
+
* 判定処理:イクナイ
|
|
2574
|
+
* @param {number} _difFrame
|
|
2575
|
+
* @param {number} _j
|
|
2576
|
+
*/
|
|
2577
|
+
const judgeIknai = (_difFrame, _j) => {
|
|
2578
|
+
changeJudgeCharacter(`iknai`, g_lblNameObj.j_iknai, `F`);
|
|
2579
|
+
comboFJ.textContent = ``;
|
|
2580
|
+
g_resultObj.fCombo = 0;
|
|
2581
|
+
|
|
2582
|
+
lifeDamage();
|
|
2583
|
+
|
|
2584
|
+
safeExecuteCustomHooks(`g_customJsObj.judg_iknai`, g_customJsObj.judg_iknai, _difFrame, _j);
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
const jdgList = [`ii`, `shakin`, `matari`, `shobon`].map(jdg => toCapitalize(jdg));
|
|
2588
|
+
const jdgFuncList = [judgeIi, judgeShakin, judgeMatari, judgeShobon];
|
|
2589
|
+
const checkJudgment = (_difCnt) => {
|
|
2590
|
+
const idx = g_judgObj.arrowJ.findIndex(jdgCnt => _difCnt <= jdgCnt);
|
|
2591
|
+
return [jdgFuncList[idx], jdgList[idx]];
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
/**
|
|
2595
|
+
* クリア表示
|
|
2596
|
+
* @param {string} _state
|
|
2597
|
+
* @returns {string}
|
|
2598
|
+
*/
|
|
2599
|
+
const resultViewText = _state => _state === `` ? `` :
|
|
2600
|
+
`<span class="result_${toCapitalize(_state)}">${g_lblNameObj[_state]}</span>`;
|
|
2601
|
+
|
|
2602
|
+
/**
|
|
2603
|
+
* フルコンボ・パーフェクト演出の作成
|
|
2604
|
+
* @param {string} _text
|
|
2605
|
+
*/
|
|
2606
|
+
const makeFinishView = _text => {
|
|
2607
|
+
finishView.innerHTML = _text;
|
|
2608
|
+
finishView.style.opacity = 1;
|
|
2609
|
+
[`charaJ`, `comboJ`, `diffJ`, `charaFJ`, `comboFJ`, `diffFJ`].forEach(label =>
|
|
2610
|
+
document.getElementById(label).textContent = ``);
|
|
2611
|
+
};
|
|
2612
|
+
|
|
2613
|
+
const finishViewing = () => {
|
|
2614
|
+
if (g_currentArrows === g_fullArrows) {
|
|
2615
|
+
if (g_resultObj.ii + g_resultObj.kita === g_fullArrows) {
|
|
2616
|
+
g_resultObj.spState = `allPerfect`;
|
|
2617
|
+
} else if (g_resultObj.ii + g_resultObj.shakin + g_resultObj.kita === g_fullArrows) {
|
|
2618
|
+
g_resultObj.spState = `perfect`;
|
|
2619
|
+
} else if (g_resultObj.uwan === 0 && g_resultObj.shobon === 0 && g_resultObj.iknai === 0) {
|
|
2620
|
+
g_resultObj.spState = `fullCombo`;
|
|
2621
|
+
}
|
|
2622
|
+
if (g_headerObj.finishView !== C_DIS_NONE && [`allPerfect`, `perfect`, `fullCombo`].includes(g_resultObj.spState)) {
|
|
2623
|
+
makeFinishView(resultViewText(g_resultObj.spState));
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
};
|