Skip to content

Game data

Overview

Game data lives in src/client/ui/gameData/. categoryRegistry groups items by category; each category has a list of ObjectItem definitions (name, icon, description). Orders, zones, structures, etc. are defined here and shown in the footer.

Categories

Category File Purpose
Orders orders.ts Chop, Mine, Haul, etc. – area actions
Zones zones.ts Sleeping, Storage, Workshop, etc.
Structures structures.ts Wall, Door, Floor, etc.
Production production.ts Production items
Furniture furniture.ts Furniture items
Misc misc.ts Miscellaneous

Display labels (object types)

gameData/objectTypes.tsgetObjectTypeDisplayLabel(typeId) returns a human-readable label for sim object type ids (e.g. wood_log → "Wood logs"). Used by ZonePanel (storage summary), ColonistPanelGearTab (carried item), IsometricMap (tooltips), and fallbacks. Add new types in OBJECT_TYPE_LABELS or rely on the fallback typeId.replace(/_/g, ' ').

Types

ObjectItem

interface ObjectItem {
  name: string;
  icon?: string;
  description?: string;
  /** If true, item is clickable and works; if false, shown as "Coming soon" and dimmed. */
  implemented?: boolean;
}

Only categories that have at least one implemented: true item appear in the footer category tabs (Orders and Zones currently). In the orders grid, each item shows an "Implemented" or "Coming soon" badge; only implemented items trigger actions on click.

ObjectCategory

Orders, Zones, Structures, Production, Furniture, Misc

Order and zone actions (registry)

Footer clicks are handled by OrderActionRegistry (src/client/ui/orderActions/). No hardcoded category/itemName branches in the map.

  • ZonePlacementAction – zone item (e.g. Storage, Sleeping) → set zone mode and area selection mode; registry maps area mode (e.g. storage-zone) back to zone type id for createZoneFromBounds().
  • OrderSelectionAction – order item (e.g. Chop Wood, Mine) → set area selection mode from item name (itemName.toLowerCase().replace(/\s+/g, '-')).

handleOrderClick(category, itemName) looks up the definition and calls def.apply(ctx); area completion uses registry.getZoneTypeIdByAreaMode(mode) for zone placement.

Zones

Zone types (sim/core)

Zone definitions (behavior and ZoneData shape) live in sim/core/zones/ – domain logic, no UI:

  • StorageZoneDefinition – name generation, findBestDestination, getSummary, canDropAt
  • SleepingZoneDefinition – name generation, findNearestTile (walkable)
  • ZoneData – in sim/core/zones/types.ts; SessionManager re-exports it for persistence

ZoneManager (client)

  • Lives in client/ui/utils/ZoneManager.ts; uses ZoneTypeRegistry from sim/core to delegate type-specific behavior.
  • createZoneFromBounds(typeId, ...), removeZone(), removeAllZones()
  • getZoneAtTile(), isTileInZone(), isTileInStorageZone(), isTileInSleepingZone()
  • findBestStorageDestination(), findNearestSleepingZoneTile(), canDropAt(), getZoneStorageSummary() – all delegate to the zone type definition.

ZoneData (sim/core/zones/types.ts)

  • id, type, start, end, tiles, name, color – serializable; SessionManager re-exports for persistence.

Skills

XP thresholds (sim/core/skills.ts)

  • 0→1: 100 XP
  • 1→2: 200 XP
  • 2→3: 500 XP
  • 3+: +500 per level

getTotalXPForLevel(level) – total XP to reach level

Client skills (gameData/skills.ts)

  • defaultSkills – default skill list for UI
  • Same getXPForNextLevel, getTotalXPForLevel logic

Skill–job mapping

  • Chop → Woodworking
  • Mine → Mining

Need handlers and gather completion (client)

  • NeedHandlerRegistry (client/ui/needHandlers/) – per need type (drinking, sleeping): isCrossed(tickNeeds result) and emit(colonistId, eventBus). IsometricMap ticks colonists and calls needHandlerRegistry.emitCrossed() instead of hardcoded needType branches. NeedJobScheduler has createJobForColonist(colonistId, needType) for the event listener.
  • GatherJobCompletionHandler (client/ui/gatherCompletion/) – on gather (chop/mine) complete: create haul jobs, invalidate tiles, render, update selection, save. IsometricMap passes a DefaultGatherJobCompletionHandler with this context into JobSystem as onJobComplete.
  • Footer main tabs (Order manager, Colonists, Jobs): only the active tab is visually highlighted (TabButton active state). The Jobs tab uses WorkAssignmentPanel and the workAssignmentJobs registry (chop, mine, haul, build) for labels and column order.
  • Object overlays (e.g. "Zzzzz" when sleeping, "I'm hungry" / "I'm thirsty"): same bubble style for all; content from object.getOverlayDescriptor(). Need-type overlays: one at a time, visible 5s, then 30s cooldown per colonist (cooldown stored on ColonistObject via setOverlayCooldownUntil). Implemented in ObjectLayer.updateOverlays(); timing constants in ObjectLayer.
  • Zone names: new zones use the format <Type> <no> (e.g. "Storage 1", "Sleeping 2"). See sim/core/zones StorageZoneDefinition and SleepingZoneDefinition generateName().

Cancel current job (in progress)

  • Jobs tab (citizen panel): when the colonist has a current job, "Current job: <label>" and a "Cancel job" button are shown.
  • JobSystem.cancelJob(jobId) removes the job from the queue and clears its path; IsometricMap.cancelJobForColonist(colonistId) calls it and clears the colonist's currentJobId.
  • Status: See todo.md – cancel job is tracked as not fully working yet (to fix: verify path clear, no re-assign, UI refresh).

Adding new definitions

  1. Order – add to orders.ts; add OrderSelectionAction and register in orderActions/registry.ts; wire job creation in area action flow if needed.
  2. Zone – add to zones.ts (footer list); add zone type class in sim/core/zones/ (e.g. storage/, sleeping/) implementing AbstractZoneDefinition, register in ZoneTypeRegistry; add ZonePlacementAction in orderActions and register with zoneTypeId and areaModeId.
  3. Structure – add to structures.ts
  4. Category – add to ObjectCategory in types.ts, create definitions file, register in registry.ts