Skip to content

Let a crafter store a bill's product in uniform inside a radius or area (v1.5.5) - #29

Merged
beverage merged 2 commits into
mainfrom
feature/bill-product-haul
Nov 6, 2026
Merged

beverage merged 2 commits into
mainfrom
feature/bill-product-haul

Conversation

@beverage

@beverage beverage commented Nov 6, 2026

Copy link
Copy Markdown
Owner

At a radius or area stand, a crafter on shift changed out of uniform to store each finished bill's product, even with the stockpile inside the ring or the area. A player reported it on the Workshop page. This branch judges that haul at the stockpile: inside the ring or the area they carry the stack there in uniform, and past the edge they still change back first. It also carries the draft change note and Workshop comment for v1.5.5 (media/changelog-v1.5.5.bbcode, media/comment-v1.5.5.txt).

The bug

When a bill finishes, Toils_Recipe.FinishRecipeAndStartStoringProduct puts the product in the crafter's hands and starts a new HaulToCell with no workGiverDef. With no giver the job has no work type, so StaysDressed found nothing the stand served, and the return trip inserted a swap ahead of the haul. The swap's drop put the stack down at the bench. The crafter walked to the stand, came back for the stack in their own clothes, stored it, and walked back to the stand to dress for the next bill.

Room stands never did this. A room stand asks only whether the job's target is in the room, and this haul's target is the stack in the crafter's hands, so at a bench in the room the answer is yes wherever the stockpile is.

The fix

StoresServedBillProduct picks this haul out, and StaysDressed answers it with PlaceCovered(job.targetB, ...), which tests the storage cell against the ring or the area. It needs all of these:

  • a HaulToCell with no giver
  • JobDriver_DoBill as the current driver, which it still is when the prefix on StartJob runs
  • a stand that serves the work type of that bill's giver
  • the job's stack in the pawn's hands

The rule follows the bill's work type, so Hauling does not have to be ticked. A haul that fails any of the four takes the path it took before.

What players see

With the stockpile inside the ring or the area, the crafter stores the stack in uniform and goes straight to the next bill. With it past the edge, nothing changes: they put the stack down at the bench, change back, haul it in their own clothes and dress again. Bills set to drop on the floor start no haul, and room stands behave as they did.

Testing

HarnessCatchments.BillProduct.cs adds 13 cases. Each runs a real DoBill at a stonecutter's table to its last toil, with the crafter already standing at the bench, and reads what the stand does when the haul starts.

  • The stockpile inside the area or the ring keeps the uniform on, with Hauling ticked or not, and with the crafter's own cell left unpainted.
  • A stockpile past the area or the ring changes them back first, with the haul queued behind the swap and the stack on the ground, with Hauling ticked or not.
  • A room stand keeps the uniform on for a stockpile in the room and for one past its door.
  • A bill the stand stopped serving while it ran, a haul of a stack on the ground during a served bill, and a stack in hand after other served work all change them back first, with the stockpile inside the area.
  • A crafter off shift at a stand ticked for Hauling alone is not sent to dress for storing what they made.

Results on 1f20ef0, RimWorld 1.7.4998 rev1299. The mod list for every row is Harmony, Core, Odyssey, Shift Change and the lab's console agent:

Build Result
this branch 141 passed, 0 failed, 7 known gaps
the rule switched off 137 passed, 4 failed: both stockpile-inside cases, the same with Hauling not ticked, and the unpainted crafter cell
without the check that the stand serves the bill 140 passed, 1 failed: the bill the stand stopped serving
without the stack-in-hand check 140 passed, 1 failed: the stack on the ground
without the JobDriver_DoBill check 140 passed, 1 failed: the stack in hand after other served work
judged at every place the job names, not the storage cell 140 passed, 1 failed: the unpainted crafter cell
always staying dressed 138 passed, 3 failed: the three past-the-edge cases

The room cases pass with the rule on or off. Every row below the first ran on a throwaway copy of this head with that one change. An earlier run of the "every place" change also failed and the first cell past the ring is not, a check on the ring's own cells that starts no job. The run in the table did not.

The 7 known gaps are Outfit Stands Plus, Complex Jobs, Common Sense, Pick Up And Haul, the Ideology recolor case and two Rimatomics cases, none of them on this mod list.

The cases stop when the haul starts, so a one-off trace followed two bills to the end with the clock moved by hand. It ran on a scratch copy with the same Patch_JobInterception.cs as this head and a temporary case that is not on the branch. The first row is the same trace on the code before the fix:

Build Stand Stockpile Hauling First stack stored Second bill starts
before the fix area inside ticked in their own clothes tick 1,109
this fix area inside ticked in uniform ticks 148 and 153, two runs
this fix ring inside ticked in uniform tick 152
this fix area inside not ticked in uniform tick 155
this fix area past the edge ticked in their own clothes tick 1,097
this fix area past the edge not ticked in their own clothes tick 1,098

check-invariants.py passes, and check-shipped-dll.py passes on the Release build the runner leaves behind.

Not covered

Nobody has played this in a real game yet: the evidence is the harness and the trace, on a test map with one crafter. Mods that add their own bill drivers or their own product hauls were not run. A driver that does not derive from JobDriver_DoBill falls outside the rule and takes the old path.

Left out on purpose

An ordinary haul at a stand with Hauling ticked is still judged at the stack alone, not at the stockpile. That comes from reading the code, not a run, and changing it means changing the arm that dresses for hauling as well, so it stays out of this fix.

Room stands keep their rule, so a crafter at one still carries a product past the door in uniform, as they always have.

The dll is not in this branch; it is built and committed at the release merge.

🤖 Generated with Claude Code

beverage and others added 2 commits November 6, 2026 13:57
…'s radius or area

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@beverage
beverage merged commit 0d5ca4d into main Nov 6, 2026
2 checks passed
@beverage
beverage deleted the feature/bill-product-haul branch November 6, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant