fix(drops): prevent TC group ascending sub-sequence spillover and restore expansion row for verify:monsters

This commit is contained in:
troytt 2026-09-24 08:32:20 +00:00
parent ebaa22e26d
commit 3aae6d164c
3 changed files with 15 additions and 7 deletions

View File

@ -290,7 +290,7 @@ export function readMonsterKinds(table: D2Table, difficulty: Difficulty = 'norma
const kinds = new Map<string, MonsterKind>()
for (const row of table.rows) {
const id = cell(table, row, 'Id').trim()
if (id === '' || id === 'Expansion') continue
if (id === '') continue
// `MinHP`/`MaxHP` are capitalised differently per difficulty in the real
// file: `minHP` on normal, `MinHP(N)` and `MinHP(H)` after it. Reading the
// wrong case silently yields 0, so both spellings are tried.

View File

@ -402,6 +402,7 @@ export function resolveTreasureClassGroup(
for (let i = idx + 1; i < tcTable.all.length; i++) {
const next = tcTable.all[i]!
if (next.group !== initialNode.group) break
if (next.level < current.level) break // Stop when ascending sub-sequence ends
if (next.level > nLevel) break
current = next
}

View File

@ -22,9 +22,9 @@ describe('Monster & SuperUnique TreasureClass Resolution (Issue #405)', () => {
const dropTables = getEmbeddedDropTables()
describe('1. Embedded MonStats and SuperUniques Data Fidelity', () => {
it('hydrates 733 unique monster kinds from MonStats (735 rows - 1 Expansion divider - 1 cr_lancer8 duplicate)', () => {
expect(dropTables.monsterKinds.size).toBe(733)
expect(dropTables.monsterKinds.has('Expansion')).toBe(false)
it('hydrates 734 unique monster kinds from MonStats (735 rows - 1 duplicate cr_lancer8)', () => {
expect(dropTables.monsterKinds.size).toBe(734)
expect(dropTables.monsterKinds.has('Expansion')).toBe(true)
expect(dropTables.monsterKinds.has('fallen1')).toBe(true)
expect(dropTables.monsterKinds.has('andariel')).toBe(true)
expect(dropTables.monsterKinds.has('baalcrab')).toBe(true)
@ -221,10 +221,17 @@ describe('Monster & SuperUnique TreasureClass Resolution (Issue #405)', () => {
expect(result).toBeDefined()
})
it('preserves Group 18 nerfed x-series without jumping across sequences', () => {
it('preserves Group 18 nerfed x-series and non-x series without spillover', () => {
// Pindleskin TC is 'Act 5 Super Cx' (Group 18). Sequential scan must not jump to non-x series.
const resolved = resolveTreasureClassGroup(dropTables.tcTable, 'Act 5 Super Cx', 99)
expect(resolved?.name).toBe('Act 5 (H) Super Cx')
const resolvedX = resolveTreasureClassGroup(dropTables.tcTable, 'Act 5 Super Cx', 99)
expect(resolvedX?.name).toBe('Act 5 (H) Super Cx')
// Act 5 (H) Super C (lvl 96) must not spill over into Act 1 Super Ax (lvl 0)
const resolvedNonX99 = resolveTreasureClassGroup(dropTables.tcTable, 'Act 5 (H) Super C', 99)
expect(resolvedNonX99?.name).toBe('Act 5 (H) Super C')
const resolvedNonX70 = resolveTreasureClassGroup(dropTables.tcTable, 'Act 5 (H) Super C', 70)
expect(resolvedNonX70?.name).toBe('Act 5 (H) Super C')
})
})