01/29/2020 Released Dwarf Fortress 0.47.01
... automated builds available at https://buildmaster.lubar.me/applications/3/overview for anyone who would like to test those ...
Only 10 days later we have a workable DFHACK for testing. This community work is simply awesome!
During the debugging of the new version of digfort I have tested that some other DFHACK parts works like intended (reveal, unreveal, liquids plugin, ls, mouse control, ...)
... Does your fixed script work properly for you? (I wasn't sure if you meant your version didn't work at all, or if you weren't sure that it always worked.)
Well at the time you asked, it do not even existed. So the
modified script that works (for me at least) with DF 47.02 plus the most recent dfhack automatic build.
# designate an area based on a '.csv' plan
=begin
digfort
=======
A script to designate an area for digging according to a plan in csv format.
This script, inspired from quickfort, can designate an area for digging.
Your plan should be stored in a .csv file like this::
# this is a comment
d;d;u;d;d;skip this tile;d
d;d;d;i
Available tile shapes are named after the 'dig' menu shortcuts:
``d`` for dig, ``u`` for upstairs, ``j`` downstairs, ``i`` updown,
``h`` channel, ``r`` upward ramp, ``x`` remove designation.
Unrecognized characters are ignored (eg the 'skip this tile' in the sample).
Empty lines and data after a ``#`` are ignored as comments.
To skip a row in your design, use a single ``;``.
One comment in the file may contain the phrase ``start(3,5)``. It is interpreted
as an offset for the pattern: instead of starting at the cursor, it will start
3 tiles left and 5 tiles up from the cursor.
additionally a comment can have a < for a rise in z level and a > for drop in z.
The script takes the plan filename, starting from the root df folder (where
``Dwarf Fortress.exe`` is found).
=end
fname = $script_args[0].to_s
map = df.world.map
Xsentinel = map.x_count - 1
Ysentinel = map.y_count - 1
Xstamp = false
Ystamp = false
if not $script_args[0] then
puts " Usage: digfort <plan filename>"
throw :script_finished
end
if not fname[-4..-1] == ".csv" then
puts " The plan file must be in .csv format."
throw :script_finished
end
if not File.file?(fname) then
puts " The specified file does not exist."
throw :script_finished
end
planfile = File.read(fname)
if df.cursor.x == -30000
puts "place the game cursor to the top-left corner of the design and retry"
throw :script_finished
end
offset = [0, 0]
tiles = []
max_x = 0
max_y = 0
y = 0
planfile.each_line { |l|
if l =~ /#.*start\s*\(\s*(-?\d+)\s*[,;]\s*(-?\d+)/
raise "Error: multiple start() comments" if offset != [0, 0]
offset = [$1.to_i, $2.to_i]
end
if l.chomp == '#<'
l = '<'
y = 0
end
if l.chomp == '#>'
l = '>'
y = 0
end
l = l.chomp.sub(/#.*/, '')
next if l == ''
x = 0
tiles << l.split(/[;,]/).map { |t|
t = t.strip
if x < Xsentinel then x += 1 else x = Xsentinel ; Xstamp = true end
max_x = x if x > max_x and not t.empty?
(t[0] == '"') ? t[1..-2] : t
}
if y < Ysentinel then y += 1 else y = Ysentinel ; Xstamp = true end
}
x = df.cursor.x - offset[0]
y = df.cursor.y - offset[1]
z = df.cursor.z
starty = y - 1
if x < 0 or y < 0 or x+max_x >= map.x_count or y+max_y >= map.y_count
max_x = max_x + x + 1
max_y = max_y + y + 1
raise "Position would designate outside map limits. Selected limits are from (#{x+1}, #{y+1}) to (#{max_x},#{max_y})"
end
tiles.each { |line|
next if line.empty? or line == ['']
line.each { |tile|
if tile.empty?
if x < Xsentinel then x += 1 else x = Xsentinel ; Xstamp = true end
next
end
t = df.map_tile_at(x, y, z)
s = t.shape_basic
case tile
when 'd'; t.dig(:Default) if s == :Wall
when 'u'; t.dig(:UpStair) if s == :Wall
when 'j'; t.dig(:DownStair) if s == :Wall or s == :Floor
when 'i'; t.dig(:UpDownStair) if s == :Wall
when 'h'; t.dig(:Channel) if s == :Wall or s == :Floor
when 'r'; t.dig(:Ramp) if s == :Wall
when 'x'; t.dig(:No)
when '<'; y=starty; z += 1
when '>'; y=starty; z -= 1
end
if x < Xsentinel then x += 1 else x = Xsentinel ; Xstamp = true end
}
x = df.cursor.x - offset[0]
if y < Ysentinel then y += 1 else y = Ysentinel ; Ystamp = true end
}
if Xstamp or Ystamp then
puts 'Warning: ' + (Xstamp ? 'the columns': '') + (Xstamp and Ystamp ? ' and ': '') + (Ystamp ? 'the rows' : '') + ' of the blueprint that overflow the designable area of the Dwarf Fortress embark have been ignored'
puts ' if your blueprint X or Y dimension is close to that of the embark map, this warning is probably a false positive due to faulty logic in this script'
end
puts ' done'
Seeing that the available workforce is working frenetically; I had tasked myself to accomplish my own desired feature set:
... maybe a better implementation than raising an exception before any work is done would be to stamp the part of the blueprint that effectively can be fit into the map and print a warning about the number of rows and/or lines not stamped to inform the user. More work done before trapping, more debug aware and in the worst case, the user can always delete the designations if they were not what he intended...
The modified script as of now just work eagerly before trapping and has some new nice features:- it stamps the safe part of blueprints that are same size than the embark. (with some more tinkering and 4 additional params partial stamping should be in the reachable zone)
- it warns when some lines and/or rows of the blueprint could had been ignored because the dimensions of the blueprint are bigger than the design-able zone of the embark.
- well formed multilevel nanoforts of 48x48 or 47x47 tiles faultily rejected by the previous script over an 1x1 embark are now possible.
I am ashamed to admit that I am almost unable to play without blueprints, at least if taking joy in it is an objective.
I am concerned with the fact that before tinkering with this script by harsh need, I did not know anything about Ruby, but were instead able to read and modify lua and C snippets.
I have only been able of correcting the bad effects of the flaw in the design, but not his source, that rest hidden for me in the part of Ruby that I do not understand So it can be said that the new script recover more gracefully from his inherent flaw and does more work for the end user,
without attacking the root problem sadly, for a 1x1 embark with 48x48 tiles the anterior script only worked when the blueprint has been taken of the area really design-able of at most 46x46 tiles.
I believe that the flaw comes because it counts the TOP and BOTTOM lines that represents areas non design-able of the blueprint in the current embark.
To resume the actual state of things, the bug has been conveniently hammered until it was almost unrecognizable but it has not been memorialized so that his ghost could potentially haunt us in the future.
Urist McAbadrausar, dabbler Ruby tinkerer, is ecstatic to have been able to tackle in a truly dwarvenly manner a long standing problem, for the nanofort forgotten designers. (Linux and OSX do not have complete support for QuickFort)