Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: Milo's DFHack Scripts  (Read 5108 times)

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Milo's DFHack Scripts
« on: March 10, 2014, 11:44:27 am »

This thread will contain all my DFHack scripts.

Once the thread gets to be 2-3 pages long I'll add a TOC, but for now just scroll down :)
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: Milo's DFHack Scripts
« Reply #1 on: March 10, 2014, 11:46:22 am »

Script #1: announce (rubble_announce)

Usage: announce "message" [color]
Code: [Select]
-- Display an announcement and write it to the game log.

--[[
Rubble Announcement DFHack Command

Copyright 2013-2014 Milo Christiansen

This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use of
this software.

Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an
acknowledgment in the product documentation would be appreciated but is not
required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
]]

local helpstring = [[ Display an announcement and write it to the game log.
  announce message|? [color]
    message  The message you want to display.
    color    The color to display the message in.
    ?        Print this help.
]]

if not dfhack.isMapLoaded() then
dfhack.printerr('Error: Map is not loaded.')
return
end

local args = {...}

local text = args[1]
if not text or text == "?" then
print(helpstring)
return
end

-- Valid Color Values
-- COLOR_BLACK
-- COLOR_BLUE
-- COLOR_GREEN
-- COLOR_CYAN
-- COLOR_RED
-- COLOR_MAGENTA
-- COLOR_BROWN
-- COLOR_GREY
-- COLOR_DARKGREY
-- COLOR_LIGHTBLUE
-- COLOR_LIGHTGREEN
-- COLOR_LIGHTCYAN
-- COLOR_LIGHTRED
-- COLOR_LIGHTMAGENTA
-- COLOR_YELLOW
-- COLOR_WHITE
local color_id = args[2]
if not color_id then color_id = "COLOR_WHITE" end

local color = _G[color_id]

dfhack.gui.showAnnouncement(text, color)

local log = io.open('gamelog.txt', 'a')
log:write(text.."\n")
log:close()
« Last Edit: March 17, 2014, 05:02:43 pm by milo christiansen »
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: Milo's DFHack Scripts
« Reply #2 on: March 10, 2014, 11:49:47 am »

Script #2: Lua module "rubble_fluids"

Usage: fluids = require "rubble_fluids"
Code: [Select]
--[[
Rubble Fluids DFHack Lua Module

Copyright 2014 Milo Christiansen

This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use of
this software.

Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an
acknowledgment in the product documentation would be appreciated but is not
required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
]]

local _ENV = mkmodule("rubble_fluids")

-- Returns true if the specified tile is downward passable (to flows).
function passableDown(x, y, z)
ttype = dfhack.maps.getTileType(x, y, z)
tshape = df.tiletype.attrs[ttype].shape
return df.tiletype_shape.attrs[tshape].passable_flow_down
end

-- Eat fluid from the specified tile, returns true if it succeeds.
function eatFluid(x, y, z, magma, amount, minimum)
local block = dfhack.maps.ensureTileBlock(x,y,z)

if block.designation[x%16][y%16].flow_size >= minimum then
if block.designation[x%16][y%16].liquid_type == magma then
block.designation[x%16][y%16].flow_size = block.designation[x%16][y%16].flow_size - amount
else
return false
end
else
return false
end

dfhack.maps.enableBlockUpdates(block,true,true)
return true
end

-- Eat from below a specified area, there needs to be access to the fluid via a downward passable tile
function eatFromArea(x1, y1, x2, y2, z, magma, amount, minimum)
for cx = x1, x2, 1 do
for cy = y1, y2, 1 do
if passableDown(cx, cy, z) then
if eatFluid(cx, cy, z-1, magma, amount, minimum) then
return true
end
end
end
end
return false
end

-- spawn fluid, returns true if the fluid could be spawned
function spawnFluid(x, y, z, magma, amount)
local block = dfhack.maps.ensureTileBlock(x,y,z)

local ttype = block.tiletypes[x%16][y%16]
local tshape = df.tiletype.attrs[ttype].shape
if not df.tiletype_shape.attrs[tshape].passable_flow then
return false
end

if amount > 7 then
dfhack.printerr("rubble_fluids: Attempt to spawn more than 7 fluid in tile.")
return false
end

local flow = block.designation[x%16][y%16].flow_size
if flow == 7 or flow + amount > 7 then
return false
end

if block.designation[x%16][y%16].liquid_type ~= magma then
return false
end

