Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Template for new versions:
# Future

## New Tools
- `modtools/moddable-gods`: (reinstated) create new deities from scratch

## New Features
- `gui/mod-manager`: when run in a loaded world, shows a list of active mods -- click to export the list to the clipboard for easy sharing or posting
Expand Down
62 changes: 44 additions & 18 deletions docs/modtools/moddable-gods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,47 @@ modtools/moddable-gods

.. dfhack-tool::
:summary: Create deities.
:tags: unavailable

This is a standardized version of Putnam's moddableGods script. It allows you
to create gods on the command-line.

Arguments::

-name godName
sets the name of the god to godName
if there's already a god of that name, the script halts
-spheres [ sphereList ]
define a space-separated list of spheres of influence of the god
-gender male|female|neuter
sets the gender of the god
-depictedAs str
often depicted as a str
-verbose
if specified, prints details about the created god
:tags: dev

This script allows you to create new gods in an existing world.

Usage
-----

::

moddable-gods --name <name> --spheres <sphereList> [<options>]

Examples
--------

``modtools/moddable-gods --name "Slarty Bog" --spheres FATE,WEATHER``
Create a new god named "Slarty Bog" with spheres of influence of FATE and
WEATHER. The god will have a random gender and will be depicted as a dwarf.

``modtools/moddable-gods -n Og -s SPEECH,SALT,SACRIFICE -g neuter -d emu``
Create a new god named "Og" with spheres of influence of SPEECH, SALT, and
SACRIFICE. The god will be genderless and will be depicted as an emu.

Options
-------

``-n``, ``--name <name>``
The name of the god to create. This is a required argument. The name must
be unique in the world. If the name is already taken, the script will exit
without action.
``-s``, ``--spheres <sphereList>``
A comma-separated list of spheres of influence for the god. This is a
required argument. To see the available spheres, run this command::

lua @df.sphere_type

``-g``, ``--gender (male|female|neuter)``
The gender of the god. If not specified, a random gender will be chosen.
``-d``, ``--depicted-as <str or race ID>``
When the deity is referenced in-game, it will be described as "often
depicted as a <str>". The string must match the token ID or descriptive
name of a race that exists in the world. You can also specify a numeric
race ID. If not specified, it defaults to "dwarf".
``-q``, ``--quiet``
If specified, suppresses all non-error output.
192 changes: 118 additions & 74 deletions modtools/moddable-gods.lua
Original file line number Diff line number Diff line change
@@ -1,92 +1,136 @@
local utils = require('utils')

local validArgs = utils.invert{
'help',
'name',
'spheres',
'gender',
'depictedAs',
'verbose',
-- 'entities',
}
local args = utils.processArgs({...}, validArgs)
local argparse = require('argparse')

local function get_spheres(arg)
local spheres = {}
for _, sphere in ipairs(argparse.stringList(arg, 'spheres')) do
local sphereType = df.sphere_type[sphere]
if not sphereType then
qerror('invalid sphere: ' .. sphere)
end
table.insert(spheres, sphereType)
end
return spheres
end

if args.help then
print(dfhack.script_help())
return
local function get_gender(arg)
if arg == 'male' then
return df.pronoun_type.he
elseif arg == 'female' then
return df.pronoun_type.she
elseif arg == 'neuter' then
return df.pronoun_type.it
else
qerror('invalid gender: ' .. arg)
end
end

if not args.name or not args.depictedAs or not args.spheres or not args.gender then
error('All arguments must be specified.')
local function get_race(arg)
local int_arg = tonumber(arg)
if int_arg then
local raw = df.creature_raw.find(int_arg)
if not raw then
qerror('race id ' .. int_arg .. ' does not exist')
end
return int_arg
end
for k, raw in ipairs(df.global.world.raws.creatures.all) do
if raw.creature_id == arg or raw.name[0] == arg then
return k
end
end
qerror('race ' .. arg .. ' does not exist')
end

local function do_god(opts)
local godFig = df.historical_figure:new()
godFig.race = opts.race
godFig.caste = 0
godFig.sex = opts.gender

godFig.appeared_year = -1
godFig.born_year = -1
godFig.born_seconds = -1
godFig.curse_year = -1
godFig.curse_seconds = -1
godFig.old_year = -1
godFig.old_seconds = -1
godFig.died_year = -1
godFig.died_seconds = -1

