From 9fc6461175d4b8f4953c13483882eb8d26c344b2 Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Tue, 6 Aug 2024 17:48:29 +0100 Subject: [PATCH 01/11] Embark Anyone --- embark-anyone.lua | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 embark-anyone.lua diff --git a/embark-anyone.lua b/embark-anyone.lua new file mode 100644 index 000000000..a5c3b007d --- /dev/null +++ b/embark-anyone.lua @@ -0,0 +1,108 @@ +local dialogs = require 'gui.dialogs' +local choices = {} + +function addCivToEmbarkList(info) + local viewscreen = dfhack.gui.getDFViewscreen(true) + + viewscreen.start_civ:insert ('#', info.civ) + viewscreen.start_civ_nem_num:insert ('#', info.nemeses) + viewscreen.start_civ_entpop_num:insert ('#', info.pops) + viewscreen.start_civ_site_num:insert ('#', info.sites) +end + +function embarkAnyone() + local viewscreen = dfhack.gui.getDFViewscreen(true) + + + if viewscreen._type ~= df.viewscreen_choose_start_sitest then + qerror("This script can only be used on the embark screen!") + end + + for i, civ in ipairs (df.global.world.entities.all) do + if civ.type == df.historical_entity_type.Civilization then + local available = false + + -- Check if civ is already available to embark + for _, item in ipairs (viewscreen.start_civ) do + if item == civ then + available = true + break + end + end + + if not available then + local sites = 0 + local pops = 0 + local nemeses = 0 + local histfigs = 0 + local label = '' + + -- Civs keep links to sites they no longer hold, so check owner + -- We also take the opportunity to count population + for j, link in ipairs(civ.site_links) do + local site = df.global.world.world_data.sites[link.target] + if site.civ_id == civ.id then + sites = sites + 1 + + -- DF stores population info as an array of groups of residents (?). + -- Inspecting these further could give a more accurate count. + for _, group in ipairs(site.populace.inhabitants) do + pops = pops + group.count + end + end + + -- Count living nemeses + for _, nem in ipairs (civ.nemesis_ids) do + if df.global.world.nemesis.all[nem].figure.died_year == -1 then + nemeses = nemeses + 1 + end + end + + -- Count living histfigs + -- Used for death detection. May be redundant. + for _, fig in ipairs (civ.histfig_ids) do + if df.global.world.history.figures[fig].died_year == -1 then + histfigs = histfigs + 1 + end + end + end + + -- Find the civ's name, or come up with one + if civ.name.has_name then + label = dfhack.TranslateName(civ.name, true) .. "\n" + else + label = "Unnamed " .. + dfhack.units.getRaceReadableNameById(civ.race) .. + " civilisation\n" + end + + -- Add species + label = label .. dfhack.units.getRaceNamePluralById(civ.race) .. "\n" + + -- Add pop & site count or mark civ as dead. + if histfigs == 0 and pops == 0 then + label = label .. "Dead" + else + label = label .. "Pop: " .. (pops + nemeses) .. " Sites: " .. sites + end + + table.insert(choices, {text = label, search_key = label:lower(), + info = {civ = civ, pops = pops, sites = sites, + nemeses = nemeses}}) + end + end + end + dialogs.ListBox{ + frame_title = 'Embark Anyone', + text = 'Select a civilisation to add to the list of origin civs:', + text_pen = COLOR_WHITE, + choices = choices, + on_select = function(id, choice) + addCivToEmbarkList(choice.info) + end, + with_filter = true, + row_height = 4, + }:show() +end + +embarkAnyone() From b653beb88aa9a8068737a9a784d739876f2abdd2 Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Tue, 6 Aug 2024 18:07:40 +0100 Subject: [PATCH 02/11] Add documentation for embark anyone --- docs/embark-anyone.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/embark-anyone.rst diff --git a/docs/embark-anyone.rst b/docs/embark-anyone.rst new file mode 100644 index 000000000..2a670fc5b --- /dev/null +++ b/docs/embark-anyone.rst @@ -0,0 +1,19 @@ +embark-anyone +======== + +.. dfhack-tool:: + :summary: Allows you to embark as any civilisation, including dead and non-dwarven ones. + :tags: embark gameplay armok + +Usage +----- + +:: + + embark-anyone + +Note +----- +Non-dwarven civs have their own mechanics which can render fortress mode difficult +to unplayable. Preparing carefully is advised, and cheating in some items may be +required. From fc393662b9de880f9e0e630b03fef669450159e2 Mon Sep 17 00:00:00 2001 From: Claire H <77733928+ProtonNumber@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:17:37 +0100 Subject: [PATCH 03/11] Fix formatting Co-authored-by: Alan --- docs/embark-anyone.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/embark-anyone.rst b/docs/embark-anyone.rst index 2a670fc5b..d86f7cb44 100644 --- a/docs/embark-anyone.rst +++ b/docs/embark-anyone.rst @@ -1,5 +1,5 @@ embark-anyone -======== +============= .. dfhack-tool:: :summary: Allows you to embark as any civilisation, including dead and non-dwarven ones. From 4e23f9174e350f8101562b1ce228728d7f30ef4b Mon Sep 17 00:00:00 2001 From: Claire H <77733928+ProtonNumber@users.noreply.github.com> Date: Wed, 7 Aug 2024 08:33:57 +0100 Subject: [PATCH 04/11] Change wording as discussed --- docs/embark-anyone.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/embark-anyone.rst b/docs/embark-anyone.rst index d86f7cb44..0935d75eb 100644 --- a/docs/embark-anyone.rst +++ b/docs/embark-anyone.rst @@ -15,5 +15,4 @@ Usage Note ----- Non-dwarven civs have their own mechanics which can render fortress mode difficult -to unplayable. Preparing carefully is advised, and cheating in some items may be -required. +to unplayable. Preparing carefully is advised, and some crucial items may need to be spawned in. From ff4cba9551f17a78ebab271e1008c4ee62e85db9 Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Fri, 9 Aug 2024 01:39:33 +0100 Subject: [PATCH 05/11] Add introductory paragraph --- docs/embark-anyone.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/embark-anyone.rst b/docs/embark-anyone.rst index 2a670fc5b..ea0e14de3 100644 --- a/docs/embark-anyone.rst +++ b/docs/embark-anyone.rst @@ -3,7 +3,12 @@ embark-anyone .. dfhack-tool:: :summary: Allows you to embark as any civilisation, including dead and non-dwarven ones. - :tags: embark gameplay armok + :tags: embark armok + +This script can be ran on the embark screen and presents a list of civilisations that +are not normally playable to add to the "Select Origin Civ" menu. This includes dead +civilisations, the normal non-dwarven civilisations, and subterranean animal people. + Usage ----- From 869386dd36a476267904ac2c5002fc43acaba202 Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Fri, 9 Aug 2024 01:50:09 +0100 Subject: [PATCH 06/11] Restructure loop around continue statement --- embark-anyone.lua | 121 ++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/embark-anyone.lua b/embark-anyone.lua index a5c3b007d..217403d47 100644 --- a/embark-anyone.lua +++ b/embark-anyone.lua @@ -12,85 +12,82 @@ end function embarkAnyone() local viewscreen = dfhack.gui.getDFViewscreen(true) + local existing_civs = {} + for _,existing_civ in ipairs(viewscreen.start_civ) do + existing_civs[existing_civ.id] = true + end if viewscreen._type ~= df.viewscreen_choose_start_sitest then qerror("This script can only be used on the embark screen!") end for i, civ in ipairs (df.global.world.entities.all) do - if civ.type == df.historical_entity_type.Civilization then - local available = false - - -- Check if civ is already available to embark - for _, item in ipairs (viewscreen.start_civ) do - if item == civ then - available = true - break + -- Test if entity is a civ + if civ.type ~= df.historical_entity_type.Civilization then goto continue end + -- Test if entity is already in embark list + if existing_civs[civ.id] then goto continue end + + local sites = 0 + local pops = 0 + local nemeses = 0 + local histfigs = 0 + local label = '' + + -- Civs keep links to sites they no longer hold, so check owner + -- We also take the opportunity to count population + for j, link in ipairs(civ.site_links) do + local site = df.global.world.world_data.sites[link.target] + if site.civ_id == civ.id then + sites = sites + 1 + + -- DF stores population info as an array of groups of residents (?). + -- Inspecting these further could give a more accurate count. + for _, group in ipairs(site.populace.inhabitants) do + pops = pops + group.count end end - if not available then - local sites = 0 - local pops = 0 - local nemeses = 0 - local histfigs = 0 - local label = '' - - -- Civs keep links to sites they no longer hold, so check owner - -- We also take the opportunity to count population - for j, link in ipairs(civ.site_links) do - local site = df.global.world.world_data.sites[link.target] - if site.civ_id == civ.id then - sites = sites + 1 - - -- DF stores population info as an array of groups of residents (?). - -- Inspecting these further could give a more accurate count. - for _, group in ipairs(site.populace.inhabitants) do - pops = pops + group.count - end - end - - -- Count living nemeses - for _, nem in ipairs (civ.nemesis_ids) do - if df.global.world.nemesis.all[nem].figure.died_year == -1 then - nemeses = nemeses + 1 - end - end - - -- Count living histfigs - -- Used for death detection. May be redundant. - for _, fig in ipairs (civ.histfig_ids) do - if df.global.world.history.figures[fig].died_year == -1 then - histfigs = histfigs + 1 - end - end + -- Count living nemeses + for _, nem in ipairs (civ.nemesis_ids) do + if df.global.world.nemesis.all[nem].figure.died_year == -1 then + nemeses = nemeses + 1 end + end - -- Find the civ's name, or come up with one - if civ.name.has_name then - label = dfhack.TranslateName(civ.name, true) .. "\n" - else - label = "Unnamed " .. - dfhack.units.getRaceReadableNameById(civ.race) .. - " civilisation\n" + -- Count living histfigs + -- Used for death detection. May be redundant. + for _, fig in ipairs (civ.histfig_ids) do + if df.global.world.history.figures[fig].died_year == -1 then + histfigs = histfigs + 1 end + end + end - -- Add species - label = label .. dfhack.units.getRaceNamePluralById(civ.race) .. "\n" + -- Find the civ's name, or come up with one + if civ.name.has_name then + label = dfhack.TranslateName(civ.name, true) .. "\n" + else + label = "Unnamed " .. + dfhack.units.getRaceReadableNameById(civ.race) .. + " civilisation\n" + end - -- Add pop & site count or mark civ as dead. - if histfigs == 0 and pops == 0 then - label = label .. "Dead" - else - label = label .. "Pop: " .. (pops + nemeses) .. " Sites: " .. sites - end + -- Add species + label = label .. dfhack.units.getRaceNamePluralById(civ.race) .. "\n" - table.insert(choices, {text = label, search_key = label:lower(), - info = {civ = civ, pops = pops, sites = sites, - nemeses = nemeses}}) - end + -- Add pop & site count or mark civ as dead. + if histfigs == 0 and pops == 0 then + label = label .. "Dead" + else + label = label .. "Pop: " .. (pops + nemeses) .. " Sites: " .. sites end + + table.insert(choices, {text = label, search_key = label:lower(), + info = {civ = civ, pops = pops, sites = sites, + nemeses = nemeses}}) + + ::continue:: end dialogs.ListBox{ frame_title = 'Embark Anyone', From 2d31c579e972b548c2d792c77b23c7b39640241c Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Fri, 9 Aug 2024 02:25:42 +0100 Subject: [PATCH 07/11] Fix bugs relating to ids not equaling offsets --- embark-anyone.lua | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/embark-anyone.lua b/embark-anyone.lua index 217403d47..060130863 100644 --- a/embark-anyone.lua +++ b/embark-anyone.lua @@ -1,4 +1,5 @@ local dialogs = require 'gui.dialogs' +local utils = require 'utils' local choices = {} function addCivToEmbarkList(info) @@ -37,8 +38,8 @@ function embarkAnyone() -- Civs keep links to sites they no longer hold, so check owner -- We also take the opportunity to count population for j, link in ipairs(civ.site_links) do - local site = df.global.world.world_data.sites[link.target] - if site.civ_id == civ.id then + local site = df.world_site.find(link.target) + if site ~= nil and site.civ_id == civ.id then sites = sites + 1 -- DF stores population info as an array of groups of residents (?). @@ -49,16 +50,18 @@ function embarkAnyone() end -- Count living nemeses - for _, nem in ipairs (civ.nemesis_ids) do - if df.global.world.nemesis.all[nem].figure.died_year == -1 then + for _, nem_id in ipairs (civ.nemesis_ids) do + local nem = df.nemesis_record.find(nem_id) + if nem ~= nil and nem.figure.died_year == -1 then nemeses = nemeses + 1 end end -- Count living histfigs -- Used for death detection. May be redundant. - for _, fig in ipairs (civ.histfig_ids) do - if df.global.world.history.figures[fig].died_year == -1 then + for _, fig_id in ipairs (civ.histfig_ids) do + local fig = df.historical_figure.find(fig_id) + if fig ~= nil and fig.died_year == -1 then histfigs = histfigs + 1 end end @@ -89,17 +92,20 @@ function embarkAnyone() ::continue:: end - dialogs.ListBox{ - frame_title = 'Embark Anyone', - text = 'Select a civilisation to add to the list of origin civs:', - text_pen = COLOR_WHITE, - choices = choices, - on_select = function(id, choice) - addCivToEmbarkList(choice.info) - end, - with_filter = true, - row_height = 4, - }:show() + if #choices then + dialogs.ListBox{ + frame_title = 'Embark Anyone', + text = 'Select a civilisation to add to the list of origin civs:', + text_pen = COLOR_WHITE, + choices = choices, + on_select = function(id, choice) + addCivToEmbarkList(choice.info) + end, + with_filter = true, + row_height = 4, + }:show() + end + end embarkAnyone() From 90e84ed05db5c8975d498c3c4cb5746297428109 Mon Sep 17 00:00:00 2001 From: ProtonNumber Date: Fri, 9 Aug 2024 02:28:07 +0100 Subject: [PATCH 08/11] Handle case where no civs are available --- embark-anyone.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embark-anyone.lua b/embark-anyone.lua index 060130863..47d689fdc 100644 --- a/embark-anyone.lua +++ b/embark-anyone.lua @@ -92,6 +92,7 @@ function embarkAnyone() ::continue:: end + if #choices then dialogs.ListBox{ frame_title = 'Embark Anyone', @@ -104,6 +105,11 @@ function embarkAnyone() with_filter = true, row_height = 4, }:show() + else + dialogs.MessageBox{ + frame_title = 'Embark Anyone', + text = 'No additional civilisations found.' + }:show() end end From 2693bf8e956f5edf26c582df972db82b2bdd9357 Mon Sep 17 00:00:00 2001 From: Claire H <77733928+ProtonNumber@users.noreply.github.com> Date: Fri, 9 Aug 2024 08:09:21 +0100 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Myk --- docs/embark-anyone.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/embark-anyone.rst b/docs/embark-anyone.rst index 6786aba9a..753317e88 100644 --- a/docs/embark-anyone.rst +++ b/docs/embark-anyone.rst @@ -5,9 +5,9 @@ embark-anyone :summary: Allows you to embark as any civilisation, including dead and non-dwarven ones. :tags: embark armok -This script can be ran on the embark screen and presents a list of civilisations that -are not normally playable to add to the "Select Origin Civ" menu. This includes dead -civilisations, the normal non-dwarven civilisations, and subterranean animal people. +This script must be run on the embark screen when choosing an origin civilization. +When run, you can add any civilization, including dead or non-dwarven civilizations, +to the list of choices. Usage @@ -20,4 +20,5 @@ Usage Note ----- Non-dwarven civs have their own mechanics which can render fortress mode difficult -to unplayable. Preparing carefully is advised, and some crucial items may need to be spawned in. +or unplayable. Preparing carefully is advised, and some crucial items may need to be +spawned in with other DFHack tools (e.g. `gui/create-item`). From f3bb9baaf15a4518cd3b98f86d88e67b25582ce5 Mon Sep 17 00:00:00 2001 From: Claire H <77733928+ProtonNumber@users.noreply.github.com> Date: Fri, 9 Aug 2024 08:11:49 +0100 Subject: [PATCH 10/11] reformat code to match preferred formatting Co-authored-by: Myk --- embark-anyone.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/embark-anyone.lua b/embark-anyone.lua index 47d689fdc..0f6fc61ad 100644 --- a/embark-anyone.lua +++ b/embark-anyone.lua @@ -1,6 +1,5 @@ -local dialogs = require 'gui.dialogs' -local utils = require 'utils' -local choices = {} +local dialogs = require('gui.dialogs') +local utils = require('utils') function addCivToEmbarkList(info) local viewscreen = dfhack.gui.getDFViewscreen(true) @@ -13,7 +12,7 @@ end function embarkAnyone() local viewscreen = dfhack.gui.getDFViewscreen(true) - local existing_civs = {} + local choices, existing_civs = {}, {} for _,existing_civ in ipairs(viewscreen.start_civ) do existing_civs[existing_civ.id] = true @@ -86,17 +85,17 @@ function embarkAnyone() label = label .. "Pop: " .. (pops + nemeses) .. " Sites: " .. sites end - table.insert(choices, {text = label, search_key = label:lower(), + table.insert(choices, {text = label, info = {civ = civ, pops = pops, sites = sites, nemeses = nemeses}}) ::continue:: end - if #choices then + if #choices > 0 then dialogs.ListBox{ frame_title = 'Embark Anyone', - text = 'Select a civilisation to add to the list of origin civs:', + text = 'Select a civilization to add to the list of origin civs:', text_pen = COLOR_WHITE, choices = choices, on_select = function(id, choice) @@ -108,7 +107,7 @@ function embarkAnyone() else dialogs.MessageBox{ frame_title = 'Embark Anyone', - text = 'No additional civilisations found.' + text = 'No additional civilizations found.' }:show() end From c5f587d4a5ca45732dcc65b47a3fdf0674807800 Mon Sep 17 00:00:00 2001 From: Claire H <77733928+ProtonNumber@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:52:22 +0100 Subject: [PATCH 11/11] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 9eb3c0b63..acab7796e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -27,6 +27,7 @@ Template for new versions: # Future ## New Tools +- `embark-anyone`: allows you to embark as any civilisation, including dead, and non-dwarven ones ## New Features