fix(monster-mapping): update hellbovine token to EC, remove XX tokens, and eliminate startsWith fallback
- Update hellbovine token from CW to EC in MONSTER_ART_MAP - Remove invalid XX cut monster entries from MONSTER_ART_MAP and ACT_MONSTER_SPECS - Replace startsWith iteration in resolveMonsterArtSpec with deterministic O(1) exact and base lookup - Prevent XX tokens from leaking into art requests TAG=agy CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
This commit is contained in:
parent
04d562a99c
commit
2e73d7b02f
|
|
@ -109,11 +109,6 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"bloodlord5": { token: "L3", weapon: "hth" },
|
"bloodlord5": { token: "L3", weapon: "hth" },
|
||||||
"bloodlord6": { token: "L3", weapon: "hth" },
|
"bloodlord6": { token: "L3", weapon: "hth" },
|
||||||
"bloodlord7": { token: "L3", weapon: "hth" },
|
"bloodlord7": { token: "L3", weapon: "hth" },
|
||||||
"bloodmage1": { token: "XX", weapon: "hth" },
|
|
||||||
"bloodmage2": { token: "XX", weapon: "hth" },
|
|
||||||
"bloodmage3": { token: "XX", weapon: "hth" },
|
|
||||||
"bloodmage4": { token: "XX", weapon: "hth" },
|
|
||||||
"bloodmage5": { token: "XX", weapon: "hth" },
|
|
||||||
"bloodraven": { token: "CR", weapon: "bow" },
|
"bloodraven": { token: "CR", weapon: "bow" },
|
||||||
"blunderbore1": { token: "PN", weapon: "hth" },
|
"blunderbore1": { token: "PN", weapon: "hth" },
|
||||||
"blunderbore2": { token: "PN", weapon: "hth" },
|
"blunderbore2": { token: "PN", weapon: "hth" },
|
||||||
|
|
@ -212,11 +207,6 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"crownest3": { token: "BN", weapon: "hth" },
|
"crownest3": { token: "BN", weapon: "hth" },
|
||||||
"crownest4": { token: "BN", weapon: "hth" },
|
"crownest4": { token: "BN", weapon: "hth" },
|
||||||
"cycleoflife": { token: "K9", weapon: "hth" },
|
"cycleoflife": { token: "K9", weapon: "hth" },
|
||||||
"darkguard1": { token: "XX", weapon: "hth" },
|
|
||||||
"darkguard2": { token: "XX", weapon: "hth" },
|
|
||||||
"darkguard3": { token: "XX", weapon: "hth" },
|
|
||||||
"darkguard4": { token: "XX", weapon: "hth" },
|
|
||||||
"darkguard5": { token: "XX", weapon: "hth" },
|
|
||||||
"darkwanderer": { token: "1Z", weapon: "hth" },
|
"darkwanderer": { token: "1Z", weapon: "hth" },
|
||||||
"deathmauler1": { token: "M5", weapon: "hth" },
|
"deathmauler1": { token: "M5", weapon: "hth" },
|
||||||
"deathmauler2": { token: "M5", weapon: "hth" },
|
"deathmauler2": { token: "M5", weapon: "hth" },
|
||||||
|
|
@ -345,7 +335,7 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"griswold": { token: "GZ", weapon: "hth" },
|
"griswold": { token: "GZ", weapon: "hth" },
|
||||||
"halbu": { token: "20", weapon: "hth" },
|
"halbu": { token: "20", weapon: "hth" },
|
||||||
"heartofwolverine": { token: "X3", weapon: "hth" },
|
"heartofwolverine": { token: "X3", weapon: "hth" },
|
||||||
"hellbovine": { token: "CW", weapon: "hth" },
|
"hellbovine": { token: "EC", weapon: "hth" },
|
||||||
"hellmeteor": { token: "K9", weapon: "hth" },
|
"hellmeteor": { token: "K9", weapon: "hth" },
|
||||||
"hephasto": { token: "5P", weapon: "hth" },
|
"hephasto": { token: "5P", weapon: "hth" },
|
||||||
"hratli": { token: "HR", weapon: "hth" },
|
"hratli": { token: "HR", weapon: "hth" },
|
||||||
|
|
@ -375,7 +365,6 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"kashya": { token: "RC", weapon: "hth" },
|
"kashya": { token: "RC", weapon: "hth" },
|
||||||
"larva": { token: "LV", weapon: "hth" },
|
"larva": { token: "LV", weapon: "hth" },
|
||||||
"larzuk": { token: "XR", weapon: "hth" },
|
"larzuk": { token: "XR", weapon: "hth" },
|
||||||
"lightningbeast": { token: "XX", weapon: "hth" },
|
|
||||||
"lightningsentry": { token: "LG", weapon: "hth" },
|
"lightningsentry": { token: "LG", weapon: "hth" },
|
||||||
"lightningspire": { token: "AE", weapon: "hth" },
|
"lightningspire": { token: "AE", weapon: "hth" },
|
||||||
"lysander": { token: "LY", weapon: "hth" },
|
"lysander": { token: "LY", weapon: "hth" },
|
||||||
|
|
@ -409,17 +398,6 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"mephistospirit": { token: "M6", weapon: "hth" },
|
"mephistospirit": { token: "M6", weapon: "hth" },
|
||||||
"meshif1": { token: "MS", weapon: "hth" },
|
"meshif1": { token: "MS", weapon: "hth" },
|
||||||
"meshif2": { token: "M3", weapon: "hth" },
|
"meshif2": { token: "M3", weapon: "hth" },
|
||||||
"minion1": { token: "XX", weapon: "hth" },
|
|
||||||
"minion10": { token: "XX", weapon: "hth" },
|
|
||||||
"minion11": { token: "XX", weapon: "hth" },
|
|
||||||
"minion2": { token: "XX", weapon: "hth" },
|
|
||||||
"minion3": { token: "XX", weapon: "hth" },
|
|
||||||
"minion4": { token: "XX", weapon: "hth" },
|
|
||||||
"minion5": { token: "XX", weapon: "hth" },
|
|
||||||
"minion6": { token: "XX", weapon: "hth" },
|
|
||||||
"minion7": { token: "XX", weapon: "hth" },
|
|
||||||
"minion8": { token: "XX", weapon: "hth" },
|
|
||||||
"minion9": { token: "XX", weapon: "hth" },
|
|
||||||
"minionspawner1": { token: "XA", weapon: "hth" },
|
"minionspawner1": { token: "XA", weapon: "hth" },
|
||||||
"minionspawner2": { token: "XA", weapon: "hth" },
|
"minionspawner2": { token: "XA", weapon: "hth" },
|
||||||
"minionspawner3": { token: "XA", weapon: "hth" },
|
"minionspawner3": { token: "XA", weapon: "hth" },
|
||||||
|
|
@ -609,7 +587,6 @@ export const MONSTER_ART_MAP: Record<string, MonsterArtSpec> = {
|
||||||
"snowyeti2": { token: "IO", weapon: "hth" },
|
"snowyeti2": { token: "IO", weapon: "hth" },
|
||||||
"snowyeti3": { token: "IO", weapon: "hth" },
|
"snowyeti3": { token: "IO", weapon: "hth" },
|
||||||
"snowyeti4": { token: "IO", weapon: "hth" },
|
"snowyeti4": { token: "IO", weapon: "hth" },
|
||||||
"spiritmummy": { token: "XX", weapon: "hth" },
|
|
||||||
"spiritofbarbs": { token: "X4", weapon: "hth" },
|
"spiritofbarbs": { token: "X4", weapon: "hth" },
|
||||||
"spiritwolf": { token: "WF", weapon: "hth" },
|
"spiritwolf": { token: "WF", weapon: "hth" },
|
||||||
"succubus1": { token: "0B", weapon: "hth" },
|
"succubus1": { token: "0B", weapon: "hth" },
|
||||||
|
|
@ -765,7 +742,7 @@ export const ACT_MONSTER_SPECS: Record<number, readonly MonsterArtSpec[]> = {
|
||||||
2: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "PW", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "VD", weapon: "hth" }, { token: "PW", weapon: "1ht" }, { token: "BN", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "SW", weapon: "hth" }, { token: "SR", weapon: "hth" }, { token: "SD", weapon: "hth" }, { token: "MM", weapon: "hth" }, { token: "GY", weapon: "hth" }, { token: "SK", weapon: "1hs" }, { token: "SK", weapon: "bow" }, { token: "BB", weapon: "hth" }, { token: "PN", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "WR", weapon: "hth" }, { token: "VA", weapon: "hth" }, { token: "GM", weapon: "2hs" }],
|
2: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "PW", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "VD", weapon: "hth" }, { token: "PW", weapon: "1ht" }, { token: "BN", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "SW", weapon: "hth" }, { token: "SR", weapon: "hth" }, { token: "SD", weapon: "hth" }, { token: "MM", weapon: "hth" }, { token: "GY", weapon: "hth" }, { token: "SK", weapon: "1hs" }, { token: "SK", weapon: "bow" }, { token: "BB", weapon: "hth" }, { token: "PN", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "WR", weapon: "hth" }, { token: "VA", weapon: "hth" }, { token: "GM", weapon: "2hs" }],
|
||||||
3: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "BB", weapon: "hth" }, { token: "MO", weapon: "hth" }, { token: "TH", weapon: "hth" }, { token: "FE", weapon: "1hs" }, { token: "FC", weapon: "hth" }, { token: "BK", weapon: "hth" }, { token: "FD", weapon: "hth" }, { token: "FW", weapon: "hth" }, { token: "WW", weapon: "hth" }, { token: "VD", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "ZZ", weapon: "hth" }, { token: "SW", weapon: "hth" }, { token: "ZP", weapon: "hth" }, { token: "SR", weapon: "hth" }, { token: "VA", weapon: "hth" }, { token: "SP", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "MM", weapon: "hth" }, { token: "FK", weapon: "1hs" }, { token: "WR", weapon: "hth" }, { token: "GY", weapon: "hth" }, { token: "CR", weapon: "1hs" }, { token: "SD", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "CR", weapon: "bow" }, { token: "PN", weapon: "hth" }],
|
3: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "BB", weapon: "hth" }, { token: "MO", weapon: "hth" }, { token: "TH", weapon: "hth" }, { token: "FE", weapon: "1hs" }, { token: "FC", weapon: "hth" }, { token: "BK", weapon: "hth" }, { token: "FD", weapon: "hth" }, { token: "FW", weapon: "hth" }, { token: "WW", weapon: "hth" }, { token: "VD", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "ZZ", weapon: "hth" }, { token: "SW", weapon: "hth" }, { token: "ZP", weapon: "hth" }, { token: "SR", weapon: "hth" }, { token: "VA", weapon: "hth" }, { token: "SP", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "MM", weapon: "hth" }, { token: "FK", weapon: "1hs" }, { token: "WR", weapon: "hth" }, { token: "GY", weapon: "hth" }, { token: "CR", weapon: "1hs" }, { token: "SD", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "CR", weapon: "bow" }, { token: "PN", weapon: "hth" }],
|
||||||
4: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "VM", weapon: "hth" }, { token: "FR", weapon: "hth" }, { token: "CS", weapon: "hth" }, { token: "UM", weapon: "fgt" }, { token: "DM", weapon: "hth" }, { token: "WW", weapon: "hth" }, { token: "BH", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "UM", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "PN", weapon: "hth" }, { token: "UM", weapon: "mgk" }],
|
4: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "SL", weapon: "hth" }, { token: "VM", weapon: "hth" }, { token: "FR", weapon: "hth" }, { token: "CS", weapon: "hth" }, { token: "UM", weapon: "fgt" }, { token: "DM", weapon: "hth" }, { token: "WW", weapon: "hth" }, { token: "BH", weapon: "hth" }, { token: "BT", weapon: "hth" }, { token: "UM", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "PN", weapon: "hth" }, { token: "UM", weapon: "mgk" }],
|
||||||
5: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "XX", weapon: "hth" }, { token: "M5", weapon: "hth" }, { token: "OS", weapon: "hth" }, { token: "IP", weapon: "hth" }, { token: "SK", weapon: "bow" }, { token: "BH", weapon: "hth" }, { token: "OX", weapon: "hth" }, { token: "F0", weapon: "hth" }, { token: "0B", weapon: "hth" }, { token: "L3", weapon: "hth" }, { token: "IO", weapon: "hth" }, { token: "RE", weapon: "hth" }, { token: "0D", weapon: "hth" }, { token: "0F", weapon: "hth" }, { token: "0E", weapon: "hth" }, { token: "45", weapon: "hth" }, { token: "0C", weapon: "hth" }, { token: "XY", weapon: "hth" }, { token: "CR", weapon: "1hs" }, { token: "CR", weapon: "bow" }, { token: "CR", weapon: "2ht" }, { token: "SW", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "SP", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "UM", weapon: "mgk" }, { token: "DM", weapon: "hth" }],
|
5: [{ token: "FA", weapon: "hth" }, { token: "ZM", weapon: "hth" }, { token: "SI", weapon: "hth" }, { token: "YE", weapon: "hth" }, { token: "SK", weapon: "hth" }, { token: "CW", weapon: "hth" }, { token: "M5", weapon: "hth" }, { token: "OS", weapon: "hth" }, { token: "IP", weapon: "hth" }, { token: "SK", weapon: "bow" }, { token: "BH", weapon: "hth" }, { token: "OX", weapon: "hth" }, { token: "F0", weapon: "hth" }, { token: "0B", weapon: "hth" }, { token: "L3", weapon: "hth" }, { token: "IO", weapon: "hth" }, { token: "RE", weapon: "hth" }, { token: "0D", weapon: "hth" }, { token: "0F", weapon: "hth" }, { token: "0E", weapon: "hth" }, { token: "45", weapon: "hth" }, { token: "0C", weapon: "hth" }, { token: "XY", weapon: "hth" }, { token: "CR", weapon: "1hs" }, { token: "CR", weapon: "bow" }, { token: "CR", weapon: "2ht" }, { token: "SW", weapon: "hth" }, { token: "SM", weapon: "hth" }, { token: "SP", weapon: "hth" }, { token: "SC", weapon: "hth" }, { token: "UM", weapon: "mgk" }, { token: "DM", weapon: "hth" }],
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -773,13 +750,15 @@ export const ACT_MONSTER_SPECS: Record<number, readonly MonsterArtSpec[]> = {
|
||||||
*/
|
*/
|
||||||
export function resolveMonsterArtSpec(id: string): MonsterArtSpec | null {
|
export function resolveMonsterArtSpec(id: string): MonsterArtSpec | null {
|
||||||
const lower = id.toLowerCase()
|
const lower = id.toLowerCase()
|
||||||
if (MONSTER_ART_MAP[lower]) {
|
const direct = MONSTER_ART_MAP[lower]
|
||||||
return MONSTER_ART_MAP[lower]
|
if (direct && direct.token !== 'XX' && direct.token.trim() !== '') {
|
||||||
|
return direct
|
||||||
}
|
}
|
||||||
const base = lower.replace(/\d+$/, '')
|
const base = lower.replace(/\d+$/, '')
|
||||||
for (const [key, spec] of Object.entries(MONSTER_ART_MAP)) {
|
if (base !== lower) {
|
||||||
if (key.startsWith(base)) {
|
const baseSpec = MONSTER_ART_MAP[base]
|
||||||
return spec
|
if (baseSpec && baseSpec.token !== 'XX' && baseSpec.token.trim() !== '') {
|
||||||
|
return baseSpec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import { resolveMonsterArtSpec, MONSTER_ART_MAP } from '../src/game/monster-mapping.ts'
|
import { resolveMonsterArtSpec, MONSTER_ART_MAP, ACT_MONSTER_SPECS } from '../src/game/monster-mapping.ts'
|
||||||
|
|
||||||
describe('monster-mapping', () => {
|
describe('monster-mapping', () => {
|
||||||
it('resolves standard Act 1 monsters', () => {
|
it('resolves standard Act 1 monsters', () => {
|
||||||
|
|
@ -10,13 +10,36 @@ describe('monster-mapping', () => {
|
||||||
expect(resolveMonsterArtSpec('cr_archer1')).toEqual({ token: 'CR', weapon: 'bow' })
|
expect(resolveMonsterArtSpec('cr_archer1')).toEqual({ token: 'CR', weapon: 'bow' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('resolves numbered variants through prefix fallback', () => {
|
it('resolves numbered variants through exact or base lookup without prefix iteration order', () => {
|
||||||
expect(resolveMonsterArtSpec('fallen3')?.token).toBe('FA')
|
expect(resolveMonsterArtSpec('fallen3')?.token).toBe('FA')
|
||||||
expect(resolveMonsterArtSpec('zombie5')?.token).toBe('ZM')
|
expect(resolveMonsterArtSpec('zombie5')?.token).toBe('ZM')
|
||||||
expect(resolveMonsterArtSpec('quillrat6')?.token).toBe('SI')
|
expect(resolveMonsterArtSpec('quillrat6')?.token).toBe('SI')
|
||||||
|
// Suffix with arbitrary letters must not prefix-match
|
||||||
|
expect(resolveMonsterArtSpec('fallen_fake')).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves hellbovine to EC token instead of CW', () => {
|
||||||
|
expect(resolveMonsterArtSpec('hellbovine')).toEqual({ token: 'EC', weapon: 'hth' })
|
||||||
|
expect(MONSTER_ART_MAP.hellbovine).toEqual({ token: 'EC', weapon: 'hth' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not leak XX tokens or crash on cut monsters', () => {
|
||||||
|
const cutMonsters = ['bloodmage1', 'darkguard1', 'lightningbeast', 'minion1', 'spiritmummy']
|
||||||
|
for (const id of cutMonsters) {
|
||||||
|
expect(resolveMonsterArtSpec(id)).toBeNull()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ACT_MONSTER_SPECS does not contain any XX tokens in any act', () => {
|
||||||
|
for (const [act, specs] of Object.entries(ACT_MONSTER_SPECS)) {
|
||||||
|
for (const spec of specs) {
|
||||||
|
expect(spec.token, `Act ${act} contains invalid token ${spec.token}`).not.toBe('XX')
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns null for unknown monsters', () => {
|
it('returns null for unknown monsters', () => {
|
||||||
expect(resolveMonsterArtSpec('non_existent_monster_xyz')).toBeNull()
|
expect(resolveMonsterArtSpec('non_existent_monster_xyz')).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ describe('offline pre-baked entity atlases & full Act 1..5 pack index (Issues #3
|
||||||
it('maps 700+ monster IDs across Acts 1..5 in MONSTER_ART_MAP', () => {
|
it('maps 700+ monster IDs across Acts 1..5 in MONSTER_ART_MAP', () => {
|
||||||
expect(Object.keys(MONSTER_ART_MAP).length).toBeGreaterThanOrEqual(700)
|
expect(Object.keys(MONSTER_ART_MAP).length).toBeGreaterThanOrEqual(700)
|
||||||
expect(MONSTER_ART_MAP.fallen).toEqual({ token: 'FA', weapon: 'hth' })
|
expect(MONSTER_ART_MAP.fallen).toEqual({ token: 'FA', weapon: 'hth' })
|
||||||
expect(MONSTER_ART_MAP.hellbovine).toEqual({ token: 'CW', weapon: 'hth' })
|
expect(MONSTER_ART_MAP.hellbovine).toEqual({ token: 'EC', weapon: 'hth' })
|
||||||
expect(MONSTER_ART_MAP.skeleton).toEqual({ token: 'SK', weapon: 'hth' })
|
expect(MONSTER_ART_MAP.skeleton).toEqual({ token: 'SK', weapon: 'hth' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ describe('offline pre-baked entity atlases & full Act 1..5 pack index (Issues #3
|
||||||
uniqueSpecs.add(`${spec.token.toLowerCase()}-${spec.weapon.toLowerCase()}`)
|
uniqueSpecs.add(`${spec.token.toLowerCase()}-${spec.weapon.toLowerCase()}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(uniqueSpecs.size).toBe(66)
|
expect(uniqueSpecs.size).toBe(65)
|
||||||
|
|
||||||
for (const key of uniqueSpecs) {
|
for (const key of uniqueSpecs) {
|
||||||
const slug = `monster-${key}`
|
const slug = `monster-${key}`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue