diff --git a/src/common/rpg/components/inventory.ts b/src/common/rpg/components/inventory.ts index 65a389e..eea3216 100644 --- a/src/common/rpg/components/inventory.ts +++ b/src/common/rpg/components/inventory.ts @@ -237,7 +237,7 @@ export class Inventory extends Component { * `slotId` specifies which inventory slot to use from (otherwise any slot is used). */ @action - async use(arg?: string | { itemId?: string; slotId?: SlotId }, ctx?: EvalContext): Promise { + use(arg?: string | { itemId?: string; slotId?: SlotId }, ctx?: EvalContext): boolean { const resolved = this.#resolveItem(arg); if (!resolved) return false; const { itemId, slotId } = resolved; @@ -261,7 +261,7 @@ export class Inventory extends Component { if (usable.consumeOnUse) this.remove({ itemId, amount: 1, slotId }); - await usable.use(ctx ?? this.context); + usable.use(ctx ?? this.context); return true; } diff --git a/src/common/rpg/components/item.ts b/src/common/rpg/components/item.ts index b728102..8b520ac 100644 --- a/src/common/rpg/components/item.ts +++ b/src/common/rpg/components/item.ts @@ -46,11 +46,11 @@ export class Usable extends Component { @variable get consumeOnUse(): boolean { return this.state.consumeOnUse; } @action - async use(arg?: EvalContext, ctx?: EvalContext): Promise { + use(arg?: EvalContext, ctx?: EvalContext): void { ctx = arg ?? ctx ?? this.context; if (!ctx) return; for (const action of this.state.actions) { - await executeAction(action, ctx); + executeAction(action, ctx); } } } diff --git a/src/common/rpg/core/world.ts b/src/common/rpg/core/world.ts index 8d01784..d519a05 100644 --- a/src/common/rpg/core/world.ts +++ b/src/common/rpg/core/world.ts @@ -78,7 +78,7 @@ export abstract class Component> { export abstract class System { onAdd(_world: World): void { } onRemove(_world: World): void { } - async update(_world: World, _dt: number): Promise { }; + update(_world: World, _dt: number): void { }; } type ComponentFilter = (component: T) => boolean; @@ -316,8 +316,10 @@ export class World { } } - async update(dt: number): Promise { - for (const system of this.#systems) await system.update(this, dt); + update(dt: number) { + for (const system of this.#systems) { + system.update(this, dt); + } } emit(entityId: string, event: string, data?: unknown): void { diff --git a/src/common/rpg/systems/combat.ts b/src/common/rpg/systems/combat.ts index 2c2e3e2..51d6992 100644 --- a/src/common/rpg/systems/combat.ts +++ b/src/common/rpg/systems/combat.ts @@ -6,7 +6,7 @@ import { System, World } from "../core/world"; let hitEffectCounter = 0; export class CombatSystem extends System { - override async update(world: World): Promise { + override update(world: World) { for (const [target] of world.query(Attacked)) { const health = target.get(Health); if (!health) { diff --git a/src/common/rpg/systems/cooldown.ts b/src/common/rpg/systems/cooldown.ts index 9ebece7..023abd8 100644 --- a/src/common/rpg/systems/cooldown.ts +++ b/src/common/rpg/systems/cooldown.ts @@ -2,7 +2,7 @@ import { Cooldown } from "../components/cooldown"; import { System, type World } from "../core/world"; export class CooldownSystem extends System { - override async update(world: World, dt: number): Promise { + override update(world: World, dt: number) { for (const [, , cooldown] of world.query(Cooldown)) { cooldown.update(dt); } diff --git a/src/common/rpg/systems/effect.ts b/src/common/rpg/systems/effect.ts index 7063377..928f885 100644 --- a/src/common/rpg/systems/effect.ts +++ b/src/common/rpg/systems/effect.ts @@ -2,7 +2,7 @@ import { Effect } from "../components/effect"; import { System, type Entity, type World } from "../core/world"; export class EffectSystem extends System { - override async update(world: World, dt: number): Promise { + override update(world: World, dt: number) { const expired: [Entity, string][] = []; for (const [entity, key, effect] of world.query(Effect)) { diff --git a/src/common/rpg/systems/quest.ts b/src/common/rpg/systems/quest.ts index 1f6f111..4518842 100644 --- a/src/common/rpg/systems/quest.ts +++ b/src/common/rpg/systems/quest.ts @@ -27,12 +27,12 @@ export class QuestSystem extends System { this.#tracking.clear(); } - override async update(world: World, _dt: number): Promise { + override update(world: World) { for (const [entity, key, questLog] of world.query(QuestLog)) { if (!this.#tracking.has(entity.id)) { this.#initTracking(entity, key, questLog); } - await this.#diffAndCheck(entity, world); + this.#diffAndCheck(entity, world); } // Prune tracking for entities that no longer exist @@ -45,9 +45,9 @@ export class QuestSystem extends System { } /** Force a full re-evaluation of all active quests. Use as an escape hatch. */ - async triggerCheck(world: World): Promise { + triggerCheck(world: World) { for (const [entity] of world.query(QuestLog)) { - await this.#checkEntity(entity, world, 'all'); + this.#checkEntity(entity, world, 'all'); } } @@ -68,7 +68,7 @@ export class QuestSystem extends System { } // Keep tracking fresh as quest state changes - const onStarted = async ({ data }: { data?: unknown }) => { + const onStarted = ({ data }: { data?: unknown }) => { const { questId } = data as { questId: string }; const quest = questLog.getQuest(questId); const state = questLog.getState(questId); @@ -76,15 +76,15 @@ export class QuestSystem extends System { if (stage) { this.#addQuestVars(tracking, questId, stage); // Evaluate immediately — conditions may already be satisfied at start - await this.#checkEntity(entity, entity.world, new Set([questId])); + this.#checkEntity(entity, entity.world, new Set([questId])); } }; - const onStage = async ({ data }: { data?: unknown }) => { + const onStage = ({ data }: { data?: unknown }) => { const { questId, stage } = data as { questId: string; stage: QuestStage }; this.#removeQuestVars(tracking, questId); this.#addQuestVars(tracking, questId, stage); - await this.#checkEntity(entity, entity.world, new Set([questId])); + this.#checkEntity(entity, entity.world, new Set([questId])); }; const onDone = ({ data }: { data?: unknown }) => { @@ -128,7 +128,7 @@ export class QuestSystem extends System { } } - async #diffAndCheck(entity: Entity, world: World): Promise { + #diffAndCheck(entity: Entity, world: World) { const tracking = this.#tracking.get(entity.id); if (!tracking || tracking.varToQuests.size === 0) return; @@ -145,10 +145,10 @@ export class QuestSystem extends System { } } - if (dirty.size > 0) await this.#checkEntity(entity, world, dirty); + if (dirty.size > 0) this.#checkEntity(entity, world, dirty); } - async #checkEntity(entity: Entity, world: World, filter: Set | 'all'): Promise { + #checkEntity(entity: Entity, world: World, filter: Set | 'all') { const questLog = entity.get(QuestLog); if (!questLog) return; @@ -171,7 +171,7 @@ export class QuestSystem extends System { if (!stage.objectives.every(o => evaluateCondition(o.condition, ctx))) continue; - for (const action of stage.actions) await executeAction(action, ctx); + for (const action of stage.actions) executeAction(action, ctx); questLog._advance(questId); } } diff --git a/src/common/rpg/utils/variables.ts b/src/common/rpg/utils/variables.ts index e4c52ee..24ae8b4 100644 --- a/src/common/rpg/utils/variables.ts +++ b/src/common/rpg/utils/variables.ts @@ -69,7 +69,7 @@ interface Contextable { readonly context: EvalContext; } -export async function executeAction(action: RPGAction, ctx: EvalContext | Contextable): Promise { +export function executeAction(action: RPGAction, ctx: EvalContext | Contextable): unknown { if (typeof action === 'string') { action = { type: action }; } diff --git a/test/common/rpg/combat.test.ts b/test/common/rpg/combat.test.ts index 14f2df2..7bbb757 100644 --- a/test/common/rpg/combat.test.ts +++ b/test/common/rpg/combat.test.ts @@ -14,7 +14,7 @@ function world() { } describe('CombatSystem — damage', () => { - it('reduces target health by damage value', async () => { + it('reduces target health by damage value', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 20, damageType: 'physical' })); @@ -22,11 +22,11 @@ describe('CombatSystem — damage', () => { const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(80); }); - it('defense on target reduces damage', async () => { + it('defense on target reduces damage', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 20, damageType: 'physical' })); @@ -35,11 +35,11 @@ describe('CombatSystem — damage', () => { target.add('health', new Health({ value: 100, min: 0 })); target.add('armor', new Defense({ value: 8, damageType: 'physical' })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(88); }); - it('defense only applies to matching damage type', async () => { + it('defense only applies to matching damage type', () => { const w = world(); const spell = w.createEntity('spell'); spell.add('dmg', new Damage({ value: 20, damageType: 'fire' })); @@ -48,11 +48,11 @@ describe('CombatSystem — damage', () => { target.add('health', new Health({ value: 100, min: 0 })); target.add('armor', new Defense({ value: 8, damageType: 'physical' })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'spell' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(80); }); - it('minDamage is enforced when defense exceeds damage', async () => { + it('minDamage is enforced when defense exceeds damage', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 5, damageType: 'physical', minDamage: 3 })); @@ -61,22 +61,22 @@ describe('CombatSystem — damage', () => { target.add('health', new Health({ value: 100, min: 0 })); target.add('armor', new Defense({ value: 10, damageType: 'physical' })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(97); }); - it('null sourceId falls back to Damage on attacker', async () => { + it('null sourceId falls back to Damage on attacker', () => { const w = world(); const attacker = w.createEntity('attacker'); attacker.add('dmg', new Damage({ value: 15, damageType: 'physical' })); const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: null })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(85); }); - it('multiple attacks in one tick accumulate', async () => { + it('multiple attacks in one tick accumulate', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 10, damageType: 'physical' })); @@ -85,11 +85,11 @@ describe('CombatSystem — damage', () => { target.add('health', new Health({ value: 100, min: 0 })); target.add('atk1', new Attacked({ attackerId: 'a', sourceId: 'sword' })); target.add('atk2', new Attacked({ attackerId: 'a', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(80); }); - it('Attacked components are removed after processing', async () => { + it('Attacked components are removed after processing', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 5, damageType: 'physical' })); @@ -97,53 +97,53 @@ describe('CombatSystem — damage', () => { const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'a', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.has(Attacked)).toBeFalse(); }); - it('missing attacker entity skips attack gracefully', async () => { + it('missing attacker entity skips attack gracefully', () => { const w = world(); const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'ghost', sourceId: null })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(100); }); - it('missing source entity skips attack gracefully', async () => { + it('missing source entity skips attack gracefully', () => { const w = world(); w.createEntity('attacker'); const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'gone' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(100); }); - it('source with no Damage component skips attack gracefully', async () => { + it('source with no Damage component skips attack gracefully', () => { const w = world(); w.createEntity('attacker'); w.createEntity('empty_source'); const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'empty_source' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(100); }); - it('target with no Health component is skipped gracefully', async () => { + it('target with no Health component is skipped gracefully', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 10, damageType: 'physical' })); w.createEntity('attacker'); const target = w.createEntity('target'); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); // should not throw + w.update(1); // should not throw }); }); describe('CombatSystem — on-hit effects', () => { - it('onHit effect is applied to target on hit', async () => { + it('onHit effect is applied to target on hit', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 10, damageType: 'physical' })); @@ -152,7 +152,7 @@ describe('CombatSystem — on-hit effects', () => { const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(target.get(Health)!.value).toBe(85); // 100 - 10 dmg - 5 burn modifier expect(target.getAll(Effect).length).toBe(1); }); @@ -166,7 +166,7 @@ describe('CombatSystem — on-hit effects', () => { expect(sword.get(Stat, 'str')!.value).toBe(50); }); - it('onHit effect expires on target after duration', async () => { + it('onHit effect expires on target after duration', () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 5, damageType: 'physical' })); @@ -175,16 +175,16 @@ describe('CombatSystem — on-hit effects', () => { const target = w.createEntity('target'); target.add('health', new Health({ value: 100, min: 0 })); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); const afterHit = target.get(Health)!.value; // 85 - await w.update(2); // burn expires + w.update(2); // burn expires expect(target.getAll(Effect).length).toBe(0); expect(target.get(Health)!.value).toBe(afterHit + 10); // modifier reverted }); }); describe('CombatSystem — events', () => { - it("emits 'hit' on target with attack info", async () => { + it("emits 'hit' on target with attack info", () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 10, damageType: 'fire' })); @@ -194,7 +194,7 @@ describe('CombatSystem — events', () => { const hits: unknown[] = []; target.on('hit', ({ data }) => hits.push(data)); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(hits.length).toBe(1); expect((hits[0] as any).damageType).toBe('fire'); expect((hits[0] as any).amount).toBe(10); @@ -202,7 +202,7 @@ describe('CombatSystem — events', () => { expect((hits[0] as any).sourceId).toBe('sword'); }); - it("emits 'kill' when target health reaches zero", async () => { + it("emits 'kill' when target health reaches zero", () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 999, damageType: 'physical' })); @@ -212,11 +212,11 @@ describe('CombatSystem — events', () => { const kills: unknown[] = []; target.on('kill', ({ data }) => kills.push(data)); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(kills.length).toBe(1); }); - it("does not emit 'kill' when target survives", async () => { + it("does not emit 'kill' when target survives", () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 5, damageType: 'physical' })); @@ -226,11 +226,11 @@ describe('CombatSystem — events', () => { const kills: unknown[] = []; target.on('kill', ({ data }) => kills.push(data)); target.add('atk', new Attacked({ attackerId: 'attacker', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(kills.length).toBe(0); }); - it("emits 'hit' per attack when multiple attacks land", async () => { + it("emits 'hit' per attack when multiple attacks land", () => { const w = world(); const sword = w.createEntity('sword'); sword.add('dmg', new Damage({ value: 5, damageType: 'physical' })); @@ -241,7 +241,7 @@ describe('CombatSystem — events', () => { target.on('hit', ({ data }) => hits.push(data)); target.add('atk1', new Attacked({ attackerId: 'a', sourceId: 'sword' })); target.add('atk2', new Attacked({ attackerId: 'a', sourceId: 'sword' })); - await w.update(1); + w.update(1); expect(hits.length).toBe(2); }); }); diff --git a/test/common/rpg/cooldown.test.ts b/test/common/rpg/cooldown.test.ts index b541d1a..10d81d7 100644 --- a/test/common/rpg/cooldown.test.ts +++ b/test/common/rpg/cooldown.test.ts @@ -136,33 +136,33 @@ describe('Cooldown — update(dt)', () => { }); describe('CooldownSystem', () => { - it('drives all cooldowns each tick', async () => { + it('drives all cooldowns each tick', () => { const w = world(); const e = w.createEntity(); e.add('cd', new Cooldown(2)); - await w.update(1); + w.update(1); expect(e.get(Cooldown, 'cd')!.state.remaining).toBe(1); }); - it('marks cooldown ready after enough ticks', async () => { + it('marks cooldown ready after enough ticks', () => { const w = world(); const e = w.createEntity(); e.add('cd', new Cooldown(2)); const events: unknown[] = []; e.on('cd.ready', () => events.push(true)); - await w.update(1); - await w.update(1); + w.update(1); + w.update(1); expect(events.length).toBe(1); expect(e.get(Cooldown, 'cd')!.ready).toBeTrue(); }); - it('handles multiple cooldowns on different entities', async () => { + it('handles multiple cooldowns on different entities', () => { const w = world(); const a = w.createEntity('a'); const b = w.createEntity('b'); a.add('cd', new Cooldown(1)); b.add('cd', new Cooldown(3)); - await w.update(2); + w.update(2); expect(a.get(Cooldown, 'cd')!.ready).toBeTrue(); expect(b.get(Cooldown, 'cd')!.ready).toBeFalse(); }); diff --git a/test/common/rpg/effect.test.ts b/test/common/rpg/effect.test.ts index 50702c1..260625c 100644 --- a/test/common/rpg/effect.test.ts +++ b/test/common/rpg/effect.test.ts @@ -54,61 +54,61 @@ describe('Effect — onAdd / onRemove', () => { }); describe('Effect — duration', () => { - it('expires after duration ticks', async () => { + it('expires after duration ticks', () => { const { w, e, stat } = withStat(10); e.add('fx', new Effect('str', 5, 'value', 2)); expect(stat.value).toBe(15); - await w.update(1); + w.update(1); expect(e.has(Effect)).toBeTrue(); - await w.update(1); + w.update(1); expect(e.has(Effect)).toBeFalse(); expect(stat.value).toBe(10); }); - it('emits expired before removal', async () => { + it('emits expired before removal', () => { const { w, e } = withStat(10); e.add('fx', new Effect('str', 1, 'value', 1)); const events: string[] = []; e.on('fx.expired', () => events.push('expired')); - await w.update(1); + w.update(1); expect(events).toEqual(['expired']); }); - it('reset() restarts timer', async () => { + it('reset() restarts timer', () => { const { w, e, stat } = withStat(10); e.add('fx', new Effect('str', 5, 'value', 2)); - await w.update(1.5); + w.update(1.5); e.get(Effect, 'fx')!.reset(); - await w.update(1.5); // would have expired without reset + w.update(1.5); // would have expired without reset expect(e.has(Effect)).toBeTrue(); expect(stat.value).toBe(15); }); - it('reset(duration) changes duration', async () => { + it('reset(duration) changes duration', () => { const { w, e } = withStat(10); e.add('fx', new Effect('str', 5, 'value', 1)); e.get(Effect, 'fx')!.reset(10); - await w.update(5); + w.update(5); expect(e.has(Effect)).toBeTrue(); }); - it('clear() immediately expires effect', async () => { + it('clear() immediately expires effect', () => { const { w, e, stat } = withStat(10); e.add('fx', new Effect('str', 5, 'value', 100)); e.get(Effect, 'fx')!.clear(); - await w.update(0.01); + w.update(0.01); expect(e.has(Effect)).toBeFalse(); expect(stat.value).toBe(10); }); }); describe('Effect — permanent', () => { - it('permanent effect is never removed by EffectSystem', async () => { + it('permanent effect is never removed by EffectSystem', () => { const { w, e, stat } = withStat(10); e.add('fx', new Effect('str', 5)); - await w.update(100); + w.update(100); expect(e.has(Effect)).toBeTrue(); expect(stat.value).toBe(15); }); @@ -128,10 +128,10 @@ describe('Effect — scope: onHit', () => { expect(stat.value).toBe(10); }); - it('EffectSystem does not tick or remove onHit effects', async () => { + it('EffectSystem does not tick or remove onHit effects', () => { const { w, e } = withStat(10); e.add('fx', new Effect('str', 5, 'value', 1, undefined, 'onHit')); - await w.update(10); + w.update(10); expect(e.has(Effect)).toBeTrue(); }); diff --git a/test/common/rpg/inventory.test.ts b/test/common/rpg/inventory.test.ts index d183db4..a3c5338 100644 --- a/test/common/rpg/inventory.test.ts +++ b/test/common/rpg/inventory.test.ts @@ -235,7 +235,7 @@ describe('Inventory — equip', () => { }); describe('Inventory — use', () => { - it('executes Usable actions', async () => { + it('executes Usable actions', () => { const w = world(); const player = w.createEntity('player'); player.add('str', new Stat({ value: 10 })); @@ -244,11 +244,11 @@ describe('Inventory — use', () => { usable: { actions: [{ type: 'str.update', arg: 5 }], consumeOnUse: false }, }); player.get(Inventory)!.add({ itemId: 'potion', amount: 1 }); - await player.get(Inventory)!.use({ itemId: 'potion' }); + player.get(Inventory)!.use({ itemId: 'potion' }); expect(player.get(Stat, 'str')!.value).toBe(15); }); - it('consumes item when consumeOnUse is true', async () => { + it('consumes item when consumeOnUse is true', () => { const w = world(); const player = w.createEntity('player'); player.add('inv', new Inventory()); @@ -257,7 +257,7 @@ describe('Inventory — use', () => { usable: { actions: [], consumeOnUse: true }, }); player.get(Inventory)!.add({ itemId: 'herb', amount: 3 }); - await player.get(Inventory)!.use({ itemId: 'herb' }); + player.get(Inventory)!.use({ itemId: 'herb' }); expect(player.get(Inventory)!.getAmount('herb')).toBe(2); }); }); diff --git a/test/common/rpg/quest.test.ts b/test/common/rpg/quest.test.ts index 928ec96..8727b86 100644 --- a/test/common/rpg/quest.test.ts +++ b/test/common/rpg/quest.test.ts @@ -371,38 +371,38 @@ describe('Quests.validate', () => { // ── QuestSystem — objective completion ──────────────────────────────────────── describe('QuestSystem — objective completion', () => { - it('completes single-stage quest when objective is satisfied', async () => { + it('completes single-stage quest when objective is satisfied', () => { const w = world(); const { vars, questLog } = makePlayer(w, [simpleQuest()]); questLog.start('q1'); vars.set({ key: 'done', value: true }); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('completed'); }); - it('does not complete quest while objective is unsatisfied', async () => { + it('does not complete quest while objective is unsatisfied', () => { const w = world(); const { questLog } = makePlayer(w, [simpleQuest()]); questLog.start('q1'); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('active'); }); - it('does not process inactive quests', async () => { + it('does not process inactive quests', () => { const w = world(); const { vars, questLog } = makePlayer(w, [simpleQuest()]); vars.set({ key: 'done', value: true }); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('inactive'); }); - it('runs stage actions before advancing', async () => { + it('runs stage actions before advancing', () => { const w = world(); // action sets vars.reward = true on the player entity const quest = simpleQuest('q1', [{ type: 'vars.set', arg: { key: 'reward', value: true } }]); @@ -410,7 +410,7 @@ describe('QuestSystem — objective completion', () => { questLog.start('q1'); vars.set({ key: 'done', value: true }); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('completed'); expect(vars.state.vars['reward']).toBe(true); @@ -418,7 +418,7 @@ describe('QuestSystem — objective completion', () => { }); describe('QuestSystem — multi-stage progression', () => { - it('advances through stages as objectives are satisfied', async () => { + it('advances through stages as objectives are satisfied', () => { const w = world(); const { vars, questLog } = makePlayer(w, [twoStageQuest()]); @@ -426,34 +426,34 @@ describe('QuestSystem — multi-stage progression', () => { // satisfy stage 0 vars.set({ key: 'step', value: 1 }); - await w.update(1); + w.update(1); expect(questLog.getState('q2')?.stageIndex).toBe(1); expect(questLog.getState('q2')?.status).toBe('active'); // satisfy stage 1 vars.set({ key: 'step', value: 2 }); - await w.update(1); + w.update(1); expect(questLog.getState('q2')?.status).toBe('completed'); }); - it('does not skip stages', async () => { + it('does not skip stages', () => { const w = world(); const { vars, questLog } = makePlayer(w, [twoStageQuest()]); questLog.start('q2'); vars.set({ key: 'step', value: 2 }); // would satisfy both stages - await w.update(1); + w.update(1); // only advances one stage per tick expect(questLog.getState('q2')?.stageIndex).toBe(1); - await w.update(1); // second tick completes it + w.update(1); // second tick completes it expect(questLog.getState('q2')?.status).toBe('completed'); }); }); describe('QuestSystem — fail conditions', () => { - it('fails quest when failCondition is met', async () => { + it('fails quest when failCondition is met', () => { const w = world(); const quest: Quest = { id: 'q1', @@ -471,12 +471,12 @@ describe('QuestSystem — fail conditions', () => { questLog.start('q1'); vars.set({ key: 'failed', value: true }); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('failed'); }); - it('fail condition takes priority over objective completion', async () => { + it('fail condition takes priority over objective completion', () => { const w = world(); const quest: Quest = { id: 'q1', @@ -494,14 +494,14 @@ describe('QuestSystem — fail conditions', () => { questLog.start('q1'); vars.set({ key: 'done', value: true }); - await w.update(1); + w.update(1); expect(questLog.getState('q1')?.status).toBe('failed'); // fail checked first }); }); describe('QuestSystem — multiple quests', () => { - it('tracks multiple quests independently', async () => { + it('tracks multiple quests independently', () => { const w = world(); const player = w.createEntity('player'); const vars = player.add('vars', new Variables()); @@ -520,7 +520,7 @@ describe('QuestSystem — multiple quests', () => { log.start('q2'); vars.set({ key: 'done1', value: true }); // only q1's condition satisfied - await w.update(1); + w.update(1); expect(log.getState('q1')?.status).toBe('completed'); expect(log.getState('q2')?.status).toBe('active');