Skip to content
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Template for new versions:

## Misc Improvements

- `gui/export-world-map`: export of bridge and road materials and more precise bridge coordinates

## Removed

# 53.16-r2
Expand Down
1 change: 0 additions & 1 deletion gui/export-world-map.lua
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ local SELECTED_ICON = dfhack.pen.parse{ch=string.char(251), fg=COLOR_LIGHTGREEN}
local DISABLED_ICON = dfhack.pen.parse{ch='x', fg=COLOR_RED}

function ExportMap:getChoices()
print("getChoices")
local choices = {}
for _, export in ipairs(exports) do
table.insert(choices, {
Expand Down
94 changes: 72 additions & 22 deletions internal/export-world-map/export-roads.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,93 @@
local json = require('json')
local util = reqscript('internal/export-world-map/util')

local function getConstructionAndGeometryType(construction)
if df.world_construction_roadst:is_instance(construction) then
local constructions = df.global.world.world_data.constructions

local function getConstructionAndGeometryType(construction, bridge_squares_by_id)
if construction:getType() == df.world_construction_type.ROAD then
local square = construction.square_obj[0] -- df populates square_obj for roads and tunnels (only)
local subtype = ""
if df.item_type[construction.square_obj[0]["item_type"]] == "BLOCKS" then
local material = ""

if df.item_type[square.item_type] == "BLOCKS" then
subtype = "paved"
else
material = dfhack.matinfo.decode(square):toString()
elseif df.item_type[square.item_type] == "NONE" then
subtype = "dirt"
end
return "road", "LineString", subtype
elseif df.world_construction_bridgest:is_instance(construction) then
return "bridge", "Point", ""
elseif df.world_construction_tunnelst:is_instance(construction) then
return "tunnel", "LineString", ""

return "road", "LineString", subtype, material
elseif construction:getType() == df.world_construction_type.BRIDGE then
local square = bridge_squares_by_id[construction.id] -- df does NOT populate square_obj for bridges
local subtype = ""
local material = ""

if df.item_type[square.item_type] == "WOOD" then
subtype = "wooden"
Comment thread
Nekkowe marked this conversation as resolved.
material = dfhack.matinfo.decode(square):toString()
elseif df.item_type[square.item_type] == "BLOCKS" then
subtype = "stone"
material = dfhack.matinfo.decode(square):toString()
end

return "bridge", "Point", subtype, material
elseif construction:getType() == df.world_construction_type.TUNNEL then
-- df assigns world construction squares to tunnels like it does to roads,
-- but tunnel squares have nothing besides positional data: no material info, no nothing.
return "tunnel", "LineString", "", ""
else
qerror("unknown construction type")
end
end

local function listBridgeSquaresById()
local squares = {}

local tile_array_width = constructions.width
local tile_array_height = constructions.height

for i = 0, (tile_array_width - 1) do
for j = 0, (tile_array_height - 1) do
for _, square in ipairs(constructions.map[i]:_displace(j).square) do
if square:getType() == df.world_construction_square_type.BRIDGE then
squares[square.construction_id] = square
end
end
end
end

return squares
end

local function gatherFeatures()
local features = {}
for _, construction in ipairs(df.global.world.world_data.constructions.list) do
local type, geometry_type, subtype = getConstructionAndGeometryType(construction)

local bridge_squares_by_id = listBridgeSquaresById()

for _, construction in ipairs(constructions.list) do
local type, geometry_type, subtype, material = getConstructionAndGeometryType(construction, bridge_squares_by_id)

local coordinates
if geometry_type == "Point" then
-- only world tile - not sure where to get region tile coordinates from
-- perhaps it gets them from neighbouring roads?
-- dwarf fortress doesn't populate square_obj for bridges, only for roads and tunnels.
-- but all world tiles are listed in df.global.world.world_data.constructions.map (not list),
-- a 2D array that has to be iterated over with _displace()
local region_x = construction.square_pos.y[0]
local region_y = construction.square_pos.y[0]
local midmap_x = bridge_squares_by_id[construction.id].embark_x[0]
local midmap_y = bridge_squares_by_id[construction.id].embark_y[0]

coordinates = {
construction.square_pos["x"][0]*768,
-(construction.square_pos["y"][0]*768)
region_x * 768 + midmap_x * 48 + 24,
-(region_y * 768 + midmap_y * 48 + 24)
}
else
coordinates = {}
for _,square_obj in ipairs(construction.square_obj) do
for i=0,#square_obj.embark_x-1 do
for _, square_obj in ipairs(construction.square_obj) do
for i = 0, #square_obj.embark_x - 1 do
Comment thread
Nekkowe marked this conversation as resolved.
table.insert(coordinates, {
square_obj.region_pos["x"]*768+square_obj.embark_x[i]*48+24,
-(square_obj.region_pos["y"]*768+square_obj.embark_y[i]*48+24)
square_obj.region_pos.x * 768 + square_obj.embark_x[i] * 48 + 24,
-(square_obj.region_pos.y * 768 + square_obj.embark_y[i] * 48 + 24)
})
end
end
Expand All @@ -49,10 +98,11 @@ local function gatherFeatures()
type = "Feature",
properties = {
id = construction.id,
name_df = dfhack.df2utf(dfhack.translation.translateName(construction["name"],false)),
name_en = dfhack.df2utf(dfhack.translation.translateName(construction["name"],true)),
name_df = dfhack.df2utf(dfhack.translation.translateName(construction.name, false)),
name_en = dfhack.df2utf(dfhack.translation.translateName(construction.name, true)),
construction_type = type,
construction_subtype = subtype,
construction_material = material,
},
geometry = {
type = geometry_type,
Expand All @@ -68,7 +118,7 @@ function export(by_world, by_date)
return function()
json.encode_file(
{ type = "FeatureCollection", features = gatherFeatures() },
util.getOutputFolder(by_world, by_date).."roads.geojson"
util.getOutputFolder(by_world, by_date) .. "roads.geojson"
)
end
end
Loading