OH GOT THE STATS AREN'T ACTUALLY STORED NOOOOOOOOO
Browse files- src/lib/db/index.ts +9 -0
- src/lib/db/piclets.ts +34 -12
- src/lib/db/schema.ts +3 -9
- src/lib/utils/battleConversion.ts +30 -49
src/lib/db/index.ts
CHANGED
@@ -39,6 +39,15 @@ export class PicletDatabase extends Dexie {
|
|
39 |
gameState: '++id, lastPlayed',
|
40 |
trainerScanProgress: 'imagePath, trainerName, status, completedAt'
|
41 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
}
|
43 |
}
|
44 |
|
|
|
39 |
gameState: '++id, lastPlayed',
|
40 |
trainerScanProgress: 'imagePath, trainerName, status, completedAt'
|
41 |
});
|
42 |
+
|
43 |
+
// Version 7: Move schema updated to include complete Move data (priority, flags, effects)
|
44 |
+
// No schema changes needed - just expanded interfaces, data will be preserved
|
45 |
+
this.version(7).stores({
|
46 |
+
picletInstances: '++id, typeId, nickname, isInRoster, rosterPosition, caughtAt',
|
47 |
+
encounters: '++id, type, createdAt',
|
48 |
+
gameState: '++id, lastPlayed',
|
49 |
+
trainerScanProgress: 'imagePath, trainerName, status, completedAt'
|
50 |
+
});
|
51 |
}
|
52 |
}
|
53 |
|
src/lib/db/piclets.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
import { db } from './index';
|
2 |
import type { PicletInstance, BattleMove } from './schema';
|
3 |
-
import { PicletType,
|
4 |
import type { PicletStats } from '../types';
|
|
|
5 |
import { generateUnlockLevels } from '../services/unlockLevels';
|
6 |
|
7 |
// Interface for generated piclet data (from PicletResult component)
|
@@ -36,28 +37,49 @@ export async function generatedDataToPicletInstance(data: GeneratedPicletData, l
|
|
36 |
const baseSpeed = Math.floor(stats.baseStats.speed * 1.5 + 30);
|
37 |
|
38 |
// Determine primary type from battle stats
|
39 |
-
const
|
40 |
-
const
|
41 |
-
const primaryType =
|
42 |
|
43 |
-
if (!
|
44 |
console.warn(`Invalid primaryType "${stats.primaryType}" from stats, falling back to concept detection`);
|
45 |
}
|
46 |
|
47 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
const baseMoves: BattleMove[] = stats.movepool.map(move => ({
|
49 |
name: move.name,
|
50 |
-
type: move.type as
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
const moves = movesWithUnlocks;
|
62 |
|
63 |
// Field stats are variations of regular stats
|
@@ -90,9 +112,9 @@ export async function generatedDataToPicletInstance(data: GeneratedPicletData, l
|
|
90 |
return {
|
91 |
// Type Info
|
92 |
typeId: data.name.toLowerCase().replace(/\s+/g, '-'),
|
93 |
-
nickname: data.name,
|
94 |
primaryType: primaryType,
|
95 |
-
secondaryType:
|
96 |
|
97 |
// Current Stats
|
98 |
currentHp: maxHp,
|
@@ -116,7 +138,7 @@ export async function generatedDataToPicletInstance(data: GeneratedPicletData, l
|
|
116 |
// Battle
|
117 |
moves,
|
118 |
nature: stats.nature,
|
119 |
-
specialAbility:
|
120 |
specialAbilityUnlockLevel: abilityUnlockLevel,
|
121 |
|
122 |
// Roster
|
|
|
1 |
import { db } from './index';
|
2 |
import type { PicletInstance, BattleMove } from './schema';
|
3 |
+
import { PicletType, getTypeFromConcept } from '../types/picletTypes';
|
4 |
import type { PicletStats } from '../types';
|
5 |
+
import type { Move as BattleEngineMove } from '../battle-engine/types';
|
6 |
import { generateUnlockLevels } from '../services/unlockLevels';
|
7 |
|
8 |
// Interface for generated piclet data (from PicletResult component)
|
|
|
37 |
const baseSpeed = Math.floor(stats.baseStats.speed * 1.5 + 30);
|
38 |
|
39 |
// Determine primary type from battle stats
|
40 |
+
const normalizedPrimaryType = stats.primaryType.toLowerCase();
|
41 |
+
const validPrimaryType = Object.values(PicletType).find(type => type === normalizedPrimaryType);
|
42 |
+
const primaryType = validPrimaryType || getTypeFromConcept(data.concept, data.imageCaption);
|
43 |
|
44 |
+
if (!validPrimaryType) {
|
45 |
console.warn(`Invalid primaryType "${stats.primaryType}" from stats, falling back to concept detection`);
|
46 |
}
|
47 |
|
48 |
+
// Handle secondary type
|
49 |
+
let secondaryType: PicletType | undefined = undefined;
|
50 |
+
if (stats.secondaryType && stats.secondaryType !== null) {
|
51 |
+
const normalizedSecondaryType = stats.secondaryType.toLowerCase();
|
52 |
+
const validSecondaryType = Object.values(PicletType).find(type => type === normalizedSecondaryType);
|
53 |
+
secondaryType = validSecondaryType;
|
54 |
+
if (!validSecondaryType) {
|
55 |
+
console.warn(`Invalid secondaryType "${stats.secondaryType}" from stats, ignoring`);
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
// Create moves from battle-ready format preserving all data
|
60 |
+
// Convert from PicletStats.BattleMove (loose types) to schema.BattleMove (strict types)
|
61 |
const baseMoves: BattleMove[] = stats.movepool.map(move => ({
|
62 |
name: move.name,
|
63 |
+
type: move.type as any, // Type conversion from string union to AttackType enum
|
64 |
power: move.power,
|
65 |
accuracy: move.accuracy,
|
66 |
pp: move.pp,
|
67 |
+
priority: move.priority,
|
68 |
+
flags: move.flags as any, // Type conversion from string[] to MoveFlag[]
|
69 |
+
effects: move.effects as any, // Type conversion between BattleEffect types
|
70 |
currentPp: move.pp,
|
|
|
71 |
unlockLevel: 1 // Temporary, will be set below
|
72 |
}));
|
73 |
|
74 |
// Generate unlock levels for moves and special ability
|
75 |
+
// Convert from PicletStats.SpecialAbility to battle-engine.SpecialAbility
|
76 |
+
const convertedSpecialAbility = {
|
77 |
+
name: stats.specialAbility.name,
|
78 |
+
description: stats.specialAbility.description,
|
79 |
+
effects: stats.specialAbility.effects as any,
|
80 |
+
triggers: stats.specialAbility.triggers as any
|
81 |
+
};
|
82 |
+
const { movesWithUnlocks, abilityUnlockLevel } = generateUnlockLevels(baseMoves, convertedSpecialAbility);
|
83 |
const moves = movesWithUnlocks;
|
84 |
|
85 |
// Field stats are variations of regular stats
|
|
|
112 |
return {
|
113 |
// Type Info
|
114 |
typeId: data.name.toLowerCase().replace(/\s+/g, '-'),
|
115 |
+
nickname: stats.name || data.name, // Use stats.name if available, fallback to data.name
|
116 |
primaryType: primaryType,
|
117 |
+
secondaryType: secondaryType,
|
118 |
|
119 |
// Current Stats
|
120 |
currentHp: maxHp,
|
|
|
138 |
// Battle
|
139 |
moves,
|
140 |
nature: stats.nature,
|
141 |
+
specialAbility: convertedSpecialAbility,
|
142 |
specialAbilityUnlockLevel: abilityUnlockLevel,
|
143 |
|
144 |
// Roster
|
src/lib/db/schema.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import type { PicletType, AttackType } from '../types/picletTypes';
|
2 |
-
import type { SpecialAbility } from '../battle-engine/types';
|
3 |
|
4 |
// Enums
|
5 |
export enum EncounterType {
|
@@ -10,15 +10,9 @@ export enum EncounterType {
|
|
10 |
FIRST_PICLET = 'firstPiclet'
|
11 |
}
|
12 |
|
13 |
-
// Battle Move
|
14 |
-
export interface BattleMove {
|
15 |
-
name: string;
|
16 |
-
type: AttackType;
|
17 |
-
power: number;
|
18 |
-
accuracy: number;
|
19 |
-
pp: number;
|
20 |
currentPp: number;
|
21 |
-
description: string;
|
22 |
unlockLevel: number; // Level at which this move is unlocked
|
23 |
}
|
24 |
|
|
|
1 |
import type { PicletType, AttackType } from '../types/picletTypes';
|
2 |
+
import type { SpecialAbility, Move } from '../battle-engine/types';
|
3 |
|
4 |
// Enums
|
5 |
export enum EncounterType {
|
|
|
10 |
FIRST_PICLET = 'firstPiclet'
|
11 |
}
|
12 |
|
13 |
+
// Battle Move with unlock level - extends the complete Move interface
|
14 |
+
export interface BattleMove extends Move {
|
|
|
|
|
|
|
|
|
|
|
15 |
currentPp: number;
|
|
|
16 |
unlockLevel: number; // Level at which this move is unlocked
|
17 |
}
|
18 |
|
src/lib/utils/battleConversion.ts
CHANGED
@@ -2,10 +2,10 @@
|
|
2 |
* Conversion utilities for transforming database types to battle engine types
|
3 |
*/
|
4 |
|
5 |
-
import type { PicletInstance
|
6 |
import type { PicletDefinition, Move, BaseStats, SpecialAbility } from '$lib/battle-engine/types';
|
7 |
-
import type { PicletStats
|
8 |
-
import { PicletType
|
9 |
import { recalculatePicletStats } from '$lib/services/levelingService';
|
10 |
import { getUnlockedMoves, isSpecialAbilityUnlocked } from '$lib/services/unlockLevels';
|
11 |
|
@@ -25,17 +25,35 @@ export function picletInstanceToBattleDefinition(instance: PicletInstance): Picl
|
|
25 |
speed: updatedInstance.speed // Includes level scaling and nature modifiers
|
26 |
};
|
27 |
|
28 |
-
// Only include unlocked moves
|
29 |
const unlockedMoves = getUnlockedMoves(instance.moves, updatedInstance.level);
|
30 |
-
const movepool: Move[] = unlockedMoves.map(move =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
// Ensure at least one move is available (first move should always be unlocked at level 1)
|
33 |
if (movepool.length === 0) {
|
34 |
console.warn(`Piclet ${instance.nickname} has no unlocked moves at level ${updatedInstance.level}!`);
|
35 |
// Emergency fallback - unlock first move
|
36 |
if (instance.moves.length > 0) {
|
37 |
-
const firstMove =
|
38 |
-
movepool.push(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
}
|
41 |
|
@@ -53,7 +71,6 @@ export function picletInstanceToBattleDefinition(instance: PicletInstance): Picl
|
|
53 |
specialAbility = {
|
54 |
name: "Locked Ability",
|
55 |
description: `Unlocks at level ${instance.specialAbilityUnlockLevel}`,
|
56 |
-
trigger: "onBattleStart" as any,
|
57 |
effects: []
|
58 |
};
|
59 |
}
|
@@ -74,47 +91,11 @@ export function picletInstanceToBattleDefinition(instance: PicletInstance): Picl
|
|
74 |
secondaryType: instance.secondaryType,
|
75 |
baseStats,
|
76 |
nature: instance.nature,
|
77 |
-
specialAbility
|
78 |
movepool
|
79 |
};
|
80 |
}
|
81 |
|
82 |
-
/**
|
83 |
-
* Convert BattleMove to full Move for battle engine
|
84 |
-
*/
|
85 |
-
function convertBattleMoveToMove(battleMove: BattleMove, primaryType: PicletType): Move {
|
86 |
-
// Create basic effects based on move properties
|
87 |
-
const effects: any[] = [];
|
88 |
-
|
89 |
-
if (battleMove.power > 0) {
|
90 |
-
effects.push({
|
91 |
-
type: 'damage',
|
92 |
-
target: 'opponent',
|
93 |
-
amount: battleMove.power >= 80 ? 'strong' :
|
94 |
-
battleMove.power >= 60 ? 'normal' : 'weak'
|
95 |
-
});
|
96 |
-
}
|
97 |
-
|
98 |
-
// Add status or stat effects for non-damaging moves
|
99 |
-
if (battleMove.power === 0) {
|
100 |
-
effects.push({
|
101 |
-
type: 'modifyStats',
|
102 |
-
target: 'self',
|
103 |
-
stats: { attack: 'increase' }
|
104 |
-
});
|
105 |
-
}
|
106 |
-
|
107 |
-
return {
|
108 |
-
name: battleMove.name,
|
109 |
-
type: battleMove.type,
|
110 |
-
power: battleMove.power,
|
111 |
-
accuracy: battleMove.accuracy,
|
112 |
-
pp: battleMove.pp,
|
113 |
-
priority: 0,
|
114 |
-
flags: battleMove.power > 0 && battleMove.name.toLowerCase().includes('tackle') ? ['contact'] : [],
|
115 |
-
effects
|
116 |
-
};
|
117 |
-
}
|
118 |
|
119 |
|
120 |
/**
|
@@ -144,12 +125,12 @@ export function picletStatsToBattleDefinition(stats: PicletStats, name: string,
|
|
144 |
name: stats.name || name,
|
145 |
description: stats.description || concept,
|
146 |
tier: stats.tier,
|
147 |
-
primaryType: stats.primaryType,
|
148 |
-
secondaryType: stats.secondaryType || undefined,
|
149 |
baseStats: stats.baseStats,
|
150 |
nature: stats.nature,
|
151 |
-
specialAbility: stats.specialAbility,
|
152 |
-
movepool: stats.movepool
|
153 |
};
|
154 |
}
|
155 |
|
|
|
2 |
* Conversion utilities for transforming database types to battle engine types
|
3 |
*/
|
4 |
|
5 |
+
import type { PicletInstance } from '$lib/db/schema';
|
6 |
import type { PicletDefinition, Move, BaseStats, SpecialAbility } from '$lib/battle-engine/types';
|
7 |
+
import type { PicletStats } from '$lib/types';
|
8 |
+
import { PicletType } from '$lib/types/picletTypes';
|
9 |
import { recalculatePicletStats } from '$lib/services/levelingService';
|
10 |
import { getUnlockedMoves, isSpecialAbilityUnlocked } from '$lib/services/unlockLevels';
|
11 |
|
|
|
25 |
speed: updatedInstance.speed // Includes level scaling and nature modifiers
|
26 |
};
|
27 |
|
28 |
+
// Only include unlocked moves - BattleMove now contains complete Move data
|
29 |
const unlockedMoves = getUnlockedMoves(instance.moves, updatedInstance.level);
|
30 |
+
const movepool: Move[] = unlockedMoves.map(move => ({
|
31 |
+
name: move.name,
|
32 |
+
type: move.type,
|
33 |
+
power: move.power,
|
34 |
+
accuracy: move.accuracy,
|
35 |
+
pp: move.pp,
|
36 |
+
priority: move.priority,
|
37 |
+
flags: move.flags,
|
38 |
+
effects: move.effects
|
39 |
+
}));
|
40 |
|
41 |
// Ensure at least one move is available (first move should always be unlocked at level 1)
|
42 |
if (movepool.length === 0) {
|
43 |
console.warn(`Piclet ${instance.nickname} has no unlocked moves at level ${updatedInstance.level}!`);
|
44 |
// Emergency fallback - unlock first move
|
45 |
if (instance.moves.length > 0) {
|
46 |
+
const firstMove = instance.moves[0];
|
47 |
+
movepool.push({
|
48 |
+
name: firstMove.name,
|
49 |
+
type: firstMove.type,
|
50 |
+
power: firstMove.power,
|
51 |
+
accuracy: firstMove.accuracy,
|
52 |
+
pp: firstMove.pp,
|
53 |
+
priority: firstMove.priority,
|
54 |
+
flags: firstMove.flags,
|
55 |
+
effects: firstMove.effects
|
56 |
+
});
|
57 |
}
|
58 |
}
|
59 |
|
|
|
71 |
specialAbility = {
|
72 |
name: "Locked Ability",
|
73 |
description: `Unlocks at level ${instance.specialAbilityUnlockLevel}`,
|
|
|
74 |
effects: []
|
75 |
};
|
76 |
}
|
|
|
91 |
secondaryType: instance.secondaryType,
|
92 |
baseStats,
|
93 |
nature: instance.nature,
|
94 |
+
specialAbility: specialAbility!,
|
95 |
movepool
|
96 |
};
|
97 |
}
|
98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
|
101 |
/**
|
|
|
125 |
name: stats.name || name,
|
126 |
description: stats.description || concept,
|
127 |
tier: stats.tier,
|
128 |
+
primaryType: stats.primaryType as PicletType,
|
129 |
+
secondaryType: stats.secondaryType as PicletType || undefined,
|
130 |
baseStats: stats.baseStats,
|
131 |
nature: stats.nature,
|
132 |
+
specialAbility: stats.specialAbility as any,
|
133 |
+
movepool: stats.movepool as any
|
134 |
};
|
135 |
}
|
136 |
|