v50 Steam/Premium information for editors
  • v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
  • Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.

Editing User:Fleeting Frames/constructmultiz

Jump to navigation Jump to search

Warning: You are not logged in.
Your IP address will be recorded in this page's edit history.


The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 3: Line 3:
 
<source lang="lua">
 
<source lang="lua">
 
--lets one construct simultaneously on z-axis
 
--lets one construct simultaneously on z-axis
--[[TODO list:
 
    Add checking for minimap being present when rendering
 
 
    Construct # previous buildings (optionally #a to #b previous buildings or selected building(s))
 
    Allow constructing constructmultiz buildings by simply copying job_filter.
 
 
    Construct in x, y or fii° direction. Allow cursor position to determine fii° (useful when combined with previous one)
 
    This means way to place cursor. mouse_x,_y will work - on same z-level. Burrow named 'cursor' would work on different z-level.
 
    With lineiterator already present, could theoretically use paintstring to paint the expected line.
 
 
    Construct on designations of given type, priority and marked/not /construct on adjacent matching designations. 
 
 
    Construct all buildings in a burrow.
 
 
    Given a set of buildings and set of locations, loop through the buildings when copying.
 
 
    High priority corners
 
 
    trigger designation seek when placing on a designation
 
 
    Better automaterial support: Keeping constructmultiz settings and automaterial's both visible by masking with display and listening to relevant keys
 
 
 
]]
 
 
local helptext = [===[
 
local helptext = [===[
 
constructonmultiplezlevels
 
constructonmultiplezlevels
 
==========================
 
==========================
     version 1.34
+
     version 1.01 (beta)
 
Script to construct multiple z-levels of buildings at once.
 
Script to construct multiple z-levels of buildings at once.
 
Currently uses general seeking for matching material and type,
 
Currently uses general seeking for matching material and type,
Line 57: Line 33:
 
qerror("")
 
qerror("")
 
end
 
end
 
local getBlock = dfhack.maps.getTileBlock
 
local getFlags = dfhack.maps.getTileFlags
 
local tin = table.insert
 
local gui = require 'gui'
 
local utils = require 'utils'
 
 
  
 
function getCurHeightAndDepth()
 
function getCurHeightAndDepth()
Line 81: Line 50:
 
end
 
end
 
return 0, 0 --if found nothing, reset to nothing
 
return 0, 0 --if found nothing, reset to nothing
end
 
 
 
local function getLen(data)
 
  -- Can't # a hashed table, must use pairs.
 
  local len = 0
 
  for i, val in pairs(data) do
 
    len = len +1
 
  end
 
  return len
 
end
 
 
designationMapTable = designationMapTable or false
 
function getDesignationMapTable()
 
    --doesn't currently support digs and plant gathering/ramp removal
 
    --tree cutting? Irrelevant I guess.
 
    if not designationMapTable then
 
    designationMapTable = {}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_DIG")] = {dig = df.tile_dig_designation.Default}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_STAIR_UPDOWN")] = {dig = df.tile_dig_designation.UpDownStair}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_CHANNEL")] = {dig = df.tile_dig_designation.Channel}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_RAMP")] = {dig = df.tile_dig_designation.Ramp}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_STAIR_DOWN")] = {dig = df.tile_dig_designation.DownStair}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_STAIR_UP")] = {dig = df.tile_dig_designation.UpStair}
 
        --smoothing, plant gathering, probably other designations that don't set dig to 2+ have issue of losing themselves over time (with save and reload?)
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_SMOOTH")] = {smooth = 1}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_ENGRAVE")] = {smooth = 2}
 
    --problematic designations: plant gathering, ramp removing, deconstructing, tree cutting, fortifying, carving tracks
 
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_TRACK")] = {carve_track_north =false, carve_track_south =false, carve_track_east=false, carve_track_west=false}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_DIG_REMOVE_STAIRS_RAMPS")] = {dig = df.tile_dig_designation.Default, targettype = "^[^C].*Ramp"}
 
    --matching non-constructed ramps
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_PLANTS")] = {dig = df.tile_dig_designation.Default, targettype = "Shrub"}
 
 
        --Following two need to check they're on construction
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_REMOVE_CONSTRUCTION")] = {dig = df.tile_dig_designation.Default, targettype = "Constructed"}
 
    designationMapTable[gui.getKeyDisplay("DESIGNATE_FORTIFY")] = {smooth = 1, targettype = "Constructed"}
 
 
    end
 
    return designationMapTable
 
end
 
 
local function getPriorities(map_block)
 
    for i,v in pairs(map_block.block_events) do
 
        if v._type == df.block_square_event_designation_priorityst then return v.priority end
 
    end
 
