Bay 12 Games Forum

Please login or register.

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

Author Topic: AutoFort  (Read 3945 times)

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: AutoFort
« Reply #15 on: July 13, 2020, 04:16:26 pm »

Can DFHack read the terrain somehow, and give me the map as a csv or something?

It's easy enough to create a script that reads the terrain. I'm not sure about writing to files. Some plugins have config files, so I assume it must be possible.

Edit: Looks like it's possible to write to files, too.

I guess I can write the script. What kind of info do you want outputted? Just the tile shape and material? Presence of water and lava? Maybe just a small set of symbols that gives just enough info to know where to build stuff.
« Last Edit: July 16, 2020, 05:55:47 am by Bumber »
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

teatime

  • Bay Watcher
    • View Profile
Re: AutoFort
« Reply #16 on: July 16, 2020, 06:04:49 pm »

Hey Bumber, thanks a lot! Yeah, that sounds like the list -
  • Tile shape ( I'm assuming this refers to wall / floor / ramp / none)
  • material
  • presence of water/lava

That should be sufficient to characterise the spaces and plan the room placements; and would save me quite a bit of bother ;D
Unrelated to this project: You have far greater knowledge of what's possible in terms of integrating with Dwarf Fortress than I do; I like the idea of a fort that is accessible only via the underground; just out of curiosity, could you say off the top of your head whether embarking inside the cavern layer with the surface obscured is in the realm of possibility?


Note to self:
the set of tiles that touches the surface
the set of tiles that touches the cave
perhaps something similar to the room characterisation for flat surfaces
calculating pathing to determine what constitutes inside or outside
the set of all tiles that can path to water
the set of all damp tiles
a personality trait that determines building up to enlarge flattery, vs digging away unevenness (plateaus are the highest form of flattery)
a fort that is spawned in the hfs layer
the set of all aquafer tiles?
the set of all tiles on the map boundary that can enter the map

Logged

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: AutoFort
« Reply #17 on: July 19, 2020, 05:16:58 pm »

Hey Bumber, thanks a lot! Yeah, that sounds like the list -
  • Tile shape ( I'm assuming this refers to wall / floor / ramp / none)
  • material
  • presence of water/lava

That should be sufficient to characterise the spaces and plan the room placements; and would save me quite a bit of bother ;D
Okay, I did this, and for a 3x3 embark I ended up with a 42 MB file. Notepad++ struggled to view it. The three fields were separated by commas. A semicolon represented the end of a tile row, and a newline represented a new z-level. Using a single newline for each row and an extra one per z-level resulted in better performance in Notepad++ but over 19,000 lines.

I think it would be much more manageable if we limited it to 1-2 characters per tile. 'm' for magma, 'w' for water. If there's no liquid in the tile then:
Code: [Select]
e = empty space
p = eerie glowing pit
sf = soil floor
sr = soil ramp
sw = soil wall
sa = soil aquifer wall
bf = brook floor
rw = rock wall
ow = ore wall
aw = adamantine wall
hw = slade (HFS) wall
xw = SMR wall
iw = ice wall
tw = tree trunk
And so on.

Unrelated to this project: You have far greater knowledge of what's possible in terms of integrating with Dwarf Fortress than I do; I like the idea of a fort that is accessible only via the underground; just out of curiosity, could you say off the top of your head whether embarking inside the cavern layer with the surface obscured is in the realm of possibility?

There's an existing script called deep-embark that seems to do that. If it doesn't automatically unreveal the surface, you can use the revflood command.
« Last Edit: July 19, 2020, 06:41:11 pm by Bumber »
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

teatime

  • Bay Watcher
    • View Profile
Re: AutoFort
« Reply #18 on: July 21, 2020, 02:04:31 pm »

While a 42bm text file sounds bad, a program using 42mb of memory doesn't sound bad at all; I'm pretty sure I can stream that file into memory, at which point I'm in business. Using 2 characters would seem to mean that all submerged tiles are taken to be exactly rectangular, and that could have implictations for feature extraction and identifying accessible water sources. I'd be happy faffing about with it it its current raw and verbose form for now, I intend to stream it all into memory anyway, so long as all the info is there the verbosity isn't that imporatant. I have a minor task to complete before I can move on to the map (generating a room is greater than O(w^3h^3).. this needs to be addressed)

Modelling absolutely everything on my side might be a bit of a pain in the ass, unless I do it by reading DF's config files... make that fastidious and detailed design work for me; and perhaps even make it mod agnostic. Sweet Jesus, the wormcan!
Logged

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: AutoFort
« Reply #19 on: July 21, 2020, 06:02:13 pm »

Okay, here's the script:
Code: (fort_csv.lua) [Select]
--Export fort tiles as .csv
--By Bumber
--@module = true
local help = [====[

fort_csv
=============
Export the fort's tiles as a .csv file.
Format is: shape,material,fluid,shape,material,fluid, ...
";\n" represents next y-coordinate. "\n\n" represents next z-level. Empty fields represent non-existent map block.
By default, export all z-levels (starting from top.) Use ``level`` argument to specify a z-level.
Use ``path`` to save the .csv to a custom location. Use ``dfpath`` to save to a custom location relative to DF folder.

Examples:
fort_csv -path "C:\\Dwarf\ Fortress"
fort_csv -level 60 -dfpath "data"

]====]

local utils = require "utils"

function gather_block_row(y_coord, z_level) --insert data for a row of map blocks into table export_strings
    for block_x=0, x_max do
        local mapblock = dfhack.maps.getTileBlock(block_x*16, y_coord, z_level)
        if mapblock == nil then
            --print("Map block at "..tostring(block_x*16)..", "..y_coord..", "..z_level.." does not exist!")
            local temp = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
            for y_offset=0,15 do
                table.insert(export_strings[y_offset], temp)
                if block_x == x_max then
                    table.insert(export_strings[y_offset], ";\n")
                else
                    table.insert(export_strings[y_offset], ",")
                end
            end
        else
            local tt = mapblock.tiletype
            local des = mapblock.designation
            for y_offset=0,15 do
                for x_offset=0,15 do
                    local temp = df.tiletype.attrs[tt[x_offset][y_offset]]
                    table.insert(export_strings[y_offset], tostring(df.tiletype_shape[temp.shape])..",")
                    table.insert(export_strings[y_offset], tostring(df.tiletype_material[temp.material]))
                    if temp.material == df.tiletype_material.FEATURE then
                        if des[x_offset][y_offset].feature_global then
                            table.insert(export_strings[y_offset],":SLADE")
                        elseif des[x_offset][y_offset].feature_local then
                            table.insert(export_strings[y_offset],":ADAMANTINE")
                        end
                    end
                    temp = des[x_offset][y_offset]
                    if temp.flow_size > 0 then
                        if temp.liquid_type then
                            table.insert(export_strings[y_offset], ",MAGMA")
                        else
                            table.insert(export_strings[y_offset], ",WATER")
                        end
                    elseif temp.water_table then
                        table.insert(export_strings[y_offset], ",AQUIFER")
                    else
                        table.insert(export_strings[y_offset], ",NONE")
                    end
                    if x_offset == 15 and block_x == x_max then
                        table.insert(export_strings[y_offset], ";\n")
                    else
                        table.insert(export_strings[y_offset], ",")
                    end
                end
            end
        end
    end
end

function export_z(z_level)
    local export_strings = {} --contains data for 16 tile rows at a time
    for block_y=0, y_max do
        for y_offset=0,15 do
            export_strings[y_offset] = {}
        end
        gather_block_row(block_y*16, z_level)
        for y_offset=0,15 do
            csv_file:write(table.concat(export_strings[y_offset]))
        end
    end
end

function export_all()
    for z_level=z_max, 0, -1 do
        export_z(z_level)
        csv_file:write("\n")
    end
end

function main(...)
    local validArgs = utils.invert({
        "help",
        "level",
        "path",
        "dfpath"
    })
    local args = utils.processArgs({...}, validArgs)
   
    if args.help then
        print(help)
        return
    end
   
    if not dfhack.isMapLoaded() then
        qerror("Error: Map not loaded!")
    end
   
    x_max, y_max, z_max = dfhack.maps.getSize()
    print("Map size (blocks): "..x_max..", "..y_max..", "..z_max)
    x_max, y_max, z_max = x_max-1, y_max-1, z_max-1 --adjust to start at index 0 and end at n-1
   
    csv_file = nil
    file_dir = dfhack.getDFPath().."\\fort_csv.csv"
    if args.path then
        if args.dfpath then
            qerror("Invalid usage: Cannot use argument \"path\" with \"dfpath\"!")
        end
        file_dir = args.path.."\\fort_csv.csv"
    elseif args.dfpath then
        file_dir = dfhack.getDFPath().."\\"..args.dfpath.."\\fort_csv.csv"
    end
    print("Writing to \""..file_dir.."\"")
    csv_file = io.open(file_dir, "w")
    if csv_file == nil then
        qerror("Error: Failed to open \""..file_dir.."\" for writing!")
    end
   
    if args.level then
        local z_level = tonumber(args.level)
        if z_level == nil then
            csv_file:close()
            qerror("Error: Level must be a number!")
        end
        z_level = math.floor(z_level)
        if z_level >= 0 and z_level <= z_max then
            print("Please wait...")
            export_z(z_level)
        else
            csv_file:close()
            qerror("Error: Z-level "..z_level.." out of bounds!")
        end
    else
        print("Please wait...")
        export_all()
    end
   
    csv_file:flush()
    csv_file:close()
    print("Export complete!")
end

if not dfhack_flags.module then
    main(...)
end

Save it as "fort_csv.lua" in <df-folder>\hack\scripts

If you see "MAGMA" as a material, that's SMR. See: https://github.com/DFHack/df-structures/blob/master/df.tile-types.xml

It doesn't differentiate slade from adamantine yet (both are FEATURE,) nor identify aquifers.
Edit: Script now identifies aquifers (as AQUIFER in the liquid field) and differentiates FEATURE:ADAMANTINE versus FEATURE:SLADE for material.
« Last Edit: August 22, 2020, 04:02:15 am by Bumber »
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

teatime

  • Bay Watcher
    • View Profile
Re: AutoFort
« Reply #20 on: July 24, 2020, 04:07:58 pm »

Thanks man, looking forward to playing with it! The map analysis is another "exciting" milestone in the future for me; so I'm trying to get some less exciting things out of the way before I treat myself with that (house keeping, optimisation, etc). The new job is taking up practically all my time during the week at the moment, so it might be some time in the future before this is actually usefully used... I just wanted to say the explicitly in the event you begin to feel unappreciated in a few weeks time ^.^ The speed of the project has decreased, but the drive is stilll there.

I am excite!
Logged
Pages: 1 [2]