From f41adf2846f9b75229437c99d0f983732e7283c4 Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Mon, 23 Oct 2023 09:46:00 +0100 Subject: [PATCH 1/9] script for a gui pregnancy tool --- gui/pregnancy.lua | 328 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 gui/pregnancy.lua diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua new file mode 100644 index 0000000000..f7a765a5fa --- /dev/null +++ b/gui/pregnancy.lua @@ -0,0 +1,328 @@ +local gui = require('gui') +local widgets = require('gui.widgets') + +PregnancyGui = defclass(PregnancyGui, widgets.Window) +PregnancyGui.ATTRS { + frame_title='My Window', + frame={w=50, h=45}, + resizable=true, -- if resizing makes sense for your dialog + resize_min={w=50, h=20}, -- try to allow users to shrink your windows +} + +function PregnancyGui:init() + self.mother = false + self.father = false + self.father_historical = false + self.msg = {} + -- self.success = false + self:addviews{ + widgets.ResizingPanel{ + frame={t=0}, + frame_style=gui.FRAME_INTERIOR, + autoarrange_subviews=true, + subviews={ + widgets.WrappedLabel{ + text_to_wrap=self:callback('getMotherLabel') + }, + widgets.HotkeyLabel{ + frame={l=0}, + label="Select Mother", + key='CUSTOM_SHIFT_M', + on_activate=self:callback('selectmother'), + }, + }, + }, + widgets.ResizingPanel{ + frame={t=6}, + frame_style=gui.FRAME_INTERIOR, + autoarrange_subviews=true, + subviews={ + widgets.WrappedLabel{ + text_to_wrap=self:callback('getFatherLabel') + }, + widgets.HotkeyLabel{ + frame={l=0}, + label="Select Father", + key='CUSTOM_SHIFT_F', + on_activate=self:callback('selectfather'), + }, + widgets.HotkeyLabel{ + frame={l=5}, + label="Set Mother's spouse as the Father", + key='CUSTOM_F', + on_activate=self:callback('spouseFather'), + disabled=function() return not self.mother or self.mother.relationship_ids.Spouse == -1 end + }, + }, + }, + widgets.ResizingPanel{ + frame={t=12}, + frame_style=gui.FRAME_INTERIOR, + autoarrange_subviews=1, + subviews={ + widgets.HotkeyLabel{ + frame={l=0}, + key='CUSTOM_SHIFT_P', + label="Create pregnancy", + on_activate=self:callback('CreatePregnancy'), + enabled=function() return self.mother or self.father and self.father_historical end + }, + widgets.TooltipLabel{ + text_to_wrap=self.msg, + show_tooltip=true + }, + + widgets.ToggleHotkeyLabel{ + view_id='Force', + label='Force', + options={{label='On', value=true, pen=COLOR_GREEN}, + {label='Off', value=false, pen=COLOR_RED}}, + initial_option=false + }, + }, + }, + widgets.ResizingPanel{ + frame={t=22}, + frame_style=gui.FRAME_INTERIOR, + autoarrange_subviews=true, + subviews={ + widgets.HotkeyLabel{ + frame={l=1, b=0}, + key='LEAVESCREEN', + label="Return to game", + on_activate=function() + repeat until not self:onInput{LEAVESCREEN=true} + view:dismiss() + end, + }, + }, + }, + } +end + +function PregnancyGui:selectmother() + local unit = dfhack.gui.getSelectedUnit() + if unit then + if unit.sex==0 and dfhack.units.isAdult(unit) then + self.mother = unit + self:updateLayout() + end + end +end + +function PregnancyGui:selectfather() + local unit = dfhack.gui.getSelectedUnit() + if unit and dfhack.units.isAdult(unit) then + self.father = unit + self.father_historical = false + self:updateLayout() + end +end + +function PregnancyGui:spouseFather() + local father = self:findSpouse(self.mother)[3] + if father then + if df.unit.find(father.unit_id) then + self.father = df.unit.find(father.unit_id) + self.father_historical = false + else + self.father_historical = father + self.father = false + end + self:updateLayout() + end +end + +function PregnancyGui:getMotherLabel() + if self.mother then + local motherName = dfhack.TranslateName(self.mother.name) + if self.mother.relationship_ids.Spouse > -1 then + local spouseInfo = self:findSpouse(self.mother) + return ('Selected mother: %s.%sShe is married to %s (%s).'):format( + self:findName(self.mother), + NEWLINE, + spouseInfo[1], + spouseInfo[2] + ) + else + return ('Selected mother: %s.%sShe is unmarried.'):format( + self:findName(self.mother), + NEWLINE + ) + end + else return ('No mother selected - Must be a adult female') + end +end + +function PregnancyGui:getFatherLabel() + if self.father or self.father_historical then + if self.father_historical or self.father.relationship_ids.Spouse > -1 then + local father = self.father or self.father_historical + local spouseInfo = self:findSpouse(father) + return ('Selected father: %s.%s%s is married to %s (%s).'):format( + self:findName(father), + NEWLINE, + df.pronoun_type[father.sex]:gsub("^%l", string.upper), + spouseInfo[1], + spouseInfo[2] + ) + else + return ('Selected father: %s.%s%s is unmarried.'):format( + self:findName(self.father), + NEWLINE, + df.pronoun_type[self.father.sex]:gsub("^%l", string.upper) + ) + end + else return ('No father selected') + end +end + +function PregnancyGui:findName(unit) + if unit.name.has_name then + return dfhack.TranslateName(unit.name) + elseif unit.name.nickname ~= "" then + return unit.name.nickname + else return ('Unnamed %s. (Unit id:%s)'):format( + string.upper(df.global.world.raws.creatures.all[unit.race].name[0]), + unit.id + ) + end +end + +function PregnancyGui:findSpouse(unit) + local historical_spouse, spouse_loc, spouse, spouseid + local culled = false + + --setting variables for if mother or father are local, followed by finding the father's spouse if he is not local + if self.father == unit or self.mother == unit then + spouseid = unit.relationship_ids.Spouse + spouse = df.unit.find(spouseid) + elseif self.father_historical == unit then + for index, relation in pairs(unit.histfig_links) do + if relation._type == df.histfig_hf_link_spousest then + historical_spouse=df.historical_figure.find(relation.target_hf) + if not historical_spouse then culled = true --there was an id, but there wasn't a histfig with that id (due culling) + elseif df.global.plotinfo.site_id==historical_spouse.info.whereabouts.site then + spouse_loc = 'local' + else spouse_loc = 'offsite' + end + end + end + return {dfhack.TranslateName(historical_spouse.name),spouse_loc,historical_spouse} + end + + --if the spouse is local this should identify them: + if spouse then + historical_spouse = df.historical_figure.find(spouse.hist_figure_id) or false + spouse_loc = 'local' + end + + --if spouse is not local (offsite): + if spouseid > -1 and not spouse then --spouse exists but isnt on the map, so search historical units: + local historical_unit = df.historical_figure.find(unit.hist_figure_id) + for index, relation in pairs(historical_unit.histfig_links) do + if relation._type == df.histfig_hf_link_spousest then + historical_spouse=df.historical_figure.find(relation.target_hf) + if not historical_spouse then culled = true --there was an id, but there wasn't a histfig with that id (due culling) + elseif df.global.plotinfo.site_id==historical_spouse.info.whereabouts.site then--i dont think this should ever be true + spouse_loc = 'local' + else spouse_loc = 'offsite' + end + end + end + end + if culled then + return {'Unknown','culled'} + else + return {dfhack.TranslateName(historical_spouse.name),spouse_loc,historical_spouse} + end +end + +function PregnancyGui:CreatePregnancy() + local genes,father_id,father_caste,father_name + local bypass = true + local force = self.subviews.Force:getOptionValue() + + local count = #self.msg + for i=0, count do self.msg[i]=nil end --empty self.msg + + if self.father then + genes=self.father.appearance.genes:new() + father_id=self.father.hist_figure_id + father_caste=self.father.caste + father_name=self:findName(self.father) + else + genes=self.mother.appearance.genes:new()--i dont think historical figures have genes + father_id=self.father_historical.id + father_caste=self.father_historical.caste + father_name=self:findName(self.father_historical) + end + + if self.mother.pregnancy_timer > 0 then + local og_father = df.historical_figure.find(self.mother.pregnancy_spouse) + bypass = false + if force and og_father then + table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy with %s aborted'):format( + NEWLINE, + self:findName(self.mother), + NEWLINE, + father_name, + NEWLINE, + dfhack.TranslateName(og_father.name) + )) + elseif force then + table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy aborted'):format( + NEWLINE, + self:findName(self.mother), + NEWLINE, + father_name, + NEWLINE + )) + elseif og_father then + table.insert(self.msg, ('FAILED:%s%s already pregnant with %s%s'):format( + NEWLINE, + self:findName(self.mother), + dfhack.TranslateName(og_father.name), + force + )) + else + table.insert(self.msg, ('FAILED:%s%s is already pregnant, no father is recorded'):format( + NEWLINE, + self:findName(self.mother) + )) + end + end + -- self.success = false + if bypass or force then + --TODO add GUI to select the number of months for pregnancy timer + self.mother.pregnancy_timer=math.random(1, 13000) + self.mother.pregnancy_caste=father_caste + self.mother.pregnancy_spouse=father_id + self.mother.pregnancy_genes=genes + -- self.success = true + if not force then + table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s'):format( + NEWLINE, + self:findName(self.mother), + NEWLINE, + father_name + )) + end + end + self:updateLayout() +end + +PregnancyScreen = defclass(PregnancyScreen, gui.ZScreen) +PregnancyScreen.ATTRS { + focus_path='PregnancyScreen', +} + +function PregnancyScreen:init() + self:addviews{PregnancyGui{}} +end + +function PregnancyScreen:onDismiss() + view = nil +end + +view = view and view:raise() or PregnancyScreen{}:show() \ No newline at end of file From 15e675214e1376319ed3469c0b0d0791d0a94f18 Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Sat, 28 Oct 2023 15:20:33 +0100 Subject: [PATCH 2/9] Implementing myk002's suggestions --- gui/pregnancy.lua | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index f7a765a5fa..20c64ac563 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -3,7 +3,7 @@ local widgets = require('gui.widgets') PregnancyGui = defclass(PregnancyGui, widgets.Window) PregnancyGui.ATTRS { - frame_title='My Window', + frame_title='Pregnancy manager', frame={w=50, h=45}, resizable=true, -- if resizing makes sense for your dialog resize_min={w=50, h=20}, -- try to allow users to shrink your windows @@ -14,7 +14,6 @@ function PregnancyGui:init() self.father = false self.father_historical = false self.msg = {} - -- self.success = false self:addviews{ widgets.ResizingPanel{ frame={t=0}, @@ -178,10 +177,9 @@ function PregnancyGui:getFatherLabel() end function PregnancyGui:findName(unit) - if unit.name.has_name then - return dfhack.TranslateName(unit.name) - elseif unit.name.nickname ~= "" then - return unit.name.nickname + local name = dfhack.TranslateName(unit.name) + if name ~= "" then + return name else return ('Unnamed %s. (Unit id:%s)'):format( string.upper(df.global.world.raws.creatures.all[unit.race].name[0]), unit.id @@ -262,7 +260,7 @@ function PregnancyGui:CreatePregnancy() local og_father = df.historical_figure.find(self.mother.pregnancy_spouse) bypass = false if force and og_father then - table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy with %s aborted'):format( + table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy with %s replaced'):format( NEWLINE, self:findName(self.mother), NEWLINE, @@ -314,7 +312,7 @@ end PregnancyScreen = defclass(PregnancyScreen, gui.ZScreen) PregnancyScreen.ATTRS { - focus_path='PregnancyScreen', + focus_path='pregnancy', } function PregnancyScreen:init() From d0d7106945d0f58bbe22f96c2b069ebbf7e7888f Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Sat, 28 Oct 2023 19:05:05 +0100 Subject: [PATCH 3/9] added Rangeslider widget for pregnancy term --- gui/pregnancy.lua | 81 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index 20c64ac563..6590f5e85a 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -4,7 +4,7 @@ local widgets = require('gui.widgets') PregnancyGui = defclass(PregnancyGui, widgets.Window) PregnancyGui.ATTRS { frame_title='Pregnancy manager', - frame={w=50, h=45}, + frame={w=64, h=35}, resizable=true, -- if resizing makes sense for your dialog resize_min={w=50, h=20}, -- try to allow users to shrink your windows } @@ -14,6 +14,18 @@ function PregnancyGui:init() self.father = false self.father_historical = false self.msg = {} + + local term_options = {} + local term_index = {} + local months + for months=0,10 do + -- table.insert(term_options,{label=('%s months'):format(months),value=months}) --I tried this to add labels, probably doing something wrong, it broke the range widget + table.insert(term_options,months) --this works though + end + for k,v in ipairs(term_options) do + term_index[v] = k + end + self:addviews{ widgets.ResizingPanel{ frame={t=0}, @@ -32,7 +44,7 @@ function PregnancyGui:init() }, }, widgets.ResizingPanel{ - frame={t=6}, + frame={t=5}, frame_style=gui.FRAME_INTERIOR, autoarrange_subviews=true, subviews={ @@ -54,34 +66,69 @@ function PregnancyGui:init() }, }, }, - widgets.ResizingPanel{ - frame={t=12}, + widgets.Panel{ + frame={t=12,h=14}, frame_style=gui.FRAME_INTERIOR, - autoarrange_subviews=1, subviews={ widgets.HotkeyLabel{ - frame={l=0}, + frame={l=0, t=0}, key='CUSTOM_SHIFT_P', label="Create pregnancy", on_activate=self:callback('CreatePregnancy'), enabled=function() return self.mother or self.father and self.father_historical end }, - widgets.TooltipLabel{ - text_to_wrap=self.msg, - show_tooltip=true - }, - widgets.ToggleHotkeyLabel{ + frame={l=1, t=1}, view_id='Force', label='Force', options={{label='On', value=true, pen=COLOR_GREEN}, {label='Off', value=false, pen=COLOR_RED}}, initial_option=false }, + widgets.TooltipLabel{ + frame={l=0, t=3}, + text_to_wrap='Pregnancy term range (months):', + show_tooltip=true, + text_pen=COLOR_WHITE + }, + widgets.CycleHotkeyLabel{ + view_id='min_term', + frame={l=0, t=6, w=SLIDER_LABEL_WIDTH}, + label='Min pregnancy term:', + key_back='CUSTOM_SHIFT_Z', + key='CUSTOM_SHIFT_X', + options=term_options, + initial_option=7 + }, + widgets.CycleHotkeyLabel{ + view_id='max_term', + frame={l=30, t=6, w=SLIDER_LABEL_WIDTH}, + label='Max pregnancy term:', + key_back='CUSTOM_SHIFT_Q', + key='CUSTOM_SHIFT_W', + options=term_options, + initial_option=9 + }, + widgets.RangeSlider{ + frame={l=0, t=4}, + num_stops=#term_options, + get_left_idx_fn=function() + return term_index[self.subviews.min_term:getOptionLabel()] + end, + get_right_idx_fn=function() + return term_index[self.subviews.max_term:getOptionLabel()] + end, + on_left_change=function(idx) self.subviews.min_term:setOption(idx, true) end, + on_right_change=function(idx) self.subviews.max_term:setOption(idx, true) end, + }, + widgets.WrappedLabel{ + frame={t=8},--, h=5}, + text_to_wrap=self.msg + }, }, }, widgets.ResizingPanel{ - frame={t=22}, + frame={t=26}, frame_style=gui.FRAME_INTERIOR, autoarrange_subviews=true, subviews={ @@ -237,13 +284,19 @@ function PregnancyGui:findSpouse(unit) end function PregnancyGui:CreatePregnancy() - local genes,father_id,father_caste,father_name + local genes,father_id,father_caste,father_name local bypass = true local force = self.subviews.Force:getOptionValue() local count = #self.msg for i=0, count do self.msg[i]=nil end --empty self.msg + if self.subviews.min_term:getOptionLabel() > self.subviews.max_term:getOptionLabel() then + table.insert(self.msg,('Min term has to be less then max term')) + self:updateLayout() + return + end + if self.father then genes=self.father.appearance.genes:new() father_id=self.father.hist_figure_id @@ -293,7 +346,7 @@ function PregnancyGui:CreatePregnancy() -- self.success = false if bypass or force then --TODO add GUI to select the number of months for pregnancy timer - self.mother.pregnancy_timer=math.random(1, 13000) + self.mother.pregnancy_timer=math.random(self.subviews.min_term:getOptionLabel()*33600+1, self.subviews.max_term:getOptionLabel()*33600+1) self.mother.pregnancy_caste=father_caste self.mother.pregnancy_spouse=father_id self.mother.pregnancy_genes=genes From 523c58558064d3291be2e93369be2632c4349040 Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Sat, 28 Oct 2023 19:08:04 +0100 Subject: [PATCH 4/9] Apply suggestions from code review Co-authored-by: Myk --- gui/pregnancy.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index 6590f5e85a..b3fc94eebb 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -147,7 +147,7 @@ function PregnancyGui:init() end function PregnancyGui:selectmother() - local unit = dfhack.gui.getSelectedUnit() + local unit = dfhack.gui.getSelectedUnit(true) if unit then if unit.sex==0 and dfhack.units.isAdult(unit) then self.mother = unit @@ -157,7 +157,7 @@ function PregnancyGui:selectmother() end function PregnancyGui:selectfather() - local unit = dfhack.gui.getSelectedUnit() + local unit = dfhack.gui.getSelectedUnit(true) if unit and dfhack.units.isAdult(unit) then self.father = unit self.father_historical = false @@ -175,7 +175,7 @@ function PregnancyGui:spouseFather() self.father_historical = father self.father = false end - self:updateLayout() + self:updateLayout() end end @@ -196,7 +196,7 @@ function PregnancyGui:getMotherLabel() NEWLINE ) end - else return ('No mother selected - Must be a adult female') + else return ('No mother selected - Must be an adult female') end end From fb43a1e2629f746677bc9fa326004ed53497694c Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Sat, 28 Oct 2023 19:44:37 +0100 Subject: [PATCH 5/9] More myk002 suggestions/corrections --- gui/pregnancy.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index b3fc94eebb..7c6739861f 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -10,7 +10,10 @@ PregnancyGui.ATTRS { } function PregnancyGui:init() - self.mother = false + if dfhack.gui.getSelectedUnit(true).sex == df.pronoun_type.she then + self.mother = dfhack.gui.getSelectedUnit(true) + else self.mother = false + end self.father = false self.father_historical = false self.msg = {} @@ -37,7 +40,7 @@ function PregnancyGui:init() }, widgets.HotkeyLabel{ frame={l=0}, - label="Select Mother", + label="Set mother to selected unit", key='CUSTOM_SHIFT_M', on_activate=self:callback('selectmother'), }, @@ -53,13 +56,13 @@ function PregnancyGui:init() }, widgets.HotkeyLabel{ frame={l=0}, - label="Select Father", + label="Set father to selected unit", key='CUSTOM_SHIFT_F', on_activate=self:callback('selectfather'), }, widgets.HotkeyLabel{ frame={l=5}, - label="Set Mother's spouse as the Father", + label="Set mother's spouse as the father", key='CUSTOM_F', on_activate=self:callback('spouseFather'), disabled=function() return not self.mother or self.mother.relationship_ids.Spouse == -1 end @@ -80,7 +83,7 @@ function PregnancyGui:init() widgets.ToggleHotkeyLabel{ frame={l=1, t=1}, view_id='Force', - label='Force', + label='Replace existing pregnancy', options={{label='On', value=true, pen=COLOR_GREEN}, {label='Off', value=false, pen=COLOR_RED}}, initial_option=false @@ -149,7 +152,7 @@ end function PregnancyGui:selectmother() local unit = dfhack.gui.getSelectedUnit(true) if unit then - if unit.sex==0 and dfhack.units.isAdult(unit) then + if unit.sex==df.pronoun_type.she and dfhack.units.isAdult(unit) then self.mother = unit self:updateLayout() end @@ -175,7 +178,7 @@ function PregnancyGui:spouseFather() self.father_historical = father self.father = false end - self:updateLayout() + self:updateLayout() end end @@ -343,14 +346,12 @@ function PregnancyGui:CreatePregnancy() )) end end - -- self.success = false + if bypass or force then - --TODO add GUI to select the number of months for pregnancy timer self.mother.pregnancy_timer=math.random(self.subviews.min_term:getOptionLabel()*33600+1, self.subviews.max_term:getOptionLabel()*33600+1) self.mother.pregnancy_caste=father_caste self.mother.pregnancy_spouse=father_id self.mother.pregnancy_genes=genes - -- self.success = true if not force then table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s'):format( NEWLINE, From 04d2b664e07518ad36e5ac1acb0331e72c2dce0a Mon Sep 17 00:00:00 2001 From: Petter Jennison Date: Thu, 2 Nov 2023 09:17:52 +0000 Subject: [PATCH 6/9] myk002 newline+msg changes pregnancy.lua added Newline and self.msg changes to pregnancy.lua --- gui/pregnancy.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index 7c6739861f..e759dfa118 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -126,7 +126,7 @@ function PregnancyGui:init() }, widgets.WrappedLabel{ frame={t=8},--, h=5}, - text_to_wrap=self.msg + text_to_wrap=function() return self.msg end }, }, }, @@ -291,8 +291,7 @@ function PregnancyGui:CreatePregnancy() local bypass = true local force = self.subviews.Force:getOptionValue() - local count = #self.msg - for i=0, count do self.msg[i]=nil end --empty self.msg + self.msg = {} if self.subviews.min_term:getOptionLabel() > self.subviews.max_term:getOptionLabel() then table.insert(self.msg,('Min term has to be less then max term')) @@ -377,4 +376,4 @@ function PregnancyScreen:onDismiss() view = nil end -view = view and view:raise() or PregnancyScreen{}:show() \ No newline at end of file +view = view and view:raise() or PregnancyScreen{}:show() From a53e7c77381f6bb8ab138adf8c4b777df106cf4d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 12 Aug 2024 23:47:54 -0700 Subject: [PATCH 7/9] spruce up gui/pregnancy --- gui/pregnancy.lua | 620 +++++++++++++++++++++++----------------------- 1 file changed, 313 insertions(+), 307 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index e759dfa118..026a8c4493 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -1,375 +1,381 @@ local gui = require('gui') local widgets = require('gui.widgets') -PregnancyGui = defclass(PregnancyGui, widgets.Window) -PregnancyGui.ATTRS { +local function zoom_to(unit) + if not unit then return end + dfhack.gui.revealInDwarfmodeMap(xyz2pos(dfhack.units.getPosition(unit)), true, true) +end + +local function is_viable_partner(unit, required_pronoun) + return unit and unit.sex == required_pronoun and dfhack.units.isAdult(unit) +end + +---------------------- +-- Pregnancy +-- + +Pregnancy = defclass(Pregnancy, widgets.Window) +Pregnancy.ATTRS { frame_title='Pregnancy manager', - frame={w=64, h=35}, - resizable=true, -- if resizing makes sense for your dialog - resize_min={w=50, h=20}, -- try to allow users to shrink your windows + frame={w=50, h=28, r=2, t=18}, + resizable=true, } -function PregnancyGui:init() - if dfhack.gui.getSelectedUnit(true).sex == df.pronoun_type.she then - self.mother = dfhack.gui.getSelectedUnit(true) - else self.mother = false - end - self.father = false - self.father_historical = false - self.msg = {} - - local term_options = {} - local term_index = {} - local months - for months=0,10 do - -- table.insert(term_options,{label=('%s months'):format(months),value=months}) --I tried this to add labels, probably doing something wrong, it broke the range widget - table.insert(term_options,months) --this works though - end - for k,v in ipairs(term_options) do - term_index[v] = k - end +function Pregnancy:init() + self.cache = {} + self.mother_id, self.father_id = -1, -1 + self.dirty = 0 self:addviews{ - widgets.ResizingPanel{ - frame={t=0}, - frame_style=gui.FRAME_INTERIOR, - autoarrange_subviews=true, - subviews={ - widgets.WrappedLabel{ - text_to_wrap=self:callback('getMotherLabel') - }, - widgets.HotkeyLabel{ - frame={l=0}, - label="Set mother to selected unit", - key='CUSTOM_SHIFT_M', - on_activate=self:callback('selectmother'), - }, + widgets.Label{ + frame={t=0, l=0}, + text='Mother:', + }, + widgets.Label{ + frame={t=0, l=8}, + text='None (please select an adult female)', + text_pen=COLOR_YELLOW, + visible=function() return not self:get_mother() end, + }, + widgets.Label{ + frame={t=0, l=8}, + text={{text=self:callback('get_name', 'mother')}}, + text_pen=COLOR_LIGHTMAGENTA, + auto_width=true, + on_click=function() zoom_to(self:get_mother()) end, + visible=self:callback('get_mother'), + }, + widgets.Label{ + frame={t=1, l=0}, + text={{text=self:callback('get_pregnancy_desc')}}, + }, + widgets.Label{ + frame={t=3, l=0}, + text='Spouse:', + }, + widgets.Label{ + frame={t=3, l=8}, + text='None', + visible=function() return not self:get_spouse_unit('mother') and not self:get_spouse_hf('mother') end, + }, + widgets.Label{ + frame={t=3, l=8}, + text={{text=self:callback('get_spouse_name', 'mother')}}, + text_pen=COLOR_BLUE, + auto_width=true, + on_click=function() zoom_to(self:get_spouse_unit('mother')) end, + visible=self:callback('get_spouse_unit', 'mother'), + }, + widgets.Label{ + frame={t=3, l=8}, + text={ + {text=self:callback('get_spouse_hf_name', 'mother')}, + ' (off-site)', }, + text_pen=COLOR_BLUE, + auto_width=true, + visible=function() return not self:get_spouse_unit('mother') and self:get_spouse_hf('mother') end, }, - widgets.ResizingPanel{ - frame={t=5}, - frame_style=gui.FRAME_INTERIOR, - autoarrange_subviews=true, - subviews={ - widgets.WrappedLabel{ - text_to_wrap=self:callback('getFatherLabel') - }, - widgets.HotkeyLabel{ - frame={l=0}, - label="Set father to selected unit", - key='CUSTOM_SHIFT_F', - on_activate=self:callback('selectfather'), - }, - widgets.HotkeyLabel{ - frame={l=5}, - label="Set mother's spouse as the father", - key='CUSTOM_F', - on_activate=self:callback('spouseFather'), - disabled=function() return not self.mother or self.mother.relationship_ids.Spouse == -1 end - }, + widgets.HotkeyLabel{ + frame={t=4, l=2}, + label="Set mother's spouse as the father", + key='CUSTOM_F', + auto_width=true, + on_activate=function() self:set_father(self:get_spouse_unit('mother')) end, + enabled=function() + local spouse = self:get_spouse_unit('mother') + return spouse and spouse.id ~= self.father_id and is_viable_partner(spouse, df.pronoun_type.he) + end, + }, + widgets.HotkeyLabel{ + frame={t=6, l=0}, + label="Set mother to selected unit", + key='CUSTOM_SHIFT_M', + auto_width=true, + on_activate=self:callback('set_mother'), + enabled=function() + local unit = dfhack.gui.getSelectedUnit(true) + return unit and unit.id ~= self.mother_id and is_viable_partner(unit, df.pronoun_type.she) + end, + }, + widgets.Divider{ + frame={t=8, h=1}, + frame_style=gui.FRAME_THIN, + frame_style_l=false, + frame_style_r=false, + }, + widgets.Label{ + frame={t=10, l=0}, + text='Father:', + }, + widgets.Label{ + frame={t=10, l=8}, + text={ + 'None ', + {text='(optionally select an adult male)', pen=COLOR_GRAY}, }, + visible=function() return not self:get_father() end, }, - widgets.Panel{ - frame={t=12,h=14}, - frame_style=gui.FRAME_INTERIOR, - subviews={ - widgets.HotkeyLabel{ - frame={l=0, t=0}, - key='CUSTOM_SHIFT_P', - label="Create pregnancy", - on_activate=self:callback('CreatePregnancy'), - enabled=function() return self.mother or self.father and self.father_historical end - }, - widgets.ToggleHotkeyLabel{ - frame={l=1, t=1}, - view_id='Force', - label='Replace existing pregnancy', - options={{label='On', value=true, pen=COLOR_GREEN}, - {label='Off', value=false, pen=COLOR_RED}}, - initial_option=false - }, - widgets.TooltipLabel{ - frame={l=0, t=3}, - text_to_wrap='Pregnancy term range (months):', - show_tooltip=true, - text_pen=COLOR_WHITE - }, - widgets.CycleHotkeyLabel{ - view_id='min_term', - frame={l=0, t=6, w=SLIDER_LABEL_WIDTH}, - label='Min pregnancy term:', - key_back='CUSTOM_SHIFT_Z', - key='CUSTOM_SHIFT_X', - options=term_options, - initial_option=7 - }, - widgets.CycleHotkeyLabel{ - view_id='max_term', - frame={l=30, t=6, w=SLIDER_LABEL_WIDTH}, - label='Max pregnancy term:', - key_back='CUSTOM_SHIFT_Q', - key='CUSTOM_SHIFT_W', - options=term_options, - initial_option=9 - }, - widgets.RangeSlider{ - frame={l=0, t=4}, - num_stops=#term_options, - get_left_idx_fn=function() - return term_index[self.subviews.min_term:getOptionLabel()] - end, - get_right_idx_fn=function() - return term_index[self.subviews.max_term:getOptionLabel()] - end, - on_left_change=function(idx) self.subviews.min_term:setOption(idx, true) end, - on_right_change=function(idx) self.subviews.max_term:setOption(idx, true) end, - }, - widgets.WrappedLabel{ - frame={t=8},--, h=5}, - text_to_wrap=function() return self.msg end - }, + widgets.Label{ + frame={t=10, l=8}, + text={{text=self:callback('get_name', 'father')}}, + text_pen=function() + local spouse = self:get_spouse_unit('mother') + if spouse and self.father_id == spouse.id then + return COLOR_BLUE + end + return COLOR_CYAN + end, + auto_width=true, + on_click=function() zoom_to(self:get_father()) end, + visible=self:callback('get_father'), + }, + widgets.Label{ + frame={t=12, l=0}, + text='Spouse:', + }, + widgets.Label{ + frame={t=12, l=8}, + text='None', + visible=function() return not self:get_spouse_unit('father') and not self:get_spouse_hf('father') end, + }, + widgets.Label{ + frame={t=12, l=8}, + text={{text=self:callback('get_spouse_name', 'father')}}, + text_pen=function() + local spouse = self:get_spouse_unit('father') + if spouse and self.mother_id == spouse.id then + return COLOR_LIGHTMAGENTA + end + return COLOR_CYAN + end, + auto_width=true, + on_click=function() zoom_to(self:get_spouse_unit('father')) end, + visible=self:callback('get_spouse_unit', 'father'), + }, + widgets.Label{ + frame={t=12, l=8}, + text={ + {text=self:callback('get_spouse_hf_name', 'father')}, + ' (off-site)', + }, + text_pen=COLOR_CYAN, + auto_width=true, + visible=function() return not self:get_spouse_unit('father') and self:get_spouse_hf('father') end, + }, + widgets.HotkeyLabel{ + frame={t=13, l=2}, + label="Set father's spouse as the mother", + key='CUSTOM_M', + auto_width=true, + on_activate=function() self:set_mother(self:get_spouse_unit('father')) end, + enabled=function() + local spouse = self:get_spouse_unit('father') + return spouse and spouse.id ~= self.mother_id and is_viable_partner(spouse, df.pronoun_type.she) + end, + }, + widgets.HotkeyLabel{ + frame={t=15, l=0}, + label="Set father to selected unit", + key='CUSTOM_SHIFT_F', + auto_width=true, + on_activate=self:callback('set_father'), + enabled=function() + local unit = dfhack.gui.getSelectedUnit(true) + return unit and unit.id ~= self.father_id and is_viable_partner(unit, df.pronoun_type.he) + end, + }, + widgets.Divider{ + frame={t=17, h=1}, + frame_style=gui.FRAME_THIN, + frame_style_l=false, + frame_style_r=false, + }, + widgets.CycleHotkeyLabel{ + view_id='term', + frame={t=19, l=0, w=40}, + label='Pregnancy term (in months):', + key_back='CUSTOM_SHIFT_Z', + key='CUSTOM_Z', + options={ + {label='Default', value='default'}, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, }, + initial_option='default', }, - widgets.ResizingPanel{ - frame={t=26}, + widgets.Panel{ + frame={t=21, w=23, h=3}, frame_style=gui.FRAME_INTERIOR, - autoarrange_subviews=true, subviews={ widgets.HotkeyLabel{ - frame={l=1, b=0}, - key='LEAVESCREEN', - label="Return to game", - on_activate=function() - repeat until not self:onInput{LEAVESCREEN=true} - view:dismiss() - end, + key='CUSTOM_SHIFT_P', + label="Generate pregnancy", + on_activate=self:callback('commit'), + enabled=function() return self:get_mother() end, }, - }, + } }, } -end -function PregnancyGui:selectmother() local unit = dfhack.gui.getSelectedUnit(true) - if unit then - if unit.sex==df.pronoun_type.she and dfhack.units.isAdult(unit) then - self.mother = unit - self:updateLayout() - end - end + self:set_mother(unit) + self:set_father(unit) end -function PregnancyGui:selectfather() - local unit = dfhack.gui.getSelectedUnit(true) - if unit and dfhack.units.isAdult(unit) then - self.father = unit - self.father_historical = false +function Pregnancy:get_mother() + self.cache.mother = self.cache.mother or df.unit.find(self.mother_id) + return self.cache.mother +end + +function Pregnancy:get_father() + self.cache.father = self.cache.father or df.unit.find(self.father_id) + return self.cache.father +end + +function Pregnancy:render(dc) + if self.dirty > 0 then + -- needs multiple iterations of updateLayout because of multiple + -- layers of indirection in the text generation self:updateLayout() + self.dirty = self.dirty - 1 end + Pregnancy.super.render(self, dc) + self.cache = {} end -function PregnancyGui:spouseFather() - local father = self:findSpouse(self.mother)[3] - if father then - if df.unit.find(father.unit_id) then - self.father = df.unit.find(father.unit_id) - self.father_historical = false - else - self.father_historical = father - self.father = false - end - self:updateLayout() - end +function Pregnancy:get_name(who) + local unit = self['get_'..who](self) + return unit and dfhack.units.getReadableName(unit) or '' end -function PregnancyGui:getMotherLabel() - if self.mother then - local motherName = dfhack.TranslateName(self.mother.name) - if self.mother.relationship_ids.Spouse > -1 then - local spouseInfo = self:findSpouse(self.mother) - return ('Selected mother: %s.%sShe is married to %s (%s).'):format( - self:findName(self.mother), - NEWLINE, - spouseInfo[1], - spouseInfo[2] - ) - else - return ('Selected mother: %s.%sShe is unmarried.'):format( - self:findName(self.mother), - NEWLINE - ) - end - else return ('No mother selected - Must be an adult female') +local TICKS_PER_DAY = 1200 +local TICKS_PER_MONTH = 28 * TICKS_PER_DAY + +function Pregnancy:get_pregnancy_desc() + local mother = self:get_mother() + if not mother or not mother.pregnancy_genes then return 'Not currently pregnant' end + local term_str = 'today' + if mother.pregnancy_timer > TICKS_PER_MONTH then + local num_months = (mother.pregnancy_timer + TICKS_PER_MONTH//2) // TICKS_PER_MONTH + term_str = ('in %d month%s'):format(num_months, num_months == 1 and '' or 's') + elseif mother.pregnancy_timer > TICKS_PER_DAY then + local num_days = (mother.pregnancy_timer + TICKS_PER_DAY//2) // TICKS_PER_DAY + term_str = ('in %d day%s'):format(num_days, num_days == 1 and '' or 's') end + return ('Currently pregnant: coming to term %s'):format(term_str) end -function PregnancyGui:getFatherLabel() - if self.father or self.father_historical then - if self.father_historical or self.father.relationship_ids.Spouse > -1 then - local father = self.father or self.father_historical - local spouseInfo = self:findSpouse(father) - return ('Selected father: %s.%s%s is married to %s (%s).'):format( - self:findName(father), - NEWLINE, - df.pronoun_type[father.sex]:gsub("^%l", string.upper), - spouseInfo[1], - spouseInfo[2] - ) - else - return ('Selected father: %s.%s%s is unmarried.'):format( - self:findName(self.father), - NEWLINE, - df.pronoun_type[self.father.sex]:gsub("^%l", string.upper) - ) +function Pregnancy:get_spouse_unit(who) + local unit = self['get_'..who](self) + if not unit then return end + return df.unit.find(unit.relationship_ids.Spouse) +end + +function Pregnancy:get_spouse_hf(who) + local unit = self['get_'..who](self) + if not unit or unit.relationship_ids.Spouse == -1 then + return + end + local spouse = df.unit.find(unit.relationship_ids.Spouse) + if spouse then + return df.historical_figure.find(spouse.hist_figure_id) + end + + for _, relation in ipairs(unit.histfig_links) do + if relation._type == df.histfig_hf_link_spousest then + -- may be nil due to hf culling, but then we just treat it as not having a spouse + return df.historical_figure.find(relation.target_hf) end - else return ('No father selected') end end -function PregnancyGui:findName(unit) - local name = dfhack.TranslateName(unit.name) - if name ~= "" then - return name - else return ('Unnamed %s. (Unit id:%s)'):format( - string.upper(df.global.world.raws.creatures.all[unit.race].name[0]), - unit.id - ) - end +function Pregnancy:get_spouse_name(who) + local spouse = self:get_spouse_unit(who) + return spouse and dfhack.units.getReadableName(spouse) or '' end -function PregnancyGui:findSpouse(unit) - local historical_spouse, spouse_loc, spouse, spouseid - local culled = false +function Pregnancy:get_spouse_hf_name(who) + local spouse_hf = self:get_spouse_hf(who) + return spouse_hf and dfhack.units.getReadableName(spouse_hf) or '' +end - --setting variables for if mother or father are local, followed by finding the father's spouse if he is not local - if self.father == unit or self.mother == unit then - spouseid = unit.relationship_ids.Spouse - spouse = df.unit.find(spouseid) - elseif self.father_historical == unit then - for index, relation in pairs(unit.histfig_links) do - if relation._type == df.histfig_hf_link_spousest then - historical_spouse=df.historical_figure.find(relation.target_hf) - if not historical_spouse then culled = true --there was an id, but there wasn't a histfig with that id (due culling) - elseif df.global.plotinfo.site_id==historical_spouse.info.whereabouts.site then - spouse_loc = 'local' - else spouse_loc = 'offsite' - end - end +function Pregnancy:set_mother(unit) + unit = unit or dfhack.gui.getSelectedUnit(true) + if not is_viable_partner(unit, df.pronoun_type.she) then return end + self.mother_id = unit.id + if self.father_id ~= -1 then + local father = self:get_father() + if not father or father.race ~= unit.race then + self.father_id = -1 end - return {dfhack.TranslateName(historical_spouse.name),spouse_loc,historical_spouse} end - - --if the spouse is local this should identify them: - if spouse then - historical_spouse = df.historical_figure.find(spouse.hist_figure_id) or false - spouse_loc = 'local' + if self.father_id == -1 then + self:set_father(self:get_spouse_unit('mother')) end + self.dirty = 2 +end - --if spouse is not local (offsite): - if spouseid > -1 and not spouse then --spouse exists but isnt on the map, so search historical units: - local historical_unit = df.historical_figure.find(unit.hist_figure_id) - for index, relation in pairs(historical_unit.histfig_links) do - if relation._type == df.histfig_hf_link_spousest then - historical_spouse=df.historical_figure.find(relation.target_hf) - if not historical_spouse then culled = true --there was an id, but there wasn't a histfig with that id (due culling) - elseif df.global.plotinfo.site_id==historical_spouse.info.whereabouts.site then--i dont think this should ever be true - spouse_loc = 'local' - else spouse_loc = 'offsite' - end - end +function Pregnancy:set_father(unit) + unit = unit or dfhack.gui.getSelectedUnit(true) + if not is_viable_partner(unit, df.pronoun_type.he) then return end + self.father_id = unit.id + if self.mother_id ~= -1 then + local mother = self:get_mother() + if not mother or mother.race ~= unit.race then + self.mother_id = -1 end end - if culled then - return {'Unknown','culled'} - else - return {dfhack.TranslateName(historical_spouse.name),spouse_loc,historical_spouse} + if self.mother_id == -1 then + self:set_mother(self:get_spouse_unit('father')) end + self.dirty = 2 end -function PregnancyGui:CreatePregnancy() - local genes,father_id,father_caste,father_name - local bypass = true - local force = self.subviews.Force:getOptionValue() +local function get_term_ticks(months) + local ticks = months * TICKS_PER_MONTH + -- subtract off a random amount between 0 and half a month + ticks = math.max(1, ticks - math.random(0, TICKS_PER_MONTH//2)) + return ticks +end - self.msg = {} +function Pregnancy:commit() + local mother = self:get_mother() + local father = self:get_father() or mother - if self.subviews.min_term:getOptionLabel() > self.subviews.max_term:getOptionLabel() then - table.insert(self.msg,('Min term has to be less then max term')) - self:updateLayout() - return + local term_months = self.subviews.term:getOptionValue() + if term_months == 'default' then + local caste_flags = mother.enemy.caste_flags + if caste_flags.CAN_SPEAK or caste_flags.CAN_LEARN then + term_months = 9 + else + term_months = 6 + end end - if self.father then - genes=self.father.appearance.genes:new() - father_id=self.father.hist_figure_id - father_caste=self.father.caste - father_name=self:findName(self.father) + if mother.pregnancy_genes then + mother.pregnancy_genes:assign(father.appearance.genes) else - genes=self.mother.appearance.genes:new()--i dont think historical figures have genes - father_id=self.father_historical.id - father_caste=self.father_historical.caste - father_name=self:findName(self.father_historical) + mother.pregnancy_genes = father.appearance.genes:new() end - if self.mother.pregnancy_timer > 0 then - local og_father = df.historical_figure.find(self.mother.pregnancy_spouse) - bypass = false - if force and og_father then - table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy with %s replaced'):format( - NEWLINE, - self:findName(self.mother), - NEWLINE, - father_name, - NEWLINE, - dfhack.TranslateName(og_father.name) - )) - elseif force then - table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s%sPrevious pregnancy aborted'):format( - NEWLINE, - self:findName(self.mother), - NEWLINE, - father_name, - NEWLINE - )) - elseif og_father then - table.insert(self.msg, ('FAILED:%s%s already pregnant with %s%s'):format( - NEWLINE, - self:findName(self.mother), - dfhack.TranslateName(og_father.name), - force - )) - else - table.insert(self.msg, ('FAILED:%s%s is already pregnant, no father is recorded'):format( - NEWLINE, - self:findName(self.mother) - )) - end - end + mother.pregnancy_timer = get_term_ticks(term_months) + mother.pregnancy_caste = father.caste + mother.pregnancy_spouse = father.hist_figure_id ~= mother.hist_figure_id and father.hist_figure_id or -1 - if bypass or force then - self.mother.pregnancy_timer=math.random(self.subviews.min_term:getOptionLabel()*33600+1, self.subviews.max_term:getOptionLabel()*33600+1) - self.mother.pregnancy_caste=father_caste - self.mother.pregnancy_spouse=father_id - self.mother.pregnancy_genes=genes - if not force then - table.insert(self.msg, ('SUCCESS:%sMother:%s%sFather:%s'):format( - NEWLINE, - self:findName(self.mother), - NEWLINE, - father_name - )) - end - end - self:updateLayout() + self.dirty = 2 end +---------------------- +-- PregnancyScreen +-- + PregnancyScreen = defclass(PregnancyScreen, gui.ZScreen) PregnancyScreen.ATTRS { focus_path='pregnancy', } function PregnancyScreen:init() - self:addviews{PregnancyGui{}} + self:addviews{Pregnancy{}} end function PregnancyScreen:onDismiss() From 97392d8d750b6e3f0fe38be4ef64866b1211d32c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 13 Aug 2024 00:15:08 -0700 Subject: [PATCH 8/9] gui/pregnancy docs --- changelog.txt | 1 + docs/gui/pregnancy.rst | 32 ++++++++++++++++++++++++++++++++ gui/pregnancy.lua | 14 ++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 docs/gui/pregnancy.rst diff --git a/changelog.txt b/changelog.txt index ff92542951..4ebea52671 100644 --- a/changelog.txt +++ b/changelog.txt @@ -28,6 +28,7 @@ Template for new versions: ## New Tools - `embark-anyone`: allows you to embark as any civilisation, including dead, and non-dwarven ones +- `gui/pregnancy`: view and generate pregnancies with specified parents ## New Features - `caravan`: DFHack dialogs for trade screens (both ``Bring goods to depot`` and the ``Trade`` barter screen) can now filter by item origins (foreign vs. fort-made) and can filter bins by whether they have a mix of ethically acceptable and unacceptable items in them diff --git a/docs/gui/pregnancy.rst b/docs/gui/pregnancy.rst new file mode 100644 index 0000000000..9ed48161d4 --- /dev/null +++ b/docs/gui/pregnancy.rst @@ -0,0 +1,32 @@ +gui/pregnancy +============= + +.. dfhack-tool:: + :summary: Generate pregnancies with pairings of your choice. + :tags: adventure fort armok animals units + +This tool provides an interface for producing pregnancies with specific mothers +and fathers. + +If a unit is selected when you run `gui/pregnancy`, they will be pre-selected +as a parent. If the unit has a spouse of a different gender, they will be +automatically selected as the other parent. You can click on other units on the +map and choose them as alternate mothers or fathers as desired. + +If a unit is selected as a mother or father, or is listed as a spouse, you can +zoom the map to their location by clicking on their name in the `gui/pregnancy` +UI. + +A unit must be on the map to participate in a pregnancy. For example, you +cannot designate a father that is not on-site, even if they are the selected +mother's spouse. + +Children cannot be selected as a parent, and, due to game limitations, +cross-species pregnancies are not supported. + +Usage +----- + +:: + + gui/pregnancy diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index 026a8c4493..c43f00b3d4 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -198,8 +198,18 @@ function Pregnancy:init() key_back='CUSTOM_SHIFT_Z', key='CUSTOM_Z', options={ - {label='Default', value='default'}, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + {label='Default', value='default', pen=COLOR_BROWN}, + {label='0', value=0, pen=COLOR_BROWN}, + {label='1', value=1, pen=COLOR_BROWN}, + {label='2', value=2, pen=COLOR_BROWN}, + {label='3', value=3, pen=COLOR_BROWN}, + {label='4', value=4, pen=COLOR_BROWN}, + {label='5', value=5, pen=COLOR_BROWN}, + {label='6', value=6, pen=COLOR_BROWN}, + {label='7', value=7, pen=COLOR_BROWN}, + {label='8', value=8, pen=COLOR_BROWN}, + {label='9', value=9, pen=COLOR_BROWN}, + {label='10', value=10, pen=COLOR_BROWN}, }, initial_option='default', }, From c3f1b416a5cd3cdf2920025a27f59d5860d41c97 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 13 Aug 2024 07:10:43 -0700 Subject: [PATCH 9/9] fix up histfig spouse processing --- gui/pregnancy.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gui/pregnancy.lua b/gui/pregnancy.lua index c43f00b3d4..dac365f502 100644 --- a/gui/pregnancy.lua +++ b/gui/pregnancy.lua @@ -263,7 +263,9 @@ local TICKS_PER_MONTH = 28 * TICKS_PER_DAY function Pregnancy:get_pregnancy_desc() local mother = self:get_mother() - if not mother or not mother.pregnancy_genes then return 'Not currently pregnant' end + if not mother or not mother.pregnancy_genes or mother.pregnancy_timer <= 0 then + return 'Not currently pregnant' + end local term_str = 'today' if mother.pregnancy_timer > TICKS_PER_MONTH then local num_months = (mother.pregnancy_timer + TICKS_PER_MONTH//2) // TICKS_PER_MONTH @@ -291,10 +293,13 @@ function Pregnancy:get_spouse_hf(who) return df.historical_figure.find(spouse.hist_figure_id) end - for _, relation in ipairs(unit.histfig_links) do - if relation._type == df.histfig_hf_link_spousest then + local hf = df.historical_figure.find(unit.hist_figure_id) + if not hf then return end + + for _, link in ipairs(hf.histfig_links) do + if link._type == df.histfig_hf_link_spousest then -- may be nil due to hf culling, but then we just treat it as not having a spouse - return df.historical_figure.find(relation.target_hf) + return df.historical_figure.find(link.target_hf) end end end