end
 
 
local function decodeDesignation(designationstring)
 
    --designationstring is something like d7mO
 
    --marked is in tileoccupancy[x][y].
 
    --designationtype is in designation[x][y].dig or .smooth
 
    --priority is in blockevents[#ofblock_square_event_designation_priorityst].priority[x][y]
 
    local designationtype = getDesignationMapTable()[designationstring:match('.')]
 
    if getLen(designationtype) == 4 then
 
        designationtype = {
 
            carve_track_north =designationstring:match('n') and true or false,
 
            carve_track_south =designationstring:match('s') and true or false,
 
            carve_track_east=designationstring:match('e') and true or false,
 
            carve_track_west=designationstring:match('w') and true or false}
 
    end
 
    local targettype = designationtype.targettype
 
    designationtype.targettype = nil
 
    local designationpriority = tonumber(designationstring:match('[%d|%,]+'))
 
    local ismarked = designationstring:match('m') and true or false
 
    local checkold = designationstring:match('O') and true or false
 
    return designationtype, designationpriority, ismarked, targettype, checkold
 
end
 
 
function isbetween(b,a,c)
 
    if a<=b and b<=c then return true end
 
    if a>=b and b>=c then return true end
 
end
 
 
local once = true
 
 
function isTileInArea(pos,area)
 
    if true then once = false
 
        --print(area, type(area),type(area)=="number",pos.x,pos.y,pos.z,df.global.window_z,(df.global.window_z+area)) --stops script cold for some reason
 
    end--]]
 
    if pos.x < 0 then return false end
 
    if not area then return true end
 
    --print("isbetween",(type(area)=="number") and isbetween(pos.z,df.global.window_z,df.global.window_z+area))
 
    --if type(area)=="number" and (pos.z==27) then print("pos is 27") else print ("pos is "..tostring(pos.z)) end
 
    if type(area)=="number" and isbetween(pos.z,df.global.window_z,(df.global.window_z+area)) then return true
 
    end
 
    if type(area) =="userdata" and area._type == df.burrow and dfhack.burrows.isAssignedTile(area,pos) then return true end
 
end
 
local area
 
    --Iterator for iterating through designations of a type in an area or everywhere.
 
