Fraser commited on
Commit
e64944b
·
1 Parent(s): 5207761
src/lib/components/Battle/BattleEffects.svelte CHANGED
@@ -16,6 +16,41 @@
16
  let flickerFrame = 0;
17
  let flickerInterval: number;
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  // Watch for flash changes to trigger flicker animation
20
  $: if (flash && !isFlickering) {
21
  startFlickerAnimation();
@@ -62,10 +97,20 @@
62
  <slot />
63
  </div>
64
 
65
- <!-- Particle effects -->
66
- {#each effects as effect (effect)}
67
- <div class="effect-particle {effect.type}" style="animation-duration: {effect.duration}ms">
68
- <span class="effect-emoji">{effect.emoji}</span>
 
 
 
 
 
 
 
 
 
 
69
  </div>
70
  {/each}
71
  </div>
@@ -87,180 +132,315 @@
87
  pointer-events: none;
88
  z-index: 5;
89
  animation-fill-mode: forwards;
 
90
  }
91
 
92
  .effect-emoji {
93
- font-size: 24px;
94
  display: block;
95
- filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.3));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
 
98
- /* Damage and status effects */
99
- .effect-particle.burn,
100
- .effect-particle.poison,
101
- .effect-particle.paralyze,
102
- .effect-particle.sleep,
103
  .effect-particle.freeze {
104
- top: 20%;
105
- left: 50%;
106
- animation: statusEffect linear;
107
  }
108
 
109
- /* Stat changes */
110
  .effect-particle.attackUp,
111
  .effect-particle.defenseUp,
112
  .effect-particle.speedUp,
113
  .effect-particle.accuracyUp {
114
- bottom: 30%;
115
- left: 50%;
116
  animation: statIncrease ease-out;
117
  }
118
 
 
119
  .effect-particle.attackDown,
120
  .effect-particle.defenseDown,
121
  .effect-particle.speedDown,
122
  .effect-particle.accuracyDown {
123
- top: 30%;
124
- left: 50%;
125
- animation: statDecrease ease-out;
126
  }
127
 
128
  /* Special effects */
129
  .effect-particle.critical,
130
  .effect-particle.superEffective {
131
- top: 10%;
132
- left: 50%;
133
- animation: criticalEffect ease-out;
134
  }
135
 
136
  .effect-particle.notVeryEffective,
137
  .effect-particle.miss {
138
- top: 40%;
139
- left: 50%;
140
- animation: missEffect ease-out;
141
  }
142
 
143
  .effect-particle.heal {
144
- bottom: 20%;
145
- left: 50%;
146
- animation: healEffect ease-out;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  }
148
 
149
- /* Animations */
150
- @keyframes statusEffect {
151
  0% {
152
- transform: translate(-50%, 0) scale(0.5);
153
  opacity: 0;
154
  }
155
  20% {
156
- transform: translate(-50%, -10px) scale(1.2);
157
  opacity: 1;
158
  }
159
  40% {
160
- transform: translate(-50%, -5px) scale(1);
161
- opacity: 1;
 
 
 
 
 
 
 
 
162
  }
163
  100% {
164
- transform: translate(-50%, -20px) scale(0.8);
165
  opacity: 0;
166
  }
167
  }
168
 
