Compare commits

..

2 Commits

Author SHA1 Message Date
wan-may 7f457daa94 fixed the camera so its motion is no longer tied to framerate
limited minimum and maximum zoom on camera
changed point scaling so that cities get smaller when zooming in
changed selection cursor to hollow circle
changed capital cities to orange squares
included data/earth/ directory so that files are loaded from there when they're not available in the mod folder
when cities are hidden, hovering over travel nodes will display the travel node location (broken for now)
when cities and travel nodes are hidden, hovering over ai markers will display their details
made the information boxes more opaque
changed border-calculating code so that it works with higher resolutions
2024-04-24 22:09:38 -03:00
wan-may ce15bfdcf7 add drag and drop, parse lines more robustly 2024-04-21 13:07:56 -03:00
17 changed files with 225 additions and 135 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

34
ai.lua
View File

@ -1,13 +1,27 @@
--Manage the AI nodes used by DEFCON. --Manage the AI nodes used by DEFCON.
local t = {}
local bmp = require 'bmp' local bmp = require 'bmp'
local lg = assert( love.graphics ) local lg = assert( love.graphics )
local locationQuery = require 'locationQuery'
local t = setmetatable( {}, {__index = locationQuery } )
local print = print local print = print
local aiNode = {}
local mtAiNode = { __index = aiNode }
function aiNode:formatDisplayInfo()
return ([[AI NODE: %d
LONGITUDE: %3.2f
LATITUDE: %3.2f
ATTACKING: %s
]]):format( self.idx, self.x, self.y, tostring(self.attacking) )
end
function t.load( filename ) function t.load( filename )
local img, imgd = bmp.load( filename ) local img, imgd = bmp.load( filename )
local nodes = { local nodes = {
visible = true, visible = true,
all = {},
att = {}, att = {},
ptsAtt = {}, ptsAtt = {},
def = {}, def = {},
@ -16,15 +30,19 @@ function t.load( filename )
imgd = imgd } imgd = imgd }
print( "=== Loading AI Markers: ===" ) print( "=== Loading AI Markers: ===" )
local idx = 1
for x = 0, 511 do for x = 0, 511 do
for y = 0, 284 do for y = 0, 284 do
local r, g = imgd:getPixel( x, 284 - y ) local r, g = imgd:getPixel( x, 284 - y )
if r > 0.5 or g > 0.5 then if r > 0.5 or g > 0.5 then
local long = x * (360 / imgd:getWidth()) - 180 local long = x * (360 / imgd:getWidth()) - 180
local lat = y * (200 / img:getHeight()) - 100 local lat = y * (200 / img:getHeight()) - 100
local set = (r > 0.5) and nodes.att or nodes.def local attacking = (r > 0.5)
set[#set + 1] = {x = long, y = lat} local set = attacking and nodes.att or nodes.def
print( #set, long, lat ) local node = setmetatable( {x = long, y = lat, attacking = attacking, idx = idx}, mtAiNode )
nodes.all[ idx ] = node
set[#set + 1] = node
idx = idx + 1
end end
end end
end end
@ -43,7 +61,13 @@ function t.load( filename )
end end
end end
return setmetatable( nodes, {__index = t } ) nodes.all = locationQuery.New( nodes.all )
setmetatable( nodes, {__index = t } )
return nodes
end
function t.selectNearest( nodes, x, y )
return (nodes.all):getClosestPoint( x, y )
end end
function t.draw( nodes ) function t.draw( nodes )

View File

@ -20,12 +20,12 @@ function Camera.GetNodeCoordinate( x, y )
return tfNodes:inverseTransformPoint( x, y ) return tfNodes:inverseTransformPoint( x, y )
end end
function Camera.Zoom( out ) function Camera.Zoom( delta )
local scale = out and 1.1 or 0.9 local scale = 1.0 + delta
tf:scale( scale, scale ) if Camera.zoom < 25.0 and delta > 0 or --zooming in
local x = Camera.x Camera.zoom > 0.5 and delta < 0 then --zooming out
local y = Camera.y return Camera.Set( Camera.x , Camera.y, Camera.w * scale, Camera.h * scale )
return Camera.Set( x, y, Camera.w * scale, Camera.h * scale ) end
end end
function Camera.Translate( x, y ) function Camera.Translate( x, y )
@ -36,9 +36,8 @@ end
--In world coordinates: top left corner at x, y, extent of w, h. --In world coordinates: top left corner at x, y, extent of w, h.
function Camera.Set( x, y, w, h ) function Camera.Set( x, y, w, h )
print( ("CAMERA: %3.2f %3.2f %3.2f %3.2f"):format(x, y, w, h) )
Camera.x, Camera.y, Camera.w, Camera.h = x, y, w, h Camera.x, Camera.y, Camera.w, Camera.h = x, y, w, h
Camera.zoom = w / 360 Camera.zoom = w / 800
tf:reset() tf:reset()
tf:scale( w / 360, -h / 200 ) tf:scale( w / 360, -h / 200 )
tf:translate( 180 - x, -y - 100 ) tf:translate( 180 - x, -y - 100 )

View File

@ -23,26 +23,40 @@ function t.unlockSelection()
end end
function t.draw() function t.draw()
if cities.visible then lg.points( points ) end return lg.points( points )
end end
function t.drawSelected( r ) function t.drawSelected( )
if not cities.visible then return end
local c = t.selected local c = t.selected
if not c then return end if not c then return end
lg.circle( "fill", c.x, c.y, r ) lg.circle( "line", c.x, c.y, 1.0 )
end end
function t.drawCapitals() function t.drawCapitals()
if cities.visible then lg.points( caps ) end if cities.visible then lg.points( caps ) end
end end
function t.selectNearestCity(x, y) function t.selectNearest( cities, x, y )
if not t.selectionLocked then t.selected = cities:getClosestPoint(x, y) end return cities:getClosestPoint(x, y) --defer to locationQuery
end
local city = {}
local citymt = {__index = city}
function city:formatDisplayInfo()
return (
[[
NAME: %s
COUNTRY: %s
LONGITUDE: %3.2f
LATITUDE: %3.2f
POP: %d
CAPITAL: %s]]):format( self.name, self.country, self.x, self.y, self.pop, tostring(self.capital) )
end end
function t.load( filename ) function t.load( filename )
print( "=== LOADING CITIES. ===" )
cities = { visible = true, active = false } cities = { visible = true, active = false }
local n = 1 local n = 1
local idxPts = 1 local idxPts = 1
@ -51,12 +65,13 @@ function t.load( filename )
for line in assert( lfs.lines( filename ), "Error: could not open cities.dat" ) do for line in assert( lfs.lines( filename ), "Error: could not open cities.dat" ) do
local _, _, x, y, pop, capital = line:sub( 83 ):find( "(%g+)%s+(%g+)%s+(%g+)%s+(%g+)" ) local _, _, x, y, pop, capital = line:sub( 83 ):find( "(%g+)%s+(%g+)%s+(%g+)%s+(%g+)" )
if capital then --check against empty or malformed line
x, y, pop, capital = tonumber( x ), tonumber( y ), tonumber( pop ), ( tonumber( capital ) > 0) x, y, pop, capital = tonumber( x ), tonumber( y ), tonumber( pop ), ( tonumber( capital ) > 0)
local city = { local city = setmetatable({
name = line:sub( 1, 39 ):gsub("%s+$",""), name = line:sub( 1, 39 ):gsub("%s+$",""),
country = line:sub( 42, 82 ):gsub("%s+$",""), country = line:sub( 42, 82 ):gsub("%s+$",""),
x = x, y = y, pop = pop, capital = capital x = x, y = y, pop = pop, capital = capital
} }, citymt )
cities[n] = city cities[n] = city
n = n + 1 n = n + 1
@ -67,13 +82,16 @@ function t.load( filename )
caps[idxCaps], caps[idxCaps + 1] = x, y caps[idxCaps], caps[idxCaps + 1] = x, y
idxCaps = idxCaps + 2 idxCaps = idxCaps + 2
end end
else
print( "CITIES: malformed line:", line )
end
end end
--Multiple inheritance. --Multiple inheritance.
cities = locationQuery.New( cities ) cities = locationQuery.New( cities )
setmetatable( getmetatable( cities ).__index, {__index = t } ) setmetatable( getmetatable( cities ).__index, {__index = t } )
print( "LOADED", filename, n ) print( "=== CITIES LOADED:", filename, n, "===" )
return cities return cities
end end

View File

@ -11,7 +11,7 @@ function love.conf(t)
t.audio.mixwithsystem = true -- Keep background music playing when opening LOVE (boolean, iOS and Android only) t.audio.mixwithsystem = true -- Keep background music playing when opening LOVE (boolean, iOS and Android only)
t.window.title = "dcEarth" -- The window title (string) t.window.title = "dcEarth" -- The window title (string)
t.window.icon = "favicon.png" -- Filepath to an image to use as the window's icon (string) t.window.icon = "icons/favicon.png" -- Filepath to an image to use as the window's icon (string)
t.window.width = 800 -- The window width (number) t.window.width = 800 -- The window width (number)
t.window.height = 600 -- The window height (number) t.window.height = 600 -- The window height (number)
t.window.borderless = false -- Remove all border visuals from the window (boolean) t.window.borderless = false -- Remove all border visuals from the window (boolean)
@ -44,7 +44,7 @@ function love.conf(t)
t.modules.sound = false -- Enable the sound module (boolean) t.modules.sound = false -- Enable the sound module (boolean)
t.modules.system = true -- Enable the system module (boolean) t.modules.system = true -- Enable the system module (boolean)
t.modules.thread = false -- Enable the thread module (boolean) t.modules.thread = false -- Enable the thread module (boolean)
t.modules.timer = false -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update
t.modules.touch = false -- Enable the touch module (boolean) t.modules.touch = false -- Enable the touch module (boolean)
t.modules.video = false -- Enable the video module (boolean) t.modules.video = false -- Enable the video module (boolean)
t.modules.window = true -- Enable the window module (boolean) t.modules.window = true -- Enable the window module (boolean)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 KiB

BIN
icons/eye.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -9,18 +9,27 @@ function t.load( filename )
local n = 0 local n = 0
local k = 1 local k = 1
for line in assert( lfs.lines( filename ) ) do for line in assert( lfs.lines( filename ) ) do
if line == "b" then if line:find "b" then
k = 1 k = 1
n = n + 1 if #poly > 2 then n = n + 1 end
poly = {} poly = {}
polys[n] = poly polys[n] = poly
else else
local _, _, x, y = line:find( "(%g+)%s+(%g+)" ) local _, _, x, y = line:find( "(%g+)%s+(%g+)" )
x, y = assert( tonumber( x ) ), assert( tonumber( y ) ) x, y = tonumber( x ), tonumber( y )
if x and y then
poly[k], poly[ k + 1 ] = x, y poly[k], poly[ k + 1 ] = x, y
k = k + 2 k = k + 2
else
print( "LINES: malformed line:", filename, line )
end end
end end
end
if not polys[n] or (#(polys[n]) < 3) then
polys[n] = nil
n = n - 1
end
print( "LOADED", filename, n ) print( "LOADED", filename, n )
return setmetatable( polys, {__index = t } ) return setmetatable( polys, {__index = t } )

View File

@ -1,7 +1,6 @@
--Shitty acceleration structure: get closest point in set. --Shitty acceleration structure: get closest point in set.
--Assumed to be in world coordinates: ( -180, 180 ) x ( -100, 100 ) --Assumed to be in world coordinates: ( -180, 180 ) x ( -100, 100 )
local t = {} local t = {}
local hashes = {}
local math = math local math = math
local hash = function( x, y, debug ) local hash = function( x, y, debug )
@ -9,9 +8,18 @@ local hash = function( x, y, debug )
return s return s
end end
function t.getHashes( points )
return assert( points.hashes )
end
function t.getClosestPoint( points, x, y ) function t.getClosestPoint( points, x, y )
local hashes = t.getHashes( points )
local closePoints = hashes[hash( x, y )] local closePoints = hashes[hash( x, y )]
if not closePoints then return end
if not closePoints then
return
end
local distance = math.huge local distance = math.huge
local px, py, point local px, py, point
for k, v in pairs(closePoints) do for k, v in pairs(closePoints) do
@ -29,6 +37,7 @@ function t.getClosestPoint( points, x, y )
end end
function t.Edit( points, point, x, y ) function t.Edit( points, point, x, y )
local hashes = t.getHashes( points )
local h = hashes[hash( point.x, point.y )] local h = hashes[hash( point.x, point.y )]
if h then if h then
for i, p in pairs(h) do for i, p in pairs(h) do
@ -50,13 +59,21 @@ function t.Add( points, x, y )
end end
function t.New( points ) function t.New( points )
local hashes = {}
for i = 1, #points do for i = 1, #points do
local x, y = points[i].x, points[i].y local x, y = points[i].x, points[i].y
local h = hash( x, y ) local h = hash( x, y )
hashes[h] = hashes[h] or {} hashes[h] = hashes[h] or {}
hashes[h][#hashes[h] + 1] = points[i] hashes[h][#hashes[h] + 1] = points[i]
end end
return setmetatable( points, {__index = t } ) points.hashes = hashes
do
local count = 0
for k, v in pairs(hashes) do count = count + 1 end
print( "LOCATION QUERY. Points:", count )
end
return setmetatable( points, {__index = t} )
end end
return t return t

View File

@ -1,4 +1,5 @@
local love = assert( love, "This tool requires LOVE: love2d.org" ) local love = assert( love, "This tool requires LOVE: love2d.org" )
--assert( require('mobdebug') ).start() --remote debugger
local map = require 'map' local map = require 'map'
local button = require 'button' local button = require 'button'
local SAVEDIRECTORY = "out/" local SAVEDIRECTORY = "out/"
@ -11,21 +12,25 @@ function love.load()
lfs.setIdentity( "dcearth", false ) lfs.setIdentity( "dcearth", false )
assert( lfs.createDirectory( SAVEDIRECTORY.."data/earth" )) assert( lfs.createDirectory( SAVEDIRECTORY.."data/earth" ))
assert( lfs.createDirectory( SAVEDIRECTORY.."data/graphics" )) assert( lfs.createDirectory( SAVEDIRECTORY.."data/graphics" ))
map.load()
love.graphics.setNewFont( 12, "mono" ) love.graphics.setNewFont( 12, "mono" )
end end
function love.directorydropped( path )
love.filesystem.mount( path, "" )
return map.load( path )
end
function love.update( dt ) function love.update( dt )
local tx, ty = 0, 0 local tx, ty = 0, 0
local moveCamera = false local moveCamera = false
if love.keyboard.isScancodeDown( "w" ) then moveCamera = true; ty = ty + 1 end if love.keyboard.isScancodeDown( "w" ) then moveCamera = true; ty = ty + 30 * dt end
if love.keyboard.isScancodeDown( "a" ) then moveCamera = true; tx = tx - 1 end if love.keyboard.isScancodeDown( "a" ) then moveCamera = true; tx = tx - 30 * dt end
if love.keyboard.isScancodeDown( "s" ) then moveCamera = true; ty = ty - 1 end if love.keyboard.isScancodeDown( "s" ) then moveCamera = true; ty = ty - 30 * dt end
if love.keyboard.isScancodeDown( "d" ) then moveCamera = true; tx = tx + 1 end if love.keyboard.isScancodeDown( "d" ) then moveCamera = true; tx = tx + 30 * dt end
if love.keyboard.isScancodeDown( "q" ) then Camera.Zoom( true ) end if love.keyboard.isScancodeDown( "q" ) then Camera.Zoom( dt ) end
if love.keyboard.isScancodeDown( "e" ) then Camera.Zoom( false ) end if love.keyboard.isScancodeDown( "e" ) then Camera.Zoom( -dt ) end
if moveCamera then Camera.Translate( tx, ty ) end if moveCamera then Camera.Translate( tx, ty ) end
@ -57,6 +62,10 @@ local layerButtons = {
function love.draw() function love.draw()
if not map.loaded then
return love.graphics.print( "Drag and drop folder to begin.")
end
love.graphics.push( "all" ) love.graphics.push( "all" )
map.draw() map.draw()
love.graphics.pop() love.graphics.pop()
@ -76,7 +85,7 @@ function love.draw()
local wx, wy = Camera.GetWorldCoordinate( x, y ) local wx, wy = Camera.GetWorldCoordinate( x, y )
local bx, by = Camera.GetBitmapCoordinate( x, y ) local bx, by = Camera.GetBitmapCoordinate( x, y )
local h = love.graphics.getHeight() - 30 local h = love.graphics.getHeight() - 30
love.graphics.setColor( 0.2, 0.1, 0.1, 0.5 ) love.graphics.setColor( 0.2, 0.1, 0.1, 1.0 )
love.graphics.rectangle( "fill", 0, h, love.graphics.getWidth() / 2, 30 ) love.graphics.rectangle( "fill", 0, h, love.graphics.getWidth() / 2, 30 )
love.graphics.setColor( 1, 1, 1, 1 ) love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, h, love.graphics.getWidth() / 2, 30 ) love.graphics.rectangle( "line", 0, h, love.graphics.getWidth() / 2, 30 )
@ -85,30 +94,13 @@ function love.draw()
--Edit box. --Edit box.
love.graphics.rectangle( "line", love.graphics.getWidth() / 2, h, love.graphics.getWidth() / 2, 30 ) love.graphics.rectangle( "line", love.graphics.getWidth() / 2, h, love.graphics.getWidth() / 2, 30 )
if map.cities.selected then if map.selected then
local c = map.cities.selected love.graphics.setColor( 0.2, 0.1, 0.1, 1.0 )
love.graphics.setColor( 0.2, 0.1, 0.1, 0.5 )
love.graphics.rectangle( "fill", 0, 0, 150 ,100 ) love.graphics.rectangle( "fill", 0, 0, 150 ,100 )
love.graphics.setColor( 1, 1, 1, 1 ) love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, 0, 150 ,100 ) love.graphics.rectangle( "line", 0, 0, 150 ,100 )
love.graphics.setColor( 1.2, 1.1, 1.1, 1.5 ) love.graphics.setColor( 1.2, 1.1, 1.1, 1.5 )
love.graphics.print( ("NAME: %s\nX: %3.2f\nY: %3.2f\nPOP: %d\nCAPITAL: %s\nCOUNTRY: %s"):format(c.name, c.x, c.y, c.pop, tostring(c.capital), c.country), 0, 0 ) love.graphics.print( map.selected:formatDisplayInfo(), 0, 0 )
elseif map.travelnodes.selected then
local c = map.travelnodes.selected
love.graphics.setColor( 0.2, 0.1, 0.1, 0.5 )
love.graphics.rectangle( "fill", 0, 0, 150 ,100 )
love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, 0, 150 ,100 )
love.graphics.setColor( 1.2, 1.1, 1.1, 1.5 )
love.graphics.print( ("Node: %d\nX: %3.2f\nY: %3.2f\n"):format(c.number, c.x, c.y) )
elseif map.ainodes.selectedNode then
local c = map.ainodes.selected
love.graphics.setColor( 0.2, 0.1, 0.1, 0.5 )
love.graphics.rectangle( "fill", 0, 0, 150 ,100 )
love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, 0, 150 ,100 )
love.graphics.setColor( 1.2, 1.1, 1.1, 1.5 )
love.graphics.print( ("Node: %d\nX: %3.2f\nY: %3.2f\noffensive: %s"):format(c.number, c.x, c.y, c.attack) )
end end
end end
@ -117,21 +109,29 @@ function love.resize(w, h)
end end
function love.wheelmoved(x, y) function love.wheelmoved(x, y)
Camera.Zoom( (y > 0) and true or false ) Camera.Zoom( (y > 0) and 0.5 or -0.5 )
end end
function love.mousepressed( x, y, button, istouch, presses ) function love.mousepressed( x, y, button, istouch, presses )
local wx, wy = Camera.GetWorldCoordinate( x, y ) local wx, wy = Camera.GetWorldCoordinate( x, y )
if map.loaded then
if button == 1 then if button == 1 then
map.cities.lockSelection() map.cities.lockSelection()
else else
map.cities.unlockSelection() map.cities.unlockSelection()
end end
end
print( ("MOUSE\tx %f\ty %f\twx %f\twy %f"):format(x, y, wx, wy) ) print( ("MOUSE\tx %f\ty %f\twx %f\twy %f"):format(x, y, wx, wy) )
end end
function love.mousemoved( x, y, dx, dy, istouch ) function love.mousemoved( x, y, dx, dy, istouch )
map.cities.selectNearestCity( Camera.GetWorldCoordinate( x, y ) ) local wx, wy = Camera.GetWorldCoordinate( x, y )
if map.loaded then
if map.cities.visible then map.selected = map.cities:selectNearest( wx, wy )
elseif map.travelnodes.visible then map.selected = map.travelnodes:selectNearest( wx, wy )
elseif map.ainodes.visible then map.selected = map.ainodes:selectNearest( wx, wy )
end
end
end end
local function ToggleVisibility( layer ) local function ToggleVisibility( layer )
@ -155,7 +155,9 @@ local layerVisibilityKeybinds = {
["8"] = "coastlines", ["8"] = "coastlines",
["9"] = "coastlinesLow", ["9"] = "coastlinesLow",
["0"] = "international", ["0"] = "international",
["-"] = "cities" ["-"] = "cities",
["="] = "travelnodes",
["backspace"] = "ainodes",
} }
function love.keypressed(key) function love.keypressed(key)

43
map.lua
View File

@ -2,12 +2,12 @@ local lg = love.graphics
local AI = require 'ai' local AI = require 'ai'
local Cities = require 'cities' local Cities = require 'cities'
local Lines = require 'lines' local Lines = require 'lines'
local Nodes = require 'nodes' local Nodes = require 'travelNodes'
local Bitmap = require 'bmp'
local Camera = require 'camera' local Camera = require 'camera'
local Territory = require 'territory' local Territory = require 'territory'
local map = { local map = {
loaded = false,
coastlines = false, coastlines = false,
coastlinesLow = false, coastlinesLow = false,
international = false, international = false,
@ -21,11 +21,11 @@ local map = {
}, },
travelnodes = false, travelnodes = false,
sailable = false, sailable = false,
aimarkers = false, ainodes = false,
cities = false cities = false
} }
function map.load() function map.load( )
map.cities = Cities.load( "data/earth/cities.dat" ) map.cities = Cities.load( "data/earth/cities.dat" )
map.coastlines = Lines.load( "data/earth/coastlines.dat" ) map.coastlines = Lines.load( "data/earth/coastlines.dat" )
map.coastlinesLow = Lines.load( "data/earth/coastlines-low.dat" ) map.coastlinesLow = Lines.load( "data/earth/coastlines-low.dat" )
@ -36,10 +36,12 @@ function map.load()
for k, v in pairs(map.territory) do for k, v in pairs(map.territory) do
map.territory[k] = Territory.load( "data/earth/"..k..".bmp", k ) map.territory[k] = Territory.load( "data/earth/"..k..".bmp", k )
end end
map.loaded = true
end end
function map.draw() function map.draw()
lg.clear( 0, 0, 0, 1 ) lg.clear( 0, 0, 0, 1 )
if not map.loaded then return end
do --territory do --territory
lg.setColor( 1,1,1,1) lg.setColor( 1,1,1,1)
@ -55,13 +57,9 @@ function map.draw()
v:drawBorder( "sea" ) v:drawBorder( "sea" )
end end
end end
if map.sailable.visible then map.sailable:draw() end if map.sailable.visible then
lg.setBlendMode( "alpha" ) map.sailable:draw()
lg.setColor( 1, 1, 1, 1 )
end
do --borders
lg.setLineJoin( "none" ) lg.setLineJoin( "none" )
lg.setLineWidth( 1 / Camera.zoom ) lg.setLineWidth( 1 / Camera.zoom )
@ -71,25 +69,35 @@ function map.draw()
lg.setLineWidth( 3 / Camera.zoom ) lg.setLineWidth( 3 / Camera.zoom )
map.sailable:drawBorder( "placeable" ) map.sailable:drawBorder( "placeable" )
end end
lg.setBlendMode( "alpha" )
lg.setColor( 1, 1, 1, 1 )
end
do --all this stuff is drawn in world coordinates, ( -180, 180 ) x ( -100, 100 ) do --all this stuff is drawn in world coordinates, ( -180, 180 ) x ( -100, 100 )
lg.replaceTransform( Camera.tf ) lg.replaceTransform( Camera.tf )
do --points if map.selected then
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
if map.cities.visible then --points
lg.setColor( 1, 0, 0, 0.5 ) lg.setColor( 1, 0, 0, 0.5 )
lg.setPointSize( 0.5 * Camera.zoom ) lg.setPointSize( 5.0 )
map.cities.draw() map.cities.draw()
lg.setColor( 1, 1, 1.0, 0.5 ) lg.setColor( 1, 1, 0.0, 0.5 )
lg.setPointSize( 1.0 * Camera.zoom )
map.cities.drawCapitals() map.cities.drawCapitals()
lg.setColor( 1, 1, 1, 0.5 ) end
map.cities.drawSelected( 15.0 / Camera.zoom )
if map.ainodes.visible then
lg.setPointSize( 5.0 )
map.ainodes:draw() map.ainodes:draw()
end end
@ -115,8 +123,11 @@ function map.draw()
do --travel nodes do --travel nodes
lg.replaceTransform( Camera.tfNodes ) lg.replaceTransform( Camera.tfNodes )
if map.travelnodes.visible then
map.travelnodes:draw() map.travelnodes:draw()
end end
end
end end

