dfhack/scripts/devel/inject-raws.lua

184 lines
4.9 KiB
Lua

-- Injects new reaction, item and building defs into the world.
-- The savegame contains a list of the relevant definition tokens in
-- the right order, but all details are read from raws every time.
-- This allows just adding stub definitions, and simply saving and
-- reloading the game.
-- Usage example:
--[[
devel/inject-raws trapcomp ITEM_TRAPCOMP_STEAM_PISTON workshop STEAM_ENGINE MAGMA_STEAM_ENGINE reaction STOKE_BOILER
]]
local utils = require 'utils'
local raws = df.global.world.raws
print[[
WARNING: THIS SCRIPT CAN PERMANENLY DAMAGE YOUR SAVE.
This script attempts to inject new raw objects into your
world. If the injected references do not match the actual
edited raws, your save will refuse to load, or load but crash.
]]
if not utils.prompt_yes_no('Did you make a backup?') then
qerror('Not backed up.')
end
df.global.pause_state = true
local changed = false
function inject_reaction(name)
for _,v in ipairs(raws.reactions) do
if v.code == name then
print('Reaction '..name..' already exists.')
return
end
end
print('Injecting reaction '..name)
changed = true
raws.reactions:insert('#', {
new = true,
code = name,
name = 'Dummy reaction '..name,
index = #raws.reactions,
})
end
local building_types = {
workshop = { df.building_def_workshopst, raws.buildings.workshops },
furnace = { df.building_def_furnacest, raws.buildings.furnaces },
}
function inject_building(btype, name)
for _,v in ipairs(raws.buildings.all) do
if v.code == name then
print('Building '..name..' already exists.')
return
end
end
print('Injecting building '..name)
changed = true
local typeinfo = building_types[btype]
local id = raws.buildings.next_id
raws.buildings.next_id = id+1
raws.buildings.all:insert('#', {
new = typeinfo[1],
code = name,
name = 'Dummy '..btype..' '..name,
id = id,
})
typeinfo[2]:insert('#', raws.buildings.all[#raws.buildings.all-1])
end
local itemdefs = raws.itemdefs
local item_types = {
weapon = { df.itemdef_weaponst, itemdefs.weapons, 'weapon_type' },
trainweapon = { df.itemdef_weaponst, itemdefs.weapons, 'training_weapon_type' },
pick = { df.itemdef_weaponst, itemdefs.weapons, 'digger_type' },
trapcomp = { df.itemdef_trapcompst, itemdefs.trapcomps, 'trapcomp_type' },
toy = { df.itemdef_toyst, itemdefs.toys, 'toy_type' },
tool = { df.itemdef_toolst, itemdefs.tools, 'tool_type' },
instrument = { df.itemdef_instrumentst, itemdefs.instruments, 'instrument_type' },
armor = { df.itemdef_armorst, itemdefs.armor, 'armor_type' },
ammo = { df.itemdef_ammost, itemdefs.ammo, 'ammo_type' },
siegeammo = { df.itemdef_siegeammost, itemdefs.siege_ammo, 'siegeammo_type' },
gloves = { df.itemdef_glovest, itemdefs.gloves, 'gloves_type' },
shoes = { df.itemdef_shoest, itemdefs.shoes, 'shoes_type' },
shield = { df.itemdef_shieldst, itemdefs.shields, 'shield_type' },
helm = { df.itemdef_helmst, itemdefs.helms, 'helm_type' },
pants = { df.itemdef_pantsst, itemdefs.pants, 'pants_type' },
food = { df.itemdef_foodst, itemdefs.food },
}
function add_to_civ(entity, bvec, id)
for _,v in ipairs(entity.resources[bvec]) do
if v == id then
return
end
end
entity.resources[bvec]:insert('#', id)
end
function add_to_dwarf_civs(btype, id)
local typeinfo = item_types[btype]
if not typeinfo[3] then
print('Not adding to civs.')
end
for _,entity in ipairs(df.global.world.entities.all) do
if entity.race == df.global.ui.race_id then
add_to_civ(entity, typeinfo[3], id)
end
end
end
function inject_item(btype, name)
for _,v in ipairs(itemdefs.all) do
if v.id == name then
print('Itemdef '..name..' already exists.')
return
end
end
print('Injecting item '..name)
changed = true
local typeinfo = item_types[btype]
local vec = typeinfo[2]
local id = #vec
vec:insert('#', {
new = typeinfo[1],
id = name,
subtype = id,
name = name,
name_plural = name,
})
itemdefs.all:insert('#', vec[id])
add_to_dwarf_civs(btype, id)
end
local args = {...}
local mode = nil
local ops = {}
for _,kv in ipairs(args) do
if mode and string.match(kv, '^[%u_]+$') then
table.insert(ops, curry(mode, kv))
elseif kv == 'reaction' then
mode = inject_reaction
elseif building_types[kv] then
mode = curry(inject_building, kv)
elseif item_types[kv] then
mode = curry(inject_item, kv)
else
qerror('Invalid option: '..kv)
end
end
if #ops > 0 then
print('')
for _,v in ipairs(ops) do
v()
end
end
if changed then
print('\nNow without unpausing save and reload the game to re-read raws.')
else
print('\nNo changes made.')
end