function targetDesignations(designationstring, sarea)
 
    --returns designationIterator, state, key
 
    if sarea and type(sarea)=="string" then
 
        area = dfhack.burrows.findByName(sarea) or
 
                (sarea:find("Burrow %i") and df.burrow.find(tonumber(sarea:match("%i")))) or
 
                tonumber(sarea)
 
    end
 
    local dtype, dpriority, ismarked, targettype, checkold = decodeDesignation(designationstring)
 
    local function iterateBlocks(area)
 
        if not area or type(area)=="number" then
 
        for iB = 0, #df.global.world.map.map_blocks -1 do
 
            if(checkold or df.global.world.map.map_blocks[iB].flags.designated)
 
                and (not area or isbetween(df.global.world.map.map_blocks[iB].map_pos.z,df.global.window_z,df.global.window_z+area)) then
 
                coroutine.yield(df.global.world.map.map_blocks[iB])
 
            end
 
        end
 
        else
 
            for i,v in pairs(dfhack.burrows.listBlocks(area)) do
 
                coroutine.yield(v)
 
            end
 
        end
 
    end
 
    local blockroutine = coroutine.create(iterateBlocks)
 
 
    local function getNextBlock(area)
 
        local errorfree, value = coroutine.resume(blockroutine,area)
 
        if not errorfree then return nil end
 
        return value
 
    end
 
 
    local jobroutine,getNextJob
 
    local checkJobs = getJobbedDesignation()[designationstring:sub(0,1)]
 
    print(checkJobs, df.job_type[checkJobs])
 
    if checkJobs then
 
        local function iterateJobs(area)
 
            local job
 
            local IsOld, JobListItem = pcall(function() return df.global.world.job_list end)--TODO replace slow pcall
 
            if not IsOld then JobListItem=df.global.world.jobs.list end
 
            while(JobListItem.next) and ((os.clock()-starttime)<5) do
 
                job = JobListItem.item
 
                rcount = rcount +1
 
                if job and isTileInArea(job.pos,area) then
 
                    coroutine.yield(job)
 
                end
 
                JobListItem=JobListItem.next
 
            end
 
        end
 
 
        jobroutine = coroutine.create(iterateJobs)
 
 
        getNextJob = function(area)
 
            local errorfree, value = coroutine.resume(jobroutine, area)
 
            if not errorfree then return nil else return value end
 
        end
 
    end
 
 
    function blockChanged(tx,ty,tz)--TODO do I use dfhack.maps??
 
        local blockx,blocky,blockz
 
        if (tx%16) ~=blockx or (ty%16) ~=blocky or tz ~=blockz then
 
            blockx =tx%16
 
            blocky =ty%16
 
            blockz=tz
 
            return true
 
        end
 
    end
 
 
    local dtypel = getLen(dtype)
 
    local x,y,z,cblock, priorities
 
    local cy,cx,ct = 0,-1,0 --start for cx -1 so I can add before returning.
 
    cblock, curJob = getNextBlock(area), true
 
        --return #(.th designation) and it's x, y and z coordinates
 
    local function designationIterator(_,nthdesignation)
 
        nthdesignation = nthdesignation +1
 
        --TODO If area was burrow check only burrow tiles not burrow block tiles
 
        while cblock do
 
        priorities = getPriorities(cblock)
 
            while(cy<16) do
 
            while(cx<15) do
 
            cx = cx+1
 
                if not area or area and type(area)=="number" or (type(area) == "userdata" and area._type == df.burrow and dfhack.burrows.isAssignedBlockTile(area,cblock,cx,cy)) then
 
                if(cblock.occupancy[cx][cy].dig_marked == ismarked) then
 
                if((not dpriority) or priorities and priorities[cx][cy] == (dpriority*1000)) then
 
                ct = 0
 
                for key, value in pairs(dtype) do
 
                    if(dtypel == 1 and (cblock.designation[cx][cy][key] == value or checkOld and priorities and targettype and cblock.designation[cx][cy][key] == 0)) then
 
                        --in case of offloaded designations, designation is zero but priority/marked is kept.
 
                        --of course, neither of those are necessarily checked so this might need a TODO fix
 
                        --also what's the point of checkOld+targettype here if I check jobs anyway??
 
                        --checkold should be more like checkoldmarked, and priorities shouldn't matter
 
                        if not targettype or df.tiletype[cblock.tiletype[cx][cy]]:match(targettype) then
 
                            return nthdesignation, (cblock.map_pos.x+cx), (cblock.map_pos.y+cy), cblock.map_pos.z
 
                        end
 
                    elseif(dtypel == 4) and (cblock.occupancy[cx][cy][key] == value) then
 
                        ct = ct + 1
 
                        if(ct == 4) then return nthdesignation, (cblock.map_pos.x+cx), (cblock.map_pos.y+cy), cblock.map_pos.z end
 
                    end
 
                end
 
                end
 
                end
 
                end
 
            end
 
            cy = cy +1
 
            cx = -1
 
            end
 
 
        if cy == 16 then cy, cx = 0, -1 end
 
        cblock = getNextBlock(area)
 
        end
 
        --tempBlocks = nil
 
        --Things don't end here; less simple designations can get offloaded into joblist!
 
        if checkJobs then
 
            while curJob and ((os.clock()-starttime)<5) do
 
            curJob = getNextJob(area)-- must be before return, or it doesn't get the next one.
 
            if(curJob) then
 
            if dpriority and blockChanged(curJob.pos.x, curJob.pos.y, curJob.pos.z) then
 
                priorities = getPriorities(dfhack.maps.getTileBlock(curJob.pos.x, curJob.pos.y, curJob.pos.z))
 
            end
 
            jcount= jcount +1
 
 
            if checkJobs == "Smooth" and ( curJob.job_type == df.job_type.DetailFloor or curJob.job_type == df.job_type.DetailWall) or curJob.job_type == checkJobs then
 
                if ((not dpriority) or priorities and priorities[curJob.pos.x%16][curJob.pos.y%16] == (dpriority*1000)) then
 
                    return nthdesignation, curJob.pos.x, curJob.pos.y, curJob.pos.z
 
                end
 
            end
 
            end
 
 
            end
 
        end
 
    end
 
    return designationIterator, nil, 0
 
end
 
 
    --Iterator for for-loop for getting nr,x,y,z of next element in line
 
function amathline(desiredlength,width,length,height)
 
--returns lineiterator, state, curlength
 
    local width = width --masking with locals since going to modify them
 
    local length = length
 
    local height = height
 
    if not width or width==1 then width = 0 end --boxes of a,b and a,b,0 and a,b,1 are equivalent
 
    if not length or length==1 then length = 0 end
 
    if not height or height==1 then height = 0 end
 
    local xm = width<0 and -1 or 1 --used only for returning
 
    local ym = length<0 and -1 or 1
 
    local zm = height<0 and -1 or 1
 
    width = width<0 and -width or width
 
    length = length<0 and -length or length
 
    height = height<0 and -height or height
 
    local cx, cy, cz = 1,1,1 --first building is on 1,1,1
 
    --ok, so, for boxes to be coordinate-agnostic, each coordinate must be projected off a plane, which means taking into account both coordinates off that plane
 
    local wlmax = width>length and width or length
 
    local whmax = width>height and width or height
 
    local lhmax = length>height and length or height
 
    local cxy, cxz, cyz=1,1,1
 
    local function lineiterator(desiredlength, curlength)
 
        if curlength<desiredlength then
 
            curlength = curlength+1
 
            cxy = cy > cx and cy or cx
 
            cxz = cz > cx and cz or cx
 
            cyz = cy > cz and cy or cz
 
            --simultaneous assignment avoids off-by-1 errors, projecting off a plane avoids coordinate dependence
 
            cx, cy, cz = cx+ (width>=lhmax and 1 or  ((cx/cyz <= width/lhmax) and 1 or 0)),
 
                        cy+ (length>=whmax and 1 or ((cy/cxz <= length/whmax) and 1 or 0)),
 
                        cz+ (height>=wlmax and 1 or ((cz/cxy <= height/wlmax) and 1 or 0))
 
            return curlength, cx*xm, cy*ym, cz*zm
 
        end
 
    end
 
