diff --git a/README.md b/README.md
index e7dea83..0ea12c2 100644
--- a/README.md
+++ b/README.md
@@ -50,32 +50,33 @@ There are also some special commands:
## Screenshots
-This is how the game looks when run (**very** preliminary GUI):
+This is how the game looks when run:
![](screenshots/gameplay.gif)
### Map
-![](screenshots/orig_map.png)
+After selecting a new game you have to generate the world, just before choosing the attributes.
-Thanks to the map generator from [Red Blob Games](https://www.redblobgames.com/), I produced the map above. The one in
-the game is fundamentally based on this (eg, it uses this heightmap) but it then simplifies the terrains into less
-groups - so my map is much less coloured and it has less water mass.
+NB: trees cannot be seen here, but they are generated (as individual obstacles) with varying probability
+depending on terrain type.
-The rivers and lakes are also currently not present. The map is **2048x2048 pixels**, and it's pixel is one "cell" in
-game, so it's pretty big.
+The rivers and lakes are upcoming in release `0.3.0`. The terrain types are currently fixed. Ordered by
+height, they are:
-In game, if it could be zoomed out it would look more like this:
+* Deep water
+* Shallow water
+* Coast
+* Grass-less ground
+* Grass plain
+* Grassy Hill
+* Rocky Hill
+* Mountain
+* High Mountain
-![](screenshots/map.png)
+Some terrains are harder to move through: more stamina will be consumed, and a higher delay is to be expected.
-The elevation thresholds are simplified to reduce the amount of colours (and thus, terrains) shown.
-
-Later the terrain will be configurable by the user.
-
-You can also see some rivers (still in-progress, not in the game yet) flowing from high to low places.
-
-Note: this is only temporary. In the final game the terrain will be randomised.
+All this should be completely configurable by the user by release `0.4.0`, hopefully.
## Features
diff --git a/alone-rl.iml b/alone-rl.iml
index a202107..79edaeb 100644
--- a/alone-rl.iml
+++ b/alone-rl.iml
@@ -13,18 +13,19 @@
-
-
+
+
+
-
-
-
-
+
+
+
+
-
+
\ No newline at end of file
diff --git a/data/items.yml b/data/items.yml
index 44e4576..c12de3b 100644
--- a/data/items.yml
+++ b/data/items.yml
@@ -62,9 +62,9 @@ tree:
sprite:
c: T
col:
- red: 0
- green: 205
- blue: 113
+ red: 77
+ green: 168
+ blue: 59
shadowView: true
obstacle: {}
cuttable: {}
diff --git a/data/map/elevation.data b/data/map/elevation.data
index 7461bad..9a78b4f 100644
Binary files a/data/map/elevation.data and b/data/map/elevation.data differ
diff --git a/data/map/map.png b/data/map/map.png
deleted file mode 100644
index 37008b2..0000000
Binary files a/data/map/map.png and /dev/null differ
diff --git a/data/map/map.yml b/data/map/map.yml
deleted file mode 100644
index e69de29..0000000
diff --git a/data/map/terrain.yml b/data/map/terrain.yml
new file mode 100644
index 0000000..a0adcad
--- /dev/null
+++ b/data/map/terrain.yml
@@ -0,0 +1,81 @@
+
+deep-water:
+ c: 247
+ col:
+ red: 51
+ green: 102
+ blue: 153
+ theight: 0.01
+ type: WATER
+
+shallow-water:
+ c: '~'
+ col:
+ red: 20
+ green: 152
+ blue: 204
+ theight: 0.05
+ type: WATER
+
+sand:
+ c: 250
+ col:
+ red: 170
+ green: 170
+ blue: 0
+ theight: 0.08
+ type: LAND
+
+ground:
+ c: 250
+ col:
+ red: 184
+ green: 134
+ blue: 11
+ theight: 0.1
+ type: LAND
+
+grass:
+ c: 250
+ col:
+ red: 31
+ green: 138
+ blue: 19
+ theight: 0.4
+ type: GRASS
+
+hill-grass:
+ c: '^'
+ col:
+ red: 74
+ green: 105
+ blue: 4
+ theight: 0.7
+ type: GRASS
+
+hill:
+ c: '^'
+ col:
+ red: 119
+ green: 93
+ blue: 61
+ theight: 0.8
+ type: LAND
+
+mountain:
+ c: '^'
+ col:
+ red: 76
+ green: 70
+ blue: 50
+ theight: 0.9
+ type: LAND
+
+high-mountain:
+ c: '^'
+ col:
+ red: 255
+ green: 240
+ blue: 220
+ theight: 1.1 # must be strictly greater than 1
+ type: ICE
diff --git a/data/palette.yml b/data/palette.yml
new file mode 100644
index 0000000..9c4a014
--- /dev/null
+++ b/data/palette.yml
@@ -0,0 +1,46 @@
+
+## Arne64 from http://www.gridsagegames.com/rexpaint/palettes/Arne64.txt
+#
+#gray: [{0,0,0},{21,21,21},{52,52,52},{123,123,123},{168,168,168},{215,215,215},{255,255,255}]
+#brown: [{ 35, 23, 18},{92,60,13},{174,108,55},{197,151,130},{226,215,181}]
+#grayblue: [{13,32,48},{65,93,102},{113,166,161}]
+#ochra: [{173,78,26},{246,143,55}]
+#cyan: [{0,82,128},{10,152,172},{37,226,205},{189,255,202}]
+#red: [{79,21,7},{224,60,40}]
+#aquamarine: [{0,96,75},{32,181,98}]
+#rosee: [{130,60,61},{218,101,94},{225,130,137},{245,183,132},{255,233,197}]
+#green: [{0,78,0},{19,157,8},{88,211,50}]
+#pink: [{135,22,70},{207, 60,113},{255,130,206}]
+#green2: [{23,40,8},{55,109,3},{106,180,23},{140,214,18},{190,235,113},{238,255,169}]
+#magenta: [{163,40,179},{204,105,228},{213,156,252},{254,201,237}]
+#acidgreen: [{147,151,23},{182,193,33}]
+#purple: [{33,22,64},{90,25,145},{106,49,202},{166,117,254},{226,201,255}]
+#yellow: [{204,143, 21},{255,187,49},{255,231,55}]
+#indigo: [{61,52,165},{98,100,220},{155,160,239}]
+#blue: [{0,23,125},{2,74,202},{0,132,255},{91,168,255},{152,220,255}]
+
+# from libtcod
+
+red: 255,0,0
+flame: 255,63,0
+orange: 255,127,0
+amber: 255,191,0
+yellow: 255,255,0,
+lime: 191,255,0
+chartreuse: 127,255,0
+green: 0,255,0
+sea: 0,255,127
+turquoise: 0,255,191
+cyan: 0,255,255
+sky: 0,191,255
+azure: 0,127,255
+blue: 0,0,255
+han: 63,0,255
+violet: 127,0,255
+purple: 191,0,255
+fuchsia: 255,0,255
+magenta: 255,0,191
+pink: 255,0,127
+crimson: 255,0,63
+sepia: 127,101,63
+gray: 127,127,127
diff --git a/make_pkg.sh b/make_pkg.sh
index fb53c7d..07a57e6 100755
--- a/make_pkg.sh
+++ b/make_pkg.sh
@@ -1,9 +1,9 @@
#!/bin/bash
-v=`ls target/alone-rl-*-jar-with-dependencies.jar | awk -F"-" '{print $3}'`
-
mvn clean package -Dmaven.test.skip=true
+v=`ls target/alone-rl-*-jar-with-dependencies.jar | awk -F"-" '{print $3}'`
+
cp target/alone-rl-*-jar-with-dependencies.jar alone-rl-$v.jar
7z a -tzip alone-rl-$v.zip data/ alone-rl-$v.jar
diff --git a/pom.xml b/pom.xml
index bfc9bf8..556fc16 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,9 +20,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- com.github.fabioticconi
+ com.github.fabio-t
alone-rl
- 0.2.0
+ 0.2.5
jar
AloneRL
@@ -41,48 +41,56 @@
net.onedaybeard.artemis
artemis-odb
- 2.1.0
+ [2,3)
net.mostlyoriginal.artemis-odb
contrib-core
- 2.2.0
+ [2,3)
com.github.fabioticconi
rlforj-alt
- 0.2.0
+ 0.3.0
- ch.qos.logback
- logback-classic
- 1.2.3
+ com.github.fabioticconi
+ terrain-generator
+ 0.0.1
- com.fasterxml.jackson.dataformat
- jackson-dataformat-yaml
- 2.9.1
+ ch.qos.logback
+ logback-classic
+ [1,2)
junit
junit
- 4.12
+ [4,5)
test
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+ 2.9.3
+
+
com.fasterxml.jackson.core
jackson-databind
+ 2.9.3
com.fasterxml.jackson.module
jackson-module-parameter-names
+ 2.9.3
@@ -92,7 +100,7 @@
com.fasterxml.jackson
jackson-bom
- 2.9.0
+ 2.9.3
import
pom
@@ -113,7 +121,7 @@
org.apache.maven.plugins
maven-release-plugin
- 2.5.3
+ [2,3)
@{project.version}
@@ -161,9 +169,9 @@
- scm:git:git@fabioticconi/alone-rl.git
- scm:git:git@fabioticconi/alone-rl.git
- scm:git:git@fabioticconi/alone-rl.git
+ scm:git:git@fabio-t/alone-rl.git
+ scm:git:git@fabio-t/alone-rl.git
+ scm:git:git@fabio-t/alone-rl.git
diff --git a/screenshots/full_colours.png b/screenshots/full_colours.png
deleted file mode 100644
index 4e56c4a..0000000
Binary files a/screenshots/full_colours.png and /dev/null differ
diff --git a/screenshots/gameplay.gif b/screenshots/gameplay.gif
index 1e0b896..7e999c4 100644
Binary files a/screenshots/gameplay.gif and b/screenshots/gameplay.gif differ
diff --git a/screenshots/map.png b/screenshots/map.png
deleted file mode 100644
index 927e979..0000000
Binary files a/screenshots/map.png and /dev/null differ
diff --git a/screenshots/orig_map.png b/screenshots/orig_map.png
deleted file mode 100644
index 15fdcd5..0000000
Binary files a/screenshots/orig_map.png and /dev/null differ
diff --git a/screenshots/screenshot.png b/screenshots/screenshot.png
deleted file mode 100644
index 68ea9a2..0000000
Binary files a/screenshots/screenshot.png and /dev/null differ
diff --git a/src/main/java/com/github/fabioticconi/alone/Main.java b/src/main/java/com/github/fabioticconi/alone/Main.java
index 426d95c..5085bc3 100644
--- a/src/main/java/com/github/fabioticconi/alone/Main.java
+++ b/src/main/java/com/github/fabioticconi/alone/Main.java
@@ -79,6 +79,7 @@ public Main() throws IOException
final WorldConfiguration config;
config = new WorldConfiguration();
// first thing to be loaded
+ config.setSystem(MapScreen.class);
config.setSystem(MapSystem.class);
// POJO
config.register(new Random());
@@ -127,6 +128,7 @@ public Main() throws IOException
config.setSystem(EquipScreen.class);
config.setSystem(CraftScreen.class);
config.setSystem(CraftItemScreen.class);
+ config.setSystem(CharScreen.class);
// last systems
config.setSystem(DeadSystem.class);
@@ -174,6 +176,8 @@ public void loop()
long repaintCooldown = 1L;
long actionCooldown = 0L;
+ world.process();
+
while (keepRunning)
{
currentTime = System.nanoTime();
diff --git a/src/main/java/com/github/fabioticconi/alone/behaviours/GrazeBehaviour.java b/src/main/java/com/github/fabioticconi/alone/behaviours/GrazeBehaviour.java
index 8dab748..3d181a2 100644
--- a/src/main/java/com/github/fabioticconi/alone/behaviours/GrazeBehaviour.java
+++ b/src/main/java/com/github/fabioticconi/alone/behaviours/GrazeBehaviour.java
@@ -23,7 +23,7 @@
import com.github.fabioticconi.alone.components.Position;
import com.github.fabioticconi.alone.components.Speed;
import com.github.fabioticconi.alone.components.attributes.Sight;
-import com.github.fabioticconi.alone.constants.Cell;
+import com.github.fabioticconi.alone.constants.TerrainType;
import com.github.fabioticconi.alone.systems.ActionSystem;
import com.github.fabioticconi.alone.systems.BumpSystem;
import com.github.fabioticconi.alone.systems.HungerSystem;
@@ -53,7 +53,7 @@ public class GrazeBehaviour extends AbstractBehaviour
// FIXME: this should be in a Context of sort
private Hunger hunger;
- private EnumSet validCells = EnumSet.of(Cell.GRASS, Cell.HILL_GRASS);
+ final private EnumSet validCells = EnumSet.of(TerrainType.GRASS);
@Override
protected void initialize()
diff --git a/src/main/java/com/github/fabioticconi/alone/behaviours/UnderwaterBehaviour.java b/src/main/java/com/github/fabioticconi/alone/behaviours/UnderwaterBehaviour.java
index 393690f..8d4ffe2 100644
--- a/src/main/java/com/github/fabioticconi/alone/behaviours/UnderwaterBehaviour.java
+++ b/src/main/java/com/github/fabioticconi/alone/behaviours/UnderwaterBehaviour.java
@@ -24,8 +24,8 @@
import com.github.fabioticconi.alone.components.Position;
import com.github.fabioticconi.alone.components.Speed;
import com.github.fabioticconi.alone.components.Underwater;
-import com.github.fabioticconi.alone.constants.Cell;
import com.github.fabioticconi.alone.constants.Side;
+import com.github.fabioticconi.alone.constants.TerrainType;
import com.github.fabioticconi.alone.systems.BumpSystem;
import com.github.fabioticconi.alone.systems.MapSystem;
@@ -39,14 +39,17 @@
*/
public class UnderwaterBehaviour extends AbstractBehaviour
{
- final EnumSet validCells = EnumSet.of(Cell.WATER, Cell.DEEP_WATER);
ComponentMapper mPos;
MapSystem map;
BumpSystem sBump;
+
@Wire
Random r;
+
private Position curPos;
+ private final EnumSet validCells = EnumSet.of(TerrainType.WATER);
+
@Override
protected void initialize()
{
@@ -63,9 +66,9 @@ public float evaluate(final int entityId)
curPos = mPos.get(entityId);
- final Cell c = map.get(curPos.x, curPos.y);
+ final MapSystem.Cell c = map.get(curPos.x, curPos.y);
- if (c != Cell.DEEP_WATER && c != Cell.WATER)
+ if (c.type != TerrainType.WATER)
{
// can't move at all if on solid ground
diff --git a/src/main/java/com/github/fabioticconi/alone/constants/Cell.java b/src/main/java/com/github/fabioticconi/alone/constants/Cell.java
deleted file mode 100644
index d0324fd..0000000
--- a/src/main/java/com/github/fabioticconi/alone/constants/Cell.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 Fabio Ticconi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- *
- */
-package com.github.fabioticconi.alone.constants;
-
-import com.github.fabioticconi.alone.utils.Util;
-
-import java.awt.*;
-
-/**
- * @author Fabio Ticconi
- */
-public enum Cell
-{
- EMPTY(),
- DEEP_WATER('=', Color.BLUE.darker().darker().darker()),
- WATER('~', Color.BLUE.brighter()),
- SAND((char) 250, Color.ORANGE),
- GROUND((char) 250, Color.ORANGE.darker().darker()),
- GRASS((char) 250, Color.GREEN.darker().darker().darker()),
- HILL_GRASS('^', Color.GREEN.darker().darker().darker()),
- HILL('^', Util.BROWN),
- MOUNTAIN('^', Util.BROWN.darker()),
- HIGH_MOUNTAIN('^', Color.GRAY);
-
- public final char c;
- public final Color col;
- public final Color bg;
-
- Cell()
- {
- this.c = ' ';
- this.col = Color.BLACK;
- this.bg = Color.BLACK;
- }
-
- Cell(final char c)
- {
- this.c = c;
- this.col = Color.BLACK;
- this.bg = Color.BLACK;
- }
-
- Cell(final char c, final Color color)
- {
- this.c = c;
- // this.col = color;
- // this.bg = Color.BLACK;
- this.col = color.darker();
- this.bg = color;
- }
-}
diff --git a/src/main/java/com/github/fabioticconi/alone/constants/Options.java b/src/main/java/com/github/fabioticconi/alone/constants/Options.java
index 63ae8dd..a5a6e4d 100644
--- a/src/main/java/com/github/fabioticconi/alone/constants/Options.java
+++ b/src/main/java/com/github/fabioticconi/alone/constants/Options.java
@@ -24,6 +24,6 @@ public class Options
{
public static final int OUTPUT_SIZE_X = 55;
public static final int OUTPUT_SIZE_Y = 55;
- public static int MAP_SIZE_X = 1000;
- public static int MAP_SIZE_Y = 1000;
+ public static int MAP_SIZE_X = 1024;
+ public static int MAP_SIZE_Y = 1024;
}
diff --git a/src/main/java/com/github/fabioticconi/alone/constants/TerrainType.java b/src/main/java/com/github/fabioticconi/alone/constants/TerrainType.java
new file mode 100644
index 0000000..f9b2d21
--- /dev/null
+++ b/src/main/java/com/github/fabioticconi/alone/constants/TerrainType.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 Fabio Ticconi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.github.fabioticconi.alone.constants;
+
+/**
+ * Author: Fabio Ticconi
+ * Date: 27/11/17
+ */
+public enum TerrainType
+{
+ WATER,
+ GRASS,
+ LAND,
+ ICE
+}
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/AbstractScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/AbstractScreen.java
index f5854d5..b87a4d5 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/AbstractScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/AbstractScreen.java
@@ -21,6 +21,8 @@
import asciiPanel.AsciiPanel;
import com.artemis.managers.PlayerManager;
import com.artemis.utils.BitVector;
+import com.github.fabioticconi.alone.systems.MapSystem;
+import com.github.fabioticconi.alone.systems.ScreenSystem;
import com.github.fabioticconi.alone.utils.Util;
import net.mostlyoriginal.api.system.core.PassiveSystem;
@@ -38,6 +40,8 @@ public abstract class AbstractScreen extends PassiveSystem implements Screen
{
public static final Letter[] ALL = Letter.values();
+ ScreenSystem screen;
+ MapSystem map;
PlayerManager pManager;
public abstract String header();
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/CharScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/CharScreen.java
new file mode 100644
index 0000000..fe2374d
--- /dev/null
+++ b/src/main/java/com/github/fabioticconi/alone/screens/CharScreen.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 Fabio Ticconi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.github.fabioticconi.alone.screens;
+
+import asciiPanel.AsciiPanel;
+import com.artemis.ComponentMapper;
+import com.artemis.utils.BitVector;
+import com.github.fabioticconi.alone.components.attributes.Agility;
+import com.github.fabioticconi.alone.components.attributes.Constitution;
+import com.github.fabioticconi.alone.components.attributes.Strength;
+import com.github.fabioticconi.alone.systems.BootstrapSystem;
+
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Author: Fabio Ticconi
+ * Date: 21/11/17
+ */
+public class CharScreen extends AbstractScreen
+{
+ BootstrapSystem sBoot;
+
+ ComponentMapper mStr;
+ ComponentMapper mAgi;
+ ComponentMapper mCon;
+
+ byte[] stats = new byte[3];
+ int curStat = 0;
+ int points = 1;
+
+ @Override
+ public String header()
+ {
+ return "Character Generation";
+ }
+
+ @Override
+ public float handleKeys(final BitVector keys)
+ {
+ if (keys.get(KeyEvent.VK_ESCAPE))
+ {
+ screen.select(MapScreen.class);
+ }
+ else if (keys.get(KeyEvent.VK_DOWN))
+ {
+ if (curStat < 2)
+ curStat++;
+ }
+ else if (keys.get(KeyEvent.VK_UP))
+ {
+ if (curStat > 0)
+ curStat--;
+ }
+ else if (keys.get(KeyEvent.VK_LEFT))
+ {
+ if (stats[curStat] > -2)
+ {
+ stats[curStat]--;
+ points++;
+ }
+ }
+ else if (keys.get(KeyEvent.VK_RIGHT))
+ {
+ if (stats[curStat] < 2 && points > 0)
+ {
+ stats[curStat]++;
+ points--;
+ }
+ }
+ else if (keys.get(KeyEvent.VK_ENTER))
+ {
+ // confirmed, let's play!
+
+ final int playerId = pManager.getEntitiesOfPlayer("player").get(0).getId();
+
+ mStr.create(playerId).value = stats[0];
+ mAgi.create(playerId).value = stats[1];
+ mCon.create(playerId).value = stats[2];
+
+ sBoot.makeDerivative(playerId);
+
+ screen.select(PlayScreen.class);
+ }
+
+ keys.clear();
+
+ return 0f;
+ }
+
+ @Override
+ public void display(final AsciiPanel terminal)
+ {
+ terminal.clear();
+
+ drawHeader(terminal);
+
+ terminal.writeCenter("Available Attribute Points: [" + points + "]", 20);
+
+ int yoff = terminal.getHeightInCharacters() / 2 - 1;
+ final int xoff = terminal.getWidthInCharacters() / 2 - 12;
+
+ final String str = "[" + String.join("", Collections.nCopies(stats[0]+3, "=")) + "]";
+ final String agi = "[" + String.join("", Collections.nCopies(stats[1]+3, "=")) + "]";
+ final String con = "[" + String.join("", Collections.nCopies(stats[2]+3, "=")) + "]";
+
+ terminal.write("Strength: " + str, xoff, yoff, curStat==0?Color.YELLOW:Color.WHITE);
+ yoff += 3;
+ terminal.write("Agility: " + agi, xoff, yoff, curStat==1?Color.YELLOW:Color.WHITE);
+ yoff += 3;
+ terminal.write("Constitution: " + con, xoff, yoff, curStat==2?Color.YELLOW:Color.WHITE);
+
+ terminal.writeCenter("[ENTER] to play, [ESC] to go back", terminal.getHeightInCharacters() - 2);
+ }
+}
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/LookScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/LookScreen.java
index 198d9d3..2d9b92e 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/LookScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/LookScreen.java
@@ -141,12 +141,13 @@ public void display(final AsciiPanel terminal)
if (t == null)
return;
- final int xmax = terminal.getWidthInCharacters();
- final int ymax = terminal.getHeightInCharacters();
+ final int ymin = 6;
+ final int xmax = terminal.getWidthInCharacters();
+ final int ymax = terminal.getHeightInCharacters();
final int panelSize = 8;
final int playerX = xmax / 2;
- final int playerY = (ymax - panelSize) / 2;
+ final int playerY = (ymax - panelSize + ymin) / 2;
terminal.write('@', playerX, playerY, Color.BLACK, Color.LIGHT_GRAY);
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java
new file mode 100644
index 0000000..8ad0df0
--- /dev/null
+++ b/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 Fabio Ticconi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.github.fabioticconi.alone.screens;
+
+import asciiPanel.AsciiPanel;
+import com.artemis.utils.BitVector;
+import com.github.fabioticconi.alone.constants.Options;
+import com.github.fabioticconi.alone.systems.MapSystem;
+import com.github.fabioticconi.tergen.HeightMap;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.ArrayList;
+
+/**
+ * Author: Fabio Ticconi
+ * Date: 21/11/17
+ */
+public class MapScreen extends AbstractScreen
+{
+ float heightmap[][];
+
+ @Override
+ protected void initialize()
+ {
+ try
+ {
+ map.loadTemplates();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+
+ regenerate();
+ }
+
+ void regenerate()
+ {
+ final int seed = (int)(System.currentTimeMillis() / 1000);
+ final float freq = 3f / Math.max(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
+
+ final HeightMap heightMap = new HeightMap()
+ .size(Options.MAP_SIZE_X, Options.MAP_SIZE_Y, seed)
+ .island(0.85f)
+ .noise(16, 0.5f, freq, 1f);
+
+ heightmap = heightMap.build();
+
+ map.terrainFromHeightmap(heightmap);
+ }
+
+ @Override
+ public String header()
+ {
+ return "World Generation:";
+ }
+
+ @Override
+ public float handleKeys(final BitVector keys)
+ {
+ if (keys.get(KeyEvent.VK_ESCAPE))
+ screen.select(StartScreen.class);
+ else if (keys.get(KeyEvent.VK_R))
+ {
+ regenerate();
+ }
+ else if (keys.get(KeyEvent.VK_ENTER))
+ {
+ try
+ {
+ map.saveTerrain(heightmap);
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ screen.select(CharScreen.class);
+ }
+
+ keys.clear();
+
+ return 0f;
+ }
+
+ @Override
+ public void display(final AsciiPanel terminal)
+ {
+ terminal.clear();
+
+ // title:
+ drawHeader(terminal);
+
+ final int xmin = 1;
+ final int xmax = terminal.getWidthInCharacters() - 1;
+ final int ymin = 4;
+ final int ymax = terminal.getHeightInCharacters() - 5;
+
+ final int tileWidth = Math.floorDiv(Options.MAP_SIZE_X, xmax - xmin);
+ final int tileHeight = Math.floorDiv(Options.MAP_SIZE_Y, ymax - ymin);
+
+ final ArrayList cells = new ArrayList<>(tileWidth * tileHeight);
+
+ for (int x = xmin; x < xmax; x++)
+ {
+ for (int y = ymin; y < ymax; y++)
+ {
+ for (int tileX = 0; tileX < tileWidth; tileX++)
+ {
+ for (int tileY = 0; tileY < tileHeight; tileY++)
+ {
+ final int posX = x * tileWidth + tileX;
+ final int posY = y * tileHeight + tileY;
+
+ // render terrain
+ final MapSystem.Cell cell = map.get(posX, posY);
+
+ cells.add(cell);
+ }
+ }
+
+ float r=0,g=0,b=0;
+ for (final MapSystem.Cell cell : cells)
+ {
+ r += cell.col.getRed()*cell.col.getRed();
+ g += cell.col.getGreen()*cell.col.getGreen();
+ b += cell.col.getBlue()*cell.col.getBlue();
+ }
+
+ r = (float)Math.sqrt(r / cells.size());
+ g = (float)Math.sqrt(g / cells.size());
+ b = (float)Math.sqrt(b / cells.size());
+
+ final Color col = new Color(Math.round(r), Math.round(g), Math.round(b));
+ terminal.write(' ', x, y, Color.WHITE, col);
+
+ // final Cell cell = cells.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet()
+ // .stream().max(Comparator.comparing(Map.Entry::getValue)).get().getKey();
+ //
+ // terminal.write(cell.c, x, y, cell.col, cell.bg);
+
+ cells.clear();
+ }
+ }
+
+ // TODO must take the full map, downscaled a lot (maybe take average colour per tile? or most common colour?)
+ // and show it in a square/rectangle leaving some little black margin
+
+ terminal.writeCenter("[R]egenerate", terminal.getHeightInCharacters() - 4);
+ terminal.writeCenter("[ENTER] to confirm, [ESC] to go back", terminal.getHeightInCharacters() - 2);
+ }
+}
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
index 06a486f..8801839 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
@@ -26,10 +26,9 @@
import com.github.fabioticconi.alone.Main;
import com.github.fabioticconi.alone.components.*;
import com.github.fabioticconi.alone.components.attributes.Sight;
-import com.github.fabioticconi.alone.constants.Cell;
import com.github.fabioticconi.alone.constants.Side;
import com.github.fabioticconi.alone.constants.WeaponType;
-import com.github.fabioticconi.alone.map.SingleGrid;
+import com.github.fabioticconi.alone.utils.SingleGrid;
import com.github.fabioticconi.alone.messages.AbstractMessage;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.Msg;
@@ -294,13 +293,15 @@ public void display(final AsciiPanel terminal)
final Position p = mPosition.get(playerId);
final int sight = mSight.get(playerId).value;
+ final int xmin = 0;
+ final int ymin = 6;
final int xmax = terminal.getWidthInCharacters();
final int ymax = terminal.getHeightInCharacters();
final int panelSize = 8;
final int halfcols = xmax / 2;
- final int halfrows = (ymax - panelSize) / 2;
+ final int halfrows = (ymax - panelSize + ymin) / 2;
int posX;
int posY;
@@ -313,9 +314,9 @@ public void display(final AsciiPanel terminal)
final LongBag cells = map.getVisibleCells(p.x, p.y, sight);
- for (int x = 0; x < xmax; x++)
+ for (int x = xmin; x < xmax; x++)
{
- for (int y = 0; y < ymax - panelSize; y++)
+ for (int y = ymin; y < ymax - panelSize; y++)
{
posX = p.x + x - halfcols;
posY = p.y + y - halfrows;
@@ -325,19 +326,19 @@ public void display(final AsciiPanel terminal)
if (map.contains(posX, posY))
{
// render terrain
- final Cell cell = map.get(posX, posY);
- Color tileFg;
- final Color tileBg;
+ final MapSystem.Cell cell = map.get(posX, posY);
+ Color tileFg;
+ final Color tileBg;
if (cells.contains(key))
{
- tileFg = cell.col;
- tileBg = cell.bg;
+ tileFg = cell.col.darker();
+ tileBg = cell.col;
}
else
{
- tileFg = cell.col.darker().darker().darker();
- tileBg = cell.bg.darker().darker().darker();
+ tileFg = cell.col.darker().darker().darker().darker();
+ tileBg = cell.col.darker().darker().darker();
}
terminal.write(cell.c, x, y, tileFg, tileBg);
@@ -400,6 +401,8 @@ else if (sprite.shadowView)
}
}
+ terminal.clear(' ', 0, 0, terminal.getWidthInCharacters(), ymin-1);
+
// title:
drawHeader(terminal);
@@ -409,7 +412,7 @@ else if (sprite.shadowView)
int x;
- final int yoff = 3;
+ final int yoff = ymin-3;
// health bar
terminal.write('[', 0, yoff, Color.RED);
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/StartScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/StartScreen.java
index 2071f27..fd128df 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/StartScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/StartScreen.java
@@ -24,6 +24,7 @@
import com.github.fabioticconi.alone.Main;
import com.github.fabioticconi.alone.systems.ScreenSystem;
+import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Collections;
import java.util.Properties;
@@ -42,10 +43,16 @@ public class StartScreen extends AbstractScreen
@Override
public float handleKeys(final BitVector keys)
{
- // TODO: eventually, "N" should re-run the world to start from scratch,
- // while "C" either selects the PlayScreen, or (at first start) loads the save file
+ // TODO: [C] should load a saved game (if any), or if the world is already loaded
+ // (eg, if the player types ESC while playing), it must simply jump to the PlayScreen
- if (keys.get(KeyEvent.VK_N) || keys.get(KeyEvent.VK_C))
+ if (keys.get(KeyEvent.VK_N))
+ {
+ keys.clear();
+
+ screen.select(MapScreen.class);
+ }
+ else if (keys.get(KeyEvent.VK_C))
{
keys.clear();
@@ -70,13 +77,13 @@ public void display(final AsciiPanel terminal)
terminal.writeCenter(String.join("", Collections.nCopies(header.length(), "-")), 3);
int y = terminal.getHeightInCharacters() / 2 - 4 * 2;
- terminal.writeCenter("(N)ew", y);
+ terminal.writeCenter("[N]ew", y);
y = y + 2;
- terminal.writeCenter("(C)ontinue", y);
+ terminal.writeCenter("[C]ontinue", y, Color.GRAY);
y = y + 2;
- terminal.writeCenter("(O)ptions [inactive]", y);
+ terminal.writeCenter("[O]ptions [inactive]", y);
y = y + 2;
- terminal.writeCenter("Save & (Q)uit", y);
+ terminal.writeCenter("Save & [Q]uit", y);
y = terminal.getHeightInCharacters() - 2;
terminal.writeCenter("by Fabio Ticconi", y);
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/AISystem.java b/src/main/java/com/github/fabioticconi/alone/systems/AISystem.java
index d5fd918..297bcea 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/AISystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/AISystem.java
@@ -132,7 +132,7 @@ protected void processExpired(final int entityId)
// run the new behaviour and update the context
if (bestBehaviour != null && maxScore > 0f)
{
- System.out.println(entityId + ": " + bestBehaviour.getClass().getSimpleName() + " (" + maxScore + ")");
+ // System.out.println(entityId + ": " + bestBehaviour.getClass().getSimpleName() + " (" + maxScore + ")");
ai.time = bestBehaviour.update();
ai.activeBehaviour = bestBehaviour;
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/BootstrapSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/BootstrapSystem.java
index c25b4c8..878c69f 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/BootstrapSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/BootstrapSystem.java
@@ -17,6 +17,8 @@
*/
package com.github.fabioticconi.alone.systems;
+import com.artemis.BaseSystem;
+import com.artemis.ComponentMapper;
import com.artemis.EntityEdit;
import com.artemis.annotations.Wire;
import com.artemis.managers.PlayerManager;
@@ -26,10 +28,12 @@
import com.github.fabioticconi.alone.behaviours.*;
import com.github.fabioticconi.alone.components.*;
import com.github.fabioticconi.alone.components.attributes.*;
-import com.github.fabioticconi.alone.constants.Cell;
import com.github.fabioticconi.alone.constants.Options;
+import com.github.fabioticconi.alone.constants.TerrainType;
import com.github.fabioticconi.alone.utils.Util;
import net.mostlyoriginal.api.system.core.PassiveSystem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.awt.*;
import java.io.FileInputStream;
@@ -40,9 +44,15 @@
/**
* @author Fabio Ticconi
*/
-public class BootstrapSystem extends PassiveSystem
+public class BootstrapSystem extends BaseSystem
{
- private final ClassLoader loader = getClass().getClassLoader();
+ static final Logger log = LoggerFactory.getLogger(BootstrapSystem.class);
+
+ ComponentMapper mStr;
+ ComponentMapper mAgi;
+ ComponentMapper mCon;
+ ComponentMapper mHerbivore;
+ ComponentMapper mCarnivore;
@Wire
Random r;
@@ -57,10 +67,10 @@ public class BootstrapSystem extends PassiveSystem
PlayerManager pManager;
@Override
- protected void initialize()
+ protected void processSystem()
{
// this must be only run once
- // setEnabled(false);
+ setEnabled(false);
int x;
int y;
@@ -247,12 +257,9 @@ protected void initialize()
{
for (y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final Cell cell = sMap.get(x, y);
+ final MapSystem.Cell cell = sMap.get(x, y);
- // if ((cell.equals(Cell.DEEP_WATER) && r.nextGaussian() > 3f) ||
- // (cell.equals(Cell.WATER) && r.nextGaussian() > 2.5f))
- if ((cell.equals(Cell.DEEP_WATER) && r.nextGaussian() > 5f) ||
- (cell.equals(Cell.WATER) && r.nextGaussian() > 5f))
+ if (cell.type.equals(TerrainType.WATER) && r.nextGaussian() > 5f)
{
if (!map.obstacles.isEmpty(x, y))
continue;
@@ -288,11 +295,10 @@ protected void initialize()
{
for (y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final Cell cell = sMap.get(x, y);
+ final MapSystem.Cell cell = sMap.get(x, y);
- if ((cell.equals(Cell.GRASS) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.HILL_GRASS) && r.nextGaussian() > 2f) ||
- (cell.equals(Cell.HILL) && r.nextGaussian() > 3f))
+ if ((cell.type.equals(TerrainType.GRASS) && r.nextGaussian() > 2.5f) ||
+ (cell.type.equals(TerrainType.LAND) && r.nextGaussian() > 3f))
{
if (!map.obstacles.isEmpty(x, y))
continue;
@@ -307,14 +313,10 @@ protected void initialize()
{
for (y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final Cell cell = sMap.get(x, y);
-
- if (((cell.equals(Cell.HIGH_MOUNTAIN)) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.MOUNTAIN) && r.nextGaussian() > 2.5f) ||
- (cell.equals(Cell.HILL) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.HILL_GRASS) && r.nextGaussian() > 3.5f) ||
- (cell.equals(Cell.GRASS) && r.nextGaussian() > 4f) ||
- (cell.equals(Cell.GROUND) && r.nextGaussian() > 4f))
+ final MapSystem.Cell cell = sMap.get(x, y);
+
+ if ((cell.type.equals(TerrainType.GRASS) && r.nextGaussian() > 3.5f) ||
+ (cell.type.equals(TerrainType.LAND) && r.nextGaussian() > 3f))
{
if (!map.obstacles.isEmpty(x, y))
continue;
@@ -329,14 +331,10 @@ protected void initialize()
{
for (y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final Cell cell = sMap.get(x, y);
-
- if (((cell.equals(Cell.HIGH_MOUNTAIN)) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.MOUNTAIN) && r.nextGaussian() > 2.5f) ||
- (cell.equals(Cell.HILL) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.HILL_GRASS) && r.nextGaussian() > 3.5f) ||
- (cell.equals(Cell.GRASS) && r.nextGaussian() > 4f) ||
- (cell.equals(Cell.GROUND) && r.nextGaussian() > 2.5f))
+ final MapSystem.Cell cell = sMap.get(x, y);
+
+ if ((cell.type.equals(TerrainType.GRASS) && r.nextGaussian() > 3f) ||
+ (cell.type.equals(TerrainType.LAND) && r.nextGaussian() > 2.5f))
{
if (!map.items.isEmpty(x, y))
continue;
@@ -351,11 +349,10 @@ protected void initialize()
{
for (y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final Cell cell = sMap.get(x, y);
+ final MapSystem.Cell cell = sMap.get(x, y);
- if ((cell.equals(Cell.GRASS) && r.nextGaussian() > 4f) ||
- (cell.equals(Cell.HILL_GRASS) && r.nextGaussian() > 3f) ||
- (cell.equals(Cell.HILL) && r.nextGaussian() > 4f))
+ if ((cell.type.equals(TerrainType.GRASS) && r.nextGaussian() > 3f) ||
+ (cell.type.equals(TerrainType.LAND) && r.nextGaussian() > 3.5f))
{
if (!map.items.isEmpty(x, y))
continue;
@@ -367,7 +364,7 @@ protected void initialize()
}
}
- System.out.println("Bootstrap done");
+ log.info("initialised");
}
public void loadBody(final String filename, final EntityEdit edit) throws IOException
@@ -445,4 +442,26 @@ public void loadBody(final String filename, final EntityEdit edit) throws IOExce
if (herbivore || carnivore)
edit.create(Hunger.class).set(0f, (size / 2f) + 2f);
}
+
+ public void makeDerivative(final int id)
+ {
+ final Strength str = mStr.get(id);
+ final Agility agi = mAgi.get(id);
+ final Constitution con = mCon.get(id);
+
+ final EntityEdit edit = world.edit(id);
+
+ // Secondary Attributes
+ final int size = Math.round((con.value - agi.value) / 2f);
+ edit.create(Size.class).set(size);
+ edit.create(Stamina.class).set((5 + str.value + con.value) * 100); // FIXME for debug, reduce/tweak later
+ edit.create(Speed.class).set((con.value - str.value - agi.value + 6) / 12f);
+ edit.create(Health.class).set((con.value + 3) * 10);
+
+ // Tertiary Attributes
+
+ // a fish does not need to eat, for now
+ if (mHerbivore.has(id) || mCarnivore.has(id))
+ edit.create(Hunger.class).set(0f, (size / 2f) + 2f);
+ }
}
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
index 8629a5d..60a5142 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
@@ -148,46 +148,36 @@ public int makeItem(final String tag, final int x, final int y)
public int makeItem(final String tag)
{
- try
- {
- loadTemplates();
+ final ItemTemplate template = templates.get(tag);
- final ItemTemplate template = templates.get(tag);
-
- if (template == null)
- {
- log.warn("Item named {} doesn't exist", tag);
- return -1;
- }
-
- final int id = world.create();
+ if (template == null)
+ {
+ log.warn("Item named {} doesn't exist", tag);
+ return -1;
+ }
- final EntityEdit edit = world.edit(id);
+ final int id = world.create();
- edit.add(new Name(template.name, tag));
+ final EntityEdit edit = world.edit(id);
- // TODO find a way to do this dynamically. Right now I cannot figure out a way
- // of deserialising an array of Components, because it's an abstract class that I cannot annotate.
- if (template.wearable != null)
- edit.add(template.wearable);
- if (template.weapon != null)
- edit.add(template.weapon);
- if (template.sprite != null)
- edit.add(template.sprite);
- if (template.obstacle != null)
- edit.add(template.obstacle);
- if (template.crushable != null)
- edit.add(template.crushable);
- if (template.cuttable != null)
- edit.add(template.cuttable);
+ edit.add(new Name(template.name, tag));
- return id;
- } catch (final IOException e)
- {
- e.printStackTrace();
+ // TODO find a way to do this dynamically. Right now I cannot figure out a way
+ // of deserialising an array of Components, because it's an abstract class that I cannot annotate.
+ if (template.wearable != null)
+ edit.add(template.wearable);
+ if (template.weapon != null)
+ edit.add(template.weapon);
+ if (template.sprite != null)
+ edit.add(template.sprite);
+ if (template.obstacle != null)
+ edit.add(template.obstacle);
+ if (template.crushable != null)
+ edit.add(template.crushable);
+ if (template.cuttable != null)
+ edit.add(template.cuttable);
- return -1;
- }
+ return id;
}
public GetAction get(final int actorId)
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/MapSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/MapSystem.java
index 02def06..86deabb 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/MapSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/MapSystem.java
@@ -18,13 +18,17 @@
package com.github.fabioticconi.alone.systems;
import com.artemis.ComponentMapper;
+import com.artemis.annotations.Wire;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ser.std.StdArraySerializers;
import com.github.fabioticconi.alone.components.Obstacle;
-import com.github.fabioticconi.alone.constants.Cell;
import com.github.fabioticconi.alone.constants.Options;
import com.github.fabioticconi.alone.constants.Side;
-import com.github.fabioticconi.alone.map.SingleGrid;
+import com.github.fabioticconi.alone.constants.TerrainType;
import com.github.fabioticconi.alone.utils.Coords;
import com.github.fabioticconi.alone.utils.LongBag;
+import com.github.fabioticconi.alone.utils.SingleGrid;
import com.github.fabioticconi.alone.utils.Util;
import net.mostlyoriginal.api.system.core.PassiveSystem;
import org.slf4j.Logger;
@@ -36,16 +40,15 @@
import rlforj.los.ShadowCasting;
import rlforj.math.Point;
import rlforj.pathfinding.AStar;
+import rlforj.pathfinding.IPathAlgorithm;
import javax.imageio.ImageIO;
+import java.awt.*;
import java.awt.image.BufferedImage;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.EnumSet;
-import java.util.LinkedHashSet;
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.util.*;
import java.util.List;
-import java.util.Set;
/**
* @author Fabio Ticconi
@@ -54,35 +57,78 @@ public class MapSystem extends PassiveSystem implements IBoard
{
static final Logger log = LoggerFactory.getLogger(MapSystem.class);
- final Cell terrain[][];
+ Cell terrain[][];
- /* FOV/LOS stuff */
- final LongBag lastVisited;
- final AStar astar;
- final IFovAlgorithm fov;
- final ILosAlgorithm los;
- final SingleGrid obstacles;
- final SingleGrid items;
+ /* FOV/LOS stuff */ LongBag lastVisited;
+ IPathAlgorithm path;
+ IFovAlgorithm fov;
+ ILosAlgorithm los;
+ SingleGrid obstacles;
+ SingleGrid items;
ComponentMapper mObstacle;
- public MapSystem() throws IOException
+ @Wire
+ ObjectMapper mapper;
+
+ Map templates;
+ TreeMap cellAtHeight;
+
+ public MapSystem()
+ {
+
+ }
+
+ @Override
+ protected void initialize()
{
lastVisited = new LongBag(256);
fov = new ShadowCasting();
los = new BresLos(true);
- final InputStream mapStream = new FileInputStream("data/map/map.png");
+ try
+ {
+ loadTerrain();
+
+ obstacles = new SingleGrid(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
+ items = new SingleGrid(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
+
+ path = new AStar(this, Options.MAP_SIZE_X, Options.MAP_SIZE_Y, true);
+ } catch (final IOException e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ log.info("initialised");
+ }
+
+ public void loadTemplates() throws IOException
+ {
+ final InputStream fileStream = new FileInputStream("data/map/terrain.yml");
+
+ templates = mapper.readValue(fileStream, new TypeReference>()
+ {
+ });
+
+ cellAtHeight = new TreeMap<>();
+
+ for (final Map.Entry entry : templates.entrySet())
+ {
+ final Cell temp = entry.getValue();
+ temp.tag = entry.getKey();
+ cellAtHeight.put(temp.theight, temp);
+ }
+ }
+
+ public void loadTerrain() throws IOException
+ {
+ loadTemplates();
+
final InputStream elevationStream = new FileInputStream("data/map/elevation.data");
- final BufferedImage img = ImageIO.read(mapStream);
final byte[] elevation = elevationStream.readAllBytes();
- Options.MAP_SIZE_X = img.getWidth();
- Options.MAP_SIZE_Y = img.getHeight();
-
terrain = new Cell[Options.MAP_SIZE_X][Options.MAP_SIZE_Y];
- obstacles = new SingleGrid(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
- items = new SingleGrid(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
// TODO: we should make Cell a class, and obviously use a pool.
// This way we can load the cells from a yaml file, with their thresholds, colours, characters etc,
@@ -90,56 +136,56 @@ public MapSystem() throws IOException
// for example.
// movement costs should also be part of this cell.
- float value;
-
for (int x = 0; x < Options.MAP_SIZE_X; x++)
{
for (int y = 0; y < Options.MAP_SIZE_Y; y++)
{
- final byte h = elevation[x * Options.MAP_SIZE_X + y];
- final int uns_h = Byte.toUnsignedInt(h);
- value = (float) (uns_h) / 255f;
+ final byte h = elevation[x * Options.MAP_SIZE_X + y];
+ final int uns_h = Byte.toUnsignedInt(h);
+ final float value = (float) (uns_h) / 255f;
- if (value < 0.01)
- {
- terrain[x][y] = Cell.DEEP_WATER;
- }
- else if (value < 0.05f)
- {
- terrain[x][y] = Cell.WATER;
- }
- else if (value < 0.08f)
- {
- terrain[x][y] = Cell.SAND;
- }
- else if (value < 0.1f)
- {
- terrain[x][y] = Cell.GROUND;
- }
- else if (value < 0.4f)
- {
- terrain[x][y] = Cell.GRASS;
- }
- else if (value < 0.7f)
- {
- terrain[x][y] = Cell.HILL_GRASS;
- }
- else if (value < 0.8f)
- {
- terrain[x][y] = Cell.HILL;
- }
- else if (value < 0.9f)
- {
- terrain[x][y] = Cell.MOUNTAIN;
- }
- else
- {
- terrain[x][y] = Cell.HIGH_MOUNTAIN;
- }
+ final float key = cellAtHeight.higherKey(value);
+ final Cell cell = cellAtHeight.get(key);
+
+ terrain[x][y] = cell;
+ }
+ }
+ }
+
+ public void saveTerrain(final float[][] heightmap) throws IOException
+ {
+ final OutputStream elevationStream = new FileOutputStream("data/map/elevation.data");
+
+ final byte[] elevation = new byte[heightmap.length * heightmap[0].length];
+
+ for (int x = 0; x < Options.MAP_SIZE_X; x++)
+ {
+ for (int y = 0; y < Options.MAP_SIZE_Y; y++)
+ {
+ elevation[x * Options.MAP_SIZE_X + y] = (byte)(heightmap[x][y]*255f);
}
}
- astar = new AStar(this, Options.MAP_SIZE_X, Options.MAP_SIZE_Y, true);
+ elevationStream.write(elevation);
+
+ elevationStream.close();
+ }
+
+ public void terrainFromHeightmap(final float[][] heightmap)
+ {
+ if (terrain == null || terrain.length != Options.MAP_SIZE_X || terrain[0].length != Options.MAP_SIZE_Y)
+ terrain = new Cell[Options.MAP_SIZE_X][Options.MAP_SIZE_Y];
+
+ for (int x = 0; x < Options.MAP_SIZE_X; x++)
+ {
+ for (int y = 0; y < Options.MAP_SIZE_Y; y++)
+ {
+ final float key = cellAtHeight.higherKey(heightmap[x][y]);
+ final Cell cell = cellAtHeight.get(key);
+
+ terrain[x][y] = cell;
+ }
+ }
}
/**
@@ -178,7 +224,7 @@ public Set getFreeExits(final int x, final int y)
* @param y
* @return A set of free exits, or HERE if none is available
*/
- public Set getFreeExits(final int x, final int y, final EnumSet set)
+ public Set getFreeExits(final int x, final int y, final EnumSet set)
{
int xn, yn;
@@ -192,7 +238,7 @@ public Set getFreeExits(final int x, final int y, final EnumSet set)
xn = x + side.x;
yn = y + side.y;
- if (contains(xn, yn) && obstacles.get(xn, yn) < 0 && set.contains(terrain[x][y]))
+ if (contains(xn, yn) && obstacles.get(xn, yn) < 0 && set.contains(terrain[x][y].type))
exits.add(side);
}
@@ -325,14 +371,14 @@ else if (maxRadius == 0)
*
* @return null if none could be found, the coordinate array otherwise
*/
- public int[] getFirstOfType(final int x, final int y, final int r, final EnumSet set)
+ public int[] getFirstOfType(final int x, final int y, final int r, final EnumSet set)
{
- if (set.contains(terrain[x][y]))
+ if (set.contains(terrain[x][y].type))
return new int[] { x, y };
lastVisited.clear();
- fov.visitFieldOfView(this, x, y, r);
+ fov.visitFoV(this, x, y, r);
int[] coords;
Cell cell;
@@ -343,7 +389,7 @@ public int[] getFirstOfType(final int x, final int y, final int r, final EnumSet
coords = Coords.unpackCoords(key);
cell = terrain[coords[0]][coords[1]];
- if (set.contains(cell))
+ if (set.contains(cell.type))
return coords;
}
@@ -443,25 +489,61 @@ public LongBag getVisibleCells(final int x, final int y, final int r)
{
lastVisited.clear();
- fov.visitFieldOfView(this, x, y, r);
+ fov.visitFoV(this, x, y, r);
return lastVisited;
}
public List getLineOfSight(final int startX, final int startY, final int endX, final int endY)
{
- final boolean exists = los.existsLineOfSight(this, startX, startY, endX, endY, true);
+ final boolean exists = los.exists(this, startX, startY, endX, endY, true);
// FIXME: rlforj-alt should either always return a list, or always an array
if (exists)
- return los.getProjectPath();
+ return los.getPath();
return null;
}
public Point[] getPath(final int startX, final int startY, final int endX, final int endY, final int radius)
{
- return astar.findPath(startX, startY, endX, endY, radius);
+ return path.findPath(startX, startY, endX, endY, radius);
+ }
+
+ /**
+ * @author Fabio Ticconi
+ */
+ public static class Cell implements Comparable
+ {
+ public final static Cell EMPTY = new Cell("empty", ' ', Color.BLACK, null, 0f);
+
+ public String tag;
+
+ public char c;
+ public Color col;
+ public TerrainType type;
+
+ public float theight;
+
+ public Cell()
+ {
+
+ }
+
+ public Cell(final String tag, final char c, final Color col, final TerrainType type, final float theight)
+ {
+ this.tag = tag;
+ this.c = c;
+ this.col = col;
+ this.type = type;
+ this.theight = theight;
+ }
+
+ @Override
+ public int compareTo(final Float o)
+ {
+ return Float.compare(theight, o);
+ }
}
}
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/MovementSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/MovementSystem.java
index 2b6da60..61fdfff 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/MovementSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/MovementSystem.java
@@ -23,8 +23,9 @@
import com.github.fabioticconi.alone.components.Speed;
import com.github.fabioticconi.alone.components.Underwater;
import com.github.fabioticconi.alone.components.actions.ActionContext;
-import com.github.fabioticconi.alone.constants.Cell;
import com.github.fabioticconi.alone.constants.Side;
+import com.github.fabioticconi.alone.constants.TerrainType;
+import com.github.fabioticconi.alone.utils.Util;
import net.mostlyoriginal.api.system.core.PassiveSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,7 +77,7 @@ public boolean tryAction()
if (!map.isFree(x2, y2))
return false;
- final Cell cell = map.get(x2, y2);
+ final MapSystem.Cell cell = map.get(x2, y2);
if (mUnderWater.has(actorId))
{
@@ -95,33 +96,10 @@ public boolean tryAction()
return true;
}
- switch (cell)
- {
- case HILL:
- case HILL_GRASS:
- cost = 1.5f;
-
- break;
-
- case MOUNTAIN:
- cost = 2f;
- break;
-
- case HIGH_MOUNTAIN:
- cost = 3f;
- break;
-
- case WATER:
- cost = 3f;
- break;
-
- case DEEP_WATER:
- cost = 4f;
- break;
-
- default:
- cost = 1f;
- }
+ if (cell.type == TerrainType.WATER)
+ cost = 2f - Util.bias(cell.theight, 0.97f);
+ else
+ cost = 1f + Util.bias(cell.theight, 0.75f);
delay = speed.value * cost;
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/UnderwaterSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/UnderwaterSystem.java
index 2cba61a..e1700c4 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/UnderwaterSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/UnderwaterSystem.java
@@ -24,7 +24,7 @@
import com.github.fabioticconi.alone.components.Dead;
import com.github.fabioticconi.alone.components.Position;
import com.github.fabioticconi.alone.components.Underwater;
-import com.github.fabioticconi.alone.constants.Cell;
+import com.github.fabioticconi.alone.constants.TerrainType;
import java.util.EnumSet;
@@ -34,11 +34,12 @@
*/
public class UnderwaterSystem extends IntervalIteratingSystem
{
- private final EnumSet validCells = EnumSet.of(Cell.WATER, Cell.DEEP_WATER);
ComponentMapper mPos;
HealthSystem sHealth;
MapSystem map;
+ private final EnumSet validCells = EnumSet.of(TerrainType.WATER);
+
public UnderwaterSystem(final float interval)
{
super(Aspect.all(Underwater.class, Position.class).exclude(Dead.class), interval);
@@ -49,7 +50,7 @@ protected void process(final int entityId)
{
final Position p = mPos.get(entityId);
- final Cell c = map.get(p.x, p.y);
+ final MapSystem.Cell c = map.get(p.x, p.y);
// if inside water, no problem
if (validCells.contains(c))
diff --git a/src/main/java/com/github/fabioticconi/alone/map/SingleGrid.java b/src/main/java/com/github/fabioticconi/alone/utils/SingleGrid.java
similarity index 99%
rename from src/main/java/com/github/fabioticconi/alone/map/SingleGrid.java
rename to src/main/java/com/github/fabioticconi/alone/utils/SingleGrid.java
index a5abef5..98ada18 100644
--- a/src/main/java/com/github/fabioticconi/alone/map/SingleGrid.java
+++ b/src/main/java/com/github/fabioticconi/alone/utils/SingleGrid.java
@@ -16,7 +16,7 @@
*
*/
-package com.github.fabioticconi.alone.map;
+package com.github.fabioticconi.alone.utils;
import com.artemis.utils.IntBag;
import com.github.fabioticconi.alone.utils.Coords;
| | | | | |