sprint cleanup: corpse_cremated signal, recipe_count, save_system
D: Workbench._last_consumed_ingredient transient field captures the carried item before queue_free so cremation_pyre.on_craft_complete can emit corpse_cremated with the real ref. Falls back to proximity scan. Pawn._on_corpse_cremated null-guarded. E: removed redundant r.ingredient_count = 0 from recipe_catalog. Field kept on Recipe for save round-trip compat; nothing reads it functionally. F: save_system._spawn_workbench simplified from 15 lines to 6 — let from_dict do all field restoration. Fixed workbench.from_dict to call _complete() instead of bare _completed=true, which was skipping light enable + beauty register + designation clear. Stale ingredient1/2 buffering comment in job_runner._tick_craft fixed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2afca16299
commit
cc6d60d044
6 changed files with 29 additions and 18 deletions
|
|
@ -493,18 +493,10 @@ func _spawn_door(world_scene: Node, d: Dictionary) -> void:
|
||||||
func _spawn_workbench(world_scene: Node, d: Dictionary) -> void:
|
func _spawn_workbench(world_scene: Node, d: Dictionary) -> void:
|
||||||
var ent = _WORKBENCH_SCENE.instantiate()
|
var ent = _WORKBENCH_SCENE.instantiate()
|
||||||
world_scene.add_child(ent)
|
world_scene.add_child(ent)
|
||||||
ent.setup(Vector2i(int(d.get("tile_x", 0)), int(d.get("tile_y", 0))))
|
# from_dict restores all fields (label_text, accepted_skill, build_progress,
|
||||||
if d.has("label_text"):
|
# bills, deposited_inputs) and calls _complete() + setup() internally.
|
||||||
ent.label_text = str(d["label_text"])
|
# No manual field assignment needed here.
|
||||||
if d.has("accepted_skill"):
|
ent.from_dict(d)
|
||||||
ent.accepted_skill = StringName(d["accepted_skill"])
|
|
||||||
ent.build_progress = int(d.get("build_progress", 0))
|
|
||||||
if bool(d.get("completed", false)):
|
|
||||||
ent.build_progress = ent.BUILD_TICKS
|
|
||||||
ent.on_build_tick()
|
|
||||||
# from_dict restores bills + any other Workbench-specific state.
|
|
||||||
if ent.has_method("from_dict"):
|
|
||||||
ent.from_dict(d)
|
|
||||||
|
|
||||||
|
|
||||||
func _spawn_crop(world_scene: Node, d: Dictionary) -> void:
|
func _spawn_crop(world_scene: Node, d: Dictionary) -> void:
|
||||||
|
|
|
||||||
|
|
@ -524,10 +524,14 @@ func _tick_craft(t) -> void:
|
||||||
|
|
||||||
# Consume ingredients.
|
# Consume ingredients.
|
||||||
# Single-ingredient: pawn.carried_item holds the only input — free it.
|
# Single-ingredient: pawn.carried_item holds the only input — free it.
|
||||||
# Two-ingredient: pawn.carried_item is ingredient2; ingredient1 was buffered
|
# Two-ingredient: pawn.carried_item is ingredient (primary); ingredient2 was buffered
|
||||||
# in wb.deposited_inputs by _tick_deposit_at_wb — remove it from the buffer.
|
# in wb.deposited_inputs by _tick_deposit_at_wb — remove it from the buffer.
|
||||||
# No-ingredient: carried_item is null; nothing to consume.
|
# No-ingredient: carried_item is null; nothing to consume.
|
||||||
var ingredient = pawn.carried_item
|
var ingredient = pawn.carried_item
|
||||||
|
# Expose the consumed ingredient to on_craft_complete() via a transient field
|
||||||
|
# so overrides (e.g. CremationPyre) can retrieve it by reference instead of
|
||||||
|
# relying on a proximity scan. Cleared below after on_craft_complete returns.
|
||||||
|
wb._last_consumed_ingredient = ingredient
|
||||||
pawn.carried_item = null
|
pawn.carried_item = null
|
||||||
if ingredient != null and is_instance_valid(ingredient):
|
if ingredient != null and is_instance_valid(ingredient):
|
||||||
ingredient.queue_free()
|
ingredient.queue_free()
|
||||||
|
|
@ -551,6 +555,8 @@ func _tick_craft(t) -> void:
|
||||||
|
|
||||||
# Record completion on the bill and reset workbench state.
|
# Record completion on the bill and reset workbench state.
|
||||||
wb.on_craft_complete()
|
wb.on_craft_complete()
|
||||||
|
# Clear transient ingredient ref now that on_craft_complete overrides have run.
|
||||||
|
wb._last_consumed_ingredient = null
|
||||||
|
|
||||||
Audit.log(
|
Audit.log(
|
||||||
"job_runner",
|
"job_runner",
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,6 @@ static func quarry_stone() -> Recipe:
|
||||||
r.id = &"quarry_stone"
|
r.id = &"quarry_stone"
|
||||||
r.label = "Quarry stone"
|
r.label = "Quarry stone"
|
||||||
r.ingredient_type = &"" # no input
|
r.ingredient_type = &"" # no input
|
||||||
r.ingredient_count = 0
|
|
||||||
r.output_type = Item.TYPE_STONE
|
r.output_type = Item.TYPE_STONE
|
||||||
r.work_ticks = 300
|
r.work_ticks = 300
|
||||||
r.required_skill = &"manual_labor"
|
r.required_skill = &"manual_labor"
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,12 @@ func on_craft_complete() -> void:
|
||||||
# Base Workbench cleanup (clears current_bill, resets work progress).
|
# Base Workbench cleanup (clears current_bill, resets work progress).
|
||||||
super.on_craft_complete()
|
super.on_craft_complete()
|
||||||
|
|
||||||
# Find and consume the corpse that was hauled as ingredient.
|
# Find the corpse that was hauled as ingredient. Prefer the transient
|
||||||
var consumed_corpse = _find_consumed_corpse()
|
# reference set by JobRunner (reliable regardless of corpse tile position);
|
||||||
|
# fall back to proximity scan only if the field is somehow unset.
|
||||||
|
var consumed_corpse = _last_consumed_ingredient if _last_consumed_ingredient != null \
|
||||||
|
and is_instance_valid(_last_consumed_ingredient) \
|
||||||
|
else _find_consumed_corpse()
|
||||||
|
|
||||||
# Drop 1 ash item on an adjacent walkable tile (same pattern as
|
# Drop 1 ash item on an adjacent walkable tile (same pattern as
|
||||||
# Tree.fell() / Workbench output drops elsewhere in Phase 6).
|
# Tree.fell() / Workbench output drops elsewhere in Phase 6).
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,12 @@ var _light: PointLight2D = null
|
||||||
## completes or is interrupted. Not stocked by single-ingredient recipes.
|
## completes or is interrupted. Not stocked by single-ingredient recipes.
|
||||||
var deposited_inputs: Dictionary = {}
|
var deposited_inputs: Dictionary = {}
|
||||||
|
|
||||||
|
## Transient: set by JobRunner._tick_craft to the carried ingredient node
|
||||||
|
## immediately before queue_free() so on_craft_complete() overrides (e.g.
|
||||||
|
## CremationPyre) can retrieve the consumed entity by reference rather than
|
||||||
|
## by proximity scan. Cleared by the caller after on_craft_complete returns.
|
||||||
|
var _last_consumed_ingredient = null
|
||||||
|
|
||||||
|
|
||||||
# ── lifecycle ─────────────────────────────────────────────────────────────────
|
# ── lifecycle ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -352,7 +358,11 @@ func from_dict(d: Dictionary) -> void:
|
||||||
label_text = str(d.get("label_text", "Workbench"))
|
label_text = str(d.get("label_text", "Workbench"))
|
||||||
accepted_skill = StringName(d.get("accepted_skill", "crafting"))
|
accepted_skill = StringName(d.get("accepted_skill", "crafting"))
|
||||||
build_progress = int(d.get("build_progress", 0))
|
build_progress = int(d.get("build_progress", 0))
|
||||||
_completed = bool(d.get("completed", false))
|
# Use _complete() when already finished so side effects (light, beauty,
|
||||||
|
# designation clear) fire correctly on load — matching what on_build_tick()
|
||||||
|
# does during normal construction.
|
||||||
|
if bool(d.get("completed", false)):
|
||||||
|
_complete()
|
||||||
current_work_progress = int(d.get("current_work_progress", 0))
|
current_work_progress = int(d.get("current_work_progress", 0))
|
||||||
# Reconstruct bills from the saved array. Clear first so this is idempotent.
|
# Reconstruct bills from the saved array. Clear first so this is idempotent.
|
||||||
bills.clear()
|
bills.clear()
|
||||||
|
|
|
||||||
|
|
@ -693,7 +693,7 @@ func _on_corpse_buried(corpse, marker) -> void:
|
||||||
## Phase 14 — fires when EventBus.corpse_cremated is emitted (CremationPyre).
|
## Phase 14 — fires when EventBus.corpse_cremated is emitted (CremationPyre).
|
||||||
## Gives the cremated_friend thought if this pawn was nearby (8 tiles).
|
## Gives the cremated_friend thought if this pawn was nearby (8 tiles).
|
||||||
func _on_corpse_cremated(corpse, pyre) -> void:
|
func _on_corpse_cremated(corpse, pyre) -> void:
|
||||||
if pyre == null:
|
if corpse == null or pyre == null:
|
||||||
return
|
return
|
||||||
var pyre_tile: Vector2i = pyre.tile if pyre.get("tile") != null else Vector2i(-999, -999)
|
var pyre_tile: Vector2i = pyre.tile if pyre.get("tile") != null else Vector2i(-999, -999)
|
||||||
var dist: int = abs(pyre_tile.x - tile.x) + abs(pyre_tile.y - tile.y)
|
var dist: int = abs(pyre_tile.x - tile.x) + abs(pyre_tile.y - tile.y)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue