dcearth/map/cities.lua

174 lines
4.0 KiB
Lua

--Load and save the fixed width plaintext data used by DEFCON.
local t = {}
local io = io
local math = math
local table = table
local tonumber = tonumber
local lfs = love.filesystem
local lg = love.graphics
local locationQuery = require 'map.locationQuery'
local cities
local points = {}
local caps = {}
t.selected = nil
t.selectionLocked = false
local invisible = 10000 --sentinel value outside the draw rectangle
function t.lockSelection()
t.selectionLocked = true
end
function t.unlockSelection()
t.selectionLocked = false
end
function t.draw()
return lg.points( points )
end
function t.drawSelected( )
local c = t.selected
if not c then return end
lg.circle( "line", c.x, c.y, 1.0 )
end
function t.drawCapitals()
if cities.visible then lg.points( caps ) end
end
function t.selectNearest( cities, x, y )
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
function city:delete()
print( "deleting city:", self.name )
self.deleted = true
if self.capital then
caps[ self.caps ] = invisible
caps[ self.caps + 1] = invisible
end
points[ self.points ] = invisible
points[ self.points + 1] = invisible
end
function city:add()
local n = #cities + 1
cities[ n ] = self
self.n = n
local idxPoints = #points + 1
self.points = idxPoints
points[ idxPoints ], points[ idxPoints + 1 ] = self.x, self.y
end
function city:moveTo(x, y)
self.x, self.y = x, y
if self.points then
points[ self.points ] = x
points[ self.points + 1 ] = y
end
if self.capital then
caps[ self.caps ] = x
caps[ self.caps + 1 ] = y
end
end
function city:toggleCapital()
if self.capital then
self.capital = false
caps[ self.caps ] = invisible
caps[ self.caps + 1 ] = invisible
else
self.capital = true
local idx = #caps + 1
caps[ idx ] = self.x
caps[ idx + 1 ] = self.y
self.caps = idx
end
end
function t.newCity( tbl )
return setmetatable({
name = "",
country = "",
x = 0,
y = 0,
pop = 0,
capital = false,
}, citymt )
end
function t.load( filename )
print( "=== LOADING CITIES. ===" )
cities = { visible = true, active = false, filename = filename }
local n = 1
local idxPts = 1
local idxCaps = 1
points = {}
caps = {}
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+)" )
if capital then --check against empty or malformed line
x, y, pop, capital = tonumber( x ), tonumber( y ), tonumber( pop ), ( tonumber( capital ) > 0)
local city = setmetatable({
name = line:sub( 1, 39 ):gsub("%s+$",""),
country = line:sub( 42, 82 ):gsub("%s+$",""),
x = x, y = y, pop = pop, capital = capital,
n = n, points = idxPts, caps = capital and idxCaps
}, citymt )
cities[n] = city
n = n + 1
points[idxPts], points[idxPts + 1] = x, y
idxPts = idxPts + 2
if capital then
caps[idxCaps], caps[idxCaps + 1] = x, y
idxCaps = idxCaps + 2
end
else
print( "CITIES: malformed line:", line )
end
end
--Multiple inheritance.
cities = locationQuery.New( cities )
setmetatable( getmetatable( cities ).__index, {__index = t } )
print( "=== CITIES LOADED:", filename, n, "===" )
return cities
end
function t.save( cities )
local str = {}
local i = 1
for _, city in ipairs( cities ) do
if not city.deleted then
str[i] = ("%-41s%-41s%-14f%-14f%-19d %d"):format(
city.name, city.country, city.x, city.y, city.pop, city.capital and 1 or 0 )
i = i + 1
end
end
return assert(table.concat( str, "\n" ))
end
return t