Fraser commited on
Commit
afa3e65
·
1 Parent(s): 90a88fc

battle fix

Browse files
public/assets/default_trainer.png ADDED

Git LFS Details

  • SHA256: 909c22d35be7a34077a3aa88dcd90a5a0a643afbbd80a0a1e3dec182b8cf3ebd
  • Pointer size: 132 Bytes
  • Size of remote file: 1.23 MB
src/lib/components/Battle/BattleField.svelte CHANGED
@@ -10,15 +10,14 @@
10
  export let enemyHpPercentage: number;
11
  export let showIntro: boolean = false;
12
 
13
- // Random background selection
14
- const backgrounds = ['ruins', 'road', 'dinner', 'cave'];
15
- const selectedBackground = backgrounds[Math.floor(Math.random() * backgrounds.length)];
16
-
17
  // Animation states
18
  let playerVisible = false;
19
  let enemyVisible = false;
20
  let trainerVisible = true;
21
 
 
 
 
22
  onMount(() => {
23
  if (showIntro) {
24
  // Intro animation sequence
@@ -39,59 +38,82 @@
39
  });
40
  </script>
41
 
42
- <div class="battle-field" style="background-image: url('/images/environments/{selectedBackground}.png')">
43
- <!-- Striped overlay pattern -->
44
- <div class="stripe-pattern"></div>
45
-
46
  <!-- Trainer intro image -->
47
  {#if showIntro && trainerVisible}
48
  <div class="trainer-intro" transition:fade={{ duration: 300 }}>
49
- <img src="/images/default_trainer.png" alt="Trainer" />
50
  </div>
51
  {/if}
52
 
53
- <!-- Enemy area -->
54
- <div class="enemy-area">
55
- <PicletInfo
56
- piclet={enemyPiclet}
57
- hpPercentage={enemyHpPercentage}
58
- isPlayer={false}
59
- />
60
-
61
- {#if enemyVisible}
62
- <div class="enemy-piclet-container">
63
- <div class="piclet-sprite enemy-sprite" transition:fade={{ duration: 300 }}>
64
- <img
65
- src={enemyPiclet.imageData || enemyPiclet.imageUrl}
66
- alt={enemyPiclet.nickname}
67
- on:error={(e) => e.currentTarget.src = 'https://via.placeholder.com/120x120?text=Piclet'}
68
- />
69
- </div>
70
- <div class="battle-platform enemy-platform"></div>
71
- </div>
72
- {/if}
73
- </div>
74
-
75
- <!-- Player area -->
76
- <div class="player-area">
77
- {#if playerVisible}
78
- <div class="player-piclet-container">
79
- <div class="piclet-sprite player-sprite" transition:fade={{ duration: 300 }}>
80
- <img
81
- src={playerPiclet.imageData || playerPiclet.imageUrl}
82
- alt={playerPiclet.nickname}
83
- on:error={(e) => e.currentTarget.src = 'https://via.placeholder.com/120x120?text=Piclet'}
84
- />
85
- </div>
86
- <div class="battle-platform player-platform"></div>
87
  </div>
88
- {/if}
89
 
90
- <PicletInfo
91
- piclet={playerPiclet}
92
- hpPercentage={playerHpPercentage}
93
- isPlayer={true}
94
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  </div>
96
  </div>
97
 
@@ -99,22 +121,14 @@
99
  .battle-field {
100
  height: 280px;
101
  position: relative;
102
- background-color: #e8f4f8;
103
  overflow: hidden;
104
- }
105
-
106
- .stripe-pattern {
107
- position: absolute;
108
- inset: 0;
109
  background: repeating-linear-gradient(
110
- 45deg,
111
- transparent,
112
- transparent 10px,
113
- rgba(0, 0, 0, 0.02) 10px,
114
- rgba(0, 0, 0, 0.02) 20px
115
  );
116
- pointer-events: none;
117
- z-index: 1;
118
  }
119
 
120
  .trainer-intro {
@@ -128,100 +142,132 @@
128
  .trainer-intro img {
129
  width: 200px;
130
  height: auto;
131
- filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
132
  }
133
 
134
- .enemy-area {
135
- position: absolute;
136
- top: 10%;
137
- right: 10%;
138
  display: flex;
139
  flex-direction: column;
140
- align-items: flex-end;
141
- gap: 1rem;
 
 
 
 
 
142
  }
143
 
144
- .player-area {
145
  position: absolute;
146
- bottom: 10%;
147
- left: 10%;
148
- display: flex;
149
- flex-direction: column;
150
- align-items: flex-start;
151
- gap: 1rem;
152
  }
153
 
154
- .piclet-sprite {
155
- width: 120px;
156
- height: 120px;
157
- display: flex;
158
- align-items: center;
159
- justify-content: center;
160
  }
161
 
162
- .piclet-sprite img {
163
- width: 100%;
164
- height: 100%;
165
  object-fit: contain;
166
- image-rendering: pixelated;
167
- filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
168
  }
169
 
170
- .enemy-sprite {
171
- order: 2;
 
 
 
 
 
172
  }
173
 
174
- .player-sprite {
175
- order: 1;
176
- transform: scaleX(-1); /* Mirror player sprite */
 
177
  }
178
 
179
- /* Piclet containers with platforms */
180
- .enemy-piclet-container,
181
- .player-piclet-container {
182
  position: relative;
183
- display: flex;
184
- flex-direction: column;
185
- align-items: center;
186
  }
187
 
188
- .battle-platform {
189
- width: 140px;
190
- height: 20px;
191
- background: #90a4ae;
192
- border-radius: 50%;
193
- margin-top: -10px;
194
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
195
- z-index: 2;
196
  }
197
 
198
- .enemy-platform {
199
  width: 120px;
 
 
 
200
  }
201
 
202
  .player-platform {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  width: 140px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  }
205
 
206
  @media (max-width: 768px) {
207
- .battle-field {
208
- height: 50vh;
209
- min-height: 300px;
210
- }
211
-
212
- .piclet-sprite {
213
  width: 80px;
214
  height: 80px;
215
  }
216
 
217
- .enemy-area {
218
- top: 5%;
219
- right: 5%;
 
 
 
 
220
  }
221
 
222
- .player-area {
223
- bottom: 5%;
224
- left: 5%;
225
  }
226
  }
227
  </style>
 
10
  export let enemyHpPercentage: number;
11
  export let showIntro: boolean = false;
12
 
 
 
 
 
13
  // Animation states
14
  let playerVisible = false;
15
  let enemyVisible = false;
16
  let trainerVisible = true;
17
 
18
+ // Calculate player XP percentage (0-100% of current level)
19
+ const playerXpPercentage = (playerPiclet.xp / 100) * 100; // Simplified, should use actual XP curve
20
+
21
  onMount(() => {
22
  if (showIntro) {
23
  // Intro animation sequence
 
38
  });
39
  </script>
40
 
41
+ <div class="battle-field">
 
 
 
42
  <!-- Trainer intro image -->
43
  {#if showIntro && trainerVisible}
44
  <div class="trainer-intro" transition:fade={{ duration: 300 }}>
45
+ <img src="/assets/default_trainer.png" alt="Trainer" />
46
  </div>
47
  {/if}
48
 
49
+ <div class="battle-content">
50
+ <!-- Enemy Row -->
51
+ <div class="enemy-row">
52
+ <div class="enemy-stack">
53
+ <PicletInfo
54
+ piclet={enemyPiclet}
55
+ hpPercentage={enemyHpPercentage}
56
+ xpPercentage={0}
57
+ isPlayer={false}
58
+ />
59
+
60
+ {#if enemyVisible}
61
+ <div class="enemy-piclet-wrapper" transition:fade={{ duration: 300 }}>
62
+ <img
63
+ class="piclet-image enemy-image"
64
+ src={enemyPiclet.imageData || enemyPiclet.imageUrl}
65
+ alt={enemyPiclet.nickname}
66
+ on:error={(e) => e.currentTarget.src = 'https://via.placeholder.com/100x100?text=Piclet'}
67
+ />
68
+ <img
69
+ class="platform enemy-platform"
70
+ src="/assets/grass.PNG"
71
+ alt="Platform"
72
+ on:error={(e) => {
73
+ e.currentTarget.style.display = 'none';
74
+ e.currentTarget.nextElementSibling.style.display = 'block';
75
+ }}
76
+ />
77
+ <div class="platform-fallback enemy-platform-fallback" style="display: none;"></div>
78
+ </div>
79
+ {/if}
 
 
 
80
  </div>
81
+ </div>
82
 
83
+ <div class="spacer"></div>
84
+
85
+ <!-- Player Row -->
86
+ <div class="player-row">
87
+ <div class="player-stack">
88
+ {#if playerVisible}
89
+ <div class="player-piclet-wrapper" transition:fade={{ duration: 300 }}>
90
+ <img
91
+ class="piclet-image player-image"
92
+ src={playerPiclet.imageData || playerPiclet.imageUrl}
93
+ alt={playerPiclet.nickname}
94
+ on:error={(e) => e.currentTarget.src = 'https://via.placeholder.com/120x120?text=Piclet'}
95
+ />
96
+ <img
97
+ class="platform player-platform"
98
+ src="/assets/grass.PNG"
99
+ alt="Platform"
100
+ on:error={(e) => {
101
+ e.currentTarget.style.display = 'none';
102
+ e.currentTarget.nextElementSibling.style.display = 'block';
103
+ }}
104
+ />
105
+ <div class="platform-fallback player-platform-fallback" style="display: none;"></div>
106
+ </div>
107
+ {/if}
108
+
109
+ <PicletInfo
110
+ piclet={playerPiclet}
111
+ hpPercentage={playerHpPercentage}
112
+ xpPercentage={playerXpPercentage}
113
+ isPlayer={true}
114
+ />
115
+ </div>
116
+ </div>
117
  </div>
118
  </div>
119
 
 
121
  .battle-field {
122
  height: 280px;
123
  position: relative;
 
124
  overflow: hidden;
 
 
 
 
 
125
  background: repeating-linear-gradient(
126
+ to bottom,
127
+ rgba(76, 175, 80, 0.2) 0px,
128
+ rgba(76, 175, 80, 0.2) 5px,
129
+ rgba(76, 175, 80, 0.1) 5px,
130
+ rgba(76, 175, 80, 0.1) 10px
131
  );
 
 
132
  }
133
 
134
  .trainer-intro {
 
142
  .trainer-intro img {
143
  width: 200px;
144
  height: auto;
 
145
  }
146
 
147
+ .battle-content {
 
 
 
148
  display: flex;
149
  flex-direction: column;
150
+ height: 100%;
151
+ }
152
+
153
+ /* Enemy Row */
154
+ .enemy-row {
155
+ flex: 1;
156
+ position: relative;
157
  }
158
 
159
+ .enemy-stack {
160
  position: absolute;
161
+ top: 0;
162
+ right: 0;
163
+ left: 0;
164
+ bottom: 0;
 
 
165
  }
166
 
167
+ .enemy-piclet-wrapper {
168
+ position: absolute;
169
+ right: 40px;
170
+ top: 0;
 
 
171
  }
172
 
173
+ .enemy-image {
174
+ width: 100px;
175
+ height: 100px;
176
  object-fit: contain;
177
+ display: block;
 
178
  }
179
 
180
+ .enemy-platform {
181
+ width: 140px;
182
+ height: 80px;
183
+ position: absolute;
184
+ bottom: -20px;
185
+ left: -20px;
186
+ z-index: -1;
187
  }
188
 
189
+ /* Player Row */
190
+ .player-row {
191
+ height: 140px;
192
+ position: relative;
193
  }
194
 
195
+ .player-stack {
 
 
196
  position: relative;
197
+ width: 100%;
198
+ height: 100%;
 
199
  }
200
 
201
+ .player-piclet-wrapper {
202
+ position: absolute;
203
+ left: 40px;
204
+ bottom: 0;
 
 
 
 
205
  }
206
 
207
+ .player-image {
208
  width: 120px;
209
+ height: 120px;
210
+ object-fit: contain;
211
+ display: block;
212
  }
213
 
214
  .player-platform {
215
+ width: 160px;
216
+ height: 80px;
217
+ position: absolute;
218
+ bottom: -40px;
219
+ left: -20px;
220
+ z-index: -1;
221
+ }
222
+
223
+ /* Platform fallbacks */
224
+ .platform-fallback {
225
+ position: absolute;
226
+ background: rgba(76, 175, 80, 0.3);
227
+ border-radius: 50%;
228
+ }
229
+
230
+ .enemy-platform-fallback {
231
  width: 140px;
232
+ height: 80px;
233
+ bottom: -20px;
234
+ left: -20px;
235
+ }
236
+
237
+ .player-platform-fallback {
238
+ width: 160px;
239
+ height: 80px;
240
+ bottom: -40px;
241
+ left: -20px;
242
+ }
243
+
244
+ /* Piclet images */
245
+ .piclet-image {
246
+ image-rendering: auto;
247
+ filter: drop-shadow(-2px 0 4px rgba(0, 0, 0, 0.1));
248
+ }
249
+
250
+ .spacer {
251
+ flex: 1;
252
  }
253
 
254
  @media (max-width: 768px) {
255
+ .enemy-image {
 
 
 
 
 
256
  width: 80px;
257
  height: 80px;
258
  }
259
 
260
+ .player-image {
261
+ width: 100px;
262
+ height: 100px;
263
+ }
264
+
265
+ .enemy-piclet-wrapper {
266
+ right: 20px;
267
  }
268
 
269
+ .player-piclet-wrapper {
270
+ left: 20px;
 
271
  }
272
  }
273
  </style>
src/lib/components/Battle/PicletInfo.svelte CHANGED
@@ -3,122 +3,180 @@
3
 
4
  export let piclet: PicletInstance;
5
  export let hpPercentage: number;
 
6
  export let isPlayer: boolean;
7
 
8
- $: hpColor = hpPercentage > 0.5 ? '#4caf50' : hpPercentage > 0.25 ? '#ffc107' : '#f44336';
9
- $: displayHp = Math.max(0, Math.round(piclet.currentHp * hpPercentage));
 
 
 
10
  </script>
11
 
12
- <div class="piclet-info {isPlayer ? 'player-info' : 'enemy-info'}">
13
- <div class="info-header">
14
- <span class="piclet-name">{piclet.nickname}</span>
15
- <span class="piclet-level">Lv.{piclet.level}</span>
16
- </div>
17
-
18
- <div class="hp-container">
19
- <div class="hp-label">HP</div>
20
- <div class="hp-bar-wrapper">
21
- <div class="hp-bar-bg">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  <div
23
- class="hp-bar-fill"
24
- style="width: {hpPercentage * 100}%; background-color: {hpColor}"
25
  ></div>
26
  </div>
27
- </div>
28
  </div>
29
 
30
- {#if isPlayer}
31
- <div class="hp-text">
32
- {displayHp} / {piclet.maxHp}
33
- </div>
34
- {/if}
35
  </div>
36
 
37
  <style>
38
- .piclet-info {
39
- background: rgba(255, 255, 255, 0.95);
40
- border: 2px solid #333;
41
- border-radius: 8px;
42
- padding: 0.75rem 1rem;
43
- min-width: 200px;
44
- box-shadow: 0 2px 8px rgba(0,0,0,0.2);
 
 
 
45
  }
46
 
47
- .player-info {
48
- order: 2;
 
 
49
  }
50
 
51
- .enemy-info {
52
- order: 1;
 
 
 
53
  }
54
 
55
- .info-header {
 
56
  display: flex;
57
- justify-content: space-between;
58
  align-items: center;
59
- margin-bottom: 0.5rem;
 
60
  }
61
 
62
  .piclet-name {
63
  font-weight: 600;
64
- font-size: 1rem;
65
  color: #1a1a1a;
 
66
  }
67
 
68
- .piclet-level {
69
- font-size: 0.875rem;
70
- color: #666;
71
- }
72
-
73
- .hp-container {
74
- display: flex;
75
- align-items: center;
76
- gap: 0.5rem;
77
- }
78
-
79
- .hp-label {
80
- font-weight: 600;
81
- font-size: 0.75rem;
82
- color: #666;
83
  }
84
 
85
- .hp-bar-wrapper {
86
- flex: 1;
 
 
 
 
 
87
  }
88
 
89
- .hp-bar-bg {
 
 
90
  height: 8px;
91
  background: #e0e0e0;
92
  border-radius: 4px;
93
  overflow: hidden;
94
- position: relative;
95
  }
96
 
97
- .hp-bar-fill {
98
  height: 100%;
99
  transition: width 0.5s ease, background-color 0.3s ease;
100
- border-radius: 4px;
101
  }
102
 
 
103
  .hp-text {
104
- text-align: right;
105
- font-size: 0.75rem;
106
  color: #666;
107
- margin-top: 0.25rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
  @media (max-width: 768px) {
111
  .piclet-info {
112
- min-width: 150px;
113
- padding: 0.5rem 0.75rem;
114
  }
115
 
116
  .piclet-name {
117
- font-size: 0.875rem;
 
 
 
 
118
  }
119
 
120
- .piclet-level {
121
- font-size: 0.75rem;
122
  }
123
  }
124
  </style>
 
3
 
4
  export let piclet: PicletInstance;
5
  export let hpPercentage: number;
6
+ export let xpPercentage: number = 0;
7
  export let isPlayer: boolean;
8
 
9
+ $: hpColor = hpPercentage > 0.5 ? '#4caf50' : hpPercentage > 0.2 ? '#ffc107' : '#f44336';
10
+ $: displayHp = Math.ceil(piclet.currentHp * hpPercentage);
11
+
12
+ // Get type emoji (simplified - should map from actual types)
13
+ const typeEmoji = '🔥'; // Default fire type
14
  </script>
15
 
16
+ <div class="piclet-info-wrapper {isPlayer ? 'player-info-wrapper' : 'enemy-info-wrapper'}">
17
+ <div class="piclet-info">
18
+ <!-- Name Row -->
19
+ <div class="name-row">
20
+ <span class="piclet-name">{piclet.nickname}</span>
21
+ <span class="type-emoji">{typeEmoji}</span>
22
+ <span class="level-badge">Lv.{piclet.level}</span>
23
+ </div>
24
+
25
+ <!-- HP Bar -->
26
+ <div class="hp-bar">
27
+ <div
28
+ class="hp-fill"
29
+ style="width: {hpPercentage * 100}%; background-color: {hpColor}"
30
+ ></div>
31
+ </div>
32
+
33
+ <!-- HP Text (Player only) -->
34
+ {#if isPlayer}
35
+ <div class="hp-text">
36
+ {displayHp}/{piclet.maxHp}
37
+ </div>
38
+
39
+ <!-- XP Bar (Player only) -->
40
+ <div class="xp-bar">
41
  <div
42
+ class="xp-fill"
43
+ style="width: {xpPercentage}%"
44
  ></div>
45
  </div>
46
+ {/if}
47
  </div>
48
 
49
+ <!-- Triangle Pointer -->
50
+ <div class="triangle-pointer {isPlayer ? 'player-pointer' : 'enemy-pointer'}"></div>
 
 
 
51
  </div>
52
 
53
  <style>
54
+ .piclet-info-wrapper {
55
+ position: absolute;
56
+ display: flex;
57
+ align-items: center;
58
+ }
59
+
60
+ .player-info-wrapper {
61
+ right: 16px;
62
+ bottom: 20px;
63
+ flex-direction: row-reverse;
64
  }
65
 
66
+ .enemy-info-wrapper {
67
+ left: 16px;
68
+ top: 20px;
69
+ flex-direction: row;
70
  }
71
 
72
+ .piclet-info {
73
+ background: rgba(255, 255, 255, 0.9);
74
+ border-radius: 8px;
75
+ padding: 12px;
76
+ min-width: 160px;
77
  }
78
 
79
+ /* Name Row */
80
+ .name-row {
81
  display: flex;
 
82
  align-items: center;
83
+ gap: 4px;
84
+ margin-bottom: 8px;
85
  }
86
 
87
  .piclet-name {
88
  font-weight: 600;
89
+ font-size: 14px;
90
  color: #1a1a1a;
91
+ flex: 1;
92
  }
93
 
94
+ .type-emoji {
95
+ font-size: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
 
98
+ .level-badge {
99
+ background: rgba(142, 142, 147, 0.3);
100
+ padding: 2px 6px;
101
+ border-radius: 12px;
102
+ font-size: 11px;
103
+ font-weight: 700;
104
+ color: #333;
105
  }
106
 
107
+ /* HP Bar */
108
+ .hp-bar {
109
+ width: 120px;
110
  height: 8px;
111
  background: #e0e0e0;
112
  border-radius: 4px;
113
  overflow: hidden;
114
+ margin-bottom: 4px;
115
  }
116
 
117
+ .hp-fill {
118
  height: 100%;
119
  transition: width 0.5s ease, background-color 0.3s ease;
 
120
  }
121
 
122
+ /* HP Text */
123
  .hp-text {
124
+ font-size: 11px;
 
125
  color: #666;
126
+ text-align: right;
127
+ margin-bottom: 4px;
128
+ }
129
+
130
+ /* XP Bar */
131
+ .xp-bar {
132
+ width: 120px;
133
+ height: 4px;
134
+ background: #e0e0e0;
135
+ border-radius: 2px;
136
+ overflow: hidden;
137
+ }
138
+
139
+ .xp-fill {
140
+ height: 100%;
141
+ background: #2196f3;
142
+ transition: width 0.5s ease;
143
+ }
144
+
145
+ /* Triangle Pointer */
146
+ .triangle-pointer {
147
+ width: 0;
148
+ height: 0;
149
+ border-style: solid;
150
+ }
151
+
152
+ .player-pointer {
153
+ border-width: 8px 16px 8px 0;
154
+ border-color: transparent rgba(255, 255, 255, 0.9) transparent transparent;
155
+ margin-right: -1px;
156
+ }
157
+
158
+ .enemy-pointer {
159
+ border-width: 8px 0 8px 16px;
160
+ border-color: transparent transparent transparent rgba(255, 255, 255, 0.9);
161
+ margin-left: -1px;
162
  }
163
 
164
  @media (max-width: 768px) {
165
  .piclet-info {
166
+ min-width: 140px;
167
+ padding: 8px;
168
  }
169
 
170
  .piclet-name {
171
+ font-size: 12px;
172
+ }
173
+
174
+ .hp-bar {
175
+ width: 100px;
176
  }
177
 
178
+ .xp-bar {
179
+ width: 100px;
180
  }
181
  }
182
  </style>
src/lib/components/Pages/Battle.svelte CHANGED
@@ -166,14 +166,7 @@
166
  }
167
 
168
  .battle-nav {
169
- display: flex;
170
- align-items: center;
171
- justify-content: space-between;
172
- padding: 1rem;
173
- background: white;
174
- border-bottom: 1px solid #e0e0e0;
175
- position: relative;
176
- z-index: 10;
177
  }
178
 
179
  .back-button {
 
166
  }
167
 
168
  .battle-nav {
169
+ display: none; /* Hide navigation in battle */
 
 
 
 
 
 
 
170
  }
171
 
172
  .back-button {