You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
4.3 KiB
115 lines
4.3 KiB
import {BattleTypeTables} 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<void>|null = null
|
|
|
|
private readonly _table: BattleTypeTables
|
|
|
|
constructor({battleTypes}: { battleTypes: BattleTypeTables }) {
|
|
this._table = battleTypes
|
|
}
|
|
|
|
async refreshCache(): Promise<void> {
|
|
if (this.refreshPromise !== null) {
|
|
await this.refreshPromise
|
|
return
|
|
}
|
|
|
|
this.refreshPromise = (async () => {
|
|
const {types, relationships} = await this._table.getTypesAndRelationships()
|
|
|
|
const existing = new Set<string>()
|
|
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<BattleType[]> {
|
|
if (this.refreshPromise !== null) {
|
|
await this.refreshPromise
|
|
}
|
|
return this.cachedTypeList
|
|
}
|
|
|
|
async getBattleTypeById(id: string): Promise<BattleType> {
|
|
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<BattleType> {
|
|
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<number> {
|
|
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)
|
|
}
|
|
}
|
|
} |