169
- @keyframes statIncrease {
170
  0% {
171
- transform: translate(-50%, 0) scale(0.5);
172
  opacity: 0;
173
  }
174
- 30% {
175
- transform: translate(-50%, -30px) scale(1.3);
176
  opacity: 1;
177
  }
178
- 70% {
179
- transform: translate(-50%, -40px) scale(1.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  opacity: 1;
181
  }
 
 
 
 
 
 
 
 
182
  100% {
183
- transform: translate(-50%, -60px) scale(0.7);
184
  opacity: 0;
185
  }
186
  }
187
 
188
- @keyframes statDecrease {
189
  0% {
190
- transform: translate(-50%, 0) scale(0.5);
191
  opacity: 0;
192
  }
193
  30% {
194
- transform: translate(-50%, 20px) scale(1.3);
195
  opacity: 1;
196
  }
197
- 70% {
198
- transform: translate(-50%, 30px) scale(1.1);
199
- opacity: 1;
 
 
 
 
200
  }
201
  100% {
202
- transform: translate(-50%, 50px) scale(0.7);
203
  opacity: 0;
204
  }
205
  }
206
 
207
- @keyframes criticalEffect {
208
  0% {
209
- transform: translate(-50%, 0) scale(0.3) rotate(-10deg);
210
  opacity: 0;
211
  }
212
- 20% {
213
- transform: translate(-50%, -20px) scale(1.5) rotate(5deg);
214
  opacity: 1;
215
  }
216
- 40% {
217
- transform: translate(-50%, -15px) scale(1.3) rotate(-2deg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  opacity: 1;
219
  }
220
- 60% {
221
- transform: translate(-50%, -25px) scale(1.4) rotate(1deg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  opacity: 1;
223
  }
 
 
 
 
 
 
 
 
 
 
 
 
224
  100% {
225
- transform: translate(-50%, -40px) scale(0.8) rotate(0deg);
226
  opacity: 0;
227
  }
228
  }
229
 
230
- @keyframes missEffect {
231
  0% {
232
- transform: translate(-50%, 0) scale(1);
233
  opacity: 0;
234
  }
235
- 20% {
236
- transform: translate(-50%, 0) scale(1.2);
237
  opacity: 0.7;
238
  }
239
- 80% {
240
- transform: translate(-50%, 0) scale(1.1);
 
 
 
 
241
  opacity: 0.3;
242
  }
243
  100% {
244
- transform: translate(-50%, 0) scale(1);
245
  opacity: 0;
246
  }
247
  }
248
 
249
- @keyframes healEffect {
250
  0% {
251
- transform: translate(-50%, 20px) scale(0.5);
252
  opacity: 0;
253
  }
254
- 30% {
255
- transform: translate(-50%, -10px) scale(1.2);
256
  opacity: 1;
257
  }
258
- 70% {
259
- transform: translate(-50%, -30px) scale(1);
260
- opacity: 1;
 
 
 
 
 
 
 
 
261
  }
262
  100% {
263
- transform: translate(-50%, -50px) scale(0.6);
264
  opacity: 0;
265
  }
266
  }
 
16
  let flickerFrame = 0;
17
  let flickerInterval: number;
18
 
19
+ // Particle system configuration
20
+ const PARTICLES_PER_EFFECT = 5; // Number of emoji particles per effect
21
+ const SPAWN_RADIUS = 60; // Radius around piclet where particles spawn
22
+
23
+ // Generate multiple particles for each effect
24
+ $: particleList = effects.flatMap((effect, effectIndex) => {
25
+ const particles = [];
26
+ for (let i = 0; i < PARTICLES_PER_EFFECT; i++) {
27
+ // Random spawn position around the piclet
28
+ const angle = (Math.PI * 2 * i) / PARTICLES_PER_EFFECT + (Math.random() - 0.5) * 0.5;
29
+ const distance = SPAWN_RADIUS * (0.7 + Math.random() * 0.6); // Vary distance
30
+ const x = Math.cos(angle) * distance;
31
+ const y = Math.sin(angle) * distance;
32
+
33
+ // Random animation properties
34
+ const scale = 0.8 + Math.random() * 0.4; // 0.8x to 1.2x size
35
+ const rotation = Math.random() * 360; // Random initial rotation
36
+ const duration = effect.duration + (Math.random() - 0.5) * 200; // Vary duration slightly
37
+ const delay = Math.random() * 100; // Stagger animation starts
38
+
39
+ particles.push({
40
+ id: `${effectIndex}-${i}`,
41
+ type: effect.type,
42
+ emoji: effect.emoji,
43
+ x,
44
+ y,
45
+ scale,
46
+ rotation,
47
+ duration,
48
+ delay
49
+ });
50
+ }
51
+ return particles;
52
+ });
53
+
54
  // Watch for flash changes to trigger flicker animation
55
  $: if (flash && !isFlickering) {
56
  startFlickerAnimation();
 
97
  <slot />
98
  </div>
99
 
100
+ <!-- Multi-particle effects -->
101
+ {#each particleList as particle (particle.id)}
102
+ <div
103
+ class="effect-particle {particle.type}"
104
+ style="
105
+ left: {particle.x}px;
106
+ top: {particle.y}px;
107
+ animation-duration: {particle.duration}ms;
108
+ animation-delay: {particle.delay}ms;
109
+ --initial-scale: {particle.scale};
110
+ --initial-rotation: {particle.rotation}deg;
111
+ "
112
+ >
113
+ <span class="effect-emoji">{particle.emoji}</span>
114
  </div>
115
  {/each}
116
  </div>
 
132
  pointer-events: none;
133
  z-index: 5;
134
  animation-fill-mode: forwards;
135
+ transform-origin: center center;
136
  }
137
 
138
  .effect-emoji {
139
+ font-size: 20px;
140
  display: block;
141
+ filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.4));
142
+ transform: scale(var(--initial-scale, 1)) rotate(var(--initial-rotation, 0deg));
143
+ }
144
+
145
+ /* Status effects - floating with rotation */
146
+ .effect-particle.burn {
147
+ animation: statusBurn ease-in-out;
148
+ }
149
+
150
+ .effect-particle.poison {
151
+ animation: statusPoison ease-in-out;
152
+ }
153
+
154
+ .effect-particle.paralyze {
155
+ animation: statusParalyze linear;
156
+ }
157
+
158
+ .effect-particle.sleep {
159
+ animation: statusSleep ease-in-out;
160
  }
161
 
 
 
 
 
 
162
  .effect-particle.freeze {
163
+ animation: statusFreeze ease-out;
 
 
164
  }
165
 
166
+ /* Stat increases - rising with spin */
167
  .effect-particle.attackUp,
168
  .effect-particle.defenseUp,
169
  .effect-particle.speedUp,
170
  .effect-particle.accuracyUp {
 
 
171
  animation: statIncrease ease-out;
172
  }
173
 
174
+ /* Stat decreases - falling with wobble */
175
  .effect-particle.attackDown,
176
  .effect-particle.defenseDown,
177
  .effect-particle.speedDown,
178
  .effect-particle.accuracyDown {
179
+ animation: statDecrease ease-in;
 
 
180
  }
181
 
182
  /* Special effects */
183
  .effect-particle.critical,
184
  .effect-particle.superEffective {
185
+ animation: criticalBurst ease-out;
 
 
186
  }
187
 
188
  .effect-particle.notVeryEffective,
189
  .effect-particle.miss {
190
+ animation: missSwirl ease-in-out;
 
 
191
  }
192
 
193
  .effect-particle.heal {
194
+ animation: healRise ease-out;
195
+ }
196
+
197
+ /* Complex multi-property animations */
198
+ @keyframes statusBurn {
199
+ 0% {
200
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.3);
201
+ opacity: 0;
202
+ }
203
+ 15% {
204
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 45deg)) scale(1.2);
205
+ opacity: 1;
206
+ }
207
+ 50% {
208
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 180deg)) scale(1.0);
209
+ opacity: 0.9;
210
+ }
211
+ 85% {
212
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 315deg)) scale(0.8);
213
+ opacity: 0.4;
214
+ }
215
+ 100% {
216
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 360deg)) scale(0.5);
217
+ opacity: 0;
218
+ }
219
  }
