chore: sync latest changes
This commit is contained in:
81
engine/systems/AchievementSystem.ts
Normal file
81
engine/systems/AchievementSystem.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { AchievementDef } from '../types'
|
||||
|
||||
type UnlockCallback = (achievement: AchievementDef) => void
|
||||
|
||||
export class AchievementSystem {
|
||||
private definitions: AchievementDef[] = []
|
||||
private unlockedIds: Set<string> = new Set()
|
||||
private onUnlock: UnlockCallback | null = null
|
||||
private toastQueue: string[] = []
|
||||
private toastActive = false
|
||||
|
||||
init(defs: AchievementDef[], alreadyUnlocked: string[]) {
|
||||
this.definitions = defs
|
||||
this.unlockedIds = new Set(alreadyUnlocked)
|
||||
this.toastQueue = []
|
||||
this.toastActive = false
|
||||
}
|
||||
|
||||
setUnlockCallback(cb: UnlockCallback) {
|
||||
this.onUnlock = cb
|
||||
}
|
||||
|
||||
check(variables: Record<string, number>) {
|
||||
for (const def of this.definitions) {
|
||||
if (this.unlockedIds.has(def.id)) continue
|
||||
|
||||
const cond = def.condition
|
||||
const val = variables[cond.variable] ?? 0
|
||||
let matched = false
|
||||
|
||||
switch (cond.op) {
|
||||
case '==': matched = val === cond.value; break
|
||||
case '!=': matched = val !== cond.value; break
|
||||
case '>': matched = val > (cond.value as number); break
|
||||
case '<': matched = val < (cond.value as number); break
|
||||
case '>=': matched = val >= (cond.value as number); break
|
||||
case '<=': matched = val <= (cond.value as number); break
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
this.unlockedIds.add(def.id)
|
||||
this.onUnlock?.(def)
|
||||
this.enqueueToast(def.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enqueueToast(id: string) {
|
||||
this.toastQueue.push(id)
|
||||
if (!this.toastActive) {
|
||||
this.showNextToast()
|
||||
}
|
||||
}
|
||||
|
||||
private showNextToast() {
|
||||
if (this.toastQueue.length === 0) {
|
||||
this.toastActive = false
|
||||
return
|
||||
}
|
||||
this.toastActive = true
|
||||
// toast is shown by the UI layer watching toastQueue
|
||||
// UI calls toastDismissed() when the toast animation finishes
|
||||
}
|
||||
|
||||
getToastQueue(): string[] {
|
||||
return [...this.toastQueue]
|
||||
}
|
||||
|
||||
toastDismissed(id: string) {
|
||||
this.toastQueue = this.toastQueue.filter((i) => i !== id)
|
||||
this.showNextToast()
|
||||
}
|
||||
|
||||
getUnlockedIds(): string[] {
|
||||
return [...this.unlockedIds]
|
||||
}
|
||||
|
||||
getDefinitions(): AchievementDef[] {
|
||||
return this.definitions
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user