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:
megaproxy 2026-05-16 18:06:55 +01:00
parent 00cf8f445d
commit d9638a4ea4
19 changed files with 711 additions and 101 deletions

View file

@ -24,7 +24,7 @@ class_name Bed extends Node2D
## Save/load:
## to_dict() serialises all persistent fields. _occupant_pawn is always saved
## as null (sleep is mid-toil state; the JobRunner saves its own side). Re-wiring
## owner_pawn from name → Pawn reference is deferred to Phase 16's full save layer.
## owner_pawn from name → Pawn reference is resolved in SaveSystem._post_load_resolve_references().
##
## World registration: World.register_bed / World.unregister_bed called from
## _ready / _exit_tree.
@ -103,6 +103,11 @@ var _owner_pawn = null
## has an active sleep job; the JobRunner handles reconnection).
var _occupant_pawn = null
## Transient: set by from_dict() to the saved owner's pawn_name string.
## SaveSystem._post_load_resolve_references() walks World.pawns, matches by
## pawn_name, assigns _owner_pawn, then clears this field.
var _pending_owner_name: String = ""
# ── lifecycle ─────────────────────────────────────────────────────────────────
@ -220,7 +225,9 @@ func to_dict() -> Dictionary:
## Restore from a dict produced by to_dict().
## owner_pawn re-wiring (name → Pawn reference) is deferred to Phase 16.
## _owner_pawn is re-wired by SaveSystem._post_load_resolve_references() after
## all pawns are spawned: it reads _pending_owner_name, matches pawn_name,
## assigns _owner_pawn, then clears _pending_owner_name.
func from_dict(d: Dictionary) -> void:
tile = Vector2i(int(d.get("tile_x", 0)), int(d.get("tile_y", 0)))
quality = int(d.get("quality", 1))
@ -228,9 +235,10 @@ func from_dict(d: Dictionary) -> void:
is_medical = bool(d.get("is_medical", false))
build_progress = int(d.get("build_progress", 0))
_completed = bool(d.get("completed", false))
# owner_pawn: Phase 16 will walk World.pawns and match by pawn_name.
_owner_pawn = null
_occupant_pawn = null
# Store name for the post-load fixup pass; cleared there once resolved.
_pending_owner_name = str(d.get("owner_pawn_name", ""))
setup(tile)