block.designation[x%16][y%16].flow_size = flow + amount
dfhack.maps.enableBlockUpdates(block,true,true)
return true
end

-- Spawn below a specified area, there needs to be access via a downward passable tile
function spawnInArea(x1, y1, x2, y2, z, magma, amount)
for cx = x1, x2, 1 do
for cy = y1, y2, 1 do
if passableDown(cx, cy, z) then
if spawnFluid(cx, cy, z-1, magma, amount) then
return true
end
end
end
end
return false
end

-- Returns true if item is magma safe.
function magmaSafe(item)
-- Should work, but always returns false, not sure what's wrong.
--item:isTemperatureSafe(2)

-- Not sure if all this is required, but better safe than sorry.
local mat = dfhack.matinfo.decode(item)
if mat.material.heat.heatdam_point > 12000 and
mat.material.heat.melting_point > 12000 and
mat.material.heat.ignite_point > 12000 and
mat.material.heat.boiling_point > 12000 then
return true
end
return false
end

-- Find an empty (possibly magma safe) cart in the specified tile
function findCart(x, y, z, magmasafe)
local itemblock = dfhack.maps.ensureTileBlock(x, y, z)
if itemblock.occupancy[x%16][y%16].item == true then
for c=#itemblock.items-1,0,-1 do
cart=df.item.find(itemblock.items[c])
if cart:isTrackCart() then
if cart.pos.x == x and cart.pos.y == y and cart.pos.z == z then
if #dfhack.items.getContainedItems(cart) == 0 then
if magmasafe then
if magmaSafe(cart) then
return cart
end
else
return cart
end
end
end
end
end
end
return nil
end

-- Find a empty (possibly magma safe) cart in the specified area.
function findCartArea(x1, y1, x2, y2, z, magmasafe)
for cx = x1, x2, 1 do
for cy = y1, y2, 1 do
cart = findCart(cx, cy, z, magmasafe)
if cart ~= nil then
return cart
end
end
end
return nil
end

-- Fill a minecart with magma or water.
function fillCart(cart, magma)
capacity = math.floor(cart.subtype.container_capacity/60)

local item=df['item_liquid_miscst']:new()
item.id=df.global.item_next_id
df.global.world.items.all:insert('#',item)
df.global.item_next_id=df.global.item_next_id+1

local mat
if magma then
mat = dfhack.matinfo.find("INORGANIC:NONE")
-- This keeps the magma from becoming solid after a few seconds
-- apparently items start out at the default room temperature.
item.temperature.whole = 12000
else
mat = dfhack.matinfo.find("WATER:NONE")
end

item:setMaterial(mat.type)
item:setMaterialIndex(mat.index)
item.stack_size = capacity
item:categorize(true)
item.flags.removed=true

dfhack.items.moveToContainer(item, cart)
end

-- This should add skill exp to a unit
-- doesn't seem to fit the theme until you consider just how often this lib gets used from Lua hooks
-- (and AFAIK Lua hooks do not award exp for completed reactions)
-- This is lifted (almost) directly from the machina script from Masterwork
function levelUp(unit, skillId, amount)
max_skill = 20

local skill = df.unit_skill:new()
local foundSkill = false
for k, soulSkill in ipairs(unit.status.current_soul.skills) do
if soulSkill.id == skillId then
skill = soulSkill
foundSkill = true
break
end
end
 
if foundSkill then
-- Let's not train beyond the max skill
if skill.rating >= max_skill then
return false
end
 
skill.experience = skill.experience + amount
if skill.experience > 100 * skill.rating + 500 then
skill.experience = skill.experience - (100 * skill.rating + 500)
skill.rating = skill.rating + 1
end
else
skill.id = skillId
skill.experience = amount
skill.rating = 0
unit.status.current_soul.skills:insert('#',skill)
end

return true
end

return _ENV

This little gem is that heart of a bunch of DFHack-powered fluid-using workshops I have made recently.
« Last Edit: March 17, 2014, 05:02:03 pm by milo christiansen »
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: Milo's DFHack Scripts
« Reply #3 on: March 10, 2014, 11:52:20 am »

Script #3: rubble_fluids (command version)

Code: [Select]
-- Do fun stuff with water and magma.

--[[
Rubble Fluids DFHack Command

Copyright 2014 Milo Christiansen

This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use of
this software.

Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an
acknowledgment in the product documentation would be appreciated but is not
required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
]]

