wire buff consumers, sick penalty, multi-count cremation
A: Storyteller.multiply_drops() stochastic-rounding helper drives crop_growth, harvest_yield, chop, mine consumption sites. sleep_decay multiplied in Pawn sleep tick. B: Pawn._sick_speed_penalty() (0% healthy → 75% severity 3, clamped to 25% min speed). JobRunner._work_speed_mult coin-flips per-tick progress on INTERACT/BUILD/CRAFT toils. Sleep/eat/treat unaffected. C: CraftingProvider builds N deposit trips for ingredient2_count > 1. JobRunner._tick_craft validates+consumes the full count from buffer. Cremation now actually requires and consumes 5 wood. crop._stage_accum round-trips through save/load to preserve buff- accumulated fractional growth. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d9638a4ea4
commit
2afca16299
9 changed files with 156 additions and 46 deletions
|
|
@ -237,7 +237,10 @@ func _tick_interact(t) -> void:
|
|||
t.done = true
|
||||
return
|
||||
|
||||
target.call(StringName(t.data.get("tick_method", "")))
|
||||
# Sick pawn coin-flip: skip this tick's work at a rate equal to the penalty.
|
||||
# Expected-value progress is unchanged when healthy (mult == 1.0).
|
||||
if randf() < _work_speed_mult():
|
||||
target.call(StringName(t.data.get("tick_method", "")))
|
||||
|
||||
# Re-check validity after the call (the call may have freed the node).
|
||||
if target == null or not is_instance_valid(target):
|
||||
|
|
@ -292,7 +295,9 @@ func _tick_build(t) -> void:
|
|||
t.done = true
|
||||
return
|
||||
|
||||
target.on_build_tick()
|
||||
# Sick pawn coin-flip: same slow-work mechanic as _tick_interact.
|
||||
if randf() < _work_speed_mult():
|
||||
target.on_build_tick()
|
||||
|
||||
# Re-check after the call (on_build_tick may complete + free the ghost state).
|
||||
if target == null or not is_instance_valid(target):
|
||||
|
|
@ -415,7 +420,7 @@ func _tick_deposit_at_wb(t) -> void:
|
|||
## true when bill.recipe.work_ticks is reached.
|
||||
## - On completion:
|
||||
## * Consumes pawn.carried_item (ingredient or ingredient2); queue_free + clear.
|
||||
## * For two-ingredient recipes, also calls wb.consume_deposited_input for ing1.
|
||||
## * For two-ingredient recipes, also calls wb.consume_deposited_input for ing2.
|
||||
## * Rolls quality via QualityCalc.roll() using the pawn's skill level.
|
||||
## * Spawns an Item scene child of wb.get_parent() at wb.tile.
|
||||
## * Calls wb.on_craft_complete() (records bill completion + resets state).
|
||||
|
|
@ -459,18 +464,20 @@ func _tick_craft(t) -> void:
|
|||
var has_secondary: bool = bill.recipe.ingredient2_type != &""
|
||||
if has_primary:
|
||||
if has_secondary:
|
||||
# Two-ingredient path: check buffer (ing1) + carry (ing2).
|
||||
if not wb.has_deposited_input(bill.recipe.ingredient_type, 1):
|
||||
# Two-ingredient path: check buffer (ing2) + carry (ing1 / primary).
|
||||
# Validate that the full ingredient2_count has been deposited.
|
||||
var ing2_count: int = int(bill.recipe.ingredient2_count) if int(bill.recipe.ingredient2_count) > 0 else 1
|
||||
if not wb.has_deposited_input(bill.recipe.ingredient2_type, ing2_count):
|
||||
Audit.log(
|
||||
"job_runner",
|
||||
"%s craft: ingredient1 not in workbench buffer — skipping" % pawn.pawn_name
|
||||
"%s craft: ingredient2 buffer has %d/%d — skipping" % [pawn.pawn_name, wb.deposited_inputs.get(bill.recipe.ingredient2_type, 0), ing2_count]
|
||||
)
|
||||
t.done = true
|
||||
return
|
||||
if pawn.carried_item == null or pawn.carried_item.item_type != bill.recipe.ingredient2_type:
|
||||
if pawn.carried_item == null or pawn.carried_item.item_type != bill.recipe.ingredient_type:
|
||||
Audit.log(
|
||||
"job_runner",
|
||||
"%s craft: wrong or missing ingredient2 — skipping" % pawn.pawn_name
|
||||
"%s craft: wrong or missing primary ingredient (expect %s) — skipping" % [pawn.pawn_name, bill.recipe.ingredient_type]
|
||||
)
|
||||
t.done = true
|
||||
return
|
||||
|
|
@ -497,7 +504,10 @@ func _tick_craft(t) -> void:
|
|||
return
|
||||
|
||||
# tick_craft() advances the progress counter and returns true when done.
|
||||
var craft_done: bool = wb.tick_craft()
|
||||
# Sick pawn coin-flip: skip this tick's progress at a rate equal to the penalty.
|
||||
var craft_done: bool = false
|
||||
if randf() < _work_speed_mult():
|
||||
craft_done = wb.tick_craft()
|
||||
if not craft_done:
|
||||
return # Still working — toil remains active.
|
||||
|
||||
|
|
@ -522,8 +532,11 @@ func _tick_craft(t) -> void:
|
|||
if ingredient != null and is_instance_valid(ingredient):
|
||||
ingredient.queue_free()
|
||||
if bill.recipe.ingredient2_type != &"":
|
||||
# ingredient2 was the carried item (consumed above); ingredient1 is in the buffer.
|
||||
wb.consume_deposited_input(bill.recipe.ingredient_type, 1)
|
||||
# New two-ingredient convention: ingredient2 was deposited in the buffer
|
||||
# (potentially multiple stacks for ingredient2_count > 1), ingredient1
|
||||
# (primary) was the carried item (consumed above via queue_free).
|
||||
var ing2_count: int = int(bill.recipe.ingredient2_count) if int(bill.recipe.ingredient2_count) > 0 else 1
|
||||
wb.consume_deposited_input(bill.recipe.ingredient2_type, ing2_count)
|
||||
|
||||
# Roll quality based on pawn skill for this recipe.
|
||||
var skill_level: int = pawn.get_skill(bill.recipe.required_skill)
|
||||
|
|
@ -974,6 +987,19 @@ func _resolve_patient(t):
|
|||
|
||||
# ── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
## Returns the effective work-speed multiplier for the current pawn.
|
||||
## Currently only the SICK status reduces it. 1.0 = full speed; < 1.0 = slow.
|
||||
## Used as a coin-flip gate: skip the per-tick work call at a rate proportional
|
||||
## to the penalty so expected-value progress matches the multiplier exactly
|
||||
## (no progress accumulator needed — the tick stream is already stochastic).
|
||||
func _work_speed_mult() -> float:
|
||||
if pawn == null:
|
||||
return 1.0
|
||||
if not pawn.has_method("_sick_speed_penalty"):
|
||||
return 1.0
|
||||
return clampf(1.0 - pawn._sick_speed_penalty(), 0.25, 1.0)
|
||||
|
||||
|
||||
## Emit job_completed, log, and clear the job reference.
|
||||
func _emit_complete() -> void:
|
||||
var completed = job
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue