diff --git a/Builder/src/fmon/builder/MapBuilder.fxml b/Builder/src/fmon/builder/MapBuilder.fxml index b2a1cdb..2149daf 100644 --- a/Builder/src/fmon/builder/MapBuilder.fxml +++ b/Builder/src/fmon/builder/MapBuilder.fxml @@ -8,6 +8,8 @@ + + @@ -23,12 +25,12 @@ - + - - + + @@ -59,11 +61,28 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/Builder/src/fmon/builder/MapBuilder.scala b/Builder/src/fmon/builder/MapBuilder.scala index 53bc647..f8607a3 100644 --- a/Builder/src/fmon/builder/MapBuilder.scala +++ b/Builder/src/fmon/builder/MapBuilder.scala @@ -1,6 +1,9 @@ package fmon.builder import java.io._ +import java.util.prefs.Preferences + +import scala.util.Properties import javafx.application.Application import javafx.fxml.FXML @@ -17,9 +20,14 @@ import scalafx.scene.image.ImageView import scalafx.scene.input.MouseEvent import scalafx.scene.paint.Color import scalafx.scene.layout._ +import scalafx.stage.FileChooser +import FileChooser.ExtensionFilter +import fmon._ +import fmon.draw.Palette import fmon.draw.tile._ import fmon.util.Direction +import fmon.world._ import Direction._ @@ -27,24 +35,41 @@ import scala.math.{min, max} class MapBuilder { @FXML var tileSelector: jfxsl.TilePane = _ + @FXML var doodadSelector: jfxsl.TilePane = _ @FXML var gameMap: jfxsl.TilePane = _ - var tileSeq: IndexedSeq[AutoFloorTile] = _ var imgSeq: IndexedSeq[ImageView] = _ - var currTile: AutoFloorTile = _ + var tileset: Tileset = _ + var currTile: AutoTile = _ - val numRows = 10 - val numCols = 10 + var level: GameMap = _ + + var lastFile: File = _ + + def lastDir(): String = { + val prefs = Preferences.userNodeForPackage(classOf[MapBuilder]) + prefs.get("dir", Properties.userDir) + } + + def rememberDir(file: File): Unit = { + val dir = if (file.isDirectory()) file.getPath else file.getParent + if (dir != lastDir) { + val prefs = Preferences.userNodeForPackage(classOf[MapBuilder]) + prefs.put("dir", dir) + } + } @FXML def initialize(): Unit = { - val file = new File(raw"C:\Users\dalyj\Documents\Design\Images\AutoTiles\tilea2.png") - val palette = new AutoTilePalette(file, 32) - val tiles = for (y <- 0 until 4; x <- 0 until 8) yield { - palette(x, y) - } - val icons = tiles.zipWithIndex.map{case(t, i) => { + tileset = new Tileset(new TilesetToken(raw"C:\Users\dalyj\Documents\Design\Images\AutoTiles\tilea2.png")) + level = new GameMap(10, 10, tileset) + setup() + } + + def setup(): Unit = { + + val icons = tileset.groundTiles.map(t => { val view = new ImageView(t.icon.croppedImage()) view.handleEvent(MouseEvent.Any) { e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) { @@ -52,33 +77,45 @@ class MapBuilder { } } view.delegate - }} + }) + tileSelector.children.clear() tileSelector.children ++= icons - currTile = tiles.head + currTile = tileset.groundTiles.head - tileSeq = for (y <- 0 until numRows; x <- 0 until numCols) yield currTile - imgSeq = for (y <- 0 until numRows; x <- 0 until numCols) yield { + val doodadFile = new File(raw"C:\Users\dalyj\Documents\Design\Images\Icons\equipment-icons-tileset.png") + val doodadPalette = Palette.bySize(doodadFile, Config.tileSize, Config.tileSize) + + val doodads = doodadPalette.images.map(d => { + val view = new ImageView(d.croppedImage()) + view.delegate + }) + doodadSelector.children.clear() + doodadSelector.children ++= doodads + + imgSeq = for (y <- 0 until level.height; x <- 0 until level.width) yield { val view = new ImageView(currTile.icon.croppedImage()) // TODO Tile with adjacent view.handleEvent(MouseEvent.Any) { e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) { val index = point2index(x, y) - tileSeq = tileSeq.updated(index, currTile) + level.tiles = level.tiles.updated(index, currTile) autotile(x, y) } } view } - gameMap.prefColumns = numCols - gameMap.prefRows = numRows + gameMap.children.clear() + gameMap.prefColumns = level.width + gameMap.prefRows = level.height gameMap.children ++= imgSeq.map(_.delegate) - for (y <- 0 until numRows; x <- 0 until numCols) { + for (y <- 0 until level.height; x <- 0 until level.width) { smoothTile(x, y) } } def autotile(x: Int, y: Int) = { - for (yy <- max(y - 1, 0) to min(y + 1, numCols - 1); xx <- max(x - 1, 0) to min(x + 1, numRows - 1)) { + for (yy <- max(y - 1, 0) to min(y + 1, level.height - 1); + xx <- max(x - 1, 0) to min(x + 1, level.width - 1)) { smoothTile(xx, yy) } } @@ -88,28 +125,74 @@ class MapBuilder { val dirs = scala.collection.mutable.Set[Direction.Value]() val onLeft = x == 0 - val onRight = x + 1 == numCols + val onRight = x + 1 == level.width val onTop = y == 0 - val onBottom = y + 1 == numRows + val onBottom = y + 1 == level.height - if (onLeft || tileSeq(left(i)) == tileSeq(i)) dirs += West - if (onRight || tileSeq(right(i)) == tileSeq(i)) dirs += East - if (onTop || tileSeq(up(i)) == tileSeq(i)) dirs += North - if (onBottom || tileSeq(down(i)) == tileSeq(i)) dirs += South - if (onLeft || onTop || tileSeq(left(up(i))) == tileSeq(i)) dirs += Northwest - if (onLeft || onBottom || tileSeq(down(left(i))) == tileSeq(i)) dirs += Southwest - if (onTop || onRight || tileSeq(right(up(i))) == tileSeq(i)) dirs += Northeast - if (onBottom || onRight || tileSeq(right(down(i))) == tileSeq(i)) dirs += Southeast + if (onLeft || level.tiles(left(i)) == level.tiles(i)) dirs += West + if (onRight || level.tiles(right(i)) == level.tiles(i)) dirs += East + if (onTop || level.tiles(up(i)) == level.tiles(i)) dirs += North + if (onBottom || level.tiles(down(i)) == level.tiles(i)) dirs += South + if (onLeft || onTop || level.tiles(left(up(i))) == level.tiles(i)) dirs += Northwest + if (onLeft || onBottom || level.tiles(down(left(i))) == level.tiles(i)) dirs += Southwest + if (onTop || onRight || level.tiles(right(up(i))) == level.tiles(i)) dirs += Northeast + if (onBottom || onRight || level.tiles(right(down(i))) == level.tiles(i)) dirs += Southeast val index = point2index(x, y) - imgSeq(index).image = tileSeq(index).build(dirs.toSet).croppedImage() + imgSeq(index).image = level.tiles(index).build(dirs.toSet).croppedImage() } - def point2index(x: Int, y: Int) = y * numCols + x + def save() = { + if (lastFile != null) { + level saveTo lastFile + } else { + saveAs() + } + } + + def saveAs() = { + val fileChooser = new FileChooser { + title = "Open Resource File" + initialDirectory = new File(lastDir()) + extensionFilters ++= Seq( + new ExtensionFilter("MAP Files", "*.map"), + new ExtensionFilter("All Files", "*.*") + ) + } + + val selectedFile = fileChooser.showSaveDialog(null) + if (selectedFile != null) { + rememberDir(selectedFile) + level saveTo selectedFile + lastFile = selectedFile + } + } + + def open() = { + val fileChooser = new FileChooser { + title = "Open Resource File" + initialDirectory = new File(lastDir()) + extensionFilters ++= Seq( + new ExtensionFilter("MAP Files", "*.map"), + new ExtensionFilter("All Files", "*.*") + ) + } + + val selectedFile = fileChooser.showOpenDialog(null) + if (selectedFile != null) { + rememberDir(selectedFile) + level = GameMap loadFrom selectedFile + tileset = level.tileset + setup() + lastFile = selectedFile + } + } + + def point2index(x: Int, y: Int) = level.pt2index(x, y) def left(i: Int) = i - 1 def right(i: Int) = i + 1 - def up(i: Int) = i - numCols - def down(i: Int) = i + numCols + def up(i: Int) = i - level.width + def down(i: Int) = i + level.width } object MapBuilder { diff --git a/FakeMon/src/fmon/Config.scala b/FakeMon/src/fmon/Config.scala index 7f9a5c3..455aa47 100644 --- a/FakeMon/src/fmon/Config.scala +++ b/FakeMon/src/fmon/Config.scala @@ -9,7 +9,8 @@ case class Config( val resistMult: Double, val weakMult: Double, val immuneMult: Double, - val maxBoost: Int + val maxBoost: Int, + val tileSize: Int ) { } @@ -24,4 +25,5 @@ object Config { def weakMult = config.weakMult def immuneMult = config.immuneMult def maxBoost = config.maxBoost + def tileSize = config.tileSize } \ No newline at end of file diff --git a/FakeMon/src/fmon/config.yaml b/FakeMon/src/fmon/config.yaml index 20a3e7e..a69fc53 100644 --- a/FakeMon/src/fmon/config.yaml +++ b/FakeMon/src/fmon/config.yaml @@ -6,3 +6,4 @@ resistMult: 0.5 immuneMult: 0.0 maxBoost: 6 newday: 02:00 +tileSize: 32 diff --git a/FakeMon/src/fmon/draw/Palette.scala b/FakeMon/src/fmon/draw/Palette.scala index 96acef0..5c2b169 100644 --- a/FakeMon/src/fmon/draw/Palette.scala +++ b/FakeMon/src/fmon/draw/Palette.scala @@ -1,6 +1,6 @@ package fmon.draw -import java.io.InputStream +import java.io._ import scalafx.geometry.Rectangle2D import scalafx.scene.image._ @@ -23,6 +23,7 @@ case class StillImg(val image: Image, val x: Double, val y: Double, val width: D class Palette(val image: Image, val numAcross: Int, val numDown: Int) { def this(url: String, numAcross: Int, numDown: Int) = this(new Image(url), numAcross, numDown) def this(stream: InputStream, numAcross: Int, numDown: Int) = this(new Image(stream), numAcross, numDown) + def this(file: File, numAcross: Int, numDown: Int) = this(new FileInputStream(file), numAcross, numDown) val imgWidth = image.width() / numAcross val imgHeight = image.height() / numDown @@ -57,10 +58,14 @@ object Palette { new Palette(img, numAcross, numDown.toInt) } - def bySize(stream: InputStream, width: Double, height: Double) = { + def bySize(stream: InputStream, width: Double, height: Double): Palette = { val img = new Image(stream) val numAcross = img.width() / width val numDown = img.height() / height new Palette(img, numAcross.toInt, numDown.toInt) } + + def bySize(file: File, width: Double, height: Double): Palette = { + bySize(new FileInputStream(file), width, height) + } } \ No newline at end of file diff --git a/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala b/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala index 7c8afcb..e774be0 100644 --- a/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala +++ b/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala @@ -12,7 +12,12 @@ import fmon.util._ import Direction._ -class AutoFloorTile(val palette: Palette, val size: Int = 48) { +trait AutoTile { + def icon: StillImg + def build(dirs: Set[Direction.Value]): StillImg +} + +class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile { def icon: StillImg = palette.apply(0, 0, 2, 2) @@ -79,7 +84,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) { } } -class AutoWallTile(val palette: Palette, val size: Int = 48) { +class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile { def icon: StillImg = { val canvas = new scalafx.scene.canvas.Canvas(size, size) val g = canvas.graphicsContext2D diff --git a/FakeMon/src/fmon/world/GameMap.scala b/FakeMon/src/fmon/world/GameMap.scala new file mode 100644 index 0000000..870a432 --- /dev/null +++ b/FakeMon/src/fmon/world/GameMap.scala @@ -0,0 +1,41 @@ +package fmon.world + +import java.io._ + +import fmon.draw.tile._ +import fmon.util._ + +class GameMap(val width: Int, val height: Int, val tileset: Tileset) { + + var tiles: IndexedSeq[AutoTile] = for (y <- 0 until height; x <- 0 until width) yield tileset.groundTiles.head + + def saveTo(file: File): Unit = { + val ostream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file))) + ostream.writeInt(width) + ostream.writeInt(height) + ostream.writeObject(tileset.token.a2)// Tileset + val tileIndices = tileset.groundTiles.zipWithIndex.toMap + tiles.foreach(t => ostream.writeInt(tileIndices(t))) + //ostream.writeObject(tiles.map(tileIndices(_)).mkString(" ")) + ostream.close() + } + + def pt2index(x: Int, y: Int) = y * width + x + def index2x(i: Int) = i % width + def index2y(i: Int) = i / width +} + +object GameMap { + def loadFrom(file: File): GameMap = { + //val istream = new BufferedReader(new FileReader(file)) + val istream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file))) + val width = istream.readInt() + val height = istream.readInt() + val tileset = new Tileset(new TilesetToken(istream.readObject().toString)) + val indices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt() + val map = new GameMap(width, height, tileset) + val tiles = indices.map(i => tileset.groundTiles(i)) + map.tiles = tiles + map + } +} \ No newline at end of file diff --git a/FakeMon/src/fmon/world/Tileset.scala b/FakeMon/src/fmon/world/Tileset.scala new file mode 100644 index 0000000..2be00e6 --- /dev/null +++ b/FakeMon/src/fmon/world/Tileset.scala @@ -0,0 +1,18 @@ +package fmon.world + +import java.io._ + +import fmon.Config +import fmon.draw.tile._ + +class Tileset(val token: TilesetToken) { + val groundTiles: IndexedSeq[AutoTile] = { + val file = new File(token.a2) + val palette = new AutoTilePalette(file, Config.tileSize) + for (y <- 0 until 4; x <- 0 until 8) yield { + palette(x, y) + } + } +} + +case class TilesetToken(val a2: String) \ No newline at end of file