139 lines
4.5 KiB
TypeScript
139 lines
4.5 KiB
TypeScript
import { describe, it, expect, beforeAll } from 'vitest'
|
|
import { ACT_BOSSES, type BossPreset } from '../src/boss.ts'
|
|
import { getEmbeddedDropTables } from '../src/game/embedded-drop-tables.ts'
|
|
import { executeDropPipeline, type DropTables } from '../src/game/drop-pipeline.ts'
|
|
import { formatItemTooltip } from '../src/game/item-tooltip.ts'
|
|
import type { Item } from '../src/game/items.ts'
|
|
|
|
describe('Act Boss Loot Simulator (boss.html)', () => {
|
|
let dropTables: DropTables
|
|
|
|
beforeAll(() => {
|
|
dropTables = getEmbeddedDropTables()
|
|
})
|
|
|
|
it('1. ACT_BOSSES catalog includes all 5 canonical Act Bosses', () => {
|
|
expect(ACT_BOSSES).toHaveLength(5)
|
|
const bossIds = ACT_BOSSES.map(b => b.id)
|
|
expect(bossIds).toEqual(['andariel', 'duriel', 'mephisto', 'diablo', 'baal'])
|
|
})
|
|
|
|
it('2. All standard TCs and Quest TCs resolve to valid nodes in TreasureClassEx', () => {
|
|
const difficulties: Array<'normal' | 'nightmare' | 'hell'> = ['normal', 'nightmare', 'hell']
|
|
|
|
for (const boss of ACT_BOSSES) {
|
|
for (const diff of difficulties) {
|
|
const stdTc = boss.tc[diff]
|
|
const questTc = boss.questTc[diff]
|
|
|
|
const stdNode = dropTables.tcTable.get(stdTc)
|
|
const questNode = dropTables.tcTable.get(questTc)
|
|
|
|
expect(stdNode, `Boss ${boss.id} [${diff}] std TC ${stdTc} should exist`).toBeDefined()
|
|
expect(questNode, `Boss ${boss.id} [${diff}] quest TC ${questTc} should exist`).toBeDefined()
|
|
|
|
expect(stdNode?.picks).toBeGreaterThan(0)
|
|
expect(questNode?.picks).toBeGreaterThan(0)
|
|
}
|
|
}
|
|
})
|
|
|
|
it('3. Simulates single Hell Mephisto kill and generates realistic dropped items with attributes', () => {
|
|
const drops: Item[] = executeDropPipeline({
|
|
tcName: 'Mephistoq (H)',
|
|
nLevel: 87,
|
|
dropTables,
|
|
difficulty: 'hell',
|
|
playerMf: 300,
|
|
gamePlayers: 1,
|
|
partyPlayers: 1,
|
|
monsterRng: 42,
|
|
})
|
|
|
|
expect(drops.length).toBeGreaterThan(0)
|
|
|
|
for (const item of drops) {
|
|
expect(item.name.length).toBeGreaterThan(0)
|
|
expect(item.code).toBeDefined()
|
|
expect(item.code!.length).toBeGreaterThan(0)
|
|
expect(item.base).toBeDefined()
|
|
|
|
const tooltip = formatItemTooltip(item)
|
|
expect(tooltip.title.length).toBeGreaterThan(0)
|
|
expect(tooltip.quality.length).toBeGreaterThan(0)
|
|
expect(tooltip.ilvl).toBe(87)
|
|
|
|
// If equipment, verify stats formatting
|
|
if (item.base.kind === 'weapon' || item.base.kind === 'armor') {
|
|
expect(tooltip.baseType).toMatch(/武器|防具/)
|
|
}
|
|
}
|
|
})
|
|
|
|
it('4. Simulates Hell Baal kill with 7 Players (low NoDrop) and rolls multi-tier affixes', () => {
|
|
const drops: Item[] = executeDropPipeline({
|
|
tcName: 'Baal (H)',
|
|
nLevel: 99,
|
|
dropTables,
|
|
difficulty: 'hell',
|
|
playerMf: 250,
|
|
gamePlayers: 7,
|
|
partyPlayers: 1,
|
|
monsterRng: 99999,
|
|
})
|
|
|
|
expect(drops.length).toBeGreaterThan(0)
|
|
const qualities = drops.map(d => d.rarity)
|
|
expect(qualities.length).toBe(drops.length)
|
|
})
|
|
|
|
it('5. Verifies formatItemTooltip generates correct properties for Unique, Rare, and Magic items', () => {
|
|
// 5.1 Unique Item Tooltip Test
|
|
const dummyUniqueBase = dropTables.getBase('uap')! // Shako
|
|
const dummyUniqueDef = dropTables.uniques.getEnabledByCode('uap')[0]!
|
|
const uniqueItem: Item = {
|
|
base: dummyUniqueBase,
|
|
prefix: null,
|
|
suffix: null,
|
|
level: 87,
|
|
ilvl: 87,
|
|
name: dummyUniqueDef.index,
|
|
stats: { defense: 141, allskills: 2, mag: 50 },
|
|
invWidth: dummyUniqueBase.invWidth,
|
|
invHeight: dummyUniqueBase.invHeight,
|
|
stack: 1,
|
|
value: 10000,
|
|
rarity: 'unique',
|
|
uniqueItemDef: dummyUniqueDef,
|
|
}
|
|
|
|
const uniqueTooltip = formatItemTooltip(uniqueItem)
|
|
expect(uniqueTooltip.title).toBe(dummyUniqueDef.index)
|
|
expect(uniqueTooltip.quality).toBe('unique')
|
|
expect(uniqueTooltip.lines.length).toBeGreaterThan(0)
|
|
|
|
// 5.2 Rune Tooltip Test
|
|
const dummyRuneBase = dropTables.getBase('r30')! // Ber Rune
|
|
const runeItem: Item = {
|
|
base: dummyRuneBase,
|
|
prefix: null,
|
|
suffix: null,
|
|
level: 63,
|
|
ilvl: 63,
|
|
name: 'Ber Rune',
|
|
code: 'r30 ',
|
|
stats: {},
|
|
invWidth: 1,
|
|
invHeight: 1,
|
|
stack: 1,
|
|
value: 100,
|
|
rarity: 'normal',
|
|
}
|
|
|
|
const runeTooltip = formatItemTooltip(runeItem)
|
|
expect(runeTooltip.title).toContain('30#')
|
|
expect(runeTooltip.quality).toContain('符文')
|
|
expect(runeTooltip.lines.some(l => l.text.includes('压碎打击'))).toBe(true)
|
|
})
|
|
})
|