better first enc
Browse files
src/lib/components/Pages/Encounters.svelte
CHANGED
@@ -103,26 +103,7 @@
|
|
103 |
}
|
104 |
|
105 |
async function handleEncounterTap(encounter: Encounter) {
|
106 |
-
if (encounter.type === EncounterType.
|
107 |
-
// Your First Piclet - auto catch and show special detail page
|
108 |
-
try {
|
109 |
-
isLoading = true;
|
110 |
-
const caughtPiclet = await EncounterService.catchFirstPiclet(encounter);
|
111 |
-
await incrementCounter('picletsCapured');
|
112 |
-
await addProgressPoints(100);
|
113 |
-
|
114 |
-
// Show the special newly caught detail page
|
115 |
-
newlyCaughtPiclet = caughtPiclet;
|
116 |
-
showNewlyCaught = true;
|
117 |
-
|
118 |
-
// Force refresh encounters to remove the first piclet encounter
|
119 |
-
await forceEncounterRefresh();
|
120 |
-
} catch (error) {
|
121 |
-
console.error('Error catching first piclet:', error);
|
122 |
-
alert(`Error catching your first Piclet: ${error.message}`);
|
123 |
-
}
|
124 |
-
isLoading = false;
|
125 |
-
} else if (encounter.type === EncounterType.WILD_PICLET && encounter.picletTypeId) {
|
126 |
// Regular wild encounter - start battle
|
127 |
await startBattle(encounter);
|
128 |
} else if (encounter.type === EncounterType.SHOP) {
|
@@ -354,12 +335,7 @@
|
|
354 |
disabled={isRefreshing}
|
355 |
>
|
356 |
<div class="encounter-icon">
|
357 |
-
{#if encounter.type === EncounterType.
|
358 |
-
<div class="first-piclet-icon">
|
359 |
-
<div class="golden-glow-effect">✨</div>
|
360 |
-
<div class="mystery-silhouette">?</div>
|
361 |
-
</div>
|
362 |
-
{:else if encounter.type === EncounterType.WILD_PICLET && encounter.picletTypeId}
|
363 |
{#if monsterImages.has(encounter.picletTypeId)}
|
364 |
<img
|
365 |
src={monsterImages.get(encounter.picletTypeId)}
|
@@ -547,39 +523,4 @@
|
|
547 |
margin: 0;
|
548 |
}
|
549 |
|
550 |
-
/* First Piclet encounter styles */
|
551 |
-
.first-piclet-icon {
|
552 |
-
position: relative;
|
553 |
-
width: 64px;
|
554 |
-
height: 64px;
|
555 |
-
display: flex;
|
556 |
-
align-items: center;
|
557 |
-
justify-content: center;
|
558 |
-
background: linear-gradient(135deg, #FFD700, #FFA500);
|
559 |
-
border-radius: 16px;
|
560 |
-
overflow: hidden;
|
561 |
-
}
|
562 |
-
|
563 |
-
.golden-glow-effect {
|
564 |
-
position: absolute;
|
565 |
-
top: 0;
|
566 |
-
left: 0;
|
567 |
-
font-size: 1.5rem;
|
568 |
-
animation: sparkleRotate 2s ease-in-out infinite;
|
569 |
-
}
|
570 |
-
|
571 |
-
.mystery-silhouette {
|
572 |
-
font-size: 2rem;
|
573 |
-
font-weight: bold;
|
574 |
-
color: white;
|
575 |
-
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
576 |
-
z-index: 2;
|
577 |
-
}
|
578 |
-
|
579 |
-
@keyframes sparkleRotate {
|
580 |
-
0%, 100% { transform: rotate(0deg) scale(1); opacity: 0.8; }
|
581 |
-
25% { transform: rotate(-10deg) scale(1.1); opacity: 1; }
|
582 |
-
50% { transform: rotate(0deg) scale(1.2); opacity: 0.9; }
|
583 |
-
75% { transform: rotate(10deg) scale(1.1); opacity: 1; }
|
584 |
-
}
|
585 |
</style>
|
|
|
103 |
}
|
104 |
|
105 |
async function handleEncounterTap(encounter: Encounter) {
|
106 |
+
if (encounter.type === EncounterType.WILD_PICLET && encounter.picletTypeId) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
// Regular wild encounter - start battle
|
108 |
await startBattle(encounter);
|
109 |
} else if (encounter.type === EncounterType.SHOP) {
|
|
|
335 |
disabled={isRefreshing}
|
336 |
>
|
337 |
<div class="encounter-icon">
|
338 |
+
{#if encounter.type === EncounterType.WILD_PICLET && encounter.picletTypeId}
|
|
|
|
|
|
|
|
|
|
|
339 |
{#if monsterImages.has(encounter.picletTypeId)}
|
340 |
<img
|
341 |
src={monsterImages.get(encounter.picletTypeId)}
|
|
|
523 |
margin: 0;
|
524 |
}
|
525 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
</style>
|
src/lib/components/PicletGenerator/PicletResult.svelte
CHANGED
@@ -69,7 +69,11 @@
|
|
69 |
<div class="success-icon">✨</div>
|
70 |
<h2>Success!</h2>
|
71 |
<p class="success-message">
|
72 |
-
|
|
|
|
|
|
|
|
|
73 |
</p>
|
74 |
</div>
|
75 |
|
|
|
69 |
<div class="success-icon">✨</div>
|
70 |
<h2>Success!</h2>
|
71 |
<p class="success-message">
|
72 |
+
{#if picletInstance?.caught}
|
73 |
+
<strong>{picletInstance?.nickname || 'This creature'}</strong> has been caught and added to your roster!
|
74 |
+
{:else}
|
75 |
+
You can now encounter <strong>{picletInstance?.nickname || 'this creature'}</strong>!
|
76 |
+
{/if}
|
77 |
</p>
|
78 |
</div>
|
79 |
|
src/lib/db/encounterService.ts
CHANGED
@@ -37,41 +37,6 @@ export class EncounterService {
|
|
37 |
await db.encounters.clear();
|
38 |
}
|
39 |
|
40 |
-
// Create a "Your First Piclet" encounter from an uncaught Piclet
|
41 |
-
static async createFirstPicletEncounter(picletId: number): Promise<Encounter> {
|
42 |
-
const piclet = await db.picletInstances.get(picletId);
|
43 |
-
if (!piclet) {
|
44 |
-
throw new Error(`Piclet with ID ${picletId} not found`);
|
45 |
-
}
|
46 |
-
|
47 |
-
const encounter: Omit<Encounter, 'id'> = {
|
48 |
-
type: EncounterType.FIRST_PICLET,
|
49 |
-
title: '✨ Your First Piclet! ✨',
|
50 |
-
description: `${piclet.nickname} wants to join your team! This special encounter will automatically catch them for you.`,
|
51 |
-
picletInstanceId: picletId,
|
52 |
-
createdAt: new Date()
|
53 |
-
};
|
54 |
-
|
55 |
-
const id = await db.encounters.add(encounter);
|
56 |
-
return { ...encounter, id };
|
57 |
-
}
|
58 |
-
|
59 |
-
// Check if the player should get a "Your First Piclet" encounter
|
60 |
-
static async shouldCreateFirstPicletEncounter(): Promise<number | null> {
|
61 |
-
const caughtPiclets = await getCaughtPiclets();
|
62 |
-
if (caughtPiclets.length > 0) {
|
63 |
-
return null; // Player already has caught Piclets
|
64 |
-
}
|
65 |
-
|
66 |
-
const uncaughtPiclets = await getUncaughtPiclets();
|
67 |
-
if (uncaughtPiclets.length === 0) {
|
68 |
-
return null; // No uncaught Piclets available
|
69 |
-
}
|
70 |
-
|
71 |
-
// Return the ID of the most recently created uncaught Piclet
|
72 |
-
const mostRecent = uncaughtPiclets.sort((a, b) => (b.id || 0) - (a.id || 0))[0];
|
73 |
-
return mostRecent.id || null;
|
74 |
-
}
|
75 |
|
76 |
// Generate new encounters
|
77 |
static async generateEncounters(): Promise<Encounter[]> {
|
@@ -81,30 +46,9 @@ export class EncounterService {
|
|
81 |
const caughtPiclets = await getCaughtPiclets();
|
82 |
const uncaughtPiclets = await getUncaughtPiclets();
|
83 |
|
84 |
-
if (caughtPiclets.length === 0
|
85 |
-
// Player has no caught piclets
|
86 |
-
console.log('Player has
|
87 |
-
|
88 |
-
// Clear existing encounters first
|
89 |
-
await db.encounters.clear();
|
90 |
-
|
91 |
-
// Create first piclet encounters for all uncaught piclets
|
92 |
-
const newEncounters: Encounter[] = [];
|
93 |
-
for (const uncaughtPiclet of uncaughtPiclets) {
|
94 |
-
if (uncaughtPiclet.id) {
|
95 |
-
const encounter = await this.createFirstPicletEncounter(uncaughtPiclet.id);
|
96 |
-
newEncounters.push(encounter);
|
97 |
-
}
|
98 |
-
}
|
99 |
-
|
100 |
-
await markEncountersRefreshed();
|
101 |
-
console.log('Created', newEncounters.length, 'first piclet encounters');
|
102 |
-
return newEncounters;
|
103 |
-
}
|
104 |
-
|
105 |
-
if (caughtPiclets.length === 0 && uncaughtPiclets.length === 0) {
|
106 |
-
// No piclets at all - return empty encounters
|
107 |
-
console.log('No piclets found - returning empty encounters');
|
108 |
await db.encounters.clear();
|
109 |
await markEncountersRefreshed();
|
110 |
return [];
|
@@ -226,39 +170,6 @@ export class EncounterService {
|
|
226 |
return Math.round(totalLevel / rosterPiclets.length);
|
227 |
}
|
228 |
|
229 |
-
// Catch your first Piclet (marks an existing uncaught Piclet as caught)
|
230 |
-
static async catchFirstPiclet(encounter: Encounter): Promise<PicletInstance> {
|
231 |
-
if (!encounter.picletInstanceId) {
|
232 |
-
throw new Error('No piclet instance ID specified for first Piclet encounter');
|
233 |
-
}
|
234 |
-
|
235 |
-
const piclet = await db.picletInstances.get(encounter.picletInstanceId);
|
236 |
-
if (!piclet) {
|
237 |
-
throw new Error(`Piclet with ID ${encounter.picletInstanceId} not found`);
|
238 |
-
}
|
239 |
-
|
240 |
-
if (piclet.caught) {
|
241 |
-
throw new Error('This Piclet has already been caught');
|
242 |
-
}
|
243 |
-
|
244 |
-
// Mark the Piclet as caught and put it in roster position 0 (first Piclet)
|
245 |
-
const updatedPiclet: PicletInstance = {
|
246 |
-
...piclet,
|
247 |
-
caught: true,
|
248 |
-
caughtAt: new Date(),
|
249 |
-
isInRoster: true,
|
250 |
-
rosterPosition: 0
|
251 |
-
};
|
252 |
-
|
253 |
-
await db.picletInstances.update(encounter.picletInstanceId, {
|
254 |
-
caught: true,
|
255 |
-
caughtAt: new Date(),
|
256 |
-
isInRoster: true,
|
257 |
-
rosterPosition: 0
|
258 |
-
});
|
259 |
-
|
260 |
-
return updatedPiclet;
|
261 |
-
}
|
262 |
|
263 |
// Catch a wild piclet (creates a new instance based on existing piclet type)
|
264 |
static async catchWildPiclet(encounter: Encounter): Promise<PicletInstance> {
|
|
|
37 |
await db.encounters.clear();
|
38 |
}
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
// Generate new encounters
|
42 |
static async generateEncounters(): Promise<Encounter[]> {
|
|
|
46 |
const caughtPiclets = await getCaughtPiclets();
|
47 |
const uncaughtPiclets = await getUncaughtPiclets();
|
48 |
|
49 |
+
if (caughtPiclets.length === 0) {
|
50 |
+
// Player has no caught piclets - return empty encounters (no shop/heal until first piclet is caught)
|
51 |
+
console.log('Player has no caught piclets - returning empty encounters');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
await db.encounters.clear();
|
53 |
await markEncountersRefreshed();
|
54 |
return [];
|
|
|
170 |
return Math.round(totalLevel / rosterPiclets.length);
|
171 |
}
|
172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
|
174 |
// Catch a wild piclet (creates a new instance based on existing piclet type)
|
175 |
static async catchWildPiclet(encounter: Encounter): Promise<PicletInstance> {
|
src/lib/db/piclets.ts
CHANGED
@@ -83,6 +83,10 @@ export async function generatedDataToPicletInstance(data: GeneratedPicletData, l
|
|
83 |
|
84 |
const bst = baseHp + baseAttack + baseDefense + baseFieldAttack + baseFieldDefense + baseSpeed;
|
85 |
|
|
|
|
|
|
|
|
|
86 |
return {
|
87 |
// Type Info
|
88 |
typeId: data.name.toLowerCase().replace(/\s+/g, '-'),
|
@@ -116,12 +120,12 @@ export async function generatedDataToPicletInstance(data: GeneratedPicletData, l
|
|
116 |
specialAbilityUnlockLevel: abilityUnlockLevel,
|
117 |
|
118 |
// Roster
|
119 |
-
isInRoster:
|
120 |
-
rosterPosition: undefined,
|
121 |
|
122 |
// Metadata
|
123 |
-
caught:
|
124 |
-
caughtAt:
|
125 |
bst,
|
126 |
tier: stats.tier, // Use tier from stats
|
127 |
role: 'balanced', // Could be enhanced based on stat distribution
|
|
|
83 |
|
84 |
const bst = baseHp + baseAttack + baseDefense + baseFieldAttack + baseFieldDefense + baseSpeed;
|
85 |
|
86 |
+
// Check if this is the first piclet (no existing piclets in database)
|
87 |
+
const existingPiclets = await db.picletInstances.count();
|
88 |
+
const isFirstPiclet = existingPiclets === 0;
|
89 |
+
|
90 |
return {
|
91 |
// Type Info
|
92 |
typeId: data.name.toLowerCase().replace(/\s+/g, '-'),
|
|
|
120 |
specialAbilityUnlockLevel: abilityUnlockLevel,
|
121 |
|
122 |
// Roster
|
123 |
+
isInRoster: isFirstPiclet,
|
124 |
+
rosterPosition: isFirstPiclet ? 0 : undefined,
|
125 |
|
126 |
// Metadata
|
127 |
+
caught: isFirstPiclet, // First piclet is automatically caught
|
128 |
+
caughtAt: isFirstPiclet ? new Date() : undefined,
|
129 |
bst,
|
130 |
tier: stats.tier, // Use tier from stats
|
131 |
role: 'balanced', // Could be enhanced based on stat distribution
|