return lineiterator, desiredlength, 1 --first building is already in place
 
end
 
 
jobbedDesignations = jobbedDesignations or false
 
function getJobbedDesignation()--designation_key)
 
    if not jobbedDesignations then
 
        --accessible designations get offloaded into joblist, have to look for them there.
 
    jobbedDesignations = {}
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_DIG")] = df.job_type.Dig
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_STAIR_UPDOWN")] = df.job_type.CarveUpDownStaircase
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_CHANNEL")] = df.job_type.DigChannel
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_RAMP")] = df.job_type.CarveRamp
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_STAIR_DOWN")] = df.job_type.CarveDownwardStaircase
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_STAIR_UP")] = df.job_type.CarveUpwardStaircase
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_SMOOTH")] = "Smooth" --smooth and engrave are both either DetailFloor or DetailWall jobs
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_ENGRAVE")] = "Smooth" --"Engrave" can't be currently checked
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_DIG_REMOVE_STAIRS_RAMPS")] = df.job_type.RemoveStairs
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_PLANTS")] = df.job_type.GatherPlants
 
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_REMOVE_CONSTRUCTION")] = df.job_type.RemoveConstruction
 
    jobbedDesignations[gui.getKeyDisplay("DESIGNATE_FORTIFY")] = df.job_type.CarveFortification
 
 
    --jobbedDesignations[gui.getKeyDisplay("DESIGNATE_TRACK")] = df.job_type.CarveTrack --TODO check job.item_category 18-21 NSWE is saved
 
    end
 
    return jobbedDesignations
 
end
 
 
jobbedDesignationsInv = jobbedDesignationsInv or false
 
if not jobbedDesignationsInv then
 
    local dummy = copyall(getJobbedDesignation())
 
    dummy[gui.getKeyDisplay("DESIGNATE_SMOOTH")] = nil
 
    dummy[gui.getKeyDisplay("DESIGNATE_ENGRAVE")] = nil
 
    jobbedDesignationsInv = utils.invert(dummy)
 
    jobbedDesignationsInv[df.job_type.DetailFloor] = gui.getKeyDisplay("DESIGNATE_SMOOTH")
 
    jobbedDesignationsInv[df.job_type.DetailWall] = gui.getKeyDisplay("DESIGNATE_SMOOTH")
 
end
 
 
    --Iterator for iterating through designations of a type in an area or everywhere.
 
z = z or -999
 
 
function normalDesignations()
 
    --returns designationIterator, state, key
 
    local function iterateBlocks()
 
        for areax = 1, df.global.world.map.x_count, 16 do
 
            for areay = 1, df.global.world.map.y_count, 16 do
 
                coroutine.yield(getBlock(areax,areay,z))
 
            end
 
        end
 
    end
 
    local blockroutine = coroutine.create(iterateBlocks)
 
 
    local function getNextBlock()
 
        local errorfree, value = coroutine.resume(blockroutine)
 
        if not errorfree then return nil end
 
        return value
 
    end
 
 
    function blockChanged(tx,ty,tz)
 
        local blockx,blocky,blockz
 
        if (tx%16) ~=blockx or (ty%16) ~=blocky or tz ~=blockz then
 
            blockx =tx%16
 
            blocky =ty%16
 
            blockz=tz
 
            return true
 
        end
 
    end
 
 
    local x,y,z,cblock, priorities
 
    local cy,cx,ct = 0,-1,0 --start for cx -1 so I can add before returning.
 
 
    cblock, curJob = getNextBlock(), true
 
        --return #(.th designation) and it's x, y and z coordinates
 
    local ddig, dsmooth, dmarked, dpriority, dn, ds, de, dw
 
    local function designationIterator(_,nthdesignation)
 
        nthdesignation = nthdesignation +1
 
        while cblock do
 
        priorities = getPriorities(cblock)
 
            while(cy<16) do
 
            while(cx<15) do
 
            cx = cx+1
 
            if cblock.occupancy[cx][cy].building == 0 then --no point watching tiles with buildings as those can't have buildings placed on top anyway
 
                ddig=cblock.designation[cx][cy].dig
 
                dsmooth=cblock.designation[cx][cy].smooth
 
                dmarked = cblock.occupancy[cx][cy].dig_marked
 
                dpriority = priorities and priorities[cx][cy] or false
 
                dn=cblock.occupancy[cx][cy].carve_track_north
 
                ds=cblock.occupancy[cx][cy].carve_track_south
 
                de=cblock.occupancy[cx][cy].carve_track_east
 
                dw=cblock.occupancy[cx][cy].carve_track_west
 
                dtt = (ddig==df.tile_dig_designation.Default or dsmooth == 1) and cblock.tiletype[cx][cy] or 0
 
 
                if not (ddig == 0 and dsmooth == 0 --[=[ and dpriority == 0 --]=] and (not dn) and (not ds) and (not de) and (not dw)) then
 
                    return nthdesignation, {x=cblock.map_pos.x+cx, y=cblock.map_pos.y+cy, dig=ddig, smooth=dsmooth, marked=dmarked, priority=dpriority, n=dn, s=ds, e=de, w=dw, tt=dtt}
 
                end
 
            end
 
 
            end
 
            cy = cy +1
 
            cx = -1
 
            end
 
 
        if cy == 16 then cy, cx = 0, -1 end
 
        cblock = getNextBlock()
 
        end
 
    end
 
    return designationIterator, nil, 0
 
