Fraser commited on
Commit
8db63ba
·
1 Parent(s): 1f2c086
src/lib/components/Battle/BattleControls.svelte CHANGED
@@ -34,7 +34,7 @@
34
  <div class="action-area">
35
  {#if waitingForContinue}
36
  <!-- Tap to continue overlay -->
37
- <div class="tap-continue-overlay" role="button" tabindex="0" onclick={onContinueTap}>
38
  <div class="tap-indicator">
39
  <span>Tap to continue</span>
40
  </div>
 
34
  <div class="action-area">
35
  {#if waitingForContinue}
36
  <!-- Tap to continue overlay -->
37
+ <div class="tap-continue-overlay" role="button" tabindex="0" onclick={onContinueTap} onkeydown={(e) => e.key === 'Enter' || e.key === ' ' ? onContinueTap() : null}>
38
  <div class="tap-indicator">
39
  <span>Tap to continue</span>
40
  </div>
src/lib/components/PicletGenerator/PicletGenerator.svelte CHANGED
@@ -7,7 +7,7 @@
7
  import PicletResult from './PicletResult.svelte';
8
  import { removeBackground } from '$lib/utils/professionalImageProcessing';
9
  import { extractPicletMetadata } from '$lib/services/picletMetadata';
10
- import { savePicletInstance, monsterToPicletInstance } from '$lib/db/piclets';
11
  import { PicletType, TYPE_DATA } from '$lib/types/picletTypes';
12
  import { EncounterService } from '$lib/db/encounterService';
13
 
@@ -892,7 +892,7 @@ Write your response within \`\`\`json\`\`\``;
892
  console.log('- stats:', cleanStats);
893
 
894
  // Convert to PicletInstance format and save
895
- const picletInstance = await monsterToPicletInstance(picletData);
896
  const picletId = await savePicletInstance(picletInstance);
897
  console.log('Piclet auto-saved as uncaught with ID:', picletId);
898
 
 
7
  import PicletResult from './PicletResult.svelte';
8
  import { removeBackground } from '$lib/utils/professionalImageProcessing';
9
  import { extractPicletMetadata } from '$lib/services/picletMetadata';
10
+ import { savePicletInstance, generatedDataToPicletInstance } from '$lib/db/piclets';
11
  import { PicletType, TYPE_DATA } from '$lib/types/picletTypes';
12
  import { EncounterService } from '$lib/db/encounterService';
13
 
 
892
  console.log('- stats:', cleanStats);
893
 
894
  // Convert to PicletInstance format and save
895
+ const picletInstance = await generatedDataToPicletInstance(picletData);
896
  const picletId = await savePicletInstance(picletInstance);
897
  console.log('Piclet auto-saved as uncaught with ID:', picletId);
898
 
src/lib/components/PicletGenerator/PicletResult.svelte CHANGED
@@ -2,7 +2,7 @@
2
  import type { PicletWorkflowState } from '$lib/types';
3
  import type { PicletInstance } from '$lib/db/schema';
4
  import { TYPE_DATA, PicletType } from '$lib/types/picletTypes';
5
- import { monsterToPicletInstance } from '$lib/db/piclets';
6
  import PicletCard from '../Piclets/PicletCard.svelte';
7
  import PicletDetail from '../Piclets/PicletDetail.svelte';
8
 
@@ -34,7 +34,7 @@
34
  };
35
 
36
  // Create piclet instance asynchronously
37
- monsterToPicletInstance(picletData).then(instance => {
38
  picletInstance = { ...instance, id: 0 }; // Add temporary id for display
39
  }).catch(error => {
40
  console.error('Failed to create piclet instance:', error);
@@ -76,7 +76,7 @@
76
  {#if picletInstance}
77
  <div class="piclet-preview">
78
  <PicletCard
79
- instance={picletInstance}
80
  size={140}
81
  onClick={handleCardClick}
82
  />
 
2
  import type { PicletWorkflowState } from '$lib/types';
3
  import type { PicletInstance } from '$lib/db/schema';
4
  import { TYPE_DATA, PicletType } from '$lib/types/picletTypes';
5
+ import { generatedDataToPicletInstance } from '$lib/db/piclets';
6
  import PicletCard from '../Piclets/PicletCard.svelte';
7
  import PicletDetail from '../Piclets/PicletDetail.svelte';
8
 
 
34
  };
35
 
36
  // Create piclet instance asynchronously
37
+ generatedDataToPicletInstance(picletData).then(instance => {
38
  picletInstance = { ...instance, id: 0 }; // Add temporary id for display
39
  }).catch(error => {
40
  console.error('Failed to create piclet instance:', error);
 
76
  {#if picletInstance}
77
  <div class="piclet-preview">
78
  <PicletCard
79
+ piclet={picletInstance}
80
  size={140}
81
  onClick={handleCardClick}
82
  />
src/lib/components/Piclets/NewlyCaughtPicletDetail.svelte CHANGED
@@ -62,12 +62,12 @@
62
  }
63
  </script>
64
 
65
- <div class="detail-overlay" role="dialog" aria-modal="true" tabindex="-1" onclick={onClose}>
66
  <div class="detail-container newly-caught" role="document" onclick={handleContainerClick}>
67
 
68
  <!-- Celebration overlay -->
69
  {#if showCelebration}
70
- <div class="celebration-overlay" role="button" tabindex="0" onclick={dismissCelebration}>
71
  <div class="celebration-content">
72
  <div class="celebration-sparkles">✨</div>
73
  <h1 class="celebration-title">Welcome to your team!</h1>
 
62
  }
63
  </script>
64
 
65
+ <div class="detail-overlay" role="dialog" aria-modal="true" tabindex="-1" onclick={onClose} onkeydown={(e) => e.key === 'Escape' ? onClose() : null}>
66
  <div class="detail-container newly-caught" role="document" onclick={handleContainerClick}>
67
 
68
  <!-- Celebration overlay -->
69
  {#if showCelebration}
70
+ <div class="celebration-overlay" role="button" tabindex="0" onclick={dismissCelebration} onkeydown={(e) => e.key === 'Enter' || e.key === ' ' ? dismissCelebration() : null}>
71
  <div class="celebration-content">
72
  <div class="celebration-sparkles">✨</div>
73
  <h1 class="celebration-title">Welcome to your team!</h1>
src/lib/db/piclets.ts CHANGED
@@ -4,6 +4,139 @@ import { PicletType, AttackType, getTypeFromConcept } from '../types/picletTypes
4
  import type { PicletStats } from '../types';
5
  import { generateUnlockLevels } from '../services/unlockLevels';
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  // Save a new PicletInstance
9
  export async function savePicletInstance(piclet: Omit<PicletInstance, 'id'>): Promise<number> {
 
4
  import type { PicletStats } from '../types';
5
  import { generateUnlockLevels } from '../services/unlockLevels';
6
 
7
+ // Interface for generated piclet data (from PicletResult component)
8
+ interface GeneratedPicletData {
9
+ name: string;
10
+ imageUrl: string;
11
+ imageData?: string;
12
+ imageCaption: string;
13
+ concept: string;
14
+ imagePrompt: string;
15
+ stats: PicletStats;
16
+ createdAt: Date;
17
+ }
18
+
19
+ // Convert generated piclet data to a PicletInstance
20
+ export async function generatedDataToPicletInstance(data: GeneratedPicletData, level: number = 5): Promise<Omit<PicletInstance, 'id'>> {
21
+ if (!data.stats) {
22
+ throw new Error('Generated data must have stats to create PicletInstance');
23
+ }
24
+
25
+ // All generated data must now have the battle-ready format
26
+ const stats = data.stats as PicletStats;
27
+
28
+ if (!stats.baseStats || !stats.specialAbility || !stats.movepool) {
29
+ throw new Error('Generated stats must be in battle-ready format with baseStats, specialAbility, and movepool');
30
+ }
31
+
32
+ // Calculate base stats from battle-ready format
33
+ const baseHp = Math.floor(stats.baseStats.hp * 2 + 50);
34
+ const baseAttack = Math.floor(stats.baseStats.attack * 1.5 + 30);
35
+ const baseDefense = Math.floor(stats.baseStats.defense * 1.5 + 30);
36
+ const baseSpeed = Math.floor(stats.baseStats.speed * 1.5 + 30);
37
+
38
+ // Determine primary type from battle stats
39
+ const normalizedType = stats.primaryType.toLowerCase();
40
+ const validType = Object.values(PicletType).find(type => type === normalizedType);
41
+ const primaryType = validType || getTypeFromConcept(data.concept, data.imageCaption);
42
+
43
+ if (!validType) {
44
+ console.warn(`Invalid primaryType "${stats.primaryType}" from stats, falling back to concept detection`);
45
+ }
46
+
47
+ // Create moves from battle-ready format (without unlock levels initially)
48
+ const baseMoves: BattleMove[] = stats.movepool.map(move => ({
49
+ name: move.name,
50
+ type: move.type as unknown as AttackType,
51
+ power: move.power,
52
+ accuracy: move.accuracy,
53
+ pp: move.pp,
54
+ currentPp: move.pp,
55
+ description: move.description,
56
+ unlockLevel: 1 // Temporary, will be set below
57
+ }));
58
+
59
+ // Generate unlock levels for moves and special ability
60
+ const { movesWithUnlocks, abilityUnlockLevel } = generateUnlockLevels(baseMoves, stats.specialAbility);
61
+ const moves = movesWithUnlocks;
62
+
63
+ // Field stats are variations of regular stats
64
+ const baseFieldAttack = Math.floor(baseAttack * 0.8);
65
+ const baseFieldDefense = Math.floor(baseDefense * 0.8);
66
+
67
+ // Use Pokemon-accurate stat calculations (matching levelingService)
68
+ const calculateStat = (base: number, level: number) => {
69
+ if (level === 1) {
70
+ return Math.max(1, Math.floor(base / 10) + 5);
71
+ }
72
+ return Math.floor((2 * base * level) / 100) + 5;
73
+ };
74
+
75
+ const calculateHp = (base: number, level: number) => {
76
+ if (level === 1) {
77
+ return Math.max(1, Math.floor(base / 10) + 11);
78
+ }
79
+ return Math.floor((2 * base * level) / 100) + level + 10;
80
+ };
81
+
82
+ const maxHp = calculateHp(baseHp, level);
83
+
84
+ const bst = baseHp + baseAttack + baseDefense + baseFieldAttack + baseFieldDefense + baseSpeed;
85
+
86
+ return {
87
+ // Type Info
88
+ typeId: data.name.toLowerCase().replace(/\s+/g, '-'),
89
+ nickname: data.name,
90
+ primaryType: primaryType,
91
+ secondaryType: undefined,
92
+
93
+ // Current Stats
94
+ currentHp: maxHp,
95
+ maxHp,
96
+ level,
97
+ xp: 0,
98
+ attack: calculateStat(baseAttack, level),
99
+ defense: calculateStat(baseDefense, level),
100
+ fieldAttack: calculateStat(baseFieldAttack, level),
101
+ fieldDefense: calculateStat(baseFieldDefense, level),
102
+ speed: calculateStat(baseSpeed, level),
103
+
104
+ // Base Stats
105
+ baseHp,
106
+ baseAttack,
107
+ baseDefense,
108
+ baseFieldAttack,
109
+ baseFieldDefense,
110
+ baseSpeed,
111
+
112
+ // Battle
113
+ moves,
114
+ nature: stats.nature,
115
+ specialAbility: stats.specialAbility,
116
+ specialAbilityUnlockLevel: abilityUnlockLevel,
117
+
118
+ // Roster
119
+ isInRoster: false,
120
+ rosterPosition: undefined,
121
+
122
+ // Metadata
123
+ caught: false, // Scanned Piclets start as uncaught
124
+ caughtAt: undefined, // Will be set when caught
125
+ bst,
126
+ tier: stats.tier, // Use tier from stats
127
+ role: 'balanced', // Could be enhanced based on stat distribution
128
+ variance: 0,
129
+
130
+ // Original generation data
131
+ imageUrl: data.imageUrl,
132
+ imageData: data.imageData,
133
+ imageCaption: data.imageCaption,
134
+ concept: data.concept,
135
+ description: stats.description,
136
+ imagePrompt: data.imagePrompt
137
+ };
138
+ }
139
+
140
 
141
  // Save a new PicletInstance
142
  export async function savePicletInstance(piclet: Omit<PicletInstance, 'id'>): Promise<number> {