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.
vore-rpg/src/managers/battle_types.ts

115 lines
4.3 KiB

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<void>|null = null
private readonly _table: BattleTypeTable
constructor({battleTypes}: { battleTypes: BattleTypeTable }) {
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)
}
}
}