end
 
 
function jobDesignations()
 
    --returns designationIterator, state, key
 
    local curJob = true
 
        --return #(.th designation) and it's x, y and z coordinates
 
    local dn, ds, de, dw
 
    local job
 
    local IsOld, JobListItem = pcall(function() return df.global.world.job_list end)--TODO replace slow pcall
 
    if not IsOld then JobListItem=df.global.world.jobs.list end
 
    starttime=os.clock()
 
    local function designationIterator(_,nthdesignation)
 
        while JobListItem.next do --and ((os.clock()-starttime)<1) do
 
            curJob = JobListItem.item
 
            JobListItem = JobListItem.next
 
            if (curJob and curJob.pos.z == z) then
 
                if jobbedDesignationsInv[curJob.job_type] and select(2,getFlags(curJob.pos.x, curJob.pos.y, z)).building==0 then
 
                -- designation job on a tile without building
 
                --    priority can be still checked after building is placed
 
                    dn= curJob.job_type == df.job_type.CarveTrack and job.item_category[18]
 
                    ds= curJob.job_type == df.job_type.CarveTrack and job.item_category[19]
 
                    dw= curJob.job_type == df.job_type.CarveTrack and job.item_category[20]
 
                    de= curJob.job_type == df.job_type.CarveTrack and job.item_category[21]
 
                    --tiletype is necessary to tell apart smooth and carve - but that check can be done when there's a difference.
 
                    nthdesignation = nthdesignation +1
 
                    return nthdesignation, {x=curJob.pos.x, y=curJob.pos.y, letter = jobbedDesignationsInv[curJob.job_type], n=dn, s=ds, e=de, w=dw}
 
                end
 
            end
 
        end
 
    end
 
    return designationIterator, nil, 0
 
end
 
 
function makeDesignationTable(updatez)
 
    DesignationTable = updatez and DesignationTable or {}
 
    DesignationTable[z]={normal = {}, job = {} }
 
    for dnr, dtab in normalDesignations() do
 
        tin(DesignationTable[z].normal, dtab)
 
    end
 
 
    for dnr, jtab in jobDesignations() do
 
        tin(DesignationTable[z].job, jtab)
 
    end
 
end
 
 
 
