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:
megaproxy 2026-05-16 18:17:29 +01:00
parent d9638a4ea4
commit 2afca16299
9 changed files with 156 additions and 46 deletions

View file

@ -241,14 +241,16 @@ func on_chop_tick() -> void:
## Drop wood Items and free this node. Called by on_chop_tick() automatically,
## but also accessible for scripted felling (debug, storyteller events).
func fell() -> void:
var drop_tiles := _pick_drop_tiles()
# Apply chop buff (lumberjacks_luck): multiply total wood drops with stochastic rounding.
var total_drops: int = Storyteller.multiply_drops(WOOD_DROPS_ON_FELL, Storyteller.get_buff_multiplier(&"chop"))
var drop_tiles := _pick_drop_tiles_count(total_drops)
var drops_count := 0
for drop_tile in drop_tiles:
var item: Item = ITEM_SCENE.instantiate()
get_parent().add_child(item)
item.setup(Item.TYPE_WOOD, STACK_SIZE_PER_DROP, drop_tile)
drops_count += 1
Audit.log("tree", "felled at %s; %d wood drops" % [tile, drops_count])
Audit.log("tree", "felled at %s; %d wood drops (buff mult=%.2f)" % [tile, drops_count, Storyteller.get_buff_multiplier(&"chop")])
if Audio != null:
Audio.play_sfx(&"tree_fell")
World.clear_designation_at(tile)
@ -310,10 +312,12 @@ func _draw() -> void:
# ── helpers ───────────────────────────────────────────────────────────────────
## Returns up to WOOD_DROPS_ON_FELL tile positions for wood drops.
## Prefers the tree's own tile then walkable 4-neighbours; falls back to the
## tree tile for any remaining drops when neighbours are scarce.
func _pick_drop_tiles() -> Array[Vector2i]:
## Returns `count` tile positions for wood drops.
## Prefers the tree's own tile then walkable 4-neighbours; fills any remaining
## slots with the tree tile if neighbours are scarce.
## Previously took an implicit count of WOOD_DROPS_ON_FELL; now accepts an
## explicit count so the chop buff can request more drops.
func _pick_drop_tiles_count(count: int) -> Array[Vector2i]:
var chosen: Array[Vector2i] = []
# First drop always goes on the tree's tile itself.
@ -322,14 +326,14 @@ func _pick_drop_tiles() -> Array[Vector2i]:
# Remaining drops prefer walkable neighbours.
var offsets: Array[Vector2i] = [Vector2i(1, 0), Vector2i(-1, 0), Vector2i(0, 1), Vector2i(0, -1)]
for offset in offsets:
if chosen.size() >= WOOD_DROPS_ON_FELL:
if chosen.size() >= count:
break
var candidate: Vector2i = tile + offset
if World.pathfinder != null and World.pathfinder.is_walkable(candidate):
chosen.append(candidate)
# Fill any remaining slots with the tree tile (all 3 land there if boxed in).
while chosen.size() < WOOD_DROPS_ON_FELL:
# Fill any remaining slots with the tree tile (all land there if boxed in).
while chosen.size() < count:
chosen.append(tile)
return chosen