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
|
|
@ -44,10 +44,14 @@ func _init() -> void:
|
|||
## Single-ingredient recipes produce a 4-toil job:
|
||||
## walk_to(ing1) → pickup → walk_to(wb) → craft_at(wb, bill_index)
|
||||
##
|
||||
## Two-ingredient recipes (ingredient2_type != &"") produce a 7-toil job:
|
||||
## walk_to(ing1) → pickup → walk_to(wb) → deposit_at_wb(wb)
|
||||
## → walk_to(ing2) → pickup → craft_at(wb, bill_index)
|
||||
## The first ingredient is stashed in wb.deposited_inputs; _tick_craft consumes both.
|
||||
## Two-ingredient recipes (ingredient2_type != &"") build the toil sequence:
|
||||
## For each item needed to satisfy ingredient2_count (one trip per item):
|
||||
## walk_to(ing2_item) → pickup → walk_to(wb) → deposit_at_wb(wb)
|
||||
## Then: walk_to(ing1) → pickup → craft_at(wb, bill_index)
|
||||
## Stack-aware: if a single wood item has stack_size >= ingredient2_count, only
|
||||
## one deposit trip is needed. Multiple smaller stacks each get their own trip.
|
||||
## The primary ingredient (ingredient_type / corpse) is always the last pickup
|
||||
## before crafting; ingredient2 is deposited in the buffer beforehand.
|
||||
##
|
||||
## No-ingredient recipes (ingredient_type == &"") produce a 2-toil job:
|
||||
## walk_to(wb) → craft_at(wb, bill_index)
|
||||
|
|
@ -92,12 +96,15 @@ func find_best_for(pawn) -> Job:
|
|||
_emit_bill_blocked(b.recipe.label, &"missing_ingredient", wb)
|
||||
continue
|
||||
|
||||
# Two-ingredient check: secondary ingredient must also be on the floor.
|
||||
# Two-ingredient check: enough secondary ingredient must be on the floor.
|
||||
# ingredient2_count items (or fewer stacks totalling that count) required.
|
||||
if b.recipe.ingredient2_type != &"":
|
||||
src2 = _find_ingredient_item(b.recipe.ingredient2_type)
|
||||
if src2 == null:
|
||||
var ing2_items := _find_ingredient_items_for_count(b.recipe.ingredient2_type, b.recipe.ingredient2_count)
|
||||
if ing2_items.is_empty():
|
||||
_emit_bill_blocked(b.recipe.label, &"missing_ingredient2", wb)
|
||||
continue
|
||||
# Use the first item as src2 for the scoring distance heuristic.
|
||||
src2 = ing2_items[0]
|
||||
|
||||
# Score: total Manhattan travel distance including both ingredient trips.
|
||||
# No-ingredient: pawn → wb.
|
||||
|
|
@ -125,23 +132,29 @@ func find_best_for(pawn) -> Job:
|
|||
best_src1 = _find_ingredient_item(best_bill.recipe.ingredient_type)
|
||||
if best_src1 == null:
|
||||
return null
|
||||
var ing2_items: Array = []
|
||||
if best_bill.recipe.ingredient2_type != &"":
|
||||
best_src2 = _find_ingredient_item(best_bill.recipe.ingredient2_type)
|
||||
if best_src2 == null:
|
||||
ing2_items = _find_ingredient_items_for_count(best_bill.recipe.ingredient2_type, best_bill.recipe.ingredient2_count)
|
||||
if ing2_items.is_empty():
|
||||
return null
|
||||
|
||||
var j := Job.new()
|
||||
j.label = "Craft %s at %s" % [best_bill.recipe.label, best_wb.get("label_text") if best_wb.get("label_text") != null else "workbench"]
|
||||
j.target_node = best_wb
|
||||
|
||||
if best_src1 != null and best_src2 != null:
|
||||
# Two-ingredient path: deposit ing1 at wb, then fetch ing2 and craft.
|
||||
j.toils.append(Toil.walk_to(best_src1.tile))
|
||||
j.toils.append(Toil.pickup())
|
||||
j.toils.append(Toil.walk_to(best_wb.tile))
|
||||
j.toils.append(Toil.deposit_at_wb(best_wb.get_path()))
|
||||
j.toils.append(Toil.walk_to(best_src2.tile))
|
||||
j.toils.append(Toil.pickup())
|
||||
if not ing2_items.is_empty():
|
||||
# Two-ingredient path: deposit ingredient2 item(s) at workbench buffer,
|
||||
# then fetch the primary ingredient and craft.
|
||||
# One deposit trip per item in ing2_items (stack-aware: fewer trips when
|
||||
# item.stack_size covers multiple units, e.g. a 5-stack of wood = 1 trip).
|
||||
for ing2 in ing2_items:
|
||||
j.toils.append(Toil.walk_to(ing2.tile))
|
||||
j.toils.append(Toil.pickup())
|
||||
j.toils.append(Toil.walk_to(best_wb.tile))
|
||||
j.toils.append(Toil.deposit_at_wb(best_wb.get_path()))
|
||||
if best_src1 != null:
|
||||
j.toils.append(Toil.walk_to(best_src1.tile))
|
||||
j.toils.append(Toil.pickup())
|
||||
elif best_src1 != null:
|
||||
# Single-ingredient path: carry ing1 directly to craft.
|
||||
j.toils.append(Toil.walk_to(best_src1.tile))
|
||||
|
|
@ -166,6 +179,27 @@ func _find_ingredient_item(item_type: StringName):
|
|||
return null
|
||||
|
||||
|
||||
## Returns a list of on-floor Items of `item_type` whose combined stack_size
|
||||
## totals at least `needed_count`. Returns an empty array if not enough exist.
|
||||
## Stack-aware: a single item with stack_size >= needed_count yields one entry.
|
||||
## Multiple smaller stacks are collected until the total is met.
|
||||
## This powers the multi-trip deposit loop for ingredient2_count > 1 recipes.
|
||||
func _find_ingredient_items_for_count(item_type: StringName, needed_count: int) -> Array:
|
||||
var result: Array = []
|
||||
var accumulated: int = 0
|
||||
for it in World.items:
|
||||
if it.being_carried:
|
||||
continue
|
||||
if it.item_type != item_type:
|
||||
continue
|
||||
result.append(it)
|
||||
accumulated += int(it.get("stack_size") if it.get("stack_size") != null else 1)
|
||||
if accumulated >= needed_count:
|
||||
return result
|
||||
# Not enough items found.
|
||||
return []
|
||||
|
||||
|
||||
## Manhattan distance between two Vector2i tile coordinates.
|
||||
func _manhattan(a: Vector2i, b: Vector2i) -> int:
|
||||
return abs(a.x - b.x) + abs(a.y - b.y)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue