Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: [1] 2

Author Topic: Help with a script - DigRoom.lua and Source.rb  (Read 2431 times)

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Help with a script - DigRoom.lua and Source.rb
« on: July 25, 2015, 02:03:27 am »

Hey guys,

I do have a script that digs rooms + up/downstairs into soil levels only, which is really neat for kobolds, but I do encounter two issues with it:

1. It works when called from dfhack and I have a cursor position, but not when triggered by a unit in a workshop. I assume that the worker-as-position is not in the script, which should be easy to fix (?).
2. The newly-dug room is hidden, it's still unrevealed. I can show it by running 'revflood', but that always takes a lot of time to run. It would be more efficient if the script itself would reveal the tiles it digs.

Can anyone have a look and let me know what can be done?

DigRoom.lua
Code: [Select]
-- -p {x,y,z} for coordinates, -h for help text. No args for default

NO_DIRECTION = '--------'
ALL_MATS_ALLOWED = false
HELP_TEXT = '-p {x,y,z} for coordinates, -h for help text. No args for default'


--Note that way the configuration is formatted below. Its unconventional, but its more familiar.
--Also note that we are using 'empty' for tiles we don't want to change
DEFAULT_CONFIGURATION =
{
--this represents a z,y,x format. This very closely resembles the Z-level format. This will be used. Note that the lowest Z-level shown first.
{--z level 1
--the outer {} represents the y, the inner the x
{df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL}, --y1
{df.tiletype_shape.WALL, df.tiletype_shape.FLOOR, df.tiletype_shape.FLOOR, df.tiletype_shape.FLOOR, df.tiletype_shape.WALL}, --y2
{df.tiletype_shape.WALL, df.tiletype_shape.STAIR_UP, df.tiletype_shape.FLOOR, df.tiletype_shape.FLOOR, df.tiletype_shape.WALL}, --y3
{df.tiletype_shape.WALL, df.tiletype_shape.FLOOR, df.tiletype_shape.FLOOR, df.tiletype_shape.FLOOR, df.tiletype_shape.WALL},
{df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL, df.tiletype_shape.WALL}
},
{ --z level 2
{'empty', 'empty', 'empty', 'empty', 'empty'},
{'empty', 'empty', 'empty', 'empty', 'empty'},
{'empty', df.tiletype_shape.STAIR_DOWN, 'empty', 'empty', 'empty'},
{'empty', 'empty', 'empty', 'empty', 'empty'},
{'empty', 'empty', 'empty', 'empty', 'empty'}
}
}
-- this method is carelessly stolen from Kurik Amudnil's magic shovel
-- Kurik Amudnil, Thank you, it provides a novel way to get the tile I want in a Lua script.
function findTileType(shape, material, variant, special, dir)
local tt_attrs
--print(shape .. '  ' .. material)
for tt=0,698 do
tt_attrs = df.tiletype.attrs[tt]
if shape ~= df.tiletype_shape.NONE and shape ~= tt_attrs.shape then
--continue
elseif material ~= df.tiletype_material.NONE and material ~= tt_attrs.material then
--continue
-- Don't require variant to match if the destination tile doesn't even have one
elseif variant ~= df.tiletype_variant.NONE and variant ~= tt_attrs.variant and
tt_attrs.variant ~= df.tiletype_variant.NONE then
--continue
-- Same for special
elseif special ~= df.tiletype_special.NONE and special ~= tt_attrs.special and
tt_attrs.special ~= df.tiletype_special.NONE then
--continue
elseif dir ~= NO_DIRECTION and dir ~= tt_attrs.direction then -- if (tdir && tdir != tileDirection(tt)),
--continue
else
--Match
return tt
end
end
print('tile type not found')
return df.tiletype.Void
end

