Skip to content

Instantly share code, notes, and snippets.

@therahedwig
Last active March 7, 2020 16:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save therahedwig/20c1686de873c59774a9d789389569a5 to your computer and use it in GitHub Desktop.
Save therahedwig/20c1686de873c59774a9d789389569a5 to your computer and use it in GitHub Desktop.
world-map-to-svg
-- Generate an SVG worldmap for the active save.
--[====[
world-map-to-svg
================
This generates an interactive SVG for the current world,
using css and svg shape titles and svg views to create some
minor interactivity.
Will save as region-world-name-svg-map.svg in the DF play folder.
Open the resulting file in chrome or firefox. Hover over elements
to learn their name. Click on glowing elements to have them fill
the viewport. On the left hand there is a list of landmass names.
On the right hand a list of civilization names with the colors
pulled from DF. The names on both these lists can be clicked to
have their regions (and in the case of civs, claims) fill the viewport.
Files can be opened in inkscape. Most of the colors are stored as
Inkscape swatches, so you can 'easily' change them. The bigger issue
is that Inkscape might have trouble with the amount of objects in a big
df world.
]====]
function checkIfCoordindateInGrid(point_x, point_y, grid_x, grid_y)
for point, x in pairs (grid_x) do
if point_x == x then
if point_y == grid_y[point] then
return true
end
end
end
return false
end
function comparePoints(p1, p2)
return p1.x == p2.x and p1.y == p2.y
end
function grid_to_border(grid)
local linesList = {}
local sortedLines = {}
local coordinateList = {}
local subpaths = {}
for point, x in pairs (grid.x) do
print(point.." / "..#grid.x)
y = grid.y[point]
topLeft = {"x", "y"}
topLeft.x = x
topLeft.y = y
topRight = {"x", "y"}
topRight.x = x+1
topRight.y = y
bottomLeft = {"x", "y"}
bottomLeft.x = x
bottomLeft.y = y+1
bottomRight = {"x", "y"}
bottomRight.x = x+1
bottomRight.y = y+1
--print(x, y)
if checkIfCoordindateInGrid(x, y-1, grid.x, grid.y) == false then
local line = {"p1", "p2"}
line.p1 = topLeft
line.p2 = topRight
--print("top| "..line.p1.x..", "..line.p1.y..", "..line.p2.x..", "..line.p2.y)
table.insert(linesList, line)
end
if checkIfCoordindateInGrid(x+1, y, grid.x, grid.y) == false then
local line = {"p1", "p2"}
line.p1 = topRight
line.p2 = bottomRight
--print("rigt| "..line.p1.x..", "..line.p1.y..", "..line.p2.x..", "..line.p2.y)
table.insert(linesList, line)
end
if checkIfCoordindateInGrid(x, y+1, grid.x, grid.y) == false then
local line = {"p1", "p2"}
line.p1 = bottomRight
line.p2 = bottomLeft
--print("bttom| "..line.p1.x..", "..line.p1.y..", "..line.p2.x..", "..line.p2.y)
table.insert(linesList, line)
end
if checkIfCoordindateInGrid(x-1, y, grid.x, grid.y) == false then
local line = {"p1", "p2"}
line.p1 = bottomLeft
line.p2 = topLeft
--print("left| "..line.p1.x..", "..line.p1.y..", "..line.p2.x..", "..line.p2.y)
table.insert(linesList, line)
end
end
print("Total border lines "..#linesList)
local sortedLines = {}
local debugstring = ""
for no, line_n in pairs(linesList) do
local sorted = false
for i, l in pairs(sortedLines) do
if comparePoints(line_n.p1, l.p2) then
table.insert(sortedLines, i+1, line_n)
sorted = true
break
end
end
if sorted == false then
table.insert(sortedLines, line_n)
end
debugstring = debugstring.."| "..line_n.p1.x..", "..line_n.p1.y..", "..line_n.p2.x..", "..line_n.p2.y
end
--print("DEBUG "..debugstring)
coordinateList = {}
while(#sortedLines > 0) do
if (#coordinateList==0) then
table.insert(coordinateList, sortedLines[1].p1)
table.insert(coordinateList, sortedLines[1].p2)
table.remove(sortedLines, 1)
else
local lastPoint = coordinateList[#coordinateList]
for n, line_j in pairs(sortedLines) do
if comparePoints(lastPoint, line_j.p1) then
if lastPoint.x+1 == line_j.p2.x then
table.insert(coordinateList, line_j.p2)
table.remove(sortedLines, n)
break
elseif lastPoint.y+1 == line_j.p2.y then
table.insert(coordinateList, line_j.p2)
table.remove(sortedLines, n)
break
elseif lastPoint.x-1 == line_j.p2.x then
table.insert(coordinateList, line_j.p2)
table.remove(sortedLines, n)
break
elseif lastPoint.y-1 == line_j.p2.y then
table.insert(coordinateList, line_j.p2)
table.remove(sortedLines, n)
break
end
elseif comparePoints(lastPoint, line_j.p2) then
if lastPoint.x+1 == line_j.p1.x then
table.insert(coordinateList, line_j.p1)
table.remove(sortedLines, n)
break
elseif lastPoint.y+1 == line_j.p1.y then
table.insert(coordinateList, line_j.p1)
table.remove(sortedLines, n)
break
elseif lastPoint.x-1 == line_j.p1.x then
table.insert(coordinateList, line_j.p1)
table.remove(sortedLines, n)
break
elseif lastPoint.y-1 == line_j.p1.y then
table.insert(coordinateList, line_j.p1)
table.remove(sortedLines, n)
break
end
end
end
if comparePoints(lastPoint, coordinateList[#coordinateList]) then
table.insert(subpaths, coordinateList)
coordinateList = {}
end
end
print(#sortedLines)
end
if #coordinateList > 0 then
table.insert(subpaths, coordinateList)
end
print("total subpaths", #subpaths)
return subpaths
end
function remove_spaces(name)
if name ~= "" then
--[[
spaces = string.find(name, ' ', 1, true)
while spaces ~= nil do
name = string.sub(name,1, spaces-1)..'-'..string.sub(name,spaces+1)
spaces = string.find(name, ' ', 1, true)
end
]]
name = string.gsub(name," ","-")
else
name = "unnamed"
end
return name
end
function write_double(double)
if type(double) ~= "number" then
print("Not a number!", type(double), double)
return ""
end
return string.gsub(""..double,",",".")
end
function write_color_swatch(id, fillString, listOfStrings)
listOfStrings[#listOfStrings+1] = "<linearGradient osb:paint=\"solid\" id=\""..id.."\">\n"
listOfStrings[#listOfStrings+1] = "\t<stop style=\"stop-color:"..fillString..";stop-opacity:1;\" />\n"
listOfStrings[#listOfStrings+1] = "</linearGradient>\n"
return listOfStrings
end
function write_rect(id, x, y, width, height, styleString, strings)
local rectangle = {}
table.insert(rectangle, "<rect")
if id ~= "" and type(id) == "string" then
table.insert(rectangle, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if type(x) == "number" then
table.insert(rectangle, string.format("x=\"%s\"", write_double(x)))
end
if type(y) == "number" then
table.insert(rectangle, string.format("y=\"%s\"", write_double(y)))
end
if type(width) == "number" then
table.insert(rectangle, string.format("width=\"%s\"", write_double(width)))
end
if type(height) == "number" then
table.insert(rectangle, string.format("height=\"%s\"", write_double(height)))
end
if styleString ~= "" and type(styleString) == "string" then
table.insert(rectangle, string.format("style=\"%s\"", styleString))
end
table.insert(rectangle, "/>")
table.insert(strings, table.concat(rectangle, " "))
end
function write_text(id, class, x, y, styleString, textString, strings)
local text = {}
table.insert(text, "<text")
if id ~= "" and type(id) == "string" then
table.insert(text, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if class ~= "" and type(class) == "string" then
table.insert(text, string.format("class=\"%s\"", class))
end
if type(x) == "number" then
table.insert(text, string.format("x=\"%s\"", write_double(x)))
end
if type(y) == "number" then
table.insert(text, string.format("y=\"%s\"", write_double(y)))
end
if styleString ~= "" and type(styleString) == "string" then
table.insert(text, string.format("style=\"%s\"", styleString))
end
table.insert(text, ">")
table.insert(text, textString)
table.insert(text, "</text>")
table.insert(strings, table.concat(text, " "))
end
function write_path(id, class, path, styleString, title, strings)
local pathShape = {}
table.insert(pathShape, "<path")
if id ~= "" and type(id) == "string" then
table.insert(pathShape, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if class ~= "" and type(class) == "string" then
table.insert(pathShape, string.format("class=\"%s\"", class))
end
if path ~= "" and type(path) == "string" then
table.insert(pathShape, string.format("d=\"%s\"", path))
end
if styleString ~= "" and type(styleString) == "string" then
table.insert(pathShape, string.format("style=\"%s\"", styleString))
end
if title ~= "" and type(title) == "string" then
table.insert(pathShape, string.format("><title>%s</title></path>", title))
else
table.insert(pathShape, "/>")
end
table.insert(strings, table.concat(pathShape, " "))
end
function write_group(id, class, transform, styleString, listOfShapes, strings)
local group = {}
table.insert(group, "<g")
if id ~= "" and type(id) == "string" then
table.insert(group, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if class ~= "" and type(class) == "string" then
table.insert(group, string.format("class=\"%s\"", class))
end
if transform ~= "" and type(transform) == "string" then
table.insert(group, string.format("transform=\"%s\"", transform))
end
if styleString ~= "" and type(styleString) == "string" then
table.insert(group, string.format("style=\"%s\"", styleString))
end
table.insert(group, ">\n")
table.insert(group, table.concat(listOfShapes, "\n\t"))
table.insert(group, "\n</g>")
table.insert(strings, table.concat(group, " "))
end
function write_link(id, link, styleString, listOfShapes, strings)
local group = {}
table.insert(group, "<a")
if id ~= "" and type(id) == "string" then
table.insert(group, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if link ~= "" and type(link) == "string" then
table.insert(group, string.format("xlink:href=\"%s\"", "#"..link))
end
if styleString ~= "" and type(styleString) == "string" then
table.insert(group, string.format("style=\"%s\"", styleString))
end
table.insert(group, ">\n")
table.insert(group, table.concat(listOfShapes, "\n\t"))
table.insert(group, "\n</a>")
table.insert(strings, table.concat(group, " "))
end
function write_view(id, x, y, width, height, strings)
local view = {}
table.insert(view, "<view")
if id ~= "" and type(id) == "string" then
table.insert(view, string.format("id=\"%s\"", string.lower(remove_spaces(id))))
end
if type(x) == "number" and type(y) == "number" and type(width) == "number" and type(height) == "number" then
table.insert(view, string.format("viewBox=\"%s %s %s %s\"", write_double(x), write_double(y), write_double(width), write_double(height)))
end
table.insert(view, "/>\n")
table.insert(strings, table.concat(view, " "))
end
worldRegionMultiplier = 16
saveDir = df.global.world.cur_savegame.save_dir
worldName = dfhack.TranslateName(df.global.world.world_data.name)
print("Getting map for "..worldName)
documentName = saveDir.."-"..remove_spaces(dfhack.TranslateName(df.global.world.world_data.name, true, true))..'-svg-map'..'.svg'
local log = io.open(documentName, 'w')
width = df.global.world.world_data.world_width
height = df.global.world.world_data.world_height
log:write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>')
namespace = 'xmlns:svg="http://www.w3.org/2000/svg"\n xmlns="http://www.w3.org/2000/svg"\n xmlns:xlink="http://www.w3.org/1999/xlink"'
namespace = namespace.." xmlns:osb=\"http://www.openswatchbook.org/uri/2009/osb\"\n"
log:write(string.format("<svg %s viewBox=\"%s %s %s %s\" >\n", namespace, (0-10)*worldRegionMultiplier, 0, (width+20)*worldRegionMultiplier, (height+10)*worldRegionMultiplier))
local worldStrings = {}
write_text("world-name", nil, (width*worldRegionMultiplier)/2, (height+4)*worldRegionMultiplier, "font-size:50pt; text-anchor:middle;", worldName, worldStrings)
write_text("world-name-translated", nil, (width*worldRegionMultiplier)/2, (height+7)*worldRegionMultiplier, "font-size:15pt; text-anchor:middle;", dfhack.TranslateName(df.global.world.world_data.name, true, true), worldStrings)
write_text("dfversion", nil, (width*worldRegionMultiplier)/2, (height+9)*worldRegionMultiplier, "font-size:15pt; text-anchor:middle;", string.format("A Dwarf Fortress %s World" , df.global.world.worldgen.version), worldStrings)
for _, string in pairs(worldStrings) do
log:write(string)
end
log:write("<defs>")
colorList = {}
listOfStrings = {}
colorList["Swamp"] = "url(#biome-temperate-freshwater-swamp)"
colorList["SWAMP_TEMPERATE_FRESHWATER"] = "url(#biome-temperate-freshwater-swamp)"
colorList["MARSH_TEMPERATE_FRESHWATER"] = "url(#biome-temperate-freshwater-marsh)"
colorList["SWAMP_TEMPERATE_SALTWATER"] = "url(#biome-temperate-saltwater-swamp)"
colorList["MARSH_TEMPERATE_SALTWATER"] = "url(#biome-temperate-saltwater-marsh)"
colorList["SWAMP_TROPICAL_FRESHWATER"] = "url(#biome-temperate-freshwater-swamp)"
colorList["MARSH_TROPICAL_FRESHWATER"] = "url(#biome-temperate-freshwater-marsh)"
colorList["SWAMP_TROPICAL_SALTWATER"] = "url(#biome-temperate-saltwater-swamp)"
colorList["MARSH_TROPICAL_SALTWATER"] = "url(#biome-temperate-saltwater-marsh)"
colorList["SWAMP_MANGROVE"] = "url(#biome-mangrove-swamp)"
write_color_swatch("biome-temperate-saltwater-marsh", "rgb(84, 131, 96)", listOfStrings)
write_color_swatch("biome-temperate-freshwater-marsh", "rgb(95, 147, 108)", listOfStrings)
write_color_swatch("biome-temperate-saltwater-swamp", "rgb(86, 129, 116)", listOfStrings)
write_color_swatch("biome-temperate-freshwater-swamp", "rgb(87, 147, 127)", listOfStrings)
write_color_swatch("biome-mangrove-swamp", "rgb(78, 115, 108)", listOfStrings)
write_color_swatch("biome-tropical-saltwater-marsh", "rgb(92, 125, 134)", listOfStrings)
write_color_swatch("biome-tropical-freshwater-marsh", "rgb(119, 163, 110)", listOfStrings)
write_color_swatch("biome-tropical-saltwater-swamp", "rgb(64, 192, 64)", listOfStrings)
write_color_swatch("biome-tropical-freshwater-swamp", "rgb(96, 192, 64)", listOfStrings)
colorList["Desert"] = "url(#biome-desert-sand)"
colorList["DESERT_SAND"] = "url(#biome-desert-sand-yellow)"
colorList["DESERT_SAND_YELLOW"] = "url(#biome-desert-sand-yellow)"
colorList["DESERT_SAND_RED"] = "url(#biome-desert-sand-red)"
colorList["DESERT_SAND_WHITE"] = "url(#biome-desert-sand-white)"
colorList["DESERT_SAND_BLACK"] = "url(#biome-desert-sand-black)"
colorList["DESERT_SAND_TAN"] = "url(#biome-desert-sand-tan)"
colorList["DESERT_ROCK"] = "url(#biome-desert-rock)"
colorList["DESERT_BADLAND"] = "url(#biome-desert-badlands)"
write_color_swatch("biome-desert-sand-yellow", "#eadd5a", listOfStrings)
write_color_swatch("biome-desert-sand-red", "#cc7362", listOfStrings)
write_color_swatch("biome-desert-sand-white", "#c0c0c0", listOfStrings)
write_color_swatch("biome-desert-sand-black", "#606060", listOfStrings)
write_color_swatch("biome-desert-sand-tan", "#d2b48c", listOfStrings)
write_color_swatch("biome-desert-rock", "#d0ac6d", listOfStrings)
write_color_swatch("biome-desert-badlands", "#c66038", listOfStrings)
colorList["Jungle"] = "url(#biome-forest-temperate-broadleaf)"
colorList["FOREST_TAIGA"] = "url(#biome-forest-taiga)"
colorList["FOREST_TEMPERATE_CONIFER"] = "url(#biome-forest-temperate-conifer)"
colorList["FOREST_TEMPERATE_BROADLEAF"] = "url(#biome-forest-temperate-broadleaf)"
colorList["FOREST_TROPICAL_CONIFER"] = "url(#biome-forest-tropical-conifer)"
colorList["FOREST_TROPICAL_DRY_BROADLEAF"] = "url(#biome-forest-tropical-dry-broadleaf)"
colorList["FOREST_TROPICAL_MOIST_BROADLEAF"] = "url(#biome-forest-tropical-moist-broadleaf)"
write_color_swatch("biome-forest-taiga", "rgb(74, 104, 94)", listOfStrings)
write_color_swatch("biome-forest-temperate-conifer", "rgb(34, 99, 85)", listOfStrings)
write_color_swatch("biome-forest-temperate-broadleaf", "rgb(0, 127, 66)", listOfStrings)
write_color_swatch("biome-forest-tropical-conifer", "rgb(0, 96, 53)", listOfStrings)
write_color_swatch("biome-forest-tropical-dry-broadleaf", "rgb(27, 146, 35)", listOfStrings)
write_color_swatch("biome-forest-tropical-moist-broadleaf", "rgb(31, 165, 41)", listOfStrings)
colorList["Mountains"] = "url(#biome-mountains)"
colorList["MOUNTAIN"] = "url(#biome-mountains)"
colorList["MOUNTAIN_MID"] = "url(#biome-mountains-mid)"
colorList["MOUNTAIN_HIGH"] = "url(#biome-mountains-high)"
write_color_swatch("biome-mountains", "#808080", listOfStrings)
write_color_swatch("biome-mountains-mid", "#a0a0a0", listOfStrings)
write_color_swatch("biome-mountains-high", "#c0c0c0", listOfStrings)
colorList["Ocean"] = "url(#biome-temperate-ocean)"
colorList["OCEAN_TEMPERATE"] = "url(#biome-temperate-ocean)"
colorList["OCEAN_TROPICAL"] = "url(#biome-tropical-ocean)"
colorList["OCEAN_ARTIC"] = "url(#biome-artic-ocean_1)"
write_color_swatch("biome-temperate-ocean", "#206f95", listOfStrings)
write_color_swatch("biome-tropical-ocean", "#39b1ea", listOfStrings)
write_color_swatch("biome-artic-ocean_2", "#0d3d49", listOfStrings)
write_color_swatch("biome-artic-ocean_1", "#a5ceda", listOfStrings)
colorList["Glacier"] = "url(#biome-glacier)"
write_color_swatch("biome-glacier", "#a5ceda", listOfStrings)
colorList["Steppe"] = "url(#biome-grassland-temperate)"
colorList["Hills"] = "url(#biome-hills)"
write_color_swatch("biome-hills", "#d8bc89", listOfStrings)
colorList["GRASSLAND_TEMPERATE"] = "url(#biome-grassland-temperate)"
colorList["SAVANNA_TEMPERATE"] = "url(#biome-savanna-temperate)"
colorList["SHRUBLAND_TEMPERATE"] = "url(#biome-shrubland-temperate)"
colorList["GRASSLAND_TROPICAL"] = "url(#biome-grassland-tropical)"
colorList["SAVANNA_TROPICAL"] = "url(#biome-savanna-tropical)"
colorList["SHRUBLAND_TROPICAL"] = "url(#biome-shrubland-tropical)"
write_color_swatch("biome-grassland-tropical", "rgb(163, 157, 72)", listOfStrings)
write_color_swatch("biome-shrubland-tropical", "rgb(158, 166, 47)", listOfStrings)
write_color_swatch("biome-savanna-tropical", "rgb(153, 173, 0)", listOfStrings)
write_color_swatch("biome-grassland-temperate", "rgb(124, 128, 90)", listOfStrings)
write_color_swatch("biome-shrubland-temperate", "rgb(105, 141, 94)", listOfStrings)
write_color_swatch("biome-savanna-temperate", "rgb(84, 151, 96)", listOfStrings)
colorList["Tundra"] = "url(#biome-tundra)"
write_color_swatch("biome-tundra", "rgb(85, 117, 113)", listOfStrings)
write_color_swatch("neutral-fg", "grey", listOfStrings)
write_color_swatch("neutral-bg", "black", listOfStrings)
colorList["Lake"] = "url(#biome-lake-temperate-freshwater)"
colorList["LAKE_TEMPERATE_FRESHWATER"] = "url(#biome-lake-temperate-freshwater)"
colorList["LAKE_TEMPERATE_BRAKISH"] = "url(#biome-lake-temperate-brackish)"
colorList["LAKE_TEMPERATE_SALTWATER"] = "url(#biome-lake-temperate-saltwater)"
colorList["LAKE_TEMPERATE_TROPICAL"] = "url(#biome-lake-temperate-freshwater)"
colorList["LAKE_TEMPERATE_TROPICAL"] = "url(#biome-lake-temperate-brackish)"
colorList["LAKE_TEMPERATE_TROPICAL"] = "url(#biome-lake-temperate-saltwater)"
write_color_swatch("biome-lake-tropical-saltwater", "#29b2ec", listOfStrings)
write_color_swatch("biome-lake-tropical-brackish", "#29c6e7", listOfStrings)
write_color_swatch("biome-lake-tropical-freshwater", "#2fdef1", listOfStrings)
write_color_swatch("biome-lake-temperate-saltwater", "#217693", listOfStrings)
write_color_swatch("biome-lake-temperate-brackish", "#2d9cb0", listOfStrings)
write_color_swatch("biome-lake-temperate-freshwater", "#298bac", listOfStrings)
write_color_swatch("river-major", "#0070ff", listOfStrings)
write_color_swatch("river-mid", "#0086e8", listOfStrings)
write_color_swatch("river-minor", "#00c1f5", listOfStrings)
write_color_swatch("river-stream", "#00e0ff", listOfStrings)
write_color_swatch("river-brook", "#00ffff", listOfStrings)
--Proly not gonna use these, but gotta keep track of them anyhow...
write_color_swatch("mud-tropical", "#a9925a", listOfStrings)
write_color_swatch("mud-temperate", "#8e6f57", listOfStrings)
write_color_swatch("mud-artic", "#574844", listOfStrings)
write_color_swatch("construction-road", "#8e6f57", listOfStrings)
write_color_swatch("construction-road-bars", "#c0c0c0", listOfStrings)
write_color_swatch("construction-road-smallgem", "#FF80FF", listOfStrings)
write_color_swatch("construction-road-blocks", "#808080", listOfStrings)
write_color_swatch("construction-road-rough", "#404040", listOfStrings)
write_color_swatch("construction-road-boulder", "#404040", listOfStrings)
write_color_swatch("construction-road-wood", "#a9925a", listOfStrings)
write_color_swatch("construction-bridge", "#808080", listOfStrings)
write_color_swatch("construction-tunnel", "#202020", listOfStrings)
write_color_swatch("construction-wall", "#808080", listOfStrings)
write_color_swatch("residence", "rgb(0, 255, 255)", listOfStrings)
write_color_swatch("capital", "rgb(255, 0, 255)", listOfStrings)
write_color_swatch("fortress", "rgb(0, 255, 180)", listOfStrings)
write_color_swatch("local_market", "rgb(0, 255, 0)", listOfStrings)
write_color_swatch("trade_partner", "rgb(255, 255, 0)", listOfStrings)
write_color_swatch("monument", "rgb(192, 0, 255)", listOfStrings)
write_color_swatch("primary_criminal_gang", "rgb(255, 192, 0)", listOfStrings)
write_color_swatch("criminal_gang", "rgb(255, 140, 0)", listOfStrings)
write_color_swatch("invasion_marked", "rgb(255, 0, 0)", listOfStrings)
write_color_swatch("land_for_holding", "rgb(80, 0, 80)", listOfStrings)
write_color_swatch("land_holder_residence", "rgb(120, 0, 120)", listOfStrings)
write_color_swatch("central_holding_land", "rgb(190, 0, 190)", listOfStrings)
write_color_swatch("reclaim", "rgb(0, 100, 100)", listOfStrings)
write_color_swatch("occupation_failed", "rgb(80, 0, 0)", listOfStrings)
log:write(string.format("<marker id=\"%s\" viewbox=\"%s\" refX=\"%s\" refY=\"%s\" markerWidth=\"%s\" markerHeight=\"%s\" orient=\"%s\">\n", "entity-link", "-10 -10 20 20", 5, 5, 10, 10, "auto-start-reverse"))
log:write("\t<circle cx=\"5\" cy=\"5\" r=\"2.5\" stroke=\"white\" />\n")
log:write("</marker>\n")
log:write("<style type=\"text/css\">\n")
--log:write("<![CDATA[\n")
log:write(string.format(".region {\n\tstroke:%s;\n\tstroke-width:%s;\n\tstroke-opacity:0.5;\n}\n",
"#000000", write_double(0.1*worldRegionMultiplier)))
log:write(string.format(".ocean {\n\tstroke:%s;\n\tstroke-width:%s;\n}\n",
"#88ddFF", write_double(0.5*worldRegionMultiplier)))
log:write(string.format(".region:hover {\n\tstroke-width:%s;\n}\n",
write_double(0.5*worldRegionMultiplier)))
log:write(string.format(".neutral:hover{\n\tstroke:%s;\n}\n",
"#c0c0c0"))
log:write(string.format(".good:hover{\n\tstroke:%s;\n}\n",
"#80ffff"))
log:write(string.format(".evil:hover{\n\tstroke:%s;\n}\n",
"#ff80ff"))
log:write(string.format(".river{\n\tstroke:%s;\n}\n",
"url(#river-mid)"))
log:write(string.format(".stream{\n\tstroke:%s;\n}\n",
"url(#river-stream)"))
log:write(string.format(".brook{\n\tstroke:%s;\n}\n",
"url(#river-brook)"))
log:write(string.format(".major{\n\tstroke:%s;\n}\n",
"url(#river-major)"))
log:write(string.format(".minor{\n\tstroke:%s;\n}\n",
"url(#river-minor)"))
log:write(string.format(".river:hover{\n\tstroke:%s;\n}\n",
"#aaffff"))
log:write(string.format(".road { \n\tfill: none; \n\tstroke-width: %s; \n\tstroke: %s;}", write_double(0.1*worldRegionMultiplier), "url(#construction-road)"))
log:write(string.format(".road-bars {\n\tstroke: %s;}", "url(#construction-road-bars)"))
log:write(string.format(".road-smallgem {\n\tstroke: %s;}", "url(#construction-road-smallgem)"))
log:write(string.format(".road-blocks {\n\tstroke: %s;}", "url(#construction-road-blocks)"))
log:write(string.format(".road-rough {\n\tstroke: %s;}", "url(#construction-road-rough)"))
log:write(string.format(".road-boulder {\n\tstroke: %s;}", "url(#construction-road-boulder)"))
log:write(string.format(".road-wood {\n\tstroke: %s;}", "url(#construction-road-wood)"))
log:write(string.format(".road:hover{\n\tstroke:%s;\n}\n", "#ffffff"))
log:write(string.format(".tunnel { \n\tfill: none; \n\tstroke-width: %s; \n\tstroke: %s;\n\tstroke-dasharray:%s, %s;}\n",
write_double(0.1*worldRegionMultiplier), "url(#construction-tunnel)", write_double(0.2*worldRegionMultiplier), write_double(0.2*worldRegionMultiplier)))
log:write(string.format(".tunnel:hover{\n\tstroke:%s;\n}\n",
"#404040"))
log:write(string.format(".wall{ \n\tfill: none; \n\tstroke-width: %s; \n\tstroke: %s;}", write_double(0.1*worldRegionMultiplier), "url(#construction-wall)"))
log:write(string.format(".wall:hover{\n\tstroke:%s;\n}\n",
"#ffffff"))
log:write(string.format(".text-legend{font-size:%spt; text-decoration:none}", write_double(0.5*worldRegionMultiplier)))
log:write(".text-legend:hover{text-decoration:underline}\n")
log:write(string.format(".entity-site-link{ \n\tvisibility: hidden; \n\tstroke-width: %s;}\n", write_double(0.1*worldRegionMultiplier), "url(#construction-wall)"))
log:write(".site{ \n\tvisibility: visible;}\n")
log:write(string.format(".entity-site-link:hover{\n\tvisibility:%s;\n}\n",
"visible"))
--log:write("]]>\n")
log:write("</style>\n")
civ_list = {}
local civoffset = 0
for no, entity in pairs(df.global.world.entities.all) do
if entity.type == 0 then
local name = dfhack.TranslateName(entity.name, true, true)
if name == "" then
name = dfhack.TranslateName(entity.name)
end
if name ~= "" then
civoffset = civoffset+1
local id = no.."-"..remove_spaces(name)
local fgcolor = df.global.world.raws.descriptors.colors[entity.resources.foreground_color[0]]
local bgcolor = df.global.world.raws.descriptors.colors[entity.resources.background_color[0]]
local colorString = "rgb("..math.floor(fgcolor.red*255)..", "..math.floor(fgcolor.green*255)..", "..math.floor(fgcolor.blue*255)..")"
write_color_swatch(id.."-fg", colorString, listOfStrings)
colorString = "rgb("..math.floor(bgcolor.red*255)..", "..math.floor(bgcolor.green*255)..", "..math.floor(bgcolor.blue*255)..")"
write_color_swatch(id.."-bg", colorString, listOfStrings)
print("getting civ colors "..id.." fore: "..fgcolor.name.." back: "..bgcolor.name)
local civdef = {}
write_rect(nil, nil, nil, worldRegionMultiplier, worldRegionMultiplier, "fill:url(#"..id.."-bg)" , civdef)
write_rect(nil, nil, 0.3*worldRegionMultiplier, worldRegionMultiplier, 0.3*worldRegionMultiplier, "fill:url(#"..id.."-fg)" , civdef)
local textShape = {}
write_text(nil, "text-legend", 1.5*worldRegionMultiplier, 0.6*worldRegionMultiplier, "text-anchor:start;", name, textShape)
table.insert(textShape, "<title>"..name.."</title>")
write_link(nil, string.lower(remove_spaces(no.."-"..name.."-view")), nil, textShape, civdef)
write_group(no.."-"..name.."-legend", nil, string.format("translate( %s , %s)", write_double((width+1)*worldRegionMultiplier), write_double(civoffset*worldRegionMultiplier)), nil, civdef, civ_list)
end
end
end
for _, string in pairs(listOfStrings) do
log:write(string)
end
log:write("</defs>")
landMassStrings = {}
for no, landmass in pairs(df.global.world.world_data.landmasses) do
local landmass_name = dfhack.TranslateName(landmass.name, true, true)
local id = string.lower(remove_spaces(no.."-"..landmass_name))
write_view(id.."-view", (landmass.min_x-1)*worldRegionMultiplier, (landmass.min_y-1)*worldRegionMultiplier,
(landmass.max_x+3-landmass.min_x)*worldRegionMultiplier
, (landmass.max_y+3-landmass.min_y)*worldRegionMultiplier, landMassStrings)
local textShape = {}
write_text(nil, "text-legend", (0-1.5)*worldRegionMultiplier, (no+1+0.6)*worldRegionMultiplier,
"text-anchor:end;",
landmass_name, textShape)
table.insert(textShape, "<title>"..landmass_name.."</title>")
write_link(nil, id.."-view", nil, textShape, landMassStrings)
end
listOfStrings = {}
write_group("civ_legend",nil, nil, nil, civ_list, listOfStrings)
write_group("landmasses",nil, nil, nil, landMassStrings, listOfStrings)
for _, string in pairs(listOfStrings) do
log:write(string)
end
landmasses = {}
for no, region in pairs(df.global.world.world_data.regions) do
local region_name = ""
local regionStrings = {}
local landmass_name = ""
local biomeamount = 0
local biometype = df.world_region_type[region.type]
if (region.name) then
region_name = dfhack.TranslateName(region.name, true, true)
end
print("bounding.. "..region_name)
local bordercoords = grid_to_border(region.region_coords)
print("done")
for biome, amount in pairs(region.biome_tile_counts) do
if amount>biomeamount then
biomeamount = amount
biometype = biome
end
end
if df.world_region_type[region.type] ~= "Ocean" then
for _, landmass in pairs(df.global.world.world_data.landmasses) do
if region.min_x >= landmass.min_x and region.max_x <= landmass.max_x and
region.min_y >= landmass.min_y and region.max_y <= landmass.max_y then
landmass_name = dfhack.TranslateName(landmass.name, true, true)
end
end
end
print(biometype)
local colorFill = colorList[biometype]
if colorFill == nil then
colorFill = colorList[df.world_region_type[region.type]]
end
local regionString = df.world_region_type[region.type]
if df.world_region_type[region.type] == "Jungle" then
regionString = "Forest"
end
local path = ""
local max_x = 0
local max_y = 0
local min_x = width
local min_y = width
for i, subpath in pairs(bordercoords) do
path = path.." M "
for p, point in pairs(subpath) do
if p ~= 1 then
path = path.." L "
end
path = path..write_double(point.x*worldRegionMultiplier).." "..write_double(point.y*worldRegionMultiplier)
max_x = math.max(point.x, max_x)
max_y = math.max(point.y, max_y)
min_x = math.min(point.x, min_x)
min_y = math.min(point.y, min_y)
end
path = path.." z"
end
local Other_Biomes = {}
-- ported from https://github.com/ragundo/exportmaps/blob/master/cpp/df_utils/biome_type.cpp#L105 and
-- https://github.com/PatrikLundell/scripts/blob/own_scripts/biomemanipulator.lua
for point, world_coord_x in pairs (region.region_coords.x) do
local biomename = biometype
local world_coord_y = region.region_coords.y[point]
local region_tile = dfhack.maps.getRegionBiome(world_coord_x, world_coord_y)
if (df.world_region_type[region.type] == "Ocean") then
if (region_tile.temperature < (0)) then
biomename = "OCEAN_ARTIC"
elseif (region_tile.temperature >= (75)) then
biomename = "OCEAN_TROPICAL"
else
biomename = "OCEAN_TEMPERATE"
end
end
if (df.world_region_type[region.type]=="Swamp") then
if region_tile.salinity >= 66 then
biomename = string.gsub(biometype,"FRESHWATER","SALTWATER")
if region_tile.temperature >= (75) and
region_tile.vegetation>=33 and
region_tile.drainage<10 then
print("SWAMP_MANGROVE")
biomename = "SWAMP_MANGROVE"
end
else
biomename = string.gsub(biometype,"SALTWATER","FRESHWATER")
end
end
if (df.world_region_type[region.type]=="Hills" or df.world_region_type[region.type]=="Steppe") then
if region_tile.vegetation < 20 then
biomename = "GRASSLAND"
elseif region_tile.vegetation >= 20 and region_tile.vegetation < 65 then
biomename = "SAVANNA"
else
biomename = "SHRUBLAND"
end
if string.find(biometype, "TROPICAL") then
biomename = biomename.."_TROPICAL"
else
biomename = biomename.."_TEMPERATE"
end
end
if (df.world_region_type[region.type]=="Jungle") then
local forest_type = "FOREST"
-- border above 180, below 184
if string.find(biometype, "TROPICAL") then
forest_type = forest_type.."_TROPICAL"
if (region_tile.rainfall < 75) then
forest_type = forest_type.."_CONIFER"
else
if string.find(biometype, "DRY") then
forest_type = forest_type.."_DRY_BROADLEAF"
else
forest_type = forest_type.."_MOIST_BROADLEAF"
end
end
else
forest_type = forest_type.."_TEMPERATE"
if ((region_tile.rainfall < 75) or (region_tile.temperature < 65)) then
if (region_tile.temperature >= 10) then
forest_type = forest_type.."_CONIFER"
else
forest_type = "FOREST_TAIGA"
end
else
forest_type = forest_type.."_BROADLEAF"
end
end
biomename = forest_type
end
if (df.world_region_type[region.type]=="Desert") then
biomename = "DESERT"
-- border above 180, below 184
if region_tile.drainage < 33 then
geolayer = df.global.world.world_data.geo_biomes[region_tile.geo_index].layers[0]
if geolayer.type == 6 then
material = df.global.world.raws.inorganics[geolayer.mat_index]
biomename = biomename.."_"..material.id
else
biomename = biomename.."_SAND"
end
elseif region_tile.drainage < 33 then
biomename = biomename.."_ROCK"
else
biomename = biomename.."_BADLAND"
end
end
if (df.world_region_type[region.type]=="Mountains") then
local mountain_type = ""
-- border above 180, below 184
if region_tile.elevation >= 183 then
mountain_type = "_MID"
end
if region_tile.elevation > 215 then
mountain_type = "_HIGH"
end
biomename = "MOUNTAIN"..mountain_type
end
if (Other_Biomes[biomename]==nil) then
Other_Biomes[biomename] = {"x", "y"}
Other_Biomes[biomename]["x"] = {}
Other_Biomes[biomename]["y"] = {}
end
table.insert(Other_Biomes[biomename]["x"], world_coord_x)
table.insert(Other_Biomes[biomename]["y"], world_coord_y)
end
local className = "neutral"
if region.evil then
className = "evil"
regionString = "Evil "..regionString
end
if region.good then
className = "good"
regionString = "Good "..regionString
end
local regionInfo = {}
table.insert(regionInfo, region_name)
table.insert(regionInfo, regionString)
if (landmass_name ~= "") then
table.insert(regionInfo, landmass_name)
end
local linkStrings = {}
className = "region "..string.lower(df.world_region_type[region.type]).." "..className
write_path(nil, nil, path, string.format("fill: %s; stroke:none;", colorFill), nil, linkStrings)
for biomeName, biome in pairs(Other_Biomes) do
if biometype~= biomeName then
print("bounding.. "..region_name.." "..biomeName)
local bordercoords = grid_to_border(biome)
print("done")
local biomePath = ""
for i, subpath in pairs(bordercoords) do
biomePath = biomePath.." M "
for p, point in pairs(subpath) do
if p ~= 1 then
biomePath = biomePath.." L "
end
biomePath = biomePath..write_double(point.x*worldRegionMultiplier).." "..write_double(point.y*worldRegionMultiplier)
end
biomePath = biomePath.." z"
end
write_path(nil, nil, biomePath, string.format("fill: %s; stroke:none;", colorList[biomeName]), nil, linkStrings)
end
end
write_path(nil, nil, path, string.format("fill: %s;", "none"), nil, linkStrings)
write_link(nil, string.lower(remove_spaces(no.."-"..region_name.."-view")), nil, linkStrings, regionStrings)
table.insert(regionStrings, string.format("<title>%s</title>", table.concat(regionInfo, ", ")))
write_view(no.."-"..region_name.."-view",
(min_x-1)*worldRegionMultiplier,
(min_y-1)*worldRegionMultiplier,
(max_x+2-min_x)*worldRegionMultiplier,
(max_y+2-min_y)*worldRegionMultiplier,
regionStrings)
if (landmass_name == "") then
landmass_name = "Unsorted"
if df.world_region_type[region.type] == "Ocean" then
landmass_name = "Water"
end
end
local landmass = landmasses[landmass_name]
if landmass == nil then
landmass = {}
end
write_group(no.."-"..region_name, className, nil, nil, regionStrings, landmass)
landmasses[landmass_name] = landmass
end
log:write("<g id=\"regions\">")
--Draw oceans first.
if landmasses["Water"] ~= nil then
landmass = landmasses["Water"]
log:write("\t<g id=\"Water\">")
for _,strings in pairs(landmass) do
log:write("\t\t"..strings)
end
log:write("\t</g>")
end
for landmass_name, landmass in pairs(landmasses) do
if landmass_name ~= "Water" then
log:write("\t<g id=\""..landmass_name.."\">")
for _,strings in pairs(landmass) do
log:write("\t\t"..strings)
end
log:write("\t</g>")
end
end
log:write("</g>")
log:write("<g id=\"rivers\">")
for no, river in pairs(df.global.world.world_data.rivers) do
local river_name = ""
local path = ""
if (river.name) then
river_name = dfhack.TranslateName(river.name, true, true)
end
local max_x = 0
local max_y = 0
local min_x = width
local min_y = width
for point, x in pairs (river.path.x) do
if (path == "") then
path = string.format("M %s %s", write_double((x+0.5)*worldRegionMultiplier),
write_double((river.path.y[point]+0.5)*worldRegionMultiplier))
else
path = string.format("%s L %s %s", path, write_double((x+0.5)*worldRegionMultiplier),
write_double((river.path.y[point]+0.5)*worldRegionMultiplier))
end
max_x = math.max(x, max_x)
max_y = math.max(river.path.y[point], max_y)
min_x = math.min(x, min_x)
min_y = math.min(river.path.y[point], min_y)
end
path = string.format("%s L %s %s", path, write_double((river.end_pos.x+0.5)*worldRegionMultiplier),
write_double((river.end_pos.y+0.5)*worldRegionMultiplier))
max_x = math.max(river.end_pos.x, max_x)
max_y = math.max(river.end_pos.y, max_y)
min_x = math.min(river.end_pos.x, min_x)
min_y = math.min(river.end_pos.y, min_y)
stroke_width = river.flow[0]
for _, flow in pairs(river.flow) do
if flow > stroke_width then
stroke_width = flow
end
end
river_type = "Stream"
if stroke_width >= 5000 then
river_type = "Minor River"
end
if stroke_width >= 10000 then
river_type = "River"
end
if stroke_width > 20000 then
river_type = "Major River"
end
stroke_width = math.floor(stroke_width / 40000 * 46) + 1
print(stroke_width)
stroke_width = math.max(math.min(stroke_width*0.5, 15), 1)
listOfStrings = {}
write_view(no.."-"..river_name.."-view",
(min_x-0.5)*worldRegionMultiplier,
(min_y-0.5)*worldRegionMultiplier,
(max_x-min_x+2.5)*worldRegionMultiplier,
(max_y-min_y+2.5)*worldRegionMultiplier,
listOfStrings)
write_path(no.."-"..river_name, "river "..string.lower(river_type), path, string.format("stroke-width: %s; fill: %s; ", write_double(stroke_width), "none"), river_name..", "..river_type, listOfStrings)
linkStrings = {}
write_link(nil,string.lower(remove_spaces(no.."-"..river_name.."-view")), nil, listOfStrings, linkStrings)
for _, string in pairs(linkStrings) do
log:write("\t"..string.."\n")
end
end
log:write("</g>")
log:write("<g id=\"mountain_peaks\">")
for no, peak in pairs(df.global.world.world_data.mountain_peaks) do
local peak_name = ""
if (peak.name) then
peak_name = dfhack.TranslateName(peak.name, true, true)
end
local fgcolor = "black"
local bgcolor = "grey"
local typeName = "Mountain Peak"
if peak.flags.is_volcano then
bgcolor = "red"
typeName = "Volcano"
end
listOfStrings = {}
write_text(nil, nil, 0.5*worldRegionMultiplier, worldRegionMultiplier, "font-size:"..write_double(0.1*worldRegionMultiplier)..";text-anchor:middle;stroke:"..fgcolor..";stroke-width:"..write_double(0.1*worldRegionMultiplier)..";fill:"..bgcolor..";paint-order:stroke markers fill", "^", listOfStrings)
table.insert(listOfStrings, "<title>"..peak_name..", "..typeName)
table.insert(listOfStrings, peak.height.." tiles high</title>")
log:write("<g id=\""..no.."-"..remove_spaces(peak_name).."\" transform=\"translate("..write_double(peak.pos.x*worldRegionMultiplier).." , "..write_double(peak.pos.y*worldRegionMultiplier)..")\" >\n")
for _, string in pairs(listOfStrings) do
log:write("\t"..string.."\n")
end
log:write("</g>\n")
end
log:write("</g>")
log:write("<g id=\"world_constructions\">")
for no, construction in pairs(df.global.world.world_data.constructions.list) do
local path = ""
local bridgeRect = {}
local construction_name = ""
local typeName = "road"
local matName = ""
local dashes = ""
if (construction.name) then
construction_name = dfhack.TranslateName(construction.name, true, true)
end
local max_x = 0
local max_y = 0
local min_x = width
local min_y = width
if (#construction.square_pos.x > 1) then
for point, x in pairs (construction.square_pos.x) do
if (path == "") then
path = string.format("M %s %s", write_double((x+0.5)*worldRegionMultiplier),
write_double((construction.square_pos.y[point]+0.5)*worldRegionMultiplier))
else
path = string.format("%s L %s %s", path, write_double((x+0.5)*worldRegionMultiplier),
write_double((construction.square_pos.y[point]+0.5)*worldRegionMultiplier))
end
max_x = math.max(x, max_x)
max_y = math.max(construction.square_pos.y[point], max_y)
min_x = math.min(x, min_x)
min_y = math.min(construction.square_pos.y[point], min_y)
end
else
write_rect(nil, construction.square_pos.x[0]*worldRegionMultiplier, construction.square_pos.y[0]*worldRegionMultiplier, worldRegionMultiplier, worldRegionMultiplier, nil, bridgeRect)
end
if (construction._type==df.world_construction_roadst) then
print(construction.square_obj[0].item_type)
if construction.square_obj[0].item_type == 0 then
matName = "-bars"
end
if construction.square_obj[0].item_type == 1 then
matName = "-smallgem"
end
if construction.square_obj[0].item_type == 2 then
matName = "-blocks"
end
if construction.square_obj[0].item_type == 3 then
matName = "-rough"
end
if construction.square_obj[0].item_type == 4 then
matName = "-boulder"
end
if construction.square_obj[0].item_type == 5 then
matName = "-wood"
end
end
if (construction._type==df.world_construction_bridgest) then
typeName = "bridge"
end
if (construction._type==df.world_construction_tunnelst) then
typeName = "tunnel"
end
if (construction._type==df.world_construction_wallst) then
typeName = "wall"
end
if (path ~= "") then
listOfStrings = {}
write_path(no.."-"..remove_spaces(construction_name), typeName.." "..typeName..matName, path, nil, construction_name..", "..typeName, listOfStrings)
write_view(no.."-"..construction_name.."-view",
(min_x-0.5)*worldRegionMultiplier,
(min_y-0.5)*worldRegionMultiplier,
(max_x-min_x+2.5)*worldRegionMultiplier,
(max_y-min_y+2.5)*worldRegionMultiplier,
listOfStrings)
local linkStrings= {}
write_link(nil,string.lower(remove_spaces(no.."-"..construction_name.."-view")), nil, listOfStrings, linkStrings)
for _, string in pairs(linkStrings) do
log:write("\t"..string.."\n")
end
else
log:write("<g id=\""..no.."-"..remove_spaces(construction_name).."\" style=\"fill:url(#construction-"..typeName.."); opacity:0.1;\" >\n")
log:write(bridgeRect[1])
log:write("\t<title>"..construction_name..", "..typeName.."\n")
log:write("</title>\n")
log:write("</g>\n")
end
end
log:write("</g>")
--links = {}
totalSiteStrings = {}
for no, site in pairs(df.global.world.world_data.sites) do
entities = df.global.world.entities.all
local site_name = ""
local typeName = ""
local symbol = "*"
local civilisation = "none"
local government = "no government"
local population = "unknown"
local fgcolor = "url(#neutral-fg)"
local bgcolor = "url(#neutral-bg)"
local site_width = math.max(site.global_max_x-site.global_min_x, 2)
local site_height = math.max(site.global_max_y-site.global_min_y, 2)
if (site.name) then
site_name = dfhack.TranslateName(site.name, true, true)
end
if (site_name == "") then
site_name = dfhack.TranslateName(site.name)
end
if (site.type~=nil) then
if (df.world_site_type[site.type]~=nil) then
typeName = df.world_site_type[site.type]
end
if typeName == "Cave" or typeName == "Lair" or typeName == "LairShrine" then
symbol = "•"
end
if (site.subtype_info~=nil) then
if (site.subtype_info.fortress_type>-1) then
typeName = string.lower(df.fortress_type[site.subtype_info.fortress_type])
if (typeName == "tower") then
symbol = "I"
elseif (typeName == "monastery" or typeName == "castle") then
symbol = "○"
elseif (typeName == "fort") then
symbol = "◙"
else
print(siteName, "unknown fort type", typeName, site.subtype_info.fortress_type)
end
end
if (site.subtype_info.monument_type>-1) then
typeName = string.lower(df.monument_type[site.subtype_info.monument_type])
if (typeName == "vault") then
symbol= "■"
elseif (typeName == "tomb") then
symbol = "0"
else
print(siteName, "unknown monument type", typeName, site.subtype_info.monument_type)
end
end
if (site.subtype_info.lair_type>-1) then
typeName = string.lower(df.lair_type[site.subtype_info.lair_type])
if (typeName == "simple_mound") then
symbol = "•"
elseif(typeName == "simple_burrow") then
symbol = "•"
elseif(typeName == "labyrinth") then
symbol = "#"
elseif(typeName == "shrine") then
symbol = "Å"
elseif (typeName == "wilderness_location") then
symbol = "•"
else
print(siteName, "unknown lair type", typeName, site.subtype_info.lair_type)
end
typeName = string.gsub(typeName, "_", " ")
end
end
if typeName == "MountainHalls" then
symbol = "Ω"
if site.is_mountain_halls>0 then
typeName = "Mountain Halls"
else
if site.is_fortress>0 then
typeName = "Mountain Fortress"
else
typeName = "Hillocks"
end
end
if(site.cur_owner_id==-1) then
symbol = "μ"
end
end
if typeName == "PlayerFortress" then
symbol = "Ω"
if(site.cur_owner_id==-1) then
symbol = "μ"
end
end
if typeName == "DarkFortress" then
symbol = "º"
typeName = "Dark Pits"
if(site.flags.Town == true) then
symbol = "Π"
typeName = "Dark Fortress"
end
if(site.cur_owner_id==-1) then
symbol = "μ"
end
end
if typeName == "Town" then
symbol = "="
if(site.flags.Town == true) then
symbol = "+"
else
typeName = "Hamlet"
end
if(site.cur_owner_id==-1) then
symbol = "μ"
end
end
if typeName == "ImportantLocation" then
symbol = "!"
end
if typeName == "ForestRetreat" then
symbol = "î"
if(site.flags.Town == true) then
symbol = "¶"
end
if(site.cur_owner_id==-1) then
symbol = "μ"
end
end
end
if (site.civ_id>0) then
if site.civ_id <= #entities then
civilisation = dfhack.TranslateName(entities[site.civ_id].name, true, true)
if (civilisation == "") then
civilisation = dfhack.TranslateName(entities[site.civ_id].name)
end
if entities[site.civ_id].type == 0 then
fgcolor = "url(#"..site.civ_id.."-"..remove_spaces(civilisation).."-fg)"
bgcolor = "url(#"..site.civ_id.."-"..remove_spaces(civilisation).."-bg)"
else
local fgcoloro = df.global.world.raws.descriptors.colors[entities[site.civ_id].resources.foreground_color[0]]
local bgcoloro = df.global.world.raws.descriptors.colors[entities[site.civ_id].resources.background_color[0]]
fgcolor = "rgb("..math.floor(fgcoloro.red*255)..", "..math.floor(fgcoloro.green*255)..", "..math.floor(fgcoloro.blue*255)..")"
bgcolor = "rgb("..math.floor(bgcoloro.red*255)..", "..math.floor(bgcoloro.green*255)..", "..math.floor(bgcoloro.blue*255)..")"
end
end
if civilisation == nil then
civilisation = "Something is seriously wrong with the civ definitions here..."..site.civ_id
end
end
if (site.cur_owner_id>0) then
government = dfhack.TranslateName(entities[site.cur_owner_id].name, true, true)
if (government == "") then
government = dfhack.TranslateName(entities[site.cur_owner_id].name)
end
fgcolor = ""
for _, link in pairs(entities[site.cur_owner_id].entity_links) do
if (link.type==0) then
if entities[link.target].type == 0 then
civilisation = dfhack.TranslateName(entities[link.target].name, true, true)
if (civilisation == "") then
civilisation = dfhack.TranslateName(entities[link.target].name)
end
fgcolor = "url(#"..link.target.."-"..remove_spaces(civilisation).."-fg)"
bgcolor = "url(#"..link.target.."-"..remove_spaces(civilisation).."-bg)"
else
local fgcoloro = df.global.world.raws.descriptors.colors[entities[link.target].resources.foreground_color[0]]
local bgcoloro = df.global.world.raws.descriptors.colors[entities[link.target].resources.background_color[0]]
fgcolor = "rgb("..math.floor(fgcoloro.red*255)..", "..math.floor(fgcoloro.green*255)..", "..math.floor(fgcoloro.blue*255)..")"
bgcolor = "rgb("..math.floor(bgcoloro.red*255)..", "..math.floor(bgcoloro.green*255)..", "..math.floor(bgcoloro.blue*255)..")"
end
end
end
if fgcolor == "" then
local fgcoloro = df.global.world.raws.descriptors.colors[entities[site.cur_owner_id].resources.foreground_color[0]]
local bgcoloro = df.global.world.raws.descriptors.colors[entities[site.cur_owner_id].resources.background_color[0]]
fgcolor = "rgb("..math.floor(fgcoloro.red*255)..", "..math.floor(fgcoloro.green*255)..", "..math.floor(fgcoloro.blue*255)..")"
bgcolor = "rgb("..math.floor(bgcoloro.red*255)..", "..math.floor(bgcoloro.green*255)..", "..math.floor(bgcoloro.blue*255)..")"
end
else
if symbol == "μ" then
fgcolor = "url(#neutral-fg)"
bgcolor = "url(#neutral-bg)"
end
end
population = site.resident_count
if typeName == "Town" or typeName == "Hamlet" then
if site.flags.Town==true then
if population>1000 then
symbol = "*"
end
if population>2000 then
symbol = "#"
end
if population>5000 then
symbol = "☼"
end
else
if population>50 then
symbol = "æ"
end
end
end
siteStrings = {}
local path = ""
write_rect(nil, nil, nil, site_width, site_height, string.format("fill:#ffffff;fill-opacity:0.3;stroke:%s;stroke-width:%s; visibility:visible", bgcolor, write_double(0.1*worldRegionMultiplier)), siteStrings)
local dashes = string.format("%s, %s;", write_double(0.2*worldRegionMultiplier), write_double(0.2*worldRegionMultiplier))
write_rect(nil, nil, nil, site_width, site_height, string.format("fill:none;stroke:%s;stroke-width:%s; stroke-dasharray:%s; visibility:visible", fgcolor, write_double(0.1*worldRegionMultiplier), dashes), siteStrings)
for _, link in pairs(site.entity_links) do
path = ""
entity = entities[link.entity_id]
local residence_name = ""
--find residence or location
for _, reslink in pairs(entity.site_links) do
if (reslink.flags["residence"] or reslink.flags["capital"]) and reslink.target ~= no+1 then
if reslink.target > -1 and reslink.target < #df.global.world.world_data.sites then
target_site = df.global.world.world_data.sites[reslink.target-1]
residence_name = dfhack.TranslateName(target_site.name, true, true)
local coord_x = ((target_site.global_max_x-target_site.global_min_x)*0.5)+target_site.global_min_x
coord_x = coord_x-site.global_min_x
local coord_y = ((target_site.global_max_y-target_site.global_min_y)*0.5)+target_site.global_min_y
coord_y = coord_y-site.global_min_y
path = string.format("M %s %s", write_double(coord_x), write_double(coord_y))
end
end
end
for fname, fb in pairs(link.flags) do
if (fb and path~="") then
path2 = path..string.format(" L %s %s", write_double((site_width*0.5)), write_double((site_height*0.5)))
local link_title = dfhack.TranslateName(entity.name, true, true)..", "..df.historical_entity_type[entity.type]
link_title = link_title.."\n"..residence_name..", "..fname
write_path(nil, nil, path2, string.format("stroke:%s;stroke-opacity: %s; marker-start:url(#entity-link)", "url(#"..fname..")", write_double(link.link_strength*0.005)), link_title, siteStrings)
end
end
end
local title = site_name..", "..typeName.."\n"
if civilisation ~= "none" then
title = title.."Civilization:\t\t"..civilisation.."\n"
end
if government ~= "no government" then
title = title.."Government:\t"..government.."\n"
end
if population ~= 0 then
title = title.."Population:\t\t"..population.."\n"
end
table.insert(siteStrings, "<title>"..title.."</title>")
local style = string.format("font-size:%spx;text-anchor:middle;stroke:%s;stroke-width:%s;fill:%s;paint-order:stroke markers fill; visibility:visible", math.min(site_width, site_height), fgcolor, write_double(0.1*worldRegionMultiplier), bgcolor )
write_text(nil, nil, 0.5*site_width, site_height, style, symbol, siteStrings)
write_group(no.."-"..site_name, "entity-site-link", string.format("translate( %s, %s)", site.global_min_x, site.global_min_y), nil, siteStrings, totalSiteStrings)
end
log:write("<g id=\"sites\">\n")
for _, string in pairs(totalSiteStrings) do
log:write(string)
end
log:write("</g>")
log:write("<g id=\"entity_claims\" visibility=\"hidden\">")
listOfStrings = {}
for no, entity in pairs(df.global.world.entities.all) do
if (#entity.claims.border.x) > 0 then
local entity_name = dfhack.TranslateName(entity.name, true, true)
if (entity_name == "") then
entity_name = dfhack.TranslateName(entity.name)
end
local typeName = df.historical_entity_type[entity.type]
local fgcolor = "url(#"..no.."-"..remove_spaces(entity_name).."-fg)"
local bgcolor = "url(#"..no.."-"..remove_spaces(entity_name).."-bg)"
print("bounding.. "..entity_name.." border")
local bordercoords = grid_to_border(entity.claims.border)
print("done")
local path = ""
local max_x = 0
local max_y = 0
local min_x = width
local min_y = width
for i, subpath in pairs(bordercoords) do
path = path.." M "
for p, point in pairs(subpath) do
if p ~= 1 then
path = path.." L "
end
path = path..write_double(point.x*worldRegionMultiplier).." "..write_double(point.y*worldRegionMultiplier)
max_x = math.max(point.x, max_x)
max_y = math.max(point.y, max_y)
min_x = math.min(point.x, min_x)
min_y = math.min(point.y, min_y)
end
path = path.." z"
end
local borderPath = {}
write_path(nil, nil, path, "stroke:"..fgcolor.."; fill:"..bgcolor.."; opacity:0.5; stroke-width:1;", nil, borderPath)
table.insert(borderPath, "<title>"..entity_name..", "..typeName.."")
table.insert(borderPath, "</title>\n")
write_view(no.."-"..entity_name.."-view",
min_x*worldRegionMultiplier,
min_y*worldRegionMultiplier,
(max_x-min_x)*worldRegionMultiplier,
(max_y-min_y)*worldRegionMultiplier,
borderPath)
write_group(no.."-"..entity_name, nil, nil, nil, borderPath, listOfStrings)
end
end
for _, string in pairs(listOfStrings) do
log:write(string)
end
log:write("</g>")
log:write("</svg>\n")
log:close()
print("Succesfully saved data to "..documentName)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment