Fraser commited on
Commit
23a36f6
·
1 Parent(s): 853c228

rm db monsters

Browse files
src/lib/components/Pages/Encounters.svelte CHANGED
@@ -29,39 +29,32 @@
29
  async function loadEncounters() {
30
  isLoading = true;
31
  try {
32
- // Check if we have discovered monsters first
33
- const discoveredMonsters = await db.monsters.toArray();
34
  const playerPiclets = await db.picletInstances.toArray();
35
 
36
- if (discoveredMonsters.length === 0) {
37
- // No monsters discovered - show empty state
38
  encounters = [];
39
  isLoading = false;
40
  return;
41
  }
42
 
43
- if (playerPiclets.length === 0) {
44
- // First catch scenario - generate first catch encounter only
45
- console.log('First catch scenario - generating first catch encounter');
46
- encounters = await EncounterService.generateEncounters();
47
- } else {
48
- // Player has piclets - always generate fresh encounters with wild piclets
49
- console.log('Player has piclets - generating fresh encounters with wild piclets');
50
- await EncounterService.forceEncounterRefresh();
51
- encounters = await EncounterService.generateEncounters();
52
- }
53
 
54
  console.log('Final encounters:', encounters.map(e => ({ type: e.type, title: e.title })));
55
 
56
- // Load monster images for wild piclet encounters
57
- await loadMonsterImages();
58
  } catch (error) {
59
  console.error('Error loading encounters:', error);
60
  }
61
  isLoading = false;
62
  }
63
 
