And one more script for those who are interested. It's kind of a niche thing I threw together for an upcoming community fort, but I think it might be useful to anyone inundated with too many babies being born, as a supplement or instead of the init child cap. I call it Family Planning, but that's probably not the best name for it since it's also simulating infertility due to age. Just drop this into a file called familyplanning.lua in your scripts folder:
-- Simulates menopause and gives a limit on the number of living kids per mother
local args = {...}
function count_children(unit_id)
local children = 0
for key, value in pairs(df.global.world.units.all) do
if value.relations.mother_id == unit_id then
children = children + 1
end
end
return children
end
function terminate_pregnancy(unit)
if unit.relations.pregnancy_timer > 0 then
unit.relations.pregnancy_ptr:delete()
unit.relations.pregnancy_ptr = nil
unit.relations.pregnancy_timer = 0
unit.relations.pregnancy_mystery = -1
return 1 -- Terminated a pregnancy
end
-- Wasn't pregnant
return 0
end
function family_planning(menopause_min, menopause_max, children_min, children_max)
local terminated_pregnancies = 0
for key, value in pairs(df.global.world.units.all) do
local children = 0
-- Only married females matter
if (value.sex == 0 and value.relations.spouse_id ~= -1) then
children = count_children(value.id)
end
math.randomseed(value.id)
local maximum_children = math.random(children_min, children_max)
local menopause_age = math.random(menopause_min, menopause_max)
local age = df.global.cur_year - value.relations.birth_year
if age > menopause_age or children > maximum_children then
-- This is awkward syntax, but I have no idea how to pass local values by reference in Lua
terminated_pregnancies = terminated_pregnancies + terminate_pregnancy(value)
end
end
print("Terminated " .. terminated_pregnancies .. " pregnancies.")
end
if df.isnull(args[4]) then
print('You did not specify four parameters, so the following are assumed: menopause at 40-60, maximum children from 2-4.')
args[1] = 40
args[2] = 60
args[3] = 2
args[4] = 4
end
dfhack.with_suspend(family_planning, tonumber(args[1]), tonumber(args[2]), tonumber(args[3]), tonumber(args[4]))
The syntax is either
familyplanning
or familyplanning menopause_min menopause_max children_min children_max
If you don't provide all four of those arguments, it uses these defaults: Menopause sets in at some age between 40 and 60. A mother will be limited to somewhere between 2 and 4 children.
The actual menopause age and child cap are randomly decided per mother, with the RNG seeded based on her unit id. This has the effect of being consistent between runs of the tool, but giving different values per mother. If a mother is found who is too old or has more kids than she's supposed, and she's pregnant, it will remove her pregnancy. I think this currently counts deceased children too, if they have migrated. I'm not positive what it will do for those who haven't migrated: it only checks the global units list, so if things that haven't migrated aren't populated in that list they won't get counted.
These are roughly human values. Ideally this would check the max age of the creature in question, but I don't know how to do that yet if it's possible. Instead, if you really care about more dwarfy values you can just enter something like 100 for the menopause ages. If you don't want that to be simulated, just enter like 1000.
This script will need to be run manually periodically. It should arrive at the same random age and child caps even between runs of DF. I don't know if it's possible to configure DFHack to run Lua scripts automatically, but I don't think so. I can't code it in C++ right now either due to a lack of a compatible compiler being available right now.
I tested this one on a 20 year old fort, but it is unfortunately modded and running a species of egg layers. It found and terminated 8 pregnancies as a result, and while they're egg layers, I assume it will work properly for dwarves and other creatures.