220
 
221
+ @keyframes statusPoison {
 
222
  0% {
223
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.4);
224
  opacity: 0;
225
  }
226
  20% {
227
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 30deg)) scale(1.1);
228
  opacity: 1;
229
  }
230
  40% {
231
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 30deg)) scale(0.9);
232
+ opacity: 0.8;
233
+ }
234
+ 60% {
235
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 20deg)) scale(1.0);
236
+ opacity: 0.6;
237
+ }
238
+ 80% {
239
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 15deg)) scale(0.7);
240
+ opacity: 0.3;
241
  }
242
  100% {
243
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.5);
244
  opacity: 0;
245
  }
246
  }
247
 
248
+ @keyframes statusParalyze {
249
  0% {
250
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.2);
251
  opacity: 0;
252
  }
253
+ 10% {
254
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 10deg)) scale(1.3);
255
  opacity: 1;
256
  }
257
+ 20% {
258
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 10deg)) scale(1.1);
259
+ opacity: 0.9;
260
+ }
261
+ 30% {
262
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 8deg)) scale(1.2);
263
+ opacity: 0.8;
264
+ }
265
+ 40% {
266
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 8deg)) scale(1.0);
267
+ opacity: 0.7;
268
+ }
269
+ 50% {
270
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 5deg)) scale(0.9);
271
+ opacity: 0.6;
272
+ }
273
+ 100% {
274
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.3);
275
+ opacity: 0;
276
+ }
277
+ }
278
+
279
+ @keyframes statusSleep {
280
+ 0% {
281
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.5);
282
+ opacity: 0;
283
+ }
284
+ 25% {
285
+ transform: translate(-50%, -55%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 15deg)) scale(1.1);
286
  opacity: 1;
287
  }
288
+ 50% {
289
+ transform: translate(-50%, -45%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 15deg)) scale(1.0);
290
+ opacity: 0.9;
291
+ }
292
+ 75% {
293
+ transform: translate(-50%, -55%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 10deg)) scale(0.9);
294
+ opacity: 0.5;
295
+ }
296
  100% {
297
+ transform: translate(-50%, -60%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.4);
298
  opacity: 0;
299
  }
