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>
61 lines
2.2 KiB
GDScript
61 lines
2.2 KiB
GDScript
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)
|