60 lines
2.8 KiB
TypeScript
60 lines
2.8 KiB
TypeScript
import type { ItemDef, PlayerClass } from './claudeCraftTypes'
|
|
|
|
export type ArmorType = 'cloth' | 'leather' | 'mail'
|
|
type WeaponArchetype = 'warrior' | 'caster' | 'rogue'
|
|
|
|
const MAIL_CLASSES = new Set<PlayerClass>(['warrior', 'paladin', 'shaman'])
|
|
const LEATHER_CLASSES = new Set<PlayerClass>(['druid', 'rogue', 'hunter'])
|
|
const CLOTH_CLASSES = new Set<PlayerClass>(['mage', 'priest', 'warlock'])
|
|
const CASTER_ARCHETYPE_CLASSES = new Set<PlayerClass>(['mage', 'priest', 'warlock', 'druid'])
|
|
const WARRIOR_WEAPON_CLASSES = new Set<PlayerClass>(['warrior', 'rogue', 'hunter', 'shaman', 'paladin'])
|
|
const CASTER_WEAPON_CLASSES = new Set<PlayerClass>(['mage', 'priest', 'warlock', 'shaman', 'paladin', 'druid'])
|
|
const ROGUE_WEAPON_CLASSES = new Set<PlayerClass>(['rogue', 'hunter'])
|
|
const OLD_WARRIOR_WEAPON_ARCHETYPE = new Set<PlayerClass>(['warrior', 'paladin', 'shaman'])
|
|
const OLD_CASTER_WEAPON_ARCHETYPE = new Set<PlayerClass>(['mage', 'priest', 'warlock', 'druid'])
|
|
|
|
const ARMOR_RANK: Record<ArmorType, number> = {
|
|
cloth: 0,
|
|
leather: 1,
|
|
mail: 2,
|
|
}
|
|
|
|
function subsetOf(classes: readonly PlayerClass[], allowed: ReadonlySet<PlayerClass>): boolean {
|
|
return classes.length > 0 && classes.every((cls) => allowed.has(cls))
|
|
}
|
|
|
|
export function armorTypeForItem(item: ItemDef): ArmorType | null {
|
|
if (item.kind !== 'armor') return null
|
|
if (item.armorType) return item.armorType
|
|
if (!item.requiredClass) return null
|
|
if (subsetOf(item.requiredClass, MAIL_CLASSES)) return 'mail'
|
|
if (subsetOf(item.requiredClass, LEATHER_CLASSES)) return 'leather'
|
|
if (subsetOf(item.requiredClass, CLOTH_CLASSES) || subsetOf(item.requiredClass, CASTER_ARCHETYPE_CLASSES)) return 'cloth'
|
|
return null
|
|
}
|
|
|
|
export function maxArmorTypeForClass(cls: PlayerClass): ArmorType {
|
|
if (MAIL_CLASSES.has(cls)) return 'mail'
|
|
if (LEATHER_CLASSES.has(cls)) return 'leather'
|
|
return 'cloth'
|
|
}
|
|
|
|
export function weaponArchetypeForItem(item: ItemDef): WeaponArchetype | null {
|
|
if (item.kind !== 'weapon' || !item.requiredClass) return null
|
|
if (subsetOf(item.requiredClass, OLD_WARRIOR_WEAPON_ARCHETYPE)) return 'warrior'
|
|
if (subsetOf(item.requiredClass, OLD_CASTER_WEAPON_ARCHETYPE)) return 'caster'
|
|
if (subsetOf(item.requiredClass, ROGUE_WEAPON_CLASSES)) return 'rogue'
|
|
return null
|
|
}
|
|
|
|
export function canEquipItem(cls: PlayerClass, item: ItemDef): boolean {
|
|
const armorType = armorTypeForItem(item)
|
|
if (armorType) return ARMOR_RANK[armorType] <= ARMOR_RANK[maxArmorTypeForClass(cls)]
|
|
const weaponArchetype = weaponArchetypeForItem(item)
|
|
if (weaponArchetype === 'warrior') return WARRIOR_WEAPON_CLASSES.has(cls)
|
|
if (weaponArchetype === 'caster') return CASTER_WEAPON_CLASSES.has(cls)
|
|
if (weaponArchetype === 'rogue') return ROGUE_WEAPON_CLASSES.has(cls)
|
|
if (item.requiredClass) return item.requiredClass.includes(cls)
|
|
return true
|
|
}
|