fix six critical bugs from audit sprint
save/load round-trip: workbench bills, crop static-method, bed owner, wolf target now all survive reload via Bill.from_dict reconstruction, _spawn_crop using setup(), and a new _post_load_resolve_references pass. PlantProvider: sow path added; consumes 1 grain on a TILLED crop tile. CraftingProvider: ingredient2 supported via new KIND_DEPOSIT_AT_WB toil and Workbench.deposited_inputs buffer. Cremation pyre now actually consumes wood. HaulingProvider: per-item haul_retry_count + haul_rejected after 3 orphan passes; new EventBus.stockpile_layout_changed resets rejects on any player stockpile edit. Storyteller: 14 stubbed event effects implemented. New buff registry (add_buff/get_buff_multiplier/has_buff, day-prune, save/load) drives seasonal/resource events. New request_pawn_spawn signal + WANDERER table for arrivals. New SICK status + 3 mood thoughts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
00cf8f445d
commit
d9638a4ea4
19 changed files with 711 additions and 101 deletions
|
|
@ -27,12 +27,20 @@ const ALERT_COOLDOWN_TICKS: int = 600
|
|||
## Per-item-type cooldown map: StringName → tick at which the next emit is allowed.
|
||||
var _alert_cooldown: Dictionary = {}
|
||||
|
||||
## Tick stamp: the last sim tick on which we incremented haul_retry_count for
|
||||
## at least one orphaned item. Guards against double-counting when multiple
|
||||
## pawns call find_best_for on the same tick (all share this provider instance).
|
||||
var _last_orphan_tick: int = -1
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
category = &"haul"
|
||||
# Priority 3 — below chop (5) and mine (4); above rest (1).
|
||||
# Adjusted once the full 9-category matrix is authored in Phase 17.
|
||||
priority = 3
|
||||
# Reset haul_rejected items whenever stockpile layout changes so a newly-
|
||||
# painted stockpile or filter edit unblocks previously-rejected items.
|
||||
EventBus.stockpile_layout_changed.connect(_on_stockpile_layout_changed)
|
||||
|
||||
|
||||
# ── WorkProvider override ─────────────────────────────────────────────────────
|
||||
|
|
@ -59,6 +67,10 @@ func find_best_for(pawn) -> Job:
|
|||
|
||||
# ── regular items ─────────────────────────────────────────────────────────
|
||||
for item in World.items_needing_haul.keys():
|
||||
# Skip items that already exhausted their retries — they stay out of
|
||||
# haul consideration until a stockpile layout change resets them.
|
||||
if item.haul_rejected:
|
||||
continue
|
||||
# Skip items another pawn is already carrying.
|
||||
if item.being_carried:
|
||||
continue
|
||||
|
|
@ -79,6 +91,18 @@ func find_best_for(pawn) -> Job:
|
|||
if first_orphan_type == &"":
|
||||
first_orphan_type = item.item_type
|
||||
first_orphan_tile = item.tile
|
||||
# Increment the per-item retry counter at most once per sim tick,
|
||||
# guarded by _last_orphan_tick so multiple pawn calls in the same
|
||||
# tick don't multiply-count the same item.
|
||||
if _last_orphan_tick < Sim.tick:
|
||||
_last_orphan_tick = Sim.tick
|
||||
item.haul_retry_count += 1
|
||||
if item.haul_retry_count >= Item.MAX_HAUL_RETRIES:
|
||||
item.haul_rejected = true
|
||||
World.items_needing_haul.erase(item)
|
||||
Audit.log("hauling", "item %s at %s rejected after %d retries" % [
|
||||
item.item_type, item.tile, item.haul_retry_count
|
||||
])
|
||||
continue
|
||||
|
||||
var drop: Vector2i = dest.find_drop_position(item)
|
||||
|
|
@ -228,3 +252,21 @@ func _destination_for_tile(tile: Vector2i):
|
|||
if dest.covers_tile(tile):
|
||||
return dest
|
||||
return null
|
||||
|
||||
|
||||
## Resets haul_rejected / haul_retry_count on every item so a stockpile layout
|
||||
## change (new zone, filter edit, priority change) gives them a fresh chance.
|
||||
## Rejected items are re-entered into items_needing_haul so sweep_for_better_
|
||||
## destinations() can re-evaluate them on the next periodic pass.
|
||||
func _on_stockpile_layout_changed() -> void:
|
||||
var reset_count: int = 0
|
||||
for item in World.items:
|
||||
if item.haul_rejected or item.haul_retry_count > 0:
|
||||
item.haul_rejected = false
|
||||
item.haul_retry_count = 0
|
||||
# Re-enqueue only if not already in the haul set and not carried.
|
||||
if not item.being_carried and not World.items_needing_haul.has(item):
|
||||
World.items_needing_haul[item] = true
|
||||
reset_count += 1
|
||||
if reset_count > 0:
|
||||
Audit.log("hauling", "stockpile layout changed — reset %d rejected/retried items" % reset_count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue