offerpk3 commited on
Commit
8109627
·
verified ·
1 Parent(s): 868b437

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1084 -19
index.html CHANGED
@@ -1,19 +1,1084 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Deep Sea Breakout - Stable Version</title>
7
+ <!-- <script src="https://cdn.tailwindcss.com"></script> Removed for simplicity, add back if needed -->
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Orbitron:wght@400;700&display=swap');
10
+
11
+ :root {
12
+ --game-width: 800px;
13
+ --game-height: 600px;
14
+ }
15
+
16
+ body {
17
+ margin: 0; padding: 0;
18
+ background: radial-gradient(ellipse at bottom, #1B2735 0%, #090A0F 100%);
19
+ display: flex; justify-content: center; align-items: center;
20
+ min-height: 100vh; font-family: 'Orbitron', sans-serif;
21
+ overflow: hidden; color: #e0f7ff;
22
+ }
23
+
24
+ .stars-bg {
25
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
26
+ z-index: -1;
27
+ }
28
+ .stars-bg::before, .stars-bg::after {
29
+ content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0;
30
+ background-image:
31
+ radial-gradient(1px 1px at 20% 30%, white, rgba(255,255,255,0)),
32
+ radial-gradient(1px 1px at 50% 70%, white, rgba(255,255,255,0)),
33
+ radial-gradient(2px 2px at 80% 40%, white, rgba(255,255,255,0)),
34
+ radial-gradient(1px 1px at 10% 90%, white, rgba(255,255,255,0)),
35
+ radial-gradient(2px 2px at 90% 10%, white, rgba(255,255,255,0));
36
+ background-size: 200px 200px; animation: twinkle 15s linear infinite alternate; opacity: 0;
37
+ }
38
+ .stars-bg::after { background-size: 300px 300px; animation-delay: -7.5s; }
39
+
40
+ @keyframes twinkle {
41
+ 0% { opacity: 0.1; transform: translateY(0px); }
42
+ 50% { opacity: 0.7; transform: translateY(-5px); }
43
+ 100% { opacity: 0.1; transform: translateY(0px); }
44
+ }
45
+
46
+ .game-container {
47
+ position: relative;
48
+ width: var(--game-width);
49
+ height: var(--game-height);
50
+ border: 3px solid #0ff; border-radius: 12px;
51
+ box-shadow: 0 0 30px rgba(0, 255, 255, 0.5), 0 0 10px rgba(0,255,255,0.7) inset;
52
+ background: rgba(0, 10, 20, 0.85); overflow: hidden;
53
+ }
54
+
55
+ canvas#gameCanvas {
56
+ display: block; width: 100%; height: 100%;
57
+ }
58
+
59
+ .ui {
60
+ position: absolute; top: 10px; left: 10px; right: 10px;
61
+ display: flex; justify-content: space-between;
62
+ color: #0ff; font-size: calc(var(--game-height) * 0.03);
63
+ font-weight: bold; text-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
64
+ pointer-events: none; font-family: 'Orbitron', sans-serif; z-index: 3;
65
+ }
66
+ .ui > div {
67
+ background: rgba(0, 40, 80, 0.6);
68
+ padding: calc(var(--game-height) * 0.008) calc(var(--game-height) * 0.025);
69
+ border-radius: 20px; border: 1px solid rgba(0, 255, 255, 0.3);
70
+ margin: 0 3px; white-space: nowrap;
71
+ }
72
+
73
+ .dialog-box, .menu, .settings-panel, .leaderboard, .shop, .daily-challenge,
74
+ .achievement-system, .tutorial-screen, .stats-screen, .credits, .customization,
75
+ .profile, .multiplayer-info, .matchmaking, .matchmaking-invite, .matchmaking-scoreboard,
76
+ #difficultySelectScreen /* Explicitly target this if it's a dialog */
77
+ {
78
+ position: absolute; top: 50%; left: 50%;
79
+ transform: translate(-50%, -50%);
80
+ background: rgba(0, 5, 15, 0.97); color: #0ff;
81
+ padding: clamp(20px, 4vh, 30px); border-radius: 15px;
82
+ text-align: center; border: 2px solid #0ff;
83
+ box-shadow: 0 0 30px rgba(0, 255, 255, 0.8), 0 0 20px #0af inset;
84
+ z-index: 20; width: 85%; max-width: 500px;
85
+ backdrop-filter: blur(4px); display: none;
86
+ max-height: 85vh; overflow-y: auto;
87
+ }
88
+
89
+ /* Titles for all dialogs */
90
+ .dialog-box h1, .dialog-box h2, .menu-title, .settings-header, .leaderboard-title,
91
+ .shop-title, .daily-challenge-title, .achievement-system-title, .tutorial-screen-title,
92
+ .stats-screen-title, .credits-title, .customization-title, .profile-title,
93
+ .multiplayer-title, .matchmaking-title, .matchmaking-scoreboard-title,
94
+ #difficultySelectScreen h2 { /* Target specific h2 for difficulty screen */
95
+ font-family: 'Press Start 2P', cursive;
96
+ font-size: clamp(20px, 3.5vw, 28px);
97
+ margin-bottom: 20px; text-shadow: 0 0 10px #0ff; color: #7ff;
98
+ }
99
+ .dialog-box p {
100
+ font-size: clamp(14px, 2.2vw, 16px); margin-bottom: 20px; line-height: 1.5;
101
+ }
102
+
103
+ .start-screen { display: flex; flex-direction: column; align-items: center; }
104
+
105
+ .pause-message {
106
+ position: absolute; top: 50%; left: 50%;
107
+ transform: translate(-50%, -50%); color: #f0f;
108
+ font-size: clamp(40px, 8vw, 60px); font-weight: bold;
109
+ text-shadow: 0 0 15px #f0f, 0 0 30px #f0f; pointer-events: none;
110
+ display: none; font-family: 'Press Start 2P', cursive; z-index: 100;
111
+ animation: pulse 1.5s infinite alternate;
112
+ }
113
+ @keyframes pulse {
114
+ from { opacity: 0.6; transform: translate(-50%, -50%) scale(1); }
115
+ to { opacity: 1; transform: translate(-50%, -50%) scale(1.05); }
116
+ }
117
+
118
+ .powerup-indicator {
119
+ position: absolute; bottom: calc(var(--game-height) * 0.08);
120
+ right: 10px; display: flex; flex-direction: column; gap: 8px; z-index: 5;
121
+ }
122
+ .powerup-icon {
123
+ width: clamp(30px, 4vw, 40px); height: clamp(30px, 4vw, 40px);
124
+ background: rgba(0, 40, 80, 0.8); border-radius: 50%;
125
+ display: flex; align-items: center; justify-content: center;
126
+ font-weight: bold; font-size: clamp(12px, 2vw, 16px);
127
+ border: 1px solid rgba(0, 255, 255, 0.6); position: relative; color: #fff;
128
+ box-shadow: 0 0 8px rgba(0,255,255,0.4);
129
+ }
130
+ .powerup-icon::after {
131
+ content: ''; position: absolute; bottom: -4px; left: 50%; transform: translateX(-50%);
132
+ height: 5px; background: #0f0; border-radius: 2px;
133
+ transition: width 0.1s linear; width: var(--time-left, 100%);
134
+ }
135
+ .powerup-icon.rare::before {
136
+ content: ''; position: absolute; inset: -3px; border-radius: 50%;
137
+ border: 2px solid gold; animation: rareGlow 1s infinite alternate; opacity: 0.9;
138
+ }
139
+ @keyframes rareGlow {
140
+ from { box-shadow: 0 0 6px gold, 0 0 12px yellow; }
141
+ to { box-shadow: 0 0 12px gold, 0 0 18px yellow; }
142
+ }
143
+
144
+ .button, .menu-button, .sound-button, .save-button, .item-button, .challenge-button,
145
+ .profile-button, .matchmaking-button, .matchmaking-control-button, .matchmaking-invite-button,
146
+ .theme-button {
147
+ background: linear-gradient(45deg, #0077aa, #00aadd);
148
+ border: 1px solid #00ccff; color: white;
149
+ padding: clamp(10px, 1.8vh, 12px) clamp(18px, 2.5vw, 24px);
150
+ margin: 8px 5px; border-radius: 8px; cursor: pointer;
151
+ font-size: clamp(13px, 2.2vw, 16px);
152
+ transition: all 0.25s ease-out;
153
+ box-shadow: 0 4px 12px rgba(0, 180, 220, 0.3), 0 0 4px rgba(0,255,255,0.4) inset;
154
+ font-family: 'Orbitron', sans-serif; text-transform: uppercase;
155
+ letter-spacing: 0.5px; position: relative; overflow: hidden;
156
+ }
157
+ .button::before, .menu-button::before, .sound-button::before, .save-button::before,
158
+ .item-button::before, .challenge-button::before, .profile-button::before,
159
+ .matchmaking-button::before, .matchmaking-control-button::before, .matchmaking-invite-button::before,
160
+ .theme-button::before {
161
+ content: ''; position: absolute; top: -50%; left: -150%; width: 50%; height: 200%;
162
+ background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.3) 50%, rgba(255,255,255,0) 100%);
163
+ transform: skewX(-25deg); transition: left 0.5s ease-in-out;
164
+ }
165
+ .button:hover, .menu-button:hover, .sound-button:hover, .save-button:hover,
166
+ .item-button:hover, .challenge-button:hover, .profile-button:hover,
167
+ .matchmaking-button:hover, .matchmaking-control-button:hover, .matchmaking-invite-button:hover,
168
+ .theme-button:hover {
169
+ transform: translateY(-2px) scale(1.02);
170
+ box-shadow: 0 6px 18px rgba(0, 255, 255, 0.6), 0 0 8px rgba(128,255,255,0.6) inset;
171
+ background: linear-gradient(45deg, #0088bb, #00bbff);
172
+ }
173
+ .button:hover::before, .menu-button:hover::before, .sound-button:hover::before,
174
+ .save-button:hover::before, .item-button:hover::before, .challenge-button:hover::before,
175
+ .profile-button:hover::before, .matchmaking-button:hover::before, .matchmaking-control-button:hover::before,
176
+ .matchmaking-invite-button:hover::before, .theme-button:hover::before { left: 150%; }
177
+
178
+ .button:active, .menu-button:active, .sound-button:active, .save-button:active,
179
+ .item-button:active, .challenge-button:active, .profile-button:active,
180
+ .matchmaking-button:active, .matchmaking-control-button:active, .matchmaking-invite-button:active,
181
+ .theme-button:active { transform: translateY(0px) scale(0.98); }
182
+
183
+ .instructions {
184
+ background: rgba(0, 20, 40, 0.7); padding: 15px; border-radius: 10px;
185
+ margin-top: 20px; border: 1px solid rgba(0, 255, 255, 0.3);
186
+ font-size: clamp(12px, 2vw, 14px);
187
+ }
188
+ .controls {
189
+ position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%);
190
+ color: #7ff; font-size: clamp(10px, 1.8vw, 12px); text-align: center;
191
+ width: 90%; max-width: 450px; background: rgba(0, 20, 40, 0.8);
192
+ padding: 6px; border-radius: 20px; border: 1px solid rgba(0, 255, 255, 0.4);
193
+ z-index: 5;
194
+ }
195
+
196
+ .combo-meter {
197
+ position: absolute; top: 45%; left: 50%;
198
+ transform: translate(-50%, -50%) scale(0.8);
199
+ font-size: clamp(30px, 7vw, 45px); font-weight: bold; color: #ff0;
200
+ text-shadow: 0 0 10px #ff0, 0 0 20px #f90, 3px 3px 0px #a50;
201
+ opacity: 0; pointer-events: none; z-index: 4;
202
+ font-family: 'Press Start 2P', cursive;
203
+ transition: opacity 0.3s ease-out, transform 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
204
+ }
205
+
206
+ .achievement-popup, .notification {
207
+ position: fixed; top: 20px; right: 20px;
208
+ background: rgba(10, 30, 50, 0.9); color: #fff;
209
+ padding: 15px 20px; border-radius: 10px; border: 2px solid #0ff;
210
+ box-shadow: 0 0 15px rgba(0, 255, 255, 0.5); font-family: 'Orbitron', sans-serif;
211
+ z-index: 100; opacity: 0; transform: translateX(100%);
212
+ transition: all 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
213
+ width: auto; max-width: 300px;
214
+ }
215
+ .achievement-popup.show, .notification.show { opacity: 1; transform: translateX(0); }
216
+ .achievement-icon, .notification-icon {
217
+ width: 30px; height: 30px; background: #0ff; border-radius: 50%;
218
+ display: flex; align-items: center; justify-content: center;
219
+ float: left; margin-right: 10px; font-size: 16px; color: #036;
220
+ }
221
+ .achievement-title, .notification-title { font-weight: bold; font-size: 16px; margin-bottom: 5px; color: #0ff; }
222
+ .achievement-description, .notification-description { font-size: 12px; color: #ccc; }
223
+
224
+ .level-transition, .boss-intro, .boss-defeated, .matchmaking-result, .loading-screen {
225
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
226
+ background: rgba(0, 5, 10, 0.9); display: flex; flex-direction: column;
227
+ align-items: center; justify-content: center;
228
+ font-family: 'Press Start 2P', cursive; font-size: clamp(30px, 6vw, 48px);
229
+ color: #0ff; z-index: 1000; opacity: 0; visibility: hidden;
230
+ transition: opacity 0.4s ease, visibility 0.4s;
231
+ }
232
+ .level-transition.active, .boss-intro.active, .boss-defeated.active,
233
+ .matchmaking-result.active, .loading-screen:not(.hidden) { opacity: 1; visibility: visible; }
234
+
235
+ .level-number, .boss-name-large, .boss-defeated-text, .matchmaking-result-text { animation: popIn 0.8s ease-in-out; }
236
+ @keyframes popIn {
237
+ 0% { transform: scale(0.3) rotate(-15deg); opacity: 0; }
238
+ 60% { transform: scale(1.1) rotate(5deg); opacity: 1; }
239
+ 100% { transform: scale(1) rotate(0deg); opacity: 1; }
240
+ }
241
+
242
+ .health-bar {
243
+ position: absolute; top: calc(var(--game-height) * 0.03); left: calc(var(--game-height) * 0.025);
244
+ width: clamp(100px, 20vw, 150px); height: calc(var(--game-height) * 0.02);
245
+ background: rgba(100, 0, 0, 0.5); border: 1px solid #f00;
246
+ border-radius: 5px; overflow: hidden; z-index: 3;
247
+ }
248
+ .health-fill {
249
+ height: 100%; width: 100%;
250
+ background: linear-gradient(to right, #ff3333, #ff9933);
251
+ border-radius: 4px 0 0 4px;
252
+ transition: width 0.3s ease-in-out;
253
+ }
254
+
255
+ .glow-border::before {
256
+ content: ""; position: absolute; top: -3px; left: -3px; right: -3px; bottom: -3px;
257
+ border-radius: 14px;
258
+ background: repeating-linear-gradient( 45deg,
259
+ rgba(0,255,255,0) 0%, rgba(0,255,255,0) 5%,
260
+ rgba(0,255,255,0.2) 10%, rgba(0,255,255,0.2) 15%,
261
+ rgba(0,255,255,0) 20%, rgba(0,255,255,0) 100%
262
+ );
263
+ background-size: 200% 200%;
264
+ animation: glowBorderMove 4s linear infinite;
265
+ pointer-events: none; z-index: 0;
266
+ }
267
+ @keyframes glowBorderMove {
268
+ 0% { background-position: 0% 0%; }
269
+ 100% { background-position: -200% -200%; }
270
+ }
271
+
272
+ .vignette {
273
+ position: absolute; top:0; left:0; width:100%; height:100%;
274
+ pointer-events:none; box-shadow: inset 0 0 100px rgba(0,0,0,0.6);
275
+ z-index:1;
276
+ }
277
+ .radial-glow {
278
+ position: absolute; top:0; left:0; width:100%; height:100%;
279
+ background: radial-gradient(ellipse at center, rgba(0,128,255,0.08) 0%, rgba(0,0,0,0) 70%);
280
+ pointer-events:none; z-index:0;
281
+ }
282
+ .water-effect {
283
+ position: absolute; bottom:0; left:0; width:100%; height:15%;
284
+ background: linear-gradient(to top, rgba(0,100,150,0.15), transparent);
285
+ pointer-events:none; z-index:0; overflow: hidden;
286
+ }
287
+ .water-effect::after {
288
+ content:""; position: absolute; top: 0; left: -50%; width: 200%; height: 100%;
289
+ background: repeating-linear-gradient(0deg,
290
+ rgba(100,200,255,0.05) 0px, rgba(100,200,255,0.05) 1px,
291
+ transparent 1px, transparent 15px);
292
+ animation: waterRipple 8s linear infinite;
293
+ }
294
+ @keyframes waterRipple {
295
+ 0% { transform: translateY(0%) translateX(0%); }
296
+ 50% { transform: translateY(-10%) translateX(2%); }
297
+ 100% { transform: translateY(0%) translateX(0%); }
298
+ }
299
+
300
+ .depth-meter {
301
+ position: absolute; top: calc(var(--game-height) * 0.1); right: 15px;
302
+ width: calc(var(--game-height) * 0.03); height: calc(var(--game-height) * 0.3);
303
+ background: rgba(0,20,40,0.7); border: 2px solid #0ff; border-radius: 10px;
304
+ overflow: hidden; z-index:3;
305
+ }
306
+ .depth-indicator {
307
+ position:absolute; bottom:0; left:0; width:100%; height:0%;
308
+ background: linear-gradient(to top, #00BFFF, #00FFFF);
309
+ transition: height 0.5s ease-out;
310
+ }
311
+
312
+ .level-progress {
313
+ position: absolute; bottom: calc(var(--game-height) * 0.08);
314
+ left: 10px; width: clamp(100px, 18vw, 150px); height: calc(var(--game-height) * 0.025);
315
+ background: rgba(0,20,40,0.7); border: 1px solid #0ff; border-radius: 10px;
316
+ overflow: hidden; z-index:3;
317
+ }
318
+ .level-progress-bar {
319
+ height:100%; width:0%;
320
+ background: linear-gradient(to right, #00FFFF, #00BFFF);
321
+ border-radius: 9px 0 0 9px;
322
+ transition: width 0.3s ease-out;
323
+ }
324
+
325
+ .boss-health-container {
326
+ position: absolute; top: calc(var(--game-height) * 0.03); left: 50%;
327
+ transform: translateX(-50%); width: 60%; max-width: 400px;
328
+ height: calc(var(--game-height) * 0.025);
329
+ background: rgba(100,0,0,0.5); border: 2px solid #f00;
330
+ border-radius: 10px; z-index:3; display: none;
331
+ }
332
+ .boss-health-bar {
333
+ height:100%; width:100%;
334
+ background: linear-gradient(to right, #ff3333, #ff9933);
335
+ border-radius: 8px 0 0 8px;
336
+ transition: width 0.3s ease-out;
337
+ }
338
+ .boss-name {
339
+ position: absolute; top: calc(var(--game-height) * 0.03 + var(--game-height) * 0.025 + 5px);
340
+ left: 50%; transform: translateX(-50%);
341
+ color: #f33; font-size: clamp(12px, 2vw, 14px); font-weight: bold;
342
+ text-shadow: 0 0 5px #f00; z-index:3; display:none;
343
+ background-color: rgba(0,0,0,0.5); padding: 2px 8px; border-radius: 5px;
344
+ }
345
+ .boss-warning {
346
+ position: absolute; top: calc(var(--game-height) * 0.1); left: 50%;
347
+ transform: translateX(-50%); color: #f00; font-size: clamp(16px, 3vw, 20px);
348
+ font-weight: bold; text-shadow: 0 0 8px #f00; z-index:5; display:none;
349
+ animation: pulseWarning 1s infinite alternate;
350
+ }
351
+ @keyframes pulseWarning { from { opacity: 0.7; } to { opacity: 1; } }
352
+
353
+ .tutorial {
354
+ position: absolute; bottom: calc(var(--game-height) * 0.15); left: 50%;
355
+ transform: translateX(-50%); background: rgba(0,10,20,0.85);
356
+ padding: 10px 15px; border-radius: 8px; border: 1px solid #0ff;
357
+ font-size: clamp(12px, 2vw, 14px); color: #9ff; z-index:10;
358
+ opacity:0; transition: opacity 0.5s, transform 0.5s; pointer-events: none;
359
+ }
360
+ .tutorial.show { opacity:1; transform: translateX(-50%) translateY(-10px); }
361
+
362
+ .slider-container {
363
+ width: 60%; background: rgba(0,40,80,0.6); border-radius: 10px;
364
+ padding: 5px; border: 1px solid rgba(0,255,255,0.3);
365
+ }
366
+ input[type="range"].volume-slider {
367
+ width: 100%; height: 8px; background: rgba(0,255,255,0.2);
368
+ border-radius: 5px; outline: none; -webkit-appearance: none; appearance: none;
369
+ }
370
+ input[type="range"].volume-slider::-webkit-slider-thumb {
371
+ -webkit-appearance: none; appearance: none;
372
+ width: 18px; height: 18px; border-radius: 50%;
373
+ background: #0ff; cursor: pointer;
374
+ box-shadow: 0 0 5px #0ff;
375
+ }
376
+ input[type="range"].volume-slider::-moz-range-thumb {
377
+ width: 18px; height: 18px; border-radius: 50%;
378
+ background: #0ff; cursor: pointer; border: none;
379
+ box-shadow: 0 0 5px #0ff;
380
+ }
381
+
382
+ .loading-bar {
383
+ width: 60%; max-width: 300px; height: 15px;
384
+ background: rgba(0,40,80,0.7); border-radius: 10px;
385
+ margin-top: 20px; overflow:hidden; border: 1px solid #08a;
386
+ }
387
+ .loading-progress {
388
+ height:100%; width:0%;
389
+ background: linear-gradient(to right, #0ff, #0aa);
390
+ transition: width 0.2s ease-out; border-radius: 9px 0 0 9px;
391
+ }
392
+
393
+ .leaderboard-table { width: 100%; border-collapse: collapse; }
394
+ .leaderboard-table th, .leaderboard-table td {
395
+ padding: 8px; border-bottom: 1px solid rgba(0,255,255,0.2);
396
+ font-size: clamp(12px, 2vw, 14px);
397
+ }
398
+ .leaderboard-table th { background:rgba(0,40,80,0.6); text-transform: uppercase; }
399
+ .leaderboard-table tr:last-child td { border-bottom:none; }
400
+ .leaderboard-table tr:nth-child(even) { background-color: rgba(0,30,60,0.3); }
401
+ .leaderboard-table td:first-child { width: 10%; text-align: center; }
402
+ .leaderboard-table td:last-child { text-align: right; }
403
+
404
+ .skin-selector { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; justify-content: center;}
405
+ .skin {
406
+ width: 50px; height: 25px;
407
+ border-radius: 5px; display: flex; align-items: center; justify-content: center;
408
+ cursor: pointer; transition: all 0.2s; border: 2px solid transparent;
409
+ }
410
+ .skin.selected { transform: scale(1.1); border-color: #f0f; box-shadow: 0 0 10px #f0f; }
411
+ .skin span { font-size: 10px; color: white; text-shadow: 1px 1px 1px black;} /* For skin name preview if needed */
412
+
413
+ .dialog-box .button-group { display: flex; justify-content: center; gap: 10px; margin-top: 15px; flex-wrap: wrap;}
414
+ .placeholder-content p { margin-top: 15px; color: #789; font-style: italic; }
415
+
416
+ /* All other specific panel styles from user's HTML like .shop, .daily-challenge, etc. are fine */
417
+ /* The .matchmaking-game-score styles are extremely numerous and won't be used functionally */
418
+
419
+ </style>
420
+ </head>
421
+ <body>
422
+ <div class="stars-bg"></div>
423
+ <div class="game-container">
424
+ <div class="glow-border"></div>
425
+ <div class="radial-glow"></div>
426
+ <canvas id="gameCanvas"></canvas>
427
+
428
+ <div class="ui">
429
+ <div class="health-bar" id="healthBarContainer"><div class="health-fill" id="healthFill"></div></div>
430
+ <div>Score: <span id="score">0</span></div>
431
+ <div>Lvl: <span id="level">1</span>/<span id="maxLevels">10</span></div>
432
+ <div>Combo: <span id="combo">0x</span></div>
433
+ </div>
434
+
435
+ <div class="depth-meter"><div class="depth-indicator" id="depthIndicator"></div></div>
436
+ <div class="level-progress"><div class="level-progress-bar" id="levelProgressBar"></div></div>
437
+
438
+ <div class="boss-health-container" id="bossHealthContainer">
439
+ <div class="boss-health-bar" id="bossHealthBar"></div>
440
+ </div>
441
+ <div class="boss-name" id="bossName">BOSS NAME</div>
442
+ <div class="boss-warning" id="bossWarning">!!! BOSS APPROACHING !!!</div>
443
+
444
+ <div class="powerup-indicator" id="powerupIndicator"></div>
445
+
446
+ <div class="dialog-box start-screen" id="mainMenu">
447
+ <h1>DEEP SEA BREAKOUT</h1>
448
+ <p>Navigate treacherous depths, clear coral, and face menacing bosses. Collect power-ups to survive!</p>
449
+ <div class="button-group">
450
+ <button class="button" onclick="showDifficultySelect()">Start Game</button>
451
+ <button class="button" onclick="showScreen('settingsPanel')">Settings</button>
452
+ </div>
453
+ <div class="button-group">
454
+ <button class="button" onclick="showScreen('leaderboardScreen')">Leaderboard</button>
455
+ <button class="button" onclick="showScreen('tutorialScreenContent')">How to Play</button>
456
+ </div>
457
+ <div class="button-group">
458
+ <button class="button" onclick="showScreen('statsScreen')">Player Stats</button>
459
+ <button class="button" onclick="showScreen('customizationScreen')">Customize</button>
460
+ </div>
461
+ <div class="button-group">
462
+ <button class="button" onclick="showScreen('achievementsScreen')">Achievements</button>
463
+ <button class="button" onclick="showScreen('creditsScreen')">Credits</button>
464
+ </div>
465
+ <div class="button-group">
466
+ <button class="button" onclick="showScreenWithPlaceholder('shopScreen', 'Item Shop')">Shop</button>
467
+ <button class="button" onclick="showScreenWithPlaceholder('dailyChallengeScreen', 'Daily Challenges')">Challenges</button>
468
+ </div>
469
+ <div class="instructions" style="margin-top:15px; font-size: 12px;">
470
+ <p><strong>Quick Controls:</strong> Mouse: Move | Click: Launch/Laser | P: Pause | M: Mute</p>
471
+ </div>
472
+ </div>
473
+
474
+ <div class="dialog-box" id="difficultySelectScreen" style="display: none;">
475
+ <h2>Select Difficulty</h2>
476
+ <div class="button-group">
477
+ <button class="button" onclick="initGame('normal')">Normal</button>
478
+ <button class="button" onclick="initGame('hardcore')">Hardcore</button>
479
+ </div>
480
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 15px;">Back</button>
481
+ </div>
482
+
483
+ <div class="pause-message" id="pauseMessage">PAUSED</div>
484
+ <div class="combo-meter" id="comboMeter">0x COMBO!</div>
485
+
486
+ <div class="dialog-box" id="gameOver" style="display: none;">
487
+ <h2>MISSION FAILED</h2>
488
+ <p>Your score: <span id="finalScore">0</span></p>
489
+ <p id="highScoreText" style="color: #facc15;"></p>
490
+ <div class="button-group">
491
+ <button class="button" onclick="initGame(game.difficulty)">Try Again</button>
492
+ <button class="button" onclick="showScreen('mainMenu')">Main Menu</button>
493
+ </div>
494
+ </div>
495
+
496
+ <div class="dialog-box" id="gameWon" style="display: none;">
497
+ <h2>MISSION COMPLETE!</h2>
498
+ <p>You conquered all <span id="totalLevelsWon">10</span> ocean levels!</p>
499
+ <p>Final score: <span id="winScore">0</span></p>
500
+ <p id="winHighScoreText" style="color: #facc15;"></p>
501
+ <div class="button-group">
502
+ <button class="button" onclick="initGame(game.difficulty)">Play Again</button>
503
+ <button class="button" onclick="showScreen('mainMenu')">Main Menu</button>
504
+ </div>
505
+ </div>
506
+
507
+ <div class="controls" id="gameControls">
508
+ Mouse: Move • Click: Launch/Laser • P: Pause • M: Mute
509
+ </div>
510
+
511
+ <div class="achievement-popup" id="achievementPopup">
512
+ <div class="achievement-icon" id="achievementPopupIcon">🏆</div>
513
+ <div>
514
+ <div class="achievement-title" id="achievementPopupTitle">Achievement Unlocked!</div>
515
+ <div class="achievement-description" id="achievementPopupDesc">You did something awesome!</div>
516
+ </div>
517
+ </div>
518
+ <div class="notification" id="notificationPopup">
519
+ <div class="notification-icon" id="notificationPopupIcon">ℹ️</div>
520
+ <div>
521
+ <div class="notification-title" id="notificationPopupTitle">Notification</div>
522
+ <div class="notification-description" id="notificationPopupDesc">Something happened.</div>
523
+ </div>
524
+ </div>
525
+
526
+ <div class="level-transition" id="levelTransitionScreen"><div class="level-number" id="levelTransitionNumber">LEVEL 1</div></div>
527
+ <div class="boss-intro" id="bossIntroScreen"><div class="boss-name-large" id="bossIntroName">BOSS NAME</div></div>
528
+ <div class="boss-defeated" id="bossDefeatedScreen"><div class="boss-defeated-text" id="bossDefeatedName">BOSS DEFEATED!</div></div>
529
+ <div class="tutorial" id="tutorialPopup"><span id="tutorialText">Move mouse to control paddle!</span></div>
530
+ <div class="tooltip" id="tooltip" style="display:none;">Tooltip text</div>
531
+
532
+ <div class="settings-panel" id="settingsPanel">
533
+ <h2 class="settings-header">Settings</h2>
534
+ <div class="setting-row">
535
+ <span class="setting-label">Master Volume:</span>
536
+ <div class="slider-container">
537
+ <input type="range" min="0" max="1" step="0.01" value="0.4" class="volume-slider" id="masterVolumeSlider">
538
+ </div>
539
+ </div>
540
+ <div class="setting-row">
541
+ <span class="setting-label">SFX Volume:</span>
542
+ <div class="slider-container">
543
+ <input type="range" min="0" max="1" step="0.01" value="0.5" class="volume-slider" id="sfxVolumeSlider">
544
+ </div>
545
+ </div>
546
+ <div class="setting-row">
547
+ <span class="setting-label">Visual Theme:</span>
548
+ <select id="themeSelector" class="button" style="padding: 5px 10px; text-transform: none; background: #005577; border-color: #0088aa;">
549
+ <option value="deepSea">Deep Sea</option>
550
+ <option value="volcanic">Volcanic Depths</option>
551
+ <option value="crystalCaverns">Crystal Caverns</option>
552
+ </select>
553
+ </div>
554
+ <div class="sound-test" style="margin-top: 15px;">
555
+ <button class="sound-button" onclick="audioManager.playSound(audioManager.definitions.blockHit)">Test Hit</button>
556
+ <button class="sound-button" onclick="audioManager.playSound(audioManager.definitions.powerUpCollect)">Test PU</button>
557
+ </div>
558
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back to Menu</button>
559
+ </div>
560
+
561
+ <div class="leaderboard dialog-box" id="leaderboardScreen">
562
+ <h2 class="leaderboard-title">High Scores</h2>
563
+ <table class="leaderboard-table" id="leaderboardTable">
564
+ <thead><tr><th>Rank</th><th>Name</th><th>Score</th></tr></thead>
565
+ <tbody></tbody>
566
+ </table>
567
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back to Menu</button>
568
+ </div>
569
+
570
+ <div class="dialog-box" id="placeholderDialog" style="display: none;">
571
+ <h2 id="placeholderTitle">Feature Not Available</h2>
572
+ <p id="placeholderMessage">This feature is currently under construction or planned for a future update. Thanks for your interest!</p>
573
+ <button class="button" onclick="showScreen('mainMenu')">Back to Menu</button>
574
+ </div>
575
+
576
+ <div class="achievement-system dialog-box" id="achievementsScreen">
577
+ <h2 class="achievement-system-title">Achievements</h2>
578
+ <div id="achievementsListContainer" style="max-height: 300px; overflow-y: auto; text-align: left;"></div>
579
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back</button>
580
+ </div>
581
+ <div class="tutorial-screen dialog-box" id="tutorialScreenContent">
582
+ <h2 class="tutorial-screen-title">How To Play</h2>
583
+ <div style="text-align: left; font-size: clamp(12px, 2vw, 14px);">
584
+ <p><strong>Objective:</strong> Clear all blocks (coral creatures) on each level by hitting them with the pearl.</p>
585
+ <p><strong>Controls:</strong></p>
586
+ <ul>
587
+ <li>- Move your mouse to control the paddle.</li>
588
+ <li>- Click the left mouse button to launch the pearl or fire lasers (if active).</li>
589
+ <li>- Press 'P' to pause or resume the game.</li>
590
+ <li>- Press 'M' to mute or unmute game sounds.</li>
591
+ </ul>
592
+ <p><strong>Gameplay:</strong></p>
593
+ <ul>
594
+ <li>- Don't let the primary pearl fall below your paddle, or you'll lose a life!</li>
595
+ <li>- Some blocks require multiple hits. Some creatures are dangerous!</li>
596
+ <li>- Collect falling power-ups for special abilities. Rare power-ups are extra potent!</li>
597
+ <li>- Build combos by hitting blocks consecutively for bonus points.</li>
598
+ <li>- Defeat mighty bosses on special levels to progress further into the abyss.</li>
599
+ </ul>
600
+ <p>Good luck, brave diver!</p>
601
+ </div>
602
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back</button>
603
+ </div>
604
+ <div class="stats-screen dialog-box" id="statsScreen">
605
+ <h2 class="stats-screen-title">Player Statistics</h2>
606
+ <div id="statsContainer" style="text-align: left;"></div>
607
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back</button>
608
+ </div>
609
+ <div class="credits dialog-box" id="creditsScreen">
610
+ <h2 class="credits-title">Credits</h2>
611
+ <p>Game Design & Development: You & AI Collaborator</p>
612
+ <p>Inspired by: Classic Breakout / Arkanoid Games</p>
613
+ <p>Fonts: Orbitron, Press Start 2P (Google Fonts)</p>
614
+ <button class="button" onclick="showScreen('mainMenu')">Back</button>
615
+ </div>
616
+ <div class="customization dialog-box" id="customizationScreen">
617
+ <h2 class="customization-title">Customize Paddle</h2>
618
+ <p>Select your paddle's appearance:</p>
619
+ <div class="skin-selector" id="paddleSkinSelector"></div>
620
+ <button class="button" onclick="showScreen('mainMenu')" style="margin-top: 20px;">Back</button>
621
+ </div>
622
+
623
+ <div class="loading-screen hidden" id="loadingScreen"> <!-- Start hidden, show via JS -->
624
+ <div id="loadingText">LOADING...</div>
625
+ <div class="loading-bar"><div class="loading-progress" id="loadingProgress"></div></div>
626
+ </div>
627
+ <div class="vignette"></div>
628
+ <div class="water-effect"></div>
629
+ </div>
630
+
631
+ <script>
632
+ // --- Game Setup ---
633
+ const gameContainer = document.querySelector('.game-container');
634
+ const canvas = document.getElementById('gameCanvas');
635
+
636
+ const GAME_WIDTH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--game-width')) || 800;
637
+ const GAME_HEIGHT = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--game-height')) || 600;
638
+ gameContainer.style.width = `${GAME_WIDTH}px`;
639
+ gameContainer.style.height = `${GAME_HEIGHT}px`;
640
+ canvas.width = GAME_WIDTH;
641
+ canvas.height = GAME_HEIGHT;
642
+ const ctx = canvas.getContext('2d');
643
+
644
+ // --- Chroma.js Basic Fallback ---
645
+ const chroma = window.chroma || {
646
+ contrast: (c1, c2) => {
647
+ const lum = (c) => 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
648
+ const c1Lum = typeof c1 === 'string' ? lum(chroma(c1)) : lum(c1);
649
+ const c2Lum = typeof c2 === 'string' ? lum(chroma(c2)) : lum(c2);
650
+ return Math.abs(c1Lum - c2Lum) > 100 ? 7 : 1.5; // Simplified: high if very different, low otherwise
651
+ },
652
+ (colorStr) => {
653
+ let r=0,g=0,b=0,a=1;
654
+ if (typeof colorStr !== 'string') colorStr = '#000'; // Safety for non-string
655
+ if (colorStr.startsWith('#')) {
656
+ const hex = colorStr.slice(1);
657
+ if (hex.length === 3) { r=parseInt(hex[0]+hex[0],16); g=parseInt(hex[1]+hex[1],16); b=parseInt(hex[2]+hex[2],16); }
658
+ else if (hex.length >= 6) { r=parseInt(hex.substring(0,2),16); g=parseInt(hex.substring(2,4),16); b=parseInt(hex.substring(4,6),16); if (hex.length === 8) a=parseInt(hex.substring(6,8),16)/255;}
659
+ } else if (colorStr.startsWith('rgb')) {
660
+ const parts = colorStr.match(/[\d.]+/g);
661
+ if (parts && parts.length >= 3) { r = +parts[0]; g = +parts[1]; b = +parts[2]; if (parts.length === 4) a = +parts[3]; }
662
+ }
663
+ return {
664
+ r,g,b,a,
665
+ darken: (amount = 1) => `rgb(${Math.max(0,r-30*amount)}, ${Math.max(0,g-30*amount)}, ${Math.max(0,b-30*amount)})`,
666
+ brighten: (amount = 1) => `rgb(${Math.min(255,r+30*amount)}, ${Math.min(255,g+30*amount)}, ${Math.min(255,b+30*amount)})`,
667
+ alpha: (newAlpha) => `rgba(${r},${g},${b},${newAlpha})`,
668
+ hex: () => `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`,
669
+ css: () => `rgba(${r},${g},${b},${a})`
670
+ }
671
+ }
672
+ };
673
+
674
+ // --- Audio Manager (from previous enhanced version, assumed stable) ---
675
+ class AudioManager {
676
+ constructor() {
677
+ this.audioContext = null; this.masterGain = null; this.sfxGain = null; this.isMuted = false;
678
+ this.definitions = { // Definitions moved here for clarity
679
+ blockHit: { freq1: 600, freq2: 300, duration: 0.05, volume: 0.15, type: 'triangle' },
680
+ paddleHit: { freq1: 440, freq2: 440, duration: 0.05, volume: 0.2, type: 'square' },
681
+ wallHit: { freq1: 200, freq2: 150, duration: 0.05, volume: 0.1, type: 'sawtooth' },
682
+ loseLife: { freq1: 300, freq2: 50, duration: 0.5, volume: 0.3, type: 'sawtooth' },
683
+ levelUp: [
684
+ { freq1: 500, freq2: 1000, duration: 0.3, volume: 0.25, type: 'sine', attack: 0.05, decay: 0.3 },
685
+ { freq1: 300, freq2: 600, duration: 0.3, volume: 0.15, type: 'square', attack: 0.05, decay: 0.3, delay: 0.05 }
686
+ ],
687
+ powerUpSpawn: { freq1: 700, freq2: 900, duration: 0.1, volume: 0.2, type: 'sine' },
688
+ powerUpCollect: { freq1: 800, freq2: 1200, duration: 0.2, volume: 0.3, type: 'triangle' },
689
+ rarePowerUpCollect: [
690
+ { freq1: 1000, freq2: 2000, duration: 0.4, volume: 0.4, type: 'sine', decay: 0.4 },
691
+ { freq1: 800, freq2: 1500, duration: 0.3, volume: 0.3, type: 'square', decay: 0.3, delay: 0.1 }
692
+ ],
693
+ combo: (comboCount) => ({
694
+ freq1: Math.min(1200, 300 + (comboCount * 25)), freq2: Math.min(1350, 450 + (comboCount * 25)),
695
+ duration: 0.15, volume: Math.min(0.4, 0.15 + (comboCount * 0.02)), type: 'sine'
696
+ }),
697
+ gameOver: [
698
+ { freq1: 300, freq2: 100, duration: 1.5, volume: 0.4, type: 'sine' },
699
+ { freq1: 200, freq2: 50, duration: 1.0, volume: 0.3, type: 'square', delay: 0.2 }
700
+ ],
701
+ gameWon: [
702
+ { freq1: 500, freq2: 1200, duration: 1.0, volume: 0.4, type: 'sine' },
703
+ { freq1: 800, freq2: 1000, duration: 0.2, volume: 0.25, type: 'triangle', delay: 0.2 },
704
+ { freq1: 900, freq2: 1100, duration: 0.2, volume: 0.25, type: 'triangle', delay: 0.4 },
705
+ { freq1: 1000, freq2: 1200, duration: 0.2, volume: 0.25, type: 'triangle', delay: 0.6 }
706
+ ],
707
+ laserFire: { freq1: 1800, freq2: 1000, duration: 0.08, volume: 0.08, type: 'sawtooth', attack:0.005, decay: 0.04 },
708
+ blackHoleOpen: { freq1: 100, freq2: 30, duration: 1.5, volume: 0.5, type: 'sawtooth', decay: 1.5 },
709
+ blackHoleAbsorb: { freq1: 200, freq2: 400, duration: 0.05, volume: 0.2, type: 'noise', decay: 0.1 },
710
+ bossHit: { freq1: 250, freq2: 150, duration: 0.2, volume: 0.35, type: 'square' },
711
+ bossDefeat: [
712
+ { freq1: 100, freq2: 50, duration: 1.0, volume: 0.5, type: 'sawtooth' },
713
+ { freq1: 1000, freq2: 400, duration: 0.8, volume: 0.4, type: 'sine', delay: 0.2 }
714
+ ],
715
+ achievement: { freq1: 1200, freq2: 1800, duration: 0.3, volume: 0.3, type: 'triangle', attack: 0.02, decay: 0.2 }
716
+ };
717
+ }
718
+ async init() { /* ... same as before ... */
719
+ if(!this.audioContext){try{this.audioContext=new(window.AudioContext||window.webkitAudioContext)();this.masterGain=this.audioContext.createGain();this.sfxGain=this.audioContext.createGain();this.sfxGain.connect(this.masterGain);this.masterGain.connect(this.audioContext.destination);this.setVolume('master',parseFloat(localStorage.getItem('masterVolume_v2')||'0.4'));this.setVolume('sfx',parseFloat(localStorage.getItem('sfxVolume_v2')||'0.5'));}catch(e){console.error("Audio API init failed.",e);return;}}
720
+ if(this.audioContext.state==='suspended')await this.audioContext.resume();
721
+ }
722
+ setVolume(type, value) { /* ... same as before, ensure localStorage keys are unique ... */
723
+ const gainNode = type === 'master' ? this.masterGain : this.sfxGain;
724
+ if (gainNode && this.audioContext) { // Add audioContext check
725
+ gainNode.gain.setValueAtTime(this.isMuted && type === 'master' ? 0 : value, this.audioContext.currentTime);
726
+ localStorage.setItem(`${type}Volume_v2`, value); // Unique key
727
+ }
728
+ if (type === 'master' && document.getElementById('masterVolumeSlider')) document.getElementById('masterVolumeSlider').value = value;
729
+ if (type === 'sfx' && document.getElementById('sfxVolumeSlider')) document.getElementById('sfxVolumeSlider').value = value;
730
+ }
731
+ playSound(soundDef, dynamicParams = {}) { /* ... same as before ... */
732
+ if(this.isMuted||!this.audioContext||this.audioContext.state!=='running'||!soundDef)return;
733
+ const playSingle=(params)=>{const{freq1,freq2,duration,volume=0.3,type='sine',attack=0.01,decay=0.1,pan=0,delay=0}=params;const osc=this.audioContext.createOscillator();const gain=this.audioContext.createGain();const panner=this.audioContext.createStereoPanner();osc.connect(gain);gain.connect(panner);panner.connect(this.sfxGain);osc.type=type;panner.pan.setValueAtTime(pan,this.audioContext.currentTime+delay);osc.frequency.setValueAtTime(freq1,this.audioContext.currentTime+delay);if(freq2&&freq1!==freq2){osc.frequency.exponentialRampToValueAtTime(freq2,this.audioContext.currentTime+delay+duration);}gain.gain.setValueAtTime(0,this.audioContext.currentTime+delay);gain.gain.linearRampToValueAtTime(volume,this.audioContext.currentTime+delay+attack);gain.gain.exponentialRampToValueAtTime(0.001,this.audioContext.currentTime+delay+duration+decay);osc.start(this.audioContext.currentTime+delay);osc.stop(this.audioContext.currentTime+delay+duration+decay+0.05);};
734
+ let effDef=typeof soundDef==='function'?soundDef(dynamicParams):soundDef;if(Array.isArray(effDef)){effDef.forEach(p=>playSingle({...p,...dynamicParams}));}else{playSingle({...effDef,...dynamicParams});}
735
+ }
736
+ toggleMute() { /* ... same as before, ensure localStorage keys are unique ... */
737
+ if(!this.masterGain)return this.isMuted;this.isMuted=!this.isMuted;const currentMasterVolume=parseFloat(localStorage.getItem('masterVolume_v2')||'0.4');if(this.audioContext)this.masterGain.gain.setValueAtTime(this.isMuted?0:currentMasterVolume,this.audioContext.currentTime);return this.isMuted;
738
+ }
739
+ }
740
+ const audioManager = new AudioManager();
741
+
742
+ // --- Game Constants (using GAME_WIDTH, GAME_HEIGHT) ---
743
+ const PADDLE_DEFAULT_WIDTH = GAME_WIDTH * 0.13;
744
+ const PADDLE_HEIGHT = GAME_HEIGHT * 0.025;
745
+ const BALL_RADIUS = GAME_WIDTH * 0.01;
746
+ const BALL_INITIAL_SPEED = GAME_HEIGHT * 0.0085;
747
+
748
+ const POWERUP_DURATION = 9000;
749
+ const RARE_POWERUP_DURATION_MULTIPLIER = 1.4;
750
+ const POWERUP_DROP_CHANCE = 0.18; // Slightly increased
751
+ const RARE_POWERUP_CHANCE = 0.08; // Slightly increased
752
+ const COMBO_TIMEOUT = 2200;
753
+ const MAX_LEVELS = 10;
754
+ const BOSS_LEVELS = [5, MAX_LEVELS];
755
+
756
+ const POWERUP_TYPES = { WIDE_PADDLE: 'WIDE_PADDLE', STICKY_PADDLE: 'STICKY_PADDLE', PIERCING_BALL: 'PIERCING_BALL', LASER_PADDLE: 'LASER_PADDLE', MULTI_BALL: 'MULTI_BALL', SLOW_MO: 'SLOW_MO', SHIELD: 'SHIELD' };
757
+ const RARE_POWERUP_TYPES = { INVINCIBILITY: 'INVINCIBILITY', TIME_STOP: 'TIME_STOP', BLACK_HOLE: 'BLACK_HOLE', PENTA_BALL: 'PENTA_BALL', MEGA_LASER: 'MEGA_LASER', BLOCK_BOMB: 'BLOCK_BOMB' };
758
+ const ALL_POWERUP_TYPES = {...POWERUP_TYPES, ...RARE_POWERUP_TYPES};
759
+
760
+ const BLOCK_CREATURES = ['🐠', '🐟', '🐡', '🐢', '🦀', '🦞', '🦐', '🐚', '⭐', '🌊', '🫧'];
761
+ const DANGEROUS_CREATURES = ['🦈', '🐙', '🦑', '🐊']; // Pufferfish removed from dangerous, added to normal
762
+ const BOSS_CREATURES = {5: '🐙👑', 10: '🐲🌌'};
763
+
764
+ const PADDLE_SKINS = [
765
+ { id: 'default', name: 'Classic Blue', color1: '#30A8F8', color2: '#0077cc', outline: '#60C8FF' },
766
+ { id: 'ember', name: 'Ember Glow', color1: '#ff7e5f', color2: '#feb47b', outline: '#ffcf9f' },
767
+ { id: 'forest', name: 'Forest Gem', color1: '#00b09b', color2: '#96c93d', outline: '#c0ff7d' },
768
+ { id: 'void', name: 'Void Walker', color1: '#4A00E0', color2: '#8E2DE2', outline: '#C675FF' },
769
+ { id: 'gold', name: 'Golden Pearl', color1: '#FFD700', color2: '#FFA500', outline: '#FFEEAA' },
770
+ ];
771
+
772
+ let game = {
773
+ score: 0, highScore: 0, // Loaded in init
774
+ lives: 3, maxLives: 3, level: 1, running: false, paused: false, difficulty: 'normal',
775
+ initialBlockCount: 0, particles: [], backgroundFish: [], backgroundBubbles: [],
776
+ powerUpsOnScreen: [], activePowerUps: {},
777
+ combo: 0, lastHitTime: 0, balls: [], lasers: [], bubbleTexts: [], blackHole: null,
778
+ currentBackgroundHue: 180, currentTheme: 'deepSea', currentBoss: null,
779
+ achievements: {}, playerStats: {}, paddleSkin: PADDLE_SKINS[0],
780
+ levelTransitioning: false, gameTime: 0, currentScreen: 'loadingScreen',
781
+ gameSessionStartTime: 0, levelStartTime: 0,
782
+ isFlawlessLevel: true, // For achievement
783
+ };
784
+
785
+ let paddle = { x:0,y:0,width:0,height:0, targetX:0 }; // Initialized in initGame
786
+ let blocks = []; let mouseX = GAME_WIDTH / 2;
787
+
788
+ const blockColors = [ '#FF6347','#FFD700','#ADFF2F','#00CED1','#1E90FF','#9370DB','#FF69B4','#FFA07A','#20B2AA','#7FFF00','#BA55D3','#DA70D6','#6495ED','#FF4500','#32CD32','#8A2BE2' ];
789
+
790
+ // --- UI Management ---
791
+ function showScreen(screenId) {
792
+ document.querySelectorAll('.dialog-box, .menu, .settings-panel, .leaderboard, .shop, .daily-challenge, .achievement-system, .tutorial-screen, .stats-screen, .credits, .customization, .profile, .multiplayer-info, .matchmaking, #difficultySelectScreen, #placeholderDialog').forEach(el => el.style.display = 'none');
793
+ const screenElement = document.getElementById(screenId);
794
+ if (screenElement) {
795
+ screenElement.style.display = 'flex';
796
+ game.currentScreen = screenId;
797
+ // Pause game if showing a dialog and game was running
798
+ if (screenId !== 'game' && game.running && !game.paused) { // Check if game means the canvas play area
799
+ game.paused = true;
800
+ document.getElementById('pauseMessage').style.display = 'block'; // Show pause message if game was running
801
+ }
802
+ // Specific updates for certain screens
803
+ if (screenId === 'leaderboardScreen') updateLeaderboardDisplay();
804
+ else if (screenId === 'statsScreen') updateStatsDisplay();
805
+ else if (screenId === 'achievementsScreen') updateAchievementsDisplay();
806
+ else if (screenId === 'customizationScreen') populatePaddleSkins();
807
+ } else {
808
+ console.warn(`Screen with ID ${screenId} not found.`);
809
+ document.getElementById('mainMenu').style.display = 'flex';
810
+ game.currentScreen = 'mainMenu';
811
+ }
812
+ }
813
+
814
+ function showScreenWithPlaceholder(screenId, title) {
815
+ showScreen('placeholderDialog');
816
+ document.getElementById('placeholderTitle').textContent = title;
817
+ document.getElementById('placeholderMessage').textContent = `The ${title.toLowerCase()} feature is currently under construction or planned for a future update. Check back later!`;
818
+ }
819
+
820
+ function showNotification(title, description, icon = 'ℹ️', duration = 3000) { /* Same as before */
821
+ const p=document.getElementById('notificationPopup');document.getElementById('notificationPopupTitle').textContent=title;document.getElementById('notificationPopupDesc').textContent=description;document.getElementById('notificationPopupIcon').textContent=icon;p.classList.add('show');setTimeout(()=>p.classList.remove('show'),duration);
822
+ }
823
+ function showAchievementPopup(achievement) { /* Same as before */
824
+ const p=document.getElementById('achievementPopup');document.getElementById('achievementPopupTitle').textContent=achievement.name;document.getElementById('achievementPopupDesc').textContent=achievement.description;document.getElementById('achievementPopupIcon').textContent=achievement.icon;p.classList.add('show');audioManager.playSound(audioManager.definitions.achievement);setTimeout(()=>p.classList.remove('show'),4000);
825
+ }
826
+
827
+ // --- Initialization ---
828
+ function initPrimaryBall() { /* Same as before */
829
+ const sM=game.difficulty==='hardcore'?1.3:1;const bS=BALL_INITIAL_SPEED*sM;game.balls=[{x:paddle.x+paddle.width/2,y:paddle.y-BALL_RADIUS*1.5,dx:0,dy:0,radius:BALL_RADIUS,speed:bS+(game.level-1)*(GAME_HEIGHT*0.0004)*sM,attached:true,piercing:false,isPrimary:true,trail:[],color1:game.paddleSkin.color1,color2:game.paddleSkin.color2,color3:game.paddleSkin.outline}];
830
+ }
831
+ function createBackgroundElements() { /* Same as before */
832
+ if(game.backgroundFish.length===0){for(let i=0;i<15;i++)game.backgroundFish.push({x:Math.random()*GAME_WIDTH,y:Math.random()*GAME_HEIGHT,dx:(Math.random()-0.5)*(GAME_WIDTH*0.001),dy:(Math.random()-0.5)*(GAME_HEIGHT*0.0005),size:Math.random()*(GAME_WIDTH*0.02)+(GAME_WIDTH*0.015),creature:['🐠','🐟','🐡'][Math.floor(Math.random()*3)],alpha:Math.random()*0.2+0.05,flipX:Math.random()>0.5});}
833
+ if(game.backgroundBubbles.length===0){for(let i=0;i<40;i++){let b={r:Math.random()*(GAME_WIDTH*0.0035)+(GAME_WIDTH*0.001),dy:-(Math.random()*(GAME_HEIGHT*0.0008)+(GAME_HEIGHT*0.0002)),a:Math.random()*0.3+0.1,amp:Math.random()*(GAME_WIDTH*0.015)+(GAME_WIDTH*0.004),freq:Math.random()*0.05+0.01};b.x=Math.random()*GAME_WIDTH;b.y=GAME_HEIGHT+Math.random()*GAME_HEIGHT+b.r;b.ix=b.x;game.backgroundBubbles.push(b);}}
834
+ }
835
+ function createBlocks() { /* Same as before */
836
+ blocks=[];if(game.currentBoss)return;const bR=game.difficulty==='hardcore'?4:3;const rS=Math.min(10,bR+Math.floor(game.level*(game.difficulty==='hardcore'?0.9:0.7)));const cS=game.difficulty==='hardcore'?14:12;const tBAW=GAME_WIDTH*0.95;const sM=(GAME_WIDTH-tBAW)/2;const bW=(tBAW/cS)*0.92;const bG=(tBAW/cS)*0.08;const bH=GAME_HEIGHT*0.04;const tM=GAME_HEIGHT*0.12;const dBC=Math.min(0.25,game.level*0.025*(game.difficulty==='hardcore'?1.6:1.1));
837
+ for(let r=0;r<rS;r++){for(let c=0;c<cS;c++){if(Math.random()<0.08&&game.level>2)continue;const iD=Math.random()<dBC&&game.level>1;let mH=1;if(game.difficulty==='hardcore')mH=r<2?3:(r<5?2:1);else mH=r<1?2:1;if(iD)mH=Math.min(4,mH+1);mH=Math.min(5,mH+Math.floor(game.level/2.5));blocks.push({x:sM+c*(bW+bG),y:tM+r*(bH+bG*0.7),width:bW,height:bH,color:blockColors[(r*cS+c+game.level)%blockColors.length],hits:mH,maxHits:mH,creature:iD?DANGEROUS_CREATURES[Math.floor(Math.random()*DANGEROUS_CREATURES.length)]:BLOCK_CREATURES[Math.floor(Math.random()*BLOCK_CREATURES.length)],isDangerous:iD,animationOffset:Math.random()*Math.PI*2,id:`block-${r}-${c}`});}}
838
+ game.initialBlockCount=blocks.length;updateLevelProgressUI();game.isFlawlessLevel=true; // Reset for new level
839
+ }
840
+ function createBoss(level) { /* Same as before */
841
+ const bC=BOSS_CREATURES[level]||'😈';let bHP,bW,bH,bS,bAP;
842
+ if(level===BOSS_LEVELS[0]){bHP=50+20*(game.difficulty==='hardcore'?2:1);bW=GAME_WIDTH*0.3;bH=GAME_HEIGHT*0.15;bS=GAME_WIDTH*0.0005;bAP='tentacleSwipe';}
843
+ else if(level===BOSS_LEVELS[1]){bHP=80+30*(game.difficulty==='hardcore'?2:1);bW=GAME_WIDTH*0.4;bH=GAME_HEIGHT*0.2;bS=GAME_WIDTH*0.0003;bAP='energyBeam';}
844
+ else return null;
845
+ game.currentBoss={x:GAME_WIDTH/2-bW/2,y:GAME_HEIGHT*0.1,width:bW,height:bH,hp:bHP,maxHp:bHP,creature:bC,color:'#FF0055',dx:bS,vulnerableTime:0,lastAttackTime:0,attackPattern:bAP,animationOffset:Math.random()*Math.PI*2};blocks=[];document.getElementById('bossHealthContainer').style.display='block';document.getElementById('bossName').textContent=bC;document.getElementById('bossName').style.display='block';updateBossHealthUI();
846
+ }
847
+
848
+ function defineAchievements() { /* Same as before */
849
+ game.achievements={FIRST_BREAK:{name:"Icebreaker",description:"Destroy your first block.",unlocked:false,icon:'💥'},LEVEL_3:{name:"Deep Diver",description:"Reach Level 3.",unlocked:false,icon:'🌊'},LEVEL_5_BOSS:{name:"Kraken Guard Defeated",description:"Defeat the boss of Level 5.",unlocked:false,icon:'🐙'},GAME_WON:{name:"Abyssal Conqueror",description:`Clear all ${MAX_LEVELS} levels.`,unlocked:false,icon:'👑'},HIGH_SCORE_10K:{name:"Coral Collector",description:"Achieve a score of 10,000.",unlocked:false,icon:'💰'},POWERUP_MASTER:{name:"Power Overwhelming",description:"Collect 5 power-ups in a single game.",unlocked:false,icon:'⚡'},COMBO_15X:{name:"Combo King",description:"Achieve a 15x combo.",unlocked:false,icon:'✨'},NO_LIVES_LOST_LEVEL:{name:"Flawless Victory (Level)",description:"Clear a level without losing a life.",unlocked:false,icon:'🛡️'},};
850
+ const sA=JSON.parse(localStorage.getItem('deepSeaBreakoutAchievements_v2')||'{}');for(const k in game.achievements){if(sA[k])game.achievements[k].unlocked=true;}
851
+ }
852
+ function unlockAchievement(id) { /* Same as before */
853
+ if(game.achievements[id]&&!game.achievements[id].unlocked){game.achievements[id].unlocked=true;showAchievementPopup(game.achievements[id]);localStorage.setItem('deepSeaBreakoutAchievements_v2',JSON.stringify(game.achievements));game.score+=500;addBubbleText(`+500 (Achievement!)`,GAME_WIDTH/2,GAME_HEIGHT/2,'#FFD700',18);}
854
+ }
855
+
856
+ function initPlayerStats() { /* Same as before */
857
+ game.playerStats=JSON.parse(localStorage.getItem('deepSeaBreakoutStats_v2')||JSON.stringify({gamesPlayed:0,totalScore:0,totalBlocksBroken:0,totalPowerupsCollected:0,totalGameTime:0,highestLevelReached:0,bossesDefeated:0}));
858
+ }
859
+ function updatePlayerStat(stat, value) { /* Same as before */
860
+ if(game.playerStats.hasOwnProperty(stat)){game.playerStats[stat]=(game.playerStats[stat]||0)+value;}else{game.playerStats[stat]=value;}
861
+ }
862
+ function savePlayerStats() { /* Same as before */
863
+ localStorage.setItem('deepSeaBreakoutStats_v2',JSON.stringify(game.playerStats));
864
+ }
865
+
866
+ function addBubbleText(text, x, y, color, size, duration = 60) { /* Same as before */
867
+ game.bubbleTexts.push({text,x,y,color,size:size*(GAME_WIDTH/800),alpha:1,life:duration,initialY:y});
868
+ }
869
+
870
+ // --- Particle & Effect Drawers (simplified to save space, assume previous good implementations) ---
871
+ function drawParticles() { /* ... */ game.particles.forEach(p=>{let a=Math.pow(p.life/p.maxLife,1.5);ctx.save();ctx.globalAlpha=a;if(p.glow){let g=ctx.createRadialGradient(p.x,p.y,0,p.x,p.y,p.size*a);g.addColorStop(0,p.color);g.addColorStop(1,`${p.color}00`);ctx.fillStyle=g;}else{ctx.fillStyle=p.color;}ctx.beginPath();ctx.arc(p.x,p.y,p.size*a,0,Math.PI*2);ctx.fill();ctx.restore();});}
872
+ function drawBallTrails() { /* ... */ game.balls.forEach(b=>{if(b.trail.length>1){ctx.save();let p=game.activePowerUps[ALL_POWERUP_TYPES.PIERCING_BALL]||b.piercing;let c=p?[255,0,255]:(b.isPrimary?[parseInt(b.color2.substring(1,3),16),parseInt(b.color2.substring(3,5),16),parseInt(b.color2.substring(5,7),16)]:[200,200,200]);for(let i=0;i<b.trail.length;i++){let pt=b.trail[i],a=(i/b.trail.length)*0.4,r=pt.r*(i/b.trail.length);ctx.fillStyle=`rgba(${c[0]},${c[1]},${c[2]},${a})`;ctx.beginPath();ctx.arc(pt.x,pt.y,r,0,Math.PI*2);ctx.fill();}ctx.restore();}}); }
873
+ function drawBackgroundElements() { /* ... */
874
+ const targetHue=game.currentTheme==='volcanic'?20:(game.currentTheme==='crystalCaverns'?260:180+(game.level*4));game.currentBackgroundHue+=(targetHue-game.currentBackgroundHue)*0.01;
875
+ const grad=ctx.createLinearGradient(0,0,0,GAME_HEIGHT);
876
+ grad.addColorStop(0,`hsla(${game.currentBackgroundHue},70%,${game.currentTheme==='volcanic'?15:20}%,0.9)`);
877
+ grad.addColorStop(0.7,`hsla(${game.currentBackgroundHue+10},70%,${game.currentTheme==='volcanic'?8:10}%,1)`);
878
+ grad.addColorStop(1,`hsla(${game.currentBackgroundHue+20},70%,${game.currentTheme==='volcanic'?3:5}%,1)`);
879
+ ctx.fillStyle=grad;ctx.fillRect(0,0,GAME_WIDTH,GAME_HEIGHT);
880
+ game.backgroundFish.forEach(f=>{ctx.save();ctx.globalAlpha=f.alpha;ctx.font=`${f.size}px Arial`;ctx.textAlign='center';if(f.flipX){ctx.scale(-1,1);ctx.fillText(f.creature,-f.x,f.y);}else{ctx.fillText(f.creature,f.x,f.y);}ctx.restore();});
881
+ game.backgroundBubbles.forEach(b=>{ctx.save();ctx.globalAlpha=b.a;ctx.fillStyle='rgba(173,216,230,0.4)';ctx.beginPath();ctx.arc(b.x,b.y,b.r,0,Math.PI*2);ctx.fill();ctx.fillStyle='rgba(255,255,255,0.6)';ctx.beginPath();ctx.arc(b.x-b.r*0.3,b.y-b.r*0.3,b.r*0.4,0,Math.PI*2);ctx.fill();ctx.restore();});
882
+ }
883
+ function drawBubbleTexts() { /* ... */ for(let i=game.bubbleTexts.length-1;i>=0;i--){let b=game.bubbleTexts[i];ctx.save();ctx.globalAlpha=b.alpha;ctx.font=`bold ${b.size}px 'Orbitron',sans-serif`;ctx.textAlign='center';ctx.fillStyle=b.color;ctx.shadowColor='rgba(0,0,0,0.7)';ctx.shadowBlur=3;ctx.shadowOffsetX=1;ctx.shadowOffsetY=1;ctx.fillText(b.text,b.x,b.y);ctx.restore();b.y-=1*(GAME_HEIGHT/600);b.alpha=Math.max(0,b.life/60);b.size*=0.995;b.life--;if(b.life<=0)game.bubbleTexts.splice(i,1);}}
884
+ function drawPaddle() { /* ... */ const{x,y,width,height}=paddle;const s=game.paddleSkin;const cR=height/2;ctx.save();ctx.shadowColor=s.outline;ctx.shadowBlur=15+Math.sin(Date.now()/200)*3;ctx.fillStyle=chroma(s.outline).alpha(0.15).css();ctx.beginPath();ctx.roundRect(x-5,y-5,width+10,height+10,cR+5);ctx.fill();ctx.restore();const grad=ctx.createLinearGradient(x,y,x,y+height);grad.addColorStop(0,s.color1);grad.addColorStop(1,s.color2);ctx.fillStyle=grad;ctx.beginPath();ctx.roundRect(x,y,width,height,cR);ctx.fill();ctx.strokeStyle=s.outline;ctx.lineWidth=2;ctx.beginPath();ctx.roundRect(x,y,width,height,cR);ctx.stroke();if(game.activePowerUps[POWERUP_TYPES.LASER_PADDLE]||game.activePowerUps[RARE_POWERUP_TYPES.MEGA_LASER]){const iM=game.activePowerUps[RARE_POWERUP_TYPES.MEGA_LASER];ctx.fillStyle=iM?'#FF8C00':'#ff3333';const cW=width*(iM?0.15:0.1);const cH=height*(iM?1.2:0.8);ctx.beginPath();ctx.roundRect(x+width*0.15-cW/2,y-cH,cW,cH,2);ctx.fill();ctx.beginPath();ctx.roundRect(x+width*0.85-cW/2,y-cH,cW,cH,2);ctx.fill();if(iM){ctx.beginPath();ctx.roundRect(x+width*0.5-cW*0.8,y-cH*1.2,cW*1.6,cH*1.2,3);ctx.fill();}}if(game.activePowerUps[POWERUP_TYPES.SHIELD]){ctx.save();ctx.strokeStyle='#00FFFF';ctx.lineWidth=3;ctx.globalAlpha=0.5+Math.sin(Date.now()/150)*0.2;ctx.beginPath();ctx.arc(x+width/2,y+height/2,width/1.8,0,Math.PI*2);ctx.stroke();ctx.restore();}}
885
+ function drawBalls() { /* ... */ game.balls.forEach(b=>{const{x,y,radius,attached,isPrimary}=b;const isP=b.piercing||game.activePowerUps[ALL_POWERUP_TYPES.PIERCING_BALL]||game.activePowerUps[RARE_POWERUP_TYPES.INVINCIBILITY];if(!attached){ctx.save();const gR=radius*(isP?2.2:1.8);const grad=ctx.createRadialGradient(x,y,0,x,y,gR);const rgb=isP?[255,50,255]:(isPrimary?[parseInt(b.color2.substring(1,3),16),parseInt(b.color2.substring(3,5),16),parseInt(b.color2.substring(5,7),16)]:[220,220,220]);grad.addColorStop(0,`rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.4)`);grad.addColorStop(0.5,`rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.15)`);grad.addColorStop(1,`rgba(${rgb[0]},${rgb[1]},${rgb[2]},0)`);ctx.fillStyle=grad;ctx.beginPath();ctx.arc(x,y,gR,0,Math.PI*2);ctx.fill();ctx.restore();}const bG=ctx.createRadialGradient(x-radius*0.3,y-radius*0.3,0,x,y,radius);const c1=isP?'#ffffff':b.color1;const c2=isP?'#ffccff':b.color2;const c3=isP?'#ff33ff':b.color3;bG.addColorStop(0,c1);bG.addColorStop(0.5,c2);bG.addColorStop(1,c3);ctx.fillStyle=bG;ctx.beginPath();ctx.arc(x,y,radius,0,Math.PI*2);ctx.fill();ctx.fillStyle='rgba(255,255,255,0.7)';ctx.beginPath();ctx.arc(x-radius*0.35,y-radius*0.35,radius*0.3,0,Math.PI*2);ctx.fill();if(game.activePowerUps[POWERUP_TYPES.STICKY_PADDLE]&&attached&&isPrimary){ctx.save();ctx.strokeStyle='rgba(0,255,255,0.4)';ctx.setLineDash([BALL_RADIUS*0.5,BALL_RADIUS*0.3]);ctx.lineWidth=1.5;ctx.beginPath();ctx.moveTo(x,y-radius);ctx.lineTo(x,0);ctx.stroke();ctx.restore();}}); }
886
+ function drawBlocks() { /* ... */ blocks.forEach(b=>{const{x,y,width,height,color,hits,maxHits,creature,isDangerous,animationOffset}=b;const hR=hits/maxHits;const bR=Math.min(width,height)*0.15;const ay=isDangerous?Math.sin(Date.now()/250+animationOffset)*(height*0.05):0;if(isDangerous){ctx.save();ctx.shadowColor=`rgba(255,${60+Math.sin(Date.now()/180+animationOffset)*40},0,0.7)`;ctx.shadowBlur=12+Math.sin(Date.now()/180+animationOffset)*4;ctx.fillStyle=`rgba(180,0,0,${0.08+Math.sin(Date.now()/180+animationOffset)*0.04})`;ctx.beginPath();ctx.roundRect(x-2,y-2+ay,width+4,height+4,bR+2);ctx.fill();ctx.restore();}const grad=ctx.createLinearGradient(x,y,x,y+height);if(hits>1){grad.addColorStop(0,color);grad.addColorStop(1,chroma(color).darken(1.8).hex());}else{grad.addColorStop(0,color);grad.addColorStop(1,chroma(color).darken(0.8).hex()+'E0');}ctx.fillStyle=grad;ctx.beginPath();ctx.roundRect(x,y+ay,width,height,bR);ctx.fill();ctx.strokeStyle='rgba(255,255,255,0.15)';ctx.lineWidth=1;ctx.beginPath();ctx.roundRect(x,y+ay,width,height,bR);ctx.stroke();ctx.font=`${Math.min(width,height)*0.55}px Arial`;ctx.textAlign='center';ctx.textBaseline='middle';const cY=y+height/2+ay;ctx.fillStyle='rgba(0,0,0,0.3)';ctx.fillText(creature,x+width/2+1,cY+1);ctx.fillStyle=hR===1?'#fff':`rgba(255,255,255,${0.4+hR*0.6})`;ctx.fillText(creature,x+width/2,cY);if(hits<maxHits&&hits>0){ctx.save();const bY=y-(height*0.18)+ay;const bH=height*0.08;ctx.fillStyle='rgba(0,0,0,0.3)';ctx.beginPath();ctx.roundRect(x,bY,width,bH,bH/2);ctx.fill();ctx.fillStyle=hR>0.5?'#5f5':(hR>0.2?'#ff5':'#f55');ctx.beginPath();ctx.roundRect(x,bY,width*hR,bH,bH/2);ctx.fill();ctx.restore();}}); }
887
+ function drawLasers() { /* ... */ game.lasers.forEach(l=>{ctx.save();let g=ctx.createLinearGradient(l.x,l.y,l.x,l.y-l.h);g.addColorStop(0,'rgba(255,0,0,0)');g.addColorStop(0.3,l.isMega?'rgba(255,100,0,1)':'rgba(255,50,50,1)');g.addColorStop(1,l.isMega?'rgba(255,255,0,1)':'rgba(255,200,0,1)');ctx.fillStyle=g;ctx.beginPath();ctx.moveTo(l.x-l.w/2,l.y);ctx.lineTo(l.x+l.w/2,l.y);ctx.lineTo(l.x,l.y-l.h);ctx.closePath();ctx.fill();ctx.fillStyle='rgba(255,255,255,0.8)';ctx.beginPath();ctx.moveTo(l.x-l.w/4,l.y);ctx.lineTo(l.x+l.w/4,l.y);ctx.lineTo(l.x,l.y-l.h);ctx.closePath();ctx.fill();ctx.restore();}); }
888
+ function drawBlackHole() { /* ... */ if(!game.blackHole)return;const{x,y,radius,timeLeft,maxTimeLeft}=game.blackHole;const effScale=Math.min(1,(maxTimeLeft-timeLeft)/(maxTimeLeft*0.2));const curRad=radius*effScale;ctx.save();const ogRad=curRad*(2.5+Math.sin(Date.now()/150)*0.3);let grad=ctx.createRadialGradient(x,y,curRad*0.8,x,y,ogRad);grad.addColorStop(0,'rgba(100,0,150,0)');grad.addColorStop(0.5,`rgba(100,0,150,${0.4*effScale})`);grad.addColorStop(1,'rgba(100,0,150,0)');ctx.fillStyle=grad;ctx.beginPath();ctx.arc(x,y,ogRad,0,Math.PI*2);ctx.fill();ctx.strokeStyle=`rgba(150,50,255,${0.6*effScale})`;ctx.lineWidth=2;const numT=5;for(let i=0;i<numT;i++){ctx.beginPath();const rot=Date.now()/500+(i*Math.PI*2/numT);for(let ang=0;ang<Math.PI*1.5;ang+=0.1){const r=curRad*0.3+ang*curRad*0.2+Math.sin(ang*5+Date.now()/200)*curRad*0.1;const sx=x+Math.cos(ang+rot)*r;const sy=y+Math.sin(ang+rot)*r;if(ang===0)ctx.moveTo(sx,sy);else ctx.lineTo(sx,sy);}ctx.stroke();}ctx.fillStyle=`rgba(0,0,0,${0.9*effScale})`;ctx.beginPath();ctx.arc(x,y,curRad,0,Math.PI*2);ctx.fill();ctx.restore();}
889
+ function drawPowerUpsOnScreen() { /* ... */ game.powerUpsOnScreen.forEach(pu=>{const{x,y,radius,color,text,isRare}=pu;const eR=radius*(1+Math.sin(Date.now()/180+x*0.1)*(isRare?0.15:0.08));if(isRare){ctx.save();const gG=ctx.createRadialGradient(x,y,0,x,y,eR*1.8);gG.addColorStop(0,chroma(color).alpha(0.5).css());gG.addColorStop(1,chroma(color).alpha(0).css());ctx.fillStyle=gG;ctx.beginPath();ctx.arc(x,y,eR*1.8,0,Math.PI*2);ctx.fill();ctx.restore();}ctx.fillStyle=color;ctx.beginPath();ctx.arc(x,y,eR,0,Math.PI*2);ctx.fill();ctx.fillStyle=chroma.contrast(chroma(color),'black')>chroma.contrast(chroma(color),'white')?'black':'white';ctx.font=`bold ${eR*(text.length>1?0.75:0.95)}px 'Orbitron'`;ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText(text,x,y+eR*0.05);});}
890
+ function drawBoss() { /* ... */ if(!game.currentBoss)return;const b=game.currentBoss;const{x,y,width,height,creature,color,animationOffset}=b;const aY=y+Math.sin(Date.now()/400+animationOffset)*(height*0.05);ctx.save();ctx.shadowColor=chroma(color).darken(1).hex();ctx.shadowBlur=20+Math.sin(Date.now()/200)*5;ctx.fillStyle=chroma(color).alpha(0.2).css();ctx.beginPath();ctx.ellipse(x+width/2,aY+height/2+10,width/1.8,height/3,0,0,Math.PI*2);ctx.fill();ctx.shadowColor='transparent';const grad=ctx.createRadialGradient(x+width/2,aY+height/2,0,x+width/2,aY+height/2,Math.max(width,height)/2);grad.addColorStop(0,chroma(color).brighten(1).hex());grad.addColorStop(0.7,color);grad.addColorStop(1,chroma(color).darken(1).hex());ctx.fillStyle=grad;ctx.fillRect(x,aY,width,height);ctx.font=`${Math.min(width,height)*0.6}px Arial`;ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillStyle='#FFF';ctx.fillText(creature,x+width/2,aY+height/2);ctx.restore();}
891
+ function drawPowerUpIndicatorsUI() { /* Same as before */
892
+ const c=document.getElementById('powerupIndicator');c.innerHTML='';Object.entries(game.activePowerUps).forEach(([t,d])=>{const rT=Math.max(0,d.endTime-Date.now());const tD=d.isRare?POWERUP_DURATION*RARE_POWERUP_DURATION_MULTIPLIER:POWERUP_DURATION;const pc=(rT/tD)*100;const iD=document.createElement('div');iD.className='powerup-icon';if(d.isRare)iD.classList.add('rare');const pI=getPowerupInfo(t);iD.textContent=pI.icon;iD.style.background=pI.color;iD.style.setProperty('--time-left',`${pc}%`);c.appendChild(iD);});
893
+ }
894
+
895
+ // --- Update Logic (Slimmed for brevity - assume previous implementations for core logic) ---
896
+ function updatePaddle() { /* ... */ if(game.activePowerUps[RARE_POWERUP_TYPES.TIME_STOP]&&!game.paused)return;paddle.x+=(paddle.targetX-paddle.x)*0.28;paddle.x=Math.max(0,Math.min(paddle.x,GAME_WIDTH-paddle.width));game.balls.forEach(b=>{if(b.attached){b.x=paddle.x+paddle.width/2;b.y=paddle.y-b.radius-1;}}); }
897
+ function updateBalls() { /* ... from previous, ensuring stability */
898
+ for(let i=game.balls.length-1;i>=0;i--){
899
+ const ball=game.balls[i];if(ball.attached)continue;
900
+ let sF=1;if(game.activePowerUps[POWERUP_TYPES.SLOW_MO])sF=0.6;if(game.activePowerUps[RARE_POWERUP_TYPES.TIME_STOP]&&!ball.isPrimary&&!game.paused)sF=0.05;
901
+ ball.x+=ball.dx*sF;ball.y+=ball.dy*sF;
902
+
903
+ if(ball.x<=ball.radius||ball.x>=GAME_WIDTH-ball.radius){ball.dx*=-1;audioManager.playSound(audioManager.definitions.wallHit,{pan:(ball.x/GAME_WIDTH)*2-1});createEffectParticle(ball.x,ball.y,'#87ceeb',5,{sizeRange:[1,2.5]});ball.x=Math.max(ball.radius,Math.min(ball.x,GAME_WIDTH-ball.radius));}
904
+ if(ball.y<=ball.radius){ball.dy*=-1;audioManager.playSound(audioManager.definitions.wallHit,{pan:(ball.x/GAME_WIDTH)*2-1});createEffectParticle(ball.x,ball.y,'#87ceeb',5,{sizeRange:[1,2.5]});ball.y=ball.radius;}
905
+
906
+ if(ball.dy>0&&ball.y+ball.radius>=paddle.y&&ball.y-ball.radius<=paddle.y+paddle.height&&ball.x+ball.radius>=paddle.x&&ball.x-ball.radius<=paddle.x+paddle.width){
907
+ if(game.activePowerUps[POWERUP_TYPES.STICKY_PADDLE]&&ball.isPrimary){ball.attached=true;ball.dx=0;ball.dy=0;}
908
+ else{const hpN=(ball.x-(paddle.x+paddle.width/2))/(paddle.width/2);const bA=hpN*(Math.PI/2.7);const tS=ball.speed*(1+game.level*0.025);ball.dx=tS*Math.sin(bA);ball.dy=-tS*Math.cos(bA);ball.dx+=(Math.random()-0.5)*0.15*tS;}
909
+ audioManager.playSound(audioManager.definitions.paddleHit);createEffectParticle(ball.x,paddle.y,'#00ffff',8,{sizeRange:[1.5,3],upwardBias:-1});ball.y=paddle.y-ball.radius;
910
+ if(ball.isPrimary&&game.activePowerUps[POWERUP_TYPES.SHIELD]){delete game.activePowerUps[POWERUP_TYPES.SHIELD];addBubbleText("SHIELD BROKEN!",paddle.x+paddle.width/2,paddle.y-20,"#FF8C00",16);drawPowerUpIndicatorsUI();}
911
+ if(!ball.isPrimary&&game.combo>0&&!game.activePowerUps[RARE_POWERUP_TYPES.PENTA_BALL]){game.combo=Math.floor(game.combo/2);document.getElementById('combo').textContent=`${game.combo}x`;}
912
+ }
913
+
914
+ const isInv=game.activePowerUps[RARE_POWERUP_TYPES.INVINCIBILITY];
915
+ ball.piercing=game.activePowerUps[POWERUP_TYPES.PIERCING_BALL]||isInv;
916
+
917
+ if(game.currentBoss){const b=game.currentBoss;if(ball.x+ball.radius>b.x&&ball.x-ball.radius<b.x+b.width&&ball.y+ball.radius>b.y&&ball.y-ball.radius<b.y+b.height){if(b.vulnerableTime>0||isInv){b.hp--;game.score+=50*game.level;audioManager.playSound(audioManager.definitions.bossHit);createEffectParticle(ball.x,ball.y,b.color,15,{glow:true,sizeRange:[2,5]});updateBossHealthUI();if(b.hp<=0)bossDefeated();}else{audioManager.playSound(audioManager.definitions.wallHit,{pan:(ball.x/GAME_WIDTH)*2-1});createEffectParticle(ball.x,ball.y,'#AAAAFF',8,{sizeRange:[1,3]});}const dX=ball.x-(b.x+b.width/2),dY=ball.y-(b.y+b.height/2);if(Math.abs(dX)/(b.width/2)>Math.abs(dY)/(b.height/2))ball.dx*=-1;else ball.dy*=-1;}}
918
+ else{for(let j=blocks.length-1;j>=0;j--){const blk=blocks[j];if(ball.x+ball.radius>blk.x&&ball.x-ball.radius<blk.x+blk.width&&ball.y+ball.radius>blk.y&&ball.y-ball.radius<blk.y+blk.height){
919
+ if(blk.isDangerous&&ball.isPrimary&&!isInv&&!game.activePowerUps[POWERUP_TYPES.SHIELD]){game.lives--;game.isFlawlessLevel=false;audioManager.playSound(audioManager.definitions.loseLife);addBubbleText("-1 LIFE!",ball.x,ball.y,"#ff4444",20);createEffectParticle(ball.x,ball.y,"#ff0000",20,{glow:true});updateHealthBarUI();if(game.lives<=0){gameOver();return;}else{resetPrimaryBallAndPaddleState();continue;}}
920
+ else if(blk.isDangerous&&ball.isPrimary&&game.activePowerUps[POWERUP_TYPES.SHIELD]){delete game.activePowerUps[POWERUP_TYPES.SHIELD];addBubbleText("SHIELD PROTECTED!",paddle.x+paddle.width/2,paddle.y-20,"#00FFFF",16);drawPowerUpIndicatorsUI();}
921
+ audioManager.playSound(audioManager.definitions.blockHit);if(blocks.length===game.initialBlockCount)unlockAchievement('FIRST_BREAK');updatePlayerStat('totalBlocksBroken',1);createEffectParticle(blk.x+blk.width/2,blk.y+blk.height/2,blk.color,10,{sizeRange:[1,3]});
922
+ if(!ball.piercing){const bX=ball.x,bY=ball.y,blX=blk.x+blk.width/2,blY=blk.y+blk.height/2,dX=bX-blX,dY=bY-blY,wTH=(ball.radius+blk.width/2),hTH=(ball.radius+blk.height/2);if(Math.abs(dX)/wTH>Math.abs(dY)/hTH){ball.dx*=-1;ball.x+=ball.dx>0?0.1:-0.1;}else{ball.dy*=-1;ball.y+=ball.dy>0?0.1:-0.1;}}
923
+ blk.hits--;game.score+=5*game.level*(blk.isDangerous?1.5:1);
924
+ if(blk.hits<=0){game.score+=(10+(ball.piercing?5:0))*game.level*(blk.isDangerous?1.5:1);blocks.splice(j,1);updateLevelProgressUI();if(Math.random()<POWERUP_DROP_CHANCE)spawnPowerUpItem(blk.x+blk.width/2,blk.y+blk.height/2);}
925
+ updateCombo();if(!ball.piercing)break;}}}
926
+
927
+ if(ball.y>GAME_HEIGHT+ball.radius*3){if(ball.isPrimary){if(!isInv&&!game.activePowerUps[POWERUP_TYPES.SHIELD]){game.lives--;game.isFlawlessLevel=false;}else if(game.activePowerUps[POWERUP_TYPES.SHIELD]){delete game.activePowerUps[POWERUP_TYPES.SHIELD];addBubbleText("SHIELD SAVED BALL!",paddle.x+paddle.width/2,paddle.y-20,"#00FFFF",16);drawPowerUpIndicatorsUI();}audioManager.playSound(audioManager.definitions.loseLife);updateHealthBarUI();if(game.lives<=0&&!isInv){gameOver();return;}else{resetPrimaryBallAndPaddleState();}}else{game.balls.splice(i,1);}}
928
+ }
929
+ }
930
+ function updateCombo() { /* ... */ const now=Date.now();if(now-game.lastHitTime>COMBO_TIMEOUT)game.combo=0;game.lastHitTime=now;game.combo++;document.getElementById('combo').textContent=`${game.combo}x`;if(game.combo>=3){const pts=Math.min(25,game.combo)*game.level;game.score+=pts;addBubbleText(`+${pts} COMBO!`,GAME_WIDTH/2,GAME_HEIGHT*0.4,'#ffff00',16+Math.min(10,game.combo));}if(game.combo>=5&&game.combo%2===(game.combo<10?1:0)){audioManager.playSound(audioManager.definitions.combo(game.combo));if(game.combo>=5){const cm=document.getElementById('comboMeter');cm.textContent=`${game.combo}X COMBO!`;cm.style.opacity='1';cm.style.transform='translate(-50%,-50%)scale(1.1)';cm.style.color=game.combo>=15?'#ff69b4':(game.combo>=10?'#ffaa00':'#ffff00');setTimeout(()=>{cm.style.opacity='0';cm.style.transform='translate(-50%,-50%)scale(0.8)';},800);}}if(game.combo>=15)unlockAchievement('COMBO_15X');}
931
+ function updateLasers() { /* ... */ for(let i=game.lasers.length-1;i>=0;i--){let l=game.lasers[i];l.y-=l.speed;if(l.y+l.h<0){game.lasers.splice(i,1);continue;}for(let j=blocks.length-1;j>=0;j--){let b=blocks[j];if(l.x>=b.x&&l.x<=b.x+b.width&&l.y<=b.y+b.height&&l.y+l.h>=b.y){createEffectParticle(l.x,b.y+b.height/2,l.isMega?'#FFA500':'#ffff00',10,{glow:true});if(l.isMega)b.hits=0;else b.hits-=2;if(b.hits<=0){blocks.splice(j,1);updateLevelProgressUI();}game.score+=(l.isMega?25:15)*game.level;updateCombo();game.lasers.splice(i,1);break;}}if(game.currentBoss&&game.lasers[i]){const boss=game.currentBoss;const laser=game.lasers[i];if(laser.x>=boss.x&&laser.x<=boss.x+boss.width&&laser.y<=boss.y+boss.height&&laser.y+laser.height>=boss.y){if(boss.vulnerableTime>0){boss.hp-=(laser.isMega?3:1);game.score+=(laser.isMega?100:75)*game.level;audioManager.playSound(audioManager.definitions.bossHit);createEffectParticle(laser.x,laser.y,boss.color,10,{glow:true,sizeRange:[1.5,4]});updateBossHealthUI();if(boss.hp<=0)bossDefeated();}game.lasers.splice(i,1);}}}}
932
+ function updateBoss() { /* ... */ if(!game.currentBoss)return;const b=game.currentBoss;b.x+=b.dx;if(b.x<=0||b.x+b.width>=GAME_WIDTH){b.dx*=-1;b.vulnerableTime=120;}if(b.vulnerableTime>0)b.vulnerableTime--;if(Date.now()-b.lastAttackTime>3000&&b.vulnerableTime<=0){addBubbleText("BOSS ATTACK!",b.x+b.width/2,b.y+b.height,"#FF5555",18);b.lastAttackTime=Date.now();}}
933
+ function updateBlackHole() { /* ... */ if(!game.blackHole)return;const bh=game.blackHole;bh.timeLeft--;if(bh.timeLeft<=0){game.blackHole=null;return;}game.balls.forEach(b=>{if(b.attached)return;const dx=bh.x-b.x,dy=bh.y-b.y;const dSq=dx*dx+dy*dy;if(dSq<Math.pow(bh.radius*5,2)&&dSq>10){const d=Math.sqrt(dSq);const f=bh.strength/dSq;b.dx+=dx/d*f;b.dy+=dy/d*f;const s=Math.sqrt(b.dx*b.dx+b.dy*b.dy);if(s>b.speed*1.5){b.dx=(b.dx/s)*b.speed*1.5;b.dy=(b.dy/s)*b.speed*1.5;}}});for(let i=blocks.length-1;i>=0;i--){const bl=blocks[i];const bX=bl.x+bl.width/2,bY=bl.y+bl.height/2;const dx=bh.x-bX,dy=bh.y-bY;const dSq=dx*dx+dy*dy;if(dSq<Math.pow(bh.radius*3,2)){if(dSq<Math.pow(bh.radius*0.8,2)){audioManager.playSound(audioManager.definitions.blackHoleAbsorb);createEffectParticle(bX,bY,chroma(bl.color).brighten(1).hex(),15,{upwardBias:0,speedRange:[1,3]});blocks.splice(i,1);updateLevelProgressUI();game.score+=20*game.level;updateCombo();}}}}
934
+ function updatePowerUpsOnScreen() { /* ... */ for(let i=game.powerUpsOnScreen.length-1;i>=0;i--){let pu=game.powerUpsOnScreen[i];pu.y+=pu.dy;if(pu.y-pu.radius>GAME_HEIGHT){game.powerUpsOnScreen.splice(i,1);continue;}if(pu.y+pu.radius>=paddle.y&&pu.y-pu.radius<=paddle.y+paddle.height&&pu.x+pu.radius>=paddle.x&&pu.x-pu.radius<=paddle.x+paddle.width){activatePowerUp(pu.type,pu.isRare);updatePlayerStat('totalPowerupsCollected',1);if(game.playerStats.totalPowerupsCollected>=5)unlockAchievement('POWERUP_MASTER');addBubbleText((pu.isRare?"RARE: ":"")+pu.type.replace(/_/g,' ')+"!",pu.x,pu.y,pu.isRare?"gold":"#00dddd",16);game.powerUpsOnScreen.splice(i,1);}}}
935
+ function activatePowerUp(type, isRare) { /* ... */ isRare?audioManager.playSound(audioManager.definitions.rarePowerUpCollect):audioManager.playSound(audioManager.definitions.powerUpCollect);const dur=(isRare?POWERUP_DURATION*RARE_POWERUP_DURATION_MULTIPLIER:POWERUP_DURATION);if(game.activePowerUps[type])game.activePowerUps[type].endTime=Math.max(game.activePowerUps[type].endTime,Date.now()+dur);else game.activePowerUps[type]={endTime:Date.now()+dur,isRare,data:{}};switch(type){case POWERUP_TYPES.WIDE_PADDLE:paddle.width=PADDLE_DEFAULT_WIDTH*1.6;break;case POWERUP_TYPES.MULTI_BALL:addNewBall();break;case RARE_POWERUP_TYPES.PENTA_BALL:for(let k=0;k<4;k++)addNewBall();break;case RARE_POWERUP_TYPES.INVINCIBILITY:game.lives=Math.min(game.lives+1,game.maxLives);addBubbleText("+1 LIFE!",paddle.x+paddle.width/2,paddle.y,"#ffff00",20);updateHealthBarUI();break;case RARE_POWERUP_TYPES.BLACK_HOLE:audioManager.playSound(audioManager.definitions.blackHoleOpen);game.blackHole={x:GAME_WIDTH/2,y:GAME_HEIGHT/3,radius:GAME_WIDTH*0.06,strength:GAME_WIDTH*0.12,timeLeft:360,maxTimeLeft:360};break;case RARE_POWERUP_TYPES.BLOCK_BOMB:const bX=paddle.x+paddle.width/2;const bY=paddle.y-20;createEffectParticle(bX,bY,'#FF8C00',30,{sizeRange:[3,8],glow:true,speedRange:[5,10]});const bR=GAME_WIDTH*0.2;for(let i=blocks.length-1;i>=0;i--){const b=blocks[i];const dSq=Math.pow(b.x+b.width/2-bX,2)+Math.pow(b.y+b.height/2-bY,2);if(dSq<Math.pow(bR,2)){game.score+=10*game.level;blocks.splice(i,1);updateLevelProgressUI();createEffectParticle(b.x+b.width/2,b.y+b.height/2,b.color,5);}}updateCombo();break;}}
936
+ function updateActivePowerUps() { /* ... */ const now=Date.now();Object.entries(game.activePowerUps).forEach(([t,d])=>{if(now>d.endTime){deactivatePowerUp(t);delete game.activePowerUps[t];}});drawPowerUpIndicatorsUI();}
937
+ function deactivatePowerUp(type) { /* ... */ switch(type){case POWERUP_TYPES.WIDE_PADDLE:paddle.width=PADDLE_DEFAULT_WIDTH;break;case POWERUP_TYPES.PIERCING_BALL:game.balls.forEach(b=>b.piercing=false);break;}}
938
+ function fireLaser() { /* ... */ const iM=game.activePowerUps[RARE_POWERUP_TYPES.MEGA_LASER];if(game.lasers.length>=(iM?2:4)||!(game.activePowerUps[POWERUP_TYPES.LASER_PADDLE]||iM))return;audioManager.playSound(audioManager.definitions.laserFire);const lW=paddle.width*(iM?0.1:0.05);const lS=GAME_HEIGHT*(iM?0.025:0.02);const lH=PADDLE_HEIGHT*(iM?2.5:1.8);if(iM){game.lasers.push({x:paddle.x+paddle.width/2,y:paddle.y,width:lW*1.5,height:lH,speed:lS,isMega:true,h:lH});}else{game.lasers.push({x:paddle.x+paddle.width*0.2,y:paddle.y,width:lW,height:lH,speed:lS,isMega:false,h:lH});game.lasers.push({x:paddle.x+paddle.width*0.8,y:paddle.y,width:lW,height:lH,speed:lS,isMega:false,h:lH});}}
939
+ function addNewBall() { /* ... */ const pB=game.balls.find(b=>b.isPrimary);if(!pB||game.balls.length>=6)return;const nB={...pB};nB.isPrimary=false;nB.attached=false;nB.x=pB.x+(Math.random()-0.5)*pB.radius;nB.y=pB.y-pB.radius;nB.dx=(Math.random()-0.5)*pB.speed*0.6;nB.dy=-pB.speed*(0.7+Math.random()*0.3);nB.trail=[];game.balls.push(nB);}
940
+
941
+ // --- Game State Management ---
942
+ function resetPrimaryBallAndPaddleState() { /* ... */ const pB=game.balls.find(b=>b.isPrimary);if(pB){pB.x=paddle.x+paddle.width/2;pB.y=paddle.y-pB.radius*1.5;pB.dx=0;pB.dy=0;pB.attached=true;pB.piercing=false;pB.trail=[];}if(game.balls.some(b=>b.isPrimary&&b.attached))game.balls=game.balls.filter(b=>b.isPrimary);if(!game.activePowerUps[POWERUP_TYPES.WIDE_PADDLE])paddle.width=PADDLE_DEFAULT_WIDTH;game.combo=0;document.getElementById('combo').textContent='0x';}
943
+ async function showLevelTransitionScreen(levelNumber, text) { /* Combined transition screen */ const s=document.getElementById('levelTransitionScreen');document.getElementById('levelTransitionNumber').textContent=text||`LEVEL ${levelNumber}`;s.classList.add('active');await new Promise(r=>setTimeout(r,1500));s.classList.remove('active');await new Promise(r=>setTimeout(r,400));}
944
+ async function showBossScreen(type, name) { /* For intro/defeat */ const s=document.getElementById(type==='intro'?'bossIntroScreen':'bossDefeatedScreen');document.getElementById(type==='intro'?'bossIntroName':'bossDefeatedName').textContent=type==='intro'?name:`${name} DEFEATED!`;s.classList.add('active');if(type==='intro')document.getElementById('bossWarning').style.display='block';await new Promise(r=>setTimeout(r,2500));s.classList.remove('active');if(type==='intro')document.getElementById('bossWarning').style.display='none';await new Promise(r=>setTimeout(r,400));}
945
+
946
+ async function nextLevel() {
947
+ if(game.levelTransitioning) return; game.levelTransitioning = true;
948
+ if(game.isFlawlessLevel && game.level > 0) unlockAchievement('NO_LIVES_LOST_LEVEL');
949
+
950
+ await showLevelTransitionScreen(game.level + 1);
951
+ audioManager.playSound(audioManager.definitions.levelUp);
952
+
953
+ game.level++; game.levelStartTime = Date.now();
954
+ updatePlayerStat('highestLevelReached', Math.max(game.playerStats.highestLevelReached || 0, game.level));
955
+
956
+ if(game.level > MAX_LEVELS){gameWon();game.levelTransitioning=false;return;}
957
+ if(game.level===3)unlockAchievement('LEVEL_3');
958
+
959
+ game.balls.forEach(b=>b.speed+=(GAME_HEIGHT*0.0005)*(game.difficulty==='hardcore'?1.8:1.2));
960
+ Object.entries(game.activePowerUps).forEach(([t,d])=>{if(!d.isRare||t===RARE_POWERUP_TYPES.BLACK_HOLE){deactivatePowerUp(t);delete game.activePowerUps[t];}});
961
+ game.powerUpsOnScreen=[];game.lasers=[];if(game.blackHole)game.blackHole=null;
962
+
963
+ paddle.width=PADDLE_DEFAULT_WIDTH;initPrimaryBall();
964
+
965
+ if(BOSS_LEVELS.includes(game.level)){await showBossScreen('intro',BOSS_CREATURES[game.level]);createBoss(game.level);game.initialBlockCount=0;}
966
+ else{game.currentBoss=null;document.getElementById('bossHealthContainer').style.display='none';document.getElementById('bossName').style.display='none';createBlocks();}
967
+
968
+ updateDepthMeterUI();updateLevelProgressUI();
969
+ if(game.level===1&& (game.playerStats.gamesPlayed || 0) <=1)showTutorialMessage("Click to launch the Pearl!",5000);
970
+ game.levelTransitioning=false;
971
+ }
972
+
973
+ async function bossDefeated() {
974
+ const bossName = game.currentBoss.creature;
975
+ await showBossScreen('defeat', bossName);
976
+ audioManager.playSound(audioManager.definitions.bossDefeat);
977
+ addBubbleText(`${bossName} Vanquished!`, GAME_WIDTH/2, GAME_HEIGHT*0.4, '#FFD700', 30, 150);
978
+ game.score += 2000 * game.level; updatePlayerStat('bossesDefeated', 1);
979
+ if (game.level === BOSS_LEVELS[0]) unlockAchievement('LEVEL_5_BOSS');
980
+ game.currentBoss=null;document.getElementById('bossHealthContainer').style.display='none';document.getElementById('bossName').style.display='none';
981
+ for(let i=0;i<3;i++)spawnPowerUpItem(GAME_WIDTH/2+(i-1)*50,GAME_HEIGHT/3);
982
+ // Next level will be triggered by gameLoop detecting blocks.length === 0 (since boss is now null)
983
+ }
984
+
985
+ function updateHighScore() { if(game.score>game.highScore){game.highScore=game.score;localStorage.setItem('deepSeaBreakoutHighScore_v2',game.highScore);if(game.score>=10000)unlockAchievement('HIGH_SCORE_10K');return true;}return false;}
986
+ function gameOver() { game.running=false;updatePlayerStat('totalGameTime', (Date.now() - game.gameSessionStartTime)/1000);savePlayerStats();const nH=updateHighScore();document.getElementById('finalScore').textContent=game.score;document.getElementById('highScoreText').textContent=nH?`NEW HIGH SCORE: ${game.highScore}`:`High Score: ${game.highScore}`;showScreen('gameOver');audioManager.playSound(audioManager.definitions.gameOver);}
987
+ function gameWon() { game.running=false;updatePlayerStat('totalGameTime', (Date.now() - game.gameSessionStartTime)/1000);savePlayerStats();unlockAchievement('GAME_WON');const nH=updateHighScore();document.getElementById('winScore').textContent=game.score;document.getElementById('totalLevelsWon').textContent=MAX_LEVELS;document.getElementById('winHighScoreText').textContent=nH?`NEW HIGH SCORE: ${game.highScore}!`:`High Score: ${game.highScore}`;showScreen('gameWon');audioManager.playSound(audioManager.definitions.gameWon);}
988
+
989
+ async function initGame(difficulty = 'normal') {
990
+ const ldSc=document.getElementById('loadingScreen');const ldTxt=document.getElementById('loadingText');const ldPr=document.getElementById('loadingProgress');
991
+ ldSc.classList.remove('hidden');ldTxt.textContent="INITIALIZING AUDIO...";ldPr.style.width='10%';await audioManager.init();
992
+ ldTxt.textContent="PREPARING GAME STATE...";ldPr.style.width='30%';await new Promise(r=>setTimeout(r,100));
993
+
994
+ game.score=0;game.difficulty=difficulty;game.maxLives=game.difficulty==='hardcore'?2:3;game.lives=game.maxLives;game.level=1;game.paused=false;game.running=true;game.levelTransitioning=false;game.initialBlockCount=0;game.particles=[];game.powerUpsOnScreen=[];game.activePowerUps={};game.combo=0;game.balls=[];game.lasers=[];game.bubbleTexts=[];game.blackHole=null;game.currentBoss=null;game.currentBackgroundHue=180;game.gameTime=0;game.gameSessionStartTime=Date.now();game.levelStartTime=Date.now();game.isFlawlessLevel=true;
995
+ game.highScore = parseInt(localStorage.getItem('deepSeaBreakoutHighScore_v2') || '0');
996
+
997
+ if(!game.paddleSkin||PADDLE_SKINS.findIndex(s=>s.id===game.paddleSkin.id)===-1){game.paddleSkin=PADDLE_SKINS.find(s=>s.id===localStorage.getItem('deepSeaBreakoutPaddleSkin_v2'))||PADDLE_SKINS[0];}
998
+ updatePlayerStat('gamesPlayed',1);defineAchievements();initPlayerStats();
999
+
1000
+ paddle={x:GAME_WIDTH/2-PADDLE_DEFAULT_WIDTH/2,y:GAME_HEIGHT-PADDLE_HEIGHT*2.5,width:PADDLE_DEFAULT_WIDTH,height:PADDLE_HEIGHT,targetX:GAME_WIDTH/2-PADDLE_DEFAULT_WIDTH/2};
1001
+ initPrimaryBall();
1002
+
1003
+ ldTxt.textContent="BUILDING LEVEL...";ldPr.style.width='60%';await new Promise(r=>setTimeout(r,100));createBlocks();
1004
+ ldTxt.textContent="SUMMONING SEA LIFE...";ldPr.style.width='80%';await new Promise(r=>setTimeout(r,100));createBackgroundElements();
1005
+
1006
+ document.querySelectorAll('.dialog-box, .menu, .settings-panel, .leaderboard, .shop, .daily-challenge, .achievement-system, .tutorial-screen, .stats-screen, .credits, .customization, .profile, .multiplayer-info, .matchmaking, #difficultySelectScreen').forEach(el=>el.style.display='none');
1007
+ document.getElementById('bossHealthContainer').style.display='none';document.getElementById('bossName').style.display='none';document.getElementById('pauseMessage').style.display='none';
1008
+
1009
+ updateHealthBarUI();updateDepthMeterUI();updateLevelProgressUI();
1010
+ ['score','level','combo'].forEach(id=>document.getElementById(id).textContent=game[id]||'0');
1011
+ document.getElementById('maxLevels').textContent=MAX_LEVELS;
1012
+ drawPowerUpIndicatorsUI();
1013
+
1014
+ ldTxt.textContent="GAME READY!";ldPr.style.width='100%';await new Promise(r=>setTimeout(r,200));ldSc.classList.add('hidden');game.currentScreen='game';
1015
+
1016
+ if((game.playerStats.gamesPlayed||0)<=1)showTutorialMessage("Move mouse to control paddle!",5000);
1017
+
1018
+ if(animationFrameId)cancelAnimationFrame(animationFrameId);
1019
+ lastTime=performance.now();
1020
+ gameLoop(lastTime);
1021
+ }
1022
+
1023
+ // --- Game Loop ---
1024
+ let lastTime = 0; let animationFrameId; let frameCount = 0;
1025
+
1026
+ function gameLoop(timestamp) {
1027
+ animationFrameId=requestAnimationFrame(gameLoop); // Loop continues even if paused, but returns early
1028
+ if(!game.running)return;
1029
+
1030
+ const deltaTime=(timestamp-lastTime)/1000||0;lastTime=timestamp;
1031
+ if (game.currentScreen === 'game' && !game.paused && !game.levelTransitioning) {
1032
+ game.gameTime += deltaTime;
1033
+ }
1034
+
1035
+ if(game.paused || game.levelTransitioning || game.currentScreen !== 'game') { // Only draw if paused but game is active screen, or if transitioning
1036
+ if (game.paused && game.currentScreen === 'game') {
1037
+ // Optionally draw a static "paused" frame of the game if desired
1038
+ // For now, only the HTML pause message is shown.
1039
+ }
1040
+ return; // Skip updates and full redraw if paused, transitioning, or not on game screen
1041
+ }
1042
+
1043
+ ctx.clearRect(0,0,GAME_WIDTH,GAME_HEIGHT);
1044
+ updateBackgroundElements();updatePaddle();updateBalls();updateBoss();updateLasers();updateParticles();createBallTrailParticles();updatePowerUpsOnScreen();updateActivePowerUps();updateBlackHole();
1045
+ drawBackgroundElements();drawBlocks();drawBoss();drawPowerUpsOnScreen();drawLasers();drawBlackHole();drawBallTrails();drawBalls();drawPaddle();drawParticles();drawBubbleTexts();
1046
+
1047
+ ['score','level'].forEach(id=>document.getElementById(id).textContent=game[id]); // Combo is updated in its own func
1048
+
1049
+ if(!game.currentBoss&&blocks.length===0&&game.running&&!game.levelTransitioning){
1050
+ nextLevel(); // This is async and sets game.levelTransitioning
1051
+ }
1052
+ frameCount++;
1053
+ }
1054
+
1055
+ // --- Event Listeners & UI Helpers ---
1056
+ let eventController = new AbortController();
1057
+ function setupEventListeners() { /* ... same as before ... */
1058
+ eventController.abort();eventController=new AbortController();const{signal}=eventController;
1059
+ canvas.addEventListener('mousemove',e=>{if(!game.paused&&game.currentScreen==='game'){const r=canvas.getBoundingClientRect();paddle.targetX=e.clientX-r.left-paddle.width/2;mouseX=e.clientX-r.left;}},{signal});
1060
+ canvas.addEventListener('click',async()=>{if(!game.running||game.paused||game.currentScreen!=='game'||game.levelTransitioning)return;await audioManager.init();let bL=false;game.balls.forEach(b=>{if(b.attached){const aO=(Math.random()-0.5)*Math.PI*0.1;const bA=-Math.PI/2;b.dx=b.speed*Math.sin(bA+aO);b.dy=b.speed*Math.cos(bA+aO);b.attached=false;bL=true;}});if(!bL&&(game.activePowerUps[POWERUP_TYPES.LASER_PADDLE]||game.activePowerUps[RARE_POWERUP_TYPES.MEGA_LASER]))fireLaser();},{signal});
1061
+ window.addEventListener('keydown',e=>{const k=e.key.toLowerCase();
1062
+ if(k==='p'&&game.running&&game.currentScreen==='game'){game.paused=!game.paused;document.getElementById('pauseMessage').style.display=game.paused?'block':'none'; if(!game.paused && animationFrameId){ /* If unpausing ensure loop continues */ lastTime = performance.now(); /* Reset lastTime to avoid large deltaTime jump */ requestAnimationFrame(gameLoop);}}
1063
+ if(k==='m'){const iM=audioManager.toggleMute();showNotification(iM?"Audio Muted":"Audio Unmuted","",iM?"🔇":"🔊",1500);}
1064
+ if(k==='n'&&e.shiftKey&&game.running&&game.currentScreen==='game'){if(game.currentBoss)bossDefeated();else blocks=[];console.log("Debug: Level skip.");}
1065
+ },{signal});
1066
+ document.getElementById('masterVolumeSlider').addEventListener('input',(e)=>audioManager.setVolume('master',parseFloat(e.target.value)),{signal});
1067
+ document.getElementById('sfxVolumeSlider').addEventListener('input',(e)=>audioManager.setVolume('sfx',parseFloat(e.target.value)),{signal});
1068
+ document.getElementById('themeSelector').addEventListener('change',(e)=>{game.currentTheme=e.target.value;localStorage.setItem('deepSeaTheme_v2',game.currentTheme);},{signal});
1069
+ const comboUI=document.querySelector('.ui div:nth-child(4)');if(comboUI){comboUI.addEventListener('mouseenter',e=>{const tt=document.getElementById('tooltip');tt.textContent="Consecutive hits score bonus points!";tt.style.left=`${e.clientX+10}px`;tt.style.top=`${e.clientY-30}px`;tt.style.display='block';setTimeout(()=>tt.classList.add('show'),10);},{signal});comboUI.addEventListener('mouseleave',()=>{const tt=document.getElementById('tooltip');tt.classList.remove('show');setTimeout(()=>tt.style.display='none',200);},{signal});}
1070
+ }
1071
+
1072
+ document.addEventListener('DOMContentLoaded', () => {
1073
+ sessionStartTime=Date.now();
1074
+ game.highScore = parseInt(localStorage.getItem('deepSeaBreakoutHighScore_v2') || '0');
1075
+ populatePaddleSkins();
1076
+ game.currentTheme=localStorage.getItem('deepSeaTheme_v2')||'deepSea';document.getElementById('themeSelector').value=game.currentTheme;
1077
+ showScreen('mainMenu'); setupEventListeners();
1078
+ window.showDifficultySelect = () => showScreen('difficultySelectScreen');
1079
+ window.showScreenWithPlaceholder = showScreenWithPlaceholder; // Make it global for HTML onclick
1080
+ });
1081
+
1082
+ </script>
1083
+ </body>
1084
+ </html>