Bay 12 Games Forum

Dwarf Fortress => DF Modding => Utilities and 3rd Party Applications => Topic started by: utunnels on April 16, 2015, 04:06:37 am

Title: [WIP] Dwarven marriage test (dmt.lua)
Post by: utunnels on April 16, 2015, 04:06:37 am
I want to run a fortress that only breeds using the starting seven. So I'm trying to write a script that prints all possible hetero couples(those who can marry and have children). It is still a WIP, but it can already print all necessary informations(age, orientation and valid mating candidates).

I'm still working on how to calculate the number of valid couples(I haven't do any math for ages so I'm a bit rusty).
For example there are two possible combinations: AB and AC, since A can only marry one from B and C, so there'll be only 1 possible couple.

Code: [Select]
local utils = require('utils')
 
local args = utils.processArgs({...})

if args.help then
 print('Dwarven marriage test script.')
 return
end

local function round(n, d)
  local m= 10^(d or 0)
  return math.floor(n*m+ 0.5) / m
end

local function getAgeString(unit)
  return ''..round(dfhack.units.getAge(unit,true),2)
end

local function getInfoString(unit)
 local infStr
 if unit.sex==0 then
  infStr='female, '
 elseif unit.sex==1 then
  infStr='male, '
 else
  infStr=""
 end
 infStr=infStr..getAgeString(unit)
 return '('..infStr..')'
end

--this is from gaydar.lua
local function determineorientation(unit)
 if unit.sex~=-1 then
  local return_string=''
  local orientation=unit.status.current_soul.orientation_flags
  local male_interested,asexual=false,true
  if orientation.romance_male then
   return_string=return_string..' likes males'
   male_interested=true
   asexual=false
  elseif orientation.marry_male then
   return_string=return_string..' will marry males'
   male_interested=true
   asexual=false
  end
  if orientation.romance_female then
   if male_interested then
 return_string=return_string..' and likes females'
   else
    return_string=return_string..' likes females'
   end
   asexual=false
  elseif orientation.marry_female then
   if male_interested then
 return_string=return_string..' and will marry females'
   else
    return_string=return_string..' will marry females'
   end
   asexual=false
  end
  if asexual then
   return_string=' is asexual'
  end

  return return_string
 else
  return "is not biologically capable of sex"
 end
end

local function nameOrSpeciesAndNumber(unit)
 if unit.name.has_name then
  return dfhack.TranslateName(dfhack.units.getVisibleName(unit))..' '..getInfoString(unit),true
 else
  return 'Unit #'..unit.id..' ('..df.creature_raw.find(unit.race).caste[unit.caste].caste_name[0]..getInfoString(unit)..')',false
 end
end

local validcitizens={}

for k,v in ipairs(df.global.world.units.active) do
  if dfhack.units.isCitizen(v)
    and ((v.sex==0 and v.status.current_soul.orientation_flags.marry_male)
          or (v.sex==1 and v.status.current_soul.orientation_flags.marry_female)) then
   table.insert(validcitizens,{v,nameOrSpeciesAndNumber(v) .. determineorientation(v)})
  end
end

local validpairs = {}
local validcount = {[0]=0,[1]=0}

local function checkAndAddValidPair(p)
  --sort first
  if p[1].sex==1 then
    local t = p[1]
    p[1] = p[2]
    p[2] = t
  end
  for j,v in ipairs(validpairs) do
    if p[1]==v[1] and p[2]==v[2] then
      return false
    end
  end
  table.insert(validpairs,p)
  return true
end


-- only find valid couples
for k,v in ipairs(validcitizens) do
  print(v[2])
  if v[1].relations.spouse_id~=-1 then
    print('  Already has a spouse')
  end
  if v[1].relations.lover_id~=-1 then
    print('  Already has a lover')
  end
  local valid = false
  for i,x in ipairs(validcitizens) do
    if x[1]~=v[1] and x[1].sex~=v[1].sex then
      if v[1].relations.spouse_id==x[1].id or v[1].relations.lover_id==x[1].id then
        print('  '..dfhack.TranslateName(dfhack.units.getVisibleName(x[1]))..' (arranged)')
checkAndAddValidPair({v[1],x[1]})
        valid = true
      elseif v[1].relations.lover_id==-1 and v[1].relations.spouse_id==-1
          and x[1].relations.lover_id==-1 and x[1].relations.spouse_id==-1
          and math.abs(dfhack.units.getAge(x[1],true)-dfhack.units.getAge(v[1],true))<10 then
        print('  '..dfhack.TranslateName(dfhack.units.getVisibleName(x[1])))
