Compare commits
8 Commits
0ff64797d9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
344f71192f | ||
|
|
f7747346d7 | ||
|
|
94f12b5676 | ||
|
|
1b6a4fac03 | ||
|
|
2fc918a728 | ||
|
|
0071e5af80 | ||
|
|
c10da7ccf9 | ||
|
|
32542df86c |
@@ -18,7 +18,7 @@
|
|||||||
<?import javafx.scene.paint.Color?>
|
<?import javafx.scene.paint.Color?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<VBox prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.MapBuilder">
|
<VBox prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.MapBuilder">
|
||||||
<children>
|
<children>
|
||||||
<MenuBar VBox.vgrow="NEVER">
|
<MenuBar VBox.vgrow="NEVER">
|
||||||
<menus>
|
<menus>
|
||||||
@@ -50,6 +50,8 @@
|
|||||||
<SeparatorMenuItem mnemonicParsing="false" />
|
<SeparatorMenuItem mnemonicParsing="false" />
|
||||||
<MenuItem mnemonicParsing="false" text="Select All" />
|
<MenuItem mnemonicParsing="false" text="Select All" />
|
||||||
<MenuItem mnemonicParsing="false" text="Unselect All" />
|
<MenuItem mnemonicParsing="false" text="Unselect All" />
|
||||||
|
<SeparatorMenuItem mnemonicParsing="false" />
|
||||||
|
<MenuItem mnemonicParsing="false" onAction="#onPropertiesDialog" text="Properties ..." />
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="Help">
|
<Menu mnemonicParsing="false" text="Help">
|
||||||
@@ -65,20 +67,28 @@
|
|||||||
<tabs>
|
<tabs>
|
||||||
<Tab closable="false" text="A">
|
<Tab closable="false" text="A">
|
||||||
<content>
|
<content>
|
||||||
<AnchorPane>
|
<ScrollPane>
|
||||||
<children>
|
<content>
|
||||||
<TilePane fx:id="tileSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
<AnchorPane>
|
||||||
</children>
|
<children>
|
||||||
</AnchorPane>
|
<TilePane fx:id="tileSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
</content>
|
||||||
|
</ScrollPane>
|
||||||
</content>
|
</content>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab closable="false" text="B">
|
<Tab closable="false" text="B">
|
||||||
<content>
|
<content>
|
||||||
<AnchorPane>
|
<ScrollPane>
|
||||||
<children>
|
<content>
|
||||||
<TilePane fx:id="doodadSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
<AnchorPane>
|
||||||
</children>
|
<children>
|
||||||
</AnchorPane>
|
<TilePane fx:id="doodadSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
</content>
|
||||||
|
</ScrollPane>
|
||||||
</content>
|
</content>
|
||||||
</Tab>
|
</Tab>
|
||||||
</tabs>
|
</tabs>
|
||||||
@@ -88,6 +98,7 @@
|
|||||||
<AnchorPane id="Content" minHeight="-1.0" minWidth="-1.0" prefHeight="545.0" prefWidth="430.0">
|
<AnchorPane id="Content" minHeight="-1.0" minWidth="-1.0" prefHeight="545.0" prefWidth="430.0">
|
||||||
<children>
|
<children>
|
||||||
<TilePane fx:id="gameMap" hgap="1.0" layoutX="14.0" layoutY="28.0" prefColumns="10" prefRows="10" vgap="1.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
<TilePane fx:id="gameMap" hgap="1.0" layoutX="14.0" layoutY="28.0" prefColumns="10" prefRows="10" vgap="1.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||||
|
<TilePane fx:id="doodadMap" hgap="1.0" vgap="1.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
</content>
|
</content>
|
||||||
|
|||||||
@@ -21,31 +21,42 @@ import scalafx.scene.input.MouseEvent
|
|||||||
import scalafx.scene.paint.Color
|
import scalafx.scene.paint.Color
|
||||||
import scalafx.scene.layout._
|
import scalafx.scene.layout._
|
||||||
import scalafx.stage.FileChooser
|
import scalafx.stage.FileChooser
|
||||||
|
import scalafx.stage.Modality
|
||||||
import FileChooser.ExtensionFilter
|
import FileChooser.ExtensionFilter
|
||||||
|
|
||||||
import fmon._
|
import fmon._
|
||||||
|
import fmon.builder.dialog.MapProperties
|
||||||
import fmon.draw.Palette
|
import fmon.draw.Palette
|
||||||
import fmon.draw.tile._
|
import fmon.draw.tile._
|
||||||
import fmon.util.{Direction, YamlHelper}
|
import fmon.util.{Direction, YamlHelper}
|
||||||
import fmon.world._
|
import fmon.world._
|
||||||
|
|
||||||
import Direction._
|
import Direction._
|
||||||
|
import Alert.AlertType
|
||||||
|
|
||||||
import scala.math.{min, max}
|
import scala.math.{min, max}
|
||||||
|
|
||||||
|
sealed trait MapBuilderState
|
||||||
|
|
||||||
|
case object GroundTile extends MapBuilderState
|
||||||
|
case object DoodadTile extends MapBuilderState
|
||||||
|
|
||||||
class MapBuilder {
|
class MapBuilder {
|
||||||
@FXML var tileSelector: jfxsl.TilePane = _
|
@FXML var tileSelector: jfxsl.TilePane = _
|
||||||
@FXML var doodadSelector: jfxsl.TilePane = _
|
@FXML var doodadSelector: jfxsl.TilePane = _
|
||||||
@FXML var gameMap: jfxsl.TilePane = _
|
@FXML var gameMap: jfxsl.TilePane = _
|
||||||
|
@FXML var doodadMap: jfxsl.TilePane = _
|
||||||
|
|
||||||
var imgSeq: IndexedSeq[ImageView] = _
|
var imgSeq: IndexedSeq[ImageView] = _
|
||||||
|
var doodadSeq: IndexedSeq[ImageView] = _
|
||||||
|
|
||||||
val tilesets = {
|
val tilesets = {
|
||||||
val dir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Data")
|
val dir = new File(Config.homedir + raw"Progena\Data")
|
||||||
YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap
|
YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap
|
||||||
}
|
}
|
||||||
var tileset: Tileset = _
|
var tileset: Tileset = _
|
||||||
var currTile: AutoTile = _
|
var currTile: AutoTile = _
|
||||||
|
var currState: MapBuilderState = GroundTile
|
||||||
|
|
||||||
var level: GameMap = _
|
var level: GameMap = _
|
||||||
|
|
||||||
@@ -66,7 +77,7 @@ class MapBuilder {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
def initialize(): Unit = {
|
def initialize(): Unit = {
|
||||||
val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets")
|
val resourceDir = new File(Config.homedir + raw"Progena\Resources\tilesets")
|
||||||
tileset = tilesets("Outside").load(resourceDir)
|
tileset = tilesets("Outside").load(resourceDir)
|
||||||
level = new GameMap(10, 10, tileset)
|
level = new GameMap(10, 10, tileset)
|
||||||
setup()
|
setup()
|
||||||
@@ -79,6 +90,7 @@ class MapBuilder {
|
|||||||
view.handleEvent(MouseEvent.Any) {
|
view.handleEvent(MouseEvent.Any) {
|
||||||
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
||||||
currTile = t
|
currTile = t
|
||||||
|
currState = GroundTile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view.delegate
|
view.delegate
|
||||||
@@ -89,26 +101,50 @@ class MapBuilder {
|
|||||||
|
|
||||||
val doodads = tileset.doodadTiles.map(d => {
|
val doodads = tileset.doodadTiles.map(d => {
|
||||||
val view = new ImageView(d.icon.croppedImage())
|
val view = new ImageView(d.icon.croppedImage())
|
||||||
|
view.handleEvent(MouseEvent.Any) {
|
||||||
|
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
||||||
|
currTile = d
|
||||||
|
currState = DoodadTile
|
||||||
|
}
|
||||||
|
}
|
||||||
view.delegate
|
view.delegate
|
||||||
})
|
})
|
||||||
doodadSelector.children.clear()
|
doodadSelector.children.clear()
|
||||||
doodadSelector.children ++= doodads
|
doodadSelector.children ++= doodads
|
||||||
|
|
||||||
imgSeq = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
imgSeq = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
||||||
val view = new ImageView(currTile.icon.croppedImage()) // TODO Tile with adjacent
|
val view = new ImageView(level(x, y).icon.croppedImage()) // TODO Tile with adjacent
|
||||||
view.handleEvent(MouseEvent.Any) {
|
view.handleEvent(MouseEvent.Any) {
|
||||||
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
||||||
val index = point2index(x, y)
|
val index = point2index(x, y)
|
||||||
level.tiles = level.tiles.updated(index, currTile)
|
currState match {
|
||||||
autotile(x, y)
|
case GroundTile => {
|
||||||
|
level.tiles = level.tiles.updated(index, currTile)
|
||||||
|
autotile(x, y)
|
||||||
|
}
|
||||||
|
case DoodadTile => {
|
||||||
|
level.doodads = level.doodads.updated(index, currTile)
|
||||||
|
doodadSeq(index).image = level.doodads(index).icon.croppedImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
doodadSeq = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
||||||
|
val view = new ImageView(level.doodad(x, y).icon.croppedImage())
|
||||||
|
view
|
||||||
|
}
|
||||||
gameMap.children.clear()
|
gameMap.children.clear()
|
||||||
gameMap.prefColumns = level.width
|
gameMap.prefColumns = level.width
|
||||||
gameMap.prefRows = level.height
|
gameMap.prefRows = level.height
|
||||||
gameMap.children ++= imgSeq.map(_.delegate)
|
gameMap.children ++= imgSeq.map(_.delegate)
|
||||||
|
doodadMap.children.clear()
|
||||||
|
doodadMap.prefColumns = level.width
|
||||||
|
doodadMap.prefRows = level.height
|
||||||
|
doodadMap.children ++= doodadSeq.map(_.delegate)
|
||||||
|
doodadMap.mouseTransparent = true
|
||||||
|
|
||||||
for (y <- 0 until level.height; x <- 0 until level.width) {
|
for (y <- 0 until level.height; x <- 0 until level.width) {
|
||||||
smoothTile(x, y)
|
smoothTile(x, y)
|
||||||
@@ -123,24 +159,39 @@ class MapBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def smoothTile(x: Int, y: Int) = {
|
def smoothTile(x: Int, y: Int) = {
|
||||||
val i = point2index(x, y)
|
imgSeq(level.pt2index(x, y)).image = level.smoothed(x, y)
|
||||||
val dirs = scala.collection.mutable.Set[Direction.Value]()
|
}
|
||||||
|
|
||||||
val onLeft = x == 0
|
@FXML
|
||||||
val onRight = x + 1 == level.width
|
def onPropertiesDialog: Unit = {
|
||||||
val onTop = y == 0
|
val fxmlLoader = new FXMLLoader(getClass().getResource("dialog/MapProperties.fxml"))
|
||||||
val onBottom = y + 1 == level.height
|
val parent: Parent = fxmlLoader.load()
|
||||||
|
val dialogController = fxmlLoader.getController[MapProperties]();
|
||||||
if (onLeft || level.tiles(left(i)) == level.tiles(i)) dirs += West
|
//dialogController.setAppMainObservableList(tvObservableList);
|
||||||
if (onRight || level.tiles(right(i)) == level.tiles(i)) dirs += East
|
dialogController.init(level)
|
||||||
if (onTop || level.tiles(up(i)) == level.tiles(i)) dirs += North
|
|
||||||
if (onBottom || level.tiles(down(i)) == level.tiles(i)) dirs += South
|
val dialog = new Alert(AlertType.Confirmation) {
|
||||||
if (onLeft || onTop || level.tiles(left(up(i))) == level.tiles(i)) dirs += Northwest
|
title = "Map Properties"
|
||||||
if (onLeft || onBottom || level.tiles(down(left(i))) == level.tiles(i)) dirs += Southwest
|
dialogPane().content = parent
|
||||||
if (onTop || onRight || level.tiles(right(up(i))) == level.tiles(i)) dirs += Northeast
|
headerText = ""
|
||||||
if (onBottom || onRight || level.tiles(right(down(i))) == level.tiles(i)) dirs += Southeast
|
graphic = null
|
||||||
val index = point2index(x, y)
|
}
|
||||||
imgSeq(index).image = level.tiles(index).build(dirs.toSet).croppedImage()
|
val result = dialog.showAndWait()
|
||||||
|
println(result)
|
||||||
|
result match {
|
||||||
|
case Some(ButtonType.OK) => {
|
||||||
|
println(dialogController.width, dialogController.height)
|
||||||
|
level = new GameMap(dialogController.width, dialogController.height, tileset)
|
||||||
|
level.tiles = level.tiles.map(_ => currTile)
|
||||||
|
setup()
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
/*val scene = new Scene(parent, 300, 200);
|
||||||
|
val stage = new Stage();
|
||||||
|
stage.initModality(Modality.ApplicationModal);
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.showAndWait();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
def save() = {
|
def save() = {
|
||||||
@@ -213,6 +264,8 @@ object MapBuilder {
|
|||||||
|
|
||||||
val scene: Scene = new Scene(root)
|
val scene: Scene = new Scene(root)
|
||||||
primaryStage.setScene(scene)
|
primaryStage.setScene(scene)
|
||||||
|
primaryStage.width = 1280
|
||||||
|
primaryStage.height = 800
|
||||||
primaryStage.show()
|
primaryStage.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class TilesetBuilder extends Savable {
|
|||||||
var bPalette = IndexedSeq[AutoTile]()
|
var bPalette = IndexedSeq[AutoTile]()
|
||||||
var cPalette = IndexedSeq[AutoTile]()
|
var cPalette = IndexedSeq[AutoTile]()
|
||||||
|
|
||||||
val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets")
|
val resourceDir = new File(Config.homedir + raw"Progena\Resources\tilesets")
|
||||||
val files = resourceDir.listFiles()
|
val files = resourceDir.listFiles()
|
||||||
val filenames = files.map(f => (f.getName(), f)).toMap
|
val filenames = files.map(f => (f.getName(), f)).toMap
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ class TilesetBuilder extends Savable {
|
|||||||
if (a1Palette.size != currTileset.a1Size()) {
|
if (a1Palette.size != currTileset.a1Size()) {
|
||||||
currTileset.tileInfo.removeRange(0, currTileset.a1Size())
|
currTileset.tileInfo.removeRange(0, currTileset.a1Size())
|
||||||
currTileset.a1Size() = a1Palette.size
|
currTileset.a1Size() = a1Palette.size
|
||||||
val info = a1Palette.map(_ => allPassInfo)
|
val info = a1Palette.map(_ => noPassInfo)
|
||||||
currTileset.tileInfo.insert(0, info : _*)
|
currTileset.tileInfo.insert(0, info : _*)
|
||||||
}
|
}
|
||||||
updateTileView()
|
updateTileView()
|
||||||
@@ -159,7 +159,7 @@ class TilesetBuilder extends Savable {
|
|||||||
currTileset.a2.value = getSelected(a2Chooser)
|
currTileset.a2.value = getSelected(a2Chooser)
|
||||||
a2Palette = if (getSelected(a2Chooser) == null) IndexedSeq() else AutoTilePalette.a2(getSelected(a2Chooser), Config.tileSize).tiles
|
a2Palette = if (getSelected(a2Chooser) == null) IndexedSeq() else AutoTilePalette.a2(getSelected(a2Chooser), Config.tileSize).tiles
|
||||||
if (a2Palette.size != currTileset.a2Size()) {
|
if (a2Palette.size != currTileset.a2Size()) {
|
||||||
val priorSize = currTileset.a2Size()
|
val priorSize = currTileset.a1Size()
|
||||||
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a2Size())
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a2Size())
|
||||||
currTileset.a2Size() = a1Palette.size
|
currTileset.a2Size() = a1Palette.size
|
||||||
val info = a2Palette.map(_ => allPassInfo)
|
val info = a2Palette.map(_ => allPassInfo)
|
||||||
@@ -175,7 +175,7 @@ class TilesetBuilder extends Savable {
|
|||||||
val priorSize = currTileset.a1Size() + currTileset.a2Size()
|
val priorSize = currTileset.a1Size() + currTileset.a2Size()
|
||||||
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a3Size())
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a3Size())
|
||||||
currTileset.a3Size() = a1Palette.size
|
currTileset.a3Size() = a1Palette.size
|
||||||
val info = a3Palette.map(_ => allPassInfo)
|
val info = a3Palette.map(_ => noPassInfo)
|
||||||
currTileset.tileInfo.insert(priorSize, info : _*)
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
||||||
}
|
}
|
||||||
updateTileView()
|
updateTileView()
|
||||||
@@ -188,7 +188,7 @@ class TilesetBuilder extends Savable {
|
|||||||
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size()
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size()
|
||||||
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a4Size())
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a4Size())
|
||||||
currTileset.a4Size() = a4Palette.size
|
currTileset.a4Size() = a4Palette.size
|
||||||
val info = a4Palette.map(_ => allPassInfo)
|
val info = a4Palette.zipWithIndex.map{case (_, i) => if ((i / 8) % 2 == 0) allPassInfo else noPassInfo}
|
||||||
currTileset.tileInfo.insert(priorSize, info : _*)
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
||||||
}
|
}
|
||||||
updateTileView()
|
updateTileView()
|
||||||
@@ -214,7 +214,7 @@ class TilesetBuilder extends Savable {
|
|||||||
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size()
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size()
|
||||||
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.bSize())
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.bSize())
|
||||||
currTileset.bSize() = bPalette.size
|
currTileset.bSize() = bPalette.size
|
||||||
val info = bPalette.map(_ => allPassInfo)
|
val info = bPalette.zipWithIndex.map{case (_, i) => if (i != 0) doodadInfo else allPassInfo}
|
||||||
currTileset.tileInfo.insert(priorSize, info : _*)
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
||||||
}
|
}
|
||||||
updateTileView()
|
updateTileView()
|
||||||
@@ -227,7 +227,7 @@ class TilesetBuilder extends Savable {
|
|||||||
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size() + currTileset.bSize()
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size() + currTileset.bSize()
|
||||||
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.cSize())
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.cSize())
|
||||||
currTileset.cSize() = cPalette.size
|
currTileset.cSize() = cPalette.size
|
||||||
val info = cPalette.map(_ => allPassInfo)
|
val info = cPalette.map(_ => doodadInfo)
|
||||||
currTileset.tileInfo.insert(priorSize, info : _*)
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
||||||
}
|
}
|
||||||
updateTileView()
|
updateTileView()
|
||||||
@@ -255,12 +255,14 @@ class TilesetBuilder extends Savable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def updateTile(): Unit = {
|
def updateTile(): Unit = {
|
||||||
currTileset.tileInfo(currTileIndex) = TileInfo(
|
val northFlag = if (doesPassNorth.selected()) TileInfo.PassNorth else TileInfo.NoPass
|
||||||
doesPassNorth.selected(),
|
val eastFlag = if (doesPassEast.selected()) TileInfo.PassEast else TileInfo.NoPass
|
||||||
doesPassEast.selected(),
|
val southFlag = if (doesPassSouth.selected()) TileInfo.PassSouth else TileInfo.NoPass
|
||||||
doesPassSouth.selected(),
|
val westFlag = if (doesPassWest.selected()) TileInfo.PassWest else TileInfo.NoPass
|
||||||
doesPassWest.selected(),
|
val counterFlag = if (isCounter.selected()) TileInfo.IsCounter else TileInfo.NoPass
|
||||||
isCounter.selected())
|
val overwriteFlag = currTileset.tileInfo(currTileIndex).flags & TileInfo.Overwrite
|
||||||
|
val flags = northFlag | eastFlag | southFlag | westFlag | counterFlag | overwriteFlag
|
||||||
|
currTileset.tileInfo(currTileIndex) = TileInfo(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
def saveTo(file: File): Unit = {
|
def saveTo(file: File): Unit = {
|
||||||
@@ -289,7 +291,9 @@ class TilesetBuilder extends Savable {
|
|||||||
tilesetList.refresh()
|
tilesetList.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def allPassInfo = TileInfo(true, true, true, true, false)
|
private def allPassInfo = TileInfo(TileInfo.PassAll)
|
||||||
|
private def noPassInfo = TileInfo(TileInfo.NoPass)
|
||||||
|
private def doodadInfo = TileInfo(TileInfo.NoPass | TileInfo.Overwrite)
|
||||||
}
|
}
|
||||||
|
|
||||||
object TilesetBuilder {
|
object TilesetBuilder {
|
||||||
|
|||||||
28
Builder/src/fmon/builder/dialog/MapProperties.fxml
Normal file
28
Builder/src/fmon/builder/dialog/MapProperties.fxml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.ComboBox?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.Spinner?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
|
||||||
|
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.dialog.MapProperties">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="294.0" minWidth="10.0" prefWidth="74.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label text="Width" />
|
||||||
|
<Label text="Height" GridPane.rowIndex="1" />
|
||||||
|
<Label text="Tileset" GridPane.rowIndex="2" />
|
||||||
|
<Spinner fx:id="widthSpin" editable="true" initialValue="10" max="100" min="10" GridPane.columnIndex="1" />
|
||||||
|
<Spinner fx:id="heightSpin" editable="true" initialValue="10" max="100" min="10" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||||
|
<ComboBox fx:id="tilesetChooser" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
26
Builder/src/fmon/builder/dialog/MapProperties.scala
Normal file
26
Builder/src/fmon/builder/dialog/MapProperties.scala
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package fmon.builder.dialog
|
||||||
|
|
||||||
|
import javafx.fxml.FXML
|
||||||
|
import javafx.scene.{control => jfxsc, layout => jfxsl, Parent, Scene}
|
||||||
|
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scalafx.scene.control.SpinnerValueFactory
|
||||||
|
|
||||||
|
import fmon.world.GameMap
|
||||||
|
|
||||||
|
class MapProperties {
|
||||||
|
@FXML var widthSpin: jfxsc.Spinner[Int] = _
|
||||||
|
@FXML var heightSpin: jfxsc.Spinner[Int] = _
|
||||||
|
|
||||||
|
@FXML def initialize(): Unit = {
|
||||||
|
println(widthSpin)
|
||||||
|
}
|
||||||
|
|
||||||
|
def init(level: GameMap): Unit = {
|
||||||
|
widthSpin.valueFactory().value = level.width
|
||||||
|
heightSpin.valueFactory().value = level.height
|
||||||
|
}
|
||||||
|
|
||||||
|
def width = widthSpin.value()
|
||||||
|
def height = heightSpin.value()
|
||||||
|
}
|
||||||
@@ -10,7 +10,9 @@ case class Config(
|
|||||||
val weakMult: Double,
|
val weakMult: Double,
|
||||||
val immuneMult: Double,
|
val immuneMult: Double,
|
||||||
val maxBoost: Int,
|
val maxBoost: Int,
|
||||||
val tileSize: Int
|
val tileSize: Int,
|
||||||
|
val moveSpeed: Double,
|
||||||
|
val yOffset: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -26,4 +28,8 @@ object Config {
|
|||||||
def immuneMult = config.immuneMult
|
def immuneMult = config.immuneMult
|
||||||
def maxBoost = config.maxBoost
|
def maxBoost = config.maxBoost
|
||||||
def tileSize = config.tileSize
|
def tileSize = config.tileSize
|
||||||
|
def moveSpeed = config.moveSpeed
|
||||||
|
def yOffset = config.yOffset
|
||||||
|
|
||||||
|
def homedir = raw"C:\Users\dalyj\Documents\Design\Project\"
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ object Game {
|
|||||||
|
|
||||||
class Game extends Application {
|
class Game extends Application {
|
||||||
override def start(primaryStage: Stage): Unit = {
|
override def start(primaryStage: Stage): Unit = {
|
||||||
|
/*
|
||||||
val url = getClass.getResource("battle/battle.fxml")
|
val url = getClass.getResource("battle/battle.fxml")
|
||||||
val loader = new FXMLLoader(url)
|
val loader = new FXMLLoader(url)
|
||||||
val root: Parent = loader.load()
|
val root: Parent = loader.load()
|
||||||
@@ -43,5 +44,6 @@ class Game extends Application {
|
|||||||
primaryStage.setTitle(Config.title)
|
primaryStage.setTitle(Config.title)
|
||||||
primaryStage.setScene(scene)
|
primaryStage.setScene(scene)
|
||||||
primaryStage.show()
|
primaryStage.show()
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
31
FakeMon/src/fmon/GameManager.scala
Normal file
31
FakeMon/src/fmon/GameManager.scala
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fmon
|
||||||
|
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scalafx.scene.Node
|
||||||
|
import scalafx.scene.Parent
|
||||||
|
import scalafx.stage.Stage
|
||||||
|
|
||||||
|
import fmon.world.ui.GameView
|
||||||
|
|
||||||
|
object GameManager {
|
||||||
|
var currLevel: Parent = _
|
||||||
|
var currController: GameView = _
|
||||||
|
|
||||||
|
var currView: Parent = _
|
||||||
|
|
||||||
|
var root: Stage = _
|
||||||
|
|
||||||
|
def setView(view: Parent): Unit = {
|
||||||
|
currController.timer.stop()
|
||||||
|
currView = view
|
||||||
|
root.scene().root = view
|
||||||
|
}
|
||||||
|
|
||||||
|
def restoreMap(): Unit = {
|
||||||
|
currView = currLevel
|
||||||
|
root.scene().root = currView
|
||||||
|
currController.timer.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package fmon.battle
|
|||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
|
import fmon._
|
||||||
import fmon.battle.msg._
|
import fmon.battle.msg._
|
||||||
import fmon.stat._
|
import fmon.stat._
|
||||||
import fmon.stat.Statistic._
|
import fmon.stat.Statistic._
|
||||||
@@ -39,10 +40,11 @@ class BattleEngine(val player: Party, val enemy: Party)(implicit val reader: Sig
|
|||||||
|
|
||||||
if (!player.lead.isAlive) {
|
if (!player.lead.isAlive) {
|
||||||
if (player.canFight) {
|
if (player.canFight) {
|
||||||
val replace = player.pollReplacement(enemy)
|
val replace = player.pollReplacement(enemy)
|
||||||
player.switchIn(replace)
|
player.switchIn(replace)
|
||||||
} else {
|
} else {
|
||||||
this ! Message(s"${player.trainer} has lost!")
|
this ! Message(s"${player.trainer} has lost!")
|
||||||
|
GameManager.restoreMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!enemy.lead.isAlive) {
|
if (!enemy.lead.isAlive) {
|
||||||
@@ -51,6 +53,7 @@ class BattleEngine(val player: Party, val enemy: Party)(implicit val reader: Sig
|
|||||||
enemy.switchIn(replace)
|
enemy.switchIn(replace)
|
||||||
} else {
|
} else {
|
||||||
this ! Message(s"${enemy.trainer} has lost!")
|
this ! Message(s"${enemy.trainer} has lost!")
|
||||||
|
GameManager.restoreMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ package fmon.battle
|
|||||||
import java.io._
|
import java.io._
|
||||||
import java.util.concurrent.locks.{Condition, ReentrantLock}
|
import java.util.concurrent.locks.{Condition, ReentrantLock}
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
|
import javafx.application.Application
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import javafx.fxml.FXMLLoader
|
import javafx.fxml.FXMLLoader
|
||||||
import javafx.fxml.JavaFXBuilderFactory
|
import javafx.fxml.JavaFXBuilderFactory
|
||||||
import javafx.scene.{control => jfxsc}
|
import javafx.scene.{control => jfxsc}
|
||||||
import javafx.scene.image.ImageView
|
import javafx.scene.image.ImageView
|
||||||
|
import javafx.stage.Stage
|
||||||
|
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import scalafx.animation._
|
import scalafx.animation._
|
||||||
@@ -23,6 +27,7 @@ import scalafx.scene.text.Font
|
|||||||
import scalafx.scene.transform.Rotate
|
import scalafx.scene.transform.Rotate
|
||||||
import scalafx.util.Duration
|
import scalafx.util.Duration
|
||||||
|
|
||||||
|
import fmon.GameManager
|
||||||
import fmon.battle.msg._
|
import fmon.battle.msg._
|
||||||
import fmon.draw._
|
import fmon.draw._
|
||||||
import fmon.stat._
|
import fmon.stat._
|
||||||
@@ -46,7 +51,24 @@ class BattleUI extends SignalConsumer {
|
|||||||
private val lock = new ReentrantLock()
|
private val lock = new ReentrantLock()
|
||||||
private val finishedPlaying = lock.newCondition()
|
private val finishedPlaying = lock.newCondition()
|
||||||
|
|
||||||
|
def beginWildBattle(player: Party, wild: Monster)(implicit rng: Random) {
|
||||||
|
implicit val consumer = this
|
||||||
|
setEngine(new BattleEngine(
|
||||||
|
player,
|
||||||
|
new Party(BattleUI.WildTrainer, new MonsterPtr(wild), IndexedSeq())
|
||||||
|
))
|
||||||
|
this ! Message(s"A wild ${wild.name} appeared!")
|
||||||
|
}
|
||||||
|
|
||||||
|
def beginTrainerBattle(player: Party, trainer: Party)(implicit rng: Random) {
|
||||||
|
implicit val consumer = this
|
||||||
|
setEngine(new BattleEngine(player, trainer))
|
||||||
|
this ! Message(s"${trainer.trainer} wants to fight!")
|
||||||
|
this ! Message(s"${trainer.trainer} sent out ${trainer.lead}")
|
||||||
|
}
|
||||||
|
|
||||||
def setEngine(engine: BattleEngine): Unit = {
|
def setEngine(engine: BattleEngine): Unit = {
|
||||||
|
messages.clear()
|
||||||
this.engine = engine
|
this.engine = engine
|
||||||
updateUI()
|
updateUI()
|
||||||
}
|
}
|
||||||
@@ -204,4 +226,62 @@ class BattleUI extends SignalConsumer {
|
|||||||
controller.setup(move, onMove)
|
controller.setup(move, onMove)
|
||||||
button
|
button
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import javafx.scene.Scene
|
||||||
|
|
||||||
|
import fmon.Config
|
||||||
|
import fmon.stat.Gender
|
||||||
|
|
||||||
|
object BattleUI {
|
||||||
|
final val WildTrainer = TrainerID("Wild", Gender.Neuter, 0)
|
||||||
|
|
||||||
|
def startWildBattle(): Unit = {
|
||||||
|
val url = getClass.getResource("battle.fxml")
|
||||||
|
val loader = new FXMLLoader(url)
|
||||||
|
val root: javafx.scene.Parent = loader.load()
|
||||||
|
implicit val controller = loader.getController[BattleUI]()
|
||||||
|
|
||||||
|
implicit val rng = new scala.util.Random()
|
||||||
|
val form1 = Form("Diabolo")
|
||||||
|
val form2 = Form("Chanilla")
|
||||||
|
val movepool1 = IndexedSeq(Move("eruption"), Move("willowisp"), Move("thunderbolt"), Move("thunderwave"), Move("thundershock"))
|
||||||
|
val movepool2 = IndexedSeq(Move("tackle"))
|
||||||
|
val p1 = TrainerID("Jaeda", Gender.Female, 0)
|
||||||
|
val party1 = new Party(p1, new MonsterPtr(Monster.generate("Allied Mon", p1, 500, form1, movepool1)), IndexedSeq())
|
||||||
|
val monster = Monster.generate(null, WildTrainer, 500, form2, movepool2)
|
||||||
|
controller.beginWildBattle(party1, monster)
|
||||||
|
GameManager.setView(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameApp extends Application {
|
||||||
|
override def start(primaryStage: Stage): Unit = {
|
||||||
|
val url = getClass.getResource("battle.fxml")
|
||||||
|
val loader = new FXMLLoader(url)
|
||||||
|
val root: javafx.scene.Parent = loader.load()
|
||||||
|
implicit val controller = loader.getController[BattleUI]()
|
||||||
|
val scene: Scene = new Scene(root)
|
||||||
|
|
||||||
|
implicit val rng = new scala.util.Random()
|
||||||
|
val form1 = Form("Diabolo")
|
||||||
|
val form2 = Form("Chanilla")
|
||||||
|
val movepool1 = IndexedSeq(Move("eruption"), Move("willowisp"), Move("thunderbolt"), Move("thunderwave"), Move("thundershock"))
|
||||||
|
val movepool2 = IndexedSeq(Move("tackle"))
|
||||||
|
val p1 = TrainerID("Jaeda", Gender.Female, 0)
|
||||||
|
val p2 = TrainerID("Wild Monster", Gender.Male, 0)
|
||||||
|
val party1 = new Party(p1, new MonsterPtr(Monster.generate("Allied Mon", p1, 500, form1, movepool1)), IndexedSeq())
|
||||||
|
val party2 = new Party(p2, new MonsterPtr(Monster.generate("Wild Mon", p2, 500, form2, movepool2)), IndexedSeq(
|
||||||
|
Monster.generate("Sideboard Mon", p2, 500, form2, movepool2)
|
||||||
|
))
|
||||||
|
controller.beginTrainerBattle(party1, party2)
|
||||||
|
|
||||||
|
primaryStage.setTitle(Config.title)
|
||||||
|
primaryStage.setScene(scene)
|
||||||
|
primaryStage.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
Application.launch(classOf[GameApp], args: _*)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<?import javafx.scene.layout.Pane?>
|
<?import javafx.scene.layout.Pane?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
|
||||||
<VBox prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.battle.BattleUI">
|
<VBox prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.battle.BattleUI">
|
||||||
<children>
|
<children>
|
||||||
<MenuBar VBox.vgrow="NEVER">
|
<MenuBar VBox.vgrow="NEVER">
|
||||||
<menus>
|
<menus>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
</Menu>
|
</Menu>
|
||||||
</menus>
|
</menus>
|
||||||
</MenuBar>
|
</MenuBar>
|
||||||
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
|
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" VBox.vgrow="ALWAYS">
|
||||||
<children>
|
<children>
|
||||||
<ImageView fx:id="backgroundImg" fitHeight="575.0" fitWidth="856.0" pickOnBounds="true">
|
<ImageView fx:id="backgroundImg" fitHeight="575.0" fitWidth="856.0" pickOnBounds="true">
|
||||||
<image>
|
<image>
|
||||||
|
|||||||
@@ -7,3 +7,5 @@ immuneMult: 0.0
|
|||||||
maxBoost: 6
|
maxBoost: 6
|
||||||
newday: 02:00
|
newday: 02:00
|
||||||
tileSize: 48
|
tileSize: 48
|
||||||
|
yOffset: -4
|
||||||
|
moveSpeed: 3.0
|
||||||
|
|||||||
35
FakeMon/src/fmon/draw/AnimatedImageView.scala
Normal file
35
FakeMon/src/fmon/draw/AnimatedImageView.scala
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package fmon.draw
|
||||||
|
|
||||||
|
import scalafx.scene.image.ImageView
|
||||||
|
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scalafx.animation.Transition
|
||||||
|
import scalafx.util.Duration
|
||||||
|
|
||||||
|
class AnimatedImageView extends ImageView {
|
||||||
|
def this(img: Drawable, dur: Duration) {
|
||||||
|
this()
|
||||||
|
animate(img, dur)
|
||||||
|
}
|
||||||
|
|
||||||
|
var drawable: Drawable = _
|
||||||
|
var duration: Duration = _
|
||||||
|
|
||||||
|
private var animation: SpriteAnimation = _
|
||||||
|
|
||||||
|
def animate(img: Drawable, dur: Duration) {
|
||||||
|
drawable = img
|
||||||
|
duration = dur
|
||||||
|
animation = new SpriteAnimation(this, drawable, duration)
|
||||||
|
animation.cycleCount = Transition.Indefinite
|
||||||
|
animation.play()
|
||||||
|
}
|
||||||
|
|
||||||
|
def pause(): Unit = animation.pause()
|
||||||
|
def play(): Unit = animation.play()
|
||||||
|
def playFromStart(): Unit = animation.playFromStart()
|
||||||
|
def stop(): Unit = {
|
||||||
|
animation.stop()
|
||||||
|
animation.interpolate(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,9 +14,9 @@ object CharSet {
|
|||||||
val palette = new Palette(new FileInputStream(file), na, nd)
|
val palette = new Palette(new FileInputStream(file), na, nd)
|
||||||
val x = index % NumAcross
|
val x = index % NumAcross
|
||||||
val y = index / NumAcross
|
val y = index / NumAcross
|
||||||
val xx = x * NumAcross
|
val xx = x * FramesPerPose + 1
|
||||||
def pose(i: Int): AnimatedImage = {
|
def pose(i: Int): AnimatedImage = {
|
||||||
val yy = y * NumDown + i
|
val yy = y * Poses.size + i
|
||||||
val images = IndexedSeq(palette(xx, yy), palette(xx - 1, yy), palette(xx, yy), palette(xx + 1, yy))
|
val images = IndexedSeq(palette(xx, yy), palette(xx - 1, yy), palette(xx, yy), palette(xx + 1, yy))
|
||||||
new AnimatedImage(images)
|
new AnimatedImage(images)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import scalafx.scene.canvas.Canvas
|
|||||||
import scalafx.scene.image._
|
import scalafx.scene.image._
|
||||||
import scalafx.scene.paint.Color
|
import scalafx.scene.paint.Color
|
||||||
|
|
||||||
|
import fmon._
|
||||||
import fmon.draw._
|
import fmon.draw._
|
||||||
import fmon.util._
|
import fmon.util._
|
||||||
|
|
||||||
@@ -14,18 +15,18 @@ import Direction._
|
|||||||
|
|
||||||
trait AutoTile {
|
trait AutoTile {
|
||||||
def icon: StillImg
|
def icon: StillImg
|
||||||
def build(dirs: Set[Direction.Value]): StillImg
|
def build(dirs: Set[Direction]): StillImg
|
||||||
}
|
}
|
||||||
|
|
||||||
class BasicTile(val icon: StillImg) extends AutoTile {
|
class BasicTile(val icon: StillImg) extends AutoTile {
|
||||||
def build(dirs: Set[Direction.Value]) = icon
|
def build(dirs: Set[Direction]) = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
||||||
|
|
||||||
def icon: StillImg = palette.apply(0, 0, 2, 2)
|
def icon: StillImg = palette.apply(0, 0, 2, 2)
|
||||||
|
|
||||||
def build(dirs: Set[Direction.Value]) = {
|
def build(dirs: Set[Direction]) = {
|
||||||
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
||||||
val g = canvas.graphicsContext2D
|
val g = canvas.graphicsContext2D
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
StillImg(img, 0, 0, size, size)
|
StillImg(img, 0, 0, size, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getNE(dirs: Set[Direction.Value]): Image = {
|
private def getNE(dirs: Set[Direction]): Image = {
|
||||||
if (!dirs(Northeast) && dirs(North) && dirs(East)) {
|
if (!dirs(Northeast) && dirs(North) && dirs(East)) {
|
||||||
palette(3, 0).croppedImage()
|
palette(3, 0).croppedImage()
|
||||||
} else {
|
} else {
|
||||||
@@ -57,7 +58,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getNW(dirs: Set[Direction.Value]): Image = {
|
private def getNW(dirs: Set[Direction]): Image = {
|
||||||
if (!dirs(Northwest) && dirs(North) && dirs(West)) {
|
if (!dirs(Northwest) && dirs(North) && dirs(West)) {
|
||||||
palette(2, 0).croppedImage()
|
palette(2, 0).croppedImage()
|
||||||
} else {
|
} else {
|
||||||
@@ -67,7 +68,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getSE(dirs: Set[Direction.Value]): Image = {
|
private def getSE(dirs: Set[Direction]): Image = {
|
||||||
if (!dirs(Southeast) && dirs(South) && dirs(East)) {
|
if (!dirs(Southeast) && dirs(South) && dirs(East)) {
|
||||||
palette(3, 1).croppedImage()
|
palette(3, 1).croppedImage()
|
||||||
} else {
|
} else {
|
||||||
@@ -77,7 +78,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getSW(dirs: Set[Direction.Value]): Image = {
|
private def getSW(dirs: Set[Direction]): Image = {
|
||||||
if (!dirs(Southwest) && dirs(South) && dirs(West)) {
|
if (!dirs(Southwest) && dirs(South) && dirs(West)) {
|
||||||
palette(2, 1).croppedImage()
|
palette(2, 1).croppedImage()
|
||||||
} else {
|
} else {
|
||||||
@@ -111,7 +112,7 @@ class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
StillImg(img, 0, 0, size, size)
|
StillImg(img, 0, 0, size, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(dirs: Set[Direction.Value]) = {
|
def build(dirs: Set[Direction]) = {
|
||||||
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
||||||
val g = canvas.graphicsContext2D
|
val g = canvas.graphicsContext2D
|
||||||
|
|
||||||
@@ -133,25 +134,25 @@ class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
|||||||
StillImg(img, 0, 0, size, size)
|
StillImg(img, 0, 0, size, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def buildUL(dirs: Set[Direction.Value]) = {
|
private def buildUL(dirs: Set[Direction]) = {
|
||||||
val x = if (dirs(West)) 2 else 0
|
val x = if (dirs(West)) 2 else 0
|
||||||
val y = if (dirs(North)) 2 else 0
|
val y = if (dirs(North)) 2 else 0
|
||||||
palette(x, y)
|
palette(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def buildUR(dirs: Set[Direction.Value]) = {
|
private def buildUR(dirs: Set[Direction]) = {
|
||||||
val x = if (dirs(East)) 1 else 3
|
val x = if (dirs(East)) 1 else 3
|
||||||
val y = if (dirs(North)) 2 else 0
|
val y = if (dirs(North)) 2 else 0
|
||||||
palette(x, y)
|
palette(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def buildLL(dirs: Set[Direction.Value]) = {
|
private def buildLL(dirs: Set[Direction]) = {
|
||||||
val x = if (dirs(West)) 2 else 0
|
val x = if (dirs(West)) 2 else 0
|
||||||
val y = if (dirs(South)) 1 else 3
|
val y = if (dirs(South)) 1 else 3
|
||||||
palette(x, y)
|
palette(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def buildLR(dirs: Set[Direction.Value]) = {
|
private def buildLR(dirs: Set[Direction]) = {
|
||||||
val x = if (dirs(East)) 1 else 3
|
val x = if (dirs(East)) 1 else 3
|
||||||
val y = if (dirs(South)) 1 else 3
|
val y = if (dirs(South)) 1 else 3
|
||||||
palette(x, y)
|
palette(x, y)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import fmon.stat._
|
|||||||
import fmon.util.{Dice, IntFraction}
|
import fmon.util.{Dice, IntFraction}
|
||||||
|
|
||||||
package object fmon {
|
package object fmon {
|
||||||
|
type Direction = fmon.util.Direction.Val
|
||||||
|
|
||||||
implicit def rngDice(rng : Random) = new Dice(rng)
|
implicit def rngDice(rng : Random) = new Dice(rng)
|
||||||
implicit def int2Helper(x : Int) = new IntFraction(x)
|
implicit def int2Helper(x : Int) = new IntFraction(x)
|
||||||
|
|||||||
5
FakeMon/src/fmon/script/Action.scala
Normal file
5
FakeMon/src/fmon/script/Action.scala
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package fmon.script
|
||||||
|
|
||||||
|
trait Action[A] {
|
||||||
|
def apply(env: A): Unit
|
||||||
|
}
|
||||||
5
FakeMon/src/fmon/script/Condition.scala
Normal file
5
FakeMon/src/fmon/script/Condition.scala
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package fmon.script
|
||||||
|
|
||||||
|
trait Condition[A] {
|
||||||
|
def apply(t: A): Boolean
|
||||||
|
}
|
||||||
7
FakeMon/src/fmon/script/action/MessageAction.scala
Normal file
7
FakeMon/src/fmon/script/action/MessageAction.scala
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package fmon.script.action
|
||||||
|
|
||||||
|
import fmon.script.Action
|
||||||
|
|
||||||
|
class MessageAction[A](val msg: String) extends Action[A] {
|
||||||
|
override def apply(env: A) = println(msg)
|
||||||
|
}
|
||||||
7
FakeMon/src/fmon/script/condition/AndCondition.scala
Normal file
7
FakeMon/src/fmon/script/condition/AndCondition.scala
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package fmon.script.condition
|
||||||
|
|
||||||
|
import fmon.script.Condition
|
||||||
|
|
||||||
|
class AndCondition[A](seq: Seq[Condition[A]]) extends Condition[A] {
|
||||||
|
def apply(env: A): Boolean = seq.forall(_(env))
|
||||||
|
}
|
||||||
7
FakeMon/src/fmon/script/condition/OrCondition.scala
Normal file
7
FakeMon/src/fmon/script/condition/OrCondition.scala
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package fmon.script.condition
|
||||||
|
|
||||||
|
import fmon.script.Condition
|
||||||
|
|
||||||
|
class OrCondition[A](seq: Seq[Condition[A]]) extends Condition[A] {
|
||||||
|
def apply(env: A): Boolean = seq.exists(_(env))
|
||||||
|
}
|
||||||
@@ -2,15 +2,18 @@ package fmon.stat
|
|||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
|
||||||
case class Gene(val gender : Gender, val nature : Nature, val ivs : Map[Stat, Int], ot : TrainerID) {
|
case class Gene(val gender : Gender, val nature : Nature, val ivs : Map[Stat, Int], ot : TrainerID) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Gene {
|
object Gene {
|
||||||
final val MaxIV = 31
|
final val MaxIV = 31
|
||||||
def randomGene(ot : TrainerID, form : Form)(implicit rng : Random) = {
|
|
||||||
|
def randomGene(ot : TrainerID, form : Form)(implicit rng : Random): Gene = {
|
||||||
val gender = Gender.Neuter // TODO
|
val gender = Gender.Neuter // TODO
|
||||||
val ivs = Statistic.values.map(s => (s, rng.nextInt(MaxIV + 1))).toMap
|
val ivs = Statistic.values.toSeq.map(s => (s, rng.nextInt(MaxIV + 1))).toMap
|
||||||
Gene(gender, Nature.randomNature, ivs, ot)
|
Gene(gender, Nature.randomNature, ivs, ot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,22 @@
|
|||||||
package fmon.util
|
package fmon.util
|
||||||
|
|
||||||
|
import fmon.Direction
|
||||||
|
|
||||||
object Direction extends Enumeration {
|
object Direction extends Enumeration {
|
||||||
val North, Northeast, East, Southeast, South, Southwest, West, Northwest = Value
|
case class Val protected(x: Int = 0, y: Int = 0) extends super.Val {
|
||||||
|
}
|
||||||
|
|
||||||
|
val Stationary = Val()
|
||||||
|
val North = Val(y = -1)
|
||||||
|
val Northeast = Val(x = 1, y = -1)
|
||||||
|
val East = Val(x = 1)
|
||||||
|
val Southeast = Val(x = 1, y = 1)
|
||||||
|
val South = Val(y = 1)
|
||||||
|
val Southwest = Val(x = -1, y = 1)
|
||||||
|
val West = Val(x = -1)
|
||||||
|
val Northwest = Val(x = -1, y = -1)
|
||||||
|
|
||||||
val cardinals = Set(North, East, South, West)
|
val cardinals = Set(North, East, South, West)
|
||||||
|
|
||||||
|
def byName(s: String): Direction = super.withName(s).asInstanceOf[Direction]
|
||||||
}
|
}
|
||||||
45
FakeMon/src/fmon/world/Actor.scala
Normal file
45
FakeMon/src/fmon/world/Actor.scala
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package fmon.world
|
||||||
|
|
||||||
|
import scalafx.util.Duration
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
import fmon.draw._
|
||||||
|
import fmon.util.Direction
|
||||||
|
|
||||||
|
abstract class Actor(val sprite: Sprite, var pos: Position, var move: Movement) {
|
||||||
|
def x: Int = pos.x
|
||||||
|
def y: Int = pos.y
|
||||||
|
def xreal: Double = x - move.direction.x * move.completion
|
||||||
|
def yreal: Double = y - move.direction.y * move.completion
|
||||||
|
|
||||||
|
val imgView = new AnimatedImageView(sprite, new Duration(600)) {
|
||||||
|
x = pos.x * Config.tileSize
|
||||||
|
y = pos.y * Config.tileSize + Config.yOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
def pose: String = sprite.pose
|
||||||
|
def pose_=(p: String) = {
|
||||||
|
sprite.pose = p
|
||||||
|
}
|
||||||
|
|
||||||
|
def slide(dt: Duration): Unit = {
|
||||||
|
move.completion -= dt.toSeconds() * Config.moveSpeed
|
||||||
|
if (move.completion <= 0) {
|
||||||
|
move = selectNextMove
|
||||||
|
pos += move.direction
|
||||||
|
if (move.direction != Direction.Stationary) {
|
||||||
|
imgView.play()
|
||||||
|
} else {
|
||||||
|
imgView.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imgView.x = xreal * Config.tileSize
|
||||||
|
imgView.y = yreal * Config.tileSize + Config.yOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
def selectNextMove: Movement
|
||||||
|
}
|
||||||
|
|
||||||
|
class Hero(sprite: Sprite, pos: Position) extends Actor(sprite, pos, new Movement(Direction.Stationary, 0)) {
|
||||||
|
def selectNextMove = new Movement(Direction.Stationary, 0)
|
||||||
|
}
|
||||||
27
FakeMon/src/fmon/world/EventPage.scala
Normal file
27
FakeMon/src/fmon/world/EventPage.scala
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package fmon.world
|
||||||
|
|
||||||
|
import fmon.draw.Sprite
|
||||||
|
import fmon.script.Action
|
||||||
|
|
||||||
|
class EventPage (
|
||||||
|
// Conditions
|
||||||
|
// Switch
|
||||||
|
// Variable
|
||||||
|
// Self-Switch
|
||||||
|
// Item
|
||||||
|
// Actor
|
||||||
|
val sprite : Sprite,
|
||||||
|
// Priority - Above or below
|
||||||
|
// Trigger - Action button / On contact
|
||||||
|
// Movement
|
||||||
|
// Type
|
||||||
|
// Speed
|
||||||
|
// Frequency
|
||||||
|
// Options
|
||||||
|
// Walking Animation
|
||||||
|
// Stepping Animation
|
||||||
|
// Direction Fix
|
||||||
|
// Pass through (no-collide)
|
||||||
|
val action: Action[Actor]
|
||||||
|
) {
|
||||||
|
}
|
||||||
18
FakeMon/src/fmon/world/GameEvent.scala
Normal file
18
FakeMon/src/fmon/world/GameEvent.scala
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fmon.world
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
import fmon.util.Direction
|
||||||
|
|
||||||
|
class GameEvent(val name: String, val pages: IndexedSeq[EventPage]) {
|
||||||
|
def currPage = pages.head // TODO : Conditions
|
||||||
|
// Event Name
|
||||||
|
// Event Pages
|
||||||
|
}
|
||||||
|
|
||||||
|
class NPC(val event: GameEvent, pos: Position)
|
||||||
|
extends Actor(event.currPage.sprite, pos, new Movement(Direction.Stationary, 0.0)) {
|
||||||
|
|
||||||
|
def selectNextMove: Movement = {
|
||||||
|
new Movement(Direction.Stationary, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,29 @@
|
|||||||
package fmon.world
|
package fmon.world
|
||||||
|
|
||||||
|
import scalafx.scene.image.Image
|
||||||
|
|
||||||
import java.io._
|
import java.io._
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
import fmon.Config
|
||||||
|
import fmon.draw._
|
||||||
import fmon.draw.tile._
|
import fmon.draw.tile._
|
||||||
import fmon.util._
|
import fmon.util._
|
||||||
|
|
||||||
|
import Direction._
|
||||||
|
|
||||||
class GameMap(val width: Int, val height: Int, val tileset: Tileset) {
|
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
|
var tiles: IndexedSeq[AutoTile] = for (y <- 0 until height; x <- 0 until width) yield tileset.groundTiles.head
|
||||||
|
var doodads: IndexedSeq[AutoTile] = for (y <- 0 until height; x <- 0 until width) yield tileset.doodadTiles.head
|
||||||
|
|
||||||
|
def tileInfo(index: Int) = tileset.infoOf(tiles(index))
|
||||||
|
def tileInfo(pos: Position) = tileset.infoOf(this(pos))
|
||||||
|
def compositeInfo(pos: Position) = {
|
||||||
|
val gi = tileset.infoOf(this(pos))
|
||||||
|
val di = tileset.infoOf(doodad(pos))
|
||||||
|
if (di.doesOverwrite) di else gi
|
||||||
|
}
|
||||||
|
|
||||||
def saveTo(file: File): Unit = {
|
def saveTo(file: File): Unit = {
|
||||||
val ostream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
|
val ostream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
|
||||||
@@ -17,12 +33,46 @@ class GameMap(val width: Int, val height: Int, val tileset: Tileset) {
|
|||||||
val tileIndices = tileset.groundTiles.zipWithIndex.toMap
|
val tileIndices = tileset.groundTiles.zipWithIndex.toMap
|
||||||
tiles.foreach(t => ostream.writeInt(tileIndices(t)))
|
tiles.foreach(t => ostream.writeInt(tileIndices(t)))
|
||||||
//ostream.writeObject(tiles.map(tileIndices(_)).mkString(" "))
|
//ostream.writeObject(tiles.map(tileIndices(_)).mkString(" "))
|
||||||
|
val doodadIndices = tileset.doodadTiles.zipWithIndex.toMap
|
||||||
|
doodads.foreach(t => ostream.writeInt(doodadIndices(t)))
|
||||||
ostream.close()
|
ostream.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
def pt2index(x: Int, y: Int) = y * width + x
|
def apply(x: Int, y: Int): AutoTile = tiles(pt2index(x, y))
|
||||||
|
def doodad(x: Int, y: Int): AutoTile = doodads(pt2index(x, y))
|
||||||
|
def apply(pos: Position): AutoTile = tiles(pt2index(pos.x, pos.y))
|
||||||
|
def doodad(pos: Position): AutoTile = doodads(pt2index(pos.x, pos.y))
|
||||||
|
|
||||||
|
def smoothed(x: Int, y: Int): Image = {
|
||||||
|
val i = pt2index(x, y)
|
||||||
|
val dirs = scala.collection.mutable.Set[Direction]()
|
||||||
|
|
||||||
|
val onLeft = x == 0
|
||||||
|
val onRight = x + 1 == width
|
||||||
|
val onTop = y == 0
|
||||||
|
val onBottom = y + 1 == height
|
||||||
|
|
||||||
|
if (onLeft || tiles(left(i)) == tiles(i)) dirs += West
|
||||||
|
if (onRight || tiles(right(i)) == tiles(i)) dirs += East
|
||||||
|
if (onTop || tiles(up(i)) == tiles(i)) dirs += North
|
||||||
|
if (onBottom || tiles(down(i)) == tiles(i)) dirs += South
|
||||||
|
if (onLeft || onTop || tiles(left(up(i))) == tiles(i)) dirs += Northwest
|
||||||
|
if (onLeft || onBottom || tiles(down(left(i))) == tiles(i)) dirs += Southwest
|
||||||
|
if (onTop || onRight || tiles(right(up(i))) == tiles(i)) dirs += Northeast
|
||||||
|
if (onBottom || onRight || tiles(right(down(i))) == tiles(i)) dirs += Southeast
|
||||||
|
val index = pt2index(x, y)
|
||||||
|
tiles(index).build(dirs.toSet).croppedImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
def pt2index(x: Int, y: Int): Int = y * width + x
|
||||||
|
def pt2index(pos: Position): Int = pt2index(pos.x, pos.y)
|
||||||
def index2x(i: Int) = i % width
|
def index2x(i: Int) = i % width
|
||||||
def index2y(i: Int) = i / width
|
def index2y(i: Int) = i / width
|
||||||
|
|
||||||
|
def left(i: Int) = i - 1
|
||||||
|
def right(i: Int) = i + 1
|
||||||
|
def up(i: Int) = i - width
|
||||||
|
def down(i: Int) = i + width
|
||||||
}
|
}
|
||||||
|
|
||||||
object GameMap {
|
object GameMap {
|
||||||
@@ -31,14 +81,17 @@ object GameMap {
|
|||||||
val istream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))
|
val istream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))
|
||||||
val width = istream.readInt()
|
val width = istream.readInt()
|
||||||
val height = istream.readInt()
|
val height = istream.readInt()
|
||||||
val dir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Data")
|
val dir = new File(Config.homedir + raw"Progena\Data")
|
||||||
val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets")
|
val resourceDir = new File(Config.homedir + raw"Progena\Resources\tilesets")
|
||||||
val tokens = YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap
|
val tokens = YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap
|
||||||
val tileset = tokens("Outside").load(resourceDir)
|
val tileset = tokens("Outside").load(resourceDir)
|
||||||
val indices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt()
|
val indices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt()
|
||||||
|
val dindices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt()
|
||||||
val map = new GameMap(width, height, tileset)
|
val map = new GameMap(width, height, tileset)
|
||||||
val tiles = indices.map(i => tileset.groundTiles(i))
|
val tiles = indices.map(i => tileset.groundTiles(i))
|
||||||
|
val doodads = dindices.map(i => tileset.doodadTiles(i))
|
||||||
map.tiles = tiles
|
map.tiles = tiles
|
||||||
|
map.doodads = doodads
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
FakeMon/src/fmon/world/Position.scala
Normal file
15
FakeMon/src/fmon/world/Position.scala
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package fmon.world
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
import fmon.util.Direction._
|
||||||
|
|
||||||
|
case class Position(val x: Int, val y: Int) {
|
||||||
|
def +(d: Direction): Position = {
|
||||||
|
Position(x + d.x, y + d.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Movement(val direction: Direction, var completion: Double) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,16 +7,36 @@ import fmon.draw.tile._
|
|||||||
|
|
||||||
class Tileset(val groundTiles: IndexedSeq[AutoTile], val doodadTiles: IndexedSeq[AutoTile], val info: IndexedSeq[TileInfo]) {
|
class Tileset(val groundTiles: IndexedSeq[AutoTile], val doodadTiles: IndexedSeq[AutoTile], val info: IndexedSeq[TileInfo]) {
|
||||||
def groundInfo(index: Int) = info(index)
|
def groundInfo(index: Int) = info(index)
|
||||||
def doodadTiles(index: Int) = info(index - groundTiles.size)
|
def doodadInfo(index: Int) = info(index + groundTiles.size)
|
||||||
|
|
||||||
|
val infoOf = (groundTiles.zipWithIndex.map{case (t, i) => (t, groundInfo(i))} ++ doodadTiles.zipWithIndex.map{case (t, i) => (t, doodadInfo(i))}).toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TileInfo(
|
case class TileInfo(val flags: Int = TileInfo.PassAll) {
|
||||||
val doesPassNorth: Boolean,
|
def doesPassNorth = (flags & TileInfo.PassNorth) != 0
|
||||||
val doesPassEast: Boolean,
|
def doesPassEast = (flags & TileInfo.PassEast) != 0
|
||||||
val doesPassSouth: Boolean,
|
def doesPassSouth = (flags & TileInfo.PassSouth) != 0
|
||||||
val doesPassWest: Boolean,
|
def doesPassWest = (flags & TileInfo.PassWest) != 0
|
||||||
val isCounter: Boolean) {
|
|
||||||
|
|
||||||
|
def doesOverwrite = (flags & TileInfo.Overwrite) != 0
|
||||||
|
|
||||||
|
def isCounter = (flags & TileInfo.IsCounter) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object TileInfo {
|
||||||
|
val PassNorth = 0x0001
|
||||||
|
val PassEast = 0x0002
|
||||||
|
val PassSouth = 0x0004
|
||||||
|
val PassWest = 0x0008
|
||||||
|
val PassAll = PassNorth | PassEast | PassSouth | PassWest
|
||||||
|
val NoPass = 0
|
||||||
|
|
||||||
|
val Overwrite = 0x0010
|
||||||
|
val Underfoot = 0x0020
|
||||||
|
val Overhead = 0x0040
|
||||||
|
|
||||||
|
val IsCounter = 0x0100
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TilesetToken(
|
case class TilesetToken(
|
||||||
|
|||||||
18
FakeMon/src/fmon/world/ui/GameView.fxml
Normal file
18
FakeMon/src/fmon/world/ui/GameView.fxml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.ScrollPane?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<?import javafx.scene.layout.TilePane?>
|
||||||
|
|
||||||
|
<ScrollPane fx:id="scroller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onKeyPressed="#onKeyDown" onKeyReleased="#onKeyUp" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.world.ui.GameView">
|
||||||
|
<content>
|
||||||
|
<StackPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||||
|
<children>
|
||||||
|
<TilePane fx:id="background" />
|
||||||
|
<TilePane fx:id="doodads" />
|
||||||
|
<AnchorPane fx:id="characterPane" />
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
</content>
|
||||||
|
</ScrollPane>
|
||||||
310
FakeMon/src/fmon/world/ui/GameView.scala
Normal file
310
FakeMon/src/fmon/world/ui/GameView.scala
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
package fmon.world.ui
|
||||||
|
|
||||||
|
import java.io._
|
||||||
|
|
||||||
|
import javafx.application.Application
|
||||||
|
import javafx.fxml.FXML
|
||||||
|
import javafx.fxml.FXMLLoader
|
||||||
|
import javafx.fxml.JavaFXBuilderFactory
|
||||||
|
import javafx.scene.{control => jfxsc, layout => jfxsl, Parent, Scene}
|
||||||
|
import javafx.scene.input.KeyEvent
|
||||||
|
import javafx.stage.Stage
|
||||||
|
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scalafx.animation.AnimationTimer
|
||||||
|
import scalafx.beans.property._
|
||||||
|
import scalafx.collections.ObservableBuffer
|
||||||
|
import scalafx.geometry.Point2D
|
||||||
|
import scalafx.scene.control._
|
||||||
|
import scalafx.scene.image.ImageView
|
||||||
|
import scalafx.scene.input.{KeyCode, MouseEvent}
|
||||||
|
import scalafx.scene.paint.Color
|
||||||
|
import scalafx.scene.layout._
|
||||||
|
import scalafx.stage.FileChooser
|
||||||
|
import scalafx.stage.Modality
|
||||||
|
import scalafx.util.Duration
|
||||||
|
import FileChooser.ExtensionFilter
|
||||||
|
|
||||||
|
import fmon._
|
||||||
|
import fmon.battle.BattleUI
|
||||||
|
import fmon.draw._
|
||||||
|
import fmon.script.action.MessageAction
|
||||||
|
import fmon.util.Direction
|
||||||
|
import fmon.world._
|
||||||
|
import fmon.util.YamlHelper
|
||||||
|
import Direction._
|
||||||
|
|
||||||
|
class GameView {
|
||||||
|
@FXML var scroller: jfxsc.ScrollPane = _
|
||||||
|
@FXML var background: jfxsl.TilePane = _
|
||||||
|
@FXML var doodads: jfxsl.TilePane = _
|
||||||
|
@FXML var characterPane: jfxsl.AnchorPane = _
|
||||||
|
|
||||||
|
var hero: Actor = _
|
||||||
|
var npcs = Seq[NPC]()
|
||||||
|
def actors = hero +: npcs
|
||||||
|
|
||||||
|
var heroImg: AnimatedImageView = _
|
||||||
|
var currDir: Option[Direction] = None
|
||||||
|
|
||||||
|
var level: GameMap = _
|
||||||
|
|
||||||
|
var lastTime = 0L
|
||||||
|
val timer = AnimationTimer(t => {
|
||||||
|
if (lastTime != 0L) {
|
||||||
|
act(new Duration((t - lastTime) * 0.000001))
|
||||||
|
}
|
||||||
|
lastTime = t
|
||||||
|
})
|
||||||
|
|
||||||
|
def loadLevel(level: GameMap): Unit = {
|
||||||
|
this.level = level
|
||||||
|
background.prefColumns = level.width
|
||||||
|
val tiles = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
||||||
|
new ImageView(level.smoothed(x, y)).delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
background.children ++= tiles
|
||||||
|
|
||||||
|
doodads.prefColumns = level.width
|
||||||
|
val dtiles = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
||||||
|
new ImageView(level.doodad(x, y).icon.croppedImage()).delegate
|
||||||
|
}
|
||||||
|
doodads.children ++= dtiles
|
||||||
|
|
||||||
|
val heroFile = Config.homedir + raw"Progena\Resources\characters\Actor1.png"
|
||||||
|
hero = new Hero(CharSet(new File(heroFile), 1), Position(5, 4))
|
||||||
|
|
||||||
|
heroImg = hero.imgView
|
||||||
|
|
||||||
|
npcs = (0 until 8).map(i => {
|
||||||
|
val event = new GameEvent(s"NPC $i", IndexedSeq(new EventPage(
|
||||||
|
CharSet(new File(heroFile), i),
|
||||||
|
new MessageAction(s"I am NPC $i")
|
||||||
|
)))
|
||||||
|
new NPC(event, Position(7 + i, 3))
|
||||||
|
})
|
||||||
|
|
||||||
|
characterPane.children += heroImg
|
||||||
|
val npcImgs = npcs.map(npc => npc.imgView)
|
||||||
|
npcImgs.foreach(characterPane.children += _)
|
||||||
|
|
||||||
|
timer.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
def onKeyDown(k: KeyEvent): Unit = {
|
||||||
|
k.code match {
|
||||||
|
case KeyCode.W | KeyCode.Up => setDir(North)
|
||||||
|
case KeyCode.D | KeyCode.Right => setDir(East)
|
||||||
|
case KeyCode.A | KeyCode.Left => setDir(West)
|
||||||
|
case KeyCode.S | KeyCode.Down => setDir(South)
|
||||||
|
case KeyCode.Space => activate()
|
||||||
|
case KeyCode.BackQuote => beginWildBattle()
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def onKeyUp(k: KeyEvent): Unit = {
|
||||||
|
k.code match {
|
||||||
|
case KeyCode.W | KeyCode.Up => clearDir(North)
|
||||||
|
case KeyCode.D | KeyCode.Right => clearDir(East)
|
||||||
|
case KeyCode.A | KeyCode.Left => clearDir(West)
|
||||||
|
case KeyCode.S | KeyCode.Down => clearDir(South)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def beginWildBattle(): Unit = {
|
||||||
|
BattleUI.startWildBattle()
|
||||||
|
}
|
||||||
|
|
||||||
|
def activate(): Unit = {
|
||||||
|
if (hero.move.direction == Direction.Stationary) {
|
||||||
|
val dir = Direction.byName(hero.sprite.pose)
|
||||||
|
val np = hero.pos + dir
|
||||||
|
npcs.filter(npc => npc.pos == np).foreach(npc => npc.event.currPage.action(npc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setDir(dir: Direction): Unit = {
|
||||||
|
currDir = Some(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clearDir(dir: Direction): Unit = {
|
||||||
|
if (currDir == Some(dir)) {
|
||||||
|
currDir = None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def act(dur: Duration): Unit = {
|
||||||
|
/*currDir match {
|
||||||
|
case Some(North) => slide(hero, 0, -dur.toSeconds() * Config.moveSpeed)
|
||||||
|
case Some(East) => slide(hero, dur.toSeconds() * Config.moveSpeed, 0)
|
||||||
|
case Some(West) => slide(hero, -dur.toSeconds() * Config.moveSpeed, 0)
|
||||||
|
case Some(South) => slide(hero, 0, +dur.toSeconds() * Config.moveSpeed)
|
||||||
|
case _ => ()
|
||||||
|
}*/
|
||||||
|
if (hero.move.completion <= 0 && currDir.isDefined) {
|
||||||
|
val dir = currDir.get
|
||||||
|
|
||||||
|
if (hero.pose != dir.toString()) {
|
||||||
|
hero.pose = dir.toString()
|
||||||
|
} else {
|
||||||
|
val dest = hero.pos + dir
|
||||||
|
val info = level.compositeInfo(hero.pos + dir)
|
||||||
|
val canPass = (dir.x < 0 && info.doesPassEast) || (dir.x > 0 && info.doesPassWest) ||
|
||||||
|
(dir.y < 0 && info.doesPassSouth) || (dir.y > 0 && info.doesPassNorth)
|
||||||
|
val unoccupied = !actors.exists(a => a.pos == dest && a != hero)
|
||||||
|
|
||||||
|
if (canPass && unoccupied) {
|
||||||
|
hero.pos += dir
|
||||||
|
hero.move = new Movement(dir, 1.0)
|
||||||
|
hero.imgView.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hero.slide(dur)
|
||||||
|
npcs.foreach(_.slide(dur))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def slide(actor: Actor, dx: Double, dy: Double): Unit = {
|
||||||
|
// Need to do all corners
|
||||||
|
val px = if (dx < 0) actor.x else actor.x + 1
|
||||||
|
val py = if (dy < 0) actor.y else actor.y + 1
|
||||||
|
val tiles = tilesOnLine(new Point2D(px, py), new Point2D(px + dx, py + dy))
|
||||||
|
|
||||||
|
val condition = if (dx < 0 && dy < 0) {
|
||||||
|
info:TileInfo => info.doesPassSouth && info.doesPassEast
|
||||||
|
} else if (dx < 0) {
|
||||||
|
info: TileInfo => info.doesPassNorth && info.doesPassEast
|
||||||
|
} else if (dy < 0) {
|
||||||
|
info: TileInfo => info.doesPassSouth && info.doesPassWest
|
||||||
|
} else {
|
||||||
|
info: TileInfo => info.doesPassNorth && info.doesPassWest
|
||||||
|
}
|
||||||
|
|
||||||
|
val collisions = tiles.filterNot{case (i, _) => condition(level.tileInfo(i))}
|
||||||
|
if (!collisions.isEmpty) {
|
||||||
|
val (i, pt) = collisions.head
|
||||||
|
println(actor.y, pt.y)
|
||||||
|
actor.x += (pt.x - px)
|
||||||
|
actor.y += (pt.y - py)
|
||||||
|
//println(actor.x, actor.y)
|
||||||
|
} else {
|
||||||
|
actor.x += dx
|
||||||
|
actor.y += dy
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
def lineIntersectionIndices(p: Point2D, q: Point2D): Seq[Int] = {
|
||||||
|
def p2i(pt: Point2D) = level.pt2index(pt.x.toInt, pt.y.toInt)
|
||||||
|
val dx = q.x - p.x
|
||||||
|
val dy = q.y - p.y
|
||||||
|
val nx = Math.abs(dx).toInt
|
||||||
|
val ny = Math.abs(dy).toInt
|
||||||
|
val sx = Math.signum(dx)
|
||||||
|
val sy = Math.signum(dy)
|
||||||
|
|
||||||
|
var pts = Seq(p2i(p))
|
||||||
|
var pt = p
|
||||||
|
var ix = 0
|
||||||
|
var iy = 0
|
||||||
|
while (ix < nx || iy < ny) {
|
||||||
|
if ((0.5+ix) * ny < (0.5+iy) * nx) {
|
||||||
|
// next step is horizontal
|
||||||
|
pt = new Point2D(pt.x + sx, pt.y)
|
||||||
|
ix += 1
|
||||||
|
} else {
|
||||||
|
// next step is vertical
|
||||||
|
pt = new Point2D(pt.x, pt.y + sy)
|
||||||
|
ix += 1
|
||||||
|
}
|
||||||
|
pts :+= p2i(pt)
|
||||||
|
}
|
||||||
|
pts
|
||||||
|
}
|
||||||
|
|
||||||
|
def lineIntersectsGrid(p: Point2D, q: Point2D, gi: Int): Point2D = {
|
||||||
|
val gx = level.index2x(gi)
|
||||||
|
val gy = level.index2y(gi)
|
||||||
|
val dx = q.x - p.x
|
||||||
|
val dy = q.y - p.y
|
||||||
|
if (dx > 0) {
|
||||||
|
new Point2D(gx, p.y)
|
||||||
|
} else if (dx < 0) {
|
||||||
|
new Point2D(gx + 1.0, p.y)
|
||||||
|
} else if (dy > 0) {
|
||||||
|
new Point2D(p.x, gy)
|
||||||
|
} else if (dy < 0) {
|
||||||
|
new Point2D(p.x, gy + 1)
|
||||||
|
} else {
|
||||||
|
new Point2D(q.x, q.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def tilesOnLine(p: Point2D, q: Point2D): Seq[(Int, Point2D)] = {
|
||||||
|
val tileIndices = lineIntersectionIndices(p, q)
|
||||||
|
tileIndices.map(i => (i, lineIntersectsGrid(p, q, i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def tilesOnLine_(p: Point2D, q: Point2D): Seq[(Int, Point2D)] = {
|
||||||
|
val dx = q.x - p.x
|
||||||
|
val dy = q.y - p.y
|
||||||
|
val nx = Math.abs(dx).toInt
|
||||||
|
val ny = Math.abs(dy).toInt
|
||||||
|
val sx = Math.signum(dx)
|
||||||
|
val sy = Math.signum(dy)
|
||||||
|
|
||||||
|
var pts = Seq(p)
|
||||||
|
var pt = p
|
||||||
|
var ix = 0
|
||||||
|
var iy = 0
|
||||||
|
while (ix < nx || iy < ny) {
|
||||||
|
if ((0.5+ix) * ny < (0.5+iy) * nx) {
|
||||||
|
// next step is horizontal
|
||||||
|
pt = new Point2D(pt.x + sx, pt.y)
|
||||||
|
ix += 1
|
||||||
|
} else {
|
||||||
|
// next step is vertical
|
||||||
|
pt = new Point2D(pt.x, pt.y + sy)
|
||||||
|
ix += 1
|
||||||
|
}
|
||||||
|
pts :+= pt
|
||||||
|
}
|
||||||
|
|
||||||
|
pts.map(pt => (level.pt2index(pt.x.toInt, pt.y.toInt), pt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object GameView {
|
||||||
|
class GameApp extends Application {
|
||||||
|
override def start(primaryStage: Stage): Unit = {
|
||||||
|
val frameLoader = new FXMLLoader(getClass.getResource("GameView.fxml"))
|
||||||
|
val root: Parent = frameLoader.load()
|
||||||
|
val controller = frameLoader.getController[GameView]()
|
||||||
|
|
||||||
|
val stageFile = Config.homedir + raw"Progena\Data\outside.map"
|
||||||
|
val level = GameMap.loadFrom(new File(stageFile))
|
||||||
|
controller.loadLevel(level)
|
||||||
|
|
||||||
|
val scene: Scene = new Scene(root)
|
||||||
|
|
||||||
|
GameManager.root = primaryStage
|
||||||
|
GameManager.currLevel = root
|
||||||
|
GameManager.currController = controller
|
||||||
|
GameManager.currView = root
|
||||||
|
|
||||||
|
primaryStage.setScene(scene)
|
||||||
|
primaryStage.width = 1280
|
||||||
|
primaryStage.height = 800
|
||||||
|
//primaryStage.maximized = true
|
||||||
|
primaryStage.show()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
Application.launch(classOf[GameApp], args: _*)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user