function findSameZDiff()
 
    local diffTable = {}
 
    local dflag, oflag
 
    local letter, ddig, dsmooth, dmarked, dpriority, dn, ds, de, dw
 
    local designationString, digString, digSmooth
 
    for i, dtab in pairs(DesignationTable[z].normal) do
 
        dflag, oflag = getFlags(dtab.x, dtab.y, z)
 
        if oflag.building > 0 then    --building was placed where previously it wasn't.
 
            --how do I handle simultaneous smooth and dig? As two separate?
 
            if dtab.dig == df.tile_dig_designation.Default then
 
                for dletter, identity in pairs(getDesignationMapTable()) do
 
                    if identity.dig == dtab.dig and identity.targettype and df.tiletype[dtab.tt]:match(identity.targettype) then
 
                        digString=dletter
 
                    end
 
                end
 
                if not digString then
 
                    digString = gui.getKeyDisplay("DESIGNATE_DIG")
 
                end
 
            else
 
                for dletter, identity in pairs(getDesignationMapTable()) do
 
                    if dtab.dig > 0 and identity.dig == dtab.dig then
 
                        digString=dletter
 
                    end
 
                end
 
            end
 
 
            if dtab.smooth == 1 then
 
                for dletter, identity in pairs(getDesignationMapTable()) do
 
                    if identity.smooth == dtab.smooth and identity.targettype and df.tiletype[dtab.tt]:match(identity.targettype) then
 
                        digSmooth=dletter
 
                    end
 
                end
 
                if not digSmooth then
 
                    digSmooth = gui.getKeyDisplay("DESIGNATE_SMOOTH")
 
                end
 
            else
 
                for dletter, identity in pairs(getDesignationMapTable()) do
 
                    if dtab.smooth > 0 and identity.smooth == dtab.smooth then
 
                        digSmooth=dletter
 
                    end
 
                end
 
            end
 
            designationString = (dtab.marked and 'm' or '') .. (dtab.priority and dtab.priority/1000 or '') .. 'O'
 
            if digString then
 
                digString = digString .. designationString
 
                diffTable[digString] = true
 
                digString = nil
 
            end
 
            if digSmooth then
 
                digSmooth = digSmooth .. designationString
 
                diffTable[digSmooth] = true
 
                digSmooth = nil
 
            end
 
 
            DesignationTable[z].normal[i] = nil
 
        end
 
                --ddig=cblock.designation[cx][cy].dig --only digs are zeroed when floor is placed on top
 
                --dsmooth=cblock.designation[cx][cy].smooth
 
                --dmarked = cblock.occupancy[cx][cy].dig_marked
 
                --dpriority = priorities and priorities[cx][cy] or 0
 
                --dn=cblock.occupancy[cx][cy].carve_track_north
 
                --ds=cblock.occupancy[cx][cy].carve_track_south
 
                --de=cblock.occupancy[cx][cy].carve_track_east
 
                --dw=cblock.occupancy[cx][cy].carve_track_west
 
                --dtt = (ddig==df.tile_dig_designation.Default or dsmooth == 1) and cblock.tiletype[cx][cy] or 0
 
 
    end
 
 
    for i, jtab in pairs(DesignationTable[z].job) do
 
        dflag, oflag = getFlags(jtab.x, jtab.y, z)
 
        if oflag.building > 0 then    --building was placed where previously it wasn't.
 
            --designationString='j2mO'
 
            dpriority = getPriorities(getBlock(jtab.x, jtab.y, z))
 
            dpriority = dpriority and dpriority[jtab.x%16][jtab.y%16] or false
 
            designationString = jtab.letter .. (dpriority and dpriority/1000 or '') .. (oflag.dig_marked and 'm' or '' ) ..'O' -- always Old/job tiles
 
            --Also still doesn't match tracks properly
 
            diffTable[designationString] = true
 
            DesignationTable[z].job[i] = nil
 
        end
 
    end
 
 
    return diffTable
 
 
end
 
end
  
Line 612: Line 91:
 
     constructMultiZPowerState(false)
 
     constructMultiZPowerState(false)
 
     --first, remove old binds
 
     --first, remove old binds
    print(curheight .. " " .. curdepth)
 
 
     curheight = height+curheight
 
     curheight = height+curheight
 
     curdepth = depth+curdepth
 
     curdepth = depth+curdepth
Line 623: Line 101:
 
     constructMultiZPowerState(true)
 
     constructMultiZPowerState(true)
 
     --then add new bindings
 
     --then add new bindings
    print("p " .. curheight .. " " .. curdepth)
 
 
   end
 
   end
 
   local indipresent, indi = pcall(function() return dfhack.script_environment('gui/indicator_screen') end)
 
   local indipresent, indi = pcall(function() return dfhack.script_environment('gui/indicator_screen') end)
Line 629: Line 106:
  
 
   local changeHeight --defined below
 
   local changeHeight --defined below
 +
  local gui = require 'gui'
 
   local dlg = require 'gui.dialogs'
 
   local dlg = require 'gui.dialogs'
  z = df.global.window_z
 
  makeDesignationTable()
 
 
   function numberprompt (above, initialvalue)
 
   function numberprompt (above, initialvalue)
 
         local retvalue = tostring(initialvalue)
 
         local retvalue = tostring(initialvalue)
Line 692: Line 168:
 
     myrfunc()
 
     myrfunc()
 
   end
 
   end
 
+
   local function isInBuildType()  
+
   local function isInBuildType()
 
     return dfhack.gui.getFocusString(df.global.gview.view.child):find("dwarfmode/Build/Type")
 
     return dfhack.gui.getFocusString(df.global.gview.view.child):find("dwarfmode/Build/Type")
 
   end
 
   end
 
   local notincountdown = true
 
   local notincountdown = true
 
   local function multizonInput(self, keys)
 
   local function multizonInput(self, keys)
     oldInput(self, keys)--TODO adapt for new indi in 4303
