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
|