64
- async function loadMonsterImages() {
65
  const wildEncounters = encounters.filter(e =>
66
  e.type === EncounterType.WILD_PICLET && e.picletTypeId
67
  );
@@ -69,18 +62,14 @@
69
  for (const encounter of wildEncounters) {
70
  if (!encounter.picletTypeId) continue;
71
 
72
- // Convert picletTypeId to monster name format
73
- const monsterName = encounter.picletTypeId
74
- .replace(/-/g, ' ')
75
- .replace(/\b\w/g, l => l.toUpperCase());
76
-
77
- const monster = await db.monsters
78
- .where('name')
79
- .equals(monsterName)
80
  .first();
81
 
82
- if (monster && monster.imageData) {
83
- monsterImages.set(encounter.picletTypeId, monster.imageData);
84
  }
85
  }
86
  // Trigger reactive update
@@ -94,8 +83,8 @@
94
  console.log('Force refreshing encounters...');
95
  encounters = await EncounterService.generateEncounters();
96
 
97
- // Load monster images for new encounters
98
- await loadMonsterImages();
99
 
100
  // Update game state with new refresh time
101
  const gameState = await getOrCreateGameState();
@@ -167,7 +156,7 @@
167
  try {
168
  await EncounterService.forceEncounterRefresh();
169
  encounters = await EncounterService.generateEncounters();
170
- await loadMonsterImages();
171
  } catch (error) {
172
  console.error('Error refreshing encounters:', error);
173
  }
@@ -253,111 +242,49 @@
253
  async function generateEnemyPiclet(encounter: Encounter): Promise<PicletInstance | null> {
254
  if (!encounter.picletTypeId || !encounter.enemyLevel) return null;
255
 
256
- // Get the discovered monster data for this piclet type
257
- const monster = await db.monsters
258
- .where('name')
259
- .equals(encounter.picletTypeId.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()))
260
  .first();
261
 
262
- if (!monster || !monster.stats) {
263
- console.error('Monster not found for typeId:', encounter.picletTypeId);
264
  return null;
265
  }
266
 
267
- // Calculate stats based on monster's base stats and encounter level
268
  const level = encounter.enemyLevel;
269
- const stats = monster.stats;
270
-
271
- // Calculate base stats from the 0-100 scale
272
- const baseHp = Math.floor(stats.HP * 2 + 50);
273
- const baseAttack = Math.floor(stats.attack * 1.5 + 30);
274
- const baseDefense = Math.floor(stats.defence * 1.5 + 30);
275
- const baseSpeed = Math.floor(stats.speed * 1.5 + 30);
276
- const baseFieldAttack = Math.floor(baseAttack * 0.8);
277
- const baseFieldDefense = Math.floor(baseDefense * 0.8);
278
 
279
- // Calculate current stats based on level
280
  const calculateStat = (base: number, level: number) => Math.floor((base * level) / 50 + 5);
281
  const calculateHp = (base: number, level: number) => Math.floor((base * level) / 50 + level + 10);
282
 
283
- const maxHp = calculateHp(baseHp, level);
284
 
285
- // Create enemy piclet instance
286
  const enemyPiclet: PicletInstance = {
 
287
  id: -1, // Temporary ID for enemy
288
- typeId: encounter.picletTypeId,
289
- nickname: monster.name,
290
- primaryType: 'beast' as any, // Default type
291
 
292
  level: level,
293
  xp: 0,
294
  currentHp: maxHp,
295
  maxHp: maxHp,
296
- attack: calculateStat(baseAttack, level),
297
- defense: calculateStat(baseDefense, level),
298
- fieldAttack: calculateStat(baseFieldAttack, level),
299
- fieldDefense: calculateStat(baseFieldDefense, level),
300
- speed: calculateStat(baseSpeed, level),
301
 
302
- baseHp,
303
- baseAttack,
304
- baseDefense,
305
- baseFieldAttack,
306
- baseFieldDefense,
307
- baseSpeed,
308
-
309
- moves: [
310
- {
311
- name: stats.attackActionName,
312
- type: 'normal' as any,
313
- power: 50,
314
- accuracy: 95,
315
- pp: 20,
316
- currentPp: 20,
317
- description: stats.attackActionDescription
318
- },
319
- {
320
- name: stats.buffActionName,
321
- type: 'normal' as any,
322
- power: 0,
323
- accuracy: 100,
324
- pp: 15,
325
- currentPp: 15,
326
- description: stats.buffActionDescription
327
- },
328
- {
329
- name: stats.debuffActionName,
330
- type: 'normal' as any,
331
- power: 0,
332
- accuracy: 85,
333
- pp: 15,
334
- currentPp: 15,
335
- description: stats.debuffActionDescription
336
- },
337
- {
338
- name: stats.specialActionName,
339
- type: 'normal' as any,
340
- power: 80,
341
- accuracy: 90,
342
- pp: 5,
343
- currentPp: 5,
344
- description: stats.specialActionDescription
345
- }
346
- ],
347
- nature: 'hardy',
348
 
349
  isInRoster: false,
350
- caughtAt: new Date(),
351
- bst: baseHp + baseAttack + baseDefense + baseFieldAttack + baseFieldDefense + baseSpeed,
352
- tier: (stats as any).tier || 'medium',
353
- role: 'balanced',
354
- variance: 0,
355
-
356
- imageUrl: monster.imageUrl,
357
- imageData: monster.imageData, // Use the transparent image data
358
- imageCaption: monster.imageCaption,
359
- concept: monster.concept,
360
- imagePrompt: monster.imagePrompt
361
  };
362
 
363
  return enemyPiclet;
 
29
  async function loadEncounters() {
30
  isLoading = true;
31
  try {
32
+ // Check if we have any piclet instances
 
33
  const playerPiclets = await db.picletInstances.toArray();
34
 
35
+ if (playerPiclets.length === 0) {
36
+ // No piclets discovered/caught - show empty state
37
  encounters = [];
38
  isLoading = false;
39
  return;
40
  }
41
 
42
+ // Player has piclets - always generate fresh encounters with wild piclets
43
+ console.log('Player has piclets - generating fresh encounters with wild piclets');
44
+ await EncounterService.forceEncounterRefresh();
45
+ encounters = await EncounterService.generateEncounters();
 
 
 
 
 
 
46
 
47
  console.log('Final encounters:', encounters.map(e => ({ type: e.type, title: e.title })));
48
 
49
+ // Load piclet images for wild encounters
50
+ await loadPicletImages();
51
  } catch (error) {
52
  console.error('Error loading encounters:', error);
53
  }
54
  isLoading = false;
55
  }
56
 
57
+ async function loadPicletImages() {
58
  const wildEncounters = encounters.filter(e =>
59
  e.type === EncounterType.WILD_PICLET && e.picletTypeId
60
  );
 
62
  for (const encounter of wildEncounters) {
63
  if (!encounter.picletTypeId) continue;
64
 
65
+ // Find a piclet instance with this typeId
66
+ const piclet = await db.picletInstances
67
+ .where('typeId')
68
+ .equals(encounter.picletTypeId)
 
 
 
 
69
  .first();
70
 
71
+ if (piclet && piclet.imageData) {
72
+ monsterImages.set(encounter.picletTypeId, piclet.imageData);
73
  }
74
  }
75
  // Trigger reactive update
 
83
  console.log('Force refreshing encounters...');
84
  encounters = await EncounterService.generateEncounters();
85
 
86
+ // Load piclet images for new encounters
87
+ await loadPicletImages();
88
 
89
  // Update game state with new refresh time
90
  const gameState = await getOrCreateGameState();
 
156
  try {
157
  await EncounterService.forceEncounterRefresh();
158
  encounters = await EncounterService.generateEncounters();
159
+ await loadPicletImages();
160
  } catch (error) {
161
  console.error('Error refreshing encounters:', error);
162
  }
 
242
  async function generateEnemyPiclet(encounter: Encounter): Promise<PicletInstance | null> {
243
  if (!encounter.picletTypeId || !encounter.enemyLevel) return null;
244
 
245
+ // Get a piclet instance with this typeId to use as a template
246
+ const templatePiclet = await db.picletInstances
247
+ .where('typeId')
248
+ .equals(encounter.picletTypeId)
249
  .first();
250
 
251
+ if (!templatePiclet) {
252
+ console.error('Piclet template not found for typeId:', encounter.picletTypeId);
253
  return null;
254
  }
255
 
256
+ // Calculate stats based on template's base stats and encounter level
257
  const level = encounter.enemyLevel;
 
 
 
 
 
 
 
 
 
258
 
259
+ // Calculate current stats based on level (using template's base stats)
260
  const calculateStat = (base: number, level: number) => Math.floor((base * level) / 50 + 5);
261
  const calculateHp = (base: number, level: number) => Math.floor((base * level) / 50 + level + 10);
262
 
263
+ const maxHp = calculateHp(templatePiclet.baseHp, level);
264
 
265
+ // Create enemy piclet instance based on template
266
  const enemyPiclet: PicletInstance = {
267
+ ...templatePiclet,
268
  id: -1, // Temporary ID for enemy
 
 
 
269
 
270
  level: level,
271
  xp: 0,
272
  currentHp: maxHp,
273
  maxHp: maxHp,
274
+ attack: calculateStat(templatePiclet.baseAttack, level),
275
+ defense: calculateStat(templatePiclet.baseDefense, level),
276
+ fieldAttack: calculateStat(templatePiclet.baseFieldAttack, level),
277
+ fieldDefense: calculateStat(templatePiclet.baseFieldDefense, level),
278
+ speed: calculateStat(templatePiclet.baseSpeed, level),
279
 
280
+ // Reset move PP to full
281
+ moves: templatePiclet.moves.map(move => ({
282
+ ...move,
283
+ currentPp: move.pp
284
+ })),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
  isInRoster: false,
287
+ caughtAt: new Date()
 
 
 
 
 
 
 
 
 
 
288
  };
289
 
290
  return enemyPiclet;
src/lib/components/PicletGenerator/PicletGenerator.svelte CHANGED
@@ -892,8 +892,8 @@ Write your response within \`\`\`json\`\`\``;
892
 
893
  // Convert to PicletInstance format and save
894
  const picletInstance = await monsterToPicletInstance(picletData);
895
- const id = await savePicletInstance(picletInstance);
896
- console.log('Piclet auto-saved with ID:', id);
897
  } catch (err) {
898
  console.error('Failed to auto-save piclet:', err);
899
  console.error('Piclet data that failed to save:', {
 
892
 
893
  // Convert to PicletInstance format and save
894
  const picletInstance = await monsterToPicletInstance(picletData);
895
+ const picletId = await savePicletInstance(picletInstance);
896
+ console.log('Piclet auto-saved with ID:', picletId);
897
  } catch (err) {
898
  console.error('Failed to auto-save piclet:', err);
899
  console.error('Piclet data that failed to save:', {
src/lib/db/encounterService.ts CHANGED
@@ -44,34 +44,12 @@ export class EncounterService {
44
  const playerPiclets = await db.picletInstances.toArray();
45
 
46
  if (playerPiclets.length === 0) {
47
- // No piclets caught yet - check for discovered piclets
48
- // For now, we'll check the monsters collection as a proxy for discovered piclets
49
- // In a real app, this would check a remote database for piclets discovered by scanning
50
- const discoveredPiclets = await db.monsters.toArray();
51
-
52
- if (discoveredPiclets.length === 0) {
53
- // No piclets discovered yet - return empty encounters
54
- await db.encounters.clear();
55
- await markEncountersRefreshed();
56
- return [];
57
- }
58
-
59
- // Player has discovered but not caught any piclets - show ONLY first catch encounter
60
- const firstDiscovered = discoveredPiclets[0];
61
- encounters.push({
62
- type: EncounterType.WILD_PICLET,
63
- title: 'Your First Piclet!',
64
- description: 'A friendly piclet appears! This one seems easy to catch.',
65
- picletTypeId: firstDiscovered.name.toLowerCase().replace(/\s+/g, '-'),
66
- enemyLevel: 5,
67
- createdAt: new Date()
68
- });
69
-
70
- // IMPORTANT: Return here - don't add shop/health center for first catch
71
  await db.encounters.clear();
72
- await db.encounters.add(encounters[0]);
73
  await markEncountersRefreshed();
74
- return await this.getCurrentEncounters();
75
  }
76
 
77
  // Player has piclets - generate normal encounters
@@ -128,34 +106,37 @@ export class EncounterService {
128
  // Get player's average level
129
  const avgLevel = await this.getPlayerAverageLevel();
130
 
131
- // Get all discovered monsters
132
- const discoveredMonsters = await db.monsters.toArray();
133
- console.log('Discovered monsters for wild encounters:', discoveredMonsters.length);
134
 
135
- if (discoveredMonsters.length === 0) {
136
- console.log('No discovered monsters - returning empty wild encounters');
137
  return encounters;
138
  }
139
 
140
- // Always allow catching duplicates for more encounters
141
- const availableMonsters = discoveredMonsters;
142
- console.log('Available monsters for encounters:', availableMonsters.map(m => m.name));
143
 
144
  const encounterCount = MIN_WILD_ENCOUNTERS + Math.floor(Math.random() * (MAX_WILD_ENCOUNTERS - MIN_WILD_ENCOUNTERS + 1));
145
  console.log('Generating', encounterCount, 'wild encounters');
146
 
147
  for (let i = 0; i < encounterCount; i++) {
148
- // Pick a random monster from discovered ones
149
- const monster = availableMonsters[Math.floor(Math.random() * availableMonsters.length)];
150
 
151
  const levelVariance = Math.floor(Math.random() * (LEVEL_VARIANCE * 2 + 1)) - LEVEL_VARIANCE;
152
  const enemyLevel = Math.max(1, avgLevel + levelVariance);
153
 
 
 
 
154
  const wildEncounter = {
155
  type: EncounterType.WILD_PICLET,
156
- title: `Wild ${monster.name} Appeared!`,
157
- description: `A level ${enemyLevel} ${monster.name} blocks your path!`,
158
- picletTypeId: monster.name.toLowerCase().replace(/\s+/g, '-'),
159
  enemyLevel,
160
  createdAt: new Date()
161
  };
@@ -187,35 +168,60 @@ export class EncounterService {
187
  return Math.round(totalLevel / rosterPiclets.length);
188
  }
189
 
190
- // Catch a wild piclet (for first encounter)
191
  static async catchWildPiclet(encounter: Encounter): Promise<PicletInstance> {
192
  if (!encounter.picletTypeId) throw new Error('No piclet type specified');
193
 
194
- // Import the conversion function
195
- const { monsterToPicletInstance } = await import('./piclets');
196
-
197
- // Get the monster data by name (typeId is the lowercase hyphenated name)
198
- const monsterName = encounter.picletTypeId.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
199
- const monster = await db.monsters
200
- .where('name')
201
- .equals(monsterName)
202
  .first();
203
 
204
- if (!monster) {
205
- throw new Error(`Monster not found: ${monsterName}`);
206
  }
207
 
208
- // Convert monster to piclet instance
209
- const picletData = await monsterToPicletInstance(monster, encounter.enemyLevel || 5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
  // Set roster position 0 if this is the first piclet
212
  const existingPiclets = await db.picletInstances.toArray();
213
- if (existingPiclets.length === 0) {
214
- picletData.rosterPosition = 0;
 
215
  }
216
 
217
  // Save the new piclet
218
- const id = await db.picletInstances.add(picletData);
219
- return { ...picletData, id };
220
  }
221
  }
 
44
  const playerPiclets = await db.picletInstances.toArray();
45
 
46
  if (playerPiclets.length === 0) {
47
+ // No piclets caught yet - this shouldn't happen in normal flow since we use picletInstances
48
+ // But just in case, return empty encounters
49
+ console.log('No piclet instances found - returning empty encounters');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  await db.encounters.clear();
 
51
  await markEncountersRefreshed();
52
+ return [];
53
  }
54
 
55
  // Player has piclets - generate normal encounters
 
106
  // Get player's average level
107
  const avgLevel = await this.getPlayerAverageLevel();
108
 
109
+ // Get all piclet instances (these represent "discovered" piclets)
110
+ const allPiclets = await db.picletInstances.toArray();
111
+ console.log('Total piclet instances for wild encounters:', allPiclets.length);
112
 
113
+ if (allPiclets.length === 0) {
114
+ console.log('No piclet instances - returning empty wild encounters');
115
  return encounters;
116
  }
117
 
118
+ // Get unique piclet types for encounters (allow duplicates)
119
+ const availablePiclets = allPiclets;
120
+ console.log('Available piclets for encounters:', availablePiclets.map(p => p.typeId));
121
 
122
  const encounterCount = MIN_WILD_ENCOUNTERS + Math.floor(Math.random() * (MAX_WILD_ENCOUNTERS - MIN_WILD_ENCOUNTERS + 1));
123
  console.log('Generating', encounterCount, 'wild encounters');
124
 
125
  for (let i = 0; i < encounterCount; i++) {
126
+ // Pick a random piclet from available ones
127
+ const piclet = availablePiclets[Math.floor(Math.random() * availablePiclets.length)];
128
 
129
  const levelVariance = Math.floor(Math.random() * (LEVEL_VARIANCE * 2 + 1)) - LEVEL_VARIANCE;
130
  const enemyLevel = Math.max(1, avgLevel + levelVariance);
131
 
132
+ // Use the piclet's nickname or typeId for display
133
+ const displayName = piclet.nickname || piclet.typeId.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
134
+
135
  const wildEncounter = {
136
  type: EncounterType.WILD_PICLET,
137
+ title: `Wild ${displayName} Appeared!`,
138
+ description: `A level ${enemyLevel} ${displayName} blocks your path!`,
139
+ picletTypeId: piclet.typeId,
140
  enemyLevel,
141
  createdAt: new Date()
142
  };
 
168
  return Math.round(totalLevel / rosterPiclets.length);
169
  }
170
 
171
+ // Catch a wild piclet (creates a new instance based on existing piclet type)
172
  static async catchWildPiclet(encounter: Encounter): Promise<PicletInstance> {
173
  if (!encounter.picletTypeId) throw new Error('No piclet type specified');
174
 
175
+ // Find an existing piclet instance with this typeId to use as a template
176
+ const templatePiclet = await db.picletInstances
177
+ .where('typeId')
178
+ .equals(encounter.picletTypeId)
 
 
 
 
179
  .first();
180
 
181
+ if (!templatePiclet) {
182
+ throw new Error(`Piclet type not found: ${encounter.picletTypeId}`);
183
  }
184
 
185
+ // Create a new piclet instance based on the template but with different stats/level
186
+ const newLevel = encounter.enemyLevel || 5;
187
+
188
+ // Calculate new stats based on level (using template's base stats)
189
+ const calculateStat = (base: number, level: number) => Math.floor((base * level) / 50 + 5);
190
+ const calculateHp = (base: number, level: number) => Math.floor((base * level) / 50 + level + 10);
191
+
192
+ const newPiclet: Omit<PicletInstance, 'id'> = {
193
+ ...templatePiclet,
194
+ level: newLevel,
195
+ xp: 0,
196
+ currentHp: calculateHp(templatePiclet.baseHp, newLevel),
197
+ maxHp: calculateHp(templatePiclet.baseHp, newLevel),
198
+ attack: calculateStat(templatePiclet.baseAttack, newLevel),
199
+ defense: calculateStat(templatePiclet.baseDefense, newLevel),
200
+ fieldAttack: calculateStat(templatePiclet.baseFieldAttack, newLevel),
201
+ fieldDefense: calculateStat(templatePiclet.baseFieldDefense, newLevel),
202
+ speed: calculateStat(templatePiclet.baseSpeed, newLevel),
203
+
204
+ // Reset move PP to full
205
+ moves: templatePiclet.moves.map(move => ({
206
+ ...move,
207
+ currentPp: move.pp
208
+ })),
209
+
210
+ // Clear roster info for wild catch
211
+ isInRoster: false,
212
+ rosterPosition: undefined,
213
+ caughtAt: new Date()
214
+ };
215
 
216
  // Set roster position 0 if this is the first piclet
217
  const existingPiclets = await db.picletInstances.toArray();
218
+ if (existingPiclets.length === 1) { // Only the template exists
219
+ newPiclet.rosterPosition = 0;
220
+ newPiclet.isInRoster = true;
221
  }
222
 
223
  // Save the new piclet
224
+ const id = await db.picletInstances.add(newPiclet);
225
+ return { ...newPiclet, id };
226
  }
227
  }