-- [[  ]] is a really stupid choice for string delimiters, particularly when you need to do a usage statement.
-- BTW: experience has shown that it is trivial to support multi-line double quote strings in a lexer,
-- (it actually takes more work to disable them) so why do most languages limit them to a single line?
local usage = [[
Usage:
fluids [-h|/?]
]].."rubble_fluids [eat] [spot|3x3|5x5|7x7] [magma|water] [amount [minimum [x y z]]]\n"..
" rubble_fluids spawn [spot|3x3|5x5|7x7] [magma|water] [amount [x y z]]\n"..[[
rubble_fluids cart [spot|3x3|5x5|7x7] [magma|water] [x y z]

Allows you to:
Spawn fluids, either in a single tile or in any tile below a downward passable tile in an area.
Eat fluids, either from a single tile or from any tile below a downward passable tile in an area.
Fill a minecart with fluids, either in a single tile or in an area.

Examples:
spawn 4/7 magma at cursor
rubble_fluids spawn magma 4
eat 2/7 magma at cursor, but only if there is at least 4/7 there
rubble_fluids magma 2 4
fill the minecart at cursor with water
rubble_fluids cart water
fill the minecart at coords <x:10, y:20, z:30> with water
rubble_fluids cart water 10 20 30
eat 2/7 magma from the first tile below a 3x3 area around the cursor that is
downward-passable and has at least 2/7 magma
rubble_fluids eat 3x3 magma 2

This script is mostly a test driver for the functions in the rubble_fluids module.

If you use Rubble there are some convenience templates avalible in the
"Libs/DFHack/Fluids" addon that make using this script in reactions MUCH easier.
(That addon also installs this script and the required lua module)
]]

local pos=df.global.cursor
local args={...}

if args[1]=="-h" or args[1]=="/?" then
print(usage)
return
end

local fluids = require "rubble_fluids"

-- parse options, oh for go's "flag" package...
local spawn = false
local area = false
local offset = 1
local tocart = false
local magma = false
local narg = 1
local amount = 1
local minimum = 1

local x = -1
local y = -1
local z = -1

if pos.x ~= -30000 then
x = pos.x
y = pos.y
z = pos.z
end

if args[narg]=="spawn" then
spawn = true
narg = narg + 1
elseif args[narg]=="eat" then
narg = narg + 1
elseif args[narg]=="cart" then
tocart = true
narg = narg + 1
end

if args[narg]=="3x3" then
area = true
offset = 1
narg = narg + 1
elseif args[narg]=="5x5" then
area = true
offset = 2
narg = narg + 1
elseif args[narg]=="7x7" then
area = true
offset = 3
narg = narg + 1
end

if args[narg]=="magma" then
magma = true
narg = narg + 1
elseif args[narg]=="water" then
narg = narg + 1
end

if not tocart then
if args[narg] ~= nil then
amount = tonumber(args[narg])
narg = narg + 1
end
end

if not spawn then
if args[narg] ~= nil then
minimum = tonumber(args[narg])
narg = narg + 1
end
end

if args[narg] ~= nil then
x = tonumber(args[narg])
narg = narg + 1
end

if args[narg] ~= nil then
y = tonumber(args[narg])
narg = narg + 1
end

if args[narg] ~= nil then
z = tonumber(args[narg])
narg = narg + 1
end

if x == -1 or y == -1 or z == -1 then
print("Error: invalid position.")
print("Drop a cursor or specify coords on the command line.")
print("Type \"rubble_fluids -h\" for help.")
return
end

if minimum < amount then
print("Warning: minimum less than amount or not specified, adjusting.")
minimum = amount
end

-- Do the requested operation.
-- Error handling is a little sparse.
if spawn then
if area then
fluids.spawnInArea(x-offset, y-offset, x+offset, y+offset, z, magma, amount)
return
end

fluids.spawnFluid(x, y, z, magma, amount)
return
elseif tocart then
local cart
if area then
cart = fluids.findCartArea(x-offset, y-offset, x+offset, y+offset, z, magma)
else
cart = fluids.findCart(x, y, z, magma)
end

if cart == nil then
print("Error: No minecart at coords/in area.")
return
end

fluids.fillCart(cart, magma)
else
if area then
fluids.eatFromArea(x-offset, y-offset, x+offset, y+offset, z, magma, amount, minimum)
return
end

fluids.eatFluid(x, y, z, magma, amount, minimum)
return
end