--configuraion is a multidimensional array
--of a room, such as floor, wall, up stair, down stair, or up/down stair.
--Ramps not supported yet.
--configuration should hold a tiletype_shape, ex: df.tiletype_shape.FLOOR
--In this manner, we can control the configuration of the room
--A hardcoded configuration will be provided as an example.
function DigRoom(configuration, absX, absY, absZ)
local shape, material, variant, special, dir
--damn indexing from 1 convention...
for relZ = 1, #configuration do
print(relZ .. ' ' .. #configuration)
for relY = 1, #configuration[relZ] do
print(relY .. ' ' .. #configuration[relZ])
for relX = 1, #configuration[relZ][relY] do
print(relX .. ' ' .. #configuration[relZ][relY])
--print('x: ' .. relX .. ' y: ' .. relY .. ' z: ' .. relZ)
if configuration[relZ][relY][relX] ~= nil and configuration[relZ][relY][relX] ~= 'empty' then
--print('Shape acquired for x: ' .. relX .. ' y: ' .. relY .. ' z: ' .. relZ)
shape = configuration[relZ][relY][relX] --set the shape of the tile from configuration
material = df.tiletype.attrs[dfhack.maps.getTileType(relX+absX-2, relY+absY-2, relZ+absZ-2)].material --get the material of the tile
variant = df.tiletype.attrs[dfhack.maps.getTileType(relX+absX-2, relY+absY-2, relZ+absZ-2)].variant
special = df.tiletype.attrs[dfhack.maps.getTileType(relX+absX-2, relY+absY-2, relZ+absZ-2)].special
dir = df.tiletype.attrs[dfhack.maps.getTileType(relX+absX-2, relY+absY-2, relZ+absZ-2)].direction
if shape == df.tiletype_shape.FLOOR then
variant = math.random(0,3)
special = df.tiletype_special.NORMAL
end
dir = NO_DIRECTION
if material == df.tiletype_material.SOIL or material == df.tiletype_material.GRASS_LIGHT or
material == df.tiletype_material.GRASS_DARK or material == df.tiletype_material.GRASS_DRY or
material == df.tiletype_material.GRASS_DEAD or material == df.tiletype_material.PLANT or
material == df.tiletype_material.AIR or ALL_MATS_ALLOWED then
local tt = findTileType(shape, material, variant, special, dir)
--print(tt)
if tt ~= df.tiletype.Void then
local effX = relX+absX-2
local effY = relY+absY-2
local effZ = relZ+absZ-2
--print('effX: ' .. effX .. ' effY: ' .. effY .. ' effZ: ' .. effZ .. ' effX%16: ' .. effX%16 .. ' effY%16: ' .. effY%16)
dfhack.maps.getTileBlock(effX, effY, effZ).tiletype[effX%16][effY%16] = tt
end
end
else
--print('nothing done')
end
end
end
end
end

local args={...}
if args == nil then
--TEST()
else
local position --an array holding x,y,z coordinates
local configuration --an array holding the configuration to be dug
local skip = false --to skip the next argument, or not to
local help = false --asking for help?
for i = 1, #args do
if not skip then
if args[i] == '-p' or args[i] == '--position' then
position = args[i+1]
skip = true
elseif args[i] == '-c' or args[i] == '--configuration' then
configuration = args[i+1]
skip = true
elseif args[i] == '-h' or args[i] == '--help' then
print(HELP_TEXT)
help = true
break
end
end
skip = false
end
if not help then
if position == nil then
position = {df.global.cursor.x, df.global.cursor.y, df.global.cursor.z}
end
if configuration == nil or true then
configuration = DEFAULT_CONFIGURATION
end
DigRoom(configuration, position[1], position[2], position[3])
end
end

In case you want to try out with workshop/reactions:
Code: [Select]
[BUILDING_WORKSHOP:DIG_SITE]
[NAME:Dig Site]
[NAME_COLOR:7:0:1]
[BUILD_LABOR:MINING]
[BUILD_KEY:CUSTOM_SHIFT_D]
[DIM:3:1]
[WORK_LOCATION:1:1]
[BLOCK:1:0:0:0]
[TILE:0:1:32:25:32]
[COLOR:0:1:0:0:0:7:0:0:0:0:0]
[TILE:1:1:32:25:32]
[COLOR:1:1:0:0:0:7:0:0:0:0:0]
[TILE:2:1:32:25:32]
[COLOR:2:1:0:0:0:7:0:0:0:0:0]
[TILE:3:1:25:157:152]
[COLOR:3:1:7:0:0:6:0:0:6:0:0]
Code: [Select]
[REACTION:DIG_HOVEL]
[NAME:Dig a warren (3x3)]
[BUILDING:DIG_SITE:CUSTOM_A]
[SKILL:MINING]
Code: [Select]
[PERMITTED_BUILDING:DIG_SITE]
[PERMITTED_REACTION:DIG_HOVEL]
« Last Edit: July 26, 2015, 02:55:26 am by Meph »
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 :::

Warmist

  • Bay Watcher
  • Master of unfinished jobs
    • View Profile
Re: Help with a script - DigRoom.lua
« Reply #1 on: July 25, 2015, 05:18:07 am »

oh wow... "findTileType" is at first glance insanely inefficient. Better way would be to have precomputed table of valid tiles and do lookup.

As for hidden tiles, you need to change:
Code: [Select]
dfhack.maps.getTileBlock(effX, effY, effZ).tiletype[effX%16][effY%16] = tt
with
Code: [Select]
local tblock=dfhack.maps.getTileBlock(effX, effY, effZ)
tblock.tiletype[effX%16][effY%16] = tt
tblock.destination[effX%16][effY%16].hidden=false
Disclaimer: theoretical programming, haven't tested it.

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua
« Reply #2 on: July 25, 2015, 05:44:57 am »

I tried, it shows an error message.

Code: [Select]
...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:100: Cannot read field map_block.destination: not found.stack traceback:
        [C]: in function '__index'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:100: in function 'DigRoom'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:142: in main chunk
        (...tail calls...)
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 :::

mifki

  • Bay Watcher
  • works secretly...
    • View Profile
    • mifki
Re: Help with a script - DigRoom.lua
« Reply #3 on: July 25, 2015, 05:56:20 am »

I think it's a typo, it should be "designation".

Warmist

  • Bay Watcher
  • Master of unfinished jobs
    • View Profile
Re: Help with a script - DigRoom.lua
« Reply #4 on: July 25, 2015, 06:24:08 am »

i blame lack of coffee! :D

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua
« Reply #5 on: July 25, 2015, 07:25:52 am »

Much better. Problem 2 solved, the area is now revealed. But when I run the script from a workshop, I still only get an error message:

Code: [Select]
...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:78: Invalid index in enum.attrs[]
stack traceback:
        [C]: in function '__index'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:78: in function 'DigRoom'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:142: in main chunk
        (...tail calls...)
        [C]: in function 'runCommand'
        ...MDF\Masterwork Reborn\Dwarf Fortress\hack\lua\dfhack.lua:447: in function '_run_command'
        ...MDF\Masterwork Reborn\Dwarf Fortress\hack\lua\dfhack.lua:462: in function 'run_command'
        ...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:106: in function 'doAction'
        ...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:146: in function <...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:75>
[DFHack]#

EDIT: And problem 3 found. The units ignore the spawned stairs, I still need to install proper stairs, and some of the ground is officially "inaccessable" even if the unit is standing right next to it. Guess I just go with empty floor and a open-space part where the down-stairs are. Is there a tiletype for open space ? Instead of df.tiletype_shape.STAIR_DOWN maybe df.tiletype_shape.OPEN_SPACE ?
« Last Edit: July 25, 2015, 09:21:59 am by Meph »
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 :::

Warmist

  • Bay Watcher
  • Master of unfinished jobs
    • View Profile
Re: Help with a script - DigRoom.lua
« Reply #6 on: July 25, 2015, 10:13:08 am »

i think you need to trigger re-pathing. Don't remember how it's done though... And starts down below open space would not work (only ramps work that way).
To check if it's pathing problem, try placing a door and lock (unpause) unlock. It should work after that.

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #7 on: July 26, 2015, 02:59:40 am »

Tried some more stuff on my own, couldnt get it to work yet. The pathing is fine, but I'm still missing the activation from a workshop (unit position instead of cursor position) and the tiletype for open-space.

By now I wanted to use another script in a similar fashion, encountered the same issue: Source.rb. I'm trying to make a 3x3 workshop that spawns liquid sources. It should be able to plant a source North, Eeast, South, or West, and the player can say 1-7 depths. Works beautifully with source.rb if I have a cursor, but I cant get the position to work with the workshop. I'd need to use the workshop or unit/worker position with these parameters: North = x, y-2, z. East = x+2, y,z. South = x, y+2, z. West = x-2, y, z.

But with ruby I even have less of a clue than with lua.

Bonus points if it would allow deleting the source at these locations too. This script would actually be very important for me, since I have plans for a water-based race that required their corridors and workshops to be connected with 3/7 water.

Code: [Select]
# create an infinite magma/water source/drain at the cursor

$sources ||= []

cur_source = {
:liquid => 'water',
:amount => 7,
:pos => [df.cursor.x, df.cursor.y, df.cursor.z]

}
cmd = 'help'

$script_args.each { |a|
case a.downcase
when 'water', 'magma'
cur_source[:liquid] = a.downcase
when /^\d+$/
cur_source[:amount] = a.to_i
when 'add', 'del', 'delete', 'clear', 'help', 'list'
cmd = a.downcase
else
puts "source: unhandled argument #{a}"
end
}

case cmd
when 'add'
$sources_onupdate ||= df.onupdate_register('sources', 12) {
# called every 12 game ticks (100x a dwarf day)
$sources.each { |s|
if tile = df.map_tile_at(*s[:pos]) and tile.shape_passableflow
# XXX does not check current liquid_type
des = tile.designation
cur = des.flow_size
if cur != s[:amount]
tile.spawn_liquid((cur > s[:amount] ? cur-1 : cur+1), s[:liquid] == 'magma')
end
end
}
if $sources.empty?
df.onupdate_unregister($sources_onupdate)
$sources_onupdate = nil
end
}

if cur_source[:pos][0] >= 0
if tile = df.map_tile_at(*cur_source[:pos])
if tile.shape_passableflow
$sources << cur_source
else
puts "Impassable tile: I'm afraid I can't do that, Dave"
end
else
puts "Unallocated map block - build something here first"
end
else
puts "Please put the game cursor where you want a source"
end

when 'del', 'delete'
$sources.delete_if { |s| s[:pos] == cur_source[:pos] }

when 'clear'
$sources.clear

when 'list'
puts "Source list:", $sources.map { |s|
" #{s[:pos].inspect} #{s[:liquid]} #{s[:amount]}"
}
puts "Current cursor pos: #{[df.cursor.x, df.cursor.y, df.cursor.z].inspect}" if df.cursor.x >= 0

else
puts <<EOS
Creates a new infinite liquid source at the cursor.

Examples:
  source add water     - create a water source under cursor
  source add water 0   - create a water drain
  source add magma 5   - create a magma source, up to 5/7 deep
  source delete        - delete source under cursor
  source clear         - remove all sources
  source list
EOS
end
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 :::

Roses

  • Bay Watcher
    • View Profile
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #8 on: July 26, 2015, 03:28:51 am »

I believe I have seen this issue before, something about the type of table the cursor is vs the \\LOCATION of a reaction-trigger. Let me see if I can find my old post that fixed it.
Logged

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #9 on: July 27, 2015, 01:42:44 am »

I tried both //LOCATION and //WORKER_ID in the Onload.init, but I only get there results:

For source add water 7:
Code: [Select]
Please put the game cursor where you want a source
For digroom:
Code: [Select]
...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:78: Invalid index in enum.attrs[]
stack traceback:
        [C]: in function '__index'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:78: in function 'DigRoom'
        ...asterwork Reborn\Dwarf Fortress\hack\scripts/digroom.lua:143: in main chunk
        (...tail calls...)
        [C]: in function 'runCommand'
        ...MDF\Masterwork Reborn\Dwarf Fortress\hack\lua\dfhack.lua:447: in function '_run_command'
        ...MDF\Masterwork Reborn\Dwarf Fortress\hack\lua\dfhack.lua:462: in function 'run_command'
        ...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:106: in function 'doAction'
        ...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:146: in function <...warf Fortress\hack\scripts/modtools/reaction-trigger.lua:75>
[DFHack]#
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 :::

mifki

  • Bay Watcher
  • works secretly...
    • View Profile
    • mifki
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #10 on: July 27, 2015, 07:15:51 am »

Well, this script expects a cursor... You can change in the beginning ":pos => [df.cursor.x, df.cursor.y, df.cursor.z]" to something else, but I don't know to what, because I've never user reaction-trigger, etc. and don't understand how all these scripts are going to be called.

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #11 on: July 27, 2015, 09:22:23 am »

I tried copy+pasting locations/position arguments from other scripts that do use the unit or worker id, but I couldnt get it to work. It's probably just a simple syntax error. I'll just wait till someone has mercy on me and fixes it. I'm much more useful with raws and modding, not with scripts and coding. :/
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 :::

lethosor

  • Bay Watcher
    • View Profile
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #12 on: July 27, 2015, 11:46:28 am »

For one thing, you need \\LOCATION, not //LOCATION. I'm also not sure if Ruby scripts like "source" can be used where you're using them, since commands that require double backslashes typically require them because they're using Lua's argument processing functions, and might only recognize other Lua scripts.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #13 on: July 27, 2015, 11:53:51 am »

I was using \\, was just a typo here in the forum. And the ruby script I can call from reaction-trigger, the only issue is that it tells me that I require a cursor. Otherwise an alternative script in lua would be needed...

Or another way to spawn water to a 3/7 level. :/
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 :::

Roses

  • Bay Watcher
    • View Profile
Re: Help with a script - DigRoom.lua and Source.rb
« Reply #14 on: July 27, 2015, 12:08:03 pm »

For DigRoom.rb
Unfortunately I have never used ruby so I don't know exactly, but from what I can tell the ruby scripts should work, but they don't use the lua utilities, so they just take inputs directly as they are written (meaning order matters). But that shouldn't be an issue for the DigRoom.rb code you posted. My question would be, if you put a print statment at the end right before the function call at line 140. print(position,position[1],position[2],position[3]) what do you get? Otherwise I don't see why something like
Code: [Select]
reaction-trigger -reactionName X -command [ DigRoom -p \\LOCATION -c X ]Shouldn't work.

For spawning water
My script eruption (which will have it's name changed at some point, but for now remains) will spawn water at the location of a reaction. The command would be
Code: [Select]
reaction-trigger -reactionName X -command [ eruption -location \\LOCATION -depth 3 -water ]You can also add the extra options
Code: [Select]
-offset x,y,zto move the placement from the location of the workshop, and
Code: [Select]
-radius x,y,zto place it in more than a single tile location.
Logged
Pages: [1] 2