From 230c20da675b936fcea30fe8b51687c2ab8fe936 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Sun, 27 Sep 2026 15:18:30 +0000 Subject: [PATCH] fix(entities): bake the Hell Bovine (MonStats Code EC) art for the Moo Moo Farm Commit 2e73d7b changed the Hell Bovine art token from CW to EC (MonStats.txt hellbovine, Code EC) but never added EC to the act 1 list of ACT_MONSTER_SPECS, so pack-entity-assets baked no ec-hth atlas and the Moo Moo Farm's (level 39) Hell Bovines had no art. - ACT_MONSTER_SPECS[1]: add { token: "EC", weapon: "hth" }. - Re-baked entities: 70 monster atlases (was 69). entities/index.json is now sha256 675757cf...; the new ec-hth entry is its only change. - Tests: pin 70 entities, 66 unique specs and the new index hash. TAG=agy CONV=a4f9163c-a011-4161-b169-7f361b1ed57e --- src/game/monster-mapping.ts | 2 +- tests/challenger-m3-entity-concurrency.test.ts | 5 +++-- tests/challenger-m4-determinism-parity.test.ts | 8 +++++--- tests/packed-entity-art.test.ts | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/game/monster-mapping.ts b/src/game/monster-mapping.ts index 236f66d..54b5a6c 100644 --- a/src/game/monster-mapping.ts +++ b/src/game/monster-mapping.ts @@ -738,7 +738,7 @@ export const MONSTER_ART_MAP: Record = { * used by the offline entity baker to pre-pack all level monsters per act. */ export const ACT_MONSTER_SPECS: Record = { - 1: [{ 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: "CR", weapon: "1hs" }, { token: "FS", weapon: "hth" }, { token: "CR", weapon: "2ht" }, { token: "SK", weapon: "1hs" }, { token: "BN", weapon: "hth" }, { token: "GM", weapon: "2hs" }, { token: "CR", weapon: "bow" }, { token: "SK", weapon: "bow" }, { token: "BH", weapon: "hth" }, { token: "WR", weapon: "hth" }, { token: "FE", weapon: "1hs" }, { token: "SP", weapon: "hth" }, { token: "VA", weapon: "hth" }], + 1: [{ 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: "CR", weapon: "1hs" }, { token: "FS", weapon: "hth" }, { token: "CR", weapon: "2ht" }, { token: "SK", weapon: "1hs" }, { token: "BN", weapon: "hth" }, { token: "GM", weapon: "2hs" }, { token: "CR", weapon: "bow" }, { token: "SK", weapon: "bow" }, { token: "BH", weapon: "hth" }, { token: "WR", weapon: "hth" }, { token: "FE", weapon: "1hs" }, { token: "SP", weapon: "hth" }, { token: "VA", weapon: "hth" }, { token: "EC", weapon: "hth" }], 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" }], 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" }], diff --git a/tests/challenger-m3-entity-concurrency.test.ts b/tests/challenger-m3-entity-concurrency.test.ts index d981878..85d8294 100644 --- a/tests/challenger-m3-entity-concurrency.test.ts +++ b/tests/challenger-m3-entity-concurrency.test.ts @@ -86,14 +86,15 @@ describe('Challenger M3_2: Entity Asset Packing Concurrency & Schema Parity', () expect(meta.height).toBe(1929) }) - it('verifies all 69 monster R8 atlases and metadata schemas', () => { + it('verifies all 70 monster R8 atlases and metadata schemas', () => { expect(existsSync(indexJsonPath)).toBe(true) const index = JSON.parse(readFileSync(indexJsonPath, 'utf8')) expect(index.schema).toBe(2) expect(index.character).toBe('char-so') expect(Array.isArray(index.entities)).toBe(true) - expect(index.entities.length).toBe(69) + // 69 + EC (Hell Bovine, Moo Moo Farm) + expect(index.entities.length).toBe(70) for (const entity of index.entities) { expect(entity.key).toBeDefined() diff --git a/tests/challenger-m4-determinism-parity.test.ts b/tests/challenger-m4-determinism-parity.test.ts index 4ba90a8..102184a 100644 --- a/tests/challenger-m4-determinism-parity.test.ts +++ b/tests/challenger-m4-determinism-parity.test.ts @@ -38,14 +38,16 @@ describe('Challenger M4_2: Asset Baking Pipeline Determinism & 365-Scene Parity' expect(existsSync(ENTITIES_INDEX_PATH)).toBe(true) const baselineHash = sha256File(ENTITIES_INDEX_PATH) - // Expected canonical SHA-256 for Schema 2 69-monster entity index (including vk-hth Valkyrie) - expect(baselineHash).toBe('51da3628b0cb049f5f5bb1282a101cbe0c793f52ed5d91e45077cd91e93a4074') + // Expected canonical SHA-256 for Schema 2 70-monster entity index (including vk-hth Valkyrie + // and ec-hth Hell Bovine: MonStats.txt hellbovine Code=EC, level 39 Moo Moo Farm). Adding + // ec-hth is the only change against the previous 69-monster index (51da3628…). + expect(baselineHash).toBe('675757cffde277b24e2aec11b7440243654282cbb743424ef02ce1d253b41c66') const baselineContent = readFileSync(ENTITIES_INDEX_PATH, 'utf8') const parsed = JSON.parse(baselineContent) expect(parsed.schema).toBe(2) expect(parsed.character).toBe('char-so') - expect(parsed.entities).toHaveLength(69) + expect(parsed.entities).toHaveLength(70) // Compare against /tmp/stress-entity-run1 and /tmp/stress-entity-run2 if present const testDirs = ['/tmp/stress-entity-run1', '/tmp/stress-entity-run2'] diff --git a/tests/packed-entity-art.test.ts b/tests/packed-entity-art.test.ts index e423c79..918d214 100644 --- a/tests/packed-entity-art.test.ts +++ b/tests/packed-entity-art.test.ts @@ -104,14 +104,14 @@ describe('offline pre-baked entity atlases & full Act 1..5 pack index (Issues #3 const charR8 = readFileSync(charR8Path) expect(charR8.byteLength).toBe(charMeta.width * charMeta.height) - // Check all 65 unique monster specs exist as global .r8 files + // Check all 66 unique monster specs exist as global .r8 files (EC = Hell Bovine, Moo Moo Farm) const uniqueSpecs = new Set() for (let act = 1; act <= 5; act += 1) { for (const spec of ACT_MONSTER_SPECS[act] ?? []) { uniqueSpecs.add(`${spec.token.toLowerCase()}-${spec.weapon.toLowerCase()}`) } } - expect(uniqueSpecs.size).toBe(65) + expect(uniqueSpecs.size).toBe(66) for (const key of uniqueSpecs) { const slug = `monster-${key}`