rimlike/autoload/strings.gd
megaproxy a1e5b38dd6 Phase 11 — Day/night cycle + Lighting (taken before Phase 9 per recommendation)
Three gdscript-refactor agents in parallel; Opus integrated and verified
the day-night transition + torch lighting via MCP runtime + screenshot.

Clock autoload (Agent A, autoload/clock.gd, ~138 lines):
- TICKS_PER_DAY = 4800 → 4 min/day at 1× / 48 s at Fast / 20 s at Ultra
- TICKS_PER_HOUR = 200 (so 60 min × ~3 ticks per minute)
- 4-phase day: night → dawn (5–7) → day (7–19) → dusk (19–22) → night
- darkness_factor() returns 0..1 with linear ramps across dawn/dusk
- phase_changed signal fires on phase transitions
- save_dict / apply_dict for save round-trip
- Boots at Day 1, 06:00 (mid-dawn for atmospheric start)
- Registered in project.godot autoload list (Opus)

Top-bar clock UI (Agent A):
- ClockLabel added to top_bar.tscn (center-anchored at ±80 px)
- _on_clock_refresh in top_bar.gd; early-out string compare to skip text
  assignments when unchanged (cheap per-tick)

Torch entity + lights registry (Agent B, scenes/entities/torch.{gd,tscn} +
workbench.gd + world.gd, ~210 lines):
- class Torch: buildable furniture, BUILD_TICKS=30, LIGHT_RADIUS=6
- Procedural radial gradient texture (64×64) generated at runtime with
  smoothstep falloff → no PNG dependency
- PointLight2D child with the gradient texture, warm fire tint, energy 1.2
- is_on / get_light_tile / get_light_radius duck-typed interface; same
  shape exposed by Workbench when label_text='Hearth' (HEARTH_LIGHT_RADIUS=5)
- World.light_sources registry + register/unregister + is_tile_lit(tile)
  (Manhattan distance, no occlusion — Phase 13 may add wall-occlusion)

CanvasModulate darkness + in_darkness thought (Agent C, ~30 lines mod +
new factory):
- DarkOverlay CanvasModulate node added to world.tscn (first child of
  World root so it tints all sibling layers + entities)
- world.gd._update_dark_overlay lerps DAY_TINT (white) ↔ NIGHT_TINT
  (0.20, 0.22, 0.40 deep cool blue) by Clock.darkness_factor() each tick
- ThoughtCatalog.in_darkness(): persistent, -3 mood, fires when
  darkness > 0.3 AND World.is_tile_lit(pawn.tile) is false
- Pawn._process_thoughts syncs in_darkness alongside hungry/tired

Opus integration:
- project.godot: Clock autoload registered
- world.tscn: DarkOverlay CanvasModulate node, plus the agent additions
- Demo seed: 2 torches inside cabin at (46, 26) + (49, 26), pre-built
- MCP-driven runtime test verified day→night transition + lighting
  effects:
  - Noon: world bright green, torches barely visible (over-bright at noon
    is minor polish — Phase 17 may scale torch energy by darkness)
  - Midnight: world deep blue/green tinted, torches cast yellow halos,
    Hearth ember glows orange, cabin interior warmly lit, exterior dark
- top_bar clock label updates each sim tick (early-out on no-change)

Phase 11 followups for later phases:
- Torch energy should scale with darkness — visible halos at noon are
  silly. Phase 17 will likely tie PointLight2D.energy to clamp(darkness,
  0.2, 1.0) so they're invisible at midday
- Wall-occlusion for light_map — Phase 13's room-detection BFS could
  treat completed wall tiles as occluders so light doesn't bleed through
- 'In darkness' thought currently treats ALL unlit cells as darkness;
  Phase 13's roof flag could differentiate 'indoors-dark' (different
  thought) from 'outdoors-dark'
- Light source visibility through CanvasModulate works correctly thanks
  to PointLight2D's additive blend mode

Acceptance — MCP-verified via play_scene + get_game_screenshot:
-  Day → Dusk → Night cycle visible (Clock.current_phase emits events)
-  CanvasModulate tints world deep blue at night
-  Torches cast visible yellow halos via PointLight2D additive blend
-  Hearth opts-in as a light source via label_text='Hearth' check
-  Top-bar clock shows 'Day N, HH:MM' format and updates each tick
-  in_darkness thought wires through _process_thoughts (would fire if
  a pawn were standing in an unlit night tile — demo didn't capture this
  specifically but the code path is verified)

Delegation report this phase:
- Agent A: Clock autoload + 4-phase day cycle + top-bar UI extension
- Agent B: Torch entity + PointLight2D + procedural radial texture +
  Workbench Hearth opt-in + World.light_sources registry
- Agent C: CanvasModulate world.tscn node + day/night colour lerp +
  in_darkness ThoughtCatalog entry + Pawn persistent thought sync
- Opus: Clock autoload registration in project.godot + 2 torches in
  demo seed + MCP runtime verification at midnight vs noon

~75% of Phase 11 GDScript was subagent-authored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:54:15 +01:00

61 lines
2.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
## i18n string table — player-visible strings ONLY. Code keys, EN values.
##
## Locked from day one (per CLAUDE.md): no hardcoded display copy in scenes or
## scripts. If you have player-facing text, add a key here and call Strings.t(key).
##
## Locale switching is post-MVP; the indirection lands now so we don't have to
## retrofit the whole game later. When the table grows, move it to a .tres or
## external CSV import; the public API (`Strings.t(key)`) stays the same.
const TABLE: Dictionary = {
# Phase 0 placeholder — populate as features land.
&"app.title": "Rimlike",
&"smoke.hello": "Phase 0 — autoloads online.",
# Speed controls (top bar)
&"speed.pause": "",
&"speed.normal": "1×",
&"speed.fast": "5×",
&"speed.ultra": "12×",
# HUD
&"hud.tick": "Tick: {n}",
# Phase 11 — in-game clock display ("{d}" = day, "{t}" = "HH:MM")
&"clock.format": "Day {d}, {t}",
# Pawn state labels
&"pawn.state.idle": "idle",
&"pawn.state.walking": "walking",
# Item types (player-visible this phase)
&"item.wood": "Wood",
&"item.stone": "Stone",
&"item.iron_ore": "Iron ore",
# Item stack count badge ("{n}" is substituted at call site via .format())
&"item.stack_count": "×{n}",
# Phase 6 — new item types (carpenter bench + smelter outputs)
&"item.plank": "Plank",
&"item.stone_block": "Stone block",
# Phase 7 — food loop and cooking chain item types
&"item.flour": "Flour",
&"item.bread": "Bread",
&"item.meal": "Meal",
# Phase 7 — cooking workbench labels
&"workbench.hearth": "Hearth",
&"workbench.millstone": "Millstone",
# Phase 7 — pawn hunger states
&"pawn.state.eating": "eating",
&"pawn.state.hungry": "hungry",
# Phase 11 — mood thoughts (player-visible in pawn-detail, Phase 17)
&"thought.in_darkness": "In darkness",
# Phase 6 — quality tier labels
&"quality.shoddy": "Shoddy",
&"quality.normal": "Normal",
&"quality.excellent": "Excellent",
&"quality.masterwork": "Masterwork",
&"quality.legendary": "Legendary",
}
func t(key: StringName) -> String:
if TABLE.has(key):
return TABLE[key]
push_warning("Strings.t(): missing key %s" % key)
return String(key)