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
|
|
@ -125,6 +125,12 @@ var current_work_progress: int = 0
|
|||
## enabled only after _complete() fires.
|
||||
var _light: PointLight2D = null
|
||||
|
||||
## Per-recipe input buffer for multi-ingredient crafts (two-trip strategy).
|
||||
## Keyed by StringName item_type → int count already deposited.
|
||||
## Populated by _tick_deposit_at_wb; consumed and cleared when the craft
|
||||
## completes or is interrupted. Not stocked by single-ingredient recipes.
|
||||
var deposited_inputs: Dictionary = {}
|
||||
|
||||
|
||||
# ── lifecycle ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -261,6 +267,30 @@ func on_craft_complete() -> void:
|
|||
func on_craft_interrupted() -> void:
|
||||
current_bill = null
|
||||
current_work_progress = 0
|
||||
deposited_inputs.clear()
|
||||
|
||||
|
||||
## Called by _tick_deposit_at_wb to stash ingredient1 into the per-recipe buffer.
|
||||
## Accumulates count; the same item type may be deposited in multiple trips if
|
||||
## ingredient1_count > 1 (Phase 14: always 1 for corpse, but flexible for future).
|
||||
func add_deposited_input(item_type: StringName, count: int) -> void:
|
||||
deposited_inputs[item_type] = deposited_inputs.get(item_type, 0) + count
|
||||
|
||||
|
||||
## Returns true if the deposited_inputs buffer holds at least `count` of `item_type`.
|
||||
func has_deposited_input(item_type: StringName, count: int) -> bool:
|
||||
return deposited_inputs.get(item_type, 0) >= count
|
||||
|
||||
|
||||
## Consume (remove) exactly `count` of `item_type` from deposited_inputs.
|
||||
## Clamps to zero; does nothing if not present.
|
||||
func consume_deposited_input(item_type: StringName, count: int) -> void:
|
||||
var held: int = deposited_inputs.get(item_type, 0)
|
||||
var remaining: int = held - count
|
||||
if remaining <= 0:
|
||||
deposited_inputs.erase(item_type)
|
||||
else:
|
||||
deposited_inputs[item_type] = remaining
|
||||
|
||||
|
||||
# ── Phase 11: light-source duck-type interface ────────────────────────────────
|
||||
|
|
@ -293,6 +323,11 @@ func to_dict() -> Dictionary:
|
|||
var bills_data: Array = []
|
||||
for b in bills:
|
||||
bills_data.append(b.to_dict())
|
||||
# Serialise deposited_inputs: StringName keys → int values.
|
||||
# Store as Array of [String, int] pairs for JSON safety.
|
||||
var deposited_array: Array = []
|
||||
for k in deposited_inputs:
|
||||
deposited_array.append([String(k), deposited_inputs[k]])
|
||||
return {
|
||||
"class_id": &"workbench",
|
||||
"tile_x": tile.x,
|
||||
|
|
@ -303,13 +338,15 @@ func to_dict() -> Dictionary:
|
|||
"completed": _completed,
|
||||
"current_work_progress": current_work_progress,
|
||||
"bills": bills_data,
|
||||
"deposited_inputs": deposited_array,
|
||||
}
|
||||
|
||||
|
||||
## Restore from a dict produced by to_dict().
|
||||
## Bill objects are reconstructed by the caller using Bill.from_dict() once the
|
||||
## Bill class is registered. current_bill is left null — JobRunner reconnects
|
||||
## from its own saved state on the next sim tick.
|
||||
## Bills are reconstructed here using Bill.from_dict(). current_bill is left
|
||||
## null — JobRunner reconnects from its own saved state on the next sim tick.
|
||||
const _BILL_SCRIPT: Script = preload("res://scenes/ai/bill.gd")
|
||||
|
||||
func from_dict(d: Dictionary) -> void:
|
||||
tile = Vector2i(int(d.get("tile_x", 0)), int(d.get("tile_y", 0)))
|
||||
label_text = str(d.get("label_text", "Workbench"))
|
||||
|
|
@ -317,8 +354,18 @@ func from_dict(d: Dictionary) -> void:
|
|||
build_progress = int(d.get("build_progress", 0))
|
||||
_completed = bool(d.get("completed", false))
|
||||
current_work_progress = int(d.get("current_work_progress", 0))
|
||||
# Bills are re-populated by World.load_workbenches() after Bill class loads.
|
||||
# Raw dicts are kept in the dict; the caller handles reconstruction.
|
||||
# Reconstruct bills from the saved array. Clear first so this is idempotent.
|
||||
bills.clear()
|
||||
for bill_dict in d.get("bills", []):
|
||||
if bill_dict is Dictionary:
|
||||
var b: Bill = _BILL_SCRIPT.from_dict(bill_dict)
|
||||
if b != null:
|
||||
bills.append(b)
|
||||
# Restore deposited_inputs from the [String, int] pair array.
|
||||
deposited_inputs.clear()
|
||||
for pair in d.get("deposited_inputs", []):
|
||||
if pair is Array and pair.size() == 2:
|
||||
deposited_inputs[StringName(str(pair[0]))] = int(pair[1])
|
||||
setup(tile)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue