jamesjun commited on
Commit
920734b
·
verified ·
1 Parent(s): 664fe81

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +5 -3
  2. index.html +1814 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Ctd2
3
- emoji: 🐨
4
  colorFrom: blue
5
  colorTo: blue
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: ctd2
3
+ emoji: 🐳
4
  colorFrom: blue
5
  colorTo: blue
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,1814 @@
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>Tower Defense Ultimate</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
+ #game-container {
11
+ position: relative;
12
+ width: 800px;
13
+ height: 600px;
14
+ background-color: #1f2937;
15
+ background-image: radial-gradient(circle at 2px 2px, rgba(255,255,255,0.05) 2px, transparent 0);
16
+ background-size: 40px 40px;
17
+ overflow: hidden;
18
+ border: 3px solid #4b5563;
19
+ box-shadow: 0 0 30px rgba(0, 0, 0, 0.5);
20
+ }
21
+
22
+ .cell {
23
+ width: 40px;
24
+ height: 40px;
25
+ position: absolute;
26
+ border: 1px solid rgba(255, 255, 255, 0.05);
27
+ transition: background-color 0.2s;
28
+ }
29
+
30
+ .cell:hover {
31
+ background-color: rgba(255, 255, 255, 0.03);
32
+ }
33
+
34
+ .path {
35
+ background-color: #4b5563;
36
+ background-image: linear-gradient(45deg, rgba(255,255,255,0.1) 25%, transparent 25%),
37
+ linear-gradient(-45deg, rgba(255,255,255,0.1) 25%, transparent 25%),
38
+ linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.1) 75%),
39
+ linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.1) 75%);
40
+ background-size: 20px 20px;
41
+ }
42
+
43
+ .tower {
44
+ width: 36px;
45
+ height: 36px;
46
+ border-radius: 50%;
47
+ position: absolute;
48
+ display: flex;
49
+ justify-content: center;
50
+ align-items: center;
51
+ color: white;
52
+ font-weight: bold;
53
+ cursor: pointer;
54
+ z-index: 10;
55
+ border: 2px solid rgba(255,255,255,0.3);
56
+ box-shadow: 0 0 10px rgba(0,0,0,0.5),
57
+ inset 0 0 10px rgba(255,255,255,0.1);
58
+ transition: transform 0.2s, filter 0.2s;
59
+ }
60
+
61
+ .tower:hover {
62
+ transform: scale(1.1);
63
+ filter: brightness(1.2);
64
+ }
65
+
66
+ .tower::after {
67
+ content: '';
68
+ position: absolute;
69
+ width: 80px;
70
+ height: 80px;
71
+ border-radius: 50%;
72
+ opacity: 0.2;
73
+ transform: translate(-50%, -50%);
74
+ top: 50%;
75
+ left: 50%;
76
+ }
77
+
78
+ .tower-1 {
79
+ background-color: #3b82f6;
80
+ background-image: radial-gradient(circle at center, #93c5fd, #3b82f6);
81
+ }
82
+
83
+ .tower-1::after {
84
+ background-color: #3b82f6;
85
+ }
86
+
87
+ .tower-2 {
88
+ background-color: #ef4444;
89
+ background-image: radial-gradient(circle at center, #fca5a5, #ef4444);
90
+ }
91
+
92
+ .tower-2::after {
93
+ background-color: #ef4444;
94
+ }
95
+
96
+ .tower-3 {
97
+ background-color: #10b981;
98
+ background-image: radial-gradient(circle at center, #6ee7b7, #10b981);
99
+ }
100
+
101
+ .tower-3::after {
102
+ background-color: #10b981;
103
+ opacity: 0.4;
104
+ }
105
+
106
+ .tower-4 {
107
+ background-color: #f59e0b;
108
+ background-image: radial-gradient(circle at center, #fcd34d, #f59e0b);
109
+ }
110
+
111
+ .tower-4::after {
112
+ background-color: #f59e0b;
113
+ }
114
+
115
+ .tower-5 {
116
+ background-color: #8b5cf6;
117
+ background-image: radial-gradient(circle at center, #c4b5fd, #8b5cf6);
118
+ }
119
+
120
+ .tower-5::after {
121
+ background-color: #8b5cf6;
122
+ opacity: 0.3;
123
+ }
124
+
125
+ .tower-6 {
126
+ background-color: #ec4899;
127
+ background-image: radial-gradient(circle at center, #f9a8d4, #ec4899);
128
+ }
129
+
130
+ .tower-6::after {
131
+ background-color: #ec4899;
132
+ }
133
+
134
+ .enemy {
135
+ width: 30px;
136
+ height: 30px;
137
+ border-radius: 50%;
138
+ position: absolute;
139
+ display: flex;
140
+ justify-content: center;
141
+ align-items: center;
142
+ color: white;
143
+ font-weight: bold;
144
+ z-index: 5;
145
+ transition: left 0.1s linear, top 0.1s linear;
146
+ border: 2px solid rgba(0,0,0,0.3);
147
+ box-shadow: 0 0 10px rgba(0,0,0,0.3);
148
+ }
149
+
150
+ .enemy-1 {
151
+ background-color: #eab308;
152
+ background-image: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, transparent 50%, rgba(0,0,0,0.1) 100%);
153
+ }
154
+
155
+ .enemy-2 {
156
+ background-color: #f97316;
157
+ background-image: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, transparent 50%, rgba(0,0,0,0.1) 100%);
158
+ }
159
+
160
+ .enemy-3 {
161
+ background-color: #7c3aed;
162
+ background-image: linear-gradient(135deg, rgba(255,255,255,0.4) 0%, transparent 50%, rgba(0,0,0,0.1) 100%);
163
+ }
164
+
165
+ .enemy-4 {
166
+ background-color: #dc2626;
167
+ background-image: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, transparent 50%, rgba(0,0,0,0.1) 100%);
168
+ }
169
+
170
+ .projectile {
171
+ position: absolute;
172
+ z-index: 8;
173
+ transform: translate(-50%, -50%);
174
+ }
175
+
176
+ .projectile-1 {
177
+ width: 8px;
178
+ height: 8px;
179
+ border-radius: 50%;
180
+ background-color: #3b82f6;
181
+ box-shadow: 0 0 5px #3b82f6;
182
+ }
183
+
184
+ .projectile-2 {
185
+ width: 10px;
186
+ height: 10px;
187
+ border-radius: 2px;
188
+ background-color: #ef4444;
189
+ box-shadow: 0 0 5px #ef4444;
190
+ transform: rotate(45deg) translate(-5px, -5px);
191
+ }
192
+
193
+ .projectile-3 {
194
+ width: 15px;
195
+ height: 3px;
196
+ background-color: #10b981;
197
+ box-shadow: 0 0 5px #10b981;
198
+ }
199
+
200
+ .projectile-4 {
201
+ width: 0;
202
+ height: 0;
203
+ border-left: 8px solid transparent;
204
+ border-right: 8px solid transparent;
205
+ border-top: 12px solid #f59e0b;
206
+ box-shadow: 0 0 5px #f59e0b;
207
+ }
208
+
209
+ .projectile-5 {
210
+ width: 5px;
211
+ height: 5px;
212
+ border-radius: 50%;
213
+ background-color: #8b5cf6;
214
+ box-shadow:
215
+ 0 0 5px #8b5cf6,
216
+ 0 0 10px #8b5cf6;
217
+ }
218
+
219
+ .projectile-6 {
220
+ width: 8px;
221
+ height: 8px;
222
+ background-color: #ec4899;
223
+ box-shadow:
224
+ 0 0 5px #ec4899,
225
+ 0 0 10px #ec4899;
226
+ animation: pulse 0.5s infinite alternate;
227
+ }
228
+
229
+ @keyframes pulse {
230
+ 0% { transform: scale(1); opacity: 1; }
231
+ 100% { transform: scale(1.5); opacity: 0.7; }
232
+ }
233
+
234
+ .range-indicator {
235
+ position: absolute;
236
+ border: 2px dashed rgba(255, 255, 255, 0.3);
237
+ border-radius: 50%;
238
+ transform: translate(-50%, -50%);
239
+ pointer-events: none;
240
+ z-index: 1;
241
+ }
242
+
243
+ #tower-menu {
244
+ position: absolute;
245
+ background-color: rgba(31, 41, 55, 0.95);
246
+ border-radius: 8px;
247
+ padding: 12px;
248
+ display: none;
249
+ z-index: 100;
250
+ border: 1px solid #4b5563;
251
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
252
+ width: 200px;
253
+ }
254
+
255
+ .health-bar {
256
+ height: 4px;
257
+ background-color: #48bb78;
258
+ position: absolute;
259
+ top: -6px;
260
+ left: 0;
261
+ width: 100%;
262
+ border-radius: 2px;
263
+ overflow: hidden;
264
+ }
265
+
266
+ .health-bar::after {
267
+ content: '';
268
+ position: absolute;
269
+ top: 0;
270
+ left: 0;
271
+ right: 0;
272
+ bottom: 0;
273
+ background-image: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
274
+ animation: shimmer 2s infinite linear;
275
+ }
276
+
277
+ @keyframes shimmer {
278
+ 0% { transform: translateX(-100%); }
279
+ 100% { transform: translateX(100%); }
280
+ }
281
+
282
+ #game-over {
283
+ position: absolute;
284
+ top: 0;
285
+ left: 0;
286
+ width: 100%;
287
+ height: 100%;
288
+ background-color: rgba(0, 0, 0, 0.85);
289
+ display: none;
290
+ justify-content: center;
291
+ align-items: center;
292
+ flex-direction: column;
293
+ z-index: 200;
294
+ text-align: center;
295
+ }
296
+
297
+ .upgrade-button {
298
+ position: relative;
299
+ overflow: hidden;
300
+ }
301
+
302
+ .upgrade-button::after {
303
+ content: '';
304
+ position: absolute;
305
+ top: 0;
306
+ left: 0;
307
+ right: 0;
308
+ bottom: 0;
309
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
310
+ transform: translateX(-100%);
311
+ transition: transform 0.3s ease;
312
+ }
313
+
314
+ .upgrade-button:hover::after {
315
+ transform: translateX(100%);
316
+ }
317
+
318
+ .special-ability {
319
+ display: inline-block;
320
+ width: 16px;
321
+ height: 16px;
322
+ border-radius: 50%;
323
+ margin-right: 5px;
324
+ }
325
+
326
+ .floating-damage {
327
+ position: absolute;
328
+ color: #ff5555;
329
+ font-weight: bold;
330
+ text-shadow: 1px 1px 2px black;
331
+ animation: floatUp 1s forwards;
332
+ z-index: 15;
333
+ }
334
+
335
+ @keyframes floatUp {
336
+ 0% { transform: translateY(0); opacity: 1; }
337
+ 100% { transform: translateY(-30px); opacity: 0; }
338
+ }
339
+
340
+ .shop-item-icon {
341
+ width: 40px;
342
+ height: 40px;
343
+ border-radius: 50%;
344
+ display: flex;
345
+ justify-content: center;
346
+ align-items: center;
347
+ margin-right: 10px;
348
+ font-size: 18px;
349
+ color: white;
350
+ box-shadow: 0 0 5px rgba(0,0,0,0.3);
351
+ }
352
+
353
+ .wave-progress {
354
+ height: 4px;
355
+ background-color: #3b82f6;
356
+ border-radius: 2px;
357
+ transition: width 0.3s;
358
+ }
359
+
360
+ .wave-indicator {
361
+ position: absolute;
362
+ left: 0;
363
+ top: 0;
364
+ width: 100%;
365
+ height: 100%;
366
+ background-color: rgba(59, 130, 246, 0.2);
367
+ border-radius: 8px;
368
+ }
369
+ </style>
370
+ </head>
371
+ <body class="bg-gray-900 text-white flex flex-col items-center p-6">
372
+ <h1 class="text-4xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500">Tower Defense Ultimate</h1>
373
+
374
+ <div class="flex justify-between w-full max-w-5xl mb-4">
375
+ <div class="flex space-x-4">
376
+ <div class="bg-gray-800 p-3 rounded-lg border border-gray-700 shadow-md">
377
+ <span class="font-bold text-blue-400">Wave:</span> <span id="wave">1</span>
378
+ </div>
379
+ <div class="bg-gray-800 p-3 rounded-lg border border-gray-700 shadow-md">
380
+ <span class="font-bold text-red-400">Lives:</span> <span id="lives">20</span>
381
+ </div>
382
+ <div class="bg-gray-800 p-3 rounded-lg border border-gray-700 shadow-md">
383
+ <span class="font-bold text-green-400">Money:</span> $<span id="money">150</span>
384
+ </div>
385
+ </div>
386
+ <div class="flex space-x-3">
387
+ <div class="relative bg-gray-800 rounded-lg p-2 w-40 border border-gray-700 shadow-md">
388
+ <div class="text-xs mb-1">Wave Progress</div>
389
+ <div class="h-2 bg-gray-700 rounded-full overflow-hidden">
390
+ <div id="wave-progress" class="wave-progress"></div>
391
+ </div>
392
+ <div id="wave-indicator" class="wave-indicator" style="display: none;"></div>
393
+ </div>
394
+ <button id="start-wave" class="bg-green-600 hover:bg-green-700 px-4 py-2 rounded-lg font-bold transition-all duration-300 hover:shadow-lg hover:shadow-green-500/20 flex items-center">
395
+ <i class="fas fa-play mr-2"></i> Start Wave
396
+ </button>
397
+ <button id="restart-wave" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg font-bold transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/20 flex items-center">
398
+ <i class="fas fa-redo mr-2"></i> Restart
399
+ </button>
400
+ </div>
401
+ </div>
402
+
403
+ <div id="game-container" class="rounded-lg shadow-2xl">
404
+ <!-- Game elements will be added here dynamically -->
405
+ </div>
406
+
407
+ <div class="mt-6 w-full max-w-5xl">
408
+ <h2 class="text-2xl font-bold mb-4 text-center bg-clip-text text-transparent bg-gradient-to-r from-blue-300 to-purple-400">Tower Shop</h2>
409
+ <div class="grid grid-cols-3 gap-4">
410
+ <!-- Tower 1: Basic Tower -->
411
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="1">
412
+ <div class="flex items-center mb-3">
413
+ <div class="shop-item-icon bg-gradient-to-br from-blue-400 to-blue-600">
414
+ <i class="fas fa-arrow-circle-up"></i>
415
+ </div>
416
+ <h3 class="font-bold text-lg">Basic Tower</h3>
417
+ </div>
418
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $50</p>
419
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 10</p>
420
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 120px</p>
421
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-blue-300">Medium</span></p>
422
+ <div class="mt-2 text-xs text-blue-400 flex items-center">
423
+ <span class="special-ability bg-blue-400"></span> Simple but effective
424
+ </div>
425
+ </div>
426
+
427
+ <!-- Tower 2: Cannon Tower -->
428
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="2">
429
+ <div class="flex items-center mb-3">
430
+ <div class="shop-item-icon bg-gradient-to-br from-red-500 to-red-700">
431
+ <i class="fas fa-bomb"></i>
432
+ </div>
433
+ <h3 class="font-bold text-lg">Cannon Tower</h3>
434
+ </div>
435
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $100</p>
436
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 25 (AOE)</p>
437
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 100px</p>
438
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-yellow-300">Slow</span></p>
439
+ <div class="mt-2 text-xs text-red-400 flex items-center">
440
+ <span class="special-ability bg-red-400"></span> Area of effect damage
441
+ </div>
442
+ </div>
443
+
444
+ <!-- Tower 3: Sniper Tower -->
445
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="3">
446
+ <div class="flex items-center mb-3">
447
+ <div class="shop-item-icon bg-gradient-to-br from-green-500 to-green-700">
448
+ <i class="fas fa-crosshairs"></i>
449
+ </div>
450
+ <h3 class="font-bold text-lg">Sniper Tower</h3>
451
+ </div>
452
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $150</p>
453
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 50</p>
454
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 200px</p>
455
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-purple-300">Very Slow</span></p>
456
+ <div class="mt-2 text-xs text-green-400 flex items-center">
457
+ <span class="special-ability bg-green-400"></span> High single-target damage
458
+ </div>
459
+ </div>
460
+
461
+ <!-- Tower 4: Fire Tower -->
462
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="4">
463
+ <div class="flex items-center mb-3">
464
+ <div class="shop-item-icon bg-gradient-to-br from-yellow-500 to-orange-600">
465
+ <i class="fas fa-fire"></i>
466
+ </div>
467
+ <h3 class="font-bold text-lg">Fire Tower</h3>
468
+ </div>
469
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $120</p>
470
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 5/sec</p>
471
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 90px</p>
472
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-orange-300">Fast</span></p>
473
+ <div class="mt-2 text-xs text-yellow-400 flex items-center">
474
+ <span class="special-ability bg-yellow-400"></span> Continuous damage over time
475
+ </div>
476
+ </div>
477
+
478
+ <!-- Tower 5: Shock Tower -->
479
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="5">
480
+ <div class="flex items-center mb-3">
481
+ <div class="shop-item-icon bg-gradient-to-br from-purple-500 to-indigo-700">
482
+ <i class="fas fa-bolt"></i>
483
+ </div>
484
+ <h3 class="font-bold text-lg">Shock Tower</h3>
485
+ </div>
486
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $175</p>
487
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 15 (Chain)</p>
488
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 110px</p>
489
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-blue-300">Medium</span></p>
490
+ <div class="mt-2 text-xs text-purple-400 flex items-center">
491
+ <span class="special-ability bg-purple-400"></span> Chains to nearby enemies
492
+ </div>
493
+ </div>
494
+
495
+ <!-- Tower 6: Magic Tower -->
496
+ <div class="bg-gray-800 p-4 rounded-lg cursor-pointer hover:bg-gray-700 hover:shadow-lg transition-all duration-200 tower-shop-item border border-gray-700" data-type="6">
497
+ <div class="flex items-center mb-3">
498
+ <div class="shop-item-icon bg-gradient-to-br from-pink-500 to-rose-600">
499
+ <i class="fas fa-magic"></i>
500
+ </div>
501
+ <h3 class="font-bold text-lg">Magic Tower</h3>
502
+ </div>
503
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Cost:</span> $200</p>
504
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Damage:</span> 30 (Random)</p>
505
+ <p class="text-sm text-gray-300 mb-1"><span class="font-medium">Range:</span> 150px</p>
506
+ <p class="text-sm text-gray-300"><span class="font-medium">Speed:</span> <span class="text-pink-300">Slow</span></p>
507
+ <div class="mt-2 text-xs text-pink-400 flex items-center">
508
+ <span class="special-ability bg-pink-400"></span> Random max damage bursts
509
+ </div>
510
+ </div>
511
+ </div>
512
+ </div>
513
+
514
+ <div id="tower-menu" class="text-sm">
515
+ <div class="flex justify-between items-center mb-3 border-b border-gray-700 pb-2">
516
+ <div>
517
+ <h3 class="font-bold text-lg" id="tower-menu-title">Tower</h3>
518
+ <div class="text-xs text-gray-400">Level <span id="tower-level">1</span></div>
519
+ </div>
520
+ <button id="sell-tower" class="bg-red-600 hover:bg-red-700 px-3 py-1 rounded text-sm flex items-center">
521
+ <i class="fas fa-coins mr-1"></i> Sell ($<span id="sell-value">25</span>)
522
+ </button>
523
+ </div>
524
+
525
+ <div class="grid grid-cols-2 gap-3 mb-3">
526
+ <div>
527
+ <div class="text-xs text-gray-400">Damage</div>
528
+ <div class="font-medium" id="tower-damage">10</div>
529
+ </div>
530
+ <div>
531
+ <div class="text-xs text-gray-400">Range</div>
532
+ <div class="font-medium"><span id="tower-range">120</span>px</div>
533
+ </div>
534
+ <div>
535
+ <div class="text-xs text-gray-400">Speed</div>
536
+ <div class="font-medium" id="tower-speed">Medium</div>
537
+ </div>
538
+ <div>
539
+ <div class="text-xs text-gray-400">Value</div>
540
+ <div class="font-medium">$<span id="tower-value">50</span></div>
541
+ </div>
542
+ </div>
543
+
544
+ <div class="mb-3">
545
+ <div class="text-xs text-gray-400 mb-1">Special Ability</div>
546
+ <div class="text-xs" id="tower-ability">Basic tower with no special abilities</div>
547
+ </div>
548
+
549
+ <button id="upgrade-tower" class="w-full py-2 rounded-lg bg-gradient-to-r from-blue-500 to-blue-700 hover:from-blue-600 hover:to-blue-800 font-bold flex items-center justify-center upgrade-button">
550
+ <i class="fas fa-arrow-up mr-2"></i> Upgrade ($<span id="upgrade-cost">50</span>)
551
+ </button>
552
+ </div>
553
+
554
+ <div id="game-over" class="text-center">
555
+ <div class="bg-gray-800 p-8 rounded-lg border border-gray-700 max-w-md">
556
+ <h2 class="text-4xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-red-400 to-pink-500">Game Over</h2>
557
+ <p class="text-xl mb-6">You survived <span id="final-wave" class="text-yellow-400">0</span> waves!</p>
558
+ <div class="mb-6">
559
+ <div class="text-sm text-gray-400">Total enemies defeated</div>
560
+ <div id="final-kills" class="text-2xl font-bold text-green-400">0</div>
561
+ </div>
562
+ <button id="restart-game" class="bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 px-8 py-3 rounded-lg font-bold text-lg shadow-lg transition-all duration-300 hover:shadow-green-500/30">
563
+ <i class="fas fa-redo mr-2"></i> Play Again
564
+ </button>
565
+ </div>
566
+ </div>
567
+
568
+ <script>
569
+ // Game state
570
+ const gameState = {
571
+ gridWidth: 20,
572
+ gridHeight: 15,
573
+ cellSize: 40,
574
+ money: 150,
575
+ lives: 20,
576
+ wave: 1,
577
+ gameActive: false,
578
+ placingTower: false,
579
+ towerType: null,
580
+ selectedTower: null,
581
+ enemies: [],
582
+ towers: [],
583
+ projectiles: [],
584
+ damageTexts: [],
585
+ path: [
586
+ {x: 0, y: 7},
587
+ {x: 5, y: 7},
588
+ {x: 5, y: 3},
589
+ {x: 10, y: 3},
590
+ {x: 10, y: 10},
591
+ {x: 15, y: 10},
592
+ {x: 15, y: 5},
593
+ {x: 20, y: 5}
594
+ ],
595
+ enemySpawnInterval: null,
596
+ gameLoopInterval: null,
597
+ currentWaveEnemies: 0,
598
+ totalWaveEnemies: 0,
599
+ enemiesDefeated: 0
600
+ };
601
+
602
+ // Tower types
603
+ const towerTypes = {
604
+ 1: {
605
+ name: "Basic Tower",
606
+ cost: 50,
607
+ damage: 10,
608
+ range: 120,
609
+ color: "blue",
610
+ upgradeCost: 50,
611
+ projectileSpeed: 8,
612
+ attackSpeed: 30,
613
+ description: "Simple but effective",
614
+ ability: "Basic tower with no special abilities",
615
+ speed: "Medium"
616
+ },
617
+ 2: {
618
+ name: "Cannon Tower",
619
+ cost: 100,
620
+ damage: 25,
621
+ range: 100,
622
+ color: "red",
623
+ upgradeCost: 75,
624
+ projectileSpeed: 6,
625
+ attackSpeed: 45,
626
+ description: "Area of effect damage",
627
+ ability: "Deals splash damage to enemies near the target",
628
+ speed: "Slow",
629
+ aoeRadius: 40
630
+ },
631
+ 3: {
632
+ name: "Sniper Tower",
633
+ cost: 150,
634
+ damage: 50,
635
+ range: 200,
636
+ color: "green",
637
+ upgradeCost: 100,
638
+ projectileSpeed: 12,
639
+ attackSpeed: 60,
640
+ description: "High single-target damage",
641
+ ability: "Long range with high damage but slow rate of fire",
642
+ speed: "Very Slow"
643
+ },
644
+ 4: {
645
+ name: "Fire Tower",
646
+ cost: 120,
647
+ damage: 5,
648
+ range: 90,
649
+ color: "orange",
650
+ upgradeCost: 60,
651
+ projectileSpeed: 10,
652
+ attackSpeed: 5,
653
+ description: "Continuous damage over time",
654
+ ability: "Burns enemies for damage over time on each hit",
655
+ speed: "Fast",
656
+ dotDuration: 60
657
+ },
658
+ 5: {
659
+ name: "Shock Tower",
660
+ cost: 175,
661
+ damage: 15,
662
+ range: 110,
663
+ color: "purple",
664
+ upgradeCost: 85,
665
+ projectileSpeed: 15,
666
+ attackSpeed: 30,
667
+ description: "Chains to nearby enemies",
668
+ ability: "Lightning jumps to 2 additional nearby enemies",
669
+ speed: "Medium",
670
+ chainTargets: 2,
671
+ chainRange: 70
672
+ },
673
+ 6: {
674
+ name: "Magic Tower",
675
+ cost: 200,
676
+ damage: 30,
677
+ range: 150,
678
+ color: "pink",
679
+ upgradeCost: 100,
680
+ projectileSpeed: 10,
681
+ attackSpeed: 40,
682
+ description: "Random max damage bursts",
683
+ ability: "Occasionally deals double damage (25% chance)",
684
+ speed: "Slow",
685
+ critChance: 0.25
686
+ }
687
+ };
688
+
689
+ // Enemy types
690
+ const enemyTypes = [
691
+ {
692
+ name: "Scout",
693
+ health: 50,
694
+ speed: 1.5,
695
+ reward: 15,
696
+ color: "yellow",
697
+ spawnRate: 1.0
698
+ },
699
+ {
700
+ name: "Warrior",
701
+ health: 100,
702
+ speed: 1.0,
703
+ reward: 25,
704
+ color: "orange",
705
+ spawnRate: 0.6
706
+ },
707
+ {
708
+ name: "Elite",
709
+ health: 200,
710
+ speed: 0.7,
711
+ reward: 40,
712
+ color: "purple",
713
+ spawnRate: 0.3
714
+ },
715
+ {
716
+ name: "Boss",
717
+ health: 500,
718
+ speed: 0.4,
719
+ reward: 100,
720
+ color: "red",
721
+ spawnRate: 0.1
722
+ }
723
+ ];
724
+
725
+ // DOM elements
726
+ const gameContainer = document.getElementById('game-container');
727
+ const waveDisplay = document.getElementById('wave');
728
+ const livesDisplay = document.getElementById('lives');
729
+ const moneyDisplay = document.getElementById('money');
730
+ const startWaveBtn = document.getElementById('start-wave');
731
+ const restartWaveBtn = document.getElementById('restart-wave');
732
+ const towerShopItems = document.querySelectorAll('.tower-shop-item');
733
+ const towerMenu = document.getElementById('tower-menu');
734
+ const towerMenuTitle = document.getElementById('tower-menu-title');
735
+ const towerLevel = document.getElementById('tower-level');
736
+ const towerDamage = document.getElementById('tower-damage');
737
+ const towerRange = document.getElementById('tower-range');
738
+ const towerValue = document.getElementById('tower-value');
739
+ const sellValue = document.getElementById('sell-value');
740
+ const towerSpeed = document.getElementById('tower-speed');
741
+ const towerAbility = document.getElementById('tower-ability');
742
+ const upgradeCost = document.getElementById('upgrade-cost');
743
+ const upgradeBtn = document.getElementById('upgrade-tower');
744
+ const sellBtn = document.getElementById('sell-tower');
745
+ const gameOverScreen = document.getElementById('game-over');
746
+ const finalWaveDisplay = document.getElementById('final-wave');
747
+ const finalKillsDisplay = document.getElementById('final-kills');
748
+ const restartBtn = document.getElementById('restart-game');
749
+ const waveProgress = document.getElementById('wave-progress');
750
+ const waveIndicator = document.getElementById('wave-indicator');
751
+
752
+ // Initialize game
753
+ function initGame() {
754
+ // Clear previous game state
755
+ gameContainer.innerHTML = '';
756
+ gameState.enemies = [];
757
+ gameState.towers = [];
758
+ gameState.projectiles = [];
759
+ gameState.damageTexts = [];
760
+
761
+ // Reset game state
762
+ gameState.money = 150;
763
+ gameState.lives = 20;
764
+ gameState.wave = 1;
765
+ gameState.gameActive = false;
766
+ gameState.placingTower = false;
767
+ gameState.towerType = null;
768
+ gameState.selectedTower = null;
769
+ gameState.currentWaveEnemies = 0;
770
+ gameState.totalWaveEnemies = 0;
771
+ gameState.enemiesDefeated = 0;
772
+
773
+ // Update UI
774
+ updateUI();
775
+
776
+ // Create grid
777
+ createGrid();
778
+
779
+ // Create path
780
+ createPath();
781
+
782
+ // Hide game over screen
783
+ gameOverScreen.style.display = 'none';
784
+
785
+ // Enable buttons
786
+ startWaveBtn.disabled = false;
787
+ restartWaveBtn.disabled = false;
788
+
789
+ // Reset wave progress
790
+ waveProgress.style.width = '0%';
791
+ waveIndicator.style.display = 'none';
792
+
793
+ // Start game loop
794
+ if (gameState.gameLoopInterval) {
795
+ clearInterval(gameState.gameLoopInterval);
796
+ }
797
+ gameState.gameLoopInterval = setInterval(gameLoop, 16); // ~60fps
798
+ }
799
+
800
+ // Create grid
801
+ function createGrid() {
802
+ for (let y = 0; y < gameState.gridHeight; y++) {
803
+ for (let x = 0; x < gameState.gridWidth; x++) {
804
+ const cell = document.createElement('div');
805
+ cell.className = 'cell';
806
+ cell.style.left = `${x * gameState.cellSize}px`;
807
+ cell.style.top = `${y * gameState.cellSize}px`;
808
+ cell.dataset.x = x;
809
+ cell.dataset.y = y;
810
+
811
+ // Add click event for tower placement
812
+ cell.addEventListener('click', () => {
813
+ if (gameState.placingTower) {
814
+ placeTower(x, y);
815
+ }
816
+ });
817
+
818
+ gameContainer.appendChild(cell);
819
+ }
820
+ }
821
+ }
822
+
823
+ // Create path
824
+ function createPath() {
825
+ // Draw path cells
826
+ for (let i = 0; i < gameState.path.length - 1; i++) {
827
+ const start = gameState.path[i];
828
+ const end = gameState.path[i + 1];
829
+
830
+ // Horizontal path
831
+ if (start.y === end.y) {
832
+ const direction = start.x < end.x ? 1 : -1;
833
+ for (let x = start.x; x !== end.x; x += direction) {
834
+ if (x >= 0 && x < gameState.gridWidth && start.y >= 0 && start.y < gameState.gridHeight) {
835
+ const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${start.y}"]`);
836
+ if (cell) cell.classList.add('path');
837
+ }
838
+ }
839
+ }
840
+ // Vertical path
841
+ else if (start.x === end.x) {
842
+ const direction = start.y < end.y ? 1 : -1;
843
+ for (let y = start.y; y !== end.y; y += direction) {
844
+ if (start.x >= 0 && start.x < gameState.gridWidth && y >= 0 && y < gameState.gridHeight) {
845
+ const cell = document.querySelector(`.cell[data-x="${start.x}"][data-y="${y}"]`);
846
+ if (cell) cell.classList.add('path');
847
+ }
848
+ }
849
+ }
850
+ }
851
+
852
+ // Add the last cell
853
+ const last = gameState.path[gameState.path.length - 1];
854
+ if (last.x >= 0 && last.x < gameState.gridWidth && last.y >= 0 && last.y < gameState.gridHeight) {
855
+ const cell = document.querySelector(`.cell[data-x="${last.x}"][data-y="${last.y}"]`);
856
+ if (cell) cell.classList.add('path');
857
+ }
858
+ }
859
+
860
+ // Place tower
861
+ function placeTower(x, y) {
862
+ // Check if cell is empty and not on path
863
+ const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
864
+ if (!cell || cell.classList.contains('path') || cell.classList.contains('has-tower')) {
865
+ return;
866
+ }
867
+
868
+ // Check if player has enough money
869
+ const towerCost = towerTypes[gameState.towerType].cost;
870
+ if (gameState.money < towerCost) {
871
+ showMessage("Not enough money!");
872
+ return;
873
+ }
874
+
875
+ // Deduct money
876
+ gameState.money -= towerCost;
877
+ updateUI();
878
+
879
+ // Create tower
880
+ const tower = {
881
+ type: gameState.towerType,
882
+ x: x,
883
+ y: y,
884
+ level: 1,
885
+ damage: towerTypes[gameState.towerType].damage,
886
+ range: towerTypes[gameState.towerType].range,
887
+ cooldown: 0,
888
+ maxCooldown: towerTypes[gameState.towerType].attackSpeed,
889
+ value: towerCost
890
+ };
891
+
892
+ gameState.towers.push(tower);
893
+
894
+ // Create tower element
895
+ const towerElement = document.createElement('div');
896
+ towerElement.className = `tower tower-${tower.type}`;
897
+ towerElement.style.left = `${x * gameState.cellSize + 2}px`;
898
+ towerElement.style.top = `${y * gameState.cellSize + 2}px`;
899
+ towerElement.textContent = tower.level;
900
+ towerElement.dataset.index = gameState.towers.length - 1;
901
+
902
+ // Add click event for tower selection
903
+ towerElement.addEventListener('click', (e) => {
904
+ e.stopPropagation();
905
+ selectTower(gameState.towers.length - 1);
906
+ });
907
+
908
+ gameContainer.appendChild(towerElement);
909
+
910
+ // Mark cell as occupied
911
+ cell.classList.add('has-tower');
912
+
913
+ // Exit tower placement mode
914
+ gameState.placingTower = false;
915
+ gameState.towerType = null;
916
+
917
+ // Remove range indicator if it exists
918
+ const rangeIndicator = document.querySelector('.range-indicator');
919
+ if (rangeIndicator) rangeIndicator.remove();
920
+
921
+ // Show effect when placing tower
922
+ showPlacementEffect(x, y, towerTypes[tower.type].color);
923
+ }
924
+
925
+ // Show placement effect
926
+ function showPlacementEffect(x, y, color) {
927
+ const effect = document.createElement('div');
928
+ effect.style.position = 'absolute';
929
+ effect.style.left = `${x * gameState.cellSize}px`;
930
+ effect.style.top = `${y * gameState.cellSize}px`;
931
+ effect.style.width = `${gameState.cellSize}px`;
932
+ effect.style.height = `${gameState.cellSize}px`;
933
+ effect.style.borderRadius = '50%';
934
+ effect.style.backgroundColor = 'transparent';
935
+ effect.style.boxShadow = `0 0 10px 5px ${color}`;
936
+ effect.style.opacity = '0';
937
+ effect.style.transition = 'all 0.5s ease-out';
938
+ effect.style.pointerEvents = 'none';
939
+ effect.style.zIndex = '20';
940
+
941
+ gameContainer.appendChild(effect);
942
+
943
+ // Trigger animation
944
+ setTimeout(() => {
945
+ effect.style.opacity = '1';
946
+ effect.style.transform = 'scale(1.5)';
947
+ }, 10);
948
+
949
+ // Remove after animation
950
+ setTimeout(() => {
951
+ effect.style.opacity = '0';
952
+ setTimeout(() => effect.remove(), 500);
953
+ }, 500);
954
+ }
955
+
956
+ // Select tower
957
+ function selectTower(index) {
958
+ // Close menu if clicking the same tower
959
+ if (gameState.selectedTower === index && towerMenu.style.display === 'block') {
960
+ towerMenu.style.display = 'none';
961
+ gameState.selectedTower = null;
962
+
963
+ // Remove range indicator
964
+ const rangeIndicator = document.querySelector('.range-indicator');
965
+ if (rangeIndicator) rangeIndicator.remove();
966
+ return;
967
+ }
968
+
969
+ gameState.selectedTower = index;
970
+ const tower = gameState.towers[index];
971
+ const towerType = towerTypes[tower.type];
972
+
973
+ // Update tower menu
974
+ towerMenuTitle.textContent = towerType.name;
975
+ towerLevel.textContent = tower.level;
976
+ towerDamage.textContent = tower.damage;
977
+ towerRange.textContent = tower.range;
978
+ towerValue.textContent = Math.floor(tower.value * 0.7);
979
+ sellValue.textContent = Math.floor(tower.value * 0.7);
980
+ towerSpeed.textContent = towerType.speed;
981
+ towerAbility.textContent = towerType.ability;
982
+ upgradeCost.textContent = towerType.upgradeCost * tower.level;
983
+
984
+ // Position menu near tower
985
+ const menuX = tower.x * gameState.cellSize + gameState.cellSize / 2;
986
+ const menuY = tower.y * gameState.cellSize + gameState.cellSize / 2;
987
+
988
+ // Adjust if near right edge
989
+ if (menuX + 250 > gameContainer.offsetWidth) {
990
+ towerMenu.style.left = `${tower.x * gameState.cellSize - 200}px`;
991
+ } else {
992
+ towerMenu.style.left = `${menuX}px`;
993
+ }
994
+
995
+ // Adjust if near bottom edge
996
+ if (menuY + 150 > gameContainer.offsetHeight) {
997
+ towerMenu.style.top = `${tower.y * gameState.cellSize - 130}px`;
998
+ } else {
999
+ towerMenu.style.top = `${menuY}px`;
1000
+ }
1001
+
1002
+ towerMenu.style.display = 'block';
1003
+
1004
+ // Show range indicator
1005
+ const rangeIndicator = document.createElement('div');
1006
+ rangeIndicator.className = 'range-indicator';
1007
+ rangeIndicator.style.width = `${tower.range * 2}px`;
1008
+ rangeIndicator.style.height = `${tower.range * 2}px`;
1009
+ rangeIndicator.style.left = `${tower.x * gameState.cellSize + gameState.cellSize / 2}px`;
1010
+ rangeIndicator.style.top = `${tower.y * gameState.cellSize + gameState.cellSize / 2}px`;
1011
+ gameContainer.appendChild(rangeIndicator);
1012
+ }
1013
+
1014
+ // Upgrade tower
1015
+ function upgradeTower() {
1016
+ if (gameState.selectedTower === null) return;
1017
+
1018
+ const tower = gameState.towers[gameState.selectedTower];
1019
+ const cost = towerTypes[tower.type].upgradeCost * tower.level;
1020
+
1021
+ if (gameState.money >= cost) {
1022
+ gameState.money -= cost;
1023
+ tower.level += 1;
1024
+ tower.damage = Math.floor(towerTypes[tower.type].damage * (1 + (tower.level - 1) * 0.5));
1025
+ tower.range = Math.floor(towerTypes[tower.type].range * (1 + (tower.level - 1) * 0.2));
1026
+ tower.maxCooldown = Math.max(5, towerTypes[tower.type].attackSpeed * (1 - (tower.level - 1) * 0.1));
1027
+ tower.value += cost;
1028
+
1029
+ // Update tower display
1030
+ const towerElement = document.querySelector(`.tower[data-index="${gameState.selectedTower}"]`);
1031
+ towerElement.textContent = tower.level;
1032
+
1033
+ // Upgrade visual effect
1034
+ towerElement.style.boxShadow = `0 0 15px ${towerTypes[tower.type].color}, inset 0 0 10px rgba(255,255,255,0.3)`;
1035
+ setTimeout(() => {
1036
+ towerElement.style.boxShadow = `0 0 10px rgba(0,0,0,0.5), inset 0 0 10px rgba(255,255,255,0.1)`;
1037
+ }, 500);
1038
+
1039
+ // Update menu
1040
+ towerLevel.textContent = tower.level;
1041
+ towerDamage.textContent = tower.damage;
1042
+ towerRange.textContent = tower.range;
1043
+ towerValue.textContent = Math.floor(tower.value * 0.7);
1044
+ sellValue.textContent = Math.floor(tower.value * 0.7);
1045
+ upgradeCost.textContent = towerTypes[tower.type].upgradeCost * tower.level;
1046
+
1047
+ // Update range indicator
1048
+ const rangeIndicator = document.querySelector('.range-indicator');
1049
+ if (rangeIndicator) {
1050
+ rangeIndicator.style.width = `${tower.range * 2}px`;
1051
+ rangeIndicator.style.height = `${tower.range * 2}px`;
1052
+ }
1053
+
1054
+ updateUI();
1055
+
1056
+ // Play upgrade sound
1057
+ playSound('upgrade');
1058
+ } else {
1059
+ showMessage("Not enough money for upgrade!");
1060
+ }
1061
+ }
1062
+
1063
+ // Sell tower
1064
+ function sellTower() {
1065
+ if (gameState.selectedTower === null) return;
1066
+
1067
+ const tower = gameState.towers[gameState.selectedTower];
1068
+ const refund = Math.floor(tower.value * 0.7);
1069
+
1070
+ gameState.money += refund;
1071
+
1072
+ // Remove tower element
1073
+ const towerElement = document.querySelector(`.tower[data-index="${gameState.selectedTower}"]`);
1074
+ towerElement.remove();
1075
+
1076
+ // Remove range indicator
1077
+ const rangeIndicator = document.querySelector('.range-indicator');
1078
+ if (rangeIndicator) rangeIndicator.remove();
1079
+
1080
+ // Mark cell as empty
1081
+ const cell = document.querySelector(`.cell[data-x="${tower.x}"][data-y="${tower.y}"]`);
1082
+ cell.classList.remove('has-tower');
1083
+
1084
+ // Remove tower from array
1085
+ gameState.towers.splice(gameState.selectedTower, 1);
1086
+
1087
+ // Update all tower elements' data-index attributes
1088
+ document.querySelectorAll('.tower').forEach((el, index) => {
1089
+ el.dataset.index = index;
1090
+ });
1091
+
1092
+ // Close menu
1093
+ towerMenu.style.display = 'none';
1094
+ gameState.selectedTower = null;
1095
+
1096
+ // Show sell effect
1097
+ showSellEffect(tower.x, tower.y);
1098
+
1099
+ updateUI();
1100
+
1101
+ // Play sell sound
1102
+ playSound('sell');
1103
+ }
1104
+
1105
+ // Show sell effect
1106
+ function showSellEffect(x, y) {
1107
+ const effect = document.createElement('div');
1108
+ effect.style.position = 'absolute';
1109
+ effect.style.left = `${x * gameState.cellSize + gameState.cellSize/2}px`;
1110
+ effect.style.top = `${y * gameState.cellSize + gameState.cellSize/2}px`;
1111
+ effect.style.width = '0';
1112
+ effect.style.height = '0';
1113
+ effect.style.borderRadius = '50%';
1114
+ effect.style.backgroundColor = 'rgba(255, 215, 0, 0.3)';
1115
+ effect.style.boxShadow = '0 0 20px 10px rgba(255, 215, 0, 0.5)';
1116
+ effect.style.transform = 'translate(-50%, -50%)';
1117
+ effect.style.transition = 'all 0.5s ease-out';
1118
+ effect.style.pointerEvents = 'none';
1119
+ effect.style.zIndex = '20';
1120
+
1121
+ gameContainer.appendChild(effect);
1122
+
1123
+ // Trigger animation
1124
+ setTimeout(() => {
1125
+ effect.style.width = '100px';
1126
+ effect.style.height = '100px';
1127
+ effect.style.opacity = '0';
1128
+ }, 10);
1129
+
1130
+ // Remove after animation
1131
+ setTimeout(() => effect.remove(), 510);
1132
+
1133
+ // Show money effect
1134
+ const moneyEffect = document.createElement('div');
1135
+ moneyEffect.textContent = `+$${Math.floor(towerTypes[gameState.towers[gameState.selectedTower]?.type].cost * 0.7)}`;
1136
+ moneyEffect.style.position = 'absolute';
1137
+ moneyEffect.style.left = `${x * gameState.cellSize + gameState.cellSize/2}px`;
1138
+ moneyEffect.style.top = `${y * gameState.cellSize}px`;
1139
+ moneyEffect.style.color = 'gold';
1140
+ moneyEffect.style.fontWeight = 'bold';
1141
+ moneyEffect.style.fontSize = '16px';
1142
+ moneyEffect.style.transform = 'translateX(-50%)';
1143
+ moneyEffect.style.opacity = '1';
1144
+ moneyEffect.style.transition = 'all 0.8s ease-out';
1145
+ moneyEffect.style.pointerEvents = 'none';
1146
+ moneyEffect.style.textShadow = '0 0 5px rgba(0,0,0,0.8)';
1147
+ moneyEffect.style.zIndex = '25';
1148
+
1149
+ gameContainer.appendChild(moneyEffect);
1150
+
1151
+ // Animate money text
1152
+ setTimeout(() => {
1153
+ moneyEffect.style.top = `${y * gameState.cellSize - 30}px`;
1154
+ moneyEffect.style.opacity = '0';
1155
+ }, 10);
1156
+
1157
+ setTimeout(() => moneyEffect.remove(), 810);
1158
+ }
1159
+
1160
+ // Start wave
1161
+ function startWave() {
1162
+ if (gameState.gameActive) return;
1163
+
1164
+ gameState.gameActive = true;
1165
+ startWaveBtn.disabled = true;
1166
+ restartWaveBtn.disabled = true;
1167
+ gameState.currentWaveEnemies = 0;
1168
+
1169
+ // Calculate total enemies for this wave
1170
+ gameState.totalWaveEnemies = Math.floor(5 + gameState.wave * 2);
1171
+
1172
+ // Show wave indicator
1173
+ waveIndicator.style.display = 'block';
1174
+
1175
+ // Spawn enemies with different types based on wave
1176
+ gameState.enemySpawnInterval = setInterval(() => {
1177
+ if (gameState.currentWaveEnemies >= gameState.totalWaveEnemies) {
1178
+ clearInterval(gameState.enemySpawnInterval);
1179
+ gameState.enemySpawnInterval = null;
1180
+ waveIndicator.style.display = 'none';
1181
+ return;
1182
+ }
1183
+
1184
+ // Update wave progress
1185
+ const progress = (gameState.currentWaveEnemies / gameState.totalWaveEnemies) * 100;
1186
+ waveProgress.style.width = `${progress}%`;
1187
+
1188
+ // Determine enemy type based on wave and random chance
1189
+ let enemyType = 0;
1190
+ const r = Math.random();
1191
+
1192
+ // Boss chance increases with waves
1193
+ const bossChance = Math.min(0.05 + gameState.wave * 0.005, 0.3);
1194
+
1195
+ if (gameState.wave >= 10 && r < bossChance) {
1196
+ enemyType = 3; // Boss
1197
+ } else if (gameState.wave >= 5 && r < 0.5) {
1198
+ enemyType = 2; // Elite
1199
+ } else if (gameState.wave >= 3 && r < 0.7) {
1200
+ enemyType = 1; // Warrior
1201
+ } else {
1202
+ enemyType = 0; // Scout
1203
+ }
1204
+
1205
+ spawnEnemy(enemyType);
1206
+ gameState.currentWaveEnemies++;
1207
+ }, 800 - Math.min(gameState.wave * 20, 600)); // Spawn faster as waves increase (min 200ms)
1208
+ }
1209
+
1210
+ // Restart current wave
1211
+ function restartWave() {
1212
+ // Clear existing enemies and projectiles
1213
+ gameState.enemies.forEach((enemy, index) => {
1214
+ const enemyElement = document.querySelectorAll('.enemy')[index];
1215
+ if (enemyElement) enemyElement.remove();
1216
+ });
1217
+ gameState.enemies = [];
1218
+
1219
+ gameState.projectiles.forEach((projectile, index) => {
1220
+ const projectileElement = document.querySelectorAll('.projectile')[index];
1221
+ if (projectileElement) projectileElement.remove();
1222
+ });
1223
+ gameState.projectiles = [];
1224
+
1225
+ // Clear damage texts
1226
+ document.querySelectorAll('.floating-damage').forEach(el => el.remove());
1227
+ gameState.damageTexts = [];
1228
+
1229
+ // Clear any active spawn interval
1230
+ if (gameState.enemySpawnInterval) {
1231
+ clearInterval(gameState.enemySpawnInterval);
1232
+ gameState.enemySpawnInterval = null;
1233
+ }
1234
+
1235
+ // Reset wave state
1236
+ gameState.gameActive = false;
1237
+ gameState.currentWaveEnemies = 0;
1238
+
1239
+ // Reset wave progress
1240
+ waveProgress.style.width = '0%';
1241
+ waveIndicator.style.display = 'none';
1242
+
1243
+ // Enable start wave button
1244
+ startWaveBtn.disabled = false;
1245
+ restartWaveBtn.disabled = false;
1246
+ }
1247
+
1248
+ // Spawn enemy
1249
+ function spawnEnemy(type) {
1250
+ let healthMultiplier = 1 + (gameState.wave - 1) * 0.2; // 20% more health per wave
1251
+
1252
+ const enemy = {
1253
+ type: type,
1254
+ health: enemyTypes[type].health * healthMultiplier,
1255
+ maxHealth: enemyTypes[type].health * healthMultiplier,
1256
+ speed: enemyTypes[type].speed,
1257
+ reward: enemyTypes[type].reward * (0.8 + Math.random() * 0.4), // Random reward variation
1258
+ pathIndex: 0,
1259
+ x: gameState.path[0].x * gameState.cellSize + gameState.cellSize / 2,
1260
+ y: gameState.path[0].y * gameState.cellSize + gameState.cellSize / 2,
1261
+ dotDamage: 0, // For fire tower's damage over time
1262
+ dotDuration: 0,
1263
+ name: enemyTypes[type].name
1264
+ };
1265
+
1266
+ gameState.enemies.push(enemy);
1267
+
1268
+ // Create enemy element
1269
+ const enemyElement = document.createElement('div');
1270
+ enemyElement.className = `enemy enemy-${type + 1}`;
1271
+ enemyElement.style.left = `${enemy.x - 15}px`;
1272
+ enemyElement.style.top = `${enemy.y - 15}px`;
1273
+
1274
+ // Add health bar
1275
+ const healthBar = document.createElement('div');
1276
+ healthBar.className = 'health-bar';
1277
+ enemyElement.appendChild(healthBar);
1278
+
1279
+ // Add enemy type indicator
1280
+ const enemyTypeIndicator = document.createElement('div');
1281
+ enemyTypeIndicator.className = 'absolute top-0 left-0 text-xs font-bold';
1282
+ enemyTypeIndicator.textContent = enemyTypes[type].name.charAt(0);
1283
+ enemyTypeIndicator.style.transform = 'translateY(-100%)';
1284
+ enemyElement.appendChild(enemyTypeIndicator);
1285
+
1286
+ gameContainer.appendChild(enemyElement);
1287
+
1288
+ // Play spawn sound
1289
+ playSound('spawn');
1290
+ }
1291
+
1292
+ // Game loop
1293
+ function gameLoop() {
1294
+ // Apply damage over time (for fire tower)
1295
+ gameState.enemies.forEach((enemy, enemyIndex) => {
1296
+ if (enemy.dotDuration > 0) {
1297
+ enemy.dotDuration--;
1298
+ enemy.health -= enemy.dotDamage;
1299
+
1300
+ // Show fire effect
1301
+ if (enemy.dotDuration % 10 === 0) {
1302
+ showDamageText(enemy.x, enemy.y, enemy.dotDamage, 'orange');
1303
+ }
1304
+
1305
+ // Update health bar
1306
+ const enemyElement = document.querySelectorAll('.enemy')[enemyIndex];
1307
+ if (enemyElement) {
1308
+ const healthBar = enemyElement.querySelector('.health-bar');
1309
+ healthBar.style.width = `${(enemy.health / enemy.maxHealth) * 100}%`;
1310
+
1311
+ if (enemy.health <= 0) {
1312
+ // Enemy died
1313
+ gameState.money += Math.floor(enemy.reward);
1314
+ gameState.enemiesDefeated++;
1315
+ updateUI();
1316
+ removeEnemy(enemyIndex);
1317
+ }
1318
+ }
1319
+ }
1320
+ });
1321
+
1322
+ // Move enemies
1323
+ gameState.enemies.forEach((enemy, enemyIndex) => {
1324
+ const target = gameState.path[enemy.pathIndex + 1];
1325
+ if (!target) {
1326
+ // Enemy reached the end
1327
+ gameState.lives--;
1328
+ updateUI();
1329
+ removeEnemy(enemyIndex);
1330
+
1331
+ if (gameState.lives <= 0) {
1332
+ gameOver();
1333
+ }
1334
+ return;
1335
+ }
1336
+
1337
+ const targetX = target.x * gameState.cellSize + gameState.cellSize / 2;
1338
+ const targetY = target.y * gameState.cellSize + gameState.cellSize / 2;
1339
+
1340
+ const dx = targetX - enemy.x;
1341
+ const dy = targetY - enemy.y;
1342
+ const distance = Math.sqrt(dx * dx + dy * dy);
1343
+
1344
+ if (distance < 2) {
1345
+ // Reached current target, move to next
1346
+ enemy.pathIndex++;
1347
+ } else {
1348
+ // Move toward target
1349
+ enemy.x += (dx / distance) * enemy.speed;
1350
+ enemy.y += (dy / distance) * enemy.speed;
1351
+
1352
+ // Update enemy element position
1353
+ const enemyElement = document.querySelectorAll('.enemy')[enemyIndex];
1354
+ if (enemyElement) {
1355
+ enemyElement.style.left = `${enemy.x - 15}px`;
1356
+ enemyElement.style.top = `${enemy.y - 15}px`;
1357
+ }
1358
+ }
1359
+ });
1360
+
1361
+ // Tower actions
1362
+ gameState.towers.forEach((tower, towerIndex) => {
1363
+ if (tower.cooldown > 0) {
1364
+ tower.cooldown--;
1365
+ return;
1366
+ }
1367
+
1368
+ // Find closest enemy in range
1369
+ let closestEnemy = null;
1370
+ let closestDistance = Infinity;
1371
+
1372
+ gameState.enemies.forEach((enemy, enemyIndex) => {
1373
+ const dx = enemy.x - (tower.x * gameState.cellSize + gameState.cellSize / 2);
1374
+ const dy = enemy.y - (tower.y * gameState.cellSize + gameState.cellSize / 2);
1375
+ const distance = Math.sqrt(dx * dx + dy * dy);
1376
+
1377
+ if (distance < tower.range && distance < closestDistance) {
1378
+ closestDistance = distance;
1379
+ closestEnemy = { enemy, enemyIndex };
1380
+ }
1381
+ });
1382
+
1383
+ if (closestEnemy) {
1384
+ // Shoot at enemy
1385
+ tower.cooldown = tower.maxCooldown;
1386
+
1387
+ // Damage calculation with potential crit
1388
+ let damage = tower.damage;
1389
+ if (tower.type === 6 && Math.random() < towerTypes[6].critChance) {
1390
+ damage *= 2; // Critical hit
1391
+ }
1392
+
1393
+ // Create projectile
1394
+ const projectile = {
1395
+ towerIndex: towerIndex,
1396
+ enemyIndex: closestEnemy.enemyIndex,
1397
+ x: tower.x * gameState.cellSize + gameState.cellSize / 2,
1398
+ y: tower.y * gameState.cellSize + gameState.cellSize / 2,
1399
+ targetX: closestEnemy.enemy.x,
1400
+ targetY: closestEnemy.enemy.y,
1401
+ speed: towerTypes[tower.type].projectileSpeed,
1402
+ damage: damage,
1403
+ type: tower.type,
1404
+ targetEnemies: [closestEnemy.enemyIndex]
1405
+ };
1406
+
1407
+ // For chain lightning tower, find additional targets
1408
+ if (tower.type === 5) {
1409
+ const chainRange = towerTypes[5].chainRange;
1410
+ const maxTargets = towerTypes[5].chainTargets;
1411
+
1412
+ gameState.enemies.forEach((enemy, i) => {
1413
+ if (i !== closestEnemy.enemyIndex &&
1414
+ projectile.targetEnemies.length < maxTargets) {
1415
+ const dX = enemy.x - closestEnemy.enemy.x;
1416
+ const dY = enemy.y - closestEnemy.enemy.y;
1417
+ const dDistance = Math.sqrt(dX * dX + dY * dY);
1418
+
1419
+ if (dDistance < chainRange) {
1420
+ projectile.targetEnemies.push(i);
1421
+ }
1422
+ }
1423
+ });
1424
+ }
1425
+
1426
+ gameState.projectiles.push(projectile);
1427
+
1428
+ // Create projectile element
1429
+ const projectileElement = document.createElement('div');
1430
+ projectileElement.className = `projectile projectile-${tower.type}`;
1431
+ projectileElement.style.left = `${projectile.x - 4}px`;
1432
+ projectileElement.style.top = `${projectile.y - 4}px`;
1433
+
1434
+ // Special projectile effect for magic tower crit
1435
+ if (tower.type === 6 && damage > tower.damage) {
1436
+ projectileElement.style.boxShadow = `0 0 15px ${towerTypes[6].color}, 0 0 30px white`;
1437
+ }
1438
+
1439
+ gameContainer.appendChild(projectileElement);
1440
+
1441
+ // Play shoot sound
1442
+ playSound('shoot');
1443
+ }
1444
+ });
1445
+
1446
+ // Move projectiles
1447
+ gameState.projectiles.forEach((projectile, projectileIndex) => {
1448
+ // For chain lightning, find current target
1449
+ const targetIndex = projectile.targetEnemies[0];
1450
+ if (targetIndex === undefined || !gameState.enemies[targetIndex]) {
1451
+ // No more targets or enemy died, remove projectile
1452
+ removeProjectile(projectileIndex);
1453
+ return;
1454
+ }
1455
+
1456
+ const enemy = gameState.enemies[targetIndex];
1457
+
1458
+ // Update target position (enemy may have moved)
1459
+ projectile.targetX = enemy.x;
1460
+ projectile.targetY = enemy.y;
1461
+
1462
+ const dx = projectile.targetX - projectile.x;
1463
+ const dy = projectile.targetY - projectile.y;
1464
+ const distance = Math.sqrt(dx * dx + dy * dy);
1465
+
1466
+ if (distance < 5) {
1467
+ // Hit enemy
1468
+ enemy.health -= projectile.damage;
1469
+
1470
+ // For fire tower, apply DOT
1471
+ if (projectile.type === 4) {
1472
+ enemy.dotDamage = towerTypes[4].damage;
1473
+ enemy.dotDuration = towerTypes[4].dotDuration;
1474
+ }
1475
+
1476
+ // Show damage text
1477
+ showDamageText(enemy.x, enemy.y, projectile.damage, towerTypes[projectile.type].color);
1478
+
1479
+ // Play hit sound
1480
+ playSound('hit');
1481
+
1482
+ // Update health bar
1483
+ const enemyElement = document.querySelectorAll('.enemy')[targetIndex];
1484
+ if (enemyElement) {
1485
+ const healthBar = enemyElement.querySelector('.health-bar');
1486
+ healthBar.style.width = `${(enemy.health / enemy.maxHealth) * 100}%`;
1487
+
1488
+ if (enemy.health <= 0) {
1489
+ // Enemy died
1490
+ gameState.money += Math.floor(enemy.reward);
1491
+ gameState.enemiesDefeated++;
1492
+ updateUI();
1493
+ removeEnemy(targetIndex);
1494
+
1495
+ // Play death sound
1496
+ playSound('death');
1497
+ }
1498
+ }
1499
+
1500
+ // For cannon tower (type 2), do AOE damage
1501
+ if (projectile.type === 2) {
1502
+ const aoeRadius = towerTypes[2].aoeRadius;
1503
+ gameState.enemies.forEach((otherEnemy, i) => {
1504
+ if (i !== targetIndex && otherEnemy) {
1505
+ const dX = otherEnemy.x - enemy.x;
1506
+ const dY = otherEnemy.y - enemy.y;
1507
+ const dDistance = Math.sqrt(dX * dX + dY * dY);
1508
+
1509
+ if (dDistance < aoeRadius) {
1510
+ const aoeDamage = Math.floor(projectile.damage * 0.5);
1511
+ otherEnemy.health -= aoeDamage;
1512
+
1513
+ // Show AOE damage text
1514
+ showDamageText(otherEnemy.x, otherEnemy.y, aoeDamage, towerTypes[2].color);
1515
+
1516
+ // Update health bar
1517
+ const otherEnemyElement = document.querySelectorAll('.enemy')[i];
1518
+ if (otherEnemyElement && otherEnemy.health > 0) {
1519
+ const healthBar = otherEnemyElement.querySelector('.health-bar');
1520
+ healthBar.style.width = `${(otherEnemy.health / otherEnemy.maxHealth) * 100}%`;
1521
+ }
1522
+
1523
+ if (otherEnemy.health <= 0) {
1524
+ // Enemy died from AOE
1525
+ gameState.money += Math.floor(otherEnemy.reward);
1526
+ gameState.enemiesDefeated++;
1527
+ updateUI();
1528
+ removeEnemy(i);
1529
+
1530
+ // Play death sound
1531
+ playSound('death');
1532
+ }
1533
+ }
1534
+ }
1535
+ });
1536
+ }
1537
+
1538
+ // For chain lightning, move to next target if available
1539
+ if (projectile.type === 5 && projectile.targetEnemies.length > 1) {
1540
+ projectile.targetEnemies.shift(); // Remove current target
1541
+ projectile.x = enemy.x;
1542
+ projectile.y = enemy.y;
1543
+
1544
+ // Update projectile position
1545
+ const projectileElement = document.querySelectorAll('.projectile')[projectileIndex];
1546
+ if (projectileElement) {
1547
+ projectileElement.style.left = `${projectile.x - 4}px`;
1548
+ projectileElement.style.top = `${projectile.y - 4}px`;
1549
+ }
1550
+ } else {
1551
+ // Remove projectile
1552
+ removeProjectile(projectileIndex);
1553
+ }
1554
+ } else {
1555
+ // Move toward target
1556
+ projectile.x += (dx / distance) * projectile.speed;
1557
+ projectile.y += (dy / distance) * projectile.speed;
1558
+
1559
+ // Update projectile element position
1560
+ const projectileElement = document.querySelectorAll('.projectile')[projectileIndex];
1561
+ if (projectileElement) {
1562
+ projectileElement.style.left = `${projectile.x - 4}px`;
1563
+ projectileElement.style.top = `${projectile.y - 4}px`;
1564
+ }
1565
+
1566
+ // For magic tower crit, update animation
1567
+ if (projectile.type === 6 && projectile.damage > towerTypes[6].damage) {
1568
+ const scale = 1 + Math.sin(Date.now() / 100) * 0.2;
1569
+ projectileElement.style.transform = `scale(${scale})`;
1570
+ }
1571
+ }
1572
+ });
1573
+
1574
+ // Update floating damage texts
1575
+ gameState.damageTexts.forEach((text, i) => {
1576
+ text.y -= 0.5;
1577
+ text.opacity -= 0.02;
1578
+
1579
+ const textElement = document.querySelectorAll('.floating-damage')[i];
1580
+ if (textElement) {
1581
+ textElement.style.left = `${text.x}px`;
1582
+ textElement.style.top = `${text.y}px`;
1583
+ textElement.style.opacity = text.opacity;
1584
+
1585
+ if (text.opacity <= 0) {
1586
+ textElement.remove();
1587
+ gameState.damageTexts.splice(i, 1);
1588
+ }
1589
+ }
1590
+ });
1591
+
1592
+ // Check if wave is complete
1593
+ if (gameState.gameActive && gameState.enemies.length === 0 && !gameState.enemySpawnInterval) {
1594
+ waveComplete();
1595
+ }
1596
+ }
1597
+
1598
+ // Show damage text
1599
+ function showDamageText(x, y, damage, color) {
1600
+ const textElement = document.createElement('div');
1601
+ textElement.className = 'floating-damage';
1602
+ textElement.textContent = `-${Math.floor(damage)}`;
1603
+ textElement.style.left = `${x}px`;
1604
+ textElement.style.top = `${y - 15}px`;
1605
+ textElement.style.color = color;
1606
+
1607
+ // Bigger text for crits
1608
+ if (damage > towerTypes[6].damage) {
1609
+ textElement.style.fontSize = '20px';
1610
+ textElement.style.color = 'white';
1611
+ textElement.style.textShadow = `0 0 10px ${color}`;
1612
+ }
1613
+
1614
+ gameContainer.appendChild(textElement);
1615
+ gameState.damageTexts.push({ x, y: y - 15, opacity: 1 });
1616
+ }
1617
+
1618
+ // Show message
1619
+ function showMessage(message) {
1620
+ const messageElement = document.createElement('div');
1621
+ messageElement.textContent = message;
1622
+ messageElement.style.position = 'absolute';
1623
+ messageElement.style.left = '50%';
1624
+ messageElement.style.top = '50%';
1625
+ messageElement.style.transform = 'translate(-50%, -50%)';
1626
+ messageElement.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
1627
+ messageElement.style.padding = '10px 20px';
1628
+ messageElement.style.borderRadius = '5px';
1629
+ messageElement.style.color = 'white';
1630
+ messageElement.style.fontWeight = 'bold';
1631
+ messageElement.style.zIndex = '300';
1632
+ messageElement.style.opacity = '0';
1633
+ messageElement.style.transition = 'opacity 0.3s';
1634
+
1635
+ gameContainer.appendChild(messageElement);
1636
+
1637
+ setTimeout(() => {
1638
+ messageElement.style.opacity = '1';
1639
+ }, 10);
1640
+
1641
+ setTimeout(() => {
1642
+ messageElement.style.opacity = '0';
1643
+ setTimeout(() => messageElement.remove(), 300);
1644
+ }, 1000);
1645
+ }
1646
+
1647
+ // Remove enemy
1648
+ function removeEnemy(index) {
1649
+ const enemyElement = document.querySelectorAll('.enemy')[index];
1650
+ if (enemyElement) enemyElement.remove();
1651
+ gameState.enemies.splice(index, 1);
1652
+
1653
+ // Update indices in projectiles
1654
+ gameState.projectiles.forEach(projectile => {
1655
+ for (let i = 0; i < projectile.targetEnemies.length; i++) {
1656
+ if (projectile.targetEnemies[i] > index) {
1657
+ projectile.targetEnemies[i]--;
1658
+ } else if (projectile.targetEnemies[i] === index) {
1659
+ projectile.targetEnemies.splice(i, 1);
1660
+ i--;
1661
+ }
1662
+ }
1663
+ });
1664
+ }
1665
+
1666
+ // Remove projectile
1667
+ function removeProjectile(index) {
1668
+ const projectileElement = document.querySelectorAll('.projectile')[index];
1669
+ if (projectileElement) projectileElement.remove();
1670
+ gameState.projectiles.splice(index, 1);
1671
+ }
1672
+
1673
+ // Wave complete
1674
+ function waveComplete() {
1675
+ gameState.gameActive = false;
1676
+ gameState.wave++;
1677
+ updateUI();
1678
+ startWaveBtn.disabled = false;
1679
+ restartWaveBtn.disabled = false;
1680
+
1681
+ // Play wave complete sound
1682
+ playSound('waveComplete');
1683
+
1684
+ // Show wave complete message
1685
+ showMessage(`Wave ${gameState.wave - 1} Complete!`);
1686
+ }
1687
+
1688
+ // Game over
1689
+ function gameOver() {
1690
+ clearInterval(gameState.gameLoopInterval);
1691
+ clearInterval(gameState.enemySpawnInterval);
1692
+ gameState.gameActive = false;
1693
+
1694
+ finalWaveDisplay.textContent = gameState.wave - 1;
1695
+ finalKillsDisplay.textContent = gameState.enemiesDefeated;
1696
+ gameOverScreen.style.display = 'flex';
1697
+
1698
+ // Play game over sound
1699
+ playSound('gameOver');
1700
+ }
1701
+
1702
+ // Update UI
1703
+ function updateUI() {
1704
+ waveDisplay.textContent = gameState.wave;
1705
+ livesDisplay.textContent = gameState.lives;
1706
+ moneyDisplay.textContent = gameState.money;
1707
+
1708
+ // Update money color based on amount
1709
+ if (gameState.money < 50) {
1710
+ moneyDisplay.className = 'text-red-400';
1711
+ } else if (gameState.money < 100) {
1712
+ moneyDisplay.className = 'text-yellow-400';
1713
+ } else {
1714
+ moneyDisplay.className = 'text-green-400';
1715
+ }
1716
+
1717
+ // Update lives color based on amount
1718
+ if (gameState.lives <= 5) {
1719
+ livesDisplay.className = 'text-red-400';
1720
+ } else if (gameState.lives <= 10) {
1721
+ livesDisplay.className = 'text-yellow-400';
1722
+ } else {
1723
+ livesDisplay.className = 'text-blue-400';
1724
+ }
1725
+ }
1726
+
1727
+ // Play sound
1728
+ function playSound(type) {
1729
+ // In a real implementation, you would play actual sound files here
1730
+ // This is just a placeholder for the concept
1731
+ const sounds = {
1732
+ shoot: () => console.log('pew!'),
1733
+ hit: () => console.log('boom!'),
1734
+ death: () => console.log('argh!'),
1735
+ spawn: () => console.log('spawning!'),
1736
+ waveComplete: () => console.log('victory!'),
1737
+ gameOver: () => console.log('game over!'),
1738
+ upgrade: () => console.log('upgrading!'),
1739
+ sell: () => console.log('cha-ching!')
1740
+ };
1741
+
1742
+ if (sounds[type]) {
1743
+ sounds[type]();
1744
+ }
1745
+ }
1746
+
1747
+ // Event listeners
1748
+ startWaveBtn.addEventListener('click', startWave);
1749
+ restartWaveBtn.addEventListener('click', restartWave);
1750
+
1751
+ towerShopItems.forEach(item => {
1752
+ item.addEventListener('click', () => {
1753
+ if (gameState.placingTower) {
1754
+ // Cancel previous placement
1755
+ gameState.placingTower = false;
1756
+ gameState.towerType = null;
1757
+
1758
+ // Remove range indicator if it exists
1759
+ const rangeIndicator = document.querySelector('.range-indicator');
1760
+ if (rangeIndicator) rangeIndicator.remove();
1761
+ }
1762
+
1763
+ const type = parseInt(item.dataset.type);
1764
+ const cost = towerTypes[type].cost;
1765
+
1766
+ if (gameState.money >= cost) {
1767
+ gameState.placingTower = true;
1768
+ gameState.towerType = type;
1769
+
1770
+ // Create range indicator
1771
+ const rangeIndicator = document.createElement('div');
1772
+ rangeIndicator.className = 'range-indicator';
1773
+ rangeIndicator.style.width = `${towerTypes[type].range * 2}px`;
1774
+ rangeIndicator.style.height = `${towerTypes[type].range * 2}px`;
1775
+ gameContainer.appendChild(rangeIndicator);
1776
+
1777
+ // Update position on mouse move
1778
+ gameContainer.addEventListener('mousemove', (e) => {
1779
+ if (gameState.placingTower) {
1780
+ const rect = gameContainer.getBoundingClientRect();
1781
+ const x = Math.floor((e.clientX - rect.left) / gameState.cellSize);
1782
+ const y = Math.floor((e.clientY - rect.top) / gameState.cellSize);
1783
+
1784
+ rangeIndicator.style.left = `${x * gameState.cellSize + gameState.cellSize / 2}px`;
1785
+ rangeIndicator.style.top = `${y * gameState.cellSize + gameState.cellSize / 2}px`;
1786
+ }
1787
+ });
1788
+ } else {
1789
+ showMessage("Not enough money!");
1790
+ }
1791
+ });
1792
+ });
1793
+
1794
+ // Close tower menu when clicking elsewhere
1795
+ document.addEventListener('click', (e) => {
1796
+ if (!towerMenu.contains(e.target) && e.target.className.indexOf('tower') === -1) {
1797
+ towerMenu.style.display = 'none';
1798
+ gameState.selectedTower = null;
1799
+
1800
+ // Remove range indicator
1801
+ const rangeIndicator = document.querySelector('.range-indicator');
1802
+ if (rangeIndicator) rangeIndicator.remove();
1803
+ }
1804
+ });
1805
+
1806
+ upgradeBtn.addEventListener('click', upgradeTower);
1807
+ sellBtn.addEventListener('click', sellTower);
1808
+ restartBtn.addEventListener('click', initGame);
1809
+
1810
+ // Initialize game
1811
+ initGame();
1812
+ </script>
1813
+ <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=jamesjun/ctd2" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
1814
+ </html>