rimlike/scenes/world/indoor_tint_overlay.gd
megaproxy 9cf9b7dbfd Phase 13: Rooms + Auto-roof + Beauty + Dirtiness + Cleaning
Three-agent fan-out — Opus pre-wrote Room class, World.rooms/room_at_tile/is_indoor,
4 EventBus signals before dispatch so the slices ran fully parallel.

DECISION: Big-room UX = bump auto-roof cap to 16, banner above. Cabin
(24 tiles) intentionally exceeds cap to exercise the warning path; a
5×5 test shed (9 interior tiles) was added to exercise the roof path.

Room detection (Agent A):
- scenes/world/room.gd — class_name Room, tiles/bounds/is_under_roof,
  contains_tile() bounds-then-list-checked, recompute_bounds()
- scenes/world/room_detector.gd — class_name RoomDetector, BFS 4-dir
  from floor/door tiles, walls/terrain as boundary, doors counted as
  room interior. Detects up to 4× cap; auto-roofs only ≤16.
- World.mark_wall_tile/mark_floor_tile/mark_door_tile hook BFS recompute
- Door._complete() now erases wall-layer stamp + registers door tile
- Designation.TOOL_NO_ROOF paint mode wired (UI button deferred Phase 17)
- EventBus.room_changed / room_too_large signals

Indoor/Shelter (Agent B):
- Pawn._is_sheltered() rerouted: World.is_indoor() first, floor-proxy fallback
- IndoorTintOverlay Node2D — _draw fills roofed-room tiles at α=0.10 warm
- Crop._on_sim_tick skips stage advance when World.is_indoor(tile)

Beauty + Dirtiness + Cleaning + Room thoughts (Agent C):
- BeautySystem sparse map, linear falloff radius=3, Quality multiplier
  (SHODDY 0.5 → LEGENDARY 2.5). Base: Bed +2, Workbench +1, Torch +3, Hearth +4
- DirtinessSystem 0-100, tier crossings (clean<25/dirty<60/filthy≥60)
  emit tile_dirtiness_changed. bump/bump_clean/bump_pawn_traffic API
- CleaningProvider priority=2, KIND_CLEAN toil, 2.5 dirt/tick for ~40 ticks
- Bed/Torch/Workbench _complete() now register with BeautySystem
- 7 room mood thoughts: clean_room (+2), dirty_room (-3), filthy_room (-6),
  beautiful_room (+4), ugly_room (-3), slept_in_room (+3 EVENT, wires Ph 17),
  ate_without_table (-3 EVENT, wires Ph 17)
- Pawn._sync_room_thoughts called from _process_thoughts after cold block,
  defensive against null rooms/systems

Integration recovery (Opus):
- Agent C's BeautySystem/DirtinessSystem/CleaningProvider/IndoorTintOverlay
  instantiation in world.gd never landed (only field declarations + entity
  hooks survived). Added preloads + runtime add_child + autoload bindings +
  CleaningProvider registration + furniture pre-seed in _ready
- Added _prestamp_test_shed_for_room_detector with _spawn_complete_wall/floor
  helpers so a 5×5 visible shed exercises the auto-roof path at boot

MCP runtime verified:
- Rooms: cabin Room#2 size=24 roofed=false (room_too_large fires),
  shed Room#3 size=9 roofed=true (auto-roof active)
- beauty_map size=50 around prebuilt furniture; bed at (47,24) beauty=4.0
- Bram teleported to (36, 25) in shed → indoor=true, sheltered=true,
  thoughts=[clean_room +2], mood=52.0
- Screenshot: shed walls + brown floor visible; cabin warmly torch-lit;
  Spring 1/12 indicator; Day 1 07:52

Delegation: 3× gdscript-refactor (Sonnet) agents in parallel;
integration recovery + MCP verify on Opus.

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

52 lines
1.8 KiB
GDScript
Raw Permalink 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 Node2D
## Phase 13 — subtle warm overlay drawn over every tile that belongs to an
## enclosed, roofed Room.
##
## Rendering model: Node2D _draw() filled on EventBus.room_changed only — NOT
## every render frame. At MVP scale (< 20 rooms × ~10 tiles each) that's at
## most ~200 draw_rect calls per room-topology change, which is negligible.
##
## Placement: child of the World Node2D, z_index = 3 (above Floor layer at 1,
## same z as Designation — kept above floor, below pawns/entities at 4+).
##
## The overlay does NOT use CanvasModulate or shaders; a plain translucent rect
## per tile is correct, cheap, and doesn't interact with the day/night modulate.
##
## When the room registry is empty (boot, before RoomDetector fires), _draw()
## simply does nothing — graceful degradation.
class_name IndoorTintOverlay
## Warm candlelight tint. Alpha is deliberately very low (0.10) so the floor
## and entity sprites beneath remain fully legible.
const INDOOR_COLOR: Color = Color(1.0, 0.95, 0.85, 0.10)
const TILE_SIZE_PX: int = 16 ## Mirror of World.TILE_SIZE_PX; standalone to avoid circular dep.
func _ready() -> void:
z_index = 3
# Listen for room topology changes and redraw. room_changed fires when any
# Room is created, destroyed, or recomputed by RoomDetector (Agent A).
EventBus.room_changed.connect(_on_room_changed)
func _on_room_changed(_room_id: int) -> void:
queue_redraw()
func _draw() -> void:
# Iterate every room in the registry. Only draw tiles belonging to roofed rooms.
for id in World.rooms:
var r = World.rooms[id]
if not r.is_under_roof:
continue
# r.tiles is an Array[Vector2i] per room.gd contract.
for t in r.tiles:
var rect := Rect2(
float(t.x * TILE_SIZE_PX),
float(t.y * TILE_SIZE_PX),
float(TILE_SIZE_PX),
float(TILE_SIZE_PX)
)
draw_rect(rect, INDOOR_COLOR)