73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { GameEngine } from '../src/game/engine.ts'
|
|
import type { Item } from '../src/game/items.ts'
|
|
|
|
function makeTestItem(id: number, code: string, name: string): Item {
|
|
return {
|
|
id,
|
|
code,
|
|
name,
|
|
type: 'misc',
|
|
quality: 'normal',
|
|
level: 1,
|
|
identified: true,
|
|
invWidth: 1,
|
|
invHeight: 1,
|
|
stats: [],
|
|
baseCost: 50,
|
|
} as unknown as Item
|
|
}
|
|
|
|
describe('Issue #522: Ground Items Single Source of Truth (engine.groundItems)', () => {
|
|
it('keeps engine.ground strictly synchronized as a read-only view over engine.groundItems', () => {
|
|
const engine = new GameEngine('nec')
|
|
const itemA = makeTestItem(1, 'hp1', 'Minor Healing Potion')
|
|
const itemB = makeTestItem(2, 'mp1', 'Minor Mana Potion')
|
|
|
|
const gA = engine.dropItemToGround(itemA, 100, 100)
|
|
const gB = engine.dropItemToGround(itemB, 108, 108)
|
|
|
|
expect(engine.groundItems.count).toBe(2)
|
|
expect(engine.ground.length).toBe(2)
|
|
expect(engine.ground.map(g => g.id)).toEqual([gA.id, gB.id])
|
|
|
|
// Picking up gA by exact ID removes only gA and preserves nearby gB
|
|
const picked = engine.pickupGroundEntity(gA.id)
|
|
expect(picked).toBe(true)
|
|
expect(engine.groundItems.count).toBe(1)
|
|
expect(engine.ground.length).toBe(1)
|
|
expect(engine.ground[0]!.id).toBe(gB.id)
|
|
expect(engine.bag.items.some(p => p.item.id === itemA.id)).toBe(true)
|
|
})
|
|
|
|
it('saves and restores ground items without phantom duplicates on level transition', () => {
|
|
const engine = new GameEngine('dru')
|
|
const item1 = makeTestItem(10, 'rvl', 'Full Rejuvenation Potion')
|
|
engine.dropItemToGround(item1, 200, 200)
|
|
engine.groundItems.spawnGold(210, 210, 350, 0)
|
|
|
|
expect(engine.groundItems.count).toBe(2)
|
|
|
|
// Transition from level 1 -> level 2
|
|
engine.saveLevelGroundState(1)
|
|
engine.restoreLevelGroundState(2)
|
|
expect(engine.groundItems.count).toBe(0)
|
|
expect(engine.ground.length).toBe(0)
|
|
|
|
// Return to level 1
|
|
engine.saveLevelGroundState(2)
|
|
engine.restoreLevelGroundState(1)
|
|
expect(engine.groundItems.count).toBe(2)
|
|
expect(engine.ground.length).toBe(2)
|
|
expect(engine.ground.some(g => g.isGold && g.goldAmount === 350)).toBe(true)
|
|
expect(engine.ground.some(g => !g.isGold && g.item?.code === 'rvl')).toBe(true)
|
|
|
|
// Verify loadSnapshot also preserves non-enumerable .id getter on restored.ground entries
|
|
const drop1 = engine.ground[0]!
|
|
const snap = engine.saveSnapshot()
|
|
const restored = new GameEngine('dru')
|
|
restored.loadSnapshot(snap)
|
|
expect(restored.ground[0]!.id).toBe(drop1.id)
|
|
})
|
|
})
|