Files
settled-reach/client/ui/time_display.gd
T
jpmschweitzerandClaude Opus 4.6 66a435e201 feat(ui): add diegetic time display on insert HUD (#263)
Time display on InsertOverlay (CanvasLayer 10) shows station local
time (HH:MM), day phase with cycle-tinted color, and day number.
Reads SimulationTime from GameState.game_time via update_from_state().
Adds Constants.format_game_time() helper for testability.
Placeholder layout — position refines when #314 wireframe lands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:16:23 +01:00

83 lines
3.1 KiB
GDScript

extends Control
## #263: Time display — diegetic time readout on the player's neural insert (D-013, D-031).
## Shows station local time (HH:MM), day phase, and day number.
## Lives on InsertOverlay (CanvasLayer 10) per D-051 diegetic insert principle.
## Draw-based for implant visual aesthetic. Updated via update_from_state() from main.gd.
##
## Placeholder layout — position and style will be refined when #314 wireframe lands.
const FONT_SIZE_TIME: int = 15
const FONT_SIZE_META: int = 10
const PADDING := Vector2(10, 7)
const BG_COLOR := Color(0.04, 0.05, 0.08, 0.70)
const BORDER_COLOR := Color(0.10, 0.20, 0.26, 0.65)
# Day phase colors — station lighting cycle (D-031)
const PHASE_COLORS := {
"Morning": Color("#aed6dc"), # pale cyan-blue — early light
"Afternoon": Color("#E0F7FA"), # bright cyan-white — full day
"Evening": Color("#9EBFC4"), # dimmed — dusk transition
"Night": Color("#4a7080"), # dark teal — station nightwatch
}
var _time_str: String = "--:--"
var _phase_str: String = ""
var _day_str: String = ""
var _phase_color: Color = Constants.IMPLANT_TEXT_DIM
var _last_signature: String = ""
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
func update_from_state() -> void:
var gt: Dictionary = GameState.game_time
if gt.is_empty():
return
var tod: int = int(gt.get("time_of_day", 0))
var day: int = int(gt.get("day", 0))
var phase: String = str(gt.get("day_phase", ""))
var sig: String = "%d:%d:%s" % [tod, day, phase]
if sig == _last_signature:
return
_last_signature = sig
_time_str = Constants.format_game_time(tod)
_phase_str = phase
_day_str = "D%d" % (day + 1)
_phase_color = PHASE_COLORS.get(phase, Constants.IMPLANT_TEXT_DIM)
queue_redraw()
func _draw() -> void:
if _time_str == "--:--":
return
var font := ThemeDB.fallback_font
# Measure
var time_size := font.get_string_size(_time_str, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_TIME)
var phase_size := font.get_string_size(_phase_str, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_META)
var day_text := " " + _day_str
var day_size := font.get_string_size(day_text, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_META)
var meta_w := phase_size.x + day_size.x
var content_w := max(time_size.x, meta_w)
var box_w := content_w + PADDING.x * 2
var meta_h := font.get_string_size("A", HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_META).y
var box_h := PADDING.y * 2 + time_size.y + 3 + meta_h
# Background
draw_rect(Rect2(Vector2.ZERO, Vector2(box_w, box_h)), BG_COLOR)
draw_rect(Rect2(Vector2.ZERO, Vector2(box_w, box_h)), BORDER_COLOR, false, 1.0)
# HH:MM (primary, full brightness)
draw_string(font, Vector2(PADDING.x, PADDING.y + time_size.y),
_time_str, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_TIME, Constants.IMPLANT_TEXT_COLOR)
# Phase + day number (secondary, dimmed + phase-tinted)
var meta_y := PADDING.y + time_size.y + 3 + meta_h
draw_string(font, Vector2(PADDING.x, meta_y),
_phase_str, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_META, _phase_color)
draw_string(font, Vector2(PADDING.x + phase_size.x, meta_y),
day_text, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE_META, Constants.IMPLANT_TEXT_DIM)