300
  }
301
 
302
+ @keyframes statusFreeze {
303
  0% {
304
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.3);
305
  opacity: 0;
306
  }
307
  30% {
308
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 5deg)) scale(1.4);
309
  opacity: 1;
310
  }
311
+ 60% {
312
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 3deg)) scale(1.2);
313
+ opacity: 0.8;
314
+ }
315
+ 90% {
316
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 2deg)) scale(0.8);
317
+ opacity: 0.3;
318
  }
319
  100% {
320
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.6);
321
  opacity: 0;
322
  }
323
  }
324
 
325
+ @keyframes statIncrease {
326
  0% {
327
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.4);
328
  opacity: 0;
329
  }
330
+ 25% {
331
+ transform: translate(-50%, -70%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 90deg)) scale(1.3);
332
  opacity: 1;
333
  }
334
+ 50% {
335
+ transform: translate(-50%, -90%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 180deg)) scale(1.1);
336
+ opacity: 0.9;
337
+ }
338
+ 75% {
339
+ transform: translate(-50%, -110%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 270deg)) scale(0.9);
340
+ opacity: 0.6;
341
+ }
342
+ 100% {
343
+ transform: translate(-50%, -130%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 360deg)) scale(0.5);
344
+ opacity: 0;
345
+ }
346
+ }
347
+
348
+ @keyframes statDecrease {
349
+ 0% {
350
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.4);
351
+ opacity: 0;
352
+ }
353
+ 25% {
354
+ transform: translate(-50%, -30%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 30deg)) scale(1.2);
355
  opacity: 1;
356
  }
357
+ 50% {
358
+ transform: translate(-50%, -10%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 30deg)) scale(1.0);
359
+ opacity: 0.8;
360
+ }
361
+ 75% {
362
+ transform: translate(-50%, 10%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 20deg)) scale(0.8);
363
+ opacity: 0.4;
364
+ }
365
+ 100% {
366
+ transform: translate(-50%, 30%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 10deg)) scale(0.6);
367
+ opacity: 0;
368
+ }
369
+ }
370
+
371
+ @keyframes criticalBurst {
372
+ 0% {
373
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.2);
374
+ opacity: 0;
375
+ }
376
+ 15% {
377
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 45deg)) scale(1.8);
378
  opacity: 1;
379
  }
380
+ 30% {
381
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 30deg)) scale(1.4);
382
+ opacity: 0.9;
383
+ }
384
+ 50% {
385
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 60deg)) scale(1.6);
386
+ opacity: 0.8;
387
+ }
388
+ 70% {
389
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 45deg)) scale(1.2);
390
+ opacity: 0.5;
391
+ }
392
  100% {
393
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 720deg)) scale(0.3);
394
  opacity: 0;
395
  }
396
  }
397
 
398
+ @keyframes missSwirl {
399
  0% {
400
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.6);
401
  opacity: 0;
402
  }
403
+ 25% {
404
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 90deg)) scale(1.2);
405
  opacity: 0.7;
406
  }
407
+ 50% {
408
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 180deg)) scale(1.0);
409
+ opacity: 0.5;
410
+ }
411
+ 75% {
412
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 270deg)) scale(0.8);
413
  opacity: 0.3;
414
  }
415
  100% {
416
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 360deg)) scale(0.4);
417
  opacity: 0;
418
  }
419
  }
420
 
421
+ @keyframes healRise {
422
  0% {
423
+ transform: translate(-50%, -30%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.5);
424
  opacity: 0;
425
  }
426
+ 20% {
427
+ transform: translate(-50%, -50%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 30deg)) scale(1.3);
428
  opacity: 1;
429
  }
430
+ 40% {
431
+ transform: translate(-50%, -70%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 20deg)) scale(1.1);
432
+ opacity: 0.9;
433
+ }
434
+ 60% {
435
+ transform: translate(-50%, -90%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) + 15deg)) scale(1.0);
436
+ opacity: 0.7;
437
+ }
438
+ 80% {
439
+ transform: translate(-50%, -110%) scale(var(--initial-scale)) rotate(calc(var(--initial-rotation) - 10deg)) scale(0.8);
440
+ opacity: 0.4;
441
  }
442
  100% {
443
+ transform: translate(-50%, -130%) scale(var(--initial-scale)) rotate(var(--initial-rotation)) scale(0.5);
444
  opacity: 0;
445
  }
446
  }