rimlike/scenes/ai/cleaning_provider.gd
megaproxy fd6f958344 sprint A cleanup: accessibility, signals, race, debris
G: large_text scales global theme font (14→20 at 1.4×) via new
GameState.get_font_scale + EventBus.settings_changed. reduce_motion
gates ResumeToast fade (HintOverlay already gated).

I: InspectTooltip long-press wired (500ms hold, 12px drift cancel,
tap-to-clear pin). Stale Phase 19 TODO replaced with accurate doc.

H: Pawn.arrived_at_destination now also emitted on
EventBus.pawn_arrived_at_destination; DirtinessSystem subscribes and
bumps indoor traffic dirt (BUMP_INDOOR_TRAFFIC = 0.2). Outdoor-tracked
bump needs Pawn.prev_tile — flagged for Phase 20.

P: CraftingProvider caches ingredient item ref on Job.ingredient_item;
JobRunner._tick_pickup validates is_instance_valid + not being_carried
before the tile scan, cancels cleanly if another pawn grabbed it.

J: rest_provider.gd deleted. Removed @onready + register call from
world.gd, ext_resource + node from world.tscn. Provider count comment
updated to 9.

M: DIRTY_THRESHOLD extracted — cleaning_provider and job_runner now
reference DirtinessSystem.DIRT_DIRTY_THRESHOLD.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 18:38:14 +01:00

68 lines
2.4 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.

class_name CleaningProvider extends WorkProvider
## Phase 13 — WorkProvider for the Cleaning work category.
##
## Priority 2: fires when there is nothing more productive to do
## (below hauling=3, above rest=0).
##
## make_job / find_best_for logic:
## Scan DirtinessSystem.dirt_map for tiles with dirt >= DIRTY_THRESHOLD.
## Pick the nearest to the pawn by Manhattan distance.
## Build a 2-toil job: walk_to(tile) → kind_clean(tile).
##
## There is no Cleaning skill yet (Phase 17+ skill matrix). The clean toil
## takes a flat CLEAN_TICKS sim ticks to reduce dirt from any level to 0.
##
## JobRunner._tick_clean reduces DirtinessSystem.dirt_at(tile) by
## DIRT_REDUCTION_PER_TICK each sim tick until dirt <= 0.
##
## Audit.log fires on job start and on toil completion (via JobRunner).
## Base number of sim ticks to clean a tile from any level to 0.
## No skill modifier for now; Phase 17 wires skill × speed.
const CLEAN_TICKS: int = 40
func _init() -> void:
category = &"clean"
priority = 2
# ── WorkProvider override ─────────────────────────────────────────────────────
## Returns a cleaning Job for `pawn`, or null if no dirty tiles exist.
## Picks the tile closest to `pawn` (Manhattan distance) with dirt >= DIRTY_THRESHOLD.
func find_best_for(pawn) -> Job:
# Safety — dirtiness system may not be wired yet (Agent A rooms arrive slightly later).
if World.get("dirtiness_system") == null:
return null
var ds = World.dirtiness_system
if ds == null:
return null
var best_tile: Vector2i = Vector2i(-1, -1)
var best_dist: int = 999999
for tile in ds.dirt_map.keys():
var dirt_val: float = float(ds.dirt_map[tile])
if dirt_val < DirtinessSystem.DIRT_DIRTY_THRESHOLD:
continue
# target_node stores the Vector2i tile coordinate (field is untyped — accepts
# non-Node values). Dirty tiles have no scene Node; the tile position itself
# is the unique claim key.
if Job.is_target_taken_by_other(tile, pawn):
continue
var d: int = abs(tile.x - pawn.tile.x) + abs(tile.y - pawn.tile.y)
if d < best_dist:
best_dist = d
best_tile = tile
if best_tile == Vector2i(-1, -1):
return null
var j := Job.new()
j.label = "Clean (%d,%d)" % [best_tile.x, best_tile.y]
j.target_node = best_tile
j.toils.append(Toil.walk_to(best_tile))
j.toils.append(Toil.clean_at(best_tile))
return j