fix(combat): resolve static typecheck errors and event double-clear race (Fixes #404)

This commit is contained in:
troytt 2026-09-24 07:18:35 +00:00
parent b327e5ee77
commit f64440c378
2 changed files with 27 additions and 9 deletions

View File

@ -5627,9 +5627,6 @@ if (typeof window !== 'undefined') {
const loop = new GameLoop({
tickRate: 25,
onTick: () => {
// Clean tick boundary: flush previous tick events before mouseController runs
engine.world.events = []
if (engine.world.pendingKills) engine.world.pendingKills = []
const mouseStep = mouseController.tick()
const effectiveMovement = mouseStep.movement
if (hudManager) {

View File

@ -4,7 +4,8 @@ import { MountedArchives } from '../src/mpq/mount.ts'
import { MpqArchive } from '../src/mpq/archive.ts'
import { fileSource } from '../src/mpq/file-source.ts'
import { loadDropTables, type DropTables } from '../src/game/drop-pipeline.ts'
import { GameEngine, type GameEngineOptions } from '../src/game/engine.ts'
import { GameEngine, type GameEngineOptions, type WorldMapProvider } from '../src/game/engine.ts'
import type { SkillDef } from '../src/game/skills.ts'
import { damageMonster, type Monster } from '../src/game/combat.ts'
import { DEMO_EXPERIENCE, DEMO_NPCS, DEMO_QUESTS } from '../src/game/demo-data.ts'
@ -24,7 +25,9 @@ describe('Combat Kill Event Lifecycle & Single-Drop Gate (Issue #404)', () => {
dropTables = await loadDropTables(archives)
})
const dummyTerrain = {
const dummyTerrain: WorldMapProvider = {
widthPx: 1000,
heightPx: 1000,
overlap: () => 0,
isMissileBlocked: () => false,
}
@ -70,7 +73,6 @@ describe('Combat Kill Event Lifecycle & Single-Drop Gate (Issue #404)', () => {
function createTestEngine(): GameEngine {
const engineOpts: GameEngineOptions = {
spawn: { x: 100, y: 100 },
combatPlayer: { x: 100, y: 100, maxHp: 100, maxMana: 100 },
stats: [
{
id: 'fallen1',
@ -94,6 +96,12 @@ describe('Combat Kill Event Lifecycle & Single-Drop Gate (Issue #404)', () => {
name: 'Attack',
manaCost: 0,
cooldownTicks: 1,
range: 48,
projectile: false,
speed: 0,
baseMinDamage: 10,
baseMaxDamage: 20,
damagePerLevel: 2,
radius: 48,
},
],
@ -116,6 +124,10 @@ describe('Combat Kill Event Lifecycle & Single-Drop Gate (Issue #404)', () => {
}
const engine = new GameEngine(dummyTerrain, engineOpts)
engine.world.player.maxHp = 100
engine.world.player.hp = 100
engine.world.player.maxMana = 100
engine.world.player.mana = 100
engine.world.monsters = [createMonster(0, 110, 100, 20)]
return engine
}
@ -155,14 +167,23 @@ describe('Combat Kill Event Lifecycle & Single-Drop Gate (Issue #404)', () => {
]
// Configure Nova (instant AoE skill)
engine.opts.skills.push({
const novaDef: SkillDef = {
id: 'nova',
name: 'Nova',
manaCost: 0,
cooldownTicks: 1,
range: 80,
projectile: false,
speed: 0,
baseMinDamage: 50,
baseMaxDamage: 50,
damagePerLevel: 0,
radius: 80,
damage: 50, // Lethal to 20 hp monsters
})
}
engine.opts = {
...engine.opts,
skills: [...engine.opts.skills, novaDef],
}
engine.selectedSkill = engine.opts.skills.length - 1
const initialDropsRolled = engine.metrics.dropsRolled