import {BattleTypeTable} from "../database/battle_types"; export interface BattleType { id: string, name: string, emoji: string, displayOrder: number, offensiveRelationships: {defender: BattleType, damagePercentage: number}[] defensiveRelationships: {attacker: BattleType, damagePercentage: number}[] } export class BattleTypeManager { private cachedBattleTypes: {[key: string]: BattleType} = {} private cachedTypeList: BattleType[] = [] private refreshPromise: Promise|null = null private readonly _table: BattleTypeTable constructor({battleTypes}: { battleTypes: BattleTypeTable }) { this._table = battleTypes } async refreshCache(): Promise { if (this.refreshPromise !== null) { await this.refreshPromise return } this.refreshPromise = (async () => { const {types, relationships} = await this._table.getTypesAndRelationships() const existing = new Set() this.cachedTypeList = [] for (const typeData of types) { const battleType: BattleType = this.cachedBattleTypes[typeData.id] ?? {} battleType.id = typeData.id battleType.name = typeData.name battleType.emoji = typeData.emoji battleType.displayOrder = typeData.display_order battleType.offensiveRelationships = [] battleType.defensiveRelationships = [] this.cachedBattleTypes[battleType.id] = battleType existing.add(battleType.id) this.cachedTypeList.push(battleType) } for (const key of Object.keys(this.cachedBattleTypes)) { if (!existing.has(key)) { delete this.cachedBattleTypes[key] } } for (const relationshipData of relationships) { const attacker: BattleType|null = this.cachedBattleTypes[relationshipData.attacker] ?? null const defender: BattleType|null = this.cachedBattleTypes[relationshipData.defender] ?? null if (attacker === null || defender === null) { throw Error("Battle types named in relationship not found: " + relationshipData.attacker + " vs. " + relationshipData.defender) } attacker.offensiveRelationships.push({defender: defender, damagePercentage: relationshipData.damage_percentage}) defender.defensiveRelationships.push({attacker: attacker, damagePercentage: relationshipData.damage_percentage}) } this.cachedTypeList.sort((a, b) => a.displayOrder - b.displayOrder) })() try { await this.refreshPromise } finally { this.refreshPromise = null } } async getBattleTypes(): Promise { if (this.refreshPromise !== null) { await this.refreshPromise } return this.cachedTypeList } async getBattleTypeById(id: string): Promise { if (this.refreshPromise !== null) { await this.refreshPromise } const result = this.cachedBattleTypes[id] ?? null if (result === null) { throw Error("No battle type found with id: " + id) } return result } async getBattleTypeByName(name: string): Promise { if (this.refreshPromise !== null) { await this.refreshPromise } const result = this.cachedTypeList.find(t => t.name === name) ?? null if (result === null) { throw Error("No battle type found with name: " + name) } return result } async getDamagePercentageByIds(attacker: string, defender: string): Promise { if (this.refreshPromise !== null) { await this.refreshPromise } if (Object.hasOwn(this.cachedBattleTypes, attacker) && Object.hasOwn(this.cachedBattleTypes, defender)) { return this.cachedBattleTypes[attacker] .offensiveRelationships .find(({defender: d}) => d.id === defender)?.damagePercentage ?? 100 } else { throw Error("Battle types not found by ID: " + attacker + " vs. " + defender) } } }