+
     oldInput(self, keys)
    if z ~= df.global.window_z then
 
      z = df.global.window_z
 
      makeDesignationTable(true)
 
    end
 
 
     if (dfhack.gui.getFocusString(df.global.gview.view.child):find("dwarfmode/Build/Position/Construction")
 
     if (dfhack.gui.getFocusString(df.global.gview.view.child):find("dwarfmode/Build/Position/Construction")
 
     or (keys.SELECT and
 
     or (keys.SELECT and
Line 714: Line 186:
 
         dfhack.timeout(math.floor(2*df.global.enabler.fps), "frames", function()
 
         dfhack.timeout(math.floor(2*df.global.enabler.fps), "frames", function()
 
         texts[1].text = ""
 
         texts[1].text = ""
         if indi.indicator_screen_version >= 1.1 and self._native then
+
         if indi.indicator_screen_version >= 1.1 then
 
           self._native.parent.child = nil
 
           self._native.parent.child = nil
 
           repeatfunction(function()
 
           repeatfunction(function()
 
             indi.placeOnTop(self._native)
 
             indi.placeOnTop(self._native)
             notincountdown = true  
+
             notincountdown = true
 
             end, isInBuildType, 10)
 
             end, isInBuildType, 10)
 
         else self:dismiss() end
 
         else self:dismiss() end
Line 753: Line 225:
  
  
function getFlag(dfvalue, key)
+
function getFlag(object, flag)
     -- Utility function for safely requesting info from df data
+
     -- Utility function for safely requesting info from userdata
     if not dfvalue or not key then return nil end --pairs crash prevention
+
     -- Returns nil if the object doesn't have flag attribute, else returns it's value
    flagtypetable = flagtypetable or {} --memoization so it doesn't iterate through the dfvalue if we've already checked that type of value for given flag
+
     -- Because well, ordinarily, {}[flag] returns nil.
     if flagtypetable[dfvalue._type] and flagtypetable[dfvalue._type][key] then return dfvalue[key] end
+
     -- However, if object is unit - or some other type, it may instead throw an error
     if flagtypetable[dfvalue._type] and flagtypetable[dfvalue._type][key]==false then return nil end
+
    local a = {}
     if not flagtypetable[dfvalue._type] then flagtypetable[dfvalue._type] = {} end
+
     if not object or not flag then return nil end
     for akey, avalue in pairs(dfvalue) do
+
        --Crash is still possible for attempting to pairs a nil
         if akey == key then
+
     for index, value in pairs(object) do
            flagtypetable[dfvalue._type][key] = true
+
         a[index] = value
            return dfvalue[akey]
 
        end
 
 
     end
 
     end
     flagtypetable[dfvalue._type][key] = false
+
     local returnvalue = a[flag]
 +
    a = nil --lua automatically garbage cleans tables without variable that links to them.
 +
    return returnvalue
 
end
 
end
  
Line 792: Line 264:
 
local zpositive = tonumber(args[1]) -- 0 0 should equal nothing being done
 
local zpositive = tonumber(args[1]) -- 0 0 should equal nothing being done
 
local znegative = tonumber(args[2])
 
local znegative = tonumber(args[2])
local zDiff = findSameZDiff()
 
local difflen = getLen(zDiff)
 
  
if zpositive > 0 or znegative > 0 or difflen > 0 then
+
 
 +
if zpositive > 0 or znegative > 0 then
  
 
local buildings = require('dfhack.buildings')
 
local buildings = require('dfhack.buildings')
Line 812: Line 283:
 
local tostring2 = tostring
 
local tostring2 = tostring
 
local tadd = table.insert    --tadd is less missleading than tin or tins
 
local tadd = table.insert    --tadd is less missleading than tin or tins
function copy1building(lbd, xoffset, yoffset, zoffset)
+
function copy1building(lbd, zoffset)
 
     bd = {}
 
     bd = {}
     bd.x = lbd.x1+xoffset
+
     bd.x = lbd.x1
 
     bd.width = 1+lbd.x2-lbd.x1
 
     bd.width = 1+lbd.x2-lbd.x1
 
     bd.height = 1+lbd.y2-lbd.y1
 
     bd.height = 1+lbd.y2-lbd.y1
     bd.y = lbd.y1+yoffset
+
     bd.y = lbd.y1
 
     bd.z = lbd.z+zoffset
 
     bd.z = lbd.z+zoffset
  
Line 831: Line 302:
 
         or (bd.type == df.building_type.Trap and bd.subtype == 4 )) then -- All traps other than weapon trap
 
         or (bd.type == df.building_type.Trap and bd.subtype == 4 )) then -- All traps other than weapon trap
 
         argumenttable = {material = {mat_type = lbd.mat_type, mat_index = lbd.mat_index,}}
 
         argumenttable = {material = {mat_type = lbd.mat_type, mat_index = lbd.mat_index,}}
         if #lbd.jobs[0].items>0 then
+
         if getFlag(lbd.jobs[0].items, 0) then
 
           argumenttable.material.item_type =
 
           argumenttable.material.item_type =
 
             df.item_type[tostring2(lbd.jobs[0].items[0].item):gsub("st:.*",""):gsub("<item_",""):upper()]
 
             df.item_type[tostring2(lbd.jobs[0].items[0].item):gsub("st:.*",""):gsub("<item_",""):upper()]
Line 980: Line 451:
 
     if (getFlag(createdbuilding,"is_vertical") or getFlag(createdbuilding,"direction") )
 
     if (getFlag(createdbuilding,"is_vertical") or getFlag(createdbuilding,"direction") )
 
     and bd.type ~= df.building_type.Bridge then --bridges are already perfect in x and y
 
     and bd.type ~= df.building_type.Bridge then --bridges are already perfect in x and y
         createdbuilding.x1 = lbd.x1+xoffset
+
         createdbuilding.x1 = lbd.x1
         createdbuilding.y1 = lbd.y1+yoffset
+
         createdbuilding.y1 = lbd.y1
         createdbuilding.x2 = lbd.x2+xoffset
+
         createdbuilding.x2 = lbd.x2
         createdbuilding.y2 = lbd.y2+yoffset
+
         createdbuilding.y2 = lbd.y2
 
     end
 
     end
     createdbuilding.centerx = lbd.centerx+xoffset
+
     createdbuilding.centerx = lbd.centerx
     createdbuilding.centery = lbd.centery+yoffset
+
     createdbuilding.centery = lbd.centery
 
     --constructbuilding tends to round center up where df rounds down.
 
     --constructbuilding tends to round center up where df rounds down.
 
     if flippedPumps % 2 ~= 0 and bd.type == df.building_type.ScrewPump then
 
     if flippedPumps % 2 ~= 0 and bd.type == df.building_type.ScrewPump then
 
       --screw pump direction was swapped, so it'd center tile has to be swapped as well
 
       --screw pump direction was swapped, so it'd center tile has to be swapped as well
       --otherwise dwarf tries to build it on impassable tile.  
+
       --otherwise dwarf tries to build it on impassable tile.
 
     if createdbuilding.direction % 2 == 0 then --northsouth
 
     if createdbuilding.direction % 2 == 0 then --northsouth
 
       createdbuilding.centery = createdbuilding.centery == createdbuilding.y1 and createdbuilding.y2 or createdbuilding.y1
 
       createdbuilding.centery = createdbuilding.centery == createdbuilding.y1 and createdbuilding.y2 or createdbuilding.y1
Line 1,002: Line 473:
 
local lenb = #df.global.world.buildings.all --changes during usage so must save beforehand
 
local lenb = #df.global.world.buildings.all --changes during usage so must save beforehand
 
local w,h
 
local w,h
--[[
 
for curlength, x, y,z in a_line(17,1,-17,1) do
 
    copy1building(df.global.world.buildings.all[lenb-1], x-1, y, z-1)
 
end
 
--]]
 
 
 
if getBuildingTypeIndex(tostring(df.global.world.buildings.all[lenb-1])) ~= 34 then
 
if getBuildingTypeIndex(tostring(df.global.world.buildings.all[lenb-1])) ~= 34 then
 
   --not construction
 
   --not construction
Line 1,015: Line 480:
 
   h = df.global.world.building_height
 
   h = df.global.world.building_height
 
end
 
end
  local xoff = 0
 
  local yoff = 0
 
 
  local nr = 0
 
if difflen > 0 then 
 
  local hdif = zpositive-znegative
 
  if zpositive > 0 and znegative > 0 then
 
    hdif = zpositive+znegative
 
    df.global.window_z = df.global.window_z - znegative
 
  end
 
 
 
  for dstring, _ in pairs(zDiff) do --typically 1 member
 
    for curlength, x, y,z in targetDesignations(dstring, tostring(hdif)) do --only current z for now, could use zpositive or znegative to do on other zs
 
      local tbld = df.global.world.buildings.all[lenb-1-curlength%w*h]
 
      copy1building(tbld, x-tbld.x1, y-tbld.y1, z-tbld.z)
 
      nr = nr + 1
 
    end
 
  end
 
 
 
  if zpositive > 0 and znegative > 0 then
 
    df.global.window_z = df.global.window_z + znegative
 
  end
 
 
 
elseif zpositive ~= 0 or znegative ~= 0 then
 
 
   for i = 1, w*h do
 
   for i = 1, w*h do
 
   if zpositive > 0 then
 
   if zpositive > 0 then
 
     for zoff = 1, zpositive do
 
     for zoff = 1, zpositive do
       copy1building(df.global.world.buildings.all[lenb-i], xoff, yoff, zoff)
+
       copy1building(df.global.world.buildings.all[lenb-i],zoff)
      nr = nr +1
 
 
     end
 
     end
 
   end
 
   end
 
   if znegative > 0 then
 
   if znegative > 0 then
 
     for zoff = -1, -znegative, -1 do
 
     for zoff = -1, -znegative, -1 do
       copy1building(df.global.world.buildings.all[lenb-i], xoff, yoff, zoff)
+
       copy1building(df.global.world.buildings.all[lenb-i],zoff)
      nr = nr +1
 
 
     end
 
     end
 
   end
 
   end
 
   end
 
   end
end
+
 
if (nr > 0) then print("Placed " .. nr .. " buildings.") end
 
 
 
end
 
end
 
end
 
end
 
</source>
 
</source>

Please note that all contributions to Dwarf Fortress Wiki are considered to be released under the GFDL & MIT (see Dwarf Fortress Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following CAPTCHA:

Cancel Editing help (opens in new window)

This page is a member of 1 hidden category: