Fraser commited on
Commit
e40394b
·
1 Parent(s): 52f4c89
src/lib/components/Battle/BattleEffects.svelte CHANGED
@@ -4,11 +4,12 @@
4
 
5
  export let effects: Array<{type: string, emoji: string, duration: number}> = [];
6
  export let flash: boolean = false;
 
7
 
8
- // GBA-style flicker animation parameters
9
  const flickerCount = 19;
10
  const frameDelay = 2;
11
- const flickerDuration = 600; // milliseconds
12
 
13
  // Flicker state management
14
  let isFlickering = false;
@@ -16,6 +17,11 @@
16
  let flickerFrame = 0;
17
  let flickerInterval: number;
18
 
 
 
 
 
 
19
  // Particle system configuration
20
  const PARTICLES_PER_EFFECT = 6; // Number of emoji particles per effect
21
  const SPAWN_RADIUS = 80; // Increased radius around piclet where particles spawn
@@ -62,6 +68,11 @@
62
  startFlickerAnimation();
63
  }
64
 
 
 
 
 
 
65
  function startFlickerAnimation() {
66
  isFlickering = true;
67
  flickerFrame = 0;
@@ -87,19 +98,60 @@
87
  }, frameDuration);
88
  }
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  onMount(() => {
91
  return () => {
92
  if (flickerInterval) {
93
  clearInterval(flickerInterval);
94
  }
 
 
 
95
  };
96
  });
97
  </script>
98
 
99
  <!-- Effects wrapper with relative positioning for particles -->
100
  <div class="effects-wrapper">
101
- <!-- GBA-style flicker effect -->
102
- <div class="effects-container" style="opacity: {(flash && isFlickering) ? (flickerVisible ? 1 : 0) : 1};">
 
 
 
 
 
 
 
 
 
 
 
 
103
  <slot />
104
  </div>
105
 
 
4
 
5
  export let effects: Array<{type: string, emoji: string, duration: number}> = [];
6
  export let flash: boolean = false;
7
+ export let faint: boolean = false;
8
 
9
+ // GBA-style flicker animation parameters (matching original Snaplings timing)
10
  const flickerCount = 19;
11
  const frameDelay = 2;
12
+ const flickerDuration = 1000; // milliseconds - matches Snaplings original
13
 
14
  // Flicker state management
15
  let isFlickering = false;
 
17
  let flickerFrame = 0;
18
  let flickerInterval: number;
19
 
20
+ // Faint animation state management
21
+ let isFainting = false;
22
+ let faintProgress = 0;
23
+ let faintAnimationId: number;
24
+
25
  // Particle system configuration
26
  const PARTICLES_PER_EFFECT = 6; // Number of emoji particles per effect
27
  const SPAWN_RADIUS = 80; // Increased radius around piclet where particles spawn
 
68
  startFlickerAnimation();
69
  }
70
 
71
+ // Watch for faint changes to trigger faint animation
72
+ $: if (faint && !isFainting) {
73
+ startFaintAnimation();
74
+ }
75
+
76
  function startFlickerAnimation() {
77
  isFlickering = true;
78
  flickerFrame = 0;
 
98
  }, frameDuration);
99
  }
100
 
101
+ function startFaintAnimation() {
102
+ isFainting = true;
103
+ faintProgress = 0;
104
+
105
+ const faintDuration = 1200; // milliseconds - matches Snaplings original
106
+ const startTime = performance.now();
107
+
108
+ function updateFaintAnimation(currentTime: number) {
109
+ const elapsed = currentTime - startTime;
110
+ const progress = Math.min(elapsed / faintDuration, 1);
111
+
112
+ // Use easeIn curve for acceleration as it falls away
113
+ faintProgress = progress * progress;
114
+
115
+ if (progress < 1) {
116
+ faintAnimationId = requestAnimationFrame(updateFaintAnimation);
117
+ } else {
118
+ // Animation completed
119
+ isFainting = false;
120
+ faintProgress = 1; // Keep final state
121
+ }
122
+ }
123
+
124
+ faintAnimationId = requestAnimationFrame(updateFaintAnimation);
125
+ }
126
+
127
  onMount(() => {
128
  return () => {
129
  if (flickerInterval) {
130
  clearInterval(flickerInterval);
131
  }
132
+ if (faintAnimationId) {
133
+ cancelAnimationFrame(faintAnimationId);
134
+ }
135
  };
136
  });
137
  </script>
138
 
139
  <!-- Effects wrapper with relative positioning for particles -->
140
  <div class="effects-wrapper">
141
+ <!-- GBA-style flicker effect with faint animation -->
142
+ <div
143
+ class="effects-container"
144
+ class:is-fainting={faint}
145
+ style="
146
+ opacity: {(flash && isFlickering) ? (flickerVisible ? 1 : 0) : (faint && faintProgress >= 1 ? 0 : 1)};
147
+ {faint ? `
148
+ transform:
149
+ scale(1, ${Math.max(0, 1 - faintProgress)})
150
+ matrix(1, 0, ${-faintProgress * 0.5}, 1, 0, 0);
151
+ transform-origin: bottom center;
152
+ ` : ''}
153
+ "
154
+ >
155
  <slot />
156
  </div>
157
 
src/lib/components/Battle/BattleField.svelte CHANGED
@@ -18,6 +18,8 @@
18
  export let enemyEffects: Array<{type: string, emoji: string, duration: number}> = [];
