danoniplus 51.4.3 → 52.1.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 +3 -3
- package/js/lib/danoni_constants.js +186 -42
- package/js/lib/settings.js +938 -4
- package/package.json +1 -1
package/js/danoni_main.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Source by tickle
|
|
6
6
|
* Created : 2018/10/08
|
|
7
|
-
* Revised : 2026/
|
|
7
|
+
* Revised : 2026/11/03
|
|
8
8
|
*
|
|
9
9
|
* https://github.com/cwtickle/danoniplus
|
|
10
10
|
*/
|
|
11
|
-
const g_version = `Ver
|
|
12
|
-
const g_revisedDate = `2026/
|
|
11
|
+
const g_version = `Ver 52.1.0`;
|
|
12
|
+
const g_revisedDate = `2026/11/03`;
|
|
13
13
|
|
|
14
14
|
// カスタム用バージョン (danoni_custom.js 等で指定可)
|
|
15
15
|
let g_localVersion = ``;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Source by tickle
|
|
7
7
|
* Created : 2019/11/19
|
|
8
|
-
* Revised : 2026/
|
|
8
|
+
* Revised : 2026/11/03 (v52.1.0)
|
|
9
9
|
*
|
|
10
10
|
* https://github.com/cwtickle/danoniplus
|
|
11
11
|
*/
|
|
@@ -96,6 +96,12 @@ const g_limitObj = {
|
|
|
96
96
|
|
|
97
97
|
// キーコンフィグで表示するカラーピッカー数
|
|
98
98
|
kcColorPickerNum: 5,
|
|
99
|
+
|
|
100
|
+
helpLongLines: 2, // 改行がこの数以上なら詳細ヘルプ化
|
|
101
|
+
helpLongChars: 120, // 文字数がこの値を超えたら詳細ヘルプ化
|
|
102
|
+
helpPreviewRate: 0.44, // 詳細ヘルプ内プレビューの高さ (画面高に対する割合)
|
|
103
|
+
helpPreviewMaxRate: 0.5, // プレビュー内プレイ画面の最大縮小率
|
|
104
|
+
helpPreviewAutoFrames: 500, // 次の選択肢へ自動で切り替えるまでのフレーム数 (0で無効)
|
|
99
105
|
};
|
|
100
106
|
|
|
101
107
|
/** 設定項目の位置 */
|
|
@@ -3168,6 +3174,13 @@ const g_shortcutObj = {
|
|
|
3168
3174
|
Tab: { id: `btnNextSetting` },
|
|
3169
3175
|
KeyU: { id: `btnSettingSummary` },
|
|
3170
3176
|
},
|
|
3177
|
+
helpOverlay: {
|
|
3178
|
+
Escape: { id: `btnHelpClose` },
|
|
3179
|
+
ArrowUp: { id: `btnHelpPrev` },
|
|
3180
|
+
ArrowDown: { id: `btnHelpNext` },
|
|
3181
|
+
ArrowLeft: { id: `btnHelpLeft` },
|
|
3182
|
+
ArrowRight: { id: `btnHelpRight` },
|
|
3183
|
+
},
|
|
3171
3184
|
keyConfig: {
|
|
3172
3185
|
//Escape: { id: `btnBack` }, // Escapeを別用途でも使用するため、ここではコメントアウト
|
|
3173
3186
|
Backspace_Enter: { id: `btnPlay` },
|
|
@@ -5084,14 +5097,39 @@ const g_lang_msgObj = {
|
|
|
5084
5097
|
|
|
5085
5098
|
difficulty: `譜面を選択します。`,
|
|
5086
5099
|
speed: `矢印の流れる速度を設定します。\n外側のボタンは1x単位、内側は0.25x単位で変更できます。`,
|
|
5087
|
-
motion:
|
|
5100
|
+
motion: `矢印の速度を一定ではなく、変動させるモーションをつけるか設定します。\n` +
|
|
5101
|
+
`[Boost] 初めは初速、ステップゾーンに近づくにつれて速くなります。\n` +
|
|
5102
|
+
`[Hi-Boost] 基本的にはBoostと同じですが、終端速度が初速に比例して速くなります。\n` +
|
|
5103
|
+
`[Brake] 初めは速く、ステップゾーンに近づくにつれて初速になります。\n` +
|
|
5104
|
+
`[Compress] 初めは初速、ステップゾーンに近づくにつれて徐々に遅くなります。\n` +
|
|
5105
|
+
`[Fountain] 矢印・フリーズアローが流れる反対側から出現し、画面奥で折り返してステップゾーンへ向かう動きをします。\n` +
|
|
5106
|
+
`[Magnet] Fountainに似ていますが、画面中央で折り返します。\n`,
|
|
5088
5107
|
reverse: `矢印の流れる向きを設定します。`,
|
|
5089
|
-
scroll: `各レーンのスクロール方向をパターンに沿って設定します。\nReverse:ON
|
|
5090
|
-
|
|
5108
|
+
scroll: `各レーンのスクロール方向をパターンに沿って設定します。\nReverse:ONでスクロール方向を反転します。\n` +
|
|
5109
|
+
`[Cross] 正、逆、正の順に流れるよう設定します。\n` +
|
|
5110
|
+
`[Split] 中央を境界として、スクロール方向を反転します。 \n` +
|
|
5111
|
+
`[Alternate] 交互にスクロール方向が反転するよう設定します。\n` +
|
|
5112
|
+
`[Twist] Crossの亜種で、もう少し細かくスクロール方向が反転するよう設定します。\n` +
|
|
5113
|
+
`[Asymmetry] Alternateの亜種で、基本的には交互にスクロール方向が反転するよう設定しますが、左右非対称になるよう設定します。\n` +
|
|
5114
|
+
`[AA-Split] アスキーアート(AA)のみスクロールを反転します。\n` +
|
|
5115
|
+
`[Flat] すべてのレーンが矢印の重なりに関係なく同じ方向に流れます。`,
|
|
5116
|
+
shuffle: `譜面を左右反転したり、ランダムにします。ランダムにした場合は別譜面扱いとなります。\nハイスコアは保存されるのはOFF,Mirror,X-Mirrorのみです。\n` +
|
|
5117
|
+
`[Mirror] 譜面をグループレーンごとに左右反転します。\n` +
|
|
5118
|
+
`[X-Mirror] Mirrorに対して、グループ内のレーン数が4, 5, 6, 7の倍数のとき中央の2, 3個(上下左右なら、上下矢印)のみさらに反転します。該当キーが無い場合は、Mirrorと同じです。\n` +
|
|
5119
|
+
`[Turning] 譜面をグループレーンごとに出現レーンを左右にスライドします。その上で反転する場合もあります。\n` +
|
|
5120
|
+
`[Random] 譜面をグループレーンごとにランダムに再配置します。\n` +
|
|
5121
|
+
`[Random+] 譜面をグループに関係なくレーンごとにランダムに再配置します。\n` +
|
|
5122
|
+
`[S-Random] 譜面をグループごとに矢印個別にランダムに再配置します。\n` +
|
|
5123
|
+
`[S-Random+] 譜面をグループに関係なく矢印個別にランダムに再配置します。\n` +
|
|
5124
|
+
`[Scatter] 譜面をグループごと、矢印個別に矢印・フリーズアローが散らばるように再配置します。\n` +
|
|
5125
|
+
`[Scatter+] 譜面をグループに関係なく、矢印個別に矢印・フリーズアローが散らばるように再配置します。`,
|
|
5091
5126
|
autoPlay: `オートプレイや一部キーを自動で打たせる設定を行います。\nオートプレイ時はハイスコアを保存しません。`,
|
|
5092
|
-
gauge: `クリア条件を設定します。\n
|
|
5127
|
+
gauge: `クリア条件を設定します。\n表にある表記は次の通りです。\n` +
|
|
5128
|
+
`- Start) ゲージ初期値\n- Border) クリア条件(ハイフン時は0)\n` +
|
|
5129
|
+
`- Recovery) 回復量\n- Damage) ダメージ量\n- Accuracy) クリアに必要な正確率、許容ミス数`,
|
|
5093
5130
|
excessive: `空押し判定を行うか設定します。`,
|
|
5094
|
-
adjustment:
|
|
5131
|
+
adjustment: `曲とのタイミングにズレを感じる場合、数値を変えることでフレーム単位のズレを直すことができます。\n` +
|
|
5132
|
+
`外側のボタンは5f刻み、真ん中は1f刻み、内側は0.5f刻みで調整できます。`,
|
|
5095
5133
|
fadein: `譜面を途中から再生します。\n途中から開始した場合はハイスコアを保存しません。`,
|
|
5096
5134
|
volume: `ゲーム内の音量を設定します。`,
|
|
5097
5135
|
|
|
@@ -5118,23 +5156,54 @@ const g_lang_msgObj = {
|
|
|
5118
5156
|
d_arroweffect: `矢印・フリーズアローモーションの有効化設定`,
|
|
5119
5157
|
d_special: `作品固有の特殊演出の有効化設定`,
|
|
5120
5158
|
|
|
5121
|
-
playWindow: `ステップゾーン及び矢印の位置を全体的に回転する等の設定です。\n
|
|
5122
|
-
`[
|
|
5159
|
+
playWindow: `ステップゾーン及び矢印の位置を全体的に回転する等の設定です。\n` +
|
|
5160
|
+
`[Stairs] ステップゾーン・矢印が階段状になるように表示します。\n` +
|
|
5161
|
+
`[Slope] Stairsよりさらに急になるように表示します。\n` +
|
|
5162
|
+
`[Distorted] ステップゾーン・矢印が歪んだ状態で表示します。\n` +
|
|
5163
|
+
`[SideScroll] 矢印が横スクロールで流れてきます。`,
|
|
5123
5164
|
playWindowType: `[Reverse] ステップゾーン及び矢印の位置について逆方向の回転が掛かります`,
|
|
5124
|
-
stepArea: `ステップゾーンの位置を変更します。\n
|
|
5125
|
-
`[
|
|
5126
|
-
`[
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
`[
|
|
5131
|
-
|
|
5132
|
-
`[
|
|
5133
|
-
|
|
5134
|
-
|
|
5165
|
+
stepArea: `ステップゾーンの位置を変更します。\n` +
|
|
5166
|
+
`[Halfway] ステップゾーンが中央に表示されます。\n` +
|
|
5167
|
+
`[2Step] ステップゾーンが2段に分かれて流れてきます。\n` +
|
|
5168
|
+
`[Mismatched] スクロールの向きが上下で異なる方向に流れます。\n` +
|
|
5169
|
+
`[R-Mismatched] Mismatchedに似ていますが、向きが反対になります。\n` +
|
|
5170
|
+
`[X-Flower] レーンが花びらのように広がります。\n` +
|
|
5171
|
+
`[Alt-Crossing] レーンが交互に違う方向から流れます。`,
|
|
5172
|
+
frzReturn: `フリーズアロー到達時及び矢印の回復判定が100の倍数に達するごとに、X/Y/Z軸のいずれかに回転します。\n` +
|
|
5173
|
+
`[X-Axis] X軸回転\n` +
|
|
5174
|
+
`[Y-Axis] Y軸回転\n` +
|
|
5175
|
+
`[Z-Axis] Z軸回転\n` +
|
|
5176
|
+
`[Random] X軸, Y軸, Z軸のいずれかが適用されます。\n` +
|
|
5177
|
+
`[XY-Axis] X-Y軸回転\n` +
|
|
5178
|
+
`[XZ-Axis] X-Z軸回転\n` +
|
|
5179
|
+
`[YZ-Axis] Y-Z軸回転\n` +
|
|
5180
|
+
`[Random+] X軸, Y軸, Z軸, X-Y軸, X-Z軸, Y-Z回転のいずれかが適用されます。`,
|
|
5181
|
+
frzReturnType: `回転幅を変更する設定です。\n[360°/120°/60°] 指定の角度まで回転します\n[±360°/±120°] 360°/120°に加えて逆回転が掛かることがあります\n[Pendulum] 振り子のように左右に動きます`,
|
|
5182
|
+
shaking: `ステップゾーン及び矢印を揺らす設定です。\n` +
|
|
5183
|
+
`[Horizontal] 横方向に揺らします。\n[Vertical] 縦方向に揺らします。\n` +
|
|
5184
|
+
`[X-Horizontal] レイヤーごとに左右交互の向きで横に揺らします。\n` +
|
|
5185
|
+
`[X-Vertical] レイヤーごとに上下交互の向きで縦に揺らします。\n` +
|
|
5186
|
+
`[Drunk] 画面全体を上下左右ランダムに揺らします。画面酔いに注意してください。\n` +
|
|
5187
|
+
`[S-Drunk] 画面全体を上下左右ランダムに揺らし、さらにレイヤーごとに上下左右に揺らします。\n` +
|
|
5188
|
+
`[H-Drunk] S-Drunkより大きく上下に揺らし、さらに回転が掛かります。`,
|
|
5189
|
+
effect: `矢印・フリーズアローにエフェクトをかけます。\n` +
|
|
5190
|
+
`[Dizzy] 矢印がZ軸回転します。\n` +
|
|
5191
|
+
`[Spin] 矢印がY軸回転します。\n` +
|
|
5192
|
+
`[Wave] 矢印とフリーズアローが左右に揺れながら移動します。\n` +
|
|
5193
|
+
`[Storm] 矢印とフリーズアローが左右に激しく揺れ、回転します。\n` +
|
|
5194
|
+
`[Blinking] 矢印が点滅します。\n[Squids] 矢印が伸び縮みします。`,
|
|
5195
|
+
camoufrage: `ステップの見た目が配置は同じでランダムに変わります。\n` +
|
|
5196
|
+
`[Color] 矢印とフリーズアローの色が他のものに擬態します。\n` +
|
|
5197
|
+
`[Arrow] 矢印とフリーズアローの矢印形状が他のものに擬態します。\n` +
|
|
5198
|
+
`[Step+Arrow] 矢印とフリーズアローの矢印形状・ステップゾーンが他のものに擬態します。\n` +
|
|
5199
|
+
`[Color+Arrow] 矢印とフリーズアローの色・矢印形状が他のものに擬態します。\n` +
|
|
5200
|
+
`[Color+Step+Arrow] 矢印とフリーズアローの色・矢印形状・ステップゾーン全てが他のものに擬態します。`,
|
|
5135
5201
|
camoufrageType: `[FrzArrow] フリーズアローの帯部分を初期表示のみ非表示にし、矢印のみで表示します(ヒット/失敗時は帯を再表示)`,
|
|
5136
|
-
swapping: `ステップゾーンの位置を入れ替える設定です。\n
|
|
5137
|
-
`[
|
|
5202
|
+
swapping: `ステップゾーンの位置を入れ替える設定です。\n` +
|
|
5203
|
+
`[InnerSwap] ステップゾーンの中央部分のみグループ単位で入れ替えます。\n` +
|
|
5204
|
+
`[OuterSwap] InnerSwapの逆側(外側)をグループ単位で入れ替えます。\n` +
|
|
5205
|
+
`[Mirror] ステップゾーンの位置をグループ単位で入れ替えます。\n` +
|
|
5206
|
+
`[Mirror+] ステップゾーンの位置をグループに関係なく全体的に反転します。`,
|
|
5138
5207
|
judgRange: `判定の許容範囲を設定します。\n[Normal] 通常、[Narrow/Hard] 辛判定、[ExHard] 激辛判定`,
|
|
5139
5208
|
autoRetry: `自動リトライの条件を設定します。\n[Miss] ミス時、[Matari] マターリ時、[Shakin] シャキン時、[FS] Fast/Slow発生時`,
|
|
5140
5209
|
|
|
@@ -5147,7 +5216,15 @@ const g_lang_msgObj = {
|
|
|
5147
5216
|
lnkResetHighScore: `譜面のハイスコア情報を消去`,
|
|
5148
5217
|
lnkHighScore: `譜面のハイスコアをクリップボードへコピー`,
|
|
5149
5218
|
|
|
5150
|
-
appearance:
|
|
5219
|
+
appearance: `流れる矢印の見え方を制御します。\n` +
|
|
5220
|
+
`[Hidden] 初めの50%までは見えますが、その後は見えなくなります。\n` +
|
|
5221
|
+
`[Hidden+] 基本的にHiddenと同じですが、Hiddenの可視範囲をプレイ中に調整できます。` +
|
|
5222
|
+
`初期値を10%~100%の間で設定できます。「Lock」ボタンで可視範囲の調整を不可にします。\n` +
|
|
5223
|
+
`[Sudden] 初めの40%までは見えませんが、その後は見えるようになります。\n` +
|
|
5224
|
+
`[Sudden+] 基本的にSuddenと同じですが、Suddenの可視範囲をプレイ中に調整できます。` +
|
|
5225
|
+
`初期値を0%~90%の間で設定できます。「Lock」ボタンで可視範囲の調整を不可にします。\n` +
|
|
5226
|
+
`[Hid&Sud+] Hidden+とSudden+を組み合わせて表示します。` +
|
|
5227
|
+
`初期値を0%~50%の間で設定できます。「Lock」ボタンで可視範囲の調整を不可にします。`,
|
|
5151
5228
|
opacity: `判定キャラクタ、コンボ数、Fast/Slowの透明度を設定します。`,
|
|
5152
5229
|
hitPosition: `判定位置にズレを感じる場合、\n数値を変えることで判定の中央位置を1px単位(プラス:手前, マイナス:奥側)で調整することができます。\n早押し・遅押し傾向にある場合に使用します。`,
|
|
5153
5230
|
displayPreview: `プレイ画面上のオブジェクトの表示状態をプレビューします。\n判定キャラクタ部分をドラッグで移動するとその位置に補正されます。`,
|
|
@@ -5195,14 +5272,41 @@ const g_lang_msgObj = {
|
|
|
5195
5272
|
|
|
5196
5273
|
difficulty: `Select a chart.`,
|
|
5197
5274
|
speed: `Set the speed of the sequences.\nThe outer button can be changed in 1x increments and the inner button in 0.25x increments.`,
|
|
5198
|
-
motion: `Set whether to turn on acceleration or deceleration
|
|
5275
|
+
motion: `Set whether to turn on acceleration or deceleration in the middle of the sequence.\n` +
|
|
5276
|
+
`[Boost] The speed starts at the initial speed and increases as it approaches the step zone.\n` +
|
|
5277
|
+
`[Hi-Boost] Similar to Boost, but the terminal speed increases in proportion to the initial speed.\n` +
|
|
5278
|
+
`[Brake] The speed starts fast and slows down as it approaches the step zone.\n` +
|
|
5279
|
+
`[Compress] The speed starts at the initial speed and gradually slows down as it approaches the step zone.\n` +
|
|
5280
|
+
`[Fountain] The sequences appear from the opposite side of the flow and turn back at the back of the screen to head towards the step zone.\n` +
|
|
5281
|
+
`[Magnet] Similar to Fountain, but turns back at the center of the screen.\n`,
|
|
5199
5282
|
reverse: `Set the flow direction of the sequences.`,
|
|
5200
|
-
scroll: `Set the scroll direction for each lane according to the pattern.\nIf "Reverse:ON" sets, reverse the scroll direction
|
|
5201
|
-
|
|
5283
|
+
scroll: `Set the scroll direction for each lane according to the pattern.\nIf "Reverse:ON" sets, reverse the scroll direction.\n` +
|
|
5284
|
+
`[Cross] Generally, set the flow to be default, reverse, and default.\n` +
|
|
5285
|
+
`[Split] Reverses the scroll direction with the center as the boundary.\n` +
|
|
5286
|
+
`[Alternate] Set the scroll direction to be reversed alternately.\n` +
|
|
5287
|
+
`[Twist] A variant of "Cross" that sets the scroll direction to be slightly more reversed.\n` +
|
|
5288
|
+
`[Asymmetry] A variant of "Alternate" that basically sets the scroll direction to be alternately reversed, but sets it to be asymmetrical.\n` +
|
|
5289
|
+
`[AA-Split] Reverses scrolling for ASCII art (AA) only.\n` +
|
|
5290
|
+
`[Flat] All lanes flow in the same direction regardless of arrow overlap.`,
|
|
5291
|
+
shuffle: `Flip the chart left and right or make it random.\nIf you make it random, it will be treated as a different chart.\n` +
|
|
5292
|
+
`Only when OFF, Mirror, or X-Mirror is selected, the high score will be saved.\n` +
|
|
5293
|
+
`[Mirror] Flip the chart left and right for each group lane.\n` +
|
|
5294
|
+
`[X-Mirror] In addition to Mirror, when the number of lanes in the group is a multiple of 4, 5, 6, or 7, only the center 2 or 3 (up and down arrows for up and down) are further flipped. If there are no corresponding keys, it will be the same as Mirror.\n` +
|
|
5295
|
+
`[Turning] Slide the appearance lane left and right for each group lane. In some cases, it may also be flipped.\n` +
|
|
5296
|
+
`[Random] Randomly rearrange the chart for each group lane.\n` +
|
|
5297
|
+
`[Random+] Randomly rearrange the chart for each lane regardless of the group.\n` +
|
|
5298
|
+
`[S-Random] Randomly rearrange the chart for each arrow in each group.\n` +
|
|
5299
|
+
`[S-Random+] Randomly rearrange the chart for each arrow regardless of the group.\n` +
|
|
5300
|
+
`[Scatter] Rearrange the chart so that arrows and freeze arrows are scattered for each group and each arrow.\n` +
|
|
5301
|
+
`[Scatter+] Rearrange the chart so that arrows and freeze arrows are scattered for each arrow regardless of the group.`,
|
|
5202
5302
|
autoPlay: `Set to auto play and to hit some keys automatically.\nHigh score is not saved during auto play.`,
|
|
5203
|
-
gauge: `Set the clear condition.\n
|
|
5303
|
+
gauge: `Set the clear condition.\n` +
|
|
5304
|
+
`The notation used in the table is as follows.\n` +
|
|
5305
|
+
`- Start) initial value\n- Border) borderline value (hyphen means zero)\n` +
|
|
5306
|
+
`- Recovery) recovery amount\n- Damage) damage amount\n- Accuracy) accuracy required to clear and the number of allowed mistakes`,
|
|
5204
5307
|
excessive: `Set whether to use excessive miss judgment.`,
|
|
5205
|
-
adjustment: `If you feel that the timing is out of sync with the music,
|
|
5308
|
+
adjustment: `If you feel that the timing is out of sync with the music, you can correct the shift in frame units by changing the value.\n` +
|
|
5309
|
+
`The outer button can be adjusted in 5 frame increments, the middle in 1 frame increments, and the inner button in 0.5 frame increments.`,
|
|
5206
5310
|
fadein: `Plays the chart from the middle.\nIf you start in the middle, the high score will not be saved.`,
|
|
5207
5311
|
volume: `Set the in-game volume.`,
|
|
5208
5312
|
|
|
@@ -5227,26 +5331,54 @@ const g_lang_msgObj = {
|
|
|
5227
5331
|
d_arroweffect: `Enable sequences' animations`,
|
|
5228
5332
|
d_special: `Enable setting of special effects to the work`,
|
|
5229
5333
|
|
|
5230
|
-
playWindow: `This is the setting for overall rotation of the step zone and arrow position, etc.\n
|
|
5231
|
-
`[
|
|
5334
|
+
playWindow: `This is the setting for overall rotation of the step zone and arrow position, etc.\n` +
|
|
5335
|
+
`[Stairs] Step zones/arrows are displayed in a staircase-like pattern.\n` +
|
|
5336
|
+
`[Slope] Step zone arrows are shown steeper than Stairs.\n` +
|
|
5337
|
+
`[Distorted] Step zones and arrows are shown distorted.\n` +
|
|
5338
|
+
`[SideScroll] The arrows scroll horizontally.`,
|
|
5232
5339
|
playWindowType: `[Reverse] Applies reverse rotation to the step zone and arrow positions.`,
|
|
5233
|
-
stepArea: `Change the position of the step zone.\n
|
|
5234
|
-
`[
|
|
5340
|
+
stepArea: `Change the position of the step zone.\n` +
|
|
5341
|
+
`[Halfway] Step zones are centered.\n[2Step] Step zones are divided into two layers.\n` +
|
|
5342
|
+
`[Mismatched] Scroll direction flows in different directions up and down.\n` +
|
|
5343
|
+
`[R-Mismatched] It's similar to "Mismatched", but the orientation is reversed.\n` +
|
|
5235
5344
|
`[X-Flower] Lanes spread out like flower petals.\n[Alt-Crossing] Lanes flow from different directions alternately.`,
|
|
5236
|
-
frzReturn: `When the Freeze Arrow is reached, and every time the arrow's recovery judgment \
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
`[
|
|
5345
|
+
frzReturn: `When the Freeze Arrow is reached, and every time the arrow's recovery judgment \n` +
|
|
5346
|
+
`reaches a multiple of 100, it will rotate on either the X, Y, or Z axis.\n` +
|
|
5347
|
+
`[X-Axis] X-axis rotation\n` +
|
|
5348
|
+
`[Y-Axis] Y-axis rotation\n` +
|
|
5349
|
+
`[Z-Axis] Z-axis rotation\n` +
|
|
5350
|
+
`[Random] Randomly rotates to one of the X/Y/Z axes.\n` +
|
|
5351
|
+
`[XY-Axis] X-Y axis rotation\n` +
|
|
5352
|
+
`[XZ-Axis] X-Z axis rotation\n` +
|
|
5353
|
+
`[YZ-Axis] Y-Z axis rotation\n` +
|
|
5354
|
+
`[Random+] Randomly rotates to one of the X/Y/Z/X-Y/X-Z/Y-Z axes.`,
|
|
5355
|
+
frzReturnType: `Set the rotation range.\n[360deg/120deg/60deg] Rotates to the specified angle.\n[±360deg/±120deg] May rotate in the opposite direction in addition to 360deg/120deg.\n[Pendulum] Moves back and forth like a pendulum.`,
|
|
5356
|
+
shaking: `This sets shaking for the step zone and arrows.\n` +
|
|
5357
|
+
`[Horizontal] Shakes horizontally.\n[Vertical] Shakes vertically.\n` +
|
|
5358
|
+
`[X-Horizontal] Per-layer shaking with alternating left/right direction by layer.\n` +
|
|
5359
|
+
`[X-Vertical] Per-layer shaking with alternating up/down direction by layer.\n` +
|
|
5240
5360
|
`[Drunk] Shakes the entire screen randomly in all directions (may cause motion sickness).\n` +
|
|
5241
5361
|
`[S-Drunk] Shakes the entire screen randomly in all directions, and also shakes each layer randomly in all directions.\n` +
|
|
5242
5362
|
`[H-Drunk] Adds stronger vertical movement than S-Drunk and adds rotation.`,
|
|
5243
5363
|
effect: `Applies effects to the arrows and freeze arrows.\n[Dizzy/Spin] Arrows rotate.\n[Wave/Storm] Swing from left to right.\n[Blinking] Arrows blink.\n[Squids] Arrows stretch and shrink.`,
|
|
5244
|
-
camoufrage: `The appearance of the steps changes randomly with the same placement
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
`[
|
|
5364
|
+
camoufrage: `The appearance of the steps changes randomly with the same placement.\n` +
|
|
5365
|
+
`[Color] The color of the arrows and freeze arrows mimics other objects.\n` +
|
|
5366
|
+
`[Arrow] The arrow shape of the arrows and freeze arrows mimics other objects.\n` +
|
|
5367
|
+
`[Step+Arrow] The arrow shape and step zone of the arrows and freeze arrows mimics other objects.\n` +
|
|
5368
|
+
`[Color+Arrow] The color and arrow shape of the arrows and freeze arrows mimics other objects.\n` +
|
|
5369
|
+
`[Color+Step+Arrow] The color, arrow shape, and step zone of the arrows and freeze arrows mimics other objects.`,
|
|
5370
|
+
camoufrageType: `[FrzArrow] Initially hides freeze-arrow bars and displays only the arrow portion (bars reappear on hit/failure).`,
|
|
5371
|
+
swapping: `This setting allows you to swap the positions of the step zones.\n` +
|
|
5372
|
+
`[InnerSwap] Swaps only the inner portion of step zones within each shuffle group.\n` +
|
|
5373
|
+
`[OuterSwap] Swaps the outer portion (inverse of InnerSwap) within each shuffle group.\n` +
|
|
5374
|
+
`[Mirror] Swaps the positions of step zones within each shuffle group. \n` +
|
|
5375
|
+
`[Mirror+] Flips the position of all step zones, regardless of shuffle groups. `,
|
|
5248
5376
|
judgRange: `Set the allowable range of judgment.\n[Normal] Normal judgment, [Narrow/Hard] Hard judgment, [ExHard] Very hard judgment`,
|
|
5249
|
-
autoRetry: `Set the conditions for automatic retry.\n
|
|
5377
|
+
autoRetry: `Set the conditions for automatic retry.\n` +
|
|
5378
|
+
`[Miss] When missed\n` +
|
|
5379
|
+
`[Matari(Good)] When good\n` +
|
|
5380
|
+
`[Shakin(Great)] When great\n` +
|
|
5381
|
+
`[Fast/Slow] When Fast/Slow occurs`,
|
|
5250
5382
|
|
|
5251
5383
|
lnkSpeedG: `Displays the velocity change status by progression of the chart.`,
|
|
5252
5384
|
lnkDensityG: `Displays the density status of the chart.`,
|
|
@@ -5257,9 +5389,19 @@ const g_lang_msgObj = {
|
|
|
5257
5389
|
lnkResetHighScore: `Erase the high score information in the chart.`,
|
|
5258
5390
|
lnkHighScore: `Copies the high score of the chart to the clipboard.`,
|
|
5259
5391
|
|
|
5260
|
-
appearance: `Controls how the flowing sequences look
|
|
5392
|
+
appearance: `Controls how the flowing sequences look.\n` +
|
|
5393
|
+
`[Hidden] Visible up to the first 50%, then disappears.\n` +
|
|
5394
|
+
`[Hidden+] Same as "Hidden", but the visibility of "Hidden" can be adjusted during play. ` +
|
|
5395
|
+
`The initial value can be set between 10% and 100%. The "Lock" button disables adjustment of the visible range.\n` +
|
|
5396
|
+
`[Sudden] Not visible until first 40%, then visible.\n` +
|
|
5397
|
+
`[Sudden+] Same as "Sudden", but the visibility of "Sudden" can be adjusted during play. The initial value can be set ` +
|
|
5398
|
+
`between 0% and 90%. The "Lock" button disables adjustment of the visible range.\n` +
|
|
5399
|
+
`[Hid&Sud+] The combination of "Hidden+" and "Sudden+" is displayed. The initial value can be set between 0% and 50%. ` +
|
|
5400
|
+
`The "Lock" button disables adjustment of the visible range.`,
|
|
5401
|
+
opacity: `判定キャラクタ、コンボ数、Fast/Slowの透明度を設定します。`,
|
|
5261
5402
|
opacity: `Set the transparency of some objects such as judgment, combo counts, fast and slow`,
|
|
5262
|
-
hitPosition: `If you feel a discrepancy in the judgment position,
|
|
5403
|
+
hitPosition: `If you feel a discrepancy in the judgment position, you can adjust the center position of the judgment in 1px increments (plus: in front, minus: at the back) by changing the numerical value. \n` +
|
|
5404
|
+
`Use this function when there is a tendency to push too fast or too slow.`,
|
|
5263
5405
|
displayPreview: `Preview the display status of objects on the play screen.\nDragging the judgment character section will adjust it to that position.`,
|
|
5264
5406
|
displayPreviewResetConfirm: `Reset the position of objects on the play screen to the initial state. Is it OK?`,
|
|
5265
5407
|
|
|
@@ -5312,6 +5454,8 @@ const g_customJsObj = {
|
|
|
5312
5454
|
difficulty: [],
|
|
5313
5455
|
settingsDisplay: [],
|
|
5314
5456
|
displayPreview: [],
|
|
5457
|
+
helpOverlay: [],
|
|
5458
|
+
helpPreview: [],
|
|
5315
5459
|
exSetting: [],
|
|
5316
5460
|
settingSummary: [],
|
|
5317
5461
|
keyconfig: [],
|
package/js/lib/settings.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dancing☆Onigiri (CW Edition)
|
|
3
3
|
* Settings, Display, Ex-Settings画面
|
|
4
|
-
* - ページ: option, difSelector, scoreDetail, settingsDisplay, displayPreview, exSetting
|
|
4
|
+
* - ページ: option, difSelector, scoreDetail, settingsDisplay, displayPreview, exSetting, helpOverlay
|
|
5
5
|
*
|
|
6
6
|
* Source by tickle
|
|
7
7
|
* Created : 2026/09/13
|
|
8
|
-
* Revised : 2026/
|
|
8
|
+
* Revised : 2026/11/03 (v52.1.0)
|
|
9
9
|
*
|
|
10
10
|
* https://github.com/cwtickle/danoniplus
|
|
11
11
|
*/
|
|
@@ -2002,10 +2002,941 @@ const createLblSetting = (_settingName, _adjY = 0, _settingLabel = _settingName)
|
|
|
2002
2002
|
const lbl = createDivCss2Label(`lbl${_settingName}`, g_lblNameObj[_settingLabel], {
|
|
2003
2003
|
x: -5, y: _adjY, w: 110, pointerEvents: C_DIS_AUTO,
|
|
2004
2004
|
}, `settings_${_settingName}`);
|
|
2005
|
-
|
|
2005
|
+
const msgKey = `${_settingName.charAt(0).toLowerCase()}${_settingName.slice(1)}`;
|
|
2006
|
+
attachHelp(lbl, g_msgObj[msgKey], { title: g_lblNameObj[_settingLabel], stateKey: msgKey });
|
|
2006
2007
|
return lbl;
|
|
2007
2008
|
};
|
|
2008
2009
|
|
|
2010
|
+
/**
|
|
2011
|
+
* 要素にヘルプを付与する
|
|
2012
|
+
* - 短文: 従来どおり title のみ
|
|
2013
|
+
* - 長文: title は1行目のみ。クリックで全文オーバーレイを表示
|
|
2014
|
+
* @param {HTMLElement} _elem
|
|
2015
|
+
* @param {string} _msg g_msgObj の文字列(文面はユーザが上書き可能なため、構造は仮定しない)
|
|
2016
|
+
* @param {string} [object.title=''] オーバーレイの見出し
|
|
2017
|
+
* @param {string} [object.stateKey=''] 現在値の突き合わせ先 (g_stateObj のキー)
|
|
2018
|
+
*/
|
|
2019
|
+
const attachHelp = (_elem, _msg, { title = ``, stateKey = `` } = {}) => {
|
|
2020
|
+
if (!hasVal(_msg)) return;
|
|
2021
|
+
const longFlg = isLongHelp(_msg);
|
|
2022
|
+
if (!longFlg && g_helpPreviewDefs[stateKey] === undefined) {
|
|
2023
|
+
_elem.title = _msg;
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
_elem.title = longFlg ? `${_msg.split(/\r?\n/)[0]} …` : _msg;
|
|
2027
|
+
_elem.style.cursor = `help`;
|
|
2028
|
+
g_handler.addListener(_elem, `click`, () => openHelpOverlay(title, _msg, stateKey));
|
|
2029
|
+
};
|
|
2030
|
+
|
|
2031
|
+
/**
|
|
2032
|
+
* ヘルプ文面を行ごとに分解する
|
|
2033
|
+
* `[名前] 説明` 形式の行は選択肢行、それ以外は通常の文として扱う
|
|
2034
|
+
* @param {string} _msg
|
|
2035
|
+
* @returns {{ name?: string, desc?: string, text?: string }[]}
|
|
2036
|
+
*/
|
|
2037
|
+
const parseHelpLines = _msg => _msg.split(/\r?\n/).map(line => {
|
|
2038
|
+
const m = line.match(/^\[(.+?)\]\s*(.*)$/);
|
|
2039
|
+
return m ? { name: m[1], desc: m[2] } : { text: line };
|
|
2040
|
+
});
|
|
2041
|
+
|
|
2042
|
+
/**
|
|
2043
|
+
* 詳細ヘルプのオーバーレイを開く
|
|
2044
|
+
* @param {string} _title
|
|
2045
|
+
* @param {string} _msg
|
|
2046
|
+
* @param {string} _stateKey
|
|
2047
|
+
*/
|
|
2048
|
+
const openHelpOverlay = (_title, _msg, _stateKey) => {
|
|
2049
|
+
const divRoot = document.getElementById(`divRoot`);
|
|
2050
|
+
if (!divRoot || document.getElementById(`helpOverlay`) !== null) return;
|
|
2051
|
+
if (![`option`, `exSetting`, `settingsDisplay`].includes(g_currentPage)) return;
|
|
2052
|
+
|
|
2053
|
+
// 現在値は、g_currentPage を切り替える前に取得する(getStgDetailName が画面名を参照するため)
|
|
2054
|
+
const sub = g_helpPreviewDefs[_stateKey]?.sub || (_stateKey + `Type`);
|
|
2055
|
+
const subList = sub !== undefined ? (g_settings[`${sub}s`] ?? []) : [];
|
|
2056
|
+
const currentVals = [g_stateObj[_stateKey], ...(subList.length > 0 ? [g_stateObj[sub]] : [])];
|
|
2057
|
+
const currentNames = currentVals.flatMap(val => [val, getStgDetailName(val)]);
|
|
2058
|
+
const optNames = new Map([...(g_settings[`${_stateKey}s`] ?? []), ...subList]
|
|
2059
|
+
.map(val => [val, [val, getStgDetailName(val)]]));
|
|
2060
|
+
|
|
2061
|
+
// Typeがある設定は、本体の説明文の後にTypeの説明文を続ける
|
|
2062
|
+
const helpMsg = [_msg, ...(subList.length > 0 ? [g_msgObj[sub]] : [])].filter(hasVal).join(`\n\n`);
|
|
2063
|
+
const rowElms = [];
|
|
2064
|
+
const bright = g_headerObj.baseBrightFlg;
|
|
2065
|
+
|
|
2066
|
+
g_helpPrevPage = g_currentPage;
|
|
2067
|
+
g_currentPage = `helpOverlay`;
|
|
2068
|
+
|
|
2069
|
+
const overlay = createEmptySprite(divRoot, `helpOverlay`, {
|
|
2070
|
+
w: g_sWidth, h: g_sHeight, background: bright ? `#eeeeeeee` : `#111111ee`, pointerEvents: C_DIS_AUTO,
|
|
2071
|
+
});
|
|
2072
|
+
// オーバーレイ自身(背景)をクリックしたときだけ閉じる。子要素(隠しボタン等)のクリックは対象外
|
|
2073
|
+
g_handler.addListener(overlay, `click`, evt => {
|
|
2074
|
+
if (evt.target === overlay) {
|
|
2075
|
+
closeHelpOverlay();
|
|
2076
|
+
}
|
|
2077
|
+
});
|
|
2078
|
+
|
|
2079
|
+
// プレビューがある設定は、本文の下にプレビュー領域を確保する
|
|
2080
|
+
const previewH = g_helpPreviewDefs[_stateKey] === undefined ? 0 : Math.round(g_sHeight * g_limitObj.helpPreviewRate);
|
|
2081
|
+
|
|
2082
|
+
// 本文(スクロール可)。本文内のクリックでは閉じない
|
|
2083
|
+
const body = createEmptySprite(overlay, `helpBody`, {
|
|
2084
|
+
x: 30, y: 60, w: g_sWidth - 60, h: g_sHeight - 90 - (previewH > 0 ? previewH + 10 : 0),
|
|
2085
|
+
overflowY: `auto`, pointerEvents: C_DIS_AUTO,
|
|
2086
|
+
});
|
|
2087
|
+
g_handler.addListener(body, `click`, evt => evt.stopPropagation());
|
|
2088
|
+
|
|
2089
|
+
parseHelpLines(helpMsg).forEach(line => {
|
|
2090
|
+
const row = document.createElement(`div`);
|
|
2091
|
+
Object.assign(row.style, {
|
|
2092
|
+
fontFamily: getBasicFont(), fontSize: wUnit(14), lineHeight: `1.1`, textAlign: `left`,
|
|
2093
|
+
whiteSpace: `normal`, wordBreak: `break-word`, padding: `2px 6px`,
|
|
2094
|
+
color: bright ? `#222222` : `#eeeeee`,
|
|
2095
|
+
});
|
|
2096
|
+
if (line.name === undefined) {
|
|
2097
|
+
row.textContent = line.text;
|
|
2098
|
+
if (line.text === ``) row.style.height = `0.8em`;
|
|
2099
|
+
} else {
|
|
2100
|
+
const nameList = line.name.split(`/`).map(name => name.trim());
|
|
2101
|
+
const isCurrent = nameList.some(name => currentNames.includes(name));
|
|
2102
|
+
const nameElm = document.createElement(`span`);
|
|
2103
|
+
const descElm = document.createElement(`span`);
|
|
2104
|
+
nameElm.textContent = `[${line.name}]`;
|
|
2105
|
+
nameElm.style.fontWeight = `bold`;
|
|
2106
|
+
descElm.textContent = line.desc;
|
|
2107
|
+
Object.assign(row.style, {
|
|
2108
|
+
display: `grid`, gridTemplateColumns: `10em 1fr`, columnGap: `0.8em`,
|
|
2109
|
+
borderLeft: `3px solid ${isCurrent ? `#66aaff` : `transparent`}`,
|
|
2110
|
+
});
|
|
2111
|
+
row.append(nameElm, descElm);
|
|
2112
|
+
rowElms.push({ nameList, row });
|
|
2113
|
+
}
|
|
2114
|
+
body.appendChild(row);
|
|
2115
|
+
});
|
|
2116
|
+
|
|
2117
|
+
// 説明文の選択行 (背景) をプレビューのカーソルに追従させる
|
|
2118
|
+
const markHelpRows = (_vals, _focus = 0) => {
|
|
2119
|
+
const names = _vals.flatMap(val => optNames.get(val) ?? [val]);
|
|
2120
|
+
const focusNames = optNames.get(_vals[_focus]) ?? [_vals[_focus]];
|
|
2121
|
+
rowElms.forEach(({ nameList, row }) => {
|
|
2122
|
+
const on = nameList.some(name => names.includes(name));
|
|
2123
|
+
row.style.background = on ? `rgba(80,140,255,0.25)` : ``;
|
|
2124
|
+
if (nameList.some(name => focusNames.includes(name))) {
|
|
2125
|
+
// 本文がスクロールする場合は、選択行が見える位置へ寄せる
|
|
2126
|
+
const [top, bottom] = [row.offsetTop, row.offsetTop + row.offsetHeight];
|
|
2127
|
+
if (top < body.scrollTop) {
|
|
2128
|
+
body.scrollTop = top;
|
|
2129
|
+
} else if (bottom > body.scrollTop + body.clientHeight) {
|
|
2130
|
+
body.scrollTop = bottom - body.clientHeight;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
};
|
|
2135
|
+
markHelpRows(currentVals);
|
|
2136
|
+
g_helpSelectHook = markHelpRows;
|
|
2137
|
+
|
|
2138
|
+
// 上下キー: プレビューの選択肢移動、または本文のスクロール
|
|
2139
|
+
const moveHelp = _dir => {
|
|
2140
|
+
if (previewH > 0) {
|
|
2141
|
+
g_helpPreviewMove(_dir);
|
|
2142
|
+
} else {
|
|
2143
|
+
body.scrollTop += _dir * 32;
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2146
|
+
|
|
2147
|
+
multiAppend(overlay,
|
|
2148
|
+
createDivCss2Label(`lblHelpTitle`, _title, { x: 0, y: 15, w: g_sWidth, h: 30, siz: 20 }),
|
|
2149
|
+
createCss2Button(`btnHelpClose`, g_lblNameObj.b_back, () => true, {
|
|
2150
|
+
x: g_btnX() + 30, y: 15, w: 100, h: 30, siz: 14, resetFunc: () => closeHelpOverlay(),
|
|
2151
|
+
}, g_cssObj.button_Back),
|
|
2152
|
+
|
|
2153
|
+
// 選択肢の前後移動 (ショートカットキー専用の隠しボタン)
|
|
2154
|
+
createCss2Button(`btnHelpPrev`, ``, () => true, {
|
|
2155
|
+
x: 0, y: 0, w: 0, h: 0, opacity: 0, resetFunc: () => moveHelp(-1),
|
|
2156
|
+
}, g_cssObj.button_Mini),
|
|
2157
|
+
createCss2Button(`btnHelpNext`, ``, () => true, {
|
|
2158
|
+
x: 0, y: 0, w: 0, h: 0, opacity: 0, resetFunc: () => moveHelp(1),
|
|
2159
|
+
}, g_cssObj.button_Mini),
|
|
2160
|
+
|
|
2161
|
+
// 操作対象の列の切り替え (本体 / Type)
|
|
2162
|
+
createCss2Button(`btnHelpLeft`, ``, () => true, {
|
|
2163
|
+
x: 0, y: 0, w: 0, h: 0, opacity: 0, resetFunc: () => g_helpPreviewColumn(-1),
|
|
2164
|
+
}, g_cssObj.button_Mini),
|
|
2165
|
+
createCss2Button(`btnHelpRight`, ``, () => true, {
|
|
2166
|
+
x: 0, y: 0, w: 0, h: 0, opacity: 0, resetFunc: () => g_helpPreviewColumn(1),
|
|
2167
|
+
}, g_cssObj.button_Mini),
|
|
2168
|
+
);
|
|
2169
|
+
createScText(btnHelpClose, `HelpClose`, { displayName: `helpOverlay`, targetLabel: `btnHelpClose`, x: -5 });
|
|
2170
|
+
if (previewH > 0) {
|
|
2171
|
+
makeHelpPreview(overlay, _stateKey, g_sHeight - 30 - previewH, previewH);
|
|
2172
|
+
}
|
|
2173
|
+
// ユーザカスタムイベント(ヘルプ表示)
|
|
2174
|
+
safeExecuteCustomHooks(`g_customJsObj.helpOverlay`, g_customJsObj.helpOverlay);
|
|
2175
|
+
|
|
2176
|
+
setShortcutEvent(g_currentPage, () => true, { displayFlg: false });
|
|
2177
|
+
};
|
|
2178
|
+
|
|
2179
|
+
/**
|
|
2180
|
+
* 詳細ヘルプのオーバーレイを閉じ、元の画面のショートカットを復帰する
|
|
2181
|
+
*/
|
|
2182
|
+
const closeHelpOverlay = () => {
|
|
2183
|
+
const overlay = document.getElementById(`helpOverlay`);
|
|
2184
|
+
if (overlay === null) return;
|
|
2185
|
+
g_helpPreviewStop();
|
|
2186
|
+
g_helpSelectHook = _val => true;
|
|
2187
|
+
deleteChildspriteAll(`helpOverlay`);
|
|
2188
|
+
overlay.remove();
|
|
2189
|
+
g_currentPage = g_helpPrevPage;
|
|
2190
|
+
setShortcutEvent(g_currentPage, () => true, {
|
|
2191
|
+
displayFlg: false, dfEvtFlg: g_currentPage !== `settingsDisplay`,
|
|
2192
|
+
});
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
/** 詳細ヘルプを開く直前のページ名 */
|
|
2196
|
+
let g_helpPrevPage = ``;
|
|
2197
|
+
|
|
2198
|
+
/** プレビューの選択が変わったときに、説明文の選択行を更新する処理 (ヘルプ表示中のみ差し替わる) */
|
|
2199
|
+
let g_helpSelectHook = _val => true;
|
|
2200
|
+
|
|
2201
|
+
/**
|
|
2202
|
+
* 詳細ヘルプを出すべき長文かどうかの判定
|
|
2203
|
+
* @param {string} _msg
|
|
2204
|
+
* @returns {boolean}
|
|
2205
|
+
*/
|
|
2206
|
+
const isLongHelp = _msg =>
|
|
2207
|
+
_msg.split(/\r?\n/).length - 1 >= g_limitObj.helpLongLines || _msg.length > g_limitObj.helpLongChars;
|
|
2208
|
+
|
|
2209
|
+
/*-----------------------------------------------------------*/
|
|
2210
|
+
/* 詳細ヘルプ内プレビュー */
|
|
2211
|
+
/*-----------------------------------------------------------*/
|
|
2212
|
+
|
|
2213
|
+
/**
|
|
2214
|
+
* 詳細ヘルプ内でプレビューを出す設定
|
|
2215
|
+
* - キー名は g_stateObj のキー名 (選択肢は g_settings[`${key}s`] を使用)
|
|
2216
|
+
* - splitLayer: 右半分のレーンを逆スクロール(レイヤー1)側に配置する
|
|
2217
|
+
* - currentKey: サンプルキーではなく実際のキーに合わせてマッピングする
|
|
2218
|
+
* (StepArea, Swappingは実際のキーには非対応)
|
|
2219
|
+
* - frzUse : サンプルでフリーズアローを使用するかどうか
|
|
2220
|
+
* - sub : 派生する設定 (Typeなど)。選択肢の列を2列目に追加する
|
|
2221
|
+
*/
|
|
2222
|
+
const g_helpPreviewDefs = {
|
|
2223
|
+
motion: {},
|
|
2224
|
+
scroll: { currentKey: true },
|
|
2225
|
+
appearance: { splitLayer: true },
|
|
2226
|
+
playWindow: { sub: `playWindowType` },
|
|
2227
|
+
stepArea: {},
|
|
2228
|
+
shaking: { splitLayer: true },
|
|
2229
|
+
frzReturn: { sub: `frzReturnType` },
|
|
2230
|
+
effect: { frzUse: true, splitLayer: true },
|
|
2231
|
+
swapping: { frzUse: true },
|
|
2232
|
+
};
|
|
2233
|
+
|
|
2234
|
+
/**
|
|
2235
|
+
* StepAreaプレビュー用のレーン配置 (4レーン分のレイヤー番号。偶数: 通常スクロール、奇数: 逆スクロール)
|
|
2236
|
+
* - キー非依存のため、サンプル用に定義
|
|
2237
|
+
*/
|
|
2238
|
+
const g_helpStepAreaLayouts = {
|
|
2239
|
+
Default: [0, 0, 0, 0],
|
|
2240
|
+
Halfway: [0, 0, 1, 1],
|
|
2241
|
+
'2Step': [0, 0, 2, 2],
|
|
2242
|
+
Mismatched: [0, 0, 1, 1],
|
|
2243
|
+
'R-Mismatched': [0, 0, 1, 1],
|
|
2244
|
+
'X-Flower': [0, 0, 2, 2],
|
|
2245
|
+
'Alt-Crossing': [0, 2, 0, 2],
|
|
2246
|
+
};
|
|
2247
|
+
|
|
2248
|
+
/**
|
|
2249
|
+
* Swappingプレビュー用のレーン配置
|
|
2250
|
+
*/
|
|
2251
|
+
const g_helpSwappingLayouts = {
|
|
2252
|
+
OFF: [0, 1, 2, 3],
|
|
2253
|
+
InnerSwap: [0, 2, 1, 3],
|
|
2254
|
+
OuterSwap: [3, 1, 2, 0],
|
|
2255
|
+
Mirror: [3, 2, 1, 0],
|
|
2256
|
+
'Mirror+': [3, 2, 1, 0],
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
/** プレビューの停止処理 (プレビュー表示中のみ差し替わる) */
|
|
2260
|
+
let g_helpPreviewStop = () => true;
|
|
2261
|
+
|
|
2262
|
+
/** プレビューの選択肢を前後へ動かす処理 (プレビュー表示中のみ差し替わる) */
|
|
2263
|
+
let g_helpPreviewMove = _dir => true;
|
|
2264
|
+
|
|
2265
|
+
/** プレビューの操作対象の列を切り替える処理 (-1: 本体、1: Type。プレビュー表示中のみ差し替わる) */
|
|
2266
|
+
let g_helpPreviewColumn = _dir => true;
|
|
2267
|
+
|
|
2268
|
+
/**
|
|
2269
|
+
* 詳細ヘルプ内プレビューの作成
|
|
2270
|
+
* @param {HTMLDivElement} _parent オーバーレイ
|
|
2271
|
+
* @param {string} _key g_helpPreviewDefs のキー
|
|
2272
|
+
* @param {number} _top 配置Y座標
|
|
2273
|
+
* @param {number} _height 領域の高さ
|
|
2274
|
+
*/
|
|
2275
|
+
const makeHelpPreview = (_parent, _key, _top, _height) => {
|
|
2276
|
+
const def = g_helpPreviewDefs[_key];
|
|
2277
|
+
const optList = g_settings[`${_key}s`];
|
|
2278
|
+
if (def === undefined || optList === undefined || document.getElementById(`mainSprite`) !== null) {
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
const playH = g_headerObj.playingHeight || g_sHeight;
|
|
2282
|
+
const subList = def.sub !== undefined ? g_settings[`${def.sub}s`] : undefined;
|
|
2283
|
+
const subUse = subList !== undefined;
|
|
2284
|
+
const colW = subUse ? 90 : 120;
|
|
2285
|
+
const chipW = subUse ? colW * 2 + 6 : colW; // 選択肢ボタン列の全体幅 (Typeがある場合は2列)
|
|
2286
|
+
const areaW = g_sWidth - 60;
|
|
2287
|
+
|
|
2288
|
+
// レーン定義: Scrollのみ現在選択中のキー・パターンの定義を使用 (他は4レーン固定)
|
|
2289
|
+
const tkObj = def.currentKey === true ? getKeyInfo() : null;
|
|
2290
|
+
const useKey = tkObj !== null && tkObj.keyNum > 0;
|
|
2291
|
+
const keyCtrlPtn = useKey ? tkObj.keyCtrlPtn : ``;
|
|
2292
|
+
const laneNum = useKey ? tkObj.keyNum : 4;
|
|
2293
|
+
const laneW = (useKey ? g_keyObj[`blank${keyCtrlPtn}`] : null) ?? g_keyObj.blank_def;
|
|
2294
|
+
const keyPos = useKey ? g_keyObj[`pos${keyCtrlPtn}`] : null;
|
|
2295
|
+
|
|
2296
|
+
// 表示するレーン (キースイッチがあるキーは、選択中のキーグループのレーンのみ)
|
|
2297
|
+
const configKeyGroupList = useKey
|
|
2298
|
+
? (g_headerObj.keyGroupOrder?.[g_stateObj.scoreId] ?? g_keyObj[`keyGroupOrder${keyCtrlPtn}`] ?? tkObj.keyGroupList)
|
|
2299
|
+
: [];
|
|
2300
|
+
const activeGroup = configKeyGroupList[g_keycons.keySwitchNum] ?? configKeyGroupList[0];
|
|
2301
|
+
const laneVisible = [...Array(laneNum).keys()].map(j =>
|
|
2302
|
+
!useKey || configKeyGroupList.length <= 1 || (tkObj.keyGroupMaps[j]?.includes(activeGroup) ?? true));
|
|
2303
|
+
const visibleLanes = [...Array(laneNum).keys()].filter(j => laneVisible[j]);
|
|
2304
|
+
if (visibleLanes.length === 0) {
|
|
2305
|
+
visibleLanes.push(...Array(laneNum).keys()); // 該当レーンが無い場合は全て表示
|
|
2306
|
+
laneVisible.fill(true);
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// 段 (下段: pos が divideCnt を超えるレーン) と、中央からのX座標差分
|
|
2310
|
+
// prepareScoreData の stdPos と同じ式。下段は既定で逆スクロールになる
|
|
2311
|
+
const laneLower = [...Array(laneNum).keys()].map(j => useKey && keyPos[j] > tkObj.divideCnt);
|
|
2312
|
+
const laneOffsets = [...Array(laneNum).keys()].map(j => useKey
|
|
2313
|
+
? laneW * (keyPos[j] - ((laneLower[j] ? tkObj.posMax : 0) + tkObj.divideCnt) / 2)
|
|
2314
|
+
: (j - (laneNum - 1) / 2) * laneW);
|
|
2315
|
+
|
|
2316
|
+
// レイヤー数 (layerGroup 指定のあるキーは4を超える)
|
|
2317
|
+
const baseLayers = useKey ? (g_keyObj[`layerGroup${keyCtrlPtn}`] ?? []) : [];
|
|
2318
|
+
const layerCnt = Math.max(4, (Math.max(0, ...baseLayers) + 1) * 2);
|
|
2319
|
+
|
|
2320
|
+
// キーが多い場合はフレームを広げ、縮小率で収める
|
|
2321
|
+
const halfSpan = Math.max(...laneOffsets.map(Math.abs)) + C_ARW_WIDTH / 2;
|
|
2322
|
+
const playW = Math.max(g_headerObj.playingWidth || g_sWidth, Math.ceil(halfSpan * 2) + 60);
|
|
2323
|
+
const rate = Math.min(g_limitObj.helpPreviewMaxRate, _height / playH, (areaW - chipW - 15) / playW);
|
|
2324
|
+
const viewW = Math.round(playW * rate);
|
|
2325
|
+
const baseX = Math.max(Math.round((areaW - viewW - chipW - 15) / 2), 0);
|
|
2326
|
+
|
|
2327
|
+
// 領域内のクリックでオーバーレイが閉じないようにする
|
|
2328
|
+
const area = createEmptySprite(_parent, `helpPreview`, {
|
|
2329
|
+
x: 30, y: _top, w: areaW, h: _height, pointerEvents: C_DIS_AUTO,
|
|
2330
|
+
});
|
|
2331
|
+
g_handler.addListener(area, `click`, evt => evt.stopPropagation());
|
|
2332
|
+
|
|
2333
|
+
// ---------------------------------------------------
|
|
2334
|
+
// ミニプレイ画面 (縮小表示)
|
|
2335
|
+
const scaler = createEmptySprite(area, `pvScale`, {
|
|
2336
|
+
x: baseX, y: 0, w: playW, h: playH, transform: `scale(${rate})`, transformOrigin: `top left`,
|
|
2337
|
+
});
|
|
2338
|
+
const pvFrame = createEmptySprite(scaler, `pvFrame`, {
|
|
2339
|
+
w: playW, h: playH, background: g_headerObj.baseBrightFlg ? `#eeeeee` : `#111111`,
|
|
2340
|
+
border: `1px solid #444444`, boxSizing: `border-box`, overflow: `hidden`,
|
|
2341
|
+
perspective: `1400px`, perspectiveOrigin: `center 60%`,
|
|
2342
|
+
});
|
|
2343
|
+
|
|
2344
|
+
// g_shakingFunc などが決め打ちで参照する id (設定画面には存在しないためここで作る)
|
|
2345
|
+
const spriteIds = [`mainSprite`, `infoSprite`, `judgeSprite`];
|
|
2346
|
+
const mainSprite = createEmptySprite(pvFrame, `mainSprite`, { w: playW, h: playH });
|
|
2347
|
+
|
|
2348
|
+
// レイヤー (StepAreaで最大4レイヤー)。ゲーム側と同じ id でステップ・矢印・フリーズヒット用スプライトを持つ
|
|
2349
|
+
const stepSprites = [], arrowSprites = [], frzHitSprites = [];
|
|
2350
|
+
for (let j = 0; j < layerCnt; j++) {
|
|
2351
|
+
const layer = createEmptySprite(mainSprite, `mainSprite${j}`, { w: playW, h: playH });
|
|
2352
|
+
stepSprites.push(createEmptySprite(layer, `stepSprite${j}`, { w: playW, h: playH }));
|
|
2353
|
+
arrowSprites.push(createEmptySprite(layer, `arrowSprite${j}`, { w: playW, h: playH }));
|
|
2354
|
+
frzHitSprites.push(createEmptySprite(layer, `frzHitSprite${j}`, { w: playW, h: playH }));
|
|
2355
|
+
spriteIds.push(`mainSprite${j}`, `stepSprite${j}`, `arrowSprite${j}`, `frzHitSprite${j}`);
|
|
2356
|
+
}
|
|
2357
|
+
const infoSprite = createEmptySprite(pvFrame, `infoSprite`, { w: playW, h: playH });
|
|
2358
|
+
const judgeSprite = createEmptySprite(pvFrame, `judgeSprite`, { w: playW, h: playH });
|
|
2359
|
+
if (_key === `frzReturn`) {
|
|
2360
|
+
mainSprite.style.transformOrigin = `center 55%`;
|
|
2361
|
+
mainSprite.style.transformStyle = `preserve-3d`;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
// レーン、ステップゾーン (4レーン。splitLayer時は右2レーンを逆スクロール側へ)
|
|
2365
|
+
const stepY = C_STEP_Y;
|
|
2366
|
+
const revStepY = playH - C_STEP_Y - C_ARW_WIDTH;
|
|
2367
|
+
const baseRtns = useKey
|
|
2368
|
+
? (g_keyObj[`stepRtn${keyCtrlPtn}`] ?? Array(laneNum).fill(0))
|
|
2369
|
+
: [0, -90, 90, 180];
|
|
2370
|
+
let rtnOffset = 0; // SideScroll時はゲーム側と同様に矢印を90度回転する
|
|
2371
|
+
// 矢印名 (onigiri等の文字列) は加算しない
|
|
2372
|
+
const getRtn = j => rtnOffset === 0 ? baseRtns[j] : baseRtns[j] + rtnOffset;
|
|
2373
|
+
const colors = useKey
|
|
2374
|
+
? (g_keyObj[`color${keyCtrlPtn}`] ?? []).map(c => g_headerObj.setColor?.[c] ?? g_dfColorObj.setColorType1[c] ?? `#ffffff`)
|
|
2375
|
+
: [0, 1, 3, 4].map(j => g_dfColorObj.setColorType1[j]);
|
|
2376
|
+
const laneX = j => Math.round(laneOffsets[j] + (playW - C_ARW_WIDTH) / 2);
|
|
2377
|
+
const getLaneInfo = laneIdxs => laneIdxs.map(j => ({ x: laneX(j), layer: 0, dir: 1, stepTop: stepY }));
|
|
2378
|
+
|
|
2379
|
+
// レーンの配置 (layer / dir / stepTop は assignLanes で設定)
|
|
2380
|
+
let laneInfo = getLaneInfo([...Array(laneNum).keys()]);
|
|
2381
|
+
let stepElms = laneInfo.map((lane, j) =>
|
|
2382
|
+
createColorObject2(`pvStep${j}`, { x: lane.x, y: stepY, rotate: getRtn(j) }, g_cssObj.main_stepDefault));
|
|
2383
|
+
|
|
2384
|
+
// ヒットモーション用の要素 (ゲーム側の stepHit と同じ位置・大きさ)
|
|
2385
|
+
const hitPos = g_lblPosObj.stepHit;
|
|
2386
|
+
const hitCnts = Array(laneNum).fill(0);
|
|
2387
|
+
const makeHitElms = () => laneInfo.map((lane, j) => createColorObject2(`pvStepHit${j}`, {
|
|
2388
|
+
...hitPos, x: lane.x + hitPos.x, y: stepY + hitPos.y, rotate: getRtn(j), styleName: `StepHit`, opacity: 0,
|
|
2389
|
+
}, g_cssObj.main_stepDefault));
|
|
2390
|
+
let hitElms = makeHitElms();
|
|
2391
|
+
|
|
2392
|
+
// フリーズアローのヒット表示 (ゲーム側の frzHit と同じ構成。先頭の矢印位置のみ光らせる)
|
|
2393
|
+
const frzHitFrames = 20;
|
|
2394
|
+
const frzHitColor = g_dfColorObj.frzColorType1[0][2];
|
|
2395
|
+
const frzHitCnts = Array(laneNum).fill(0);
|
|
2396
|
+
const makeFrzHitElms = () => laneInfo.map((lane, j) => {
|
|
2397
|
+
const root = createEmptySprite(frzHitSprites[0], `pvFrzHit${j}`, {
|
|
2398
|
+
x: lane.x, y: stepY, w: C_ARW_WIDTH, h: C_ARW_WIDTH, opacity: 0,
|
|
2399
|
+
});
|
|
2400
|
+
if (isNaN(parseFloat(baseRtns[j]))) {
|
|
2401
|
+
multiAppend(root,
|
|
2402
|
+
createColorObject2(`pvFrzHitShadow${j}`, { rotate: getRtn(j), styleName: `Shadow` }, g_cssObj.main_objShadow),
|
|
2403
|
+
createColorObject2(`pvFrzHitTop${j}`, { background: frzHitColor, rotate: getRtn(j) }),
|
|
2404
|
+
);
|
|
2405
|
+
} else {
|
|
2406
|
+
root.appendChild(createColorObject2(`pvFrzHitTop${j}`, {
|
|
2407
|
+
...g_lblPosObj.frzHitTop, rotate: getRtn(j), styleName: `Shadow`,
|
|
2408
|
+
}, g_cssObj.main_frzHitTop));
|
|
2409
|
+
}
|
|
2410
|
+
return root;
|
|
2411
|
+
});
|
|
2412
|
+
let frzHitElms = makeFrzHitElms();
|
|
2413
|
+
|
|
2414
|
+
const assignSwapping = _option => {
|
|
2415
|
+
laneInfo = getLaneInfo(g_helpSwappingLayouts[_option] ?? [...Array(laneNum).keys()]);
|
|
2416
|
+
laneInfo.forEach((lane, j) => {
|
|
2417
|
+
document.getElementById(`pvStep${j}`)?.remove();
|
|
2418
|
+
document.getElementById(`pvStepHit${j}`)?.remove();
|
|
2419
|
+
document.getElementById(`pvFrzHit${j}`)?.remove();
|
|
2420
|
+
});
|
|
2421
|
+
stepElms = laneInfo.map((lane, j) =>
|
|
2422
|
+
createColorObject2(`pvStep${j}`, { x: lane.x, y: stepY, rotate: getRtn(j) }, g_cssObj.main_stepDefault));
|
|
2423
|
+
hitElms = makeHitElms();
|
|
2424
|
+
frzHitElms = makeFrzHitElms();
|
|
2425
|
+
};
|
|
2426
|
+
const assignLanes = layout => laneInfo.forEach((lane, j) => {
|
|
2427
|
+
lane.layer = layout[j];
|
|
2428
|
+
lane.dir = lane.layer % 2 === 0 ? 1 : -1;
|
|
2429
|
+
lane.stepTop = lane.dir === 1 ? stepY : revStepY;
|
|
2430
|
+
stepElms[j].style.top = wUnit(lane.stepTop);
|
|
2431
|
+
stepElms[j].style.display = laneVisible[j] ? `` : C_DIS_NONE;
|
|
2432
|
+
stepSprites[lane.layer].appendChild(stepElms[j]);
|
|
2433
|
+
hitElms[j].style.top = wUnit(lane.stepTop + hitPos.y);
|
|
2434
|
+
stepSprites[lane.layer].appendChild(hitElms[j]);
|
|
2435
|
+
frzHitElms[j].style.top = wUnit(lane.stepTop);
|
|
2436
|
+
frzHitSprites[lane.layer].appendChild(frzHitElms[j]);
|
|
2437
|
+
});
|
|
2438
|
+
|
|
2439
|
+
// ライフゲージ、判定キャラクタ (画面全体を揺らす設定の確認用)
|
|
2440
|
+
multiAppend(infoSprite,
|
|
2441
|
+
createDivCss2Label(`pvLifeBack`, ``, g_lblPosObj.previewLifeBack, g_cssObj.life_Background),
|
|
2442
|
+
createDivCss2Label(`pvLifeBar`, ``, g_lblPosObj.previewLifeBar, g_cssObj.life_Cleared),
|
|
2443
|
+
);
|
|
2444
|
+
const jdgPos = { y: Math.round(playH / 2 - 60), w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight, siz: g_limitObj.jdgCharaSiz };
|
|
2445
|
+
multiAppend(judgeSprite,
|
|
2446
|
+
createDivCss2Label(`pvChara`, g_lblNameObj.j_ii, { ...jdgPos, x: Math.round(playW / 2 - 220) }, g_cssObj.common_ii),
|
|
2447
|
+
createDivCss2Label(`pvCombo`, `5 Combo!!`, { ...jdgPos, x: Math.round(playW / 2 - 50) }, g_cssObj.common_comboJ),
|
|
2448
|
+
);
|
|
2449
|
+
|
|
2450
|
+
// ---------------------------------------------------
|
|
2451
|
+
// プレビュー状態
|
|
2452
|
+
const noteInterval = Math.max(8, Math.round(24 * 4 / visibleLanes.length));
|
|
2453
|
+
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
2454
|
+
let stride = Math.max(Math.round(visibleLanes.length * 0.6), 1);
|
|
2455
|
+
while (gcd(stride, visibleLanes.length) !== 1) stride++;
|
|
2456
|
+
let selected = ``;
|
|
2457
|
+
let subSelected = subUse ? (subList.includes(g_stateObj[def.sub]) ? g_stateObj[def.sub] : subList[0]) : ``;
|
|
2458
|
+
let activeCol = 0; // 上下キーの対象列 (0: 本体、1: Type)
|
|
2459
|
+
let frameCnt = 0;
|
|
2460
|
+
let noteCnt = 0;
|
|
2461
|
+
let autoCnt = 0; // 自動切替までの経過フレーム数
|
|
2462
|
+
let timerId = null;
|
|
2463
|
+
let notes = [];
|
|
2464
|
+
let dist = [];
|
|
2465
|
+
let bStart = 0;
|
|
2466
|
+
let effectCls = { arrow: ``, frz: ``, frzArrow: `` };
|
|
2467
|
+
let filterElms = []; // Appearanceのフィルターバー・ラベル
|
|
2468
|
+
const frzLen = 90; // Effectプレビュー用フリーズアローの長さ(px)
|
|
2469
|
+
const work = { drunkXFlg: true, drunkYFlg: true, drunkAxisFlg: false, drunkRotateFlg: false };
|
|
2470
|
+
const frz = { seq: null, seqNo: 0, axes: [], start: 0, next: 0 };
|
|
2471
|
+
|
|
2472
|
+
/** 付与したtransformの初期化 */
|
|
2473
|
+
const resetTransforms = () => spriteIds.forEach(id => {
|
|
2474
|
+
delete g_transforms[id];
|
|
2475
|
+
const elm = document.getElementById(id);
|
|
2476
|
+
if (elm !== null) {
|
|
2477
|
+
elm.style.transform = ``;
|
|
2478
|
+
elm.style.opacity = ``;
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2481
|
+
|
|
2482
|
+
const clearNotes = () => {
|
|
2483
|
+
notes.forEach(note => note.el.remove());
|
|
2484
|
+
notes = [];
|
|
2485
|
+
hitCnts.fill(0);
|
|
2486
|
+
frzHitCnts.fill(0);
|
|
2487
|
+
hitElms.forEach(elm => elm.style.opacity = 0);
|
|
2488
|
+
frzHitElms.forEach(elm => elm.style.opacity = 0);
|
|
2489
|
+
};
|
|
2490
|
+
|
|
2491
|
+
/** ヒットモーション (矢印のみ。自動判定時と同様、イイ判定の見た目で表示) */
|
|
2492
|
+
const hitArrow = j => {
|
|
2493
|
+
const hit = hitElms[j];
|
|
2494
|
+
hit.style.opacity = 0.75;
|
|
2495
|
+
hit.classList.value = ``;
|
|
2496
|
+
hit.classList.add(g_cssObj.main_stepIi);
|
|
2497
|
+
hitCnts[j] = C_FRM_HITMOTION;
|
|
2498
|
+
};
|
|
2499
|
+
|
|
2500
|
+
/** フリーズアローのヒット表示 (先頭の矢印位置のみ。長さは待たず、一定フレームで消す) */
|
|
2501
|
+
const hitFrz = j => {
|
|
2502
|
+
frzHitElms[j].style.opacity = 0.9;
|
|
2503
|
+
frzHitCnts[j] = frzHitFrames;
|
|
2504
|
+
};
|
|
2505
|
+
|
|
2506
|
+
/**
|
|
2507
|
+
* Effectのクラス名取得
|
|
2508
|
+
* - g_effectFunc は g_workObj.*CssMotions へ書き込むため、呼び出し中だけ空配列へ差し替え、
|
|
2509
|
+
* ユーザ個別指定のモーションを排除したうえで元に戻す
|
|
2510
|
+
*/
|
|
2511
|
+
const getEffectClasses = opt => {
|
|
2512
|
+
const keys = [`arrowCssMotions`, `frzCssMotions`, `frzArrowCssMotions`];
|
|
2513
|
+
const org = {};
|
|
2514
|
+
const result = { arrow: ``, frz: ``, frzArrow: `` };
|
|
2515
|
+
keys.forEach(key => {
|
|
2516
|
+
org[key] = g_workObj[key];
|
|
2517
|
+
g_workObj[key] = [];
|
|
2518
|
+
});
|
|
2519
|
+
try {
|
|
2520
|
+
g_effectFunc.get(opt)();
|
|
2521
|
+
result.arrow = g_workObj.arrowCssMotions[0] ?? ``;
|
|
2522
|
+
result.frz = g_workObj.frzCssMotions[0] ?? ``;
|
|
2523
|
+
result.frzArrow = g_workObj.frzArrowCssMotions[0] ?? ``;
|
|
2524
|
+
} catch (e) {
|
|
2525
|
+
console.warn(`Effect preview error: ${e}`);
|
|
2526
|
+
} finally {
|
|
2527
|
+
keys.forEach(key => g_workObj[key] = org[key]);
|
|
2528
|
+
}
|
|
2529
|
+
return result;
|
|
2530
|
+
};
|
|
2531
|
+
|
|
2532
|
+
/** StepArea: ゲーム側の関数を、プレビュー用の状態に一時的に差し替えて実行 */
|
|
2533
|
+
const runStepArea = opt => {
|
|
2534
|
+
const orgState = {
|
|
2535
|
+
layerNum: g_stateObj.layerNum, layerNumDf: g_stateObj.layerNumDf, appearance: g_stateObj.appearance,
|
|
2536
|
+
};
|
|
2537
|
+
const orgFlatFlg = g_workObj.orgFlatFlg;
|
|
2538
|
+
Object.assign(g_stateObj, {
|
|
2539
|
+
layerNumDf: 2, layerNum: g_settings.stepAreaLayers.includes(opt) ? 4 : 2, appearance: `Visible`,
|
|
2540
|
+
});
|
|
2541
|
+
g_workObj.orgFlatFlg = false;
|
|
2542
|
+
try {
|
|
2543
|
+
g_stepAreaFunc.get(opt)();
|
|
2544
|
+
} finally {
|
|
2545
|
+
Object.assign(g_stateObj, orgState);
|
|
2546
|
+
g_workObj.orgFlatFlg = orgFlatFlg;
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
2549
|
+
|
|
2550
|
+
/**
|
|
2551
|
+
* Appearance: フィルター範囲の切り抜きとフィルターバーの表示
|
|
2552
|
+
* - changeAppearanceFilter は g_hidSudObj.filterPos の書き換えやカスタムフックの実行を伴うため使わず、
|
|
2553
|
+
* 切り抜き範囲の考え方 (g_hidSudObj の上下対応) のみ同じにして自前で設定する
|
|
2554
|
+
*/
|
|
2555
|
+
const applyAppearance = opt => {
|
|
2556
|
+
arrowSprites.forEach(sprite => sprite.style.clipPath = ``);
|
|
2557
|
+
filterElms.forEach(elm => elm.remove());
|
|
2558
|
+
filterElms = [];
|
|
2559
|
+
const defaultFilterPos = 30;
|
|
2560
|
+
|
|
2561
|
+
const hidSudFlg = opt === `Hid&Sud+`;
|
|
2562
|
+
let num = g_appearanceRanges.includes(opt) ? defaultFilterPos : (g_hidSudObj.filterPosDefault[opt] ?? 0);
|
|
2563
|
+
if (hidSudFlg) {
|
|
2564
|
+
num = Math.min(num, 50);
|
|
2565
|
+
}
|
|
2566
|
+
if (num <= 0) return;
|
|
2567
|
+
|
|
2568
|
+
const numPlus = hidSudFlg ? num : 0;
|
|
2569
|
+
const topNum = g_hidSudObj[opt];
|
|
2570
|
+
const edges = new Set();
|
|
2571
|
+
[0, 1].forEach(s => {
|
|
2572
|
+
const [cutTop, cutBottom] = s === topNum ? [num, numPlus] : [numPlus, num];
|
|
2573
|
+
arrowSprites[s].style.clipPath = `inset(${cutTop}% 0% ${cutBottom}% 0%)`;
|
|
2574
|
+
if (cutTop > 0) edges.add(cutTop);
|
|
2575
|
+
if (cutBottom > 0) edges.add(100 - cutBottom);
|
|
2576
|
+
});
|
|
2577
|
+
|
|
2578
|
+
const filterCss = g_stateObj.filterLock === C_FLG_OFF ? g_cssObj.life_Failed : g_cssObj.life_Cleared;
|
|
2579
|
+
[...edges].forEach((pct, i) => {
|
|
2580
|
+
const bar = createColorObject2(`pvFilterBar${i}`, {
|
|
2581
|
+
x: 0, y: Math.round(playH * pct / 100), w: playW - 50, h: 4, styleName: `lifeBar`, opacity: 1,
|
|
2582
|
+
}, filterCss);
|
|
2583
|
+
mainSprite.appendChild(bar);
|
|
2584
|
+
filterElms.push(bar);
|
|
2585
|
+
});
|
|
2586
|
+
|
|
2587
|
+
// 割合の表示 (最も上のバーの下、右端)
|
|
2588
|
+
const viewText = `${num}%` + (g_appearanceRanges.includes(opt) ? `↑↓` : ``);
|
|
2589
|
+
const view = createDivCss2Label(`pvFilterView`, viewText, {
|
|
2590
|
+
x: playW - 120, y: Math.round(playH * Math.min(...edges) / 100) + 6, w: 100, h: 26, siz: 24, align: C_ALIGN_RIGHT,
|
|
2591
|
+
});
|
|
2592
|
+
mainSprite.appendChild(view);
|
|
2593
|
+
filterElms.push(view);
|
|
2594
|
+
};
|
|
2595
|
+
|
|
2596
|
+
/** Scroll: 選択中のキー・パターンのスクロール方向 (1: 通常、-1: 逆) をレイヤー番号 (0, 1) へ変換 */
|
|
2597
|
+
const getScrollLayout = opt => {
|
|
2598
|
+
const dirs = g_keyObj[`scrollDir${keyCtrlPtn}`]?.[opt] ?? Array(laneNum).fill(1);
|
|
2599
|
+
return [...Array(laneNum).keys()].map(j => (baseLayers[j] || 0) * 2 +
|
|
2600
|
+
((laneLower[j] ? 1 : 0) + (dirs[j] === 1 ? 0 : 1) + (g_stateObj.reverse === C_FLG_OFF ? 0 : 1)) % 2);
|
|
2601
|
+
};
|
|
2602
|
+
|
|
2603
|
+
/** Flat系のスクロール: ステップゾーンを帯状 (横線2本) に切り替える */
|
|
2604
|
+
let flatElms = [];
|
|
2605
|
+
const applyFlat = opt => {
|
|
2606
|
+
flatElms.forEach(elm => elm.remove());
|
|
2607
|
+
flatElms = [];
|
|
2608
|
+
const flatFlg = _key === `scroll` && opt.endsWith(`Flat`);
|
|
2609
|
+
stepElms.forEach((elm, j) => elm.style.display = (flatFlg || !laneVisible[j]) ? C_DIS_NONE : ``);
|
|
2610
|
+
if (!flatFlg) return;
|
|
2611
|
+
|
|
2612
|
+
[...new Set(laneInfo.map(lane => lane.layer))].forEach(layer => {
|
|
2613
|
+
const top = layer % 2 === 0 ? stepY : revStepY;
|
|
2614
|
+
const h = g_stateObj.flatStepHeight;
|
|
2615
|
+
[(C_ARW_WIDTH - h) / 2, (C_ARW_WIDTH + h) / 2].forEach((y, k) => {
|
|
2616
|
+
const bar = createColorObject2(`pvFlatBar${layer}_${k}`, {
|
|
2617
|
+
x: 25, y: top + y, w: playW - 50, h: 1, styleName: `lifeBar`, background: `#999999`
|
|
2618
|
+
}, g_cssObj.life_Failed);
|
|
2619
|
+
stepSprites[layer].appendChild(bar);
|
|
2620
|
+
flatElms.push(bar);
|
|
2621
|
+
});
|
|
2622
|
+
});
|
|
2623
|
+
};
|
|
2624
|
+
|
|
2625
|
+
/** Typeの選択値を、ゲーム側の関数が参照する g_stateObj へ一時的に差し替えて実行 (g_playWindowDir など) */
|
|
2626
|
+
const withSub = func => {
|
|
2627
|
+
if (!subUse) return func();
|
|
2628
|
+
const org = g_stateObj[def.sub];
|
|
2629
|
+
g_stateObj[def.sub] = subSelected;
|
|
2630
|
+
try {
|
|
2631
|
+
return func();
|
|
2632
|
+
} finally {
|
|
2633
|
+
g_stateObj[def.sub] = org;
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* 選択肢の適用
|
|
2639
|
+
* - Motion: 「配列の15がステップゾーン上」として、ステップゾーンからの距離を逆算する
|
|
2640
|
+
* distance(b) = Σ(speed + motion[i]), i = 16..b (b: 到達までの残りフレーム数)
|
|
2641
|
+
*/
|
|
2642
|
+
const applyOption = opt => {
|
|
2643
|
+
selected = opt;
|
|
2644
|
+
resetTransforms();
|
|
2645
|
+
clearNotes();
|
|
2646
|
+
effectCls = _key === `effect` ? getEffectClasses(opt) : { arrow: ``, frz: ``, frzArrow: `` };
|
|
2647
|
+
|
|
2648
|
+
assignSwapping(_key === `swapping` ? opt : null);
|
|
2649
|
+
// レーンのレイヤー配置 (StepAreaは選択肢ごと、Shakingは右半分を逆スクロール側へ)
|
|
2650
|
+
assignLanes((g_helpPreviewDefs[_key]?.currentKey ? getScrollLayout(opt) : null)
|
|
2651
|
+
?? (_key === `stepArea` ? g_helpStepAreaLayouts[opt] : null)
|
|
2652
|
+
?? (def.splitLayer ? [0, 0, 1, 1] : [0, 0, 0, 0])
|
|
2653
|
+
.map(val => g_stateObj.reverse === C_FLG_OFF ? val : val ^ 1));
|
|
2654
|
+
applyFlat(opt);
|
|
2655
|
+
if (_key === `stepArea`) {
|
|
2656
|
+
runStepArea(opt);
|
|
2657
|
+
}
|
|
2658
|
+
if (_key === `appearance`) {
|
|
2659
|
+
applyAppearance(opt);
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
// SideScrollのみ矢印を90度回転 (ゲーム側の changeStepRtn と同じ符号)
|
|
2663
|
+
rtnOffset = (_key === `playWindow` && opt === `SideScroll` && g_stateObj.rotateEnabled)
|
|
2664
|
+
? 90 * (subSelected === C_FLG_REVERSE2 ? -1 : 1) : 0;
|
|
2665
|
+
if (g_stateObj.rotateEnabled) {
|
|
2666
|
+
laneInfo.forEach((lane, j) => {
|
|
2667
|
+
if (typeof getRtn(j) === `number`) {
|
|
2668
|
+
document.getElementById(`pvStep${j}`).style.transform = `rotate(${getRtn(j)}deg)`;
|
|
2669
|
+
hitElms[j].style.transform = `rotate(${getRtn(j)}deg)`;
|
|
2670
|
+
const frzHitTop = document.getElementById(`pvFrzHitTop${j}`);
|
|
2671
|
+
if (frzHitTop !== null) {
|
|
2672
|
+
frzHitTop.style.transform = `rotate(${getRtn(j)}deg)`;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// Motion用の加算フレーム数計算
|
|
2679
|
+
const trace = g_motionFunc.get(_key === `motion` ? opt : C_FLG_OFF)(fillArray(101));
|
|
2680
|
+
const distRate = _key === `motion` ? (g_settings.motionDistRates[g_settings.motions.indexOf(opt)] ?? 1) : 1;
|
|
2681
|
+
const stretchRate = g_headerObj.stretchYRate?.[g_stateObj.scoreId] ?? 1;
|
|
2682
|
+
const distY = Math.max(stretchRate, distRate) * (g_posObj.distY || (playH - C_STEP_Y));
|
|
2683
|
+
const frameSpd = g_stateObj.speed * g_headerObj.baseSpeed * 2;
|
|
2684
|
+
bStart = C_MOTION_STD_POS + Math.ceil(distY / frameSpd);
|
|
2685
|
+
dist = [];
|
|
2686
|
+
dist[C_MOTION_STD_POS] = 0;
|
|
2687
|
+
for (let b = C_MOTION_STD_POS + 1; b <= bStart; b++) {
|
|
2688
|
+
dist[b] = dist[b - 1] + frameSpd + (trace[b] || 0);
|
|
2689
|
+
}
|
|
2690
|
+
if (_key === `playWindow`) {
|
|
2691
|
+
addTransform(`mainSprite`, `playWindow`, withSub(() => g_playWindowFunc.get(opt)()), g_transPriority.playWindow);
|
|
2692
|
+
}
|
|
2693
|
+
if (_key === `shaking`) {
|
|
2694
|
+
Object.assign(work, { drunkXFlg: true, drunkYFlg: true, drunkAxisFlg: false, drunkRotateFlg: false });
|
|
2695
|
+
}
|
|
2696
|
+
if (_key === `frzReturn`) {
|
|
2697
|
+
frz.seq = null;
|
|
2698
|
+
frz.seqNo = 0;
|
|
2699
|
+
frz.next = frameCnt + 30;
|
|
2700
|
+
}
|
|
2701
|
+
};
|
|
2702
|
+
|
|
2703
|
+
const spawnNote = () => {
|
|
2704
|
+
const j = visibleLanes[(noteCnt * stride) % visibleLanes.length];
|
|
2705
|
+
const lane = laneInfo[j];
|
|
2706
|
+
const frzFlg = g_helpPreviewDefs[_key]?.frzUse && noteCnt % 4 === 2;
|
|
2707
|
+
const len = frzFlg ? frzLen : 0;
|
|
2708
|
+
noteCnt++;
|
|
2709
|
+
|
|
2710
|
+
const el = createEmptySprite(arrowSprites[lane.layer], `pvNote${noteCnt}`, {
|
|
2711
|
+
x: lane.x, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH + len,
|
|
2712
|
+
});
|
|
2713
|
+
const sub = createEmptySprite(el, `pvSub${noteCnt}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH + len });
|
|
2714
|
+
|
|
2715
|
+
// setCssMotions と同様に、クラス付与と到達フレーム数に合わせたアニメーション時間を設定
|
|
2716
|
+
const duration = `${(bStart - C_MOTION_STD_POS) / g_fps}s`;
|
|
2717
|
+
const addEffect = (target, cls) => {
|
|
2718
|
+
if (cls !== ``) {
|
|
2719
|
+
target.classList.add(cls);
|
|
2720
|
+
target.style.animationDuration = duration;
|
|
2721
|
+
}
|
|
2722
|
+
};
|
|
2723
|
+
|
|
2724
|
+
if (!frzFlg) {
|
|
2725
|
+
sub.appendChild(createColorObject2(`pvNoteTop${noteCnt}`, { background: colors[j], rotate: getRtn(j) }));
|
|
2726
|
+
addEffect(sub, effectCls.arrow);
|
|
2727
|
+
} else {
|
|
2728
|
+
const [normalColor, barColor] = g_dfColorObj.frzColorType1[0];
|
|
2729
|
+
const makeArrowRoot = (_name, _y) => {
|
|
2730
|
+
const root = createEmptySprite(sub, `pv${_name}Root${noteCnt}`, { x: 0, y: _y, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
|
|
2731
|
+
root.appendChild(createColorObject2(`pv${_name}${noteCnt}`, { background: normalColor, rotate: getRtn(j) }));
|
|
2732
|
+
addEffect(root, effectCls.frzArrow);
|
|
2733
|
+
return root;
|
|
2734
|
+
};
|
|
2735
|
+
sub.appendChild(createColorObject2(`pvBar${noteCnt}`, {
|
|
2736
|
+
x: 5, y: C_ARW_WIDTH / 2 + (lane.dir === 1 ? 0 : -len), w: C_ARW_WIDTH - 10,
|
|
2737
|
+
h: len, background: barColor, styleName: `frzBar`, opacity: 0.75,
|
|
2738
|
+
}));
|
|
2739
|
+
makeArrowRoot(`Top`, 0);
|
|
2740
|
+
makeArrowRoot(`Btm`, lane.dir === 1 ? len : -len);
|
|
2741
|
+
addEffect(sub, effectCls.frz);
|
|
2742
|
+
}
|
|
2743
|
+
const note = { el, lane, j, frzFlg, b: bStart };
|
|
2744
|
+
placeNote(note);
|
|
2745
|
+
notes.push(note);
|
|
2746
|
+
};
|
|
2747
|
+
|
|
2748
|
+
const placeNote = note => {
|
|
2749
|
+
const d = dist[note.b];
|
|
2750
|
+
note.el.style.top = wUnit(note.lane.dir === 1 ? stepY + d : revStepY - d);
|
|
2751
|
+
};
|
|
2752
|
+
|
|
2753
|
+
/** Shaking: ゲーム側の関数を、プレビュー用の状態に一時的に差し替えて実行 */
|
|
2754
|
+
const runShaking = () => {
|
|
2755
|
+
const orgWork = {};
|
|
2756
|
+
Object.keys(work).forEach(key => orgWork[key] = g_workObj[key]);
|
|
2757
|
+
const orgState = { layerNum: g_stateObj.layerNum, layerNumDf: g_stateObj.layerNumDf };
|
|
2758
|
+
const orgFrame = g_scoreObj.baseFrame;
|
|
2759
|
+
|
|
2760
|
+
Object.assign(g_workObj, work);
|
|
2761
|
+
Object.assign(g_stateObj, { layerNum: 2, layerNumDf: 2 });
|
|
2762
|
+
g_scoreObj.baseFrame = frameCnt;
|
|
2763
|
+
try {
|
|
2764
|
+
g_shakingFunc.get(selected)();
|
|
2765
|
+
} finally {
|
|
2766
|
+
Object.keys(work).forEach(key => work[key] = g_workObj[key]);
|
|
2767
|
+
Object.assign(g_workObj, orgWork);
|
|
2768
|
+
Object.assign(g_stateObj, orgState);
|
|
2769
|
+
g_scoreObj.baseFrame = orgFrame;
|
|
2770
|
+
}
|
|
2771
|
+
};
|
|
2772
|
+
|
|
2773
|
+
/** FrzReturn: 回転配列・回転軸はゲーム側の定義を使用し、一定間隔で自動実行 */
|
|
2774
|
+
const runFrzReturn = () => {
|
|
2775
|
+
if (selected === C_FLG_OFF) return;
|
|
2776
|
+
if (frz.seq === null) {
|
|
2777
|
+
if (frameCnt < frz.next) return;
|
|
2778
|
+
const seqs = (g_frzReturnSeqFunc.get(subSelected) ?? g_frzReturnSeqFunc.get(`360deg`))();
|
|
2779
|
+
frz.seq = seqs[frz.seqNo++ % seqs.length];
|
|
2780
|
+
frz.axes = [...g_frzReturnFunc.get(selected)()].filter(Boolean);
|
|
2781
|
+
frz.start = frameCnt;
|
|
2782
|
+
}
|
|
2783
|
+
const idx = Math.floor((frameCnt - frz.start) * 1000 / g_fps / 20);
|
|
2784
|
+
if (idx >= frz.seq.length) {
|
|
2785
|
+
frz.seq = null;
|
|
2786
|
+
frz.next = frameCnt + 60;
|
|
2787
|
+
delTransform(`mainSprite`, `frzReturn`);
|
|
2788
|
+
mainSprite.style.opacity = 1;
|
|
2789
|
+
return;
|
|
2790
|
+
}
|
|
2791
|
+
const deg = frz.seq[idx];
|
|
2792
|
+
const rad360 = ((deg % 360) + 360) % 360;
|
|
2793
|
+
const isBack = frz.axes.some(axis => (axis === `X` || axis === `Y`) && rad360 > 90 && rad360 < 270);
|
|
2794
|
+
mainSprite.style.opacity = isBack ? 0.7 : 1;
|
|
2795
|
+
addTransform(`mainSprite`, `frzReturn`,
|
|
2796
|
+
frz.axes.map(axis => `rotate${axis}(${deg}deg)`).join(` `), g_transPriority.frzReturn);
|
|
2797
|
+
};
|
|
2798
|
+
|
|
2799
|
+
const tick = () => {
|
|
2800
|
+
if (document.getElementById(`pvFrame`) === null) {
|
|
2801
|
+
stop();
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
frameCnt++;
|
|
2805
|
+
if (++autoCnt >= g_limitObj.helpPreviewAutoFrames && g_limitObj.helpPreviewAutoFrames > 0) {
|
|
2806
|
+
autoCnt = 0;
|
|
2807
|
+
moveOption(1);
|
|
2808
|
+
}
|
|
2809
|
+
if (frameCnt % noteInterval === 0) {
|
|
2810
|
+
spawnNote();
|
|
2811
|
+
}
|
|
2812
|
+
notes = notes.filter(note => {
|
|
2813
|
+
note.b--;
|
|
2814
|
+
if (note.b <= C_MOTION_STD_POS) {
|
|
2815
|
+
if (note.frzFlg) {
|
|
2816
|
+
hitFrz(note.j);
|
|
2817
|
+
} else {
|
|
2818
|
+
hitArrow(note.j);
|
|
2819
|
+
}
|
|
2820
|
+
note.el.remove();
|
|
2821
|
+
return false;
|
|
2822
|
+
}
|
|
2823
|
+
placeNote(note);
|
|
2824
|
+
return true;
|
|
2825
|
+
});
|
|
2826
|
+
|
|
2827
|
+
// ヒットモーションの消去 (一定フレームで非表示)
|
|
2828
|
+
hitCnts.forEach((cnt, j) => {
|
|
2829
|
+
if (cnt > 0 && --hitCnts[j] === 0) {
|
|
2830
|
+
hitElms[j].style.opacity = 0;
|
|
2831
|
+
}
|
|
2832
|
+
});
|
|
2833
|
+
frzHitCnts.forEach((cnt, j) => {
|
|
2834
|
+
if (cnt > 0 && --frzHitCnts[j] === 0) {
|
|
2835
|
+
frzHitElms[j].style.opacity = 0;
|
|
2836
|
+
}
|
|
2837
|
+
});
|
|
2838
|
+
if (_key === `shaking` && frameCnt % 2 === 0) {
|
|
2839
|
+
runShaking();
|
|
2840
|
+
} else if (_key === `frzReturn`) {
|
|
2841
|
+
runFrzReturn();
|
|
2842
|
+
}
|
|
2843
|
+
timerId = g_timerHandler.setTimeout(tick, 1000 / g_fps);
|
|
2844
|
+
};
|
|
2845
|
+
|
|
2846
|
+
const stop = () => {
|
|
2847
|
+
if (timerId !== null) {
|
|
2848
|
+
g_timerHandler.clearTimeout(timerId);
|
|
2849
|
+
}
|
|
2850
|
+
timerId = null;
|
|
2851
|
+
spriteIds.forEach(id => delete g_transforms[id]);
|
|
2852
|
+
g_helpPreviewStop = () => true;
|
|
2853
|
+
g_helpPreviewMove = _dir => true;
|
|
2854
|
+
g_helpPreviewColumn = _dir => true;
|
|
2855
|
+
};
|
|
2856
|
+
g_helpPreviewStop = stop;
|
|
2857
|
+
|
|
2858
|
+
// ---------------------------------------------------
|
|
2859
|
+
// 選択肢ボタン (本体の列と、Typeがある設定のみTypeの列)
|
|
2860
|
+
const chipX = baseX + viewW + 15;
|
|
2861
|
+
const colMain = createEmptySprite(area, `pvColMain`, { x: chipX, y: 0, w: colW, h: _height });
|
|
2862
|
+
const colSub = subUse ? createEmptySprite(area, `pvColSub`, { x: chipX + colW + 6, y: 0, w: colW, h: _height }) : null;
|
|
2863
|
+
|
|
2864
|
+
const makeChips = (_list, _prefix, _onSelect, _title = ``) => {
|
|
2865
|
+
const chipH = Math.min(20, Math.floor(_height / _list.length));
|
|
2866
|
+
return _list.map((opt, i) =>
|
|
2867
|
+
createCss2Button(`${_prefix}${i}`, getStgDetailName(opt), () => _onSelect(opt), {
|
|
2868
|
+
x: 0, y: i * chipH, w: colW, h: chipH - 2, siz: 12, title: _title,
|
|
2869
|
+
}, g_cssObj.button_Default));
|
|
2870
|
+
};
|
|
2871
|
+
const chips = makeChips(optList, `pvChip`, opt => selectMain(opt));
|
|
2872
|
+
const subChips = subUse ? makeChips(subList, `pvSubChip`, opt => selectSub(opt), g_msgObj[def.sub] ?? ``) : [];
|
|
2873
|
+
multiAppend(colMain, ...chips);
|
|
2874
|
+
if (subUse) {
|
|
2875
|
+
multiAppend(colSub, ...subChips);
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
const markChips = () => {
|
|
2879
|
+
const mark = (_list, _chips, _current) => _chips.forEach((chip, i) => {
|
|
2880
|
+
chip.classList.remove(g_cssObj.button_Default, g_cssObj.button_Setting);
|
|
2881
|
+
chip.classList.add(_list[i] === _current ? g_cssObj.button_Setting : g_cssObj.button_Default);
|
|
2882
|
+
});
|
|
2883
|
+
mark(optList, chips, selected);
|
|
2884
|
+
if (subUse) {
|
|
2885
|
+
mark(subList, subChips, subSelected);
|
|
2886
|
+
colSub.style.opacity = activeCol === 1 ? 1 : 0.5; // 操作対象でない列は薄く表示
|
|
2887
|
+
}
|
|
2888
|
+
colMain.style.opacity = subUse && activeCol !== 0 ? 0.5 : 1;
|
|
2889
|
+
g_helpSelectHook(subUse ? [selected, subSelected] : [selected], activeCol);
|
|
2890
|
+
safeExecuteCustomHooks(`g_customJsObj.helpPreview`, g_customJsObj.helpPreview, _key, selected,
|
|
2891
|
+
{ pvFrame, mainSprite, stepSprites, arrowSprites, playW, playH, sub: subSelected });
|
|
2892
|
+
};
|
|
2893
|
+
|
|
2894
|
+
// 本体の選択(選択時は自動移動時間を2倍にする)
|
|
2895
|
+
const selectMain = opt => {
|
|
2896
|
+
autoCnt = -g_limitObj.helpPreviewAutoFrames;
|
|
2897
|
+
activeCol = 0;
|
|
2898
|
+
applyOption(opt);
|
|
2899
|
+
markChips();
|
|
2900
|
+
};
|
|
2901
|
+
|
|
2902
|
+
// Typeの選択 (本体がOFF/Defaultのときは、効果が見える基準の選択肢へ切り替える)
|
|
2903
|
+
const selectSub = opt => {
|
|
2904
|
+
autoCnt = -g_limitObj.helpPreviewAutoFrames;
|
|
2905
|
+
activeCol = 1;
|
|
2906
|
+
subSelected = opt;
|
|
2907
|
+
const base = optList[1];
|
|
2908
|
+
applyOption(selected === optList[0] && optList.includes(base) ? base : selected);
|
|
2909
|
+
markChips();
|
|
2910
|
+
};
|
|
2911
|
+
|
|
2912
|
+
// 上下キー: 操作対象の列の選択肢を前後に動かす (端では反対側へ循環)
|
|
2913
|
+
const moveOption = _dir => {
|
|
2914
|
+
applyOption(optList[nextPos(optList.indexOf(selected), _dir, optList.length)]);
|
|
2915
|
+
markChips();
|
|
2916
|
+
};
|
|
2917
|
+
g_helpPreviewMove = _dir => {
|
|
2918
|
+
if (subUse && activeCol === 1) {
|
|
2919
|
+
selectSub(subList[nextPos(subList.indexOf(subSelected), _dir, subList.length)]);
|
|
2920
|
+
} else {
|
|
2921
|
+
autoCnt = -g_limitObj.helpPreviewAutoFrames;
|
|
2922
|
+
moveOption(_dir);
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
2925
|
+
|
|
2926
|
+
// 左右キー: 操作対象の列を切り替える (←: 本体、→: Type)
|
|
2927
|
+
g_helpPreviewColumn = _dir => {
|
|
2928
|
+
if (!subUse) return;
|
|
2929
|
+
activeCol = _dir > 0 ? 1 : 0;
|
|
2930
|
+
markChips();
|
|
2931
|
+
};
|
|
2932
|
+
|
|
2933
|
+
// 初期表示: 現在値 (OFF/Default の場合は最初の非OFFの選択肢)
|
|
2934
|
+
const current = g_stateObj[_key];
|
|
2935
|
+
applyOption(optList.includes(current) && current !== optList[0] ? current : (optList[1] ?? optList[0]));
|
|
2936
|
+
markChips();
|
|
2937
|
+
timerId = g_timerHandler.setTimeout(tick, 1000 / g_fps);
|
|
2938
|
+
};
|
|
2939
|
+
|
|
2009
2940
|
/**
|
|
2010
2941
|
* 設定名の置き換え処理(未指定時は原則g_lblNameObjの値を使用、明示的な指定がある場合のみ元の名前を返却)
|
|
2011
2942
|
* @param {string} _name
|
|
@@ -3307,7 +4238,10 @@ const createGeneralSettingEx = (_spriteList, _name, { defaultList = [C_FLG_OFF],
|
|
|
3307
4238
|
funcEx();
|
|
3308
4239
|
createExpandedScView(_name);
|
|
3309
4240
|
},
|
|
3310
|
-
|
|
4241
|
+
// 拡張ボタンの説明文表示は「拡張元」設定のヘルプが長い場合、詳細ヘルプ表示側で表示するため省略する
|
|
4242
|
+
title: isLongHelp(g_msgObj[`${_name}`] ?? ``) || g_helpPreviewDefs[_name] !== undefined
|
|
4243
|
+
? ``
|
|
4244
|
+
: (g_msgObj[`${_name}Type`] ?? ``),
|
|
3311
4245
|
}, g_cssObj.button_Default, g_cssObj.button_RevON);
|
|
3312
4246
|
|
|
3313
4247
|
/**
|