|
import { db } from './index'; |
|
import type { Encounter, PicletInstance } from './schema'; |
|
import { EncounterType } from './schema'; |
|
import { getOrCreateGameState, markEncountersRefreshed } from './gameState'; |
|
import { getCaughtPiclets } from './piclets'; |
|
|
|
|
|
const ENCOUNTER_REFRESH_HOURS = 2; |
|
const MIN_WILD_ENCOUNTERS = 2; |
|
const MAX_WILD_ENCOUNTERS = 4; |
|
|
|
export class EncounterService { |
|
|
|
static async shouldRefreshEncounters(): Promise<boolean> { |
|
const state = await getOrCreateGameState(); |
|
const hoursSinceRefresh = (Date.now() - state.lastEncounterRefresh.getTime()) / (1000 * 60 * 60); |
|
return hoursSinceRefresh >= ENCOUNTER_REFRESH_HOURS; |
|
} |
|
|
|
|
|
static async forceEncounterRefresh(): Promise<void> { |
|
await db.encounters.clear(); |
|
await markEncountersRefreshed(); |
|
} |
|
|
|
|
|
static async getCurrentEncounters(): Promise<Encounter[]> { |
|
return await db.encounters |
|
.orderBy('createdAt') |
|
.reverse() |
|
.toArray(); |
|
} |
|
|
|
|
|
static async clearEncounters(): Promise<void> { |
|
await db.encounters.clear(); |
|
} |
|
|
|
|
|
static async generateEncounters(): Promise<Encounter[]> { |
|
const encounters: Omit<Encounter, 'id'>[] = []; |
|
|
|
|
|
const caughtPiclets = await getCaughtPiclets(); |
|
|
|
if (caughtPiclets.length === 0) { |
|
|
|
console.log('Player has no caught piclets - returning empty encounters'); |
|
await db.encounters.clear(); |
|
await markEncountersRefreshed(); |
|
return []; |
|
} |
|
|
|
|
|
console.log('Generating wild battle encounters'); |
|
const wildEncounters = await this.generateWildBattleEncounters(); |
|
encounters.push(...wildEncounters); |
|
|
|
|
|
await db.encounters.clear(); |
|
for (const encounter of encounters) { |
|
await db.encounters.add(encounter); |
|
} |
|
|
|
await markEncountersRefreshed(); |
|
return await this.getCurrentEncounters(); |
|
} |
|
|
|
|
|
private static async generateWildBattleEncounters(): Promise<Omit<Encounter, 'id'>[]> { |
|
const encounters: Omit<Encounter, 'id'>[] = []; |
|
|
|
|
|
const caughtPiclets = await getCaughtPiclets(); |
|
|
|
if (caughtPiclets.length === 0) { |
|
return encounters; |
|
} |
|
|
|
|
|
const numEncounters = Math.floor(Math.random() * (MAX_WILD_ENCOUNTERS - MIN_WILD_ENCOUNTERS + 1)) + MIN_WILD_ENCOUNTERS; |
|
|
|
for (let i = 0; i < numEncounters; i++) { |
|
|
|
const randomPiclet = caughtPiclets[Math.floor(Math.random() * caughtPiclets.length)]; |
|
|
|
|
|
const displayName = randomPiclet.typeId.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); |
|
|
|
const encounter: Omit<Encounter, 'id'> = { |
|
type: EncounterType.WILD_PICLET, |
|
title: `Wild ${displayName}`, |
|
description: `A wild ${displayName} appears! Ready for battle?`, |
|
picletInstanceId: randomPiclet.id, |
|
picletTypeId: randomPiclet.typeId, |
|
enemyLevel: 5, |
|
createdAt: new Date() |
|
}; |
|
|
|
encounters.push(encounter); |
|
} |
|
|
|
return encounters; |
|
} |
|
|
|
|
|
static async getEncounter(id: number): Promise<Encounter | undefined> { |
|
return await db.encounters.get(id); |
|
} |
|
|
|
|
|
static async deleteEncounter(id: number): Promise<void> { |
|
await db.encounters.delete(id); |
|
} |
|
} |