Xacodavt commited on
Commit
e546cf2
·
verified ·
1 Parent(s): eeaf6bd

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1580 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: O
3
- emoji: 🚀
4
- colorFrom: indigo
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: o
3
+ emoji: 🐳
4
+ colorFrom: red
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1580 @@
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="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sniper Elite Pro - Jogo de Tiro Avançado</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ body {
11
+ overflow: hidden;
12
+ background-color: #111;
13
+ font-family: 'Arial', sans-serif;
14
+ user-select: none;
15
+ }
16
+
17
+ #game-container {
18
+ position: relative;
19
+ width: 100vw;
20
+ height: 100vh;
21
+ background-image: url('https://images.unsplash.com/photo-1519751138087-5bf79df62d5b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80');
22
+ background-size: cover;
23
+ background-position: center;
24
+ transition: transform 0.3s ease-out;
25
+ }
26
+
27
+ #scope {
28
+ position: absolute;
29
+ width: 100px;
30
+ height: 100px;
31
+ border: 2px solid rgba(255, 0, 0, 0.8);
32
+ border-radius: 50%;
33
+ pointer-events: none;
34
+ z-index: 100;
35
+ transform: translate(-50%, -50%);
36
+ box-shadow: 0 0 15px rgba(255, 0, 0, 0.5);
37
+ }
38
+
39
+ #scope:before, #scope:after {
40
+ content: '';
41
+ position: absolute;
42
+ background: rgba(255, 0, 0, 0.8);
43
+ }
44
+
45
+ #scope:before {
46
+ width: 2px;
47
+ height: 30px;
48
+ left: 50%;
49
+ top: -30px;
50
+ transform: translateX(-50%);
51
+ }
52
+
53
+ #scope:after {
54
+ width: 30px;
55
+ height: 2px;
56
+ left: -30px;
57
+ top: 50%;
58
+ transform: translateY(-50%);
59
+ }
60
+
61
+ .target {
62
+ position: absolute;
63
+ width: 60px;
64
+ height: 60px;
65
+ background-size: contain;
66
+ background-repeat: no-repeat;
67
+ background-position: center;
68
+ transition: transform 0.1s;
69
+ z-index: 10;
70
+ filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.7));
71
+ }
72
+
73
+ .target.civilian {
74
+ background-image: url('https://cdn-icons-png.flaticon.com/512/4320/4320339.png');
75
+ }
76
+
77
+ .target.soldier {
78
+ background-image: url('https://cdn-icons-png.flaticon.com/512/102/102637.png');
79
+ }
80
+
81
+ .target.vip {
82
+ background-image: url('https://cdn-icons-png.flaticon.com/512/102/102642.png');
83
+ }
84
+
85
+ .target.hostage {
86
+ background-image: url('https://cdn-icons-png.flaticon.com/512/4320/4320344.png');
87
+ }
88
+
89
+ .bullet-hole {
90
+ position: absolute;
91
+ width: 20px;
92
+ height: 20px;
93
+ background-image: url('https://cdn-icons-png.flaticon.com/512/102/102661.png');
94
+ background-size: contain;
95
+ z-index: 5;
96
+ }
97
+
98
+ .blood-splatter {
99
+ position: absolute;
100
+ width: 80px;
101
+ height: 80px;
102
+ background-image: url('https://cdn-icons-png.flaticon.com/512/102/102664.png');
103
+ background-size: contain;
104
+ z-index: 15;
105
+ opacity: 0;
106
+ animation: fadeIn 0.5s forwards;
107
+ }
108
+
109
+ @keyframes fadeIn {
110
+ to { opacity: 1; }
111
+ }
112
+
113
+ #reticle {
114
+ position: absolute;
115
+ width: 10px;
116
+ height: 10px;
117
+ background-color: rgba(255, 0, 0, 0.7);
118
+ border-radius: 50%;
119
+ pointer-events: none;
120
+ z-index: 90;
121
+ transform: translate(-50%, -50%);
122
+ box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
123
+ }
124
+
125
+ #breathing-effect {
126
+ position: absolute;
127
+ width: 120px;
128
+ height: 120px;
129
+ border: 1px solid rgba(255, 255, 255, 0.3);
130
+ border-radius: 50%;
131
+ pointer-events: none;
132
+ z-index: 80;
133
+ transform: translate(-50%, -50%);
134
+ animation: breathe 4s infinite ease-in-out;
135
+ }
136
+
137
+ @keyframes breathe {
138
+ 0%, 100% { transform: translate(-50%, -50%) scale(1); }
139
+ 50% { transform: translate(-50%, -50%) scale(1.1); }
140
+ }
141
+
142
+ #wind-indicator {
143
+ position: absolute;
144
+ top: 20px;
145
+ right: 20px;
146
+ color: white;
147
+ background-color: rgba(0, 0, 0, 0.7);
148
+ padding: 10px;
149
+ border-radius: 5px;
150
+ z-index: 200;
151
+ backdrop-filter: blur(5px);
152
+ border: 1px solid rgba(255, 255, 255, 0.1);
153
+ }
154
+
155
+ #ammo-counter {
156
+ position: absolute;
157
+ bottom: 20px;
158
+ right: 20px;
159
+ color: white;
160
+ background-color: rgba(0, 0, 0, 0.7);
161
+ padding: 10px;
162
+ border-radius: 5px;
163
+ z-index: 200;
164
+ backdrop-filter: blur(5px);
165
+ border: 1px solid rgba(255, 255, 255, 0.1);
166
+ }
167
+
168
+ #score-display {
169
+ position: absolute;
170
+ top: 20px;
171
+ left: 20px;
172
+ color: white;
173
+ background-color: rgba(0, 0, 0, 0.7);
174
+ padding: 10px;
175
+ border-radius: 5px;
176
+ z-index: 200;
177
+ backdrop-filter: blur(5px);
178
+ border: 1px solid rgba(255, 255, 255, 0.1);
179
+ }
180
+
181
+ #distance-display {
182
+ position: absolute;
183
+ top: 70px;
184
+ left: 20px;
185
+ color: white;
186
+ background-color: rgba(0, 0, 0, 0.7);
187
+ padding: 10px;
188
+ border-radius: 5px;
189
+ z-index: 200;
190
+ backdrop-filter: blur(5px);
191
+ border: 1px solid rgba(255, 255, 255, 0.1);
192
+ }
193
+
194
+ #game-over {
195
+ position: absolute;
196
+ top: 0;
197
+ left: 0;
198
+ width: 100%;
199
+ height: 100%;
200
+ background-color: rgba(0, 0, 0, 0.9);
201
+ display: flex;
202
+ flex-direction: column;
203
+ justify-content: center;
204
+ align-items: center;
205
+ color: white;
206
+ z-index: 300;
207
+ display: none;
208
+ backdrop-filter: blur(5px);
209
+ }
210
+
211
+ #recoil-effect {
212
+ position: absolute;
213
+ width: 100%;
214
+ height: 100%;
215
+ background-color: rgba(255, 255, 255, 0.3);
216
+ pointer-events: none;
217
+ z-index: 95;
218
+ opacity: 0;
219
+ }
220
+
221
+ #zoom-controls {
222
+ position: absolute;
223
+ bottom: 20px;
224
+ left: 20px;
225
+ z-index: 200;
226
+ display: flex;
227
+ gap: 10px;
228
+ }
229
+
230
+ .zoom-btn {
231
+ width: 40px;
232
+ height: 40px;
233
+ background-color: rgba(0, 0, 0, 0.7);
234
+ color: white;
235
+ border: none;
236
+ border-radius: 50%;
237
+ display: flex;
238
+ justify-content: center;
239
+ align-items: center;
240
+ cursor: pointer;
241
+ font-size: 18px;
242
+ backdrop-filter: blur(5px);
243
+ border: 1px solid rgba(255, 255, 255, 0.1);
244
+ transition: all 0.2s;
245
+ }
246
+
247
+ .zoom-btn:hover {
248
+ background-color: rgba(255, 255, 255, 0.2);
249
+ transform: scale(1.1);
250
+ }
251
+
252
+ #sound-control {
253
+ position: absolute;
254
+ bottom: 20px;
255
+ left: 80px;
256
+ z-index: 200;
257
+ }
258
+
259
+ #sound-btn {
260
+ width: 40px;
261
+ height: 40px;
262
+ background-color: rgba(0, 0, 0, 0.7);
263
+ color: white;
264
+ border: none;
265
+ border-radius: 50%;
266
+ display: flex;
267
+ justify-content: center;
268
+ align-items: center;
269
+ cursor: pointer;
270
+ font-size: 18px;
271
+ backdrop-filter: blur(5px);
272
+ border: 1px solid rgba(255, 255, 255, 0.1);
273
+ transition: all 0.2s;
274
+ }
275
+
276
+ #sound-btn:hover {
277
+ background-color: rgba(255, 255, 255, 0.2);
278
+ transform: scale(1.1);
279
+ }
280
+
281
+ #main-menu {
282
+ position: absolute;
283
+ top: 0;
284
+ left: 0;
285
+ width: 100%;
286
+ height: 100%;
287
+ background-color: rgba(0, 0, 0, 0.8);
288
+ display: flex;
289
+ flex-direction: column;
290
+ justify-content: center;
291
+ align-items: center;
292
+ color: white;
293
+ z-index: 400;
294
+ backdrop-filter: blur(5px);
295
+ }
296
+
297
+ .menu-title {
298
+ font-size: 4rem;
299
+ font-weight: bold;
300
+ margin-bottom: 2rem;
301
+ text-shadow: 0 0 10px rgba(255, 0, 0, 0.7);
302
+ background: linear-gradient(to right, #ff0000, #ff6600);
303
+ -webkit-background-clip: text;
304
+ -webkit-text-fill-color: transparent;
305
+ }
306
+
307
+ .menu-btn {
308
+ background: linear-gradient(to right, #ff0000, #ff6600);
309
+ color: white;
310
+ border: none;
311
+ padding: 15px 30px;
312
+ margin: 10px;
313
+ border-radius: 50px;
314
+ font-size: 1.2rem;
315
+ cursor: pointer;
316
+ transition: all 0.3s;
317
+ box-shadow: 0 5px 15px rgba(255, 0, 0, 0.3);
318
+ min-width: 200px;
319
+ text-align: center;
320
+ }
321
+
322
+ .menu-btn:hover {
323
+ transform: translateY(-3px);
324
+ box-shadow: 0 8px 20px rgba(255, 0, 0, 0.4);
325
+ }
326
+
327
+ .menu-btn:active {
328
+ transform: translateY(1px);
329
+ }
330
+
331
+ #difficulty-select {
332
+ margin: 20px 0;
333
+ display: flex;
334
+ gap: 10px;
335
+ }
336
+
337
+ .difficulty-btn {
338
+ padding: 10px 20px;
339
+ border-radius: 50px;
340
+ border: 2px solid rgba(255, 255, 255, 0.3);
341
+ cursor: pointer;
342
+ transition: all 0.3s;
343
+ }
344
+
345
+ .difficulty-btn.active {
346
+ background: linear-gradient(to right, #ff0000, #ff6600);
347
+ border-color: transparent;
348
+ transform: scale(1.05);
349
+ }
350
+
351
+ #weapon-select {
352
+ margin: 20px 0;
353
+ display: flex;
354
+ gap: 15px;
355
+ }
356
+
357
+ .weapon-card {
358
+ background-color: rgba(0, 0, 0, 0.5);
359
+ border-radius: 10px;
360
+ padding: 15px;
361
+ width: 120px;
362
+ text-align: center;
363
+ cursor: pointer;
364
+ transition: all 0.3s;
365
+ border: 1px solid rgba(255, 255, 255, 0.1);
366
+ }
367
+
368
+ .weapon-card:hover {
369
+ transform: translateY(-5px);
370
+ box-shadow: 0 5px 15px rgba(255, 0, 0, 0.3);
371
+ }
372
+
373
+ .weapon-card.active {
374
+ border: 2px solid #ff0000;
375
+ transform: scale(1.05);
376
+ background-color: rgba(255, 0, 0, 0.1);
377
+ }
378
+
379
+ .weapon-icon {
380
+ font-size: 2rem;
381
+ margin-bottom: 10px;
382
+ }
383
+
384
+ .weapon-name {
385
+ font-weight: bold;
386
+ margin-bottom: 5px;
387
+ }
388
+
389
+ .weapon-stats {
390
+ font-size: 0.8rem;
391
+ color: #ccc;
392
+ }
393
+
394
+ #mission-briefing {
395
+ max-width: 600px;
396
+ text-align: center;
397
+ margin: 20px 0;
398
+ line-height: 1.6;
399
+ color: #ccc;
400
+ }
401
+
402
+ #sniper-sway {
403
+ position: absolute;
404
+ width: 100px;
405
+ height: 100px;
406
+ pointer-events: none;
407
+ z-index: 85;
408
+ transform-origin: center;
409
+ }
410
+
411
+ .hit-marker {
412
+ position: absolute;
413
+ width: 30px;
414
+ height: 30px;
415
+ background-image: url('https://cdn-icons-png.flaticon.com/512/102/102665.png');
416
+ background-size: contain;
417
+ z-index: 110;
418
+ opacity: 0;
419
+ transform: translate(-50%, -50%) scale(0.5);
420
+ animation: hitMarker 0.5s forwards;
421
+ }
422
+
423
+ @keyframes hitMarker {
424
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
425
+ 50% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
426
+ 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
427
+ }
428
+
429
+ #bullet-drop-indicator {
430
+ position: absolute;
431
+ width: 10px;
432
+ height: 10px;
433
+ background-color: rgba(255, 255, 0, 0.7);
434
+ border-radius: 50%;
435
+ pointer-events: none;
436
+ z-index: 86;
437
+ transform: translate(-50%, -50%);
438
+ box-shadow: 0 0 10px rgba(255, 255, 0, 0.5);
439
+ display: none;
440
+ }
441
+
442
+ #mission-timer {
443
+ position: absolute;
444
+ top: 120px;
445
+ left: 20px;
446
+ color: white;
447
+ background-color: rgba(0, 0, 0, 0.7);
448
+ padding: 10px;
449
+ border-radius: 5px;
450
+ z-index: 200;
451
+ backdrop-filter: blur(5px);
452
+ border: 1px solid rgba(255, 255, 255, 0.1);
453
+ }
454
+
455
+ #level-display {
456
+ position: absolute;
457
+ top: 170px;
458
+ left: 20px;
459
+ color: white;
460
+ background-color: rgba(0, 0, 0, 0.7);
461
+ padding: 10px;
462
+ border-radius: 5px;
463
+ z-index: 200;
464
+ backdrop-filter: blur(5px);
465
+ border: 1px solid rgba(255, 255, 255, 0.1);
466
+ }
467
+
468
+ .xp-bar {
469
+ width: 100%;
470
+ height: 5px;
471
+ background-color: rgba(255, 255, 255, 0.2);
472
+ border-radius: 5px;
473
+ margin-top: 5px;
474
+ overflow: hidden;
475
+ }
476
+
477
+ .xp-progress {
478
+ height: 100%;
479
+ background: linear-gradient(to right, #ff0000, #ff6600);
480
+ width: 0%;
481
+ transition: width 0.3s;
482
+ }
483
+
484
+ #notification {
485
+ position: absolute;
486
+ top: 50%;
487
+ left: 50%;
488
+ transform: translate(-50%, -50%);
489
+ background-color: rgba(0, 0, 0, 0.8);
490
+ color: white;
491
+ padding: 15px 30px;
492
+ border-radius: 5px;
493
+ z-index: 500;
494
+ opacity: 0;
495
+ transition: opacity 0.3s;
496
+ backdrop-filter: blur(5px);
497
+ border: 1px solid rgba(255, 0, 0, 0.5);
498
+ text-align: center;
499
+ max-width: 80%;
500
+ }
501
+ </style>
502
+ </head>
503
+ <body>
504
+ <div id="main-menu">
505
+ <h1 class="menu-title">SNIPER ELITE PRO</h1>
506
+
507
+ <div id="difficulty-select">
508
+ <div class="difficulty-btn active" data-difficulty="easy">Fácil</div>
509
+ <div class="difficulty-btn" data-difficulty="medium">Médio</div>
510
+ <div class="difficulty-btn" data-difficulty="hard">Difícil</div>
511
+ <div class="difficulty-btn" data-difficulty="expert">Especialista</div>
512
+ </div>
513
+
514
+ <div id="weapon-select">
515
+ <div class="weapon-card active" data-weapon="m24">
516
+ <div class="weapon-icon"><i class="fas fa-gun"></i></div>
517
+ <div class="weapon-name">M24</div>
518
+ <div class="weapon-stats">Dano: Médio<br>Estabilidade: Alta<br>Munição: 10</div>
519
+ </div>
520
+ <div class="weapon-card" data-weapon="awp">
521
+ <div class="weapon-icon"><i class="fas fa-gun"></i></div>
522
+ <div class="weapon-name">AWP</div>
523
+ <div class="weapon-stats">Dano: Alto<br>Estabilidade: Baixa<br>Munição: 5</div>
524
+ </div>
525
+ <div class="weapon-card" data-weapon="barrett">
526
+ <div class="weapon-icon"><i class="fas fa-gun"></i></div>
527
+ <div class="weapon-name">Barrett</div>
528
+ <div class="weapon-stats">Dano: Altíssimo<br>Estabilidade: Muito Baixa<br>Munição: 4</div>
529
+ </div>
530
+ </div>
531
+
532
+ <div id="mission-briefing">
533
+ <h3 class="text-xl font-bold mb-2">MISSÃO ATUAL: OPERAÇÃO FANTASMA</h3>
534
+ <p>Você foi destacado como atirador de elite para neutralizar alvos hostis em zona de conflito. Cuidado com civis e reféns - atirar neles resultará em penalidades. Complete a missão no tempo determinado e avance para o próximo nível.</p>
535
+ </div>
536
+
537
+ <button id="start-btn" class="menu-btn">
538
+ <i class="fas fa-play mr-2"></i>INICIAR MISSÃO
539
+ </button>
540
+ <button id="how-to-play-btn" class="menu-btn">
541
+ <i class="fas fa-question-circle mr-2"></i>COMO JOGAR
542
+ </button>
543
+ </div>
544
+
545
+ <div id="game-container">
546
+ <div id="scope"></div>
547
+ <div id="reticle"></div>
548
+ <div id="breathing-effect"></div>
549
+ <div id="recoil-effect"></div>
550
+ <div id="sniper-sway"></div>
551
+ <div id="bullet-drop-indicator"></div>
552
+
553
+ <div id="wind-indicator">
554
+ <i class="fas fa-wind mr-2"></i>
555
+ <span id="wind-value">0 m/s</span>
556
+ <span id="wind-direction">→</span>
557
+ </div>
558
+
559
+ <div id="ammo-counter">
560
+ <i class="fas fa-bullseye mr-2"></i>
561
+ <span id="ammo">10</span>/<span id="max-ammo">10</span>
562
+ </div>
563
+
564
+ <div id="score-display">
565
+ <i class="fas fa-star mr-2"></i>
566
+ Pontuação: <span id="score">0</span>
567
+ </div>
568
+
569
+ <div id="distance-display">
570
+ <i class="fas fa-ruler-combined mr-2"></i>
571
+ Distância: <span id="distance">0</span>m
572
+ </div>
573
+
574
+ <div id="mission-timer">
575
+ <i class="fas fa-clock mr-2"></i>
576
+ Tempo: <span id="timer">01:00</span>
577
+ </div>
578
+
579
+ <div id="level-display">
580
+ <i class="fas fa-level-up-alt mr-2"></i>
581
+ Nível: <span id="level">1</span>
582
+ <div class="xp-bar">
583
+ <div class="xp-progress" id="xp-bar"></div>
584
+ </div>
585
+ </div>
586
+
587
+ <div id="zoom-controls">
588
+ <button id="zoom-in" class="zoom-btn">+</button>
589
+ <button id="zoom-out" class="zoom-btn">-</button>
590
+ </div>
591
+
592
+ <div id="sound-control">
593
+ <button id="sound-btn" class="zoom-btn">
594
+ <i class="fas fa-volume-up"></i>
595
+ </button>
596
+ </div>
597
+
598
+ <div id="game-over">
599
+ <h1 class="text-4xl font-bold mb-4" id="result-title">MISSÃO CONCLUÍDA</h1>
600
+ <p class="text-2xl mb-2">Pontuação Final: <span id="final-score">0</span></p>
601
+ <p class="text-xl mb-2">Precisão: <span id="accuracy">0</span>%</p>
602
+ <p class="text-xl mb-2">Alvos Neutralizados: <span id="targets-hit">0</span>/<span id="total-targets">0</span></p>
603
+ <p class="text-xl mb-6">XP Ganho: <span id="xp-earned">0</span></p>
604
+ <button id="restart-btn" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-6 rounded-lg text-xl">
605
+ <i class="fas fa-redo mr-2"></i>Jogar Novamente
606
+ </button>
607
+ <button id="menu-btn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-6 rounded-lg text-xl mt-4">
608
+ <i class="fas fa-home mr-2"></i>Menu Principal
609
+ </button>
610
+ </div>
611
+
612
+ <div id="notification"></div>
613
+ </div>
614
+
615
+ <audio id="gunshot-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-gun-shot-1669.mp3" preload="auto"></audio>
616
+ <audio id="reload-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-gun-reload-2293.mp3" preload="auto"></audio>
617
+ <audio id="hit-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-arrow-whoosh-1491.mp3" preload="auto"></audio>
618
+ <audio id="miss-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-short-explosion-1694.mp3" preload="auto"></audio>
619
+ <audio id="bg-music" loop src="https://assets.mixkit.co/music/preview/mixkit-suspense-ambience-267.mp3" preload="auto"></audio>
620
+ <audio id="headshot-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-explosion-1689.mp3" preload="auto"></audio>
621
+ <audio id="penalty-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-negative-answer-interface-beep-220.mp3" preload="auto"></audio>
622
+ <audio id="level-up-sound" src="https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3" preload="auto"></audio>
623
+
624
+ <script>
625
+ // Configurações do jogo
626
+ const config = {
627
+ ammo: 10,
628
+ maxAmmo: 10,
629
+ score: 0,
630
+ targetsHit: 0,
631
+ totalTargets: 0,
632
+ shotsFired: 0,
633
+ zoomLevel: 1,
634
+ maxZoom: 3,
635
+ windSpeed: 0,
636
+ windDirection: 0,
637
+ soundEnabled: true,
638
+ gameTime: 60000, // 1 minuto
639
+ gameStarted: false,
640
+ gameOver: false,
641
+ difficulty: 'easy',
642
+ weapon: 'm24',
643
+ level: 1,
644
+ xp: 0,
645
+ xpToNextLevel: 100,
646
+ sniperSway: 0,
647
+ breathingPhase: 0,
648
+ showBulletDrop: false,
649
+ currentMission: 1,
650
+ totalMissions: 5,
651
+ missionObjectives: {
652
+ 1: { targets: 10, time: 60000, description: "Neutralize 10 alvos em 1 minuto" },
653
+ 2: { targets: 15, time: 60000, description: "Neutralize 15 alvos em 1 minuto" },
654
+ 3: { targets: 20, time: 60000, description: "Neutralize 20 alvos em 1 minuto" },
655
+ 4: { targets: 25, time: 60000, description: "Neutralize 25 alvos em 1 minuto" },
656
+ 5: { targets: 30, time: 60000, description: "Neutralize 30 alvos em 1 minuto" }
657
+ },
658
+ weapons: {
659
+ m24: { name: "M24", damage: 2, stability: 0.8, ammo: 10, reloadTime: 2000, sway: 1.0 },
660
+ awp: { name: "AWP", damage: 3, stability: 0.6, ammo: 5, reloadTime: 2500, sway: 1.5 },
661
+ barrett: { name: "Barrett", damage: 4, stability: 0.4, ammo: 4, reloadTime: 3000, sway: 2.0 }
662
+ }
663
+ };
664
+
665
+ // Elementos do DOM
666
+ const gameContainer = document.getElementById('game-container');
667
+ const scope = document.getElementById('scope');
668
+ const reticle = document.getElementById('reticle');
669
+ const windValue = document.getElementById('wind-value');
670
+ const windDirection = document.getElementById('wind-direction');
671
+ const ammoDisplay = document.getElementById('ammo');
672
+ const maxAmmoDisplay = document.getElementById('max-ammo');
673
+ const scoreDisplay = document.getElementById('score');
674
+ const distanceDisplay = document.getElementById('distance');
675
+ const gameOverScreen = document.getElementById('game-over');
676
+ const finalScore = document.getElementById('final-score');
677
+ const accuracyDisplay = document.getElementById('accuracy');
678
+ const restartBtn = document.getElementById('restart-btn');
679
+ const zoomInBtn = document.getElementById('zoom-in');
680
+ const zoomOutBtn = document.getElementById('zoom-out');
681
+ const soundBtn = document.getElementById('sound-btn');
682
+ const recoilEffect = document.getElementById('recoil-effect');
683
+ const sniperSway = document.getElementById('sniper-sway');
684
+ const bulletDropIndicator = document.getElementById('bullet-drop-indicator');
685
+ const timerDisplay = document.getElementById('timer');
686
+ const levelDisplay = document.getElementById('level');
687
+ const xpBar = document.getElementById('xp-bar');
688
+ const targetsHitDisplay = document.getElementById('targets-hit');
689
+ const totalTargetsDisplay = document.getElementById('total-targets');
690
+ const xpEarnedDisplay = document.getElementById('xp-earned');
691
+ const resultTitle = document.getElementById('result-title');
692
+ const mainMenu = document.getElementById('main-menu');
693
+ const startBtn = document.getElementById('start-btn');
694
+ const howToPlayBtn = document.getElementById('how-to-play-btn');
695
+ const menuBtn = document.getElementById('menu-btn');
696
+ const difficultyBtns = document.querySelectorAll('.difficulty-btn');
697
+ const weaponCards = document.querySelectorAll('.weapon-card');
698
+ const notification = document.getElementById('notification');
699
+
700
+ // Elementos de áudio
701
+ const gunshotSound = document.getElementById('gunshot-sound');
702
+ const reloadSound = document.getElementById('reload-sound');
703
+ const hitSound = document.getElementById('hit-sound');
704
+ const missSound = document.getElementById('miss-sound');
705
+ const bgMusic = document.getElementById('bg-music');
706
+ const headshotSound = document.getElementById('headshot-sound');
707
+ const penaltySound = document.getElementById('penalty-sound');
708
+ const levelUpSound = document.getElementById('level-up-sound');
709
+
710
+ // Variáveis do jogo
711
+ let mouseX = 0;
712
+ let mouseY = 0;
713
+ let targets = [];
714
+ let bulletHoles = [];
715
+ let gameTimer;
716
+ let targetSpawnInterval;
717
+ let windChangeInterval;
718
+ let countdownInterval;
719
+ let timeLeft = 0;
720
+ let swayInterval;
721
+ let breathingInterval;
722
+
723
+ // Inicialização do jogo
724
+ function initGame() {
725
+ // Resetar configurações
726
+ config.ammo = config.weapons[config.weapon].ammo;
727
+ config.maxAmmo = config.weapons[config.weapon].ammo;
728
+ config.score = 0;
729
+ config.targetsHit = 0;
730
+ config.totalTargets = 0;
731
+ config.shotsFired = 0;
732
+ config.zoomLevel = 1;
733
+ config.windSpeed = 0;
734
+ config.windDirection = 0;
735
+ config.gameOver = false;
736
+ config.gameStarted = true;
737
+
738
+ // Definir tempo baseado na dificuldade
739
+ const mission = config.missionObjectives[config.currentMission];
740
+ timeLeft = mission.time;
741
+ config.totalTargets = mission.targets;
742
+
743
+ // Atualizar displays
744
+ updateAmmoDisplay();
745
+ updateScoreDisplay();
746
+ updateWindDisplay();
747
+ updateTimerDisplay();
748
+ updateLevelDisplay();
749
+ totalTargetsDisplay.textContent = config.totalTargets;
750
+ targetsHitDisplay.textContent = config.targetsHit;
751
+
752
+ // Limpar alvos e marcas de tiro
753
+ clearTargets();
754
+ clearBulletHoles();
755
+
756
+ // Esconder menus
757
+ gameOverScreen.style.display = 'none';
758
+ mainMenu.style.display = 'none';
759
+
760
+ // Resetar zoom
761
+ gameContainer.style.transform = 'scale(1)';
762
+
763
+ // Iniciar temporizador do jogo
764
+ startGameTimer();
765
+
766
+ // Iniciar spawn de alvos
767
+ startTargetSpawning();
768
+
769
+ // Iniciar mudanças de vento
770
+ startWindChanges();
771
+
772
+ // Iniciar música de fundo
773
+ if (config.soundEnabled) {
774
+ bgMusic.currentTime = 0;
775
+ bgMusic.volume = 0.3;
776
+ bgMusic.play();
777
+ }
778
+
779
+ // Iniciar efeitos de sniper
780
+ startSniperEffects();
781
+
782
+ // Mostrar notificação de missão
783
+ showNotification(`MISSÃO ${config.currentMission}: ${mission.description}`);
784
+ }
785
+
786
+ // Atualizar display de munição
787
+ function updateAmmoDisplay() {
788
+ ammoDisplay.textContent = config.ammo;
789
+ maxAmmoDisplay.textContent = config.maxAmmo;
790
+ }
791
+
792
+ // Atualizar display de pontuação
793
+ function updateScoreDisplay() {
794
+ scoreDisplay.textContent = config.score;
795
+ }
796
+
797
+ // Atualizar display de vento
798
+ function updateWindDisplay() {
799
+ windValue.textContent = `${config.windSpeed.toFixed(1)} m/s`;
800
+
801
+ // Definir direção do vento
802
+ let directionSymbol;
803
+ if (config.windDirection >= 337.5 || config.windDirection < 22.5) directionSymbol = '→';
804
+ else if (config.windDirection < 67.5) directionSymbol = '↗';
805
+ else if (config.windDirection < 112.5) directionSymbol = '↑';
806
+ else if (config.windDirection < 157.5) directionSymbol = '↖';
807
+ else if (config.windDirection < 202.5) directionSymbol = '←';
808
+ else if (config.windDirection < 247.5) directionSymbol = '↙';
809
+ else if (config.windDirection < 292.5) directionSymbol = '↓';
810
+ else directionSymbol = '↘';
811
+
812
+ windDirection.textContent = directionSymbol;
813
+ }
814
+
815
+ // Atualizar display de distância
816
+ function updateDistanceDisplay(x, y) {
817
+ // Calcular distância aproximada baseada na posição do alvo
818
+ const distance = Math.sqrt(Math.pow(x - window.innerWidth/2, 2) + Math.pow(y - window.innerHeight/2, 2));
819
+ const scaledDistance = Math.floor(distance / 10);
820
+ distanceDisplay.textContent = scaledDistance;
821
+ return scaledDistance;
822
+ }
823
+
824
+ // Atualizar display de tempo
825
+ function updateTimerDisplay() {
826
+ const minutes = Math.floor(timeLeft / 60000);
827
+ const seconds = Math.floor((timeLeft % 60000) / 1000);
828
+ timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
829
+
830
+ // Mudar cor quando o tempo estiver acabando
831
+ if (timeLeft < 10000) {
832
+ timerDisplay.style.color = '#ff0000';
833
+ } else {
834
+ timerDisplay.style.color = '#ffffff';
835
+ }
836
+ }
837
+
838
+ // Atualizar display de nível
839
+ function updateLevelDisplay() {
840
+ levelDisplay.textContent = config.level;
841
+ xpBar.style.width = `${(config.xp / config.xpToNextLevel) * 100}%`;
842
+ }
843
+
844
+ // Iniciar temporizador do jogo
845
+ function startGameTimer() {
846
+ clearInterval(countdownInterval);
847
+
848
+ countdownInterval = setInterval(() => {
849
+ timeLeft -= 1000;
850
+ updateTimerDisplay();
851
+
852
+ if (timeLeft <= 0) {
853
+ clearInterval(countdownInterval);
854
+ checkMissionCompletion();
855
+ }
856
+ }, 1000);
857
+ }
858
+
859
+ // Verificar conclusão da missão
860
+ function checkMissionCompletion() {
861
+ if (config.targetsHit >= config.totalTargets) {
862
+ // Missão completada
863
+ const xpEarned = calculateXPEarned(true);
864
+ config.xp += xpEarned;
865
+
866
+ // Verificar level up
867
+ checkLevelUp();
868
+
869
+ // Próxima missão ou fim do jogo
870
+ if (config.currentMission < config.totalMissions) {
871
+ config.currentMission++;
872
+ showNotification(`MISSÃO ${config.currentMission} DESBLOQUEADA!`, 3000);
873
+ endGame(true);
874
+ } else {
875
+ endGame(true);
876
+ resultTitle.textContent = "TODAS AS MISSÕES CONCLUÍDAS!";
877
+ }
878
+ } else {
879
+ // Missão falhou
880
+ endGame(false);
881
+ resultTitle.textContent = "MISSÃO FALHOU";
882
+ }
883
+ }
884
+
885
+ // Calcular XP ganho
886
+ function calculateXPEarned(success) {
887
+ if (!success) return 0;
888
+
889
+ let baseXP = 100;
890
+ let multiplier = 1;
891
+
892
+ // Multiplicador de dificuldade
893
+ if (config.difficulty === 'medium') multiplier = 1.2;
894
+ else if (config.difficulty === 'hard') multiplier = 1.5;
895
+ else if (config.difficulty === 'expert') multiplier = 2;
896
+
897
+ // Bônus por precisão
898
+ const accuracy = config.shotsFired > 0 ? (config.targetsHit / config.shotsFired) : 0;
899
+ if (accuracy > 0.8) multiplier += 0.3;
900
+ else if (accuracy > 0.6) multiplier += 0.2;
901
+ else if (accuracy > 0.4) multiplier += 0.1;
902
+
903
+ // Bônus por tempo
904
+ const timeBonus = timeLeft / config.missionObjectives[config.currentMission].time;
905
+ multiplier += timeBonus * 0.5;
906
+
907
+ return Math.floor(baseXP * multiplier);
908
+ }
909
+
910
+ // Verificar level up
911
+ function checkLevelUp() {
912
+ if (config.xp >= config.xpToNextLevel) {
913
+ config.level++;
914
+ config.xp -= config.xpToNextLevel;
915
+ config.xpToNextLevel = Math.floor(config.xpToNextLevel * 1.2);
916
+
917
+ if (config.soundEnabled) {
918
+ levelUpSound.currentTime = 0;
919
+ levelUpSound.play();
920
+ }
921
+
922
+ showNotification(`LEVEL UP! Agora você é nível ${config.level}`, 3000);
923
+ updateLevelDisplay();
924
+ }
925
+ }
926
+
927
+ // Iniciar spawn de alvos
928
+ function startTargetSpawning() {
929
+ clearInterval(targetSpawnInterval);
930
+
931
+ // Intervalo baseado na dificuldade
932
+ let spawnInterval;
933
+ switch(config.difficulty) {
934
+ case 'easy': spawnInterval = 3000; break;
935
+ case 'medium': spawnInterval = 2500; break;
936
+ case 'hard': spawnInterval = 2000; break;
937
+ case 'expert': spawnInterval = 1500; break;
938
+ default: spawnInterval = 3000;
939
+ }
940
+
941
+ targetSpawnInterval = setInterval(spawnTarget, spawnInterval);
942
+ }
943
+
944
+ // Iniciar mudanças de vento
945
+ function startWindChanges() {
946
+ clearInterval(windChangeInterval);
947
+
948
+ // Intervalo baseado na dificuldade
949
+ let windChangeIntervalTime;
950
+ switch(config.difficulty) {
951
+ case 'easy': windChangeIntervalTime = 10000; break;
952
+ case 'medium': windChangeIntervalTime = 8000; break;
953
+ case 'hard': windChangeIntervalTime = 6000; break;
954
+ case 'expert': windChangeIntervalTime = 4000; break;
955
+ default: windChangeIntervalTime = 10000;
956
+ }
957
+
958
+ windChangeInterval = setInterval(changeWind, windChangeIntervalTime);
959
+ changeWind(); // Definir vento inicial
960
+ }
961
+
962
+ // Iniciar efeitos de sniper
963
+ function startSniperEffects() {
964
+ clearInterval(swayInterval);
965
+ clearInterval(breathingInterval);
966
+
967
+ // Efeito de oscilação baseado na arma e dificuldade
968
+ const weaponSway = config.weapons[config.weapon].sway;
969
+ let difficultyMultiplier = 1;
970
+
971
+ switch(config.difficulty) {
972
+ case 'medium': difficultyMultiplier = 1.3; break;
973
+ case 'hard': difficultyMultiplier = 1.7; break;
974
+ case 'expert': difficultyMultiplier = 2.2; break;
975
+ }
976
+
977
+ config.sniperSway = 0;
978
+ config.breathingPhase = 0;
979
+
980
+ swayInterval = setInterval(() => {
981
+ // Oscilação baseada na arma e dificuldade
982
+ config.sniperSway = Math.sin(Date.now() / 1000 * weaponSway * difficultyMultiplier) * 20;
983
+
984
+ // Efeito de respiração
985
+ config.breathingPhase += 0.01;
986
+ const breathingOffset = Math.sin(config.breathingPhase) * 5;
987
+
988
+ // Aplicar oscilação à mira
989
+ reticle.style.transform = `translate(-50%, -50%) translate(${config.sniperSway + breathingOffset}px, ${Math.cos(Date.now() / 1000 * weaponSway * 0.8 * difficultyMultiplier) * 10 + breathingOffset}px)`;
990
+
991
+ // Mostrar indicador de queda de bala quando zoomado
992
+ if (config.zoomLevel > 1.5 && config.showBulletDrop) {
993
+ const dropDistance = calculateBulletDrop();
994
+ bulletDropIndicator.style.display = 'block';
995
+ bulletDropIndicator.style.left = `${mouseX + config.sniperSway}px`;
996
+ bulletDropIndicator.style.top = `${mouseY + dropDistance}px`;
997
+ } else {
998
+ bulletDropIndicator.style.display = 'none';
999
+ }
1000
+ }, 16); // ~60fps
1001
+ }
1002
+
1003
+ // Calcular queda da bala
1004
+ function calculateBulletDrop() {
1005
+ // Baseado na distância, zoom e gravidade
1006
+ const distance = Math.sqrt(Math.pow(mouseX - window.innerWidth/2, 2) + Math.pow(mouseY - window.innerHeight/2, 2));
1007
+ const drop = (distance / 1000) * (config.zoomLevel * 0.5);
1008
+
1009
+ // Efeito do vento
1010
+ const windEffect = config.windSpeed * Math.sin(config.windDirection * Math.PI / 180) * 0.5;
1011
+
1012
+ return drop + windEffect;
1013
+ }
1014
+
1015
+ // Mudar vento aleatoriamente
1016
+ function changeWind() {
1017
+ // Velocidade baseada na dificuldade
1018
+ let maxWindSpeed;
1019
+ switch(config.difficulty) {
1020
+ case 'easy': maxWindSpeed = 5; break;
1021
+ case 'medium': maxWindSpeed = 8; break;
1022
+ case 'hard': maxWindSpeed = 12; break;
1023
+ case 'expert': maxWindSpeed = 15; break;
1024
+ default: maxWindSpeed = 5;
1025
+ }
1026
+
1027
+ config.windSpeed = Math.random() * maxWindSpeed;
1028
+ config.windDirection = Math.random() * 360;
1029
+ updateWindDisplay();
1030
+ }
1031
+
1032
+ // Spawnar alvo
1033
+ function spawnTarget() {
1034
+ if (config.gameOver || config.totalTargets <= targets.length) return;
1035
+
1036
+ const target = document.createElement('div');
1037
+
1038
+ // Tipo de alvo aleatório (com probabilidades diferentes)
1039
+ const targetTypeRoll = Math.random();
1040
+ let targetType, targetClass, health, speed, score;
1041
+
1042
+ if (targetTypeRoll < 0.7) { // 70% de chance - Soldado comum
1043
+ targetType = 'soldier';
1044
+ targetClass = 'target soldier';
1045
+ health = 2;
1046
+ speed = 1;
1047
+ score = 100;
1048
+ } else if (targetTypeRoll < 0.9) { // 20% de chance - VIP
1049
+ targetType = 'vip';
1050
+ targetClass = 'target vip';
1051
+ health = 3;
1052
+ speed = 0.8;
1053
+ score = 250;
1054
+ } else if (targetTypeRoll < 0.95) { // 5% de chance - Civil
1055
+ targetType = 'civilian';
1056
+ targetClass = 'target civilian';
1057
+ health = 1;
1058
+ speed = 1.2;
1059
+ score = -200;
1060
+ } else { // 5% de chance - Refém
1061
+ targetType = 'hostage';
1062
+ targetClass = 'target hostage';
1063
+ health = 1;
1064
+ speed = 0.7;
1065
+ score = -300;
1066
+ }
1067
+
1068
+ target.className = targetClass;
1069
+
1070
+ // Posição aleatória, mas não muito perto das bordas
1071
+ const x = 100 + Math.random() * (window.innerWidth - 200);
1072
+ const y = 100 + Math.random() * (window.innerHeight - 200);
1073
+
1074
+ target.style.left = `${x}px`;
1075
+ target.style.top = `${y}px`;
1076
+
1077
+ // Definir movimento do alvo
1078
+ const speedX = (Math.random() - 0.5) * 2 * speed;
1079
+ const speedY = (Math.random() - 0.5) * 2 * speed;
1080
+
1081
+ // Adicionar ao container
1082
+ gameContainer.appendChild(target);
1083
+
1084
+ // Adicionar aos alvos ativos
1085
+ targets.push({
1086
+ element: target,
1087
+ x: x,
1088
+ y: y,
1089
+ speedX: speedX,
1090
+ speedY: speedY,
1091
+ health: health,
1092
+ maxHealth: health,
1093
+ hit: false,
1094
+ type: targetType,
1095
+ score: score,
1096
+ headshot: false
1097
+ });
1098
+
1099
+ // Remover alvo após algum tempo
1100
+ setTimeout(() => {
1101
+ if (!target.hit) {
1102
+ removeTarget(target);
1103
+ }
1104
+ }, 10000);
1105
+ }
1106
+
1107
+ // Remover alvo
1108
+ function removeTarget(targetElement) {
1109
+ const index = targets.findIndex(t => t.element === targetElement);
1110
+ if (index !== -1) {
1111
+ targets.splice(index, 1);
1112
+ if (targetElement.parentNode) {
1113
+ gameContainer.removeChild(targetElement);
1114
+ }
1115
+ }
1116
+ }
1117
+
1118
+ // Limpar todos os alvos
1119
+ function clearTargets() {
1120
+ targets.forEach(target => {
1121
+ if (target.element.parentNode) {
1122
+ gameContainer.removeChild(target.element);
1123
+ }
1124
+ });
1125
+ targets = [];
1126
+ }
1127
+
1128
+ // Limpar todas as marcas de tiro
1129
+ function clearBulletHoles() {
1130
+ bulletHoles.forEach(hole => {
1131
+ if (hole.parentNode) {
1132
+ gameContainer.removeChild(hole);
1133
+ }
1134
+ });
1135
+ bulletHoles = [];
1136
+ }
1137
+
1138
+ // Disparar
1139
+ function fireShot() {
1140
+ if (config.ammo <= 0 || config.gameOver) return;
1141
+
1142
+ config.ammo--;
1143
+ config.shotsFired++;
1144
+ updateAmmoDisplay();
1145
+
1146
+ // Efeito de recuo
1147
+ showRecoil();
1148
+
1149
+ // Som de disparo
1150
+ if (config.soundEnabled) {
1151
+ gunshotSound.currentTime = 0;
1152
+ gunshotSound.volume = 0.7;
1153
+ gunshotSound.play();
1154
+ }
1155
+
1156
+ // Verificar se acertou algum alvo
1157
+ checkHit();
1158
+
1159
+ // Recarregar se acabou a munição
1160
+ if (config.ammo <= 0) {
1161
+ setTimeout(reload, config.weapons[config.weapon].reloadTime);
1162
+ }
1163
+ }
1164
+
1165
+ // Mostrar efeito de recuo
1166
+ function showRecoil() {
1167
+ recoilEffect.style.opacity = '0.3';
1168
+
1169
+ // Efeito de tremor baseado na arma
1170
+ const recoilAmount = (1 - config.weapons[config.weapon].stability) * 30;
1171
+ gameContainer.style.transform = `scale(${config.zoomLevel}) translate(${Math.random() * recoilAmount - recoilAmount/2}px, ${Math.random() * recoilAmount - recoilAmount/2}px)`;
1172
+ gameContainer.style.transformOrigin = `${mouseX/window.innerWidth*100}% ${mouseY/window.innerHeight*100}%`;
1173
+
1174
+ setTimeout(() => {
1175
+ recoilEffect.style.opacity = '0';
1176
+ gameContainer.style.transform = `scale(${config.zoomLevel})`;
1177
+ gameContainer.style.transformOrigin = `${mouseX/window.innerWidth*100}% ${mouseY/window.innerHeight*100}%`;
1178
+ }, 100);
1179
+ }
1180
+
1181
+ // Verificar acerto
1182
+ function checkHit() {
1183
+ // Calcular posição real do tiro considerando o vento e oscilação
1184
+ const windOffsetX = Math.cos(config.windDirection * Math.PI / 180) * config.windSpeed * 5;
1185
+ const windOffsetY = Math.sin(config.windDirection * Math.PI / 180) * config.windSpeed * 5;
1186
+
1187
+ const shotX = mouseX + windOffsetX + config.sniperSway;
1188
+ const shotY = mouseY + windOffsetY + calculateBulletDrop();
1189
+
1190
+ // Criar marca de tiro
1191
+ createBulletHole(shotX, shotY);
1192
+
1193
+ // Verificar colisão com alvos
1194
+ let hit = false;
1195
+
1196
+ for (let i = 0; i < targets.length; i++) {
1197
+ const target = targets[i];
1198
+ const targetRect = target.element.getBoundingClientRect();
1199
+
1200
+ if (
1201
+ shotX >= targetRect.left &&
1202
+ shotX <= targetRect.right &&
1203
+ shotY >= targetRect.top &&
1204
+ shotY <= targetRect.bottom
1205
+ ) {
1206
+ // Acertou o alvo
1207
+ hit = true;
1208
+
1209
+ // Verificar se foi headshot (parte superior do alvo)
1210
+ const isHeadshot = shotY < targetRect.top + targetRect.height * 0.3;
1211
+
1212
+ // Dano baseado na arma e headshot
1213
+ let damage = config.weapons[config.weapon].damage;
1214
+ if (isHeadshot) {
1215
+ damage *= 2;
1216
+ target.headshot = true;
1217
+ }
1218
+
1219
+ target.health -= damage;
1220
+
1221
+ // Som de acerto
1222
+ if (config.soundEnabled) {
1223
+ if (isHeadshot) {
1224
+ headshotSound.currentTime = 0;
1225
+ headshotSound.play();
1226
+ } else {
1227
+ hitSound.currentTime = 0;
1228
+ hitSound.play();
1229
+ }
1230
+ }
1231
+
1232
+ // Criar efeito de sangue
1233
+ createBloodSplatter(shotX, shotY);
1234
+
1235
+ // Mostrar marcador de acerto
1236
+ showHitMarker(shotX, shotY, isHeadshot);
1237
+
1238
+ // Verificar se destruiu o alvo
1239
+ if (target.health <= 0) {
1240
+ target.hit = true;
1241
+ config.targetsHit++;
1242
+ targetsHitDisplay.textContent = config.targetsHit;
1243
+
1244
+ // Calcular pontuação baseada na distância e tipo de alvo
1245
+ const distance = updateDistanceDisplay(target.x, target.y);
1246
+ let score = target.score;
1247
+
1248
+ // Bônus por headshot
1249
+ if (target.headshot) {
1250
+ score *= 1.5;
1251
+ showNotification("HEADSHOT!", 1000);
1252
+ }
1253
+
1254
+ // Bônus por distância
1255
+ score += distance * 2;
1256
+
1257
+ // Bônus por dificuldade
1258
+ switch(config.difficulty) {
1259
+ case 'medium': score *= 1.2; break;
1260
+ case 'hard': score *= 1.5; break;
1261
+ case 'expert': score *= 2; break;
1262
+ }
1263
+
1264
+ config.score += Math.floor(score);
1265
+
1266
+ updateScoreDisplay();
1267
+ removeTarget(target.element);
1268
+
1269
+ // Penalidade por acertar civil ou refém
1270
+ if (target.type === 'civilian' || target.type === 'hostage') {
1271
+ if (config.soundEnabled) {
1272
+ penaltySound.currentTime = 0;
1273
+ penaltySound.play();
1274
+ }
1275
+
1276
+ const penaltyText = target.type === 'civilian' ? "CIVIL ATINGIDO!" : "REFÉM ATINGIDO!";
1277
+ showNotification(penaltyText, 2000);
1278
+ }
1279
+ } else {
1280
+ // Efeito de dano
1281
+ target.element.style.transform = 'scale(1.2)';
1282
+ setTimeout(() => {
1283
+ target.element.style.transform = 'scale(1)';
1284
+ }, 100);
1285
+ }
1286
+
1287
+ break;
1288
+ }
1289
+ }
1290
+
1291
+ // Som de erro se não acertou
1292
+ if (!hit && config.soundEnabled) {
1293
+ missSound.currentTime = 0;
1294
+ missSound.play();
1295
+ }
1296
+ }
1297
+
1298
+ // Mostrar marcador de acerto
1299
+ function showHitMarker(x, y, isHeadshot) {
1300
+ const marker = document.createElement('div');
1301
+ marker.className = 'hit-marker';
1302
+
1303
+ if (isHeadshot) {
1304
+ marker.style.filter = 'hue-rotate(300deg) brightness(1.5)';
1305
+ }
1306
+
1307
+ marker.style.left = `${x}px`;
1308
+ marker.style.top = `${y}px`;
1309
+
1310
+ gameContainer.appendChild(marker);
1311
+
1312
+ // Remover após animação
1313
+ setTimeout(() => {
1314
+ if (marker.parentNode) {
1315
+ gameContainer.removeChild(marker);
1316
+ }
1317
+ }, 500);
1318
+ }
1319
+
1320
+ // Criar marca de tiro
1321
+ function createBulletHole(x, y) {
1322
+ const hole = document.createElement('div');
1323
+ hole.className = 'bullet-hole';
1324
+ hole.style.left = `${x - 10}px`;
1325
+ hole.style.top = `${y - 10}px`;
1326
+
1327
+ gameContainer.appendChild(hole);
1328
+ bulletHoles.push(hole);
1329
+
1330
+ // Limitar número de marcas de tiro
1331
+ if (bulletHoles.length > 20) {
1332
+ const oldHole = bulletHoles.shift();
1333
+ if (oldHole.parentNode) {
1334
+ gameContainer.removeChild(oldHole);
1335
+ }
1336
+ }
1337
+ }
1338
+
1339
+ // Criar efeito de sangue
1340
+ function createBloodSplatter(x, y) {
1341
+ const splatter = document.createElement('div');
1342
+ splatter.className = 'blood-splatter';
1343
+ splatter.style.left = `${x - 40}px`;
1344
+ splatter.style.top = `${y - 40}px`;
1345
+
1346
+ gameContainer.appendChild(splatter);
1347
+
1348
+ // Remover após animação
1349
+ setTimeout(() => {
1350
+ if (splatter.parentNode) {
1351
+ gameContainer.removeChild(splatter);
1352
+ }
1353
+ }, 2000);
1354
+ }
1355
+
1356
+ // Recarregar
1357
+ function reload() {
1358
+ if (config.ammo >= config.maxAmmo || config.gameOver) return;
1359
+
1360
+ // Som de recarga
1361
+ if (config.soundEnabled) {
1362
+ reloadSound.currentTime = 0;
1363
+ reloadSound.play();
1364
+ }
1365
+
1366
+ // Tempo de recarga
1367
+ setTimeout(() => {
1368
+ config.ammo = config.maxAmmo;
1369
+ updateAmmoDisplay();
1370
+ }, config.weapons[config.weapon].reloadTime);
1371
+ }
1372
+
1373
+ // Finalizar jogo
1374
+ function endGame(success) {
1375
+ config.gameOver = true;
1376
+ clearInterval(targetSpawnInterval);
1377
+ clearInterval(windChangeInterval);
1378
+ clearInterval(countdownInterval);
1379
+ clearInterval(swayInterval);
1380
+ clearInterval(breathingInterval);
1381
+
1382
+ // Calcular precisão
1383
+ const accuracy = config.shotsFired > 0
1384
+ ? Math.floor((config.targetsHit / config.shotsFired) * 100)
1385
+ : 0;
1386
+
1387
+ // Calcular XP ganho
1388
+ const xpEarned = calculateXPEarned(success);
1389
+ config.xp += xpEarned;
1390
+
1391
+ // Verificar level up
1392
+ checkLevelUp();
1393
+
1394
+ // Atualizar tela de game over
1395
+ finalScore.textContent = config.score;
1396
+ accuracyDisplay.textContent = accuracy;
1397
+ targetsHitDisplay.textContent = config.targetsHit;
1398
+ totalTargetsDisplay.textContent = config.totalTargets;
1399
+ xpEarnedDisplay.textContent = xpEarned;
1400
+
1401
+ if (success) {
1402
+ resultTitle.textContent = "MISSÃO CONCLUÍDA";
1403
+ resultTitle.style.color = "#4ade80";
1404
+ } else {
1405
+ resultTitle.textContent = "MISSÃO FALHOU";
1406
+ resultTitle.style.color = "#f87171";
1407
+ }
1408
+
1409
+ gameOverScreen.style.display = 'flex';
1410
+
1411
+ // Parar música de fundo
1412
+ bgMusic.pause();
1413
+ }
1414
+
1415
+ // Zoom in
1416
+ function zoomIn() {
1417
+ if (config.zoomLevel >= config.maxZoom) return;
1418
+
1419
+ config.zoomLevel += 0.5;
1420
+ updateZoom();
1421
+
1422
+ // Mostrar indicador de queda de bala quando muito zoomado
1423
+ config.showBulletDrop = config.zoomLevel > 1.5;
1424
+ }
1425
+
1426
+ // Zoom out
1427
+ function zoomOut() {
1428
+ if (config.zoomLevel <= 1) return;
1429
+
1430
+ config.zoomLevel -= 0.5;
1431
+ updateZoom();
1432
+
1433
+ // Esconder indicador de queda de bala quando pouco zoomado
1434
+ if (config.zoomLevel <= 1.5) {
1435
+ config.showBulletDrop = false;
1436
+ bulletDropIndicator.style.display = 'none';
1437
+ }
1438
+ }
1439
+
1440
+ // Atualizar zoom
1441
+ function updateZoom() {
1442
+ gameContainer.style.transform = `scale(${config.zoomLevel})`;
1443
+ gameContainer.style.transformOrigin = `${mouseX/window.innerWidth*100}% ${mouseY/window.innerHeight*100}%`;
1444
+ }
1445
+
1446
+ // Alternar som
1447
+ function toggleSound() {
1448
+ config.soundEnabled = !config.soundEnabled;
1449
+
1450
+ if (config.soundEnabled) {
1451
+ soundBtn.innerHTML = '<i class="fas fa-volume-up"></i>';
1452
+ if (config.gameStarted && !config.gameOver) {
1453
+ bgMusic.play();
1454
+ }
1455
+ } else {
1456
+ soundBtn.innerHTML = '<i class="fas fa-volume-mute"></i>';
1457
+ bgMusic.pause();
1458
+ }
1459
+ }
1460
+
1461
+ // Mostrar notificação
1462
+ function showNotification(message, duration = 2000) {
1463
+ notification.textContent = message;
1464
+ notification.style.opacity = '1';
1465
+
1466
+ setTimeout(() => {
1467
+ notification.style.opacity = '0';
1468
+ }, duration);
1469
+ }
1470
+
1471
+ // Event Listeners
1472
+ document.addEventListener('mousemove', (e) => {
1473
+ mouseX = e.clientX;
1474
+ mouseY = e.clientY;
1475
+
1476
+ // Atualizar posição da mira
1477
+ scope.style.left = `${mouseX}px`;
1478
+ scope.style.top = `${mouseY}px`;
1479
+
1480
+ // Atualizar efeito de respiração
1481
+ document.getElementById('breathing-effect').style.left = `${mouseX}px`;
1482
+ document.getElementById('breathing-effect').style.top = `${mouseY}px`;
1483
+
1484
+ // Atualizar zoom origin se estiver zoomado
1485
+ if (config.zoomLevel > 1) {
1486
+ gameContainer.style.transformOrigin = `${mouseX/window.innerWidth*100}% ${mouseY/window.innerHeight*100}%`;
1487
+ }
1488
+ });
1489
+
1490
+ document.addEventListener('click', (e) => {
1491
+ if (!config.gameStarted) return;
1492
+ if (config.gameOver) return;
1493
+
1494
+ fireShot();
1495
+ });
1496
+
1497
+ document.addEventListener('keydown', (e) => {
1498
+ if (e.code === 'Space') {
1499
+ e.preventDefault();
1500
+ if (!config.gameStarted) {
1501
+ initGame();
1502
+ } else if (config.ammo <= 0 && !config.gameOver) {
1503
+ reload();
1504
+ } else if (!config.gameOver) {
1505
+ fireShot();
1506
+ }
1507
+ } else if (e.code === 'KeyR' && config.gameStarted && !config.gameOver) {
1508
+ reload();
1509
+ } else if (e.code === 'KeyZ') {
1510
+ zoomIn();
1511
+ } else if (e.code === 'KeyX') {
1512
+ zoomOut();
1513
+ } else if (e.code === 'KeyM') {
1514
+ toggleSound();
1515
+ } else if (e.code === 'Escape' && config.gameStarted && !config.gameOver) {
1516
+ endGame(false);
1517
+ }
1518
+ });
1519
+
1520
+ zoomInBtn.addEventListener('click', zoomIn);
1521
+ zoomOutBtn.addEventListener('click', zoomOut);
1522
+ restartBtn.addEventListener('click', initGame);
1523
+ soundBtn.addEventListener('click', toggleSound);
1524
+ startBtn.addEventListener('click', initGame);
1525
+ menuBtn.addEventListener('click', () => {
1526
+ gameOverScreen.style.display = 'none';
1527
+ mainMenu.style.display = 'flex';
1528
+ });
1529
+
1530
+ howToPlayBtn.addEventListener('click', () => {
1531
+ alert('CONTROLES DO JOGO:\n\n- CLIQUE ou ESPAÇO: Atirar\n- R: Recarregar\n- Z: Zoom In\n- X: Zoom Out\n- M: Alternar Som\n- ESC: Sair da Missão\n\nOBJETIVO:\nNeutralize os alvos hostis (soldados e VIPs) evitando civis e reféns. Complete cada missão dentro do tempo limite para avançar.\n\nDICAS:\n- Mantenha a calma e controle sua respiração\n- Considere o vento e a distância\n- Headshots dão mais pontos\n- Armas diferentes têm características únicas');
1532
+ });
1533
+
1534
+ // Selecionar dificuldade
1535
+ difficultyBtns.forEach(btn => {
1536
+ btn.addEventListener('click', () => {
1537
+ difficultyBtns.forEach(b => b.classList.remove('active'));
1538
+ btn.classList.add('active');
1539
+ config.difficulty = btn.dataset.difficulty;
1540
+ });
1541
+ });
1542
+
1543
+ // Selecionar arma
1544
+ weaponCards.forEach(card => {
1545
+ card.addEventListener('click', () => {
1546
+ weaponCards.forEach(c => c.classList.remove('active'));
1547
+ card.classList.add('active');
1548
+ config.weapon = card.dataset.weapon;
1549
+ });
1550
+ });
1551
+
1552
+ // Atualizar alvos
1553
+ function updateTargets() {
1554
+ targets.forEach(target => {
1555
+ // Mover alvo
1556
+ target.x += target.speedX;
1557
+ target.y += target.speedY;
1558
+
1559
+ // Verificar bordas
1560
+ if (target.x <= 0 || target.x >= window.innerWidth - 60) {
1561
+ target.speedX *= -1;
1562
+ }
1563
+
1564
+ if (target.y <= 0 || target.y >= window.innerHeight - 60) {
1565
+ target.speedY *= -1;
1566
+ }
1567
+
1568
+ // Atualizar posição
1569
+ target.element.style.left = `${target.x}px`;
1570
+ target.element.style.top = `${target.y}px`;
1571
+ });
1572
+
1573
+ requestAnimationFrame(updateTargets);
1574
+ }
1575
+
1576
+ // Iniciar loop de atualização
1577
+ updateTargets();
1578
+ </script>
1579
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Xacodavt/o" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1580
+ </html>