Prechádzať zdrojové kódy

several new tiles, more tiles in swamps, town generation, town leave animation, blockage of visited towns, builder for all tiles

Kajetan Johannes Hammerle 5 rokov pred
rodič
commit
0f1b2698c0

+ 4 - 3
src/pathgame/PathGame.java

@@ -21,7 +21,7 @@ public class PathGame implements IGame
     private final Gamestate gamestate = new Gamestate();
 
     private final TileMapRenderer mapRenderer = new TileMapRenderer();
-    private TileMap map = TileMapGenerator.getMap(50, 50);
+    private TileMap map = TileMapGenerator.getMap(50, 50, 15);
 
     private final PlayerRenderer playerRenderer = new PlayerRenderer();
     private final Player player = new Player(10, 10);
@@ -40,6 +40,7 @@ public class PathGame implements IGame
     @Override
     public void tick()
     {
+        map.tick();
         mapRenderer.tick();
         if(gamestate.getState() == Gamestates.GAMEPLAY)
         {
@@ -57,9 +58,9 @@ public class PathGame implements IGame
             scale /= 1.1f;
         }
         
-        if(Keys.CONFIRM_KEY.isReleased())
+        if(Keys.TEST_KEY.getTime() == 1)
         {
-            map = TileMapGenerator.getMap(50, 50);
+            map = TileMapGenerator.getMap(50, 50, 15);
 
             TravellingSalesAlg.calcSalesPathLen(map);
         }

+ 1 - 0
src/pathgame/gameplay/Keys.java

@@ -14,4 +14,5 @@ public class Keys
     public static final KeyBinding ZOOM_OUT_KEY = KeyHandler.register(GLFW.GLFW_KEY_O);
     public static final KeyBinding CONFIRM_KEY = KeyHandler.register(GLFW.GLFW_KEY_ENTER);
     public static final KeyBinding ESCAPE_KEY = KeyHandler.register(GLFW.GLFW_KEY_ESCAPE);
+    public static final KeyBinding TEST_KEY = KeyHandler.register(GLFW.GLFW_KEY_T);
 }

+ 15 - 6
src/pathgame/gameplay/Player.java

@@ -2,8 +2,8 @@ package pathgame.gameplay;
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import pathgame.tilemap.Tile;
 import pathgame.tilemap.TileMap;
