dcearth/map/map.lua

268 lines
7.0 KiB
Lua

local love = assert( love )
local io = io
local coroutine = coroutine
local mkdir = assert( require 'lib.mkdir' )
local lg = love.graphics
local AI = require 'map.ai'
local Cities = require 'map.cities'
local Lines = require 'map.lines'
local Nodes = require 'map.travelNodes'
local Camera = require 'ui.camera'
local Territory = require 'map.territory'
local Blur = require 'map.blur'
--flat list of editable layers for convenience
local layers = {
coastlines = false,
coastlinesLow = false,
international = false,
africa = false,
europe = false,
northamerica = false,
russia = false,
southamerica = false,
southasia = false,
travelnodes = false,
sailable = false,
ainodes = false,
cities = false,
blur = false,
}
local map = {
layers = layers,
path = false,
loaded = false,
selected = false,
selectionLocked = false,
editLayer = false,
territory = {
africa = false,
europe = false,
northamerica = false,
russia = false,
southamerica = false,
southasia = false
},
background = false,
coastlines = false,
coastlinesLow = false,
international = false,
travelnodes = false,
sailable = false,
ainodes = false,
cities = false,
blur = false,
}
function map.reloadLayer( path )
--Shouldn't call this before the map loads, but just in case
if not map.loaded then return end
for name, layer in pairs( layers ) do
if layer.filename and
(layer.filename:gsub( ".+[\\/]", "") == path.filename:gsub( ".+[\\/]", "" )) then
local newLayer = layer:load( path )
newLayer.filename = layer.filename --we don't store the full path in there
map[ name ] = newLayer
layers[ name ] = newLayer
return layer.filename
end
end
return
end
function map.load( path )
map.background = lg.newImage( "/data/graphics/blur.bmp" )
map.cities = Cities.load( "/data/earth/cities.dat" )
map.coastlines = Lines.load( "/data/earth/coastlines.dat" )
map.coastlinesLow = Lines.load( "/data/earth/coastlines-low.dat" )
map.international = Lines.load( "/data/earth/international.dat" )
map.sailable = Territory.load( "/data/earth/sailable.bmp", "sailable" )
map.travelnodes = Nodes.load( "/data/earth/travel_nodes.bmp", map.sailable.isSailable ) --travel node adjacency matrix depends on sailable bitmap
map.ainodes = AI.load( "/data/earth/ai_markers.bmp" )
map.blur = Blur.load( "/data/graphics/blur.bmp", map )
for k, v in pairs(map.territory) do
map.territory[k] = Territory.load( "/data/earth/"..k..".bmp", k )
end
map.loaded = true
map.path = path
--update references
for k, v in pairs( layers ) do
layers[k] = map[k] or map.territory[k]
end
end
function map.draw()
love.graphics.setScissor( 0, 200, love.graphics.getWidth(), love.graphics.getHeight() - 200 )
lg.clear( 0, 0, 0, 1 )
if not map.loaded then return end
do --territory
lg.setLineJoin( "none" )
lg.replaceTransform( Camera.tfTerritory )
lg.setBlendMode( "add" )
lg.setColor( 1, 1, 1, 0.2 )
--lg.draw( map.background )
lg.setColor( 1, 1, 1, 0.5 )
local sh = require 'shaders.sailable'
lg.setShader( sh )
sh:send( "lowBorder", 60 )
sh:send( "highBorder", 130 )
for k, v in pairs(map.territory) do
if v.visible then
v:draw()
--[[lg.setLineWidth( 1 / Camera.zoom )
v:drawBorder( "land" )
lg.setLineWidth( 3 / Camera.zoom )
v:drawBorder( "sea" )]]
end
end
if map.sailable.visible then
sh:send( "lowBorder", 20 )
sh:send( "highBorder", 60 )
lg.setShader( require 'shaders.sailable' )
map.sailable:draw()
end
lg.setShader()
lg.setBlendMode( "alpha" )
lg.setColor( 1, 1, 1, 1 )
end
do --all this stuff is drawn in world coordinates, ( -180, 180 ) x ( -100, 100 )
lg.replaceTransform( Camera.tf )
if map.selected then
if map.selected[1] then --lines
local p = map.selected
lg.setColor( 0.4, 0.5, 0.8, 0.5 )
lg.setLineWidth( 0.2 / Camera.zoom )
lg.rectangle( "fill", p.x, p.y, p.X - p.x, p.Y - p.y )
lg.setColor( 1.0, 0, 0, 0.5 )
lg.line( p )
p:drawDirection()
else --points
lg.setColor( 1.0, 0.5, 0.5, 0.9 )
lg.setLineJoin( "miter" )
lg.setLineWidth( 1.0 / Camera.zoom )
lg.circle( "line", map.selected.x, map.selected.y, 0.2 + 1.0 / Camera.zoom )
end
end
if map.cities.visible then --points
lg.setColor( 1, 0, 0, 0.5 )
lg.setPointSize( 5.0 )
map.cities.draw()
lg.setColor( 1, 1, 0.0, 0.5 )
map.cities.drawCapitals()
end
if map.ainodes.visible then
lg.setPointSize( 5.0 )
map.ainodes:draw()
end
do --line stuff
lg.setColor(1, 1, 1, 0.2 )
lg.setLineJoin( "miter" )
lg.setLineWidth( 0.2 / Camera.zoom )
map.international:draw()
lg.setColor(1, 1, 1, 0.5 )
map.coastlines:draw()
map.coastlinesLow:draw()
--International Date Line
lg.line( -180, -100, -180, 100 )
lg.line( 180, -100, 180, 100 )
lg.line( -180, 90, 180, 90 )
lg.line( -180, -90, 180, -90 )
lg.line( -180, 100, 180, 100 )
lg.line( -180, -100, 180, -100 )
end
do --travel nodes
lg.replaceTransform( Camera.tfNodes )
if map.travelnodes.visible then
map.travelnodes:draw()
end
end
end
end
do
local function write( filename, string )
local file = assert( io.open( filename, "wb" ) )
assert( file:write( string ) )
assert( file:flush() ) --your toilet is set to stun, not kill
file:close()
end
local function save()
--should be cross platform-ish.
--race condition, unfortunately.
--maybe we should do this on part on load, then keep a lockfile open in each of these folders
for _, folder in ipairs{ "/data/", "/data/earth/", "/data/graphics/" } do
coroutine.yield( "Creating folder ".. folder )
assert( mkdir.exists( map.path ), map.path )
local path = map.path..folder
if not mkdir.exists( path ) then mkdir.mkdir( path ) end
end
local files = {}
--Write everything to strings first, in case there are errors we don't want to half-write the map
for k, layer in pairs( layers ) do
coroutine.yield( "Exporting layer ".. k )
files[ map.path..tostring( layer.filename ) ] = assert( layer:save() )
end
for filename, str in pairs( files ) do
coroutine.yield( "Writing ".. filename )
write( filename, str )
end
coroutine.yield() --yield nothing to indicate we're done
return save() --save again
end
map.save = coroutine.wrap( save )
end
function map.hover(x, y)
end
function map.undo()
print( "=== UNDO ===" )
end
function map.setEditLayer( layerName )
if not layerName then
map.editLayer = nil
for name, layer in pairs( layers ) do layer.visible = true end
else
for name, layer in pairs( layers ) do
layer.visible = false
end
map.editLayer = layers[ layerName ]
if map.editLayer then map.editLayer.visible = true end
end
end
return map