sketch out more menus, implement editing and deleting cities, quantize 8-bit sailables back to 4
BIN
icons/check.png
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 391 B |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
14
main.lua
|
@ -64,12 +64,14 @@ end
|
||||||
function love.mousemoved( x, y, dx, dy, istouch )
|
function love.mousemoved( x, y, dx, dy, istouch )
|
||||||
if not map.loaded then return end
|
if not map.loaded then return end
|
||||||
--mouse over menu
|
--mouse over menu
|
||||||
button.selectIn( x, y )
|
if y < mainmenu.menuHeight then
|
||||||
|
button.selectIn( x, y )
|
||||||
--mouse on map
|
--mouse on map
|
||||||
if map.selectionLocked then return end
|
else
|
||||||
if map.editLayer and map.editLayer.selectNearest then
|
if map.selectionLocked then return end
|
||||||
map.selected = map.editLayer:selectNearest( Camera.GetWorldCoordinate( x, y ) )
|
if map.editLayer and map.editLayer.selectNearest then
|
||||||
|
map.selected = map.editLayer:selectNearest( Camera.GetWorldCoordinate( x, y ) )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
12
map/ai.lua
|
@ -17,6 +17,14 @@ function aiNode:formatDisplayInfo()
|
||||||
]]):format( self.idx, self.x, self.y, tostring(self.attacking) )
|
]]):format( self.idx, self.x, self.y, tostring(self.attacking) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function aiNode:add()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function aiNode:moveTo( x, y )
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
@ -82,4 +90,8 @@ function t.save( nodes )
|
||||||
return bmp.ai( nodes.all )
|
return bmp.ai( nodes.all )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function t.newNode( isAttacking )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
return t
|
return t
|
75
map/bmp.lua
|
@ -244,40 +244,63 @@ function formats.sailable:test()
|
||||||
print "sailable OK"
|
print "sailable OK"
|
||||||
end
|
end
|
||||||
|
|
||||||
function formats.sailable:encode( data )
|
|
||||||
local w, h = self.w, self.h
|
|
||||||
local bytes = { self.header:sub( 1, -2 ) }
|
|
||||||
local i = 2
|
|
||||||
|
|
||||||
--y coordinates are written top to bottom
|
do --sailable
|
||||||
for y = h - 1, 0, -1 do
|
|
||||||
for x = 0, w - 1 do
|
local reversePalette = {}
|
||||||
bytes[i] = assert( self.palette[ math.floor( data:getPixel(x, y) * 255 )] )
|
for eight, four in pairs( formats.sailable.palette ) do
|
||||||
i = i + 1
|
reversePalette[ four ] = eight
|
||||||
|
end
|
||||||
|
|
||||||
|
--take the red channel in float [0, 1] format
|
||||||
|
--expand it to a byte, then quantize it to 4 bits
|
||||||
|
--according to the sailable palette
|
||||||
|
local function sailableQuantize( r )
|
||||||
|
if r == 0 then return 0 end
|
||||||
|
if r >= 1 then return 15 end
|
||||||
|
r = math.floor( r * 255 )
|
||||||
|
|
||||||
|
for four = 1, #reversePalette do
|
||||||
|
if reversePalette[ four ] > r then return four end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
error( "Could not quantize sailable.bmp!" )
|
||||||
end
|
end
|
||||||
|
|
||||||
--fold into 4-bit pixel array
|
function formats.sailable:encode( data )
|
||||||
local nybbles = { bytes[1] }
|
local w, h = self.w, self.h
|
||||||
for j = 2, #bytes / 2 do
|
local bytes = { self.header:sub( 1, -2 ) }
|
||||||
local a, b = bytes[ 2 * j ], bytes[ 2 * j + 1 ]
|
local i = 2
|
||||||
nybbles[j] = string.char( 16 * a + b )
|
|
||||||
|
--y coordinates are written top to bottom
|
||||||
|
for y = h - 1, 0, -1 do
|
||||||
|
for x = 0, w - 1 do
|
||||||
|
bytes[i] = sailableQuantize( data:getPixel(x, y) )
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--fold into 4-bit pixel array
|
||||||
|
local nybbles = { bytes[1] }
|
||||||
|
for j = 2, #bytes / 2 do
|
||||||
|
local a, b = bytes[ 2 * j ], bytes[ 2 * j + 1 ]
|
||||||
|
nybbles[j] = string.char( 16 * a + b )
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat( nybbles )
|
||||||
end
|
end
|
||||||
|
|
||||||
return table.concat( nybbles )
|
function formats.africa:test()
|
||||||
|
print "testing africa"
|
||||||
|
local filename = "data/earth/africa.bmp"
|
||||||
|
local img, imgd = test.load( filename )
|
||||||
|
local encoded = self:encode( imgd )
|
||||||
|
love.filesystem.write( "africa_out.bmp", encoded )
|
||||||
|
test.compareData( love.filesystem.read( filename ), encoded )
|
||||||
|
print "africa OK"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function formats.africa:test()
|
|
||||||
print "testing africa"
|
|
||||||
local filename = "data/earth/africa.bmp"
|
|
||||||
local img, imgd = test.load( filename )
|
|
||||||
local encoded = self:encode( imgd )
|
|
||||||
love.filesystem.write( "africa_out.bmp", encoded )
|
|
||||||
test.compareData( love.filesystem.read( filename ), encoded )
|
|
||||||
print "africa OK"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function formats.africa:encode( data )
|
function formats.africa:encode( data )
|
||||||
local w, h = self.w, self.h
|
local w, h = self.w, self.h
|
||||||
local bytes = { self.header:sub( 1, -3 ) }
|
local bytes = { self.header:sub( 1, -3 ) }
|
||||||
|
|
|
@ -13,6 +13,7 @@ local caps = {}
|
||||||
|
|
||||||
t.selected = nil
|
t.selected = nil
|
||||||
t.selectionLocked = false
|
t.selectionLocked = false
|
||||||
|
local invisible = 10000 --sentinel value outside the draw rectangle
|
||||||
|
|
||||||
function t.lockSelection()
|
function t.lockSelection()
|
||||||
t.selectionLocked = true
|
t.selectionLocked = true
|
||||||
|
@ -54,7 +55,14 @@ function city:formatDisplayInfo()
|
||||||
end
|
end
|
||||||
|
|
||||||
function city:delete()
|
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
|
end
|
||||||
|
|
||||||
function city:add()
|
function city:add()
|
||||||
|
@ -81,17 +89,27 @@ function city:moveTo(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
function city:toggleCapital()
|
function city:toggleCapital()
|
||||||
self.capital = not( self.capital )
|
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
|
end
|
||||||
|
|
||||||
function t.newCity( tbl )
|
function t.newCity( tbl )
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
name = "",
|
name = "",
|
||||||
country = "",
|
country = "",
|
||||||
x = 0,
|
x = 0,
|
||||||
y = 0,
|
y = 0,
|
||||||
pop = 0,
|
pop = 0,
|
||||||
capital = false,
|
capital = false,
|
||||||
}, citymt )
|
}, citymt )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -112,11 +130,11 @@ function t.load( filename )
|
||||||
if capital then --check against empty or malformed line
|
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 = setmetatable({
|
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,
|
||||||
n = n, points = idxPts, caps = capital and idxCaps
|
n = n, points = idxPts, caps = capital and idxCaps
|
||||||
}, citymt )
|
}, citymt )
|
||||||
cities[n] = city
|
cities[n] = city
|
||||||
n = n + 1
|
n = n + 1
|
||||||
|
|
||||||
|
@ -142,9 +160,13 @@ end
|
||||||
|
|
||||||
function t.save( cities )
|
function t.save( cities )
|
||||||
local str = {}
|
local str = {}
|
||||||
for n, city in ipairs( cities ) do
|
local i = 1
|
||||||
str[n] = ("%-41s%-41s%-14f%-14f%-19d %d"):format(
|
for _, city in ipairs( cities ) do
|
||||||
city.name, city.country, city.x, city.y, city.pop, city.capital and 1 or 0 )
|
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
|
end
|
||||||
return assert(table.concat( str, "\n" ))
|
return assert(table.concat( str, "\n" ))
|
||||||
end
|
end
|
||||||
|
|
14
map/map.lua
|
@ -191,18 +191,24 @@ local function write( filename, string )
|
||||||
end
|
end
|
||||||
|
|
||||||
function map.save()
|
function map.save()
|
||||||
--should be cross platform-ish
|
--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
|
for _, folder in ipairs{ "/data/", "/data/earth/", "/data/graphics/" } do
|
||||||
--getInfo checks if a directory exists
|
|
||||||
assert( mkdir.exists( map.path ), map.path )
|
assert( mkdir.exists( map.path ), map.path )
|
||||||
local path = map.path..folder
|
local path = map.path..folder
|
||||||
if not mkdir.exists( path ) then mkdir.mkdir( path ) end
|
if not mkdir.exists( path ) then mkdir.mkdir( path ) end
|
||||||
end
|
end
|
||||||
|
|
||||||
--OK back to normal
|
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
|
for k, layer in pairs( layers ) do
|
||||||
write( map.path..tostring( layer.filename ), assert( layer:save() ) )
|
files[ map.path..tostring( layer.filename ) ] = assert( layer:save() )
|
||||||
end
|
end
|
||||||
|
for filename, str in pairs( files ) do
|
||||||
|
write( filename, str )
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function map.hover(x, y)
|
function map.hover(x, y)
|
||||||
|
|
|
@ -11,6 +11,7 @@ local t = {
|
||||||
h = 24,
|
h = 24,
|
||||||
group = false,
|
group = false,
|
||||||
visible = false,
|
visible = false,
|
||||||
|
align = "center",
|
||||||
callback = function( self ) return print( "clicked button: ", self.name, self.x, self.y, self.w, self.h, self.visible ) end
|
callback = function( self ) return print( "clicked button: ", self.name, self.x, self.y, self.w, self.h, self.visible ) end
|
||||||
}
|
}
|
||||||
t.selected, t.next, t.prev = t, t, t
|
t.selected, t.next, t.prev = t, t, t
|
||||||
|
@ -45,7 +46,7 @@ function t.draw( b )
|
||||||
b.x + (b.icon and b.h or 0),
|
b.x + (b.icon and b.h or 0),
|
||||||
b.y + 0.5 * ( b.h - lg.getFont():getHeight() ),
|
b.y + 0.5 * ( b.h - lg.getFont():getHeight() ),
|
||||||
b.w - (b.icon and b.h or 0),
|
b.w - (b.icon and b.h or 0),
|
||||||
"center" )
|
b.align )
|
||||||
if b.icon then
|
if b.icon then
|
||||||
local h = b.icon:getHeight()
|
local h = b.icon:getHeight()
|
||||||
lg.draw( b.icon,
|
lg.draw( b.icon,
|
||||||
|
|
|
@ -40,8 +40,8 @@ function t.start()
|
||||||
modal.start( t )
|
modal.start( t )
|
||||||
loadLocation = loadLocation or map.path
|
loadLocation = loadLocation or map.path
|
||||||
button.selected = loadButton
|
button.selected = loadButton
|
||||||
loadButton.name = "save to "..loadLocation
|
loadButton.name = "load from "..loadLocation
|
||||||
button.displayGroup( t, true )
|
button.displayGroup( t, false, true )
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.draw()
|
function t.draw()
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
local t = {}
|
||||||
|
local lg = assert( love ).graphics
|
||||||
|
local modal = require 'ui.modal'
|
||||||
|
local button = require 'ui.button'
|
||||||
|
local camera = require 'ui.camera'
|
||||||
|
local map = require 'map.map'
|
||||||
|
|
||||||
|
local node
|
||||||
|
local moveModal = modal.new{}
|
||||||
|
local selectModal = modal.new{}
|
||||||
|
|
||||||
|
button.new{ name = "ATTACK NODE",
|
||||||
|
group = t,
|
||||||
|
icon = lg.newImage("icons/node-attack.png"),
|
||||||
|
x = 615,
|
||||||
|
y = 0,
|
||||||
|
callback = function()
|
||||||
|
node = map.ainodes.newNode( true )
|
||||||
|
return moveModal:start()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
button.new{ name = "PLACEMENT NODE",
|
||||||
|
group = t,
|
||||||
|
icon = lg.newImage("icons/node-place.png"),
|
||||||
|
x = 615,
|
||||||
|
y = 1 * (4 + button.h),
|
||||||
|
callback = function()
|
||||||
|
node = map.ainodes.newNode( true )
|
||||||
|
return moveModal:start()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
button.new{ name = "MOVE NODE",
|
||||||
|
group = t,
|
||||||
|
y = 2 * (4 + button.h),
|
||||||
|
x = 615,
|
||||||
|
}
|
||||||
|
|
||||||
|
button.new{ name = "DELETE NODE",
|
||||||
|
group = t,
|
||||||
|
y = 3 * (4 + button.h),
|
||||||
|
x = 615,
|
||||||
|
}
|
||||||
|
return t
|
|
@ -22,27 +22,29 @@ end
|
||||||
--and clicking escape will clear the previously selected mode
|
--and clicking escape will clear the previously selected mode
|
||||||
local selectModal = modal.new{}
|
local selectModal = modal.new{}
|
||||||
local textModal = modal.new{}
|
local textModal = modal.new{}
|
||||||
local numberModal = modal.new{ cursor = 1 }
|
local numberModal = modal.new{}
|
||||||
local editModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, }
|
local editModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, }
|
||||||
local moveModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, mousemoved = button.selectIn }
|
local moveModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, mousemoved = button.selectIn }
|
||||||
local deleteModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed }
|
local deleteModal = modal.new{ keypressed = keypressed }
|
||||||
local currentMode
|
local currentMode
|
||||||
|
|
||||||
button.new{ name = "NEW CITY",
|
button.new{ name = "NEW CITY",
|
||||||
group = t,
|
group = t,
|
||||||
icon = lg.newImage("icons/layer-cities.png"),
|
icon = lg.newImage("icons/city-new.png"),
|
||||||
x = 615,
|
x = 615,
|
||||||
y = 0,
|
y = 0,
|
||||||
callback = function()
|
callback = function()
|
||||||
city = map.cities.newCity()
|
city = map.cities.newCity()
|
||||||
|
city:add()
|
||||||
return editModal:start()
|
return editModal:start()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
moveModal.button = button.new{ name = "MOVE CITY",
|
moveModal.button = button.new{ name = "MOVE CITY",
|
||||||
group = t,
|
group = t,
|
||||||
|
icon = lg.newImage("icons/city-move.png"),
|
||||||
x = 615,
|
x = 615,
|
||||||
y = 28,
|
y = button.h + 4,
|
||||||
callback = function( self )
|
callback = function( self )
|
||||||
self.lit = true
|
self.lit = true
|
||||||
selectModal.mode = moveModal
|
selectModal.mode = moveModal
|
||||||
|
@ -53,7 +55,7 @@ moveModal.button = button.new{ name = "MOVE CITY",
|
||||||
editModal.button = button.new{ name = "EDIT CITY",
|
editModal.button = button.new{ name = "EDIT CITY",
|
||||||
group = t,
|
group = t,
|
||||||
x = 615,
|
x = 615,
|
||||||
y = 28 * 2,
|
y = (button.h + 4) * 2,
|
||||||
callback = function( self )
|
callback = function( self )
|
||||||
self.lit = true
|
self.lit = true
|
||||||
selectModal.mode = editModal
|
selectModal.mode = editModal
|
||||||
|
@ -63,48 +65,57 @@ editModal.button = button.new{ name = "EDIT CITY",
|
||||||
|
|
||||||
deleteModal.button = button.new{ name = "DELETE CITY",
|
deleteModal.button = button.new{ name = "DELETE CITY",
|
||||||
group = t,
|
group = t,
|
||||||
|
icon = lg.newImage("icons/city-delete.png"),
|
||||||
x = 615,
|
x = 615,
|
||||||
y = 28 * 3,
|
y = (button.h + 4) * 3,
|
||||||
icon = lg.newImage("icons/x.png"),
|
|
||||||
callback = function( self )
|
callback = function( self )
|
||||||
self.lit = true
|
self.lit = true
|
||||||
selectModal.mode = deleteModal
|
return deleteModal:start()
|
||||||
return selectModal:start()
|
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
--editButtons
|
--editButtons
|
||||||
local function editText( self )
|
local function editText( self )
|
||||||
print( "editing: ", self.field, city.name )
|
print( "editing: ", self.field, city.name )
|
||||||
|
self.lit = true
|
||||||
return textModal:start( self.field )
|
return textModal:start( self.field )
|
||||||
end
|
end
|
||||||
|
|
||||||
local function editNumber( self )
|
local function editNumber( self )
|
||||||
local field = self.field
|
print( "editing: ", self.field, city.name )
|
||||||
|
self.lit = true
|
||||||
|
return numberModal:start( self.field )
|
||||||
end
|
end
|
||||||
|
|
||||||
local editButtons = {
|
local editButtons = {
|
||||||
|
|
||||||
save = button.new{
|
save = button.new{
|
||||||
icon = lg.newImage( "icons/save.png" ),
|
icon = lg.newImage( "icons/check.png" ),
|
||||||
callback = function() print( "stop editing city" ) return editModal:stop() end,},
|
callback = function() return editModal:stop() end,},
|
||||||
|
|
||||||
|
|
||||||
name = button.new{ callback = editText },
|
name = button.new{ callback = editText },
|
||||||
country = button.new{ callback = editText },
|
country = button.new{ callback = editText },
|
||||||
x = button.new{ callback = editNumber },
|
x = button.new{ callback = editNumber },
|
||||||
y = button.new{ callback = editNumber },
|
y = button.new{ callback = editNumber },
|
||||||
capital = button.new{ callback = function() if city then return city:toggleCapital() end end },
|
capital = button.new{ callback = function( self )
|
||||||
|
if city then
|
||||||
|
self.name = tostring( not( city.capital ) )
|
||||||
|
return city:toggleCapital()
|
||||||
|
end
|
||||||
|
end },
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
local i = 0
|
local i = 0
|
||||||
for key, b in pairs( editButtons ) do
|
for _, key in ipairs{ "save", "name", "country", "x", "y", "capital" } do
|
||||||
|
local b = assert( editButtons[ key ] )
|
||||||
|
b.align = "right"
|
||||||
b.field = key
|
b.field = key
|
||||||
b.name = key
|
b.name = tostring( key ) --bools must be cast to string before getting passed to printf
|
||||||
b.group = editModal
|
b.group = editModal
|
||||||
b.x = 0
|
b.x = lg.getWidth() / 2 - button.w / 2
|
||||||
b.y = 28 * i
|
b.y = (button.h + 4) * i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -113,17 +124,34 @@ function editModal:start()
|
||||||
modal.start( self )
|
modal.start( self )
|
||||||
button.displayGroup( self, false, true )
|
button.displayGroup( self, false, true )
|
||||||
for k, b in pairs( editButtons ) do
|
for k, b in pairs( editButtons ) do
|
||||||
b.name = city[k] or b.name
|
b.name = tostring( city[k] or b.name )
|
||||||
end
|
end
|
||||||
|
if city.capital == false then editButtons.capital.name = "false" end
|
||||||
|
end
|
||||||
|
|
||||||
|
function editModal:stop()
|
||||||
|
return modal.stop( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
function editModal.draw()
|
function editModal.draw()
|
||||||
|
lg.setColor( 1, 1, 1, 0.5 )
|
||||||
return button:draw()
|
return button:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function editModal.resize( w, h )
|
||||||
|
local i = 0
|
||||||
|
local high = h / 6
|
||||||
|
for key, b in pairs( editButtons ) do
|
||||||
|
b.x = w / 2 - button.w / 2
|
||||||
|
b.y = ( high + 4 ) * i
|
||||||
|
b.h = high
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function moveModal.update( dt )
|
function moveModal.update( dt )
|
||||||
local x, y = love.mouse.getPosition()
|
local x, y = love.mouse.getPosition()
|
||||||
if y > 200 and love.mouse.isDown( 1 ) then
|
if y > t.menuHeight and love.mouse.isDown( 1 ) then
|
||||||
local wx, wy = camera.GetWorldCoordinate( x, y )
|
local wx, wy = camera.GetWorldCoordinate( x, y )
|
||||||
city:moveTo( wx, wy )
|
city:moveTo( wx, wy )
|
||||||
end
|
end
|
||||||
|
@ -134,7 +162,7 @@ function moveModal.mousemoved( x, y, dx, dy, istouch )
|
||||||
end
|
end
|
||||||
|
|
||||||
function moveModal.mousepressed( x, y, mouseButton, istouch, presses )
|
function moveModal.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
if y < 200 then
|
if y < t.menuHeight then
|
||||||
moveModal:stop()
|
moveModal:stop()
|
||||||
return button.mousepressed( x, y, mouseButton, istouch, presses )
|
return button.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
end
|
end
|
||||||
|
@ -143,19 +171,48 @@ function moveModal.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function deleteModal.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
|
if map.selected then
|
||||||
|
map.selected:delete()
|
||||||
|
end
|
||||||
|
if y < t.menuHeight then
|
||||||
|
deleteModal.button.lit = false
|
||||||
|
deleteModal:stop()
|
||||||
|
return button.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function numberModal:start( field )
|
function numberModal:start( field )
|
||||||
self.field = field
|
self.field = field
|
||||||
return modal.start( self )
|
return modal.start( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
function numberModal.keypressed( key, code, isrepeat )
|
function numberModal.keypressed( key, code, isrepeat )
|
||||||
if code == 'backspace' then end
|
if code == "backspace" then
|
||||||
if code == 'escape' then return numberModal:stop() end
|
local text = tostring( city[numberModal.field] )
|
||||||
|
-- get the byte offset to the last UTF-8 character in the string.
|
||||||
|
local byteoffset = utf8.offset(text, -1)
|
||||||
|
print( "textmodal: backspace", byteoffset )
|
||||||
|
|
||||||
|
if byteoffset then
|
||||||
|
-- remove the last UTF-8 character.
|
||||||
|
-- string.sub operates on bytes rather than UTF-8 characters, so we couldn't do string.sub(text, 1, -2).
|
||||||
|
local newstr = text:sub( 1, byteoffset - 1)
|
||||||
|
if newstr == "" then newstr = 0 end
|
||||||
|
city[numberModal.field] = tonumber( newstr ) or city[numberModal.field]
|
||||||
|
editButtons[numberModal.field].name = city[numberModal.field]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if code == "escape" or code == "return" then
|
||||||
|
return numberModal:stop()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function numberModal.textinput( char )
|
function numberModal.textinput( char )
|
||||||
local str = tostring( city[ numberModal.field ] )
|
local str = tostring( city[ numberModal.field ] )
|
||||||
local plus = str..char
|
local plus = str..char
|
||||||
|
print( "text input: ", char )
|
||||||
if tonumber( plus ) then
|
if tonumber( plus ) then
|
||||||
city[ numberModal.field ] = plus
|
city[ numberModal.field ] = plus
|
||||||
editButtons[ numberModal.field ].name = plus
|
editButtons[ numberModal.field ].name = plus
|
||||||
|
@ -196,7 +253,7 @@ function textModal.keypressed( key, code, isRepeat )
|
||||||
editButtons[textModal.field].name = city[textModal.field]
|
editButtons[textModal.field].name = city[textModal.field]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if code == "escape" then
|
if code == "escape" or code == "return" then
|
||||||
return textModal:stop()
|
return textModal:stop()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -215,7 +272,7 @@ function selectModal:stop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function selectModal.mousepressed( x, y, mouseButton, istouch, presses )
|
function selectModal.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
if y < 200 then
|
if y < t.menuHeight then
|
||||||
selectModal:stop()
|
selectModal:stop()
|
||||||
return button.mousepressed( x, y, mouseButton, istouch, presses )
|
return button.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
end
|
end
|
||||||
|
@ -226,6 +283,8 @@ function selectModal.mousepressed( x, y, mouseButton, istouch, presses )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function t.setMenuHeight( h )
|
||||||
|
t.menuHeight = h
|
||||||
|
end
|
||||||
|
|
||||||
return t
|
return t
|
|
@ -0,0 +1,3 @@
|
||||||
|
local t = {}
|
||||||
|
|
||||||
|
return t
|
|
@ -1,11 +1,10 @@
|
||||||
|
|
||||||
local love = assert( love )
|
local love = assert( love )
|
||||||
local button = require 'ui.button'
|
local button = require 'ui.button'
|
||||||
local savemodal = require 'ui.savemodal'
|
local modal = require 'ui.modal'
|
||||||
local loadmodal = require 'ui.loadmodal'
|
local camera = require 'ui.camera'
|
||||||
local Camera = require 'ui.camera'
|
|
||||||
local map = require 'map.map'
|
local map = require 'map.map'
|
||||||
local t = {}
|
local t = { menuHeight = 200 }
|
||||||
|
|
||||||
local loadImg = love.graphics.newImage
|
local loadImg = love.graphics.newImage
|
||||||
local layers = {
|
local layers = {
|
||||||
|
@ -27,12 +26,12 @@ local layers = {
|
||||||
button.new{
|
button.new{
|
||||||
name = "LOAD", x = 250, y = 0,
|
name = "LOAD", x = 250, y = 0,
|
||||||
group = t,
|
group = t,
|
||||||
callback = loadmodal.start,
|
callback = require( 'ui.loadmodal' ).start,
|
||||||
icon = love.graphics.newImage( "icons/load.png" )}
|
icon = love.graphics.newImage( "icons/load.png" )}
|
||||||
button.new{
|
button.new{
|
||||||
name = "SAVE", x = 250, y = 28,
|
name = "SAVE", x = 250, y = 28,
|
||||||
group = t,
|
group = t,
|
||||||
callback = savemodal.start,
|
callback = require( 'ui.savemodal' ).start,
|
||||||
icon = love.graphics.newImage( "icons/save.png" )}
|
icon = love.graphics.newImage( "icons/save.png" )}
|
||||||
button.new{
|
button.new{
|
||||||
name = "UNDO", x = 250, y = 2 * 28,
|
name = "UNDO", x = 250, y = 2 * 28,
|
||||||
|
@ -61,9 +60,13 @@ end
|
||||||
|
|
||||||
local activeLayerButton
|
local activeLayerButton
|
||||||
local function back( self )
|
local function back( self )
|
||||||
activeLayerButton.lit = false
|
print( "back button clicked" )
|
||||||
|
if activeLayerButton then
|
||||||
|
activeLayerButton.lit = false
|
||||||
|
end
|
||||||
activeLayerButton = nil
|
activeLayerButton = nil
|
||||||
map.setEditLayer()
|
map.setEditLayer()
|
||||||
|
modal.exitAll()
|
||||||
button.displayGroup( t, false, true )
|
button.displayGroup( t, false, true )
|
||||||
for i, b in ipairs( editButtons ) do
|
for i, b in ipairs( editButtons ) do
|
||||||
b.visible = true
|
b.visible = true
|
||||||
|
@ -86,6 +89,7 @@ local backButton = button.new{
|
||||||
}
|
}
|
||||||
|
|
||||||
local function editLayer( self )
|
local function editLayer( self )
|
||||||
|
back( backButton )
|
||||||
self.lit = true
|
self.lit = true
|
||||||
map.setEditLayer( self.layer )
|
map.setEditLayer( self.layer )
|
||||||
activeLayerButton = self
|
activeLayerButton = self
|
||||||
|
@ -106,6 +110,8 @@ end
|
||||||
local x = 250
|
local x = 250
|
||||||
for i = 1, #layers do
|
for i = 1, #layers do
|
||||||
|
|
||||||
|
layers[i].menu.menuHeight = t.menuHeight
|
||||||
|
|
||||||
editButtons[i] = button.new( copy( i, {
|
editButtons[i] = button.new( copy( i, {
|
||||||
y = 3 * 28,
|
y = 3 * 28,
|
||||||
x = x + (button.h + 4) * ( i - 1 ),
|
x = x + (button.h + 4) * ( i - 1 ),
|
||||||
|
@ -126,17 +132,20 @@ for i = 1, #layers do
|
||||||
group = showButtons,
|
group = showButtons,
|
||||||
tooltip = "show "..layers[i].layer
|
tooltip = "show "..layers[i].layer
|
||||||
}))
|
}))
|
||||||
|
|
||||||
layerButtons[ 2 * i - 1 ] = showButtons[i]
|
layerButtons[ 2 * i - 1 ] = showButtons[i]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function t.draw()
|
function t.draw()
|
||||||
--Status bar.
|
--Status bar.
|
||||||
love.graphics.setScissor( 0, 0, 250, 200 )
|
love.graphics.setScissor( 0, 0, 250, t.menuHeight )
|
||||||
local x, y = love.mouse.getPosition()
|
local x, y = love.mouse.getPosition()
|
||||||
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() - 60
|
local h = love.graphics.getHeight() - 60
|
||||||
love.graphics.setColor( 0, 0, 0, 1 )
|
love.graphics.setColor( 0, 0, 0, 1 )
|
||||||
love.graphics.rectangle( "fill", 0, 0, 250, love.graphics.getHeight() )
|
love.graphics.rectangle( "fill", 0, 0, 250, love.graphics.getHeight() )
|
||||||
|
@ -156,10 +165,10 @@ function t.draw()
|
||||||
if map.selected then love.graphics.print( map.selected:formatDisplayInfo(), 0, 80 ) end
|
if map.selected then love.graphics.print( map.selected:formatDisplayInfo(), 0, 80 ) end
|
||||||
if map.selectionLocked then end
|
if map.selectionLocked then end
|
||||||
|
|
||||||
love.graphics.setScissor( 250, 0, love.graphics.getWidth() - 250, 200 )
|
love.graphics.setScissor( 250, 0, love.graphics.getWidth() - 250, t.menuHeight)
|
||||||
love.graphics.rectangle( "line", 0, 0 , 250, 200 )
|
love.graphics.rectangle( "line", 0, 0 , 250, t.menuHeight )
|
||||||
love.graphics.rectangle( "line", 250, 0, love.graphics.getWidth() - 250, 200 )
|
love.graphics.rectangle( "line", 250, 0, love.graphics.getWidth() - 250, t.menuHeight )
|
||||||
love.graphics.rectangle( "line", 250, 0, button.w, 200 )
|
love.graphics.rectangle( "line", 250, 0, button.w, t.menuHeight )
|
||||||
|
|
||||||
|
|
||||||
love.graphics.setColor( 1, 1, 1, 0.8 )
|
love.graphics.setColor( 1, 1, 1, 0.8 )
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
local t = {}
|
||||||
|
|
||||||
|
return t
|
|
@ -0,0 +1,3 @@
|
||||||
|
local t = {}
|
||||||
|
|
||||||
|
return t
|
|
@ -34,7 +34,6 @@ function t.start( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.stop( self )
|
function t.stop( self )
|
||||||
print( "stopping modal:", i )
|
|
||||||
--restore callbacks
|
--restore callbacks
|
||||||
for name in pairs( self ) do
|
for name in pairs( self ) do
|
||||||
if love[name] then
|
if love[name] then
|
||||||
|
@ -56,7 +55,13 @@ function t.stop( self )
|
||||||
i = i - 1
|
i = i - 1
|
||||||
t.previous = t[i - 1]
|
t.previous = t[i - 1]
|
||||||
|
|
||||||
love.graphics.setScissor(0, 0, love.graphics.getDimensions())
|
love.graphics.setScissor(0, 0, love.graphics.getDimensions())
|
||||||
|
end
|
||||||
|
|
||||||
|
function t.exitAll()
|
||||||
|
if i < 1 then return end
|
||||||
|
i = 1
|
||||||
|
return t.stop( love )
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.new( modal )
|
function t.new( modal )
|
||||||
|
|