Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embark Anyone #1260

Merged
merged 12 commits into from
Aug 9, 2024
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
24 changes: 24 additions & 0 deletions docs/embark-anyone.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
embark-anyone
=============

.. dfhack-tool::
:summary: Allows you to embark as any civilisation, including dead and non-dwarven ones.
:tags: embark armok

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.


myk002 marked this conversation as resolved.
Show resolved Hide resolved
Usage
-----

::

embark-anyone

Note
-----
Non-dwarven civs have their own mechanics which can render fortress mode difficult
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`).
116 changes: 116 additions & 0 deletions embark-anyone.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
local dialogs = require('gui.dialogs')
local utils = require('utils')

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)
local choices, 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
-- 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.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 (?).
-- 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_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_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
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,
info = {civ = civ, pops = pops, sites = sites,
nemeses = nemeses}})

::continue::
end

if #choices > 0 then
dialogs.ListBox{
frame_title = 'Embark Anyone',
text = 'Select a civilization 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()
else
dialogs.MessageBox{
frame_title = 'Embark Anyone',
text = 'No additional civilizations found.'
}:show()
end

end

embarkAnyone()