19
  export let playerFlash: boolean = false;
20
  export let enemyFlash: boolean = false;
 
 
21
 
22
  // Animation states
23
  let playerVisible = false;
@@ -74,7 +76,7 @@
74
  {#if enemyVisible}
75
  <div class="enemy-piclet-wrapper" class:animate-in={showIntro}>
76
  <!-- Enemy Battle Effects wrap the image for flicker animation -->
77
- <BattleEffects effects={enemyEffects} flash={enemyFlash}>
78
  <img
79
  class="piclet-image enemy-image"
80
  src={enemyPiclet.imageData || enemyPiclet.imageUrl}
@@ -118,7 +120,7 @@
118
  {#if playerVisible}
119
  <div class="player-piclet-wrapper" class:animate-in={showIntro}>
120
  <!-- Player Battle Effects wrap the image for flicker animation -->
121
- <BattleEffects effects={playerEffects} flash={playerFlash}>
122
  <img
123
  class="piclet-image player-image"
124
  src={playerPiclet.imageData || playerPiclet.imageUrl}
 
18
  export let enemyEffects: Array<{type: string, emoji: string, duration: number}> = [];
19
  export let playerFlash: boolean = false;
20
  export let enemyFlash: boolean = false;
21
+ export let playerFaint: boolean = false;
22
+ export let enemyFaint: boolean = false;
23
 
24
  // Animation states
25
  let playerVisible = false;
 
76
  {#if enemyVisible}
77
  <div class="enemy-piclet-wrapper" class:animate-in={showIntro}>
78
  <!-- Enemy Battle Effects wrap the image for flicker animation -->
79
+ <BattleEffects effects={enemyEffects} flash={enemyFlash} faint={enemyFaint}>
80
  <img
81
  class="piclet-image enemy-image"
82
  src={enemyPiclet.imageData || enemyPiclet.imageUrl}
 
120
  {#if playerVisible}
121
  <div class="player-piclet-wrapper" class:animate-in={showIntro}>
122
  <!-- Player Battle Effects wrap the image for flicker animation -->
123
+ <BattleEffects effects={playerEffects} flash={playerFlash} faint={playerFaint}>
124
  <img
125
  class="piclet-image player-image"
126
  src={playerPiclet.imageData || playerPiclet.imageUrl}
src/lib/components/Pages/Battle.svelte CHANGED
@@ -38,6 +38,8 @@
38
  let enemyEffects: Array<{type: string, emoji: string, duration: number}> = [];
39
  let playerFlash = false;
40
  let enemyFlash = false;
 
 
41
 
42
  onMount(() => {
43
  // Initialize battle engine with converted piclet definitions
@@ -253,15 +255,34 @@
253
  if (message.includes('missed')) {
254
  triggerEffect('both', 'miss', '💫', 800);
255
  }
 
 
 
 
 
 
 
 
 
256
  }
257
 
258
  function triggerDamageFlash(target: 'player' | 'enemy') {
259
  if (target === 'player') {
260
  playerFlash = true;
261
- setTimeout(() => playerFlash = false, 600); // Match GBA flicker duration
262
  } else {
263
  enemyFlash = true;
264
- setTimeout(() => enemyFlash = false, 600); // Match GBA flicker duration
 
 
 
 
 
 
 
 
 
 
265
  }
266
  }
267
 
@@ -348,6 +369,8 @@
348
  {enemyEffects}
349
  {playerFlash}
350
  {enemyFlash}
 
 
351
  />
352
 
353
  <BattleControls
 
38
  let enemyEffects: Array<{type: string, emoji: string, duration: number}> = [];
39
  let playerFlash = false;
40
  let enemyFlash = false;
41
+ let playerFaint = false;
42
+ let enemyFaint = false;
43
 
44
  onMount(() => {
45
  // Initialize battle engine with converted piclet definitions
 
255
  if (message.includes('missed')) {
256
  triggerEffect('both', 'miss', '💫', 800);
257
  }
258
+
259
+ // Faint effects
260
+ if (message.includes('fainted')) {
261
+ if (message.includes(playerName)) {
262
+ triggerFaintAnimation('player');
263
+ } else if (message.includes(enemyName)) {
264
+ triggerFaintAnimation('enemy');
265
+ }
266
+ }
267
  }
268
 
269
  function triggerDamageFlash(target: 'player' | 'enemy') {
270
  if (target === 'player') {
271
  playerFlash = true;
272
+ setTimeout(() => playerFlash = false, 1000); // Match original Snaplings flicker duration
273
  } else {
274
  enemyFlash = true;
275
+ setTimeout(() => enemyFlash = false, 1000); // Match original Snaplings flicker duration
276
+ }
277
+ }
278
+
279
+ function triggerFaintAnimation(target: 'player' | 'enemy') {
280
+ if (target === 'player') {
281
+ playerFaint = true;
282
+ // Don't reset - faint animation should persist until battle ends
283
+ } else {
284
+ enemyFaint = true;
285
+ // Don't reset - faint animation should persist until battle ends
286
  }
287
  }
288
 
 
369
  {enemyEffects}
370
  {playerFlash}
371
  {enemyFlash}
372
+ {playerFaint}
373
+ {enemyFaint}
374
  />
375
 
376
  <BattleControls