For the past few days I've been pondering at a few little nagging problems. Problems like "How come Boogiemen are so tough for their tiny size?" and "Can my adventurer be a demon
and breathe fire?"
So, after a few days of feeling irritated that I couldn't find the information I wanted in the game's available raw files, I started digging around in memory, and found that the entire creature raw files are cached in memory. A little bit of curiosity lead to these two new yet simple script files.
dumpraw: This script will save a creature's raw data to a .txt file, allowing you to see how that creature works. Unlike the game's actual raw files, this works on procedurally generated creatures like forgotten beasts and night creatures.
function openFile(name)
if (not dfhack.filesystem.isdir("rawdump/")) then
dfhack.filesystem.mkdir("rawdump/")
end
return io.open("rawdump/"..name..".txt", 'w')
end
local args = {...}
local id = tonumber(args[1])
if (id) then
local creature = df.global.world.raws.creatures.all[id]
local file = openFile(creature.name[0])
for raw_k, raw_v in ipairs(creature.raws) do
file:write(raw_v.value.."\n")
end
file:close()
print("Creature \""..creature.name[0].."\" ("..tostring(cr_k)..") dumped.")
else
local filter = ""
for k,v in ipairs(args) do
if (filter == "") then
filter = v
else
filter = filter.." "..v
end
end
if (filter == "") then
qerror("No filter given.")
end
for cr_k,creature in ipairs(df.global.world.raws.creatures.all) do
local name = creature.name[0]
if (string.find(name,filter) or string.lower(filter)=="all") then
local file = openFile(name)
for raw_k, raw_v in ipairs(creature.raws) do
file:write(raw_v.value.."\n")
end
file:close()
print("Creature \""..creature.name[0].."\" ("..tostring(cr_k)..") dumped.")
break
end
end
end
loadraw: This script will take a saved raw txt file, and load it back into the game, allowing you to modify procedurally generated creatures. (Potentially regular creatures too, but I have not tested it to see if it takes priority over the main raw txt files.)
function trim(s)
return s:match "^%s*(.-)%s*$"
end
function updateraw(creature, file)
local oldraws = creature.raws
local newraws = oldraws:new()
newraws:resize(0)
local line = 0
for text in io.lines(file) do
local data = trim(text)
if (data ~= "") then
local nextline = line + 1
local rawline = oldraws[0]:new()
rawline.value = data
newraws:resize(line)
newraws:insert(line, rawline)
line = nextline
end
end
creature.raws = newraws
-- Probably a memory leak here?
print("Creature \""..creature.name[0].."\" updated!")
end
local args = {...}
local id = tonumber(args[1])
if (not id or not args[2] or not dfhack.filesystem.isfile(args[2])) then
qerror("Parameter format error. Correct format: load id filename")
return
end
local creature = df.global.world.raws.creatures.all[id]
if (not creature) then
qerror("No such creature found.")
return
end
updateraw(creature, args[2])
In order to run the scripts, you'll need to have a world loaded in fortress, adventure or legends mode. Legends mode does not save the game when exited, so loading in a raw in legends mode will have no effect, as you need to save the game and reload it before a loaded raw takes effect.
Both scripts use the raw-styled .txt files, you'll notice they're formatted a little differently - this is how they're formatted in memory, so if you are loading in a raw make sure to format it in the same way.
And in case it wasn't obvious, these scripts work on the game's memory, and they're not exactly polished, so I take no responsibility for the horrible things they could do to your save games. (Always back up your saves, and all that!)