-import pathgame.tilemap.Tiles;
 
 public class Player
 {
@@ -72,7 +72,11 @@ public class Player
     {
         tickSteps();
         
-        currSpeedSlowdown = map.getTile(Math.round(x), Math.round(y)).getEnergyCost(abilities);
+        int currentTileX = Math.round(x);
+        int currentTileY = Math.round(y);
+        Tile currentTile = map.getTile(currentTileX, currentTileY);
+        
+        currSpeedSlowdown = currentTile.getEnergyCost(abilities);
         lastX = x;
         lastY = y;
 
@@ -82,6 +86,7 @@ public class Player
             velY = 0.0f;
             if(isMoving)
             {
+                currentTile.onEnter(this, map, currentTileX, currentTileY);
                 ++objectivesVisited;//TODO check for objective
                 //System.out.print(map.getTile((int)x,(int) y).getEnergyCost());
                 steps.addLast(new MinusStepsValues(currSpeedSlowdown));
@@ -90,25 +95,29 @@ public class Player
             isMoving = false;
         }
 
-        if(Keys.LEFT_KEY.isDown() && !isMoving && x > 0)
+        if(Keys.LEFT_KEY.isDown() && !isMoving && x > 0 && !map.getTile(currentTileX - 1, currentTileY).isBlockingMovement())
         {
             velX = -SPEED;
             isMoving = true;
+            currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.RIGHT_KEY.isDown() && !isMoving && x < map.getWidth() - 1)
+        else if(Keys.RIGHT_KEY.isDown() && !isMoving && x < map.getWidth() - 1 && !map.getTile(currentTileX + 1, currentTileY).isBlockingMovement())
         {
             velX = SPEED;
             isMoving = true;
+            currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.UP_KEY.isDown() && !isMoving && y > 0)
+        else if(Keys.UP_KEY.isDown() && !isMoving && y > 0 && !map.getTile(currentTileX, currentTileY - 1).isBlockingMovement())
         {
             velY = -SPEED;
             isMoving = true;
+            currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.DOWN_KEY.isDown() && !isMoving && y < map.getHeight() - 1)
+        else if(Keys.DOWN_KEY.isDown() && !isMoving && y < map.getHeight() - 1 && !map.getTile(currentTileX, currentTileY + 1).isBlockingMovement())
         {
             velY = SPEED;
             isMoving = true;
+            currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
 
         float moveX = Math.abs(velX / currSpeedSlowdown);

+ 12 - 1
src/pathgame/rendering/TileRenderer.java

@@ -28,7 +28,10 @@ public class TileRenderer
         register(Tiles.GRASS_WITH_STONE, new StaticTextureProvider(TileTexture.fromTextureId(1)));
         register(Tiles.GRASS_WITH_6_BUSHES, new StaticTextureProvider(TileTexture.fromTextureId(2)));
         register(Tiles.GRASS_WITH_3_BUSHES, new StaticTextureProvider(TileTexture.fromTextureId(3)));
-        register(Tiles.GRASS_WITH_FLOWERS, new StaticTextureProvider(TileTexture.fromTextureId(4)));
+        register(Tiles.GRASS_WITH_FLOWERS_1, new StaticTextureProvider(TileTexture.fromTextureId(4)));
+        register(Tiles.GRASS_WITH_FLOWERS_2, new StaticTextureProvider(TileTexture.fromTextureId(21)));
+        register(Tiles.GRASS_WITH_FLOWERS_3, new StaticTextureProvider(TileTexture.fromTextureId(22)));
+        register(Tiles.GRASS_WITH_FLOWERS_4, new StaticTextureProvider(TileTexture.fromTextureId(23)));
         register(Tiles.GRASS_WITH_HILL, new StaticTextureProvider(TileTexture.fromTextureId(5)));
         register(Tiles.GRASS_WITH_EARTH, new StaticTextureProvider(TileTexture.fromTextureId(6)));
         register(Tiles.FOREST, new StaticTextureProvider(TileTexture.fromTextureId(7)));
@@ -37,6 +40,14 @@ public class TileRenderer
         register(Tiles.HILL, new StaticTextureProvider(TileTexture.fromTextureId(10)));
         register(Tiles.MOUNTAIN, new StaticTextureProvider(TileTexture.fromTextureId(11)));
         register(Tiles.SWAMP, new StaticTextureProvider(TileTexture.fromTextureId(12)));
+        register(Tiles.SWAMP_DECO, new StaticTextureProvider(TileTexture.fromTextureId(13)));
+        register(Tiles.SWAMP_TREE, new StaticTextureProvider(TileTexture.fromTextureId(14)));
+        register(Tiles.TOWN, new StaticTextureProvider(TileTexture.fromTextureId(16)));
+        register(Tiles.TOWN_BLOCKED_1, new StaticTextureProvider(TileTexture.fromTextureId(17)));
+        register(Tiles.TOWN_BLOCKED_2, new StaticTextureProvider(TileTexture.fromTextureId(18)));
+        register(Tiles.TOWN_BLOCKED_3, new StaticTextureProvider(TileTexture.fromTextureId(19)));
+        register(Tiles.TOWN_BLOCKED_4, new StaticTextureProvider(TileTexture.fromTextureId(20)));
+        register(Tiles.PORT, new StaticTextureProvider(TileTexture.fromTextureId(15)));
     }
     
     public static TileTexture getTileTexture(TileMap map, Tile t, int x, int y)

+ 99 - 20
src/pathgame/tilemap/Tile.java

@@ -1,6 +1,7 @@
 package pathgame.tilemap;
 
 import java.util.function.Function;
+import pathgame.gameplay.Player;
 import pathgame.gameplay.PlayerAbilities;
 
 /** Base class for tiles. Tiles are registered on construction.
@@ -9,6 +10,59 @@ import pathgame.gameplay.PlayerAbilities;
  */
 public class Tile
 {
+    public static class TileBuilder
+    {
+        private int energyCost = 1;
+        private float forestReplaceChance = 1.0f;
+        private Function<PlayerAbilities, Integer> speedUp = (pa) -> 0;
+        private boolean canHostTown = true;
+        private boolean blocksMovement = false;
+        
+        private TileBuilder()
+        {
+        }
+        
+        public static TileBuilder create()
+        {
+            return new TileBuilder();
+        }
+
+        public TileBuilder setEnergyCost(int energyCost)
+        {
+            this.energyCost = energyCost;
+            return this;
+        }
+
+        public TileBuilder setForestReplaceChance(float forestReplaceChance)
+        {
+            this.forestReplaceChance = forestReplaceChance;
+            return this;
+        }
+
+        public TileBuilder setSpeedUp(Function<PlayerAbilities, Integer> speedUp)
+        {
+            this.speedUp = speedUp;
+            return this;
+        }
+
+        public TileBuilder noTown()
+        {
+            this.canHostTown = false;
+            return this;
+        }
+        
+        public TileBuilder noMovement()
+        {
+            this.blocksMovement = true;
+            return this;
+        }
+        
+        public Tile build()
+        {
+            return new Tile(energyCost, forestReplaceChance, speedUp, canHostTown, blocksMovement);
+        }
+    }
+    
     private static int idCounter = 0;
     private static Tile[] tiles = new Tile[8];
     
@@ -42,32 +96,17 @@ public class Tile
     private final int energyCost;
     private final float forestReplaceChance;
     private final Function<PlayerAbilities, Integer> speedUp;
+    private final boolean canHostTown;
+    private final boolean blocksMovement;
     
-    /** Creates a new tile, which is automatically registered.
-     *
-     */
-    public Tile(int energyCost, float forestReplaceChance, Function<PlayerAbilities, Integer> speedUp)
+    protected Tile(int energyCost, float forestReplaceChance, Function<PlayerAbilities, Integer> speedUp, boolean canHostTown, boolean blocksMovement)
     {
         id = addTile(this);
         this.energyCost = energyCost;
         this.forestReplaceChance = forestReplaceChance;
         this.speedUp = speedUp;
-    }
-    
-    /** Creates a new tile, which is automatically registered.
-     *
-     */
-    public Tile(int energyCost, Function<PlayerAbilities, Integer> speedUp)
-    {
-        this(energyCost, 1.0f, speedUp);
-    }
-    
-    /** Creates a new tile, which is automatically registered.
-     *
-     */
-    public Tile(int energyCost)
-    {
-        this(energyCost, 1.0f, (pa) -> 0);
+        this.canHostTown = canHostTown;
+        this.blocksMovement = blocksMovement;
     }
 
     /** Returns the id of the tile.
@@ -92,4 +131,44 @@ public class Tile
     {
         return forestReplaceChance;
     } 
+    
+    /** Returns true if this tile can be replaced by a town.
+     *
+     * @return true if this tile can be replaced by a town
+     */
+    public boolean canHostTown()
+    {
+        return canHostTown;
+    } 
+    
+    /** Called when the player fully enters a tile.
+     *
+     * @param p the player
+     * @param map the current tilemap
+     * @param x the x coordinate of the tile
+     * @param y the y coordinate of the tile
+     */
+    public void onEnter(Player p, TileMap map, int x, int y)
+    {
+    }
+    
+    /** Called when the player leaves a tile.
+     *
+     * @param p the player
+     * @param map the current tilemap
+     * @param x the x coordinate of the tile
+     * @param y the y coordinate of the tile
+     */
+    public void onLeave(Player p, TileMap map, int x, int y)
+    {
+    }
+
+    /** Returns true if this tile blocks movement.
+     *
+     * @return true if this tile blocks movement
+     */
+    public boolean isBlockingMovement()
+    {
+        return blocksMovement;
+    }
 }

+ 39 - 0
src/pathgame/tilemap/TileMap.java

@@ -1,5 +1,8 @@
 package pathgame.tilemap;
 
+import java.util.Iterator;
+import java.util.LinkedList;
+
 /** Fixed size container for tile maps. Changes are stored in a dirty flag,
  * which can be used for rendering.
  *
@@ -7,10 +10,19 @@ package pathgame.tilemap;
  */
 public class TileMap
 {
+    private static class TownConverter
+    {
+        private int x;
+        private int y;
+        private int ticks = 0;
+        private int index = -1;
+    }
+    
     private final int width;
     private final int height;
     private final int[][] tiles;
     private boolean dirty = true;
+    private final LinkedList<TownConverter> townConverters = new LinkedList<>();
     
     /** Creates a new tile map of the given size.
      *
@@ -82,5 +94,32 @@ public class TileMap
         dirty = false;
     }
     
+    public void tick()
+    {
+        Iterator<TownConverter> iter = townConverters.iterator();
+        while(iter.hasNext())
+        {
+            TownConverter tc = iter.next();
+            tc.ticks++;
+            if(tc.ticks % 10 == 0)
+            {
+                tc.index++;
+                if(tc.index >= Tiles.TOWN_BLOCKED.length)
+                {
+                    iter.remove();
+                    continue;
+                }
+                setTile(tc.x, tc.y, Tiles.TOWN_BLOCKED[tc.index]);
+            }
+        }
+    }
+    
+    public void convertTown(int x, int y)
+    {
+        TownConverter tc = new TownConverter();
+        tc.x = x;
+        tc.y = y;
+        townConverters.add(tc);
+    }
 }
 

+ 65 - 24
src/pathgame/tilemap/TileMapGenerator.java

@@ -1,34 +1,21 @@
 package pathgame.tilemap;
 
 import java.util.Random;
-import java.util.TreeMap;
 
 public class TileMapGenerator
 {
-    private static final TreeMap<Integer, Tile> GRASS_MAP = new TreeMap<>();
-    
-    static
-    {
-        GRASS_MAP.put(0, Tiles.GRASS);
-        GRASS_MAP.put(76, Tiles.GRASS_WITH_STONE);
-        GRASS_MAP.put(80, Tiles.GRASS_WITH_6_BUSHES);
-        GRASS_MAP.put(84, Tiles.GRASS_WITH_3_BUSHES);
-        GRASS_MAP.put(88, Tiles.GRASS_WITH_FLOWERS);
-        GRASS_MAP.put(92, Tiles.GRASS_WITH_HILL);
-        GRASS_MAP.put(96, Tiles.GRASS_WITH_EARTH);
-    }
-    
     private static long seed = 1;
     
     /** Returns a random generated map
      *
      * @param width the width of the map
      * @param height the height of the map
+     * @param towns the amount of towns
      * @return a random generated map
      */
-    public static TileMap getMap(int width, int height)
+    public static TileMap getMap(int width, int height, int towns)
     {
-        return getMap(width, height, seed++);
+        return getMap(width, height, seed++, towns);
     }
     
     /** Returns a random generated map
@@ -36,9 +23,10 @@ public class TileMapGenerator
      * @param width the width of the map
      * @param height the height of the map
      * @param seed the seed for the random number generator
+     * @param towns the amount of towns
      * @return a random generated map
      */
-    public static TileMap getMap(int width, int height, long seed)
+    public static TileMap getMap(int width, int height, long seed, int towns)
     {
         Random r = new Random(seed);
         
@@ -74,18 +62,23 @@ public class TileMapGenerator
         
         int forestSize = ((width + height) / 2) / 10;
         forestSize *= forestSize;
-        
         generateForest(map, r, forestSize, 10, 2, Tiles.FOREST);
-        generateForest(map, r, forestSize, 5, 2, Tiles.SWAMP);
+        generateForest(map, r, forestSize, 5, 2, Tiles.SWAMP, Tiles.SWAMP, Tiles.SWAMP_DECO, Tiles.SWAMP_TREE);
+        
+        generateTowns(map, r, towns);
         return map;
     }
     
     private static Tile randomGrass(Random r)
     {
-        return GRASS_MAP.floorEntry(r.nextInt(100)).getValue();
+        if(r.nextFloat() < 0.3f)
+        {
+            return randomTile(Tiles.GRASS_VARIANTS, r);
+        }
+        return Tiles.GRASS;
     }
     
-    private static void generateForest(TileMap map, Random r, int depth, int placements, int jumpRadius, Tile t)
+    private static void generateForest(TileMap map, Random r, int depth, int placements, int jumpRadius, Tile... t)
     {
         for(int i = 0; i < placements; i++)
         {
@@ -109,7 +102,7 @@ public class TileMapGenerator
                 
                 if(r.nextFloat() < map.getTile(x, y).getForestReplaceChance())
                 {
-                    map.setTile(x, y, t);
+                    map.setTile(x, y, randomTile(t, r));
                     placeForest(map, r, x - 1, y, t);
                     placeForest(map, r, x + 1, y, t);
                     placeForest(map, r, x, y - 1, t);
@@ -124,14 +117,62 @@ public class TileMapGenerator
         }
     }
     
-    private static void placeForest(TileMap map, Random r, int x, int y, Tile t)
+    private static Tile randomTile(Tile[] tiles, Random r)
+    {
+        if(tiles.length == 1)
+        {
+            return tiles[0];
+        }
+        return tiles[r.nextInt(tiles.length)];
+    }
+    
+    private static void placeForest(TileMap map, Random r, int x, int y, Tile... t)
     {
         if(x >= 0 && x < map.getWidth() && y >= 0 && y < map.getHeight())
         {
             if(r.nextFloat() * 2 < map.getTile(x, y).getForestReplaceChance())
             {
-                map.setTile(x, y, t);
+                map.setTile(x, y, randomTile(t, r));
+            }
+        }
+    }
+    
+    private static void generateTowns(TileMap map, Random r, int towns)
+    {
+        int failCounter = 0;
+        while(towns > 0 && failCounter < 100)
+        {
+            int x = r.nextInt(map.getWidth());
+            int y = r.nextInt(map.getHeight());
+            if(map.getTile(x, y).canHostTown() && checkNearbyTowns(map, x, y, 2))
+            {
+                map.setTile(x, y, Tiles.TOWN);
+                towns--;
+                failCounter = 0;
+            }
+            else
+            {
+                failCounter++;
+            }
+        }
+    }
+    
+    private static boolean checkNearbyTowns(TileMap map, int x, int y, int radius)
+    {
+        int startX = Math.max(x - radius, 0);
+        int startY = Math.max(y - radius, 0);
+        int endX = Math.min(x + radius, map.getWidth() - 1);
+        int endY = Math.min(y + radius, map.getHeight() - 1);
+        for(int mx = startX; mx <= endX; mx++)
+        {
+            for(int my = startY; my <= endY; my++)
+            {
+                if(map.getTile(mx, my) == Tiles.TOWN)
+                {
+                    return false;
+                }
             }
         }
+        return true;
     }
 }

+ 24 - 0
src/pathgame/tilemap/TileTown.java

@@ -0,0 +1,24 @@
+package pathgame.tilemap;
+
+import pathgame.gameplay.Player;
+
+public class TileTown extends Tile
+{
+    public TileTown()
+    {
+        super(1, 0.0f, (pa) -> 0, false, false);
+    }
+
+    @Override
+    public void onEnter(Player p, TileMap map, int x, int y)
+    {
+        System.out.println("Enter Town " + x + " " + y);
+    }
+
+    @Override
+    public void onLeave(Player p, TileMap map, int x, int y)
+    {
+        System.out.println("Leave Town " + x + " " + y);
+        map.convertTown(x, y);
+    }
+}

+ 82 - 14
src/pathgame/tilemap/Tiles.java

@@ -2,24 +2,92 @@ package pathgame.tilemap;
 
 public class Tiles
 {
-    public final static Tile GRASS = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_STONE = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_6_BUSHES = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_3_BUSHES = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_FLOWERS = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_HILL = new Tile(1, (pa) -> pa.getFasterGrass());
-    public final static Tile GRASS_WITH_EARTH = new Tile(1, (pa) -> pa.getFasterGrass());
+    public final static Tile GRASS = buildGrass();
+    public final static Tile GRASS_WITH_STONE = buildGrass();
+    public final static Tile GRASS_WITH_6_BUSHES = buildGrass();
+    public final static Tile GRASS_WITH_3_BUSHES = buildGrass();
+    public final static Tile GRASS_WITH_FLOWERS_1 = buildGrass();
+    public final static Tile GRASS_WITH_FLOWERS_2 = buildGrass();
+    public final static Tile GRASS_WITH_FLOWERS_3 = buildGrass();
+    public final static Tile GRASS_WITH_FLOWERS_4 = buildGrass();
+    public final static Tile GRASS_WITH_HILL = buildGrass();
+    public final static Tile GRASS_WITH_EARTH = buildGrass();
     
     public final static Tile[] GRASS_VARIANTS = new Tile[]
     {
         GRASS, GRASS_WITH_STONE, GRASS_WITH_6_BUSHES, GRASS_WITH_3_BUSHES, 
-        GRASS_WITH_FLOWERS, GRASS_WITH_HILL, GRASS_WITH_EARTH
+        GRASS_WITH_FLOWERS_1, GRASS_WITH_FLOWERS_2, GRASS_WITH_FLOWERS_3,
+        GRASS_WITH_FLOWERS_4, GRASS_WITH_HILL, GRASS_WITH_EARTH
     };
     
-    public final static Tile FOREST = new Tile(2, 0.0f, (pa) -> pa.getFasterForest());
-    public final static Tile SWAMP = new Tile(3);
-    public final static Tile SHALLOW_WATER = new Tile(3, 0.0f, (pa) -> pa.getFasterShallowWater());
-    public final static Tile DEEP_WATER = new Tile(5, 0.0f, (pa) -> pa.getFasterDeepWater());
-    public final static Tile HILL = new Tile(3, 0.5f, (pa) -> pa.getFasterHill());
-    public final static Tile MOUNTAIN = new Tile(5, 0.0f, (pa) -> pa.getFasterMountain());
+    public final static Tile FOREST = Tile.TileBuilder.create()
+            .setEnergyCost(2)
+            .setForestReplaceChance(0.0f)
+            .setSpeedUp((pa) -> pa.getFasterForest())
+            .build();
+    public final static Tile SWAMP = buildSwamp();
+    public final static Tile SWAMP_DECO = buildSwamp();
+    public final static Tile SWAMP_TREE = buildSwamp();
+    public final static Tile SHALLOW_WATER = Tile.TileBuilder.create()
+            .setEnergyCost(3)
+            .setForestReplaceChance(0.0f)
+            .setSpeedUp((pa) -> pa.getFasterShallowWater())
+            .noTown()
+            .build();
+    public final static Tile DEEP_WATER = Tile.TileBuilder.create()
+            .setEnergyCost(3)
+            .setForestReplaceChance(0.0f)
+            .setSpeedUp((pa) -> pa.getFasterDeepWater())
+            .noTown()
+            .build();
+    public final static Tile HILL = Tile.TileBuilder.create()
+            .setEnergyCost(3)
+            .setForestReplaceChance(0.5f)
+            .setSpeedUp((pa) -> pa.getFasterHill())
+            .build();
+    public final static Tile MOUNTAIN = Tile.TileBuilder.create()
+            .setEnergyCost(5)
+            .setForestReplaceChance(0.0f)
+            .setSpeedUp((pa) -> pa.getFasterMountain())
+            .noTown()
+            .build();
+    public final static Tile TOWN = new TileTown();
+    public final static Tile TOWN_BLOCKED_1 = buildBlockedTown();
+    public final static Tile TOWN_BLOCKED_2 = buildBlockedTown();
+    public final static Tile TOWN_BLOCKED_3 = buildBlockedTown();
+    public final static Tile TOWN_BLOCKED_4 = buildBlockedTown();
+    
+    public final static Tile[] TOWN_BLOCKED = new Tile[]
+    {
+        TOWN_BLOCKED_1, TOWN_BLOCKED_2, TOWN_BLOCKED_3, TOWN_BLOCKED_4
+    };
+    
+    public final static Tile PORT = Tile.TileBuilder.create()
+            .noTown()
+            .setForestReplaceChance(0.0f)
+            .build();
+    
+    public final static Tile buildGrass()
+    {
+        return Tile.TileBuilder.create()
+                .setSpeedUp((pa) -> pa.getFasterGrass())
+                .build();
+    }
+    
+    public final static Tile buildSwamp()
+    {
+        return Tile.TileBuilder.create()
+                .setEnergyCost(3)
+                .setForestReplaceChance(0.0f)
+                .build();
+    }
+    
+    public final static Tile buildBlockedTown()
+    {
+        return Tile.TileBuilder.create()
+                .setForestReplaceChance(0.0f)
+                .noTown()
+                .noMovement()
+                .build();
+    }
 }