From e88ff329b9303413f54179dc86ad0a59fa2da4dc Mon Sep 17 00:00:00 2001 From: Edward Becker Date: Thu, 15 Oct 2026 10:59:07 -0400 Subject: [PATCH] workorder: require item_subtype for item-making orders An order for an item type that has subtypes (shoes, armor, weapons, tools, ammo, ...) created without "item_subtype" was left at item_subtype -1. DF accepts and validates such an order, but segfaults in its job-name code whenever a resulting job is named (by dfhack.job.getName or by the game drawing the job), and the bad order persists in the save. Refuse these orders with an error that names a valid subtype. Meals (PrepareMeal / FOOD) keep item_subtype -1 as in vanilla and are exempt. Co-Authored-By: Claude Opus 5.5 --- changelog.txt | 1 + workorder.lua | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/changelog.txt b/changelog.txt index 5b582e5859..7fba82d692 100644 --- a/changelog.txt +++ b/changelog.txt @@ -31,6 +31,7 @@ Template for new versions: ## New Features ## Fixes +- `workorder`: refuse item-making orders that lack a required ``item_subtype`` instead of creating orders whose jobs crash DF when they are named ## Misc Improvements diff --git a/workorder.lua b/workorder.lua index 21a3d7bde2..b1f0a3d744 100644 --- a/workorder.lua +++ b/workorder.lua @@ -228,6 +228,21 @@ function create_orders(orders, quiet) .. df.item_type[order.item_type] .. ":" .. it["item_subtype"] ) end + -- An item that has subtypes (shoes, armor, weapons, tools, ammo, toys, ...) needs one: + -- an order left at item_subtype -1 validates, but DF crashes when it names the resulting job. + -- Meals are the exception: they keep item_subtype -1 and store the ingredient count in mat_type. + if order.item_subtype == -1 then + local produced = order.item_type ~= df.item_type.NONE and order.item_type + or df.job_type.attrs[order.job_type].item + if produced and produced ~= df.item_type.NONE and produced ~= df.item_type.FOOD then + local def = df['itemdef_' .. string.lower(df.item_type[produced]) .. 'st'] + if def and #def.get_vector() > 0 then + qerror(("Manager order %s needs an item_subtype (e.g. %s)"):format( + df.job_type[order.job_type], def.get_vector()[0].id)) + end + end + end + if it["meal_ingredients"] then order.mat_type = tonumber(it["meal_ingredients"]) or qerror ( "Invalid meal ingredients for managed order: " .. it["meal_ingredients"]