From 0ff4c24bd6a85fda86452a46cf7d831111176a3d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 Mar 2026 00:41:11 +0000 Subject: [PATCH] feat(server): extend InventionTimeline with full invention data and getSummaries Co-Authored-By: Claude Opus 4.6 --- .../__tests__/inventionTimeline.test.ts | 58 +++++++++++++++++-- server/src/industry/inventionTimeline.ts | 21 ++++++- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/server/src/industry/__tests__/inventionTimeline.test.ts b/server/src/industry/__tests__/inventionTimeline.test.ts index 7d66892..baa8ff0 100644 --- a/server/src/industry/__tests__/inventionTimeline.test.ts +++ b/server/src/industry/__tests__/inventionTimeline.test.ts @@ -15,6 +15,11 @@ describe('InventionTimeline', () => { inventorName: 'Gwen', tick: 500, day: 2, + name: 'Rope', + category: 'material', + inputs: [{ itemId: 'plant_fiber', quantity: 3 }], + workshopType: null, + toolRequired: null, }); const all = timeline.getAll(); expect(all).toHaveLength(1); @@ -24,9 +29,9 @@ describe('InventionTimeline', () => { it('counts inventions per entity', () => { const timeline = createInventionTimeline(); - timeline.record({ itemId: 'rope', inventorEntityId: 1, inventorName: 'Gwen', tick: 500, day: 2 }); - timeline.record({ itemId: 'clay', inventorEntityId: 1, inventorName: 'Gwen', tick: 600, day: 2 }); - timeline.record({ itemId: 'kiln', inventorEntityId: 2, inventorName: 'Bram', tick: 700, day: 3 }); + timeline.record({ itemId: 'rope', inventorEntityId: 1, inventorName: 'Gwen', tick: 500, day: 2, name: 'Item', category: 'resource' as const, inputs: [], workshopType: null, toolRequired: null }); + timeline.record({ itemId: 'clay', inventorEntityId: 1, inventorName: 'Gwen', tick: 600, day: 2, name: 'Item', category: 'resource' as const, inputs: [], workshopType: null, toolRequired: null }); + timeline.record({ itemId: 'kiln', inventorEntityId: 2, inventorName: 'Bram', tick: 700, day: 3, name: 'Item', category: 'resource' as const, inputs: [], workshopType: null, toolRequired: null }); expect(timeline.countByEntity(1)).toBe(2); expect(timeline.countByEntity(2)).toBe(1); @@ -35,10 +40,53 @@ describe('InventionTimeline', () => { it('returns entries in insertion order', () => { const timeline = createInventionTimeline(); - timeline.record({ itemId: 'a', inventorEntityId: 1, inventorName: 'X', tick: 300, day: 1 }); - timeline.record({ itemId: 'b', inventorEntityId: 2, inventorName: 'Y', tick: 100, day: 1 }); + timeline.record({ itemId: 'a', inventorEntityId: 1, inventorName: 'X', tick: 300, day: 1, name: 'Item', category: 'resource' as const, inputs: [], workshopType: null, toolRequired: null }); + timeline.record({ itemId: 'b', inventorEntityId: 2, inventorName: 'Y', tick: 100, day: 1, name: 'Item', category: 'resource' as const, inputs: [], workshopType: null, toolRequired: null }); const all = timeline.getAll(); expect(all[0].tick).toBe(300); expect(all[1].tick).toBe(100); }); + + it('stores and returns full invention summary data', () => { + const timeline = createInventionTimeline(); + timeline.record({ + itemId: 'rope', + inventorEntityId: 1, + inventorName: 'Gwen', + tick: 500, + day: 2, + name: 'Rope', + category: 'material', + inputs: [{ itemId: 'plant_fiber', quantity: 3 }], + workshopType: null, + toolRequired: null, + }); + const summaries = timeline.getSummaries(); + expect(summaries).toHaveLength(1); + expect(summaries[0]).toEqual({ + itemId: 'rope', + name: 'Rope', + category: 'material', + inputs: [{ itemId: 'plant_fiber', quantity: 3 }], + workshopType: null, + toolRequired: null, + inventorName: 'Gwen', + day: 2, + }); + }); + + it('getSummaries returns entries in insertion order', () => { + const timeline = createInventionTimeline(); + timeline.record({ + itemId: 'a', inventorEntityId: 1, inventorName: 'X', tick: 300, day: 1, + name: 'A Item', category: 'tool', inputs: [], workshopType: null, toolRequired: null, + }); + timeline.record({ + itemId: 'b', inventorEntityId: 2, inventorName: 'Y', tick: 100, day: 1, + name: 'B Item', category: 'resource', inputs: [], workshopType: null, toolRequired: null, + }); + const summaries = timeline.getSummaries(); + expect(summaries[0].itemId).toBe('a'); + expect(summaries[1].itemId).toBe('b'); + }); }); diff --git a/server/src/industry/inventionTimeline.ts b/server/src/industry/inventionTimeline.ts index ef4d57e..20f1692 100644 --- a/server/src/industry/inventionTimeline.ts +++ b/server/src/industry/inventionTimeline.ts @@ -1,4 +1,4 @@ -import type { EntityId } from '@dflike/shared'; +import type { EntityId, InventionSummary } from '@dflike/shared'; export interface InventionEntry { itemId: string; @@ -6,11 +6,17 @@ export interface InventionEntry { inventorName: string; tick: number; day: number; + name: string; + category: 'resource' | 'tool' | 'material' | 'structure'; + inputs: { itemId: string; quantity: number }[]; + workshopType: string | null; + toolRequired: string | null; } export interface InventionTimeline { record(entry: InventionEntry): void; getAll(): InventionEntry[]; + getSummaries(): InventionSummary[]; countByEntity(entityId: EntityId): number; } @@ -26,6 +32,19 @@ export function createInventionTimeline(): InventionTimeline { return [...entries]; }, + getSummaries(): InventionSummary[] { + return entries.map(e => ({ + itemId: e.itemId, + name: e.name, + category: e.category, + inputs: e.inputs, + workshopType: e.workshopType, + toolRequired: e.toolRequired, + inventorName: e.inventorName, + day: e.day, + })); + }, + countByEntity(entityId: EntityId): number { return entries.filter(e => e.inventorEntityId === entityId).length; },