Merge pull request #730 from PeridexisErrant/add-scripts
Add updated emigration script, gui/family-affairsdevelop
commit
2f8f5b071a
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
@ -0,0 +1,130 @@
|
|||||||
|
--Allow stressed dwarves to emigrate from the fortress
|
||||||
|
-- For 34.11 by IndigoFenix; update and cleanup by PeridexisErrant
|
||||||
|
-- old version: http://dffd.bay12games.com/file.php?id=8404
|
||||||
|
--[[=begin
|
||||||
|
|
||||||
|
emigration
|
||||||
|
==========
|
||||||
|
Allows dwarves to emigrate from the fortress when stressed,
|
||||||
|
in proportion to how badly stressed they are and adjusted
|
||||||
|
for who they would have to leave with - a dwarven merchant
|
||||||
|
being more attractive than leaving alone (or with an elf).
|
||||||
|
The check is made monthly.
|
||||||
|
|
||||||
|
A happy dwarf (ie with negative stress) will never emigrate.
|
||||||
|
|
||||||
|
Usage: ``emigration enable|disable``
|
||||||
|
|
||||||
|
=end]]
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
if args[1] == "enable" then
|
||||||
|
enabled = true
|
||||||
|
elseif args[1] == "disable" then
|
||||||
|
enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function desireToStay(unit,method,civ_id)
|
||||||
|
-- on a percentage scale
|
||||||
|
value = 100 - unit.status.current_soul.personality.stress_level / 5000
|
||||||
|
if method == 'merchant' or method == 'diplomat' then
|
||||||
|
if civ_id ~= unit.civ_id then value = value*2 end end
|
||||||
|
if method == 'wild' then
|
||||||
|
value = value*5 end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
function desert(u,method,civ)
|
||||||
|
u.relations.following = nil
|
||||||
|
local line = dfhack.TranslateName(dfhack.units.getVisibleName(u)) .. " has "
|
||||||
|
if method == 'merchant' then
|
||||||
|
line = line.."joined the merchants"
|
||||||
|
u.flags1.merchant = true
|
||||||
|
u.civ_id = civ
|
||||||
|
elseif method == 'diplomat' then
|
||||||
|
line = line.."followed the diplomat"
|
||||||
|
u.flags1.diplomat = true
|
||||||
|
u.civ_id = civ
|
||||||
|
else
|
||||||
|
line = line.."abandoned the settlement in search of a better life."
|
||||||
|
u.civ_id = -1
|
||||||
|
u.flags1.forest = true
|
||||||
|
u.animal.leave_countdown = 2
|
||||||
|
end
|
||||||
|
print(line)
|
||||||
|
dfhack.gui.showAnnouncement(line, COLOR_WHITE)
|
||||||
|
end
|
||||||
|
|
||||||
|
function canLeave(unit)
|
||||||
|
for _, skill in pairs(unit.status.current_soul.skills) do
|
||||||
|
if skill.rating > 14 then return false end
|
||||||
|
end
|
||||||
|
if unit.flags1.caged
|
||||||
|
or u.race ~= df.global.ui.race_id
|
||||||
|
or u.civ_id ~= df.global.ui.civ_id
|
||||||
|
or dfhack.units.isDead(u)
|
||||||
|
or dfhack.units.isOpposedToLife(u)
|
||||||
|
or u.flags1.merchant
|
||||||
|
or u.flags1.diplomat
|
||||||
|
or unit.flags1.chained
|
||||||
|
or dfhack.units.getNoblePositions(unit) ~= nil
|
||||||
|
or unit.military.squad_id ~= -1
|
||||||
|
or dfhack.units.isCitizen(unit)
|
||||||
|
or dfhack.units.isSane(unit)
|
||||||
|
or unit.profession ~= 103
|
||||||
|
or not dfhack.units.isDead(unit)
|
||||||
|
then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkForDeserters(method,civ_id)
|
||||||
|
local allUnits = df.global.world.units.active
|
||||||
|
for i=#allUnits-1,0,-1 do -- search list in reverse
|
||||||
|
local u = allUnits[i]
|
||||||
|
if canLeave(u) and math.random(100) < desireToStay(u,method,civ_id) then
|
||||||
|
desert(u,method,civ_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function checkmigrationnow()
|
||||||
|
local merchant_civ_ids = {}
|
||||||
|
local diplomat_civ_ids = {}
|
||||||
|
local allUnits = df.global.world.units.active
|
||||||
|
for i=0, #allUnits-1 do
|
||||||
|
local unit = allUnits[i]
|
||||||
|
if dfhack.units.isSane(unit)
|
||||||
|
and not dfhack.units.isDead(unit)
|
||||||
|
and not dfhack.units.isOpposedToLife(unit)
|
||||||
|
and not unit.flags1.tame
|
||||||
|
then
|
||||||
|
if unit.flags1.merchant then table.insert(merchant_civ_ids, unit.civ_id) end
|
||||||
|
if unit.flags1.diplomat then table.insert(diplomat_civ_ids, unit.civ_id) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, civ_id in pairs(merchant_civ_ids) do checkForDeserters('merchant', civ_id) end
|
||||||
|
for _, civ_id in pairs(diplomat_civ_ids) do checkForDeserters('diplomat', civ_id) end
|
||||||
|
checkForDeserters('wild', -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function event_loop()
|
||||||
|
checkmigrationnow()
|
||||||
|
dfhack.timeout(1, 'months', event_loop)
|
||||||
|
end
|
||||||
|
|
||||||
|
dfhack.onStateChange.loadEmigration = function(code)
|
||||||
|
if code==SC_MAP_LOADED then
|
||||||
|
if enabled then
|
||||||
|
print("Emigration enabled.")
|
||||||
|
event_loop()
|
||||||
|
else
|
||||||
|
print("Emigration disabled.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if dfhack.isMapLoaded() then
|
||||||
|
dfhack.onStateChange.loadEmigration(SC_MAP_LOADED)
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,296 @@
|
|||||||
|
-- gui/family-affairs
|
||||||
|
-- derived from v1.2 @ http://www.bay12forums.com/smf/index.php?topic=147779
|
||||||
|
local help = [[=begin
|
||||||
|
|
||||||
|
gui/family-affairs
|
||||||
|
==================
|
||||||
|
A user-friendly interface to view romantic relationships,
|
||||||
|
with the ability to add, remove, or otherwise change them at
|
||||||
|
your whim - fantastic for depressed dwarves with a dead spouse
|
||||||
|
(or matchmaking players...).
|
||||||
|
|
||||||
|
The target/s must be alive, sane, and in fortress mode.
|
||||||
|
|
||||||
|
.. image:: /docs/images/family-affairs.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
``gui/family-affairs [unitID]``
|
||||||
|
shows GUI for the selected unit, or the specified unit ID
|
||||||
|
|
||||||
|
``gui/family-affairs divorce [unitID]``
|
||||||
|
removes all spouse and lover information from the unit
|
||||||
|
and it's partner, bypassing almost all checks.
|
||||||
|
|
||||||
|
``gui/family-affairs [unitID] [unitID]``
|
||||||
|
divorces the two specificed units and their partners,
|
||||||
|
then arranges for the two units to marry, bypassing
|
||||||
|
almost all checks. Use with caution.
|
||||||
|
|
||||||
|
=end]]
|
||||||
|
|
||||||
|
local dlg = require ('gui.dialogs')
|
||||||
|
|
||||||
|
function ErrorPopup (msg,color)
|
||||||
|
if not tostring(msg) then msg = "Error" end
|
||||||
|
if not color then color = COLOR_LIGHTRED end
|
||||||
|
dlg.showMessage("Dwarven Family Affairs", msg, color, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function AnnounceAndGamelog (text,l)
|
||||||
|
if not l then l = true end
|
||||||
|
dfhack.gui.showAnnouncement(text, _G["COLOR_LIGHTMAGENTA"])
|
||||||
|
if l then
|
||||||
|
local log = io.open('gamelog.txt', 'a')
|
||||||
|
log:write(text.."\n")
|
||||||
|
log:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ListPrompt (msg, choicelist, bool, yes_func)
|
||||||
|
dlg.showListPrompt(
|
||||||
|
"Dwarven Family Affairs",
|
||||||
|
msg,
|
||||||
|
COLOR_WHITE,
|
||||||
|
choicelist,
|
||||||
|
--called if choice is yes
|
||||||
|
yes_func,
|
||||||
|
--called on cancel
|
||||||
|
function() end,
|
||||||
|
15,
|
||||||
|
bool
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetMarriageSummary (source)
|
||||||
|
local familystate = ""
|
||||||
|
|
||||||
|
if source.relations.spouse_id ~= -1 then
|
||||||
|
if dfhack.units.isSane(df.unit.find(source.relations.spouse_id)) then
|
||||||
|
familystate = dfhack.TranslateName(source.name).." has a spouse ("..dfhack.TranslateName(df.unit.find(source.relations.spouse_id).name)..")"
|
||||||
|
end
|
||||||
|
if dfhack.units.isSane(df.unit.find(source.relations.spouse_id)) == false then
|
||||||
|
familystate = dfhack.TranslateName(source.name).."'s spouse is dead or not sane, would you like to choose a new one?"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if source.relations.spouse_id == -1 and source.relations.lover_id ~= -1 then
|
||||||
|
if dfhack.units.isSane(df.unit.find(source.relations.lover_id)) then
|
||||||
|
familystate = dfhack.TranslateName(source.name).." already has a lover ("..dfhack.TranslateName(df.unit.find(source.relations.spouse_id).name)..")"
|
||||||
|
end
|
||||||
|
if dfhack.units.isSane(df.unit.find(source.relations.lover_id)) == false then
|
||||||
|
familystate = dfhack.TranslateName(source.name).."'s lover is dead or not sane, would you like that love forgotten?"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if source.relations.spouse_id == -1 and source.relations.lover_id == -1 then
|
||||||
|
familystate = dfhack.TranslateName(source.name).." is not involved in romantic relationships with anyone"
|
||||||
|
end
|
||||||
|
|
||||||
|
if source.relations.pregnancy_timer > 0 then
|
||||||
|
familystate = familystate.."\nShe is pregnant."
|
||||||
|
local father = df.historical_figure.find(source.relations.pregnancy_spouse)
|
||||||
|
if father then
|
||||||
|
familystate = familystate.." The father is "..dfhack.TranslateName(father.name).."."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return familystate
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetSpouseData (source)
|
||||||
|
local spouse = df.unit.find(source.relations.spouse_id)
|
||||||
|
local spouse_hf
|
||||||
|
if spouse then
|
||||||
|
spouse_hf = df.historical_figure.find (spouse.hist_figure_id)
|
||||||
|
end
|
||||||
|
return spouse,spouse_hf
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetLoverData (source)
|
||||||
|
local lover = df.unit.find(source.relations.spouse_id)
|
||||||
|
local lover_hf
|
||||||
|
if lover then
|
||||||
|
lover_hf = df.historical_figure.find (lover.hist_figure_id)
|
||||||
|
end
|
||||||
|
return lover,lover_hf
|
||||||
|
end
|
||||||
|
|
||||||
|
function EraseHFLinksLoverSpouse (hf)
|
||||||
|
for i = #hf.histfig_links-1,0,-1 do
|
||||||
|
if hf.histfig_links[i]._type == df.histfig_hf_link_spousest or hf.histfig_links[i]._type == df.histfig_hf_link_loverst then
|
||||||
|
local todelete = hf.histfig_links[i]
|
||||||
|
hf.histfig_links:erase(i)
|
||||||
|
todelete:delete()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Divorce (source)
|
||||||
|
local source_hf = df.historical_figure.find(source.hist_figure_id)
|
||||||
|
local spouse,spouse_hf = GetSpouseData (source)
|
||||||
|
local lover,lover_hf = GetLoverData (source)
|
||||||
|
|
||||||
|
source.relations.spouse_id = -1
|
||||||
|
source.relations.lover_id = -1
|
||||||
|
|
||||||
|
if source_hf then
|
||||||
|
EraseHFLinksLoverSpouse (source_hf)
|
||||||
|
end
|
||||||
|
if spouse then
|
||||||
|
spouse.relations.spouse_id = -1
|
||||||
|
spouse.relations.lover_id = -1
|
||||||
|
end
|
||||||
|
if lover then
|
||||||
|
spouse.relations.spouse_id = -1
|
||||||
|
spouse.relations.lover_id = -1
|
||||||
|
end
|
||||||
|
if spouse_hf then
|
||||||
|
EraseHFLinksLoverSpouse (spouse_hf)
|
||||||
|
end
|
||||||
|
if lover_hf then
|
||||||
|
EraseHFLinksLoverSpouse (lover_hf)
|
||||||
|
end
|
||||||
|
|
||||||
|
local partner = spouse or lover
|
||||||
|
if not partner then
|
||||||
|
AnnounceAndGamelog(dfhack.TranslateName(source.name).." is now single")
|
||||||
|
else
|
||||||
|
AnnounceAndGamelog(dfhack.TranslateName(source.name).." and "..dfhack.TranslateName(partner.name).." are now single")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Marriage (source,target)
|
||||||
|
local source_hf = df.historical_figure.find(source.hist_figure_id)
|
||||||
|
local target_hf = df.historical_figure.find(target.hist_figure_id)
|
||||||
|
source.relations.spouse_id = target.id
|
||||||
|
target.relations.spouse_id = source.id
|
||||||
|
|
||||||
|
local new_link = df.histfig_hf_link_spousest:new() -- adding hf link to source
|
||||||
|
new_link.target_hf = target_hf.id
|
||||||
|
new_link.link_strength = 100
|
||||||
|
source_hf.histfig_links:insert('#',new_link)
|
||||||
|
|
||||||
|
new_link = df.histfig_hf_link_spousest:new() -- adding hf link to target
|
||||||
|
new_link.target_hf = source_hf.id
|
||||||
|
new_link.link_strength = 100
|
||||||
|
target_hf.histfig_links:insert('#',new_link)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ChooseNewSpouse (source)
|
||||||
|
|
||||||
|
if not source then
|
||||||
|
qerror("no unit") return
|
||||||
|
end
|
||||||
|
if (source.profession == 103 or source.profession == 104) then
|
||||||
|
ErrorPopup("target is too young") return
|
||||||
|
end
|
||||||
|
if not (source.relations.spouse_id == -1 and source.relations.lover_id == -1) then
|
||||||
|
ErrorPopup("target already has a spouse or a lover")
|
||||||
|
qerror("source already has a spouse or a lover")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local choicelist = {}
|
||||||
|
targetlist = {}
|
||||||
|
|
||||||
|
for k,v in pairs (df.global.world.units.active) do
|
||||||
|
if dfhack.units.isCitizen(v)
|
||||||
|
and v.race == source.race
|
||||||
|
and v.sex ~= source.sex
|
||||||
|
and v.relations.spouse_id == -1
|
||||||
|
and v.relations.lover_id == -1
|
||||||
|
and not (v.profession == 103 or v.profession == 104)
|
||||||
|
then
|
||||||
|
table.insert(choicelist,dfhack.TranslateName(v.name)..', '..dfhack.units.getProfessionName(v))
|
||||||
|
table.insert(targetlist,v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #choicelist > 0 then
|
||||||
|
ListPrompt(
|
||||||
|
"Assign new spouse for "..dfhack.TranslateName(source.name),
|
||||||
|
choicelist,
|
||||||
|
true,
|
||||||
|
function(a,b)
|
||||||
|
local target = targetlist[a]
|
||||||
|
Marriage (source,target)
|
||||||
|
AnnounceAndGamelog(dfhack.TranslateName(source.name).." and "..dfhack.TranslateName(target.name).." have married!")
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
ErrorPopup("No suitable candidates")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainDialog (source)
|
||||||
|
|
||||||
|
local familystate = GetMarriageSummary(source)
|
||||||
|
|
||||||
|
familystate = familystate.."\nSelect action:"
|
||||||
|
local choicelist = {}
|
||||||
|
local on_select = {}
|
||||||
|
|
||||||
|
local child = (source.profession == 103 or source.profession == 104)
|
||||||
|
local is_single = source.relations.spouse_id == -1 and source.relations.lover_id == -1
|
||||||
|
local ready_for_marriage = single and not child
|
||||||
|
|
||||||
|
if not child then
|
||||||
|
table.insert(choicelist,"Remove romantic relationships (if any)")
|
||||||
|
table.insert(on_select, Divorce)
|
||||||
|
if ready_for_marriage then
|
||||||
|
table.insert(choicelist,"Assign a new spouse")
|
||||||
|
table.insert(on_select,ChooseNewSpouse)
|
||||||
|
end
|
||||||
|
if not ready_for_marriage then
|
||||||
|
table.insert(choicelist,"[Assign a new spouse]")
|
||||||
|
table.insert(on_select,function () ErrorPopup ("Existing relationships must be removed if you wish to assign a new spouse.") end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(choicelist,"Leave this child alone")
|
||||||
|
table.insert(on_select,nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
ListPrompt(familystate, choicelist, false,
|
||||||
|
function(a,b) if on_select[a] then on_select[a](source) end end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
if args[1] == "help" or args[1] == "?" then print(helpstr) return end
|
||||||
|
|
||||||
|
if not df.global.gamemode == 0 then
|
||||||
|
print (helpstr) qerror ("invalid gamemode") return
|
||||||
|
end
|
||||||
|
|
||||||
|
if args[1] == "divorce" and tonumber(args[2]) then
|
||||||
|
local unit = df.unit.find(args[2])
|
||||||
|
if unit then Divorce (unit) return end
|
||||||
|
end
|
||||||
|
|
||||||
|
if tonumber(args[1]) and tonumber(args[2]) then
|
||||||
|
local unit1 = df.unit.find(args[1])
|
||||||
|
local unit2 = df.unit.find(args[2])
|
||||||
|
if unit1 and unit2 then
|
||||||
|
Divorce (unit1)
|
||||||
|
Divorce (unit2)
|
||||||
|
Marriage (unit1,unit2)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local selected = dfhack.gui.getSelectedUnit(true)
|
||||||
|
if tonumber(args[1]) then
|
||||||
|
selected = df.unit.find(tonumber(args[1])) or selected
|
||||||
|
end
|
||||||
|
|
||||||
|
if selected then
|
||||||
|
if dfhack.units.isCitizen(selected) and dfhack.units.isSane(selected) then
|
||||||
|
MainDialog(selected)
|
||||||
|
else
|
||||||
|
qerror("You must select sane fortress citizen.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print (helpstr)
|
||||||
|
qerror("select a sane fortress dwarf")
|
||||||
|
end
|
Loading…
Reference in New Issue