godFig.name.has_name = true
godFig.name.first_name = opts.name

godFig.breed_id = -1
godFig.flags.deity = true
godFig.flags.brag_on_kill = true
godFig.flags.kill_quest = true
godFig.flags.chatworthy = true
godFig.flags.flashes = true
godFig.flags.never_cull = true

godFig.info = df.historical_figure_info:new()
godFig.info.metaphysical = {new=true}
godFig.info.known_info = {new=true}
for _,sphere in ipairs(opts.spheres) do
godFig.info.metaphysical.spheres:insert('#', sphere)
end

godFig.pool_id = -1 -- will get a pool_id when game is saved and reloaded
godFig.id = df.global.hist_figure_next_id
df.global.hist_figure_next_id = 1 + df.global.hist_figure_next_id
df.global.world.history.figures:insert('#', godFig)

return godFig
end

local templateGod
for _,fig in ipairs(df.global.world.history.figures) do
if fig.flags.deity then
templateGod = fig
break
end
if not dfhack.isWorldLoaded() then
qerror('This script requires a loaded world.')
end
if not templateGod then
error 'Could not find template god.'

local opts = {
name=nil,
spheres=nil,
gender=nil,
race=nil,
quiet=false,
help=false,
}

local _ = argparse.processArgsGetopt({ ... }, {
{'n', 'name', hasArg=true, handler=function(arg) opts.name = arg end},
{'s', 'spheres', hasArg=true, handler=function(arg) opts.spheres = get_spheres(arg) end},
{'g', 'gender', hasArg=true, handler=function(arg) opts.gender = get_gender(arg) end},
{'d', 'depicted-as', hasArg=true, handler=function(arg) opts.race = get_race(arg) end},
{'h', 'help', handler=function() opts.help = true end},
{'q', 'quiet', handler=function() opts.quiet = true end},
})

if opts.help then
print(dfhack.script_help())
return
end

local gender
if args.gender == 'male' then
gender = 1
elseif args.gender == 'female' then
gender = 0
elseif args.gender == "neuter" then
gender = -1
else
error 'invalid gender'
if not opts.name or not opts.spheres or #opts.name == 0 or #opts.spheres == 0 then
qerror('name and spheres must be specified.')
end

local race
for k,v in ipairs(df.global.world.raws.creatures.all) do
if v.creature_id == args.depictedAs or v.name[0] == args.depictedAs then
race = k
break
for _, fig in ipairs(df.global.world.history.figures) do
if fig.name.first_name == opts.name then
print('god "' .. opts.name .. '" already exists.')
return
end
end
if not race then
error('invalid race: ' .. args.depictedAs)
end

for _,fig in ipairs(df.global.world.history.figures) do
if fig.name.first_name == args.name then
print('god ' .. args.name .. ' already exists. Skipping')
return
end
if not opts.gender then
opts.gender = math.random(-1, 1)
end

local godFig = df.historical_figure:new()
godFig.appeared_year = -1
godFig.born_year = -1
godFig.born_seconds = -1
godFig.curse_year = -1
godFig.curse_seconds = -1
godFig.old_year = -1
godFig.old_seconds = -1
godFig.died_year = -1
godFig.died_seconds = -1
godFig.name.has_name = true
godFig.breed_id = -1
godFig.flags:assign(templateGod.flags)
godFig.id = df.global.hist_figure_next_id
df.global.hist_figure_next_id = 1+df.global.hist_figure_next_id
godFig.info = df.historical_figure_info:new()
godFig.info.spheres = {new=true}
godFig.info.known_info = df.knowledge_profilest:new()
godFig.race = race
godFig.caste = 0
godFig.sex = gender
godFig.name.first_name = args.name
for _,sphere in ipairs(args.spheres) do
godFig.info.metaphysical.spheres:insert('#',df.sphere_type[sphere])
if not opts.race then
opts.race = get_race('dwarf')
end
df.global.world.history.figures:insert('#',godFig)

if args.verbose then
print(godFig.name.first_name .. " created as historical figure " .. tostring(godFig.id))
local godFig = do_god(opts)

if not opts.quiet then
print(godFig.name.first_name .. " created as historical figure " .. tostring(godFig.id))
end