checkAndAddValidPair({v[1],x[1]})
        valid = true
      end
    end
  end
  if valid then
validcount[v[1].sex] = validcount[v[1].sex]+1
  end
end
print('')
print('There are ' ..math.min(validcount[1],validcount[0]).. ' possible valid couples')

for k,v in ipairs(validpairs) do
print(' '..dfhack.TranslateName(dfhack.units.getVisibleName(v[1]))..' x '..dfhack.TranslateName(dfhack.units.getVisibleName(v[2])))
end
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: Putnam on April 16, 2015, 09:51:40 pm
Number of valid breeding couples = (n2 - n) / 2, where n is total number of eligible opposite-sex marry units.

Shipping science. (http://www.mspaintadventures.com/?s=6&p=006871)
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: utunnels on April 16, 2015, 10:30:29 pm
Sorry maybe I didn't describe my goal clearly.

I figured out the result should be min(n_male, n_female), where n_male and n_female is corresponding total number of each gender among all valid pairs.
For example, there are 5 dorfs A,B,C,D & E, A & E are female, B,C & E are male, and there are 3 possible pairs, like this:

A--B
A--C
D--E

There are 2 possible couples, either (A--B and D--E), or (A--C and D--E).


1--4
A--B
A--C
A--E
A--F

result: 1


2--3
A--B
A--C
D--B
D--E

reulst:2

A--B, D--E
or
A--C, D--E
or
A--C, D--B


.....



Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: Putnam on April 16, 2015, 10:37:40 pm
Oh, total sets of couples as opposed to total sets of pairings, okay.
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: TheKaspa on April 22, 2015, 03:02:06 am
I tried your script and found it very useful.
I have three possible couples, one of which is already with child and another one is still on "lover" stage.

Would it be possible to extend it to check if the couple is formed or at least on lover status?
I don't know how to mod, but I suppose it requires only to check into relationships.
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: Putnam on April 22, 2015, 03:05:55 am
Even I do not know how to check relationships. (mainly because i haven't bothered to find out yet :P)

Checking if a couple is already formed, however, is as simple as checking if unit.relations.lover_id~=-1 or unit.relations.spouse_id~=-1.
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: TheKaspa on April 22, 2015, 03:11:29 am
Exactly what I was looking for. A way to check if said dwarf is a spouse or a lover.
I will toy with this once at home
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: Roses on April 22, 2015, 08:40:59 am
I noticed when playing around with the relationship screen that you can find the types of relationships they have and even the "level" they are at, but I couldn't find where that information was actually stored (i.e. where the screen got the info).
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: utunnels on April 23, 2015, 03:51:04 am
I tried your script and found it very useful.
I have three possible couples, one of which is already with child and another one is still on "lover" stage.

Would it be possible to extend it to check if the couple is formed or at least on lover status?
I don't know how to mod, but I suppose it requires only to check into relationships.
The script already does. It will not print other candidates if said dwarf already has a spouse or lover.
However if you want to trace a family tree the relation screen is a better choice.
Also I don't know if children can have some sort of relationships. For example, two dwarven babies who grow up together. Will they become lovers when they both turn 12 years old?

edit*

Oh, maybe it should filter those children.
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: TheKaspa on April 23, 2015, 08:53:14 am
But it doesn't tell that there is only one candidate because already in a relationship, right?
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: utunnels on April 23, 2015, 09:56:13 am
Oh, it does. But the information was print before the list.

Something like this:


Mebzuth Avuzenkos (male, 70.58) will marry females
  Already has a lover
  Rakust Mosusnunok (arranged)
Rakust Mosusnunok (female, 66.25) will marry males and likes females
  Already has a lover
  Mebzuth Avuzenkos (arranged)
Bembul Oggezrimtar (female, 86.27) will marry males and will marry females
  Tobul Egomdatan
Tobul Egomdatan (male, 87.05) will marry females
  Bembul Oggezrimtar
Momuz Tosedfath (female, 67.2) will marry males
Urdim Thikutfotthor (male, 52.29) will marry females

There are 2 possible valid couples

 Rakust Mosusnunok x Mebzuth Avuzenkos
 Bembul Oggezrimtar x Tobul Egomdatan
Title: Re: [WIP] Dwarven marriage test (dmt.lua)
Post by: TheKaspa on April 23, 2015, 10:28:10 am
Ops, sorry.
I was so concerned with my civ being dead that I overlooked the details