View File

@ -109,8 +109,9 @@ function t.computeBorder( territory, threshold, key )
local border = territory[key] local border = territory[key]
local n = 1 local n = 1
for x = 0, 511 do local w, h = territory.imgd:getWidth() - 1, territory.imgd:getHeight() - 1
for y = 0, 284 do for x = 0, w do
for y = 0, h do
--Bottom left, bottom right, and top right of pixel in image coordinates: --Bottom left, bottom right, and top right of pixel in image coordinates:
local blx, bly = x, y + 1 local blx, bly = x, y + 1
local brx, bry = x + 1, y + 1 local brx, bry = x + 1, y + 1

View File

@ -1,10 +1,13 @@
--Manage the pathfinding nodes used by DEFCON. --Manage the pathfinding nodes used by DEFCON.
--This is important for a mapping tool because the DEFCON client will not load a map unless --This is important for a mapping tool because the DEFCON client will not load a map unless
--the pathfinding nodes form a connected graph. --the pathfinding nodes form a connected graph.
local t = {}
local bmp = require 'bmp' local bmp = require 'bmp'
local locationQuery = require 'locationQuery'
local lg = assert( love.graphics ) local lg = assert( love.graphics )
local t = setmetatable({}, {__index = locationQuery})
local isSailable local isSailable
local function isConnected( startNode, endNode ) local function isConnected( startNode, endNode )
@ -25,15 +28,17 @@ local function isConnected( startNode, endNode )
return true return true
end end
function t.getClosest( nodes, x, y ) function t.selectNearest( nodes, x, y )
local d = math.huge return (nodes.nodes):getClosestPoint( x, y )
local closestNode end
for _, node in pairs( nodes.nodes ) do
local nx, ny = node.x, node.y local travelNode = {}
local nd = (nx - x) * (nx - x) + (ny - y) * (ny - y) local mtTravelNode = { __index = travelNode }
if nd < d then d = nd; closestNode = node end
end function travelNode:formatDisplayInfo()
return closestNode return ([[ TRAVEL NODE: %d
LONGITUDE: %3.2f
LATITUDE: %3.2f]]):format( self.idx, self.x, self.y )
end end
function t.load( filename, sailable ) function t.load( filename, sailable )
@ -49,10 +54,10 @@ function t.load( filename, sailable )
if imgd:getPixel( x, 399 - y ) > 0 then if imgd:getPixel( x, 399 - y ) > 0 then
local long = 360 * ( x - 800 ) / 800 - 360 / 2 + 360 local long = 360 * ( x - 800 ) / 800 - 360 / 2 + 360
local lat = 360 * ( 600 / 800 ) * ( 600 - y ) / 600 - 180 local lat = 360 * ( 600 / 800 ) * ( 600 - y ) / 600 - 180
nodes.nodes[n] = {x = long, y = lat} nodes.nodes[n] = setmetatable({x = long, y = lat, idx = n}, mtTravelNode )
print( nodes.nodes[n]:formatDisplayInfo() )
nodes.points[ 2 * n - 1 ] = long nodes.points[ 2 * n - 1 ] = long
nodes.points[ 2 * n ] = lat nodes.points[ 2 * n ] = lat
print( n, long, lat )
n = n + 1 n = n + 1
end end
end end
@ -69,7 +74,9 @@ function t.load( filename, sailable )
end end
print( "=== Nodes Loaded ===" ) print( "=== Nodes Loaded ===" )
return setmetatable( nodes, {__index = t } ) nodes.nodes = locationQuery.New( nodes.nodes )
setmetatable( nodes, {__index = t} )
return nodes
end end
--Determine if graph has more than one connected component. --Determine if graph has more than one connected component.
@ -78,9 +85,13 @@ function t.isConnected( nodes )
end end
function t.draw( nodes ) function t.draw( nodes )
lg.setPointSize( 10 ) lg.setPointSize( 8 )
lg.setColor( 1, 1, 1, 0.5 ) lg.setColor( 1, 1, 1, 0.5 )
lg.points( nodes.points ) lg.points( nodes.points )
return t.drawConnections( nodes )
end
function t.drawConnections( nodes )
for i, connection in pairs( nodes.connections ) do for i, connection in pairs( nodes.connections ) do
for j in pairs( connection ) do for j in pairs( connection ) do
@ -88,9 +99,6 @@ function t.draw( nodes )
lg.line( ix, iy, fx, fy ) lg.line( ix, iy, fx, fy )
end end
end end
end
function t.drawConnections( nodes )
end end