This command is mostly a test driver for the rubble_fluids Lua module, but it also works well in some case when used with autoSyndrome or the like.
« Last Edit: March 17, 2014, 05:03:25 pm by milo christiansen »
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: Milo's DFHack Scripts
« Reply #4 on: March 10, 2014, 11:55:47 am »

Example for using "rubble_fluids" Lua module:

Code: [Select]
local event = require "plugins.eventful"
local fluids = require "rubble_fluids"

function fillCartMagma(reaction, unit, in_items, in_reag, out_items, call_native)
call_native.value=false

cart = fluids.findCartArea(unit.pos.x-2, unit.pos.y-2, unit.pos.x+2, unit.pos.y+2, unit.pos.z, true)
if cart == nil then
dfhack.gui.showAnnouncement("Your Cart Filler cannot find an empty magma-safe minecart!", COLOR_LIGHTRED)
return
end

-- Handle carts of various sizes
amount = math.floor(math.floor(cart.subtype.container_capacity/60)/7)
if amount > 7 then amount = 7 end
minimum = 4
if minimum < amount then minimum = amount end

if fluids.eatFromArea(unit.pos.x-2, unit.pos.y-2, unit.pos.x+2, unit.pos.y+2, unit.pos.z, true, amount, minimum) then
fluids.fillCart(cart, true)
else
dfhack.gui.showAnnouncement("Your Cart Filler has run out of magma!", COLOR_LIGHTRED)
return
end
end

function fillCartWater(reaction, unit, in_items, in_reag, out_items, call_native)
call_native.value=false

cart = fluids.findCartArea(unit.pos.x-2, unit.pos.y-2, unit.pos.x+2, unit.pos.y+2, unit.pos.z, false)
if cart == nil then
dfhack.gui.showAnnouncement("Your Cart Filler cannot find an empty minecart!", COLOR_LIGHTBLUE)
return
end

-- Handle carts of various sizes
amount = math.floor(math.floor(cart.subtype.container_capacity/60)/7)
if amount > 7 then amount = 7 end
minimum = 4
if minimum < amount then minimum = amount end

if fluids.eatFromArea(unit.pos.x-2, unit.pos.y-2, unit.pos.x+2, unit.pos.y+2, unit.pos.z, false, amount, minimum) then
fluids.fillCart(cart, false)
else
dfhack.gui.showAnnouncement("Your Cart Filler has run out of water!", COLOR_LIGHTBLUE)
return
end
end

event.registerReaction("LUA_HOOK_FILL_CART_MAGMA", fillCartMagma)
event.registerReaction("LUA_HOOK_FILL_CART_WATER", fillCartWater)

This scipt uses any water or magma below a 5x5 area (centered on the worker) to fill any minecart in the same area.

Reactions:
Code: [Select]
[OBJECT:REACTION]

{REACTION;LUA_HOOK_FILL_CART_MAGMA;ADDON_HOOK_PLAYABLE}
[NAME:fill minecart]
[BUILDING:CART_FILLER_MAGMA:CUSTOM_F]
[PRODUCT:100:1:BAR:NONE:INORGANIC:NONE]
[SKILL:OPERATE_PUMP]

{REACTION;LUA_HOOK_FILL_CART_WATER;ADDON_HOOK_PLAYABLE}
[NAME:fill minecart]
[BUILDING:CART_FILLER:CUSTOM_F]
[PRODUCT:100:1:BAR:NONE:INORGANIC:NONE]
[SKILL:OPERATE_PUMP]
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Milo's DFHack Scripts
« Reply #5 on: March 11, 2014, 05:41:53 am »

Wouldnt this be better added to the dfhack script collection? One place for all custom scripts, that was the idea behind it. :) Makes it easier for people to find everything.
Logged
::: ☼Meph Tileset☼☼Map Tileset☼- 32x graphic sets with TWBT :::
::: ☼MASTERWORK DF☼ - A comprehensive mod pack now on Patreon - 250.000+ downloads and counting :::
::: WorldBicyclist.com - Follow my bike tours around the world - 148 countries visited :::

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: Milo's DFHack Scripts
« Reply #6 on: March 17, 2014, 05:01:13 pm »

They are all listed there, I just want one thread for me to post the scripts themselves.

Anyway, I acidently uploaded the wrong copy of the liquids scripts, so minecart filling will not work, the fixed versions are up now.
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS